- Fix FreeLDR for ARM build after some header changes that happen in NTOS.
[reactos.git] / reactos / boot / freeldr / freeldr / arch / arm / loader.c
1 /*
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <freeldr.h>
12 #include <internal/arm/ke.h>
13 #include <internal/arm/mm.h>
14 #include <internal/arm/intrin_i.h>
15
16 #define KERNEL_DESCRIPTOR_PAGE(x) (((ULONG_PTR)x &~ KSEG0_BASE) >> PAGE_SHIFT)
17
18 /* GLOBALS ********************************************************************/
19
20 typedef struct _BIOS_MEMORY_DESCRIPTOR
21 {
22 ULONG BlockBase;
23 ULONG BlockSize;
24 } BIOS_MEMORY_DESCRIPTOR, *PBIOS_MEMORY_DESCRIPTOR;
25
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;
40 PCHAR ArmSharedHeap;
41
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];
51 extern ULONG Drivers;
52 extern ULONG BootStack, TranslationTableStart, TranslationTableEnd;
53
54 ULONG SizeBits[] =
55 {
56 -1, // INVALID
57 -1, // INVALID
58 1 << 12, // 4KB
59 1 << 13, // 8KB
60 1 << 14, // 16KB
61 1 << 15, // 32KB
62 1 << 16, // 64KB
63 1 << 17 // 128KB
64 };
65
66 ULONG AssocBits[] =
67 {
68 -1, // INVALID
69 -1, // INVALID
70 4 // 4-way associative
71 };
72
73 ULONG LenBits[] =
74 {
75 -1, // INVALID
76 -1, // INVALID
77 8 // 8 words per line (32 bytes)
78 };
79
80 //
81 // Where to map the serial port
82 //
83 #define UART_VIRTUAL 0xE0000000
84
85 /* FUNCTIONS ******************************************************************/
86
87 PVOID
88 ArmAllocateFromSharedHeap(IN ULONG Size)
89 {
90 PVOID Buffer;
91
92 //
93 // Allocate from the shared heap
94 //
95 Buffer = &ArmSharedHeap[ArmSharedHeapSize];
96 ArmSharedHeapSize += Size;
97 return Buffer;
98 }
99
100 PMEMORY_ALLOCATION_DESCRIPTOR
101 NTAPI
102 ArmAllocateMemoryDescriptor(VOID)
103 {
104 //
105 // Allocate a descriptor from the heap
106 //
107 return ArmAllocateFromSharedHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
108 }
109
110 VOID
111 NTAPI
112 ArmAddBoardMemoryDescriptor(IN ULONG Address,
113 IN ULONG Size)
114 {
115 PBIOS_MEMORY_DESCRIPTOR BiosBlock = ArmBoardMemoryList;
116
117 //
118 // Loop board DRAM configuration
119 //
120 while (BiosBlock->BlockSize > 0)
121 {
122 /* Check if we've found a matching head block */
123 if (Address + Size == BiosBlock->BlockBase)
124 {
125 /* Simply enlarge and rebase it */
126 BiosBlock->BlockBase = Address;
127 BiosBlock->BlockSize += Size;
128 break;
129 }
130
131 /* Check if we've found a matching tail block */
132 if (Address == (BiosBlock->BlockBase + BiosBlock->BlockSize))
133 {
134 /* Simply enlarge it */
135 BiosBlock->BlockSize += Size;
136 break;
137 }
138
139 /* Nothing suitable found, try the next block */
140 BiosBlock++;
141 }
142
143 /* No usable blocks found, found a free block instead */
144 if (!BiosBlock->BlockSize)
145 {
146 /* Write our data */
147 BiosBlock->BlockBase = Address;
148 BiosBlock->BlockSize = Size;
149
150 /* Create a new block and mark it as the end of the array */
151 BiosBlock++;
152 BiosBlock->BlockBase = BiosBlock->BlockSize = 0L;
153 }
154 }
155
156 VOID
157 NTAPI
158 ArmBuildBoardMemoryMap(VOID)
159 {
160 ULONG BlockBegin, BlockEnd;
161 ULONG j;
162
163 /* Loop the BIOS Memory Map */
164 for (j = 0; j < ArmBoardMemoryMapRangeCount; j++)
165 {
166 /* Get the start and end addresses */
167 BlockBegin = ArmBoardMemoryMap[j].BaseAddrLow;
168 BlockEnd = ArmBoardMemoryMap[j].BaseAddrLow + ArmBoardMemoryMap[j].LengthLow - 1;
169
170 /* Make sure this isn't a > 4GB descriptor */
171 if (!ArmBoardMemoryMap[j].BaseAddrHigh)
172 {
173 /* Make sure we don't overflow */
174 if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
175
176 /* Check if this is free memory */
177 if (ArmBoardMemoryMap[j].Type == 1)
178 {
179 /* Add it to our BIOS descriptors */
180 ArmAddBoardMemoryDescriptor(BlockBegin, BlockEnd - BlockBegin + 1);
181 }
182 }
183 }
184 }
185
186 NTSTATUS
187 NTAPI
188 ArmConfigureArcDescriptor(IN ULONG PageBegin,
189 IN ULONG PageEnd,
190 IN TYPE_OF_MEMORY MemoryType)
191 {
192 ULONG i;
193 ULONG BlockBegin, BlockEnd;
194 MEMORY_TYPE BlockType;
195 BOOLEAN Combined = FALSE;
196
197 /* If this descriptor seems bogus, just return */
198 if (PageEnd <= PageBegin) return STATUS_SUCCESS;
199
200 /* Loop every ARC descriptor, trying to find one we can modify */
201 for (i = 0; i < NumberDescriptors; i++)
202 {
203 /* Get its settings */
204 BlockBegin = MDArray[i].BasePage;
205 BlockEnd = MDArray[i].BasePage + MDArray[i].PageCount;
206 BlockType = MDArray[i].MemoryType;
207
208 /* Check if we can fit inside this block */
209 if (BlockBegin < PageBegin)
210 {
211 /* Check if we are larger then it */
212 if ((BlockEnd > PageBegin) && (BlockEnd <= PageEnd))
213 {
214 /* Make it end where we start */
215 BlockEnd = PageBegin;
216 }
217
218 /* Check if it ends after we do */
219 if (BlockEnd > PageEnd)
220 {
221 /* Make sure we can allocate a descriptor */
222 if (NumberDescriptors == 60) return ENOMEM;
223
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;
228 NumberDescriptors++;
229
230 /* The next block ending is now where we begin */
231 BlockEnd = PageBegin;
232 }
233 }
234 else
235 {
236 /* Check if the blog begins inside our range */
237 if (BlockBegin < PageEnd)
238 {
239 /* Check if it ends before we do */
240 if (BlockEnd < PageEnd)
241 {
242 /* Then make it disappear */
243 BlockEnd = BlockBegin;
244 }
245 else
246 {
247 /* Otherwise make it start where we end */
248 BlockBegin = PageEnd;
249 }
250 }
251 }
252
253 /* Check if the block matches us, and we haven't tried combining yet */
254 if ((BlockType == MemoryType) && !(Combined))
255 {
256 /* Check if it starts where we end */
257 if (BlockBegin == PageEnd)
258 {
259 /* Make it start with us, and combine us */
260 BlockBegin = PageBegin;
261 Combined = TRUE;
262 }
263 else if (BlockEnd == PageBegin)
264 {
265 /* Otherwise, it ends where we begin, combine its ending */
266 BlockEnd = PageEnd;
267 Combined = TRUE;
268 }
269 }
270
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))
274 {
275 /* Then skip it */
276 continue;
277 }
278
279 /* Otherwise, set our new settings for this block */
280 MDArray[i].BasePage = BlockBegin;
281 MDArray[i].PageCount = BlockEnd - BlockBegin;
282
283 /* Check if we are killing the block */
284 if (BlockBegin == BlockEnd)
285 {
286 /* Delete this block and restart the loop properly */
287 NumberDescriptors--;
288 if (i < NumberDescriptors) MDArray[i] = MDArray[NumberDescriptors];
289 i--;
290 }
291 }
292
293 /* If we got here without combining, we need to allocate a new block */
294 if (!(Combined) && (MemoryType < LoaderMaximum))
295 {
296 /* Make sure there's enough descriptors */
297 if (NumberDescriptors == 60) return ENOMEM;
298
299 /* Allocate a new block with our data */
300 MDArray[NumberDescriptors].MemoryType = MemoryType;
301 MDArray[NumberDescriptors].BasePage = PageBegin;
302 MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
303 NumberDescriptors++;
304 }
305
306 /* Changes complete, return success */
307 return STATUS_SUCCESS;
308 }
309
310 NTSTATUS
311 NTAPI
312 ArmBuildOsMemoryMap(VOID)
313 {
314 PBIOS_MEMORY_DESCRIPTOR MdBlock;
315 ULONG BlockStart, BlockEnd, BiasedStart, BiasedEnd, PageStart, PageEnd;
316 NTSTATUS Status = STATUS_SUCCESS;
317
318 /* Loop the BIOS Memory Descriptor List */
319 MdBlock = ArmBoardMemoryList;
320 while (MdBlock->BlockSize)
321 {
322 /* Get the statrt and end addresses */
323 BlockStart = MdBlock->BlockBase;
324 BlockEnd = BlockStart + MdBlock->BlockSize - 1;
325
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;
331
332 /* Get the actual page numbers */
333 PageStart = BlockStart >> PAGE_SHIFT;
334 PageEnd = (BlockEnd + 1) >> PAGE_SHIFT;
335
336 /* Check if we did any alignment */
337 if (BiasedStart)
338 {
339 /* Mark that region as reserved */
340 Status = ArmConfigureArcDescriptor(PageStart - 1,
341 PageStart,
342 MemorySpecialMemory);
343 if (Status != STATUS_SUCCESS) break;
344 }
345
346 /* Check if we did any alignment */
347 if (BiasedEnd)
348 {
349 /* Mark that region as reserved */
350 Status = ArmConfigureArcDescriptor(PageEnd - 1,
351 PageEnd,
352 MemorySpecialMemory);
353 if (Status != STATUS_SUCCESS) break;
354 }
355
356 /* It is, mark the memory a free */
357 Status = ArmConfigureArcDescriptor(PageStart,
358 PageEnd,
359 LoaderFree);
360
361 /* If we failed, break out, otherwise, go to the next BIOS block */
362 if (Status != STATUS_SUCCESS) break;
363 MdBlock++;
364 }
365
366 /* Return error code */
367 return Status;
368 }
369
370 VOID
371 NTAPI
372 ArmInsertMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
373 {
374 PLIST_ENTRY ListHead, PreviousEntry, NextEntry;
375 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor = NULL, NextDescriptor = NULL;
376
377 /* Loop the memory descriptor list */
378 ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
379 PreviousEntry = ListHead;
380 NextEntry = ListHead->Flink;
381 while (NextEntry != ListHead)
382 {
383 /* Get the current descriptor and check if it's below ours */
384 NextDescriptor = CONTAINING_RECORD(NextEntry,
385 MEMORY_ALLOCATION_DESCRIPTOR,
386 ListEntry);
387 if (NewDescriptor->BasePage < NextDescriptor->BasePage) break;
388
389 /* It isn't, save the previous entry and descriptor, and try again */
390 PreviousEntry = NextEntry;
391 Descriptor = NextDescriptor;
392 NextEntry = NextEntry->Flink;
393 }
394
395 /* So we found the right spot to insert. Is this free memory? */
396 if (NewDescriptor->MemoryType != LoaderFree)
397 {
398 /* It isn't, so insert us before the last descriptor */
399 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
400 }
401 else
402 {
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))
409 {
410 /* It's free memory, and we're right after it. Enlarge that block */
411 Descriptor->PageCount += NewDescriptor->PageCount;
412 NewDescriptor = Descriptor;
413 }
414 else
415 {
416 /* Our range scan't be combined, so just insert us separately */
417 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
418 }
419
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))
426 {
427 /* Update our own block */
428 NewDescriptor->PageCount += NextDescriptor->PageCount;
429
430 /* Remove the next block */
431 RemoveEntryList(&NextDescriptor->ListEntry);
432 }
433 }
434 }
435
436 NTSTATUS
437 NTAPI
438 ArmBuildMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
439 IN MEMORY_TYPE MemoryType,
440 IN ULONG BasePage,
441 IN ULONG PageCount)
442 {
443 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor, NextDescriptor = NULL;
444 LONG Delta;
445 TYPE_OF_MEMORY CurrentType;
446 BOOLEAN UseNext;
447
448 /* Check how many pages we'll be consuming */
449 Delta = BasePage - MemoryDescriptor->BasePage;
450 if (!(Delta) && (PageCount == MemoryDescriptor->PageCount))
451 {
452 /* We can simply convert the current descriptor into our new type */
453 MemoryDescriptor->MemoryType = MemoryType;
454 }
455 else
456 {
457 /* Get the current memory type of the descriptor, and reserve it */
458 CurrentType = MemoryDescriptor->MemoryType;
459 MemoryDescriptor->MemoryType = LoaderSpecialMemory;
460
461 /* Check if we'll need another descriptor for what's left of memory */
462 UseNext = ((BasePage != MemoryDescriptor->BasePage) &&
463 (Delta + PageCount != MemoryDescriptor->PageCount));
464
465 /* Get a descriptor */
466 Descriptor = ArmAllocateMemoryDescriptor();
467 if (!Descriptor) return STATUS_INSUFFICIENT_RESOURCES;
468
469 /* Check if we are using another descriptor */
470 if (UseNext)
471 {
472 /* Allocate that one too */
473 NextDescriptor = ArmAllocateMemoryDescriptor();
474 if (!NextDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
475 }
476
477 /* Build the descriptor we got */
478 Descriptor->MemoryType = MemoryType;
479 Descriptor->BasePage = BasePage;
480 Descriptor->PageCount = PageCount;
481
482 /* Check if we're starting at the same place as the old one */
483 if (BasePage == MemoryDescriptor->BasePage)
484 {
485 /* Simply decrease the old descriptor and rebase it */
486 MemoryDescriptor->BasePage += PageCount;
487 MemoryDescriptor->PageCount -= PageCount;
488 MemoryDescriptor->MemoryType = CurrentType;
489 }
490 else if (Delta + PageCount == MemoryDescriptor->PageCount)
491 {
492 /* We finish where the old one did, shorten it */
493 MemoryDescriptor->PageCount -= PageCount;
494 MemoryDescriptor->MemoryType = CurrentType;
495 }
496 else
497 {
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 -
502 (PageCount + Delta);
503
504 /* And cut down the current descriptor */
505 MemoryDescriptor->PageCount = Delta;
506 MemoryDescriptor->MemoryType = CurrentType;
507
508 /* Finally, insert our new free descriptor into the list */
509 ArmInsertMemoryDescriptor(NextDescriptor);
510 }
511
512 /* Insert the descriptor we allocated */
513 ArmInsertMemoryDescriptor(Descriptor);
514 }
515
516 /* Return success */
517 return STATUS_SUCCESS;
518 }
519
520 PMEMORY_ALLOCATION_DESCRIPTOR
521 NTAPI
522 ArmFindMemoryDescriptor(IN ULONG BasePage)
523 {
524 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
525 PLIST_ENTRY NextEntry, ListHead;
526
527 /* Scan the memory descriptor list */
528 ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
529 NextEntry = ListHead->Flink;
530 while (NextEntry != ListHead)
531 {
532 /* Get the current descriptor */
533 MdBlock = CONTAINING_RECORD(NextEntry,
534 MEMORY_ALLOCATION_DESCRIPTOR,
535 ListEntry);
536
537 /* Check if it can contain our memory range */
538 if ((MdBlock->BasePage <= BasePage) &&
539 (MdBlock->BasePage + MdBlock->PageCount > BasePage))
540 {
541 /* It can, break out */
542 break;
543 }
544
545 /* Go to the next descriptor */
546 NextEntry = NextEntry->Flink;
547 }
548
549 /* Return the descriptor we found, if any */
550 return MdBlock;
551 }
552
553 NTSTATUS
554 NTAPI
555 ArmCreateMemoryDescriptor(IN TYPE_OF_MEMORY MemoryType,
556 IN ULONG BasePage,
557 IN ULONG PageCount,
558 IN ULONG Alignment,
559 OUT PULONG ReturnedBase)
560 {
561 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
562 ULONG AlignedBase, AlignedLimit;
563 PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock;
564 ULONG ActiveAlignedBase = 0;
565 PLIST_ENTRY NextEntry, ListHead;
566
567 /* If no information was given, make some assumptions */
568 if (!Alignment) Alignment = 1;
569 if (!PageCount) PageCount = 1;
570
571 /* Start looking for a matching descvriptor */
572 do
573 {
574 /* Calculate the limit of the range */
575 AlignedLimit = PageCount + BasePage;
576
577 /* Find a descriptor that already contains our base address */
578 MdBlock = ArmFindMemoryDescriptor(BasePage);
579 if (MdBlock)
580 {
581 /* If it contains our limit as well, break out early */
582 if ((MdBlock->PageCount + MdBlock->BasePage) >= AlignedLimit) break;
583 }
584
585 /* Loop the memory list */
586 AlignedBase = 0;
587 ActiveMdBlock = NULL;
588 ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
589 NextEntry = ListHead->Flink;
590 while (NextEntry != ListHead)
591 {
592 /* Get the current descriptors */
593 MdBlock = CONTAINING_RECORD(NextEntry,
594 MEMORY_ALLOCATION_DESCRIPTOR,
595 ListEntry);
596
597 /* Align the base address and our limit */
598 AlignedBase = (MdBlock->BasePage + (Alignment - 1)) &~ Alignment;
599 AlignedLimit = MdBlock->PageCount -
600 AlignedBase +
601 MdBlock->BasePage;
602
603 /* Check if this is a free block that can satisfy us */
604 if ((MdBlock->MemoryType == LoaderFree) &&
605 (AlignedLimit <= MdBlock->PageCount) &&
606 (PageCount <= AlignedLimit))
607 {
608 /* It is, stop searching */
609 ActiveMdBlock = MdBlock;
610 ActiveAlignedBase = AlignedBase;
611 break;
612 }
613
614 /* Try the next block */
615 NextEntry = NextEntry->Flink;
616 }
617
618 /* See if we came up with an adequate block */
619 if (ActiveMdBlock)
620 {
621 /* Generate a descriptor in it */
622 *ReturnedBase = AlignedBase;
623 return ArmBuildMemoryDescriptor(ActiveMdBlock,
624 MemoryType,
625 ActiveAlignedBase,
626 PageCount);
627 }
628 } while (TRUE);
629
630 /* We found a matching block, generate a descriptor with it */
631 *ReturnedBase = BasePage;
632 return ArmBuildMemoryDescriptor(MdBlock, MemoryType, BasePage, PageCount);
633 }
634
635 NTSTATUS
636 NTAPI
637 ArmBuildLoaderMemoryList(VOID)
638 {
639 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
640 MEMORY_DESCRIPTOR *Memory;
641 ULONG i;
642
643 /* Loop all BIOS Memory Descriptors */
644 for (i = 0; i < NumberDescriptors; i++)
645 {
646 /* Get the current descriptor */
647 Memory = &MDArray[i];
648
649 /* Allocate an NT Memory Descriptor */
650 Descriptor = ArmAllocateMemoryDescriptor();
651 if (!Descriptor) return ENOMEM;
652
653 /* Copy the memory type */
654 Descriptor->MemoryType = Memory->MemoryType;
655 if (Memory->MemoryType == MemoryFreeContiguous)
656 {
657 /* Convert this to free */
658 Descriptor->MemoryType = LoaderFree;
659 }
660 else if (Memory->MemoryType == MemorySpecialMemory)
661 {
662 /* Convert this to special memory */
663 Descriptor->MemoryType = LoaderSpecialMemory;
664 }
665
666 /* Copy the range data */
667 Descriptor->BasePage = Memory->BasePage;
668 Descriptor->PageCount = Memory->PageCount;
669
670 /* Insert the descriptor */
671 if (Descriptor->PageCount) ArmInsertMemoryDescriptor(Descriptor);
672 }
673
674 /* All went well */
675 return STATUS_SUCCESS;
676 }
677
678 VOID
679 ArmSetupPageDirectory(VOID)
680 {
681 ARM_TTB_REGISTER TtbRegister;
682 ARM_DOMAIN_REGISTER DomainRegister;
683 ARM_PTE Pte;
684 ULONG i, j;
685 PARM_TRANSLATION_TABLE ArmTable;
686 PARM_COARSE_PAGE_TABLE BootTable, KernelTable, FlatMapTable, MasterTable, HyperSpaceTable;
687
688 //
689 // Get the PDEs that we will use
690 //
691 ArmTable = &ArmTranslationTable;
692 BootTable = &BootTranslationTable;
693 KernelTable = &KernelTranslationTable;
694 FlatMapTable = &FlatMapTranslationTable;
695 MasterTable = &MasterTranslationTable;
696 HyperSpaceTable = &HyperSpaceTranslationTable;
697
698 //
699 // Set the master L1 PDE as the TTB
700 //
701 TtbRegister.AsUlong = (ULONG)ArmTable;
702 ASSERT(TtbRegister.Reserved == 0);
703 KeArmTranslationTableRegisterSet(TtbRegister);
704
705 //
706 // Use Domain 0, enforce AP bits (client)
707 //
708 DomainRegister.AsUlong = 0;
709 DomainRegister.Domain0 = ClientDomain;
710 KeArmDomainRegisterSet(DomainRegister);
711
712 //
713 // Set Fault PTEs everywhere
714 //
715 RtlZeroMemory(ArmTable, sizeof(ARM_TRANSLATION_TABLE));
716
717 //
718 // Identity map the first MB of memory
719 //
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;
729
730 //
731 // Map the page in MMIO space that contains the serial port and timers
732 //
733 Pte.L1.Section.BaseAddress = ArmBoardBlock->UartRegisterBase >> PDE_SHIFT;
734 ArmTable->Pte[UART_VIRTUAL >> PDE_SHIFT] = Pte;
735
736 //
737 // Create template PTE for the coarse page table which maps the PTE_BASE
738 //
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;
744
745 //
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.
749 //
750 // To describe a 4MB region, on x86, only requires a page table, which can
751 // be linked from the page table directory.
752 //
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.
757 //
758 // This means we must:
759 //
760 // - Allocate page tables (in physical memory) with 4KB granularity, instead
761 // of 1KB (the other 3KB is unused and invalid).
762 //
763 // - "Skip" the other 3KB in the region, because we can't point to another
764 // coarse page table after just 1KB.
765 //
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).
772 //
773 // We call this region the flat-map area
774 //
775 for (i = (PTE_BASE >> PDE_SHIFT); i < ((PTE_BASE + 0x1000000) >> PDE_SHIFT); i++)
776 {
777 //
778 // Write PTE and update the base address (next MB) for the next one
779 //
780 ArmTable->Pte[i] = Pte;
781 Pte.L1.Coarse.BaseAddress += 4;
782 }
783
784 //
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.
792 //
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.
797 //
798 // Note that for us, this region starts at 0xC1000000, after the flat-map
799 // area.
800 //
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.
804 //
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.
808 //
809 // We'll call this region the master translation area.
810 //
811 Pte.L1.Coarse.BaseAddress = (ULONG)MasterTable >> CPT_SHIFT;
812 ArmTable->Pte[PDE_BASE >> PDE_SHIFT] = Pte;
813
814 //
815 // Now create the template for the hyperspace table which maps 1MB
816 //
817 Pte.L1.Coarse.BaseAddress = (ULONG)HyperSpaceTable >> CPT_SHIFT;
818 ArmTable->Pte[HYPER_SPACE >> PDE_SHIFT] = Pte;
819
820 //
821 // Now create the template for the coarse page tables which map the first 8MB
822 //
823 Pte.L1.Coarse.BaseAddress = (ULONG)BootTable >> CPT_SHIFT;
824
825 //
826 // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
827 // This is where the freeldr boot structures are located, and we need them.
828 //
829 for (i = (KSEG0_BASE >> PDE_SHIFT); i < ((KSEG0_BASE + 0x800000) >> PDE_SHIFT); i++)
830 {
831 //
832 // Write PTE and update the base address (next MB) for the next one
833 //
834 ArmTable->Pte[i] = Pte;
835 Pte.L1.Coarse.BaseAddress += 4;
836 }
837
838 //
839 // Now create the template PTE for the coarse page tables for the next 6MB
840 //
841 Pte.L1.Coarse.BaseAddress = (ULONG)KernelTable >> CPT_SHIFT;
842
843 //
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.
847 //
848 ASSERT(KernelBase == 0x80800000);
849 for (i = (KernelBase >> PDE_SHIFT); i < ((KernelBase + 0x600000) >> PDE_SHIFT); i++)
850 {
851 //
852 // Write PTE and update the base address (next MB) for the next one
853 //
854 ArmTable->Pte[i] = Pte;
855 Pte.L1.Coarse.BaseAddress += 4;
856 }
857
858 //
859 // Now build the template PTE for the pages mapping the first 8MB
860 //
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;
868
869 //
870 // Loop each boot coarse page table (i).
871 // Each PDE describes 1MB. We're mapping an area of 8MB, so 8 times.
872 //
873 for (i = 0; i < 8; i++)
874 {
875 //
876 // Loop and set each the PTE (j).
877 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
878 //
879 for (j = 0; j < (PDE_SIZE / PAGE_SIZE); j++)
880 {
881 //
882 // Write PTE and update the base address (next MB) for the next one
883 //
884 BootTable->Pte[j] = Pte;
885 Pte.L2.Small.BaseAddress++;
886 }
887
888 //
889 // Next iteration
890 //
891 BootTable++;
892 }
893
894 //
895 // Now create the template PTE for the pages mapping the next 6MB
896 //
897 Pte.L2.Small.BaseAddress = (ULONG)KERNEL_BASE_PHYS >> PTE_SHIFT;
898
899 //
900 // Loop each kernel coarse page table (i).
901 // Each PDE describes 1MB. We're mapping an area of 6MB, so 6 times.
902 //
903 for (i = 0; i < 6; i++)
904 {
905 //
906 // Loop and set each the PTE (j).
907 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
908 //
909 for (j = 0; j < (PDE_SIZE / PAGE_SIZE); j++)
910 {
911 //
912 // Write PTE and update the base address (next MB) for the next one
913 //
914 KernelTable->Pte[j] = Pte;
915 Pte.L2.Small.BaseAddress++;
916 }
917
918 //
919 // Next iteration
920 //
921 KernelTable++;
922 }
923
924 //
925 // Now we need to create the PTEs for the addresses which have been mapped
926 // already.
927 //
928 // We have allocated 4 page table directories:
929 //
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
934 //
935 // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
936 // we will require 31 pages.
937 //
938
939 //
940 // For the 0x80000000 region (8MB)
941 //
942 Pte.L2.Small.BaseAddress = (ULONG)&BootTranslationTable >> PTE_SHIFT;
943 FlatMapTable = &(&FlatMapTranslationTable)[0x80000000 >> 28];
944 for (i = 0; i < 8; i++)
945 {
946 //
947 // Point to the page table mapping the next MB
948 //
949 FlatMapTable->Pte[i] = Pte;
950 Pte.L2.Small.BaseAddress++;
951 }
952
953 //
954 // For the 0x80800000 region (6MB)
955 //
956 Pte.L2.Small.BaseAddress = (ULONG)&KernelTranslationTable >> PTE_SHIFT;
957 for (i = 8; i < 14; i++)
958 {
959 //
960 // Point to the page table mapping the next MB
961 //
962 FlatMapTable->Pte[i] = Pte;
963 Pte.L2.Small.BaseAddress++;
964 }
965
966 //
967 // For the 0xC0000000 region (16MB)
968 //
969 Pte.L2.Small.BaseAddress = (ULONG)&FlatMapTranslationTable >> PTE_SHIFT;
970 FlatMapTable = &(&FlatMapTranslationTable)[0xC0000000 >> 28];
971 for (i = 0; i < 16; i++)
972 {
973 //
974 // Point to the page table mapping the next MB
975 //
976 FlatMapTable->Pte[i] = Pte;
977 Pte.L2.Small.BaseAddress++;
978 }
979
980 //
981 // For the 0xC1000000 region (1MB)
982 //
983 Pte.L2.Small.BaseAddress = (ULONG)&MasterTranslationTable >> PTE_SHIFT;
984 FlatMapTable->Pte[16] = Pte;
985
986 //
987 // And finally for the 0xC1100000 region (1MB)
988 //
989 Pte.L2.Small.BaseAddress = (ULONG)&HyperSpaceTranslationTable >> PTE_SHIFT;
990 FlatMapTable->Pte[17] = Pte;
991
992 //
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.
995 //
996 Pte.L2.Small.BaseAddress = (ULONG)&ArmTranslationTable >> PTE_SHIFT;
997 for (i = 0; i < 4; i++)
998 {
999 //
1000 // Point to the page table mapping the next MB
1001 //
1002 MasterTable->Pte[i] = Pte;
1003 Pte.L2.Small.BaseAddress++;
1004 }
1005 }
1006
1007 VOID
1008 ArmSetupPagingAndJump(IN ULONG Magic)
1009 {
1010 ARM_CONTROL_REGISTER ControlRegister;
1011
1012 //
1013 // Enable MMU, DCache and ICache
1014 //
1015 ControlRegister = KeArmControlRegisterGet();
1016 ControlRegister.MmuEnabled = TRUE;
1017 ControlRegister.ICacheEnabled = TRUE;
1018 ControlRegister.DCacheEnabled = TRUE;
1019 KeArmControlRegisterSet(ControlRegister);
1020
1021 //
1022 // Reconfigure UART0
1023 //
1024 ArmBoardBlock->UartRegisterBase = UART_VIRTUAL |
1025 (ArmBoardBlock->UartRegisterBase &
1026 ((1 << PDE_SHIFT) - 1));
1027 TuiPrintf("Mapped serial port to 0x%x\n", ArmBoardBlock->UartRegisterBase);
1028
1029 //
1030 // Jump to Kernel
1031 //
1032 (*KernelEntryPoint)(Magic, (PVOID)((ULONG_PTR)ArmLoaderBlock | KSEG0_BASE));
1033 }
1034
1035 VOID
1036 ArmPrepareForReactOS(IN BOOLEAN Setup)
1037 {
1038 ARM_CACHE_REGISTER CacheReg;
1039 PVOID Base, MemBase;
1040 PCHAR BootPath, HalPath;
1041 NTSTATUS Status;
1042 ULONG Dummy, i;
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;
1049 PULONG Buffer;
1050 PWCHAR ArmModuleName;
1051
1052 //
1053 // Allocate the ARM Shared Heap
1054 //
1055 ArmSharedHeap = MmAllocateMemory(PAGE_SIZE);
1056 ArmSharedHeapSize = 0;
1057 if (!ArmSharedHeap) return;
1058
1059 //
1060 // Allocate the loader block and extension
1061 //
1062 ArmLoaderBlock = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK));
1063 if (!ArmLoaderBlock) return;
1064 ArmExtension = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION));
1065 if (!ArmExtension) return;
1066
1067 //
1068 // Initialize the loader block
1069 //
1070 InitializeListHead(&ArmLoaderBlock->BootDriverListHead);
1071 InitializeListHead(&ArmLoaderBlock->LoadOrderListHead);
1072 InitializeListHead(&ArmLoaderBlock->MemoryDescriptorListHead);
1073
1074 //
1075 // Setup the extension and setup block
1076 //
1077 ArmLoaderBlock->Extension = (PVOID)((ULONG_PTR)ArmExtension | KSEG0_BASE);
1078 ArmLoaderBlock->SetupLdrBlock = NULL;
1079
1080 //
1081 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1082 // BIOS descriptor format -- this needs to be removed later.
1083 //
1084 ArmBuildBoardMemoryMap();
1085
1086 //
1087 // Now basically convert these entries to the ARC format, so that we can
1088 // get a good map of free (usable) memory
1089 //
1090 ArmBuildOsMemoryMap();
1091
1092 //
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.
1097 //
1098 ArmBuildLoaderMemoryList();
1099
1100 //
1101 // Setup descriptor for the shared heap
1102 //
1103 Status = ArmCreateMemoryDescriptor(LoaderOsloaderHeap,
1104 (ULONG_PTR)ArmSharedHeap >> PAGE_SHIFT,
1105 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap,
1106 ArmSharedHeapSize),
1107 0,
1108 &Dummy);
1109 if (Status != STATUS_SUCCESS) return;
1110
1111 //
1112 // Setup descriptor for the boot stack
1113 //
1114 Status = ArmCreateMemoryDescriptor(LoaderOsloaderStack,
1115 (ULONG_PTR)&BootStack >> PAGE_SHIFT,
1116 4,
1117 0,
1118 &Dummy);
1119 if (Status != STATUS_SUCCESS) return;
1120
1121 //
1122 // Setup descriptor for the boot page tables
1123 //
1124 Status = ArmCreateMemoryDescriptor(LoaderMemoryData,
1125 (ULONG_PTR)&TranslationTableStart >> PAGE_SHIFT,
1126 ((ULONG_PTR)&TranslationTableEnd -
1127 (ULONG_PTR)&TranslationTableStart) / PAGE_SIZE,
1128 0,
1129 &Dummy);
1130 if (Status != STATUS_SUCCESS) return;
1131
1132 //
1133 // Setup descriptor for the kernel
1134 //
1135 Status = ArmCreateMemoryDescriptor(LoaderSystemCode,
1136 KernelData >> PAGE_SHIFT,
1137 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData,
1138 KernelSize),
1139 0,
1140 &Dummy);
1141 if (Status != STATUS_SUCCESS) return;
1142
1143 //
1144 // Setup descriptor for the HAL
1145 //
1146 Status = ArmCreateMemoryDescriptor(LoaderHalCode,
1147 HalData >> PAGE_SHIFT,
1148 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData,
1149 HalSize),
1150 0,
1151 &Dummy);
1152 if (Status != STATUS_SUCCESS) return;
1153
1154 //
1155 // Setup registry data
1156 //
1157 ArmLoaderBlock->RegistryBase = (PVOID)((ULONG_PTR)RegistryData | KSEG0_BASE);
1158 ArmLoaderBlock->RegistryLength = RegistrySize;
1159
1160 //
1161 // Create an MD for it
1162 //
1163 Status = ArmCreateMemoryDescriptor(LoaderRegistryData,
1164 RegistryData >> PAGE_SHIFT,
1165 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData,
1166 RegistrySize),
1167 0,
1168 &Dummy);
1169 if (Status != STATUS_SUCCESS) return;
1170
1171 //
1172 // TODO: Setup ARC Hardware tree data
1173 //
1174
1175 //
1176 // Setup NLS data
1177 //
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);
1184
1185 //
1186 // Setup ANSI NLS Memory Descriptor
1187 //
1188 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1189 AnsiData >> PAGE_SHIFT,
1190 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData,
1191 AnsiSize),
1192 0,
1193 &Dummy);
1194 if (Status != STATUS_SUCCESS) return;
1195
1196 //
1197 // Setup OEM NLS Memory Descriptor
1198 //
1199 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1200 OemData >> PAGE_SHIFT,
1201 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData,
1202 OemSize),
1203 0,
1204 &Dummy);
1205 if (Status != STATUS_SUCCESS) return;
1206
1207 //
1208 // Setup Unicode NLS Memory Descriptor
1209 //
1210 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1211 UnicodeData >> PAGE_SHIFT,
1212 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData,
1213 UnicodeSize),
1214 0,
1215 &Dummy);
1216 if (Status != STATUS_SUCCESS) return;
1217
1218 //
1219 // Setup loader entry for the kernel
1220 //
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);
1235
1236 //
1237 // Setup loader entry for the HAL
1238 //
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);
1255
1256 //
1257 // Build descriptors for the drivers loaded
1258 //
1259 for (i = 0; i < Drivers; i++)
1260 {
1261 //
1262 // Setup loader entry for the driver
1263 //
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);
1283
1284 //
1285 // Build a descriptor for the driver
1286 //
1287 Status = ArmCreateMemoryDescriptor(LoaderBootDriver,
1288 DriverData[i] >> PAGE_SHIFT,
1289 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData[i],
1290 DriverSize[i]),
1291 0,
1292 &Dummy);
1293 if (Status != STATUS_SUCCESS) return;
1294 }
1295
1296 //
1297 // Loop driver list
1298 //
1299 NextEntry = ArmLoaderBlock->LoadOrderListHead.Flink;
1300 while (NextEntry != &ArmLoaderBlock->LoadOrderListHead)
1301 {
1302 //
1303 // Remember the physical entry
1304 //
1305 OldEntry = NextEntry->Flink;
1306
1307 //
1308 // Edit the data
1309 //
1310 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1311 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1312
1313 //
1314 // Keep looping
1315 //
1316 NextEntry = OldEntry;
1317 }
1318
1319 //
1320 // Now edit the root itself
1321 //
1322 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1323 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1324
1325 //
1326 // Setup extension parameters
1327 //
1328 ArmExtension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
1329 ArmExtension->MajorVersion = 5;
1330 ArmExtension->MinorVersion = 2;
1331
1332 //
1333 // Make a copy of the command line
1334 //
1335 ArmLoaderBlock->LoadOptions = ArmCommandLine;
1336 strcpy(ArmCommandLine, reactos_kernel_cmdline);
1337
1338 //
1339 // Find the first \, separating the ARC path from NT path
1340 //
1341 BootPath = strchr(ArmCommandLine, '\\');
1342 *BootPath = ANSI_NULL;
1343
1344 //
1345 // Set the ARC Boot Path
1346 //
1347 strncpy(ArmArcBootPath, ArmCommandLine, 63);
1348 ArmLoaderBlock->ArcBootDeviceName = (PVOID)((ULONG_PTR)ArmArcBootPath | KSEG0_BASE);
1349
1350 //
1351 // The rest of the string is the NT path
1352 //
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);
1359
1360 //
1361 // Set the HAL paths
1362 //
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);
1367
1368 //
1369 // Use this new command line
1370 //
1371 strncpy(ArmLoaderBlock->LoadOptions, HalPath + 2, 255);
1372
1373 //
1374 // Parse it and change every slash to a space
1375 //
1376 BootPath = ArmLoaderBlock->LoadOptions;
1377 do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
1378
1379 //
1380 // Fixup command-line pointer
1381 //
1382 ArmLoaderBlock->LoadOptions = (PVOID)((ULONG_PTR)ArmLoaderBlock->LoadOptions | KSEG0_BASE);
1383
1384 //
1385 // Setup cache information
1386 //
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;
1398
1399 //
1400 // Allocate the Interrupt stack
1401 //
1402 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupDpcStack);
1403 ArmLoaderBlock->u.Arm.InterruptStack = KSEG0_BASE | (ULONG)Base;
1404 ArmLoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
1405
1406 //
1407 // Build an entry for it
1408 //
1409 Status = ArmCreateMemoryDescriptor(LoaderStartupDpcStack,
1410 (ULONG_PTR)Base >> PAGE_SHIFT,
1411 KERNEL_STACK_SIZE / PAGE_SIZE,
1412 0,
1413 &Dummy);
1414 if (Status != STATUS_SUCCESS) return;
1415
1416 //
1417 // Allocate the Kernel Boot stack
1418 //
1419 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupKernelStack);
1420 ArmLoaderBlock->KernelStack = KSEG0_BASE | (ULONG)Base;
1421 ArmLoaderBlock->KernelStack += KERNEL_STACK_SIZE;
1422
1423 //
1424 // Build an entry for it
1425 //
1426 Status = ArmCreateMemoryDescriptor(LoaderStartupKernelStack,
1427 (ULONG_PTR)Base >> PAGE_SHIFT,
1428 KERNEL_STACK_SIZE / PAGE_SIZE,
1429 0,
1430 &Dummy);
1431 if (Status != STATUS_SUCCESS) return;
1432
1433 //
1434 // Allocate the Abort stack
1435 //
1436 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupPanicStack);
1437 ArmLoaderBlock->u.Arm.PanicStack = KSEG0_BASE | (ULONG)Base;
1438 ArmLoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
1439
1440 //
1441 // Build an entry for it
1442 //
1443 Status = ArmCreateMemoryDescriptor(LoaderStartupPanicStack,
1444 (ULONG_PTR)Base >> PAGE_SHIFT,
1445 KERNEL_STACK_SIZE / PAGE_SIZE,
1446 0,
1447 &Dummy);
1448 if (Status != STATUS_SUCCESS) return;
1449
1450 //
1451 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1452 //
1453 Base = MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage);
1454 MemBase = Base;
1455 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1456 ArmLoaderBlock->u.Arm.PcrPage = (ULONG)Base >> PDE_SHIFT;
1457
1458 //
1459 // Build an entry for the KPCR and KUSER_SHARED_DATA
1460 //
1461 Status = ArmCreateMemoryDescriptor(LoaderStartupPcrPage,
1462 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1463 (2 * 1024 * 1024) / PAGE_SIZE,
1464 0,
1465 &Dummy);
1466 if (Status != STATUS_SUCCESS) return;
1467
1468 //
1469 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1470 //
1471 Base = MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage);
1472 MemBase = Base;
1473 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1474 ArmLoaderBlock->u.Arm.PdrPage = (ULONG)Base >> PDE_SHIFT;
1475
1476 //
1477 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1478 //
1479 Status = ArmCreateMemoryDescriptor(LoaderStartupPdrPage,
1480 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1481 (4 * 1024 * 1024) / PAGE_SIZE,
1482 0,
1483 &Dummy);
1484 if (Status != STATUS_SUCCESS) return;
1485
1486 //
1487 // Set initial PRCB, Thread and Process on the last PDR page
1488 //
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);
1493
1494 //
1495 // Check if we're booting from RAM disk
1496 //
1497 if ((gRamDiskBase) && (gRamDiskSize))
1498 {
1499 //
1500 // Allocate a descriptor to describe it
1501 //
1502 Status = ArmCreateMemoryDescriptor(LoaderXIPRom,
1503 (ULONG_PTR)gRamDiskBase >> PAGE_SHIFT,
1504 gRamDiskSize / PAGE_SIZE,
1505 0,
1506 &Dummy);
1507 if (Status != STATUS_SUCCESS) return;
1508 }
1509
1510 //
1511 // Loop memory list
1512 //
1513 NextEntry = ArmLoaderBlock->MemoryDescriptorListHead.Flink;
1514 while (NextEntry != &ArmLoaderBlock->MemoryDescriptorListHead)
1515 {
1516 //
1517 // Remember the physical entry
1518 //
1519 OldEntry = NextEntry->Flink;
1520
1521 //
1522 // Edit the data
1523 //
1524 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1525 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1526
1527 //
1528 // Keep looping
1529 //
1530 NextEntry = OldEntry;
1531 }
1532
1533 //
1534 // Now edit the root itself
1535 //
1536 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1537 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1538
1539 //
1540 // Allocate ARC disk structure
1541 //
1542 ArcDiskInformation = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_INFORMATION));
1543 InitializeListHead(&ArcDiskInformation->DiskSignatureListHead);
1544 ArmLoaderBlock->ArcDiskInformation = (PVOID)((ULONG_PTR)ArcDiskInformation | KSEG0_BASE);
1545
1546 //
1547 // Read the MBR
1548 //
1549 MachDiskReadLogicalSectors(0x49, 0ULL, 1, (PVOID)DISKREADBUFFER);
1550 Buffer = (ULONG*)DISKREADBUFFER;
1551 Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
1552
1553 //
1554 // Calculate the MBR checksum
1555 //
1556 for (i = 0; i < 128; i++) Checksum += Buffer[i];
1557 Checksum = ~Checksum + 1;
1558
1559 //
1560 // Allocate a disk signature and fill it out
1561 //
1562 ArcDiskSignature = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_SIGNATURE));
1563 ArcDiskSignature->Signature = Mbr->Signature;
1564 ArcDiskSignature->CheckSum = Checksum;
1565
1566 //
1567 // Allocare a string for the name and fill it out
1568 //
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);
1572
1573 //
1574 // Insert the descriptor into the list
1575 //
1576 InsertTailList(&ArcDiskInformation->DiskSignatureListHead,
1577 &ArcDiskSignature->ListEntry);
1578
1579 //
1580 // Loop ARC disk list
1581 //
1582 NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
1583 while (NextEntry != &ArcDiskInformation->DiskSignatureListHead)
1584 {
1585 //
1586 // Remember the physical entry
1587 //
1588 OldEntry = NextEntry->Flink;
1589
1590 //
1591 // Edit the data
1592 //
1593 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1594 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1595
1596 //
1597 // Keep looping
1598 //
1599 NextEntry = OldEntry;
1600 }
1601
1602 //
1603 // Now edit the root itself
1604 //
1605 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1606 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1607 }
1608
1609 VOID
1610 FrLdrStartup(IN ULONG Magic)
1611 {
1612 //
1613 // Disable interrupts (aleady done)
1614 //
1615
1616 //
1617 // Set proper CPSR (already done)
1618 //
1619
1620 //
1621 // Initialize the page directory
1622 //
1623 ArmSetupPageDirectory();
1624
1625 //
1626 // Initialize paging and load NTOSKRNL
1627 //
1628 ArmSetupPagingAndJump(Magic);
1629 }