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 WCHAR ArmModuleName
[64];
34 PNLS_DATA_BLOCK ArmNlsDataBlock
;
35 PLOADER_PARAMETER_EXTENSION ArmExtension
;
36 BIOS_MEMORY_DESCRIPTOR ArmBoardMemoryDescriptors
[16] = {{0}};
37 PBIOS_MEMORY_DESCRIPTOR ArmBoardMemoryList
= ArmBoardMemoryDescriptors
;
38 ULONG NumberDescriptors
= 0;
39 MEMORY_DESCRIPTOR MDArray
[16] = {{0}};
40 ULONG ArmSharedHeapSize
;
43 extern ADDRESS_RANGE ArmBoardMemoryMap
[16];
44 extern ULONG ArmBoardMemoryMapRangeCount
;
45 extern ARM_TRANSLATION_TABLE ArmTranslationTable
;
46 extern ARM_COARSE_PAGE_TABLE BootTranslationTable
, KernelTranslationTable
, FlatMapTranslationTable
, MasterTranslationTable
, HyperSpaceTranslationTable
;
47 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint
;
48 extern ULONG_PTR KernelBase
;
49 extern ULONG_PTR AnsiData
, OemData
, UnicodeData
, RegistryData
, KernelData
, HalData
, DriverData
[16];
50 extern ULONG RegistrySize
, AnsiSize
, OemSize
, UnicodeSize
, KernelSize
, HalSize
, DriverSize
[16];
52 extern ULONG BootStack
, TranslationTableStart
, TranslationTableEnd
;
70 4 // 4-way associative
77 8 // 8 words per line (32 bytes)
81 // Where to map the serial port
83 #define UART_VIRTUAL 0xE0000000
85 #define PTE_BASE 0xC0000000
86 #define PDE_BASE 0xC1000000
87 #define HYPER_SPACE 0xC1100000
90 // Take 0x80812345 and extract:
91 // PTE_BASE[0x808][0x12]
93 #define MiAddressToPte(x) \
94 (PTE_BASE + (((x) >> 20) << 12) + ((((x) >> 12) & 0xFF) << 2))
96 #define MiAddressToPde(x) \
97 (PDE_BASE + (((x) >> 20) << 2))
99 /* FUNCTIONS ******************************************************************/
102 ArmAllocateFromSharedHeap(IN ULONG Size
)
107 // Allocate from the shared heap
109 Buffer
= &ArmSharedHeap
[ArmSharedHeapSize
];
110 ArmSharedHeapSize
+= Size
;
114 PMEMORY_ALLOCATION_DESCRIPTOR
116 ArmAllocateMemoryDescriptor(VOID
)
119 // Allocate a descriptor from the heap
121 return ArmAllocateFromSharedHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
));
126 ArmAddBoardMemoryDescriptor(IN ULONG Address
,
129 PBIOS_MEMORY_DESCRIPTOR BiosBlock
= ArmBoardMemoryList
;
132 // Loop board DRAM configuration
134 while (BiosBlock
->BlockSize
> 0)
136 /* Check if we've found a matching head block */
137 if (Address
+ Size
== BiosBlock
->BlockBase
)
139 /* Simply enlarge and rebase it */
140 BiosBlock
->BlockBase
= Address
;
141 BiosBlock
->BlockSize
+= Size
;
145 /* Check if we've found a matching tail block */
146 if (Address
== (BiosBlock
->BlockBase
+ BiosBlock
->BlockSize
))
148 /* Simply enlarge it */
149 BiosBlock
->BlockSize
+= Size
;
153 /* Nothing suitable found, try the next block */
157 /* No usable blocks found, found a free block instead */
158 if (!BiosBlock
->BlockSize
)
161 BiosBlock
->BlockBase
= Address
;
162 BiosBlock
->BlockSize
= Size
;
164 /* Create a new block and mark it as the end of the array */
166 BiosBlock
->BlockBase
= BiosBlock
->BlockSize
= 0L;
172 ArmBuildBoardMemoryMap(VOID
)
174 ULONG BlockBegin
, BlockEnd
;
177 /* Loop the BIOS Memory Map */
178 for (j
= 0; j
< ArmBoardMemoryMapRangeCount
; j
++)
180 /* Get the start and end addresses */
181 BlockBegin
= ArmBoardMemoryMap
[j
].BaseAddrLow
;
182 BlockEnd
= ArmBoardMemoryMap
[j
].BaseAddrLow
+ ArmBoardMemoryMap
[j
].LengthLow
- 1;
184 /* Make sure this isn't a > 4GB descriptor */
185 if (!ArmBoardMemoryMap
[j
].BaseAddrHigh
)
187 /* Make sure we don't overflow */
188 if (BlockEnd
< BlockBegin
) BlockEnd
= 0xFFFFFFFF;
190 /* Check if this is free memory */
191 if (ArmBoardMemoryMap
[j
].Type
== 1)
193 /* Add it to our BIOS descriptors */
194 ArmAddBoardMemoryDescriptor(BlockBegin
, BlockEnd
- BlockBegin
+ 1);
202 ArmConfigureArcDescriptor(IN ULONG PageBegin
,
204 IN TYPE_OF_MEMORY MemoryType
)
207 ULONG BlockBegin
, BlockEnd
;
208 MEMORY_TYPE BlockType
;
209 BOOLEAN Combined
= FALSE
;
211 /* If this descriptor seems bogus, just return */
212 if (PageEnd
<= PageBegin
) return STATUS_SUCCESS
;
214 /* Loop every ARC descriptor, trying to find one we can modify */
215 for (i
= 0; i
< NumberDescriptors
; i
++)
217 /* Get its settings */
218 BlockBegin
= MDArray
[i
].BasePage
;
219 BlockEnd
= MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
;
220 BlockType
= MDArray
[i
].MemoryType
;
222 /* Check if we can fit inside this block */
223 if (BlockBegin
< PageBegin
)
225 /* Check if we are larger then it */
226 if ((BlockEnd
> PageBegin
) && (BlockEnd
<= PageEnd
))
228 /* Make it end where we start */
229 BlockEnd
= PageBegin
;
232 /* Check if it ends after we do */
233 if (BlockEnd
> PageEnd
)
235 /* Make sure we can allocate a descriptor */
236 if (NumberDescriptors
== 60) return ENOMEM
;
238 /* Create a descriptor for whatever memory we're not part of */
239 MDArray
[NumberDescriptors
].MemoryType
= BlockType
;
240 MDArray
[NumberDescriptors
].BasePage
= PageEnd
;
241 MDArray
[NumberDescriptors
].PageCount
= BlockEnd
- PageEnd
;
244 /* The next block ending is now where we begin */
245 BlockEnd
= PageBegin
;
250 /* Check if the blog begins inside our range */
251 if (BlockBegin
< PageEnd
)
253 /* Check if it ends before we do */
254 if (BlockEnd
< PageEnd
)
256 /* Then make it disappear */
257 BlockEnd
= BlockBegin
;
261 /* Otherwise make it start where we end */
262 BlockBegin
= PageEnd
;
267 /* Check if the block matches us, and we haven't tried combining yet */
268 if ((BlockType
== MemoryType
) && !(Combined
))
270 /* Check if it starts where we end */
271 if (BlockBegin
== PageEnd
)
273 /* Make it start with us, and combine us */
274 BlockBegin
= PageBegin
;
277 else if (BlockEnd
== PageBegin
)
279 /* Otherwise, it ends where we begin, combine its ending */
285 /* Check the original block data matches with what we came up with */
286 if ((MDArray
[i
].BasePage
== BlockBegin
) &&
287 (MDArray
[i
].PageCount
== BlockEnd
- BlockBegin
))
293 /* Otherwise, set our new settings for this block */
294 MDArray
[i
].BasePage
= BlockBegin
;
295 MDArray
[i
].PageCount
= BlockEnd
- BlockBegin
;
297 /* Check if we are killing the block */
298 if (BlockBegin
== BlockEnd
)
300 /* Delete this block and restart the loop properly */
302 if (i
< NumberDescriptors
) MDArray
[i
] = MDArray
[NumberDescriptors
];
307 /* If we got here without combining, we need to allocate a new block */
308 if (!(Combined
) && (MemoryType
< LoaderMaximum
))
310 /* Make sure there's enough descriptors */
311 if (NumberDescriptors
== 60) return ENOMEM
;
313 /* Allocate a new block with our data */
314 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
315 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
316 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
320 /* Changes complete, return success */
321 return STATUS_SUCCESS
;
326 ArmBuildOsMemoryMap(VOID
)
328 PBIOS_MEMORY_DESCRIPTOR MdBlock
;
329 ULONG BlockStart
, BlockEnd
, BiasedStart
, BiasedEnd
, PageStart
, PageEnd
;
330 NTSTATUS Status
= STATUS_SUCCESS
;
332 /* Loop the BIOS Memory Descriptor List */
333 MdBlock
= ArmBoardMemoryList
;
334 while (MdBlock
->BlockSize
)
336 /* Get the statrt and end addresses */
337 BlockStart
= MdBlock
->BlockBase
;
338 BlockEnd
= BlockStart
+ MdBlock
->BlockSize
- 1;
340 /* Align them to page boundaries */
341 BiasedStart
= BlockStart
& (PAGE_SIZE
- 1);
342 if (BiasedStart
) BlockStart
= BlockStart
+ PAGE_SIZE
- BiasedStart
;
343 BiasedEnd
= (BlockEnd
+ 1) & (ULONG
)(PAGE_SIZE
- 1);
344 if (BiasedEnd
) BlockEnd
-= BiasedEnd
;
346 /* Get the actual page numbers */
347 PageStart
= BlockStart
>> PAGE_SHIFT
;
348 PageEnd
= (BlockEnd
+ 1) >> PAGE_SHIFT
;
350 /* Check if we did any alignment */
353 /* Mark that region as reserved */
354 Status
= ArmConfigureArcDescriptor(PageStart
- 1,
356 MemorySpecialMemory
);
357 if (Status
!= STATUS_SUCCESS
) break;
360 /* Check if we did any alignment */
363 /* Mark that region as reserved */
364 Status
= ArmConfigureArcDescriptor(PageEnd
- 1,
366 MemorySpecialMemory
);
367 if (Status
!= STATUS_SUCCESS
) break;
370 /* It is, mark the memory a free */
371 Status
= ArmConfigureArcDescriptor(PageStart
,
375 /* If we failed, break out, otherwise, go to the next BIOS block */
376 if (Status
!= STATUS_SUCCESS
) break;
380 /* Return error code */
386 ArmInsertMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
388 PLIST_ENTRY ListHead
, PreviousEntry
, NextEntry
;
389 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
= NULL
, NextDescriptor
= NULL
;
391 /* Loop the memory descriptor list */
392 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
393 PreviousEntry
= ListHead
;
394 NextEntry
= ListHead
->Flink
;
395 while (NextEntry
!= ListHead
)
397 /* Get the current descriptor and check if it's below ours */
398 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
399 MEMORY_ALLOCATION_DESCRIPTOR
,
401 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
) break;
403 /* It isn't, save the previous entry and descriptor, and try again */
404 PreviousEntry
= NextEntry
;
405 Descriptor
= NextDescriptor
;
406 NextEntry
= NextEntry
->Flink
;
409 /* So we found the right spot to insert. Is this free memory? */
410 if (NewDescriptor
->MemoryType
!= LoaderFree
)
412 /* It isn't, so insert us before the last descriptor */
413 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
417 /* We're free memory. Check if the entry we found is also free memory */
418 if ((PreviousEntry
!= ListHead
) &&
419 ((Descriptor
->MemoryType
== LoaderFree
) ||
420 (Descriptor
->MemoryType
== LoaderReserve
)) &&
421 ((Descriptor
->BasePage
+ Descriptor
->PageCount
) ==
422 NewDescriptor
->BasePage
))
424 /* It's free memory, and we're right after it. Enlarge that block */
425 Descriptor
->PageCount
+= NewDescriptor
->PageCount
;
426 NewDescriptor
= Descriptor
;
430 /* Our range scan't be combined, so just insert us separately */
431 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
434 /* Check if we merged with an existing free memory block */
435 if ((NextEntry
!= ListHead
) &&
436 ((NextDescriptor
->MemoryType
== LoaderFree
) ||
437 (NextDescriptor
->MemoryType
== LoaderReserve
)) &&
438 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) ==
439 NextDescriptor
->BasePage
))
441 /* Update our own block */
442 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
444 /* Remove the next block */
445 RemoveEntryList(&NextDescriptor
->ListEntry
);
452 ArmBuildMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor
,
453 IN MEMORY_TYPE MemoryType
,
457 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
, NextDescriptor
= NULL
;
459 TYPE_OF_MEMORY CurrentType
;
462 /* Check how many pages we'll be consuming */
463 Delta
= BasePage
- MemoryDescriptor
->BasePage
;
464 if (!(Delta
) && (PageCount
== MemoryDescriptor
->PageCount
))
466 /* We can simply convert the current descriptor into our new type */
467 MemoryDescriptor
->MemoryType
= MemoryType
;
471 /* Get the current memory type of the descriptor, and reserve it */
472 CurrentType
= MemoryDescriptor
->MemoryType
;
473 MemoryDescriptor
->MemoryType
= LoaderSpecialMemory
;
475 /* Check if we'll need another descriptor for what's left of memory */
476 UseNext
= ((BasePage
!= MemoryDescriptor
->BasePage
) &&
477 (Delta
+ PageCount
!= MemoryDescriptor
->PageCount
));
479 /* Get a descriptor */
480 Descriptor
= ArmAllocateMemoryDescriptor();
481 if (!Descriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
483 /* Check if we are using another descriptor */
486 /* Allocate that one too */
487 NextDescriptor
= ArmAllocateMemoryDescriptor();
488 if (!NextDescriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
491 /* Build the descriptor we got */
492 Descriptor
->MemoryType
= MemoryType
;
493 Descriptor
->BasePage
= BasePage
;
494 Descriptor
->PageCount
= PageCount
;
496 /* Check if we're starting at the same place as the old one */
497 if (BasePage
== MemoryDescriptor
->BasePage
)
499 /* Simply decrease the old descriptor and rebase it */
500 MemoryDescriptor
->BasePage
+= PageCount
;
501 MemoryDescriptor
->PageCount
-= PageCount
;
502 MemoryDescriptor
->MemoryType
= CurrentType
;
504 else if (Delta
+ PageCount
== MemoryDescriptor
->PageCount
)
506 /* We finish where the old one did, shorten it */
507 MemoryDescriptor
->PageCount
-= PageCount
;
508 MemoryDescriptor
->MemoryType
= CurrentType
;
512 /* We're inside the current block, mark our free region */
513 NextDescriptor
->MemoryType
= LoaderFree
;
514 NextDescriptor
->BasePage
= BasePage
+ PageCount
;
515 NextDescriptor
->PageCount
= MemoryDescriptor
->PageCount
-
518 /* And cut down the current descriptor */
519 MemoryDescriptor
->PageCount
= Delta
;
520 MemoryDescriptor
->MemoryType
= CurrentType
;
522 /* Finally, insert our new free descriptor into the list */
523 ArmInsertMemoryDescriptor(NextDescriptor
);
526 /* Insert the descriptor we allocated */
527 ArmInsertMemoryDescriptor(Descriptor
);
531 return STATUS_SUCCESS
;
534 PMEMORY_ALLOCATION_DESCRIPTOR
536 ArmFindMemoryDescriptor(IN ULONG BasePage
)
538 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
= NULL
;
539 PLIST_ENTRY NextEntry
, ListHead
;
541 /* Scan the memory descriptor list */
542 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
543 NextEntry
= ListHead
->Flink
;
544 while (NextEntry
!= ListHead
)
546 /* Get the current descriptor */
547 MdBlock
= CONTAINING_RECORD(NextEntry
,
548 MEMORY_ALLOCATION_DESCRIPTOR
,
551 /* Check if it can contain our memory range */
552 if ((MdBlock
->BasePage
<= BasePage
) &&
553 (MdBlock
->BasePage
+ MdBlock
->PageCount
> BasePage
))
555 /* It can, break out */
559 /* Go to the next descriptor */
560 NextEntry
= NextEntry
->Flink
;
563 /* Return the descriptor we found, if any */
569 ArmCreateMemoryDescriptor(IN TYPE_OF_MEMORY MemoryType
,
573 OUT PULONG ReturnedBase
)
575 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
576 ULONG AlignedBase
, AlignedLimit
;
577 PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock
;
578 ULONG ActiveAlignedBase
= 0;
579 PLIST_ENTRY NextEntry
, ListHead
;
581 /* If no information was given, make some assumptions */
582 if (!Alignment
) Alignment
= 1;
583 if (!PageCount
) PageCount
= 1;
585 /* Start looking for a matching descvriptor */
588 /* Calculate the limit of the range */
589 AlignedLimit
= PageCount
+ BasePage
;
591 /* Find a descriptor that already contains our base address */
592 MdBlock
= ArmFindMemoryDescriptor(BasePage
);
595 /* If it contains our limit as well, break out early */
596 if ((MdBlock
->PageCount
+ MdBlock
->BasePage
) >= AlignedLimit
) break;
599 /* Loop the memory list */
601 ActiveMdBlock
= NULL
;
602 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
603 NextEntry
= ListHead
->Flink
;
604 while (NextEntry
!= ListHead
)
606 /* Get the current descriptors */
607 MdBlock
= CONTAINING_RECORD(NextEntry
,
608 MEMORY_ALLOCATION_DESCRIPTOR
,
611 /* Align the base address and our limit */
612 AlignedBase
= (MdBlock
->BasePage
+ (Alignment
- 1)) &~ Alignment
;
613 AlignedLimit
= MdBlock
->PageCount
-
617 /* Check if this is a free block that can satisfy us */
618 if ((MdBlock
->MemoryType
== LoaderFree
) &&
619 (AlignedLimit
<= MdBlock
->PageCount
) &&
620 (PageCount
<= AlignedLimit
))
622 /* It is, stop searching */
623 ActiveMdBlock
= MdBlock
;
624 ActiveAlignedBase
= AlignedBase
;
628 /* Try the next block */
629 NextEntry
= NextEntry
->Flink
;
632 /* See if we came up with an adequate block */
635 /* Generate a descriptor in it */
636 *ReturnedBase
= AlignedBase
;
637 return ArmBuildMemoryDescriptor(ActiveMdBlock
,
644 /* We found a matching block, generate a descriptor with it */
645 *ReturnedBase
= BasePage
;
646 return ArmBuildMemoryDescriptor(MdBlock
, MemoryType
, BasePage
, PageCount
);
651 ArmBuildLoaderMemoryList(VOID
)
653 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
654 MEMORY_DESCRIPTOR
*Memory
;
657 /* Loop all BIOS Memory Descriptors */
658 for (i
= 0; i
< NumberDescriptors
; i
++)
660 /* Get the current descriptor */
661 Memory
= &MDArray
[i
];
663 /* Allocate an NT Memory Descriptor */
664 Descriptor
= ArmAllocateMemoryDescriptor();
665 if (!Descriptor
) return ENOMEM
;
667 /* Copy the memory type */
668 Descriptor
->MemoryType
= Memory
->MemoryType
;
669 if (Memory
->MemoryType
== MemoryFreeContiguous
)
671 /* Convert this to free */
672 Descriptor
->MemoryType
= LoaderFree
;
674 else if (Memory
->MemoryType
== MemorySpecialMemory
)
676 /* Convert this to special memory */
677 Descriptor
->MemoryType
= LoaderSpecialMemory
;
680 /* Copy the range data */
681 Descriptor
->BasePage
= Memory
->BasePage
;
682 Descriptor
->PageCount
= Memory
->PageCount
;
684 /* Insert the descriptor */
685 if (Descriptor
->PageCount
) ArmInsertMemoryDescriptor(Descriptor
);
689 return STATUS_SUCCESS
;
693 ArmSetupPageDirectory(VOID
)
695 ARM_TTB_REGISTER TtbRegister
;
696 ARM_DOMAIN_REGISTER DomainRegister
;
699 PARM_TRANSLATION_TABLE ArmTable
;
700 PARM_COARSE_PAGE_TABLE BootTable
, KernelTable
, FlatMapTable
, MasterTable
, HyperSpaceTable
;
703 // Get the PDEs that we will use
705 ArmTable
= &ArmTranslationTable
;
706 BootTable
= &BootTranslationTable
;
707 KernelTable
= &KernelTranslationTable
;
708 FlatMapTable
= &FlatMapTranslationTable
;
709 MasterTable
= &MasterTranslationTable
;
710 HyperSpaceTable
= &HyperSpaceTranslationTable
;
713 // Set the master L1 PDE as the TTB
715 TtbRegister
.AsUlong
= (ULONG
)ArmTable
;
716 ASSERT(TtbRegister
.Reserved
== 0);
717 KeArmTranslationTableRegisterSet(TtbRegister
);
720 // Use Domain 0, enforce AP bits (client)
722 DomainRegister
.AsUlong
= 0;
723 DomainRegister
.Domain0
= ClientDomain
;
724 KeArmDomainRegisterSet(DomainRegister
);
727 // Set Fault PTEs everywhere
729 RtlZeroMemory(ArmTable
, sizeof(ARM_TRANSLATION_TABLE
));
732 // Identity map the first MB of memory
734 Pte
.L1
.Section
.Type
= SectionPte
;
735 Pte
.L1
.Section
.Buffered
= FALSE
;
736 Pte
.L1
.Section
.Cached
= FALSE
;
737 Pte
.L1
.Section
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
738 Pte
.L1
.Section
.Domain
= Domain0
;
739 Pte
.L1
.Section
.Access
= SupervisorAccess
;
740 Pte
.L1
.Section
.BaseAddress
= 0;
741 Pte
.L1
.Section
.Ignored
= Pte
.L1
.Section
.Ignored1
= 0;
742 ArmTable
->Pte
[0] = Pte
;
745 // Map the page in MMIO space that contains the serial port and timers
747 Pte
.L1
.Section
.BaseAddress
= ArmBoardBlock
->UartRegisterBase
>> PDE_SHIFT
;
748 ArmTable
->Pte
[UART_VIRTUAL
>> PDE_SHIFT
] = Pte
;
751 // Create template PTE for the coarse page table which maps the PTE_BASE
753 Pte
.L1
.Coarse
.Type
= CoarsePte
;
754 Pte
.L1
.Coarse
.Domain
= Domain0
;
755 Pte
.L1
.Coarse
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
756 Pte
.L1
.Coarse
.Ignored
= Pte
.L1
.Coarse
.Ignored1
= 0;
757 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)FlatMapTable
>> CPT_SHIFT
;
760 // On x86, there is 4MB of space, starting at 0xC0000000 to 0xC0400000
761 // which contains the mappings for each PTE on the system. 4MB is needed
762 // since for 4GB, there will be 1 million PTEs, each of 4KB.
764 // To describe a 4MB region, on x86, only requires a page table, which can
765 // be linked from the page table directory.
767 // On the other hand, on ARM, we can only describe 1MB regions, so we need
768 // four times less PTE entries to represent a single mapping (an L2 coarse
769 // page table). This is problematic, because this would only take up 1KB of
770 // space, and we can't have a page that small.
772 // This means we must:
774 // - Allocate page tables (in physical memory) with 4KB granularity, instead
775 // of 1KB (the other 3KB is unused and invalid).
777 // - "Skip" the other 3KB in the region, because we can't point to another
778 // coarse page table after just 1KB.
780 // So 0xC0000000 will be mapped to the page table that maps the range of
781 // 0x00000000 to 0x01000000, while 0xC0001000 till be mapped to the page
782 // table that maps the area from 0x01000000 to 0x02000000, and so on. In
783 // total, this will require 4 million entries, and additionally, because of
784 // the padding, since each 256 entries will be 4KB (instead of 1KB), this
785 // means we'll need 16MB (0xC0000000 to 0xC1000000).
787 // We call this region the flat-map area
789 for (i
= (PTE_BASE
>> PDE_SHIFT
); i
< ((PTE_BASE
+ 0x1000000) >> PDE_SHIFT
); i
++)
792 // Write PTE and update the base address (next MB) for the next one
794 ArmTable
->Pte
[i
] = Pte
;
795 Pte
.L1
.Coarse
.BaseAddress
+= 4;
799 // On x86, there is also the region of 0xC0300000 to 0xC03080000 which maps
800 // to the various PDEs on the system. Yes, this overlaps with the above, and
801 // works because of an insidious dark magic (self-mapping the PDE as a PTE).
802 // Unfortunately, this doesn't work on ARM, firstly because the size of a L1
803 // page table is different than from an L2 page table, and secondly, which
804 // is even worse, the format for an L1 page table is different than the one
805 // for an L2 page table -- basically meaning we cannot self-map.
807 // However, we somewhat emulate this behavior on ARM. This will be expensive
808 // since we manually need to keep track of every page directory added and
809 // add an entry in our flat-map region. We also need to keep track of every
810 // change in the TTB, so that we can update the mappings in our PDE region.
812 // Note that for us, this region starts at 0xC1000000, after the flat-map
815 // Finally, to deal with different sizes (1KB page tables, 4KB page size!),
816 // we pad the ARM L2 page tables to make them 4KB, so that each page will
817 // therefore point to an L2 page table.
819 // This region is a lot easier than the first -- an L1 page table is only
820 // 16KB, so to access any index inside it, we just need 4 pages, since each
821 // page is 4KB... Clearly, there's also no need to pad in this case.
823 // We'll call this region the master translation area.
825 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)MasterTable
>> CPT_SHIFT
;
826 ArmTable
->Pte
[PDE_BASE
>> PDE_SHIFT
] = Pte
;
829 // Now create the template for the hyperspace table which maps 1MB
831 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)HyperSpaceTable
>> CPT_SHIFT
;
832 ArmTable
->Pte
[HYPER_SPACE
>> PDE_SHIFT
] = Pte
;
835 // Now create the template for the coarse page tables which map the first 8MB
837 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)BootTable
>> CPT_SHIFT
;
840 // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
841 // This is where the freeldr boot structures are located, and we need them.
843 for (i
= (KSEG0_BASE
>> PDE_SHIFT
); i
< ((KSEG0_BASE
+ 0x800000) >> PDE_SHIFT
); i
++)
846 // Write PTE and update the base address (next MB) for the next one
848 ArmTable
->Pte
[i
] = Pte
;
849 Pte
.L1
.Coarse
.BaseAddress
+= 4;
853 // Now create the template PTE for the coarse page tables for the next 6MB
855 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)KernelTable
>> CPT_SHIFT
;
858 // Map 0x00800000 - 0x00DFFFFF to 0x80800000 - 0x80DFFFFF
859 // In this way, the KERNEL_PHYS_ADDR (0x800000) becomes 0x80800000
860 // which is the kernel virtual base address, just like on x86.
862 ASSERT(KernelBase
== 0x80800000);
863 for (i
= (KernelBase
>> PDE_SHIFT
); i
< ((KernelBase
+ 0x600000) >> PDE_SHIFT
); i
++)
866 // Write PTE and update the base address (next MB) for the next one
868 ArmTable
->Pte
[i
] = Pte
;
869 Pte
.L1
.Coarse
.BaseAddress
+= 4;
873 // Now build the template PTE for the pages mapping the first 8MB
875 Pte
.L2
.Small
.Type
= SmallPte
;
876 Pte
.L2
.Small
.Buffered
= Pte
.L2
.Small
.Cached
= 0;
877 Pte
.L2
.Small
.Access0
=
878 Pte
.L2
.Small
.Access1
=
879 Pte
.L2
.Small
.Access2
=
880 Pte
.L2
.Small
.Access3
= SupervisorAccess
;
881 Pte
.L2
.Small
.BaseAddress
= 0;
884 // Loop each boot coarse page table (i).
885 // Each PDE describes 1MB. We're mapping an area of 8MB, so 8 times.
887 for (i
= 0; i
< 8; i
++)
890 // Loop and set each the PTE (j).
891 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
893 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
896 // Write PTE and update the base address (next MB) for the next one
898 BootTable
->Pte
[j
] = Pte
;
899 Pte
.L2
.Small
.BaseAddress
++;
909 // Now create the template PTE for the pages mapping the next 6MB
911 Pte
.L2
.Small
.BaseAddress
= (ULONG
)KERNEL_BASE_PHYS
>> PTE_SHIFT
;
914 // Loop each kernel coarse page table (i).
915 // Each PDE describes 1MB. We're mapping an area of 6MB, so 6 times.
917 for (i
= 0; i
< 6; i
++)
920 // Loop and set each the PTE (j).
921 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
923 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
926 // Write PTE and update the base address (next MB) for the next one
928 KernelTable
->Pte
[j
] = Pte
;
929 Pte
.L2
.Small
.BaseAddress
++;
939 // Now we need to create the PTEs for the addresses which have been mapped
942 // We have allocated 4 page table directories:
944 // - One for the kernel, 6MB
945 // - One for low-memory FreeLDR, 8MB
946 // - One for identity-mapping below 1MB, 1MB
947 // - And finally, one for the flat-map itself, 16MB
949 // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
950 // we will require 31 pages.
954 // For the 0x80000000 region (8MB)
956 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&BootTranslationTable
>> PTE_SHIFT
;
957 FlatMapTable
= &(&FlatMapTranslationTable
)[0x80000000 >> 28];
958 for (i
= 0; i
< 8; i
++)
961 // Point to the page table mapping the next MB
963 FlatMapTable
->Pte
[i
] = Pte
;
964 Pte
.L2
.Small
.BaseAddress
++;
968 // For the 0x80800000 region (6MB)
970 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&KernelTranslationTable
>> PTE_SHIFT
;
971 for (i
= 8; i
< 14; i
++)
974 // Point to the page table mapping the next MB
976 FlatMapTable
->Pte
[i
] = Pte
;
977 Pte
.L2
.Small
.BaseAddress
++;
981 // For the 0xC0000000 region (16MB)
983 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&FlatMapTranslationTable
>> PTE_SHIFT
;
984 FlatMapTable
= &(&FlatMapTranslationTable
)[0xC0000000 >> 28];
985 for (i
= 0; i
< 16; i
++)
988 // Point to the page table mapping the next MB
990 FlatMapTable
->Pte
[i
] = Pte
;
991 Pte
.L2
.Small
.BaseAddress
++;
995 // For the 0xC1000000 region (1MB)
997 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&MasterTranslationTable
>> PTE_SHIFT
;
998 FlatMapTable
->Pte
[16] = Pte
;
1001 // And finally for the 0xC1100000 region (1MB)
1003 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&HyperSpaceTranslationTable
>> PTE_SHIFT
;
1004 FlatMapTable
->Pte
[17] = Pte
;
1007 // Now we handle the master translation area for our PDEs. We'll just make
1008 // the 4 page tables point to the ARM TTB.
1010 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&ArmTranslationTable
>> PTE_SHIFT
;
1011 for (i
= 0; i
< 4; i
++)
1014 // Point to the page table mapping the next MB
1016 MasterTable
->Pte
[i
] = Pte
;
1017 Pte
.L2
.Small
.BaseAddress
++;
1022 ArmSetupPagingAndJump(IN ULONG Magic
)
1024 ARM_CONTROL_REGISTER ControlRegister
;
1027 // Enable MMU, DCache and ICache
1029 ControlRegister
= KeArmControlRegisterGet();
1030 ControlRegister
.MmuEnabled
= TRUE
;
1031 ControlRegister
.ICacheEnabled
= TRUE
;
1032 ControlRegister
.DCacheEnabled
= TRUE
;
1033 KeArmControlRegisterSet(ControlRegister
);
1036 // Reconfigure UART0
1038 ArmBoardBlock
->UartRegisterBase
= UART_VIRTUAL
|
1039 (ArmBoardBlock
->UartRegisterBase
&
1040 ((1 << PDE_SHIFT
) - 1));
1041 TuiPrintf("Mapped serial port to 0x%x\n", ArmBoardBlock
->UartRegisterBase
);
1046 (*KernelEntryPoint
)(Magic
, (PVOID
)((ULONG_PTR
)ArmLoaderBlock
| KSEG0_BASE
));
1050 ArmPrepareForReactOS(IN BOOLEAN Setup
)
1052 ARM_CACHE_REGISTER CacheReg
;
1053 PVOID Base
, MemBase
;
1054 PCHAR BootPath
, HalPath
;
1057 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1058 PLIST_ENTRY NextEntry
, OldEntry
;
1061 // Allocate the ARM Shared Heap
1063 ArmSharedHeap
= MmAllocateMemory(PAGE_SIZE
);
1064 ArmSharedHeapSize
= 0;
1065 if (!ArmSharedHeap
) return;
1068 // Allocate the loader block and extension
1070 ArmLoaderBlock
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK
));
1071 if (!ArmLoaderBlock
) return;
1072 ArmExtension
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION
));
1073 if (!ArmExtension
) return;
1076 // Initialize the loader block
1078 InitializeListHead(&ArmLoaderBlock
->BootDriverListHead
);
1079 InitializeListHead(&ArmLoaderBlock
->LoadOrderListHead
);
1080 InitializeListHead(&ArmLoaderBlock
->MemoryDescriptorListHead
);
1083 // Setup the extension and setup block
1085 ArmLoaderBlock
->Extension
= (PVOID
)((ULONG_PTR
)ArmExtension
| KSEG0_BASE
);
1086 ArmLoaderBlock
->SetupLdrBlock
= NULL
;
1089 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1090 // BIOS descriptor format -- this needs to be removed later.
1092 ArmBuildBoardMemoryMap();
1095 // Now basically convert these entries to the ARC format, so that we can
1096 // get a good map of free (usable) memory
1098 ArmBuildOsMemoryMap();
1101 // NT uses an extended ARC format, with slightly different memory types.
1102 // We also want to link the ARC descriptors together into a linked list,
1103 // instead of the array, and allocate the semi-permanent storage in which
1104 // these entries will be stored so that the kernel can read them.
1106 ArmBuildLoaderMemoryList();
1109 // Setup descriptor for the shared heap
1111 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderHeap
,
1112 (ULONG_PTR
)ArmSharedHeap
>> PAGE_SHIFT
,
1113 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap
,
1117 if (Status
!= STATUS_SUCCESS
) return;
1120 // Setup descriptor for the boot stack
1122 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderStack
,
1123 (ULONG_PTR
)&BootStack
>> PAGE_SHIFT
,
1127 if (Status
!= STATUS_SUCCESS
) return;
1130 // Setup descriptor for the boot page tables
1132 Status
= ArmCreateMemoryDescriptor(LoaderMemoryData
,
1133 (ULONG_PTR
)&TranslationTableStart
>> PAGE_SHIFT
,
1134 ((ULONG_PTR
)&TranslationTableEnd
-
1135 (ULONG_PTR
)&TranslationTableStart
) / PAGE_SIZE
,
1138 if (Status
!= STATUS_SUCCESS
) return;
1141 // Setup descriptor for the kernel
1143 Status
= ArmCreateMemoryDescriptor(LoaderSystemCode
,
1144 KernelData
>> PAGE_SHIFT
,
1145 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData
,
1149 if (Status
!= STATUS_SUCCESS
) return;
1152 // Setup descriptor for the HAL
1154 Status
= ArmCreateMemoryDescriptor(LoaderHalCode
,
1155 HalData
>> PAGE_SHIFT
,
1156 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData
,
1160 if (Status
!= STATUS_SUCCESS
) return;
1163 // Setup registry data
1165 ArmLoaderBlock
->RegistryBase
= (PVOID
)((ULONG_PTR
)RegistryData
| KSEG0_BASE
);
1166 ArmLoaderBlock
->RegistryLength
= RegistrySize
;
1169 // Create an MD for it
1171 Status
= ArmCreateMemoryDescriptor(LoaderRegistryData
,
1172 RegistryData
>> PAGE_SHIFT
,
1173 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData
,
1177 if (Status
!= STATUS_SUCCESS
) return;
1180 // TODO: Setup ARC Hardware tree data
1186 ArmNlsDataBlock
= ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK
));
1187 ArmLoaderBlock
->NlsData
= ArmNlsDataBlock
;
1188 ArmLoaderBlock
->NlsData
->AnsiCodePageData
= (PVOID
)(AnsiData
| KSEG0_BASE
);
1189 ArmLoaderBlock
->NlsData
->OemCodePageData
= (PVOID
)(OemData
| KSEG0_BASE
);
1190 ArmLoaderBlock
->NlsData
->UnicodeCodePageData
= (PVOID
)(UnicodeData
| KSEG0_BASE
);
1191 ArmLoaderBlock
->NlsData
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->NlsData
| KSEG0_BASE
);
1194 // Setup ANSI NLS Memory Descriptor
1196 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1197 AnsiData
>> PAGE_SHIFT
,
1198 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData
,
1202 if (Status
!= STATUS_SUCCESS
) return;
1205 // Setup OEM NLS Memory Descriptor
1207 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1208 OemData
>> PAGE_SHIFT
,
1209 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData
,
1213 if (Status
!= STATUS_SUCCESS
) return;
1216 // Setup Unicode NLS Memory Descriptor
1218 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1219 UnicodeData
>> PAGE_SHIFT
,
1220 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData
,
1224 if (Status
!= STATUS_SUCCESS
) return;
1227 // Setup loader entry for the kernel
1229 wcscpy(ArmModuleName
, L
"ntoskrnl.exe");
1230 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1231 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1232 LdrEntry
->DllBase
= (PVOID
)KernelBase
;
1233 LdrEntry
->SizeOfImage
= KernelSize
;
1234 LdrEntry
->EntryPoint
= KernelEntryPoint
;
1235 LdrEntry
->LoadCount
= 1;
1236 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1237 RtlInitUnicodeString(&LdrEntry
->FullDllName
, ArmModuleName
);
1238 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, ArmModuleName
);
1239 LdrEntry
->FullDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->FullDllName
.Buffer
| KSEG0_BASE
);
1240 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->BaseDllName
.Buffer
| KSEG0_BASE
);
1241 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1244 // TODO: Setup boot-driver data
1248 // Build descriptors for the drivers loaded
1250 for (i
= 0; i
< Drivers
; i
++)
1253 // Build a descriptor for the driver
1255 Status
= ArmCreateMemoryDescriptor(LoaderBootDriver
,
1256 DriverData
[i
] >> PAGE_SHIFT
,
1257 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData
[i
],
1261 if (Status
!= STATUS_SUCCESS
) return;
1268 NextEntry
= ArmLoaderBlock
->LoadOrderListHead
.Flink
;
1269 while (NextEntry
!= &ArmLoaderBlock
->LoadOrderListHead
)
1272 // Remember the physical entry
1274 OldEntry
= NextEntry
->Flink
;
1279 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1280 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1285 NextEntry
= OldEntry
;
1289 // Now edit the root itself
1291 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1292 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1295 // Setup extension parameters
1297 ArmExtension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
1298 ArmExtension
->MajorVersion
= 5;
1299 ArmExtension
->MinorVersion
= 2;
1302 // Make a copy of the command line
1304 ArmLoaderBlock
->LoadOptions
= ArmCommandLine
;
1305 strcpy(ArmCommandLine
, reactos_kernel_cmdline
);
1308 // Find the first \, separating the ARC path from NT path
1310 BootPath
= strchr(ArmCommandLine
, '\\');
1311 *BootPath
= ANSI_NULL
;
1314 // Set the ARC Boot Path
1316 strncpy(ArmArcBootPath
, ArmCommandLine
, 63);
1317 ArmLoaderBlock
->ArcBootDeviceName
= (PVOID
)((ULONG_PTR
)ArmArcBootPath
| KSEG0_BASE
);
1320 // The rest of the string is the NT path
1322 HalPath
= strchr(BootPath
+ 1, ' ');
1323 *HalPath
= ANSI_NULL
;
1324 ArmNtBootPath
[0] = '\\';
1325 strncat(ArmNtBootPath
, BootPath
+ 1, 63);
1326 strcat(ArmNtBootPath
,"\\");
1327 ArmLoaderBlock
->NtBootPathName
= (PVOID
)((ULONG_PTR
)ArmNtBootPath
| KSEG0_BASE
);
1330 // Set the HAL paths
1332 strncpy(ArmArcHalPath
, ArmArcBootPath
, 63);
1333 ArmLoaderBlock
->ArcHalDeviceName
= (PVOID
)((ULONG_PTR
)ArmArcHalPath
| KSEG0_BASE
);
1334 strcpy(ArmNtHalPath
, "\\");
1335 ArmLoaderBlock
->NtHalPathName
= (PVOID
)((ULONG_PTR
)ArmNtHalPath
| KSEG0_BASE
);
1338 // Use this new command line
1340 strncpy(ArmLoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
1343 // Parse it and change every slash to a space
1345 BootPath
= ArmLoaderBlock
->LoadOptions
;
1346 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
1349 // Fixup command-line pointer
1351 ArmLoaderBlock
->LoadOptions
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->LoadOptions
| KSEG0_BASE
);
1354 // Setup cache information
1356 CacheReg
= KeArmCacheRegisterGet();
1357 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheSize
= SizeBits
[CacheReg
.DSize
];
1358 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
= LenBits
[CacheReg
.DLength
];
1359 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
<<= 2;
1360 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheSize
= SizeBits
[CacheReg
.ISize
];
1361 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
= LenBits
[CacheReg
.ILength
];
1362 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
<<= 2;
1363 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheSize
=
1364 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheFillSize
=
1365 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheSize
=
1366 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheFillSize
= 0;
1369 // Allocate the Interrupt stack
1371 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupDpcStack
);
1372 ArmLoaderBlock
->u
.Arm
.InterruptStack
= KSEG0_BASE
| (ULONG
)Base
;
1373 ArmLoaderBlock
->u
.Arm
.InterruptStack
+= KERNEL_STACK_SIZE
;
1376 // Build an entry for it
1378 Status
= ArmCreateMemoryDescriptor(LoaderStartupDpcStack
,
1379 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1380 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1383 if (Status
!= STATUS_SUCCESS
) return;
1386 // Allocate the Kernel Boot stack
1388 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupKernelStack
);
1389 ArmLoaderBlock
->KernelStack
= KSEG0_BASE
| (ULONG
)Base
;
1390 ArmLoaderBlock
->KernelStack
+= KERNEL_STACK_SIZE
;
1393 // Build an entry for it
1395 Status
= ArmCreateMemoryDescriptor(LoaderStartupKernelStack
,
1396 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1397 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1400 if (Status
!= STATUS_SUCCESS
) return;
1403 // Allocate the Abort stack
1405 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupPanicStack
);
1406 ArmLoaderBlock
->u
.Arm
.PanicStack
= KSEG0_BASE
| (ULONG
)Base
;
1407 ArmLoaderBlock
->u
.Arm
.PanicStack
+= KERNEL_STACK_SIZE
;
1410 // Build an entry for it
1412 Status
= ArmCreateMemoryDescriptor(LoaderStartupPanicStack
,
1413 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1414 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1417 if (Status
!= STATUS_SUCCESS
) return;
1420 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1422 Base
= MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage
);
1424 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1425 ArmLoaderBlock
->u
.Arm
.PcrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1428 // Build an entry for the KPCR and KUSER_SHARED_DATA
1430 Status
= ArmCreateMemoryDescriptor(LoaderStartupPcrPage
,
1431 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1432 (2 * 1024 * 1024) / PAGE_SIZE
,
1435 if (Status
!= STATUS_SUCCESS
) return;
1438 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1440 Base
= MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage
);
1442 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1443 ArmLoaderBlock
->u
.Arm
.PdrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1446 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1448 Status
= ArmCreateMemoryDescriptor(LoaderStartupPdrPage
,
1449 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1450 (4 * 1024 * 1024) / PAGE_SIZE
,
1453 if (Status
!= STATUS_SUCCESS
) return;
1456 // Set initial PRCB, Thread and Process on the last PDR page
1458 Base
= (PVOID
)((ULONG
)Base
+ 2 * 1024 * 1024);
1459 ArmLoaderBlock
->Prcb
= KSEG0_BASE
| (ULONG
)Base
;
1460 ArmLoaderBlock
->Process
= ArmLoaderBlock
->Prcb
+ sizeof(KPRCB
);
1461 ArmLoaderBlock
->Thread
= ArmLoaderBlock
->Process
+ sizeof(EPROCESS
);
1466 NextEntry
= ArmLoaderBlock
->MemoryDescriptorListHead
.Flink
;
1467 while (NextEntry
!= &ArmLoaderBlock
->MemoryDescriptorListHead
)
1470 // Remember the physical entry
1472 OldEntry
= NextEntry
->Flink
;
1477 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1478 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1483 NextEntry
= OldEntry
;
1487 // Now edit the root itself
1489 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1490 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1494 FrLdrStartup(IN ULONG Magic
)
1497 // Disable interrupts (aleady done)
1501 // Set proper CPSR (already done)
1505 // Initialize the page directory
1507 ArmSetupPageDirectory();
1510 // Initialize paging and load NTOSKRNL
1512 ArmSetupPagingAndJump(Magic
);