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