1 /* 2 * Copyright 2010, Ithamar R. Adema, ithamar.adema@team-embedded.nl 3 * Copyright 2010, Ingo Weinhold, ingo_weinhold@gmx.de. 4 * Distributed under the terms of the MIT License. 5 */ 6 #ifndef KERNEL_ARCH_ARM_PAGING_32_BIT_ARM_PAGING_METHOD_32_BIT_H 7 #define KERNEL_ARCH_ARM_PAGING_32_BIT_ARM_PAGING_METHOD_32_BIT_H 8 9 10 #include "paging/32bit/paging.h" 11 #include "paging/ARMPagingMethod.h" 12 #include "paging/ARMPagingStructures.h" 13 14 15 class TranslationMapPhysicalPageMapper; 16 class ARMPhysicalPageMapper; 17 18 19 class ARMPagingMethod32Bit : public ARMPagingMethod { 20 public: 21 ARMPagingMethod32Bit(); 22 virtual ~ARMPagingMethod32Bit(); 23 24 virtual status_t Init(kernel_args* args, 25 VMPhysicalPageMapper** _physicalPageMapper); 26 virtual status_t InitPostArea(kernel_args* args); 27 28 virtual status_t CreateTranslationMap(bool kernel, 29 VMTranslationMap** _map); 30 31 virtual status_t MapEarly(kernel_args* args, 32 addr_t virtualAddress, 33 phys_addr_t physicalAddress, 34 uint8 attributes, 35 page_num_t (*get_free_page)(kernel_args*)); 36 37 virtual bool IsKernelPageAccessible(addr_t virtualAddress, 38 uint32 protection); 39 40 inline uint32 KernelPhysicalPageDirectory() const 41 { return fKernelPhysicalPageDirectory; } 42 inline page_directory_entry* KernelVirtualPageDirectory() const 43 { return fKernelVirtualPageDirectory; } 44 inline ARMPhysicalPageMapper* PhysicalPageMapper() const 45 { return fPhysicalPageMapper; } 46 inline TranslationMapPhysicalPageMapper* KernelPhysicalPageMapper() const 47 { return fKernelPhysicalPageMapper; } 48 49 static ARMPagingMethod32Bit* Method(); 50 51 static void PutPageTableInPageDir( 52 page_directory_entry* entry, 53 phys_addr_t pgtablePhysical, 54 uint32 attributes); 55 static void PutPageTableEntryInTable( 56 page_table_entry* entry, 57 phys_addr_t physicalAddress, 58 uint32 attributes, uint32 memoryType, 59 bool globalPage); 60 static page_table_entry SetPageTableEntry(page_table_entry* entry, 61 page_table_entry newEntry); 62 static page_table_entry SetPageTableEntryFlags(page_table_entry* entry, 63 uint32 flags); 64 static page_table_entry TestAndSetPageTableEntry( 65 page_table_entry* entry, 66 page_table_entry newEntry, 67 page_table_entry oldEntry); 68 static page_table_entry ClearPageTableEntry(page_table_entry* entry); 69 static page_table_entry ClearPageTableEntryFlags( 70 page_table_entry* entry, uint32 flags); 71 72 static uint32 AttributesToPageTableEntryFlags( 73 uint32 attributes); 74 static uint32 PageTableEntryFlagsToAttributes( 75 uint32 pageTableEntry); 76 static uint32 MemoryTypeToPageTableEntryFlags( 77 uint32 memoryType); 78 79 private: 80 struct PhysicalPageSlotPool; 81 friend struct PhysicalPageSlotPool; 82 83 private: 84 inline int32 _GetInitialPoolCount(); 85 86 static void _EarlyPreparePageTables( 87 page_table_entry* pageTables, 88 addr_t address, size_t size); 89 static status_t _EarlyQuery(addr_t virtualAddress, 90 phys_addr_t *_physicalAddress); 91 92 private: 93 uint32 fKernelPhysicalPageDirectory; 94 page_directory_entry* fKernelVirtualPageDirectory; 95 96 ARMPhysicalPageMapper* fPhysicalPageMapper; 97 TranslationMapPhysicalPageMapper* fKernelPhysicalPageMapper; 98 }; 99 100 101 /*static*/ inline ARMPagingMethod32Bit* 102 ARMPagingMethod32Bit::Method() 103 { 104 return static_cast<ARMPagingMethod32Bit*>(gARMPagingMethod); 105 } 106 107 108 /*static*/ inline page_table_entry 109 ARMPagingMethod32Bit::SetPageTableEntry(page_table_entry* entry, 110 page_table_entry newEntry) 111 { 112 return atomic_get_and_set((int32*)entry, newEntry); 113 } 114 115 116 /*static*/ inline page_table_entry 117 ARMPagingMethod32Bit::SetPageTableEntryFlags(page_table_entry* entry, 118 uint32 flags) 119 { 120 return atomic_or((int32*)entry, flags); 121 } 122 123 124 /*static*/ inline page_table_entry 125 ARMPagingMethod32Bit::TestAndSetPageTableEntry(page_table_entry* entry, 126 page_table_entry newEntry, page_table_entry oldEntry) 127 { 128 return atomic_test_and_set((int32*)entry, newEntry, oldEntry); 129 } 130 131 132 /*static*/ inline page_table_entry 133 ARMPagingMethod32Bit::ClearPageTableEntry(page_table_entry* entry) 134 { 135 return SetPageTableEntry(entry, 0); 136 } 137 138 139 /*static*/ inline page_table_entry 140 ARMPagingMethod32Bit::ClearPageTableEntryFlags(page_table_entry* entry, uint32 flags) 141 { 142 return atomic_and((int32*)entry, ~flags); 143 } 144 145 146 /*static*/ inline uint32 147 ARMPagingMethod32Bit::AttributesToPageTableEntryFlags(uint32 attributes) 148 { 149 int apFlags = 0; 150 151 if ((attributes & B_WRITE_AREA) != 0) { 152 // kernel rw user rw 153 apFlags = ARM_MMU_L2_FLAG_AP1 | ARM_MMU_L2_FLAG_AP0; 154 } else if ((attributes & B_READ_AREA) != 0) { 155 if ((attributes & B_KERNEL_WRITE_AREA) != 0) { 156 // kernel rw user ro 157 apFlags = ARM_MMU_L2_FLAG_AP1; 158 } else { 159 // kernel ro user ro 160 apFlags = ARM_MMU_L2_FLAG_AP2 | ARM_MMU_L2_FLAG_AP1; 161 } 162 } else if ((attributes & B_KERNEL_WRITE_AREA) != 0) { 163 // kernel rw 164 apFlags = ARM_MMU_L2_FLAG_AP0; 165 } else { 166 // kernel ro 167 apFlags = ARM_MMU_L2_FLAG_AP2 | ARM_MMU_L2_FLAG_AP0; 168 } 169 170 if (((attributes & B_KERNEL_EXECUTE_AREA) == 0) && 171 ((attributes & B_EXECUTE_AREA) == 0)) { 172 apFlags |= ARM_MMU_L2_FLAG_XN; 173 } 174 175 return apFlags; 176 } 177 178 179 /*static*/ inline uint32 180 ARMPagingMethod32Bit::PageTableEntryFlagsToAttributes(uint32 pageTableEntry) 181 { 182 uint32 attributes; 183 184 if ((pageTableEntry & ARM_MMU_L2_FLAG_AP2) == 0) { 185 if ((pageTableEntry & ARM_MMU_L2_FLAG_AP1) != 0) { 186 if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0) 187 attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA; 188 else 189 attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA; 190 } else { 191 if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0) 192 attributes = B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA; 193 else 194 attributes = 0; 195 } 196 } else { 197 if ((pageTableEntry & ARM_MMU_L2_FLAG_AP1) != 0) 198 attributes = B_KERNEL_READ_AREA | B_READ_AREA; 199 else if ((pageTableEntry & ARM_MMU_L2_FLAG_AP0) != 0) 200 attributes = B_KERNEL_READ_AREA; 201 else 202 attributes = 0; 203 } 204 205 if ((pageTableEntry & ARM_MMU_L2_FLAG_XN) == 0) { 206 if ((attributes & B_KERNEL_READ_AREA) != 0) 207 attributes |= B_KERNEL_EXECUTE_AREA; 208 if ((attributes & B_READ_AREA) != 0) 209 attributes |= B_EXECUTE_AREA; 210 } 211 212 return attributes; 213 } 214 215 216 /*static*/ inline uint32 217 ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(uint32 memoryType) 218 { 219 switch (memoryType) { 220 case B_MTR_UC: 221 // Strongly Ordered 222 return 0; 223 case B_MTR_WC: 224 // Shareable Device Memory 225 return ARM_MMU_L2_FLAG_B; 226 case B_MTR_WT: 227 // Outer and Inner Write-Through, no Write-Allocate 228 return ARM_MMU_L2_FLAG_C; 229 case B_MTR_WP: 230 case B_MTR_WB: 231 default: 232 // Outer and Inner Write-Back, no Write-Allocate 233 return ARM_MMU_L2_FLAG_B | ARM_MMU_L2_FLAG_C; 234 } 235 } 236 237 238 #endif // KERNEL_ARCH_ARM_PAGING_32_BIT_ARM_PAGING_METHOD_32_BIT_H 239