^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* -*- linux-c -*- ------------------------------------------------------- *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 1991, 1992 Linus Torvalds
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2007 rPath, Inc. - All Rights Reserved
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright 2009 Intel Corporation; author H. Peter Anvin
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * ----------------------------------------------------------------------- */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * Memory detection code
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "boot.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define SMAP 0x534d4150 /* ASCII "SMAP" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) static void detect_memory_e820(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) int count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct boot_e820_entry *desc = boot_params.e820_table;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static struct boot_e820_entry buf; /* static so it is zeroed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) ireg.ax = 0xe820;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) ireg.cx = sizeof(buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) ireg.edx = SMAP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) ireg.di = (size_t)&buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * Note: at least one BIOS is known which assumes that the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) * buffer pointed to by one e820 call is the same one as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) * the previous call, and only changes modified fields. Therefore,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) * we use a temporary buffer and copy the results entry by entry.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * This routine deliberately does not try to account for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * ACPI 3+ extended attributes. This is because there are
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) * BIOSes in the field which report zero for the valid bit for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * all ranges, and we don't currently make any use of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * other attribute bits. Revisit this if we see the extended
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) * attribute bits deployed in a meaningful way in the future.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) intcall(0x15, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) ireg.ebx = oreg.ebx; /* for next iteration... */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* BIOSes which terminate the chain with CF = 1 as opposed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) to %ebx = 0 don't always report the SMAP signature on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) the final, failing, probe. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) if (oreg.eflags & X86_EFLAGS_CF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) /* Some BIOSes stop returning SMAP in the middle of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) the search loop. We don't know exactly how the BIOS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) screwed up the map at that point, we might have a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) partial map, the full map, or complete garbage, so
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) just return failure. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (oreg.eax != SMAP) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) *desc++ = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_table));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) boot_params.e820_entries = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) static void detect_memory_e801(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) ireg.ax = 0xe801;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) intcall(0x15, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (oreg.eflags & X86_EFLAGS_CF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) /* Do we really need to do this? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (oreg.cx || oreg.dx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) oreg.ax = oreg.cx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) oreg.bx = oreg.dx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) if (oreg.ax > 15*1024) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return; /* Bogus! */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) } else if (oreg.ax == 15*1024) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * This ignores memory above 16MB if we have a memory
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * hole there. If someone actually finds a machine
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * with a memory hole at 16MB and no support for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) * 0E820h they should probably generate a fake e820
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) * map.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) boot_params.alt_mem_k = oreg.ax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static void detect_memory_88(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) struct biosregs ireg, oreg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) initregs(&ireg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) ireg.ah = 0x88;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) intcall(0x15, &ireg, &oreg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) boot_params.screen_info.ext_mem_k = oreg.ax;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) void detect_memory(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) detect_memory_e820();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) detect_memory_e801();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) detect_memory_88();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }