Linux 版 (精华区)

发信人: netiscpu (说不如做), 信区: Linux
标  题: Linux大内存支持之彻底方案
发信站: 紫 丁 香 (Sun Jul 19 19:17:03 1998), 转信


发信人: BlueOcean (Blue), 信区: Linux
标  题: Linux大内存支持之彻底方案
发信站: BBS 水木清华站 (Sun Jul 19 18:41:21 1998)

Linux大内存支持之彻底方案

Linux gets memory configuration from BIOS. Due to lousy design, standard
BIOS can only report 64MB memory at most. Well, Linux can only
automatically found 64MB. When there is more memory, you have to add
"mem=xxx[MmKk]", then kernel knows that there is more memory available. It
is not convenient for flexible configuration, system may crash during boot.
To make kernel automatically probe memory size need adding into kernel. I
hacked the booting code and added such support. Patches for RedHat5.0 &
RedHat5.1 (kernel 2.0.32 & kernel 2.0.34) and installation are here:

installation steps:
1. patching
        cd /usr/src/linux/arch/i386/kernel
        patch < mem-2.0.xx.patch
2. re-compile your kernel
3. edit lilo, remove "mem=xxx[MmKk]"
3. run lilo and reboot your box

patches:
-------------------8<-----mem-2.0.32.patch-----------8<-------------------
diff -c -r -N setup.c.orig setup.c
*** setup.c.orig        Sat Jul 18 21:54:40 1998
--- setup.c     Sun Jul 19 16:34:02 1998
***************
*** 32,37 ****
--- 32,38 ----
  #include <asm/segment.h>
  #include <asm/system.h>
  #include <asm/smp.h>
+ #include <asm/pgtable.h>
  
  /*
   * Tell us the machine setup..
***************
*** 76,87 ****
  extern int root_mountflags;
  extern int _etext, _edata, _end;
  
  extern char empty_zero_page[PAGE_SIZE];
  
  /*
   * This is set up by the setup-routine at boot-time
   */
! #define PARAM empty_zero_page
  #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
  #ifdef CONFIG_APM
  #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
--- 77,90 ----
  extern int root_mountflags;
  extern int _etext, _edata, _end;
  
+ #if 0
  extern char empty_zero_page[PAGE_SIZE];
+ #endif
  
  /*
   * This is set up by the setup-routine at boot-time
   */
! #define PARAM ((char *)empty_zero_page)
  #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
  #ifdef CONFIG_APM
  #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
***************
*** 109,117 ****
  void 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;
        static unsigned char smptrap=0;
  
        if(smptrap==1)
--- 112,120 ----
  void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
  {
!       unsigned long memory_start, memory_end, cfg;
        char c = ' ', *to = command_line, *from = COMMAND_LINE;
!       int len = 0, page_ok;
        static unsigned char smptrap=0;
  
        if(smptrap==1)
***************
*** 128,133 ****
--- 131,182 ----
  #endif
        aux_device_present = AUX_DEVICE_INFO;
        memory_end = (1<<20) + (EXT_MEM_K<<10);
+       if (EXT_MEM_K >= 63 * 1024) {
+               printk("BIOS report extended memory %d\n", EXT_MEM_K);
+               /* 63MB extended memory (totally 64MB memory) is the largest
+                * amount that BIOS can currently report. Probe real amount
+                * of memory when BIOS report us there is totally 64MB memory
+                */
+               /* store PTE0, linux kernel store all 0's in PTE0 to
+                * catch NULL references */
+               cfg = pg0[0];
+               page_ok = 1;
+               do {
+                       /* mmap address 0 to where we will test */
+                       pg0[0] = (memory_end |
+                               _PAGE_PRESENT |
+                               _PAGE_RW |
+                               _PAGE_PCD);     /* uncachable */
+                       local_flush_tlb();      /* invalidate local TLB */

+                       /* test for alternating 1's and 0's */
+                       *((volatile unsigned long *)0) = 0xaaaaaaaa;
+                       if (*((volatile unsigned long *)0) != 0xaaaaaaaa)
+                               page_ok = 0;

+                       /* test for alternating 0's and 1's */
+                       *((volatile unsigned long *)0) = 0x55555555;
+                       if (*((volatile unsigned long *)0) != 0x55555555)
+                               page_ok = 0;

+                       /* test for all 1's */
+                       *((volatile unsigned long *)0) = 0xffffffff;
+                       if (*((volatile unsigned long *)0) != 0xffffffff)
+                               page_ok = 0;

+                       /* test for all 0's */
+                       *((volatile unsigned long *)0) = 0x00000000;
+                       if (*((volatile unsigned long *)0) != 0x00000000)
+                               page_ok = 0;

+                       if (page_ok)
+                               memory_end += PAGE_SIZE;
+               } while (page_ok);

+               /* restore PTE0 */
+               pg0[0] = cfg;
+               local_flush_tlb();      /* invalidate local TLB */
+       }
        memory_end &= PAGE_MASK;
  #ifdef CONFIG_BLK_DEV_RAM
        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-------------------8<-----mem-2.0.32.patch-----------8<-------------------

-------------------8<-----mem-2.0.34.patch-----------8<-------------------
diff -c -r -N setup.c.orig setup.c
*** setup.c.orig        Sat Jul 18 17:40:35 1998
--- setup.c     Sun Jul 19 16:08:16 1998
***************
*** 32,37 ****
--- 32,38 ----
  #include <asm/segment.h>
  #include <asm/system.h>
  #include <asm/smp.h>
+ #include <asm/pgtable.h>
  
  /*
   * Tell us the machine setup..
***************
*** 81,92 ****
  extern int root_mountflags;
  extern int _etext, _edata, _end;
  
  extern char empty_zero_page[PAGE_SIZE];
  
  /*
   * This is set up by the setup-routine at boot-time
   */
! #define PARAM empty_zero_page
  #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
  #ifdef CONFIG_APM
  #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
--- 82,95 ----
  extern int root_mountflags;
  extern int _etext, _edata, _end;
  
+ #if 0
  extern char empty_zero_page[PAGE_SIZE];
+ #endif
  
  /*
   * This is set up by the setup-routine at boot-time
   */
! #define PARAM ((char *)empty_zero_page)
  #define EXT_MEM_K (*(unsigned short *) (PARAM+2))
  #ifdef CONFIG_APM
  #define APM_BIOS_INFO (*(struct apm_bios_info *) (PARAM+64))
***************
*** 114,122 ****
  void 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;
        static unsigned char smptrap=0;
  
        if(smptrap==1)
--- 117,125 ----
  void setup_arch(char **cmdline_p,
        unsigned long * memory_start_p, unsigned long * memory_end_p)
  {
!       unsigned long memory_start, memory_end, cfg;
        char c = ' ', *to = command_line, *from = COMMAND_LINE;
!       int len = 0, page_ok;
        static unsigned char smptrap=0;
  
        if(smptrap==1)
***************
*** 133,138 ****
--- 136,187 ----
  #endif
        aux_device_present = AUX_DEVICE_INFO;
        memory_end = (1<<20) + (EXT_MEM_K<<10);
+       if (EXT_MEM_K >= 63 * 1024) {
+               printk("BIOS report extened memory %d\n", EXT_MEM_K);
+               /* 63MB extended memory (totally 64MB memory) is the largest
+                * amount that BIOS can currently report. Probe real amount
+                * of memory when BIOS report us there is totally 64MB memory
+                */
+               /* store PTE0, linux kernel store all 0's in PTE0 to
+                * catch NULL references */
+               cfg = pg0[0];
+               page_ok = 1;
+               do {
+                       /* mmap address 0 to where we will test */
+                       pg0[0] = (memory_end |
+                               _PAGE_PRESENT | 
+                               _PAGE_RW |
+                               _PAGE_PCD);     /* uncachable */
+                       local_flush_tlb();      /* invalidate local TLB */

+                       /* test for alternating 1's and 0's */
+                       *((volatile unsigned long *)0) = 0xaaaaaaaa;
+                       if (*((volatile unsigned long *)0) != 0xaaaaaaaa)
+                               page_ok = 0;

+                       /* test for alternating 0's and 1's */
+                       *((volatile unsigned long *)0) = 0x55555555;
+                       if (*((volatile unsigned long *)0) != 0x55555555)
+                               page_ok = 0;

+                       /* test for all 1's */
+                       *((volatile unsigned long *)0) = 0xffffffff;
+                       if (*((volatile unsigned long *)0) != 0xffffffff)
+                               page_ok = 0;

+                       /* test for all 0's */
+                       *((volatile unsigned long *)0) = 0x00000000;
+                       if (*((volatile unsigned long *)0) != 0x00000000)
+                               page_ok = 0;

+                       /* if this page is available, try the next one */
+                       if (page_ok)
+                               memory_end += PAGE_SIZE;
+               } while (page_ok);
+               /* restore PTE0 */
+               pg0[0] = cfg;
+               local_flush_tlb();      /* invalidate local TLB */
+       }
        memory_end &= PAGE_MASK;
  #ifdef CONFIG_BLK_DEV_RAM
        rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
-------------------8<-----mem-2.0.34.patch-----------8<-------------------

If your kernel is not 2.0.32 or 2.0.34, you can modify
arch/kernel/setup.c manually by the following steps.

1. add '#include <asm/pgtable.h>'
2. comment out the line 'extern char empty_zero_page[PAGE_SIZE];'
3. re-define PARAM to '((char *)empty_zero_page)'
4. in function setup_arch(), add declarations of cfg(unsigned long)
   and page_ok(int)
5. still in function setup_arch() find two line likes this
   'memory_end = (1<<20) + (EXT_MEM_K<<10);
    memory_end &= PAGE_MASK;', now insert the following codes between
   the two lines

        if (EXT_MEM_K >= 63 * 1024) {
                printk("BIOS report extened memory %d\n", EXT_MEM_K);
                /* 63MB extended memory (totally 64MB memory) is the largest
                 * amount that BIOS can currently report. Probe real amount
                 * of memory when BIOS report us there is totally 64MB memory
                 */
                /* store PTE0, linux kernel store all 0's in PTE0 to
                 * catch NULL references */
                cfg = pg0[0];
                page_ok = 1;
                do {
                        /* mmap address 0 to where we will test */
                        pg0[0] = (memory_end |
                                _PAGE_PRESENT | 
                                _PAGE_RW |
                                _PAGE_PCD);     /* uncachable */
                        local_flush_tlb();      /* invalidate local TLB */
 
                        /* test for alternating 1's and 0's */
                        *((volatile unsigned long *)0) = 0xaaaaaaaa;
                        if (*((volatile unsigned long *)0) != 0xaaaaaaaa)
                                page_ok = 0;
 
                        /* test for alternating 0's and 1's */
                        *((volatile unsigned long *)0) = 0x55555555;
                        if (*((volatile unsigned long *)0) != 0x55555555)
                                page_ok = 0;
 
                        /* test for all 1's */
                        *((volatile unsigned long *)0) = 0xffffffff;
                        if (*((volatile unsigned long *)0) != 0xffffffff)
                                page_ok = 0;
 
                        /* test for all 0's */
                        *((volatile unsigned long *)0) = 0x00000000;
                        if (*((volatile unsigned long *)0) != 0x00000000)
                                page_ok = 0;
 
                        /* if this page is available, try the next one */
                        if (page_ok)
                                memory_end += PAGE_SIZE;
                } while (page_ok);
                /* restore PTE0 */
                pg0[0] = cfg;
                local_flush_tlb();      /* invalidate local TLB */
        }

Codes for automatical probing memory size is inspired by booting codes
of FreeBSD. Wish you can enjoy it.

I have test it on two machines, one is PentiumIIx2/128MB/6GB, the other
is PentiumIIx2/196MB/6GB, it works. I want to know whether it works on
other machine ( 386, 486, Pentium, PentiumPro, especially 386 boxes). If
you encounter some problem, please contract me at para@cs.sebuaa.ac.cn.

More strict way to describe physical memory is using set of <base,size>
pairs. Instead Linux use a single <memory_start, memory_end>. It may
crash system on some motherboard and BIOS. But, fortunately, most system
apply to the Linux' way, it works very well.

BlueOcean
1998/7/19

--
3m4m                                  7;40m0m
3m4m    Buck barks in the darkness    7;40m0m
3m4m                                  7;40m0m

m2m※ 来源:·BBS 水木清华站 bbs.net.tsinghua.edu.cn·[FROM: 202.112.142.40]m


--

                              Enjoy Linux!
                          -----It's FREE!-----

※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: mtlab.hit.edu.cn]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:209.951毫秒