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