summaryrefslogtreecommitdiff
path: root/sys/arch/i386/stand
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/i386/stand')
-rw-r--r--sys/arch/i386/stand/README33
-rw-r--r--sys/arch/i386/stand/boot/conf.c4
-rw-r--r--sys/arch/i386/stand/libsa/Makefile5
-rw-r--r--sys/arch/i386/stand/libsa/biosdev.c75
-rw-r--r--sys/arch/i386/stand/libsa/biosdev.h6
-rw-r--r--sys/arch/i386/stand/libsa/cmd_i386.c105
-rw-r--r--sys/arch/i386/stand/libsa/gidt.S10
-rw-r--r--sys/arch/i386/stand/libsa/libsa.h5
-rw-r--r--sys/arch/i386/stand/libsa/machdep.c3
-rw-r--r--sys/arch/i386/stand/libsa/memprobe.c326
10 files changed, 510 insertions, 62 deletions
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;
+}
+