lkml.org 
[lkml]   [1999]   [Aug]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    SubjectRe: [PATCH] 2.3.15 fancy memory detection patch, reworked
    Date
    In article <linux.kernel.7q13ak$c4k@pell.pell.portland.or.us>,
    david parsons <o.r.c@p.e.l.l.p.o.r.t.l.a.n.d.o.r.u.s> wrote:
    >This is the latest and greatest of my fancy memory detection patch,
    >reworked after review by Linux (``I hate this patch'' :-) It uses
    >the whitelist as the only method of setting up memory, and tweaks
    >the old style detection methods, plus mem=, into fake whitelists
    >instead of the old method.


    Whoops. This patch was against 2.3.15pre3, which differs from
    2.3.15 in one small detail (an odd addition to a comment in
    the middle of the memory setup code in mm/init.c). Here's a
    slightly newer one that works on two machine I have at my
    disposal (a laptop I use at work, and the workstation I have
    at home); If you'd like less of a thrill, try it out:


    ____
    david parsons \bi/ Kernel panics can be very thrilling, doncha know.
    \/


    --- linux-2.3.15-orig/arch/i386/boot/setup.S Thu Aug 19 10:54:13 1999
    +++ linux-2.3.15/arch/i386/boot/setup.S Thu Aug 26 12:50:59 1999
    @@ -37,6 +37,7 @@
    #include <linux/version.h>
    #include <linux/compile.h>
    #include <asm/boot.h>
    +#include <asm/e820.h>

    ! Signature words to ensure LILO loaded us right
    #define SIG1 0xAA55
    @@ -59,7 +60,7 @@

    entry start
    start:
    - jmp start_of_setup
    + jmp trampoline
    ! ------------------------ start of header --------------------------------
    !
    ! SETUP-header, must start at CS:2 (old 0x9020:2)
    @@ -119,6 +120,8 @@
    heap_end_ptr: .word modelist+1024 ! space from here (exclusive) down to
    ! end of setup code can be used by setup
    ! for local heap purposes.
    +trampoline: call start_of_setup
    + .space 1024
    ! ------------------------ end of header ----------------------------------

    start_of_setup:
    @@ -245,37 +248,91 @@
    loader_ok:
    ! Get memory size (extended mem, kB)

    + xor eax, eax
    + mov dword ptr [0x1e0], eax
    #ifndef STANDARD_MEMORY_BIOS_CALL
    - push ebx

    - xor ebx,ebx ! preload new memory slot with 0k
    - mov [0x1e0], ebx
    + mov byte ptr [E820NR], al

    - mov ax,#0xe801
    - int 0x15
    - jc oldstylemem
    +! 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].
    +!
    +
    +meme820:
    + mov edx, #0x534d4150 ! ascii `SMAP'
    + xor ebx, ebx ! continuation counter
    +
    + mov di, #E820MAP ! point into the whitelist
    + ! so we can have the bios
    + ! directly write into it.
    +
    +jmpe820:
    + mov eax, #0x0000e820 ! e820, upper word zeroed
    + mov ecx, #20 ! size of the e820rec
    +
    + push ds ! data record.
    + pop es
    + int 0x15 ! make the call
    + jc bail820 ! fall to e801 if it fails
    +
    + cmp eax, #0x534d4150 ! check the return is `SMAP'
    + jne bail820 ! fall to e801 if it fails

    -! Memory size is in 1 k chunksizes, to avoid confusing loadlin.
    -! We store the 0xe801 memory size in a completely different place,
    +! cmp dword ptr [16+di], #1 ! is this usable memory?
    +! jne again820
    +
    + ! If this is usable memory, we save it by simply advancing di by
    + ! sizeof(e820rec).
    + !
    +good820:
    + mov al, byte ptr [E820NR] ! up to 32 good entries, that is
    + cmp al, #E820MAX
    + jnl bail820
    + inc byte ptr [E820NR]
    + mov ax, di
    + add ax, #20
    + mov di, ax
    +
    +again820:
    + cmp ebx, #0 ! check to see if ebx is
    + jne jmpe820 ! 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.)

    - and ebx, #0xffff ! clear sign extend
    - shl ebx, 6 ! and go from 64k to 1k chunks
    - mov [0x1e0],ebx ! store extended memory size
    -
    - and eax, #0xffff ! clear sign extend
    - add [0x1e0],eax ! and add lower memory into total size.
    -
    - ! and fall into the old memory detection code to populate the
    - ! compatibility slot.
    +meme801:
    +
    + mov ax,#0xe801
    + int 0x15
    + jc mem88
    +
    + and edx, #0xffff ! clear sign extend
    + shl edx, 6 ! and go from 64k to 1k chunks
    + mov [0x1e0],edx ! store extended memory size
    +
    + and ecx, #0xffff ! clear sign extend
    + add [0x1e0],ecx ! and add lower memory into total size.
    +
    +! Ye Olde Traditional Methode. Returns the memory size (up to 16mb or
    +! 64mb, depending on the bios) in ax.
    +mem88:

    -oldstylemem:
    - pop ebx
    -#else
    - mov dword ptr [0x1e0], #0
    #endif
    mov ah,#0x88
    int 0x15
    --- linux-2.3.15-orig/arch/i386/kernel/setup.c Wed Aug 25 15:49:00 1999
    +++ linux-2.3.15/arch/i386/kernel/setup.c Fri Aug 27 10:43:21 1999
    @@ -17,6 +17,9 @@
    *
    * IDT Winchip tweaks, misc clean ups.
    * Dave Jones <dave@powertweak.com>, August 1999
    + *
    + * Memory region support
    + * David Parsons <orc@pell.chi.il.us>, July-August 1999
    */

    /*
    @@ -51,6 +54,7 @@
    #include <asm/cobalt.h>
    #include <asm/msr.h>
    #include <asm/desc.h>
    +#include <asm/e820.h>

    /*
    * Machine setup..
    @@ -84,6 +88,8 @@
    unsigned char table[0];
    };

    +struct e820map e820 = { 0 };
    +
    unsigned char aux_device_present;

    #ifdef CONFIG_BLK_DEV_RAM
    @@ -103,6 +109,8 @@
    #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))
    @@ -345,12 +353,80 @@
    }
    }

    +__initfunc(unsigned long memparse(char *ptr, char **retptr))
    +{
    + unsigned long ret;
    +
    + ret = simple_strtoul(ptr, retptr, 0);
    +
    + if (**retptr == 'K' || **retptr == 'k') {
    + ret <<= 10;
    + (*retptr)++;
    + }
    + else if (**retptr == 'M' || **retptr == 'm') {
    + ret <<= 20;
    + (*retptr)++;
    + }
    + return ret;
    +} /* memparse */
    +
    +
    +__initfunc(void 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 LOWMEMSIZE() ((*(unsigned short *)__va(0x413)) * 1024)
    +
    +
    +__initfunc(void 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.
    + */
    + if (E820_MAP_NR) {
    + /* 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(), 1);
    + add_memory_region(HIGH_MEMORY, mem_size << 10, 1);
    + }
    +} /* setup_memory_region */
    +
    +
    void __init setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p)
    {
    unsigned long memory_start, memory_end;
    char c = ' ', *to = command_line, *from = COMMAND_LINE;
    int len = 0;
    int i;
    + int usermem=0;

    #ifdef CONFIG_VISWS
    visws_get_board_type_and_rev();
    @@ -367,24 +443,14 @@
    BIOS_revision = SYS_DESC_TABLE.table[2];
    }
    aux_device_present = AUX_DEVICE_INFO;
    - memory_end = (1<<20) + (EXT_MEM_K<<10);
    -#ifndef STANDARD_MEMORY_BIOS_CALL
    - {
    - unsigned long memory_alt_end = (1<<20) + (ALT_MEM_K<<10);
    - /* printk(KERN_DEBUG "Memory sizing: %08x %08x\n", memory_end, memory_alt_end); */
    - if (memory_alt_end > memory_end)
    - memory_end = memory_alt_end;
    - }
    -#endif
    -
    - ram_resources[1].end = memory_end-1;

    - memory_end &= PAGE_MASK;
    #ifdef CONFIG_BLK_DEV_RAM
    rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
    rd_prompt = ((RAMDISK_FLAGS & RAMDISK_PROMPT_FLAG) != 0);
    rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
    #endif
    + setup_memory_region();
    +
    if (!MOUNT_ROOT_RDONLY)
    root_mountflags &= ~MS_RDONLY;
    memory_start = (unsigned long) &_end;
    @@ -405,8 +471,10 @@
    for (;;) {
    /*
    * "mem=nopentium" disables the 4MB page tables.
    - * "mem=XXX[kKmM]" overrides the BIOS-reported
    - * memory size
    + * "mem=XXX[kKmM]" defines a memory region from HIGH_MEM
    + * to <mem>, overriding the bios size.
    + * "mem=XXX[KkmM]@XXX[KkmM]" defines a memory region from
    + * <start> to <start>+<mem>, overriding the bios size.
    */
    if (c == ' ' && *(const unsigned long *)from == *(const unsigned long *)"mem=") {
    if (to != command_line) to--;
    @@ -414,16 +482,29 @@
    from += 9+4;
    boot_cpu_data.x86_capability &= ~X86_FEATURE_PSE;
    } else {
    - memory_end = simple_strtoul(from+4, &from, 0);
    - if ( *from == 'K' || *from == 'k' ) {
    - memory_end = memory_end << 10;
    - from++;
    - } else if ( *from == 'M' || *from == 'm' ) {
    - memory_end = memory_end << 20;
    - from++;
    + /* If the user specifies memory size, we
    + * blow away any automatically generated
    + * size
    + */
    + 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(), 1);
    }
    - if (memory_end > ram_resources[1].end)
    - ram_resources[1].end = memory_end-1;
    + mem_size = memparse(from+4, &from);
    + if (*from == '@')
    + start_at = memparse(from+1,&from);
    + else {
    + start_at = HIGH_MEMORY;
    + mem_size -= HIGH_MEMORY;
    + }
    + add_memory_region(start_at, mem_size, 1);
    }
    }
    c = *(from++);
    @@ -436,23 +517,33 @@
    *to = '\0';
    *cmdline_p = command_line;

    - /* Request the standard RAM and ROM resources - they eat up PCI memory space */
    - request_resource(&iomem_resource, ram_resources+0);
    - request_resource(&iomem_resource, ram_resources+1);
    - request_resource(&iomem_resource, ram_resources+2);
    - request_resource(ram_resources+1, &code_resource);
    - request_resource(ram_resources+1, &data_resource);
    - probe_roms();

    #define VMALLOC_RESERVE (128 << 20) /* 128MB for vmalloc and initrd */
    #define MAXMEM ((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))

    + for (memory_end=i=0; i < e820.nr_map; i++)
    + if ((e820.map[i].type == 1) && ((unsigned long)(e820.map[i].addr + e820.map[i].size) > memory_end))
    + memory_end = (unsigned long)(e820.map[i].addr + e820.map[i].size);
    +
    if (memory_end > MAXMEM)
    {
    memory_end = MAXMEM;
    printk(KERN_WARNING "Warning only %ldMB will be used.\n",
    MAXMEM>>20);
    }
    + memory_end &= PAGE_MASK;
    +
    + ram_resources[1].end = memory_end-1;
    +
    + /* Request the standard RAM and ROM resources -
    + * they eat up PCI memory space
    + */
    + request_resource(&iomem_resource, ram_resources+0);
    + request_resource(&iomem_resource, ram_resources+1);
    + request_resource(&iomem_resource, ram_resources+2);
    + request_resource(ram_resources+1, &code_resource);
    + request_resource(ram_resources+1, &data_resource);
    + probe_roms();

    memory_end += PAGE_OFFSET;
    *memory_start_p = memory_start;
    --- linux-2.3.15-orig/arch/i386/mm/init.c Wed Aug 25 14:54:07 1999
    +++ linux-2.3.15/arch/i386/mm/init.c Fri Aug 27 10:42:48 1999
    @@ -27,6 +27,7 @@
    #include <asm/pgtable.h>
    #include <asm/dma.h>
    #include <asm/fixmap.h>
    +#include <asm/e820.h>

    static unsigned long totalram = 0;

    @@ -361,7 +362,8 @@
    int datapages = 0;
    int initpages = 0;
    unsigned long tmp;
    - unsigned long endbase;
    + unsigned long addr;
    + int i, avail;

    end_mem &= PAGE_MASK;
    high_memory = (void *) end_mem;
    @@ -385,23 +387,43 @@
    #endif
    start_mem = PAGE_ALIGN(start_mem);

    - /*
    - * IBM messed up *AGAIN* in their thinkpad: 0xA0000 -> 0x9F000.
    - * They seem to have done something stupid with the floppy
    - * controller as well..
    - * The amount of available base memory is in WORD 40:13. Except
    - * when it isn't.
    + /* walk the whitelist, unreserving good memory
    */
    - endbase = PAGE_OFFSET + 0x9f000;
    - while (start_low_mem < endbase) {
    - clear_bit(PG_reserved, &mem_map[MAP_NR(start_low_mem)].flags);
    - start_low_mem += PAGE_SIZE;
    - }
    + for (avail = i = 0; i < e820.nr_map; i++) {
    + if (e820.map[i].type != 1) /* not usable memory */
    + continue;
    + printk("memory region: %luk @ %08lx\n",
    + ((long)(e820.map[i].size)) / 1024,
    + (long)(e820.map[i].addr) );
    + for (addr=PAGE_ALIGN(((long)(e820.map[i].addr)))+PAGE_OFFSET,
    + tmp = 0;
    + tmp < (unsigned long)(e820.map[i].size);
    + tmp += PAGE_SIZE,
    + addr += PAGE_SIZE) {
    +
    + /* this little bit of grossness is for dealing
    + * with memory borrowing for system bookkeeping
    + * (smp stacks, zero page, kernel code, etc)
    + * without having to go back and edit the e820
    + * map to compensate.
    + *
    + * if we're in low memory (<1024k), we need to
    + * avoid the smp stack and zero page.
    + * if we're in high memory, we need to avoid
    + * the kernel code.
    + * in any case, we don't want to hack mem_map
    + * entries above end_mem.
    + */
    + if ( (addr < start_low_mem)
    + || (addr >= HIGH_MEMORY && addr <= start_mem)
    + || (addr > end_mem) )
    + continue;

    - while (start_mem < end_mem) {
    - clear_bit(PG_reserved, &mem_map[MAP_NR(start_mem)].flags);
    - start_mem += PAGE_SIZE;
    + avail++;
    + clear_bit(PG_reserved, &mem_map[MAP_NR(addr)].flags);
    + }
    }
    +
    for (tmp = PAGE_OFFSET ; tmp < end_mem ; tmp += PAGE_SIZE) {
    if (tmp >= MAX_DMA_ADDRESS)
    clear_bit(PG_DMA, &mem_map[MAP_NR(tmp)].flags);
    @@ -424,8 +446,7 @@
    set_page_count(mem_map+MAP_NR(tmp), 1);
    totalram += PAGE_SIZE;
    #ifdef CONFIG_BLK_DEV_INITRD
    - if (!initrd_start || (tmp < initrd_start || tmp >=
    - initrd_end))
    + if (!initrd_start || (tmp < initrd_start || tmp >= initrd_end))
    #endif
    free_page(tmp);
    }
    @@ -439,6 +460,7 @@

    if (boot_cpu_data.wp_works_ok < 0)
    test_wp_bit();
    +
    }

    void free_initmem(void)
    diff -Naur linux-2.3.15-orig/Documentation/i386/zero-page.txt linux-2.3.15/Documentation/i386/zero-page.txt
    --- linux-2.3.15-orig/Documentation/i386/zero-page.txt Mon Oct 5 12:59:25 1998
    +++ linux-2.3.15/Documentation/i386/zero-page.txt Thu Aug 26 13:04:10 1999
    @@ -30,6 +30,7 @@
    0xb0 - 0x1df Free. Add more parameters here if you really need them.

    0x1e0 unsigned long ALT_MEM_K, alternative mem check, in Kb
    +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)
    0x1f4 unsigned short size of compressed kernel-part in the
    @@ -64,7 +65,7 @@
    0x21c unsigned long INITRD_SIZE, size in bytes of ramdisk image
    0x220 4 bytes (setup.S)
    0x224 unsigned short setup.S heap end pointer
    -0x226 - 0x7ff setup.S code.
    +0x2d0 - 0x600 E820MAP

    0x800 string, 2K max COMMAND_LINE, the kernel commandline as
    copied using CL_OFFSET.
    diff -Naur linux-2.3.15-orig/include/asm-i386/e820.h linux-2.3.15/include/asm-i386/e820.h
    --- linux-2.3.15-orig/include/asm-i386/e820.h Wed Dec 31 16:00:00 1969
    +++ linux-2.3.15/include/asm-i386/e820.h Thu Aug 26 12:51:01 1999
    @@ -0,0 +1,35 @@
    +/*
    + * structures and definitions for the int 15, ax=e820 memory map
    + * scheme.
    + *
    + * 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.
    + *
    + */
    +#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 HIGH_MEMORY (1024*1024)
    +
    +#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];
    +};
    +
    +extern struct e820map e820;
    +#endif/*!__ASSEMBLY__*/
    +
    +#endif/*__E820_HEADER*/
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.rutgers.edu
    Please read the FAQ at http://www.tux.org/lkml/

    \
     
     \ /
      Last update: 2005-03-22 13:53    [W:0.051 / U:155.236 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site