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