Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* -*- linux-c -*- ------------------------------------------------------- *
0003  *
0004  *   Copyright (C) 1991, 1992 Linus Torvalds
0005  *   Copyright 2007 rPath, Inc. - All Rights Reserved
0006  *   Copyright 2009 Intel Corporation; author H. Peter Anvin
0007  *
0008  * ----------------------------------------------------------------------- */
0009 
0010 /*
0011  * Memory detection code
0012  */
0013 
0014 #include "boot.h"
0015 
0016 #define SMAP    0x534d4150  /* ASCII "SMAP" */
0017 
0018 static void detect_memory_e820(void)
0019 {
0020     int count = 0;
0021     struct biosregs ireg, oreg;
0022     struct boot_e820_entry *desc = boot_params.e820_table;
0023     static struct boot_e820_entry buf; /* static so it is zeroed */
0024 
0025     initregs(&ireg);
0026     ireg.ax  = 0xe820;
0027     ireg.cx  = sizeof(buf);
0028     ireg.edx = SMAP;
0029     ireg.di  = (size_t)&buf;
0030 
0031     /*
0032      * Note: at least one BIOS is known which assumes that the
0033      * buffer pointed to by one e820 call is the same one as
0034      * the previous call, and only changes modified fields.  Therefore,
0035      * we use a temporary buffer and copy the results entry by entry.
0036      *
0037      * This routine deliberately does not try to account for
0038      * ACPI 3+ extended attributes.  This is because there are
0039      * BIOSes in the field which report zero for the valid bit for
0040      * all ranges, and we don't currently make any use of the
0041      * other attribute bits.  Revisit this if we see the extended
0042      * attribute bits deployed in a meaningful way in the future.
0043      */
0044 
0045     do {
0046         intcall(0x15, &ireg, &oreg);
0047         ireg.ebx = oreg.ebx; /* for next iteration... */
0048 
0049         /* BIOSes which terminate the chain with CF = 1 as opposed
0050            to %ebx = 0 don't always report the SMAP signature on
0051            the final, failing, probe. */
0052         if (oreg.eflags & X86_EFLAGS_CF)
0053             break;
0054 
0055         /* Some BIOSes stop returning SMAP in the middle of
0056            the search loop.  We don't know exactly how the BIOS
0057            screwed up the map at that point, we might have a
0058            partial map, the full map, or complete garbage, so
0059            just return failure. */
0060         if (oreg.eax != SMAP) {
0061             count = 0;
0062             break;
0063         }
0064 
0065         *desc++ = buf;
0066         count++;
0067     } while (ireg.ebx && count < ARRAY_SIZE(boot_params.e820_table));
0068 
0069     boot_params.e820_entries = count;
0070 }
0071 
0072 static void detect_memory_e801(void)
0073 {
0074     struct biosregs ireg, oreg;
0075 
0076     initregs(&ireg);
0077     ireg.ax = 0xe801;
0078     intcall(0x15, &ireg, &oreg);
0079 
0080     if (oreg.eflags & X86_EFLAGS_CF)
0081         return;
0082 
0083     /* Do we really need to do this? */
0084     if (oreg.cx || oreg.dx) {
0085         oreg.ax = oreg.cx;
0086         oreg.bx = oreg.dx;
0087     }
0088 
0089     if (oreg.ax > 15*1024) {
0090         return; /* Bogus! */
0091     } else if (oreg.ax == 15*1024) {
0092         boot_params.alt_mem_k = (oreg.bx << 6) + oreg.ax;
0093     } else {
0094         /*
0095          * This ignores memory above 16MB if we have a memory
0096          * hole there.  If someone actually finds a machine
0097          * with a memory hole at 16MB and no support for
0098          * 0E820h they should probably generate a fake e820
0099          * map.
0100          */
0101         boot_params.alt_mem_k = oreg.ax;
0102     }
0103 }
0104 
0105 static void detect_memory_88(void)
0106 {
0107     struct biosregs ireg, oreg;
0108 
0109     initregs(&ireg);
0110     ireg.ah = 0x88;
0111     intcall(0x15, &ireg, &oreg);
0112 
0113     boot_params.screen_info.ext_mem_k = oreg.ax;
0114 }
0115 
0116 void detect_memory(void)
0117 {
0118     detect_memory_e820();
0119 
0120     detect_memory_e801();
0121 
0122     detect_memory_88();
0123 }