- For one thing, fix build in ARM3/init.c (sorry!)
[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)(Magic, (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 //
1040 // Allocate the ARM Shared Heap
1041 //
1042 ArmSharedHeap = MmAllocateMemoryWithType(PAGE_SIZE, LoaderOsloaderHeap);
1043 ArmSharedHeapSize = 0;
1044 if (!ArmSharedHeap) return;
1045
1046 //
1047 // Allocate the loader block and extension
1048 //
1049 ArmLoaderBlock = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK));
1050 if (!ArmLoaderBlock) return;
1051 ArmExtension = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION));
1052 if (!ArmExtension) return;
1053
1054 //
1055 // Initialize the loader block
1056 //
1057 InitializeListHead(&ArmLoaderBlock->BootDriverListHead);
1058 InitializeListHead(&ArmLoaderBlock->LoadOrderListHead);
1059 InitializeListHead(&ArmLoaderBlock->MemoryDescriptorListHead);
1060
1061 //
1062 // Setup the extension and setup block
1063 //
1064 ArmLoaderBlock->Extension = (PVOID)((ULONG_PTR)ArmExtension | KSEG0_BASE);
1065 ArmLoaderBlock->SetupLdrBlock = NULL;
1066
1067 //
1068 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
1069 // BIOS descriptor format -- this needs to be removed later.
1070 //
1071 ArmBuildBoardMemoryMap();
1072
1073 //
1074 // Now basically convert these entries to the ARC format, so that we can
1075 // get a good map of free (usable) memory
1076 //
1077 ArmBuildOsMemoryMap();
1078
1079 //
1080 // NT uses an extended ARC format, with slightly different memory types.
1081 // We also want to link the ARC descriptors together into a linked list,
1082 // instead of the array, and allocate the semi-permanent storage in which
1083 // these entries will be stored so that the kernel can read them.
1084 //
1085 ArmBuildLoaderMemoryList();
1086
1087 //
1088 // Setup descriptor for the shared heap
1089 //
1090 Status = ArmCreateMemoryDescriptor(LoaderOsloaderHeap,
1091 (ULONG_PTR)ArmSharedHeap >> PAGE_SHIFT,
1092 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap,
1093 ArmSharedHeapSize),
1094 0,
1095 &Dummy);
1096 if (Status != STATUS_SUCCESS) return;
1097
1098 //
1099 // Setup descriptor for the boot stack
1100 //
1101 Status = ArmCreateMemoryDescriptor(LoaderOsloaderStack,
1102 (ULONG_PTR)&BootStack >> PAGE_SHIFT,
1103 4,
1104 0,
1105 &Dummy);
1106 if (Status != STATUS_SUCCESS) return;
1107
1108 //
1109 // Setup descriptor for the boot page tables
1110 //
1111 Status = ArmCreateMemoryDescriptor(LoaderMemoryData,
1112 (ULONG_PTR)&TranslationTableStart >> PAGE_SHIFT,
1113 ((ULONG_PTR)&TranslationTableEnd -
1114 (ULONG_PTR)&TranslationTableStart) / PAGE_SIZE,
1115 0,
1116 &Dummy);
1117 if (Status != STATUS_SUCCESS) return;
1118
1119 //
1120 // Setup descriptor for the kernel
1121 //
1122 Status = ArmCreateMemoryDescriptor(LoaderSystemCode,
1123 KernelData >> PAGE_SHIFT,
1124 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData,
1125 KernelSize),
1126 0,
1127 &Dummy);
1128 if (Status != STATUS_SUCCESS) return;
1129
1130 //
1131 // Setup descriptor for the HAL
1132 //
1133 Status = ArmCreateMemoryDescriptor(LoaderHalCode,
1134 HalData >> PAGE_SHIFT,
1135 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData,
1136 HalSize),
1137 0,
1138 &Dummy);
1139 if (Status != STATUS_SUCCESS) return;
1140
1141 //
1142 // Setup registry data
1143 //
1144 ArmLoaderBlock->RegistryBase = (PVOID)((ULONG_PTR)RegistryData | KSEG0_BASE);
1145 ArmLoaderBlock->RegistryLength = RegistrySize;
1146
1147 //
1148 // Create an MD for it
1149 //
1150 Status = ArmCreateMemoryDescriptor(LoaderRegistryData,
1151 RegistryData >> PAGE_SHIFT,
1152 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData,
1153 RegistrySize),
1154 0,
1155 &Dummy);
1156 if (Status != STATUS_SUCCESS) return;
1157
1158 //
1159 // TODO: Setup ARC Hardware tree data
1160 //
1161
1162 //
1163 // Setup NLS data
1164 //
1165 ArmNlsDataBlock = ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK));
1166 ArmLoaderBlock->NlsData = ArmNlsDataBlock;
1167 ArmLoaderBlock->NlsData->AnsiCodePageData = (PVOID)(AnsiData | KSEG0_BASE);
1168 ArmLoaderBlock->NlsData->OemCodePageData = (PVOID)(OemData | KSEG0_BASE);
1169 ArmLoaderBlock->NlsData->UnicodeCodePageData = (PVOID)(UnicodeData | KSEG0_BASE);
1170 ArmLoaderBlock->NlsData = (PVOID)((ULONG_PTR)ArmLoaderBlock->NlsData | KSEG0_BASE);
1171
1172 //
1173 // Setup ANSI NLS Memory Descriptor
1174 //
1175 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1176 AnsiData >> PAGE_SHIFT,
1177 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData,
1178 AnsiSize),
1179 0,
1180 &Dummy);
1181 if (Status != STATUS_SUCCESS) return;
1182
1183 //
1184 // Setup OEM NLS Memory Descriptor
1185 //
1186 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1187 OemData >> PAGE_SHIFT,
1188 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData,
1189 OemSize),
1190 0,
1191 &Dummy);
1192 if (Status != STATUS_SUCCESS) return;
1193
1194 //
1195 // Setup Unicode NLS Memory Descriptor
1196 //
1197 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1198 UnicodeData >> PAGE_SHIFT,
1199 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData,
1200 UnicodeSize),
1201 0,
1202 &Dummy);
1203 if (Status != STATUS_SUCCESS) return;
1204
1205 //
1206 // Setup loader entry for the kernel
1207 //
1208 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1209 wcscpy(ArmModuleName, L"ntoskrnl.exe");
1210 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1211 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1212 LdrEntry->DllBase = (PVOID)KernelBase;
1213 LdrEntry->SizeOfImage = KernelSize;
1214 LdrEntry->EntryPoint = KernelEntryPoint;
1215 LdrEntry->LoadCount = 1;
1216 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1217 RtlInitUnicodeString(&LdrEntry->FullDllName, ArmModuleName);
1218 RtlInitUnicodeString(&LdrEntry->BaseDllName, ArmModuleName);
1219 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1220 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1221 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1222
1223 //
1224 // Setup loader entry for the HAL
1225 //
1226 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1227 wcscpy(ArmModuleName, L"hal.dll");
1228 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1229 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1230 LdrEntry->DllBase = (PVOID)(HalData | KSEG0_BASE);
1231 LdrEntry->SizeOfImage = HalSize;
1232 LdrEntry->EntryPoint = (PVOID)RtlImageNtHeader((PVOID)HalData)->
1233 OptionalHeader.AddressOfEntryPoint;
1234 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)LdrEntry->EntryPoint | KSEG0_BASE);
1235 LdrEntry->LoadCount = 1;
1236 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1237 RtlInitUnicodeString(&LdrEntry->FullDllName, ArmModuleName);
1238 RtlInitUnicodeString(&LdrEntry->BaseDllName, ArmModuleName);
1239 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1240 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1241 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1242
1243 //
1244 // Build descriptors for the drivers loaded
1245 //
1246 for (i = 0; i < Drivers; i++)
1247 {
1248 //
1249 // Setup loader entry for the driver
1250 //
1251 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1252 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1253 LdrEntry->DllBase = (PVOID)(DriverData[i] | KSEG0_BASE);
1254 LdrEntry->SizeOfImage = DriverSize[i];
1255 LdrEntry->EntryPoint = (PVOID)RtlImageNtHeader((PVOID)DriverData[i])->
1256 OptionalHeader.AddressOfEntryPoint;
1257 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)LdrEntry->EntryPoint | KSEG0_BASE);
1258 LdrEntry->LoadCount = 1;
1259 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1260 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1261 RtlZeroMemory(ArmModuleName, 64 * sizeof(WCHAR));
1262 LdrEntry->FullDllName.Length = strlen(DriverName[i]) * sizeof(WCHAR);
1263 LdrEntry->FullDllName.MaximumLength = LdrEntry->FullDllName.Length;
1264 LdrEntry->FullDllName.Buffer = ArmModuleName;
1265 LdrEntry->BaseDllName = LdrEntry->FullDllName;
1266 while (*DriverName[i]) *ArmModuleName++ = *DriverName[i]++;
1267 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1268 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1269 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1270
1271 //
1272 // Build a descriptor for the driver
1273 //
1274 Status = ArmCreateMemoryDescriptor(LoaderBootDriver,
1275 DriverData[i] >> PAGE_SHIFT,
1276 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData[i],
1277 DriverSize[i]),
1278 0,
1279 &Dummy);
1280 if (Status != STATUS_SUCCESS) return;
1281 }
1282
1283 //
1284 // Loop driver list
1285 //
1286 NextEntry = ArmLoaderBlock->LoadOrderListHead.Flink;
1287 while (NextEntry != &ArmLoaderBlock->LoadOrderListHead)
1288 {
1289 //
1290 // Remember the physical entry
1291 //
1292 OldEntry = NextEntry->Flink;
1293
1294 //
1295 // Edit the data
1296 //
1297 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1298 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1299
1300 //
1301 // Keep looping
1302 //
1303 NextEntry = OldEntry;
1304 }
1305
1306 //
1307 // Now edit the root itself
1308 //
1309 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1310 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1311
1312 //
1313 // Setup extension parameters
1314 //
1315 ArmExtension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
1316 ArmExtension->MajorVersion = 5;
1317 ArmExtension->MinorVersion = 2;
1318
1319 //
1320 // Make a copy of the command line
1321 //
1322 ArmLoaderBlock->LoadOptions = ArmCommandLine;
1323 strcpy(ArmCommandLine, reactos_kernel_cmdline);
1324
1325 //
1326 // Find the first \, separating the ARC path from NT path
1327 //
1328 BootPath = strchr(ArmCommandLine, '\\');
1329 *BootPath = ANSI_NULL;
1330
1331 //
1332 // Set the ARC Boot Path
1333 //
1334 strncpy(ArmArcBootPath, ArmCommandLine, 63);
1335 ArmLoaderBlock->ArcBootDeviceName = (PVOID)((ULONG_PTR)ArmArcBootPath | KSEG0_BASE);
1336
1337 //
1338 // The rest of the string is the NT path
1339 //
1340 HalPath = strchr(BootPath + 1, ' ');
1341 *HalPath = ANSI_NULL;
1342 ArmNtBootPath[0] = '\\';
1343 strncat(ArmNtBootPath, BootPath + 1, 63);
1344 strcat(ArmNtBootPath,"\\");
1345 ArmLoaderBlock->NtBootPathName = (PVOID)((ULONG_PTR)ArmNtBootPath | KSEG0_BASE);
1346
1347 //
1348 // Set the HAL paths
1349 //
1350 strncpy(ArmArcHalPath, ArmArcBootPath, 63);
1351 ArmLoaderBlock->ArcHalDeviceName = (PVOID)((ULONG_PTR)ArmArcHalPath | KSEG0_BASE);
1352 strcpy(ArmNtHalPath, "\\");
1353 ArmLoaderBlock->NtHalPathName = (PVOID)((ULONG_PTR)ArmNtHalPath | KSEG0_BASE);
1354
1355 //
1356 // Use this new command line
1357 //
1358 strncpy(ArmLoaderBlock->LoadOptions, HalPath + 2, 255);
1359
1360 //
1361 // Parse it and change every slash to a space
1362 //
1363 BootPath = ArmLoaderBlock->LoadOptions;
1364 do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
1365
1366 //
1367 // Fixup command-line pointer
1368 //
1369 ArmLoaderBlock->LoadOptions = (PVOID)((ULONG_PTR)ArmLoaderBlock->LoadOptions | KSEG0_BASE);
1370
1371 //
1372 // Setup cache information
1373 //
1374 CacheReg = KeArmCacheRegisterGet();
1375 ArmLoaderBlock->u.Arm.FirstLevelDcacheSize = SizeBits[CacheReg.DSize];
1376 ArmLoaderBlock->u.Arm.FirstLevelDcacheFillSize = LenBits[CacheReg.DLength];
1377 ArmLoaderBlock->u.Arm.FirstLevelDcacheFillSize <<= 2;
1378 ArmLoaderBlock->u.Arm.FirstLevelIcacheSize = SizeBits[CacheReg.ISize];
1379 ArmLoaderBlock->u.Arm.FirstLevelIcacheFillSize = LenBits[CacheReg.ILength];
1380 ArmLoaderBlock->u.Arm.FirstLevelIcacheFillSize <<= 2;
1381 ArmLoaderBlock->u.Arm.SecondLevelDcacheSize =
1382 ArmLoaderBlock->u.Arm.SecondLevelDcacheFillSize =
1383 ArmLoaderBlock->u.Arm.SecondLevelIcacheSize =
1384 ArmLoaderBlock->u.Arm.SecondLevelIcacheFillSize = 0;
1385
1386 //
1387 // Allocate the Interrupt stack
1388 //
1389 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupDpcStack);
1390 ArmLoaderBlock->u.Arm.InterruptStack = KSEG0_BASE | (ULONG)Base;
1391 ArmLoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
1392
1393 //
1394 // Build an entry for it
1395 //
1396 Status = ArmCreateMemoryDescriptor(LoaderStartupDpcStack,
1397 (ULONG_PTR)Base >> PAGE_SHIFT,
1398 KERNEL_STACK_SIZE / PAGE_SIZE,
1399 0,
1400 &Dummy);
1401 if (Status != STATUS_SUCCESS) return;
1402
1403 //
1404 // Allocate the Kernel Boot stack
1405 //
1406 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupKernelStack);
1407 ArmLoaderBlock->KernelStack = KSEG0_BASE | (ULONG)Base;
1408 ArmLoaderBlock->KernelStack += KERNEL_STACK_SIZE;
1409
1410 //
1411 // Build an entry for it
1412 //
1413 Status = ArmCreateMemoryDescriptor(LoaderStartupKernelStack,
1414 (ULONG_PTR)Base >> PAGE_SHIFT,
1415 KERNEL_STACK_SIZE / PAGE_SIZE,
1416 0,
1417 &Dummy);
1418 if (Status != STATUS_SUCCESS) return;
1419
1420 //
1421 // Allocate the Abort stack
1422 //
1423 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupPanicStack);
1424 ArmLoaderBlock->u.Arm.PanicStack = KSEG0_BASE | (ULONG)Base;
1425 ArmLoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
1426
1427 //
1428 // Build an entry for it
1429 //
1430 Status = ArmCreateMemoryDescriptor(LoaderStartupPanicStack,
1431 (ULONG_PTR)Base >> PAGE_SHIFT,
1432 KERNEL_STACK_SIZE / PAGE_SIZE,
1433 0,
1434 &Dummy);
1435 if (Status != STATUS_SUCCESS) return;
1436
1437 //
1438 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1439 //
1440 Base = MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage);
1441 MemBase = Base;
1442 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1443 ArmLoaderBlock->u.Arm.PcrPage = (ULONG)Base >> PDE_SHIFT;
1444
1445 //
1446 // Build an entry for the KPCR and KUSER_SHARED_DATA
1447 //
1448 Status = ArmCreateMemoryDescriptor(LoaderStartupPcrPage,
1449 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1450 (2 * 1024 * 1024) / PAGE_SIZE,
1451 0,
1452 &Dummy);
1453 if (Status != STATUS_SUCCESS) return;
1454
1455 //
1456 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1457 //
1458 Base = MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage);
1459 MemBase = Base;
1460 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1461 ArmLoaderBlock->u.Arm.PdrPage = (ULONG)Base >> PDE_SHIFT;
1462
1463 //
1464 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1465 //
1466 Status = ArmCreateMemoryDescriptor(LoaderStartupPdrPage,
1467 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1468 (4 * 1024 * 1024) / PAGE_SIZE,
1469 0,
1470 &Dummy);
1471 if (Status != STATUS_SUCCESS) return;
1472
1473 //
1474 // Set initial PRCB, Thread and Process on the last PDR page
1475 //
1476 Base = (PVOID)((ULONG)Base + 2 * 1024 * 1024);
1477 ArmLoaderBlock->Prcb = KSEG0_BASE | (ULONG)Base;
1478 ArmLoaderBlock->Process = ArmLoaderBlock->Prcb + sizeof(KPRCB);
1479 ArmLoaderBlock->Thread = ArmLoaderBlock->Process + sizeof(EPROCESS);
1480
1481 //
1482 // Check if we're booting from RAM disk
1483 //
1484 if ((gRamDiskBase) && (gRamDiskSize))
1485 {
1486 //
1487 // Allocate a descriptor to describe it
1488 //
1489 Status = ArmCreateMemoryDescriptor(LoaderXIPRom,
1490 (ULONG_PTR)gRamDiskBase >> PAGE_SHIFT,
1491 gRamDiskSize / PAGE_SIZE,
1492 0,
1493 &Dummy);
1494 if (Status != STATUS_SUCCESS) return;
1495 }
1496
1497 //
1498 // Loop memory list
1499 //
1500 NextEntry = ArmLoaderBlock->MemoryDescriptorListHead.Flink;
1501 while (NextEntry != &ArmLoaderBlock->MemoryDescriptorListHead)
1502 {
1503 //
1504 // Remember the physical entry
1505 //
1506 OldEntry = NextEntry->Flink;
1507
1508 //
1509 // Edit the data
1510 //
1511 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1512 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1513
1514 //
1515 // Keep looping
1516 //
1517 NextEntry = OldEntry;
1518 }
1519
1520 //
1521 // Now edit the root itself
1522 //
1523 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1524 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1525
1526 //
1527 // Allocate ARC disk structure
1528 //
1529 ArcDiskInformation = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_INFORMATION));
1530 InitializeListHead(&ArcDiskInformation->DiskSignatureListHead);
1531 ArmLoaderBlock->ArcDiskInformation = (PVOID)((ULONG_PTR)ArcDiskInformation | KSEG0_BASE);
1532
1533 //
1534 // Read the MBR
1535 //
1536 MachDiskReadLogicalSectors(0x49, 0ULL, 1, (PVOID)DISKREADBUFFER);
1537 Buffer = (ULONG*)DISKREADBUFFER;
1538 Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
1539
1540 //
1541 // Calculate the MBR checksum
1542 //
1543 for (i = 0; i < 128; i++) Checksum += Buffer[i];
1544 Checksum = ~Checksum + 1;
1545
1546 //
1547 // Allocate a disk signature and fill it out
1548 //
1549 ArcDiskSignature = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_SIGNATURE));
1550 ArcDiskSignature->Signature = Mbr->Signature;
1551 ArcDiskSignature->CheckSum = Checksum;
1552
1553 //
1554 // Allocare a string for the name and fill it out
1555 //
1556 ArcDiskSignature->ArcName = ArmAllocateFromSharedHeap(256);
1557 sprintf(ArcDiskSignature->ArcName, "multi(0)disk(0)rdisk(%lu)", ArcDiskCount++);
1558 ArcDiskSignature->ArcName = (PVOID)((ULONG_PTR)ArcDiskSignature->ArcName | KSEG0_BASE);
1559
1560 //
1561 // Insert the descriptor into the list
1562 //
1563 InsertTailList(&ArcDiskInformation->DiskSignatureListHead,
1564 &ArcDiskSignature->ListEntry);
1565
1566 //
1567 // Loop ARC disk list
1568 //
1569 NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
1570 while (NextEntry != &ArcDiskInformation->DiskSignatureListHead)
1571 {
1572 //
1573 // Remember the physical entry
1574 //
1575 OldEntry = NextEntry->Flink;
1576
1577 //
1578 // Edit the data
1579 //
1580 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1581 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1582
1583 //
1584 // Keep looping
1585 //
1586 NextEntry = OldEntry;
1587 }
1588
1589 //
1590 // Now edit the root itself
1591 //
1592 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1593 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1594 }
1595
1596 VOID
1597 FrLdrStartup(IN ULONG Magic)
1598 {
1599 //
1600 // Disable interrupts (aleady done)
1601 //
1602
1603 //
1604 // Set proper CPSR (already done)
1605 //
1606
1607 //
1608 // Initialize the page directory
1609 //
1610 ArmSetupPageDirectory();
1611
1612 //
1613 // Initialize paging and load NTOSKRNL
1614 //
1615 ArmSetupPagingAndJump(Magic);
1616 }