1
/* Some code here borrowed from dmidecode, also GPLed and copyrighted by:
2
* (C) 2000-2002 Alan Cox <alan@redhat.com>
3
* (C) 2002-2005 Jean Delvare <khali@linux-fr.org>
4
* I (Colin Watson) copied it in reduced form rather than using dmidecode
5
* directly because (a) the d-i initrd is tight on space and this is much
6
* smaller and (b) parsing the output of dmidecode in shell is unreasonably
15
#include <sys/types.h>
20
#define WORD(x) (*(const uint16_t *)(x))
21
#define DWORD(x) (*(const uint32_t *)(x))
30
static int checksum(const uint8_t *buf, size_t len)
35
for (a = 0; a < len; a++)
40
/* Copy a physical memory chunk into a memory buffer.
41
* This function allocates memory.
43
static void *mem_chunk(size_t base, size_t len)
50
fd = open("/dev/mem", O_RDONLY);
62
mmoffset = base % sysconf(_SC_PAGESIZE);
64
mmoffset = base % getpagesize();
66
/* Please note that we don't use mmap() for performance reasons here,
67
* but to workaround problems many people encountered when trying
68
* to read from /dev/mem using regular read() calls.
70
mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd,
72
if (mmp == MAP_FAILED)
79
memcpy(p, mmp + mmoffset, len);
81
munmap(mmp, mmoffset + len);
88
static uint64_t dmi_table(uint32_t base, uint16_t len, uint16_t num)
92
uint64_t available = 0;
94
buf = mem_chunk(base, len);
99
while (i < num && data + sizeof(struct dmi_header) <= buf + len)
102
struct dmi_header *h = (struct dmi_header *)data;
104
/* Stop decoding at end of table marker */
108
/* Look for the next handle */
109
next = data + h->length;
110
while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0))
113
/* Memory Array Mapped Address */
114
if (h->type == 19 && h->length >= 0x0F)
117
start = DWORD(data + 0x04);
118
end = DWORD(data + 0x08);
120
/* output in kilobytes */
121
available += end - start + 1;
132
static uint64_t smbios_decode(uint8_t *buf)
134
if (checksum(buf, buf[0x05]) &&
135
memcmp(buf + 0x10, "_DMI_", 5) == 0 &&
136
checksum(buf + 0x10, 0x0F))
138
return dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16),
145
static uint64_t legacy_decode(uint8_t *buf)
147
if (checksum(buf, 0x0F))
149
return dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06),
156
static uint64_t dmi_available_memory(void)
162
buf = mem_chunk(0xF0000, 0x10000);
166
for (fp = 0; fp <= 0xFFF0; fp += 16)
168
if (memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0)
170
ret = smbios_decode(buf + fp);
175
else if (memcmp(buf + fp, "_DMI_", 5) == 0)
177
ret = legacy_decode(buf + fp);
187
int main(int argc, char **argv)
189
printf("%llu\n", dmi_available_memory());