2 * PROJECT: ReactOS Boot Loader
3 * LICENSE: BSD - See COPYING.ARM 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
;
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];
50 extern PCHAR DriverName
[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 /* FUNCTIONS ******************************************************************/
88 ArmAllocateFromSharedHeap(IN ULONG Size
)
93 // Allocate from the shared heap
95 Buffer
= &ArmSharedHeap
[ArmSharedHeapSize
];
96 ArmSharedHeapSize
+= Size
;
100 PMEMORY_ALLOCATION_DESCRIPTOR
102 ArmAllocateMemoryDescriptor(VOID
)
105 // Allocate a descriptor from the heap
107 return ArmAllocateFromSharedHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
));
112 ArmAddBoardMemoryDescriptor(IN ULONG Address
,
115 PBIOS_MEMORY_DESCRIPTOR BiosBlock
= ArmBoardMemoryList
;
118 // Loop board DRAM configuration
120 while (BiosBlock
->BlockSize
> 0)
122 /* Check if we've found a matching head block */
123 if (Address
+ Size
== BiosBlock
->BlockBase
)
125 /* Simply enlarge and rebase it */
126 BiosBlock
->BlockBase
= Address
;
127 BiosBlock
->BlockSize
+= Size
;
131 /* Check if we've found a matching tail block */
132 if (Address
== (BiosBlock
->BlockBase
+ BiosBlock
->BlockSize
))
134 /* Simply enlarge it */
135 BiosBlock
->BlockSize
+= Size
;
139 /* Nothing suitable found, try the next block */
143 /* No usable blocks found, found a free block instead */
144 if (!BiosBlock
->BlockSize
)
147 BiosBlock
->BlockBase
= Address
;
148 BiosBlock
->BlockSize
= Size
;
150 /* Create a new block and mark it as the end of the array */
152 BiosBlock
->BlockBase
= BiosBlock
->BlockSize
= 0L;
158 ArmBuildBoardMemoryMap(VOID
)
160 ULONG BlockBegin
, BlockEnd
;
163 /* Loop the BIOS Memory Map */
164 for (j
= 0; j
< ArmBoardMemoryMapRangeCount
; j
++)
166 /* Get the start and end addresses */
167 BlockBegin
= ArmBoardMemoryMap
[j
].BaseAddrLow
;
168 BlockEnd
= ArmBoardMemoryMap
[j
].BaseAddrLow
+ ArmBoardMemoryMap
[j
].LengthLow
- 1;
170 /* Make sure this isn't a > 4GB descriptor */
171 if (!ArmBoardMemoryMap
[j
].BaseAddrHigh
)
173 /* Make sure we don't overflow */
174 if (BlockEnd
< BlockBegin
) BlockEnd
= 0xFFFFFFFF;
176 /* Check if this is free memory */
177 if (ArmBoardMemoryMap
[j
].Type
== 1)
179 /* Add it to our BIOS descriptors */
180 ArmAddBoardMemoryDescriptor(BlockBegin
, BlockEnd
- BlockBegin
+ 1);
188 ArmConfigureArcDescriptor(IN ULONG PageBegin
,
190 IN TYPE_OF_MEMORY MemoryType
)
193 ULONG BlockBegin
, BlockEnd
;
194 MEMORY_TYPE BlockType
;
195 BOOLEAN Combined
= FALSE
;
197 /* If this descriptor seems bogus, just return */
198 if (PageEnd
<= PageBegin
) return STATUS_SUCCESS
;
200 /* Loop every ARC descriptor, trying to find one we can modify */
201 for (i
= 0; i
< NumberDescriptors
; i
++)
203 /* Get its settings */
204 BlockBegin
= MDArray
[i
].BasePage
;
205 BlockEnd
= MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
;
206 BlockType
= MDArray
[i
].MemoryType
;
208 /* Check if we can fit inside this block */
209 if (BlockBegin
< PageBegin
)
211 /* Check if we are larger then it */
212 if ((BlockEnd
> PageBegin
) && (BlockEnd
<= PageEnd
))
214 /* Make it end where we start */
215 BlockEnd
= PageBegin
;
218 /* Check if it ends after we do */
219 if (BlockEnd
> PageEnd
)
221 /* Make sure we can allocate a descriptor */
222 if (NumberDescriptors
== 60) return ENOMEM
;
224 /* Create a descriptor for whatever memory we're not part of */
225 MDArray
[NumberDescriptors
].MemoryType
= BlockType
;
226 MDArray
[NumberDescriptors
].BasePage
= PageEnd
;
227 MDArray
[NumberDescriptors
].PageCount
= BlockEnd
- PageEnd
;
230 /* The next block ending is now where we begin */
231 BlockEnd
= PageBegin
;
236 /* Check if the blog begins inside our range */
237 if (BlockBegin
< PageEnd
)
239 /* Check if it ends before we do */
240 if (BlockEnd
< PageEnd
)
242 /* Then make it disappear */
243 BlockEnd
= BlockBegin
;
247 /* Otherwise make it start where we end */
248 BlockBegin
= PageEnd
;
253 /* Check if the block matches us, and we haven't tried combining yet */
254 if ((BlockType
== MemoryType
) && !(Combined
))
256 /* Check if it starts where we end */
257 if (BlockBegin
== PageEnd
)
259 /* Make it start with us, and combine us */
260 BlockBegin
= PageBegin
;
263 else if (BlockEnd
== PageBegin
)
265 /* Otherwise, it ends where we begin, combine its ending */
271 /* Check the original block data matches with what we came up with */
272 if ((MDArray
[i
].BasePage
== BlockBegin
) &&
273 (MDArray
[i
].PageCount
== BlockEnd
- BlockBegin
))
279 /* Otherwise, set our new settings for this block */
280 MDArray
[i
].BasePage
= BlockBegin
;
281 MDArray
[i
].PageCount
= BlockEnd
- BlockBegin
;
283 /* Check if we are killing the block */
284 if (BlockBegin
== BlockEnd
)
286 /* Delete this block and restart the loop properly */
288 if (i
< NumberDescriptors
) MDArray
[i
] = MDArray
[NumberDescriptors
];
293 /* If we got here without combining, we need to allocate a new block */
294 if (!(Combined
) && (MemoryType
< LoaderMaximum
))
296 /* Make sure there's enough descriptors */
297 if (NumberDescriptors
== 60) return ENOMEM
;
299 /* Allocate a new block with our data */
300 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
301 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
302 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
306 /* Changes complete, return success */
307 return STATUS_SUCCESS
;
312 ArmBuildOsMemoryMap(VOID
)
314 PBIOS_MEMORY_DESCRIPTOR MdBlock
;
315 ULONG BlockStart
, BlockEnd
, BiasedStart
, BiasedEnd
, PageStart
, PageEnd
;
316 NTSTATUS Status
= STATUS_SUCCESS
;
318 /* Loop the BIOS Memory Descriptor List */
319 MdBlock
= ArmBoardMemoryList
;
320 while (MdBlock
->BlockSize
)
322 /* Get the statrt and end addresses */
323 BlockStart
= MdBlock
->BlockBase
;
324 BlockEnd
= BlockStart
+ MdBlock
->BlockSize
- 1;
326 /* Align them to page boundaries */
327 BiasedStart
= BlockStart
& (PAGE_SIZE
- 1);
328 if (BiasedStart
) BlockStart
= BlockStart
+ PAGE_SIZE
- BiasedStart
;
329 BiasedEnd
= (BlockEnd
+ 1) & (ULONG
)(PAGE_SIZE
- 1);
330 if (BiasedEnd
) BlockEnd
-= BiasedEnd
;
332 /* Get the actual page numbers */
333 PageStart
= BlockStart
>> PAGE_SHIFT
;
334 PageEnd
= (BlockEnd
+ 1) >> PAGE_SHIFT
;
336 /* Check if we did any alignment */
339 /* Mark that region as reserved */
340 Status
= ArmConfigureArcDescriptor(PageStart
- 1,
342 MemorySpecialMemory
);
343 if (Status
!= STATUS_SUCCESS
) break;
346 /* Check if we did any alignment */
349 /* Mark that region as reserved */
350 Status
= ArmConfigureArcDescriptor(PageEnd
- 1,
352 MemorySpecialMemory
);
353 if (Status
!= STATUS_SUCCESS
) break;
356 /* It is, mark the memory a free */
357 Status
= ArmConfigureArcDescriptor(PageStart
,
361 /* If we failed, break out, otherwise, go to the next BIOS block */
362 if (Status
!= STATUS_SUCCESS
) break;
366 /* Return error code */
372 ArmInsertMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
374 PLIST_ENTRY ListHead
, PreviousEntry
, NextEntry
;
375 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
= NULL
, NextDescriptor
= NULL
;
377 /* Loop the memory descriptor list */
378 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
379 PreviousEntry
= ListHead
;
380 NextEntry
= ListHead
->Flink
;
381 while (NextEntry
!= ListHead
)
383 /* Get the current descriptor and check if it's below ours */
384 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
385 MEMORY_ALLOCATION_DESCRIPTOR
,
387 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
) break;
389 /* It isn't, save the previous entry and descriptor, and try again */
390 PreviousEntry
= NextEntry
;
391 Descriptor
= NextDescriptor
;
392 NextEntry
= NextEntry
->Flink
;
395 /* So we found the right spot to insert. Is this free memory? */
396 if (NewDescriptor
->MemoryType
!= LoaderFree
)
398 /* It isn't, so insert us before the last descriptor */
399 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
403 /* We're free memory. Check if the entry we found is also free memory */
404 if ((PreviousEntry
!= ListHead
) &&
405 ((Descriptor
->MemoryType
== LoaderFree
) ||
406 (Descriptor
->MemoryType
== LoaderReserve
)) &&
407 ((Descriptor
->BasePage
+ Descriptor
->PageCount
) ==
408 NewDescriptor
->BasePage
))
410 /* It's free memory, and we're right after it. Enlarge that block */
411 Descriptor
->PageCount
+= NewDescriptor
->PageCount
;
412 NewDescriptor
= Descriptor
;
416 /* Our range scan't be combined, so just insert us separately */
417 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
420 /* Check if we merged with an existing free memory block */
421 if ((NextEntry
!= ListHead
) &&
422 ((NextDescriptor
->MemoryType
== LoaderFree
) ||
423 (NextDescriptor
->MemoryType
== LoaderReserve
)) &&
424 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) ==
425 NextDescriptor
->BasePage
))
427 /* Update our own block */
428 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
430 /* Remove the next block */
431 RemoveEntryList(&NextDescriptor
->ListEntry
);
438 ArmBuildMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor
,
439 IN MEMORY_TYPE MemoryType
,
443 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
, NextDescriptor
= NULL
;
445 TYPE_OF_MEMORY CurrentType
;
448 /* Check how many pages we'll be consuming */
449 Delta
= BasePage
- MemoryDescriptor
->BasePage
;
450 if (!(Delta
) && (PageCount
== MemoryDescriptor
->PageCount
))
452 /* We can simply convert the current descriptor into our new type */
453 MemoryDescriptor
->MemoryType
= MemoryType
;
457 /* Get the current memory type of the descriptor, and reserve it */
458 CurrentType
= MemoryDescriptor
->MemoryType
;
459 MemoryDescriptor
->MemoryType
= LoaderSpecialMemory
;
461 /* Check if we'll need another descriptor for what's left of memory */
462 UseNext
= ((BasePage
!= MemoryDescriptor
->BasePage
) &&
463 (Delta
+ PageCount
!= MemoryDescriptor
->PageCount
));
465 /* Get a descriptor */
466 Descriptor
= ArmAllocateMemoryDescriptor();
467 if (!Descriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
469 /* Check if we are using another descriptor */
472 /* Allocate that one too */
473 NextDescriptor
= ArmAllocateMemoryDescriptor();
474 if (!NextDescriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
477 /* Build the descriptor we got */
478 Descriptor
->MemoryType
= MemoryType
;
479 Descriptor
->BasePage
= BasePage
;
480 Descriptor
->PageCount
= PageCount
;
482 /* Check if we're starting at the same place as the old one */
483 if (BasePage
== MemoryDescriptor
->BasePage
)
485 /* Simply decrease the old descriptor and rebase it */
486 MemoryDescriptor
->BasePage
+= PageCount
;
487 MemoryDescriptor
->PageCount
-= PageCount
;
488 MemoryDescriptor
->MemoryType
= CurrentType
;
490 else if (Delta
+ PageCount
== MemoryDescriptor
->PageCount
)
492 /* We finish where the old one did, shorten it */
493 MemoryDescriptor
->PageCount
-= PageCount
;
494 MemoryDescriptor
->MemoryType
= CurrentType
;
498 /* We're inside the current block, mark our free region */
499 NextDescriptor
->MemoryType
= LoaderFree
;
500 NextDescriptor
->BasePage
= BasePage
+ PageCount
;
501 NextDescriptor
->PageCount
= MemoryDescriptor
->PageCount
-
504 /* And cut down the current descriptor */
505 MemoryDescriptor
->PageCount
= Delta
;
506 MemoryDescriptor
->MemoryType
= CurrentType
;
508 /* Finally, insert our new free descriptor into the list */
509 ArmInsertMemoryDescriptor(NextDescriptor
);
512 /* Insert the descriptor we allocated */
513 ArmInsertMemoryDescriptor(Descriptor
);
517 return STATUS_SUCCESS
;
520 PMEMORY_ALLOCATION_DESCRIPTOR
522 ArmFindMemoryDescriptor(IN ULONG BasePage
)
524 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
= NULL
;
525 PLIST_ENTRY NextEntry
, ListHead
;
527 /* Scan the memory descriptor list */
528 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
529 NextEntry
= ListHead
->Flink
;
530 while (NextEntry
!= ListHead
)
532 /* Get the current descriptor */
533 MdBlock
= CONTAINING_RECORD(NextEntry
,
534 MEMORY_ALLOCATION_DESCRIPTOR
,
537 /* Check if it can contain our memory range */
538 if ((MdBlock
->BasePage
<= BasePage
) &&
539 (MdBlock
->BasePage
+ MdBlock
->PageCount
> BasePage
))
541 /* It can, break out */
545 /* Go to the next descriptor */
546 NextEntry
= NextEntry
->Flink
;
549 /* Return the descriptor we found, if any */
555 ArmCreateMemoryDescriptor(IN TYPE_OF_MEMORY MemoryType
,
559 OUT PULONG ReturnedBase
)
561 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
562 ULONG AlignedBase
, AlignedLimit
;
563 PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock
;
564 ULONG ActiveAlignedBase
= 0;
565 PLIST_ENTRY NextEntry
, ListHead
;
567 /* If no information was given, make some assumptions */
568 if (!Alignment
) Alignment
= 1;
569 if (!PageCount
) PageCount
= 1;
571 /* Start looking for a matching descvriptor */
574 /* Calculate the limit of the range */
575 AlignedLimit
= PageCount
+ BasePage
;
577 /* Find a descriptor that already contains our base address */
578 MdBlock
= ArmFindMemoryDescriptor(BasePage
);
581 /* If it contains our limit as well, break out early */
582 if ((MdBlock
->PageCount
+ MdBlock
->BasePage
) >= AlignedLimit
) break;
585 /* Loop the memory list */
587 ActiveMdBlock
= NULL
;
588 ListHead
= &ArmLoaderBlock
->MemoryDescriptorListHead
;
589 NextEntry
= ListHead
->Flink
;
590 while (NextEntry
!= ListHead
)
592 /* Get the current descriptors */
593 MdBlock
= CONTAINING_RECORD(NextEntry
,
594 MEMORY_ALLOCATION_DESCRIPTOR
,
597 /* Align the base address and our limit */
598 AlignedBase
= (MdBlock
->BasePage
+ (Alignment
- 1)) &~ Alignment
;
599 AlignedLimit
= MdBlock
->PageCount
-
603 /* Check if this is a free block that can satisfy us */
604 if ((MdBlock
->MemoryType
== LoaderFree
) &&
605 (AlignedLimit
<= MdBlock
->PageCount
) &&
606 (PageCount
<= AlignedLimit
))
608 /* It is, stop searching */
609 ActiveMdBlock
= MdBlock
;
610 ActiveAlignedBase
= AlignedBase
;
614 /* Try the next block */
615 NextEntry
= NextEntry
->Flink
;
618 /* See if we came up with an adequate block */
621 /* Generate a descriptor in it */
622 *ReturnedBase
= AlignedBase
;
623 return ArmBuildMemoryDescriptor(ActiveMdBlock
,
630 /* We found a matching block, generate a descriptor with it */
631 *ReturnedBase
= BasePage
;
632 return ArmBuildMemoryDescriptor(MdBlock
, MemoryType
, BasePage
, PageCount
);
637 ArmBuildLoaderMemoryList(VOID
)
639 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
640 MEMORY_DESCRIPTOR
*Memory
;
643 /* Loop all BIOS Memory Descriptors */
644 for (i
= 0; i
< NumberDescriptors
; i
++)
646 /* Get the current descriptor */
647 Memory
= &MDArray
[i
];
649 /* Allocate an NT Memory Descriptor */
650 Descriptor
= ArmAllocateMemoryDescriptor();
651 if (!Descriptor
) return ENOMEM
;
653 /* Copy the memory type */
654 Descriptor
->MemoryType
= Memory
->MemoryType
;
655 if (Memory
->MemoryType
== MemoryFreeContiguous
)
657 /* Convert this to free */
658 Descriptor
->MemoryType
= LoaderFree
;
660 else if (Memory
->MemoryType
== MemorySpecialMemory
)
662 /* Convert this to special memory */
663 Descriptor
->MemoryType
= LoaderSpecialMemory
;
666 /* Copy the range data */
667 Descriptor
->BasePage
= Memory
->BasePage
;
668 Descriptor
->PageCount
= Memory
->PageCount
;
670 /* Insert the descriptor */
671 if (Descriptor
->PageCount
) ArmInsertMemoryDescriptor(Descriptor
);
675 return STATUS_SUCCESS
;
679 ArmSetupPageDirectory(VOID
)
681 ARM_TTB_REGISTER TtbRegister
;
682 ARM_DOMAIN_REGISTER DomainRegister
;
685 PARM_TRANSLATION_TABLE ArmTable
;
686 PARM_COARSE_PAGE_TABLE BootTable
, KernelTable
, FlatMapTable
, MasterTable
;
689 // Get the PDEs that we will use
691 ArmTable
= &ArmTranslationTable
;
692 BootTable
= &BootTranslationTable
;
693 KernelTable
= &KernelTranslationTable
;
694 FlatMapTable
= &FlatMapTranslationTable
;
695 MasterTable
= &MasterTranslationTable
;
698 // Set the master L1 PDE as the TTB
700 TtbRegister
.AsUlong
= (ULONG
)ArmTable
;
701 ASSERT(TtbRegister
.Reserved
== 0);
702 KeArmTranslationTableRegisterSet(TtbRegister
);
705 // Use Domain 0, enforce AP bits (client)
707 DomainRegister
.AsUlong
= 0;
708 DomainRegister
.Domain0
= ClientDomain
;
709 KeArmDomainRegisterSet(DomainRegister
);
712 // Set Fault PTEs everywhere
714 RtlZeroMemory(ArmTable
, sizeof(ARM_TRANSLATION_TABLE
));
717 // Identity map the first MB of memory
719 Pte
.L1
.Section
.Type
= SectionPte
;
720 Pte
.L1
.Section
.Buffered
= FALSE
;
721 Pte
.L1
.Section
.Cached
= FALSE
;
722 Pte
.L1
.Section
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
723 Pte
.L1
.Section
.Domain
= Domain0
;
724 Pte
.L1
.Section
.Access
= SupervisorAccess
;
725 Pte
.L1
.Section
.BaseAddress
= 0;
726 Pte
.L1
.Section
.Ignored
= Pte
.L1
.Section
.Ignored1
= 0;
727 ArmTable
->Pte
[0] = Pte
;
730 // Map the page in MMIO space that contains the serial port and timers
732 Pte
.L1
.Section
.BaseAddress
= ArmBoardBlock
->UartRegisterBase
>> PDE_SHIFT
;
733 ArmTable
->Pte
[UART_VIRTUAL
>> PDE_SHIFT
] = Pte
;
736 // Create template PTE for the coarse page table which maps the PTE_BASE
738 Pte
.L1
.Coarse
.Type
= CoarsePte
;
739 Pte
.L1
.Coarse
.Domain
= Domain0
;
740 Pte
.L1
.Coarse
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
741 Pte
.L1
.Coarse
.Ignored
= Pte
.L1
.Coarse
.Ignored1
= 0;
742 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)FlatMapTable
>> CPT_SHIFT
;
745 // On x86, there is 4MB of space, starting at 0xC0000000 to 0xC0400000
746 // which contains the mappings for each PTE on the system. 4MB is needed
747 // since for 4GB, there will be 1 million PTEs, each of 4KB.
749 // To describe a 4MB region, on x86, only requires a page table, which can
750 // be linked from the page table directory.
752 // On the other hand, on ARM, we can only describe 1MB regions, so we need
753 // four times less PTE entries to represent a single mapping (an L2 coarse
754 // page table). This is problematic, because this would only take up 1KB of
755 // space, and we can't have a page that small.
757 // This means we must:
759 // - Allocate page tables (in physical memory) with 4KB granularity, instead
760 // of 1KB (the other 3KB is unused and invalid).
762 // - "Skip" the other 3KB in the region, because we can't point to another
763 // coarse page table after just 1KB.
765 // So 0xC0000000 will be mapped to the page table that maps the range of
766 // 0x00000000 to 0x01000000, while 0xC0001000 till be mapped to the page
767 // table that maps the area from 0x01000000 to 0x02000000, and so on. In
768 // total, this will require 4 million entries, and additionally, because of
769 // the padding, since each 256 entries will be 4KB (instead of 1KB), this
770 // means we'll need 16MB (0xC0000000 to 0xC1000000).
772 // We call this region the flat-map area
774 for (i
= (PTE_BASE
>> PDE_SHIFT
); i
< ((PTE_BASE
+ 0x1000000) >> PDE_SHIFT
); i
++)
777 // Write PTE and update the base address (next MB) for the next one
779 ArmTable
->Pte
[i
] = Pte
;
780 Pte
.L1
.Coarse
.BaseAddress
+= 4;
784 // On x86, there is also the region of 0xC0300000 to 0xC03080000 which maps
785 // to the various PDEs on the system. Yes, this overlaps with the above, and
786 // works because of an insidious dark magic (self-mapping the PDE as a PTE).
787 // Unfortunately, this doesn't work on ARM, firstly because the size of a L1
788 // page table is different than from an L2 page table, and secondly, which
789 // is even worse, the format for an L1 page table is different than the one
790 // for an L2 page table -- basically meaning we cannot self-map.
792 // However, we somewhat emulate this behavior on ARM. This will be expensive
793 // since we manually need to keep track of every page directory added and
794 // add an entry in our flat-map region. We also need to keep track of every
795 // change in the TTB, so that we can update the mappings in our PDE region.
797 // Note that for us, this region starts at 0xC1000000, after the flat-map
800 // Finally, to deal with different sizes (1KB page tables, 4KB page size!),
801 // we pad the ARM L2 page tables to make them 4KB, so that each page will
802 // therefore point to an L2 page table.
804 // This region is a lot easier than the first -- an L1 page table is only
805 // 16KB, so to access any index inside it, we just need 4 pages, since each
806 // page is 4KB... Clearly, there's also no need to pad in this case.
808 // We'll call this region the master translation area.
810 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)MasterTable
>> CPT_SHIFT
;
811 ArmTable
->Pte
[PDE_BASE
>> PDE_SHIFT
] = Pte
;
814 // Now create the template for the coarse page tables which map the first 8MB
816 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)BootTable
>> CPT_SHIFT
;
819 // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
820 // This is where the freeldr boot structures are located, and we need them.
822 for (i
= (KSEG0_BASE
>> PDE_SHIFT
); i
< ((KSEG0_BASE
+ 0x800000) >> PDE_SHIFT
); i
++)
825 // Write PTE and update the base address (next MB) for the next one
827 ArmTable
->Pte
[i
] = Pte
;
828 Pte
.L1
.Coarse
.BaseAddress
+= 4;
832 // Now create the template PTE for the coarse page tables for the next 6MB
834 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)KernelTable
>> CPT_SHIFT
;
837 // Map 0x00800000 - 0x00DFFFFF to 0x80800000 - 0x80DFFFFF
838 // In this way, the KERNEL_PHYS_ADDR (0x800000) becomes 0x80800000
839 // which is the kernel virtual base address, just like on x86.
841 ASSERT(KernelBase
== 0x80800000);
842 for (i
= (KernelBase
>> PDE_SHIFT
); i
< ((KernelBase
+ 0x600000) >> 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 build the template PTE for the pages mapping the first 8MB
854 Pte
.L2
.Small
.Type
= SmallPte
;
855 Pte
.L2
.Small
.Buffered
= Pte
.L2
.Small
.Cached
= 0;
856 Pte
.L2
.Small
.Access0
=
857 Pte
.L2
.Small
.Access1
=
858 Pte
.L2
.Small
.Access2
=
859 Pte
.L2
.Small
.Access3
= SupervisorAccess
;
860 Pte
.L2
.Small
.BaseAddress
= 0;
863 // Loop each boot coarse page table (i).
864 // Each PDE describes 1MB. We're mapping an area of 8MB, so 8 times.
866 for (i
= 0; i
< 8; i
++)
869 // Loop and set each the PTE (j).
870 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
872 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
875 // Write PTE and update the base address (next MB) for the next one
877 BootTable
->Pte
[j
] = Pte
;
878 Pte
.L2
.Small
.BaseAddress
++;
888 // Now create the template PTE for the pages mapping the next 6MB
890 Pte
.L2
.Small
.BaseAddress
= (ULONG
)KERNEL_BASE_PHYS
>> PTE_SHIFT
;
893 // Loop each kernel coarse page table (i).
894 // Each PDE describes 1MB. We're mapping an area of 6MB, so 6 times.
896 for (i
= 0; i
< 6; i
++)
899 // Loop and set each the PTE (j).
900 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
902 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
905 // Write PTE and update the base address (next MB) for the next one
907 KernelTable
->Pte
[j
] = Pte
;
908 Pte
.L2
.Small
.BaseAddress
++;
918 // Now we need to create the PTEs for the addresses which have been mapped
921 // We have allocated 4 page table directories:
923 // - One for the kernel, 6MB
924 // - One for low-memory FreeLDR, 8MB
925 // - One for identity-mapping below 1MB, 1MB
926 // - And finally, one for the flat-map itself, 16MB
928 // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
929 // we will require 31 pages.
933 // For the 0x80000000 region (8MB)
935 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&BootTranslationTable
>> PTE_SHIFT
;
936 FlatMapTable
= &(&FlatMapTranslationTable
)[0x80000000 >> 28];
937 for (i
= 0; i
< 8; i
++)
940 // Point to the page table mapping the next MB
942 FlatMapTable
->Pte
[i
] = Pte
;
943 Pte
.L2
.Small
.BaseAddress
++;
947 // For the 0x80800000 region (6MB)
949 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&KernelTranslationTable
>> PTE_SHIFT
;
950 for (i
= 8; i
< 14; i
++)
953 // Point to the page table mapping the next MB
955 FlatMapTable
->Pte
[i
] = Pte
;
956 Pte
.L2
.Small
.BaseAddress
++;
960 // For the 0xC0000000 region (16MB)
962 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&FlatMapTranslationTable
>> PTE_SHIFT
;
963 FlatMapTable
= &(&FlatMapTranslationTable
)[0xC0000000 >> 28];
964 for (i
= 0; i
< 16; i
++)
967 // Point to the page table mapping the next MB
969 FlatMapTable
->Pte
[i
] = Pte
;
970 Pte
.L2
.Small
.BaseAddress
++;
974 // For the 0xC1000000 region (1MB)
976 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&MasterTranslationTable
>> PTE_SHIFT
;
977 FlatMapTable
->Pte
[16] = Pte
;
980 // Now we handle the master translation area for our PDEs. We'll just make
981 // the 4 page tables point to the ARM TTB.
983 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&ArmTranslationTable
>> PTE_SHIFT
;
984 for (i
= 0; i
< 4; i
++)
987 // Point to the page table mapping the next MB
989 MasterTable
->Pte
[i
] = Pte
;
990 Pte
.L2
.Small
.BaseAddress
++;
995 ArmSetupPagingAndJump(IN ULONG Magic
)
997 ARM_CONTROL_REGISTER ControlRegister
;
1000 // Enable MMU, DCache and ICache
1002 ControlRegister
= KeArmControlRegisterGet();
1003 ControlRegister
.MmuEnabled
= TRUE
;
1004 ControlRegister
.ICacheEnabled
= TRUE
;
1005 ControlRegister
.DCacheEnabled
= TRUE
;
1006 KeArmControlRegisterSet(ControlRegister
);
1009 // Reconfigure UART0
1011 ArmBoardBlock
->UartRegisterBase
= UART_VIRTUAL
|
1012 (ArmBoardBlock
->UartRegisterBase
&
1013 ((1 << PDE_SHIFT
) - 1));
1014 TuiPrintf("Mapped serial port to 0x%x\n", ArmBoardBlock
->UartRegisterBase
);
1019 (*KernelEntryPoint
)((PVOID
)((ULONG_PTR
)ArmLoaderBlock
| KSEG0_BASE
));
1023 ArmPrepareForReactOS(IN BOOLEAN Setup
)
1025 ARM_CACHE_REGISTER CacheReg
;
1026 PVOID Base
, MemBase
;
1027 PCHAR BootPath
, HalPath
;
1030 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1031 PLIST_ENTRY NextEntry
, OldEntry
;
1032 PARC_DISK_INFORMATION ArcDiskInformation
;
1033 PARC_DISK_SIGNATURE ArcDiskSignature
;
1034 ULONG ArcDiskCount
= 0, Checksum
= 0;
1035 PMASTER_BOOT_RECORD Mbr
;
1037 PWCHAR ArmModuleName
;
1040 // Allocate the ARM Shared Heap
1042 ArmSharedHeap
= MmAllocateMemoryWithType(PAGE_SIZE
, LoaderOsloaderHeap
);
1043 ArmSharedHeapSize
= 0;
1044 if (!ArmSharedHeap
) return;
1047 // Allocate the loader block and extension
1049 ArmLoaderBlock
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK
));
1050 if (!ArmLoaderBlock
) return;
1051 ArmExtension
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION
));
1052 if (!ArmExtension
) return;
1055 // Initialize the loader block
1057 InitializeListHead(&ArmLoaderBlock
->BootDriverListHead
);
1058 InitializeListHead(&ArmLoaderBlock
->LoadOrderListHead
);
1059 InitializeListHead(&ArmLoaderBlock
->MemoryDescriptorListHead
);
1062 // Setup the extension and setup block
1064 ArmLoaderBlock
->Extension
= (PVOID
)((ULONG_PTR
)ArmExtension
| KSEG0_BASE
);
1065 ArmLoaderBlock
->SetupLdrBlock
= NULL
;
1068 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1069 // BIOS descriptor format -- this needs to be removed later.
1071 ArmBuildBoardMemoryMap();
1074 // Now basically convert these entries to the ARC format, so that we can
1075 // get a good map of free (usable) memory
1077 ArmBuildOsMemoryMap();
1080 // NT uses an extended ARC format, with slightly different memory types.
1081 // We also want to link the ARC descriptors together into a linked list,
1082 // instead of the array, and allocate the semi-permanent storage in which
1083 // these entries will be stored so that the kernel can read them.
1085 ArmBuildLoaderMemoryList();
1088 // Setup descriptor for the shared heap
1090 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderHeap
,
1091 (ULONG_PTR
)ArmSharedHeap
>> PAGE_SHIFT
,
1092 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap
,
1096 if (Status
!= STATUS_SUCCESS
) return;
1099 // Setup descriptor for the boot stack
1101 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderStack
,
1102 (ULONG_PTR
)&BootStack
>> PAGE_SHIFT
,
1106 if (Status
!= STATUS_SUCCESS
) return;
1109 // Setup descriptor for the boot page tables
1111 Status
= ArmCreateMemoryDescriptor(LoaderMemoryData
,
1112 (ULONG_PTR
)&TranslationTableStart
>> PAGE_SHIFT
,
1113 ((ULONG_PTR
)&TranslationTableEnd
-
1114 (ULONG_PTR
)&TranslationTableStart
) / PAGE_SIZE
,
1117 if (Status
!= STATUS_SUCCESS
) return;
1120 // Setup descriptor for the kernel
1122 Status
= ArmCreateMemoryDescriptor(LoaderSystemCode
,
1123 KernelData
>> PAGE_SHIFT
,
1124 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData
,
1128 if (Status
!= STATUS_SUCCESS
) return;
1131 // Setup descriptor for the HAL
1133 Status
= ArmCreateMemoryDescriptor(LoaderHalCode
,
1134 HalData
>> PAGE_SHIFT
,
1135 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData
,
1139 if (Status
!= STATUS_SUCCESS
) return;
1142 // Setup registry data
1144 ArmLoaderBlock
->RegistryBase
= (PVOID
)((ULONG_PTR
)RegistryData
| KSEG0_BASE
);
1145 ArmLoaderBlock
->RegistryLength
= RegistrySize
;
1148 // Create an MD for it
1150 Status
= ArmCreateMemoryDescriptor(LoaderRegistryData
,
1151 RegistryData
>> PAGE_SHIFT
,
1152 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData
,
1156 if (Status
!= STATUS_SUCCESS
) return;
1159 // TODO: Setup ARC Hardware tree data
1165 ArmNlsDataBlock
= ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK
));
1166 ArmLoaderBlock
->NlsData
= ArmNlsDataBlock
;
1167 ArmLoaderBlock
->NlsData
->AnsiCodePageData
= (PVOID
)(AnsiData
| KSEG0_BASE
);
1168 ArmLoaderBlock
->NlsData
->OemCodePageData
= (PVOID
)(OemData
| KSEG0_BASE
);
1169 ArmLoaderBlock
->NlsData
->UnicodeCodePageData
= (PVOID
)(UnicodeData
| KSEG0_BASE
);
1170 ArmLoaderBlock
->NlsData
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->NlsData
| KSEG0_BASE
);
1173 // Setup ANSI NLS Memory Descriptor
1175 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1176 AnsiData
>> PAGE_SHIFT
,
1177 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData
,
1181 if (Status
!= STATUS_SUCCESS
) return;
1184 // Setup OEM NLS Memory Descriptor
1186 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1187 OemData
>> PAGE_SHIFT
,
1188 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData
,
1192 if (Status
!= STATUS_SUCCESS
) return;
1195 // Setup Unicode NLS Memory Descriptor
1197 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1198 UnicodeData
>> PAGE_SHIFT
,
1199 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData
,
1203 if (Status
!= STATUS_SUCCESS
) return;
1206 // Setup loader entry for the kernel
1208 ArmModuleName
= ArmAllocateFromSharedHeap(64 * sizeof(WCHAR
));
1209 wcscpy(ArmModuleName
, L
"ntoskrnl.exe");
1210 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1211 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1212 LdrEntry
->DllBase
= (PVOID
)KernelBase
;
1213 LdrEntry
->SizeOfImage
= KernelSize
;
1214 LdrEntry
->EntryPoint
= KernelEntryPoint
;
1215 LdrEntry
->LoadCount
= 1;
1216 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1217 RtlInitUnicodeString(&LdrEntry
->FullDllName
, ArmModuleName
);
1218 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, ArmModuleName
);
1219 LdrEntry
->FullDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->FullDllName
.Buffer
| KSEG0_BASE
);
1220 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->BaseDllName
.Buffer
| KSEG0_BASE
);
1221 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1224 // Setup loader entry for the HAL
1226 ArmModuleName
= ArmAllocateFromSharedHeap(64 * sizeof(WCHAR
));
1227 wcscpy(ArmModuleName
, L
"hal.dll");
1228 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1229 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1230 LdrEntry
->DllBase
= (PVOID
)(HalData
| KSEG0_BASE
);
1231 LdrEntry
->SizeOfImage
= HalSize
;
1232 LdrEntry
->EntryPoint
= (PVOID
)RtlImageNtHeader((PVOID
)HalData
)->
1233 OptionalHeader
.AddressOfEntryPoint
;
1234 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)LdrEntry
->EntryPoint
| KSEG0_BASE
);
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 // Build descriptors for the drivers loaded
1246 for (i
= 0; i
< Drivers
; i
++)
1249 // Setup loader entry for the driver
1251 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1252 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1253 LdrEntry
->DllBase
= (PVOID
)(DriverData
[i
] | KSEG0_BASE
);
1254 LdrEntry
->SizeOfImage
= DriverSize
[i
];
1255 LdrEntry
->EntryPoint
= (PVOID
)RtlImageNtHeader((PVOID
)DriverData
[i
])->
1256 OptionalHeader
.AddressOfEntryPoint
;
1257 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)LdrEntry
->EntryPoint
| KSEG0_BASE
);
1258 LdrEntry
->LoadCount
= 1;
1259 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1260 ArmModuleName
= ArmAllocateFromSharedHeap(64 * sizeof(WCHAR
));
1261 RtlZeroMemory(ArmModuleName
, 64 * sizeof(WCHAR
));
1262 LdrEntry
->FullDllName
.Length
= strlen(DriverName
[i
]) * sizeof(WCHAR
);
1263 LdrEntry
->FullDllName
.MaximumLength
= LdrEntry
->FullDllName
.Length
;
1264 LdrEntry
->FullDllName
.Buffer
= ArmModuleName
;
1265 LdrEntry
->BaseDllName
= LdrEntry
->FullDllName
;
1266 while (*DriverName
[i
]) *ArmModuleName
++ = *DriverName
[i
]++;
1267 LdrEntry
->FullDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->FullDllName
.Buffer
| KSEG0_BASE
);
1268 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->BaseDllName
.Buffer
| KSEG0_BASE
);
1269 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1272 // Build a descriptor for the driver
1274 Status
= ArmCreateMemoryDescriptor(LoaderBootDriver
,
1275 DriverData
[i
] >> PAGE_SHIFT
,
1276 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData
[i
],
1280 if (Status
!= STATUS_SUCCESS
) return;
1286 NextEntry
= ArmLoaderBlock
->LoadOrderListHead
.Flink
;
1287 while (NextEntry
!= &ArmLoaderBlock
->LoadOrderListHead
)
1290 // Remember the physical entry
1292 OldEntry
= NextEntry
->Flink
;
1297 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1298 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1303 NextEntry
= OldEntry
;
1307 // Now edit the root itself
1309 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1310 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1313 // Setup extension parameters
1315 ArmExtension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
1316 ArmExtension
->MajorVersion
= 5;
1317 ArmExtension
->MinorVersion
= 2;
1320 // Make a copy of the command line
1322 ArmLoaderBlock
->LoadOptions
= ArmCommandLine
;
1323 strcpy(ArmCommandLine
, reactos_kernel_cmdline
);
1326 // Find the first \, separating the ARC path from NT path
1328 BootPath
= strchr(ArmCommandLine
, '\\');
1329 *BootPath
= ANSI_NULL
;
1332 // Set the ARC Boot Path
1334 strncpy(ArmArcBootPath
, ArmCommandLine
, 63);
1335 ArmLoaderBlock
->ArcBootDeviceName
= (PVOID
)((ULONG_PTR
)ArmArcBootPath
| KSEG0_BASE
);
1338 // The rest of the string is the NT path
1340 HalPath
= strchr(BootPath
+ 1, ' ');
1341 *HalPath
= ANSI_NULL
;
1342 ArmNtBootPath
[0] = '\\';
1343 strncat(ArmNtBootPath
, BootPath
+ 1, 63);
1344 strcat(ArmNtBootPath
,"\\");
1345 ArmLoaderBlock
->NtBootPathName
= (PVOID
)((ULONG_PTR
)ArmNtBootPath
| KSEG0_BASE
);
1348 // Set the HAL paths
1350 strncpy(ArmArcHalPath
, ArmArcBootPath
, 63);
1351 ArmLoaderBlock
->ArcHalDeviceName
= (PVOID
)((ULONG_PTR
)ArmArcHalPath
| KSEG0_BASE
);
1352 strcpy(ArmNtHalPath
, "\\");
1353 ArmLoaderBlock
->NtHalPathName
= (PVOID
)((ULONG_PTR
)ArmNtHalPath
| KSEG0_BASE
);
1356 // Use this new command line
1358 strncpy(ArmLoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
1361 // Parse it and change every slash to a space
1363 BootPath
= ArmLoaderBlock
->LoadOptions
;
1364 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
1367 // Fixup command-line pointer
1369 ArmLoaderBlock
->LoadOptions
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->LoadOptions
| KSEG0_BASE
);
1372 // Setup cache information
1374 CacheReg
= KeArmCacheRegisterGet();
1375 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheSize
= SizeBits
[CacheReg
.DSize
];
1376 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
= LenBits
[CacheReg
.DLength
];
1377 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
<<= 2;
1378 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheSize
= SizeBits
[CacheReg
.ISize
];
1379 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
= LenBits
[CacheReg
.ILength
];
1380 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
<<= 2;
1381 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheSize
=
1382 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheFillSize
=
1383 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheSize
=
1384 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheFillSize
= 0;
1387 // Allocate the Interrupt stack
1389 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupDpcStack
);
1390 ArmLoaderBlock
->u
.Arm
.InterruptStack
= KSEG0_BASE
| (ULONG
)Base
;
1391 ArmLoaderBlock
->u
.Arm
.InterruptStack
+= KERNEL_STACK_SIZE
;
1394 // Build an entry for it
1396 Status
= ArmCreateMemoryDescriptor(LoaderStartupDpcStack
,
1397 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1398 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1401 if (Status
!= STATUS_SUCCESS
) return;
1404 // Allocate the Kernel Boot stack
1406 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupKernelStack
);
1407 ArmLoaderBlock
->KernelStack
= KSEG0_BASE
| (ULONG
)Base
;
1408 ArmLoaderBlock
->KernelStack
+= KERNEL_STACK_SIZE
;
1411 // Build an entry for it
1413 Status
= ArmCreateMemoryDescriptor(LoaderStartupKernelStack
,
1414 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1415 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1418 if (Status
!= STATUS_SUCCESS
) return;
1421 // Allocate the Abort stack
1423 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupPanicStack
);
1424 ArmLoaderBlock
->u
.Arm
.PanicStack
= KSEG0_BASE
| (ULONG
)Base
;
1425 ArmLoaderBlock
->u
.Arm
.PanicStack
+= KERNEL_STACK_SIZE
;
1428 // Build an entry for it
1430 Status
= ArmCreateMemoryDescriptor(LoaderStartupPanicStack
,
1431 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1432 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1435 if (Status
!= STATUS_SUCCESS
) return;
1438 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1440 Base
= MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage
);
1442 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1443 ArmLoaderBlock
->u
.Arm
.PcrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1446 // Build an entry for the KPCR and KUSER_SHARED_DATA
1448 Status
= ArmCreateMemoryDescriptor(LoaderStartupPcrPage
,
1449 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1450 (2 * 1024 * 1024) / PAGE_SIZE
,
1453 if (Status
!= STATUS_SUCCESS
) return;
1456 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1458 Base
= MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage
);
1460 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1461 ArmLoaderBlock
->u
.Arm
.PdrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1464 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1466 Status
= ArmCreateMemoryDescriptor(LoaderStartupPdrPage
,
1467 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1468 (4 * 1024 * 1024) / PAGE_SIZE
,
1471 if (Status
!= STATUS_SUCCESS
) return;
1474 // Set initial PRCB, Thread and Process on the last PDR page
1476 Base
= (PVOID
)((ULONG
)Base
+ 2 * 1024 * 1024);
1477 ArmLoaderBlock
->Prcb
= KSEG0_BASE
| (ULONG
)Base
;
1478 ArmLoaderBlock
->Process
= ArmLoaderBlock
->Prcb
+ sizeof(KPRCB
);
1479 ArmLoaderBlock
->Thread
= ArmLoaderBlock
->Process
+ sizeof(EPROCESS
);
1482 // Check if we're booting from RAM disk
1484 if ((gRamDiskBase
) && (gRamDiskSize
))
1487 // Allocate a descriptor to describe it
1489 Status
= ArmCreateMemoryDescriptor(LoaderXIPRom
,
1490 (ULONG_PTR
)gRamDiskBase
>> PAGE_SHIFT
,
1491 gRamDiskSize
/ PAGE_SIZE
,
1494 if (Status
!= STATUS_SUCCESS
) return;
1500 NextEntry
= ArmLoaderBlock
->MemoryDescriptorListHead
.Flink
;
1501 while (NextEntry
!= &ArmLoaderBlock
->MemoryDescriptorListHead
)
1504 // Remember the physical entry
1506 OldEntry
= NextEntry
->Flink
;
1511 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1512 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1517 NextEntry
= OldEntry
;
1521 // Now edit the root itself
1523 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1524 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1527 // Allocate ARC disk structure
1529 ArcDiskInformation
= ArmAllocateFromSharedHeap(sizeof(ARC_DISK_INFORMATION
));
1530 InitializeListHead(&ArcDiskInformation
->DiskSignatureListHead
);
1531 ArmLoaderBlock
->ArcDiskInformation
= (PVOID
)((ULONG_PTR
)ArcDiskInformation
| KSEG0_BASE
);
1536 MachDiskReadLogicalSectors(0x49, 0ULL, 1, (PVOID
)DISKREADBUFFER
);
1537 Buffer
= (ULONG
*)DISKREADBUFFER
;
1538 Mbr
= (PMASTER_BOOT_RECORD
)DISKREADBUFFER
;
1541 // Calculate the MBR checksum
1543 for (i
= 0; i
< 128; i
++) Checksum
+= Buffer
[i
];
1544 Checksum
= ~Checksum
+ 1;
1547 // Allocate a disk signature and fill it out
1549 ArcDiskSignature
= ArmAllocateFromSharedHeap(sizeof(ARC_DISK_SIGNATURE
));
1550 ArcDiskSignature
->Signature
= Mbr
->Signature
;
1551 ArcDiskSignature
->CheckSum
= Checksum
;
1554 // Allocare a string for the name and fill it out
1556 ArcDiskSignature
->ArcName
= ArmAllocateFromSharedHeap(256);
1557 sprintf(ArcDiskSignature
->ArcName
, "multi(0)disk(0)rdisk(%lu)", ArcDiskCount
++);
1558 ArcDiskSignature
->ArcName
= (PVOID
)((ULONG_PTR
)ArcDiskSignature
->ArcName
| KSEG0_BASE
);
1561 // Insert the descriptor into the list
1563 InsertTailList(&ArcDiskInformation
->DiskSignatureListHead
,
1564 &ArcDiskSignature
->ListEntry
);
1567 // Loop ARC disk list
1569 NextEntry
= ArcDiskInformation
->DiskSignatureListHead
.Flink
;
1570 while (NextEntry
!= &ArcDiskInformation
->DiskSignatureListHead
)
1573 // Remember the physical entry
1575 OldEntry
= NextEntry
->Flink
;
1580 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1581 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1586 NextEntry
= OldEntry
;
1590 // Now edit the root itself
1592 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1593 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1597 FrLdrStartup(IN ULONG Magic
)
1600 // Disable interrupts (already done)
1604 // Set proper CPSR (already done)
1608 // Initialize the page directory
1611 ArmSetupPageDirectory();
1614 // Initialize paging and load NTOSKRNL
1616 ArmSetupPagingAndJump(Magic
);