1 /* 2 * PROJECT: ReactOS Boot Loader 3 * LICENSE: BSD - See COPYING.ARM in the top level directory 4 * FILE: boot/freeldr/freeldr/arch/arm/winldr.c 5 * PURPOSE: ARM Kernel Loader 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 */ 8 9 /* INCLUDES ***************************************************************/ 10 11 #include <freeldr.h> 12 #include <debug.h> 13 #include <internal/arm/mm.h> 14 #include <internal/arm/intrin_i.h> 15 #include "../../winldr.h" 16 17 #define PFN_SHIFT 12 18 #define LARGE_PFN_SHIFT 20 19 20 #define PTE_BASE 0xC0000000 21 #define PDE_BASE 0xC0400000 22 #define PDR_BASE 0xFFD00000 23 #define VECTOR_BASE 0xFFFF0000 24 25 #ifdef _ZOOM2_ 26 #define IDMAP_BASE 0x81000000 27 #define MMIO_BASE 0x10000000 28 #else 29 #define IDMAP_BASE 0x00000000 30 #define MMIO_BASE 0x10000000 31 #endif 32 33 #define LowMemPageTableIndex (IDMAP_BASE >> PDE_SHIFT) 34 #define MmioPageTableIndex (MMIO_BASE >> PDE_SHIFT) 35 #define KernelPageTableIndex (KSEG0_BASE >> PDE_SHIFT) 36 #define StartupPtePageTableIndex (PTE_BASE >> PDE_SHIFT) 37 #define StartupPdePageTableIndex (PDE_BASE >> PDE_SHIFT) 38 #define PdrPageTableIndex (PDR_BASE >> PDE_SHIFT) 39 #define VectorPageTableIndex (VECTOR_BASE >> PDE_SHIFT) 40 41 #ifndef _ZOOM2_ 42 PVOID MempPdrBaseAddress = (PVOID)0x70000; 43 PVOID MempKernelBaseAddress = (PVOID)0; 44 #else 45 PVOID MempPdrBaseAddress = (PVOID)0x81100000; 46 PVOID MempKernelBaseAddress = (PVOID)0x80000000; 47 #endif 48 49 /* Converts a Physical Address into a Page Frame Number */ 50 #define PaToPfn(p) ((p) >> PFN_SHIFT) 51 #define PaToLargePfn(p) ((p) >> LARGE_PFN_SHIFT) 52 #define PaPtrToPfn(p) (((ULONG_PTR)(p)) >> PFN_SHIFT) 53 54 /* Converts a Physical Address into a Coarse Page Table PFN */ 55 #define PaPtrToPdePfn(p) (((ULONG_PTR)(p)) >> CPT_SHIFT) 56 57 typedef struct _KPDR_PAGE 58 { 59 PAGE_DIRECTORY_ARM PageDir; // 0xC0400000 [0xFFD00000] 60 CHAR HyperSpace[233 * PAGE_SIZE]; // 0xC0404000 [0xFFD04000] 61 PAGE_TABLE_ARM KernelPageTable[3]; // 0xC04ED000 [0xFFDED000] 62 CHAR SharedData[PAGE_SIZE]; // 0xC04F0000 [0xFFDF0000] 63 CHAR KernelStack[KERNEL_STACK_SIZE]; // 0xC04F1000 [0xFFDF1000] 64 CHAR PanicStack[KERNEL_STACK_SIZE]; // 0xC04F4000 [0xFFDF4000] 65 CHAR InterruptStack[KERNEL_STACK_SIZE]; // 0xC04F7000 [0xFFDF7000] 66 CHAR InitialProcess[PAGE_SIZE]; // 0xC04FA000 [0xFFDFA000] 67 CHAR InitialThread[PAGE_SIZE]; // 0xC04FB000 [0xFFDFB000] 68 CHAR Prcb[PAGE_SIZE]; // 0xC04FC000 [0xFFDFC000] 69 PAGE_TABLE_ARM PageDirPageTable; // 0xC04FD000 [0xFFDFD000] 70 PAGE_TABLE_ARM VectorPageTable; // 0xC04FE000 [0xFFDFE000] 71 CHAR Pcr[PAGE_SIZE]; // 0xC04FF000 [0xFFDFF000] 72 } KPDR_PAGE, *PKPDR_PAGE; 73 74 C_ASSERT(sizeof(KPDR_PAGE) == (1 * 1024 * 1024)); 75 76 HARDWARE_PTE_ARMV6 TempPte; 77 HARDWARE_LARGE_PTE_ARMV6 TempLargePte; 78 HARDWARE_PDE_ARMV6 TempPde; 79 PKPDR_PAGE PdrPage; 80 81 /* FUNCTIONS **************************************************************/ 82 83 BOOLEAN 84 MempSetupPaging(IN PFN_NUMBER StartPage, 85 IN PFN_NUMBER NumberOfPages, 86 IN BOOLEAN KernelMapping) 87 { 88 return TRUE; 89 } 90 91 VOID 92 MempUnmapPage(IN PFN_NUMBER Page) 93 { 94 return; 95 } 96 97 VOID 98 MempDump(VOID) 99 { 100 return; 101 } 102 103 static 104 BOOLEAN 105 WinLdrMapSpecialPages(ULONG PcrBasePage) 106 { 107 ULONG i; 108 PHARDWARE_PTE_ARMV6 PointerPte; 109 PHARDWARE_PDE_ARMV6 PointerPde; 110 PHARDWARE_LARGE_PTE_ARMV6 LargePte; 111 PFN_NUMBER Pfn; 112 113 /* Setup the Startup PDE */ 114 LargePte = &PdrPage->PageDir.Pte[StartupPdePageTableIndex]; 115 TempLargePte.PageFrameNumber = PaToLargePfn((ULONG_PTR)&PdrPage->PageDir); 116 *LargePte = TempLargePte; 117 118 /* Map-in the PDR */ 119 LargePte = &PdrPage->PageDir.Pte[PdrPageTableIndex]; 120 *LargePte = TempLargePte; 121 122 /* After this point, any MiAddressToPde is guaranteed not to fault */ 123 124 /* 125 * Link them in the Startup PDE. 126 * Note these are the entries in the PD at (MiAddressToPde(PTE_BASE)). 127 */ 128 PointerPde = &PdrPage->PageDir.Pde[StartupPtePageTableIndex]; 129 Pfn = PaPtrToPdePfn(&PdrPage->PageDirPageTable); 130 for (i = 0; i < 4; i++) 131 { 132 TempPde.PageFrameNumber = Pfn++; 133 *PointerPde++ = TempPde; 134 } 135 136 /* 137 * Now map these page tables in PTE space (MiAddressToPte(PTE_BASE)). 138 * Note that they all live on a single page, since each is 1KB. 139 */ 140 PointerPte = &PdrPage->PageDirPageTable.Pte[0x300]; 141 TempPte.PageFrameNumber = PaPtrToPfn(&PdrPage->PageDirPageTable); 142 *PointerPte = TempPte; 143 144 /* 145 * After this point, MiAddressToPte((PDE_BASE) to MiAddressToPte(PDE_TOP)) 146 * is guaranteed not to fault. 147 * Any subsequent page allocation will first need its page table created 148 * and mapped in the PTE_BASE first, then the page table itself will be 149 * editable through its flat PTE address. 150 */ 151 152 /* Setup the Vector PDE */ 153 PointerPde = &PdrPage->PageDir.Pde[VectorPageTableIndex]; 154 TempPde.PageFrameNumber = PaPtrToPdePfn(&PdrPage->VectorPageTable); 155 *PointerPde = TempPde; 156 157 /* Setup the Vector PTEs */ 158 PointerPte = &PdrPage->VectorPageTable.Pte[0xF0]; 159 TempPte.PageFrameNumber = 0; 160 *PointerPte = TempPte; 161 162 /* TODO: Map in the kernel CPTs */ 163 return TRUE; 164 } 165 166 VOID 167 WinLdrSetupForNt(IN PLOADER_PARAMETER_BLOCK LoaderBlock, 168 IN PVOID *GdtIdt, 169 IN PULONG PcrBasePage, 170 IN PULONG TssBasePage) 171 { 172 PKPDR_PAGE PdrPage = (PVOID)0xFFD00000; 173 174 /* Load cache information */ 175 LoaderBlock->u.Arm.FirstLevelDcacheSize = FirstLevelDcacheSize; 176 LoaderBlock->u.Arm.FirstLevelDcacheFillSize = FirstLevelDcacheFillSize; 177 LoaderBlock->u.Arm.FirstLevelIcacheSize = FirstLevelIcacheSize; 178 LoaderBlock->u.Arm.FirstLevelIcacheFillSize = FirstLevelIcacheFillSize; 179 LoaderBlock->u.Arm.SecondLevelDcacheSize = SecondLevelDcacheSize; 180 LoaderBlock->u.Arm.SecondLevelDcacheFillSize = SecondLevelDcacheFillSize; 181 LoaderBlock->u.Arm.SecondLevelIcacheSize = SecondLevelIcacheSize; 182 LoaderBlock->u.Arm.SecondLevelIcacheFillSize = SecondLevelIcacheSize; 183 184 /* Write initial context information */ 185 LoaderBlock->KernelStack = (ULONG_PTR)PdrPage->KernelStack; 186 LoaderBlock->KernelStack += KERNEL_STACK_SIZE; 187 LoaderBlock->u.Arm.PanicStack = (ULONG_PTR)PdrPage->PanicStack; 188 LoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE; 189 LoaderBlock->u.Arm.InterruptStack = (ULONG_PTR)PdrPage->InterruptStack; 190 LoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE; 191 LoaderBlock->Prcb = (ULONG_PTR)PdrPage->Prcb; 192 LoaderBlock->Process = (ULONG_PTR)PdrPage->InitialProcess; 193 LoaderBlock->Thread = (ULONG_PTR)PdrPage->InitialThread; 194 } 195 196 static 197 BOOLEAN 198 MempAllocatePageTables(VOID) 199 { 200 ULONG i; 201 PHARDWARE_PTE_ARMV6 PointerPte; 202 PHARDWARE_PDE_ARMV6 PointerPde; 203 PHARDWARE_LARGE_PTE_ARMV6 LargePte; 204 PFN_NUMBER Pfn; 205 206 /* Setup templates */ 207 TempPte.Sbo = TempPte.Valid = TempLargePte.LargePage = TempLargePte.Sbo = TempPde.Valid = 1; 208 209 /* Allocate the 1MB "PDR" (Processor Data Region). Must be 1MB aligned */ 210 PdrPage = MmAllocateMemoryAtAddress(sizeof(KPDR_PAGE), 211 MempPdrBaseAddress, 212 LoaderMemoryData); 213 214 /* Setup the Low Memory PDE as an identity-mapped Large Page (1MB) */ 215 LargePte = &PdrPage->PageDir.Pte[LowMemPageTableIndex]; 216 TempLargePte.PageFrameNumber = PaToLargePfn(IDMAP_BASE); 217 *LargePte = TempLargePte; 218 219 /* Setup the MMIO PDE as two identity mapped large pages -- the kernel will blow these away later */ 220 LargePte = &PdrPage->PageDir.Pte[MmioPageTableIndex]; 221 Pfn = PaToLargePfn(MMIO_BASE); 222 for (i = 0; i < 2; i++) 223 { 224 TempLargePte.PageFrameNumber = Pfn++; 225 *LargePte++ = TempLargePte; 226 } 227 228 /* Setup the Kernel PDEs */ 229 PointerPde = &PdrPage->PageDir.Pde[KernelPageTableIndex]; 230 Pfn = PaPtrToPdePfn(PdrPage->KernelPageTable); 231 for (i = 0; i < 12; i++) 232 { 233 TempPde.PageFrameNumber = Pfn; 234 *PointerPde++ = TempPde; 235 Pfn++; 236 } 237 238 /* Setup the Kernel PTEs */ 239 PointerPte = PdrPage->KernelPageTable[0].Pte; 240 Pfn = PaPtrToPfn(MempKernelBaseAddress); 241 for (i = 0; i < 3072; i++) 242 { 243 TempPte.PageFrameNumber = Pfn++; 244 *PointerPte++ = TempPte; 245 } 246 247 /* Done */ 248 return TRUE; 249 } 250 251 VOID 252 WinLdrSetProcessorContext(VOID) 253 { 254 ARM_CONTROL_REGISTER ControlRegister; 255 ARM_TTB_REGISTER TtbRegister; 256 ARM_DOMAIN_REGISTER DomainRegister; 257 258 /* Set the TTBR */ 259 TtbRegister.AsUlong = (ULONG_PTR)&PdrPage->PageDir; 260 ASSERT(TtbRegister.Reserved == 0); 261 KeArmTranslationTableRegisterSet(TtbRegister); 262 263 /* Disable domains and simply use access bits on PTEs */ 264 DomainRegister.AsUlong = 0; 265 DomainRegister.Domain0 = ClientDomain; 266 KeArmDomainRegisterSet(DomainRegister); 267 268 /* Enable ARMv6+ paging (MMU), caches and the access bit */ 269 ControlRegister = KeArmControlRegisterGet(); 270 ControlRegister.MmuEnabled = TRUE; 271 ControlRegister.ICacheEnabled = TRUE; 272 ControlRegister.DCacheEnabled = TRUE; 273 ControlRegister.ForceAp = TRUE; 274 ControlRegister.ExtendedPageTables = TRUE; 275 KeArmControlRegisterSet(ControlRegister); 276 } 277 278 VOID 279 WinLdrSetupMachineDependent( 280 PLOADER_PARAMETER_BLOCK LoaderBlock) 281 { 282 } 283