b742a898b68c7f326e96b585fbe8242cd6f0f4ea
[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 PAGE_TABLE_ARM kernel_pagetable;
44 extern ROS_KERNEL_ENTRY_POINT KernelEntryPoint;
45 extern ULONG_PTR KernelBase;
46
47 extern ADDRESS_RANGE ArmBoardMemoryMap[16];
48 extern ULONG ArmBoardMemoryMapRangeCount;
49 extern ULONG_PTR AnsiData, OemData, UnicodeData, RegistryData, KernelData, HalData, DriverData[16];
50 extern ULONG RegistrySize, AnsiSize, OemSize, UnicodeSize, KernelSize, HalSize, DriverSize[16];
51 extern PCHAR DriverName[16];
52 extern ULONG Drivers;
53 extern ULONG BootStack;
54
55 ULONG SizeBits[] =
56 {
57 -1, // INVALID
58 -1, // INVALID
59 1 << 12, // 4KB
60 1 << 13, // 8KB
61 1 << 14, // 16KB
62 1 << 15, // 32KB
63 1 << 16, // 64KB
64 1 << 17 // 128KB
65 };
66
67 ULONG AssocBits[] =
68 {
69 -1, // INVALID
70 -1, // INVALID
71 4 // 4-way associative
72 };
73
74 ULONG LenBits[] =
75 {
76 -1, // INVALID
77 -1, // INVALID
78 8 // 8 words per line (32 bytes)
79 };
80
81 //
82 // Where to map the serial port
83 //
84 #define UART_VIRTUAL 0xE0000000
85
86 /* FUNCTIONS ******************************************************************/
87
88 PVOID
89 ArmAllocateFromSharedHeap(IN ULONG Size)
90 {
91 PVOID Buffer;
92
93 //
94 // Allocate from the shared heap
95 //
96 Buffer = &ArmSharedHeap[ArmSharedHeapSize];
97 ArmSharedHeapSize += Size;
98 return Buffer;
99 }
100
101 PMEMORY_ALLOCATION_DESCRIPTOR
102 NTAPI
103 ArmAllocateMemoryDescriptor(VOID)
104 {
105 //
106 // Allocate a descriptor from the heap
107 //
108 return ArmAllocateFromSharedHeap(sizeof(MEMORY_ALLOCATION_DESCRIPTOR));
109 }
110
111 VOID
112 NTAPI
113 ArmAddBoardMemoryDescriptor(IN ULONG Address,
114 IN ULONG Size)
115 {
116 PBIOS_MEMORY_DESCRIPTOR BiosBlock = ArmBoardMemoryList;
117
118 //
119 // Loop board DRAM configuration
120 //
121 while (BiosBlock->BlockSize > 0)
122 {
123 /* Check if we've found a matching head block */
124 if (Address + Size == BiosBlock->BlockBase)
125 {
126 /* Simply enlarge and rebase it */
127 BiosBlock->BlockBase = Address;
128 BiosBlock->BlockSize += Size;
129 break;
130 }
131
132 /* Check if we've found a matching tail block */
133 if (Address == (BiosBlock->BlockBase + BiosBlock->BlockSize))
134 {
135 /* Simply enlarge it */
136 BiosBlock->BlockSize += Size;
137 break;
138 }
139
140 /* Nothing suitable found, try the next block */
141 BiosBlock++;
142 }
143
144 /* No usable blocks found, found a free block instead */
145 if (!BiosBlock->BlockSize)
146 {
147 /* Write our data */
148 BiosBlock->BlockBase = Address;
149 BiosBlock->BlockSize = Size;
150
151 /* Create a new block and mark it as the end of the array */
152 BiosBlock++;
153 BiosBlock->BlockBase = BiosBlock->BlockSize = 0L;
154 }
155 }
156
157 VOID
158 NTAPI
159 ArmBuildBoardMemoryMap(VOID)
160 {
161 ULONG BlockBegin, BlockEnd;
162 ULONG j;
163
164 /* Loop the BIOS Memory Map */
165 for (j = 0; j < ArmBoardMemoryMapRangeCount; j++)
166 {
167 /* Get the start and end addresses */
168 BlockBegin = ArmBoardMemoryMap[j].BaseAddrLow;
169 BlockEnd = ArmBoardMemoryMap[j].BaseAddrLow + ArmBoardMemoryMap[j].LengthLow - 1;
170
171 /* Make sure this isn't a > 4GB descriptor */
172 if (!ArmBoardMemoryMap[j].BaseAddrHigh)
173 {
174 /* Make sure we don't overflow */
175 if (BlockEnd < BlockBegin) BlockEnd = 0xFFFFFFFF;
176
177 /* Check if this is free memory */
178 if (ArmBoardMemoryMap[j].Type == 1)
179 {
180 /* Add it to our BIOS descriptors */
181 ArmAddBoardMemoryDescriptor(BlockBegin, BlockEnd - BlockBegin + 1);
182 }
183 }
184 }
185 }
186
187 NTSTATUS
188 NTAPI
189 ArmConfigureArcDescriptor(IN ULONG PageBegin,
190 IN ULONG PageEnd,
191 IN TYPE_OF_MEMORY MemoryType)
192 {
193 ULONG i;
194 ULONG BlockBegin, BlockEnd;
195 MEMORY_TYPE BlockType;
196 BOOLEAN Combined = FALSE;
197
198 /* If this descriptor seems bogus, just return */
199 if (PageEnd <= PageBegin) return STATUS_SUCCESS;
200
201 /* Loop every ARC descriptor, trying to find one we can modify */
202 for (i = 0; i < NumberDescriptors; i++)
203 {
204 /* Get its settings */
205 BlockBegin = MDArray[i].BasePage;
206 BlockEnd = MDArray[i].BasePage + MDArray[i].PageCount;
207 BlockType = MDArray[i].MemoryType;
208
209 /* Check if we can fit inside this block */
210 if (BlockBegin < PageBegin)
211 {
212 /* Check if we are larger then it */
213 if ((BlockEnd > PageBegin) && (BlockEnd <= PageEnd))
214 {
215 /* Make it end where we start */
216 BlockEnd = PageBegin;
217 }
218
219 /* Check if it ends after we do */
220 if (BlockEnd > PageEnd)
221 {
222 /* Make sure we can allocate a descriptor */
223 if (NumberDescriptors == 60) return ENOMEM;
224
225 /* Create a descriptor for whatever memory we're not part of */
226 MDArray[NumberDescriptors].MemoryType = BlockType;
227 MDArray[NumberDescriptors].BasePage = PageEnd;
228 MDArray[NumberDescriptors].PageCount = BlockEnd - PageEnd;
229 NumberDescriptors++;
230
231 /* The next block ending is now where we begin */
232 BlockEnd = PageBegin;
233 }
234 }
235 else
236 {
237 /* Check if the blog begins inside our range */
238 if (BlockBegin < PageEnd)
239 {
240 /* Check if it ends before we do */
241 if (BlockEnd < PageEnd)
242 {
243 /* Then make it disappear */
244 BlockEnd = BlockBegin;
245 }
246 else
247 {
248 /* Otherwise make it start where we end */
249 BlockBegin = PageEnd;
250 }
251 }
252 }
253
254 /* Check if the block matches us, and we haven't tried combining yet */
255 if ((BlockType == MemoryType) && !(Combined))
256 {
257 /* Check if it starts where we end */
258 if (BlockBegin == PageEnd)
259 {
260 /* Make it start with us, and combine us */
261 BlockBegin = PageBegin;
262 Combined = TRUE;
263 }
264 else if (BlockEnd == PageBegin)
265 {
266 /* Otherwise, it ends where we begin, combine its ending */
267 BlockEnd = PageEnd;
268 Combined = TRUE;
269 }
270 }
271
272 /* Check the original block data matches with what we came up with */
273 if ((MDArray[i].BasePage == BlockBegin) &&
274 (MDArray[i].PageCount == BlockEnd - BlockBegin))
275 {
276 /* Then skip it */
277 continue;
278 }
279
280 /* Otherwise, set our new settings for this block */
281 MDArray[i].BasePage = BlockBegin;
282 MDArray[i].PageCount = BlockEnd - BlockBegin;
283
284 /* Check if we are killing the block */
285 if (BlockBegin == BlockEnd)
286 {
287 /* Delete this block and restart the loop properly */
288 NumberDescriptors--;
289 if (i < NumberDescriptors) MDArray[i] = MDArray[NumberDescriptors];
290 i--;
291 }
292 }
293
294 /* If we got here without combining, we need to allocate a new block */
295 if (!(Combined) && (MemoryType < LoaderMaximum))
296 {
297 /* Make sure there's enough descriptors */
298 if (NumberDescriptors == 60) return ENOMEM;
299
300 /* Allocate a new block with our data */
301 MDArray[NumberDescriptors].MemoryType = MemoryType;
302 MDArray[NumberDescriptors].BasePage = PageBegin;
303 MDArray[NumberDescriptors].PageCount = PageEnd - PageBegin;
304 NumberDescriptors++;
305 }
306
307 /* Changes complete, return success */
308 return STATUS_SUCCESS;
309 }
310
311 NTSTATUS
312 NTAPI
313 ArmBuildOsMemoryMap(VOID)
314 {
315 PBIOS_MEMORY_DESCRIPTOR MdBlock;
316 ULONG BlockStart, BlockEnd, BiasedStart, BiasedEnd, PageStart, PageEnd;
317 NTSTATUS Status = STATUS_SUCCESS;
318
319 /* Loop the BIOS Memory Descriptor List */
320 MdBlock = ArmBoardMemoryList;
321 while (MdBlock->BlockSize)
322 {
323 /* Get the statrt and end addresses */
324 BlockStart = MdBlock->BlockBase;
325 BlockEnd = BlockStart + MdBlock->BlockSize - 1;
326
327 /* Align them to page boundaries */
328 BiasedStart = BlockStart & (PAGE_SIZE - 1);
329 if (BiasedStart) BlockStart = BlockStart + PAGE_SIZE - BiasedStart;
330 BiasedEnd = (BlockEnd + 1) & (ULONG)(PAGE_SIZE - 1);
331 if (BiasedEnd) BlockEnd -= BiasedEnd;
332
333 /* Get the actual page numbers */
334 PageStart = BlockStart >> PAGE_SHIFT;
335 PageEnd = (BlockEnd + 1) >> PAGE_SHIFT;
336
337 /* Check if we did any alignment */
338 if (BiasedStart)
339 {
340 /* Mark that region as reserved */
341 Status = ArmConfigureArcDescriptor(PageStart - 1,
342 PageStart,
343 MemorySpecialMemory);
344 if (Status != STATUS_SUCCESS) break;
345 }
346
347 /* Check if we did any alignment */
348 if (BiasedEnd)
349 {
350 /* Mark that region as reserved */
351 Status = ArmConfigureArcDescriptor(PageEnd - 1,
352 PageEnd,
353 MemorySpecialMemory);
354 if (Status != STATUS_SUCCESS) break;
355 }
356
357 /* It is, mark the memory a free */
358 Status = ArmConfigureArcDescriptor(PageStart,
359 PageEnd,
360 LoaderFree);
361
362 /* If we failed, break out, otherwise, go to the next BIOS block */
363 if (Status != STATUS_SUCCESS) break;
364 MdBlock++;
365 }
366
367 /* Return error code */
368 return Status;
369 }
370
371 VOID
372 NTAPI
373 ArmInsertMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
374 {
375 PLIST_ENTRY ListHead, PreviousEntry, NextEntry;
376 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor = NULL, NextDescriptor = NULL;
377
378 /* Loop the memory descriptor list */
379 ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
380 PreviousEntry = ListHead;
381 NextEntry = ListHead->Flink;
382 while (NextEntry != ListHead)
383 {
384 /* Get the current descriptor and check if it's below ours */
385 NextDescriptor = CONTAINING_RECORD(NextEntry,
386 MEMORY_ALLOCATION_DESCRIPTOR,
387 ListEntry);
388 if (NewDescriptor->BasePage < NextDescriptor->BasePage) break;
389
390 /* It isn't, save the previous entry and descriptor, and try again */
391 PreviousEntry = NextEntry;
392 Descriptor = NextDescriptor;
393 NextEntry = NextEntry->Flink;
394 }
395
396 /* So we found the right spot to insert. Is this free memory? */
397 if (NewDescriptor->MemoryType != LoaderFree)
398 {
399 /* It isn't, so insert us before the last descriptor */
400 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
401 }
402 else
403 {
404 /* We're free memory. Check if the entry we found is also free memory */
405 if ((PreviousEntry != ListHead) &&
406 ((Descriptor->MemoryType == LoaderFree) ||
407 (Descriptor->MemoryType == LoaderReserve)) &&
408 ((Descriptor->BasePage + Descriptor->PageCount) ==
409 NewDescriptor->BasePage))
410 {
411 /* It's free memory, and we're right after it. Enlarge that block */
412 Descriptor->PageCount += NewDescriptor->PageCount;
413 NewDescriptor = Descriptor;
414 }
415 else
416 {
417 /* Our range scan't be combined, so just insert us separately */
418 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
419 }
420
421 /* Check if we merged with an existing free memory block */
422 if ((NextEntry != ListHead) &&
423 ((NextDescriptor->MemoryType == LoaderFree) ||
424 (NextDescriptor->MemoryType == LoaderReserve)) &&
425 ((NewDescriptor->BasePage + NewDescriptor->PageCount) ==
426 NextDescriptor->BasePage))
427 {
428 /* Update our own block */
429 NewDescriptor->PageCount += NextDescriptor->PageCount;
430
431 /* Remove the next block */
432 RemoveEntryList(&NextDescriptor->ListEntry);
433 }
434 }
435 }
436
437 NTSTATUS
438 NTAPI
439 ArmBuildMemoryDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptor,
440 IN MEMORY_TYPE MemoryType,
441 IN ULONG BasePage,
442 IN ULONG PageCount)
443 {
444 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor, NextDescriptor = NULL;
445 LONG Delta;
446 TYPE_OF_MEMORY CurrentType;
447 BOOLEAN UseNext;
448
449 /* Check how many pages we'll be consuming */
450 Delta = BasePage - MemoryDescriptor->BasePage;
451 if (!(Delta) && (PageCount == MemoryDescriptor->PageCount))
452 {
453 /* We can simply convert the current descriptor into our new type */
454 MemoryDescriptor->MemoryType = MemoryType;
455 }
456 else
457 {
458 /* Get the current memory type of the descriptor, and reserve it */
459 CurrentType = MemoryDescriptor->MemoryType;
460 MemoryDescriptor->MemoryType = LoaderSpecialMemory;
461
462 /* Check if we'll need another descriptor for what's left of memory */
463 UseNext = ((BasePage != MemoryDescriptor->BasePage) &&
464 (Delta + PageCount != MemoryDescriptor->PageCount));
465
466 /* Get a descriptor */
467 Descriptor = ArmAllocateMemoryDescriptor();
468 if (!Descriptor) return STATUS_INSUFFICIENT_RESOURCES;
469
470 /* Check if we are using another descriptor */
471 if (UseNext)
472 {
473 /* Allocate that one too */
474 NextDescriptor = ArmAllocateMemoryDescriptor();
475 if (!NextDescriptor) return STATUS_INSUFFICIENT_RESOURCES;
476 }
477
478 /* Build the descriptor we got */
479 Descriptor->MemoryType = MemoryType;
480 Descriptor->BasePage = BasePage;
481 Descriptor->PageCount = PageCount;
482
483 /* Check if we're starting at the same place as the old one */
484 if (BasePage == MemoryDescriptor->BasePage)
485 {
486 /* Simply decrease the old descriptor and rebase it */
487 MemoryDescriptor->BasePage += PageCount;
488 MemoryDescriptor->PageCount -= PageCount;
489 MemoryDescriptor->MemoryType = CurrentType;
490 }
491 else if (Delta + PageCount == MemoryDescriptor->PageCount)
492 {
493 /* We finish where the old one did, shorten it */
494 MemoryDescriptor->PageCount -= PageCount;
495 MemoryDescriptor->MemoryType = CurrentType;
496 }
497 else
498 {
499 /* We're inside the current block, mark our free region */
500 NextDescriptor->MemoryType = LoaderFree;
501 NextDescriptor->BasePage = BasePage + PageCount;
502 NextDescriptor->PageCount = MemoryDescriptor->PageCount -
503 (PageCount + Delta);
504
505 /* And cut down the current descriptor */
506 MemoryDescriptor->PageCount = Delta;
507 MemoryDescriptor->MemoryType = CurrentType;
508
509 /* Finally, insert our new free descriptor into the list */
510 ArmInsertMemoryDescriptor(NextDescriptor);
511 }
512
513 /* Insert the descriptor we allocated */
514 ArmInsertMemoryDescriptor(Descriptor);
515 }
516
517 /* Return success */
518 return STATUS_SUCCESS;
519 }
520
521 PMEMORY_ALLOCATION_DESCRIPTOR
522 NTAPI
523 ArmFindMemoryDescriptor(IN ULONG BasePage)
524 {
525 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
526 PLIST_ENTRY NextEntry, ListHead;
527
528 /* Scan the memory descriptor list */
529 ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
530 NextEntry = ListHead->Flink;
531 while (NextEntry != ListHead)
532 {
533 /* Get the current descriptor */
534 MdBlock = CONTAINING_RECORD(NextEntry,
535 MEMORY_ALLOCATION_DESCRIPTOR,
536 ListEntry);
537
538 /* Check if it can contain our memory range */
539 if ((MdBlock->BasePage <= BasePage) &&
540 (MdBlock->BasePage + MdBlock->PageCount > BasePage))
541 {
542 /* It can, break out */
543 break;
544 }
545
546 /* Go to the next descriptor */
547 NextEntry = NextEntry->Flink;
548 }
549
550 /* Return the descriptor we found, if any */
551 return MdBlock;
552 }
553
554 NTSTATUS
555 NTAPI
556 ArmCreateMemoryDescriptor(IN TYPE_OF_MEMORY MemoryType,
557 IN ULONG BasePage,
558 IN ULONG PageCount,
559 IN ULONG Alignment,
560 OUT PULONG ReturnedBase)
561 {
562 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock;
563 ULONG AlignedBase, AlignedLimit;
564 PMEMORY_ALLOCATION_DESCRIPTOR ActiveMdBlock;
565 ULONG ActiveAlignedBase = 0;
566 PLIST_ENTRY NextEntry, ListHead;
567
568 /* If no information was given, make some assumptions */
569 if (!Alignment) Alignment = 1;
570 if (!PageCount) PageCount = 1;
571
572 /* Start looking for a matching descvriptor */
573 do
574 {
575 /* Calculate the limit of the range */
576 AlignedLimit = PageCount + BasePage;
577
578 /* Find a descriptor that already contains our base address */
579 MdBlock = ArmFindMemoryDescriptor(BasePage);
580 if (MdBlock)
581 {
582 /* If it contains our limit as well, break out early */
583 if ((MdBlock->PageCount + MdBlock->BasePage) >= AlignedLimit) break;
584 }
585
586 /* Loop the memory list */
587 AlignedBase = 0;
588 ActiveMdBlock = NULL;
589 ListHead = &ArmLoaderBlock->MemoryDescriptorListHead;
590 NextEntry = ListHead->Flink;
591 while (NextEntry != ListHead)
592 {
593 /* Get the current descriptors */
594 MdBlock = CONTAINING_RECORD(NextEntry,
595 MEMORY_ALLOCATION_DESCRIPTOR,
596 ListEntry);
597
598 /* Align the base address and our limit */
599 AlignedBase = (MdBlock->BasePage + (Alignment - 1)) &~ Alignment;
600 AlignedLimit = MdBlock->PageCount -
601 AlignedBase +
602 MdBlock->BasePage;
603
604 /* Check if this is a free block that can satisfy us */
605 if ((MdBlock->MemoryType == LoaderFree) &&
606 (AlignedLimit <= MdBlock->PageCount) &&
607 (PageCount <= AlignedLimit))
608 {
609 /* It is, stop searching */
610 ActiveMdBlock = MdBlock;
611 ActiveAlignedBase = AlignedBase;
612 break;
613 }
614
615 /* Try the next block */
616 NextEntry = NextEntry->Flink;
617 }
618
619 /* See if we came up with an adequate block */
620 if (ActiveMdBlock)
621 {
622 /* Generate a descriptor in it */
623 *ReturnedBase = AlignedBase;
624 return ArmBuildMemoryDescriptor(ActiveMdBlock,
625 MemoryType,
626 ActiveAlignedBase,
627 PageCount);
628 }
629 } while (TRUE);
630
631 /* We found a matching block, generate a descriptor with it */
632 *ReturnedBase = BasePage;
633 return ArmBuildMemoryDescriptor(MdBlock, MemoryType, BasePage, PageCount);
634 }
635
636 NTSTATUS
637 NTAPI
638 ArmBuildLoaderMemoryList(VOID)
639 {
640 PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
641 MEMORY_DESCRIPTOR *Memory;
642 ULONG i;
643
644 /* Loop all BIOS Memory Descriptors */
645 for (i = 0; i < NumberDescriptors; i++)
646 {
647 /* Get the current descriptor */
648 Memory = &MDArray[i];
649
650 /* Allocate an NT Memory Descriptor */
651 Descriptor = ArmAllocateMemoryDescriptor();
652 if (!Descriptor) return ENOMEM;
653
654 /* Copy the memory type */
655 Descriptor->MemoryType = Memory->MemoryType;
656 if (Memory->MemoryType == MemoryFreeContiguous)
657 {
658 /* Convert this to free */
659 Descriptor->MemoryType = LoaderFree;
660 }
661 else if (Memory->MemoryType == MemorySpecialMemory)
662 {
663 /* Convert this to special memory */
664 Descriptor->MemoryType = LoaderSpecialMemory;
665 }
666
667 /* Copy the range data */
668 Descriptor->BasePage = Memory->BasePage;
669 Descriptor->PageCount = Memory->PageCount;
670
671 /* Insert the descriptor */
672 if (Descriptor->PageCount) ArmInsertMemoryDescriptor(Descriptor);
673 }
674
675 /* All went well */
676 return STATUS_SUCCESS;
677 }
678
679 #define PFN_SHIFT 12
680 #define LARGE_PFN_SHIFT 20
681
682 #define PTE_BASE 0xC0000000
683 #define PDE_BASE 0xC0400000
684 #define HAL_BASE 0xFFC00000
685 #define MMIO_BASE 0x10000000
686
687 #define LowMemPageTableIndex 0
688 #define StartupPtePageTableIndex (PTE_BASE >> PDE_SHIFT)
689 #define StartupPdePageTableIndex (PDE_BASE >> PDE_SHIFT)
690 #define MmioPageTableIndex (MMIO_BASE >> PDE_SHIFT)
691 #define HalPageTableIndex (HAL_BASE >> PDE_SHIFT)
692
693 /* Converts a Physical Address into a Page Frame Number */
694 #define PaToPfn(p) ((p) >> PFN_SHIFT)
695 #define PaToLargePfn(p) ((p) >> LARGE_PFN_SHIFT)
696 #define PaPtrToPfn(p) (((ULONG_PTR)(p)) >> PFN_SHIFT)
697
698 /* Converts a Physical Address into a Coarse Page Table PFN */
699 #define PaPtrToPdePfn(p) (((ULONG_PTR)(p)) >> CPT_SHIFT)
700
701 HARDWARE_PTE_ARMV6 TempPte;
702 HARDWARE_LARGE_PTE_ARMV6 TempLargePte;
703 HARDWARE_PDE_ARMV6 TempPde;
704
705 PVOID
706 ArmSetupPageDirectory(VOID)
707 {
708 PPAGE_DIRECTORY_ARM PageDir;
709 PPAGE_TABLE_ARM PageTable, KernelPageTable;
710 ULONG KernelPageTableIndex;
711 ULONG i;
712 PHARDWARE_PTE_ARMV6 PointerPte;
713 PHARDWARE_PDE_ARMV6 PointerPde;
714 PHARDWARE_LARGE_PTE_ARMV6 LargePte;
715 PFN_NUMBER Pfn;
716
717 /* Setup templates */
718 TempPte.Accessed = TempPte.Valid = TempLargePte.LargePage = TempLargePte.Accessed = TempPde.Valid = 1;
719
720 /* Get the Kernel Table Index */
721 KernelPageTableIndex = KernelBase >> PDE_SHIFT;
722 printf("Kernel Base: 0x%p (PDE Index: %lx)\n", KernelBase, KernelPageTableIndex);
723
724 /* Allocate 1MB PDE_BASE and HYPER_SPACE. This will be improved later. Must be 1MB aligned */
725 PageDir = MmAllocateMemoryAtAddress(1 * 1024 * 1024, (PVOID)0x700000, LoaderMemoryData);
726 if (!PageDir) { printf("FATAL: No memory!\n"); while (TRUE); }
727 printf("Initial Page Directory: 0x%p\n", PageDir);
728
729 /* Setup the Low Memory PDE as an identity-mapped Large Page (1MB) */
730 LargePte = &PageDir->Pte[LowMemPageTableIndex];
731 *LargePte = TempLargePte;
732
733 /* Setup the MMIO PDE as two identity mapped large pages -- the kernel will blow these away later */
734 LargePte = &PageDir->Pte[MmioPageTableIndex];
735 Pfn = PaToLargePfn(0x10000000);
736 for (i = 0; i < 2; i++)
737 {
738 TempLargePte.PageFrameNumber = Pfn++;
739 *LargePte++ = TempLargePte;
740 }
741
742 /* Allocate 8 page tables (8KB) to describe the 8MB initial kernel region */
743 KernelPageTable = MmAllocateMemoryWithType(8192, LoaderMemoryData);
744 if (!KernelPageTable) { printf("FATAL: No memory!\n"); while (TRUE); }
745 printf("Kernel Page Tables: 0x%p\n", KernelPageTable);
746
747 /* Setup the Kernel PDEs */
748 PointerPde = &PageDir->Pde[KernelPageTableIndex];
749 Pfn = PaPtrToPdePfn(KernelPageTable);
750 for (i = 0; i < 8; i++)
751 {
752 TempPde.PageFrameNumber = Pfn++;
753 *PointerPde++ = TempPde;
754 }
755
756 /* Setup the Startup PDE */
757 printf("PAGEDIR: %p IDX: %lx PPDE: %p PFN: %lx \n", PageDir, StartupPdePageTableIndex, &PageDir->Pte[StartupPdePageTableIndex], PaToLargePfn((ULONG_PTR)PageDir));
758 LargePte = &PageDir->Pte[StartupPdePageTableIndex];
759 TempLargePte.PageFrameNumber = PaToLargePfn((ULONG_PTR)PageDir);
760 printf("PAGEDIR: %p IDX: %lx PPDE: %p PFN: %lx \n", PageDir, StartupPdePageTableIndex, LargePte, TempLargePte.PageFrameNumber);
761 *LargePte = TempLargePte;
762
763 /* After this point, any MiAddressToPde is guaranteed not to fault */
764
765 /* Allocate 4 page tables (4KB) to describe the 4MB PTE_BASE region */
766 PageTable = MmAllocateMemoryWithType(4096, LoaderMemoryData);
767 if (!PageTable) { printf("FATAL: No memory!\n"); while (TRUE); }
768 printf("Initial Page Tables: 0x%p\n", PageTable);
769
770 /*
771 * Link them in the Startup PDE.
772 * Note these are the entries in the PD at (MiAddressToPde(PTE_BASE)).
773 */
774 PointerPde = &PageDir->Pde[StartupPtePageTableIndex];
775 Pfn = PaPtrToPdePfn(PageTable);
776 for (i = 0; i < 4; i++)
777 {
778 TempPde.PageFrameNumber = Pfn++;
779 *PointerPde++ = TempPde;
780 }
781
782 /*
783 * Now map these page tables in PTE space (MiAddressToPte(PTE_BASE)).
784 * Note that they all live on a single page, since each is 1KB.
785 */
786 PointerPte = &PageTable->Pte[0x300];
787 TempPte.PageFrameNumber = PaPtrToPfn(PageTable);
788 *PointerPte = TempPte;
789
790 /*
791 * After this point, MiAddressToPte((PDE_BASE) to MiAddressToPte(PDE_TOP))
792 * is guaranteed not to fault.
793 * Any subsequent page allocation will first need its page table created
794 * and mapped in the PTE_BASE first, then the page table itself will be
795 * editable through its flat PTE address.
796 */
797 printf("Paging init done\n");
798 return PageDir;
799 }
800
801 VOID
802 ArmSetupPagingAndJump(IN PVOID PageDirectoryBaseAddress)
803 {
804 ARM_CONTROL_REGISTER ControlRegister;
805 ARM_TTB_REGISTER TtbRegister;
806 ARM_DOMAIN_REGISTER DomainRegister;
807
808 /* Set the TTBR */
809 TtbRegister.AsUlong = (ULONG_PTR)PageDirectoryBaseAddress;
810 ASSERT(TtbRegister.Reserved == 0);
811 KeArmTranslationTableRegisterSet(TtbRegister);
812
813 /* Disable domains and simply use access bits on PTEs */
814 DomainRegister.AsUlong = 0;
815 DomainRegister.Domain0 = ClientDomain;
816 KeArmDomainRegisterSet(DomainRegister);
817
818 /* Enable ARMv6+ paging (MMU), caches and the access bit */
819 ControlRegister = KeArmControlRegisterGet();
820 ControlRegister.MmuEnabled = TRUE;
821 ControlRegister.ICacheEnabled = TRUE;
822 ControlRegister.DCacheEnabled = TRUE;
823 ControlRegister.ForceAp = TRUE;
824 ControlRegister.ExtendedPageTables = TRUE;
825 KeArmControlRegisterSet(ControlRegister);
826
827 /* Jump to Kernel */
828 TuiPrintf("Hello from MMU Enabled!\n");
829 while (TRUE);
830 (*KernelEntryPoint)((PVOID)((ULONG_PTR)ArmLoaderBlock | KSEG0_BASE));
831 }
832
833 VOID
834 ArmPrepareForReactOS(IN BOOLEAN Setup)
835 {
836 ARM_CACHE_REGISTER CacheReg;
837 PVOID Base, MemBase;
838 PCHAR BootPath, HalPath;
839 NTSTATUS Status;
840 ULONG Dummy, i;
841 PLDR_DATA_TABLE_ENTRY LdrEntry;
842 PLIST_ENTRY NextEntry, OldEntry;
843 PARC_DISK_INFORMATION ArcDiskInformation;
844 PARC_DISK_SIGNATURE ArcDiskSignature;
845 ULONG ArcDiskCount = 0;
846 #if 0
847 ULONG Checksum = 0;
848 PMASTER_BOOT_RECORD Mbr;
849 PULONG Buffer;
850 #endif
851 PWCHAR ArmModuleName;
852
853 //
854 // Allocate the ARM Shared Heap
855 //
856 ArmSharedHeap = MmAllocateMemoryWithType(PAGE_SIZE, LoaderOsloaderHeap);
857 ArmSharedHeapSize = 0;
858 if (!ArmSharedHeap) return;
859
860 //
861 // Allocate the loader block and extension
862 //
863 ArmLoaderBlock = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_BLOCK));
864 if (!ArmLoaderBlock) return;
865 ArmExtension = ArmAllocateFromSharedHeap(sizeof(LOADER_PARAMETER_EXTENSION));
866 if (!ArmExtension) return;
867
868 //
869 // Initialize the loader block
870 //
871 InitializeListHead(&ArmLoaderBlock->BootDriverListHead);
872 InitializeListHead(&ArmLoaderBlock->LoadOrderListHead);
873 InitializeListHead(&ArmLoaderBlock->MemoryDescriptorListHead);
874
875 //
876 // Setup the extension and setup block
877 //
878 ArmLoaderBlock->Extension = (PVOID)((ULONG_PTR)ArmExtension | KSEG0_BASE);
879 ArmLoaderBlock->SetupLdrBlock = NULL;
880
881 //
882 // Add the Board Memory Map from U-Boot into the STARTUP.COM-style
883 // BIOS descriptor format -- this needs to be removed later.
884 //
885 ArmBuildBoardMemoryMap();
886
887 //
888 // Now basically convert these entries to the ARC format, so that we can
889 // get a good map of free (usable) memory
890 //
891 ArmBuildOsMemoryMap();
892
893 //
894 // NT uses an extended ARC format, with slightly different memory types.
895 // We also want to link the ARC descriptors together into a linked list,
896 // instead of the array, and allocate the semi-permanent storage in which
897 // these entries will be stored so that the kernel can read them.
898 //
899 ArmBuildLoaderMemoryList();
900
901 //
902 // Setup descriptor for the shared heap
903 //
904 Status = ArmCreateMemoryDescriptor(LoaderOsloaderHeap,
905 (ULONG_PTR)ArmSharedHeap >> PAGE_SHIFT,
906 ADDRESS_AND_SIZE_TO_SPAN_PAGES(ArmSharedHeap,
907 ArmSharedHeapSize),
908 0,
909 &Dummy);
910 if (Status != STATUS_SUCCESS) return;
911
912 //
913 // Setup descriptor for the boot stack
914 //
915 Status = ArmCreateMemoryDescriptor(LoaderOsloaderStack,
916 (ULONG_PTR)&BootStack >> PAGE_SHIFT,
917 4,
918 0,
919 &Dummy);
920 if (Status != STATUS_SUCCESS) return;
921 #if 0
922 //
923 // Setup descriptor for the boot page tables
924 //
925 Status = ArmCreateMemoryDescriptor(LoaderMemoryData,
926 (ULONG_PTR)&TranslationTableStart >> PAGE_SHIFT,
927 ((ULONG_PTR)&TranslationTableEnd -
928 (ULONG_PTR)&TranslationTableStart) / PAGE_SIZE,
929 0,
930 &Dummy);
931 if (Status != STATUS_SUCCESS) return;
932 #endif
933 //
934 // Setup descriptor for the kernel
935 //
936 Status = ArmCreateMemoryDescriptor(LoaderSystemCode,
937 KernelData >> PAGE_SHIFT,
938 ADDRESS_AND_SIZE_TO_SPAN_PAGES(KernelData,
939 KernelSize),
940 0,
941 &Dummy);
942 if (Status != STATUS_SUCCESS) return;
943
944 //
945 // Setup descriptor for the HAL
946 //
947 Status = ArmCreateMemoryDescriptor(LoaderHalCode,
948 HalData >> PAGE_SHIFT,
949 ADDRESS_AND_SIZE_TO_SPAN_PAGES(HalData,
950 HalSize),
951 0,
952 &Dummy);
953 if (Status != STATUS_SUCCESS) return;
954
955 //
956 // Setup registry data
957 //
958 ArmLoaderBlock->RegistryBase = (PVOID)((ULONG_PTR)RegistryData | KSEG0_BASE);
959 ArmLoaderBlock->RegistryLength = RegistrySize;
960
961 //
962 // Create an MD for it
963 //
964 Status = ArmCreateMemoryDescriptor(LoaderRegistryData,
965 RegistryData >> PAGE_SHIFT,
966 ADDRESS_AND_SIZE_TO_SPAN_PAGES(RegistryData,
967 RegistrySize),
968 0,
969 &Dummy);
970 if (Status != STATUS_SUCCESS) return;
971
972 //
973 // TODO: Setup ARC Hardware tree data
974 //
975
976 //
977 // Setup NLS data
978 //
979 ArmNlsDataBlock = ArmAllocateFromSharedHeap(sizeof(NLS_DATA_BLOCK));
980 ArmLoaderBlock->NlsData = ArmNlsDataBlock;
981 ArmLoaderBlock->NlsData->AnsiCodePageData = (PVOID)(AnsiData | KSEG0_BASE);
982 ArmLoaderBlock->NlsData->OemCodePageData = (PVOID)(OemData | KSEG0_BASE);
983 ArmLoaderBlock->NlsData->UnicodeCodePageData = (PVOID)(UnicodeData | KSEG0_BASE);
984 ArmLoaderBlock->NlsData = (PVOID)((ULONG_PTR)ArmLoaderBlock->NlsData | KSEG0_BASE);
985
986 //
987 // Setup ANSI NLS Memory Descriptor
988 //
989 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
990 AnsiData >> PAGE_SHIFT,
991 ADDRESS_AND_SIZE_TO_SPAN_PAGES(AnsiData,
992 AnsiSize),
993 0,
994 &Dummy);
995 if (Status != STATUS_SUCCESS) return;
996
997 //
998 // Setup OEM NLS Memory Descriptor
999 //
1000 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1001 OemData >> PAGE_SHIFT,
1002 ADDRESS_AND_SIZE_TO_SPAN_PAGES(OemData,
1003 OemSize),
1004 0,
1005 &Dummy);
1006 if (Status != STATUS_SUCCESS) return;
1007
1008 //
1009 // Setup Unicode NLS Memory Descriptor
1010 //
1011 Status = ArmCreateMemoryDescriptor(LoaderNlsData,
1012 UnicodeData >> PAGE_SHIFT,
1013 ADDRESS_AND_SIZE_TO_SPAN_PAGES(UnicodeData,
1014 UnicodeSize),
1015 0,
1016 &Dummy);
1017 if (Status != STATUS_SUCCESS) return;
1018
1019 //
1020 // Setup loader entry for the kernel
1021 //
1022 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1023 wcscpy(ArmModuleName, L"ntoskrnl.exe");
1024 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1025 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1026 LdrEntry->DllBase = (PVOID)KernelBase;
1027 LdrEntry->SizeOfImage = KernelSize;
1028 LdrEntry->EntryPoint = KernelEntryPoint;
1029 LdrEntry->LoadCount = 1;
1030 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1031 RtlInitUnicodeString(&LdrEntry->FullDllName, ArmModuleName);
1032 RtlInitUnicodeString(&LdrEntry->BaseDllName, ArmModuleName);
1033 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1034 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1035 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1036
1037 //
1038 // Setup loader entry for the HAL
1039 //
1040 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1041 wcscpy(ArmModuleName, L"hal.dll");
1042 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1043 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1044 LdrEntry->DllBase = (PVOID)(HalData | KSEG0_BASE);
1045 LdrEntry->SizeOfImage = HalSize;
1046 LdrEntry->EntryPoint = (PVOID)RtlImageNtHeader((PVOID)HalData)->
1047 OptionalHeader.AddressOfEntryPoint;
1048 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)LdrEntry->EntryPoint | KSEG0_BASE);
1049 LdrEntry->LoadCount = 1;
1050 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1051 RtlInitUnicodeString(&LdrEntry->FullDllName, ArmModuleName);
1052 RtlInitUnicodeString(&LdrEntry->BaseDllName, ArmModuleName);
1053 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1054 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1055 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1056
1057 //
1058 // Build descriptors for the drivers loaded
1059 //
1060 for (i = 0; i < Drivers; i++)
1061 {
1062 //
1063 // Setup loader entry for the driver
1064 //
1065 LdrEntry = ArmAllocateFromSharedHeap(sizeof(LDR_DATA_TABLE_ENTRY));
1066 RtlZeroMemory(LdrEntry, sizeof(LDR_DATA_TABLE_ENTRY));
1067 LdrEntry->DllBase = (PVOID)(DriverData[i] | KSEG0_BASE);
1068 LdrEntry->SizeOfImage = DriverSize[i];
1069 LdrEntry->EntryPoint = (PVOID)RtlImageNtHeader((PVOID)DriverData[i])->
1070 OptionalHeader.AddressOfEntryPoint;
1071 LdrEntry->EntryPoint = (PVOID)((ULONG_PTR)LdrEntry->EntryPoint | KSEG0_BASE);
1072 LdrEntry->LoadCount = 1;
1073 LdrEntry->Flags = LDRP_IMAGE_DLL | LDRP_ENTRY_PROCESSED;
1074 ArmModuleName = ArmAllocateFromSharedHeap(64 * sizeof(WCHAR));
1075 RtlZeroMemory(ArmModuleName, 64 * sizeof(WCHAR));
1076 LdrEntry->FullDllName.Length = strlen(DriverName[i]) * sizeof(WCHAR);
1077 LdrEntry->FullDllName.MaximumLength = LdrEntry->FullDllName.Length;
1078 LdrEntry->FullDllName.Buffer = ArmModuleName;
1079 LdrEntry->BaseDllName = LdrEntry->FullDllName;
1080 while (*DriverName[i]) *ArmModuleName++ = *DriverName[i]++;
1081 LdrEntry->FullDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->FullDllName.Buffer | KSEG0_BASE);
1082 LdrEntry->BaseDllName.Buffer = (PVOID)((ULONG_PTR)LdrEntry->BaseDllName.Buffer | KSEG0_BASE);
1083 InsertTailList(&ArmLoaderBlock->LoadOrderListHead, &LdrEntry->InLoadOrderLinks);
1084
1085 //
1086 // Build a descriptor for the driver
1087 //
1088 Status = ArmCreateMemoryDescriptor(LoaderBootDriver,
1089 DriverData[i] >> PAGE_SHIFT,
1090 ADDRESS_AND_SIZE_TO_SPAN_PAGES(DriverData[i],
1091 DriverSize[i]),
1092 0,
1093 &Dummy);
1094 if (Status != STATUS_SUCCESS) return;
1095 }
1096
1097 //
1098 // Loop driver list
1099 //
1100 NextEntry = ArmLoaderBlock->LoadOrderListHead.Flink;
1101 while (NextEntry != &ArmLoaderBlock->LoadOrderListHead)
1102 {
1103 //
1104 // Remember the physical entry
1105 //
1106 OldEntry = NextEntry->Flink;
1107
1108 //
1109 // Edit the data
1110 //
1111 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1112 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1113
1114 //
1115 // Keep looping
1116 //
1117 NextEntry = OldEntry;
1118 }
1119
1120 //
1121 // Now edit the root itself
1122 //
1123 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1124 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1125
1126 //
1127 // Setup extension parameters
1128 //
1129 ArmExtension->Size = sizeof(LOADER_PARAMETER_EXTENSION);
1130 ArmExtension->MajorVersion = 5;
1131 ArmExtension->MinorVersion = 2;
1132
1133 //
1134 // Make a copy of the command line
1135 //
1136 ArmLoaderBlock->LoadOptions = ArmCommandLine;
1137 strcpy(ArmCommandLine, reactos_kernel_cmdline);
1138
1139 //
1140 // Find the first \, separating the ARC path from NT path
1141 //
1142 BootPath = strchr(ArmCommandLine, '\\');
1143 *BootPath = ANSI_NULL;
1144
1145 //
1146 // Set the ARC Boot Path
1147 //
1148 strncpy(ArmArcBootPath, ArmCommandLine, 63);
1149 ArmLoaderBlock->ArcBootDeviceName = (PVOID)((ULONG_PTR)ArmArcBootPath | KSEG0_BASE);
1150
1151 //
1152 // The rest of the string is the NT path
1153 //
1154 HalPath = strchr(BootPath + 1, ' ');
1155 *HalPath = ANSI_NULL;
1156 ArmNtBootPath[0] = '\\';
1157 strncat(ArmNtBootPath, BootPath + 1, 63);
1158 strcat(ArmNtBootPath,"\\");
1159 ArmLoaderBlock->NtBootPathName = (PVOID)((ULONG_PTR)ArmNtBootPath | KSEG0_BASE);
1160
1161 //
1162 // Set the HAL paths
1163 //
1164 strncpy(ArmArcHalPath, ArmArcBootPath, 63);
1165 ArmLoaderBlock->ArcHalDeviceName = (PVOID)((ULONG_PTR)ArmArcHalPath | KSEG0_BASE);
1166 strcpy(ArmNtHalPath, "\\");
1167 ArmLoaderBlock->NtHalPathName = (PVOID)((ULONG_PTR)ArmNtHalPath | KSEG0_BASE);
1168
1169 //
1170 // Use this new command line
1171 //
1172 strncpy(ArmLoaderBlock->LoadOptions, HalPath + 2, 255);
1173
1174 //
1175 // Parse it and change every slash to a space
1176 //
1177 BootPath = ArmLoaderBlock->LoadOptions;
1178 do {if (*BootPath == '/') *BootPath = ' ';} while (*BootPath++);
1179
1180 //
1181 // Fixup command-line pointer
1182 //
1183 ArmLoaderBlock->LoadOptions = (PVOID)((ULONG_PTR)ArmLoaderBlock->LoadOptions | KSEG0_BASE);
1184
1185 //
1186 // Setup cache information
1187 //
1188 CacheReg = KeArmCacheRegisterGet();
1189 ArmLoaderBlock->u.Arm.FirstLevelDcacheSize = SizeBits[CacheReg.DSize];
1190 ArmLoaderBlock->u.Arm.FirstLevelDcacheFillSize = LenBits[CacheReg.DLength];
1191 ArmLoaderBlock->u.Arm.FirstLevelDcacheFillSize <<= 2;
1192 ArmLoaderBlock->u.Arm.FirstLevelIcacheSize = SizeBits[CacheReg.ISize];
1193 ArmLoaderBlock->u.Arm.FirstLevelIcacheFillSize = LenBits[CacheReg.ILength];
1194 ArmLoaderBlock->u.Arm.FirstLevelIcacheFillSize <<= 2;
1195 ArmLoaderBlock->u.Arm.SecondLevelDcacheSize =
1196 ArmLoaderBlock->u.Arm.SecondLevelDcacheFillSize =
1197 ArmLoaderBlock->u.Arm.SecondLevelIcacheSize =
1198 ArmLoaderBlock->u.Arm.SecondLevelIcacheFillSize = 0;
1199
1200 //
1201 // Allocate the Interrupt stack
1202 //
1203 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupDpcStack);
1204 ArmLoaderBlock->u.Arm.InterruptStack = KSEG0_BASE | (ULONG)Base;
1205 ArmLoaderBlock->u.Arm.InterruptStack += KERNEL_STACK_SIZE;
1206
1207 //
1208 // Build an entry for it
1209 //
1210 Status = ArmCreateMemoryDescriptor(LoaderStartupDpcStack,
1211 (ULONG_PTR)Base >> PAGE_SHIFT,
1212 KERNEL_STACK_SIZE / PAGE_SIZE,
1213 0,
1214 &Dummy);
1215 if (Status != STATUS_SUCCESS) return;
1216
1217 //
1218 // Allocate the Kernel Boot stack
1219 //
1220 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupKernelStack);
1221 ArmLoaderBlock->KernelStack = KSEG0_BASE | (ULONG)Base;
1222 ArmLoaderBlock->KernelStack += KERNEL_STACK_SIZE;
1223
1224 //
1225 // Build an entry for it
1226 //
1227 Status = ArmCreateMemoryDescriptor(LoaderStartupKernelStack,
1228 (ULONG_PTR)Base >> PAGE_SHIFT,
1229 KERNEL_STACK_SIZE / PAGE_SIZE,
1230 0,
1231 &Dummy);
1232 if (Status != STATUS_SUCCESS) return;
1233
1234 //
1235 // Allocate the Abort stack
1236 //
1237 Base = MmAllocateMemoryWithType(KERNEL_STACK_SIZE, LoaderStartupPanicStack);
1238 ArmLoaderBlock->u.Arm.PanicStack = KSEG0_BASE | (ULONG)Base;
1239 ArmLoaderBlock->u.Arm.PanicStack += KERNEL_STACK_SIZE;
1240
1241 //
1242 // Build an entry for it
1243 //
1244 Status = ArmCreateMemoryDescriptor(LoaderStartupPanicStack,
1245 (ULONG_PTR)Base >> PAGE_SHIFT,
1246 KERNEL_STACK_SIZE / PAGE_SIZE,
1247 0,
1248 &Dummy);
1249 if (Status != STATUS_SUCCESS) return;
1250
1251 //
1252 // Allocate the PCR/KUSER_SHARED page -- align it to 1MB (we only need 2x4KB)
1253 //
1254 Base = MmAllocateMemoryWithType(2 * 1024 * 1024, LoaderStartupPcrPage);
1255 MemBase = Base;
1256 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1257 ArmLoaderBlock->u.Arm.PcrPage = (ULONG)Base >> PDE_SHIFT;
1258
1259 //
1260 // Build an entry for the KPCR and KUSER_SHARED_DATA
1261 //
1262 Status = ArmCreateMemoryDescriptor(LoaderStartupPcrPage,
1263 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1264 (2 * 1024 * 1024) / PAGE_SIZE,
1265 0,
1266 &Dummy);
1267 if (Status != STATUS_SUCCESS) return;
1268
1269 //
1270 // Allocate PDR pages -- align them to 1MB (we only need 3x4KB)
1271 //
1272 Base = MmAllocateMemoryWithType(4 * 1024 * 1024, LoaderStartupPdrPage);
1273 MemBase = Base;
1274 Base = (PVOID)ROUND_UP(Base, 1 * 1024 * 1024);
1275 ArmLoaderBlock->u.Arm.PdrPage = (ULONG)Base >> PDE_SHIFT;
1276
1277 //
1278 // Build an entry for the PDR, PRCB and initial KPROCESS/KTHREAD
1279 //
1280 Status = ArmCreateMemoryDescriptor(LoaderStartupPdrPage,
1281 (ULONG_PTR)MemBase >> PAGE_SHIFT,
1282 (4 * 1024 * 1024) / PAGE_SIZE,
1283 0,
1284 &Dummy);
1285 if (Status != STATUS_SUCCESS) return;
1286
1287 //
1288 // Set initial PRCB, Thread and Process on the last PDR page
1289 //
1290 Base = (PVOID)((ULONG)Base + 2 * 1024 * 1024);
1291 ArmLoaderBlock->Prcb = KSEG0_BASE | (ULONG)Base;
1292 ArmLoaderBlock->Process = ArmLoaderBlock->Prcb + sizeof(KPRCB);
1293 ArmLoaderBlock->Thread = ArmLoaderBlock->Process + sizeof(EPROCESS);
1294
1295 //
1296 // Check if we're booting from RAM disk
1297 //
1298 if ((gRamDiskBase) && (gRamDiskSize))
1299 {
1300 //
1301 // Allocate a descriptor to describe it
1302 //
1303 Status = ArmCreateMemoryDescriptor(LoaderXIPRom,
1304 (ULONG_PTR)gRamDiskBase >> PAGE_SHIFT,
1305 gRamDiskSize / PAGE_SIZE,
1306 0,
1307 &Dummy);
1308 if (Status != STATUS_SUCCESS) return;
1309 }
1310
1311 //
1312 // Loop memory list
1313 //
1314 NextEntry = ArmLoaderBlock->MemoryDescriptorListHead.Flink;
1315 while (NextEntry != &ArmLoaderBlock->MemoryDescriptorListHead)
1316 {
1317 //
1318 // Remember the physical entry
1319 //
1320 OldEntry = NextEntry->Flink;
1321
1322 //
1323 // Edit the data
1324 //
1325 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1326 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1327
1328 //
1329 // Keep looping
1330 //
1331 NextEntry = OldEntry;
1332 }
1333
1334 //
1335 // Now edit the root itself
1336 //
1337 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1338 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1339
1340 //
1341 // Allocate ARC disk structure
1342 //
1343 ArcDiskInformation = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_INFORMATION));
1344 InitializeListHead(&ArcDiskInformation->DiskSignatureListHead);
1345 ArmLoaderBlock->ArcDiskInformation = (PVOID)((ULONG_PTR)ArcDiskInformation | KSEG0_BASE);
1346
1347 #if 0
1348 //
1349 // Read the MBR
1350 //
1351 MachDiskReadLogicalSectors(0x49, 0ULL, 1, (PVOID)DISKREADBUFFER);
1352 Buffer = (ULONG*)DISKREADBUFFER;
1353 Mbr = (PMASTER_BOOT_RECORD)DISKREADBUFFER;
1354
1355 //
1356 // Calculate the MBR checksum
1357 //
1358 for (i = 0; i < 128; i++) Checksum += Buffer[i];
1359 Checksum = ~Checksum + 1;
1360
1361 #endif
1362 //
1363 // Allocate a disk signature and fill it out
1364 //
1365 ArcDiskSignature = ArmAllocateFromSharedHeap(sizeof(ARC_DISK_SIGNATURE));
1366 ArcDiskSignature->Signature = 0xBADAB00B;// Mbr->Signature;
1367 ArcDiskSignature->CheckSum = 0xFAB4BEEF; //Checksum;
1368
1369 //
1370 // Allocare a string for the name and fill it out
1371 //
1372 ArcDiskSignature->ArcName = ArmAllocateFromSharedHeap(256);
1373 sprintf(ArcDiskSignature->ArcName, "multi(0)disk(0)rdisk(%lu)", ArcDiskCount++);
1374 ArcDiskSignature->ArcName = (PVOID)((ULONG_PTR)ArcDiskSignature->ArcName | KSEG0_BASE);
1375
1376 //
1377 // Insert the descriptor into the list
1378 //
1379 InsertTailList(&ArcDiskInformation->DiskSignatureListHead,
1380 &ArcDiskSignature->ListEntry);
1381
1382 //
1383 // Loop ARC disk list
1384 //
1385 NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
1386 while (NextEntry != &ArcDiskInformation->DiskSignatureListHead)
1387 {
1388 //
1389 // Remember the physical entry
1390 //
1391 OldEntry = NextEntry->Flink;
1392
1393 //
1394 // Edit the data
1395 //
1396 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1397 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1398
1399 //
1400 // Keep looping
1401 //
1402 NextEntry = OldEntry;
1403 }
1404
1405 //
1406 // Now edit the root itself
1407 //
1408 NextEntry->Flink = (PVOID)((ULONG_PTR)NextEntry->Flink | KSEG0_BASE);
1409 NextEntry->Blink = (PVOID)((ULONG_PTR)NextEntry->Blink | KSEG0_BASE);
1410 }
1411
1412 VOID
1413 FrLdrStartup(IN ULONG Magic)
1414 {
1415 PVOID PageDir;
1416 //
1417 // Disable interrupts (already done)
1418 //
1419
1420 //
1421 // Set proper CPSR (already done)
1422 //
1423
1424 //
1425 // Initialize the page directory
1426 //
1427 PageDir = ArmSetupPageDirectory();
1428
1429 //
1430 // Initialize paging and load NTOSKRNL
1431 //
1432 ArmSetupPagingAndJump(PageDir);
1433 }