Adding upstream version 4.00~pre54+dfsg.
[syslinux-debian/hramrach.git] / com32 / lib / syslinux / memscan.c
blobfc676cbfd76ce57c3e977162389362887a95dbc1
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
13 * conditions:
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 * ----------------------------------------------------------------------- */
30 * memscan.c
32 * Query the system for free memory
35 #include <assert.h>
36 #include <stdbool.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <inttypes.h>
40 #include <com32.h>
42 #include <syslinux/memscan.h>
44 struct e820_entry {
45 uint64_t start;
46 uint64_t len;
47 uint32_t type;
50 int syslinux_scan_memory(scan_memory_callback_t callback, void *data)
52 static com32sys_t ireg;
53 com32sys_t oreg;
54 struct e820_entry *e820buf;
55 uint64_t start, len, maxlen;
56 int memfound = 0;
57 int rv;
58 addr_t dosmem;
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;
69 else
70 dosmem = 640 * 1024; /* Hope for the best... */
72 rv = callback(data, bios_data, dosmem - bios_data, true);
73 if (rv)
74 return rv;
76 /* First try INT 15h AX=E820h */
77 e820buf = lzalloc(sizeof *e820buf);
78 if (!e820buf)
79 return -1;
81 ireg.eax.l = 0xe820;
82 ireg.edx.l = 0x534d4150;
83 ireg.ebx.l = 0;
84 ireg.ecx.l = sizeof(*e820buf);
85 ireg.es = SEG(e820buf);
86 ireg.edi.w[0] = OFFS(e820buf);
88 do {
89 __intcall(0x15, &ireg, &oreg);
91 if ((oreg.eflags.l & EFLAGS_CF) ||
92 (oreg.eax.l != 0x534d4150) || (oreg.ecx.l < 20))
93 break;
95 start = e820buf->start;
96 len = e820buf->len;
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;
105 else
106 len = 0;
107 start = 0x100000ULL;
110 maxlen = 0x100000000ULL - start;
111 if (len > maxlen)
112 len = maxlen;
114 if (len) {
115 rv = callback(data, (addr_t) start, (addr_t) len,
116 e820buf->type == 1);
117 if (rv)
118 return rv;
119 memfound = 1;
123 ireg.ebx.l = oreg.ebx.l;
124 } while (oreg.ebx.l);
126 lfree(e820buf);
128 if (memfound)
129 return 0;
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);
137 if (rv)
138 return rv;
140 if (oreg.edx.w[0]) {
141 rv = callback(data, (addr_t) 16 << 20, oreg.edx.w[0] << 16, true);
142 if (rv)
143 return rv;
146 return 0;
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);
153 if (rv)
154 return rv;
157 return 0;