mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
123 lines
3.1 KiB
123 lines
3.1 KiB
// SPDX-License-Identifier: GPL-2.0-only |
|
/* -*- linux-c -*- ------------------------------------------------------- * |
|
* |
|
* Copyright (C) 1991, 1992 Linus Torvalds |
|
* Copyright 2007 rPath, Inc. - All Rights Reserved |
|
* Copyright 2009 Intel Corporation; author H. Peter Anvin |
|
* |
|
* ----------------------------------------------------------------------- */ |
|
|
|
/* |
|
* Memory detection code |
|
*/ |
|
|
|
#include "boot.h" |
|
|
|
#define SMAP 0x534d4150 /* ASCII "SMAP" */ |
|
|
|
static void detect_memory_e820(void) |
|
{ |
|
int count = 0; |
|
struct biosregs ireg, oreg; |
|
struct boot_e820_entry *desc = boot_params.e820_table; |
|
static struct boot_e820_entry buf; /* static so it is zeroed */ |
|
|
|
initregs(&ireg); |
|
ireg.ax = 0xe820; |
|
ireg.cx = sizeof(buf); |
|
ireg.edx = SMAP; |
|
ireg.di = (size_t)&buf; |
|
|
|
/* |
|
* Note: at least one BIOS is known which assumes that the |
|
* buffer pointed to by one e820 call is the same one as |
|
* the previous call, and only changes modified fields. Therefore, |
|
* we use a temporary buffer and copy the results entry by entry. |
|
* |
|
* This routine deliberately does not try to account for |
|
* ACPI 3+ extended attributes. This is because there are |
|
* BIOSes in the field which report zero for the valid bit for |
|
* all ranges, and we don't currently make any use of the |
|
* other attribute bits. Revisit this if we see the extended |
|
* attribute bits deployed in a meaningful way in the future. |
|
*/ |
|
|
|
do { |
|
intcall(0x15, &ireg, &oreg); |
|
ireg.ebx = oreg.ebx; /* for next iteration... */ |
|
|
|
/* BIOSes which terminate the chain with CF = 1 as opposed |
|
to %ebx = 0 don't always report the SMAP signature on |
|
the final, failing, probe. */ |
|
if (oreg.eflags & X86_EFLAGS_CF) |
|
break; |
|
|
|
/* Some BIOSes stop returning SMAP in the middle of |
|
the search loop. We don't know exactly how the BIOS |
|
screwed up the map at that point, we might have a |
|
partial map, the full map, or complete garbage, so |
|
just return failure. */ |
|
if (oreg.eax != SMAP) { |
|
count = 0; |
|
break; |
|
} |
|
|
|
*desc++ = buf; |
|
count++; |
|
} while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_table)); |
|
|
|
boot_params.e820_entries = count; |
|
} |
|
|
|
static void detect_memory_e801(void) |
|
{ |
|
struct biosregs ireg, oreg; |
|
|
|
initregs(&ireg); |
|
ireg.ax = 0xe801; |
|
intcall(0x15, &ireg, &oreg); |
|
|
|
if (oreg.eflags & X86_EFLAGS_CF) |
|
return; |
|
|
|
/* Do we really need to do this? */ |
|
if (oreg.cx || oreg.dx) { |
|
oreg.ax = oreg.cx; |
|
oreg.bx = oreg.dx; |
|
} |
|
|
|
if (oreg.ax > 15*1024) { |
|
return; /* Bogus! */ |
|
} else if (oreg.ax == 15*1024) { |
|
boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax; |
|
} else { |
|
/* |
|
* This ignores memory above 16MB if we have a memory |
|
* hole there. If someone actually finds a machine |
|
* with a memory hole at 16MB and no support for |
|
* 0E820h they should probably generate a fake e820 |
|
* map. |
|
*/ |
|
boot_params.alt_mem_k = oreg.ax; |
|
} |
|
} |
|
|
|
static void detect_memory_88(void) |
|
{ |
|
struct biosregs ireg, oreg; |
|
|
|
initregs(&ireg); |
|
ireg.ah = 0x88; |
|
intcall(0x15, &ireg, &oreg); |
|
|
|
boot_params.screen_info.ext_mem_k = oreg.ax; |
|
} |
|
|
|
void detect_memory(void) |
|
{ |
|
detect_memory_e820(); |
|
|
|
detect_memory_e801(); |
|
|
|
detect_memory_88(); |
|
}
|
|
|