1 /* ----------------------------------------------------------------------- *
3 * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
4 * Copyright 2009 H. Peter Anvin - All Rights Reserved
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or
11 * sell copies of the Software, and to permit persons to whom
12 * the Software is furnished to do so, subject to the following
15 * The above copyright notice and this permission notice shall
16 * be included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
27 * ----------------------------------------------------------------------- */
32 * Query the system for free memory
42 #include <syslinux/memscan.h>
50 int syslinux_scan_memory(scan_memory_callback_t callback
, void *data
)
52 static com32sys_t ireg
;
54 struct e820_entry
*e820buf
;
55 uint64_t start
, len
, maxlen
;
59 const addr_t bios_data
= 0x510; /* Amount to reserve for BIOS data */
61 /* Use INT 12h to get DOS memory */
62 __intcall(0x12, &__com32_zero_regs
, &oreg
);
63 dosmem
= oreg
.eax
.w
[0] << 10;
64 if (dosmem
< 32 * 1024 || dosmem
> 640 * 1024) {
65 /* INT 12h reports nonsense... now what? */
66 uint16_t ebda_seg
= *(uint16_t *) 0x40e;
67 if (ebda_seg
>= 0x8000 && ebda_seg
< 0xa000)
68 dosmem
= ebda_seg
<< 4;
70 dosmem
= 640 * 1024; /* Hope for the best... */
72 rv
= callback(data
, bios_data
, dosmem
- bios_data
, true);
76 /* First try INT 15h AX=E820h */
77 e820buf
= lzalloc(sizeof *e820buf
);
82 ireg
.edx
.l
= 0x534d4150;
84 ireg
.ecx
.l
= sizeof(*e820buf
);
85 ireg
.es
= SEG(e820buf
);
86 ireg
.edi
.w
[0] = OFFS(e820buf
);
89 __intcall(0x15, &ireg
, &oreg
);
91 if ((oreg
.eflags
.l
& EFLAGS_CF
) ||
92 (oreg
.eax
.l
!= 0x534d4150) || (oreg
.ecx
.l
< 20))
95 start
= e820buf
->start
;
98 if (start
< 0x100000000ULL
) {
99 /* Don't rely on E820 being valid for low memory. Doing so
100 could mean stuff like overwriting the PXE stack even when
101 using "keeppxe", etc. */
102 if (start
< 0x100000ULL
) {
103 if (len
> 0x100000ULL
- start
)
104 len
-= 0x100000ULL
- start
;
110 maxlen
= 0x100000000ULL
- start
;
115 rv
= callback(data
, (addr_t
) start
, (addr_t
) len
,
123 ireg
.ebx
.l
= oreg
.ebx
.l
;
124 } while (oreg
.ebx
.l
);
131 /* Next try INT 15h AX=E801h */
132 ireg
.eax
.w
[0] = 0xe801;
133 __intcall(0x15, &ireg
, &oreg
);
135 if (!(oreg
.eflags
.l
& EFLAGS_CF
) && oreg
.ecx
.w
[0]) {
136 rv
= callback(data
, (addr_t
) 1 << 20, oreg
.ecx
.w
[0] << 10, true);
141 rv
= callback(data
, (addr_t
) 16 << 20, oreg
.edx
.w
[0] << 16, true);
149 /* Finally try INT 15h AH=88h */
150 ireg
.eax
.w
[0] = 0x8800;
151 if (!(oreg
.eflags
.l
& EFLAGS_CF
) && oreg
.eax
.w
[0]) {
152 rv
= callback(data
, (addr_t
) 1 << 20, oreg
.ecx
.w
[0] << 10, true);