1/* 2 * Copyright 2007-2010, Fran��ois Revol, revol@free.fr. 3 * Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Copyright 2002-2007, Axel D��rfler, axeld@pinc-software.de. All rights 5 * reserved. 6 * Copyright 2019, Adrien Destugues, pulkomandy@pulkomandy.tk. 7 * Distributed under the terms of the MIT License. 8 * 9 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 10 * Distributed under the terms of the NewOS License. 11 */ 12 13 14#include <arch_cpu_defs.h> 15#include <boot/kernel_args.h> 16#include <KernelExport.h> 17#include <kernel.h> 18#include <vm/vm.h> 19#include <vm/vm_priv.h> 20#include <vm/VMAddressSpace.h> 21#include <Clint.h> 22#include <Htif.h> 23#include <Plic.h> 24 25#include "RISCV64VMTranslationMap.h" 26 27 28#define TRACE_VM_TMAP 29#ifdef TRACE_VM_TMAP 30# define TRACE(x...) dprintf(x) 31#else 32# define TRACE(x...) ; 33#endif 34 35 36ssize_t gVirtFromPhysOffset = 0; 37 38phys_addr_t sPageTable = 0; 39char sPhysicalPageMapperData[sizeof(RISCV64VMPhysicalPageMapper)]; 40 41 42// TODO: Consolidate function with RISCV64VMTranslationMap 43 44static Pte* 45LookupPte(addr_t virtAdr, bool alloc, kernel_args* args, 46 phys_addr_t (*get_free_page)(kernel_args *)) 47{ 48 Pte *pte = (Pte*)VirtFromPhys(sPageTable); 49 for (int level = 2; level > 0; level --) { 50 pte += VirtAdrPte(virtAdr, level); 51 if (!pte->isValid) { 52 if (!alloc) 53 return NULL; 54 page_num_t ppn = get_free_page(args); 55 if (ppn == 0) 56 return NULL; 57 memset((Pte*)VirtFromPhys(B_PAGE_SIZE * ppn), 0, B_PAGE_SIZE); 58 Pte newPte { 59 .isValid = true, 60 .isGlobal = true, 61 .ppn = ppn 62 }; 63 pte->val = newPte.val; 64 } 65 pte = (Pte*)VirtFromPhys(B_PAGE_SIZE * pte->ppn); 66 } 67 pte += VirtAdrPte(virtAdr, 0); 68 return pte; 69} 70 71 72static void 73Map(addr_t virtAdr, phys_addr_t physAdr, uint64 flags, kernel_args* args, 74 phys_addr_t (*get_free_page)(kernel_args *)) 75{ 76 // dprintf("Map(0x%" B_PRIxADDR ", 0x%" B_PRIxADDR ")\n", virtAdr, physAdr); 77 Pte* pte = LookupPte(virtAdr, true, args, get_free_page); 78 if (pte == NULL) panic("can't allocate page table"); 79 80 Pte newPte { 81 .isValid = true, 82 .isGlobal = true, // we map only kernel pages here so always set global flag 83 .isAccessed = true, 84 .isDirty = true, 85 .ppn = physAdr / B_PAGE_SIZE 86 }; 87 newPte.val |= flags; 88 89 pte->val = newPte.val; 90 91 FlushTlbPage(virtAdr); 92} 93 94 95//#pragma mark - 96 97status_t 98arch_vm_translation_map_init(kernel_args *args, 99 VMPhysicalPageMapper** _physicalPageMapper) 100{ 101 TRACE("vm_translation_map_init: entry\n"); 102 103#ifdef TRACE_VM_TMAP 104 TRACE("physical memory ranges:\n"); 105 for (uint32 i = 0; i < args->num_physical_memory_ranges; i++) { 106 phys_addr_t start = args->physical_memory_range[i].start; 107 phys_addr_t end = start + args->physical_memory_range[i].size; 108 TRACE(" %" B_PRIxPHYSADDR " - %" B_PRIxPHYSADDR "\n", start, end); 109 } 110 111 TRACE("allocated physical ranges:\n"); 112 for (uint32 i = 0; i < args->num_physical_allocated_ranges; i++) { 113 phys_addr_t start = args->physical_allocated_range[i].start; 114 phys_addr_t end = start + args->physical_allocated_range[i].size; 115 TRACE(" %" B_PRIxPHYSADDR " - %" B_PRIxPHYSADDR "\n", start, end); 116 } 117 118 TRACE("allocated virtual ranges:\n"); 119 for (uint32 i = 0; i < args->num_virtual_allocated_ranges; i++) { 120 addr_t start = args->virtual_allocated_range[i].start; 121 addr_t end = start + args->virtual_allocated_range[i].size; 122 TRACE(" %" B_PRIxADDR " - %" B_PRIxADDR "\n", start, end); 123 } 124 125 TRACE("kernel args ranges:\n"); 126 for (uint32 i = 0; i < args->num_kernel_args_ranges; i++) { 127 phys_addr_t start = args->kernel_args_range[i].start; 128 phys_addr_t end = start + args->kernel_args_range[i].size; 129 TRACE(" %" B_PRIxPHYSADDR " - %" B_PRIxPHYSADDR "\n", start, end); 130 } 131#endif 132 133 sPageTable = SatpReg{.val = Satp()}.ppn * B_PAGE_SIZE; 134 135 dprintf("physMapBase: %#" B_PRIxADDR "\n", args->arch_args.physMap.start); 136 dprintf("physMemBase: %#" B_PRIxADDR "\n", args->physical_memory_range[0].start); 137 gVirtFromPhysOffset = args->arch_args.physMap.start - args->physical_memory_range[0].start; 138 139 clear_ac(); 140 141 *_physicalPageMapper = new(&sPhysicalPageMapperData) 142 RISCV64VMPhysicalPageMapper(); 143 144 return B_OK; 145} 146 147 148status_t 149arch_vm_translation_map_init_post_sem(kernel_args *args) 150{ 151 return B_OK; 152} 153 154 155status_t 156arch_vm_translation_map_init_post_area(kernel_args *args) 157{ 158 TRACE("vm_translation_map_init_post_area: entry\n"); 159 return B_OK; 160} 161 162 163status_t 164arch_vm_translation_map_early_map(kernel_args *args, 165 addr_t virtAdr, phys_addr_t physAdr, uint8 attributes, 166 phys_addr_t (*get_free_page)(kernel_args *)) 167{ 168 //dprintf("early_map(%#" B_PRIxADDR ", %#" B_PRIxADDR ")\n", virtAdr, physAdr); 169 Pte flags { 170 .isRead = (attributes & B_KERNEL_READ_AREA) != 0, 171 .isWrite = (attributes & B_KERNEL_WRITE_AREA) != 0, 172 .isExec = (attributes & B_KERNEL_EXECUTE_AREA) != 0, 173 }; 174 Map(virtAdr, physAdr, flags.val, args, get_free_page); 175 return B_OK; 176} 177 178 179status_t 180arch_vm_translation_map_create_map(bool kernel, VMTranslationMap** _map) 181{ 182 *_map = new(std::nothrow) RISCV64VMTranslationMap(kernel, 183 (kernel) ? sPageTable : 0); 184 185 if (*_map == NULL) 186 return B_NO_MEMORY; 187 188 return B_OK; 189} 190 191 192bool 193arch_vm_translation_map_is_kernel_page_accessible(addr_t virtualAddress, 194 uint32 protection) 195{ 196 return virtualAddress != 0; 197} 198