2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: boot/freeldr/arch/arm/loader.c
5 * PURPOSE: ARM Kernel Loader
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
12 #include <internal/arm/ke.h>
13 #include <internal/arm/mm.h>
14 #include <internal/arm/intrin_i.h>
16 #define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)x &~ KSEG0_BASE) >> PAGE_SHIFT)
18 /* GLOBALS ********************************************************************/
20 typedef struct _BIOS_MEMORY_DESCRIPTOR
24 } BIOS_MEMORY_DESCRIPTOR
, *PBIOS_MEMORY_DESCRIPTOR
;
26 ULONG PageDirectoryStart
, PageDirectoryEnd
;
27 PLOADER_PARAMETER_BLOCK ArmLoaderBlock
;
28 CHAR ArmCommandLine
[256];
29 CHAR ArmArcBootPath
[64];
30 CHAR ArmArcHalPath
[64];
31 CHAR ArmNtHalPath
[64];
32 CHAR ArmNtBootPath
[64];
33 PNLS_DATA_BLOCK ArmNlsDataBlock
;
34 PLOADER_PARAMETER_EXTENSION ArmExtension
;
35 BIOS_MEMORY_DESCRIPTOR ArmBoardMemoryDescriptors
[16] = {{0}};
36 PBIOS_MEMORY_DESCRIPTOR ArmBoardMemoryList
= ArmBoardMemoryDescriptors
;
37 ULONG NumberDescriptors
= 0;
38 MEMORY_DESCRIPTOR MDArray
[16] = {{0}};
39 ULONG ArmSharedHeapSize
;
42 extern ADDRESS_RANGE ArmBoardMemoryMap
[16];
43 extern ULONG ArmBoardMemoryMapRangeCount
;
44 extern ARM_TRANSLATION_TABLE ArmTranslationTable
;
45 extern ARM_COARSE_PAGE_TABLE BootTranslationTable
, KernelTranslationTable
, FlatMapTranslationTable
, MasterTranslationTable
, HyperSpaceTranslationTable
;
46 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint
;
47 extern ULONG_PTR KernelBase
;
48 extern ULONG_PTR AnsiData
, OemData
, UnicodeData
, RegistryData
, KernelData
, HalData
, DriverData
[16];
49 extern ULONG RegistrySize
, AnsiSize
, OemSize
, UnicodeSize
, KernelSize
, HalSize
, DriverSize
[16];
51 extern ULONG BootStack
, TranslationTableStart
, TranslationTableEnd
;
69 4 // 4-way associative
76 8 // 8 words per line (32 bytes)
80 // Where to map the serial port
82 #define UART_VIRTUAL 0xE0000000
84 #define PTE_BASE 0xC0000000
85 #define PDE_BASE 0xC1000000
86 #define HYPER_SPACE 0xC1100000
89 // Take 0x80812345 and extract:
90 // PTE_BASE[0x808][0x12]
92 #define MiAddressToPte(x) \
93 (PTE_BASE + (((x) >> 20) << 12) + ((((x) >> 12) & 0xFF) << 2))
95 #define MiAddressToPde(x) \
96 (PDE_BASE + (((x) >> 20) << 2))
98 /* FUNCTIONS ******************************************************************/
101 ArmAllocateFromSharedHeap(IN ULONG Size
)
106 // Allocate from the shared heap
108 Buffer
= &ArmSharedHeap
[ArmSharedHeapSize
];
109 ArmSharedHeapSize
+= Size
;
113 PMEMORY_ALLOCATION_DESCRIPTOR
115 ArmAllocateMemoryDescriptor(VOID
)
118 // Allocate a descriptor from the heap
120 return ArmAllocateFromSharedHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
));
125 ArmAddBoardMemoryDescriptor(IN ULONG Address
,
128 PBIOS_MEMORY_DESCRIPTOR BiosBlock
= ArmBoardMemoryList
;
131 // Loop board DRAM configuration
133 while (BiosBlock
->BlockSize
> 0)
135 /* Check if we've found a matching head block */
136 if (Address
+ Size
== BiosBlock
->BlockBase
)
138 /* Simply enlarge and rebase it */
139 BiosBlock
->BlockBase
= Address
;
140 BiosBlock
->BlockSize
+= Size
;
144 /* Check if we've found a matching tail block */
145 if (Address
== (BiosBlock
->BlockBase
+ BiosBlock
->BlockSize
))
147 /* Simply enlarge it */
148 BiosBlock
->BlockSize
+= Size
;
152 /* Nothing suitable found, try the next block */
156 /* No usable blocks found, found a free block instead */
157 if (!BiosBlock
->BlockSize
)
160 BiosBlock
->BlockBase
= Address
;
161 BiosBlock
->BlockSize
= Size
;
163 /* Create a new block and mark it as the end of the array */
165 BiosBlock
->BlockBase
= BiosBlock
->BlockSize
= 0L;
171 ArmBuildBoardMemoryMap(VOID
)
173 ULONG BlockBegin
, BlockEnd
;
176 /* Loop the BIOS Memory Map */
177 for (j
= 0; j
< ArmBoardMemoryMapRangeCount
; j
++)
179 /* Get the start and end addresses */
180 BlockBegin
= ArmBoardMemoryMap
[j
].BaseAddrLow
;
181 BlockEnd
= ArmBoardMemoryMap
[j
].BaseAddrLow
+ ArmBoardMemoryMap
[j
].LengthLow
- 1;
183 /* Make sure this isn't a > 4GB descriptor */
184 if (!ArmBoardMemoryMap
[j
].BaseAddrHigh
)
186 /* Make sure we don't overflow */
187 if (BlockEnd
< BlockBegin
) BlockEnd
= 0xFFFFFFFF;
189 /* Check if this is free memory */
190 if (ArmBoardMemoryMap
[j
].Type
== 1)
192 /* Add it to our BIOS descriptors */
193 ArmAddBoardMemoryDescriptor(BlockBegin
, BlockEnd
- BlockBegin
+ 1);
201 ArmConfigureArcDescriptor(IN ULONG PageBegin
,
203 IN TYPE_OF_MEMORY MemoryType
)
206 ULONG BlockBegin
, BlockEnd
;
207 MEMORY_TYPE BlockType
;
208 BOOLEAN Combined
= FALSE
;
210 /* If this descriptor seems bogus, just return */
211 if (PageEnd
<= PageBegin
) return STATUS_SUCCESS
;
213 /* Loop every ARC descriptor, trying to find one we can modify */
214 for (i
= 0; i
< NumberDescriptors
; i
++)
216 /* Get its settings */
217 BlockBegin
= MDArray
[i
].BasePage
;
218 BlockEnd
= MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
;
219 BlockType
= MDArray
[i
].MemoryType
;
221 /* Check if we can fit inside this block */
222 if (BlockBegin
< PageBegin
)
224 /* Check if we are larger then it */
225 if ((BlockEnd
> PageBegin
) && (BlockEnd
<= PageEnd
))
227 /* Make it end where we start */
228 BlockEnd
= PageBegin
;
231 /* Check if it ends after we do */
232 if (BlockEnd
> PageEnd
)
234 /* Make sure we can allocate a descriptor */
235 if (NumberDescriptors
== 60) return ENOMEM
;
237 /* Create a descriptor for whatever memory we're not part of */
238 MDArray
[NumberDescriptors
].MemoryType
= BlockType
;
239 MDArray
[NumberDescriptors
].BasePage
= PageEnd
;
240 MDArray
[NumberDescriptors
].PageCount
= BlockEnd
- PageEnd
;
243 /* The next block ending is now where we begin */
244 BlockEnd
= PageBegin
;
249 /* Check if the blog begins inside our range */
250 if (BlockBegin
< PageEnd
)
252 /* Check if it ends before we do */
253 if (BlockEnd
< PageEnd
)
255 /* Then make it disappear */
256 BlockEnd
= BlockBegin
;
260 /* Otherwise make it start where we end */
261 BlockBegin
= PageEnd
;
266 /* Check if the block matches us, and we haven't tried combining yet */
267 if ((BlockType
== MemoryType
) && !(Combined
))
269 /* Check if it starts where we end */
270 if (BlockBegin
== PageEnd
)
272 /* Make it start with us, and combine us */
273 BlockBegin
= PageBegin
;
276 else if (BlockEnd
== PageBegin
)
278 /* Otherwise, it ends where we begin, combine its ending */
284 /* Check the original block data matches with what we came up with */
285 if ((MDArray
[i
].BasePage
== BlockBegin
) &&
286 (MDArray
[i
].PageCount
== BlockEnd
- BlockBegin
))
292 /* Otherwise, set our new settings for this block */
293 MDArray
[i
].BasePage
= BlockBegin
;
294 MDArray
[i
].PageCount
= BlockEnd
- BlockBegin
;
296 /* Check if we are killing the block */
297 if (BlockBegin
== BlockEnd
)
299 /* Delete this block and restart the loop properly */
301 if (i
< NumberDescriptors
) MDArray
[i
] = MDArray
[NumberDescriptors
];
306 /* If we got here without combining, we need to allocate a new block */
307 if (!(Combined
) && (MemoryType
< LoaderMaximum
))
309 /* Make sure there's enough descriptors */
310 if (NumberDescriptors
== 60) return ENOMEM
;
312 /* Allocate a new block with our data */
313 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
314 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
315 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
319 /* Changes complete, return success */
320 return STATUS_SUCCESS
;
325 ArmBuildOsMemoryMap(VOID
)
327 PBIOS_MEMORY_DESCRIPTOR MdBlock
;
328 ULONG BlockStart
, BlockEnd
, BiasedStart
, BiasedEnd
, PageStart
, PageEnd
;
329 NTSTATUS Status
= STATUS_SUCCESS
;
331 /* Loop the BIOS Memory Descriptor List */
332 MdBlock
= ArmBoardMemoryList
;
333 while (MdBlock
->BlockSize
)
335 /* Get the statrt and end addresses */
336 BlockStart
= MdBlock
->BlockBase
;
337 BlockEnd
= BlockStart
+ MdBlock
->BlockSize
- 1;
339 /* Align them to page boundaries */
340 BiasedStart
= BlockStart
& (PAGE_SIZE
- 1);
341 if (BiasedStart
) BlockStart
= BlockStart
+ PAGE_SIZE
- BiasedStart
;
342 BiasedEnd
= (BlockEnd
+ 1) & (ULONG
)(PAGE_SIZE
- 1);
343 if (BiasedEnd
) BlockEnd
-= BiasedEnd
;
345 /* Get the actual page numbers */
346 PageStart
= BlockStart
>> PAGE_SHIFT
;
347 PageEnd
= (BlockEnd
+ 1) >> PAGE_SHIFT
;
349 /* Check if we did any alignment */
352 /* Mark that region as reserved */
353 Status
= ArmConfigureArcDescriptor(PageStart
- 1,
355 MemorySpecialMemory
);
356 if (Status
!= STATUS_SUCCESS
) break;
359 /* Check if we did any alignment */
362 /* Mark that region as reserved */
363 Status
= ArmConfigureArcDescriptor(PageEnd
- 1,
365 MemorySpecialMemory
);
366 if (Status
!= STATUS_SUCCESS
) break;
369 /* It is, mark the memory a free */
370 Status
= ArmConfigureArcDescriptor(PageStart
,
374 /* If we failed, break out, otherwise, go to the next BIOS block */
375 if (Status
!= STATUS_SUCCESS
) break;
379 /* Return error code */
385 ArmInsertMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
387 PLIST_ENTRY ListHead
, PreviousEntry
, NextEntry
;
388 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
= NULL
, NextDescriptor
= NULL
;
390 /* Loop the memory descriptor list */
391 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
392 PreviousEntry
= ListHead
;
393 NextEntry
= ListHead
->Flink
;
394 while (NextEntry
!= ListHead
)
396 /* Get the current descriptor and check if it's below ours */
397 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
398 MEMORY_ALLOCATION_DESCRIPTOR
,
400 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
) break;
402 /* It isn't, save the previous entry and descriptor, and try again */
403 PreviousEntry
= NextEntry
;
404 Descriptor
= NextDescriptor
;
405 NextEntry
= NextEntry
->Flink
;
408 /* So we found the right spot to insert. Is this free memory? */
409 if (NewDescriptor
->MemoryType
!= LoaderFree
)
411 /* It isn't, so insert us before the last descriptor */
412 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
416 /* We're free memory. Check if the entry we found is also free memory */
417 if ((PreviousEntry
!= ListHead
) &&
418 ((Descriptor
->MemoryType
== LoaderFree
) ||
419 (Descriptor
->MemoryType
== LoaderReserve
)) &&
420 ((Descriptor
->BasePage
+ Descriptor
->PageCount
) ==
421 NewDescriptor
->BasePage
))
423 /* It's free memory, and we're right after it. Enlarge that block */
424 Descriptor
->PageCount
+= NewDescriptor
->PageCount
;
425 NewDescriptor
= Descriptor
;
429 /* Our range scan't be combined, so just insert us separately */
430 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
433 /* Check if we merged with an existing free memory block */
434 if ((NextEntry
!= ListHead
) &&
435 ((NextDescriptor
->MemoryType
== LoaderFree
) ||
436 (NextDescriptor
->MemoryType
== LoaderReserve
)) &&
437 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) ==
438 NextDescriptor
->BasePage
))
440 /* Update our own block */
441 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
443 /* Remove the next block */
444 RemoveEntryList(&NextDescriptor
->ListEntry
);
451 ArmBuildMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor
,
452 IN MEMORY_TYPE MemoryType
,
456 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
, NextDescriptor
= NULL
;
458 TYPE_OF_MEMORY CurrentType
;
461 /* Check how many pages we'll be consuming */
462 Delta
= BasePage
- MemoryDescriptor
->BasePage
;
463 if (!(Delta
) && (PageCount
== MemoryDescriptor
->PageCount
))
465 /* We can simply convert the current descriptor into our new type */
466 MemoryDescriptor
->MemoryType
= MemoryType
;
470 /* Get the current memory type of the descriptor, and reserve it */
471 CurrentType
= MemoryDescriptor
->MemoryType
;
472 MemoryDescriptor
->MemoryType
= LoaderSpecialMemory
;
474 /* Check if we'll need another descriptor for what's left of memory */
475 UseNext
= ((BasePage
!= MemoryDescriptor
->BasePage
) &&
476 (Delta
+ PageCount
!= MemoryDescriptor
->PageCount
));
478 /* Get a descriptor */
479 Descriptor
= ArmAllocateMemoryDescriptor();
480 if (!Descriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
482 /* Check if we are using another descriptor */
485 /* Allocate that one too */
486 NextDescriptor
= ArmAllocateMemoryDescriptor();
487 if (!NextDescriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
490 /* Build the descriptor we got */
491 Descriptor
->MemoryType
= MemoryType
;
492 Descriptor
->BasePage
= BasePage
;
493 Descriptor
->PageCount
= PageCount
;
495 /* Check if we're starting at the same place as the old one */
496 if (BasePage
== MemoryDescriptor
->BasePage
)
498 /* Simply decrease the old descriptor and rebase it */
499 MemoryDescriptor
->BasePage
+= PageCount
;
500 MemoryDescriptor
->PageCount
-= PageCount
;
501 MemoryDescriptor
->MemoryType
= CurrentType
;
503 else if (Delta
+ PageCount
== MemoryDescriptor
->PageCount
)
505 /* We finish where the old one did, shorten it */
506 MemoryDescriptor
->PageCount
-= PageCount
;
507 MemoryDescriptor
->MemoryType
= CurrentType
;
511 /* We're inside the current block, mark our free region */
512 NextDescriptor
->MemoryType
= LoaderFree
;
513 NextDescriptor
->BasePage
= BasePage
+ PageCount
;
514 NextDescriptor
->PageCount
= MemoryDescriptor
->PageCount
-
517 /* And cut down the current descriptor */
518 MemoryDescriptor
->PageCount
= Delta
;
519 MemoryDescriptor
->MemoryType
= CurrentType
;
521 /* Finally, insert our new free descriptor into the list */
522 ArmInsertMemoryDescriptor(NextDescriptor
);
525 /* Insert the descriptor we allocated */
526 ArmInsertMemoryDescriptor(Descriptor
);
530 return STATUS_SUCCESS
;
533 PMEMORY_ALLOCATION_DESCRIPTOR
535 ArmFindMemoryDescriptor(IN ULONG BasePage
)
537 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
= NULL
;
538 PLIST_ENTRY NextEntry
, ListHead
;
540 /* Scan the memory descriptor list */
541 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
542 NextEntry
= ListHead
->Flink
;
543 while (NextEntry
!= ListHead
)
545 /* Get the current descriptor */
546 MdBlock
= CONTAINING_RECORD(NextEntry
,
547 MEMORY_ALLOCATION_DESCRIPTOR
,
550 /* Check if it can contain our memory range */
551 if ((MdBlock
->BasePage
<= BasePage
) &&
552 (MdBlock
->BasePage
+ MdBlock
->PageCount
> BasePage
))
554 /* It can, break out */
558 /* Go to the next descriptor */
559 NextEntry
= NextEntry
->Flink
;
562 /* Return the descriptor we found, if any */
568 ArmCreateMemoryDescriptor(IN TYPE_OF_MEMORY MemoryType
,
572 OUT PULONG ReturnedBase
)
574 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
575 ULONG AlignedBase
, AlignedLimit
;
576 PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock
;
577 ULONG ActiveAlignedBase
= 0;
578 PLIST_ENTRY NextEntry
, ListHead
;
580 /* If no information was given, make some assumptions */
581 if (!Alignment
) Alignment
= 1;
582 if (!PageCount
) PageCount
= 1;
584 /* Start looking for a matching descvriptor */
587 /* Calculate the limit of the range */
588 AlignedLimit
= PageCount
+ BasePage
;
590 /* Find a descriptor that already contains our base address */
591 MdBlock
= ArmFindMemoryDescriptor(BasePage
);
594 /* If it contains our limit as well, break out early */
595 if ((MdBlock
->PageCount
+ MdBlock
->BasePage
) >= AlignedLimit
) break;
598 /* Loop the memory list */
600 ActiveMdBlock
= NULL
;
601 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
602 NextEntry
= ListHead
->Flink
;
603 while (NextEntry
!= ListHead
)
605 /* Get the current descriptors */
606 MdBlock
= CONTAINING_RECORD(NextEntry
,
607 MEMORY_ALLOCATION_DESCRIPTOR
,
610 /* Align the base address and our limit */
611 AlignedBase
= (MdBlock
->BasePage
+ (Alignment
- 1)) &~ Alignment
;
612 AlignedLimit
= MdBlock
->PageCount
-
616 /* Check if this is a free block that can satisfy us */
617 if ((MdBlock
->MemoryType
== LoaderFree
) &&
618 (AlignedLimit
<= MdBlock
->PageCount
) &&
619 (PageCount
<= AlignedLimit
))
621 /* It is, stop searching */
622 ActiveMdBlock
= MdBlock
;
623 ActiveAlignedBase
= AlignedBase
;
627 /* Try the next block */
628 NextEntry
= NextEntry
->Flink
;
631 /* See if we came up with an adequate block */
634 /* Generate a descriptor in it */
635 *ReturnedBase
= AlignedBase
;
636 return ArmBuildMemoryDescriptor(ActiveMdBlock
,
643 /* We found a matching block, generate a descriptor with it */
644 *ReturnedBase
= BasePage
;
645 return ArmBuildMemoryDescriptor(MdBlock
, MemoryType
, BasePage
, PageCount
);
650 ArmBuildLoaderMemoryList(VOID
)
652 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
653 MEMORY_DESCRIPTOR
*Memory
;
656 /* Loop all BIOS Memory Descriptors */
657 for (i
= 0; i
< NumberDescriptors
; i
++)
659 /* Get the current descriptor */
660 Memory
= &MDArray
[i
];
662 /* Allocate an NT Memory Descriptor */
663 Descriptor
= ArmAllocateMemoryDescriptor();
664 if (!Descriptor
) return ENOMEM
;
666 /* Copy the memory type */
667 Descriptor
->MemoryType
= Memory
->MemoryType
;
668 if (Memory
->MemoryType
== MemoryFreeContiguous
)
670 /* Convert this to free */
671 Descriptor
->MemoryType
= LoaderFree
;
673 else if (Memory
->MemoryType
== MemorySpecialMemory
)
675 /* Convert this to special memory */
676 Descriptor
->MemoryType
= LoaderSpecialMemory
;
679 /* Copy the range data */
680 Descriptor
->BasePage
= Memory
->BasePage
;
681 Descriptor
->PageCount
= Memory
->PageCount
;
683 /* Insert the descriptor */
684 if (Descriptor
->PageCount
) ArmInsertMemoryDescriptor(Descriptor
);
688 return STATUS_SUCCESS
;
692 ArmSetupPageDirectory(VOID
)
694 ARM_TTB_REGISTER TtbRegister
;
695 ARM_DOMAIN_REGISTER DomainRegister
;
698 PARM_TRANSLATION_TABLE ArmTable
;
699 PARM_COARSE_PAGE_TABLE BootTable
, KernelTable
, FlatMapTable
, MasterTable
, HyperSpaceTable
;
702 // Get the PDEs that we will use
704 ArmTable
= &ArmTranslationTable
;
705 BootTable
= &BootTranslationTable
;
706 KernelTable
= &KernelTranslationTable
;
707 FlatMapTable
= &FlatMapTranslationTable
;
708 MasterTable
= &MasterTranslationTable
;
709 HyperSpaceTable
= &HyperSpaceTranslationTable
;
712 // Set the master L1 PDE as the TTB
714 TtbRegister
.AsUlong
= (ULONG
)ArmTable
;
715 ASSERT(TtbRegister
.Reserved
== 0);
716 KeArmTranslationTableRegisterSet(TtbRegister
);
719 // Use Domain 0, enforce AP bits (client)
721 DomainRegister
.AsUlong
= 0;
722 DomainRegister
.Domain0
= ClientDomain
;
723 KeArmDomainRegisterSet(DomainRegister
);
726 // Set Fault PTEs everywhere
728 RtlZeroMemory(ArmTable
, sizeof(ARM_TRANSLATION_TABLE
));
731 // Identity map the first MB of memory
733 Pte
.L1
.Section
.Type
= SectionPte
;
734 Pte
.L1
.Section
.Buffered
= FALSE
;
735 Pte
.L1
.Section
.Cached
= FALSE
;
736 Pte
.L1
.Section
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
737 Pte
.L1
.Section
.Domain
= Domain0
;
738 Pte
.L1
.Section
.Access
= SupervisorAccess
;
739 Pte
.L1
.Section
.BaseAddress
= 0;
740 Pte
.L1
.Section
.Ignored
= Pte
.L1
.Section
.Ignored1
= 0;
741 ArmTable
->Pte
[0] = Pte
;
744 // Map the page in MMIO space that contains the serial port into virtual memory
746 Pte
.L1
.Section
.BaseAddress
= ArmBoardBlock
->UartRegisterBase
>> PDE_SHIFT
;
747 ArmTable
->Pte
[UART_VIRTUAL
>> PDE_SHIFT
] = Pte
;
750 // Create template PTE for the coarse page table which maps the PTE_BASE
752 Pte
.L1
.Coarse
.Type
= CoarsePte
;
753 Pte
.L1
.Coarse
.Domain
= Domain0
;
754 Pte
.L1
.Coarse
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
755 Pte
.L1
.Coarse
.Ignored
= Pte
.L1
.Coarse
.Ignored1
= 0;
756 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)FlatMapTable
>> CPT_SHIFT
;
759 // On x86, there is 4MB of space, starting at 0xC0000000 to 0xC0400000
760 // which contains the mappings for each PTE on the system. 4MB is needed
761 // since for 4GB, there will be 1 million PTEs, each of 4KB.
763 // To describe a 4MB region, on x86, only requires a page table, which can
764 // be linked from the page table directory.
766 // On the other hand, on ARM, we can only describe 1MB regions, so we need
767 // four times less PTE entries to represent a single mapping (an L2 coarse
768 // page table). This is problematic, because this would only take up 1KB of
769 // space, and we can't have a page that small.
771 // This means we must:
773 // - Allocate page tables (in physical memory) with 4KB granularity, instead
774 // of 1KB (the other 3KB is unused and invalid).
776 // - "Skip" the other 3KB in the region, because we can't point to another
777 // coarse page table after just 1KB.
779 // So 0xC0000000 will be mapped to the page table that maps the range of
780 // 0x00000000 to 0x01000000, while 0xC0001000 till be mapped to the page
781 // table that maps the area from 0x01000000 to 0x02000000, and so on. In
782 // total, this will require 4 million entries, and additionally, because of
783 // the padding, since each 256 entries will be 4KB (instead of 1KB), this
784 // means we'll need 16MB (0xC0000000 to 0xC1000000).
786 // We call this region the flat-map area
788 for (i
= (PTE_BASE
>> PDE_SHIFT
); i
< ((PTE_BASE
+ 0x1000000) >> PDE_SHIFT
); i
++)
791 // Write PTE and update the base address (next MB) for the next one
793 ArmTable
->Pte
[i
] = Pte
;
794 Pte
.L1
.Coarse
.BaseAddress
+= 4;
798 // On x86, there is also the region of 0xC0300000 to 0xC03080000 which maps
799 // to the various PDEs on the system. Yes, this overlaps with the above, and
800 // works because of an insidious dark magic (self-mapping the PDE as a PTE).
801 // Unfortunately, this doesn't work on ARM, firstly because the size of a L1
802 // page table is different than from an L2 page table, and secondly, which
803 // is even worse, the format for an L1 page table is different than the one
804 // for an L2 page table -- basically meaning we cannot self-map.
806 // However, we somewhat emulate this behavior on ARM. This will be expensive
807 // since we manually need to keep track of every page directory added and
808 // add an entry in our flat-map region. We also need to keep track of every
809 // change in the TTB, so that we can update the mappings in our PDE region.
811 // Note that for us, this region starts at 0xC1000000, after the flat-map
814 // Finally, to deal with different sizes (1KB page tables, 4KB page size!),
815 // we pad the ARM L2 page tables to make them 4KB, so that each page will
816 // therefore point to an L2 page table.
818 // This region is a lot easier than the first -- an L1 page table is only
819 // 16KB, so to access any index inside it, we just need 4 pages, since each
820 // page is 4KB... Clearly, there's also no need to pad in this case.
822 // We'll call this region the master translation area.
824 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)MasterTable
>> CPT_SHIFT
;
825 ArmTable
->Pte
[PDE_BASE
>> PDE_SHIFT
] = Pte
;
828 // Now create the template for the hyperspace table which maps 1MB
830 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)HyperSpaceTable
>> CPT_SHIFT
;
831 ArmTable
->Pte
[HYPER_SPACE
>> PDE_SHIFT
] = Pte
;
834 // Now create the template for the coarse page tables which map the first 8MB
836 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)BootTable
>> CPT_SHIFT
;
839 // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
840 // This is where the freeldr boot structures are located, and we need them.
842 for (i
= (KSEG0_BASE
>> PDE_SHIFT
); i
< ((KSEG0_BASE
+ 0x800000) >> PDE_SHIFT
); i
++)
845 // Write PTE and update the base address (next MB) for the next one
847 ArmTable
->Pte
[i
] = Pte
;
848 Pte
.L1
.Coarse
.BaseAddress
+= 4;
852 // Now create the template PTE for the coarse page tables for the next 6MB
854 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)KernelTable
>> CPT_SHIFT
;
857 // Map 0x00800000 - 0x00DFFFFF to 0x80800000 - 0x80DFFFFF
858 // In this way, the KERNEL_PHYS_ADDR (0x800000) becomes 0x80800000
859 // which is the kernel virtual base address, just like on x86.
861 ASSERT(KernelBase
== 0x80800000);
862 for (i
= (KernelBase
>> PDE_SHIFT
); i
< ((KernelBase
+ 0x600000) >> PDE_SHIFT
); i
++)
865 // Write PTE and update the base address (next MB) for the next one
867 ArmTable
->Pte
[i
] = Pte
;
868 Pte
.L1
.Coarse
.BaseAddress
+= 4;
872 // Now build the template PTE for the pages mapping the first 8MB
874 Pte
.L2
.Small
.Type
= SmallPte
;
875 Pte
.L2
.Small
.Buffered
= Pte
.L2
.Small
.Cached
= 0;
876 Pte
.L2
.Small
.Access0
=
877 Pte
.L2
.Small
.Access1
=
878 Pte
.L2
.Small
.Access2
=
879 Pte
.L2
.Small
.Access3
= SupervisorAccess
;
880 Pte
.L2
.Small
.BaseAddress
= 0;
883 // Loop each boot coarse page table (i).
884 // Each PDE describes 1MB. We're mapping an area of 8MB, so 8 times.
886 for (i
= 0; i
< 8; i
++)
889 // Loop and set each the PTE (j).
890 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
892 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
895 // Write PTE and update the base address (next MB) for the next one
897 BootTable
->Pte
[j
] = Pte
;
898 Pte
.L2
.Small
.BaseAddress
++;
908 // Now create the template PTE for the pages mapping the next 6MB
910 Pte
.L2
.Small
.BaseAddress
= (ULONG
)KERNEL_BASE_PHYS
>> PTE_SHIFT
;
913 // Loop each kernel coarse page table (i).
914 // Each PDE describes 1MB. We're mapping an area of 6MB, so 6 times.
916 for (i
= 0; i
< 6; i
++)
919 // Loop and set each the PTE (j).
920 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
922 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
925 // Write PTE and update the base address (next MB) for the next one
927 KernelTable
->Pte
[j
] = Pte
;
928 Pte
.L2
.Small
.BaseAddress
++;
938 // Now we need to create the PTEs for the addresses which have been mapped
941 // We have allocated 4 page table directories:
943 // - One for the kernel, 6MB
944 // - One for low-memory FreeLDR, 8MB
945 // - One for identity-mapping below 1MB, 1MB
946 // - And finally, one for the flat-map itself, 16MB
948 // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
949 // we will require 31 pages.
953 // For the 0x80000000 region (8MB)
955 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&BootTranslationTable
>> PTE_SHIFT
;
956 FlatMapTable
= &(&FlatMapTranslationTable
)[0x80000000 >> 28];
957 for (i
= 0; i
< 8; i
++)
960 // Point to the page table mapping the next MB
962 FlatMapTable
->Pte
[i
] = Pte
;
963 Pte
.L2
.Small
.BaseAddress
++;
967 // For the 0x80800000 region (6MB)
969 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&KernelTranslationTable
>> PTE_SHIFT
;
970 for (i
= 8; i
< 14; i
++)
973 // Point to the page table mapping the next MB
975 FlatMapTable
->Pte
[i
] = Pte
;
976 Pte
.L2
.Small
.BaseAddress
++;
980 // For the 0xC0000000 region (16MB)
982 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&FlatMapTranslationTable
>> PTE_SHIFT
;
983 FlatMapTable
= &(&FlatMapTranslationTable
)[0xC0000000 >> 28];
984 for (i
= 0; i
< 16; i
++)
987 // Point to the page table mapping the next MB
989 FlatMapTable
->Pte
[i
] = Pte
;
990 Pte
.L2
.Small
.BaseAddress
++;
994 // For the 0xC1000000 region (1MB)
996 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&MasterTranslationTable
>> PTE_SHIFT
;
997 FlatMapTable
->Pte
[16] = Pte
;
1000 // And finally for the 0xC1100000 region (1MB)
1002 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&HyperSpaceTranslationTable
>> PTE_SHIFT
;
1003 FlatMapTable
->Pte
[17] = Pte
;
1006 // Now we handle the master translation area for our PDEs. We'll just make
1007 // the 4 page tables point to the ARM TTB.
1009 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&ArmTranslationTable
>> PTE_SHIFT
;
1010 for (i
= 0; i
< 4; i
++)
1013 // Point to the page table mapping the next MB
1015 MasterTable
->Pte
[i
] = Pte
;
1016 Pte
.L2
.Small
.BaseAddress
++;
1021 ArmSetupPagingAndJump(IN ULONG Magic
)
1023 ARM_CONTROL_REGISTER ControlRegister
;
1026 // Enable MMU, DCache and ICache
1028 ControlRegister
= KeArmControlRegisterGet();
1029 ControlRegister
.MmuEnabled
= TRUE
;
1030 ControlRegister
.ICacheEnabled
= TRUE
;
1031 ControlRegister
.DCacheEnabled
= TRUE
;
1032 KeArmControlRegisterSet(ControlRegister
);
1035 // Reconfigure UART0
1037 ArmBoardBlock
->UartRegisterBase
= UART_VIRTUAL
|
1038 (ArmBoardBlock
->UartRegisterBase
&
1039 ((1 << PDE_SHIFT
) - 1));
1040 TuiPrintf("Mapped serial port to 0x%x\n", ArmBoardBlock
->UartRegisterBase
);
1045 (*KernelEntryPoint
)(Magic
, (PVOID
)ArmLoaderBlock
);
1049 ArmPrepareForReactOS(IN BOOLEAN Setup
)
1051 ARM_CACHE_REGISTER CacheReg
;
1052 PVOID Base
, MemBase
;
1053 PCHAR BootPath
, HalPath
;
1056 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1059 // Allocate the ARM Shared Heap
1061 ArmSharedHeap
= MmAllocateMemory(PAGE_SIZE
);
1062 ArmSharedHeapSize
= 0;
1063 if (!ArmSharedHeap
) return;
1066 // Allocate the loader block and extension
1068 ArmLoaderBlock
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK
));
1069 if (!ArmLoaderBlock
) return;
1070 ArmExtension
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION
));
1071 if (!ArmExtension
) return;
1074 // Initialize the loader block
1076 InitializeListHead(&ArmLoaderBlock
->BootDriverListHead
);
1077 InitializeListHead(&ArmLoaderBlock
->LoadOrderListHead
);
1078 InitializeListHead(&ArmLoaderBlock
->MemoryDescriptorListHead
);
1081 // Setup the extension and setup block
1083 ArmLoaderBlock
->Extension
= ArmExtension
;
1084 ArmLoaderBlock
->SetupLdrBlock
= NULL
;
1087 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1088 // BIOS descriptor format -- this needs to be removed later.
1090 ArmBuildBoardMemoryMap();
1093 // Now basically convert these entries to the ARC format, so that we can
1094 // get a good map of free (usable) memory
1096 ArmBuildOsMemoryMap();
1099 // NT uses an extended ARC format, with slightly different memory types.
1100 // We also want to link the ARC descriptors together into a linked list,
1101 // instead of the array, and allocate the semi-permanent storage in which
1102 // these entries will be stored so that the kernel can read them.
1104 ArmBuildLoaderMemoryList();
1107 // Setup descriptor for the shared heap
1109 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderHeap
,
1110 (ULONG_PTR
)ArmSharedHeap
>> PAGE_SHIFT
,
1111 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap
,
1115 if (Status
!= STATUS_SUCCESS
) return;
1118 // Setup descriptor for the boot stack
1120 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderStack
,
1121 (ULONG_PTR
)&BootStack
>> PAGE_SHIFT
,
1125 if (Status
!= STATUS_SUCCESS
) return;
1128 // Setup descriptor for the boot page tables
1130 Status
= ArmCreateMemoryDescriptor(LoaderMemoryData
,
1131 (ULONG_PTR
)&TranslationTableStart
>> PAGE_SHIFT
,
1132 ((ULONG_PTR
)&TranslationTableEnd
-
1133 (ULONG_PTR
)&TranslationTableStart
) / PAGE_SIZE
,
1136 if (Status
!= STATUS_SUCCESS
) return;
1139 // Setup descriptor for the kernel
1141 Status
= ArmCreateMemoryDescriptor(LoaderSystemCode
,
1142 KernelData
>> PAGE_SHIFT
,
1143 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData
,
1147 if (Status
!= STATUS_SUCCESS
) return;
1150 // Setup descriptor for the HAL
1152 Status
= ArmCreateMemoryDescriptor(LoaderHalCode
,
1153 HalData
>> PAGE_SHIFT
,
1154 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData
,
1158 if (Status
!= STATUS_SUCCESS
) return;
1161 // Setup registry data
1163 ArmLoaderBlock
->RegistryBase
= (PVOID
)((ULONG_PTR
)RegistryData
| KSEG0_BASE
);
1166 // Create an MD for it
1168 Status
= ArmCreateMemoryDescriptor(LoaderRegistryData
,
1169 RegistryData
>> PAGE_SHIFT
,
1170 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData
,
1174 if (Status
!= STATUS_SUCCESS
) return;
1177 // TODO: Setup ARC Hardware tree data
1183 ArmNlsDataBlock
= ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK
));
1184 ArmLoaderBlock
->NlsData
= ArmNlsDataBlock
;
1185 ArmLoaderBlock
->NlsData
->AnsiCodePageData
= (PVOID
)(AnsiData
| KSEG0_BASE
);
1186 ArmLoaderBlock
->NlsData
->OemCodePageData
= (PVOID
)(OemData
| KSEG0_BASE
);
1187 ArmLoaderBlock
->NlsData
->UnicodeCodePageData
= (PVOID
)(UnicodeData
| KSEG0_BASE
);
1188 ArmLoaderBlock
->NlsData
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->NlsData
| KSEG0_BASE
);
1191 // Setup ANSI NLS Memory Descriptor
1193 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1194 AnsiData
>> PAGE_SHIFT
,
1195 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData
,
1199 if (Status
!= STATUS_SUCCESS
) return;
1202 // Setup OEM NLS Memory Descriptor
1204 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1205 OemData
>> PAGE_SHIFT
,
1206 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData
,
1210 if (Status
!= STATUS_SUCCESS
) return;
1213 // Setup Unicode NLS Memory Descriptor
1215 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1216 UnicodeData
>> PAGE_SHIFT
,
1217 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData
,
1221 if (Status
!= STATUS_SUCCESS
) return;
1224 // Setup loader entry for the kernel
1226 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1227 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1228 LdrEntry
->DllBase
= (PVOID
)KernelBase
;
1229 LdrEntry
->SizeOfImage
= KernelSize
;
1230 LdrEntry
->EntryPoint
= KernelEntryPoint
;
1231 LdrEntry
->LoadCount
= 1;
1232 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1233 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1236 // TODO: Setup boot-driver data
1240 // Build descriptors for the drivers loaded
1242 for (i
= 0; i
< Drivers
; i
++)
1245 // Build a descriptor for the driver
1247 Status
= ArmCreateMemoryDescriptor(LoaderBootDriver
,
1248 DriverData
[i
] >> PAGE_SHIFT
,
1249 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData
[i
],
1253 if (Status
!= STATUS_SUCCESS
) return;
1257 // Setup extension parameters
1259 ArmExtension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
1260 ArmExtension
->MajorVersion
= 5;
1261 ArmExtension
->MinorVersion
= 2;
1264 // Make a copy of the command line
1266 ArmLoaderBlock
->LoadOptions
= ArmCommandLine
;
1267 strcpy(ArmCommandLine
, reactos_kernel_cmdline
);
1270 // Find the first \, separating the ARC path from NT path
1272 BootPath
= strchr(ArmCommandLine
, '\\');
1273 *BootPath
= ANSI_NULL
;
1276 // Set the ARC Boot Path
1278 strncpy(ArmArcBootPath
, ArmCommandLine
, 63);
1279 ArmLoaderBlock
->ArcBootDeviceName
= ArmArcBootPath
;
1282 // The rest of the string is the NT path
1284 HalPath
= strchr(BootPath
+ 1, ' ');
1285 *HalPath
= ANSI_NULL
;
1286 ArmNtBootPath
[0] = '\\';
1287 strncat(ArmNtBootPath
, BootPath
+ 1, 63);
1288 strcat(ArmNtBootPath
,"\\");
1289 ArmLoaderBlock
->NtBootPathName
= ArmNtBootPath
;
1292 // Set the HAL paths
1294 strncpy(ArmArcHalPath
, ArmArcBootPath
, 63);
1295 ArmLoaderBlock
->ArcHalDeviceName
= ArmArcHalPath
;
1296 strcpy(ArmNtHalPath
, "\\");
1297 ArmLoaderBlock
->NtHalPathName
= ArmNtHalPath
;
1299 /* Use this new command line */
1300 strncpy(ArmLoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
1302 /* Parse it and change every slash to a space */
1303 BootPath
= ArmLoaderBlock
->LoadOptions
;
1304 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
1307 // Setup cache information
1309 CacheReg
= KeArmCacheRegisterGet();
1310 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheSize
= SizeBits
[CacheReg
.DSize
];
1311 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
= LenBits
[CacheReg
.DLength
];
1312 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
<<= 2;
1313 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheSize
= SizeBits
[CacheReg
.ISize
];
1314 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
= LenBits
[CacheReg
.ILength
];
1315 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
<<= 2;
1316 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheSize
=
1317 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheFillSize
=
1318 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheSize
=
1319 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheFillSize
= 0;
1322 // Allocate the Interrupt stack
1324 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupDpcStack
);
1325 ArmLoaderBlock
->u
.Arm
.InterruptStack
= KSEG0_BASE
| (ULONG
)Base
;
1326 ArmLoaderBlock
->u
.Arm
.InterruptStack
+= KERNEL_STACK_SIZE
;
1329 // Build an entry for it
1331 Status
= ArmCreateMemoryDescriptor(LoaderStartupDpcStack
,
1332 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1333 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1336 if (Status
!= STATUS_SUCCESS
) return;
1339 // Allocate the Kernel Boot stack
1341 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupKernelStack
);
1342 ArmLoaderBlock
->KernelStack
= KSEG0_BASE
| (ULONG
)Base
;
1343 ArmLoaderBlock
->KernelStack
+= KERNEL_STACK_SIZE
;
1346 // Build an entry for it
1348 Status
= ArmCreateMemoryDescriptor(LoaderStartupKernelStack
,
1349 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1350 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1353 if (Status
!= STATUS_SUCCESS
) return;
1356 // Allocate the Abort stack
1358 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupPanicStack
);
1359 ArmLoaderBlock
->u
.Arm
.PanicStack
= KSEG0_BASE
| (ULONG
)Base
;
1360 ArmLoaderBlock
->u
.Arm
.PanicStack
+= KERNEL_STACK_SIZE
;
1363 // Build an entry for it
1365 Status
= ArmCreateMemoryDescriptor(LoaderStartupPanicStack
,
1366 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1367 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1370 if (Status
!= STATUS_SUCCESS
) return;
1373 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1375 Base
= MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage
);
1377 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1378 ArmLoaderBlock
->u
.Arm
.PcrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1381 // Build an entry for the KPCR and KUSER_SHARED_DATA
1383 Status
= ArmCreateMemoryDescriptor(LoaderStartupPcrPage
,
1384 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1385 (2 * 1024 * 1024) / PAGE_SIZE
,
1388 if (Status
!= STATUS_SUCCESS
) return;
1391 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1393 Base
= MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage
);
1395 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1396 ArmLoaderBlock
->u
.Arm
.PdrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1399 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1401 Status
= ArmCreateMemoryDescriptor(LoaderStartupPdrPage
,
1402 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1403 (4 * 1024 * 1024) / PAGE_SIZE
,
1406 if (Status
!= STATUS_SUCCESS
) return;
1409 // Set initial PRCB, Thread and Process on the last PDR page
1411 Base
= (PVOID
)((ULONG
)Base
+ 2 * 1024 * 1024);
1412 ArmLoaderBlock
->Prcb
= KSEG0_BASE
| (ULONG
)Base
;
1413 ArmLoaderBlock
->Process
= ArmLoaderBlock
->Prcb
+ sizeof(KPRCB
);
1414 ArmLoaderBlock
->Thread
= ArmLoaderBlock
->Process
+ sizeof(EPROCESS
);
1418 FrLdrStartup(IN ULONG Magic
)
1421 // Disable interrupts (aleady done)
1425 // Set proper CPSR (already done)
1429 // Initialize the page directory
1431 ArmSetupPageDirectory();
1434 // Initialize paging and load NTOSKRNL
1436 ArmSetupPagingAndJump(Magic
);