Major update to the kernel's BIOS-calling ability.
- Add support for calling 32-bit code in other segments - Add support for calling 16-bit protected mode code Update APM to use this facility. Submitted by: jlemon
This commit is contained in:
parent
8799702cbc
commit
496027bf08
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=49197
@ -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);
|
||||
}
|
||||
|
@ -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[] = {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
|
@ -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,67 +127,24 @@ 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
|
||||
@ -212,80 +152,79 @@ 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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
struct apm_softc *sc = &apm_softc;
|
||||
|
||||
eax = (APM_BIOS << 8) | APM_SETPWSTATE;
|
||||
ebx = PMDV_ALLDEV;
|
||||
ecx = PMST_LASTREQNOTIFY;
|
||||
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_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;
|
||||
vmf.vmf_bx = 0;
|
||||
if (((i = vm86_intcall(SYSTEM_BIOS, &vmf)) == 0) &&
|
||||
!(vmf.vmf_eflags & PSL_C) &&
|
||||
(vmf.vmf_bx == 0x504d)) {
|
||||
|
||||
apm_version = vmf.vmf_ax;
|
||||
apm_flags = vmf.vmf_cx;
|
||||
|
||||
vmf.vmf_ax = (APM_BIOS << 8) | 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
|
||||
}
|
||||
} 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
|
||||
}
|
||||
|
||||
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");
|
||||
vmf.vmf_ah = APM_BIOS;
|
||||
vmf.vmf_al = APM_INSTCHECK;
|
||||
vmf.vmf_bx = 0;
|
||||
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 (flags & 0x20)
|
||||
statclock_disable = 1;
|
||||
return 0;
|
||||
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);
|
||||
|
||||
vmf.vmf_ah = APM_BIOS;
|
||||
vmf.vmf_al = APM_DISCONNECT;
|
||||
vmf.vmf_bx = 0;
|
||||
vm86_intcall(APM_INT, &vmf); /* disconnect, just in case */
|
||||
|
||||
if ((vmf.vmf_cx & APM_32BIT_SUPPORT) != 0) {
|
||||
vmf.vmf_ah = APM_BIOS;
|
||||
vmf.vmf_al = APM_PROT32CONNECT;
|
||||
vmf.vmf_bx = 0;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (apm_version == 0x100) {
|
||||
/* APM v1.0 does not set SI/DI */
|
||||
sc->bios.seg.code16.limit = 0xffff;
|
||||
sc->bios.seg.data.limit = 0xffff;
|
||||
}
|
||||
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;
|
||||
|
@ -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,67 +127,24 @@ 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
|
||||
@ -212,80 +152,79 @@ 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;
|
||||
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;
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
struct apm_softc *sc = &apm_softc;
|
||||
|
||||
eax = (APM_BIOS << 8) | APM_SETPWSTATE;
|
||||
ebx = PMDV_ALLDEV;
|
||||
ecx = PMST_LASTREQNOTIFY;
|
||||
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_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;
|
||||
vmf.vmf_bx = 0;
|
||||
if (((i = vm86_intcall(SYSTEM_BIOS, &vmf)) == 0) &&
|
||||
!(vmf.vmf_eflags & PSL_C) &&
|
||||
(vmf.vmf_bx == 0x504d)) {
|
||||
|
||||
apm_version = vmf.vmf_ax;
|
||||
apm_flags = vmf.vmf_cx;
|
||||
|
||||
vmf.vmf_ax = (APM_BIOS << 8) | 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
|
||||
}
|
||||
} 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
|
||||
}
|
||||
|
||||
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");
|
||||
vmf.vmf_ah = APM_BIOS;
|
||||
vmf.vmf_al = APM_INSTCHECK;
|
||||
vmf.vmf_bx = 0;
|
||||
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 (flags & 0x20)
|
||||
statclock_disable = 1;
|
||||
return 0;
|
||||
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);
|
||||
|
||||
vmf.vmf_ah = APM_BIOS;
|
||||
vmf.vmf_al = APM_DISCONNECT;
|
||||
vmf.vmf_bx = 0;
|
||||
vm86_intcall(APM_INT, &vmf); /* disconnect, just in case */
|
||||
|
||||
if ((vmf.vmf_cx & APM_32BIT_SUPPORT) != 0) {
|
||||
vmf.vmf_ah = APM_BIOS;
|
||||
vmf.vmf_al = APM_PROT32CONNECT;
|
||||
vmf.vmf_bx = 0;
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (apm_version == 0x100) {
|
||||
/* APM v1.0 does not set SI/DI */
|
||||
sc->bios.seg.code16.limit = 0xffff;
|
||||
sc->bios.seg.data.limit = 0xffff;
|
||||
}
|
||||
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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
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
|
||||
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
|
||||
ret
|
||||
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
|
||||
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
|
||||
popl %ebp
|
||||
|
||||
movl (%esp),%ecx
|
||||
pushl %ecx /* return address */
|
||||
movl $KCSEL,4(%esp)
|
||||
lret /* reload %cs on the way out */
|
||||
|
@ -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[] = {
|
||||
|
@ -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];
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user