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 17class TranslationMapPhysicalPageMapper; 18class ARMPhysicalPageMapper; 19 20 21class ARMPagingMethod32Bit : public ARMPagingMethod { 22public: 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 83private: 84 struct PhysicalPageSlotPool; 85 friend struct PhysicalPageSlotPool; 86 87private: 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 96private: 97 uint32 fKernelPhysicalPageDirectory; 98 page_directory_entry* fKernelVirtualPageDirectory; 99 100 ARMPhysicalPageMapper* fPhysicalPageMapper; 101 TranslationMapPhysicalPageMapper* fKernelPhysicalPageMapper; 102}; 103 104 105/*static*/ inline ARMPagingMethod32Bit* 106ARMPagingMethod32Bit::Method() 107{ 108 return static_cast<ARMPagingMethod32Bit*>(gARMPagingMethod); 109} 110 111 112/*static*/ inline page_table_entry 113ARMPagingMethod32Bit::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 121ARMPagingMethod32Bit::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 129ARMPagingMethod32Bit::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 137ARMPagingMethod32Bit::ClearPageTableEntry(page_table_entry* entry) 138{ 139 return SetPageTableEntry(entry, 0); 140} 141 142 143/*static*/ inline page_table_entry 144ARMPagingMethod32Bit::ClearPageTableEntryFlags(page_table_entry* entry, uint32 flags) 145{ 146 return atomic_and((int32*)entry, ~flags); 147} 148 149 150/*static*/ inline page_table_entry 151ARMPagingMethod32Bit::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 168ARMPagingMethod32Bit::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 203ARMPagingMethod32Bit::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 238ARMPagingMethod32Bit::MemoryTypeToPageTableEntryFlags(uint32 memoryType) 239{ 240 switch (memoryType) { 241 case B_MTR_UC: 242 // Strongly Ordered 243 return 0; 244 case B_MTR_WC: 245 // Shareable Device Memory 246 return ARM_MMU_L2_FLAG_B; 247 case B_MTR_WT: 248 // Outer and Inner Write-Through, no Write-Allocate 249 return ARM_MMU_L2_FLAG_C; 250 case B_MTR_WP: 251 case B_MTR_WB: 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