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