ee7402df88fd7c13bcad5b7b632e3609cf790533
[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;
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;
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
697 //
698 // Set the master L1 PDE as the TTB
699 //
700 TtbRegister.AsUlong = (ULONG)ArmTable;
701 ASSERT(TtbRegister.Reserved == 0);
702 KeArmTranslationTableRegisterSet(TtbRegister);
703
704 //
705 // Use Domain 0, enforce AP bits (client)
706 //
707 DomainRegister.AsUlong = 0;
708 DomainRegister.Domain0 = ClientDomain;
709 KeArmDomainRegisterSet(DomainRegister);
710
711 //
712 // Set Fault PTEs everywhere
713 //
714 RtlZeroMemory(ArmTable, sizeof(ARM_TRANSLATION_TABLE));
715
716 //
717 // Identity map the first MB of memory
718 //
719 Pte.L1.Section.Type = SectionPte;
720 Pte.L1.Section.Buffered = FALSE;
721 Pte.L1.Section.Cached = FALSE;
722 Pte.L1.Section.Reserved = 1; // ARM926EJ-S manual recommends setting to 1
723 Pte.L1.Section.Domain = Domain0;
724 Pte.L1.Section.Access = SupervisorAccess;
725 Pte.L1.Section.BaseAddress = 0;
726 Pte.L1.Section.Ignored = Pte.L1.Section.Ignored1 = 0;
727 ArmTable->Pte[0] = Pte;
728
729 //
730 // Map the page in MMIO space that contains the serial port and timers
731 //
732 Pte.L1.Section.BaseAddress = ArmBoardBlock->UartRegisterBase >> PDE_SHIFT;
733 ArmTable->Pte[UART_VIRTUAL >> PDE_SHIFT] = Pte;
734
735 //
736 // Create template PTE for the coarse page table which maps the PTE_BASE
737 //
738 Pte.L1.Coarse.Type = CoarsePte;
739 Pte.L1.Coarse.Domain = Domain0;
740 Pte.L1.Coarse.Reserved = 1; // ARM926EJ-S manual recommends setting to 1
741 Pte.L1.Coarse.Ignored = Pte.L1.Coarse.Ignored1 = 0;
742 Pte.L1.Coarse.BaseAddress = (ULONG)FlatMapTable >> CPT_SHIFT;
743
744 //
745 // On x86, there is 4MB of space, starting at 0xC0000000 to 0xC0400000
746 // which contains the mappings for each PTE on the system. 4MB is needed
747 // since for 4GB, there will be 1 million PTEs, each of 4KB.
748 //
749 // To describe a 4MB region, on x86, only requires a page table, which can
750 // be linked from the page table directory.
751 //
752 // On the other hand, on ARM, we can only describe 1MB regions, so we need
753 // four times less PTE entries to represent a single mapping (an L2 coarse
754 // page table). This is problematic, because this would only take up 1KB of
755 // space, and we can't have a page that small.
756 //
757 // This means we must:
758 //
759 // - Allocate page tables (in physical memory) with 4KB granularity, instead
760 // of 1KB (the other 3KB is unused and invalid).
761 //
762 // - "Skip" the other 3KB in the region, because we can't point to another
763 // coarse page table after just 1KB.
764 //
765 // So 0xC0000000 will be mapped to the page table that maps the range of
766 // 0x00000000 to 0x01000000, while 0xC0001000 till be mapped to the page
767 // table that maps the area from 0x01000000 to 0x02000000, and so on. In
768 // total, this will require 4 million entries, and additionally, because of
769 // the padding, since each 256 entries will be 4KB (instead of 1KB), this
770 // means we'll need 16MB (0xC0000000 to 0xC1000000).
771 //
772 // We call this region the flat-map area
773 //
774 for (i = (PTE_BASE >> PDE_SHIFT); i < ((PTE_BASE + 0x1000000) >> PDE_SHIFT); i++)
775 {
776 //
777 // Write PTE and update the base address (next MB) for the next one
778 //
779 ArmTable->Pte[i] = Pte;
780 Pte.L1.Coarse.BaseAddress += 4;
781 }
782
783 //
784 // On x86, there is also the region of 0xC0300000 to 0xC03080000 which maps
785 // to the various PDEs on the system. Yes, this overlaps with the above, and
786 // works because of an insidious dark magic (self-mapping the PDE as a PTE).
787 // Unfortunately, this doesn't work on ARM, firstly because the size of a L1
788 // page table is different than from an L2 page table, and secondly, which
789 // is even worse, the format for an L1 page table is different than the one
790 // for an L2 page table -- basically meaning we cannot self-map.
791 //
792 // However, we somewhat emulate this behavior on ARM. This will be expensive
793 // since we manually need to keep track of every page directory added and
794 // add an entry in our flat-map region. We also need to keep track of every
795 // change in the TTB, so that we can update the mappings in our PDE region.
796 //
797 // Note that for us, this region starts at 0xC1000000, after the flat-map
798 // area.
799 //
800 // Finally, to deal with different sizes (1KB page tables, 4KB page size!),
801 // we pad the ARM L2 page tables to make them 4KB, so that each page will
802 // therefore point to an L2 page table.
803 //
804 // This region is a lot easier than the first -- an L1 page table is only
805 // 16KB, so to access any index inside it, we just need 4 pages, since each
806 // page is 4KB... Clearly, there's also no need to pad in this case.
807 //
808 // We'll call this region the master translation area.
809 //
810 Pte.L1.Coarse.BaseAddress = (ULONG)MasterTable >> CPT_SHIFT;
811 ArmTable->Pte[PDE_BASE >> PDE_SHIFT] = Pte;
812
813 //
814 // Now create the template for the coarse page tables which map the first 8MB
815 //
816 Pte.L1.Coarse.BaseAddress = (ULONG)BootTable >> CPT_SHIFT;
817
818 //
819 // Map 0x00000000 - 0x007FFFFF to 0x80000000 - 0x807FFFFF.
820 // This is where the freeldr boot structures are located, and we need them.
821 //
822 for (i = (KSEG0_BASE >> PDE_SHIFT); i < ((KSEG0_BASE + 0x800000) >> PDE_SHIFT); i++)
823 {
824 //
825 // Write PTE and update the base address (next MB) for the next one
826 //
827 ArmTable->Pte[i] = Pte;
828 Pte.L1.Coarse.BaseAddress += 4;
829 }
830
831 //
832 // Now create the template PTE for the coarse page tables for the next 6MB
833 //
834 Pte.L1.Coarse.BaseAddress = (ULONG)KernelTable >> CPT_SHIFT;
835
836 //
837 // Map 0x00800000 - 0x00DFFFFF to 0x80800000 - 0x80DFFFFF
838 // In this way, the KERNEL_PHYS_ADDR (0x800000) becomes 0x80800000
839 // which is the kernel virtual base address, just like on x86.
840 //
841 ASSERT(KernelBase == 0x80800000);
842 for (i = (KernelBase >> PDE_SHIFT); i < ((KernelBase + 0x600000) >> PDE_SHIFT); i++)
843 {
844 //
845 // Write PTE and update the base address (next MB) for the next one
846 //
847 ArmTable->Pte[i] = Pte;
848 Pte.L1.Coarse.BaseAddress += 4;
849 }
850
851 //
852 // Now build the template PTE for the pages mapping the first 8MB
853 //
854 Pte.L2.Small.Type = SmallPte;
855 Pte.L2.Small.Buffered = Pte.L2.Small.Cached = 0;
856 Pte.L2.Small.Access0 =
857 Pte.L2.Small.Access1 =
858 Pte.L2.Small.Access2 =
859 Pte.L2.Small.Access3 = SupervisorAccess;
860 Pte.L2.Small.BaseAddress = 0;
861
862 //
863 // Loop each boot coarse page table (i).
864 // Each PDE describes 1MB. We're mapping an area of 8MB, so 8 times.
865 //
866 for (i = 0; i < 8; i++)
867 {
868 //
869 // Loop and set each the PTE (j).
870 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
871 //
872 for (j = 0; j < (PDE_SIZE / PAGE_SIZE); j++)
873 {
874 //
875 // Write PTE and update the base address (next MB) for the next one
876 //
877 BootTable->Pte[j] = Pte;
878 Pte.L2.Small.BaseAddress++;
879 }
880
881 //
882 // Next iteration
883 //
884 BootTable++;
885 }
886
887 //
888 // Now create the template PTE for the pages mapping the next 6MB
889 //
890 Pte.L2.Small.BaseAddress = (ULONG)KERNEL_BASE_PHYS >> PTE_SHIFT;
891
892 //
893 // Loop each kernel coarse page table (i).
894 // Each PDE describes 1MB. We're mapping an area of 6MB, so 6 times.
895 //
896 for (i = 0; i < 6; i++)
897 {
898 //
899 // Loop and set each the PTE (j).
900 // Each PTE describes 4KB. We're mapping an area of 1MB, so 256 times.
901 //
902 for (j = 0; j < (PDE_SIZE / PAGE_SIZE); j++)
903 {
904 //
905 // Write PTE and update the base address (next MB) for the next one
906 //
907 KernelTable->Pte[j] = Pte;
908 Pte.L2.Small.BaseAddress++;
909 }
910
911 //
912 // Next iteration
913 //
914 KernelTable++;
915 }
916
917 //
918 // Now we need to create the PTEs for the addresses which have been mapped
919 // already.
920 //
921 // We have allocated 4 page table directories:
922 //
923 // - One for the kernel, 6MB
924 // - One for low-memory FreeLDR, 8MB
925 // - One for identity-mapping below 1MB, 1MB
926 // - And finally, one for the flat-map itself, 16MB
927 //
928 // - Each MB mapped is a 1KB table, which we'll use a page to reference, so
929 // we will require 31 pages.
930 //
931
932 //
933 // For the 0x80000000 region (8MB)
934 //
935 Pte.L2.Small.BaseAddress = (ULONG)&BootTranslationTable >> PTE_SHIFT;
936 FlatMapTable = &(&FlatMapTranslationTable)[0x80000000 >> 28];
937 for (i = 0; i < 8; i++)
938 {
939 //
940 // Point to the page table mapping the next MB
941 //
942 FlatMapTable->Pte[i] = Pte;
943 Pte.L2.Small.BaseAddress++;
944 }
945
946 //
947 // For the 0x80800000 region (6MB)
948 //
949 Pte.L2.Small.BaseAddress = (ULONG)&KernelTranslationTable >> PTE_SHIFT;
950 for (i = 8; i < 14; i++)
951 {
952 //
953 // Point to the page table mapping the next MB
954 //
955 FlatMapTable->Pte[i] = Pte;
956 Pte.L2.Small.BaseAddress++;
957 }
958
959 //
960 // For the 0xC0000000 region (16MB)
961 //
962 Pte.L2.Small.BaseAddress = (ULONG)&FlatMapTranslationTable >> PTE_SHIFT;
963 FlatMapTable = &(&FlatMapTranslationTable)[0xC0000000 >> 28];
964 for (i = 0; i < 16; i++)
965 {
966 //
967 // Point to the page table mapping the next MB
968 //
969 FlatMapTable->Pte[i] = Pte;
970 Pte.L2.Small.BaseAddress++;
971 }
972
973 //
974 // For the 0xC1000000 region (1MB)
975 //
976 Pte.L2.Small.BaseAddress = (ULONG)&MasterTranslationTable >> PTE_SHIFT;
977 FlatMapTable->Pte[16] = Pte;
978
979 //
980 // Now we handle the master translation area for our PDEs. We'll just make
981 // the 4 page tables point to the ARM TTB.
982 //
983 Pte.L2.Small.BaseAddress = (ULONG)&ArmTranslationTable >> PTE_SHIFT;
984 for (i = 0; i < 4; i++)
985 {
986 //
987 // Point to the page table mapping the next MB
988 //
989 MasterTable->Pte[i] = Pte;
990 Pte.L2.Small.BaseAddress++;
991 }
992 }
993
994 VOID
995 ArmSetupPagingAndJump(IN ULONG Magic)
996 {
997 ARM_CONTROL_REGISTER ControlRegister;
998
999 //
1000 // Enable MMU, DCache and ICache
1001 //
1002 ControlRegister = KeArmControlRegisterGet();
1003 ControlRegister.MmuEnabled = TRUE;
1004 ControlRegister.ICacheEnabled = TRUE;
1005 ControlRegister.DCacheEnabled = TRUE;
1006 KeArmControlRegisterSet(ControlRegister);
1007
1008 //
1009 // Reconfigure UART0
1010 //
1011 ArmBoardBlock->UartRegisterBase = UART_VIRTUAL |
1012 (ArmBoardBlock->UartRegisterBase &
1013 ((1 << PDE_SHIFT) - 1));
1014 TuiPrintf("Mapped serial port to 0x%x\n", ArmBoardBlock->UartRegisterBase);
1015
1016 //
1017 // Jump to Kernel
1018 //
1019 (*KernelEntryPoint)((PVOID)((ULONG_PTR)ArmLoaderBlock | KSEG0_BASE));
1020 }
1021
1022 VOID
1023 ArmPrepareForReactOS(IN BOOLEAN Setup)
1024 {
1025 ARM_CACHE_REGISTER CacheReg;
1026 PVOID Base, MemBase;
1027 PCHAR BootPath, HalPath;
1028 NTSTATUS Status;
1029 ULONG Dummy, i;
1030 PLDR_DATA_TABLE_ENTRY LdrEntry;
1031 PLIST_ENTRY NextEntry, OldEntry;
1032 PARC_DISK_INFORMATION ArcDiskInformation;
1033 PARC_DISK_SIGNATURE ArcDiskSignature;
1034 ULONG ArcDiskCount = 0, Checksum = 0;
1035 PMASTER_BOOT_RECORD Mbr;
1036 PULONG Buffer;
1037 PWCHAR ArmModuleName;
1038
1039 TuiPrintf("About to prepare for kernel boot\n");
1040 while (TRUE);
1041
1042 //
1043 // Allocate the ARM Shared Heap
1044 //
1045 ArmSharedHeap = MmAllocateMemoryWithType(PAGE_SIZE, LoaderOsloaderHeap);
1046 ArmSharedHeapSize = 0;
1047 if (!ArmSharedHeap) return;
1048
1049 //
1050 // Allocate the loader block and extension
1051 //
1052 ArmLoaderBlock = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK));
1053 if (!ArmLoaderBlock) return;
1054 ArmExtension = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION));
1055 if (!ArmExtension) return;
1056
1057 //
1058 // Initialize the loader block
1059 //
1060 InitializeListHead(&ArmLoaderBlock->BootDriverListHead);
1061 InitializeListHead(&ArmLoaderBlock->LoadOrderListHead);
1062 InitializeListHead(&ArmLoaderBlock->MemoryDescriptorListHead);
1063
1064 //
1065 // Setup the extension and setup block
1066 //
1067 ArmLoaderBlock->Extension = (PVOID)((ULONG_PTR)ArmExtension | KSEG0_BASE);
1068 ArmLoaderBlock->SetupLdrBlock = NULL;
1069
1070 //
1071 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1072 // BIOS descriptor format -- this needs to be removed later.
1073 //
1074 ArmBuildBoardMemoryMap();
1075
1076 //
1077 // Now basically convert these entries to the ARC format, so that we can
1078 // get a good map of free (usable) memory
1079 //
1080 ArmBuildOsMemoryMap();
1081
1082 //
1083 // NT uses an extended ARC format, with slightly different memory types.
1084 // We also want to link the ARC descriptors together into a linked list,
1085 // instead of the array, and allocate the semi-permanent storage in which
1086 // these entries will be stored so that the kernel can read them.
1087 //
1088 ArmBuildLoaderMemoryList();
1089
1090 //
1091 // Setup descriptor for the shared heap
1092 //
1093 Status = ArmCreateMemoryDescriptor(LoaderOsloaderHeap,
1094 (ULONG_PTR)ArmSharedHeap >> PAGE_SHIFT,
1095 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap,
1096 ArmSharedHeapSize),
1097 0,
1098 &Dummy);
1099 if (Status != STATUS_SUCCESS) return;
1100
1101 //
1102 // Setup descriptor for the boot stack
1103 //
1104 Status = ArmCreateMemoryDescriptor(LoaderOsloaderStack,
1105 (ULONG_PTR)&BootStack >> PAGE_SHIFT,
1106 4,
1107 0,
1108 &Dummy);
1109 if (Status != STATUS_SUCCESS) return;
1110
1111 //
1112 // Setup descriptor for the boot page tables
1113 //
1114 Status = ArmCreateMemoryDescriptor(LoaderMemoryData,
1115 (ULONG_PTR)&TranslationTableStart >> PAGE_SHIFT,
1116 ((ULONG_PTR)&TranslationTableEnd -
1117 (ULONG_PTR)&TranslationTableStart) / PAGE_SIZE,
1118 0,
1119 &Dummy);
1120 if (Status != STATUS_SUCCESS) return;
1121
1122 //
1123 // Setup descriptor for the kernel
1124 //
1125 Status = ArmCreateMemoryDescriptor(LoaderSystemCode,
1126 KernelData >> PAGE_SHIFT,
1127 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData,
1128 KernelSize),
1129 0,
1130 &Dummy);
1131 if (Status != STATUS_SUCCESS) return;
1132
1133 //
1134 // Setup descriptor for the HAL
1135 //
1136 Status = ArmCreateMemoryDescriptor(LoaderHalCode,
1137 HalData >> PAGE_SHIFT,
1138 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData,
1139 HalSize),
1140 0,
1141 &Dummy);
1142 if (Status != STATUS_SUCCESS) return;
1143
1144 //
1145 // Setup registry data
1146 //
1147 ArmLoaderBlock->RegistryBase = (PVOID)((ULONG_PTR)RegistryData | KSEG0_BASE);
1148 ArmLoaderBlock->RegistryLength = RegistrySize;
1149
1150 //
1151 // Create an MD for it
1152 //
1153 Status = ArmCreateMemoryDescriptor(LoaderRegistryData,
1154 RegistryData >> PAGE_SHIFT,
1155 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData,
1156 RegistrySize),
1157 0,
1158 &Dummy);
1159 if (Status != STATUS_SUCCESS) return;
1160
1161 //
1162 // TODO: Setup ARC Hardware tree data
1163 //
1164
1165 //
1166 // Setup NLS data
1167 //
1168 ArmNlsDataBlock = ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK));
1169 ArmLoaderBlock->NlsData = ArmNlsDataBlock;
1170 ArmLoaderBlock->NlsData->AnsiCodePageData = (PVOID)(AnsiData | KSEG0_BASE);
1171 ArmLoaderBlock->NlsData->OemCodePageData = (PVOID)(OemData | KSEG0_BASE);
1172 ArmLoaderBlock->NlsData->UnicodeCodePageData = (PVOID)(UnicodeData | KSEG0_BASE);
1173 ArmLoaderBlock->NlsData = (PVOID)((ULONG_PTR)ArmLoaderBlock->NlsData | KSEG0_BASE);
1174
1175 //
1176 // Setup ANSI NLS Memory Descriptor
1177 //
1178 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1179 AnsiData >> PAGE_SHIFT,
1180 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData,
1181 AnsiSize),
1182 0,
1183 &Dummy);
1184 if (Status != STATUS_SUCCESS) return;
1185
1186 //
1187 // Setup OEM NLS Memory Descriptor
1188 //
1189 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1190 OemData >> PAGE_SHIFT,
1191 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData,
1192 OemSize),
1193 0,
1194 &Dummy);
1195 if (Status != STATUS_SUCCESS) return;
1196
1197 //
1198 // Setup Unicode NLS Memory Descriptor
1199 //
1200 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1201 UnicodeData >> PAGE_SHIFT,
1202 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData,
1203 UnicodeSize),
1204 0,
1205 &Dummy);
1206 if (Status != STATUS_SUCCESS) return;
1207
1208 //
1209 // Setup loader entry for the kernel
1210 //
1211 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1212 wcscpy(ArmModuleName, L"ntoskrnl.exe");
1213 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1214 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1215 LdrEntry->DllBase = (PVOID)KernelBase;
1216 LdrEntry->SizeOfImage = KernelSize;
1217 LdrEntry->EntryPoint = KernelEntryPoint;
1218 LdrEntry->LoadCount = 1;
1219 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1220 RtlInitUnicodeString(&LdrEntry->FullDllName, ArmModuleName);
1221 RtlInitUnicodeString(&LdrEntry->BaseDllName, ArmModuleName);
1222 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1223 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1224 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1225
1226 //
1227 // Setup loader entry for the HAL
1228 //
1229 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1230 wcscpy(ArmModuleName, L"hal.dll");
1231 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1232 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1233 LdrEntry->DllBase = (PVOID)(HalData | KSEG0_BASE);
1234 LdrEntry->SizeOfImage = HalSize;
1235 LdrEntry->EntryPoint = (PVOID)RtlImageNtHeader((PVOID)HalData)->
1236 OptionalHeader.AddressOfEntryPoint;
1237 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)LdrEntry->EntryPoint | KSEG0_BASE);
1238 LdrEntry->LoadCount = 1;
1239 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1240 RtlInitUnicodeString(&LdrEntry->FullDllName, ArmModuleName);
1241 RtlInitUnicodeString(&LdrEntry->BaseDllName, ArmModuleName);
1242 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1243 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1244 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1245
1246 //
1247 // Build descriptors for the drivers loaded
1248 //
1249 for (i = 0; i < Drivers; i++)
1250 {
1251 //
1252 // Setup loader entry for the driver
1253 //
1254 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1255 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1256 LdrEntry->DllBase = (PVOID)(DriverData[i] | KSEG0_BASE);
1257 LdrEntry->SizeOfImage = DriverSize[i];
1258 LdrEntry->EntryPoint = (PVOID)RtlImageNtHeader((PVOID)DriverData[i])->
1259 OptionalHeader.AddressOfEntryPoint;
1260 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)LdrEntry->EntryPoint | KSEG0_BASE);
1261 LdrEntry->LoadCount = 1;
1262 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1263 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1264 RtlZeroMemory(ArmModuleName, 64 * sizeof(WCHAR));
1265 LdrEntry->FullDllName.Length = strlen(DriverName[i]) * sizeof(WCHAR);
1266 LdrEntry->FullDllName.MaximumLength = LdrEntry->FullDllName.Length;
1267 LdrEntry->FullDllName.Buffer = ArmModuleName;
1268 LdrEntry->BaseDllName = LdrEntry->FullDllName;
1269 while (*DriverName[i]) *ArmModuleName++ = *DriverName[i]++;
1270 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1271 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1272 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1273
1274 //
1275 // Build a descriptor for the driver
1276 //
1277 Status = ArmCreateMemoryDescriptor(LoaderBootDriver,
1278 DriverData[i] >> PAGE_SHIFT,
1279 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData[i],
1280 DriverSize[i]),
1281 0,
1282 &Dummy);
1283 if (Status != STATUS_SUCCESS) return;
1284 }
1285
1286 //
1287 // Loop driver list
1288 //
1289 NextEntry = ArmLoaderBlock->LoadOrderListHead.Flink;
1290 while (NextEntry != &ArmLoaderBlock->LoadOrderListHead)
1291 {
1292 //
1293 // Remember the physical entry
1294 //
1295 OldEntry = NextEntry->Flink;
1296
1297 //
1298 // Edit the data
1299 //
1300 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1301 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1302
1303 //
1304 // Keep looping
1305 //
1306 NextEntry = OldEntry;
1307 }
1308
1309 //
1310 // Now edit the root itself
1311 //
1312 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1313 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1314
1315 //
1316 // Setup extension parameters
1317 //
1318 ArmExtension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
1319 ArmExtension->MajorVersion = 5;
1320 ArmExtension->MinorVersion = 2;
1321
1322 //
1323 // Make a copy of the command line
1324 //
1325 ArmLoaderBlock->LoadOptions = ArmCommandLine;
1326 strcpy(ArmCommandLine, reactos_kernel_cmdline);
1327
1328 //
1329 // Find the first \, separating the ARC path from NT path
1330 //
1331 BootPath = strchr(ArmCommandLine, '\\');
1332 *BootPath = ANSI_NULL;
1333
1334 //
1335 // Set the ARC Boot Path
1336 //
1337 strncpy(ArmArcBootPath, ArmCommandLine, 63);
1338 ArmLoaderBlock->ArcBootDeviceName = (PVOID)((ULONG_PTR)ArmArcBootPath | KSEG0_BASE);
1339
1340 //
1341 // The rest of the string is the NT path
1342 //
1343 HalPath = strchr(BootPath + 1, ' ');
1344 *HalPath = ANSI_NULL;
1345 ArmNtBootPath[0] = '\\';
1346 strncat(ArmNtBootPath, BootPath + 1, 63);
1347 strcat(ArmNtBootPath,"\\");
1348 ArmLoaderBlock->NtBootPathName = (PVOID)((ULONG_PTR)ArmNtBootPath | KSEG0_BASE);
1349
1350 //
1351 // Set the HAL paths
1352 //
1353 strncpy(ArmArcHalPath, ArmArcBootPath, 63);
1354 ArmLoaderBlock->ArcHalDeviceName = (PVOID)((ULONG_PTR)ArmArcHalPath | KSEG0_BASE);
1355 strcpy(ArmNtHalPath, "\\");
1356 ArmLoaderBlock->NtHalPathName = (PVOID)((ULONG_PTR)ArmNtHalPath | KSEG0_BASE);
1357
1358 //
1359 // Use this new command line
1360 //
1361 strncpy(ArmLoaderBlock->LoadOptions, HalPath + 2, 255);
1362
1363 //
1364 // Parse it and change every slash to a space
1365 //
1366 BootPath = ArmLoaderBlock->LoadOptions;
1367 do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
1368
1369 //
1370 // Fixup command-line pointer
1371 //
1372 ArmLoaderBlock->LoadOptions = (PVOID)((ULONG_PTR)ArmLoaderBlock->LoadOptions | KSEG0_BASE);
1373
1374 //
1375 // Setup cache information
1376 //
1377 CacheReg = KeArmCacheRegisterGet();
1378 ArmLoaderBlock->u.Arm.FirstLevelDcacheSize = SizeBits[CacheReg.DSize];
1379 ArmLoaderBlock->u.Arm.FirstLevelDcacheFillSize = LenBits[CacheReg.DLength];
1380 ArmLoaderBlock->u.Arm.FirstLevelDcacheFillSize <<= 2;
1381 ArmLoaderBlock->u.Arm.FirstLevelIcacheSize = SizeBits[CacheReg.ISize];
1382 ArmLoaderBlock->u.Arm.FirstLevelIcacheFillSize = LenBits[CacheReg.ILength];
1383 ArmLoaderBlock->u.Arm.FirstLevelIcacheFillSize <<= 2;
1384 ArmLoaderBlock->u.Arm.SecondLevelDcacheSize =
1385 ArmLoaderBlock->u.Arm.SecondLevelDcacheFillSize =
1386 ArmLoaderBlock->u.Arm.SecondLevelIcacheSize =
1387 ArmLoaderBlock->u.Arm.SecondLevelIcacheFillSize = 0;
1388
1389 //
1390 // Allocate the Interrupt stack
1391 //
1392 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupDpcStack);
1393 ArmLoaderBlock->u.Arm.InterruptStack = KSEG0_BASE | (ULONG)Base;
1394 ArmLoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
1395
1396 //
1397 // Build an entry for it
1398 //
1399 Status = ArmCreateMemoryDescriptor(LoaderStartupDpcStack,
1400 (ULONG_PTR)Base >> PAGE_SHIFT,
1401 KERNEL_STACK_SIZE / PAGE_SIZE,
1402 0,
1403 &Dummy);
1404 if (Status != STATUS_SUCCESS) return;
1405
1406 //
1407 // Allocate the Kernel Boot stack
1408 //
1409 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupKernelStack);
1410 ArmLoaderBlock->KernelStack = KSEG0_BASE | (ULONG)Base;
1411 ArmLoaderBlock->KernelStack += KERNEL_STACK_SIZE;
1412
1413 //
1414 // Build an entry for it
1415 //
1416 Status = ArmCreateMemoryDescriptor(LoaderStartupKernelStack,
1417 (ULONG_PTR)Base >> PAGE_SHIFT,
1418 KERNEL_STACK_SIZE / PAGE_SIZE,
1419 0,
1420 &Dummy);
1421 if (Status != STATUS_SUCCESS) return;
1422
1423 //
1424 // Allocate the Abort stack
1425 //
1426 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupPanicStack);
1427 ArmLoaderBlock->u.Arm.PanicStack = KSEG0_BASE | (ULONG)Base;
1428 ArmLoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
1429
1430 //
1431 // Build an entry for it
1432 //
1433 Status = ArmCreateMemoryDescriptor(LoaderStartupPanicStack,
1434 (ULONG_PTR)Base >> PAGE_SHIFT,
1435 KERNEL_STACK_SIZE / PAGE_SIZE,
1436 0,
1437 &Dummy);
1438 if (Status != STATUS_SUCCESS) return;
1439
1440 //
1441 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1442 //
1443 Base = MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage);
1444 MemBase = Base;
1445 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1446 ArmLoaderBlock->u.Arm.PcrPage = (ULONG)Base >> PDE_SHIFT;
1447
1448 //
1449 // Build an entry for the KPCR and KUSER_SHARED_DATA
1450 //
1451 Status = ArmCreateMemoryDescriptor(LoaderStartupPcrPage,
1452 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1453 (2 * 1024 * 1024) / PAGE_SIZE,
1454 0,
1455 &Dummy);
1456 if (Status != STATUS_SUCCESS) return;
1457
1458 //
1459 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1460 //
1461 Base = MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage);
1462 MemBase = Base;
1463 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1464 ArmLoaderBlock->u.Arm.PdrPage = (ULONG)Base >> PDE_SHIFT;
1465
1466 //
1467 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1468 //
1469 Status = ArmCreateMemoryDescriptor(LoaderStartupPdrPage,
1470 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1471 (4 * 1024 * 1024) / PAGE_SIZE,
1472 0,
1473 &Dummy);
1474 if (Status != STATUS_SUCCESS) return;
1475
1476 //
1477 // Set initial PRCB, Thread and Process on the last PDR page
1478 //
1479 Base = (PVOID)((ULONG)Base + 2 * 1024 * 1024);
1480 ArmLoaderBlock->Prcb = KSEG0_BASE | (ULONG)Base;
1481 ArmLoaderBlock->Process = ArmLoaderBlock->Prcb + sizeof(KPRCB);
1482 ArmLoaderBlock->Thread = ArmLoaderBlock->Process + sizeof(EPROCESS);
1483
1484 //
1485 // Check if we're booting from RAM disk
1486 //
1487 if ((gRamDiskBase) && (gRamDiskSize))
1488 {
1489 //
1490 // Allocate a descriptor to describe it
1491 //
1492 Status = ArmCreateMemoryDescriptor(LoaderXIPRom,
1493 (ULONG_PTR)gRamDiskBase >> PAGE_SHIFT,
1494 gRamDiskSize / PAGE_SIZE,
1495 0,
1496 &Dummy);
1497 if (Status != STATUS_SUCCESS) return;
1498 }
1499
1500 //
1501 // Loop memory list
1502 //
1503 NextEntry = ArmLoaderBlock->MemoryDescriptorListHead.Flink;
1504 while (NextEntry != &ArmLoaderBlock->MemoryDescriptorListHead)
1505 {
1506 //
1507 // Remember the physical entry
1508 //
1509 OldEntry = NextEntry->Flink;
1510
1511 //
1512 // Edit the data
1513 //
1514 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1515 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1516
1517 //
1518 // Keep looping
1519 //
1520 NextEntry = OldEntry;
1521 }
1522
1523 //
1524 // Now edit the root itself
1525 //
1526 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1527 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1528
1529 //
1530 // Allocate ARC disk structure
1531 //
1532 ArcDiskInformation = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_INFORMATION));
1533 InitializeListHead(&ArcDiskInformation->DiskSignatureListHead);
1534 ArmLoaderBlock->ArcDiskInformation = (PVOID)((ULONG_PTR)ArcDiskInformation | KSEG0_BASE);
1535
1536 //
1537 // Read the MBR
1538 //
1539 MachDiskReadLogicalSectors(0x49, 0ULL, 1, (PVOID)DISKREADBUFFER);
1540 Buffer = (ULONG*)DISKREADBUFFER;
1541 Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
1542
1543 //
1544 // Calculate the MBR checksum
1545 //
1546 for (i = 0; i < 128; i++) Checksum += Buffer[i];
1547 Checksum = ~Checksum + 1;
1548
1549 //
1550 // Allocate a disk signature and fill it out
1551 //
1552 ArcDiskSignature = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_SIGNATURE));
1553 ArcDiskSignature->Signature = Mbr->Signature;
1554 ArcDiskSignature->CheckSum = Checksum;
1555
1556 //
1557 // Allocare a string for the name and fill it out
1558 //
1559 ArcDiskSignature->ArcName = ArmAllocateFromSharedHeap(256);
1560 sprintf(ArcDiskSignature->ArcName, "multi(0)disk(0)rdisk(%lu)", ArcDiskCount++);
1561 ArcDiskSignature->ArcName = (PVOID)((ULONG_PTR)ArcDiskSignature->ArcName | KSEG0_BASE);
1562
1563 //
1564 // Insert the descriptor into the list
1565 //
1566 InsertTailList(&ArcDiskInformation->DiskSignatureListHead,
1567 &ArcDiskSignature->ListEntry);
1568
1569 //
1570 // Loop ARC disk list
1571 //
1572 NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
1573 while (NextEntry != &ArcDiskInformation->DiskSignatureListHead)
1574 {
1575 //
1576 // Remember the physical entry
1577 //
1578 OldEntry = NextEntry->Flink;
1579
1580 //
1581 // Edit the data
1582 //
1583 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1584 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1585
1586 //
1587 // Keep looping
1588 //
1589 NextEntry = OldEntry;
1590 }
1591
1592 //
1593 // Now edit the root itself
1594 //
1595 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1596 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1597 }
1598
1599 VOID
1600 FrLdrStartup(IN ULONG Magic)
1601 {
1602 //
1603 // Disable interrupts (already done)
1604 //
1605
1606 //
1607 // Set proper CPSR (already done)
1608 //
1609
1610 //
1611 // Initialize the page directory
1612 //
1613 TuiPrintf("About to jump into kernel\n");
1614 while (TRUE);
1615 ArmSetupPageDirectory();
1616
1617 //
1618 // Initialize paging and load NTOSKRNL
1619 //
1620 ArmSetupPagingAndJump(Magic);
1621 }