diff options
-rw-r--r-- | sys/amd64/amd64/bios.c | 275 | ||||
-rw-r--r-- | sys/amd64/amd64/machdep.c | 32 | ||||
-rw-r--r-- | sys/amd64/include/pc/bios.h | 88 | ||||
-rw-r--r-- | sys/amd64/include/segments.h | 12 | ||||
-rw-r--r-- | sys/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/i386/apm/apm.c | 522 | ||||
-rw-r--r-- | sys/i386/bios/apm.c | 522 | ||||
-rw-r--r-- | sys/i386/conf/files.i386 | 3 | ||||
-rw-r--r-- | sys/i386/i386/bios.c | 275 | ||||
-rw-r--r-- | sys/i386/i386/bioscall.s | 144 | ||||
-rw-r--r-- | sys/i386/i386/machdep.c | 32 | ||||
-rw-r--r-- | sys/i386/include/apm_bios.h | 24 | ||||
-rw-r--r-- | sys/i386/include/asnames.h | 3 | ||||
-rw-r--r-- | sys/i386/include/pc/bios.h | 88 | ||||
-rw-r--r-- | sys/i386/include/segments.h | 12 |
15 files changed, 1311 insertions, 724 deletions
diff --git a/sys/amd64/amd64/bios.c b/sys/amd64/amd64/bios.c index 5029db4..82afa3f 100644 --- a/sys/amd64/amd64/bios.c +++ b/sys/amd64/amd64/bios.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1997 Michael Smith + * Copyright (c) 1998 Jonathan Lemon * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bios.c,v 1.11 1998/07/15 03:58:57 bde Exp $ + * $Id: bios.c,v 1.12 1999/03/16 21:11:28 msmith Exp $ */ /* @@ -31,12 +32,17 @@ */ #include <sys/param.h> +#include <sys/proc.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <vm/vm.h> #include <vm/pmap.h> #include <machine/md_var.h> - +#include <machine/segments.h> +#include <machine/stdarg.h> +#include <machine/tss.h> +#include <machine/vmparam.h> #include <machine/pc/bios.h> #define BIOS_START 0xe0000 @@ -47,7 +53,7 @@ struct bios32_SDentry PCIbios = {entry : 0}; static struct SMBIOS_table *SMBIOStable = 0; static struct DMI_table *DMItable = 0; -static caddr_t bios32_SDCI = NULL; +static u_int bios32_SDCI = 0; static void bios32_init(void *junk); @@ -84,10 +90,10 @@ bios32_init(void *junk) } /* If checksum is OK, enable use of the entrypoint */ if ((ck == 0) && (sdh->entry < (BIOS_START + BIOS_SIZE))) { - bios32_SDCI = (caddr_t)BIOS_PADDRTOVADDR(sdh->entry); + bios32_SDCI = BIOS_PADDRTOVADDR(sdh->entry); if (bootverbose) { printf("Found BIOS32 Service Directory header at %p\n", sdh); - printf("Entry = 0x%x (%p) Rev = %d Len = %d\n", + printf("Entry = 0x%x (%x) Rev = %d Len = %d\n", sdh->entry, bios32_SDCI, sdh->revision, sdh->len); } /* See if there's a PCI BIOS entrypoint here */ @@ -168,23 +174,24 @@ bios32_init(void *junk) int bios32_SDlookup(struct bios32_SDentry *ent) { - struct bios32_args args; - - if (bios32_SDCI != NULL) { + struct bios_regs args; + + if (bios32_SDCI == 0) + return (1); args.eax = ent->ident.id; /* set up arguments */ args.ebx = args.ecx = args.edx = 0; - bios32(bios32_SDCI, &args); /* make the BIOS call */ + bios32(&args, bios32_SDCI, GSEL(GCODE_SEL, SEL_KPL)); if ((args.eax & 0xff) == 0) { /* success? */ - ent->base = args.ebx; - ent->len = args.ecx; - ent->entry = args.edx; - return(0); /* all OK */ + ent->base = args.ebx; + ent->len = args.ecx; + ent->entry = args.edx; + return (0); /* all OK */ } - } - return(1); /* failed */ + return (1); /* failed */ } + /* * bios_sigsearch * @@ -234,5 +241,239 @@ bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs return(0); } - - +/* + * do not staticize, used by bioscall.s + */ +union { + struct { + u_short offset; + u_short segment; + } vec16; + struct { + u_int offset; + u_short segment; + } vec32; +} bioscall_vector; /* bios jump vector */ + +void +set_bios_selectors(struct bios_segments *seg, int flags) +{ + static u_int curgen = 1; + struct soft_segment_descriptor ssd = { + 0, /* segment base address (overwritten) */ + 0, /* length (overwritten) */ + SDT_MEMERA, /* segment type (overwritten) */ + 0, /* priority level */ + 1, /* descriptor present */ + 0, 0, + 1, /* descriptor size (overwritten) */ + 0 /* granularity == byte units */ + }; + + if (seg->generation == curgen) + return; + if (++curgen == 0) + curgen = 1; + seg->generation = curgen; + + ssd.ssd_base = seg->code32.base; + ssd.ssd_limit = seg->code32.limit; + ssdtosd(&ssd, &gdt[GBIOSCODE32_SEL].sd); + + ssd.ssd_def32 = 0; + if (flags & BIOSCODE_FLAG) { + ssd.ssd_base = seg->code16.base; + ssd.ssd_limit = seg->code16.limit; + ssdtosd(&ssd, &gdt[GBIOSCODE16_SEL].sd); + } + + ssd.ssd_type = SDT_MEMRWA; + if (flags & BIOSDATA_FLAG) { + ssd.ssd_base = seg->data.base; + ssd.ssd_limit = seg->data.limit; + ssdtosd(&ssd, &gdt[GBIOSDATA_SEL].sd); + } + + if (flags & BIOSUTIL_FLAG) { + ssd.ssd_base = seg->util.base; + ssd.ssd_limit = seg->util.limit; + ssdtosd(&ssd, &gdt[GBIOSUTIL_SEL].sd); + } + + if (flags & BIOSARGS_FLAG) { + ssd.ssd_base = seg->args.base; + ssd.ssd_limit = seg->args.limit; + ssdtosd(&ssd, &gdt[GBIOSARGS_SEL].sd); + } +} + +/* + * for pointers, we don't know how much space is supposed to be allocated, + * so we assume a minimum size of 256 bytes. If more than this is needed, + * then this can be revisited, such as adding a length specifier. + */ +#define ASSUMED_ARGSIZE 256 + +extern int vm86pa; + +/* + * this routine is really greedy with selectors, and uses 5: + * + * 32-bit code selector: to return to kernel + * 16-bit code selector: for running code + * data selector: for 16-bit data + * util selector: extra utility selector + * args selector: to handle pointers + * + * the util selector is set from the util16 entry in bios16_args, if a + * "U" specifier is seen. + * + * See <machine/pc/bios.h> for description of format specifiers + */ +int +bios16(struct bios_args *args, char *fmt, ...) +{ + char *p, *stack, *stack_top; + va_list ap; + int flags = BIOSCODE_FLAG | BIOSDATA_FLAG; + u_int i, arg_start, arg_end; + u_int *pte, *ptd; + + arg_start = 0xffffffff; + arg_end = 0; + + stack = (caddr_t)PAGE_SIZE; + va_start(ap, fmt); + for (p = fmt; p && *p; p++) { + switch (*p) { + case 'p': /* 32-bit pointer */ + i = va_arg(ap, u_int); + arg_start = min(arg_start, i); + arg_end = max(arg_end, i + ASSUMED_ARGSIZE); + flags |= BIOSARGS_FLAG; + stack -= 4; + break; + + case 'i': /* 32-bit integer */ + i = va_arg(ap, u_int); + stack -= 4; + break; + + case 'U': /* 16-bit selector */ + flags |= BIOSUTIL_FLAG; + /* FALL THROUGH */ + case 'D': /* 16-bit selector */ + case 'C': /* 16-bit selector */ + case 's': /* 16-bit integer */ + i = va_arg(ap, u_short); + stack -= 2; + break; + + default: + return (EINVAL); + } + } + + if (flags & BIOSARGS_FLAG) { + if (arg_end - arg_start > ctob(16)) + return (EACCES); + args->seg.args.base = arg_start; + args->seg.args.limit = arg_end - arg_start; + } + + args->seg.code32.base = (u_int)&bios16_call & PG_FRAME; + args->seg.code32.limit = 0xffff; + + ptd = (u_int *)rcr3(); +#ifdef SMP + if (ptd == my_idlePTD) +#else + if (ptd == IdlePTD) +#endif + { + /* + * no page table, so create one and install it. + */ + pte = (u_int *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + ptd = (u_int *)((u_int)ptd + KERNBASE); + *ptd = vtophys(pte) | PG_RW | PG_V; + } else { + /* + * this is a user-level page table + */ + pte = (u_int *)&PTmap; + } + /* + * install pointer to page 0. we don't need to flush the tlb, + * since there should not be a previous mapping for page 0. + */ + *pte = (vm86pa - PAGE_SIZE) | PG_RW | PG_V; + + stack_top = stack; + va_start(ap, fmt); + for (p = fmt; p && *p; p++) { + switch (*p) { + case 'p': /* 32-bit pointer */ + i = va_arg(ap, u_int); + *(u_int *)stack = (i - arg_start) | + (GSEL(GBIOSARGS_SEL, SEL_KPL) << 16); + stack += 4; + break; + + case 'i': /* 32-bit integer */ + i = va_arg(ap, u_int); + *(u_int *)stack = i; + stack += 4; + break; + + case 'U': /* 16-bit selector */ + i = va_arg(ap, u_short); + *(u_short *)stack = GSEL(GBIOSUTIL_SEL, SEL_KPL); + stack += 2; + break; + + case 'D': /* 16-bit selector */ + i = va_arg(ap, u_short); + *(u_short *)stack = GSEL(GBIOSDATA_SEL, SEL_KPL); + stack += 2; + break; + + case 'C': /* 16-bit selector */ + i = va_arg(ap, u_short); + *(u_short *)stack = GSEL(GBIOSCODE16_SEL, SEL_KPL); + stack += 2; + break; + + case 's': /* 16-bit integer */ + i = va_arg(ap, u_short); + *(u_short *)stack = i; + stack += 2; + break; + + default: + return (EINVAL); + } + } + + args->seg.generation = 0; /* reload selectors */ + set_bios_selectors(&args->seg, flags); + bioscall_vector.vec16.offset = (u_short)args->entry; + bioscall_vector.vec16.segment = GSEL(GBIOSCODE16_SEL, SEL_KPL); + + i = bios16_call(&args->r, stack_top); + + if (pte == (u_int *)&PTmap) { + *pte = 0; /* remove entry */ + } else { + *ptd = 0; /* remove page table */ + free(pte, M_TEMP); /* ... and free it */ + } + + + /* + * XXX only needs to be invlpg(0) but that doesn't work on the 386 + */ + invltlb(); + + return (i); +} diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index a321bb2..c0dc2eb 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.355 1999/07/09 04:15:40 jlemon Exp $ + * $Id: machdep.c,v 1.356 1999/07/19 23:36:30 peter Exp $ */ #include "apm.h" @@ -1004,8 +1004,8 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, -/* GAPMCODE32_SEL 9 APM BIOS 32-bit interface (32bit Code) */ -{ 0, /* segment base address (overwritten by APM) */ +/* GBIOSCODE32_SEL 9 BIOS 32-bit interface (32bit Code) */ +{ 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ @@ -1013,8 +1013,8 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, -/* GAPMCODE16_SEL 10 APM BIOS 32-bit interface (16bit Code) */ -{ 0, /* segment base address (overwritten by APM) */ +/* GBIOSCODE16_SEL 10 BIOS 32-bit interface (16bit Code) */ +{ 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ @@ -1022,8 +1022,8 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, -/* GAPMDATA_SEL 11 APM BIOS 32-bit interface (Data) */ -{ 0, /* segment base address (overwritten by APM) */ +/* GBIOSDATA_SEL 11 BIOS 32-bit interface (Data) */ +{ 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ @@ -1031,6 +1031,24 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, +/* GBIOSUTIL_SEL 12 BIOS 16-bit interface (Utility) */ +{ 0, /* segment base address (overwritten) */ + 0xfffff, /* length */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 0, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, +/* GBIOSARGS_SEL 13 BIOS 16-bit interface (Arguments) */ +{ 0, /* segment base address (overwritten) */ + 0xfffff, /* length */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 0, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { diff --git a/sys/amd64/include/pc/bios.h b/sys/amd64/include/pc/bios.h index 4e47eae..0c88a4d 100644 --- a/sys/amd64/include/pc/bios.h +++ b/sys/amd64/include/pc/bios.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 1997 Michael Smith + * Copyright (c) 1998 Jonathan Lemon * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bios.h,v 1.1 1997/08/01 06:04:59 msmith Exp $ + * $Id: bios.h,v 1.2 1997/08/04 03:31:23 msmith Exp $ */ /* @@ -59,17 +60,6 @@ extern int bios32_SDlookup(struct bios32_SDentry *ent); extern u_int32_t bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs); -/* - * Call a 32-bit BIOS function - */ -struct bios32_args { - u_long eax; - u_long ebx; - u_long ecx; - u_long edx; -}; -extern void bios32(caddr_t func_addr, struct bios32_args *args); - #define BIOS_PADDRTOVADDR(x) (((x) - ISA_HOLE_START) + atdevbase) #define BIOS_VADDRTOPADDR(x) (((x) - atdevbase) + ISA_HOLE_START) @@ -108,5 +98,77 @@ extern struct bios32_SDentry PCIbios; extern struct SMBIOS_table *SMBIOS_table; extern struct DMI_table *DMI_table; +struct segment_info { + u_int base; + u_int limit; +}; + +#define BIOSCODE_FLAG 0x01 +#define BIOSDATA_FLAG 0x02 +#define BIOSUTIL_FLAG 0x04 +#define BIOSARGS_FLAG 0x08 + +struct bios_segments { + u_int generation; + struct segment_info code32; /* 32-bit code (mandatory) */ + struct segment_info code16; /* 16-bit code */ + struct segment_info data; /* 16-bit data */ + struct segment_info util; /* 16-bit utility */ + struct segment_info args; /* 16-bit args */ +}; + +struct bios_regs { + u_int eax; + u_int ebx; + u_int ecx; + u_int edx; + u_int esi; + u_int edi; +}; + +struct bios_args { + u_int entry; /* entry point of routine */ + struct bios_regs r; + struct bios_segments seg; +}; + +/* + * format specifiers and defines for bios16() + * s = short (16 bits) + * i = int (32 bits) + * p = pointer (converted to seg:offset) + * C,D,U = selector (corresponding to code/data/utility segment) + */ +#define PNP_COUNT_DEVNODES "sppD", 0x00 +#define PNP_GET_DEVNODE "sppsD", 0x01 +#define PNP_SET_DEVNODE "sppsD", 0x02 +#define PNP_GET_EVENT "spD", 0x03 +#define PNP_SEND_MSG "ssD", 0x04 +#define PNP_GET_DOCK_INFO "spD", 0x05 + +#define PNP_SEL_PRIBOOT "ssiiisspD", 0x07 +#define PNP_GET_PRIBOOT "sspppppD", 0x08 +#define PNP_SET_RESINFO "spD", 0x09 +#define PNP_GET_RESINFO "spD", 0x0A +#define PNP_GET_APM_ID "sppD", 0x0B + +#define PNP_GET_ISA_INFO "spD", 0x40 +#define PNP_GET_ECSD_INFO "spppD", 0x41 +#define PNP_READ_ESCD "spUD", 0x42 +#define PNP_WRITE_ESCD "spUD", 0x43 + +#define PNP_GET_DMI_INFO "spppppD", 0x50 +#define PNP_GET_DMI "sppUD", 0x51 + +#define PNP_BOOT_CHECK "sp", 0x60 +#define PNP_COUNT_IPL "sppp", 0x61 +#define PNP_GET_BOOTPRI "spp", 0x62 +#define PNP_SET_BOOTPRI "sp", 0x63 +#define PNP_GET_LASTBOOT "sp", 0x64 +#define PNP_GET_BOOTFIRST "sp", 0x65 +#define PNP_SET_BOOTFIRST "sp", 0x66 - +extern int bios16(struct bios_args *, char *, ...); +extern int bios16_call(struct bios_regs *, char *); +extern int bios32(struct bios_regs *, u_int, u_short); +extern void set_bios_selectors(struct bios_segments *, int); diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h index 7028185..14afa57 100644 --- a/sys/amd64/include/segments.h +++ b/sys/amd64/include/segments.h @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)segments.h 7.1 (Berkeley) 5/9/91 - * $Id: segments.h,v 1.19 1999/04/28 01:04:06 luoqi Exp $ + * $Id: segments.h,v 1.20 1999/06/18 14:32:21 bde Exp $ */ #ifndef _MACHINE_SEGMENTS_H_ @@ -215,14 +215,16 @@ struct region_descriptor { #define GUSERLDT_SEL 6 /* User LDT */ #define GTGATE_SEL 7 /* Process task switch gate */ #define GPANIC_SEL 8 /* Task state to consider panic from */ -#define GAPMCODE32_SEL 9 /* APM BIOS 32-bit interface (32bit Code) */ -#define GAPMCODE16_SEL 10 /* APM BIOS 32-bit interface (16bit Code) */ -#define GAPMDATA_SEL 11 /* APM BIOS 32-bit interface (Data) */ +#define GBIOSCODE32_SEL 9 /* BIOS interface (32bit Code) */ +#define GBIOSCODE16_SEL 10 /* BIOS interface (16bit Code) */ +#define GBIOSDATA_SEL 11 /* BIOS interface (Data) */ +#define GBIOSUTIL_SEL 12 /* BIOS interface (Utility) */ +#define GBIOSARGS_SEL 13 /* BIOS interface (Arguments) */ #ifdef BDE_DEBUGGER #define NGDT 18 /* some of 11-17 are reserved for debugger */ #else -#define NGDT 12 +#define NGDT 14 #endif /* diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index e613804..2e9b459 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.253 1999/07/03 19:19:34 peter Exp $ +# $Id: files.i386,v 1.254 1999/07/26 07:43:20 phk Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -107,7 +107,6 @@ gnu/i386/isa/dgb.c optional dgb gnu/i386/isa/dgm.c optional dgm gnu/i386/isa/sound/awe_wave.c optional awe i386/apm/apm.c optional apm -i386/apm/apm_setup.s optional apm i386/eisa/3c5x9.c optional ep i386/eisa/adv_eisa.c optional adv i386/eisa/ahb.c optional ahb diff --git a/sys/i386/apm/apm.c b/sys/i386/apm/apm.c index da06805..ae2d0ec 100644 --- a/sys/i386/apm/apm.c +++ b/sys/i386/apm/apm.c @@ -15,11 +15,10 @@ * * Sep, 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) * - * $Id: apm.c,v 1.92 1999/07/28 19:37:32 msmith Exp $ + * $Id: apm.c,v 1.93 1999/07/28 20:20:29 msmith Exp $ */ #include "opt_devfs.h" -#include "opt_smp.h" #include <sys/param.h> #include <sys/systm.h> @@ -45,28 +44,14 @@ #include <vm/pmap.h> #include <sys/syslog.h> -#include <machine/psl.h> +#include <machine/pc/bios.h> #include <machine/vm86.h> -#ifdef SMP -#include <machine/smp.h> -#endif - static int apm_display __P((int newstate)); -static int apm_int __P((u_long *eax, u_long *ebx, u_long *ecx, u_long *edx)); static void apm_resume __P((void)); - -extern int apm_bios_call __P((struct apm_bios_arg *)); /* in apm_setup.s */ +static int apm_bioscall(void); static u_long apm_version; -static u_long apm_cs_entry; -static u_short apm_cs32_base; -static u_short apm_cs16_base; -static u_short apm_ds_base; -static u_short apm_cs32_limit; -static u_short apm_cs16_limit; -static u_short apm_ds_limit; -static u_short apm_flags; #define APM_NEVENTS 16 #define APM_NPMEV 13 @@ -75,14 +60,12 @@ int apm_evindex; /* static data */ struct apm_softc { - int initialized, active; + int initialized, active, bios_busy; int always_halt_cpu, slow_idle_cpu; int disabled, disengaged; u_int minorversion, majorversion; - u_int cs32_base, cs16_base, ds_base; - u_int cs16_limit, cs32_limit, ds_limit; - u_int cs_entry; - u_int intversion; + u_int intversion, connectmode; + struct bios_args bios; struct apmhook sc_suspend; struct apmhook sc_resume; struct selinfo sc_rsel; @@ -144,148 +127,104 @@ static struct cdevsw apm_cdevsw = { /* bmaj */ -1 }; -/* setup APM GDT discriptors */ -static void -setup_apm_gdt(u_int code32_base, u_int code16_base, u_int data_base, u_int code32_limit, u_int code16_limit, u_int data_limit) -{ -#ifdef SMP - int x; -#endif - - /* setup 32bit code segment */ - gdt_segs[GAPMCODE32_SEL].ssd_base = code32_base; - gdt_segs[GAPMCODE32_SEL].ssd_limit = code32_limit; - - /* setup 16bit code segment */ - gdt_segs[GAPMCODE16_SEL].ssd_base = code16_base; - gdt_segs[GAPMCODE16_SEL].ssd_limit = code16_limit; - - /* setup data segment */ - gdt_segs[GAPMDATA_SEL ].ssd_base = data_base; - gdt_segs[GAPMDATA_SEL ].ssd_limit = data_limit; - - /* reflect these changes on physical GDT */ - ssdtosd(gdt_segs + GAPMCODE32_SEL, &gdt[GAPMCODE32_SEL].sd); - ssdtosd(gdt_segs + GAPMCODE16_SEL, &gdt[GAPMCODE16_SEL].sd); - ssdtosd(gdt_segs + GAPMDATA_SEL , &gdt[GAPMDATA_SEL ].sd); - -#ifdef SMP - for (x = 1; x < NCPU; x++) { - gdt[x * NGDT + GAPMCODE32_SEL].sd = gdt[GAPMCODE32_SEL].sd; - gdt[x * NGDT + GAPMCODE16_SEL].sd = gdt[GAPMCODE16_SEL].sd; - gdt[x * NGDT + GAPMDATA_SEL ].sd = gdt[GAPMDATA_SEL ].sd; - } -#endif -} - -/* 48bit far pointer. Do not staticize - used from apm_setup.s */ -struct addr48 { - u_long offset; - u_short segment; -} apm_addr; - -static int apm_errno; - static int -apm_int(u_long *eax, u_long *ebx, u_long *ecx, u_long *edx) +apm_bioscall(void) { - struct apm_bios_arg apa; - int cf; - - apa.eax = *eax; - apa.ebx = *ebx; - apa.ecx = *ecx; - apa.edx = *edx; - cf = apm_bios_call(&apa); - *eax = apa.eax; - *ebx = apa.ebx; - *ecx = apa.ecx; - *edx = apa.edx; - apm_errno = ((*eax) >> 8) & 0xff; - return cf; + struct apm_softc *sc = &apm_softc; + int errno = 0; + + sc->bios_busy = 1; + if (sc->connectmode == APM_PROT32CONNECT) { + set_bios_selectors(&sc->bios.seg, + BIOSCODE_FLAG | BIOSDATA_FLAG); + errno = bios32(&sc->bios.r, + sc->bios.entry, GSEL(GBIOSCODE32_SEL, SEL_KPL)); + } else { + errno = bios16(&sc->bios, NULL); + } + sc->bios_busy = 0; + return (errno); } - /* enable/disable power management */ static int apm_enable_disable_pm(int enable) { struct apm_softc *sc = &apm_softc; - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_ENABLEDISABLEPM; + sc->bios.r.eax = (APM_BIOS << 8) | APM_ENABLEDISABLEPM; if (sc->intversion >= INTVERSION(1, 1)) - ebx = PMDV_ALLDEV; + sc->bios.r.ebx = PMDV_ALLDEV; else - ebx = 0xffff; /* APM version 1.0 only */ - ecx = enable; - edx = 0; - return apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.ebx = 0xffff; /* APM version 1.0 only */ + sc->bios.r.ecx = enable; + sc->bios.r.edx = 0; + return (apm_bioscall()); } -static void +/* register driver version (APM 1.1 or later) */ +static int apm_driver_version(int version) { - u_long eax, ebx, ecx, edx; - - /* First try APM 1.2 */ - eax = (APM_BIOS << 8) | APM_DRVVERSION; - ebx = 0x0; - ecx = version; - edx = 0; - if(!apm_int(&eax, &ebx, &ecx, &edx)) - apm_version = eax & 0xffff; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_DRVVERSION; + sc->bios.r.ebx = 0x0; + sc->bios.r.ecx = version; + sc->bios.r.edx = 0; + + if (apm_bioscall() == 0 && sc->bios.r.eax == version) + return (0); + return (1); } - + /* engage/disengage power management (APM 1.1 or later) */ static int apm_engage_disengage_pm(int engage) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_ENGAGEDISENGAGEPM; - ebx = PMDV_ALLDEV; - ecx = engage; - edx = 0; - return(apm_int(&eax, &ebx, &ecx, &edx)); + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_ENGAGEDISENGAGEPM; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = engage; + sc->bios.r.edx = 0; + return (apm_bioscall()); } - + /* get PM event */ static u_int apm_getevent(void) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_GETPMEVENT; - - ebx = 0; - ecx = 0; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) - return PMEV_NOEVENT; - - return ebx & 0xffff; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPMEVENT; + + sc->bios.r.ebx = 0; + sc->bios.r.ecx = 0; + sc->bios.r.edx = 0; + if (apm_bioscall()) + return (PMEV_NOEVENT); + return (sc->bios.r.ebx & 0xffff); } - + /* suspend entire system */ static int apm_suspend_system(int state) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = state; - edx = 0; - - if (apm_int(&eax, &ebx, &ecx, &edx)) { - printf("Entire system suspend failure: errcode = %ld\n", - 0xff & (eax >> 8)); - return 1; - } - return 0; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = state; + sc->bios.r.edx = 0; + + if (apm_bioscall()) { + printf("Entire system suspend failure: errcode = %d\n", + 0xff & (sc->bios.r.eax >> 8)); + return 1; + } + return 0; } /* Display control */ @@ -297,18 +236,18 @@ apm_suspend_system(int state) static int apm_display(int newstate) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_DISP0; - ecx = newstate ? PMST_APMENABLED:PMST_SUSPEND; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { - printf("Display off failure: errcode = %ld\n", - 0xff & (eax >> 8)); - return 1; - } - return 0; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_DISP0; + sc->bios.r.ecx = newstate ? PMST_APMENABLED:PMST_SUSPEND; + sc->bios.r.edx = 0; + if (apm_bioscall()) { + printf("Display off failure: errcode = %d\n", + 0xff & (sc->bios.r.eax >> 8)); + return 1; + } + return 0; } /* @@ -317,16 +256,16 @@ apm_display(int newstate) static void apm_power_off(int howto, void *junk) { - u_long eax, ebx, ecx, edx; + struct apm_softc *sc = &apm_softc; /* Not halting powering off, or not active */ if (!(howto & RB_POWEROFF) || !apm_softc.active) return; - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = PMST_OFF; - edx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = PMST_OFF; + sc->bios.r.edx = 0; + (void) apm_bioscall(); } /* APM Battery low handler */ @@ -495,39 +434,36 @@ static u_int apm_op_inprog = 0; static void apm_lastreq_notify(void) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = PMST_LASTREQNOTIFY; - edx = 0; + struct apm_softc *sc = &apm_softc; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = PMST_LASTREQNOTIFY; + sc->bios.r.edx = 0; + apm_bioscall(); } static int apm_lastreq_rejected(void) { - u_long eax, ebx, ecx, edx; + struct apm_softc *sc = &apm_softc; if (apm_op_inprog == 0) { return 1; /* no operation in progress */ } - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = PMST_LASTREQREJECT; - edx = 0; + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = PMST_LASTREQREJECT; + sc->bios.r.edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { + if (apm_bioscall()) { #ifdef APM_DEBUG printf("apm_lastreq_rejected: failed\n"); #endif return 1; } - apm_op_inprog = 0; - return 0; } @@ -587,41 +523,40 @@ static int apm_get_info(apm_info_t aip) { struct apm_softc *sc = &apm_softc; - u_long eax, ebx, ecx, edx; - eax = (APM_BIOS << 8) | APM_GETPWSTATUS; - ebx = PMDV_ALLDEV; - ecx = 0; - edx = 0xffff; /* default to unknown battery time */ + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPWSTATUS; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = 0; + sc->bios.r.edx = 0xffff; /* default to unknown battery time */ - if (apm_int(&eax, &ebx, &ecx, &edx)) + if (apm_bioscall()) return 1; aip->ai_infoversion = 1; - aip->ai_acline = (ebx >> 8) & 0xff; - aip->ai_batt_stat = ebx & 0xff; - aip->ai_batt_life = ecx & 0xff; + aip->ai_acline = (sc->bios.r.ebx >> 8) & 0xff; + aip->ai_batt_stat = sc->bios.r.ebx & 0xff; + aip->ai_batt_life = sc->bios.r.ecx & 0xff; aip->ai_major = (u_int)sc->majorversion; aip->ai_minor = (u_int)sc->minorversion; aip->ai_status = (u_int)sc->active; - edx &= 0xffff; - if (edx == 0xffff) /* Time is unknown */ + sc->bios.r.edx &= 0xffff; + if (sc->bios.r.edx == 0xffff) /* Time is unknown */ aip->ai_batt_time = -1; - else if (edx & 0x8000) /* Time is in minutes */ - aip->ai_batt_time = (edx & 0x7fff) * 60; + else if (sc->bios.r.edx & 0x8000) /* Time is in minutes */ + aip->ai_batt_time = (sc->bios.r.edx & 0x7fff) * 60; else /* Time is in seconds */ - aip->ai_batt_time = edx; + aip->ai_batt_time = sc->bios.r.edx; - eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; - ebx = 0; - ecx = 0; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; + sc->bios.r.ebx = 0; + sc->bios.r.ecx = 0; + sc->bios.r.edx = 0; + if (apm_bioscall()) { aip->ai_batteries = -1; /* Unknown */ aip->ai_capabilities = 0xff00; /* Unknown, with no bits set */ } else { - aip->ai_batteries = ebx & 0xff; - aip->ai_capabilities = ecx & 0xf; + aip->ai_batteries = sc->bios.r.ebx & 0xff; + aip->ai_capabilities = sc->bios.r.ecx & 0xf; } bzero(aip->ai_spare, sizeof aip->ai_spare); @@ -637,11 +572,10 @@ apm_cpu_idle(void) struct apm_softc *sc = &apm_softc; if (sc->active) { - u_long eax, ebx, ecx, edx; - eax = (APM_BIOS <<8) | APM_CPUIDLE; - edx = ecx = ebx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS <<8) | APM_CPUIDLE; + sc->bios.r.edx = sc->bios.r.ecx = sc->bios.r.ebx = 0; + (void) apm_bioscall(); } /* * Some APM implementation halts CPU in BIOS, whenever @@ -669,11 +603,10 @@ apm_cpu_busy(void) * necessary. */ if (sc->slow_idle_cpu && sc->active) { - u_long eax, ebx, ecx, edx; - eax = (APM_BIOS <<8) | APM_CPUBUSY; - edx = ecx = ebx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS <<8) | APM_CPUBUSY; + sc->bios.r.edx = sc->bios.r.ecx = sc->bios.r.ebx = 0; + apm_bioscall(); } } @@ -692,7 +625,8 @@ apm_timeout(void *dummy) if (apm_op_inprog) apm_lastreq_notify(); - apm_processevent(); + if (!sc->bios_busy) + apm_processevent(); if (sc->active == 1) /* Run slightly more oftan than 1 Hz */ @@ -752,14 +686,14 @@ apm_not_halt_cpu(void) /* device driver definitions */ /* - * probe APM + * probe for APM BIOS */ - static int apm_probe(device_t dev) { +#define APM_KERNBASE KERNBASE struct vm86frame vmf; - int i; + struct apm_softc *sc = &apm_softc; int disabled, flags; if (resource_int_value("apm", 0, "disabled", &disabled) == 0 @@ -777,69 +711,72 @@ apm_probe(device_t dev) flags = 0; bzero(&vmf, sizeof(struct vm86frame)); /* safety */ - vmf.vmf_ax = (APM_BIOS << 8) | APM_INSTCHECK; + bzero(&apm_softc, sizeof(apm_softc)); + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_INSTCHECK; vmf.vmf_bx = 0; - if (((i = vm86_intcall(SYSTEM_BIOS, &vmf)) == 0) && - !(vmf.vmf_eflags & PSL_C) && - (vmf.vmf_bx == 0x504d)) { + if (vm86_intcall(APM_INT, &vmf)) + return ENXIO; /* APM not found */ + if (vmf.vmf_bx != 0x504d) { + printf("apm: incorrect signature (0x%x)\n", vmf.vmf_bx); + return ENXIO; + } + if ((vmf.vmf_cx & (APM_32BIT_SUPPORT | APM_16BIT_SUPPORT)) == 0) { + printf("apm: protected mode connections are not supported\n"); + return ENXIO; + } + + apm_version = vmf.vmf_ax; + sc->slow_idle_cpu = ((vmf.vmf_cx & APM_CPUIDLE_SLOW) != 0); + sc->disabled = ((vmf.vmf_cx & APM_DISABLED) != 0); + sc->disengaged = ((vmf.vmf_cx & APM_DISENGAGED) != 0); - apm_version = vmf.vmf_ax; - apm_flags = vmf.vmf_cx; + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_DISCONNECT; + vmf.vmf_bx = 0; + vm86_intcall(APM_INT, &vmf); /* disconnect, just in case */ - vmf.vmf_ax = (APM_BIOS << 8) | APM_PROT32CONNECT; + if ((vmf.vmf_cx & APM_32BIT_SUPPORT) != 0) { + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_PROT32CONNECT; vmf.vmf_bx = 0; - if (((i = vm86_intcall(SYSTEM_BIOS, &vmf)) == 0) && - !(vmf.vmf_eflags & PSL_C)) { - - apm_cs32_base = vmf.vmf_ax; - apm_cs_entry = vmf.vmf_ebx; - apm_cs16_base = vmf.vmf_cx; - apm_ds_base = vmf.vmf_dx; - apm_cs32_limit = vmf.vmf_si; - if (apm_version >= 0x0102) - apm_cs16_limit = (vmf.esi.r_ex >> 16); - apm_ds_limit = vmf.vmf_di; -#ifdef APM_DEBUG - printf("apm: BIOS probe/32-bit connect successful\n"); -#endif - } else { - /* XXX constant typo! */ - if (vmf.vmf_ah == APME_PROT32NOTDUPPORTED) { - apm_version = APMINI_NOT32BIT; - } else { - apm_version = APMINI_CONNECTERR; - } -#ifdef APM_DEBUG - printf("apm: BIOS 32-bit connect failed: error 0x%x carry %d ah 0x%x\n", - i, (vmf.vmf_eflags & PSL_C) ? 1 : 0, vmf.vmf_ah); -#endif + if (vm86_intcall(APM_INT, &vmf)) { + printf("apm: 32-bit connection error.\n"); + return (ENXIO); + } + sc->bios.seg.code32.base = (vmf.vmf_ax << 4) + APM_KERNBASE; + sc->bios.seg.code32.limit = 0xffff; + sc->bios.seg.code16.base = (vmf.vmf_cx << 4) + APM_KERNBASE; + sc->bios.seg.code16.limit = vmf.vmf_si; + sc->bios.seg.data.base = (vmf.vmf_dx << 4) + APM_KERNBASE; + sc->bios.seg.data.limit = vmf.vmf_di; + sc->bios.entry = vmf.vmf_ebx; + sc->connectmode = APM_PROT32CONNECT; + } else { + /* use 16-bit connection */ + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_PROT16CONNECT; + vmf.vmf_bx = 0; + if (vm86_intcall(APM_INT, &vmf)) { + printf("apm: 16-bit connection error.\n"); + return (ENXIO); } - } else { - apm_version = APMINI_CANTFIND; -#ifdef APM_DEBUG - printf("apm: BIOS probe failed: error 0x%x carry %d bx 0x%x\n", - i, (vmf.vmf_eflags & PSL_C) ? 1 : 0, vmf.vmf_bx); -#endif + sc->bios.seg.code16.base = (vmf.vmf_ax << 4) + APM_KERNBASE; + sc->bios.seg.code16.limit = vmf.vmf_si; + sc->bios.seg.data.base = (vmf.vmf_cx << 4) + APM_KERNBASE; + sc->bios.seg.data.limit = vmf.vmf_di; + sc->bios.entry = vmf.vmf_bx; + sc->connectmode = APM_PROT16CONNECT; } - - bzero(&apm_softc, sizeof(apm_softc)); - - switch (apm_version) { - case APMINI_CANTFIND: - /* silent */ - return ENXIO; - case APMINI_NOT32BIT: - printf("apm: 32bit connection is not supported.\n"); - return ENXIO; - case APMINI_CONNECTERR: - printf("apm: 32-bit connection error.\n"); - return ENXIO; + if (apm_version == 0x100) { + /* APM v1.0 does not set SI/DI */ + sc->bios.seg.code16.limit = 0xffff; + sc->bios.seg.data.limit = 0xffff; } - if (flags & 0x20) - statclock_disable = 1; - return 0; + return(0); } + /* * return 0 if the user will notice and handle the event, * return 1 if the kernel driver should do so. @@ -953,62 +890,40 @@ apm_processevent(void) static int apm_attach(device_t dev) { -#define APM_KERNBASE KERNBASE struct apm_softc *sc = &apm_softc; int flags; + int drv_version; if (resource_int_value("apm", 0, "flags", &flags) != 0) flags = 0; + if (flags & 0x20) + statclock_disable = 1; + sc->initialized = 0; /* Must be externally enabled */ sc->active = 0; - /* setup APM parameters */ - sc->cs16_base = (apm_cs16_base << 4) + APM_KERNBASE; - sc->cs32_base = (apm_cs32_base << 4) + APM_KERNBASE; - sc->ds_base = (apm_ds_base << 4) + APM_KERNBASE; - sc->cs32_limit = apm_cs32_limit - 1; - if (apm_cs16_limit == 0) - apm_cs16_limit = apm_cs32_limit; - sc->cs16_limit = apm_cs16_limit - 1; - sc->ds_limit = apm_ds_limit - 1; - sc->cs_entry = apm_cs_entry; - /* Always call HLT in idle loop */ sc->always_halt_cpu = 1; - sc->slow_idle_cpu = ((apm_flags & APM_CPUIDLE_SLOW) != 0); - sc->disabled = ((apm_flags & APM_DISABLED) != 0); - sc->disengaged = ((apm_flags & APM_DISENGAGED) != 0); - /* print bootstrap messages */ #ifdef APM_DEBUG printf("apm: APM BIOS version %04x\n", apm_version); - printf("apm: Code32 0x%08x, Code16 0x%08x, Data 0x%08x\n", - sc->cs32_base, sc->cs16_base, sc->ds_base); + printf("apm: Code16 0x%08x, Data 0x%08x\n", + sc->bios.seg.code16.base, sc->bios.seg.data.base); printf("apm: Code entry 0x%08x, Idling CPU %s, Management %s\n", - sc->cs_entry, is_enabled(sc->slow_idle_cpu), - is_enabled(!sc->disabled)); - printf("apm: CS32_limit=0x%x, CS16_limit=0x%x, DS_limit=0x%x\n", - (u_short)sc->cs32_limit, (u_short)sc->cs16_limit, (u_short)sc->ds_limit); + sc->bios.entry, is_enabled(sc->slow_idle_cpu), + is_enabled(!sc->disabled)); + printf("apm: CS_limit=0x%x, DS_limit=0x%x\n", + sc->bios.seg.code16.limit, sc->bios.seg.data.limit); #endif /* APM_DEBUG */ #if 0 - /* Workaround for some buggy APM BIOS implementations */ - sc->cs_limit = 0xffff; - sc->ds_limit = 0xffff; -#endif - - /* setup GDT */ - setup_apm_gdt(sc->cs32_base, sc->cs16_base, sc->ds_base, - sc->cs32_limit, sc->cs16_limit, sc->ds_limit); - - /* setup entry point 48bit pointer */ - apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL); - apm_addr.offset = sc->cs_entry; - + /* + * XXX this may not be needed anymore + */ if ((flags & 0x10)) { if ((flags & 0xf) >= 0x2) { apm_driver_version(0x102); @@ -1021,13 +936,20 @@ apm_attach(device_t dev) if (!apm_version) apm_driver_version(0x101); } - if (!apm_version) - apm_version = 0x100; - - sc->minorversion = ((apm_version & 0x00f0) >> 4) * 10 + - ((apm_version & 0x000f) >> 0); - sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 + - ((apm_version & 0x0f00) >> 8); +#endif + /* + * In one test, apm bios version was 1.02; an attempt to register + * a 1.04 driver resulted in a 1.00 connection! Registering a + * 1.02 driver resulted in a 1.02 connection. + */ + drv_version = apm_version > 0x102 ? 0x102 : apm_version; + for (; drv_version > 0x100; drv_version--) + if (apm_driver_version(drv_version) == 0) + break; + sc->minorversion = ((drv_version & 0x00f0) >> 4) * 10 + + ((drv_version & 0x000f) >> 0); + sc->majorversion = ((drv_version & 0xf000) >> 12) * 10 + + ((apm_version & 0x0f00) >> 8); sc->intversion = INTVERSION(sc->majorversion, sc->minorversion); @@ -1036,8 +958,10 @@ apm_attach(device_t dev) printf("apm: Engaged control %s\n", is_enabled(!sc->disengaged)); #endif - printf("apm: found APM BIOS version %d.%d\n", - sc->majorversion, sc->minorversion); + printf("apm: found APM BIOS v%ld.%ld, connected at v%d.%d\n", + ((apm_version & 0xf000) >> 12) * 10 + ((apm_version & 0x0f00) >> 8), + ((apm_version & 0x00f0) >> 4) * 10 + ((apm_version & 0x000f) >> 0), + sc->majorversion, sc->minorversion); #ifdef APM_DEBUG printf("apm: Slow Idling CPU %s\n", is_enabled(sc->slow_idle_cpu)); @@ -1079,8 +1003,6 @@ apm_attach(device_t dev) apm_hook_establish(APM_HOOK_SUSPEND, &sc->sc_suspend); apm_hook_establish(APM_HOOK_RESUME , &sc->sc_resume); - apm_event_enable(); - /* Power the system off using APM */ at_shutdown_pri(apm_power_off, NULL, SHUTDOWN_FINAL, SHUTDOWN_PRI_LAST); @@ -1208,10 +1130,12 @@ apmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) if (apm_display(newstate)) error = ENXIO; break; +#if 0 case APMIO_BIOS: if (apm_bios_call((struct apm_bios_arg*)addr) == 0) ((struct apm_bios_arg*)addr)->eax &= 0xff; break; +#endif default: error = EINVAL; break; diff --git a/sys/i386/bios/apm.c b/sys/i386/bios/apm.c index da06805..ae2d0ec 100644 --- a/sys/i386/bios/apm.c +++ b/sys/i386/bios/apm.c @@ -15,11 +15,10 @@ * * Sep, 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) * - * $Id: apm.c,v 1.92 1999/07/28 19:37:32 msmith Exp $ + * $Id: apm.c,v 1.93 1999/07/28 20:20:29 msmith Exp $ */ #include "opt_devfs.h" -#include "opt_smp.h" #include <sys/param.h> #include <sys/systm.h> @@ -45,28 +44,14 @@ #include <vm/pmap.h> #include <sys/syslog.h> -#include <machine/psl.h> +#include <machine/pc/bios.h> #include <machine/vm86.h> -#ifdef SMP -#include <machine/smp.h> -#endif - static int apm_display __P((int newstate)); -static int apm_int __P((u_long *eax, u_long *ebx, u_long *ecx, u_long *edx)); static void apm_resume __P((void)); - -extern int apm_bios_call __P((struct apm_bios_arg *)); /* in apm_setup.s */ +static int apm_bioscall(void); static u_long apm_version; -static u_long apm_cs_entry; -static u_short apm_cs32_base; -static u_short apm_cs16_base; -static u_short apm_ds_base; -static u_short apm_cs32_limit; -static u_short apm_cs16_limit; -static u_short apm_ds_limit; -static u_short apm_flags; #define APM_NEVENTS 16 #define APM_NPMEV 13 @@ -75,14 +60,12 @@ int apm_evindex; /* static data */ struct apm_softc { - int initialized, active; + int initialized, active, bios_busy; int always_halt_cpu, slow_idle_cpu; int disabled, disengaged; u_int minorversion, majorversion; - u_int cs32_base, cs16_base, ds_base; - u_int cs16_limit, cs32_limit, ds_limit; - u_int cs_entry; - u_int intversion; + u_int intversion, connectmode; + struct bios_args bios; struct apmhook sc_suspend; struct apmhook sc_resume; struct selinfo sc_rsel; @@ -144,148 +127,104 @@ static struct cdevsw apm_cdevsw = { /* bmaj */ -1 }; -/* setup APM GDT discriptors */ -static void -setup_apm_gdt(u_int code32_base, u_int code16_base, u_int data_base, u_int code32_limit, u_int code16_limit, u_int data_limit) -{ -#ifdef SMP - int x; -#endif - - /* setup 32bit code segment */ - gdt_segs[GAPMCODE32_SEL].ssd_base = code32_base; - gdt_segs[GAPMCODE32_SEL].ssd_limit = code32_limit; - - /* setup 16bit code segment */ - gdt_segs[GAPMCODE16_SEL].ssd_base = code16_base; - gdt_segs[GAPMCODE16_SEL].ssd_limit = code16_limit; - - /* setup data segment */ - gdt_segs[GAPMDATA_SEL ].ssd_base = data_base; - gdt_segs[GAPMDATA_SEL ].ssd_limit = data_limit; - - /* reflect these changes on physical GDT */ - ssdtosd(gdt_segs + GAPMCODE32_SEL, &gdt[GAPMCODE32_SEL].sd); - ssdtosd(gdt_segs + GAPMCODE16_SEL, &gdt[GAPMCODE16_SEL].sd); - ssdtosd(gdt_segs + GAPMDATA_SEL , &gdt[GAPMDATA_SEL ].sd); - -#ifdef SMP - for (x = 1; x < NCPU; x++) { - gdt[x * NGDT + GAPMCODE32_SEL].sd = gdt[GAPMCODE32_SEL].sd; - gdt[x * NGDT + GAPMCODE16_SEL].sd = gdt[GAPMCODE16_SEL].sd; - gdt[x * NGDT + GAPMDATA_SEL ].sd = gdt[GAPMDATA_SEL ].sd; - } -#endif -} - -/* 48bit far pointer. Do not staticize - used from apm_setup.s */ -struct addr48 { - u_long offset; - u_short segment; -} apm_addr; - -static int apm_errno; - static int -apm_int(u_long *eax, u_long *ebx, u_long *ecx, u_long *edx) +apm_bioscall(void) { - struct apm_bios_arg apa; - int cf; - - apa.eax = *eax; - apa.ebx = *ebx; - apa.ecx = *ecx; - apa.edx = *edx; - cf = apm_bios_call(&apa); - *eax = apa.eax; - *ebx = apa.ebx; - *ecx = apa.ecx; - *edx = apa.edx; - apm_errno = ((*eax) >> 8) & 0xff; - return cf; + struct apm_softc *sc = &apm_softc; + int errno = 0; + + sc->bios_busy = 1; + if (sc->connectmode == APM_PROT32CONNECT) { + set_bios_selectors(&sc->bios.seg, + BIOSCODE_FLAG | BIOSDATA_FLAG); + errno = bios32(&sc->bios.r, + sc->bios.entry, GSEL(GBIOSCODE32_SEL, SEL_KPL)); + } else { + errno = bios16(&sc->bios, NULL); + } + sc->bios_busy = 0; + return (errno); } - /* enable/disable power management */ static int apm_enable_disable_pm(int enable) { struct apm_softc *sc = &apm_softc; - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_ENABLEDISABLEPM; + sc->bios.r.eax = (APM_BIOS << 8) | APM_ENABLEDISABLEPM; if (sc->intversion >= INTVERSION(1, 1)) - ebx = PMDV_ALLDEV; + sc->bios.r.ebx = PMDV_ALLDEV; else - ebx = 0xffff; /* APM version 1.0 only */ - ecx = enable; - edx = 0; - return apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.ebx = 0xffff; /* APM version 1.0 only */ + sc->bios.r.ecx = enable; + sc->bios.r.edx = 0; + return (apm_bioscall()); } -static void +/* register driver version (APM 1.1 or later) */ +static int apm_driver_version(int version) { - u_long eax, ebx, ecx, edx; - - /* First try APM 1.2 */ - eax = (APM_BIOS << 8) | APM_DRVVERSION; - ebx = 0x0; - ecx = version; - edx = 0; - if(!apm_int(&eax, &ebx, &ecx, &edx)) - apm_version = eax & 0xffff; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_DRVVERSION; + sc->bios.r.ebx = 0x0; + sc->bios.r.ecx = version; + sc->bios.r.edx = 0; + + if (apm_bioscall() == 0 && sc->bios.r.eax == version) + return (0); + return (1); } - + /* engage/disengage power management (APM 1.1 or later) */ static int apm_engage_disengage_pm(int engage) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_ENGAGEDISENGAGEPM; - ebx = PMDV_ALLDEV; - ecx = engage; - edx = 0; - return(apm_int(&eax, &ebx, &ecx, &edx)); + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_ENGAGEDISENGAGEPM; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = engage; + sc->bios.r.edx = 0; + return (apm_bioscall()); } - + /* get PM event */ static u_int apm_getevent(void) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_GETPMEVENT; - - ebx = 0; - ecx = 0; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) - return PMEV_NOEVENT; - - return ebx & 0xffff; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPMEVENT; + + sc->bios.r.ebx = 0; + sc->bios.r.ecx = 0; + sc->bios.r.edx = 0; + if (apm_bioscall()) + return (PMEV_NOEVENT); + return (sc->bios.r.ebx & 0xffff); } - + /* suspend entire system */ static int apm_suspend_system(int state) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = state; - edx = 0; - - if (apm_int(&eax, &ebx, &ecx, &edx)) { - printf("Entire system suspend failure: errcode = %ld\n", - 0xff & (eax >> 8)); - return 1; - } - return 0; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = state; + sc->bios.r.edx = 0; + + if (apm_bioscall()) { + printf("Entire system suspend failure: errcode = %d\n", + 0xff & (sc->bios.r.eax >> 8)); + return 1; + } + return 0; } /* Display control */ @@ -297,18 +236,18 @@ apm_suspend_system(int state) static int apm_display(int newstate) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_DISP0; - ecx = newstate ? PMST_APMENABLED:PMST_SUSPEND; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { - printf("Display off failure: errcode = %ld\n", - 0xff & (eax >> 8)); - return 1; - } - return 0; + struct apm_softc *sc = &apm_softc; + + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_DISP0; + sc->bios.r.ecx = newstate ? PMST_APMENABLED:PMST_SUSPEND; + sc->bios.r.edx = 0; + if (apm_bioscall()) { + printf("Display off failure: errcode = %d\n", + 0xff & (sc->bios.r.eax >> 8)); + return 1; + } + return 0; } /* @@ -317,16 +256,16 @@ apm_display(int newstate) static void apm_power_off(int howto, void *junk) { - u_long eax, ebx, ecx, edx; + struct apm_softc *sc = &apm_softc; /* Not halting powering off, or not active */ if (!(howto & RB_POWEROFF) || !apm_softc.active) return; - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = PMST_OFF; - edx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = PMST_OFF; + sc->bios.r.edx = 0; + (void) apm_bioscall(); } /* APM Battery low handler */ @@ -495,39 +434,36 @@ static u_int apm_op_inprog = 0; static void apm_lastreq_notify(void) { - u_long eax, ebx, ecx, edx; - - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = PMST_LASTREQNOTIFY; - edx = 0; + struct apm_softc *sc = &apm_softc; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = PMST_LASTREQNOTIFY; + sc->bios.r.edx = 0; + apm_bioscall(); } static int apm_lastreq_rejected(void) { - u_long eax, ebx, ecx, edx; + struct apm_softc *sc = &apm_softc; if (apm_op_inprog == 0) { return 1; /* no operation in progress */ } - eax = (APM_BIOS << 8) | APM_SETPWSTATE; - ebx = PMDV_ALLDEV; - ecx = PMST_LASTREQREJECT; - edx = 0; + sc->bios.r.eax = (APM_BIOS << 8) | APM_SETPWSTATE; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = PMST_LASTREQREJECT; + sc->bios.r.edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { + if (apm_bioscall()) { #ifdef APM_DEBUG printf("apm_lastreq_rejected: failed\n"); #endif return 1; } - apm_op_inprog = 0; - return 0; } @@ -587,41 +523,40 @@ static int apm_get_info(apm_info_t aip) { struct apm_softc *sc = &apm_softc; - u_long eax, ebx, ecx, edx; - eax = (APM_BIOS << 8) | APM_GETPWSTATUS; - ebx = PMDV_ALLDEV; - ecx = 0; - edx = 0xffff; /* default to unknown battery time */ + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETPWSTATUS; + sc->bios.r.ebx = PMDV_ALLDEV; + sc->bios.r.ecx = 0; + sc->bios.r.edx = 0xffff; /* default to unknown battery time */ - if (apm_int(&eax, &ebx, &ecx, &edx)) + if (apm_bioscall()) return 1; aip->ai_infoversion = 1; - aip->ai_acline = (ebx >> 8) & 0xff; - aip->ai_batt_stat = ebx & 0xff; - aip->ai_batt_life = ecx & 0xff; + aip->ai_acline = (sc->bios.r.ebx >> 8) & 0xff; + aip->ai_batt_stat = sc->bios.r.ebx & 0xff; + aip->ai_batt_life = sc->bios.r.ecx & 0xff; aip->ai_major = (u_int)sc->majorversion; aip->ai_minor = (u_int)sc->minorversion; aip->ai_status = (u_int)sc->active; - edx &= 0xffff; - if (edx == 0xffff) /* Time is unknown */ + sc->bios.r.edx &= 0xffff; + if (sc->bios.r.edx == 0xffff) /* Time is unknown */ aip->ai_batt_time = -1; - else if (edx & 0x8000) /* Time is in minutes */ - aip->ai_batt_time = (edx & 0x7fff) * 60; + else if (sc->bios.r.edx & 0x8000) /* Time is in minutes */ + aip->ai_batt_time = (sc->bios.r.edx & 0x7fff) * 60; else /* Time is in seconds */ - aip->ai_batt_time = edx; + aip->ai_batt_time = sc->bios.r.edx; - eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; - ebx = 0; - ecx = 0; - edx = 0; - if (apm_int(&eax, &ebx, &ecx, &edx)) { + sc->bios.r.eax = (APM_BIOS << 8) | APM_GETCAPABILITIES; + sc->bios.r.ebx = 0; + sc->bios.r.ecx = 0; + sc->bios.r.edx = 0; + if (apm_bioscall()) { aip->ai_batteries = -1; /* Unknown */ aip->ai_capabilities = 0xff00; /* Unknown, with no bits set */ } else { - aip->ai_batteries = ebx & 0xff; - aip->ai_capabilities = ecx & 0xf; + aip->ai_batteries = sc->bios.r.ebx & 0xff; + aip->ai_capabilities = sc->bios.r.ecx & 0xf; } bzero(aip->ai_spare, sizeof aip->ai_spare); @@ -637,11 +572,10 @@ apm_cpu_idle(void) struct apm_softc *sc = &apm_softc; if (sc->active) { - u_long eax, ebx, ecx, edx; - eax = (APM_BIOS <<8) | APM_CPUIDLE; - edx = ecx = ebx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS <<8) | APM_CPUIDLE; + sc->bios.r.edx = sc->bios.r.ecx = sc->bios.r.ebx = 0; + (void) apm_bioscall(); } /* * Some APM implementation halts CPU in BIOS, whenever @@ -669,11 +603,10 @@ apm_cpu_busy(void) * necessary. */ if (sc->slow_idle_cpu && sc->active) { - u_long eax, ebx, ecx, edx; - eax = (APM_BIOS <<8) | APM_CPUBUSY; - edx = ecx = ebx = 0; - apm_int(&eax, &ebx, &ecx, &edx); + sc->bios.r.eax = (APM_BIOS <<8) | APM_CPUBUSY; + sc->bios.r.edx = sc->bios.r.ecx = sc->bios.r.ebx = 0; + apm_bioscall(); } } @@ -692,7 +625,8 @@ apm_timeout(void *dummy) if (apm_op_inprog) apm_lastreq_notify(); - apm_processevent(); + if (!sc->bios_busy) + apm_processevent(); if (sc->active == 1) /* Run slightly more oftan than 1 Hz */ @@ -752,14 +686,14 @@ apm_not_halt_cpu(void) /* device driver definitions */ /* - * probe APM + * probe for APM BIOS */ - static int apm_probe(device_t dev) { +#define APM_KERNBASE KERNBASE struct vm86frame vmf; - int i; + struct apm_softc *sc = &apm_softc; int disabled, flags; if (resource_int_value("apm", 0, "disabled", &disabled) == 0 @@ -777,69 +711,72 @@ apm_probe(device_t dev) flags = 0; bzero(&vmf, sizeof(struct vm86frame)); /* safety */ - vmf.vmf_ax = (APM_BIOS << 8) | APM_INSTCHECK; + bzero(&apm_softc, sizeof(apm_softc)); + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_INSTCHECK; vmf.vmf_bx = 0; - if (((i = vm86_intcall(SYSTEM_BIOS, &vmf)) == 0) && - !(vmf.vmf_eflags & PSL_C) && - (vmf.vmf_bx == 0x504d)) { + if (vm86_intcall(APM_INT, &vmf)) + return ENXIO; /* APM not found */ + if (vmf.vmf_bx != 0x504d) { + printf("apm: incorrect signature (0x%x)\n", vmf.vmf_bx); + return ENXIO; + } + if ((vmf.vmf_cx & (APM_32BIT_SUPPORT | APM_16BIT_SUPPORT)) == 0) { + printf("apm: protected mode connections are not supported\n"); + return ENXIO; + } + + apm_version = vmf.vmf_ax; + sc->slow_idle_cpu = ((vmf.vmf_cx & APM_CPUIDLE_SLOW) != 0); + sc->disabled = ((vmf.vmf_cx & APM_DISABLED) != 0); + sc->disengaged = ((vmf.vmf_cx & APM_DISENGAGED) != 0); - apm_version = vmf.vmf_ax; - apm_flags = vmf.vmf_cx; + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_DISCONNECT; + vmf.vmf_bx = 0; + vm86_intcall(APM_INT, &vmf); /* disconnect, just in case */ - vmf.vmf_ax = (APM_BIOS << 8) | APM_PROT32CONNECT; + if ((vmf.vmf_cx & APM_32BIT_SUPPORT) != 0) { + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_PROT32CONNECT; vmf.vmf_bx = 0; - if (((i = vm86_intcall(SYSTEM_BIOS, &vmf)) == 0) && - !(vmf.vmf_eflags & PSL_C)) { - - apm_cs32_base = vmf.vmf_ax; - apm_cs_entry = vmf.vmf_ebx; - apm_cs16_base = vmf.vmf_cx; - apm_ds_base = vmf.vmf_dx; - apm_cs32_limit = vmf.vmf_si; - if (apm_version >= 0x0102) - apm_cs16_limit = (vmf.esi.r_ex >> 16); - apm_ds_limit = vmf.vmf_di; -#ifdef APM_DEBUG - printf("apm: BIOS probe/32-bit connect successful\n"); -#endif - } else { - /* XXX constant typo! */ - if (vmf.vmf_ah == APME_PROT32NOTDUPPORTED) { - apm_version = APMINI_NOT32BIT; - } else { - apm_version = APMINI_CONNECTERR; - } -#ifdef APM_DEBUG - printf("apm: BIOS 32-bit connect failed: error 0x%x carry %d ah 0x%x\n", - i, (vmf.vmf_eflags & PSL_C) ? 1 : 0, vmf.vmf_ah); -#endif + if (vm86_intcall(APM_INT, &vmf)) { + printf("apm: 32-bit connection error.\n"); + return (ENXIO); + } + sc->bios.seg.code32.base = (vmf.vmf_ax << 4) + APM_KERNBASE; + sc->bios.seg.code32.limit = 0xffff; + sc->bios.seg.code16.base = (vmf.vmf_cx << 4) + APM_KERNBASE; + sc->bios.seg.code16.limit = vmf.vmf_si; + sc->bios.seg.data.base = (vmf.vmf_dx << 4) + APM_KERNBASE; + sc->bios.seg.data.limit = vmf.vmf_di; + sc->bios.entry = vmf.vmf_ebx; + sc->connectmode = APM_PROT32CONNECT; + } else { + /* use 16-bit connection */ + vmf.vmf_ah = APM_BIOS; + vmf.vmf_al = APM_PROT16CONNECT; + vmf.vmf_bx = 0; + if (vm86_intcall(APM_INT, &vmf)) { + printf("apm: 16-bit connection error.\n"); + return (ENXIO); } - } else { - apm_version = APMINI_CANTFIND; -#ifdef APM_DEBUG - printf("apm: BIOS probe failed: error 0x%x carry %d bx 0x%x\n", - i, (vmf.vmf_eflags & PSL_C) ? 1 : 0, vmf.vmf_bx); -#endif + sc->bios.seg.code16.base = (vmf.vmf_ax << 4) + APM_KERNBASE; + sc->bios.seg.code16.limit = vmf.vmf_si; + sc->bios.seg.data.base = (vmf.vmf_cx << 4) + APM_KERNBASE; + sc->bios.seg.data.limit = vmf.vmf_di; + sc->bios.entry = vmf.vmf_bx; + sc->connectmode = APM_PROT16CONNECT; } - - bzero(&apm_softc, sizeof(apm_softc)); - - switch (apm_version) { - case APMINI_CANTFIND: - /* silent */ - return ENXIO; - case APMINI_NOT32BIT: - printf("apm: 32bit connection is not supported.\n"); - return ENXIO; - case APMINI_CONNECTERR: - printf("apm: 32-bit connection error.\n"); - return ENXIO; + if (apm_version == 0x100) { + /* APM v1.0 does not set SI/DI */ + sc->bios.seg.code16.limit = 0xffff; + sc->bios.seg.data.limit = 0xffff; } - if (flags & 0x20) - statclock_disable = 1; - return 0; + return(0); } + /* * return 0 if the user will notice and handle the event, * return 1 if the kernel driver should do so. @@ -953,62 +890,40 @@ apm_processevent(void) static int apm_attach(device_t dev) { -#define APM_KERNBASE KERNBASE struct apm_softc *sc = &apm_softc; int flags; + int drv_version; if (resource_int_value("apm", 0, "flags", &flags) != 0) flags = 0; + if (flags & 0x20) + statclock_disable = 1; + sc->initialized = 0; /* Must be externally enabled */ sc->active = 0; - /* setup APM parameters */ - sc->cs16_base = (apm_cs16_base << 4) + APM_KERNBASE; - sc->cs32_base = (apm_cs32_base << 4) + APM_KERNBASE; - sc->ds_base = (apm_ds_base << 4) + APM_KERNBASE; - sc->cs32_limit = apm_cs32_limit - 1; - if (apm_cs16_limit == 0) - apm_cs16_limit = apm_cs32_limit; - sc->cs16_limit = apm_cs16_limit - 1; - sc->ds_limit = apm_ds_limit - 1; - sc->cs_entry = apm_cs_entry; - /* Always call HLT in idle loop */ sc->always_halt_cpu = 1; - sc->slow_idle_cpu = ((apm_flags & APM_CPUIDLE_SLOW) != 0); - sc->disabled = ((apm_flags & APM_DISABLED) != 0); - sc->disengaged = ((apm_flags & APM_DISENGAGED) != 0); - /* print bootstrap messages */ #ifdef APM_DEBUG printf("apm: APM BIOS version %04x\n", apm_version); - printf("apm: Code32 0x%08x, Code16 0x%08x, Data 0x%08x\n", - sc->cs32_base, sc->cs16_base, sc->ds_base); + printf("apm: Code16 0x%08x, Data 0x%08x\n", + sc->bios.seg.code16.base, sc->bios.seg.data.base); printf("apm: Code entry 0x%08x, Idling CPU %s, Management %s\n", - sc->cs_entry, is_enabled(sc->slow_idle_cpu), - is_enabled(!sc->disabled)); - printf("apm: CS32_limit=0x%x, CS16_limit=0x%x, DS_limit=0x%x\n", - (u_short)sc->cs32_limit, (u_short)sc->cs16_limit, (u_short)sc->ds_limit); + sc->bios.entry, is_enabled(sc->slow_idle_cpu), + is_enabled(!sc->disabled)); + printf("apm: CS_limit=0x%x, DS_limit=0x%x\n", + sc->bios.seg.code16.limit, sc->bios.seg.data.limit); #endif /* APM_DEBUG */ #if 0 - /* Workaround for some buggy APM BIOS implementations */ - sc->cs_limit = 0xffff; - sc->ds_limit = 0xffff; -#endif - - /* setup GDT */ - setup_apm_gdt(sc->cs32_base, sc->cs16_base, sc->ds_base, - sc->cs32_limit, sc->cs16_limit, sc->ds_limit); - - /* setup entry point 48bit pointer */ - apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL); - apm_addr.offset = sc->cs_entry; - + /* + * XXX this may not be needed anymore + */ if ((flags & 0x10)) { if ((flags & 0xf) >= 0x2) { apm_driver_version(0x102); @@ -1021,13 +936,20 @@ apm_attach(device_t dev) if (!apm_version) apm_driver_version(0x101); } - if (!apm_version) - apm_version = 0x100; - - sc->minorversion = ((apm_version & 0x00f0) >> 4) * 10 + - ((apm_version & 0x000f) >> 0); - sc->majorversion = ((apm_version & 0xf000) >> 12) * 10 + - ((apm_version & 0x0f00) >> 8); +#endif + /* + * In one test, apm bios version was 1.02; an attempt to register + * a 1.04 driver resulted in a 1.00 connection! Registering a + * 1.02 driver resulted in a 1.02 connection. + */ + drv_version = apm_version > 0x102 ? 0x102 : apm_version; + for (; drv_version > 0x100; drv_version--) + if (apm_driver_version(drv_version) == 0) + break; + sc->minorversion = ((drv_version & 0x00f0) >> 4) * 10 + + ((drv_version & 0x000f) >> 0); + sc->majorversion = ((drv_version & 0xf000) >> 12) * 10 + + ((apm_version & 0x0f00) >> 8); sc->intversion = INTVERSION(sc->majorversion, sc->minorversion); @@ -1036,8 +958,10 @@ apm_attach(device_t dev) printf("apm: Engaged control %s\n", is_enabled(!sc->disengaged)); #endif - printf("apm: found APM BIOS version %d.%d\n", - sc->majorversion, sc->minorversion); + printf("apm: found APM BIOS v%ld.%ld, connected at v%d.%d\n", + ((apm_version & 0xf000) >> 12) * 10 + ((apm_version & 0x0f00) >> 8), + ((apm_version & 0x00f0) >> 4) * 10 + ((apm_version & 0x000f) >> 0), + sc->majorversion, sc->minorversion); #ifdef APM_DEBUG printf("apm: Slow Idling CPU %s\n", is_enabled(sc->slow_idle_cpu)); @@ -1079,8 +1003,6 @@ apm_attach(device_t dev) apm_hook_establish(APM_HOOK_SUSPEND, &sc->sc_suspend); apm_hook_establish(APM_HOOK_RESUME , &sc->sc_resume); - apm_event_enable(); - /* Power the system off using APM */ at_shutdown_pri(apm_power_off, NULL, SHUTDOWN_FINAL, SHUTDOWN_PRI_LAST); @@ -1208,10 +1130,12 @@ apmioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) if (apm_display(newstate)) error = ENXIO; break; +#if 0 case APMIO_BIOS: if (apm_bios_call((struct apm_bios_arg*)addr) == 0) ((struct apm_bios_arg*)addr)->eax &= 0xff; break; +#endif default: error = EINVAL; break; diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index e613804..2e9b459 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,7 +1,7 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.253 1999/07/03 19:19:34 peter Exp $ +# $Id: files.i386,v 1.254 1999/07/26 07:43:20 phk Exp $ # # The long compile-with and dependency lines are required because of # limitations in config: backslash-newline doesn't work in strings, and @@ -107,7 +107,6 @@ gnu/i386/isa/dgb.c optional dgb gnu/i386/isa/dgm.c optional dgm gnu/i386/isa/sound/awe_wave.c optional awe i386/apm/apm.c optional apm -i386/apm/apm_setup.s optional apm i386/eisa/3c5x9.c optional ep i386/eisa/adv_eisa.c optional adv i386/eisa/ahb.c optional ahb diff --git a/sys/i386/i386/bios.c b/sys/i386/i386/bios.c index 5029db4..82afa3f 100644 --- a/sys/i386/i386/bios.c +++ b/sys/i386/i386/bios.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 1997 Michael Smith + * Copyright (c) 1998 Jonathan Lemon * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bios.c,v 1.11 1998/07/15 03:58:57 bde Exp $ + * $Id: bios.c,v 1.12 1999/03/16 21:11:28 msmith Exp $ */ /* @@ -31,12 +32,17 @@ */ #include <sys/param.h> +#include <sys/proc.h> #include <sys/systm.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <vm/vm.h> #include <vm/pmap.h> #include <machine/md_var.h> - +#include <machine/segments.h> +#include <machine/stdarg.h> +#include <machine/tss.h> +#include <machine/vmparam.h> #include <machine/pc/bios.h> #define BIOS_START 0xe0000 @@ -47,7 +53,7 @@ struct bios32_SDentry PCIbios = {entry : 0}; static struct SMBIOS_table *SMBIOStable = 0; static struct DMI_table *DMItable = 0; -static caddr_t bios32_SDCI = NULL; +static u_int bios32_SDCI = 0; static void bios32_init(void *junk); @@ -84,10 +90,10 @@ bios32_init(void *junk) } /* If checksum is OK, enable use of the entrypoint */ if ((ck == 0) && (sdh->entry < (BIOS_START + BIOS_SIZE))) { - bios32_SDCI = (caddr_t)BIOS_PADDRTOVADDR(sdh->entry); + bios32_SDCI = BIOS_PADDRTOVADDR(sdh->entry); if (bootverbose) { printf("Found BIOS32 Service Directory header at %p\n", sdh); - printf("Entry = 0x%x (%p) Rev = %d Len = %d\n", + printf("Entry = 0x%x (%x) Rev = %d Len = %d\n", sdh->entry, bios32_SDCI, sdh->revision, sdh->len); } /* See if there's a PCI BIOS entrypoint here */ @@ -168,23 +174,24 @@ bios32_init(void *junk) int bios32_SDlookup(struct bios32_SDentry *ent) { - struct bios32_args args; - - if (bios32_SDCI != NULL) { + struct bios_regs args; + + if (bios32_SDCI == 0) + return (1); args.eax = ent->ident.id; /* set up arguments */ args.ebx = args.ecx = args.edx = 0; - bios32(bios32_SDCI, &args); /* make the BIOS call */ + bios32(&args, bios32_SDCI, GSEL(GCODE_SEL, SEL_KPL)); if ((args.eax & 0xff) == 0) { /* success? */ - ent->base = args.ebx; - ent->len = args.ecx; - ent->entry = args.edx; - return(0); /* all OK */ + ent->base = args.ebx; + ent->len = args.ecx; + ent->entry = args.edx; + return (0); /* all OK */ } - } - return(1); /* failed */ + return (1); /* failed */ } + /* * bios_sigsearch * @@ -234,5 +241,239 @@ bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs return(0); } - - +/* + * do not staticize, used by bioscall.s + */ +union { + struct { + u_short offset; + u_short segment; + } vec16; + struct { + u_int offset; + u_short segment; + } vec32; +} bioscall_vector; /* bios jump vector */ + +void +set_bios_selectors(struct bios_segments *seg, int flags) +{ + static u_int curgen = 1; + struct soft_segment_descriptor ssd = { + 0, /* segment base address (overwritten) */ + 0, /* length (overwritten) */ + SDT_MEMERA, /* segment type (overwritten) */ + 0, /* priority level */ + 1, /* descriptor present */ + 0, 0, + 1, /* descriptor size (overwritten) */ + 0 /* granularity == byte units */ + }; + + if (seg->generation == curgen) + return; + if (++curgen == 0) + curgen = 1; + seg->generation = curgen; + + ssd.ssd_base = seg->code32.base; + ssd.ssd_limit = seg->code32.limit; + ssdtosd(&ssd, &gdt[GBIOSCODE32_SEL].sd); + + ssd.ssd_def32 = 0; + if (flags & BIOSCODE_FLAG) { + ssd.ssd_base = seg->code16.base; + ssd.ssd_limit = seg->code16.limit; + ssdtosd(&ssd, &gdt[GBIOSCODE16_SEL].sd); + } + + ssd.ssd_type = SDT_MEMRWA; + if (flags & BIOSDATA_FLAG) { + ssd.ssd_base = seg->data.base; + ssd.ssd_limit = seg->data.limit; + ssdtosd(&ssd, &gdt[GBIOSDATA_SEL].sd); + } + + if (flags & BIOSUTIL_FLAG) { + ssd.ssd_base = seg->util.base; + ssd.ssd_limit = seg->util.limit; + ssdtosd(&ssd, &gdt[GBIOSUTIL_SEL].sd); + } + + if (flags & BIOSARGS_FLAG) { + ssd.ssd_base = seg->args.base; + ssd.ssd_limit = seg->args.limit; + ssdtosd(&ssd, &gdt[GBIOSARGS_SEL].sd); + } +} + +/* + * for pointers, we don't know how much space is supposed to be allocated, + * so we assume a minimum size of 256 bytes. If more than this is needed, + * then this can be revisited, such as adding a length specifier. + */ +#define ASSUMED_ARGSIZE 256 + +extern int vm86pa; + +/* + * this routine is really greedy with selectors, and uses 5: + * + * 32-bit code selector: to return to kernel + * 16-bit code selector: for running code + * data selector: for 16-bit data + * util selector: extra utility selector + * args selector: to handle pointers + * + * the util selector is set from the util16 entry in bios16_args, if a + * "U" specifier is seen. + * + * See <machine/pc/bios.h> for description of format specifiers + */ +int +bios16(struct bios_args *args, char *fmt, ...) +{ + char *p, *stack, *stack_top; + va_list ap; + int flags = BIOSCODE_FLAG | BIOSDATA_FLAG; + u_int i, arg_start, arg_end; + u_int *pte, *ptd; + + arg_start = 0xffffffff; + arg_end = 0; + + stack = (caddr_t)PAGE_SIZE; + va_start(ap, fmt); + for (p = fmt; p && *p; p++) { + switch (*p) { + case 'p': /* 32-bit pointer */ + i = va_arg(ap, u_int); + arg_start = min(arg_start, i); + arg_end = max(arg_end, i + ASSUMED_ARGSIZE); + flags |= BIOSARGS_FLAG; + stack -= 4; + break; + + case 'i': /* 32-bit integer */ + i = va_arg(ap, u_int); + stack -= 4; + break; + + case 'U': /* 16-bit selector */ + flags |= BIOSUTIL_FLAG; + /* FALL THROUGH */ + case 'D': /* 16-bit selector */ + case 'C': /* 16-bit selector */ + case 's': /* 16-bit integer */ + i = va_arg(ap, u_short); + stack -= 2; + break; + + default: + return (EINVAL); + } + } + + if (flags & BIOSARGS_FLAG) { + if (arg_end - arg_start > ctob(16)) + return (EACCES); + args->seg.args.base = arg_start; + args->seg.args.limit = arg_end - arg_start; + } + + args->seg.code32.base = (u_int)&bios16_call & PG_FRAME; + args->seg.code32.limit = 0xffff; + + ptd = (u_int *)rcr3(); +#ifdef SMP + if (ptd == my_idlePTD) +#else + if (ptd == IdlePTD) +#endif + { + /* + * no page table, so create one and install it. + */ + pte = (u_int *)malloc(PAGE_SIZE, M_TEMP, M_WAITOK); + ptd = (u_int *)((u_int)ptd + KERNBASE); + *ptd = vtophys(pte) | PG_RW | PG_V; + } else { + /* + * this is a user-level page table + */ + pte = (u_int *)&PTmap; + } + /* + * install pointer to page 0. we don't need to flush the tlb, + * since there should not be a previous mapping for page 0. + */ + *pte = (vm86pa - PAGE_SIZE) | PG_RW | PG_V; + + stack_top = stack; + va_start(ap, fmt); + for (p = fmt; p && *p; p++) { + switch (*p) { + case 'p': /* 32-bit pointer */ + i = va_arg(ap, u_int); + *(u_int *)stack = (i - arg_start) | + (GSEL(GBIOSARGS_SEL, SEL_KPL) << 16); + stack += 4; + break; + + case 'i': /* 32-bit integer */ + i = va_arg(ap, u_int); + *(u_int *)stack = i; + stack += 4; + break; + + case 'U': /* 16-bit selector */ + i = va_arg(ap, u_short); + *(u_short *)stack = GSEL(GBIOSUTIL_SEL, SEL_KPL); + stack += 2; + break; + + case 'D': /* 16-bit selector */ + i = va_arg(ap, u_short); + *(u_short *)stack = GSEL(GBIOSDATA_SEL, SEL_KPL); + stack += 2; + break; + + case 'C': /* 16-bit selector */ + i = va_arg(ap, u_short); + *(u_short *)stack = GSEL(GBIOSCODE16_SEL, SEL_KPL); + stack += 2; + break; + + case 's': /* 16-bit integer */ + i = va_arg(ap, u_short); + *(u_short *)stack = i; + stack += 2; + break; + + default: + return (EINVAL); + } + } + + args->seg.generation = 0; /* reload selectors */ + set_bios_selectors(&args->seg, flags); + bioscall_vector.vec16.offset = (u_short)args->entry; + bioscall_vector.vec16.segment = GSEL(GBIOSCODE16_SEL, SEL_KPL); + + i = bios16_call(&args->r, stack_top); + + if (pte == (u_int *)&PTmap) { + *pte = 0; /* remove entry */ + } else { + *ptd = 0; /* remove page table */ + free(pte, M_TEMP); /* ... and free it */ + } + + + /* + * XXX only needs to be invlpg(0) but that doesn't work on the 386 + */ + invltlb(); + + return (i); +} diff --git a/sys/i386/i386/bioscall.s b/sys/i386/i386/bioscall.s index a041e0b..3b27ad2 100644 --- a/sys/i386/i386/bioscall.s +++ b/sys/i386/i386/bioscall.s @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id$ + * $Id: bioscall.s,v 1.1 1997/08/01 06:07:13 msmith Exp $ */ /* @@ -32,28 +32,136 @@ #include <machine/asmacros.h> +#include "assym.s" + +#define KCSEL 0x08 /* GSEL(GCODE_SEL, SEL_KPL) */ +#define KDSEL 0x10 /* GSEL(GDATA_SEL, SEL_KPL) */ +#define BC32SEL 0x40 /* GSEL(GBIOSCODE32_SEL, SEL_KPL) */ +#define BSSEL 0x60 /* GSEL(GBIOSSTACK_SEL, SEL_KPL) */ + +#define data16 .byte 0x66 + + .data + ALIGN_DATA +bioscall_frame: .long 0 +bioscall_stack: .long 0 + .text /* - * bios32(caddr_t func_addr, bios32_args *args) + * bios32(regs, offset, segment) + * struct bios_regs *regs; + * u_int offset; + * u_short segment; */ - ENTRY(bios32) + pushl %ebp + movl 16(%esp),%ebp + mov %bp,_bioscall_vector+4 + movl 12(%esp),%ebp + movl %ebp,_bioscall_vector + movl 8(%esp),%ebp + pushl %ebx + pushl %esi + pushl %edi + movl 0(%ebp),%eax + movl 4(%ebp),%ebx + movl 8(%ebp),%ecx + movl 12(%ebp),%edx + movl 16(%ebp),%esi + movl 20(%ebp),%edi + pushl %ebp + lcall _bioscall_vector + popl %ebp + movl %eax,0(%ebp) + movl %ebx,4(%ebp) + movl %ecx,8(%ebp) + movl %edx,12(%ebp) + movl %esi,16(%ebp) + movl %edi,20(%ebp) + movl $0,%eax /* presume success */ + jnc 1f + movl $1,%eax /* nope */ +1: + popl %edi + popl %esi + popl %ebx + popl %ebp + ret + + +/* + * bios16_call(regs, stack) + * struct bios_regs *regs; + * char *stack; + */ +ENTRY(bios16_call) + pushl %ebp + movl %esp,%ebp + addl $4,%ebp /* frame pointer */ + movl %ebp,bioscall_frame /* ... save it */ pushl %ebx pushl %esi - movl (2*4+2*4)(%esp), %esi - movl 0(%esi), %eax - movl 4(%esi), %ebx - movl 8(%esi), %ecx - movl 12(%esi), %edx - movl (2*4+1*4)(%esp), %esi - mov %cs, %di - pushl %edi /* really lcall/lret */ - call %esi - movl (2*4+2*4)(%esp), %esi - movl %eax, 0(%esi) - movl %ebx, 4(%esi) - movl %ecx, 8(%esi) - movl %edx, 12(%esi) + pushl %edi +/* + * the problem with a full 32-bit stack segment is that 16-bit code + * tends to do a pushf, which only pushes %sp, not %esp. This value + * is then popped off (into %esp) which causes a page fault because + * it is the wrong address. + * + * the reverse problem happens for 16-bit stack addresses; the kernel + * code attempts to get the address of something on the stack, and the + * value returned is the address relative to %ss, not %ds. + * + * we fix this by installing a temporary stack at page 0, so the + * addresses are always valid in both 32 bit and 16 bit modes. + */ + movl %esp,bioscall_stack /* save current stack location */ + movl 8(%ebp),%esp /* switch to page 0 stack */ + + movl 4(%ebp),%ebp /* regs */ + + movl 0(%ebp),%eax + movl 4(%ebp),%ebx + movl 8(%ebp),%ecx + movl 12(%ebp),%edx + movl 16(%ebp),%esi + movl 20(%ebp),%edi + + pushl $BC32SEL + leal bios_jmp,%ebp + andl $PAGE_MASK,%ebp + pushl %ebp /* reload %cs and */ + lret /* ...continue below */ +bios_jmp: + data16 + lcall _bioscall_vector /* 16-bit call */ + + jc 1f + pushl $0 /* success */ + jmp 2f +1: + pushl $1 /* failure */ +2: + movl bioscall_frame,%ebp + + movl 4(%ebp),%ebp /* regs */ + + movl %eax,0(%ebp) + movl %ebx,4(%ebp) + movl %ecx,8(%ebp) + movl %edx,12(%ebp) + movl %esi,16(%ebp) + movl %edi,20(%ebp) + + popl %eax /* recover return value */ + movl bioscall_stack,%esp /* return to normal stack */ + + popl %edi popl %esi popl %ebx - ret + popl %ebp + + movl (%esp),%ecx + pushl %ecx /* return address */ + movl $KCSEL,4(%esp) + lret /* reload %cs on the way out */ diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index a321bb2..c0dc2eb 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.355 1999/07/09 04:15:40 jlemon Exp $ + * $Id: machdep.c,v 1.356 1999/07/19 23:36:30 peter Exp $ */ #include "apm.h" @@ -1004,8 +1004,8 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, -/* GAPMCODE32_SEL 9 APM BIOS 32-bit interface (32bit Code) */ -{ 0, /* segment base address (overwritten by APM) */ +/* GBIOSCODE32_SEL 9 BIOS 32-bit interface (32bit Code) */ +{ 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ @@ -1013,8 +1013,8 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, -/* GAPMCODE16_SEL 10 APM BIOS 32-bit interface (16bit Code) */ -{ 0, /* segment base address (overwritten by APM) */ +/* GBIOSCODE16_SEL 10 BIOS 32-bit interface (16bit Code) */ +{ 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMERA, /* segment type */ 0, /* segment descriptor priority level */ @@ -1022,8 +1022,8 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 0, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, -/* GAPMDATA_SEL 11 APM BIOS 32-bit interface (Data) */ -{ 0, /* segment base address (overwritten by APM) */ +/* GBIOSDATA_SEL 11 BIOS 32-bit interface (Data) */ +{ 0, /* segment base address (overwritten) */ 0xfffff, /* length */ SDT_MEMRWA, /* segment type */ 0, /* segment descriptor priority level */ @@ -1031,6 +1031,24 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 1, /* default 32 vs 16 bit size */ 1 /* limit granularity (byte/page units)*/ }, +/* GBIOSUTIL_SEL 12 BIOS 16-bit interface (Utility) */ +{ 0, /* segment base address (overwritten) */ + 0xfffff, /* length */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 0, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, +/* GBIOSARGS_SEL 13 BIOS 16-bit interface (Arguments) */ +{ 0, /* segment base address (overwritten) */ + 0xfffff, /* length */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 0, /* default 32 vs 16 bit size */ + 1 /* limit granularity (byte/page units)*/ }, }; static struct soft_segment_descriptor ldt_segs[] = { diff --git a/sys/i386/include/apm_bios.h b/sys/i386/include/apm_bios.h index f13c7c5..755fd17 100644 --- a/sys/i386/include/apm_bios.h +++ b/sys/i386/include/apm_bios.h @@ -12,7 +12,7 @@ * * Aug, 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) * - * $Id: apm_bios.h,v 1.21 1998/10/30 05:41:15 msmith Exp $ + * $Id: apm_bios.h,v 1.22 1999/07/10 18:08:57 iwasaki Exp $ */ #ifndef _MACHINE_APM_BIOS_H_ @@ -26,10 +26,10 @@ /* BIOS id */ #ifdef PC98 #define APM_BIOS 0x9a -#define SYSTEM_BIOS 0x1f +#define APM_INT 0x1f #else #define APM_BIOS 0x53 -#define SYSTEM_BIOS 0x15 +#define APM_INT 0x15 #endif /* APM flags */ @@ -42,11 +42,6 @@ /* APM initializer physical address */ #define APM_OURADDR 0x00080000 -/* Error code of APM initializer */ -#define APMINI_CANTFIND 0xffffffff -#define APMINI_NOT32BIT 0xfffffffe -#define APMINI_CONNECTERR 0xfffffffd - /* APM functions */ #define APM_INSTCHECK 0x00 #define APM_REALCONNECT 0x01 @@ -224,17 +219,8 @@ typedef struct apm_info { u_int ai_spare[6]; /* For future expansion */ } *apm_info_t; -struct apm_bios_arg { - u_long eax; - u_long ebx; - u_long ecx; - u_long edx; - u_long esi; - u_long edi; -}; - -struct apm_event_info { - u_int type; +struct apm_event_info { + u_int type; u_int index; u_int spare[8]; }; diff --git a/sys/i386/include/asnames.h b/sys/i386/include/asnames.h index 6b31bac..8d1b478 100644 --- a/sys/i386/include/asnames.h +++ b/sys/i386/include/asnames.h @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: asnames.h,v 1.36 1999/07/10 15:27:56 bde Exp $ + * $Id: asnames.h,v 1.37 1999/07/20 06:52:33 msmith Exp $ */ #ifndef _MACHINE_ASNAMES_H_ @@ -179,6 +179,7 @@ #define _bigJump bigJump #define _bintr bintr #define _bio_imask bio_imask +#define _bioscall_vector bioscall_vector #define _bluetrap bluetrap #define _bootCodeSeg bootCodeSeg #define _bootDataSeg bootDataSeg diff --git a/sys/i386/include/pc/bios.h b/sys/i386/include/pc/bios.h index 4e47eae..0c88a4d 100644 --- a/sys/i386/include/pc/bios.h +++ b/sys/i386/include/pc/bios.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 1997 Michael Smith + * Copyright (c) 1998 Jonathan Lemon * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -23,7 +24,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: bios.h,v 1.1 1997/08/01 06:04:59 msmith Exp $ + * $Id: bios.h,v 1.2 1997/08/04 03:31:23 msmith Exp $ */ /* @@ -59,17 +60,6 @@ extern int bios32_SDlookup(struct bios32_SDentry *ent); extern u_int32_t bios_sigsearch(u_int32_t start, u_char *sig, int siglen, int paralen, int sigofs); -/* - * Call a 32-bit BIOS function - */ -struct bios32_args { - u_long eax; - u_long ebx; - u_long ecx; - u_long edx; -}; -extern void bios32(caddr_t func_addr, struct bios32_args *args); - #define BIOS_PADDRTOVADDR(x) (((x) - ISA_HOLE_START) + atdevbase) #define BIOS_VADDRTOPADDR(x) (((x) - atdevbase) + ISA_HOLE_START) @@ -108,5 +98,77 @@ extern struct bios32_SDentry PCIbios; extern struct SMBIOS_table *SMBIOS_table; extern struct DMI_table *DMI_table; +struct segment_info { + u_int base; + u_int limit; +}; + +#define BIOSCODE_FLAG 0x01 +#define BIOSDATA_FLAG 0x02 +#define BIOSUTIL_FLAG 0x04 +#define BIOSARGS_FLAG 0x08 + +struct bios_segments { + u_int generation; + struct segment_info code32; /* 32-bit code (mandatory) */ + struct segment_info code16; /* 16-bit code */ + struct segment_info data; /* 16-bit data */ + struct segment_info util; /* 16-bit utility */ + struct segment_info args; /* 16-bit args */ +}; + +struct bios_regs { + u_int eax; + u_int ebx; + u_int ecx; + u_int edx; + u_int esi; + u_int edi; +}; + +struct bios_args { + u_int entry; /* entry point of routine */ + struct bios_regs r; + struct bios_segments seg; +}; + +/* + * format specifiers and defines for bios16() + * s = short (16 bits) + * i = int (32 bits) + * p = pointer (converted to seg:offset) + * C,D,U = selector (corresponding to code/data/utility segment) + */ +#define PNP_COUNT_DEVNODES "sppD", 0x00 +#define PNP_GET_DEVNODE "sppsD", 0x01 +#define PNP_SET_DEVNODE "sppsD", 0x02 +#define PNP_GET_EVENT "spD", 0x03 +#define PNP_SEND_MSG "ssD", 0x04 +#define PNP_GET_DOCK_INFO "spD", 0x05 + +#define PNP_SEL_PRIBOOT "ssiiisspD", 0x07 +#define PNP_GET_PRIBOOT "sspppppD", 0x08 +#define PNP_SET_RESINFO "spD", 0x09 +#define PNP_GET_RESINFO "spD", 0x0A +#define PNP_GET_APM_ID "sppD", 0x0B + +#define PNP_GET_ISA_INFO "spD", 0x40 +#define PNP_GET_ECSD_INFO "spppD", 0x41 +#define PNP_READ_ESCD "spUD", 0x42 +#define PNP_WRITE_ESCD "spUD", 0x43 + +#define PNP_GET_DMI_INFO "spppppD", 0x50 +#define PNP_GET_DMI "sppUD", 0x51 + +#define PNP_BOOT_CHECK "sp", 0x60 +#define PNP_COUNT_IPL "sppp", 0x61 +#define PNP_GET_BOOTPRI "spp", 0x62 +#define PNP_SET_BOOTPRI "sp", 0x63 +#define PNP_GET_LASTBOOT "sp", 0x64 +#define PNP_GET_BOOTFIRST "sp", 0x65 +#define PNP_SET_BOOTFIRST "sp", 0x66 - +extern int bios16(struct bios_args *, char *, ...); +extern int bios16_call(struct bios_regs *, char *); +extern int bios32(struct bios_regs *, u_int, u_short); +extern void set_bios_selectors(struct bios_segments *, int); diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h index 7028185..14afa57 100644 --- a/sys/i386/include/segments.h +++ b/sys/i386/include/segments.h @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)segments.h 7.1 (Berkeley) 5/9/91 - * $Id: segments.h,v 1.19 1999/04/28 01:04:06 luoqi Exp $ + * $Id: segments.h,v 1.20 1999/06/18 14:32:21 bde Exp $ */ #ifndef _MACHINE_SEGMENTS_H_ @@ -215,14 +215,16 @@ struct region_descriptor { #define GUSERLDT_SEL 6 /* User LDT */ #define GTGATE_SEL 7 /* Process task switch gate */ #define GPANIC_SEL 8 /* Task state to consider panic from */ -#define GAPMCODE32_SEL 9 /* APM BIOS 32-bit interface (32bit Code) */ -#define GAPMCODE16_SEL 10 /* APM BIOS 32-bit interface (16bit Code) */ -#define GAPMDATA_SEL 11 /* APM BIOS 32-bit interface (Data) */ +#define GBIOSCODE32_SEL 9 /* BIOS interface (32bit Code) */ +#define GBIOSCODE16_SEL 10 /* BIOS interface (16bit Code) */ +#define GBIOSDATA_SEL 11 /* BIOS interface (Data) */ +#define GBIOSUTIL_SEL 12 /* BIOS interface (Utility) */ +#define GBIOSARGS_SEL 13 /* BIOS interface (Arguments) */ #ifdef BDE_DEBUGGER #define NGDT 18 /* some of 11-17 are reserved for debugger */ #else -#define NGDT 12 +#define NGDT 14 #endif /* |