b6024ff73ac84ffe8c7d19b1a20506c79237a7fd
[reactos.git] / boot / freeldr / freeldr / arch / i386 / pcmem.c
1 /*
2 * FreeLoader
3 *
4 * Copyright ... ... (See below.)
5 * Copyright 2017 Serge Gautherie <reactos-git_serge_171003@gautherie.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Note: Most of this code comes from the old file "i386mem.c", which
22 * was Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
23 */
24
25 #include <freeldr.h>
26 #include <arch/pc/x86common.h>
27
28 #include <debug.h>
29
30 DBG_DEFAULT_CHANNEL(MEMORY);
31
32 #define ULONGLONG_ALIGN_DOWN_BY(size, align) \
33 ((ULONGLONG)(size) & ~((ULONGLONG)(align) - 1))
34
35 #define ULONGLONG_ALIGN_UP_BY(size, align) \
36 (ULONGLONG_ALIGN_DOWN_BY(((ULONGLONG)(size) + align - 1), align))
37
38 #define MAX_BIOS_DESCRIPTORS 80ul
39
40 BIOS_MEMORY_MAP PcBiosMemoryMap[MAX_BIOS_DESCRIPTORS];
41 ULONG PcBiosMapCount;
42
43 FREELDR_MEMORY_DESCRIPTOR PcMemoryMap[MAX_BIOS_DESCRIPTORS + 1];
44 ULONG PcMapCount;
45
46 ULONG
47 AddMemoryDescriptor(
48 IN OUT PFREELDR_MEMORY_DESCRIPTOR List,
49 IN ULONG MaxCount,
50 IN PFN_NUMBER BasePage,
51 IN PFN_NUMBER PageCount,
52 IN TYPE_OF_MEMORY MemoryType);
53
54 static
55 BOOLEAN
56 GetExtendedMemoryConfiguration(ULONG* pMemoryAtOneMB /* in KB */, ULONG* pMemoryAtSixteenMB /* in 64KB */)
57 {
58 REGS RegsIn;
59 REGS RegsOut;
60
61 TRACE("GetExtendedMemoryConfiguration()\n");
62
63 *pMemoryAtOneMB = 0;
64 *pMemoryAtSixteenMB = 0;
65
66 // Int 15h AX=E801h
67 // Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
68 //
69 // AX = E801h
70 // Return:
71 // CF clear if successful
72 // AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
73 // BX = extended memory above 16M, in 64K blocks
74 // CX = configured memory 1M to 16M, in K
75 // DX = configured memory above 16M, in 64K blocks
76 // CF set on error
77 RegsIn.w.ax = 0xE801;
78 Int386(0x15, &RegsIn, &RegsOut);
79
80 TRACE("Int15h AX=E801h\n");
81 TRACE("AX = 0x%x\n", RegsOut.w.ax);
82 TRACE("BX = 0x%x\n", RegsOut.w.bx);
83 TRACE("CX = 0x%x\n", RegsOut.w.cx);
84 TRACE("DX = 0x%x\n", RegsOut.w.dx);
85 TRACE("CF set = %s\n", (RegsOut.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
86
87 if (INT386_SUCCESS(RegsOut))
88 {
89 // If AX=BX=0000h the use CX and DX
90 if (RegsOut.w.ax == 0)
91 {
92 // Return extended memory size in K
93 *pMemoryAtSixteenMB = RegsOut.w.dx;
94 *pMemoryAtOneMB = RegsOut.w.cx;
95 return TRUE;
96 }
97 else
98 {
99 // Return extended memory size in K
100 *pMemoryAtSixteenMB = RegsOut.w.bx;
101 *pMemoryAtOneMB = RegsOut.w.ax;
102 return TRUE;
103 }
104 }
105
106 // If we get here then Int15 Func E801h didn't work
107 // So try Int15 Func 88h
108 // Int 15h AH=88h
109 // SYSTEM - GET EXTENDED MEMORY SIZE (286+)
110 //
111 // AH = 88h
112 // Return:
113 // CF clear if successful
114 // AX = number of contiguous KB starting at absolute address 100000h
115 // CF set on error
116 // AH = status
117 // 80h invalid command (PC,PCjr)
118 // 86h unsupported function (XT,PS30)
119 RegsIn.b.ah = 0x88;
120 Int386(0x15, &RegsIn, &RegsOut);
121
122 TRACE("Int15h AH=88h\n");
123 TRACE("AX = 0x%x\n", RegsOut.w.ax);
124 TRACE("CF set = %s\n", (RegsOut.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
125
126 if (INT386_SUCCESS(RegsOut) && RegsOut.w.ax != 0)
127 {
128 *pMemoryAtOneMB = RegsOut.w.ax;
129 return TRUE;
130 }
131
132 // If we get here then Int15 Func 88h didn't work
133 // So try reading the CMOS
134 WRITE_PORT_UCHAR((PUCHAR)0x70, 0x31);
135 *pMemoryAtOneMB = READ_PORT_UCHAR((PUCHAR)0x71);
136 *pMemoryAtOneMB = (*pMemoryAtOneMB & 0xFFFF);
137 *pMemoryAtOneMB = (*pMemoryAtOneMB << 8);
138
139 TRACE("Int15h Failed\n");
140 TRACE("CMOS reports: 0x%lx\n", *pMemoryAtOneMB);
141
142 if (*pMemoryAtOneMB != 0)
143 {
144 return TRUE;
145 }
146
147 return FALSE;
148 }
149
150 static
151 ULONG
152 PcMemGetConventionalMemorySize(VOID)
153 {
154 REGS Regs;
155
156 TRACE("PcMemGetConventionalMemorySize()\n");
157
158 /* Int 12h
159 * BIOS - GET MEMORY SIZE
160 *
161 * Return:
162 * AX = kilobytes of contiguous memory starting at absolute address 00000h
163 *
164 * This call returns the contents of the word at 0040h:0013h;
165 * in PC and XT, this value is set from the switches on the motherboard
166 */
167 Regs.w.ax = 0;
168 Int386(0x12, &Regs, &Regs);
169
170 TRACE("Int12h\n");
171 TRACE("AX = 0x%x\n", Regs.w.ax);
172
173 return (ULONG)Regs.w.ax;
174 }
175
176 static
177 BOOLEAN
178 GetEbdaLocation(
179 PULONG BaseAddress,
180 PULONG Size)
181 {
182 REGS Regs;
183
184 TRACE("GetEbdaLocation()\n");
185
186 /* Get the address of the Extended BIOS Data Area (EBDA).
187 * Int 15h, AH=C1h
188 * SYSTEM - RETURN EXTENDED-BIOS DATA-AREA SEGMENT ADDRESS (PS)
189 *
190 * Return:
191 * CF set on error
192 * CF clear if successful
193 * ES = segment of data area
194 */
195 Regs.x.eax = 0x0000C100;
196 Int386(0x15, &Regs, &Regs);
197
198 /* If the function fails, there is no EBDA */
199 if (!INT386_SUCCESS(Regs))
200 {
201 return FALSE;
202 }
203
204 /* Get Base address and (maximum) size */
205 *BaseAddress = (ULONG)Regs.w.es << 4;
206 *Size = 0xA0000 - *BaseAddress;
207 return TRUE;
208 }
209
210 static
211 VOID
212 PcMemCheckUsableMemorySize(VOID)
213 {
214 ULONG Size, RequiredSize;
215
216 TRACE("PcMemCheckUsableMemorySize()\n");
217
218 /* Make sure the usable memory is large enough. To do this we check the 16
219 bit value at address 0x413 inside the BDA, which gives us the usable size
220 in KB */
221 Size = (*(PUSHORT)(ULONG_PTR)0x413) * 1024;
222 RequiredSize = FREELDR_BASE + FrLdrImageSize + PAGE_SIZE;
223 if (Size < RequiredSize)
224 {
225 FrLdrBugCheckWithMessage(
226 MEMORY_INIT_FAILURE,
227 __FILE__,
228 __LINE__,
229 "The BIOS reported a usable memory range up to 0x%lx, which is too small!\n"
230 "Required size is 0x%lx\n\n"
231 "If you see this, please report to the ReactOS team!",
232 Size, RequiredSize);
233 }
234 }
235
236 static
237 ULONG
238 PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
239 {
240 REGS Regs;
241 ULONGLONG RealBaseAddress, EndAddress, RealSize;
242 TYPE_OF_MEMORY MemoryType;
243
244 ASSERT(PcBiosMapCount == 0);
245
246 TRACE("PcMemGetBiosMemoryMap()\n");
247
248 /* Int 15h AX=E820h
249 * Newer BIOSes - GET SYSTEM MEMORY MAP
250 *
251 * AX = E820h
252 * EAX = 0000E820h
253 * EDX = 534D4150h ('SMAP')
254 * EBX = continuation value or 00000000h to start at beginning of map
255 * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
256 * ES:DI -> buffer for result
257 * Return:
258 * CF clear if successful
259 * EAX = 534D4150h ('SMAP')
260 * ES:DI buffer filled
261 * EBX = next offset from which to copy or 00000000h if all done
262 * ECX = actual length returned in bytes
263 * CF set on error
264 * AH = error code (86h)
265 */
266 Regs.x.ebx = 0x00000000;
267
268 while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
269 {
270 /* ACPI 3.0/4.0: Set Extended Attributes to enabled/valid by default, in case entry has no E.A.. */
271 ((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributesAsULONG = 0;
272 ((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributes.Enabled_Reserved = 1;
273
274 /* Setup the registers for the BIOS call */
275 Regs.x.eax = 0x0000E820;
276 Regs.x.edx = 0x534D4150; /* ('SMAP') */
277 /* Regs.x.ebx = 0x00000001; Continuation value already set */
278 Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
279 Regs.w.es = BIOSCALLBUFSEGMENT;
280 Regs.w.di = BIOSCALLBUFOFFSET;
281 Int386(0x15, &Regs, &Regs);
282
283 TRACE("Memory Map Entry %lu\n", PcBiosMapCount);
284 TRACE("Int15h AX=E820h\n");
285 TRACE("EAX = 0x%lx\n", Regs.x.eax);
286 TRACE("EBX = 0x%lx\n", Regs.x.ebx);
287 TRACE("ECX = %lu\n", Regs.x.ecx);
288 TRACE("CF set = %s\n", (Regs.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
289
290 /* If the BIOS didn't return 'SMAP' in EAX then
291 * it doesn't support this call. */
292 if (Regs.x.eax != 0x534D4150)
293 {
294 WARN("BIOS doesn't support Int15h AX=E820h!\n");
295 break;
296 }
297
298 /* If the carry flag is set,
299 * then this call was past the last entry, so we're done. */
300 if (!INT386_SUCCESS(Regs))
301 {
302 TRACE("End of System Memory Map! (Past last)\n");
303 break;
304 }
305
306 if (Regs.x.ecx == 0)
307 {
308 TRACE("Discard empty entry. (would-be-PcBiosMapCount = %lu)\n",
309 PcBiosMapCount);
310 goto nextRange;
311 }
312
313 /* Extra safety: unexpected entry length.
314 * All in-between values are valid too, as x86 is little-indian
315 * and only lower byte is used per ACPI 6.2-A.
316 */
317 if (Regs.x.ecx < RTL_SIZEOF_THROUGH_FIELD(BIOS_MEMORY_MAP, Type) ||
318 Regs.x.ecx > sizeof(BIOS_MEMORY_MAP))
319 {
320 ERR("Int 15h AX=E820h returned an invalid entry length! (would-be-PcBiosMapCount = %lu, Entry length = (%Iu <=) %lu (<= %Iu))\n",
321 PcBiosMapCount, RTL_SIZEOF_THROUGH_FIELD(BIOS_MEMORY_MAP, Type), Regs.x.ecx, sizeof(BIOS_MEMORY_MAP));
322 /* Warn user, unless wrong case is "first and not too big entry", which is otherwise harmless. */
323 if (PcBiosMapCount > 0 || Regs.x.ecx > sizeof(BIOS_MEMORY_MAP))
324 {
325 ASSERTMSG("Int 15h AX=E820h returned an invalid entry length!", FALSE);
326 }
327 /* We keep previous entries (if any), but do not dare trying next entries.
328 * We assume these entries are good to use as is. If they are not, we are in trouble...
329 * (And don't ask what happens if BIOS actually overflowed our entry buffer...)
330 *
331 * FIXME: Safer = revert previous entries, Safest = blacklist this BIOS.
332 */
333 break;
334 }
335
336 if (((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributes.Enabled_Reserved == 0)
337 {
338 WARN("Discard disabled/invalid entry. (would-be-PcBiosMapCount = %lu)\n",
339 PcBiosMapCount);
340 /* This unlikely case was correct between ACPI 3.0 and 4.0, so assume all is fine.
341 * Unless we would be ready to drop ACPI 3.0 compatibility.
342 */
343 goto nextRange;
344 }
345
346 /* Copy data to global buffer */
347 RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, sizeof(BIOS_MEMORY_MAP));
348
349 TRACE("BaseAddress: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
350 TRACE("Length: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].Length);
351 TRACE("Type: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Type);
352 TRACE("ExtendedAttributesAsULONG: 0x%08lx\n", PcBiosMemoryMap[PcBiosMapCount].ExtendedAttributesAsULONG);
353
354 if (PcBiosMemoryMap[PcBiosMapCount].Length == 0)
355 {
356 TRACE("Discard empty range. (would-be-PcBiosMapCount = %lu, BaseAddress = 0x%llx, Length = 0)\n",
357 PcBiosMapCount, PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
358 goto nextRange;
359 }
360
361 /* Check if this is free memory */
362 if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryUsable)
363 {
364 MemoryType = LoaderFree;
365
366 /* Align up base of memory range */
367 RealBaseAddress = ULONGLONG_ALIGN_UP_BY(
368 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
369 PAGE_SIZE);
370
371 /* Calculate aligned EndAddress */
372 EndAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
373 PcBiosMemoryMap[PcBiosMapCount].Length;
374 EndAddress = ULONGLONG_ALIGN_DOWN_BY(EndAddress, PAGE_SIZE);
375
376 /* Check if there is anything left */
377 if (EndAddress <= RealBaseAddress)
378 {
379 /* This doesn't span any page, so continue with next range */
380 TRACE("Skipping aligned range < PAGE_SIZE. (would-be-PcBiosMapCount = %lu, BaseAddress = 0x%llx, Length = 0x%llx)\n",
381 PcBiosMapCount,
382 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
383 PcBiosMemoryMap[PcBiosMapCount].Length);
384 goto nextRange;
385 }
386
387 /* Calculate the length of the aligned range */
388 RealSize = EndAddress - RealBaseAddress;
389 }
390 else
391 {
392 if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryReserved)
393 {
394 MemoryType = LoaderFirmwarePermanent;
395 }
396 else
397 {
398 MemoryType = LoaderSpecialMemory;
399 }
400
401 /* Align down base of memory area */
402 RealBaseAddress = ULONGLONG_ALIGN_DOWN_BY(
403 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
404 PAGE_SIZE);
405
406 /* Calculate the length after aligning the base */
407 RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
408 PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
409 RealSize = ULONGLONG_ALIGN_UP_BY(RealSize, PAGE_SIZE);
410 }
411
412 /* Check if we can add this descriptor */
413 if (RealSize < MM_PAGE_SIZE)
414 {
415 TRACE("Skipping aligned range < MM_PAGE_SIZE. (PcBiosMapCount = %lu, BaseAddress = 0x%llx, Length = 0x%llx)\n",
416 PcBiosMapCount,
417 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
418 PcBiosMemoryMap[PcBiosMapCount].Length);
419 }
420 else if (PcMapCount >= MaxMemoryMapSize)
421 {
422 ERR("PcMemoryMap is already full! (PcBiosMapCount = %lu, PcMapCount = %lu (>= %lu))\n",
423 PcBiosMapCount, PcMapCount, MaxMemoryMapSize);
424 // NotWantedForPublicBuilds: ASSERTMSG("PcMemoryMap is already full!", FALSE);
425 /* We keep previous entries, and half-retrieve current/next entries.
426 * We assume all these entries are good to use as is. If they are not, we are in trouble...
427 *
428 * FIXME: Safer = revert (half-)retrieved entries, Safest = increase MaxMemoryMapSize.
429 */
430 }
431 else
432 {
433 /* Add the descriptor */
434 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
435 MAX_BIOS_DESCRIPTORS,
436 (PFN_NUMBER)(RealBaseAddress / MM_PAGE_SIZE),
437 (PFN_NUMBER)(RealSize / MM_PAGE_SIZE),
438 MemoryType);
439 }
440
441 PcBiosMapCount++;
442
443 nextRange:
444 /* If the continuation value is zero,
445 * then this was the last entry, so we're done. */
446 if (Regs.x.ebx == 0x00000000)
447 {
448 TRACE("End of System Memory Map! (Reset)\n");
449 break;
450 }
451 }
452 /* Check whether there would be more entries to process. */
453 if (PcBiosMapCount >= MAX_BIOS_DESCRIPTORS && Regs.x.ebx != 0x00000000)
454 {
455 ERR("PcBiosMemoryMap is already full! (PcBiosMapCount = %lu (>= %lu), PcMapCount = %lu)\n",
456 PcBiosMapCount, MAX_BIOS_DESCRIPTORS, PcMapCount);
457 // NotWantedForPublicBuilds: ASSERTMSG("PcBiosMemoryMap is already full!", FALSE);
458 /* We keep retrieved entries, but ignore next entries.
459 * We assume these entries are good to use as is. If they are not, we are in trouble...
460 *
461 * FIXME: Safer = revert retrieved entries, Safest = increase MAX_BIOS_DESCRIPTORS.
462 */
463 }
464
465 TRACE("PcMemGetBiosMemoryMap end: PcBiosMapCount = %lu\n", PcBiosMapCount);
466 return PcBiosMapCount;
467 }
468
469 VOID
470 ReserveMemory(
471 ULONG_PTR BaseAddress,
472 SIZE_T Size,
473 TYPE_OF_MEMORY MemoryType,
474 PCHAR Usage)
475 {
476 ULONG_PTR BasePage, PageCount;
477 ULONG i;
478
479 BasePage = BaseAddress / PAGE_SIZE;
480 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size);
481
482 for (i = 0; i < PcMapCount; i++)
483 {
484 /* Check for conflicting descriptor */
485 if ((PcMemoryMap[i].BasePage < BasePage + PageCount) &&
486 (PcMemoryMap[i].BasePage + PcMemoryMap[i].PageCount > BasePage))
487 {
488 /* Check if the memory is free */
489 if (PcMemoryMap[i].MemoryType != LoaderFree)
490 {
491 FrLdrBugCheckWithMessage(
492 MEMORY_INIT_FAILURE,
493 __FILE__,
494 __LINE__,
495 "Failed to reserve memory in the range 0x%Ix - 0x%Ix for %s",
496 BaseAddress,
497 Size,
498 Usage);
499 }
500 }
501 }
502
503 /* Add the memory descriptor */
504 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
505 MAX_BIOS_DESCRIPTORS,
506 BasePage,
507 PageCount,
508 MemoryType);
509 }
510
511 VOID
512 SetMemory(
513 ULONG_PTR BaseAddress,
514 SIZE_T Size,
515 TYPE_OF_MEMORY MemoryType)
516 {
517 ULONG_PTR BasePage, PageCount;
518
519 BasePage = BaseAddress / PAGE_SIZE;
520 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size);
521
522 /* Add the memory descriptor */
523 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
524 MAX_BIOS_DESCRIPTORS,
525 BasePage,
526 PageCount,
527 MemoryType);
528 }
529
530 PFREELDR_MEMORY_DESCRIPTOR
531 PcMemGetMemoryMap(ULONG *MemoryMapSize)
532 {
533 ULONG i, EntryCount;
534 ULONG ExtendedMemorySizeAtOneMB;
535 ULONG ExtendedMemorySizeAtSixteenMB;
536 ULONG EbdaBase, EbdaSize;
537
538 TRACE("PcMemGetMemoryMap()\n");
539
540 PcMemCheckUsableMemorySize();
541
542 EntryCount = PcMemGetBiosMemoryMap(PcMemoryMap, MAX_BIOS_DESCRIPTORS);
543
544 /* If the BIOS didn't provide a memory map, synthesize one */
545 if (EntryCount == 0)
546 {
547 GetExtendedMemoryConfiguration(&ExtendedMemorySizeAtOneMB,
548 &ExtendedMemorySizeAtSixteenMB);
549
550 /* Conventional memory */
551 AddMemoryDescriptor(PcMemoryMap,
552 MAX_BIOS_DESCRIPTORS,
553 0,
554 PcMemGetConventionalMemorySize() * 1024 / PAGE_SIZE,
555 LoaderFree);
556
557 /* Extended memory */
558 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
559 MAX_BIOS_DESCRIPTORS,
560 1024 * 1024 / PAGE_SIZE,
561 ExtendedMemorySizeAtOneMB * 1024 / PAGE_SIZE,
562 LoaderFree);
563
564 if (ExtendedMemorySizeAtSixteenMB != 0)
565 {
566 /* Extended memory at 16MB */
567 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
568 MAX_BIOS_DESCRIPTORS,
569 0x1000000 / PAGE_SIZE,
570 ExtendedMemorySizeAtSixteenMB * 64 * 1024 / PAGE_SIZE,
571 LoaderFree);
572 }
573
574 /* Check if we have an EBDA and get it's location */
575 if (GetEbdaLocation(&EbdaBase, &EbdaSize))
576 {
577 /* Add the descriptor */
578 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
579 MAX_BIOS_DESCRIPTORS,
580 (EbdaBase / PAGE_SIZE),
581 ADDRESS_AND_SIZE_TO_SPAN_PAGES(EbdaBase, EbdaSize),
582 LoaderFirmwarePermanent);
583 }
584 }
585
586 /* Setup some protected ranges */
587 SetMemory(0x000000, 0x01000, LoaderFirmwarePermanent); // Realmode IVT / BDA
588 SetMemory(0x0A0000, 0x50000, LoaderFirmwarePermanent); // Video memory
589 SetMemory(0x0F0000, 0x10000, LoaderSpecialMemory); // ROM
590 SetMemory(0xFFF000, 0x01000, LoaderSpecialMemory); // unusable memory (do we really need this?)
591
592 /* Reserve some static ranges for freeldr */
593 ReserveMemory(0x1000, STACKLOW - 0x1000, LoaderFirmwareTemporary, "BIOS area");
594 ReserveMemory(STACKLOW, STACKADDR - STACKLOW, LoaderOsloaderStack, "FreeLdr stack");
595 ReserveMemory(FREELDR_BASE, FrLdrImageSize, LoaderLoadedProgram, "FreeLdr image");
596
597 /* Default to 1 page above freeldr for the disk read buffer */
598 DiskReadBuffer = (PUCHAR)ALIGN_UP_BY(FREELDR_BASE + FrLdrImageSize, PAGE_SIZE);
599 DiskReadBufferSize = PAGE_SIZE;
600
601 /* Scan for free range above freeldr image */
602 for (i = 0; i < PcMapCount; i++)
603 {
604 if ((PcMemoryMap[i].BasePage > (FREELDR_BASE / PAGE_SIZE)) &&
605 (PcMemoryMap[i].MemoryType == LoaderFree))
606 {
607 /* Use this range for the disk read buffer */
608 DiskReadBuffer = (PVOID)(PcMemoryMap[i].BasePage * PAGE_SIZE);
609 DiskReadBufferSize = min(PcMemoryMap[i].PageCount * PAGE_SIZE,
610 MAX_DISKREADBUFFER_SIZE);
611 break;
612 }
613 }
614
615 TRACE("DiskReadBuffer=0x%p, DiskReadBufferSize=0x%lx\n",
616 DiskReadBuffer, DiskReadBufferSize);
617
618 /* Now reserve the range for the disk read buffer */
619 ReserveMemory((ULONG_PTR)DiskReadBuffer,
620 DiskReadBufferSize,
621 LoaderFirmwareTemporary,
622 "Disk read buffer");
623
624 TRACE("Dumping resulting memory map:\n");
625 for (i = 0; i < PcMapCount; i++)
626 {
627 TRACE("BasePage=0x%lx, PageCount=0x%lx, Type=%s\n",
628 PcMemoryMap[i].BasePage,
629 PcMemoryMap[i].PageCount,
630 MmGetSystemMemoryMapTypeString(PcMemoryMap[i].MemoryType));
631 }
632
633 *MemoryMapSize = PcMapCount;
634 return PcMemoryMap;
635 }
636
637
638 /* EOF */