Patch to detect > 64M on i386 in 2.0.30

Larry M. Augustin (lma@varesearch.com)
Wed, 16 Apr 1997 23:53:24 -0700


Here's a patch I wrote some time ago to detect more than 64M RAM in
i386 systems. It works on 2.0 kernels. Diffs are against 2.0.30. It
tries several different BIOS calls for RAM detection. If the BIOS
supports it, it reports the amount of memory actually cached.

I just checked 2.1.34 and noticed similar but less extensive code. If
there's a desire for something more extensive, let me know and I'll
work this into 2.1.34.

I noticed 2.1.34 still has the keyboard repeat code which causes
intermittent hangs on a number of Pentium Pro systems during boot.
I'd sure like to see it go away.

Larry

diff -r -c linux-orig/arch/i386/boot/setup.S linux/arch/i386/boot/setup.S
*** linux-orig/arch/i386/boot/setup.S Sat Mar 30 10:58:57 1996
--- linux/arch/i386/boot/setup.S Wed Apr 16 17:40:39 1997
***************
*** 26,31 ****
--- 26,34 ----
!
! Video handling moved to video.S by Martin Mares, March 1996
! <mj@k332.feld.cvut.cz>
+ !
+ ! Modifications to detect > 64M RAM by Larry M. Augustin lma@varesearch.com 4/16/97.
+

! NOTE! These had better be the same as in bootsect.s!
#define __ASSEMBLY__
***************
*** 230,246 ****
db 0

loader_ok:
- ! Get memory size (extended mem, kB)

mov ah,#0x88
int 0x15
! mov [2],ax

! Set the keyboard repeat rate to the max

! mov ax,#0x0305
! xor bx,bx ! clear bx
! int 0x16

! Check for video adapter and its parameters and allow the
! user to browse video modes.
--- 233,320 ----
db 0

loader_ok:

+ ! Start of memory size detection code
+ !
+ ! int 15h, ah=0x88
+ ! Returns amount of memory above 1MB in KB in AX
+ ! 16M == 3C00 (15M extended memory)
+ ! ...
+ ! 64M == FC00 (63M extended memory)
+ xor eax,eax ! Clear upper part of EAX
mov ah,#0x88
int 0x15
! pushf ! Save CF error flag
! and eax, #0x0000ffff ! Clear upper 16 bits
! add eax, #0x0400 ! Add 1MB
! mov [0x220], eax ! Save 32-bit result in case we need to return it
! popf ! Restore CF error flag
! jnc int15_88_good ! CF = 1 indicates error
! movb [0x228], #0x01 ! Return the result code
! lea cx, end_memdetect ! gas can't do 16-bit offset jumps. very annoying.
! jmp cx
! int15_88_good:
! cmp eax, #0x00010000 ! check AX for memory >= 64M
! jge testfor_int15_c7 ! if >= 64M, check for more advanced BIOS calls
! movb [0x228], #0x05 ! else return the result code
! jmp end_memdetect ! and we're done
! testfor_int15_c7:
! ! 64M or more
! ! Test if int 15h ah=c7h is supported using int 15h, ah=c0
! push es
! mov ah, #0xc0
! int 0x15 ! ES:BX points to a configuration table
! seg es
! movb al, 6(bx) ! Save byte at ES:BX + 6 for testing
! pop es
! or ah,ah ! check return code
! jnz try_int15_e801 ! BIOS call failed, try int 15h, ax=e801
! int15_c0_good: ! int 15, c0 call succeeded
! and al,#0x10 ! Test bit 4 of byte at ES:BX + 6
! jnz try_int15_c7 ! int 15h, ah=c7h is supported. call it.
! try_int15_e801: ! else try int 15h, ax=e801
! mov ax,#0xe801
! int 0x15
! jnc int15_e801_good ! CF = 1 indicates error
! movb [0x228], #0x02 ! Only int 15h, ah=88h succeeded. Return the result code.
! jmp end_memdetect ! Return int 15h, ah=88h result.
! int15_e801_good:
! and eax, #0x0000ffff ! Clear upper 16 bits
! and ebx, #0x0000ffff ! Clear upper 16 bits
! shl ebx, 6 ! Multiply EBX by 64 so we have memory in 1K blocks
! add eax, ebx
! add eax, #0x0400 ! Add 1MB
! mov [0x220], eax ! Return 32-bit result
! movb [0x228], #0x03 ! int 15h,ax=e801h succeeded. Return the result code.
! jmp end_memdetect
! try_int15_c7: ! Try calling int 15 ah=c7
! push ds
! push cs
! pop ds
! lea si,mem_tbl ! address of memory map table
! mov ah,#0xc7 !
! int 0x15 !
! pop ds
! jc try_int15_e801 ! CF = 1 indicates an error, fall back to int 15h ax=e801
! int15_c7_good:
! mov eax, lmlo ! Memory between 1M and 16M in 1K blocks
! add eax, lmhi ! Memory above 16M in 1K blocks
! add eax, #0x0400 ! Add 1MB
! mov [0x220], eax ! Return 32-bit result
! mov eax, cmlo ! Cacheable memory between 1M and 16M in 1K blocks
! add eax, cmhi ! Cacheable memory above 16M in 1K blocks
! add eax, #0x0400 ! Add 1MB
! mov [0x224], eax ! Return 32-bit result
! movb [0x228], #0x04 ! Return the result code
! end_memdetect:

+ ! LMA 4/15/97 removed setting of keyboard repeat rate. Causes some systems
+ ! to hang at boot.
! Set the keyboard repeat rate to the max

! ! mov ax,#0x0305
! ! xor bx,bx ! clear bx
! ! int 0x16

! Check for video adapter and its parameters and allow the
! user to browse video modes.
***************
*** 700,705 ****
--- 774,792 ----
gdt_48:
.word 0x800 ! gdt limit=2048, 256 GDT entries
.word 512+gdt,0x9 ! gdt base = 0X9xxxx
+
+ mem_tbl:
+ .word 0x0000 ! length of table (excluding this word)
+ lmlo: .word 0x0000, 0x0000 ! local memory between 1M and 16M in 1K blocks
+ lmhi: .word 0x0000, 0x0000 ! local memory between 16M and 4G in 1K blocks
+ smlo: .word 0x0000, 0x0000 ! system memory between 1M and 16M in 1K blocks
+ smhi: .word 0x0000, 0x0000 ! system memory between 16M and 4G in 1K blocks
+ cmlo: .word 0x0000, 0x0000 ! cacheable memory between 1M and 16M in 1K blocks
+ cmhi: .word 0x0000, 0x0000 ! cacheable memory between 16M and 4G in 1K blocks
+ .word 0x0000, 0x0000 ! 1K blocks before start of non-system memory between 1M and 16M
+ .word 0x0000, 0x0000 ! 1K blocks before start of non-system memory between 16M and 4G
+ .word 0x0000, 0x0000 ! reserved
+ .word 0x0000, 0x0000 ! reserved

!
! Include video setup & detection code
diff -r -c linux-orig/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c
*** linux-orig/arch/i386/kernel/setup.c Fri Sep 20 07:00:34 1996
--- linux/arch/i386/kernel/setup.c Wed Apr 16 23:13:42 1997
***************
*** 95,100 ****
--- 95,106 ----
#define KERNEL_START (*(unsigned long *) (PARAM+0x214))
#define INITRD_START (*(unsigned long *) (PARAM+0x218))
#define INITRD_SIZE (*(unsigned long *) (PARAM+0x21c))
+ /* Total memory in 1K blocks */
+ #define MEM_K (*(unsigned int *) (PARAM+0x220))
+ /* Amounted of memory cached in 1K blocks */
+ #define MEM_K_CACHED (*(unsigned int *) (PARAM+0x224))
+ /* Return code from BIOS memory detection routines in setup.S */
+ #define MEM_BIOS_RESULTS (*(unsigned char *) (PARAM+0x228))
#define COMMAND_LINE ((char *) (PARAM+2048))
#define COMMAND_LINE_SIZE 256

***************
*** 126,132 ****
apm_bios_info = APM_BIOS_INFO;
#endif
aux_device_present = AUX_DEVICE_INFO;
! memory_end = (1<<20) + (EXT_MEM_K<<10);
memory_end &= PAGE_MASK;
#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;
--- 132,161 ----
apm_bios_info = APM_BIOS_INFO;
#endif
aux_device_present = AUX_DEVICE_INFO;
!
! /* Memory detection code added by lma@varesearch.com 4/16/97 */
! memory_end = MEM_K << 10;
! printk("BIOS query detected %dKB RAM. Report errors to lma@varesearch.com\n", MEM_K);
! switch(MEM_BIOS_RESULTS) {
! case 0x01:
! printk("Warning: BIOS function int 15h ah=88h used to determine RAM size returned an error code\n indicating failure. The amount of detected RAM may be incorrect.\n");
! break;
! case 0x02:
! printk("Warning: BIOS function int 15h ah=88h indicated at least 64M system RAM\n and all BIOS calls capable of detecting more than 64M RAM failed.\n");
! break;
! case 0x03:
! printk("Total RAM size was detected using BIOS function int 15h, ax=e801h.\n");
! break;
! case 0x04:
! printk("BIOS int 15h, ah=c7h reports %dKB of %dKB RAM is cached.\n", MEM_K, MEM_K_CACHED);
! break;
! case 0x05:
! printk("Total RAM size was detected using BIOS function int 15h, ah=88h.\n");
! break;
! default:
! printk("Warning: BIOS based memory detection routine returned unknown result code %x.\n", MEM_BIOS_RESULTS);
! }
!
memory_end &= PAGE_MASK;
#ifdef CONFIG_BLK_DEV_RAM
rd_image_start = RAMDISK_FLAGS & RAMDISK_IMAGE_START_MASK;