blob: 4420850dad577131b30672c6bd3aee6cd7bf5d92 [file] [log] [blame]
/*
* Copyright 2023 Google LLC
* Copyright lowRISC contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "hw/top_matcha/sw/autogen/top_matcha.h"
#include "sw/device/lib/runtime/log.h"
#include "sw/device/lib/runtime/print.h"
#include "sw/device/lib/testing/test_framework/check.h"
#include "sw/device/lib/testing/test_framework/ottf_test_config.h"
#include "sw/device/lib/testing/test_framework/status.h"
#include "sw/device/lib/testing/test_framework/test_util.h"
#include "sw/device/lib/virtual_memory.h"
#define CAUSE_USER_ECALL (0x8)
uint32_t supervisor_l1pt[PAGE_SIZE / sizeof(uint32_t)]
__attribute__((aligned(PAGE_SIZE)));
uint32_t supervisor_l2pt[PAGE_SIZE / sizeof(uint32_t)]
__attribute__((aligned(PAGE_SIZE)));
uint32_t user_l2pt[PAGE_SIZE / sizeof(uint32_t)]
__attribute__((aligned(PAGE_SIZE)));
extern uint32_t __VIRTUAL_ROM;
extern uint32_t __virtual_start;
extern uint32_t __virtual_end;
extern uint32_t __SUPER_VIRTUAL_ROM;
extern uint32_t __super_virtual_start;
extern uint32_t __super_virtual_end;
OTTF_DEFINE_TEST_CONFIG();
static dif_uart_t smc_uart;
// Overrides the default supervisor ecall handler.
// From here, we will set the test pass.
void ottf_supervisor_ecall_handler(void) { test_status_set(kTestStatusPassed); }
// Simple method for U-mode. Simply does an ecall.
// Due to how we configure delegation in main, this ecall will
// be handled by S-mode.
__attribute__((section(".virtual"))) static void umode_fn(void) {
asm volatile(
".option push \n"
".option norvc \n"
"ecall \n"
".option pop \n");
}
// Function that will execute in S-mode.
// Passes a virtual function address to the U-mode trampoline.
static __attribute__((section(".super_virtual"))) void smode_fn(void) {
user_trampoline((uint32_t)umode_fn);
}
// S-mode trap handler.
// We simply ecall into M-mode.
static __attribute__((section(".super_virtual")))
__attribute__((naked, aligned(256))) void
stvec(void) {
asm volatile(
".option push \n"
".option norvc \n"
"ecall \n"
".option pop \n");
}
void _ottf_main(void) {
test_status_set(kTestStatusInTest);
// Initialize the SMC UART to enable logging for non-DV simulation platforms.
if (kDeviceType != kDeviceSimDV) {
init_uart(TOP_MATCHA_SMC_UART_BASE_ADDR, &smc_uart);
}
// Map our code space and UART peripheral.
// Both are mapped such that the virtual addresses
// and physical addresses are the same, but this still
// causes address translation to happen.
machine_map_megapage((void *)TOP_MATCHA_RAM_SMC_BASE_ADDR,
(void *)TOP_MATCHA_RAM_SMC_BASE_ADDR,
(uint32_t *)supervisor_l1pt);
machine_map_megapage((void *)TOP_MATCHA_SMC_UART_BASE_ADDR,
(void *)TOP_MATCHA_SMC_UART_BASE_ADDR,
(uint32_t *)supervisor_l1pt);
// Set up 2-level page tables, one set for user-mode and one set for
// supervisor-mode.
machine_map_region((uint32_t)&__VIRTUAL_ROM, (uint32_t)&__virtual_start,
(uint32_t)&__virtual_end, supervisor_l1pt, user_l2pt,
true);
machine_map_region(
(uint32_t)&__SUPER_VIRTUAL_ROM, (uint32_t)&__super_virtual_start,
(uint32_t)&__super_virtual_end, supervisor_l1pt, supervisor_l2pt, false);
// Calculate the value of the SATP register.
// We enable SV32 virtual memory, and store the page
// containing our page tables.
uint32_t satp = (uint32_t)(0x1llu << 31) | ((uint32_t)supervisor_l1pt >> 12);
// Delegate U-mode ecalls to S-mode.
uint32_t medeleg = (1 << CAUSE_USER_ECALL);
// Execute smode_fn in supervisor mode, after enabling virtual memory.
supervisor_trampoline((uint32_t)smode_fn, (uint32_t)satp, (uint32_t)medeleg,
(uint32_t)stvec, 0);
__builtin_unreachable();
}