diff options
-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; +} + |