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