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
, 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];
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
, HyperSpaceTable
;
689 // Get the PDEs that we will use
691 ArmTable
= &ArmTranslationTable
;
692 BootTable
= &BootTranslationTable
;
693 KernelTable
= &KernelTranslationTable
;
694 FlatMapTable
= &FlatMapTranslationTable
;
695 MasterTable
= &MasterTranslationTable
;
696 HyperSpaceTable
= &HyperSpaceTranslationTable
;
699 // Set the master L1 PDE as the TTB
701 TtbRegister
.AsUlong
= (ULONG
)ArmTable
;
702 ASSERT(TtbRegister
.Reserved
== 0);
703 KeArmTranslationTableRegisterSet(TtbRegister
);
706 // Use Domain 0, enforce AP bits (client)
708 DomainRegister
.AsUlong
= 0;
709 DomainRegister
.Domain0
= ClientDomain
;
710 KeArmDomainRegisterSet(DomainRegister
);
713 // Set Fault PTEs everywhere
715 RtlZeroMemory(ArmTable
, sizeof(ARM_TRANSLATION_TABLE
));
718 // Identity map the first MB of memory
720 Pte
.L1
.Section
.Type
= SectionPte
;
721 Pte
.L1
.Section
.Buffered
= FALSE
;
722 Pte
.L1
.Section
.Cached
= FALSE
;
723 Pte
.L1
.Section
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
724 Pte
.L1
.Section
.Domain
= Domain0
;
725 Pte
.L1
.Section
.Access
= SupervisorAccess
;
726 Pte
.L1
.Section
.BaseAddress
= 0;
727 Pte
.L1
.Section
.Ignored
= Pte
.L1
.Section
.Ignored1
= 0;
728 ArmTable
->Pte
[0] = Pte
;
731 // Map the page in MMIO space that contains the serial port and timers
733 Pte
.L1
.Section
.BaseAddress
= ArmBoardBlock
->UartRegisterBase
>> PDE_SHIFT
;
734 ArmTable
->Pte
[UART_VIRTUAL
>> PDE_SHIFT
] = Pte
;
737 // Create template PTE for the coarse page table which maps the PTE_BASE
739 Pte
.L1
.Coarse
.Type
= CoarsePte
;
740 Pte
.L1
.Coarse
.Domain
= Domain0
;
741 Pte
.L1
.Coarse
.Reserved
= 1; // ARM926EJ-S manual recommends setting to 1
742 Pte
.L1
.Coarse
.Ignored
= Pte
.L1
.Coarse
.Ignored1
= 0;
743 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)FlatMapTable
>> CPT_SHIFT
;
746 // On x86, there is 4MB of space, starting at 0xC0000000 to 0xC0400000
747 // which contains the mappings for each PTE on the system. 4MB is needed
748 // since for 4GB, there will be 1 million PTEs, each of 4KB.
750 // To describe a 4MB region, on x86, only requires a page table, which can
751 // be linked from the page table directory.
753 // On the other hand, on ARM, we can only describe 1MB regions, so we need
754 // four times less PTE entries to represent a single mapping (an L2 coarse
755 // page table). This is problematic, because this would only take up 1KB of
756 // space, and we can't have a page that small.
758 // This means we must:
760 // - Allocate page tables (in physical memory) with 4KB granularity, instead
761 // of 1KB (the other 3KB is unused and invalid).
763 // - "Skip" the other 3KB in the region, because we can't point to another
764 // coarse page table after just 1KB.
766 // So 0xC0000000 will be mapped to the page table that maps the range of
767 // 0x00000000 to 0x01000000, while 0xC0001000 till be mapped to the page
768 // table that maps the area from 0x01000000 to 0x02000000, and so on. In
769 // total, this will require 4 million entries, and additionally, because of
770 // the padding, since each 256 entries will be 4KB (instead of 1KB), this
771 // means we'll need 16MB (0xC0000000 to 0xC1000000).
773 // We call this region the flat-map area
775 for (i
= (PTE_BASE
>> PDE_SHIFT
); i
< ((PTE_BASE
+ 0x1000000) >> PDE_SHIFT
); i
++)
778 // Write PTE and update the base address (next MB) for the next one
780 ArmTable
->Pte
[i
] = Pte
;
781 Pte
.L1
.Coarse
.BaseAddress
+= 4;
785 // On x86, there is also the region of 0xC0300000 to 0xC03080000 which maps
786 // to the various PDEs on the system. Yes, this overlaps with the above, and
787 // works because of an insidious dark magic (self-mapping the PDE as a PTE).
788 // Unfortunately, this doesn't work on ARM, firstly because the size of a L1
789 // page table is different than from an L2 page table, and secondly, which
790 // is even worse, the format for an L1 page table is different than the one
791 // for an L2 page table -- basically meaning we cannot self-map.
793 // However, we somewhat emulate this behavior on ARM. This will be expensive
794 // since we manually need to keep track of every page directory added and
795 // add an entry in our flat-map region. We also need to keep track of every
796 // change in the TTB, so that we can update the mappings in our PDE region.
798 // Note that for us, this region starts at 0xC1000000, after the flat-map
801 // Finally, to deal with different sizes (1KB page tables, 4KB page size!),
802 // we pad the ARM L2 page tables to make them 4KB, so that each page will
803 // therefore point to an L2 page table.
805 // This region is a lot easier than the first -- an L1 page table is only
806 // 16KB, so to access any index inside it, we just need 4 pages, since each
807 // page is 4KB... Clearly, there's also no need to pad in this case.
809 // We'll call this region the master translation area.
811 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)MasterTable
>> CPT_SHIFT
;
812 ArmTable
->Pte
[PDE_BASE
>> PDE_SHIFT
] = Pte
;
815 // Now create the template for the hyperspace table which maps 1MB
817 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)HyperSpaceTable
>> CPT_SHIFT
;
818 ArmTable
->Pte
[HYPER_SPACE
>> PDE_SHIFT
] = Pte
;
821 // Now create the template for the coarse page tables which map the first 8MB
823 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)BootTable
>> CPT_SHIFT
;
826 // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
827 // This is where the freeldr boot structures are located, and we need them.
829 for (i
= (KSEG0_BASE
>> PDE_SHIFT
); i
< ((KSEG0_BASE
+ 0x800000) >> PDE_SHIFT
); i
++)
832 // Write PTE and update the base address (next MB) for the next one
834 ArmTable
->Pte
[i
] = Pte
;
835 Pte
.L1
.Coarse
.BaseAddress
+= 4;
839 // Now create the template PTE for the coarse page tables for the next 6MB
841 Pte
.L1
.Coarse
.BaseAddress
= (ULONG
)KernelTable
>> CPT_SHIFT
;
844 // Map 0x00800000 - 0x00DFFFFF to 0x80800000 - 0x80DFFFFF
845 // In this way, the KERNEL_PHYS_ADDR (0x800000) becomes 0x80800000
846 // which is the kernel virtual base address, just like on x86.
848 ASSERT(KernelBase
== 0x80800000);
849 for (i
= (KernelBase
>> PDE_SHIFT
); i
< ((KernelBase
+ 0x600000) >> PDE_SHIFT
); i
++)
852 // Write PTE and update the base address (next MB) for the next one
854 ArmTable
->Pte
[i
] = Pte
;
855 Pte
.L1
.Coarse
.BaseAddress
+= 4;
859 // Now build the template PTE for the pages mapping the first 8MB
861 Pte
.L2
.Small
.Type
= SmallPte
;
862 Pte
.L2
.Small
.Buffered
= Pte
.L2
.Small
.Cached
= 0;
863 Pte
.L2
.Small
.Access0
=
864 Pte
.L2
.Small
.Access1
=
865 Pte
.L2
.Small
.Access2
=
866 Pte
.L2
.Small
.Access3
= SupervisorAccess
;
867 Pte
.L2
.Small
.BaseAddress
= 0;
870 // Loop each boot coarse page table (i).
871 // Each PDE describes 1MB. We're mapping an area of 8MB, so 8 times.
873 for (i
= 0; i
< 8; i
++)
876 // Loop and set each the PTE (j).
877 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
879 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
882 // Write PTE and update the base address (next MB) for the next one
884 BootTable
->Pte
[j
] = Pte
;
885 Pte
.L2
.Small
.BaseAddress
++;
895 // Now create the template PTE for the pages mapping the next 6MB
897 Pte
.L2
.Small
.BaseAddress
= (ULONG
)KERNEL_BASE_PHYS
>> PTE_SHIFT
;
900 // Loop each kernel coarse page table (i).
901 // Each PDE describes 1MB. We're mapping an area of 6MB, so 6 times.
903 for (i
= 0; i
< 6; i
++)
906 // Loop and set each the PTE (j).
907 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
909 for (j
= 0; j
< (PDE_SIZE
/ PAGE_SIZE
); j
++)
912 // Write PTE and update the base address (next MB) for the next one
914 KernelTable
->Pte
[j
] = Pte
;
915 Pte
.L2
.Small
.BaseAddress
++;
925 // Now we need to create the PTEs for the addresses which have been mapped
928 // We have allocated 4 page table directories:
930 // - One for the kernel, 6MB
931 // - One for low-memory FreeLDR, 8MB
932 // - One for identity-mapping below 1MB, 1MB
933 // - And finally, one for the flat-map itself, 16MB
935 // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
936 // we will require 31 pages.
940 // For the 0x80000000 region (8MB)
942 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&BootTranslationTable
>> PTE_SHIFT
;
943 FlatMapTable
= &(&FlatMapTranslationTable
)[0x80000000 >> 28];
944 for (i
= 0; i
< 8; i
++)
947 // Point to the page table mapping the next MB
949 FlatMapTable
->Pte
[i
] = Pte
;
950 Pte
.L2
.Small
.BaseAddress
++;
954 // For the 0x80800000 region (6MB)
956 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&KernelTranslationTable
>> PTE_SHIFT
;
957 for (i
= 8; i
< 14; i
++)
960 // Point to the page table mapping the next MB
962 FlatMapTable
->Pte
[i
] = Pte
;
963 Pte
.L2
.Small
.BaseAddress
++;
967 // For the 0xC0000000 region (16MB)
969 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&FlatMapTranslationTable
>> PTE_SHIFT
;
970 FlatMapTable
= &(&FlatMapTranslationTable
)[0xC0000000 >> 28];
971 for (i
= 0; i
< 16; i
++)
974 // Point to the page table mapping the next MB
976 FlatMapTable
->Pte
[i
] = Pte
;
977 Pte
.L2
.Small
.BaseAddress
++;
981 // For the 0xC1000000 region (1MB)
983 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&MasterTranslationTable
>> PTE_SHIFT
;
984 FlatMapTable
->Pte
[16] = Pte
;
987 // And finally for the 0xC1100000 region (1MB)
989 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&HyperSpaceTranslationTable
>> PTE_SHIFT
;
990 FlatMapTable
->Pte
[17] = Pte
;
993 // Now we handle the master translation area for our PDEs. We'll just make
994 // the 4 page tables point to the ARM TTB.
996 Pte
.L2
.Small
.BaseAddress
= (ULONG
)&ArmTranslationTable
>> PTE_SHIFT
;
997 for (i
= 0; i
< 4; i
++)
1000 // Point to the page table mapping the next MB
1002 MasterTable
->Pte
[i
] = Pte
;
1003 Pte
.L2
.Small
.BaseAddress
++;
1008 ArmSetupPagingAndJump(IN ULONG Magic
)
1010 ARM_CONTROL_REGISTER ControlRegister
;
1013 // Enable MMU, DCache and ICache
1015 ControlRegister
= KeArmControlRegisterGet();
1016 ControlRegister
.MmuEnabled
= TRUE
;
1017 ControlRegister
.ICacheEnabled
= TRUE
;
1018 ControlRegister
.DCacheEnabled
= TRUE
;
1019 KeArmControlRegisterSet(ControlRegister
);
1022 // Reconfigure UART0
1024 ArmBoardBlock
->UartRegisterBase
= UART_VIRTUAL
|
1025 (ArmBoardBlock
->UartRegisterBase
&
1026 ((1 << PDE_SHIFT
) - 1));
1027 TuiPrintf("Mapped serial port to 0x%x\n", ArmBoardBlock
->UartRegisterBase
);
1032 (*KernelEntryPoint
)(Magic
, (PVOID
)((ULONG_PTR
)ArmLoaderBlock
| KSEG0_BASE
));
1036 ArmPrepareForReactOS(IN BOOLEAN Setup
)
1038 ARM_CACHE_REGISTER CacheReg
;
1039 PVOID Base
, MemBase
;
1040 PCHAR BootPath
, HalPath
;
1043 PLDR_DATA_TABLE_ENTRY LdrEntry
;
1044 PLIST_ENTRY NextEntry
, OldEntry
;
1045 PARC_DISK_INFORMATION ArcDiskInformation
;
1046 PARC_DISK_SIGNATURE ArcDiskSignature
;
1047 ULONG ArcDiskCount
= 0, Checksum
= 0;
1048 PMASTER_BOOT_RECORD Mbr
;
1050 PWCHAR ArmModuleName
;
1053 // Allocate the ARM Shared Heap
1055 ArmSharedHeap
= MmAllocateMemory(PAGE_SIZE
);
1056 ArmSharedHeapSize
= 0;
1057 if (!ArmSharedHeap
) return;
1060 // Allocate the loader block and extension
1062 ArmLoaderBlock
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK
));
1063 if (!ArmLoaderBlock
) return;
1064 ArmExtension
= ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION
));
1065 if (!ArmExtension
) return;
1068 // Initialize the loader block
1070 InitializeListHead(&ArmLoaderBlock
->BootDriverListHead
);
1071 InitializeListHead(&ArmLoaderBlock
->LoadOrderListHead
);
1072 InitializeListHead(&ArmLoaderBlock
->MemoryDescriptorListHead
);
1075 // Setup the extension and setup block
1077 ArmLoaderBlock
->Extension
= (PVOID
)((ULONG_PTR
)ArmExtension
| KSEG0_BASE
);
1078 ArmLoaderBlock
->SetupLdrBlock
= NULL
;
1081 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1082 // BIOS descriptor format -- this needs to be removed later.
1084 ArmBuildBoardMemoryMap();
1087 // Now basically convert these entries to the ARC format, so that we can
1088 // get a good map of free (usable) memory
1090 ArmBuildOsMemoryMap();
1093 // NT uses an extended ARC format, with slightly different memory types.
1094 // We also want to link the ARC descriptors together into a linked list,
1095 // instead of the array, and allocate the semi-permanent storage in which
1096 // these entries will be stored so that the kernel can read them.
1098 ArmBuildLoaderMemoryList();
1101 // Setup descriptor for the shared heap
1103 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderHeap
,
1104 (ULONG_PTR
)ArmSharedHeap
>> PAGE_SHIFT
,
1105 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap
,
1109 if (Status
!= STATUS_SUCCESS
) return;
1112 // Setup descriptor for the boot stack
1114 Status
= ArmCreateMemoryDescriptor(LoaderOsloaderStack
,
1115 (ULONG_PTR
)&BootStack
>> PAGE_SHIFT
,
1119 if (Status
!= STATUS_SUCCESS
) return;
1122 // Setup descriptor for the boot page tables
1124 Status
= ArmCreateMemoryDescriptor(LoaderMemoryData
,
1125 (ULONG_PTR
)&TranslationTableStart
>> PAGE_SHIFT
,
1126 ((ULONG_PTR
)&TranslationTableEnd
-
1127 (ULONG_PTR
)&TranslationTableStart
) / PAGE_SIZE
,
1130 if (Status
!= STATUS_SUCCESS
) return;
1133 // Setup descriptor for the kernel
1135 Status
= ArmCreateMemoryDescriptor(LoaderSystemCode
,
1136 KernelData
>> PAGE_SHIFT
,
1137 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData
,
1141 if (Status
!= STATUS_SUCCESS
) return;
1144 // Setup descriptor for the HAL
1146 Status
= ArmCreateMemoryDescriptor(LoaderHalCode
,
1147 HalData
>> PAGE_SHIFT
,
1148 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData
,
1152 if (Status
!= STATUS_SUCCESS
) return;
1155 // Setup registry data
1157 ArmLoaderBlock
->RegistryBase
= (PVOID
)((ULONG_PTR
)RegistryData
| KSEG0_BASE
);
1158 ArmLoaderBlock
->RegistryLength
= RegistrySize
;
1161 // Create an MD for it
1163 Status
= ArmCreateMemoryDescriptor(LoaderRegistryData
,
1164 RegistryData
>> PAGE_SHIFT
,
1165 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData
,
1169 if (Status
!= STATUS_SUCCESS
) return;
1172 // TODO: Setup ARC Hardware tree data
1178 ArmNlsDataBlock
= ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK
));
1179 ArmLoaderBlock
->NlsData
= ArmNlsDataBlock
;
1180 ArmLoaderBlock
->NlsData
->AnsiCodePageData
= (PVOID
)(AnsiData
| KSEG0_BASE
);
1181 ArmLoaderBlock
->NlsData
->OemCodePageData
= (PVOID
)(OemData
| KSEG0_BASE
);
1182 ArmLoaderBlock
->NlsData
->UnicodeCodePageData
= (PVOID
)(UnicodeData
| KSEG0_BASE
);
1183 ArmLoaderBlock
->NlsData
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->NlsData
| KSEG0_BASE
);
1186 // Setup ANSI NLS Memory Descriptor
1188 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1189 AnsiData
>> PAGE_SHIFT
,
1190 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData
,
1194 if (Status
!= STATUS_SUCCESS
) return;
1197 // Setup OEM NLS Memory Descriptor
1199 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1200 OemData
>> PAGE_SHIFT
,
1201 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData
,
1205 if (Status
!= STATUS_SUCCESS
) return;
1208 // Setup Unicode NLS Memory Descriptor
1210 Status
= ArmCreateMemoryDescriptor(LoaderNlsData
,
1211 UnicodeData
>> PAGE_SHIFT
,
1212 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData
,
1216 if (Status
!= STATUS_SUCCESS
) return;
1219 // Setup loader entry for the kernel
1221 ArmModuleName
= ArmAllocateFromSharedHeap(64 * sizeof(WCHAR
));
1222 wcscpy(ArmModuleName
, L
"ntoskrnl.exe");
1223 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1224 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1225 LdrEntry
->DllBase
= (PVOID
)KernelBase
;
1226 LdrEntry
->SizeOfImage
= KernelSize
;
1227 LdrEntry
->EntryPoint
= KernelEntryPoint
;
1228 LdrEntry
->LoadCount
= 1;
1229 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1230 RtlInitUnicodeString(&LdrEntry
->FullDllName
, ArmModuleName
);
1231 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, ArmModuleName
);
1232 LdrEntry
->FullDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->FullDllName
.Buffer
| KSEG0_BASE
);
1233 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->BaseDllName
.Buffer
| KSEG0_BASE
);
1234 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1237 // Setup loader entry for the HAL
1239 ArmModuleName
= ArmAllocateFromSharedHeap(64 * sizeof(WCHAR
));
1240 wcscpy(ArmModuleName
, L
"hal.dll");
1241 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1242 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1243 LdrEntry
->DllBase
= (PVOID
)(HalData
| KSEG0_BASE
);
1244 LdrEntry
->SizeOfImage
= HalSize
;
1245 LdrEntry
->EntryPoint
= (PVOID
)RtlImageNtHeader((PVOID
)HalData
)->
1246 OptionalHeader
.AddressOfEntryPoint
;
1247 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)LdrEntry
->EntryPoint
| KSEG0_BASE
);
1248 LdrEntry
->LoadCount
= 1;
1249 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1250 RtlInitUnicodeString(&LdrEntry
->FullDllName
, ArmModuleName
);
1251 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, ArmModuleName
);
1252 LdrEntry
->FullDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->FullDllName
.Buffer
| KSEG0_BASE
);
1253 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->BaseDllName
.Buffer
| KSEG0_BASE
);
1254 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1257 // Build descriptors for the drivers loaded
1259 for (i
= 0; i
< Drivers
; i
++)
1262 // Setup loader entry for the driver
1264 LdrEntry
= ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY
));
1265 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1266 LdrEntry
->DllBase
= (PVOID
)(DriverData
[i
] | KSEG0_BASE
);
1267 LdrEntry
->SizeOfImage
= DriverSize
[i
];
1268 LdrEntry
->EntryPoint
= (PVOID
)RtlImageNtHeader((PVOID
)DriverData
[i
])->
1269 OptionalHeader
.AddressOfEntryPoint
;
1270 LdrEntry
->EntryPoint
= (PVOID
)((ULONG_PTR
)LdrEntry
->EntryPoint
| KSEG0_BASE
);
1271 LdrEntry
->LoadCount
= 1;
1272 LdrEntry
->Flags
= LDRP_IMAGE_DLL
| LDRP_ENTRY_PROCESSED
;
1273 ArmModuleName
= ArmAllocateFromSharedHeap(64 * sizeof(WCHAR
));
1274 RtlZeroMemory(ArmModuleName
, 64 * sizeof(WCHAR
));
1275 LdrEntry
->FullDllName
.Length
= strlen(DriverName
[i
]) * sizeof(WCHAR
);
1276 LdrEntry
->FullDllName
.MaximumLength
= LdrEntry
->FullDllName
.Length
;
1277 LdrEntry
->FullDllName
.Buffer
= ArmModuleName
;
1278 LdrEntry
->BaseDllName
= LdrEntry
->FullDllName
;
1279 while (*DriverName
[i
]) *ArmModuleName
++ = *DriverName
[i
]++;
1280 LdrEntry
->FullDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->FullDllName
.Buffer
| KSEG0_BASE
);
1281 LdrEntry
->BaseDllName
.Buffer
= (PVOID
)((ULONG_PTR
)LdrEntry
->BaseDllName
.Buffer
| KSEG0_BASE
);
1282 InsertTailList(&ArmLoaderBlock
->LoadOrderListHead
, &LdrEntry
->InLoadOrderLinks
);
1285 // Build a descriptor for the driver
1287 Status
= ArmCreateMemoryDescriptor(LoaderBootDriver
,
1288 DriverData
[i
] >> PAGE_SHIFT
,
1289 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData
[i
],
1293 if (Status
!= STATUS_SUCCESS
) return;
1299 NextEntry
= ArmLoaderBlock
->LoadOrderListHead
.Flink
;
1300 while (NextEntry
!= &ArmLoaderBlock
->LoadOrderListHead
)
1303 // Remember the physical entry
1305 OldEntry
= NextEntry
->Flink
;
1310 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1311 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1316 NextEntry
= OldEntry
;
1320 // Now edit the root itself
1322 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1323 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1326 // Setup extension parameters
1328 ArmExtension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
1329 ArmExtension
->MajorVersion
= 5;
1330 ArmExtension
->MinorVersion
= 2;
1333 // Make a copy of the command line
1335 ArmLoaderBlock
->LoadOptions
= ArmCommandLine
;
1336 strcpy(ArmCommandLine
, reactos_kernel_cmdline
);
1339 // Find the first \, separating the ARC path from NT path
1341 BootPath
= strchr(ArmCommandLine
, '\\');
1342 *BootPath
= ANSI_NULL
;
1345 // Set the ARC Boot Path
1347 strncpy(ArmArcBootPath
, ArmCommandLine
, 63);
1348 ArmLoaderBlock
->ArcBootDeviceName
= (PVOID
)((ULONG_PTR
)ArmArcBootPath
| KSEG0_BASE
);
1351 // The rest of the string is the NT path
1353 HalPath
= strchr(BootPath
+ 1, ' ');
1354 *HalPath
= ANSI_NULL
;
1355 ArmNtBootPath
[0] = '\\';
1356 strncat(ArmNtBootPath
, BootPath
+ 1, 63);
1357 strcat(ArmNtBootPath
,"\\");
1358 ArmLoaderBlock
->NtBootPathName
= (PVOID
)((ULONG_PTR
)ArmNtBootPath
| KSEG0_BASE
);
1361 // Set the HAL paths
1363 strncpy(ArmArcHalPath
, ArmArcBootPath
, 63);
1364 ArmLoaderBlock
->ArcHalDeviceName
= (PVOID
)((ULONG_PTR
)ArmArcHalPath
| KSEG0_BASE
);
1365 strcpy(ArmNtHalPath
, "\\");
1366 ArmLoaderBlock
->NtHalPathName
= (PVOID
)((ULONG_PTR
)ArmNtHalPath
| KSEG0_BASE
);
1369 // Use this new command line
1371 strncpy(ArmLoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
1374 // Parse it and change every slash to a space
1376 BootPath
= ArmLoaderBlock
->LoadOptions
;
1377 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
1380 // Fixup command-line pointer
1382 ArmLoaderBlock
->LoadOptions
= (PVOID
)((ULONG_PTR
)ArmLoaderBlock
->LoadOptions
| KSEG0_BASE
);
1385 // Setup cache information
1387 CacheReg
= KeArmCacheRegisterGet();
1388 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheSize
= SizeBits
[CacheReg
.DSize
];
1389 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
= LenBits
[CacheReg
.DLength
];
1390 ArmLoaderBlock
->u
.Arm
.FirstLevelDcacheFillSize
<<= 2;
1391 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheSize
= SizeBits
[CacheReg
.ISize
];
1392 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
= LenBits
[CacheReg
.ILength
];
1393 ArmLoaderBlock
->u
.Arm
.FirstLevelIcacheFillSize
<<= 2;
1394 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheSize
=
1395 ArmLoaderBlock
->u
.Arm
.SecondLevelDcacheFillSize
=
1396 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheSize
=
1397 ArmLoaderBlock
->u
.Arm
.SecondLevelIcacheFillSize
= 0;
1400 // Allocate the Interrupt stack
1402 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupDpcStack
);
1403 ArmLoaderBlock
->u
.Arm
.InterruptStack
= KSEG0_BASE
| (ULONG
)Base
;
1404 ArmLoaderBlock
->u
.Arm
.InterruptStack
+= KERNEL_STACK_SIZE
;
1407 // Build an entry for it
1409 Status
= ArmCreateMemoryDescriptor(LoaderStartupDpcStack
,
1410 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1411 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1414 if (Status
!= STATUS_SUCCESS
) return;
1417 // Allocate the Kernel Boot stack
1419 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupKernelStack
);
1420 ArmLoaderBlock
->KernelStack
= KSEG0_BASE
| (ULONG
)Base
;
1421 ArmLoaderBlock
->KernelStack
+= KERNEL_STACK_SIZE
;
1424 // Build an entry for it
1426 Status
= ArmCreateMemoryDescriptor(LoaderStartupKernelStack
,
1427 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1428 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1431 if (Status
!= STATUS_SUCCESS
) return;
1434 // Allocate the Abort stack
1436 Base
= MmAllocateMemoryWithType(KERNEL_STACK_SIZE
, LoaderStartupPanicStack
);
1437 ArmLoaderBlock
->u
.Arm
.PanicStack
= KSEG0_BASE
| (ULONG
)Base
;
1438 ArmLoaderBlock
->u
.Arm
.PanicStack
+= KERNEL_STACK_SIZE
;
1441 // Build an entry for it
1443 Status
= ArmCreateMemoryDescriptor(LoaderStartupPanicStack
,
1444 (ULONG_PTR
)Base
>> PAGE_SHIFT
,
1445 KERNEL_STACK_SIZE
/ PAGE_SIZE
,
1448 if (Status
!= STATUS_SUCCESS
) return;
1451 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1453 Base
= MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage
);
1455 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1456 ArmLoaderBlock
->u
.Arm
.PcrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1459 // Build an entry for the KPCR and KUSER_SHARED_DATA
1461 Status
= ArmCreateMemoryDescriptor(LoaderStartupPcrPage
,
1462 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1463 (2 * 1024 * 1024) / PAGE_SIZE
,
1466 if (Status
!= STATUS_SUCCESS
) return;
1469 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1471 Base
= MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage
);
1473 Base
= (PVOID
)ROUND_UP(Base
, 1 * 1024 * 1024);
1474 ArmLoaderBlock
->u
.Arm
.PdrPage
= (ULONG
)Base
>> PDE_SHIFT
;
1477 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1479 Status
= ArmCreateMemoryDescriptor(LoaderStartupPdrPage
,
1480 (ULONG_PTR
)MemBase
>> PAGE_SHIFT
,
1481 (4 * 1024 * 1024) / PAGE_SIZE
,
1484 if (Status
!= STATUS_SUCCESS
) return;
1487 // Set initial PRCB, Thread and Process on the last PDR page
1489 Base
= (PVOID
)((ULONG
)Base
+ 2 * 1024 * 1024);
1490 ArmLoaderBlock
->Prcb
= KSEG0_BASE
| (ULONG
)Base
;
1491 ArmLoaderBlock
->Process
= ArmLoaderBlock
->Prcb
+ sizeof(KPRCB
);
1492 ArmLoaderBlock
->Thread
= ArmLoaderBlock
->Process
+ sizeof(EPROCESS
);
1495 // Check if we're booting from RAM disk
1497 if ((gRamDiskBase
) && (gRamDiskSize
))
1500 // Allocate a descriptor to describe it
1502 Status
= ArmCreateMemoryDescriptor(LoaderXIPRom
,
1503 (ULONG_PTR
)gRamDiskBase
>> PAGE_SHIFT
,
1504 gRamDiskSize
/ PAGE_SIZE
,
1507 if (Status
!= STATUS_SUCCESS
) return;
1513 NextEntry
= ArmLoaderBlock
->MemoryDescriptorListHead
.Flink
;
1514 while (NextEntry
!= &ArmLoaderBlock
->MemoryDescriptorListHead
)
1517 // Remember the physical entry
1519 OldEntry
= NextEntry
->Flink
;
1524 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1525 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1530 NextEntry
= OldEntry
;
1534 // Now edit the root itself
1536 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1537 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1540 // Allocate ARC disk structure
1542 ArcDiskInformation
= ArmAllocateFromSharedHeap(sizeof(ARC_DISK_INFORMATION
));
1543 InitializeListHead(&ArcDiskInformation
->DiskSignatureListHead
);
1544 ArmLoaderBlock
->ArcDiskInformation
= (PVOID
)((ULONG_PTR
)ArcDiskInformation
| KSEG0_BASE
);
1549 MachDiskReadLogicalSectors(0x49, 0ULL, 1, (PVOID
)DISKREADBUFFER
);
1550 Buffer
= (ULONG
*)DISKREADBUFFER
;
1551 Mbr
= (PMASTER_BOOT_RECORD
)DISKREADBUFFER
;
1554 // Calculate the MBR checksum
1556 for (i
= 0; i
< 128; i
++) Checksum
+= Buffer
[i
];
1557 Checksum
= ~Checksum
+ 1;
1560 // Allocate a disk signature and fill it out
1562 ArcDiskSignature
= ArmAllocateFromSharedHeap(sizeof(ARC_DISK_SIGNATURE
));
1563 ArcDiskSignature
->Signature
= Mbr
->Signature
;
1564 ArcDiskSignature
->CheckSum
= Checksum
;
1567 // Allocare a string for the name and fill it out
1569 ArcDiskSignature
->ArcName
= ArmAllocateFromSharedHeap(256);
1570 sprintf(ArcDiskSignature
->ArcName
, "multi(0)disk(0)rdisk(%lu)", ArcDiskCount
++);
1571 ArcDiskSignature
->ArcName
= (PVOID
)((ULONG_PTR
)ArcDiskSignature
->ArcName
| KSEG0_BASE
);
1574 // Insert the descriptor into the list
1576 InsertTailList(&ArcDiskInformation
->DiskSignatureListHead
,
1577 &ArcDiskSignature
->ListEntry
);
1580 // Loop ARC disk list
1582 NextEntry
= ArcDiskInformation
->DiskSignatureListHead
.Flink
;
1583 while (NextEntry
!= &ArcDiskInformation
->DiskSignatureListHead
)
1586 // Remember the physical entry
1588 OldEntry
= NextEntry
->Flink
;
1593 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1594 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1599 NextEntry
= OldEntry
;
1603 // Now edit the root itself
1605 NextEntry
->Flink
= (PVOID
)((ULONG_PTR
)NextEntry
->Flink
| KSEG0_BASE
);
1606 NextEntry
->Blink
= (PVOID
)((ULONG_PTR
)NextEntry
->Blink
| KSEG0_BASE
);
1610 FrLdrStartup(IN ULONG Magic
)
1613 // Disable interrupts (aleady done)
1617 // Set proper CPSR (already done)
1621 // Initialize the page directory
1623 ArmSetupPageDirectory();
1626 // Initialize paging and load NTOSKRNL
1628 ArmSetupPagingAndJump(Magic
);