5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * Note: Most of this code comes from the old file "i386mem.c", which
20 * was Copyright (C) 1998-2003 Brian Palmer <brianp@sginet.com>
28 DBG_DEFAULT_CHANNEL(MEMORY
);
30 #define MAX_BIOS_DESCRIPTORS 32
32 BIOS_MEMORY_MAP PcBiosMemoryMap
[MAX_BIOS_DESCRIPTORS
];
37 GetExtendedMemoryConfiguration(ULONG
* pMemoryAtOneMB
/* in KB */, ULONG
* pMemoryAtSixteenMB
/* in 64KB */)
42 TRACE("GetExtendedMemoryConfiguration()\n");
45 *pMemoryAtSixteenMB
= 0;
48 // Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
52 // CF clear if successful
53 // AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
54 // BX = extended memory above 16M, in 64K blocks
55 // CX = configured memory 1M to 16M, in K
56 // DX = configured memory above 16M, in 64K blocks
59 Int386(0x15, &RegsIn
, &RegsOut
);
61 TRACE("Int15h AX=E801h\n");
62 TRACE("AX = 0x%x\n", RegsOut
.w
.ax
);
63 TRACE("BX = 0x%x\n", RegsOut
.w
.bx
);
64 TRACE("CX = 0x%x\n", RegsOut
.w
.cx
);
65 TRACE("DX = 0x%x\n", RegsOut
.w
.dx
);
66 TRACE("CF set = %s\n\n", (RegsOut
.x
.eflags
& EFLAGS_CF
) ? "TRUE" : "FALSE");
68 if (INT386_SUCCESS(RegsOut
))
70 // If AX=BX=0000h the use CX and DX
71 if (RegsOut
.w
.ax
== 0)
73 // Return extended memory size in K
74 *pMemoryAtSixteenMB
= RegsOut
.w
.dx
;
75 *pMemoryAtOneMB
= RegsOut
.w
.cx
;
80 // Return extended memory size in K
81 *pMemoryAtSixteenMB
= RegsOut
.w
.bx
;
82 *pMemoryAtOneMB
= RegsOut
.w
.ax
;
87 // If we get here then Int15 Func E801h didn't work
88 // So try Int15 Func 88h
90 // SYSTEM - GET EXTENDED MEMORY SIZE (286+)
94 // CF clear if successful
95 // AX = number of contiguous KB starting at absolute address 100000h
98 // 80h invalid command (PC,PCjr)
99 // 86h unsupported function (XT,PS30)
101 Int386(0x15, &RegsIn
, &RegsOut
);
103 TRACE("Int15h AH=88h\n");
104 TRACE("AX = 0x%x\n", RegsOut
.w
.ax
);
105 TRACE("CF set = %s\n\n", (RegsOut
.x
.eflags
& EFLAGS_CF
) ? "TRUE" : "FALSE");
107 if (INT386_SUCCESS(RegsOut
) && RegsOut
.w
.ax
!= 0)
109 *pMemoryAtOneMB
= RegsOut
.w
.ax
;
113 // If we get here then Int15 Func 88h didn't work
114 // So try reading the CMOS
115 WRITE_PORT_UCHAR((PUCHAR
)0x70, 0x31);
116 *pMemoryAtOneMB
= READ_PORT_UCHAR((PUCHAR
)0x71);
117 *pMemoryAtOneMB
= (*pMemoryAtOneMB
& 0xFFFF);
118 *pMemoryAtOneMB
= (*pMemoryAtOneMB
<< 8);
120 TRACE("Int15h Failed\n");
121 TRACE("CMOS reports: 0x%x\n", *pMemoryAtOneMB
);
123 if (*pMemoryAtOneMB
!= 0)
132 PcMemGetConventionalMemorySize(VOID
)
136 TRACE("GetConventionalMemorySize()\n");
139 * BIOS - GET MEMORY SIZE
142 * AX = kilobytes of contiguous memory starting at absolute address 00000h
144 * This call returns the contents of the word at 0040h:0013h;
145 * in PC and XT, this value is set from the switches on the motherboard
148 Int386(0x12, &Regs
, &Regs
);
151 TRACE("AX = 0x%x\n\n", Regs
.w
.ax
);
153 return (ULONG
)Regs
.w
.ax
;
157 PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap
, ULONG MaxMemoryMapSize
)
162 TRACE("GetBiosMemoryMap()\n");
165 * Newer BIOSes - GET SYSTEM MEMORY MAP
169 * EDX = 534D4150h ('SMAP')
170 * EBX = continuation value or 00000000h to start at beginning of map
171 * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
172 * ES:DI -> buffer for result
174 * CF clear if successful
175 * EAX = 534D4150h ('SMAP')
176 * ES:DI buffer filled
177 * EBX = next offset from which to copy or 00000000h if all done
178 * ECX = actual length returned in bytes
180 * AH = error code (86h)
182 Regs
.x
.ebx
= 0x00000000;
184 for (MapCount
= 0; MapCount
< MaxMemoryMapSize
; MapCount
++)
186 /* Setup the registers for the BIOS call */
187 Regs
.x
.eax
= 0x0000E820;
188 Regs
.x
.edx
= 0x534D4150; /* ('SMAP') */
189 /* Regs.x.ebx = 0x00000001; Continuation value already set */
190 Regs
.x
.ecx
= sizeof(BIOS_MEMORY_MAP
);
191 Regs
.w
.es
= BIOSCALLBUFSEGMENT
;
192 Regs
.w
.di
= BIOSCALLBUFOFFSET
;
193 Int386(0x15, &Regs
, &Regs
);
195 TRACE("Memory Map Entry %d\n", MapCount
);
196 TRACE("Int15h AX=E820h\n");
197 TRACE("EAX = 0x%x\n", Regs
.x
.eax
);
198 TRACE("EBX = 0x%x\n", Regs
.x
.ebx
);
199 TRACE("ECX = 0x%x\n", Regs
.x
.ecx
);
200 TRACE("CF set = %s\n", (Regs
.x
.eflags
& EFLAGS_CF
) ? "TRUE" : "FALSE");
202 /* If the BIOS didn't return 'SMAP' in EAX then
203 * it doesn't support this call. If CF is set, we're done */
204 if (Regs
.x
.eax
!= 0x534D4150 || !INT386_SUCCESS(Regs
))
209 /* Copy data to caller's buffer */
210 RtlCopyMemory(&BiosMemoryMap
[MapCount
], (PVOID
)BIOSCALLBUFFER
, Regs
.x
.ecx
);
212 TRACE("BaseAddress: 0x%p\n", (PVOID
)(ULONG_PTR
)BiosMemoryMap
[MapCount
].BaseAddress
);
213 TRACE("Length: 0x%p\n", (PVOID
)(ULONG_PTR
)BiosMemoryMap
[MapCount
].Length
);
214 TRACE("Type: 0x%x\n", BiosMemoryMap
[MapCount
].Type
);
215 TRACE("Reserved: 0x%x\n", BiosMemoryMap
[MapCount
].Reserved
);
218 /* If the continuation value is zero or the
219 * carry flag is set then this was
220 * the last entry so we're done */
221 if (Regs
.x
.ebx
== 0x00000000)
223 TRACE("End Of System Memory Map!\n\n");
233 PcMemGetMemoryMap(ULONG
*MemoryMapSize
)
236 ULONG ExtendedMemorySizeAtOneMB
;
237 ULONG ExtendedMemorySizeAtSixteenMB
;
239 EntryCount
= PcMemGetBiosMemoryMap(PcBiosMemoryMap
, MAX_BIOS_DESCRIPTORS
);
240 PcBiosMapCount
= EntryCount
;
242 /* If the BIOS didn't provide a memory map, synthesize one */
245 GetExtendedMemoryConfiguration(&ExtendedMemorySizeAtOneMB
, &ExtendedMemorySizeAtSixteenMB
);
247 /* Conventional memory */
248 PcBiosMemoryMap
[EntryCount
].BaseAddress
= 0;
249 PcBiosMemoryMap
[EntryCount
].Length
= PcMemGetConventionalMemorySize() * 1024;
250 PcBiosMemoryMap
[EntryCount
].Type
= BiosMemoryUsable
;
253 /* Extended memory at 1MB */
254 PcBiosMemoryMap
[EntryCount
].BaseAddress
= 1024 * 1024;
255 PcBiosMemoryMap
[EntryCount
].Length
= ExtendedMemorySizeAtOneMB
* 1024;
256 PcBiosMemoryMap
[EntryCount
].Type
= BiosMemoryUsable
;
259 if (ExtendedMemorySizeAtSixteenMB
!= 0)
261 /* Extended memory at 16MB */
262 PcBiosMemoryMap
[EntryCount
].BaseAddress
= 0x1000000;
263 PcBiosMemoryMap
[EntryCount
].Length
= ExtendedMemorySizeAtSixteenMB
* 64 * 1024;
264 PcBiosMemoryMap
[EntryCount
].Type
= BiosMemoryUsable
;
269 *MemoryMapSize
= EntryCount
;
271 return PcBiosMemoryMap
;