2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/freeldr.c
5 * PURPOSE: FreeLDR Bootstrap Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES *****************************************************************/
15 typedef struct _BIOS_MEMORY_DESCRIPTOR
19 } BIOS_MEMORY_DESCRIPTOR
, *PBIOS_MEMORY_DESCRIPTOR
;
21 /* GLOBALS *******************************************************************/
23 /* FreeLDR Memory Data */
24 ULONG_PTR MmFreeLdrFirstKrnlPhysAddr
, MmFreeLdrLastKrnlPhysAddr
;
25 ULONG_PTR MmFreeLdrLastKernelAddress
;
26 ULONG MmFreeLdrMemHigher
;
27 ULONG MmFreeLdrPageDirectoryEnd
;
29 /* FreeLDR Loader Data */
30 PROS_LOADER_PARAMETER_BLOCK KeRosLoaderBlock
;
31 BOOLEAN AcpiTableDetected
;
32 ADDRESS_RANGE KeMemoryMap
[64];
33 ULONG KeMemoryMapRangeCount
;
35 /* NT Loader Module/Descriptor Count */
39 /* NT Loader Data. Eats up about 80KB! */
40 LOADER_PARAMETER_BLOCK BldrLoaderBlock
; // 0x0000
41 LOADER_PARAMETER_EXTENSION BldrExtensionBlock
; // 0x0060
42 CHAR BldrCommandLine
[256]; // 0x00DC
43 CHAR BldrArcBootPath
[64]; // 0x01DC
44 CHAR BldrArcHalPath
[64]; // 0x021C
45 CHAR BldrNtHalPath
[64]; // 0x025C
46 CHAR BldrNtBootPath
[64]; // 0x029C
47 LDR_DATA_TABLE_ENTRY BldrModules
[64]; // 0x02DC
48 MEMORY_ALLOCATION_DESCRIPTOR BldrMemoryDescriptors
[60]; // 0x14DC
49 WCHAR BldrModuleStrings
[64][260]; // 0x19DC
50 WCHAR BldrModuleStringsFull
[64][260]; // 0x9BDC
51 NLS_DATA_BLOCK BldrNlsDataBlock
; // 0x11DDC
52 SETUP_LOADER_BLOCK BldrSetupBlock
; // 0x11DE8
53 ARC_DISK_INFORMATION BldrArcDiskInfo
; // 0x12134
54 CHAR BldrArcNames
[32][256]; // 0x1213C
55 ARC_DISK_SIGNATURE BldrDiskInfo
[32]; // 0x1413C
59 BIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptors
[16] = {{0}};
60 PBIOS_MEMORY_DESCRIPTOR BiosMemoryDescriptorList
= BiosMemoryDescriptors
;
63 ULONG NumberDescriptors
= 0;
64 MEMORY_DESCRIPTOR MDArray
[60] = {{0}};
66 /* FUNCTIONS *****************************************************************/
68 PMEMORY_ALLOCATION_DESCRIPTOR
70 KiRosGetMdFromArray(VOID
)
72 /* Return the next MD from the list, but make sure we don't overflow */
73 if (BldrCurrentMd
> 60) KEBUGCHECK(0);
74 return &BldrMemoryDescriptors
[BldrCurrentMd
++];
79 KiRosAddBiosBlock(ULONG Address
,
82 PBIOS_MEMORY_DESCRIPTOR BiosBlock
= BiosMemoryDescriptorList
;
84 /* Loop our BIOS Memory Descriptor List */
85 while (BiosBlock
->BlockSize
> 0)
87 /* Check if we've found a matching head block */
88 if (Address
+ Size
== BiosBlock
->BlockBase
)
90 /* Simply enlarge and rebase it */
91 BiosBlock
->BlockBase
= Address
;
92 BiosBlock
->BlockSize
+= Size
;
96 /* Check if we've found a matching tail block */
97 if (Address
== (BiosBlock
->BlockBase
+ BiosBlock
->BlockSize
))
99 /* Simply enlarge it */
100 BiosBlock
->BlockSize
+= Size
;
104 /* Nothing suitable found, try the next block */
108 /* No usable blocks found, found a free block instead */
109 if (!BiosBlock
->BlockSize
)
112 BiosBlock
->BlockBase
= Address
;
113 BiosBlock
->BlockSize
= Size
;
115 /* Create a new block and mark it as the end of the array */
117 BiosBlock
->BlockBase
= BiosBlock
->BlockSize
= 0L;
123 KiRosBuildBiosMemoryMap(VOID
)
126 ULONG BlockBegin
, BlockEnd
;
128 /* Loop the BIOS Memory Map */
129 for (j
= 0; j
< KeMemoryMapRangeCount
; j
++)
131 /* Get the start and end addresses */
132 BlockBegin
= KeMemoryMap
[j
].BaseAddrLow
;
133 BlockEnd
= KeMemoryMap
[j
].BaseAddrLow
+ KeMemoryMap
[j
].LengthLow
- 1;
135 /* Make sure this isn't a > 4GB descriptor */
136 if (!KeMemoryMap
[j
].BaseAddrHigh
)
138 /* Make sure we don't overflow */
139 if (BlockEnd
< BlockBegin
) BlockEnd
= 0xFFFFFFFF;
141 /* Check if this is free memory */
142 if (KeMemoryMap
[j
].Type
== 1)
144 /* Add it to our BIOS descriptors */
145 KiRosAddBiosBlock(BlockBegin
, BlockEnd
- BlockBegin
+ 1);
153 KiRosAllocateArcDescriptor(IN ULONG PageBegin
,
155 IN MEMORY_TYPE MemoryType
)
159 /* Loop all our descriptors */
160 for (i
= 0; i
< NumberDescriptors
; i
++)
162 /* Attempt to fing a free block that describes our region */
163 if ((MDArray
[i
].MemoryType
== MemoryFree
) &&
164 (MDArray
[i
].BasePage
<= PageBegin
) &&
165 (MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
> PageBegin
) &&
166 (MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
>= PageEnd
))
173 /* Check if we found no free blocks, and fail if so */
174 if (i
== NumberDescriptors
) return ENOMEM
;
176 /* Check if the block has our base address */
177 if (MDArray
[i
].BasePage
== PageBegin
)
179 /* Check if it also has our ending address */
180 if ((MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
) == PageEnd
)
182 /* Then convert this region into our new memory type */
183 MDArray
[i
].MemoryType
= MemoryType
;
187 /* Otherwise, make sure we have enough descriptors */
188 if (NumberDescriptors
== 60) return ENOMEM
;
190 /* Cut this descriptor short */
191 MDArray
[i
].BasePage
= PageEnd
;
192 MDArray
[i
].PageCount
-= (PageEnd
- PageBegin
);
194 /* And allocate a new descriptor for our memory range */
195 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
196 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
197 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
201 else if ((MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
) == PageEnd
)
203 /* This block has our end address, make sure we have a free block */
204 if (NumberDescriptors
== 60) return ENOMEM
;
206 /* Rebase this descriptor */
207 MDArray
[i
].PageCount
= PageBegin
- MDArray
[i
].BasePage
;
209 /* And allocate a new descriptor for our memory range */
210 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
211 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
212 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
217 /* We'll need two descriptors, make sure they're available */
218 if ((NumberDescriptors
+ 1) >= 60) return ENOMEM
;
220 /* Allocate a free memory descriptor for what follows us */
221 MDArray
[NumberDescriptors
].BasePage
= PageEnd
;
222 MDArray
[NumberDescriptors
].PageCount
= MDArray
[i
].PageCount
-
223 (PageEnd
- MDArray
[i
].BasePage
);
224 MDArray
[NumberDescriptors
].MemoryType
= MemoryFree
;
227 /* Cut down the current free descriptor */
228 MDArray
[i
].PageCount
= PageBegin
- MDArray
[i
].BasePage
;
230 /* Allocate a new memory descriptor for our memory range */
231 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
232 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
233 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
237 /* Everything went well */
238 return STATUS_SUCCESS
;
243 KiRosConfigureArcDescriptor(IN ULONG PageBegin
,
245 IN TYPE_OF_MEMORY MemoryType
)
248 ULONG BlockBegin
, BlockEnd
;
249 MEMORY_TYPE BlockType
;
250 BOOLEAN Combined
= FALSE
;
252 /* If this descriptor seems bogus, just return */
253 if (PageEnd
<= PageBegin
) return STATUS_SUCCESS
;
255 /* Loop every ARC descriptor, trying to find one we can modify */
256 for (i
= 0; i
< NumberDescriptors
; i
++)
258 /* Get its settings */
259 BlockBegin
= MDArray
[i
].BasePage
;
260 BlockEnd
= MDArray
[i
].BasePage
+ MDArray
[i
].PageCount
;
261 BlockType
= MDArray
[i
].MemoryType
;
263 /* Check if we can fit inside this block */
264 if (BlockBegin
< PageBegin
)
266 /* Check if we are larger then it */
267 if ((BlockEnd
> PageBegin
) && (BlockEnd
<= PageEnd
))
269 /* Make it end where we start */
270 BlockEnd
= PageBegin
;
273 /* Check if it ends after we do */
274 if (BlockEnd
> PageEnd
)
276 /* Make sure we can allocate a descriptor */
277 if (NumberDescriptors
== 60) return ENOMEM
;
279 /* Create a descriptor for whatever memory we're not part of */
280 MDArray
[NumberDescriptors
].MemoryType
= BlockType
;
281 MDArray
[NumberDescriptors
].BasePage
= PageEnd
;
282 MDArray
[NumberDescriptors
].PageCount
= BlockEnd
- PageEnd
;
285 /* The next block ending is now where we begin */
286 BlockEnd
= PageBegin
;
291 /* Check if the blog begins inside our range */
292 if (BlockBegin
< PageEnd
)
294 /* Check if it ends before we do */
295 if (BlockEnd
< PageEnd
)
297 /* Then make it disappear */
298 BlockEnd
= BlockBegin
;
302 /* Otherwise make it start where we end */
303 BlockBegin
= PageEnd
;
308 /* Check if the block matches us, and we haven't tried combining yet */
309 if ((BlockType
== MemoryType
) && !(Combined
))
311 /* Check if it starts where we end */
312 if (BlockBegin
== PageEnd
)
314 /* Make it start with us, and combine us */
315 BlockBegin
= PageBegin
;
318 else if (BlockEnd
== PageBegin
)
320 /* Otherwise, it ends where we begin, combine its ending */
326 /* Check the original block data matches with what we came up with */
327 if ((MDArray
[i
].BasePage
== BlockBegin
) &&
328 (MDArray
[i
].PageCount
== BlockEnd
- BlockBegin
))
334 /* Otherwise, set our new settings for this block */
335 MDArray
[i
].BasePage
= BlockBegin
;
336 MDArray
[i
].PageCount
= BlockEnd
- BlockBegin
;
338 /* Check if we are killing the block */
339 if (BlockBegin
== BlockEnd
)
341 /* Delete this block and restart the loop properly */
343 if (i
< NumberDescriptors
) MDArray
[i
] = MDArray
[NumberDescriptors
];
348 /* If we got here without combining, we need to allocate a new block */
349 if (!(Combined
) && (MemoryType
< LoaderMaximum
))
351 /* Make sure there's enough descriptors */
352 if (NumberDescriptors
== 60) return ENOMEM
;
354 /* Allocate a new block with our data */
355 MDArray
[NumberDescriptors
].MemoryType
= MemoryType
;
356 MDArray
[NumberDescriptors
].BasePage
= PageBegin
;
357 MDArray
[NumberDescriptors
].PageCount
= PageEnd
- PageBegin
;
361 /* Changes complete, return success */
362 return STATUS_SUCCESS
;
367 KiRosBuildOsMemoryMap(VOID
)
369 PBIOS_MEMORY_DESCRIPTOR MdBlock
;
370 ULONG BlockStart
, BlockEnd
, BiasedStart
, BiasedEnd
, PageStart
, PageEnd
;
371 NTSTATUS Status
= STATUS_SUCCESS
;
372 ULONG BiosPage
= 0xA0;
374 /* Loop the BIOS Memory Descriptor List */
375 MdBlock
= BiosMemoryDescriptorList
;
376 while (MdBlock
->BlockSize
)
378 /* Get the statrt and end addresses */
379 BlockStart
= MdBlock
->BlockBase
;
380 BlockEnd
= BlockStart
+ MdBlock
->BlockSize
- 1;
382 /* Align them to page boundaries */
383 BiasedStart
= BlockStart
& (PAGE_SIZE
- 1);
384 if (BiasedStart
) BlockStart
= BlockStart
+ PAGE_SIZE
- BiasedStart
;
385 BiasedEnd
= (BlockEnd
+ 1) & (ULONG
)(PAGE_SIZE
- 1);
386 if (BiasedEnd
) BlockEnd
-= BiasedEnd
;
388 /* Get the actual page numbers */
389 PageStart
= BlockStart
>> PAGE_SHIFT
;
390 PageEnd
= (BlockEnd
+ 1) >> PAGE_SHIFT
;
392 /* If we're starting at page 0, then put the BIOS page at the end */
393 if (!PageStart
) BiosPage
= PageEnd
;
395 /* Check if we did any alignment */
398 /* Mark that region as reserved */
399 Status
= KiRosConfigureArcDescriptor(PageStart
- 1,
401 MemorySpecialMemory
);
402 if (Status
!= STATUS_SUCCESS
) break;
405 /* Check if we did any alignment */
408 /* Mark that region as reserved */
409 Status
= KiRosConfigureArcDescriptor(PageEnd
- 1,
411 MemorySpecialMemory
);
412 if (Status
!= STATUS_SUCCESS
) break;
414 /* If the bios page was the last page, use the next one instead */
415 if (BiosPage
== PageEnd
) BiosPage
+= 1;
418 /* Check if the page is below the 16MB Memory hole */
419 if (PageEnd
<= 0xFC0)
421 /* It is, mark the memory a free */
422 Status
= KiRosConfigureArcDescriptor(PageStart
,
426 else if (PageStart
>= 0x1000)
428 /* It's over 16MB, so that memory gets marked as reserve */
429 Status
= KiRosConfigureArcDescriptor(PageStart
,
435 /* Check if it starts below the memory hole */
436 if (PageStart
< 0xFC0)
438 /* Mark that part as free */
439 Status
= KiRosConfigureArcDescriptor(PageStart
,
442 if (Status
!= STATUS_SUCCESS
) break;
444 /* And update the page start for the code below */
448 /* Any code in the memory hole region ends up as reserve */
449 Status
= KiRosConfigureArcDescriptor(PageStart
,
454 /* If we failed, break out, otherwise, go to the next BIOS block */
455 if (Status
!= STATUS_SUCCESS
) break;
459 /* If anything failed until now, return error code */
460 if (Status
!= STATUS_SUCCESS
) return Status
;
462 /* Set the top 16MB region as reserved */
463 Status
= KiRosConfigureArcDescriptor(0xFC0, 0x1000, MemorySpecialMemory
);
464 if (Status
!= STATUS_SUCCESS
) return Status
;
466 /* Setup the BIOS region as reserved */
467 KiRosConfigureArcDescriptor(0xA0, 0x100, LoaderMaximum
);
468 KiRosConfigureArcDescriptor(BiosPage
, 0x100, MemoryFirmwarePermanent
);
470 /* Build an entry for the IVT */
471 Status
= KiRosAllocateArcDescriptor(0, 1, MemoryFirmwarePermanent
);
472 if (Status
!= STATUS_SUCCESS
) return Status
;
474 /* Build an entry for the KPCR and KUSER_SHARED_DATA */
475 Status
= KiRosAllocateArcDescriptor(1, 3, LoaderMemoryData
);
476 if (Status
!= STATUS_SUCCESS
) return Status
;
478 /* Build an entry for the PDE and return the status */
479 Status
= KiRosAllocateArcDescriptor(KeRosLoaderBlock
->
480 PageDirectoryStart
>> PAGE_SHIFT
,
482 PageDirectoryEnd
>> PAGE_SHIFT
,
489 KiRosBuildReservedMemoryMap(VOID
)
492 ULONG BlockBegin
, BlockEnd
, BiasedPage
;
494 /* Loop the BIOS Memory Map */
495 for (j
= 0; j
< KeMemoryMapRangeCount
; j
++)
497 /* Get the start and end addresses */
498 BlockBegin
= KeMemoryMap
[j
].BaseAddrLow
;
499 BlockEnd
= BlockBegin
+ KeMemoryMap
[j
].LengthLow
- 1;
501 /* Make sure it wasn't a > 4GB descriptor */
502 if (!KeMemoryMap
[j
].BaseAddrHigh
)
504 /* Make sure it doesn't overflow */
505 if (BlockEnd
< BlockBegin
) BlockEnd
= 0xFFFFFFFF;
507 /* Check if this was free memory */
508 if (KeMemoryMap
[j
].Type
== 1)
510 /* Get the page-aligned addresses */
511 BiasedPage
= BlockBegin
& (PAGE_SIZE
- 1);
512 BlockBegin
>>= PAGE_SHIFT
;
513 if (BiasedPage
) BlockBegin
++;
514 BlockEnd
= (BlockEnd
>> PAGE_SHIFT
) + 1;
516 /* Check if the block is within the 16MB memory hole */
517 if ((BlockBegin
< 0xFC0) && (BlockEnd
>= 0xFC0))
519 /* Don't allow it to cross this boundary */
523 /* Check if the boundary is across 16MB */
524 if ((BlockEnd
> 0xFFF) && (BlockBegin
<= 0xFFF))
526 /* Don't let it cross */
530 /* Check if the block describes the memory hole */
531 if ((BlockBegin
>= 0xFC0) && (BlockEnd
<= 0xFFF))
533 /* Set this region as temporary */
534 KiRosConfigureArcDescriptor(BlockBegin
,
536 MemoryFirmwareTemporary
);
541 /* Get the page-aligned addresses */
542 BlockBegin
>>= PAGE_SHIFT
;
543 BiasedPage
= (BlockEnd
+ 1) & (PAGE_SIZE
- 1);
544 BlockEnd
>>= PAGE_SHIFT
;
545 if (BiasedPage
) BlockEnd
++;
547 /* Set this memory as reserved */
548 KiRosConfigureArcDescriptor(BlockBegin
,
550 MemorySpecialMemory
);
558 KiRosInsertNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
560 PLIST_ENTRY ListHead
, PreviousEntry
, NextEntry
;
561 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
= NULL
, NextDescriptor
= NULL
;
563 /* Loop the memory descriptor list */
564 ListHead
= &KeLoaderBlock
->MemoryDescriptorListHead
;
565 PreviousEntry
= ListHead
;
566 NextEntry
= ListHead
->Flink
;
567 while (NextEntry
!= ListHead
)
569 /* Get the current descriptor and check if it's below ours */
570 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
571 MEMORY_ALLOCATION_DESCRIPTOR
,
573 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
) break;
575 /* It isn't, save the previous entry and descriptor, and try again */
576 PreviousEntry
= NextEntry
;
577 Descriptor
= NextDescriptor
;
578 NextEntry
= NextEntry
->Flink
;
581 /* So we found the right spot to insert. Is this free memory? */
582 if (NewDescriptor
->MemoryType
!= LoaderFree
)
584 /* It isn't, so insert us before the last descriptor */
585 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
589 /* We're free memory. Check if the entry we found is also free memory */
590 if ((PreviousEntry
!= ListHead
) &&
591 ((Descriptor
->MemoryType
== LoaderFree
) ||
592 (Descriptor
->MemoryType
== LoaderReserve
)) &&
593 ((Descriptor
->BasePage
+ Descriptor
->PageCount
) ==
594 NewDescriptor
->BasePage
))
596 /* It's free memory, and we're right after it. Enlarge that block */
597 Descriptor
->PageCount
+= NewDescriptor
->PageCount
;
598 NewDescriptor
= Descriptor
;
602 /* Our range scan't be combined, so just insert us separately */
603 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
606 /* Check if we merged with an existing free memory block */
607 if ((NextEntry
!= ListHead
) &&
608 ((NextDescriptor
->MemoryType
== LoaderFree
) ||
609 (NextDescriptor
->MemoryType
== LoaderReserve
)) &&
610 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) ==
611 NextDescriptor
->BasePage
))
613 /* Update our own block */
614 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
616 /* Remove the next block */
617 RemoveEntryList(&NextDescriptor
->ListEntry
);
624 KiRosBuildNtDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor
,
625 IN MEMORY_TYPE MemoryType
,
629 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
, NextDescriptor
= NULL
;
631 TYPE_OF_MEMORY CurrentType
;
634 /* Check how many pages we'll be consuming */
635 Delta
= BasePage
- MemoryDescriptor
->BasePage
;
636 if (!(Delta
) && (PageCount
== MemoryDescriptor
->PageCount
))
638 /* We can simply convert the current descriptor into our new type */
639 MemoryDescriptor
->MemoryType
= MemoryType
;
643 /* Get the current memory type of the descriptor, and reserve it */
644 CurrentType
= MemoryDescriptor
->MemoryType
;
645 MemoryDescriptor
->MemoryType
= LoaderSpecialMemory
;
647 /* Check if we'll need another descriptor for what's left of memory */
648 UseNext
= ((BasePage
!= MemoryDescriptor
->BasePage
) &&
649 (Delta
+ PageCount
!= MemoryDescriptor
->PageCount
));
651 /* Get a descriptor */
652 Descriptor
= KiRosGetMdFromArray();
653 if (!Descriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
655 /* Check if we are using another descriptor */
658 /* Allocate that one too */
659 NextDescriptor
= KiRosGetMdFromArray();
660 if (!NextDescriptor
) return STATUS_INSUFFICIENT_RESOURCES
;
663 /* Build the descriptor we got */
664 Descriptor
->MemoryType
= MemoryType
;
665 Descriptor
->BasePage
= BasePage
;
666 Descriptor
->PageCount
= PageCount
;
668 /* Check if we're starting at the same place as the old one */
669 if (BasePage
== MemoryDescriptor
->BasePage
)
671 /* Simply decrease the old descriptor and rebase it */
672 MemoryDescriptor
->BasePage
+= PageCount
;
673 MemoryDescriptor
->PageCount
-= PageCount
;
674 MemoryDescriptor
->MemoryType
= CurrentType
;
676 else if (Delta
+ PageCount
== MemoryDescriptor
->PageCount
)
678 /* We finish where the old one did, shorten it */
679 MemoryDescriptor
->PageCount
-= PageCount
;
680 MemoryDescriptor
->MemoryType
= CurrentType
;
684 /* We're inside the current block, mark our free region */
685 NextDescriptor
->MemoryType
= LoaderFree
;
686 NextDescriptor
->BasePage
= BasePage
+ PageCount
;
687 NextDescriptor
->PageCount
= MemoryDescriptor
->PageCount
-
690 /* And cut down the current descriptor */
691 MemoryDescriptor
->PageCount
= Delta
;
692 MemoryDescriptor
->MemoryType
= CurrentType
;
694 /* Finally, insert our new free descriptor into the list */
695 KiRosInsertNtDescriptor(NextDescriptor
);
698 /* Insert the descriptor we allocated */
699 KiRosInsertNtDescriptor(Descriptor
);
703 return STATUS_SUCCESS
;
706 PMEMORY_ALLOCATION_DESCRIPTOR
708 KiRosFindNtDescriptor(IN ULONG BasePage
)
710 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
= NULL
;
711 PLIST_ENTRY NextEntry
, ListHead
;
713 /* Scan the memory descriptor list */
714 ListHead
= &KeLoaderBlock
->MemoryDescriptorListHead
;
715 NextEntry
= ListHead
->Flink
;
716 while (NextEntry
!= ListHead
)
718 /* Get the current descriptor */
719 MdBlock
= CONTAINING_RECORD(NextEntry
,
720 MEMORY_ALLOCATION_DESCRIPTOR
,
723 /* Check if it can contain our memory range */
724 if ((MdBlock
->BasePage
<= BasePage
) &&
725 (MdBlock
->BasePage
+ MdBlock
->PageCount
> BasePage
))
727 /* It can, break out */
731 /* Go to the next descriptor */
732 NextEntry
= NextEntry
->Flink
;
735 /* Return the descriptor we found, if any */
741 KiRosAllocateNtDescriptor(IN TYPE_OF_MEMORY MemoryType
,
745 OUT PULONG ReturnedBase
)
747 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock
;
748 ULONG AlignedBase
, AlignedLimit
;
749 PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock
;
750 ULONG ActiveAlignedBase
= 0;
751 PLIST_ENTRY NextEntry
, ListHead
;
753 /* If no information was given, make some assumptions */
754 if (!Alignment
) Alignment
= 1;
755 if (!PageCount
) PageCount
= 1;
757 /* Start looking for a matching descvriptor */
760 /* Calculate the limit of the range */
761 AlignedLimit
= PageCount
+ BasePage
;
763 /* Find a descriptor that already contains our base address */
764 MdBlock
= KiRosFindNtDescriptor(BasePage
);
767 /* If it contains our limit as well, break out early */
768 if ((MdBlock
->PageCount
+ MdBlock
->BasePage
) > AlignedLimit
) break;
771 /* Loop the memory list */
772 ActiveMdBlock
= NULL
;
773 ListHead
= &KeLoaderBlock
->MemoryDescriptorListHead
;
774 NextEntry
= ListHead
->Flink
;
775 while (NextEntry
!= ListHead
)
777 /* Get the current descriptors */
778 MdBlock
= CONTAINING_RECORD(NextEntry
,
779 MEMORY_ALLOCATION_DESCRIPTOR
,
782 /* Align the base address and our limit */
783 AlignedBase
= (MdBlock
->BasePage
+ (Alignment
- 1)) &~ Alignment
;
784 AlignedLimit
= MdBlock
->PageCount
-
788 /* Check if this is a free block that can satisfy us */
789 if ((MdBlock
->MemoryType
== LoaderFree
) &&
790 (AlignedLimit
<= MdBlock
->PageCount
) &&
791 (PageCount
<= AlignedLimit
))
793 /* It is, stop searching */
794 ActiveMdBlock
= MdBlock
;
795 ActiveAlignedBase
= AlignedBase
;
799 /* Try the next block */
800 NextEntry
= NextEntry
->Flink
;
803 /* See if we came up with an adequate block */
806 /* Generate a descriptor in it */
807 *ReturnedBase
= AlignedBase
;
808 return KiRosBuildNtDescriptor(ActiveMdBlock
,
815 /* We found a matching block, generate a descriptor with it */
816 *ReturnedBase
= BasePage
;
817 return KiRosBuildNtDescriptor(MdBlock
, MemoryType
, BasePage
, PageCount
);
822 KiRosBuildArcMemoryList(VOID
)
824 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
;
825 MEMORY_DESCRIPTOR
*Memory
;
828 /* Loop all BIOS Memory Descriptors */
829 for (i
= 0; i
< NumberDescriptors
; i
++)
831 /* Get the current descriptor */
832 Memory
= &MDArray
[i
];
834 /* Allocate an NT Memory Descriptor */
835 Descriptor
= KiRosGetMdFromArray();
836 if (!Descriptor
) return ENOMEM
;
838 /* Copy the memory type */
839 Descriptor
->MemoryType
= Memory
->MemoryType
;
840 if (Memory
->MemoryType
== MemoryFreeContiguous
)
842 /* Convert this to free */
843 Descriptor
->MemoryType
= LoaderFree
;
845 else if (Memory
->MemoryType
== MemorySpecialMemory
)
847 /* Convert this to special memory */
848 Descriptor
->MemoryType
= LoaderSpecialMemory
;
851 /* Copy the range data */
852 Descriptor
->BasePage
= Memory
->BasePage
;
853 Descriptor
->PageCount
= Memory
->PageCount
;
855 /* Insert the descriptor */
856 if (Descriptor
->PageCount
) KiRosInsertNtDescriptor(Descriptor
);
860 return STATUS_SUCCESS
;
865 KiRosFrldrLpbToNtLpb(IN PROS_LOADER_PARAMETER_BLOCK RosLoaderBlock
,
866 IN PLOADER_PARAMETER_BLOCK
*NtLoaderBlock
)
868 PLOADER_PARAMETER_BLOCK LoaderBlock
;
869 PLDR_DATA_TABLE_ENTRY LdrEntry
;
870 PLOADER_MODULE RosEntry
;
874 PCHAR BootPath
, HalPath
;
875 CHAR CommandLine
[256];
876 PARC_DISK_SIGNATURE RosDiskInfo
, ArcDiskInfo
;
877 PIMAGE_NT_HEADERS NtHeader
;
878 WCHAR PathToDrivers
[] = L
"\\SystemRoot\\System32\\drivers\\";
879 WCHAR PathToSystem32
[] = L
"\\SystemRoot\\System32\\";
880 CHAR DriverNameLow
[256];
883 /* First get some kernel-loader globals */
884 AcpiTableDetected
= (RosLoaderBlock
->Flags
& MB_FLAGS_ACPI_TABLE
) ? TRUE
: FALSE
;
885 MmFreeLdrMemHigher
= RosLoaderBlock
->MemHigher
;
886 MmFreeLdrPageDirectoryEnd
= RosLoaderBlock
->PageDirectoryEnd
;
887 if (!MmFreeLdrPageDirectoryEnd
) MmFreeLdrPageDirectoryEnd
= 0x40000;
889 /* Set the NT Loader block and initialize it */
890 *NtLoaderBlock
= KeLoaderBlock
= LoaderBlock
= &BldrLoaderBlock
;
891 RtlZeroMemory(LoaderBlock
, sizeof(LOADER_PARAMETER_BLOCK
));
893 /* Set the NLS Data block */
894 LoaderBlock
->NlsData
= &BldrNlsDataBlock
;
896 /* Set the ARC Data block */
897 LoaderBlock
->ArcDiskInformation
= &BldrArcDiskInfo
;
899 /* Assume this is from FreeLDR's SetupLdr */
900 LoaderBlock
->SetupLdrBlock
= &BldrSetupBlock
;
902 /* Setup the list heads */
903 InitializeListHead(&LoaderBlock
->LoadOrderListHead
);
904 InitializeListHead(&LoaderBlock
->MemoryDescriptorListHead
);
905 InitializeListHead(&LoaderBlock
->BootDriverListHead
);
906 InitializeListHead(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
);
908 /* Build the free memory map, which uses BIOS Descriptors */
909 KiRosBuildBiosMemoryMap();
911 /* Build entries for ReactOS memory ranges, which uses ARC Descriptors */
912 KiRosBuildOsMemoryMap();
914 /* Build entries for the reserved map, which uses ARC Descriptors */
915 KiRosBuildReservedMemoryMap();
917 /* Now convert the BIOS and ARC Descriptors into NT Memory Descirptors */
918 KiRosBuildArcMemoryList();
920 /* Loop boot driver list */
921 for (i
= 0; i
< RosLoaderBlock
->ModsCount
; i
++)
923 /* Get the ROS loader entry */
924 RosEntry
= &RosLoaderBlock
->ModsAddr
[i
];
925 DriverName
= (PCHAR
)RosEntry
->String
;
926 ModStart
= (PVOID
)RosEntry
->ModStart
;
927 ModSize
= RosEntry
->ModEnd
- (ULONG_PTR
)ModStart
;
929 /* Check if this is any of the NLS files */
930 if (!_stricmp(DriverName
, "ansi.nls"))
933 ModStart
= RVA(ModStart
, KSEG0_BASE
);
934 LoaderBlock
->NlsData
->AnsiCodePageData
= ModStart
;
936 /* Create an MD for it */
937 KiRosAllocateNtDescriptor(LoaderNlsData
,
938 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
940 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
945 else if (!_stricmp(DriverName
, "oem.nls"))
948 ModStart
= RVA(ModStart
, KSEG0_BASE
);
949 LoaderBlock
->NlsData
->OemCodePageData
= ModStart
;
951 /* Create an MD for it */
952 KiRosAllocateNtDescriptor(LoaderNlsData
,
953 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
955 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
960 else if (!_stricmp(DriverName
, "casemap.nls"))
962 /* Unicode Code page */
963 ModStart
= RVA(ModStart
, KSEG0_BASE
);
964 LoaderBlock
->NlsData
->UnicodeCodePageData
= ModStart
;
966 /* Create an MD for it */
967 KiRosAllocateNtDescriptor(LoaderNlsData
,
968 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
970 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
976 /* Check if this is the SYSTEM hive */
977 if (!(_stricmp(DriverName
, "system")) ||
978 !(_stricmp(DriverName
, "system.hiv")))
980 /* Save registry data */
981 ModStart
= RVA(ModStart
, KSEG0_BASE
);
982 LoaderBlock
->RegistryBase
= ModStart
;
983 LoaderBlock
->RegistryLength
= ModSize
;
985 /* Disable setup mode */
986 LoaderBlock
->SetupLdrBlock
= NULL
;
988 /* Create an MD for it */
989 KiRosAllocateNtDescriptor(LoaderRegistryData
,
990 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
992 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
998 /* Check if this is the HARDWARE hive */
999 if (!(_stricmp(DriverName
, "hardware")) ||
1000 !(_stricmp(DriverName
, "hardware.hiv")))
1002 /* Create an MD for it */
1003 KiRosAllocateNtDescriptor(LoaderRegistryData
,
1004 (ULONG_PTR
)ModStart
>> PAGE_SHIFT
,
1005 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
1011 /* Check if this is the kernel */
1012 if (!(_stricmp(DriverName
, "ntoskrnl.exe")))
1014 /* Create an MD for it */
1015 KiRosAllocateNtDescriptor(LoaderSystemCode
,
1016 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
1018 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
1022 else if (!(_stricmp(DriverName
, "hal.dll")))
1024 /* Create an MD for the HAL */
1025 KiRosAllocateNtDescriptor(LoaderHalCode
,
1026 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
1028 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
1034 /* Create an MD for any driver */
1035 KiRosAllocateNtDescriptor(LoaderBootDriver
,
1036 ((ULONG_PTR
)ModStart
&~ KSEG0_BASE
) >>
1038 (ModSize
+ PAGE_SIZE
- 1)>> PAGE_SHIFT
,
1043 /* Lowercase the drivername so we can check its extension later */
1044 strcpy(DriverNameLow
, DriverName
);
1045 _strlwr(DriverNameLow
);
1047 /* Setup the loader entry */
1048 LdrEntry
= &BldrModules
[i
];
1049 RtlZeroMemory(LdrEntry
, sizeof(LDR_DATA_TABLE_ENTRY
));
1051 /* Convert driver name from ANSI to Unicode */
1052 for (j
= 0; j
< strlen(DriverName
); j
++)
1054 BldrModuleStrings
[i
][j
] = DriverName
[j
];
1057 /* Setup driver name */
1058 RtlInitUnicodeString(&LdrEntry
->BaseDllName
, BldrModuleStrings
[i
]);
1060 /* Construct a correct full name */
1061 BldrModuleStringsFull
[i
][0] = 0;
1062 LdrEntry
->FullDllName
.MaximumLength
= 260 * sizeof(WCHAR
);
1063 LdrEntry
->FullDllName
.Length
= 0;
1064 LdrEntry
->FullDllName
.Buffer
= BldrModuleStringsFull
[i
];
1066 /* Guess the path */
1067 if (strstr(DriverNameLow
, ".dll") || strstr(DriverNameLow
, ".exe"))
1069 UNICODE_STRING TempString
;
1070 RtlInitUnicodeString(&TempString
, PathToSystem32
);
1071 RtlAppendUnicodeStringToString(&LdrEntry
->FullDllName
, &TempString
);
1075 UNICODE_STRING TempString
;
1076 RtlInitUnicodeString(&TempString
, PathToDrivers
);
1077 RtlAppendUnicodeStringToString(&LdrEntry
->FullDllName
, &TempString
);
1080 /* Append base name of the driver */
1081 RtlAppendUnicodeStringToString(&LdrEntry
->FullDllName
, &LdrEntry
->BaseDllName
);
1083 /* Copy data from Freeldr Module Entry */
1084 LdrEntry
->DllBase
= ModStart
;
1085 LdrEntry
->SizeOfImage
= ModSize
;
1087 /* Copy additional data */
1088 NtHeader
= RtlImageNtHeader(ModStart
);
1089 LdrEntry
->EntryPoint
= RVA(ModStart
,
1091 OptionalHeader
.AddressOfEntryPoint
);
1093 /* Initialize other data */
1094 LdrEntry
->LoadCount
= 1;
1095 LdrEntry
->Flags
= LDRP_IMAGE_DLL
|
1096 LDRP_ENTRY_PROCESSED
;
1097 if (RosEntry
->Reserved
) LdrEntry
->Flags
|= LDRP_ENTRY_INSERTED
;
1099 /* Insert it into the loader block */
1100 InsertTailList(&LoaderBlock
->LoadOrderListHead
,
1101 &LdrEntry
->InLoadOrderLinks
);
1104 /* Setup command line */
1105 LoaderBlock
->LoadOptions
= BldrCommandLine
;
1106 strcpy(BldrCommandLine
, RosLoaderBlock
->CommandLine
);
1108 /* Setup the extension block */
1109 LoaderBlock
->Extension
= &BldrExtensionBlock
;
1110 LoaderBlock
->Extension
->Size
= sizeof(LOADER_PARAMETER_EXTENSION
);
1111 LoaderBlock
->Extension
->MajorVersion
= 5;
1112 LoaderBlock
->Extension
->MinorVersion
= 2;
1114 /* FreeLDR hackllocates 1536 static pages for the initial boot images */
1115 LoaderBlock
->Extension
->LoaderPagesSpanned
= 1536 * PAGE_SIZE
;
1117 /* ReactOS always boots the kernel at 0x80800000 (just like NT 5.2) */
1118 LoaderBlock
->Extension
->LoaderPagesSpanned
+= 0x80800000 - KSEG0_BASE
;
1120 /* Now convert to pages */
1121 LoaderBlock
->Extension
->LoaderPagesSpanned
/= PAGE_SIZE
;
1123 /* Now setup the setup block if we have one */
1124 if (LoaderBlock
->SetupLdrBlock
)
1126 /* All we'll setup right now is the flag for text-mode setup */
1127 LoaderBlock
->SetupLdrBlock
->Flags
= 1;
1130 /* Make a copy of the command line */
1131 strcpy(CommandLine
, LoaderBlock
->LoadOptions
);
1133 /* Find the first \, separating the ARC path from NT path */
1134 BootPath
= strchr(CommandLine
, '\\');
1135 *BootPath
= ANSI_NULL
;
1136 strncpy(BldrArcBootPath
, CommandLine
, 63);
1137 LoaderBlock
->ArcBootDeviceName
= BldrArcBootPath
;
1139 /* The rest of the string is the NT path */
1140 HalPath
= strchr(BootPath
+ 1, ' ');
1141 *HalPath
= ANSI_NULL
;
1142 BldrNtBootPath
[0] = '\\';
1143 strncat(BldrNtBootPath
, BootPath
+ 1, 63);
1144 strcat(BldrNtBootPath
,"\\");
1145 LoaderBlock
->NtBootPathName
= BldrNtBootPath
;
1147 /* Set the HAL paths */
1148 strncpy(BldrArcHalPath
, BldrArcBootPath
, 63);
1149 LoaderBlock
->ArcHalDeviceName
= BldrArcHalPath
;
1150 strcpy(BldrNtHalPath
, "\\");
1151 LoaderBlock
->NtHalPathName
= BldrNtHalPath
;
1153 /* Use this new command line */
1154 strncpy(LoaderBlock
->LoadOptions
, HalPath
+ 2, 255);
1156 /* Parse it and change every slash to a space */
1157 BootPath
= LoaderBlock
->LoadOptions
;
1158 do {if (*BootPath
== '/') *BootPath
= ' ';} while (*BootPath
++);
1160 /* Now let's loop ARC disk information */
1161 for (i
= 0; i
< RosLoaderBlock
->DrivesCount
; i
++)
1163 /* Get the ROS loader entry */
1164 RosDiskInfo
= &RosLoaderBlock
->DrivesAddr
[i
];
1166 /* Get the ARC structure */
1167 ArcDiskInfo
= &BldrDiskInfo
[i
];
1169 /* Copy the data over */
1170 ArcDiskInfo
->Signature
= RosDiskInfo
->Signature
;
1171 ArcDiskInfo
->CheckSum
= RosDiskInfo
->CheckSum
;
1173 /* Copy the ARC Name */
1174 strcpy(BldrArcNames
[i
], RosDiskInfo
->ArcName
);
1175 ArcDiskInfo
->ArcName
= BldrArcNames
[i
];
1177 /* Insert into the list */
1178 InsertTailList(&LoaderBlock
->ArcDiskInformation
->DiskSignatureListHead
,
1179 &ArcDiskInfo
->ListEntry
);
1185 KiRosPrepareForSystemStartup(IN ULONG Dummy
,
1186 IN PROS_LOADER_PARAMETER_BLOCK LoaderBlock
)
1188 PLOADER_PARAMETER_BLOCK NtLoaderBlock
;
1190 #if defined(_M_IX86)
1192 PKGDTENTRY TssEntry
;
1194 /* Load the GDT and IDT */
1195 Ke386SetGlobalDescriptorTable(*(PKDESCRIPTOR
)&KiGdtDescriptor
.Limit
);
1196 Ke386SetInterruptDescriptorTable(*(PKDESCRIPTOR
)&KiIdtDescriptor
.Limit
);
1198 /* Initialize the boot TSS */
1200 TssEntry
= &KiBootGdt
[KGDT_TSS
/ sizeof(KGDTENTRY
)];
1201 TssEntry
->HighWord
.Bits
.Type
= I386_TSS
;
1202 TssEntry
->HighWord
.Bits
.Pres
= 1;
1203 TssEntry
->HighWord
.Bits
.Dpl
= 0;
1204 TssEntry
->BaseLow
= (USHORT
)((ULONG_PTR
)Tss
& 0xFFFF);
1205 TssEntry
->HighWord
.Bytes
.BaseMid
= (UCHAR
)((ULONG_PTR
)Tss
>> 16);
1206 TssEntry
->HighWord
.Bytes
.BaseHi
= (UCHAR
)((ULONG_PTR
)Tss
>> 24);
1209 /* Save pointer to ROS Block */
1210 KeRosLoaderBlock
= LoaderBlock
;
1211 MmFreeLdrLastKernelAddress
= PAGE_ROUND_UP(KeRosLoaderBlock
->
1212 ModsAddr
[KeRosLoaderBlock
->
1215 MmFreeLdrFirstKrnlPhysAddr
= KeRosLoaderBlock
->ModsAddr
[0].ModStart
-
1217 MmFreeLdrLastKrnlPhysAddr
= MmFreeLdrLastKernelAddress
- KSEG0_BASE
;
1219 /* Save memory manager data */
1220 KeMemoryMapRangeCount
= 0;
1221 if (LoaderBlock
->Flags
& MB_FLAGS_MMAP_INFO
)
1223 /* We have a memory map from the nice BIOS */
1224 size
= *((PULONG
)(LoaderBlock
->MmapAddr
- sizeof(ULONG
)));
1227 /* Map it until we run out of size */
1228 while (i
< LoaderBlock
->MmapLength
)
1230 /* Copy into the Kernel Memory Map */
1231 memcpy (&KeMemoryMap
[KeMemoryMapRangeCount
],
1232 (PVOID
)(LoaderBlock
->MmapAddr
+ i
),
1233 sizeof(ADDRESS_RANGE
));
1235 /* Increase Memory Map Count */
1236 KeMemoryMapRangeCount
++;
1243 LoaderBlock
->MmapLength
= KeMemoryMapRangeCount
* sizeof(ADDRESS_RANGE
);
1244 LoaderBlock
->MmapAddr
= (ULONG
)KeMemoryMap
;
1248 /* Nothing from BIOS */
1249 LoaderBlock
->MmapLength
= 0;
1250 LoaderBlock
->MmapAddr
= (ULONG
)KeMemoryMap
;
1253 #if defined(_M_IX86)
1254 /* Set up the VDM Data */
1258 /* Convert the loader block */
1259 KiRosFrldrLpbToNtLpb(KeRosLoaderBlock
, &NtLoaderBlock
);
1261 /* Do general System Startup */
1262 KiSystemStartup(NtLoaderBlock
);