1 /* $Id: pcmem.c 24238 2006-09-23 16:50:39Z fireball $
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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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>
29 PcMemGetExtendedMemorySize(VOID
)
35 DbgPrint((DPRINT_MEMORY
, "GetExtendedMemorySize()\n"));
38 * Phoenix BIOS v4.0 - GET MEMORY SIZE FOR >64M CONFIGURATIONS
42 * CF clear if successful
43 * AX = extended memory between 1M and 16M, in K (max 3C00h = 15MB)
44 * BX = extended memory above 16M, in 64K blocks
45 * CX = configured memory 1M to 16M, in K
46 * DX = configured memory above 16M, in 64K blocks
50 Int386(0x15, &RegsIn
, &RegsOut
);
52 DbgPrint((DPRINT_MEMORY
, "Int15h AX=E801h\n"));
53 DbgPrint((DPRINT_MEMORY
, "AX = 0x%x\n", RegsOut
.w
.ax
));
54 DbgPrint((DPRINT_MEMORY
, "BX = 0x%x\n", RegsOut
.w
.bx
));
55 DbgPrint((DPRINT_MEMORY
, "CX = 0x%x\n", RegsOut
.w
.cx
));
56 DbgPrint((DPRINT_MEMORY
, "DX = 0x%x\n", RegsOut
.w
.dx
));
57 DbgPrint((DPRINT_MEMORY
, "CF set = %s\n\n", (RegsOut
.x
.eflags
& I386FLAG_CF
) ? "TRUE" : "FALSE"));
59 if (INT386_SUCCESS(RegsOut
))
61 /* If AX=BX=0000h the use CX and DX */
62 if (RegsOut
.w
.ax
== 0)
64 /* Return extended memory size in K */
65 MemorySize
= RegsOut
.w
.dx
* 64;
66 MemorySize
+= RegsOut
.w
.cx
;
71 /* Return extended memory size in K */
72 MemorySize
= RegsOut
.w
.bx
* 64;
73 MemorySize
+= RegsOut
.w
.ax
;
78 /* If we get here then Int15 Func E801h didn't work */
79 /* So try Int15 Func 88h */
82 * SYSTEM - GET EXTENDED MEMORY SIZE (286+)
86 * CF clear if successful
87 * AX = number of contiguous KB starting at absolute address 100000h
90 * 80h invalid command (PC,PCjr)
91 * 86h unsupported function (XT,PS30)
94 Int386(0x15, &RegsIn
, &RegsOut
);
96 DbgPrint((DPRINT_MEMORY
, "Int15h AH=88h\n"));
97 DbgPrint((DPRINT_MEMORY
, "AX = 0x%x\n", RegsOut
.w
.ax
));
98 DbgPrint((DPRINT_MEMORY
, "CF set = %s\n\n", (RegsOut
.x
.eflags
& I386FLAG_CF
) ? "TRUE" : "FALSE"));
100 if (INT386_SUCCESS(RegsOut
) && RegsOut
.w
.ax
!= 0)
102 MemorySize
= RegsOut
.w
.ax
;
106 /* If we get here then Int15 Func 88h didn't work */
107 /* So try reading the CMOS */
108 WRITE_PORT_UCHAR((PUCHAR
)0x70, 0x31);
109 MemorySize
= READ_PORT_UCHAR((PUCHAR
)0x71);
110 MemorySize
= (MemorySize
& 0xFFFF);
111 MemorySize
= (MemorySize
<< 8);
113 DbgPrint((DPRINT_MEMORY
, "Int15h Failed\n"));
114 DbgPrint((DPRINT_MEMORY
, "CMOS reports: 0x%x\n", MemorySize
));
120 PcMemGetConventionalMemorySize(VOID
)
124 DbgPrint((DPRINT_MEMORY
, "GetConventionalMemorySize()\n"));
127 * BIOS - GET MEMORY SIZE
130 * AX = kilobytes of contiguous memory starting at absolute address 00000h
132 * This call returns the contents of the word at 0040h:0013h;
133 * in PC and XT, this value is set from the switches on the motherboard
136 Int386(0x12, &Regs
, &Regs
);
138 DbgPrint((DPRINT_MEMORY
, "Int12h\n"));
139 DbgPrint((DPRINT_MEMORY
, "AX = 0x%x\n\n", Regs
.w
.ax
));
141 return (ULONG
)Regs
.w
.ax
;
145 PcMemGetBiosMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap
, ULONG MaxMemoryMapSize
)
150 DbgPrint((DPRINT_MEMORY
, "GetBiosMemoryMap()\n"));
153 * Newer BIOSes - GET SYSTEM MEMORY MAP
157 * EDX = 534D4150h ('SMAP')
158 * EBX = continuation value or 00000000h to start at beginning of map
159 * ECX = size of buffer for result, in bytes (should be >= 20 bytes)
160 * ES:DI -> buffer for result
162 * CF clear if successful
163 * EAX = 534D4150h ('SMAP')
164 * ES:DI buffer filled
165 * EBX = next offset from which to copy or 00000000h if all done
166 * ECX = actual length returned in bytes
168 * AH = error code (86h)
170 Regs
.x
.eax
= 0x0000E820;
171 Regs
.x
.edx
= 0x534D4150; /* ('SMAP') */
172 Regs
.x
.ebx
= 0x00000000;
173 Regs
.x
.ecx
= sizeof(BIOS_MEMORY_MAP
);
174 Regs
.w
.es
= BIOSCALLBUFSEGMENT
;
175 Regs
.w
.di
= BIOSCALLBUFOFFSET
;
176 for (MapCount
= 0; MapCount
< MaxMemoryMapSize
; MapCount
++)
178 Int386(0x15, &Regs
, &Regs
);
180 DbgPrint((DPRINT_MEMORY
, "Memory Map Entry %d\n", MapCount
));
181 DbgPrint((DPRINT_MEMORY
, "Int15h AX=E820h\n"));
182 DbgPrint((DPRINT_MEMORY
, "EAX = 0x%x\n", Regs
.x
.eax
));
183 DbgPrint((DPRINT_MEMORY
, "EBX = 0x%x\n", Regs
.x
.ebx
));
184 DbgPrint((DPRINT_MEMORY
, "ECX = 0x%x\n", Regs
.x
.ecx
));
185 DbgPrint((DPRINT_MEMORY
, "CF set = %s\n", (Regs
.x
.eflags
& I386FLAG_CF
) ? "TRUE" : "FALSE"));
187 /* If the BIOS didn't return 'SMAP' in EAX then
188 * it doesn't support this call */
189 if (Regs
.x
.eax
!= 0x534D4150)
194 /* Copy data to caller's buffer */
195 RtlCopyMemory(&BiosMemoryMap
[MapCount
], (PVOID
)BIOSCALLBUFFER
, Regs
.x
.ecx
);
197 DbgPrint((DPRINT_MEMORY
, "BaseAddress: 0x%p\n", (PVOID
)BiosMemoryMap
[MapCount
].BaseAddress
));
198 DbgPrint((DPRINT_MEMORY
, "Length: 0x%p\n", (PVOID
)BiosMemoryMap
[MapCount
].Length
));
199 DbgPrint((DPRINT_MEMORY
, "Type: 0x%x\n", BiosMemoryMap
[MapCount
].Type
));
200 DbgPrint((DPRINT_MEMORY
, "Reserved: 0x%x\n", BiosMemoryMap
[MapCount
].Reserved
));
201 DbgPrint((DPRINT_MEMORY
, "\n"));
203 /* If the continuation value is zero or the
204 * carry flag is set then this was
205 * the last entry so we're done */
206 if (Regs
.x
.ebx
== 0x00000000 || !INT386_SUCCESS(Regs
))
209 DbgPrint((DPRINT_MEMORY
, "End Of System Memory Map!\n\n"));
213 /* Setup the registers for the next call */
214 Regs
.x
.eax
= 0x0000E820;
215 Regs
.x
.edx
= 0x534D4150; /* ('SMAP') */
216 /* Regs.x.ebx = 0x00000001; Continuation value already set by the BIOS */
217 Regs
.x
.ecx
= sizeof(BIOS_MEMORY_MAP
);
218 Regs
.w
.es
= BIOSCALLBUFSEGMENT
;
219 Regs
.w
.di
= BIOSCALLBUFOFFSET
;
226 PcMemGetMemoryMap(PBIOS_MEMORY_MAP BiosMemoryMap
, ULONG MaxMemoryMapSize
)
230 EntryCount
= PcMemGetBiosMemoryMap(BiosMemoryMap
, MaxMemoryMapSize
);
232 /* If the BIOS didn't provide a memory map, synthesize one */
233 if (0 == EntryCount
&& 2 <= MaxMemoryMapSize
)
235 /* Conventional memory */
236 BiosMemoryMap
[0].BaseAddress
= 0;
237 BiosMemoryMap
[0].Length
= PcMemGetConventionalMemorySize() * 1024;
238 BiosMemoryMap
[0].Type
= BiosMemoryUsable
;
239 /* Extended memory */
240 BiosMemoryMap
[1].BaseAddress
= 1024 * 1024;
241 BiosMemoryMap
[1].Length
= PcMemGetExtendedMemorySize() * 1024;
242 BiosMemoryMap
[1].Type
= BiosMemoryUsable
;