[FREELDR] FreeLdr debug.h does not care about NDEBUG. (#201)
[reactos.git] / boot / freeldr / freeldr / arch / i386 / pcmem.c
1 /*
2 * FreeLoader
3 *
4 * Copyright ... ... (See below.)
5 * Copyright 2017 Serge Gautherie
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\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\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\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 /* Get the address of the Extended BIOS Data Area (EBDA).
185 * Int 15h, AH=C1h
186 * SYSTEM - RETURN EXTENDED-BIOS DATA-AREA SEGMENT ADDRESS (PS)
187 *
188 * Return:
189 * CF set on error
190 * CF clear if successful
191 * ES = segment of data area
192 */
193 Regs.x.eax = 0x0000C100;
194 Int386(0x15, &Regs, &Regs);
195
196 /* If the function fails, there is no EBDA */
197 if (!INT386_SUCCESS(Regs))
198 {
199 return FALSE;
200 }
201
202 /* Get Base address and (maximum) size */
203 *BaseAddress = (ULONG)Regs.w.es << 4;
204 *Size = 0xA0000 - *BaseAddress;
205 return TRUE;
206 }
207
208 static
209 VOID
210 PcMemCheckUsableMemorySize(VOID)
211 {
212 ULONG Size, RequiredSize;
213
214 /* Make sure the usable memory is large enough. To do this we check the 16
215 bit value at address 0x413 inside the BDA, which gives us the usable size
216 in KB */
217 Size = (*(PUSHORT)(ULONG_PTR)0x413) * 1024;
218 RequiredSize = FREELDR_BASE + FrLdrImageSize + PAGE_SIZE;
219 if (Size < RequiredSize)
220 {
221 FrLdrBugCheckWithMessage(
222 MEMORY_INIT_FAILURE,
223 __FILE__,
224 __LINE__,
225 "The BIOS reported a usable memory range up to 0x%lx, which is too small!\n"
226 "Required size is 0x%lx\n\n"
227 "If you see this, please report to the ReactOS team!",
228 Size, RequiredSize);
229 }
230 }
231
232 static
233 ULONG
234 PcMemGetBiosMemoryMap(PFREELDR_MEMORY_DESCRIPTOR MemoryMap, ULONG MaxMemoryMapSize)
235 {
236 REGS Regs;
237 ULONGLONG RealBaseAddress, EndAddress, RealSize;
238 TYPE_OF_MEMORY MemoryType;
239
240 ASSERT(PcBiosMapCount == 0);
241
242 TRACE("PcMemGetBiosMemoryMap()\n");
243
244 /* Int 15h AX=E820h
245 * Newer BIOSes - GET SYSTEM MEMORY MAP
246 *
247 * AX = E820h
248 * EAX = 0000E820h
249 * EDX = 534D4150h ('SMAP')
250 * EBX = continuation value or 00000000h to start at beginning of map
251 * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
252 * ES:DI -> buffer for result
253 * Return:
254 * CF clear if successful
255 * EAX = 534D4150h ('SMAP')
256 * ES:DI buffer filled
257 * EBX = next offset from which to copy or 00000000h if all done
258 * ECX = actual length returned in bytes
259 * CF set on error
260 * AH = error code (86h)
261 */
262 Regs.x.ebx = 0x00000000;
263
264 while (PcBiosMapCount < MAX_BIOS_DESCRIPTORS)
265 {
266 /* ACPI 3.0/4.0: Set Extended Attributes to enabled/valid by default, in case entry has no E.A.. */
267 ((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributesAsULONG = 0;
268 ((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributes.Enabled_Reserved = 1;
269
270 /* Setup the registers for the BIOS call */
271 Regs.x.eax = 0x0000E820;
272 Regs.x.edx = 0x534D4150; /* ('SMAP') */
273 /* Regs.x.ebx = 0x00000001; Continuation value already set */
274 Regs.x.ecx = sizeof(BIOS_MEMORY_MAP);
275 Regs.w.es = BIOSCALLBUFSEGMENT;
276 Regs.w.di = BIOSCALLBUFOFFSET;
277 Int386(0x15, &Regs, &Regs);
278
279 TRACE("Memory Map Entry %lu\n", PcBiosMapCount);
280 TRACE("Int15h AX=E820h\n");
281 TRACE("EAX = 0x%lx\n", Regs.x.eax);
282 TRACE("EBX = 0x%lx\n", Regs.x.ebx);
283 TRACE("ECX = %lu\n", Regs.x.ecx);
284 TRACE("CF set = %s\n", (Regs.x.eflags & EFLAGS_CF) ? "TRUE" : "FALSE");
285
286 /* If the BIOS didn't return 'SMAP' in EAX then
287 * it doesn't support this call. */
288 if (Regs.x.eax != 0x534D4150)
289 {
290 WARN("BIOS doesn't support Int15h AX=E820h!\n\n");
291 break;
292 }
293
294 /* If the carry flag is set,
295 * then this call was past the last entry, so we're done. */
296 if (!INT386_SUCCESS(Regs))
297 {
298 TRACE("End of System Memory Map! (Past last)\n\n");
299 break;
300 }
301
302 if (Regs.x.ecx == 0)
303 {
304 TRACE("Discard empty entry. (would-be-PcBiosMapCount = %lu)\n",
305 PcBiosMapCount);
306 goto nextRange;
307 }
308
309 /* Extra safety: unexpected entry length.
310 * All in-between values are valid too, as x86 is little-indian
311 * and only lower byte is used per ACPI 6.2-A.
312 */
313 if (Regs.x.ecx < RTL_SIZEOF_THROUGH_FIELD(BIOS_MEMORY_MAP, Type) ||
314 Regs.x.ecx > sizeof(BIOS_MEMORY_MAP))
315 {
316 ERR("Int 15h AX=E820h returned an invalid entry length! (would-be-PcBiosMapCount = %lu, Entry length = (%Iu <=) %lu (<= %Iu))\n\n",
317 PcBiosMapCount, RTL_SIZEOF_THROUGH_FIELD(BIOS_MEMORY_MAP, Type), Regs.x.ecx, sizeof(BIOS_MEMORY_MAP));
318 /* Warn user, unless wrong case is "first and not too big entry", which is otherwise harmless. */
319 if (PcBiosMapCount > 0 || Regs.x.ecx > sizeof(BIOS_MEMORY_MAP))
320 {
321 ASSERTMSG("Int 15h AX=E820h returned an invalid entry length!", FALSE);
322 }
323 /* We keep previous entries (if any), but do not dare trying next entries.
324 * We assume these entries are good to use as is. If they are not, we are in trouble...
325 * (And don't ask what happens if BIOS actually overflowed our entry buffer...)
326 *
327 * FIXME: Safer = revert previous entries, Safest = blacklist this BIOS.
328 */
329 break;
330 }
331
332 if (((PBIOS_MEMORY_MAP)BIOSCALLBUFFER)->ExtendedAttributes.Enabled_Reserved == 0)
333 {
334 WARN("Discard disabled/invalid entry. (would-be-PcBiosMapCount = %lu)\n",
335 PcBiosMapCount);
336 /* This unlikely case was correct between ACPI 3.0 and 4.0, so assume all is fine.
337 * Unless we would be ready to drop ACPI 3.0 compatibility.
338 */
339 goto nextRange;
340 }
341
342 /* Copy data to global buffer */
343 RtlCopyMemory(&PcBiosMemoryMap[PcBiosMapCount], (PVOID)BIOSCALLBUFFER, sizeof(BIOS_MEMORY_MAP));
344
345 TRACE("BaseAddress: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
346 TRACE("Length: 0x%llx\n", PcBiosMemoryMap[PcBiosMapCount].Length);
347 TRACE("Type: 0x%lx\n", PcBiosMemoryMap[PcBiosMapCount].Type);
348 TRACE("ExtendedAttributesAsULONG: 0x%08lx\n", PcBiosMemoryMap[PcBiosMapCount].ExtendedAttributesAsULONG);
349
350 if (PcBiosMemoryMap[PcBiosMapCount].Length == 0)
351 {
352 TRACE("Discard empty range. (would-be-PcBiosMapCount = %lu, BaseAddress = %lu, Length = 0)\n",
353 PcBiosMapCount, PcBiosMemoryMap[PcBiosMapCount].BaseAddress);
354 goto nextRange;
355 }
356
357 /* Check if this is free memory */
358 if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryUsable)
359 {
360 MemoryType = LoaderFree;
361
362 /* Align up base of memory range */
363 RealBaseAddress = ULONGLONG_ALIGN_UP_BY(
364 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
365 PAGE_SIZE);
366
367 /* Calculate aligned EndAddress */
368 EndAddress = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
369 PcBiosMemoryMap[PcBiosMapCount].Length;
370 EndAddress = ULONGLONG_ALIGN_DOWN_BY(EndAddress, PAGE_SIZE);
371
372 /* Check if there is anything left */
373 if (EndAddress <= RealBaseAddress)
374 {
375 /* This doesn't span any page, so continue with next range */
376 TRACE("Skipping aligned range < PAGE_SIZE. (would-be-PcBiosMapCount = %lu, BaseAddress = %lu, Length = %lu)\n",
377 PcBiosMapCount,
378 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
379 PcBiosMemoryMap[PcBiosMapCount].Length);
380 goto nextRange;
381 }
382
383 /* Calculate the length of the aligned range */
384 RealSize = EndAddress - RealBaseAddress;
385 }
386 else
387 {
388 if (PcBiosMemoryMap[PcBiosMapCount].Type == BiosMemoryReserved)
389 {
390 MemoryType = LoaderFirmwarePermanent;
391 }
392 else
393 {
394 MemoryType = LoaderSpecialMemory;
395 }
396
397 /* Align down base of memory area */
398 RealBaseAddress = ULONGLONG_ALIGN_DOWN_BY(
399 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
400 PAGE_SIZE);
401
402 /* Calculate the length after aligning the base */
403 RealSize = PcBiosMemoryMap[PcBiosMapCount].BaseAddress +
404 PcBiosMemoryMap[PcBiosMapCount].Length - RealBaseAddress;
405 RealSize = ULONGLONG_ALIGN_UP_BY(RealSize, PAGE_SIZE);
406 }
407
408 /* Check if we can add this descriptor */
409 if (RealSize < MM_PAGE_SIZE)
410 {
411 TRACE("Skipping aligned range < MM_PAGE_SIZE. (PcBiosMapCount = %lu, BaseAddress = %lu, Length = %lu)\n",
412 PcBiosMapCount,
413 PcBiosMemoryMap[PcBiosMapCount].BaseAddress,
414 PcBiosMemoryMap[PcBiosMapCount].Length);
415 }
416 else if (PcMapCount >= MaxMemoryMapSize)
417 {
418 ERR("PcMemoryMap is already full! (PcBiosMapCount = %lu, PcMapCount = %lu (>= %lu))\n",
419 PcBiosMapCount, PcMapCount, MaxMemoryMapSize);
420 // NotWantedForPublicBuilds: ASSERTMSG("PcMemoryMap is already full!", FALSE);
421 /* We keep previous entries, and half-retrieve current/next entries.
422 * We assume all these entries are good to use as is. If they are not, we are in trouble...
423 *
424 * FIXME: Safer = revert (half-)retrieved entries, Safest = increase MaxMemoryMapSize.
425 */
426 }
427 else
428 {
429 /* Add the descriptor */
430 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
431 MAX_BIOS_DESCRIPTORS,
432 (PFN_NUMBER)(RealBaseAddress / MM_PAGE_SIZE),
433 (PFN_NUMBER)(RealSize / MM_PAGE_SIZE),
434 MemoryType);
435 }
436
437 PcBiosMapCount++;
438
439 nextRange:
440 TRACE("\n");
441
442 /* If the continuation value is zero,
443 * then this was the last entry, so we're done. */
444 if (Regs.x.ebx == 0x00000000)
445 {
446 TRACE("End of System Memory Map! (Reset)\n\n");
447 break;
448 }
449 }
450 /* Check whether there would be more entries to process. */
451 if (PcBiosMapCount >= MAX_BIOS_DESCRIPTORS && Regs.x.ebx != 0x00000000)
452 {
453 ERR("PcBiosMemoryMap is already full! (PcBiosMapCount = %lu (>= %lu), PcMapCount = %lu)\n",
454 PcBiosMapCount, MAX_BIOS_DESCRIPTORS, PcMapCount);
455 // NotWantedForPublicBuilds: ASSERTMSG("PcBiosMemoryMap is already full!", FALSE);
456 /* We keep retrieved entries, but ignore next entries.
457 * We assume these entries are good to use as is. If they are not, we are in trouble...
458 *
459 * FIXME: Safer = revert retrieved entries, Safest = increase MAX_BIOS_DESCRIPTORS.
460 */
461 }
462
463 TRACE("PcMemGetBiosMemoryMap end: PcBiosMapCount = %lu\n", PcBiosMapCount);
464 return PcBiosMapCount;
465 }
466
467 VOID
468 ReserveMemory(
469 ULONG_PTR BaseAddress,
470 SIZE_T Size,
471 TYPE_OF_MEMORY MemoryType,
472 PCHAR Usage)
473 {
474 ULONG_PTR BasePage, PageCount;
475 ULONG i;
476
477 BasePage = BaseAddress / PAGE_SIZE;
478 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size);
479
480 for (i = 0; i < PcMapCount; i++)
481 {
482 /* Check for conflicting descriptor */
483 if ((PcMemoryMap[i].BasePage < BasePage + PageCount) &&
484 (PcMemoryMap[i].BasePage + PcMemoryMap[i].PageCount > BasePage))
485 {
486 /* Check if the memory is free */
487 if (PcMemoryMap[i].MemoryType != LoaderFree)
488 {
489 FrLdrBugCheckWithMessage(
490 MEMORY_INIT_FAILURE,
491 __FILE__,
492 __LINE__,
493 "Failed to reserve memory in the range 0x%Ix - 0x%Ix for %s",
494 BaseAddress,
495 Size,
496 Usage);
497 }
498 }
499 }
500
501 /* Add the memory descriptor */
502 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
503 MAX_BIOS_DESCRIPTORS,
504 BasePage,
505 PageCount,
506 MemoryType);
507 }
508
509 VOID
510 SetMemory(
511 ULONG_PTR BaseAddress,
512 SIZE_T Size,
513 TYPE_OF_MEMORY MemoryType)
514 {
515 ULONG_PTR BasePage, PageCount;
516
517 BasePage = BaseAddress / PAGE_SIZE;
518 PageCount = ADDRESS_AND_SIZE_TO_SPAN_PAGES(BaseAddress, Size);
519
520 /* Add the memory descriptor */
521 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
522 MAX_BIOS_DESCRIPTORS,
523 BasePage,
524 PageCount,
525 MemoryType);
526 }
527
528 PFREELDR_MEMORY_DESCRIPTOR
529 PcMemGetMemoryMap(ULONG *MemoryMapSize)
530 {
531 ULONG i, EntryCount;
532 ULONG ExtendedMemorySizeAtOneMB;
533 ULONG ExtendedMemorySizeAtSixteenMB;
534 ULONG EbdaBase, EbdaSize;
535
536 TRACE("PcMemGetMemoryMap()\n");
537
538 PcMemCheckUsableMemorySize();
539
540 EntryCount = PcMemGetBiosMemoryMap(PcMemoryMap, MAX_BIOS_DESCRIPTORS);
541
542 /* If the BIOS didn't provide a memory map, synthesize one */
543 if (EntryCount == 0)
544 {
545 GetExtendedMemoryConfiguration(&ExtendedMemorySizeAtOneMB,
546 &ExtendedMemorySizeAtSixteenMB);
547
548 /* Conventional memory */
549 AddMemoryDescriptor(PcMemoryMap,
550 MAX_BIOS_DESCRIPTORS,
551 0,
552 PcMemGetConventionalMemorySize() * 1024 / PAGE_SIZE,
553 LoaderFree);
554
555 /* Extended memory */
556 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
557 MAX_BIOS_DESCRIPTORS,
558 1024 * 1024 / PAGE_SIZE,
559 ExtendedMemorySizeAtOneMB * 1024 / PAGE_SIZE,
560 LoaderFree);
561
562 if (ExtendedMemorySizeAtSixteenMB != 0)
563 {
564 /* Extended memory at 16MB */
565 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
566 MAX_BIOS_DESCRIPTORS,
567 0x1000000 / PAGE_SIZE,
568 ExtendedMemorySizeAtSixteenMB * 64 * 1024 / PAGE_SIZE,
569 LoaderFree);
570 }
571
572 /* Check if we have an EBDA and get it's location */
573 if (GetEbdaLocation(&EbdaBase, &EbdaSize))
574 {
575 /* Add the descriptor */
576 PcMapCount = AddMemoryDescriptor(PcMemoryMap,
577 MAX_BIOS_DESCRIPTORS,
578 (EbdaBase / PAGE_SIZE),
579 ADDRESS_AND_SIZE_TO_SPAN_PAGES(EbdaBase, EbdaSize),
580 LoaderFirmwarePermanent);
581 }
582 }
583
584 /* Setup some protected ranges */
585 SetMemory(0x000000, 0x01000, LoaderFirmwarePermanent); // Realmode IVT / BDA
586 SetMemory(0x0A0000, 0x50000, LoaderFirmwarePermanent); // Video memory
587 SetMemory(0x0F0000, 0x10000, LoaderSpecialMemory); // ROM
588 SetMemory(0xFFF000, 0x01000, LoaderSpecialMemory); // unusable memory (do we really need this?)
589
590 /* Reserve some static ranges for freeldr */
591 ReserveMemory(0x1000, STACKLOW - 0x1000, LoaderFirmwareTemporary, "BIOS area");
592 ReserveMemory(STACKLOW, STACKADDR - STACKLOW, LoaderOsloaderStack, "FreeLdr stack");
593 ReserveMemory(FREELDR_BASE, FrLdrImageSize, LoaderLoadedProgram, "FreeLdr image");
594
595 /* Default to 1 page above freeldr for the disk read buffer */
596 DiskReadBuffer = (PUCHAR)ALIGN_UP_BY(FREELDR_BASE + FrLdrImageSize, PAGE_SIZE);
597 DiskReadBufferSize = PAGE_SIZE;
598
599 /* Scan for free range above freeldr image */
600 for (i = 0; i < PcMapCount; i++)
601 {
602 if ((PcMemoryMap[i].BasePage > (FREELDR_BASE / PAGE_SIZE)) &&
603 (PcMemoryMap[i].MemoryType == LoaderFree))
604 {
605 /* Use this range for the disk read buffer */
606 DiskReadBuffer = (PVOID)(PcMemoryMap[i].BasePage * PAGE_SIZE);
607 DiskReadBufferSize = min(PcMemoryMap[i].PageCount * PAGE_SIZE,
608 MAX_DISKREADBUFFER_SIZE);
609 break;
610 }
611 }
612
613 TRACE("DiskReadBuffer=%p, DiskReadBufferSize=%lx\n",
614 DiskReadBuffer, DiskReadBufferSize);
615
616 /* Now reserve the range for the disk read buffer */
617 ReserveMemory((ULONG_PTR)DiskReadBuffer,
618 DiskReadBufferSize,
619 LoaderFirmwareTemporary,
620 "Disk read buffer");
621
622 TRACE("Dumping resulting memory map:\n");
623 for (i = 0; i < PcMapCount; i++)
624 {
625 TRACE("BasePage=0x%lx, PageCount=0x%lx, Type=%s\n",
626 PcMemoryMap[i].BasePage,
627 PcMemoryMap[i].PageCount,
628 MmGetSystemMemoryMapTypeString(PcMemoryMap[i].MemoryType));
629 }
630
631 *MemoryMapSize = PcMapCount;
632 return PcMemoryMap;
633 }
634
635
636 /* EOF */