diff options
author | Tobias Weingartner <weingart@cvs.openbsd.org> | 1997-10-17 15:03:29 +0000 |
---|---|---|
committer | Tobias Weingartner <weingart@cvs.openbsd.org> | 1997-10-17 15:03:29 +0000 |
commit | 41093f286d691912ac4dbf211375b21dbff49e4e (patch) | |
tree | 2921090c2b4c87b93ba68120400a50ef8a5cfec7 /sys | |
parent | 82b80c5d2e1dea90de4bcb7b3dda8c4854d6564a (diff) |
Use BIOS to probe for memory map.
Probe for BIOS supported disks.
Use BIOS to get geometry for supported disks.
All in preparation to passing the whole thing
to the kernel.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/i386/include/biosvar.h | 22 | ||||
-rw-r--r-- | sys/arch/i386/stand/README | 33 | ||||
-rw-r--r-- | sys/arch/i386/stand/boot/conf.c | 4 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/Makefile | 5 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/biosdev.c | 75 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/biosdev.h | 6 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/cmd_i386.c | 105 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/gidt.S | 10 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/libsa.h | 5 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/machdep.c | 3 | ||||
-rw-r--r-- | sys/arch/i386/stand/libsa/memprobe.c | 326 |
11 files changed, 531 insertions, 63 deletions
diff --git a/sys/arch/i386/include/biosvar.h b/sys/arch/i386/include/biosvar.h index 0eb4ee8a081..1aa6add713b 100644 --- a/sys/arch/i386/include/biosvar.h +++ b/sys/arch/i386/include/biosvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biosvar.h,v 1.16 1997/10/14 01:04:25 weingart Exp $ */ +/* $OpenBSD: biosvar.h,v 1.17 1997/10/17 15:03:15 weingart Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff @@ -130,6 +130,26 @@ struct BIOS_MAP { int type; /* Type of block */ }; +/* Info about disk from the bios, plus the mapping from + * BIOS numbers to BSD major (driver?) number. + * + * Also, do not bother with BIOSN*() macros, just parcel + * the info out, and use it like this. This makes for less + * of a dependance on BIOSN*() macros having to be the same + * across /boot, /bsd, and userland. + */ +typedef struct _bios_diskinfo { + /* BIOS section */ + signed int bios_number; /* BIOS number of drive (or -1) */ + unsigned int bios_cylinders; /* BIOS cylinders */ + unsigned int bios_heads; /* BIOS heads */ + unsigned int bios_sectors; /* BIOS sectors */ + + /* BSD section */ + signed int bsd_major; /* Major number of driver (or -1) */ +} bios_diskinfo_t; + + #ifdef _KERNEL #include <machine/bus.h> diff --git a/sys/arch/i386/stand/README b/sys/arch/i386/stand/README index a5748f08075..e596ac29873 100644 --- a/sys/arch/i386/stand/README +++ b/sys/arch/i386/stand/README @@ -1,4 +1,4 @@ -$OpenBSD: README,v 1.10 1997/09/02 21:41:29 kstailey Exp $ +$OpenBSD: README,v 1.11 1997/10/17 15:03:16 weingart Exp $ # hmm, no copyright @@ -92,14 +92,14 @@ things work without -DSAVE_MEMORY, and don't with it defined. Mon Apr 21 15:25:42 EDT 1997 ---------------------------- -Now memory limits are not in concern. No any restrictions on placement -and sizes of code/data. It would be an idea to move PMMM code from kernel -into /boot to use low memory somehow, then remember that upper 64k are -used by apm, so do not grow too much... Low 64k are used for real mode +Now memory limits are not a concern. No more restrictions on placement +and size of code/data. It would be an idea to move PMMM code from kernel +into /boot to use low memory somehow. Also remember that the upper 64k is +used by apm, so do not grow heap too much... Low 64k is used for real mode IDT, BIOS data, stack for /boot, so stack is big enough (about 60k). All the magic w/ prot-real mode interface now in one place <libsa/gidt.S>. BIOS (and DOS soon) interrupt entry points are now just as simple as -they are in real mode (just use a macro BIOSINT, which shifts int# +they are in real mode (just use a macro BIOSINT, which shifts int number by 0x20, that all! ;). @@ -114,22 +114,33 @@ to use sleep instead, it's known to work. Thu Jul 17 21:24:42 EDT 1997 ---------------------------- -Return to the way when code have to be less then 64k, or better say that +Return to the way when code has to be less then 64k, or better say that whole gidt.S code must be in the 1st 64k of /boot .text section. This saves about 2k of code (idt initialization). APM information is now gathered and passed to the locore.s upon kernel -startup as pointer to the struct apm_connect_info. +startup as a pointer to the struct apm_connect_info. Wed Aug 27 16:30:51 EDT 1997 ---------------------------- -BIOS boot device number is passed to kernel along with BIOS geometry for that -drive and other info. APM connect info is passed as well not in that -apm0 structure, so apm0 will become a slave on bios0 soon. +BIOS boot device number is passed to the kernel along with BIOS geometry +for that drive and other info. APM connect info is passed as well not in +that apm0 structure, so apm0 will become a slave on bios0 soon. To get your /boot installed properly on a hardrive you have to load /bsd from that hd/partition (since only boot drive geometry is passed). The passed geometry will be used for all the drives, if you will try to installboot on other disks (floppies and pseudo-disks will honor the disklabel), that might be useful on some bioses, esp. SCSI HAs which use fixed translated geometry for all the drives. + + +Mon Oct 13 16:41:18 CDT 1997 +---------------------------- + +Clean up memprobe some, adding support for querying the BIOS for the +memory map. Resort to the old invasive probe if all else fails. Add +preliminary support for passing a memory map to the kernel, instead of +cnvmem/extmem. This should make weird boards easier to support in the +future. + diff --git a/sys/arch/i386/stand/boot/conf.c b/sys/arch/i386/stand/boot/conf.c index 45853997b84..ac38063a69c 100644 --- a/sys/arch/i386/stand/boot/conf.c +++ b/sys/arch/i386/stand/boot/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.8 1997/09/29 22:59:03 mickey Exp $ */ +/* $OpenBSD: conf.c,v 1.9 1997/10/17 15:03:18 weingart Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -47,7 +47,7 @@ #include <biosdev.h> #include <dev/cons.h> -const char version[] = "1.01"; +const char version[] = "1.05"; int debug; struct fs_ops file_system[] = { diff --git a/sys/arch/i386/stand/libsa/Makefile b/sys/arch/i386/stand/libsa/Makefile index a1d5a8c9dd1..dd0e818b045 100644 --- a/sys/arch/i386/stand/libsa/Makefile +++ b/sys/arch/i386/stand/libsa/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.26 1997/09/21 10:02:08 mickey Exp $ +# $OpenBSD: Makefile,v 1.27 1997/10/17 15:03:20 weingart Exp $ LIB= sa @@ -15,7 +15,8 @@ DIR_KERN=$S/lib/libkern # i386 stuff (so, it will possibly load in the same 64k) SRCS= gidt.S debug_i386.S alloca.S \ machdep.c dev_i386.c exec_i386.c cmd_i386.c \ - biosdev.c bioscons.c gateA20.c memprobe.c time.c + biosdev.c bioscons.c gateA20.c smpprobe.c \ + memprobe.c diskprobe.c time.c # stand routines SRCS+= alloc.c exit.c exec.c getfile.c gets.c globals.c strcmp.c strlen.c \ diff --git a/sys/arch/i386/stand/libsa/biosdev.c b/sys/arch/i386/stand/libsa/biosdev.c index 193a4755780..8ba83e43fa9 100644 --- a/sys/arch/i386/stand/libsa/biosdev.c +++ b/sys/arch/i386/stand/libsa/biosdev.c @@ -1,4 +1,4 @@ -/* $OpenBSD: biosdev.c,v 1.36 1997/10/07 08:56:19 mickey Exp $ */ +/* $OpenBSD: biosdev.c,v 1.37 1997/10/17 15:03:21 weingart Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -52,13 +52,13 @@ struct biosdisk { }; /* - * * return a word that represents the max number * of sectors and heads for this device * */ u_int32_t -biosdinfo(int dev) +biosdinfo(dev) + int dev; { u_int f, rv; __asm __volatile (DOINT(0x13) "; setc %b0\n\t" @@ -71,10 +71,37 @@ biosdinfo(int dev) } /* + * Probe if given bios disk exists. + * + * NOTE: This seems to hang on certain machines. Use biosdinfo() + * first, and verify with biosdprobe() IFF biosdinfo() succeeds + * first. + * + * XXX - biosdinfo() and biosdprobe() should be integrated into 1 fcn. + */ +u_int32_t +biosdprobe(dev) + int dev; +{ + u_int32_t val = 0; + + __asm __volatile ( + DOINT(0x13) "\n\t" + "setc %b0 \n\t" + : "=a" (val) + : "0" (0x1500), + "d" (dev) + : "%ecx", "%edx", "cc"); + + return(val & 0xffff); +} + +/* * reset disk system */ static __inline int -biosdreset(int dev) +biosdreset(dev) + int dev; { int rv; __asm __volatile (DOINT(0x13) "; setc %b0" : "=a" (rv) @@ -82,8 +109,11 @@ biosdreset(int dev) return (rv & 0xff)? rv >> 8 : 0; } -static __inline int -biosd_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void* buf) +__inline int +biosd_rw(rw, dev, cyl, head, sect, nsect, buf) + int rw, dev, cyl, head; + int sect, nsect; + void* buf; { int rv; BIOS_regs.biosr_es = (u_int32_t)buf >> 4; @@ -110,7 +140,8 @@ biosd_rw(int rw, int dev, int cyl, int head, int sect, int nsect, void* buf) * check the features supported by the bios for the drive */ static __inline int -EDDcheck (int dev) +EDDcheck (dev) + int dev; { int rv, bm, sgn; __asm __volatile(DOINT(0x13) "; setc %b0" @@ -120,7 +151,11 @@ EDDcheck (int dev) } int -EDD_rw(int rw, int dev, u_int64_t daddr, u_int32_t nblk, void *buf) +EDD_rw(rw, dev, daddr, nblk, buf) + int rw, dev; + u_int64_t daddr; + u_int32_t nblk; + void *buf; { int rv; struct EDD_CB cb; @@ -332,8 +367,10 @@ biosopen(struct open_file *f, ...) return 0; } + static __inline const char * -biosdisk_err(u_int error) +biosdisk_err(error) + u_int error; { static const u_char errs[] = /* ignored "\x00" "successful completion\0" */ @@ -379,7 +416,8 @@ biosdisk_err(u_int error) } static __inline int -biosdisk_errno(u_int error) +biosdisk_errno(error) + u_int error; { static const struct biosdisk_errors { u_char error; @@ -410,8 +448,13 @@ biosdisk_errno(u_int error) } int -biosstrategy(void *devdata, int rw, - daddr_t blk, size_t size, void *buf, size_t *rsize) +biosstrategy(devdata, rw, blk, size, buf, rsize) + void *devdata; + int rw; + daddr_t blk; + size_t size; + void *buf; + size_t *rsize; { u_int8_t error = 0; register struct biosdisk *bd = (struct biosdisk *)devdata; @@ -498,14 +541,18 @@ biosstrategy(void *devdata, int rw, } int -biosclose(struct open_file *f) +biosclose(f) + struct open_file *f; { free(f->f_devdata, 0); return 0; } int -biosioctl(struct open_file *f, u_long cmd, void *data) +biosioctl(f, cmd, data) + struct open_file *f; + u_long cmd; + void *data; { return 0; } diff --git a/sys/arch/i386/stand/libsa/biosdev.h b/sys/arch/i386/stand/libsa/biosdev.h index e54a352ba41..b3aff102afa 100644 --- a/sys/arch/i386/stand/libsa/biosdev.h +++ b/sys/arch/i386/stand/libsa/biosdev.h @@ -1,4 +1,4 @@ -/* $OpenBSD: biosdev.h,v 1.21 1997/09/20 22:40:44 flipk Exp $ */ +/* $OpenBSD: biosdev.h,v 1.22 1997/10/17 15:03:22 weingart Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -41,7 +41,9 @@ int biosstrategy __P((void *, int, daddr_t, size_t, void *, size_t *)); int biosopen __P((struct open_file *, ...)); int biosclose __P((struct open_file *)); int biosioctl __P((struct open_file *, u_long, void *)); -u_int32_t biosdinfo(int); +u_int32_t biosdinfo __P((int)); +u_int32_t biosdprobe __P((int)); +int biosd_rw __P((int, int, int, int, int, int, void*)); /* bioscons.c */ diff --git a/sys/arch/i386/stand/libsa/cmd_i386.c b/sys/arch/i386/stand/libsa/cmd_i386.c index 4d8db5efb49..1934e21dff8 100644 --- a/sys/arch/i386/stand/libsa/cmd_i386.c +++ b/sys/arch/i386/stand/libsa/cmd_i386.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cmd_i386.c,v 1.9 1997/10/09 22:23:00 deraadt Exp $ */ +/* $OpenBSD: cmd_i386.c,v 1.10 1997/10/17 15:03:23 weingart Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff, Tobias Weingartner @@ -33,6 +33,7 @@ */ #include <sys/param.h> +#include <sys/disklabel.h> #include <machine/biosvar.h> #include "debug.h" #include "biosdev.h" @@ -41,24 +42,39 @@ static int Xdiskinfo __P((void)); static int Xregs __P((void)); +static int Xboot __P((void)); +static int Xmemory __P((void)); + +/* From gidt.S */ +int bootbuf __P((int, int)); + +/* From probedisk.c */ +extern bios_diskinfo_t bios_diskinfo[]; + const struct cmd_table cmd_machine[] = { { "diskinfo", CMDT_CMD, Xdiskinfo }, { "regs", CMDT_CMD, Xregs }, + { "boot", CMDT_CMD, Xboot }, + { "memory", CMDT_CMD, Xmemory }, { NULL, 0 } }; static int Xdiskinfo() { - u_int32_t di; int i; - printf("Disk\tCylinders\tHeads\tSectors\n"); - for(i = 0x80; i < 0x84; i++){ - if ((di = biosdinfo(i))) - printf("0x%x\t %d \t%d\t%d\n", i, - BIOSNTRACKS(di), BIOSNHEADS(di), BIOSNSECTS(di)); + printf("Disk\tBIOS#\tCylinders\tHeads\tSectors\n"); + for(i = 0; bios_diskinfo[i].bios_number != -1 && i < 10; i++){ + int d = bios_diskinfo[i].bios_number; + + printf("%cd%d\t 0x%x\t %s%d \t%d\t%d\n", + (d & 0x80)?'h':'f', (d & 0x80)?d - 128:d, d, + (bios_diskinfo[i].bios_cylinders < 100)?" ":" ", + bios_diskinfo[i].bios_cylinders, + bios_diskinfo[i].bios_heads, + bios_diskinfo[i].bios_sectors); } return 0; @@ -70,3 +86,78 @@ Xregs() DUMP_REGS; return 0; } + +static int +Xboot() +{ + int dev, part, st; + char *buf = (void *)0x7c00; + + if(cmd.argc != 2) { + printf("machine boot {fd,hd}[0123][abcd]\n"); + return 0; + } + + /* Check arg */ + if(cmd.argv[1][0] != 'f' && cmd.argv[1][0] != 'h') + goto bad; + if(cmd.argv[1][1] != 'd') + goto bad; + if(cmd.argv[1][2] < '0' || cmd.argv[1][2] > '3') + goto bad; + if(cmd.argv[1][3] < 'a' || cmd.argv[1][3] > 'd') + goto bad; + + printf("Booting from %s ", cmd.argv[1]); + + dev = (cmd.argv[1][0] == 'h')?0x80:0; + dev += (cmd.argv[1][2] - '0'); + part = (cmd.argv[1][3] - 'a'); + + printf("[%x,%d]\n", dev, part); + + /* Read boot sector from device */ + st = biosd_rw(F_READ, dev, 0, 0, 1, 1, buf); + if(st) goto bad; + + /* Frob boot flag in buffer from HD */ + if(dev & 0x80){ + int i, j; + + for(i = 0, j = DOSPARTOFF; i < 4; i++, j += 16) + if(part == i) + buf[j] = 0x80; + else + buf[j] = 0x00; + } + + printf("%x %x %x %x %x\n", buf[0], buf[1], buf[2], buf[3], buf[4]); + + /* Load %dl, ljmp */ + bootbuf(dev, part); + +bad: + printf("Invalid device!\n"); + return 0; +} + +int +Xmemory() +{ + struct BIOS_MAP *tm = memory_map; + int count, total = 0; + + for(count = 0; tm[count].type != BIOS_MAP_END; count++){ + printf("Region %d: type %u at 0x%x for %uKB\n", count, + tm[count].type, tm[count].addr, tm[count].size/1024); + + if(tm[count].type == BIOS_MAP_FREE) + total += tm[count].size; + } + + printf("Low ram: %dKB High ram: %dKB\n", cnvmem, extmem); + printf("Total free memory: %dKB\n", total/1024); + + return 0; +} + diff --git a/sys/arch/i386/stand/libsa/gidt.S b/sys/arch/i386/stand/libsa/gidt.S index dcba77861a4..db4d7da3295 100644 --- a/sys/arch/i386/stand/libsa/gidt.S +++ b/sys/arch/i386/stand/libsa/gidt.S @@ -1,4 +1,4 @@ -/* $OpenBSD: gidt.S,v 1.15 1997/09/02 17:05:12 mickey Exp $ */ +/* $OpenBSD: gidt.S,v 1.16 1997/10/17 15:03:24 weingart Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff @@ -416,3 +416,11 @@ intno = . - 1 popal iret +/* Call buffer at 07c0:0000 in real mode to simulate a BIOS boot */ +ENTRY(bootbuf) + popl %eax /* Don't need return address */ + popl %edx /* Device */ + popl %eax /* Partition - Not used, overwritten */ + prot2real /* Switch */ + ljmp $0x7c0, $0x000 + diff --git a/sys/arch/i386/stand/libsa/libsa.h b/sys/arch/i386/stand/libsa/libsa.h index 911a59e9cb8..15ac5f6d5ca 100644 --- a/sys/arch/i386/stand/libsa/libsa.h +++ b/sys/arch/i386/stand/libsa/libsa.h @@ -1,4 +1,4 @@ -/* $OpenBSD: libsa.h,v 1.17 1997/09/17 17:56:10 mickey Exp $ */ +/* $OpenBSD: libsa.h,v 1.18 1997/10/17 15:03:26 weingart Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -35,7 +35,9 @@ #include <lib/libsa/stand.h> void gateA20 __P((int)); +void smpprobe __P((void)); void memprobe __P((void)); +void diskprobe __P((void)); void devboot __P((dev_t, char *)); void *alloca __P((size_t)); void machdep __P((void)); @@ -43,6 +45,7 @@ void time_print __P((void)); extern const char bdevs[][4]; extern const int nbdevs; +extern struct BIOS_MAP *memory_map; extern int bootdev; /* XXX pass through the global to exec_i386 */ extern u_int cnvmem, extmem; /* XXX global pass memprobe()->machdep_start() */ diff --git a/sys/arch/i386/stand/libsa/machdep.c b/sys/arch/i386/stand/libsa/machdep.c index c5b5bed28be..14ee4567561 100644 --- a/sys/arch/i386/stand/libsa/machdep.c +++ b/sys/arch/i386/stand/libsa/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.17 1997/10/12 21:14:23 mickey Exp $ */ +/* $OpenBSD: machdep.c,v 1.18 1997/10/17 15:03:27 weingart Exp $ */ /* * Copyright (c) 1997 Michael Shalayeff @@ -143,6 +143,7 @@ machdep() cninit(); CKPT('3'); #ifndef _TEST memprobe(); CKPT('4'); + diskprobe(); CKPT('6'); #endif if ((BIOS_vars.bios_apm_detail = apm_check())) { diff --git a/sys/arch/i386/stand/libsa/memprobe.c b/sys/arch/i386/stand/libsa/memprobe.c index 180d742f4dc..64e25790cee 100644 --- a/sys/arch/i386/stand/libsa/memprobe.c +++ b/sys/arch/i386/stand/libsa/memprobe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: memprobe.c,v 1.14 1997/10/12 21:01:01 mickey Exp $ */ +/* $OpenBSD: memprobe.c,v 1.15 1997/10/17 15:03:28 weingart Exp $ */ /* * Copyright (c) 1997 Tobias Weingartner @@ -37,36 +37,194 @@ #include "libsa.h" static int addrprobe __P((u_int)); -u_int cnvmem, extmem; +u_int cnvmem, extmem; /* XXX - remove */ +struct BIOS_MAP *memory_map; -void -memprobe() +struct E820_desc_t { + u_int32_t addr_lo; + u_int32_t addr_hi; + u_int32_t size_lo; + u_int32_t size_hi; + u_int32_t type; +} __attribute__ ((packed)); +static struct E820_desc_t Desc; + + +#define E820_MAX_MAPENT 10 + +/* BIOS int 15, AX=E820 + * + * This is the "prefered" method. + */ +struct BIOS_MAP * +bios_E820() { - int ram; + static struct BIOS_MAP bm[E820_MAX_MAPENT]; /* This is easier */ + int E820Present = 0; + int eax = 0, count = 0; + volatile int ebx = 0; - __asm __volatile(DOINT(0x12) : "=a" (cnvmem) - :: "%ecx", "%edx", "cc"); - cnvmem &= 0xffff; + do { + BIOS_regs.biosr_es = ((unsigned)(&Desc) >> 4); + __asm __volatile( + "movl %2, %%ebx\n\t" + "movl $0x534D4150, %%edx\n\t" + DOINT(0x15) "\n\t" + "movl %%eax, %%edx\n\t" + "setc %b0\n\t" + "movzbl %b0, %0\n\t" + "cmpl $0x534D4150, %%edx\n\t" + "je 1f\n\t" + "incl %%eax\n\t" + "1:\n\t" + : "=a" (eax) + : "0" (0xE820), + "1" (ebx), + "c" (sizeof(Desc)), + "D" ((unsigned)(&Desc) & 0xF) + : "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi", "cc", "memory"); + ebx = BIOS_regs.biosr_bx; - printf("%d Kb conventional memory.\n", cnvmem); + if(eax) break; /* Not present, or done */ - /* probe extended memory - * - * There is no need to do this in assembly language. This is - * much easier to debug in C anyways. - */ - for(ram = 1024; ram < 512*1024; ram += 4){ + /* We are ignoring the upper 32 bits in the 64 bit + * integer returned. If anyone has a PC where the + * upper 32 bits are not zeros, *please* tell me! ;) + * + * NOTE: the BIOS_MAP_* numbers are the same, save for + * the "zero" case, which we remap to reserved. + */ + bm[count].addr = Desc.addr_lo; + bm[count].size = Desc.size_lo; + bm[count].type = (Desc.type)?Desc.type:BIOS_MAP_RES; - if(!(ram % 64)) - printf("Probing memory: %d KB\r", ram-1024); - if(addrprobe(ram)) - break; + E820Present = 1; + } while((++count < E820_MAX_MAPENT) && (ebx != 0)); /* Do not re-oder! */ + + if(E820Present){ + printf("int 0x15 [E820]\n"); + bm[count].type = BIOS_MAP_END; + return(bm); } - printf("%d Kb extended memory.\n", ram-1024); - extmem = ram - 1024; + return(NULL); +} + + +/* BIOS int 15, AX=E801 + * + * Only used if int 15, AX=E820 does not work. + * This should work for more than 64MB. + */ +struct BIOS_MAP * +bios_E801() +{ + static struct BIOS_MAP bm[3]; + int eax, edx = 0; + + /* Test for 0xE801 */ + __asm __volatile( + DOINT(0x15) "\n\t" + "setc %b0\n\t" + "movzbl %b0, %0\n\t" + : "=a" (eax) + : "a" (0xE801) + ); + + /* Make a memory map from info */ + if(!eax){ + printf("int 0x15 [E801], "); + + __asm __volatile( + DOINT(0x15) "\n\t" + : "=a" (eax), "=d" (edx) + : "a" (0xE801) + ); + + /* Make sure only valid bits */ + eax &= 0xFFFF; + edx &= 0xFFFF; + + /* Fill out BIOS map */ + bm[0].addr = (1024 * 1024); /* 1MB */ + bm[0].size = eax * 1024; + bm[0].type = BIOS_MAP_FREE; + + bm[1].addr = (1024 * 1024) * 16; /* 16MB */ + bm[1].size = (edx * 1024) * 64; + bm[1].type = BIOS_MAP_FREE; + + bm[2].type = BIOS_MAP_END; + + return(bm); + } + + return(NULL); +} + + +/* BIOS int 15, AX=8800 + * + * Only used if int 15, AX=E801 does not work. + * Machines with this are restricted to 64MB. + */ +struct BIOS_MAP * +bios_8800() +{ + static struct BIOS_MAP bm[2]; + int eax, mem; + + __asm __volatile( + DOINT(0x15) "\n\t" + "movl %%eax, %%ecx\n\t" + "setc %b0\n\t" + "movzbl %b0, %0\n\t" + : "=a" (eax), "=c" (mem) + : "a" (0x8800) + ); + + if(eax) return(NULL); + + printf("int 0x15 [8800], "); + + /* Fill out a BIOS_MAP */ + bm[0].addr = 1024*1024; /* 1MB */ + bm[0].size = (mem & 0xFFFF) * 1024; + bm[0].type = BIOS_MAP_FREE; + + bm[1].type = BIOS_MAP_END; + + return(bm); +} + + +/* BIOS int 0x12 Get Conventional Memory + * + * Only used if int 15, AX=E820 does not work. + */ +struct BIOS_MAP * +bios_int12() +{ + static struct BIOS_MAP bm[2]; + int mem; + + printf("int 0x12\n"); + + __asm __volatile(DOINT(0x12) : "=a" (mem) + :: "%ecx", "%edx", "cc"); + mem &= 0xffff; + + /* Fill out a BIOS_MAP */ + bm[0].addr = 0; + bm[0].size = mem * 1024; + bm[0].type = BIOS_MAP_FREE; + + bm[1].type = BIOS_MAP_END; + + return(bm); } + /* addrprobe(kloc): Probe memory at address kloc * 1024. * * This is a hack, but it seems to work ok. Maybe this is @@ -77,6 +235,8 @@ memprobe() * return values just written on non-existent memory... * * BTW: These machines are pretty broken IMHO. + * + * XXX - Does not detect aliased memory. */ static int addrprobe(kloc) @@ -122,3 +282,127 @@ addrprobe(kloc) } +/* Probe for all extended memory. + * + * This is only used as a last resort. If we resort to this + * routine, we are getting pretty desparate. Hopefully nobody + * has to rely on this after all the work above. + * + * XXX - Does not detect aliases memory. + * XXX - Could be destructive, as it does write. + */ +struct BIOS_MAP * +badprobe() +{ + static struct BIOS_MAP bm[2]; + int ram; + + printf("Physical, "); + /* probe extended memory + * + * There is no need to do this in assembly language. This is + * much easier to debug in C anyways. + */ + for(ram = 1024; ram < 512*1024; ram += 4) + if(addrprobe(ram)) + break; + + bm[0].addr = 1024 * 1024; + bm[0].size = (ram - 1024) * 1024; + bm[0].type = BIOS_MAP_FREE; + + bm[1].type = BIOS_MAP_END; + + return(bm); +} + + +int +count(map) + struct BIOS_MAP *map; +{ + int i; + + for(i = 0; map[i].type != BIOS_MAP_END; i++) ; + + return(i); +} + + +struct BIOS_MAP * +combine(a, b) + struct BIOS_MAP *a, *b; +{ + struct BIOS_MAP *res; + int size, i; + + /* Sanity checks */ + if(!b) return(a); + if(!a) return(b); + + size = (count(a) + count(b) + 1) * sizeof(struct BIOS_MAP); + res = alloc(size); + + /* Again */ + if(!res) return(NULL); /* We are in deep doggie-doo */ + + for(i = 0; a[i].type != BIOS_MAP_END; i++) + res[i] = a[i]; + size = count(a); + for(; b[i - size].type != BIOS_MAP_END; i++) + res[i] = b[i - size]; + + res[i].type = BIOS_MAP_END; + return(res); +} + + +void +memprobe() +{ + struct BIOS_MAP *tm, *em, *bm; /* total, extended, base */ + int count, total = 0; + + printf("Probing memory: "); + tm = em = bm = NULL; + + tm = bios_E820(); + if(!tm){ + em = bios_E801(); + if(!em) em = bios_8800(); + if(!em) em = badprobe(); + bm = bios_int12(); + + tm = combine(bm, em); + } + + /* Register in global var */ + memory_map = tm; + printf("mem0:"); + + /* Get total free memory */ + for(count = 0; tm[count].type != BIOS_MAP_END; count++) { + if(tm[count].type == BIOS_MAP_FREE) { + total += tm[count].size; + + printf(" %dKB", tm[count].size/1024); + } + } + printf("\n"); + + /* XXX - Compatibility, remove later */ + cnvmem = extmem = 0; + for(count = 0; tm[count].type != BIOS_MAP_END; count++) { + if((tm[count].addr < 0xFFFFF) && (tm[count].type == BIOS_MAP_FREE)){ + + cnvmem += tm[count].size; + } + if((tm[count].addr > 0xFFFFF) && (tm[count].type == BIOS_MAP_FREE)){ + + extmem += tm[count].size; + } + } + cnvmem /= 1024; + extmem /= 1024; +} + |