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