| /* | |
| * Copyright 2023 Google LLC | |
| * | |
| * 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 "sw/device/lib/virtual_memory.h" | |
| #include "sw/device/lib/testing/test_framework/check.h" | |
| // Defines to help build page tables for the SV32 scheme. | |
| // More details can be found in the | |
| // RISC-V privileged spec. | |
| // Mask to preserve the top 22-bits of a physical address. | |
| #define SV32_PPN_MASK (0xFFFFFC00U) | |
| // Shift to apply to PPNs when making a PTE. | |
| // This is due to physical addresses being 34-bits under the hood. | |
| // See section 4.3.1 in the privileged spec for more detail. | |
| #define SV32_PPN_SHIFT (2) | |
| // Number of bits to shift right to get the VPN0 of a virtual address. | |
| // VPN1 is used as an index into the L1 page-table. | |
| #define SV32_VPN1_SHIFT (22) | |
| // Number of bits to shift right to get the VPN0 of a virtual address. | |
| // VPN0 is used as an index into the L2 page-table. | |
| #define SV32_VPN0_SHIFT (12) | |
| // Mask to apply after shifting a virtual address, to preserve VPN0 only. | |
| #define SV32_VPN0_MASK (0x3FF) | |
| // PTE status bits, setting the page as valid and RWX. | |
| #define SV32_PAGE_SUPERVISOR (0xCF) | |
| // PTE status bits, setting the page as valid, RWX, and available to user mode. | |
| #define SV32_PAGE_USER (0xDF) | |
| // PTE status bits, to indicate that the PTE is valid. Used alone for non-leaf | |
| // pages. | |
| #define SV32_PTE_VALID (1) | |
| void machine_map_megapage(void *paddr, void *vaddr, uint32_t *pt) { | |
| uint32_t page = (uint32_t)vaddr >> SV32_VPN1_SHIFT; | |
| uint32_t leaf = (((uint32_t)paddr & SV32_PPN_MASK) >> SV32_PPN_SHIFT) | | |
| SV32_PAGE_SUPERVISOR; | |
| pt[page] = leaf; | |
| } | |
| void machine_map_region(uint32_t paddr, uint32_t vaddr_start, | |
| uint32_t vaddr_end, uint32_t *l1pt, uint32_t *l2pt, | |
| bool user) { | |
| CHECK((vaddr_start % PAGE_SIZE) == 0); | |
| CHECK((paddr % PAGE_SIZE) == 0); | |
| uint32_t ppn1 = vaddr_start >> SV32_VPN1_SHIFT; | |
| uint32_t pte_lvl1 = | |
| (((uint32_t)l2pt & SV32_PPN_MASK) >> SV32_PPN_SHIFT) | SV32_PTE_VALID; | |
| l1pt[ppn1] = pte_lvl1; | |
| uint32_t page_count = vaddr_end - vaddr_start; | |
| page_count = (page_count + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1); | |
| page_count /= PAGE_SIZE; | |
| for (int i = 0; i < page_count; ++i) { | |
| uint32_t paddr_l2 = paddr + (PAGE_SIZE * i); | |
| uint32_t vaddr_l2 = vaddr_start + (PAGE_SIZE * i); | |
| uint32_t vpn0_2 = (vaddr_l2 >> SV32_VPN0_SHIFT) & SV32_VPN0_MASK; | |
| uint32_t pte_lvl2 = ((paddr_l2 & SV32_PPN_MASK) >> SV32_PPN_SHIFT); | |
| if (user) { | |
| pte_lvl2 |= SV32_PAGE_USER; | |
| } else { | |
| pte_lvl2 |= SV32_PAGE_SUPERVISOR; | |
| } | |
| l2pt[vpn0_2] = pte_lvl2; | |
| } | |
| } | |
| __attribute__((naked)) void supervisor_trampoline(uint32_t a0_smode_fn, | |
| uint32_t a1_satp, | |
| uint32_t a2_medeleg, | |
| uint32_t a3_stvec, | |
| uint32_t a4_mideleg) { | |
| asm volatile( | |
| ".option push\n" | |
| ".option norelax\n" | |
| "csrw mideleg, a4\n" | |
| "csrw medeleg, a2\n" | |
| "csrw stvec, a3\n" | |
| "csrw satp, a1\n" | |
| "sfence.vma\n" | |
| "li x1, 0x0000080a\n" | |
| "csrw mstatus, x1\n" | |
| "csrw mepc, a0\n" | |
| "mret\n" | |
| ".option pop\n" | |
| : | |
| : | |
| : "memory"); | |
| } | |
| __attribute__((naked)) void user_trampoline(uint32_t a0_umode_fn) { | |
| asm volatile( | |
| ".option push\n" | |
| ".option norelax\n" | |
| "csrw sepc, a0\n" | |
| "sret\n" | |
| ".option pop\n" | |
| : | |
| : | |
| : "memory"); | |
| } |