diff -Naur linux-2.4.0orig/Documentation/Configure.help linux-2.4.0exp/Documentation/Configure.help --- linux-2.4.0orig/Documentation/Configure.help Wed May 31 12:01:46 2000 +++ linux-2.4.0exp/Documentation/Configure.help Wed May 31 11:29:19 2000 @@ -185,6 +185,40 @@ on the Alpha. The only time you would ever not say Y is to say M in order to debug the code. Say Y unless you know what you are doing. +Use extended bios calls to detect memory +CONFIG_MEM_E820 + The traditional Linux memory detection code for ia32 machines is + restricted to detecting 64mb (or 16mb!) of core. The E820 call, + which is used by many operating systems, is a modern replacement + for it, which gives back a detailed memory map of usable memory, + rom, and ACPI tables. Older machines ignore this detection method, + so you should be able to say Y here unless your machine has + problems correctly detecting memory. + +Merge adjacent memory regions +CONFIG_E820_MERGE + The E820 bios call may return a fragmented map where many segments + of the map are too small to fit a Linux memory table entry onto. + This option merges adjacent memory sections together before + initializing the Linux memory tables. + +Reclaim ACPI table memory (DANGEROUS) +CONFIG_E820_RECLAIM + If you are not using ACPI (CONFIG_ACPI) on this machine, you can + use this option to use ACPI tables as regular memory. This is a + dangerous option -- some people have reported that attempting to + reclaim ACPI tables result in Linux crashing -- so only answer Y + if you know what you are doing. + +Use bios call e801 to detect memory +CONFIG_MEM_E801 + The E801 bios call was an earlier method for detecting memory on + ia32 machines. It has fallen out of favor, and some modern + bioses have broken it so that it returns garbage. The kernel + will attempt to use this call if the e820 bios call does not + exist on the machine. It's probably safe to answer Y here, + though 99% of the machines out there won't use this call. + High Memory support CONFIG_NOHIGHMEM Linux can use up to 64 Gigabytes of physical memory on x86 systems. diff -Naur linux-2.4.0orig/Documentation/i386/zero-page.txt linux-2.4.0exp/Documentation/i386/zero-page.txt --- linux-2.4.0orig/Documentation/i386/zero-page.txt Wed May 31 12:01:20 2000 +++ linux-2.4.0exp/Documentation/i386/zero-page.txt Sat May 27 01:59:31 2000 @@ -29,7 +29,8 @@ ( struct sys_desc_table_struct ) 0xb0 - 0x1df Free. Add more parameters here if you really need them. -0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb +0x1e0 unsigned long E801_MEM_LOW, e801 # kbytes between 1mb and 16mb +0x1e4 unsigned long E801_MEM_HIGH, e801 # kbytes above 16mb 0x1e8 char number of entries in E820MAP (below) 0x1f1 char size of setup.S, number of sectors 0x1f2 unsigned short MOUNT_ROOT_RDONLY (if !=0) diff -Naur linux-2.4.0orig/Makefile linux-2.4.0exp/Makefile --- linux-2.4.0orig/Makefile Wed May 31 12:01:46 2000 +++ linux-2.4.0exp/Makefile Wed May 31 11:29:19 2000 @@ -336,10 +336,10 @@ if [ -f PCMCIA_CHAR_MODULES ]; then inst_mod PCMCIA_CHAR_MODULES pcmcia; fi; \ if [ -f PCMCIA_SCSI_MODULES ]; then inst_mod PCMCIA_SCSI_MODULES pcmcia; fi; \ \ - ls -1 -U *.o | sort > $$MODLIB/.allmods; \ + ls -1 *.o | sort > $$MODLIB/.allmods; \ if [ -f $$MODLIB/net/3c59x.o ]; then \ mkdir -p $$MODLIB/pcmcia; \ - ln -nfs ../net/3c59x.o $$MODLIB/pcmcia/3c575_cb.o; \ + ln -fs ../net/3c59x.o $$MODLIB/pcmcia/3c575_cb.o; \ MODULES="$$MODULES 3c575_cb.o"; fi; \ echo $$MODULES | tr ' ' '\n' | sort | comm -23 $$MODLIB/.allmods - > $$MODLIB/.misc; \ if [ -s $$MODLIB/.misc ]; then inst_mod $$MODLIB/.misc misc; fi; \ diff -Naur linux-2.4.0orig/arch/i386/boot/setup.S linux-2.4.0exp/arch/i386/boot/setup.S --- linux-2.4.0orig/arch/i386/boot/setup.S Wed May 31 12:01:19 2000 +++ linux-2.4.0exp/arch/i386/boot/setup.S Sat May 27 01:59:30 2000 @@ -32,6 +32,9 @@ * * Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999. * + * + * Extended memory detection made more paranoid by orc@pell.chi.il.us (jessica l. + * parsons) and Nathan Zook (nathan.zook@amd.com), December 1999-February 2000. */ #define __ASSEMBLY__ @@ -255,91 +258,99 @@ loader_panic_mess: .string "Wrong loader, giving up..." loader_ok: -# Get memory size (extended mem, kB) +/* MEMORY DETECTION CODE */ xorl %eax, %eax - movl %eax, (0x1e0) -#ifndef STANDARD_MEMORY_BIOS_CALL - movb %al, (E820NR) -# Try three different memory detection schemes. First, try -# e820h, which lets us assemble a memory map, then try e801h, -# which returns a 32-bit memory size, and finally 88h, which -# returns 0-64m - -# method E820H: -# the memory map from hell. e820h returns memory classified into -# a whole bunch of different types, and allows memory holes and -# everything. We scan through this memory map and build a list -# of the first 32 memory areas, which we return at [E820MAP]. -# + movl %eax, (0x1e0) # zero e801_mem_low + movl %eax, (0x1e4) # " e801_mem_high + movb %al, (E820NR) # " e820_nr + +/* + * Try three different memory detection schemes. First, try + * e820h, which lets us assemble a memory map, then try e801h, + * which returns a 32-bit memory size, and finally 88h, which + * returns 0-64m + */ -meme820: - movl $0x534d4150, %edx # ascii `SMAP' - xorl %ebx, %ebx # continuation counter - movw $E820MAP, %di # point into the whitelist - # so we can have the bios - # directly write into it. +#ifdef CONFIG_MEM_E820 + +/* + * method E820H: + * the memory map from hell. e820h returns memory classified into + * a whole bunch of different types, and allows memory holes and + * everything. We scan through this memory map and build a list + * of the first E820MAX memory areas, which we return at [E820MAP]. + */ +#define SMAP 0x534d4150 +meme820: + xorl %ebx, %ebx # e820 continuation counter + movw $E820MAP, %di # point di at the map jmpe820: - movl $0x0000e820, %eax # e820, upper word zeroed - movl $20, %ecx # size of the e820rec - pushw %ds # data record. + pushw %ds # set es := ds every time around. popw %es - int $0x15 # make the call - jc bail820 # fall to e801 if it fails - - cmpl $0x534d4150, %eax # check the return is `SMAP' - jne bail820 # fall to e801 if it fails - -# cmpl $1, 16(%di) # is this usable memory? -# jne again820 - - # If this is usable memory, we save it by simply advancing %di by - # sizeof(e820rec). - # -good820: - movb (E820NR), %al # up to 32 entries - cmpb $E820MAX, %al - jnl bail820 - - incb (E820NR) - movw %di, %ax - addw $20, %ax - movw %ax, %di -again820: - cmpl $0, %ebx # check to see if - jne jmpe820 # %ebx is set to EOF -bail820: - - -# method E801H: -# memory size is in 1k chunksizes, to avoid confusing loadlin. -# we store the 0xe801 memory size in a completely different place, -# because it will most likely be longer than 16 bits. -# (use 1e0 because that's what Larry Augustine uses in his -# alternative new memory detection scheme, and it's sensible -# to write everything into the same place.) + movl $0x0000e820, %eax # e820, upper word zeroed + movl $SMAP, %edx # assign magic numbers + movl $E820LEN, %ecx # we'd like one memory record, please. + + int $0x15 # make the call + jc fin820 # fall out if it fails + + cmpl $SMAP, %eax # did e820 properly move the magic? + jne punte820 + + cmpw $E820LEN, %cx # did we get back a whole memory record? + jne punte820 + +stash820: + incb (E820NR) # up the # of records + movb (E820NR), %al # If the table fills up + cmpb $E820MAX, %al # we must flee + jnl fin820 + + cmp $0, %ebx # any more records in the pipe? + jz fin820 # apparently not + + addw $E820LEN, %di # point %di at the next record + jmp jmpe820 # and go around again + +punte820: # if something goes wrong, don't + xor %ah, %ah # let userland look at this (corrupt?) + movb %ah, (E820NR) # e820 map. +fin820: + +#endif/*CONFIG_MEM_E820*/ + +#ifdef CONFIG_MEM_E801 +/* + * method E801H: + * e801 returns 2 memory chunks: 1 from 1mb to 16mb, and 1 from 16mb up. + * return the both of them, low in 1e0h, for compatability with older + * versions of memory detection code, and high in 1e4h. + */ meme801: movw $0xe801, %ax int $0x15 - jc mem88 + jc fine801 - andl $0xffff, %edx # clear sign extend - shll $6, %edx # and go from 64k to 1k chunks - movl %edx, (0x1e0) # store extended memory size andl $0xffff, %ecx # clear sign extend - addl %ecx, (0x1e0) # and add lower memory into - # total size. + movl %ecx, (0x1e0) # store 1kb between 1-16mb + andl $0xffff, %edx # clear sign extend + movl %edx, (0x1e4) # store 64kb chunks above 16mb +fine801: -# Ye Olde Traditional Methode. Returns the memory size (up to 16mb or -# 64mb, depending on the bios) in ax. -mem88: +#endif/*CONFIG_MEM_E801*/ -#endif +/* + * Ye Olde Traditional Methode. Returns the memory size (up to 16mb or + * 64mb, depending on the bios) in ax. + */ movb $0x88, %ah int $0x15 movw %ax, (2) + +/* END OF MEMORY DETECTION CODE */ # Set the keyboard repeat rate to the max movw $0x0305, %ax diff -Naur linux-2.4.0orig/arch/i386/config.in linux-2.4.0exp/arch/i386/config.in --- linux-2.4.0orig/arch/i386/config.in Wed May 31 12:01:46 2000 +++ linux-2.4.0exp/arch/i386/config.in Wed May 31 11:29:19 2000 @@ -108,6 +108,16 @@ define_bool CONFIG_X86_PAE y fi +mainmenu_option next_comment +comment 'Memory detection' +bool 'Use extended bios calls to detect memory' CONFIG_MEM_E820 +if [ "$CONFIG_MEM_E820" = "y" ]; then + bool ' Merge adjacent memory regions' CONFIG_E820_MERGE + bool ' Reclaim ACPI table memory (DANGEROUS)' CONFIG_E820_RECLAIM + bool ' Also try bios call E801' CONFIG_MEM_E801 +fi +endmenu + if [ "$CONFIG_X86_FXSR" != "y" ]; then bool 'Math emulation' CONFIG_MATH_EMULATION fi diff -Naur linux-2.4.0orig/arch/i386/defconfig linux-2.4.0exp/arch/i386/defconfig --- linux-2.4.0orig/arch/i386/defconfig Wed May 31 12:01:46 2000 +++ linux-2.4.0exp/arch/i386/defconfig Wed May 31 11:29:19 2000 @@ -37,6 +37,10 @@ # CONFIG_X86_MSR is not set # CONFIG_X86_CPUID is not set CONFIG_NOHIGHMEM=y +CONFIG_MEM_E820=y +CONFIG_MEM_E801=y +CONFIG_E820_MERGE=y +#CONFIG_MEM_RECLAIM is not set # CONFIG_HIGHMEM4G is not set # CONFIG_HIGHMEM64G is not set # CONFIG_MATH_EMULATION is not set diff -Naur linux-2.4.0orig/arch/i386/kernel/Makefile linux-2.4.0exp/arch/i386/kernel/Makefile --- linux-2.4.0orig/arch/i386/kernel/Makefile Wed May 31 12:01:19 2000 +++ linux-2.4.0exp/arch/i386/kernel/Makefile Sat May 27 01:59:31 2000 @@ -15,7 +15,7 @@ O_TARGET := kernel.o O_OBJS := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \ ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \ - pci-dma.o + pci-dma.o regions.o OX_OBJS := i386_ksyms.o MX_OBJS := diff -Naur linux-2.4.0orig/arch/i386/kernel/regions.c linux-2.4.0exp/arch/i386/kernel/regions.c --- linux-2.4.0orig/arch/i386/kernel/regions.c Wed May 31 12:01:19 2000 +++ linux-2.4.0exp/arch/i386/kernel/regions.c Wed May 31 11:40:13 2000 @@ -0,0 +1,364 @@ +/* + * memory region setup and pruning code + * + * Copyright (c) 2000 by Jessica L. Parsons, Nathan Zook. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PARAM ((unsigned char *)empty_zero_page) + +#define EXT_MEM_K (*(unsigned short *) (PARAM+2)) +#define E801_MEM_LOW (*(unsigned long *) (PARAM+0x1e0)) +#define E801_MEM_HIGH (*(unsigned long *) (PARAM+0x1e4)) +#define E820_MAP_NR (*(char*) (PARAM+E820NR)) +#define E820_MAP ((unsigned long *) (PARAM+E820MAP)) + +#define GIGABYTE(x) ((x) * 1024LL * 1024LL * 1024LL) +#define MEGABYTE(x) ((x) * 1024LL * 1024LL) +#if FLAG_E820_DEBUG +# define E820DBG(x) printk x +#else +# define E820DBG(x) +#endif + +/* + * Do NOT EVER look at the BIOS memory size location. + * It does not work on many machines. + */ +#define LOWMEMSIZE() (639 * 1024) + + + +static struct excluded_memory memory_hole; + +#define Hole memory_hole.hole + +/* + * clear_memory_regions() wipes out the memory regions map so that it + * can be populated from scratch + */ +static void __init clear_memory_regions() +{ + physical_memory.nr_region = 0; +} + + +/* + * add_memory_region() adds a memory region, merging and reclaiming memory + * as needed. it returns a bitmask of what happened. + */ +enum region_flags __init add_memory_region(__u64 start, __u64 end, __u32 type) +{ + int i, x; + enum region_flags flag = 0; + +#ifdef CONFIG_E820_RECLAIM + if ( type == E820_ACPI ) + flag |= RF_RECLAIM; + else +#endif + if (type != E820_RAM) + return RF_NOT_RAM; + + if (start == end) + return flag|RF_ZERO; + + if (start > end) + return RF_TOOLONG; + +#ifdef CONFIG_E820_MERGE + /* see if we can merge this region with an existing one */ + + for (x=0; x < physical_memory.nr_region; x++) + if (end == Region[x].start) { + /* glue memory region onto the start of this one */ + Region[x].start = start; + break; + } + else if (Region[x].end == start) { + /* glue memory region onto the end of this one */ + Region[x].end = end; + break; + } + if (x < physical_memory.nr_region) { + /* If we've merged a region, check to see if the new region + * want to merge with anyone else. + */ + if (x > 0 && Region[x].start == Region[x-1].end) { + Region[x-1].end = Region[x].end; + for (i=x; i < physical_memory.nr_region; i++) + Region[x] = Region[x+1]; + physical_memory.nr_region--; + x--; + } + if (x < physical_memory.nr_region-1 && Region[x].end == Region[x+1].start) { + Region[x].end = Region[x+1].end; + for (i=x+1; i < physical_memory.nr_region-1; i++) + Region[x] = Region[x+1]; + physical_memory.nr_region--; + } + else + return flag|RF_MERGED; + } +#endif + + if (physical_memory.nr_region == E820MAX) + return flag|RF_OVERFLOW; + + /* insert the new region in order */ + for (x=0; x < physical_memory.nr_region; x++) + if (end < Region[x].start) { + /* add it in here */ + for (i=physical_memory.nr_region; i>x; --i) + Region[i] = Region[i-1]; + Region[x].start = start; + Region[x].end = end; + physical_memory.nr_region++; + return flag|RF_ADDED; + } + Region[physical_memory.nr_region].start = start; + Region[physical_memory.nr_region].end = end; + physical_memory.nr_region++; + return flag|RF_ADDED; +} /* add_memory_region */ + + +void __init print_region_map() +{ + int x; + for (x = 0; x < physical_memory.nr_region; x++) + printk("MEM: %010L-%010L\n", Region[x].start, Region[x].end); +} /* print_region_map */ + + +#if FLAG_E820_DEBUG && defined(CONFIG_MEM_E820) +/* + * report_memory_region() decodes the return value from add_memory_region + */ +static void __init report_memory_region(enum region_flags code) +{ + if (code & RF_RECLAIM) + printk(" reclaimed"); + if (code & RF_ADDED) + printk(" added"); + if (code & RF_MERGED) + printk(" merged"); + if (code & RF_NOT_RAM) + printk(" rom"); + if (code & RF_ZERO) + printk(" zero-length"); + + if (code & RF_OVERFLOW) + printk(" ERROR: table overflow"); + else if (code & RF_TOOLONG) + printk(" ERROR: start+size > 64 bits"); +} +#endif + + +/* + * prune_memory_region() checks a memory region to see if it needs to be + * cut to fit around memory holes. It returns the index on the next + * memory region to process usually x+1, but it will be x if the memory + * region in question is swallowed by a memory hole. + */ +static int __init prune_memory_region(int x) +{ + int i, ct; + + for (ct = 0; ct < memory_hole.nr_hole; ct++) { + + if (Region[x].start >= Hole[ct].start || Region[x].end <= Hole[ct].end) + continue; + + if (Region[x].start >= Hole[ct].start) { + if (Region[x].end < Hole[ct].end) { + E820DBG(("SMAP: %010Lx - %010Lx dropped\n", + Region[x].start, Region[x].end)); + for (i=x; i < physical_memory.nr_region; i++) + Region[i] = Region[i+1]; + physical_memory.nr_region--; + return x; + } + else { + E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010Lx - %010Lx\n", + Region[x].start, Region[x].end, + Hole[ct].start, Region[x].end)); + Region[x].start = Hole[ct].start; + } + } + else if (Region[x].end < Hole[ct].end || physical_memory.nr_region >= E820PHYSMAX) { + if (physical_memory.nr_region >= E820PHYSMAX) + E820DBG(("SMAP: Memory region overflow\n")); + E820DBG(("SMAP: %010Lx - %010Lx trimmed to %010Lx - %010Lx\n", + Region[x].start, Region[x].end, + Region[x].start, Hole[ct].start)); + Region[x].end = Hole[ct].start; + } + else { + E820DBG(("SMAP: %010Lx - %010Lx split to %010Lx - %010Lx, %010Lx - %010Lx\n", + Region[x].start, Region[x].end, + Region[x].start, Hole[ct].start, + Hole[ct].end, Region[x].end)); + for (i=physical_memory.nr_region; i > x; --i) + Region[i+1] = Region[i]; + + Region[x+1].start = Hole[ct].end; + Region[x+1].end = Region[x].end; + Region[x].end = Hole[ct].start; + physical_memory.nr_region++; + } + } + return x+1; +} + + +/* + * validate_regions() validates the physical_memory map, plus lops out memory + * that lives in suspicious places. + */ +int __init validate_regions(void) +{ + unsigned int x; + + for (x=0; x < physical_memory.nr_region; ) { + if (x < physical_memory.nr_region-1 + && Region[x].end >= Region[x+1].start) { + printk("SMAP: region %d (%010Lx - %010Lx) overlaps region %d (%010Lx - %010Lx)\n", + x, Region[x].start, + Region[x].end, + x+1, Region[x+1].start, + Region[x+1].end); + return 1; + } + if ( (x = prune_memory_region(x)) < 0) + return 1; + } + return 0; +} /* validate_regions */ + + +/* + * add_memory_hole() does what you'd think it does. + */ +int __init add_memory_hole(__u64 start, __u64 end) +{ + int idx; + + if ( (idx=memory_hole.nr_hole) < NR_HOLES) { + Hole[idx].start = start; + Hole[idx].end = end; + memory_hole.nr_hole ++ ; + return 0; + } + printk("memory hole overflow adding %010Lx-%010Lx\n", start, end); + return 1; +} /* add_memory_hole */ + + +/* + * setup_detected_memory() build the initial physical_memory.region[] map + * from the information returned by the system bios (either an e820 memory + * map, a 801 low/high memory map, or the old fashioned 88 call) + */ +void __init setup_detected_memory(void) +{ + int i; + enum region_flags ret; + + add_memory_hole(LOWMEMSIZE(), HIGH_MEMORY); +#if FLAG_E820_4GB_ONLY + add_memory_hole(GIGABYTE(4), (__u64)-1); +#endif + clear_memory_regions(); + +#ifdef CONFIG_MEM_E820 + /* + * If we're lucky and live on a modern system, the setup code + * will have given us a memory map that we can use to properly + * set up memory. If we aren't, we'll fake a memory map. + * + * We check to see that the memory map contains at least 2 elements + * before we'll use it, because the detection code in setup.S may + * not be perfect and most every PC known to man has two memory + * regions: one from 0 to ~640k, and one from 1mb up. + */ + if ( (E820_MAP_NR > 1) && (E820_MAP_NR < E820MAX) ) { + /* got a memory map; copy it into a safe place. + */ + physical_memory.nr_bios = E820_MAP_NR; + memcpy(&(Bios), E820_MAP, E820_MAP_NR * sizeof Bios[0]); + for (i=0; i < E820_MAP_NR; i++) { + ret = add_memory_region(Bios[i].addr, + Bios[i].addr + Bios[i].size, + Bios[i].type); +#if FLAG_E820_DEBUG + printk("SMAP: %010Lx - %010Lx ", + Bios[i].addr, + Bios[i].addr + Bios[i].size); + switch (Bios[i].type) { + case E820_RAM: printk("(usable)"); + break; + case E820_RESERVED: + printk("(reserved)"); + break; + case E820_ACPI: + printk("(ACPI data)"); + break; + case E820_NVS: + printk("(ACPI NVS)"); + break; + default: + printk("(type %lu)", + (unsigned long)Bios[i].type); + break; + } + report_memory_region(ret); + printk("\n"); +#endif + if (ret & (RF_TOOLONG|RF_OVERFLOW)) + goto oldstyle; + } + /* after putting in the e820 map, massage it into shape + * for use by the kernel. If validate_regions returns + * anything except 0, something is very ill in the state + * of the bios map and we'll discard it with extreme + * prejudice. + */ + if (validate_regions() == 0) + return /* the map is fine, so we'll use it */; + } +#endif + + oldstyle: + clear_memory_regions(); + +#ifdef CONFIG_MEM_E801 + if (E801_MEM_LOW > 0) { + add_memory_region(0, (E801_MEM_LOW<<10)+HIGH_MEMORY, E820_RAM); + add_memory_region(MEGABYTE(16), MEGABYTE(16)+(E801_MEM_HIGH<<16), E820_RAM); + } + else +#endif + add_memory_region(0, HIGH_MEMORY+(EXT_MEM_K << 10), E820_RAM); + + validate_regions(); +} /* setup_detected_memory */ diff -Naur linux-2.4.0orig/arch/i386/kernel/setup.c linux-2.4.0exp/arch/i386/kernel/setup.c --- linux-2.4.0orig/arch/i386/kernel/setup.c Wed May 31 12:01:46 2000 +++ linux-2.4.0exp/arch/i386/kernel/setup.c Wed May 31 12:18:51 2000 @@ -120,7 +120,7 @@ unsigned char table[0]; }; -struct e820map e820 = { 0 }; +struct physical_memory physical_memory; unsigned char aux_device_present; @@ -139,10 +139,7 @@ */ #define PARAM ((unsigned char *)empty_zero_page) #define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) -#define EXT_MEM_K (*(unsigned short *) (PARAM+2)) -#define ALT_MEM_K (*(unsigned long *) (PARAM+0x1e0)) -#define E820_MAP_NR (*(char*) (PARAM+E820NR)) -#define E820_MAP ((unsigned long *) (PARAM+E820MAP)) + #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+0x40)) #define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) #define SYS_DESC_TABLE (*(struct sys_desc_table_struct*)(PARAM+0xa0)) @@ -380,9 +377,9 @@ } } -unsigned long __init memparse(char *ptr, char **retptr) +unsigned long long __init memparse(char *ptr, char **retptr) { - unsigned long ret; + unsigned long long ret; ret = simple_strtoul(ptr, retptr, 0); @@ -394,98 +391,21 @@ ret <<= 20; (*retptr)++; } + else if (**retptr == 'G' || **retptr == 'g') { + ret <<= 30; + (*retptr)++; + } return ret; } /* memparse */ -void __init add_memory_region(unsigned long start, - unsigned long size, int type) -{ - int x = e820.nr_map; - - if (x == E820MAX) { - printk("Ooops! Too many entries in the memory map!\n"); - return; - } - - e820.map[x].addr = start; - e820.map[x].size = size; - e820.map[x].type = type; - e820.nr_map++; -} /* add_memory_region */ - -#define E820_DEBUG 1 - -static void __init print_e820_map(void) -{ - int i; - - for (i = 0; i < e820.nr_map; i++) { - printk(" e820: %016Lx @ %016Lx ", - e820.map[i].size, e820.map[i].addr); - switch (e820.map[i].type) { - case E820_RAM: printk("(usable)\n"); - break; - case E820_RESERVED: - printk("(reserved)\n"); - break; - case E820_ACPI: - printk("(ACPI data)\n"); - break; - case E820_NVS: - printk("(ACPI NVS)\n"); - break; - default: printk("type %lu\n", e820.map[i].type); - break; - } - } -} - -/* - * Do NOT EVER look at the BIOS memory size location. - * It does not work on many machines. +/* setup_cmdline_memory() parses the command line looking for mem= arguments, + * and builds a memory region map out of any that it + * finds. + * it returns 1 if mem= is valid, + * 0 if mem= is bogus or there is no mem= to be found. */ -#define LOWMEMSIZE() (0x9f000) - -void __init setup_memory_region(void) -{ - /* - * If we're lucky and live on a modern system, the setup code - * will have given us a memory map that we can use to properly - * set up memory. If we aren't, we'll fake a memory map. - * - * We check to see that the memory map contains at least 2 elements - * before we'll use it, because the detection code in setup.S may - * not be perfect and most every PC known to man has two memory - * regions: one from 0 to 640k, and one from 1mb up. (The IBM - * thinkpad 560x, for example, does not cooperate with the memory - * detection code.) - */ - if (E820_MAP_NR > 1) { - /* got a memory map; copy it into a safe place. - */ - e820.nr_map = E820_MAP_NR; - if (e820.nr_map > E820MAX) - e820.nr_map = E820MAX; - memcpy(e820.map, E820_MAP, e820.nr_map * sizeof e820.map[0]); - } - else { - /* otherwise fake a memory map; one section from 0k->640k, - * the next section from 1mb->appropriate_mem_k - */ - unsigned long mem_size; - - mem_size = (ALT_MEM_K < EXT_MEM_K) ? EXT_MEM_K : ALT_MEM_K; - - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - add_memory_region(HIGH_MEMORY, mem_size << 10, E820_RAM); - } - printk("BIOS-provided physical RAM map:\n"); - print_e820_map(); -} /* setup_memory_region */ - - -static inline void parse_mem_cmdline (char ** cmdline_p) +static inline int setup_cmdline_memory (char ** cmdline_p) { char c = ' ', *to = command_line, *from = COMMAND_LINE; int len = 0; @@ -509,10 +429,6 @@ if (!memcmp(from+4, "nopentium", 9)) { from += 9+4; boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE; - } else if (!memcmp(from+4, "exactmap", 8)) { - from += 8+4; - e820.nr_map = 0; - usermem = 1; } else { /* If the user specifies memory size, we * blow away any automatically generated @@ -520,23 +436,16 @@ */ unsigned long start_at, mem_size; - if (usermem == 0) { - /* first time in: zap the whitelist - * and reinitialize it with the - * standard low-memory region. - */ - e820.nr_map = 0; - usermem = 1; - add_memory_region(0, LOWMEMSIZE(), E820_RAM); - } + usermem = 1; mem_size = memparse(from+4, &from); if (*from == '@') start_at = memparse(from+1, &from); - else { - start_at = HIGH_MEMORY; - mem_size -= HIGH_MEMORY; - usermem=0; + else if (*from == '-') { + start_at = mem_size; + mem_size += memparse(from+1, &from); } + else + start_at = 0; add_memory_region(start_at, mem_size, E820_RAM); } } @@ -550,9 +459,13 @@ *to = '\0'; *cmdline_p = command_line; if (usermem) { - printk("user-defined physical RAM map:\n"); - print_e820_map(); + if (validate_regions()) { + printk("user-defined physical RAM map:\n"); + print_region_map(); + return 1; + } } + return 0; } void __init setup_arch(char **cmdline_p) @@ -582,7 +495,8 @@ rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0); rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0); #endif - setup_memory_region(); + if (!setup_cmdline_memory(cmdline_p)) + setup_detected_memory(); if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; @@ -596,12 +510,6 @@ data_resource.start = virt_to_bus(&_etext); data_resource.end = virt_to_bus(&_edata)-1; - parse_mem_cmdline(cmdline_p); - -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((x) << PAGE_SHIFT) - /* * 128MB for vmalloc and initrd */ @@ -617,21 +525,16 @@ start_pfn = PFN_UP(__pa(&_end)); /* - * Find the highest page frame number we have available - */ - max_pfn = 0; - for (i = 0; i < e820.nr_map; i++) { - unsigned long start, end; - /* RAM? */ - if (e820.map[i].type != E820_RAM) - continue; - start = PFN_UP(e820.map[i].addr); - end = PFN_DOWN(e820.map[i].addr + e820.map[i].size); - if (start >= end) - continue; - if (end > max_pfn) - max_pfn = end; - } + * Find the highest page frame number we have available + */ + max_pfn = 0; + for (i = 0; i < physical_memory.nr_region; i++) { + unsigned long start, end; + start = PFN_UP(Region[i].start); + end = PFN_DOWN(Region[i].end); + if ( (start < end) && (end > max_pfn) ) + max_pfn = end; + } /* * Determine low and high memory ranges: @@ -674,23 +577,19 @@ /* * Register fully available low RAM pages with the bootmem allocator. */ - for (i = 0; i < e820.nr_map; i++) { + for (i = 0; i < physical_memory.nr_region; i++) { unsigned long curr_pfn, last_pfn, size; - /* - * Reserve usable low memory - */ - if (e820.map[i].type != E820_RAM) - continue; + /* * We are rounding up the start address of usable memory: */ - curr_pfn = PFN_UP(e820.map[i].addr); + curr_pfn = PFN_UP(Region[i].start); if (curr_pfn >= max_low_pfn) continue; /* * ... and at the end of the usable range downwards: */ - last_pfn = PFN_DOWN(e820.map[i].addr + e820.map[i].size); + last_pfn = PFN_DOWN(Region[i].end); if (last_pfn > max_low_pfn) last_pfn = max_low_pfn; @@ -771,30 +670,37 @@ * and also for regions reported as reserved by the e820. */ probe_roms(); - for (i = 0; i < e820.nr_map; i++) { + for (i = 0; i < physical_memory.nr_region; i++) { + struct resource *res; + res = alloc_bootmem_low(sizeof(struct resource)); + res->start = Region[i].start; + res->end = Region[i].end-1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + res->name = "System RAM"; + request_resource(&iomem_resource, res); + /* + * We dont't know which RAM region contains the + * kernel data, so we try it repeatedly and let + * the resource manager test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } + for (i = 0; i < physical_memory.nr_bios; i++) { struct resource *res; - if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL) + if (Bios[i].type == E820_RAM) continue; + res = alloc_bootmem_low(sizeof(struct resource)); - switch (e820.map[i].type) { - case E820_RAM: res->name = "System RAM"; break; + switch (Bios[i].type) { case E820_ACPI: res->name = "ACPI Tables"; break; case E820_NVS: res->name = "ACPI Non-volatile Storage"; break; default: res->name = "reserved"; } - res->start = e820.map[i].addr; - res->end = res->start + e820.map[i].size - 1; + res->start = Bios[i].addr; + res->end = Bios[i].addr + Bios[i].size - 1; res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; request_resource(&iomem_resource, res); - if (e820.map[i].type == E820_RAM) { - /* - * We dont't know which RAM region contains kernel data, - * so we try it repeatedly and let the resource manager - * test it. - */ - request_resource(res, &code_resource); - request_resource(res, &data_resource); - } } request_resource(&iomem_resource, &vram_resource); diff -Naur linux-2.4.0orig/arch/i386/mm/init.c linux-2.4.0exp/arch/i386/mm/init.c --- linux-2.4.0orig/arch/i386/mm/init.c Wed May 31 12:01:19 2000 +++ linux-2.4.0exp/arch/i386/mm/init.c Sat May 27 01:59:31 2000 @@ -538,21 +538,11 @@ { int i; - for (i = 0; i < e820.nr_map; i++) { - unsigned long addr, end; - - if (e820.map[i].type != E820_RAM) /* not usable memory */ - continue; - /* - * !!!FIXME!!! Some BIOSen report areas as RAM that - * are not. Notably the 640->1Mb area. We need a sanity - * check here. - */ - addr = (e820.map[i].addr+PAGE_SIZE-1) >> PAGE_SHIFT; - end = (e820.map[i].addr+e820.map[i].size) >> PAGE_SHIFT; - if ((pagenr >= addr) && (pagenr < end)) + for (i = 0; i < physical_memory.nr_region; i++) + if (pagenr >= PFN_UP(physical_memory.region[i].start) + && pagenr < PFN_DOWN(physical_memory.region[i].end) ) return 1; - } + return 0; } diff -Naur linux-2.4.0orig/drivers/char/Config.in linux-2.4.0exp/drivers/char/Config.in --- linux-2.4.0orig/drivers/char/Config.in Sat May 27 01:58:50 2000 +++ linux-2.4.0exp/drivers/char/Config.in Wed May 31 11:45:26 2000 @@ -220,7 +220,7 @@ fi dep_tristate ' CPiA Video For Linux' CONFIG_VIDEO_CPIA $CONFIG_VIDEO_DEV if [ "$CONFIG_VIDEO_CPIA" != "n" ]; then - if [ "CONFIG_PARPORT_1284" != "n" ]; then + if [ "$CONFIG_PARPORT_1284" != "n" ]; then dep_tristate ' CPiA Parallel Port Lowlevel Support' CONFIG_VIDEO_CPIA_PP $CONFIG_VIDEO_CPIA $CONFIG_PARPORT fi if [ "$CONFIG_USB" != "n" ]; then diff -Naur linux-2.4.0orig/drivers/ide/Config.in linux-2.4.0exp/drivers/ide/Config.in --- linux-2.4.0orig/drivers/ide/Config.in Wed May 31 12:01:47 2000 +++ linux-2.4.0exp/drivers/ide/Config.in Wed May 31 11:42:40 2000 @@ -140,9 +140,9 @@ fi if [ "$CONFIG_BLK_DEV_TIVO" = "y" ]; then - define CONFIG_DMA_NONPCI y + define_bool CONFIG_DMA_NONPCI y else - define CONFIG_DMA_NONPCI n + define_bool CONFIG_DMA_NONPCI n fi if [ "$CONFIG_IDE_CHIPSETS" = "y" -o \ "$CONFIG_BLK_DEV_AEC62XX" = "y" -o \ diff -Naur linux-2.4.0orig/include/asm-i386/e820.h linux-2.4.0exp/include/asm-i386/e820.h --- linux-2.4.0orig/include/asm-i386/e820.h Wed May 31 12:01:19 2000 +++ linux-2.4.0exp/include/asm-i386/e820.h Wed May 31 11:41:06 2000 @@ -5,16 +5,19 @@ * In a nutshell, arch/i386/boot/setup.S populates a scratch table * in the empty_zero_block that contains a list of usable address/size * duples. In arch/i386/kernel/setup.c, this information is - * transferred into the e820map, and in arch/i386/mm/init.c, that - * new information is used to mark pages reserved or not. + * transferred into the bios[], then converted into a list of valid + * memory regions in region[], and that new information is used in + * arch/i386/mm/init.c to mark pages available or not. * */ #ifndef __E820_HEADER #define __E820_HEADER -#define E820MAP 0x2d0 /* our map */ -#define E820MAX 32 /* number of entries in E820MAP */ -#define E820NR 0x1e8 /* # entries in E820MAP */ +#define E820MAP 0x2d0 /* our map */ +#define E820MAX 32 /* number of entries in E820MAP */ +#define E820PHYSMAX 64 /* number of entries in physical_memory.region */ +#define E820NR 0x1e8 /* # entries in E820MAP */ +#define E820LEN 20 /* size of an e820 entry */ #define E820_RAM 1 #define E820_RESERVED 2 @@ -23,18 +26,90 @@ #define HIGH_MEMORY (1024*1024) +/* HACK: These macros map between page numbers and physical addresses. + * They used to be in arch/i386/kernel/setup.c, but have been moved here + * so that they can also be used in arch/i386/mm/init.c. + */ +#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + +/* + * FLAG_E820_DEBUG enables bunches of debug messages. + */ +#define FLAG_E820_DEBUG 1 + +/* FLAG_E820_RECLAIM tells add_memory_region/check_memory_region to + * attempt to use E820 reclaim memory sections. To have reclaim work, + * you need to configure it on, _plus_ CONFIG_ACPI needs to be turned off. + */ +#if defined(CONFIG_E820_RECLAIM) && !defined(CONFIG_ACPI) +# define FLAG_E820_RECLAIM 1 +#else +# define FLAG_E820_RECLAIM 0 +#endif + +/* FLAG_E820_4GB_ONLY tells the memory region adder to truncate memory + * segments to the first 4 gb of memory. + */ +#define FLAG_E820_4GB_ONLY 1 + + #ifndef __ASSEMBLY__ -struct e820map { - int nr_map; - struct { - long long addr; /* start of memory segment */ - long long size; /* size of memory segment */ - long type; /* type of memory segment */ - } map[E820MAX]; -}; +struct e820 { + __u64 addr; /* addr,size,type are returned by e820 bios call */ + __u64 size; + __u32 type; +} __attribute__ ((__packed__)); + +struct physical_region { + __u64 start; + __u64 end; +} ; + +struct physical_memory { + int nr_bios; /* bios[] holds memory region */ + int nr_region; /* region[] holds valid mem */ + struct e820 bios[E820MAX]; /* returned by the bios */ + struct physical_region region[E820PHYSMAX]; /* that we want to allocate */ +} ; + +#define NR_HOLES 10 + +struct excluded_memory { + int nr_hole; + struct __hole { + __u64 start; + __u64 end; + __u32 mask; + } hole[NR_HOLES]; +} ; -extern struct e820map e820; -#endif/*!__ASSEMBLY__*/ +extern struct physical_memory physical_memory; + +/* Typing shortcuts. + */ +#define Region physical_memory.region +#define Bios physical_memory.bios +/* + * setup functions + */ +enum region_flags { RF_RECLAIM =0x01, + RF_NOT_RAM =0x02, + RF_OVERFLOW=0x04, + RF_ZERO =0x08, + RF_MERGED =0x10, + RF_ADDED =0x20, + RF_TOOLONG =0x80 } ; + +enum region_flags add_memory_region(__u64, __u64, __u32); +int add_memory_hole(__u64, __u64); +int validate_regions(void); +void print_region_map(void); +void setup_detected_memory(void); + + +#endif/*!__ASSEMBLY__*/ #endif/*__E820_HEADER*/ diff -Naur linux-2.4.0orig/scripts/Menuconfig linux-2.4.0exp/scripts/Menuconfig --- linux-2.4.0orig/scripts/Menuconfig Wed May 31 12:01:20 2000 +++ linux-2.4.0exp/scripts/Menuconfig Sat May 27 01:59:31 2000 @@ -545,7 +545,7 @@ # Semantics of + and ? in GNU expr changed, so # we avoid them: - if expr "$answer" : '0$\|-[1-9][0-9]*$\|[1-9][0-9]*$' >/dev/null + if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null then eval $2="$answer" else