diff options
58 files changed, 4180 insertions, 160 deletions
diff --git a/sys/alpha/include/console.h b/sys/alpha/include/console.h index 209baa4..ad441e1 100644 --- a/sys/alpha/include/console.h +++ b/sys/alpha/include/console.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: console.h,v 1.10 1994/09/15 07:26:04 sos Exp $ + * $Id: console.h,v 1.11 1994/09/29 08:31:39 sos Exp $ */ #ifndef _CONSOLE_H_ @@ -218,6 +218,7 @@ typedef struct ssaver ssaver_t; #define META 0x7f /* meta key */ #define RBT 0x80 /* boot machine */ #define DBG 0x81 /* call debugger */ +#define SUSP 0x82 /* suspend power (APM BIOS) */ #define F(x) ((x)+F_FN-1) #define S(x) ((x)+F_SCR-1) diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S index 7031c64..ad83a9a 100644 --- a/sys/amd64/amd64/cpu_switch.S +++ b/sys/amd64/amd64/cpu_switch.S @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.12 1994/09/01 05:12:18 davidg Exp $ + * $Id: swtch.s,v 1.13 1994/09/02 05:58:51 davidg Exp $ */ #include "npx.h" /* for NNPX */ @@ -204,8 +204,13 @@ idle_loop: jne sw1a cmpl $0,_whichqs jne nortqr +#ifdef APM + call _apm_cpu_idle + call _apm_cpu_busy +#else sti hlt /* wait for interrupt */ +#endif jmp idle_loop badsw: diff --git a/sys/amd64/amd64/locore.S b/sys/amd64/amd64/locore.S index 72973aa..bc7b854 100644 --- a/sys/amd64/amd64/locore.S +++ b/sys/amd64/amd64/locore.S @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 - * $Id: locore.s,v 1.28 1994/09/15 07:26:31 sos Exp $ + * $Id: locore.s,v 1.29 1994/09/26 16:56:22 pst Exp $ */ /* @@ -54,6 +54,11 @@ #include <machine/cputypes.h> /* x86 cpu type definitions */ #include <sys/syscall.h> /* system call numbers */ #include <machine/asmacros.h> /* miscellaneous asm macros */ +#ifdef APM +#define ASM +#include <machine/apm_bios.h> +#include <machine/apm_segments.h> +#endif /* * XXX @@ -130,7 +135,15 @@ _proc0paddr: .long 0 /* address of proc 0 address space */ .globl _bdb_exists /* flag to indicate BDE debugger is available */ _bdb_exists: .long 0 #endif - +#ifdef APM + .globl _apm_current_gdt_pdesc /* current GDT pseudo desc. */ +_apm_current_gdt_pdesc: + .byte 0, 0, 0 + + .globl _bootstrap_gdt +_bootstrap_gdt: + .space SIZEOF_GDT * BOOTSTRAP_GDT_NUM +#endif /* APM */ .globl tmpstk .space 0x1000 tmpstk: @@ -195,6 +208,89 @@ NON_GPROF_ENTRY(btext) rep movsb #endif +#ifdef APM + /* + * Setup APM BIOS: + * + * APM BIOS initialization should be done from real mode or V86 mode. + * + * (by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>) + */ + + /* + * Copy APM initializer under 1MB boundary: + * + * APM initializer program must switch the CPU to real mode. + * But FreeBSD kernel runs above 1MB boundary. So we must + * copy the initializer code to conventional memory. + */ + movl _apm_init_image_size-KERNBASE, %ecx /* size */ + lea _apm_init_image-KERNBASE, %esi /* source */ + movl $ APM_OURADDR, %edi /* destination */ + cld + rep + movsb + + /* get GDT base */ + sgdt _apm_current_gdt_pdesc-KERNBASE + + /* copy GDT to _bootstrap_gdt */ + xorl %ecx, %ecx + movw _apm_current_gdt_pdesc-KERNBASE, %cx + movl _apm_current_gdt_pdesc-KERNBASE+2, %esi + lea _bootstrap_gdt-KERNBASE, %edi + cld + rep + movsb + + /* setup GDT pseudo descriptor */ + movw $(SIZEOF_GDT*BOOTSTRAP_GDT_NUM), %ax + movw %ax, _apm_current_gdt_pdesc-KERNBASE + leal _bootstrap_gdt-KERNBASE, %eax + movl %eax, _apm_current_gdt_pdesc-KERNBASE+2 + + /* load new GDTR */ + lgdt _apm_current_gdt_pdesc-KERNBASE + + /* setup GDT for APM initializer */ + lea _bootstrap_gdt-KERNBASE, %ecx + movl $(APM_OURADDR), %eax /* use %ax for 15..0 */ + movl %eax, %ebx + shrl $16, %ebx /* use %bl for 23..16 */ + /* use %bh for 31..24 */ +#define APM_SETUP_GDT(index, attrib) \ + movl $(index), %si ; \ + lea 0(%ecx,%esi,8), %edx ; \ + movw $0xffff, (%edx) ; \ + movw %ax, 2(%edx) ; \ + movb %bl, 4(%edx) ; \ + movw $(attrib), 5(%edx) ; \ + movb %bh, 7(%edx) + + APM_SETUP_GDT(APM_INIT_CS_INDEX , CS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_DS_INDEX , DS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB) + + /* + * Call the initializer: + * + * direct intersegment call to conventional memory code + */ + .byte 0x9a /* actually, lcall $APM_INIT_CS_SEL, $0 */ + .long 0 + .word APM_INIT_CS_SEL + + movw %ax, _apm_version-KERNBASE + movl %ebx, _apm_cs_entry-KERNBASE + movw %cx, _apm_cs32_base-KERNBASE + shrl $16, %ecx + movw %cx, _apm_cs16_base-KERNBASE + movw %dx, _apm_ds_base-KERNBASE + movw %si, _apm_cs_limit-KERNBASE + shrl $16, %esi + movw %si, _apm_ds_limit-KERNBASE + movw %di, _apm_flags-KERNBASE +#endif /* APM */ /* Find out our CPU type. */ diff --git a/sys/amd64/amd64/locore.s b/sys/amd64/amd64/locore.s index 72973aa..bc7b854 100644 --- a/sys/amd64/amd64/locore.s +++ b/sys/amd64/amd64/locore.s @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 - * $Id: locore.s,v 1.28 1994/09/15 07:26:31 sos Exp $ + * $Id: locore.s,v 1.29 1994/09/26 16:56:22 pst Exp $ */ /* @@ -54,6 +54,11 @@ #include <machine/cputypes.h> /* x86 cpu type definitions */ #include <sys/syscall.h> /* system call numbers */ #include <machine/asmacros.h> /* miscellaneous asm macros */ +#ifdef APM +#define ASM +#include <machine/apm_bios.h> +#include <machine/apm_segments.h> +#endif /* * XXX @@ -130,7 +135,15 @@ _proc0paddr: .long 0 /* address of proc 0 address space */ .globl _bdb_exists /* flag to indicate BDE debugger is available */ _bdb_exists: .long 0 #endif - +#ifdef APM + .globl _apm_current_gdt_pdesc /* current GDT pseudo desc. */ +_apm_current_gdt_pdesc: + .byte 0, 0, 0 + + .globl _bootstrap_gdt +_bootstrap_gdt: + .space SIZEOF_GDT * BOOTSTRAP_GDT_NUM +#endif /* APM */ .globl tmpstk .space 0x1000 tmpstk: @@ -195,6 +208,89 @@ NON_GPROF_ENTRY(btext) rep movsb #endif +#ifdef APM + /* + * Setup APM BIOS: + * + * APM BIOS initialization should be done from real mode or V86 mode. + * + * (by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>) + */ + + /* + * Copy APM initializer under 1MB boundary: + * + * APM initializer program must switch the CPU to real mode. + * But FreeBSD kernel runs above 1MB boundary. So we must + * copy the initializer code to conventional memory. + */ + movl _apm_init_image_size-KERNBASE, %ecx /* size */ + lea _apm_init_image-KERNBASE, %esi /* source */ + movl $ APM_OURADDR, %edi /* destination */ + cld + rep + movsb + + /* get GDT base */ + sgdt _apm_current_gdt_pdesc-KERNBASE + + /* copy GDT to _bootstrap_gdt */ + xorl %ecx, %ecx + movw _apm_current_gdt_pdesc-KERNBASE, %cx + movl _apm_current_gdt_pdesc-KERNBASE+2, %esi + lea _bootstrap_gdt-KERNBASE, %edi + cld + rep + movsb + + /* setup GDT pseudo descriptor */ + movw $(SIZEOF_GDT*BOOTSTRAP_GDT_NUM), %ax + movw %ax, _apm_current_gdt_pdesc-KERNBASE + leal _bootstrap_gdt-KERNBASE, %eax + movl %eax, _apm_current_gdt_pdesc-KERNBASE+2 + + /* load new GDTR */ + lgdt _apm_current_gdt_pdesc-KERNBASE + + /* setup GDT for APM initializer */ + lea _bootstrap_gdt-KERNBASE, %ecx + movl $(APM_OURADDR), %eax /* use %ax for 15..0 */ + movl %eax, %ebx + shrl $16, %ebx /* use %bl for 23..16 */ + /* use %bh for 31..24 */ +#define APM_SETUP_GDT(index, attrib) \ + movl $(index), %si ; \ + lea 0(%ecx,%esi,8), %edx ; \ + movw $0xffff, (%edx) ; \ + movw %ax, 2(%edx) ; \ + movb %bl, 4(%edx) ; \ + movw $(attrib), 5(%edx) ; \ + movb %bh, 7(%edx) + + APM_SETUP_GDT(APM_INIT_CS_INDEX , CS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_DS_INDEX , DS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB) + + /* + * Call the initializer: + * + * direct intersegment call to conventional memory code + */ + .byte 0x9a /* actually, lcall $APM_INIT_CS_SEL, $0 */ + .long 0 + .word APM_INIT_CS_SEL + + movw %ax, _apm_version-KERNBASE + movl %ebx, _apm_cs_entry-KERNBASE + movw %cx, _apm_cs32_base-KERNBASE + shrl $16, %ecx + movw %cx, _apm_cs16_base-KERNBASE + movw %dx, _apm_ds_base-KERNBASE + movw %si, _apm_cs_limit-KERNBASE + shrl $16, %esi + movw %si, _apm_ds_limit-KERNBASE + movw %di, _apm_flags-KERNBASE +#endif /* APM */ /* Find out our CPU type. */ diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c index 46df0ca..3242846 100644 --- a/sys/amd64/amd64/machdep.c +++ b/sys/amd64/amd64/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.65 1994/09/16 05:46:54 phk Exp $ + * $Id: machdep.c,v 1.66 1994/09/24 12:22:47 davidg Exp $ */ #include "npx.h" @@ -1012,7 +1012,7 @@ struct soft_segment_descriptor gdt_segs[] = { 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* User LDT Descriptor per process */ -{ (int) ldt, /* segment base address */ +{ (int) ldt, /* segment base address */ (512 * sizeof(union descriptor)-1), /* length */ SDT_SYSLDT, /* segment type */ 0, /* segment descriptor priority level */ @@ -1020,6 +1020,60 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, +#ifdef APM + /* APM BIOS 32-bit interface (32bit Code) */ +{ 0, /* segment base address (overwritten by APM) */ + 0xffff, /* length */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* APM BIOS 32-bit interface (16bit Code) */ +{ 0, /* segment base address (overwritten by APM) */ + 0xffff, /* length */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* APM BIOS 32-bit interface (Data) */ +{ 0, /* segment base address (overwritten by APM) */ + 0xffff, /* length */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +#else /* APM */ +{ 0, /* segment base address */ + 0, /* length */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0, 0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +{ 0, /* segment base address */ + 0, /* length */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0, 0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +{ 0, /* segment base address */ + 0, /* length */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0, 0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +#endif /* APMBIOS */ }; struct soft_segment_descriptor ldt_segs[] = { @@ -1103,6 +1157,22 @@ extern idtvec_t int _gsel_tss; +/* added sdtossd() by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> */ +int +sdtossd(sd, ssd) + struct segment_descriptor *sd; + struct soft_segment_descriptor *ssd; +{ + ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; + ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; + ssd->ssd_type = sd->sd_type; + ssd->ssd_dpl = sd->sd_dpl; + ssd->ssd_p = sd->sd_p; + ssd->ssd_def32 = sd->sd_def32; + ssd->ssd_gran = sd->sd_gran; + return 0; +} + void init386(first) int first; diff --git a/sys/amd64/amd64/swtch.s b/sys/amd64/amd64/swtch.s index 7031c64..ad83a9a 100644 --- a/sys/amd64/amd64/swtch.s +++ b/sys/amd64/amd64/swtch.s @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.12 1994/09/01 05:12:18 davidg Exp $ + * $Id: swtch.s,v 1.13 1994/09/02 05:58:51 davidg Exp $ */ #include "npx.h" /* for NNPX */ @@ -204,8 +204,13 @@ idle_loop: jne sw1a cmpl $0,_whichqs jne nortqr +#ifdef APM + call _apm_cpu_idle + call _apm_cpu_busy +#else sti hlt /* wait for interrupt */ +#endif jmp idle_loop badsw: diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c index 49b4ffd..fcaa6e9 100644 --- a/sys/amd64/amd64/trap.c +++ b/sys/amd64/amd64/trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.33 1994/09/08 11:48:52 bde Exp $ + * $Id: trap.c,v 1.34 1994/09/11 11:26:18 davidg Exp $ */ /* @@ -459,10 +459,12 @@ trap_fatal(frame) struct trapframe *frame; { int code, type, eva; + struct soft_segment_descriptor softseg; code = frame->tf_err; type = frame->tf_trapno; eva = rcr2(); + sdtossd(gdt + IDXSEL(frame->tf_cs & 0xffff), &softseg); if (type <= MAX_TRAP_MSG) printf("\n\nFatal trap %d: %s while in %s mode\n", @@ -475,7 +477,11 @@ trap_fatal(frame) code & PGEX_W ? "write" : "read", code & PGEX_P ? "protection violation" : "page not present"); } - printf("instruction pointer = 0x%x\n", frame->tf_eip); + printf("instruction pointer = 0x%x:0x%x\n", frame->tf_cs & 0xffff, frame->tf_eip); + printf("code segment = base 0x%x, limit 0x%x, type 0x%x\n", + softseg.ssd_base, softseg.ssd_limit, softseg.ssd_type); + printf(" = DPL %d, pres %d, def32 %d, gran %d\n", + softseg.ssd_dpl, softseg.ssd_p, softseg.ssd_def32, softseg.ssd_gran); printf("processor eflags = "); if (frame->tf_eflags & PSL_T) printf("trace/trap, "); diff --git a/sys/amd64/include/segments.h b/sys/amd64/include/segments.h index 023a0cf..0e996e6 100644 --- a/sys/amd64/include/segments.h +++ b/sys/amd64/include/segments.h @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)segments.h 7.1 (Berkeley) 5/9/91 - * $Id: segments.h,v 1.3 1993/11/07 17:43:08 wollman Exp $ + * $Id: segments.h,v 1.4 1994/01/31 10:27:13 davidg Exp $ */ #ifndef _MACHINE_SEGMENTS_H_ @@ -211,7 +211,11 @@ struct region_descriptor { #define GPANIC_SEL 5 /* Task state to consider panic from */ #define GPROC0_SEL 6 /* Task state process slot zero and up */ #define GUSERLDT_SEL 7 /* User LDT */ -#define NGDT GUSERLDT_SEL+1 +#define GAPMCODE32_SEL 8 /* APM BIOS 32-bit interface (32bit Code) */ +#define GAPMCODE16_SEL 9 /* APM BIOS 32-bit interface (16bit Code) */ +#define GAPMDATA_SEL 10 /* APM BIOS 32-bit interface (Data) */ + +#define NGDT (GAPMDATA_SEL+1) /* * Entries in the Local Descriptor Table (LDT) diff --git a/sys/amd64/isa/icu.h b/sys/amd64/isa/icu.h index 5cecf65..a68269b 100644 --- a/sys/amd64/isa/icu.h +++ b/sys/amd64/isa/icu.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)icu.h 5.6 (Berkeley) 5/9/91 - * $Id: icu.h,v 1.5 1994/09/18 23:08:56 bde Exp $ + * $Id: icu.h,v 1.6 1994/09/18 23:18:32 bde Exp $ */ /* @@ -52,9 +52,10 @@ */ extern unsigned imen; /* interrupt mask enable */ -#define INTREN(s) (imen &= ~(s), SET_ICUS()) -#define INTRDIS(s) (imen |= (s), SET_ICUS()) -#define INTRMASK(msk,s) (msk |= (s)) +#define INTREN(s) (imen &= ~(s), SET_ICUS()) +#define INTRDIS(s) (imen |= (s), SET_ICUS()) +#define INTRMASK(msk,s) (msk |= (s)) +#define INTRUNMASK(msk,s) (msk &= ~(s)) #if 0 #define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8)) #else diff --git a/sys/amd64/isa/isa.c b/sys/amd64/isa/isa.c index 2cd9d23..2f93fcc 100644 --- a/sys/amd64/isa/isa.c +++ b/sys/amd64/isa/isa.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: isa.c,v 1.25 1994/09/20 05:07:11 bde Exp $ + * $Id: isa.c,v 1.26 1994/09/30 05:35:55 swallace Exp $ */ /* @@ -317,13 +317,35 @@ isa_configure() { /* * Configure an ISA device. */ + + +static void config_isadev_c(); + static void config_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + config_isadev_c(isdp, mp, 0); +} + +void +reconfig_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + config_isadev_c(isdp, mp, 1); +} + +static void +config_isadev_c(isdp, mp, reconfig) struct isa_device *isdp; u_int *mp; + int reconfig; { u_int checkbits; int id_alive; + int last_alive; struct isa_driver *dp = isdp->id_driver; checkbits = 0; @@ -339,12 +361,18 @@ config_isadev(isdp, mp) #ifndef ALLOW_CONFLICT_MEMADDR checkbits |= CC_MEMADDR; #endif - if (haveseen_isadev(isdp, checkbits)) + if (!reconfig && haveseen_isadev(isdp, checkbits)) return; - if (isdp->id_maddr) { + if (!reconfig && isdp->id_maddr) { isdp->id_maddr -= 0xa0000; /* XXX should be a define */ isdp->id_maddr += atdevbase; } + if (reconfig) { + last_alive = isdp->id_alive; + } + else { + last_alive = 0; + } id_alive = (*dp->probe)(isdp); if (id_alive) { /* @@ -354,50 +382,52 @@ config_isadev(isdp, mp) * 16 it will not report I/O addresses. * Rod Grimes 04/26/94 */ - printf("%s%d", dp->name, isdp->id_unit); - if (id_alive != -1) { - printf(" at 0x%x", isdp->id_iobase); - if ((isdp->id_iobase + id_alive - 1) != - isdp->id_iobase) { - printf("-0x%x", - isdp->id_iobase + id_alive - 1); + if (!isdp->id_reconfig) { + printf("%s%d", dp->name, isdp->id_unit); + if (id_alive != -1) { + printf(" at 0x%x", isdp->id_iobase); + if ((isdp->id_iobase + id_alive - 1) != + isdp->id_iobase) { + printf("-0x%x", + isdp->id_iobase + id_alive - 1); + } } - } - if (isdp->id_irq) - printf(" irq %d", ffs(isdp->id_irq) - 1); - if (isdp->id_drq != -1) - printf(" drq %d", isdp->id_drq); - if (isdp->id_maddr) - printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); - if (isdp->id_msize) - printf(" msize %d", isdp->id_msize); - if (isdp->id_flags) - printf(" flags 0x%x", isdp->id_flags); - if (isdp->id_iobase) { - if (isdp->id_iobase < 0x100) { - printf(" on motherboard\n"); - } else { - if (isdp->id_iobase >= 0x1000) { - printf (" on eisa\n"); + if (isdp->id_irq) + printf(" irq %d", ffs(isdp->id_irq) - 1); + if (isdp->id_drq != -1) + printf(" drq %d", isdp->id_drq); + if (isdp->id_maddr) + printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); + if (isdp->id_msize) + printf(" msize %d", isdp->id_msize); + if (isdp->id_flags) + printf(" flags 0x%x", isdp->id_flags); + if (isdp->id_iobase) { + if (isdp->id_iobase < 0x100) { + printf(" on motherboard\n"); } else { - printf (" on isa\n"); + if (isdp->id_iobase >= 0x1000) { + printf (" on eisa\n"); + } else { + printf (" on isa\n"); + } } } - } - /* - * Check for conflicts again. The driver may have changed - * *dvp. We should weaken the early check since the - * driver may have been able to change *dvp to avoid - * conflicts if given a chance. We already skip the early - * check for IRQs and force a check for IRQs in the next - * group of checks. - */ + /* + * Check for conflicts again. The driver may have + * changed *dvp. We should weaken the early check + * since the driver may have been able to change + * *dvp to avoid conflicts if given a chance. We + * already skip the early check for IRQs and force + * a check for IRQs in the next group of checks. + */ #ifndef ALLOW_CONFLICT_IRQ - checkbits |= CC_IRQ; + checkbits |= CC_IRQ; #endif - if (haveseen_isadev(isdp, checkbits)) - return; - isdp->id_alive = id_alive; + if (haveseen_isadev(isdp, checkbits)) + return; + isdp->id_alive = id_alive; + } (*dp->attach)(isdp); if (isdp->id_irq) { if (mp) @@ -408,11 +438,28 @@ config_isadev(isdp, mp) INTREN(isdp->id_irq); } } else { - printf("%s%d not found", dp->name, isdp->id_unit); - if (isdp->id_iobase) { - printf(" at 0x%x", isdp->id_iobase); + if (isdp->id_reconfig) { + (*dp->attach)(isdp); /* reconfiguration attach */ + } + if (!last_alive) { + if (!isdp->id_reconfig) { + printf("%s%d not found", dp->name, isdp->id_unit); + if (isdp->id_iobase) { + printf(" at 0x%x", isdp->id_iobase); + } + printf("\n"); + } + } + else { + /* This code has not been tested.... */ + if (isdp->id_irq) { + INTRDIS(isdp->id_irq); + unregister_intr(ffs(isdp->id_irq) - 1, + isdp->id_intr); + if (mp) + INTRUNMASK(*mp, isdp->id_irq); + } } - printf("\n"); } } diff --git a/sys/amd64/isa/isa.h b/sys/amd64/isa/isa.h index e2a26e7..7f6b02a 100644 --- a/sys/amd64/isa/isa.h +++ b/sys/amd64/isa/isa.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.h 5.7 (Berkeley) 5/9/91 - * $Id: isa.h,v 1.4 1994/01/05 15:03:28 rgrimes Exp $ + * $Id: isa.h,v 1.5 1994/04/21 14:20:54 sos Exp $ */ #ifndef _I386_ISA_ISA_H_ @@ -62,6 +62,7 @@ unsigned char rtcin __P((int)); /* CPU Board */ #define IO_DMA1 0x000 /* 8237A DMA Controller #1 */ #define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */ +#define IO_PMP1 0x026 /* 82347 Power Management Peripheral */ #define IO_TIMER1 0x040 /* 8253 Timer #1 */ #define IO_TIMER2 0x048 /* 8253 Timer #2 */ #define IO_KBD 0x060 /* 8042 Keyboard */ @@ -78,7 +79,9 @@ unsigned char rtcin __P((int)); #define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ - /* 0x178 - 0x1EF Open */ +#define IO_PMP2 0x178 /* 82347 Power Management Peripheral */ + + /* 0x17A - 0x1EF Open */ #define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */ #define IO_GAME 0x200 /* Game Controller */ @@ -146,6 +149,7 @@ unsigned char rtcin __P((int)); #define IO_TMRSIZE 16 /* 8253 programmable timers */ #define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ #define IO_VGASIZE 16 /* VGA controllers */ +#define IO_PMPSIZE 2 /* 82347 power management peripheral */ #endif /* IO_ISASIZES */ diff --git a/sys/conf/Makefile.i386 b/sys/conf/Makefile.i386 index 097d688..b4f6efc 100644 --- a/sys/conf/Makefile.i386 +++ b/sys/conf/Makefile.i386 @@ -1,6 +1,6 @@ # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 -# $Id: Makefile.i386,v 1.38 1994/09/23 07:01:59 phk Exp $ +# $Id: Makefile.i386,v 1.39 1994/09/29 14:02:40 csgr Exp $ # # Makefile for FreeBSD # @@ -66,7 +66,7 @@ DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< SFILES= ${I386}/i386/exception.s ${I386}/i386/microtime.s \ - ${I386}/i386/support.s ${I386}/i386/swtch.s + ${I386}/i386/support.s ${I386}/i386/swtch.s ${I386}/apm/apm_setup.s SYSTEM_CFILES= ioconf.c param.c vnode_if.c SYSTEM_SFILES= ${I386}/i386/locore.s SYSTEM_OBJS=locore.o vnode_if.o ${OBJS} ioconf.o param.o diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc index 097d688..b4f6efc 100644 --- a/sys/conf/Makefile.powerpc +++ b/sys/conf/Makefile.powerpc @@ -1,6 +1,6 @@ # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 -# $Id: Makefile.i386,v 1.38 1994/09/23 07:01:59 phk Exp $ +# $Id: Makefile.i386,v 1.39 1994/09/29 14:02:40 csgr Exp $ # # Makefile for FreeBSD # @@ -66,7 +66,7 @@ DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< SFILES= ${I386}/i386/exception.s ${I386}/i386/microtime.s \ - ${I386}/i386/support.s ${I386}/i386/swtch.s + ${I386}/i386/support.s ${I386}/i386/swtch.s ${I386}/apm/apm_setup.s SYSTEM_CFILES= ioconf.c param.c vnode_if.c SYSTEM_SFILES= ${I386}/i386/locore.s SYSTEM_OBJS=locore.o vnode_if.o ${OBJS} ioconf.o param.o diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 index 5ccdaab..c08c577 100644 --- a/sys/conf/files.i386 +++ b/sys/conf/files.i386 @@ -1,8 +1,10 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.49 1994/09/26 16:15:06 jkh Exp $ +# $Id: files.i386,v 1.50 1994/10/01 02:36:24 swallace Exp $ # +i386/apm/apm.c optional apm device-driver +i386/apm/apm_setup.s optional apm i386/i386/autoconf.c standard device-driver i386/i386/conf.c standard i386/i386/cons.c standard diff --git a/sys/dev/kbd/kbdtables.h b/sys/dev/kbd/kbdtables.h index 7e8318f..a48b6a6 100644 --- a/sys/dev/kbd/kbdtables.h +++ b/sys/dev/kbd/kbdtables.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: kbdtables.h,v 1.14 1994/09/29 08:29:17 sos Exp $ */ #define SET8 0x80 /* eight bit for emacs SET8-key */ @@ -799,7 +799,7 @@ keymap_t key_map = { 0x69, /* US iso8859 keymap */ /* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, -/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00, +/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', SUSP, ' ', 0x02, 0x00, /* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00, /* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00, /* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00, diff --git a/sys/dev/syscons/syscons.c b/sys/dev/syscons/syscons.c index 0479f76..230c945 100644 --- a/sys/dev/syscons/syscons.c +++ b/sys/dev/syscons/syscons.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: syscons.c,v 1.59 1994/09/29 08:29:21 sos Exp $ + * $Id: syscons.c,v 1.60 1994/09/29 15:49:09 ache Exp $ */ #include "sc.h" @@ -64,6 +64,9 @@ #include <i386/isa/timerreg.h> #include <i386/isa/kbdtables.h> #include <i386/i386/cons.h> +#ifdef APM +#include <machine/apm_bios.h> +#endif #if !defined(NCONS) #define NCONS 12 @@ -288,6 +291,16 @@ struct isa_driver scdriver = { pcprobe, pcattach, "sc", }; +#ifdef APM +static int +pc_resume(void) +{ + /* when the system wakes up, modifier keys must be re-initialized */ + shfts = ctls = alts = agrs = metas = 0; + return 0; +} +#endif /* APM */ + int pcprobe(struct isa_device *dev) { @@ -391,6 +404,9 @@ pcattach(struct isa_device *dev) #endif cursor_pos(1); update_leds(console[0].status); +#ifdef APM + apm_resume_hook_init(pc_resume, "Syscons console", APM_MID_ORDER); +#endif return 0; } @@ -2081,7 +2097,11 @@ scinit(void) scp->ysize = ROW; scp->bell_pitch = BELL_PITCH; scp->bell_duration = BELL_DURATION; +#ifndef LAPTOP scp->status = NLKED; +#else + scp->status = 0; +#endif scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; @@ -2429,6 +2449,12 @@ next_code: case RBT: shutdown_nice(); break; + case SUSP: +#ifdef APM + apm_suspend_resume(); +#endif /* APM */ + break; + case DBG: #ifdef DDB /* try to switch to console 0 */ if (cur_console->smode.mode == VT_AUTO && diff --git a/sys/i386/apm/apm.c b/sys/i386/apm/apm.c new file mode 100644 index 0000000..3660844 --- /dev/null +++ b/sys/i386/apm/apm.c @@ -0,0 +1,823 @@ +/* + * LP (Laptop Package) + * + * Copyright (c) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep, 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include "apm.h" + +#if NAPM > 0 + +#include <sys/param.h> +#include "conf.h" +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/file.h> +#include <sys/proc.h> +#include <sys/vnode.h> +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include <machine/apm_bios.h> +#include <machine/segments.h> +#include <vm/vm.h> +#include <sys/syslog.h> +#include "apm_setup.h" + +/* static data */ +static int apm_initialized = 0, active = 0, halt_cpu = 1; +static u_int minorversion, majorversion; +static u_int cs32_base, cs16_base, ds_base; +static u_int cs_limit, ds_limit; +static u_int cs_entry; +static u_int intversion; +static int idle_cpu, disabled, disengaged; + +/* Map version number to integer (keeps ordering of version numbers) */ +#define INTVERSION(major, minor) ((major)*100 + (minor)) + +static timeout_t apm_timeout; + +/* setup APM GDT discriptors */ +static void +setup_apm_gdt(u_int code32_base, u_int code16_base, u_int data_base, u_int code_limit, u_int data_limit) +{ + /* setup 32bit code segment */ + gdt_segs[GAPMCODE32_SEL].ssd_base = code32_base; + gdt_segs[GAPMCODE32_SEL].ssd_limit = code_limit; + + /* setup 16bit code segment */ + gdt_segs[GAPMCODE16_SEL].ssd_base = code16_base; + gdt_segs[GAPMCODE16_SEL].ssd_limit = code_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); + ssdtosd(gdt_segs + GAPMCODE16_SEL, gdt + GAPMCODE16_SEL); + ssdtosd(gdt_segs + GAPMDATA_SEL , gdt + GAPMDATA_SEL ); +} + +/* 48bit far pointer */ +struct addr48 { + u_long offset; + u_short segment; +} apm_addr; + + +/* register structure for BIOS call */ +union real_regs { + struct xregs { + u_short ax; + u_short bx __attribute__ ((packed)); + u_short cx __attribute__ ((packed)); + u_short dx __attribute__ ((packed)); + u_short si __attribute__ ((packed)); + u_short di __attribute__ ((packed)); + u_short cf __attribute__ ((packed)); /* carry */ + } x; + struct hlregs { + u_char al; + u_char ah __attribute__ ((packed)); + u_char bl __attribute__ ((packed)); + u_char bh __attribute__ ((packed)); + u_char cl __attribute__ ((packed)); + u_char ch __attribute__ ((packed)); + u_char dl __attribute__ ((packed)); + u_char dh __attribute__ ((packed)); + u_short si __attribute__ ((packed)); + u_short di __attribute__ ((packed)); + u_short cf __attribute__ ((packed)); /* carry */ + } hl; +}; + + +/* call APM BIOS */ +extern void call_apm(union real_regs* regs); + +extern u_char apm_errno; + +/* enable/disable power management */ +static int +apm_enable_disable_pm(int enable) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_ENABLEDISABLEPM; + if (intversion >= INTVERSION(1, 1)) { + regs.x.bx = PMDV_ALLDEV; + } + else { + regs.x.bx = 0xffff; /* APM version 1.0 only */ + } + regs.x.cx = enable; + call_apm(®s); + return regs.x.cf; +} + +/* engage/disengage power management (APM 1.1 or later) */ +static int +apm_engage_disengage_pm(int engage) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_ENGAGEDISENGAGEPM; + regs.x.bx = PMDV_ALLDEV; + regs.x.cx = engage; + call_apm(®s); + return regs.x.cf; +} + +/* get PM event */ +static u_int +apm_getevent(void) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_GETPMEVENT; + call_apm(®s); + if (regs.x.cf) { +#if 0 + printf("No event: errcode = %d\n", apm_errno); +#endif + return PMEV_NOEVENT; + } + return (u_int)regs.x.bx; +} + +/* + * In many cases, the first event that occured after resume, needs + * special treatment. This binary flag make this process possible. + * Initial value of this variable is 1, because the bootstrap + * condition is equivalent to resumed condition for the power + * manager. + */ +static int resumed_event = 1; + +/* suspend entire system */ +static int +apm_suspend_system(void) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_SETPWSTATE; + regs.x.bx = PMDV_ALLDEV; + regs.x.cx = PMST_SUSPEND; + call_apm(®s); + if (regs.x.cf) { + printf("Entire system suspend failure: errcode = %d\n", apm_errno); + return 1; + } + resumed_event = 1; + + return 0; +} + +/* APM Battery low handler */ +static void +apm_battery_low(void) +{ + /* Currently, this routine has not been implemented. Sorry... */ +} + + +/* APM driver calls some functions automatically when the system wakes up */ +static void +apm_execute_hook(apm_hook_func_t list) +{ + apm_hook_func_t p; + + for (p = list; p != NULL; p = p->next) { + if ((*(p->func))()) { + printf("Warning: APM hook of %s failed", p->name); + } + } +} + + +/* APM hook manager */ +static apm_hook_func_t +apm_hook_init(apm_hook_func_t *list, int (*func)(void), char *name, int order) +{ + int pl; + apm_hook_func_t p, prev, new_node; + + pl = splhigh(); + new_node = malloc(sizeof(*new_node), M_DEVBUF, M_NOWAIT); + if (new_node == NULL) { + panic("Can't allocate device buffer for apm_resume_hook."); + } + new_node->func = func; + new_node->name = name; +#if 0 + new_node->next = *list; + *list = new_node; +#else + prev = NULL; + for (p = *list; p != NULL; prev = p, p = p->next) { + if (p->order > order) { + break; + } + } + + if (prev == NULL) { + new_node->next = *list; + *list = new_node; + } + else { + new_node->next = prev->next; + prev->next = new_node; + } +#endif + splx(pl); + return new_node; +} + +void +apm_hook_delete(apm_hook_func_t *list, apm_hook_func_t delete_node) +{ + int pl; + apm_hook_func_t p, prev; + + pl = splhigh(); + prev = NULL; + for (p = *list; p != NULL; prev = p, p = p->next) { + if (p == delete_node) { + goto deleteit; + } + } + panic("Tried to delete unregistered apm_resume_hook."); + goto nosuchnode; +deleteit: + if (prev != NULL) { + prev->next = p->next; + } + else { + *list = p->next; + } + free(delete_node, M_DEVBUF); +nosuchnode: + splx(pl); +} + +static struct timeval suspend_time; + +/* default APM hook functions */ +static int +apm_default_resume(void) +{ + u_int second, minute, hour; + struct timeval resume_time; + + inittodr(0); /* adjust time to RTC */ + microtime(&resume_time); + second = resume_time.tv_sec - suspend_time.tv_sec; + hour = second / 3600; + second %= 3600; + minute = second / 60; + second %= 60; + log(LOG_NOTICE, "resumed from suspended mode (slept %02d:%02d:%02d)\n", hour, minute, second); + return 0; +} + +static int +apm_default_suspend(void) +{ + int pl; +#if 0 + pl = splhigh(); + sync(curproc, NULL, NULL); + splx(pl); +#endif + microtime(&suspend_time); + return 0; +} + +/* list structure for hook */ +static apm_hook_func_t apm_resume_hook = NULL; +static apm_hook_func_t apm_suspend_hook = NULL; + +/* execute resume hook */ +static void +apm_execute_resume_hook(void) +{ + apm_execute_hook(apm_resume_hook); +} + +/* add a node on resume hook */ +apm_hook_func_t +apm_resume_hook_init(int (*func)(void), char *name, int order) +{ + return apm_hook_init(&apm_resume_hook, func, name, order); +} + +/* delete a node from resume hook */ +void +apm_resume_hook_delete(apm_hook_func_t delete_node) +{ + apm_hook_delete(&apm_resume_hook, delete_node); +} + +/* execute suspend hook */ +static void +apm_execute_suspend_hook(void) +{ + apm_execute_hook(apm_suspend_hook); +} + +/* add a node on resume hook */ +apm_hook_func_t +apm_suspend_hook_init(int (*func)(void), char *name, int order) +{ + return apm_hook_init(&apm_suspend_hook, func, name, order); +} + +/* delete a node from resume hook */ +void +apm_suspend_hook_delete(apm_hook_func_t delete_node) +{ + apm_hook_delete(&apm_suspend_hook, delete_node); +} + +/* get APM information */ +static int +apm_get_info(apm_info_t aip) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_GETPWSTATUS; + regs.x.bx = PMDV_ALLDEV; + call_apm(®s); + if (regs.x.cf) { + printf("Get APM info failure: errcode = %d\n", apm_errno); + return 1; + } + aip->ai_major = (u_int)majorversion; + aip->ai_minor = (u_int)minorversion; + aip->ai_acline = (u_int)regs.hl.bh; + aip->ai_batt_stat = (u_int)regs.hl.bl; + aip->ai_batt_life = (u_int)regs.hl.cl; + return 0; +} + + +/* Define equivalent event sets */ + +static int equiv_event_num = 0; +static struct apm_eqv_event equiv_events[APM_MAX_EQUIV_EVENTS]; + +static int +apm_def_eqv(apm_eqv_event_t aee) +{ + if (equiv_event_num == APM_MAX_EQUIV_EVENTS) { + return 1; + } + memcpy(&equiv_events[equiv_event_num], aee, sizeof(struct apm_eqv_event)); + equiv_event_num++; + return 0; +} + +static void +apm_flush_eqv(void) +{ + equiv_event_num = 0; +} + +static void apm_processevent(void); + +/* + * Public interface to the suspend/resume: + * + * Execute suspend and resume hook before and after sleep, respectively. + */ + +void +apm_suspend_resume(void) +{ + int pl; +#if 0 + printf("Called apm_suspend_resume();\n"); +#endif + if (apm_initialized) { + apm_execute_suspend_hook(); + apm_suspend_system(); + apm_execute_resume_hook(); + apm_processevent(); + } +} + +/* inform APM BIOS that CPU is idle */ +void +apm_cpu_idle(void) +{ + if (idle_cpu) { + if (active) { + asm("movw $0x5305, %ax; lcall _apm_addr"); + } + } + /* + * Some APM implementation halts CPU in BIOS, whenever + * "CPU-idle" function are invoked, but swtch() of + * FreeBSD halts CPU, therefore, CPU is halted twice + * in the sched loop. It makes the interrupt latency + * terribly long and be able to cause a serious problem + * in interrupt processing. We prevent it by removing + * "hlt" operation from swtch() and managed it under + * APM driver. + */ + if (!active || halt_cpu) { + asm("sti ; hlt"); /* wait for interrupt */ + } +} + +/* inform APM BIOS that CPU is busy */ +void +apm_cpu_busy(void) +{ + if (idle_cpu && active) { + asm("movw $0x5306, %ax; lcall _apm_addr"); + } +} + + +/* + * APM timeout routine: + * + * This routine is automatically called by timer two times within one + * seconed. + */ + +static void +apm_timeout(void *arg1) +{ +#if 0 + printf("Called apm_timeout\n"); +#endif + apm_processevent(); + timeout(apm_timeout, NULL, hz / 2); /* 2 Hz */ + /* APM driver must polls APM event a time per second */ +} + +/* enable APM BIOS */ +static void +apm_event_enable(void) +{ +#if 0 + printf("called apm_event_enable()\n"); +#endif + if (apm_initialized) { + active = 1; + timeout(apm_timeout, NULL, 2 * hz); + } +} + +/* disable APM BIOS */ +static void +apm_event_disable(void) +{ +#if 0 + printf("called apm_event_disable()\n"); +#endif + if (apm_initialized) { + untimeout(apm_timeout, NULL); + active = 0; + } +} + +/* halt CPU in scheduling loop */ +static void apm_halt_cpu(void) +{ + if (apm_initialized) { + halt_cpu = 1; + } +} + +/* don't halt CPU in scheduling loop */ +static void apm_not_halt_cpu(void) +{ + if (apm_initialized) { + halt_cpu = 0; + } +} + +/* device driver definitions */ +int apmprobe (struct isa_device *); +int apmattach(struct isa_device *); + +struct isa_driver apmdriver = { apmprobe, apmattach, "apm" }; + + +/* + * probe APM (dummy): + * + * APM probing routine is placed on locore.s and apm_init.S because + * this process forces the CPU to turn to real mode or V86 mode. + * Current version uses real mode, but on future version, we want + * to use V86 mode in APM initialization. + */ +int +apmprobe(struct isa_device *dvp) +{ + switch (apm_version) { + case APMINI_CANTFIND: + /* silent */ + return 0; + case APMINI_NOT32BIT: + printf("apm%d: 32bit connection is not supported.\n", dvp->id_unit); + return 0; + case APMINI_CONNECTERR: + printf("apm%d: 32-bit connection error.\n", dvp->id_unit); + return 0; + } + return -1; +} + +static const char * +is_enabled(int enabled) +{ + if (enabled) { + return "enabled"; + } + return "disabled"; +} + +static const char * +apm_error(void) +{ + static char buffer[64]; + + switch (apm_errno) { + case 0: + return "APM OK."; + default: + sprintf(buffer, "Unknown Error 0x%x", (u_int)apm_errno); + return buffer; + } +} + + + +/* Process APM event */ +static void +apm_processevent(void) +{ + int i, apm_event; + +getevent: + while (1) { + if ((apm_event = apm_getevent()) == PMEV_NOEVENT) { + break; + } +#if 0 +#if 1 +#define OPMEV_DEBUGMESSAGE(symbol) case symbol: break; +#else +#define OPMEV_DEBUGMESSAGE(symbol) case symbol: printf("Original APM Event: " #symbol "\n"); break +#endif + switch (apm_event) { + OPMEV_DEBUGMESSAGE(PMEV_NOEVENT); + OPMEV_DEBUGMESSAGE(PMEV_STANDBYREQ); + OPMEV_DEBUGMESSAGE(PMEV_SUSPENDREQ); + OPMEV_DEBUGMESSAGE(PMEV_NORMRESUME); + OPMEV_DEBUGMESSAGE(PMEV_CRITRESUME); + OPMEV_DEBUGMESSAGE(PMEV_BATTERYLOW); + OPMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE); + OPMEV_DEBUGMESSAGE(PMEV_UPDATETIME); + OPMEV_DEBUGMESSAGE(PMEV_CRITSUSPEND); + OPMEV_DEBUGMESSAGE(PMEV_USERSUSPENDREQ); + OPMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME); + default: + printf("Unknown Original APM Event 0x%x\n", apm_event); + break; + } +#endif + for (i = 0; i < equiv_event_num; i++) { + if (equiv_events[i].aee_event == apm_event) { + u_int tmp = PMEV_DEFAULT; + if (resumed_event) { + tmp = equiv_events[i].aee_resume; + } + else { + tmp = equiv_events[i].aee_equiv; + } + if (tmp != PMEV_DEFAULT) { + apm_event = tmp; + break; + } + } + } +#if 1 +#if 1 +#define PMEV_DEBUGMESSAGE(symbol) case symbol: break; +#else +#define PMEV_DEBUGMESSAGE(symbol) case symbol: printf("APM Event: " #symbol "\n"); break +#endif + switch (apm_event) { + PMEV_DEBUGMESSAGE(PMEV_NOEVENT); + PMEV_DEBUGMESSAGE(PMEV_STANDBYREQ); + PMEV_DEBUGMESSAGE(PMEV_SUSPENDREQ); + PMEV_DEBUGMESSAGE(PMEV_NORMRESUME); + PMEV_DEBUGMESSAGE(PMEV_CRITRESUME); + PMEV_DEBUGMESSAGE(PMEV_BATTERYLOW); + PMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE); + PMEV_DEBUGMESSAGE(PMEV_UPDATETIME); + PMEV_DEBUGMESSAGE(PMEV_CRITSUSPEND); + PMEV_DEBUGMESSAGE(PMEV_USERSUSPENDREQ); + PMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME); + default: + printf("Unknown APM Event 0x%x\n", apm_event); + break; + } +#endif + switch (apm_event) { + case PMEV_NOEVENT: + case PMEV_STANDBYREQ: + case PMEV_POWERSTATECHANGE: + case PMEV_CRITSUSPEND: + case PMEV_USERSTANDBYREQ: + case PMEV_USERSUSPENDREQ: + break; + case PMEV_BATTERYLOW: + apm_battery_low(); + break; + case PMEV_SUSPENDREQ: + apm_suspend_resume(); + break; + case PMEV_NORMRESUME: + case PMEV_CRITRESUME: + case PMEV_UPDATETIME: + case PMEV_STANDBYRESUME: + inittodr(0); /* adjust time to RTC */ + break; + } + } + resumed_event = 0; +} + + +/* + * Attach APM: + * + * Initialize APM driver (APM BIOS itself has been initialized in locore.s) + */ + +int +apmattach(struct isa_device *dvp) +{ + + /* setup APM parameters */ + minorversion = ((apm_version & 0x00f0) >> 4) * 10 + ((apm_version & 0x000f) >> 0); + majorversion = ((apm_version & 0xf000) >> 12) * 10 + ((apm_version & 0x0f00) >> 8); + intversion = INTVERSION(majorversion, minorversion); + cs32_base = (apm_cs32_base << 4) + KERNBASE; + cs16_base = (apm_cs16_base << 4) + KERNBASE; + ds_base = (apm_ds_base << 4) + KERNBASE; + cs_limit = apm_cs_limit; + ds_limit = apm_ds_limit; + cs_entry = apm_cs_entry; + idle_cpu = ((apm_flags & APM_CPUIDLE_SLOW) != 0); + disabled = ((apm_flags & APM_DISABLED) != 0); + disengaged = ((apm_flags & APM_DISENGAGED) != 0); + + /* print bootstrap messages */ + printf(" found APM BIOS version %d.%d\n", dvp->id_unit, majorversion, minorversion); + printf("apm%d: Code32 0x%08x, Code16 0x%08x, Data 0x%08x\n", dvp->id_unit, cs32_base, cs16_base, ds_base); + printf("apm%d: Code entry 0x%08x, Idling CPU %s, Management %s\n", dvp->id_unit, cs_entry, is_enabled(idle_cpu), is_enabled(!disabled)); + + /* + * APM 1.0 does not have: + * + * 1. segment limit parameters + * + * 2. engage/disengage operations + */ + if (intversion >= INTVERSION(1, 1)) { + printf("apm%d: Engaged control %s\n", dvp->id_unit, is_enabled(!disengaged)); + } + else { + cs_limit = 0xffff; + ds_limit = 0xffff; + } + + /* setup GDT */ + setup_apm_gdt(cs32_base, cs16_base, ds_base, cs_limit, ds_limit); + + /* setup entry point 48bit pointer */ + apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL); + apm_addr.offset = cs_entry; + + /* enable power management */ + if (disabled) { + if (apm_enable_disable_pm(1)) { + printf("Warning: APM enable function failed! [%s]\n", apm_error()); + } + } + + /* engage power managment (APM 1.1 or later) */ + if (intversion >= INTVERSION(1, 1) && disengaged) { + if (apm_engage_disengage_pm(1)) { + printf("Warning: APM engage function failed [%s]\n", apm_error()); + } + } + + apm_suspend_hook_init(apm_default_suspend, "default suspend", APM_MAX_ORDER); + apm_resume_hook_init (apm_default_resume , "default resume" , APM_MIN_ORDER); + apm_initialized = 1; + + return 0; +} + +int +apmopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + if (!apm_initialized) { + return ENXIO; + } + switch (minor(dev)) { + case 0: /* apm0 */ + break; + defaults: + return (ENXIO); + } + return 0; +} + +int +apmclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + return 0; +} + +int +apmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) +{ + int error = 0; + int pl; + +#if 0 + printf("APM ioctl: minor = %d, cmd = 0x%x\n", minor(dev), cmd); +#endif + + pl = splhigh(); + if (minor(dev) != 0) { + return ENXIO; + } + if (!apm_initialized) { + return ENXIO; + } + switch (cmd) { + case APMIO_SUSPEND: + apm_suspend_resume(); + break; + case APMIO_GETINFO: + if (apm_get_info((apm_info_t)addr)) { + error = ENXIO; + } + break; + case APMIO_DEFEQV: + if (apm_def_eqv((apm_eqv_event_t)addr)) { + error = ENOSPC; + } + break; + case APMIO_FLUSHEQV: + apm_flush_eqv(); + break; + case APMIO_ENABLE: + apm_event_enable(); + break; + case APMIO_DISABLE: + apm_event_disable(); + break; + case APMIO_HALTCPU: + apm_halt_cpu(); + break; + case APMIO_NOTHALTCPU: + apm_not_halt_cpu(); + break; + default: + error = EINVAL; + break; + } + splx(pl); + return error; +} + +#endif /* NAPM > 0 */ diff --git a/sys/i386/apm/apm_init/Makefile b/sys/i386/apm/apm_init/Makefile new file mode 100644 index 0000000..22d6d60 --- /dev/null +++ b/sys/i386/apm/apm_init/Makefile @@ -0,0 +1,50 @@ +# +# LP (Laptop Package) +# +# (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> +# +# This software may be used, modified, copied, and distributed in +# both source and binary form provided that the above copyright and +# these terms are retained. Under no circumstances is the author +# responsible for the proper functioning of this software, nor does +# the author assume any responsibility for damages incurred with its +# use. +# +# Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) +# + +OBJS = apm_init.o real_prot.o table.o +CFLAGS = -DKERNEL -DINITIALIZER +OPTFLAGS = -O2 +I386INCDIR = ${.CURDIR}/../../include +INC= -I$(I386INCDIR) + +all: apm_init.inc + +.SUFFIXES: .c .S .o + +.c.o: + $(CC) $(CFLAGS) $(OPTFLAGS) $(INC) -c $< + +.S.o: + $(CC) $(CFLAGS) $(INC) -c $< + +apm_init.inc: apm_init bin2asm + ./bin2asm apm_init apm_init.inc + +apm_init: $(OBJS) + $(LD) -Bstatic -N -T 0 -o apm_init $(OBJS) + cp apm_init apm_init.sym + @strip apm_init + @sh ${.CURDIR}/rmaouthdr apm_init apm_init.tmp + @mv -f apm_init.tmp apm_init + +bin2asm: bin2asm.c + $(CC) -o bin2asm ${.CURDIR}/bin2asm.c + +allclean: clean + @rm -f apm_init.inc +clean: + @rm -f *.o apm_init apm_init.sym bin2asm + +.include <bsd.prog.mk> diff --git a/sys/i386/apm/apm_init/apm_init.S b/sys/i386/apm/apm_init/apm_init.S new file mode 100644 index 0000000..6c22571 --- /dev/null +++ b/sys/i386/apm/apm_init/apm_init.S @@ -0,0 +1,207 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* + * If you want to know the specification of APM BIOS, see the following + * documentations, + * + * [1] Intel Corporation and Microsoft Corporation, "Advanced Power + * Management, The Next Generation, Version 1.0", Feb.,1992. + * + * [2] Intel Corporation and Microsoft Corporation, "Advanced Power + * Management (APM) BIOS Interface Specification Revision 1.1", + * Sep.,1993, Intel Order Number: 241704-001, Microsoft Part + * Number: 781-110-X01 + * + * or contact + * + * APM Support Desk (Intel Corporation, US) + * TEL: (800)628-8686 + * FAX: (916)356-6100. + */ + + .file "apm_init.S" + +#define ASM + +#include "real_prot.h" +#include "apm_bios.h" +#include "apm_segments.h" + +/* + * APM BIOS initializer + * + * Return value: + * %eax 0xfffffff Can't find APM BIOS + * 0xffffffe Don't support 32bit connection + * 0xffffffd Connection error + * otherwise APM version (16bit BCD format) + * %ebx APM cs entry offset (32bit) + * %ecx lower 16bit APM 16bit cs base (real mode segment) + * upper 16bit APM 32bit cs base (real mode segment) + * %edx lower 16bit APM ds limit (real mode segment) + * upper 16bit [Reserved] + * %esi lower 16bit APM cs limit (APM 1.1 or later) + * upper 16bit APM ds limit (APM 1.1 or later) + * %edi bit0 = 1 16bit protected mode interface supported + * bit1 = 1 32bit protected mode interface supported + * bit2 = 1 "CPU idle" call slows processor clock speed + * bit3 = 1 APM BIOS Power Management disabled + * bit4 = 1 APM BIOS Power Management disengaged + */ + + .text +ENTRY(apm_init) + cli /* disable interrupt */ + push %ebp /* save original base pointer */ + /* ebp is used as a register variable */ + /* + * save old data segments: We assume that %ds == %es && %ds == %ss + */ + push %fs + movw %ds, %ax + movw %ax, %fs + movw $(APM_INIT_DS_SEL), %ax /* initializer data segment */ + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movl %esp, old_esp /* save original stack pointer */ + movl $0x10000, %esp /* setup temporary stack */ + /* (note that it isn't 0x00000000) */ + + sidt EXT(Idtr_prot) /* save current IDT */ + call EXT(prot_to_real) /* return to real mode */ + + /* + * APM installation check + */ + movb $(APM_BIOS), %ah + movb $(APM_INSTCHECK), %al + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) /* call system BIOS */ + cli + + jnc 1f /* if found, goto 1f */ + + data32 + call EXT(real_to_prot) /* come back again to protected mode */ + movl $(APMINI_CANTFIND), apm_version + /* can't find APM BIOS */ + jmp finish + +1: + movl %eax, %edx /* actually, movw %ax, %dx */ + /* save the value of %ax */ + data32 + call EXT(real_to_prot) /* come back again to protected mode */ + cmpb $0x50, %bh /* %bh == 'P'? */ + jnz 1f + cmpb $0x4d, %bl /* %bl == 'M'? */ + jz 2f + +1: + movl $(APMINI_CANTFIND), apm_version + /* can't find APM BIOS */ + jmp finish + +2: + testl $(APM_32BIT_SUPPORT), %ecx + /* supports 32bit connection? */ + jnz 1f + + movl $(APMINI_NOT32BIT), apm_version + /* don't support 32bit connection */ + jmp finish +1: + movl %edx, apm_version + andl $0x0000ffff, %ecx + movl %ecx, apm_flags + + /* + * APM Protected Mode 32-bit Interface Connect + */ + call EXT(prot_to_real) /* return to real mode */ + + movb $(APM_BIOS), %ah + movb $(APM_PROT32CONNECT), %al + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) + cli + jnc 1f /* if successed, go to 1f */ + data32 + call EXT(real_to_prot) + movl $(APMINI_CONNECTERR), apm_version + /* connection error */ + jmp finish +1: + /* save PM 32bit code segment into %bp */ + movl %eax, %ebp /* actually, movw %ax, %bp */ + data32 + call EXT(real_to_prot) + movl $0x0000ffff, %eax + andl %eax, %ebp /* 32bit cs base */ + andl %eax, %ecx /* 16bit cs base */ + andl %eax, %edx /* ds base */ + andl %eax, %esi /* cs length (APM 1.1 or later) */ + andl %eax, %edi /* ds length (APM 1.1 or later) */ + /* %ebx is code offset */ + /* pack 32bit cs and 16bit cs into %ecx */ + shll $16, %ebp + orl %ebp, %ecx + /* pack cs length and ds length into %esi */ + shll $16, %edi + orl %edi, %esi +finish: + cli + lidt EXT(Idtr_prot) /* restore old IDTR */ + movl old_esp, %esp /* restore old stack pointer */ + movl apm_version, %ebp /* stored to %eax later */ + movl apm_flags, %edi +#if 0 + movw $(BOOTSTRAP_DS_SEL), %ax + /* restore old data segments */ +#else + movw %fs, %ax +#endif + movw %ax, %ss + movw %ax, %es + movw %ax, %ds + movl %ebp, %eax + pop %fs + popl %ebp /* restore old base pointer */ + lret /* restore old code segment */ + + .data + + .globl EXT(ouraddr) +LEXT(ouraddr) + .long APM_OURADDR + +old_esp: + .long 0 +apm_version: + .long 0 +apm_flags: + .long 0 +old_ds: + .word 0 +old_es: + .word 0 +old_ss: + .word 0 diff --git a/sys/i386/apm/apm_init/apm_init.inc b/sys/i386/apm/apm_init/apm_init.inc new file mode 100644 index 0000000..d241334 --- /dev/null +++ b/sys/i386/apm/apm_init/apm_init.inc @@ -0,0 +1,59 @@ +/* This file is automatically generated by bin2asm */ +/* Original file is 'apm_init' */ + + .byte 0xfa, 0x55, 0x0f, 0xa0, 0x66, 0x8c, 0xd8, 0x66 + .byte 0x8e, 0xe0, 0x66, 0xb8, 0xf0, 0x00, 0x66, 0x8e + .byte 0xd8, 0x66, 0x8e, 0xc0, 0x66, 0x8e, 0xd0, 0x89 + .byte 0x25, 0x84, 0x01, 0x00, 0x00, 0xbc, 0x00, 0x00 + .byte 0x01, 0x00, 0x0f, 0x01, 0x0d, 0xa0, 0x01, 0x00 + .byte 0x00, 0xe8, 0x12, 0x01, 0x00, 0x00, 0xb4, 0x53 + .byte 0xb0, 0x00, 0x66, 0xbb, 0x00, 0x00, 0x00, 0x00 + .byte 0xfb, 0xcd, 0x15, 0xfa, 0x73, 0x15, 0x66, 0xe8 + .byte 0xcc, 0x00, 0x00, 0x00, 0xc7, 0x05, 0x88, 0x01 + .byte 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x8c + .byte 0x00, 0x00, 0x00, 0x89, 0xc2, 0x66, 0xe8, 0xb5 + .byte 0x00, 0x00, 0x00, 0x80, 0xff, 0x50, 0x75, 0x05 + .byte 0x80, 0xfb, 0x4d, 0x74, 0x0c, 0xc7, 0x05, 0x88 + .byte 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xeb + .byte 0x6e, 0xf7, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x75 + .byte 0x0c, 0xc7, 0x05, 0x88, 0x01, 0x00, 0x00, 0xfe + .byte 0xff, 0xff, 0xff, 0xeb, 0x5a, 0x89, 0x15, 0x88 + .byte 0x01, 0x00, 0x00, 0x81, 0xe1, 0xff, 0xff, 0x00 + .byte 0x00, 0x89, 0x0d, 0x8c, 0x01, 0x00, 0x00, 0xe8 + .byte 0xa4, 0x00, 0x00, 0x00, 0xb4, 0x53, 0xb0, 0x03 + .byte 0x66, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xcd + .byte 0x15, 0xfa, 0x73, 0x12, 0x66, 0xe8, 0x5e, 0x00 + .byte 0x00, 0x00, 0xc7, 0x05, 0x88, 0x01, 0x00, 0x00 + .byte 0xfd, 0xff, 0xff, 0xff, 0xeb, 0x21, 0x89, 0xc5 + .byte 0x66, 0xe8, 0x4a, 0x00, 0x00, 0x00, 0xb8, 0xff + .byte 0xff, 0x00, 0x00, 0x21, 0xc5, 0x21, 0xc1, 0x21 + .byte 0xc2, 0x21, 0xc6, 0x21, 0xc7, 0xc1, 0xe5, 0x10 + .byte 0x09, 0xe9, 0xc1, 0xe7, 0x10, 0x09, 0xfe, 0xfa + .byte 0x0f, 0x01, 0x1d, 0xa0, 0x01, 0x00, 0x00, 0x8b + .byte 0x25, 0x84, 0x01, 0x00, 0x00, 0x8b, 0x2d, 0x88 + .byte 0x01, 0x00, 0x00, 0x8b, 0x3d, 0x8c, 0x01, 0x00 + .byte 0x00, 0x66, 0x8c, 0xe0, 0x66, 0x8e, 0xd0, 0x66 + .byte 0x8e, 0xc0, 0x66, 0x8e, 0xd8, 0x89, 0xe8, 0x0f + .byte 0xa1, 0x5d, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0xfa, 0x0f, 0x20, 0xc0, 0x66, 0x83, 0xc8, 0x01 + .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x23, 0x01, 0x00 + .byte 0x00, 0xe8, 0x00, 0xb8, 0xf0, 0x00, 0x00, 0x00 + .byte 0x66, 0x8e, 0xd8, 0x66, 0x8e, 0xd0, 0x66, 0x8e + .byte 0xc0, 0x0f, 0x01, 0x1d, 0xa0, 0x01, 0x00, 0x00 + .byte 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0xa1, 0x80, 0x01, 0x00, 0x00, 0xc1, 0xf8, 0x04 + .byte 0x66, 0x50, 0x66, 0xb8, 0x62, 0x01, 0x66, 0x50 + .byte 0xea, 0x57, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x0f + .byte 0x20, 0xc0, 0x66, 0x83, 0xe0, 0xfe, 0x0f, 0x22 + .byte 0xc0, 0xcb, 0x66, 0x8c, 0xc8, 0x66, 0x8e, 0xd8 + .byte 0x66, 0x8e, 0xd0, 0x66, 0x8e, 0xc0, 0x67, 0x66 + .byte 0x0f, 0x01, 0x1d, 0xa6, 0x01, 0x00, 0x00, 0x66 + .byte 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +/* Total size = 0x01b0 */ diff --git a/sys/i386/apm/apm_init/bin2asm.c b/sys/i386/apm/apm_init/bin2asm.c new file mode 100644 index 0000000..b826e68 --- /dev/null +++ b/sys/i386/apm/apm_init/bin2asm.c @@ -0,0 +1,64 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include <stdio.h> + +#define NCOLS 8 + +int main(int argc, char *argv[]) +{ + int c, col; + FILE *infile, *outfile; + + if (argc != 3) { + fprintf(stderr, "Usage: %s infile outfile\n", argv[0]); + exit(1); + } + + if ((infile = fopen(argv[1], "rb")) == NULL) { + fprintf(stderr, "Can't open %s.\n", argv[1]); + exit(1); + } + + if ((outfile = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "Can't open %s.\n", argv[2]); + exit(1); + } + + col = 0; + + fprintf(outfile, "/* This file is automatically generated by bin2asm */\n"); + fprintf(outfile, "/* Original file is '%s' */\n\n", argv[1]); + + while ((c = fgetc(infile)) != EOF) { + if (col % NCOLS == 0) { + fprintf(outfile, "\t.byte\t"); + } + fprintf(outfile, "0x%02x", c); + if (col % NCOLS == NCOLS - 1) { + fprintf(outfile, "\n"); + } + else { + fprintf(outfile, ", "); + } + col++; + } + + fprintf(outfile, "\n/* Total size = 0x%04x */\n", col); + + fclose(infile); + fclose(outfile); + return 0; +} diff --git a/sys/i386/apm/apm_init/real_prot.S b/sys/i386/apm/apm_init/real_prot.S new file mode 100644 index 0000000..d61a394 --- /dev/null +++ b/sys/i386/apm/apm_init/real_prot.S @@ -0,0 +1,185 @@ +/* + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.2 92/04/04 11:34:13 rpd + * $Id: asm.S,v 1.2 1993/10/16 19:11:27 rgrimes Exp $ + */ + + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* + * Modified for APM BIOS initializer by HOSOKAWA Tatsumi + * + * See also locore.s. It supports these functions works correctly. + */ + + .file "real_prot.S" + +#include "real_prot.h" +#include "apm_segments.h" + +CR0_PE_ON = 0x1 +CR0_PE_OFF = 0xfffffffe + +.globl _ouraddr + .text + +/* + * + * real_to_prot() + * transfer from real mode to protected mode. + */ + +ENTRY(real_to_prot) + /* guarantee that interrupt is disabled when in prot mode */ + cli + + /* + * deleted for APM initializer by HOSOKAWA Tatsumi + * <hosoakwa@mt.cs.keio.ac.jp> + */ +#if 0 + /* load the gdtr */ + addr32 + data32 + lgdt EXT(Gdtr) +#endif + + /* set the PE bit of CR0 */ + mov %cr0, %eax + + data32 + or $CR0_PE_ON, %eax + mov %eax, %cr0 + + /* + * make intrasegment jump to flush the processor pipeline and + * reload CS register + */ + data32 + ljmp $(APM_INIT_CS_SEL), $xprot + +xprot: + /* + * we are in USE32 mode now + * set up the protected mode segment registers : DS, SS, ES + */ + mov $(APM_INIT_DS_SEL), %eax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* load idtr so we can debug */ + lidt EXT(Idtr_prot) + + ret + +/* + * + * prot_to_real() + * transfer from protected mode to real mode + * + */ + +ENTRY(prot_to_real) + + /* set up a dummy stack frame for the second seg change. */ + movl _ouraddr, %eax + sarl $4, %eax + pushw %ax + movw $xreal, %ax /* gas botches pushw $xreal - extra bytes 0, 0*/ + pushw %ax /* decode to add %al, (%eax) (%al usually 0) */ + + /* Change to use16 mode. */ + ljmp $(APM_INIT_CS16_SEL), $x16 + +x16: + /* clear the PE bit of CR0 */ + mov %cr0, %eax + data32 + and $CR0_PE_OFF, %eax + mov %eax, %cr0 + + /* + * make intersegment jmp to flush the processor pipeline + * using the fake stack frame set up earlier + * and reload CS register + */ + lret + +xreal: + /* + * we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* load idtr so we can debug */ + addr32 + data32 + lidt EXT(Idtr_real) + + data32 + ret diff --git a/sys/i386/apm/apm_init/real_prot.h b/sys/i386/apm/apm_init/real_prot.h new file mode 100644 index 0000000..bc02200 --- /dev/null +++ b/sys/i386/apm/apm_init/real_prot.h @@ -0,0 +1,56 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.7 92/02/29 15:33:41 rpd + * $Id: asm.h,v 1.3 1993/10/16 19:11:29 rgrimes Exp $ + */ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* + * Modified to APM BIOS initializer by HOSOKAWA, Tatsumi + */ + +#define ALIGN 4 +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : + +#define addr32 .byte 0x67 +#define data32 .byte 0x66 + +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) diff --git a/sys/i386/apm/apm_init/rmaouthdr b/sys/i386/apm/apm_init/rmaouthdr new file mode 100644 index 0000000..47838b0 --- /dev/null +++ b/sys/i386/apm/apm_init/rmaouthdr @@ -0,0 +1,6 @@ +#!/bin/csh -f +# +# from: Mach, Revision 2.2 92/04/04 11:36:01 rpd +# $Id: rmaouthdr,v 1.3 1993/10/16 19:11:37 rgrimes Exp $ +# +dd if=$1 of=$2 ibs=32 skip=1 obs=1024b diff --git a/sys/i386/apm/apm_init/table.c b/sys/i386/apm/apm_init/table.c new file mode 100644 index 0000000..eaf2fc6 --- /dev/null +++ b/sys/i386/apm/apm_init/table.c @@ -0,0 +1,24 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include <apm_bios.h> + +struct pseudo_desc { + unsigned short limit; + unsigned long base __attribute__ ((packed)); +}; + +struct pseudo_desc Idtr_prot = { 0, 0 }; /* filled on run time */ +struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0 }; diff --git a/sys/i386/apm/apm_setup.h b/sys/i386/apm/apm_setup.h new file mode 100644 index 0000000..0009e56 --- /dev/null +++ b/sys/i386/apm/apm_setup.h @@ -0,0 +1,23 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, distributed, and sold, + * in both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +extern u_long apm_version; +extern u_long apm_cs_entry; +extern u_short apm_cs32_base; +extern u_short apm_cs16_base; +extern u_short apm_ds_base; +extern u_short apm_cs_limit; +extern u_short apm_ds_limit; +extern u_short apm_flags; diff --git a/sys/i386/apm/apm_setup.s b/sys/i386/apm/apm_setup.s new file mode 100644 index 0000000..df1e9c9 --- /dev/null +++ b/sys/i386/apm/apm_setup.s @@ -0,0 +1,126 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, distributed, and sold, + * in both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#ifdef APM + +#define ASM + +#include <machine/asmacros.h> +#include "assym.s" +#include <machine/apm_bios.h> + + .file "apm_setup.s" + + .text + + /* void call_apm(union real_regs *); */ +_call_apm: + .globl _call_apm + pushl %ebp + movl %esp, %ebp + pushl %esi + pushl %edi + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax + movl %eax, struct_regs + movw 2(%eax), %bx + movw 4(%eax), %cx + movw 6(%eax), %dx + movw 8(%eax), %si + movw 10(%eax), %di + movw 0(%eax), %ax + + lcall _apm_addr /* intersegment call */ + + setc cf_result + movb %ah, _apm_errno + push %eax + movl struct_regs, %eax + movw %bx, 2(%eax) + movw %cx, 4(%eax) + movw %dx, 6(%eax) + movw %si, 8(%eax) + movw %di, 10(%eax) + movb cf_result, %bl + xorb %bh, %bh + movw %bx, 12(%eax) + popl %ebx + movl %ebx, 0(%eax) + + popl %ecx + popl %ebx + popl %edi + popl %esi + leave + ret + + .data +struct_regs: + .long 0 + +cf_result: + .byte 0 + +_apm_errno: + .globl _apm_errno + .byte 0 + + .data +_apm_init_image: + .globl _apm_init_image + +1: +#include "apm_init/apm_init.inc" +2: + +_apm_init_image_size: + .globl _apm_init_image_size + .long 2b - 1b + +_apm_version: + .globl _apm_version + .long 0 + +_apm_cs_entry: + .globl _apm_cs_entry + .long 0 + +_apm_cs16_base: + .globl _apm_cs16_base + .word 0 + +_apm_cs32_base: + .globl _apm_cs32_base + .word 0 + +_apm_ds_base: + .globl _apm_ds_base + .word 0 + +_apm_cs_limit: + .globl _apm_cs_limit + .word 0 + +_apm_ds_limit: + .globl _apm_ds_limit + .word 0 + +_apm_flags: + .globl _apm_flags + .word 0 + +#endif /* APM */ diff --git a/sys/i386/bios/apm.c b/sys/i386/bios/apm.c new file mode 100644 index 0000000..3660844 --- /dev/null +++ b/sys/i386/bios/apm.c @@ -0,0 +1,823 @@ +/* + * LP (Laptop Package) + * + * Copyright (c) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep, 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include "apm.h" + +#if NAPM > 0 + +#include <sys/param.h> +#include "conf.h" +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/file.h> +#include <sys/proc.h> +#include <sys/vnode.h> +#include "i386/isa/isa.h" +#include "i386/isa/isa_device.h" +#include <machine/apm_bios.h> +#include <machine/segments.h> +#include <vm/vm.h> +#include <sys/syslog.h> +#include "apm_setup.h" + +/* static data */ +static int apm_initialized = 0, active = 0, halt_cpu = 1; +static u_int minorversion, majorversion; +static u_int cs32_base, cs16_base, ds_base; +static u_int cs_limit, ds_limit; +static u_int cs_entry; +static u_int intversion; +static int idle_cpu, disabled, disengaged; + +/* Map version number to integer (keeps ordering of version numbers) */ +#define INTVERSION(major, minor) ((major)*100 + (minor)) + +static timeout_t apm_timeout; + +/* setup APM GDT discriptors */ +static void +setup_apm_gdt(u_int code32_base, u_int code16_base, u_int data_base, u_int code_limit, u_int data_limit) +{ + /* setup 32bit code segment */ + gdt_segs[GAPMCODE32_SEL].ssd_base = code32_base; + gdt_segs[GAPMCODE32_SEL].ssd_limit = code_limit; + + /* setup 16bit code segment */ + gdt_segs[GAPMCODE16_SEL].ssd_base = code16_base; + gdt_segs[GAPMCODE16_SEL].ssd_limit = code_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); + ssdtosd(gdt_segs + GAPMCODE16_SEL, gdt + GAPMCODE16_SEL); + ssdtosd(gdt_segs + GAPMDATA_SEL , gdt + GAPMDATA_SEL ); +} + +/* 48bit far pointer */ +struct addr48 { + u_long offset; + u_short segment; +} apm_addr; + + +/* register structure for BIOS call */ +union real_regs { + struct xregs { + u_short ax; + u_short bx __attribute__ ((packed)); + u_short cx __attribute__ ((packed)); + u_short dx __attribute__ ((packed)); + u_short si __attribute__ ((packed)); + u_short di __attribute__ ((packed)); + u_short cf __attribute__ ((packed)); /* carry */ + } x; + struct hlregs { + u_char al; + u_char ah __attribute__ ((packed)); + u_char bl __attribute__ ((packed)); + u_char bh __attribute__ ((packed)); + u_char cl __attribute__ ((packed)); + u_char ch __attribute__ ((packed)); + u_char dl __attribute__ ((packed)); + u_char dh __attribute__ ((packed)); + u_short si __attribute__ ((packed)); + u_short di __attribute__ ((packed)); + u_short cf __attribute__ ((packed)); /* carry */ + } hl; +}; + + +/* call APM BIOS */ +extern void call_apm(union real_regs* regs); + +extern u_char apm_errno; + +/* enable/disable power management */ +static int +apm_enable_disable_pm(int enable) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_ENABLEDISABLEPM; + if (intversion >= INTVERSION(1, 1)) { + regs.x.bx = PMDV_ALLDEV; + } + else { + regs.x.bx = 0xffff; /* APM version 1.0 only */ + } + regs.x.cx = enable; + call_apm(®s); + return regs.x.cf; +} + +/* engage/disengage power management (APM 1.1 or later) */ +static int +apm_engage_disengage_pm(int engage) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_ENGAGEDISENGAGEPM; + regs.x.bx = PMDV_ALLDEV; + regs.x.cx = engage; + call_apm(®s); + return regs.x.cf; +} + +/* get PM event */ +static u_int +apm_getevent(void) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_GETPMEVENT; + call_apm(®s); + if (regs.x.cf) { +#if 0 + printf("No event: errcode = %d\n", apm_errno); +#endif + return PMEV_NOEVENT; + } + return (u_int)regs.x.bx; +} + +/* + * In many cases, the first event that occured after resume, needs + * special treatment. This binary flag make this process possible. + * Initial value of this variable is 1, because the bootstrap + * condition is equivalent to resumed condition for the power + * manager. + */ +static int resumed_event = 1; + +/* suspend entire system */ +static int +apm_suspend_system(void) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_SETPWSTATE; + regs.x.bx = PMDV_ALLDEV; + regs.x.cx = PMST_SUSPEND; + call_apm(®s); + if (regs.x.cf) { + printf("Entire system suspend failure: errcode = %d\n", apm_errno); + return 1; + } + resumed_event = 1; + + return 0; +} + +/* APM Battery low handler */ +static void +apm_battery_low(void) +{ + /* Currently, this routine has not been implemented. Sorry... */ +} + + +/* APM driver calls some functions automatically when the system wakes up */ +static void +apm_execute_hook(apm_hook_func_t list) +{ + apm_hook_func_t p; + + for (p = list; p != NULL; p = p->next) { + if ((*(p->func))()) { + printf("Warning: APM hook of %s failed", p->name); + } + } +} + + +/* APM hook manager */ +static apm_hook_func_t +apm_hook_init(apm_hook_func_t *list, int (*func)(void), char *name, int order) +{ + int pl; + apm_hook_func_t p, prev, new_node; + + pl = splhigh(); + new_node = malloc(sizeof(*new_node), M_DEVBUF, M_NOWAIT); + if (new_node == NULL) { + panic("Can't allocate device buffer for apm_resume_hook."); + } + new_node->func = func; + new_node->name = name; +#if 0 + new_node->next = *list; + *list = new_node; +#else + prev = NULL; + for (p = *list; p != NULL; prev = p, p = p->next) { + if (p->order > order) { + break; + } + } + + if (prev == NULL) { + new_node->next = *list; + *list = new_node; + } + else { + new_node->next = prev->next; + prev->next = new_node; + } +#endif + splx(pl); + return new_node; +} + +void +apm_hook_delete(apm_hook_func_t *list, apm_hook_func_t delete_node) +{ + int pl; + apm_hook_func_t p, prev; + + pl = splhigh(); + prev = NULL; + for (p = *list; p != NULL; prev = p, p = p->next) { + if (p == delete_node) { + goto deleteit; + } + } + panic("Tried to delete unregistered apm_resume_hook."); + goto nosuchnode; +deleteit: + if (prev != NULL) { + prev->next = p->next; + } + else { + *list = p->next; + } + free(delete_node, M_DEVBUF); +nosuchnode: + splx(pl); +} + +static struct timeval suspend_time; + +/* default APM hook functions */ +static int +apm_default_resume(void) +{ + u_int second, minute, hour; + struct timeval resume_time; + + inittodr(0); /* adjust time to RTC */ + microtime(&resume_time); + second = resume_time.tv_sec - suspend_time.tv_sec; + hour = second / 3600; + second %= 3600; + minute = second / 60; + second %= 60; + log(LOG_NOTICE, "resumed from suspended mode (slept %02d:%02d:%02d)\n", hour, minute, second); + return 0; +} + +static int +apm_default_suspend(void) +{ + int pl; +#if 0 + pl = splhigh(); + sync(curproc, NULL, NULL); + splx(pl); +#endif + microtime(&suspend_time); + return 0; +} + +/* list structure for hook */ +static apm_hook_func_t apm_resume_hook = NULL; +static apm_hook_func_t apm_suspend_hook = NULL; + +/* execute resume hook */ +static void +apm_execute_resume_hook(void) +{ + apm_execute_hook(apm_resume_hook); +} + +/* add a node on resume hook */ +apm_hook_func_t +apm_resume_hook_init(int (*func)(void), char *name, int order) +{ + return apm_hook_init(&apm_resume_hook, func, name, order); +} + +/* delete a node from resume hook */ +void +apm_resume_hook_delete(apm_hook_func_t delete_node) +{ + apm_hook_delete(&apm_resume_hook, delete_node); +} + +/* execute suspend hook */ +static void +apm_execute_suspend_hook(void) +{ + apm_execute_hook(apm_suspend_hook); +} + +/* add a node on resume hook */ +apm_hook_func_t +apm_suspend_hook_init(int (*func)(void), char *name, int order) +{ + return apm_hook_init(&apm_suspend_hook, func, name, order); +} + +/* delete a node from resume hook */ +void +apm_suspend_hook_delete(apm_hook_func_t delete_node) +{ + apm_hook_delete(&apm_suspend_hook, delete_node); +} + +/* get APM information */ +static int +apm_get_info(apm_info_t aip) +{ + union real_regs regs; + + regs.hl.ah = APM_BIOS; + regs.hl.al = APM_GETPWSTATUS; + regs.x.bx = PMDV_ALLDEV; + call_apm(®s); + if (regs.x.cf) { + printf("Get APM info failure: errcode = %d\n", apm_errno); + return 1; + } + aip->ai_major = (u_int)majorversion; + aip->ai_minor = (u_int)minorversion; + aip->ai_acline = (u_int)regs.hl.bh; + aip->ai_batt_stat = (u_int)regs.hl.bl; + aip->ai_batt_life = (u_int)regs.hl.cl; + return 0; +} + + +/* Define equivalent event sets */ + +static int equiv_event_num = 0; +static struct apm_eqv_event equiv_events[APM_MAX_EQUIV_EVENTS]; + +static int +apm_def_eqv(apm_eqv_event_t aee) +{ + if (equiv_event_num == APM_MAX_EQUIV_EVENTS) { + return 1; + } + memcpy(&equiv_events[equiv_event_num], aee, sizeof(struct apm_eqv_event)); + equiv_event_num++; + return 0; +} + +static void +apm_flush_eqv(void) +{ + equiv_event_num = 0; +} + +static void apm_processevent(void); + +/* + * Public interface to the suspend/resume: + * + * Execute suspend and resume hook before and after sleep, respectively. + */ + +void +apm_suspend_resume(void) +{ + int pl; +#if 0 + printf("Called apm_suspend_resume();\n"); +#endif + if (apm_initialized) { + apm_execute_suspend_hook(); + apm_suspend_system(); + apm_execute_resume_hook(); + apm_processevent(); + } +} + +/* inform APM BIOS that CPU is idle */ +void +apm_cpu_idle(void) +{ + if (idle_cpu) { + if (active) { + asm("movw $0x5305, %ax; lcall _apm_addr"); + } + } + /* + * Some APM implementation halts CPU in BIOS, whenever + * "CPU-idle" function are invoked, but swtch() of + * FreeBSD halts CPU, therefore, CPU is halted twice + * in the sched loop. It makes the interrupt latency + * terribly long and be able to cause a serious problem + * in interrupt processing. We prevent it by removing + * "hlt" operation from swtch() and managed it under + * APM driver. + */ + if (!active || halt_cpu) { + asm("sti ; hlt"); /* wait for interrupt */ + } +} + +/* inform APM BIOS that CPU is busy */ +void +apm_cpu_busy(void) +{ + if (idle_cpu && active) { + asm("movw $0x5306, %ax; lcall _apm_addr"); + } +} + + +/* + * APM timeout routine: + * + * This routine is automatically called by timer two times within one + * seconed. + */ + +static void +apm_timeout(void *arg1) +{ +#if 0 + printf("Called apm_timeout\n"); +#endif + apm_processevent(); + timeout(apm_timeout, NULL, hz / 2); /* 2 Hz */ + /* APM driver must polls APM event a time per second */ +} + +/* enable APM BIOS */ +static void +apm_event_enable(void) +{ +#if 0 + printf("called apm_event_enable()\n"); +#endif + if (apm_initialized) { + active = 1; + timeout(apm_timeout, NULL, 2 * hz); + } +} + +/* disable APM BIOS */ +static void +apm_event_disable(void) +{ +#if 0 + printf("called apm_event_disable()\n"); +#endif + if (apm_initialized) { + untimeout(apm_timeout, NULL); + active = 0; + } +} + +/* halt CPU in scheduling loop */ +static void apm_halt_cpu(void) +{ + if (apm_initialized) { + halt_cpu = 1; + } +} + +/* don't halt CPU in scheduling loop */ +static void apm_not_halt_cpu(void) +{ + if (apm_initialized) { + halt_cpu = 0; + } +} + +/* device driver definitions */ +int apmprobe (struct isa_device *); +int apmattach(struct isa_device *); + +struct isa_driver apmdriver = { apmprobe, apmattach, "apm" }; + + +/* + * probe APM (dummy): + * + * APM probing routine is placed on locore.s and apm_init.S because + * this process forces the CPU to turn to real mode or V86 mode. + * Current version uses real mode, but on future version, we want + * to use V86 mode in APM initialization. + */ +int +apmprobe(struct isa_device *dvp) +{ + switch (apm_version) { + case APMINI_CANTFIND: + /* silent */ + return 0; + case APMINI_NOT32BIT: + printf("apm%d: 32bit connection is not supported.\n", dvp->id_unit); + return 0; + case APMINI_CONNECTERR: + printf("apm%d: 32-bit connection error.\n", dvp->id_unit); + return 0; + } + return -1; +} + +static const char * +is_enabled(int enabled) +{ + if (enabled) { + return "enabled"; + } + return "disabled"; +} + +static const char * +apm_error(void) +{ + static char buffer[64]; + + switch (apm_errno) { + case 0: + return "APM OK."; + default: + sprintf(buffer, "Unknown Error 0x%x", (u_int)apm_errno); + return buffer; + } +} + + + +/* Process APM event */ +static void +apm_processevent(void) +{ + int i, apm_event; + +getevent: + while (1) { + if ((apm_event = apm_getevent()) == PMEV_NOEVENT) { + break; + } +#if 0 +#if 1 +#define OPMEV_DEBUGMESSAGE(symbol) case symbol: break; +#else +#define OPMEV_DEBUGMESSAGE(symbol) case symbol: printf("Original APM Event: " #symbol "\n"); break +#endif + switch (apm_event) { + OPMEV_DEBUGMESSAGE(PMEV_NOEVENT); + OPMEV_DEBUGMESSAGE(PMEV_STANDBYREQ); + OPMEV_DEBUGMESSAGE(PMEV_SUSPENDREQ); + OPMEV_DEBUGMESSAGE(PMEV_NORMRESUME); + OPMEV_DEBUGMESSAGE(PMEV_CRITRESUME); + OPMEV_DEBUGMESSAGE(PMEV_BATTERYLOW); + OPMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE); + OPMEV_DEBUGMESSAGE(PMEV_UPDATETIME); + OPMEV_DEBUGMESSAGE(PMEV_CRITSUSPEND); + OPMEV_DEBUGMESSAGE(PMEV_USERSUSPENDREQ); + OPMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME); + default: + printf("Unknown Original APM Event 0x%x\n", apm_event); + break; + } +#endif + for (i = 0; i < equiv_event_num; i++) { + if (equiv_events[i].aee_event == apm_event) { + u_int tmp = PMEV_DEFAULT; + if (resumed_event) { + tmp = equiv_events[i].aee_resume; + } + else { + tmp = equiv_events[i].aee_equiv; + } + if (tmp != PMEV_DEFAULT) { + apm_event = tmp; + break; + } + } + } +#if 1 +#if 1 +#define PMEV_DEBUGMESSAGE(symbol) case symbol: break; +#else +#define PMEV_DEBUGMESSAGE(symbol) case symbol: printf("APM Event: " #symbol "\n"); break +#endif + switch (apm_event) { + PMEV_DEBUGMESSAGE(PMEV_NOEVENT); + PMEV_DEBUGMESSAGE(PMEV_STANDBYREQ); + PMEV_DEBUGMESSAGE(PMEV_SUSPENDREQ); + PMEV_DEBUGMESSAGE(PMEV_NORMRESUME); + PMEV_DEBUGMESSAGE(PMEV_CRITRESUME); + PMEV_DEBUGMESSAGE(PMEV_BATTERYLOW); + PMEV_DEBUGMESSAGE(PMEV_POWERSTATECHANGE); + PMEV_DEBUGMESSAGE(PMEV_UPDATETIME); + PMEV_DEBUGMESSAGE(PMEV_CRITSUSPEND); + PMEV_DEBUGMESSAGE(PMEV_USERSUSPENDREQ); + PMEV_DEBUGMESSAGE(PMEV_STANDBYRESUME); + default: + printf("Unknown APM Event 0x%x\n", apm_event); + break; + } +#endif + switch (apm_event) { + case PMEV_NOEVENT: + case PMEV_STANDBYREQ: + case PMEV_POWERSTATECHANGE: + case PMEV_CRITSUSPEND: + case PMEV_USERSTANDBYREQ: + case PMEV_USERSUSPENDREQ: + break; + case PMEV_BATTERYLOW: + apm_battery_low(); + break; + case PMEV_SUSPENDREQ: + apm_suspend_resume(); + break; + case PMEV_NORMRESUME: + case PMEV_CRITRESUME: + case PMEV_UPDATETIME: + case PMEV_STANDBYRESUME: + inittodr(0); /* adjust time to RTC */ + break; + } + } + resumed_event = 0; +} + + +/* + * Attach APM: + * + * Initialize APM driver (APM BIOS itself has been initialized in locore.s) + */ + +int +apmattach(struct isa_device *dvp) +{ + + /* setup APM parameters */ + minorversion = ((apm_version & 0x00f0) >> 4) * 10 + ((apm_version & 0x000f) >> 0); + majorversion = ((apm_version & 0xf000) >> 12) * 10 + ((apm_version & 0x0f00) >> 8); + intversion = INTVERSION(majorversion, minorversion); + cs32_base = (apm_cs32_base << 4) + KERNBASE; + cs16_base = (apm_cs16_base << 4) + KERNBASE; + ds_base = (apm_ds_base << 4) + KERNBASE; + cs_limit = apm_cs_limit; + ds_limit = apm_ds_limit; + cs_entry = apm_cs_entry; + idle_cpu = ((apm_flags & APM_CPUIDLE_SLOW) != 0); + disabled = ((apm_flags & APM_DISABLED) != 0); + disengaged = ((apm_flags & APM_DISENGAGED) != 0); + + /* print bootstrap messages */ + printf(" found APM BIOS version %d.%d\n", dvp->id_unit, majorversion, minorversion); + printf("apm%d: Code32 0x%08x, Code16 0x%08x, Data 0x%08x\n", dvp->id_unit, cs32_base, cs16_base, ds_base); + printf("apm%d: Code entry 0x%08x, Idling CPU %s, Management %s\n", dvp->id_unit, cs_entry, is_enabled(idle_cpu), is_enabled(!disabled)); + + /* + * APM 1.0 does not have: + * + * 1. segment limit parameters + * + * 2. engage/disengage operations + */ + if (intversion >= INTVERSION(1, 1)) { + printf("apm%d: Engaged control %s\n", dvp->id_unit, is_enabled(!disengaged)); + } + else { + cs_limit = 0xffff; + ds_limit = 0xffff; + } + + /* setup GDT */ + setup_apm_gdt(cs32_base, cs16_base, ds_base, cs_limit, ds_limit); + + /* setup entry point 48bit pointer */ + apm_addr.segment = GSEL(GAPMCODE32_SEL, SEL_KPL); + apm_addr.offset = cs_entry; + + /* enable power management */ + if (disabled) { + if (apm_enable_disable_pm(1)) { + printf("Warning: APM enable function failed! [%s]\n", apm_error()); + } + } + + /* engage power managment (APM 1.1 or later) */ + if (intversion >= INTVERSION(1, 1) && disengaged) { + if (apm_engage_disengage_pm(1)) { + printf("Warning: APM engage function failed [%s]\n", apm_error()); + } + } + + apm_suspend_hook_init(apm_default_suspend, "default suspend", APM_MAX_ORDER); + apm_resume_hook_init (apm_default_resume , "default resume" , APM_MIN_ORDER); + apm_initialized = 1; + + return 0; +} + +int +apmopen(dev_t dev, int flag, int fmt, struct proc *p) +{ + if (!apm_initialized) { + return ENXIO; + } + switch (minor(dev)) { + case 0: /* apm0 */ + break; + defaults: + return (ENXIO); + } + return 0; +} + +int +apmclose(dev_t dev, int flag, int fmt, struct proc *p) +{ + return 0; +} + +int +apmioctl(dev_t dev, int cmd, caddr_t addr, int flag, struct proc *p) +{ + int error = 0; + int pl; + +#if 0 + printf("APM ioctl: minor = %d, cmd = 0x%x\n", minor(dev), cmd); +#endif + + pl = splhigh(); + if (minor(dev) != 0) { + return ENXIO; + } + if (!apm_initialized) { + return ENXIO; + } + switch (cmd) { + case APMIO_SUSPEND: + apm_suspend_resume(); + break; + case APMIO_GETINFO: + if (apm_get_info((apm_info_t)addr)) { + error = ENXIO; + } + break; + case APMIO_DEFEQV: + if (apm_def_eqv((apm_eqv_event_t)addr)) { + error = ENOSPC; + } + break; + case APMIO_FLUSHEQV: + apm_flush_eqv(); + break; + case APMIO_ENABLE: + apm_event_enable(); + break; + case APMIO_DISABLE: + apm_event_disable(); + break; + case APMIO_HALTCPU: + apm_halt_cpu(); + break; + case APMIO_NOTHALTCPU: + apm_not_halt_cpu(); + break; + default: + error = EINVAL; + break; + } + splx(pl); + return error; +} + +#endif /* NAPM > 0 */ diff --git a/sys/i386/bios/apm_init/Makefile b/sys/i386/bios/apm_init/Makefile new file mode 100644 index 0000000..22d6d60 --- /dev/null +++ b/sys/i386/bios/apm_init/Makefile @@ -0,0 +1,50 @@ +# +# LP (Laptop Package) +# +# (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> +# +# This software may be used, modified, copied, and distributed in +# both source and binary form provided that the above copyright and +# these terms are retained. Under no circumstances is the author +# responsible for the proper functioning of this software, nor does +# the author assume any responsibility for damages incurred with its +# use. +# +# Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) +# + +OBJS = apm_init.o real_prot.o table.o +CFLAGS = -DKERNEL -DINITIALIZER +OPTFLAGS = -O2 +I386INCDIR = ${.CURDIR}/../../include +INC= -I$(I386INCDIR) + +all: apm_init.inc + +.SUFFIXES: .c .S .o + +.c.o: + $(CC) $(CFLAGS) $(OPTFLAGS) $(INC) -c $< + +.S.o: + $(CC) $(CFLAGS) $(INC) -c $< + +apm_init.inc: apm_init bin2asm + ./bin2asm apm_init apm_init.inc + +apm_init: $(OBJS) + $(LD) -Bstatic -N -T 0 -o apm_init $(OBJS) + cp apm_init apm_init.sym + @strip apm_init + @sh ${.CURDIR}/rmaouthdr apm_init apm_init.tmp + @mv -f apm_init.tmp apm_init + +bin2asm: bin2asm.c + $(CC) -o bin2asm ${.CURDIR}/bin2asm.c + +allclean: clean + @rm -f apm_init.inc +clean: + @rm -f *.o apm_init apm_init.sym bin2asm + +.include <bsd.prog.mk> diff --git a/sys/i386/bios/apm_init/apm_init.S b/sys/i386/bios/apm_init/apm_init.S new file mode 100644 index 0000000..6c22571 --- /dev/null +++ b/sys/i386/bios/apm_init/apm_init.S @@ -0,0 +1,207 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* + * If you want to know the specification of APM BIOS, see the following + * documentations, + * + * [1] Intel Corporation and Microsoft Corporation, "Advanced Power + * Management, The Next Generation, Version 1.0", Feb.,1992. + * + * [2] Intel Corporation and Microsoft Corporation, "Advanced Power + * Management (APM) BIOS Interface Specification Revision 1.1", + * Sep.,1993, Intel Order Number: 241704-001, Microsoft Part + * Number: 781-110-X01 + * + * or contact + * + * APM Support Desk (Intel Corporation, US) + * TEL: (800)628-8686 + * FAX: (916)356-6100. + */ + + .file "apm_init.S" + +#define ASM + +#include "real_prot.h" +#include "apm_bios.h" +#include "apm_segments.h" + +/* + * APM BIOS initializer + * + * Return value: + * %eax 0xfffffff Can't find APM BIOS + * 0xffffffe Don't support 32bit connection + * 0xffffffd Connection error + * otherwise APM version (16bit BCD format) + * %ebx APM cs entry offset (32bit) + * %ecx lower 16bit APM 16bit cs base (real mode segment) + * upper 16bit APM 32bit cs base (real mode segment) + * %edx lower 16bit APM ds limit (real mode segment) + * upper 16bit [Reserved] + * %esi lower 16bit APM cs limit (APM 1.1 or later) + * upper 16bit APM ds limit (APM 1.1 or later) + * %edi bit0 = 1 16bit protected mode interface supported + * bit1 = 1 32bit protected mode interface supported + * bit2 = 1 "CPU idle" call slows processor clock speed + * bit3 = 1 APM BIOS Power Management disabled + * bit4 = 1 APM BIOS Power Management disengaged + */ + + .text +ENTRY(apm_init) + cli /* disable interrupt */ + push %ebp /* save original base pointer */ + /* ebp is used as a register variable */ + /* + * save old data segments: We assume that %ds == %es && %ds == %ss + */ + push %fs + movw %ds, %ax + movw %ax, %fs + movw $(APM_INIT_DS_SEL), %ax /* initializer data segment */ + movw %ax, %ds + movw %ax, %es + movw %ax, %ss + movl %esp, old_esp /* save original stack pointer */ + movl $0x10000, %esp /* setup temporary stack */ + /* (note that it isn't 0x00000000) */ + + sidt EXT(Idtr_prot) /* save current IDT */ + call EXT(prot_to_real) /* return to real mode */ + + /* + * APM installation check + */ + movb $(APM_BIOS), %ah + movb $(APM_INSTCHECK), %al + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) /* call system BIOS */ + cli + + jnc 1f /* if found, goto 1f */ + + data32 + call EXT(real_to_prot) /* come back again to protected mode */ + movl $(APMINI_CANTFIND), apm_version + /* can't find APM BIOS */ + jmp finish + +1: + movl %eax, %edx /* actually, movw %ax, %dx */ + /* save the value of %ax */ + data32 + call EXT(real_to_prot) /* come back again to protected mode */ + cmpb $0x50, %bh /* %bh == 'P'? */ + jnz 1f + cmpb $0x4d, %bl /* %bl == 'M'? */ + jz 2f + +1: + movl $(APMINI_CANTFIND), apm_version + /* can't find APM BIOS */ + jmp finish + +2: + testl $(APM_32BIT_SUPPORT), %ecx + /* supports 32bit connection? */ + jnz 1f + + movl $(APMINI_NOT32BIT), apm_version + /* don't support 32bit connection */ + jmp finish +1: + movl %edx, apm_version + andl $0x0000ffff, %ecx + movl %ecx, apm_flags + + /* + * APM Protected Mode 32-bit Interface Connect + */ + call EXT(prot_to_real) /* return to real mode */ + + movb $(APM_BIOS), %ah + movb $(APM_PROT32CONNECT), %al + data32 + movl $(PMDV_APMBIOS), %ebx + sti + int $(SYSTEM_BIOS) + cli + jnc 1f /* if successed, go to 1f */ + data32 + call EXT(real_to_prot) + movl $(APMINI_CONNECTERR), apm_version + /* connection error */ + jmp finish +1: + /* save PM 32bit code segment into %bp */ + movl %eax, %ebp /* actually, movw %ax, %bp */ + data32 + call EXT(real_to_prot) + movl $0x0000ffff, %eax + andl %eax, %ebp /* 32bit cs base */ + andl %eax, %ecx /* 16bit cs base */ + andl %eax, %edx /* ds base */ + andl %eax, %esi /* cs length (APM 1.1 or later) */ + andl %eax, %edi /* ds length (APM 1.1 or later) */ + /* %ebx is code offset */ + /* pack 32bit cs and 16bit cs into %ecx */ + shll $16, %ebp + orl %ebp, %ecx + /* pack cs length and ds length into %esi */ + shll $16, %edi + orl %edi, %esi +finish: + cli + lidt EXT(Idtr_prot) /* restore old IDTR */ + movl old_esp, %esp /* restore old stack pointer */ + movl apm_version, %ebp /* stored to %eax later */ + movl apm_flags, %edi +#if 0 + movw $(BOOTSTRAP_DS_SEL), %ax + /* restore old data segments */ +#else + movw %fs, %ax +#endif + movw %ax, %ss + movw %ax, %es + movw %ax, %ds + movl %ebp, %eax + pop %fs + popl %ebp /* restore old base pointer */ + lret /* restore old code segment */ + + .data + + .globl EXT(ouraddr) +LEXT(ouraddr) + .long APM_OURADDR + +old_esp: + .long 0 +apm_version: + .long 0 +apm_flags: + .long 0 +old_ds: + .word 0 +old_es: + .word 0 +old_ss: + .word 0 diff --git a/sys/i386/bios/apm_init/apm_init.inc b/sys/i386/bios/apm_init/apm_init.inc new file mode 100644 index 0000000..d241334 --- /dev/null +++ b/sys/i386/bios/apm_init/apm_init.inc @@ -0,0 +1,59 @@ +/* This file is automatically generated by bin2asm */ +/* Original file is 'apm_init' */ + + .byte 0xfa, 0x55, 0x0f, 0xa0, 0x66, 0x8c, 0xd8, 0x66 + .byte 0x8e, 0xe0, 0x66, 0xb8, 0xf0, 0x00, 0x66, 0x8e + .byte 0xd8, 0x66, 0x8e, 0xc0, 0x66, 0x8e, 0xd0, 0x89 + .byte 0x25, 0x84, 0x01, 0x00, 0x00, 0xbc, 0x00, 0x00 + .byte 0x01, 0x00, 0x0f, 0x01, 0x0d, 0xa0, 0x01, 0x00 + .byte 0x00, 0xe8, 0x12, 0x01, 0x00, 0x00, 0xb4, 0x53 + .byte 0xb0, 0x00, 0x66, 0xbb, 0x00, 0x00, 0x00, 0x00 + .byte 0xfb, 0xcd, 0x15, 0xfa, 0x73, 0x15, 0x66, 0xe8 + .byte 0xcc, 0x00, 0x00, 0x00, 0xc7, 0x05, 0x88, 0x01 + .byte 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xe9, 0x8c + .byte 0x00, 0x00, 0x00, 0x89, 0xc2, 0x66, 0xe8, 0xb5 + .byte 0x00, 0x00, 0x00, 0x80, 0xff, 0x50, 0x75, 0x05 + .byte 0x80, 0xfb, 0x4d, 0x74, 0x0c, 0xc7, 0x05, 0x88 + .byte 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xeb + .byte 0x6e, 0xf7, 0xc1, 0x02, 0x00, 0x00, 0x00, 0x75 + .byte 0x0c, 0xc7, 0x05, 0x88, 0x01, 0x00, 0x00, 0xfe + .byte 0xff, 0xff, 0xff, 0xeb, 0x5a, 0x89, 0x15, 0x88 + .byte 0x01, 0x00, 0x00, 0x81, 0xe1, 0xff, 0xff, 0x00 + .byte 0x00, 0x89, 0x0d, 0x8c, 0x01, 0x00, 0x00, 0xe8 + .byte 0xa4, 0x00, 0x00, 0x00, 0xb4, 0x53, 0xb0, 0x03 + .byte 0x66, 0xbb, 0x00, 0x00, 0x00, 0x00, 0xfb, 0xcd + .byte 0x15, 0xfa, 0x73, 0x12, 0x66, 0xe8, 0x5e, 0x00 + .byte 0x00, 0x00, 0xc7, 0x05, 0x88, 0x01, 0x00, 0x00 + .byte 0xfd, 0xff, 0xff, 0xff, 0xeb, 0x21, 0x89, 0xc5 + .byte 0x66, 0xe8, 0x4a, 0x00, 0x00, 0x00, 0xb8, 0xff + .byte 0xff, 0x00, 0x00, 0x21, 0xc5, 0x21, 0xc1, 0x21 + .byte 0xc2, 0x21, 0xc6, 0x21, 0xc7, 0xc1, 0xe5, 0x10 + .byte 0x09, 0xe9, 0xc1, 0xe7, 0x10, 0x09, 0xfe, 0xfa + .byte 0x0f, 0x01, 0x1d, 0xa0, 0x01, 0x00, 0x00, 0x8b + .byte 0x25, 0x84, 0x01, 0x00, 0x00, 0x8b, 0x2d, 0x88 + .byte 0x01, 0x00, 0x00, 0x8b, 0x3d, 0x8c, 0x01, 0x00 + .byte 0x00, 0x66, 0x8c, 0xe0, 0x66, 0x8e, 0xd0, 0x66 + .byte 0x8e, 0xc0, 0x66, 0x8e, 0xd8, 0x89, 0xe8, 0x0f + .byte 0xa1, 0x5d, 0xcb, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0xfa, 0x0f, 0x20, 0xc0, 0x66, 0x83, 0xc8, 0x01 + .byte 0x0f, 0x22, 0xc0, 0x66, 0xea, 0x23, 0x01, 0x00 + .byte 0x00, 0xe8, 0x00, 0xb8, 0xf0, 0x00, 0x00, 0x00 + .byte 0x66, 0x8e, 0xd8, 0x66, 0x8e, 0xd0, 0x66, 0x8e + .byte 0xc0, 0x0f, 0x01, 0x1d, 0xa0, 0x01, 0x00, 0x00 + .byte 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0xa1, 0x80, 0x01, 0x00, 0x00, 0xc1, 0xf8, 0x04 + .byte 0x66, 0x50, 0x66, 0xb8, 0x62, 0x01, 0x66, 0x50 + .byte 0xea, 0x57, 0x01, 0x00, 0x00, 0xf8, 0x00, 0x0f + .byte 0x20, 0xc0, 0x66, 0x83, 0xe0, 0xfe, 0x0f, 0x22 + .byte 0xc0, 0xcb, 0x66, 0x8c, 0xc8, 0x66, 0x8e, 0xd8 + .byte 0x66, 0x8e, 0xd0, 0x66, 0x8e, 0xc0, 0x67, 0x66 + .byte 0x0f, 0x01, 0x1d, 0xa6, 0x01, 0x00, 0x00, 0x66 + .byte 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03 + .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + +/* Total size = 0x01b0 */ diff --git a/sys/i386/bios/apm_init/bin2asm.c b/sys/i386/bios/apm_init/bin2asm.c new file mode 100644 index 0000000..b826e68 --- /dev/null +++ b/sys/i386/bios/apm_init/bin2asm.c @@ -0,0 +1,64 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include <stdio.h> + +#define NCOLS 8 + +int main(int argc, char *argv[]) +{ + int c, col; + FILE *infile, *outfile; + + if (argc != 3) { + fprintf(stderr, "Usage: %s infile outfile\n", argv[0]); + exit(1); + } + + if ((infile = fopen(argv[1], "rb")) == NULL) { + fprintf(stderr, "Can't open %s.\n", argv[1]); + exit(1); + } + + if ((outfile = fopen(argv[2], "wb")) == NULL) { + fprintf(stderr, "Can't open %s.\n", argv[2]); + exit(1); + } + + col = 0; + + fprintf(outfile, "/* This file is automatically generated by bin2asm */\n"); + fprintf(outfile, "/* Original file is '%s' */\n\n", argv[1]); + + while ((c = fgetc(infile)) != EOF) { + if (col % NCOLS == 0) { + fprintf(outfile, "\t.byte\t"); + } + fprintf(outfile, "0x%02x", c); + if (col % NCOLS == NCOLS - 1) { + fprintf(outfile, "\n"); + } + else { + fprintf(outfile, ", "); + } + col++; + } + + fprintf(outfile, "\n/* Total size = 0x%04x */\n", col); + + fclose(infile); + fclose(outfile); + return 0; +} diff --git a/sys/i386/bios/apm_init/real_prot.S b/sys/i386/bios/apm_init/real_prot.S new file mode 100644 index 0000000..d61a394 --- /dev/null +++ b/sys/i386/bios/apm_init/real_prot.S @@ -0,0 +1,185 @@ +/* + * Mach Operating System + * Copyright (c) 1992, 1991 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.2 92/04/04 11:34:13 rpd + * $Id: asm.S,v 1.2 1993/10/16 19:11:27 rgrimes Exp $ + */ + + +/* + Copyright 1988, 1989, 1990, 1991, 1992 + by Intel Corporation, Santa Clara, California. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appears in all +copies and that both the copyright notice and this permission notice +appear in supporting documentation, and that the name of Intel +not be used in advertising or publicity pertaining to distribution +of the software without specific, written prior permission. + +INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, +IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, +NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* + * Modified for APM BIOS initializer by HOSOKAWA Tatsumi + * + * See also locore.s. It supports these functions works correctly. + */ + + .file "real_prot.S" + +#include "real_prot.h" +#include "apm_segments.h" + +CR0_PE_ON = 0x1 +CR0_PE_OFF = 0xfffffffe + +.globl _ouraddr + .text + +/* + * + * real_to_prot() + * transfer from real mode to protected mode. + */ + +ENTRY(real_to_prot) + /* guarantee that interrupt is disabled when in prot mode */ + cli + + /* + * deleted for APM initializer by HOSOKAWA Tatsumi + * <hosoakwa@mt.cs.keio.ac.jp> + */ +#if 0 + /* load the gdtr */ + addr32 + data32 + lgdt EXT(Gdtr) +#endif + + /* set the PE bit of CR0 */ + mov %cr0, %eax + + data32 + or $CR0_PE_ON, %eax + mov %eax, %cr0 + + /* + * make intrasegment jump to flush the processor pipeline and + * reload CS register + */ + data32 + ljmp $(APM_INIT_CS_SEL), $xprot + +xprot: + /* + * we are in USE32 mode now + * set up the protected mode segment registers : DS, SS, ES + */ + mov $(APM_INIT_DS_SEL), %eax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* load idtr so we can debug */ + lidt EXT(Idtr_prot) + + ret + +/* + * + * prot_to_real() + * transfer from protected mode to real mode + * + */ + +ENTRY(prot_to_real) + + /* set up a dummy stack frame for the second seg change. */ + movl _ouraddr, %eax + sarl $4, %eax + pushw %ax + movw $xreal, %ax /* gas botches pushw $xreal - extra bytes 0, 0*/ + pushw %ax /* decode to add %al, (%eax) (%al usually 0) */ + + /* Change to use16 mode. */ + ljmp $(APM_INIT_CS16_SEL), $x16 + +x16: + /* clear the PE bit of CR0 */ + mov %cr0, %eax + data32 + and $CR0_PE_OFF, %eax + mov %eax, %cr0 + + /* + * make intersegment jmp to flush the processor pipeline + * using the fake stack frame set up earlier + * and reload CS register + */ + lret + +xreal: + /* + * we are in real mode now + * set up the real mode segment registers : DS, SS, ES + */ + movw %cs, %ax + movw %ax, %ds + movw %ax, %ss + movw %ax, %es + + /* load idtr so we can debug */ + addr32 + data32 + lidt EXT(Idtr_real) + + data32 + ret diff --git a/sys/i386/bios/apm_init/real_prot.h b/sys/i386/bios/apm_init/real_prot.h new file mode 100644 index 0000000..bc02200 --- /dev/null +++ b/sys/i386/bios/apm_init/real_prot.h @@ -0,0 +1,56 @@ +/* + * Mach Operating System + * Copyright (c) 1991,1990,1989 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + * + * from: Mach, Revision 2.7 92/02/29 15:33:41 rpd + * $Id: asm.h,v 1.3 1993/10/16 19:11:29 rgrimes Exp $ + */ + +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +/* + * Modified to APM BIOS initializer by HOSOKAWA, Tatsumi + */ + +#define ALIGN 4 +#define EXT(x) _ ## x +#define LEXT(x) _ ## x ## : + +#define addr32 .byte 0x67 +#define data32 .byte 0x66 + +#define ENTRY(x) .globl EXT(x); .align ALIGN; LEXT(x) diff --git a/sys/i386/bios/apm_init/rmaouthdr b/sys/i386/bios/apm_init/rmaouthdr new file mode 100644 index 0000000..47838b0 --- /dev/null +++ b/sys/i386/bios/apm_init/rmaouthdr @@ -0,0 +1,6 @@ +#!/bin/csh -f +# +# from: Mach, Revision 2.2 92/04/04 11:36:01 rpd +# $Id: rmaouthdr,v 1.3 1993/10/16 19:11:37 rgrimes Exp $ +# +dd if=$1 of=$2 ibs=32 skip=1 obs=1024b diff --git a/sys/i386/bios/apm_init/table.c b/sys/i386/bios/apm_init/table.c new file mode 100644 index 0000000..eaf2fc6 --- /dev/null +++ b/sys/i386/bios/apm_init/table.c @@ -0,0 +1,24 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, and distributed, in + * both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#include <apm_bios.h> + +struct pseudo_desc { + unsigned short limit; + unsigned long base __attribute__ ((packed)); +}; + +struct pseudo_desc Idtr_prot = { 0, 0 }; /* filled on run time */ +struct pseudo_desc Idtr_real = { 0x400 - 1, 0x0 }; diff --git a/sys/i386/bios/apm_setup.h b/sys/i386/bios/apm_setup.h new file mode 100644 index 0000000..0009e56 --- /dev/null +++ b/sys/i386/bios/apm_setup.h @@ -0,0 +1,23 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, distributed, and sold, + * in both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +extern u_long apm_version; +extern u_long apm_cs_entry; +extern u_short apm_cs32_base; +extern u_short apm_cs16_base; +extern u_short apm_ds_base; +extern u_short apm_cs_limit; +extern u_short apm_ds_limit; +extern u_short apm_flags; diff --git a/sys/i386/bios/apm_setup.s b/sys/i386/bios/apm_setup.s new file mode 100644 index 0000000..df1e9c9 --- /dev/null +++ b/sys/i386/bios/apm_setup.s @@ -0,0 +1,126 @@ +/* + * LP (Laptop Package) + * + * Copyright (C) 1994 by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + * + * This software may be used, modified, copied, distributed, and sold, + * in both source and binary form provided that the above copyright and + * these terms are retained. Under no circumstances is the author + * responsible for the proper functioning of this software, nor does + * the author assume any responsibility for damages incurred with its + * use. + * + * Sep., 1994 Implemented on FreeBSD 1.1.5.1R (Toshiba AVS001WD) + */ + +#ifdef APM + +#define ASM + +#include <machine/asmacros.h> +#include "assym.s" +#include <machine/apm_bios.h> + + .file "apm_setup.s" + + .text + + /* void call_apm(union real_regs *); */ +_call_apm: + .globl _call_apm + pushl %ebp + movl %esp, %ebp + pushl %esi + pushl %edi + pushl %ebx + pushl %ecx + + movl 8(%ebp), %eax + movl %eax, struct_regs + movw 2(%eax), %bx + movw 4(%eax), %cx + movw 6(%eax), %dx + movw 8(%eax), %si + movw 10(%eax), %di + movw 0(%eax), %ax + + lcall _apm_addr /* intersegment call */ + + setc cf_result + movb %ah, _apm_errno + push %eax + movl struct_regs, %eax + movw %bx, 2(%eax) + movw %cx, 4(%eax) + movw %dx, 6(%eax) + movw %si, 8(%eax) + movw %di, 10(%eax) + movb cf_result, %bl + xorb %bh, %bh + movw %bx, 12(%eax) + popl %ebx + movl %ebx, 0(%eax) + + popl %ecx + popl %ebx + popl %edi + popl %esi + leave + ret + + .data +struct_regs: + .long 0 + +cf_result: + .byte 0 + +_apm_errno: + .globl _apm_errno + .byte 0 + + .data +_apm_init_image: + .globl _apm_init_image + +1: +#include "apm_init/apm_init.inc" +2: + +_apm_init_image_size: + .globl _apm_init_image_size + .long 2b - 1b + +_apm_version: + .globl _apm_version + .long 0 + +_apm_cs_entry: + .globl _apm_cs_entry + .long 0 + +_apm_cs16_base: + .globl _apm_cs16_base + .word 0 + +_apm_cs32_base: + .globl _apm_cs32_base + .word 0 + +_apm_ds_base: + .globl _apm_ds_base + .word 0 + +_apm_cs_limit: + .globl _apm_cs_limit + .word 0 + +_apm_ds_limit: + .globl _apm_ds_limit + .word 0 + +_apm_flags: + .globl _apm_flags + .word 0 + +#endif /* APM */ diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386 index 097d688..b4f6efc 100644 --- a/sys/i386/conf/Makefile.i386 +++ b/sys/i386/conf/Makefile.i386 @@ -1,6 +1,6 @@ # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 -# $Id: Makefile.i386,v 1.38 1994/09/23 07:01:59 phk Exp $ +# $Id: Makefile.i386,v 1.39 1994/09/29 14:02:40 csgr Exp $ # # Makefile for FreeBSD # @@ -66,7 +66,7 @@ DRIVER_C= ${CC} -c ${CFLAGS} ${PROF} $< DRIVER_C_C= ${CC} -c ${CFLAGS} ${PROF} ${PARAM} $< SFILES= ${I386}/i386/exception.s ${I386}/i386/microtime.s \ - ${I386}/i386/support.s ${I386}/i386/swtch.s + ${I386}/i386/support.s ${I386}/i386/swtch.s ${I386}/apm/apm_setup.s SYSTEM_CFILES= ioconf.c param.c vnode_if.c SYSTEM_SFILES= ${I386}/i386/locore.s SYSTEM_OBJS=locore.o vnode_if.o ${OBJS} ioconf.o param.o diff --git a/sys/i386/conf/files.i386 b/sys/i386/conf/files.i386 index 5ccdaab..c08c577 100644 --- a/sys/i386/conf/files.i386 +++ b/sys/i386/conf/files.i386 @@ -1,8 +1,10 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # -# $Id: files.i386,v 1.49 1994/09/26 16:15:06 jkh Exp $ +# $Id: files.i386,v 1.50 1994/10/01 02:36:24 swallace Exp $ # +i386/apm/apm.c optional apm device-driver +i386/apm/apm_setup.s optional apm i386/i386/autoconf.c standard device-driver i386/i386/conf.c standard i386/i386/cons.c standard diff --git a/sys/i386/i386/conf.c b/sys/i386/i386/conf.c index 121e4b7..181c976 100644 --- a/sys/i386/i386/conf.c +++ b/sys/i386/i386/conf.c @@ -41,7 +41,7 @@ * SUCH DAMAGE. * * from: @(#)conf.c 5.8 (Berkeley) 5/12/91 - * $Id: conf.c,v 1.34 1994/09/28 22:44:35 wollman Exp $ + * $Id: conf.c,v 1.35 1994/09/29 08:59:33 sos Exp $ */ #include <sys/param.h> @@ -533,6 +533,17 @@ d_open_t lkmcopen; d_close_t lkmcclose; d_ioctl_t lkmcioctl; +#include "apm.h" +#if NAPM > 0 +d_open_t apmopen; +d_close_t apmclose; +d_ioctl_t apmioctl; +#else +#define apmopen (d_open_t *)enxio +#define apmclose (d_close_t *)enxio +#define apmioctl (d_ioctl_t *)enxio +#endif + #define noopen (d_open_t *)enodev #define noclose (d_close_t *)enodev #define noread (d_rdwr_t *)enodev @@ -671,8 +682,11 @@ struct cdevsw cdevsw[] = { lkmopen, lkmclose, lkmread, lkmwrite, /*38*/ lkmioctl, lkmstop, lkmreset, NULL, lkmselect, lkmmmap, NULL }, - /* character device 39 is reserved for local use */ - { (d_open_t *)enxio, (d_close_t *)enxio, (d_rdwr_t *)enxio, /*39*/ + { apmopen, apmclose, noread, nowrite, /*39*/ + apmioctl, nostop, nullreset, NULL, /* laptop APM */ + seltrue, nommap, NULL }, + /* character device 40 is reserved for local use */ + { (d_open_t *)enxio, (d_close_t *)enxio, (d_rdwr_t *)enxio, /*40*/ (d_rdwr_t *)enxio, (d_ioctl_t *)enxio, (d_stop_t *)enxio, (d_reset_t *)enxio, NULL, (d_select_t *)enxio, (d_mmap_t *)enxio, NULL } diff --git a/sys/i386/i386/locore.s b/sys/i386/i386/locore.s index 72973aa..bc7b854 100644 --- a/sys/i386/i386/locore.s +++ b/sys/i386/i386/locore.s @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)locore.s 7.3 (Berkeley) 5/13/91 - * $Id: locore.s,v 1.28 1994/09/15 07:26:31 sos Exp $ + * $Id: locore.s,v 1.29 1994/09/26 16:56:22 pst Exp $ */ /* @@ -54,6 +54,11 @@ #include <machine/cputypes.h> /* x86 cpu type definitions */ #include <sys/syscall.h> /* system call numbers */ #include <machine/asmacros.h> /* miscellaneous asm macros */ +#ifdef APM +#define ASM +#include <machine/apm_bios.h> +#include <machine/apm_segments.h> +#endif /* * XXX @@ -130,7 +135,15 @@ _proc0paddr: .long 0 /* address of proc 0 address space */ .globl _bdb_exists /* flag to indicate BDE debugger is available */ _bdb_exists: .long 0 #endif - +#ifdef APM + .globl _apm_current_gdt_pdesc /* current GDT pseudo desc. */ +_apm_current_gdt_pdesc: + .byte 0, 0, 0 + + .globl _bootstrap_gdt +_bootstrap_gdt: + .space SIZEOF_GDT * BOOTSTRAP_GDT_NUM +#endif /* APM */ .globl tmpstk .space 0x1000 tmpstk: @@ -195,6 +208,89 @@ NON_GPROF_ENTRY(btext) rep movsb #endif +#ifdef APM + /* + * Setup APM BIOS: + * + * APM BIOS initialization should be done from real mode or V86 mode. + * + * (by HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp>) + */ + + /* + * Copy APM initializer under 1MB boundary: + * + * APM initializer program must switch the CPU to real mode. + * But FreeBSD kernel runs above 1MB boundary. So we must + * copy the initializer code to conventional memory. + */ + movl _apm_init_image_size-KERNBASE, %ecx /* size */ + lea _apm_init_image-KERNBASE, %esi /* source */ + movl $ APM_OURADDR, %edi /* destination */ + cld + rep + movsb + + /* get GDT base */ + sgdt _apm_current_gdt_pdesc-KERNBASE + + /* copy GDT to _bootstrap_gdt */ + xorl %ecx, %ecx + movw _apm_current_gdt_pdesc-KERNBASE, %cx + movl _apm_current_gdt_pdesc-KERNBASE+2, %esi + lea _bootstrap_gdt-KERNBASE, %edi + cld + rep + movsb + + /* setup GDT pseudo descriptor */ + movw $(SIZEOF_GDT*BOOTSTRAP_GDT_NUM), %ax + movw %ax, _apm_current_gdt_pdesc-KERNBASE + leal _bootstrap_gdt-KERNBASE, %eax + movl %eax, _apm_current_gdt_pdesc-KERNBASE+2 + + /* load new GDTR */ + lgdt _apm_current_gdt_pdesc-KERNBASE + + /* setup GDT for APM initializer */ + lea _bootstrap_gdt-KERNBASE, %ecx + movl $(APM_OURADDR), %eax /* use %ax for 15..0 */ + movl %eax, %ebx + shrl $16, %ebx /* use %bl for 23..16 */ + /* use %bh for 31..24 */ +#define APM_SETUP_GDT(index, attrib) \ + movl $(index), %si ; \ + lea 0(%ecx,%esi,8), %edx ; \ + movw $0xffff, (%edx) ; \ + movw %ax, 2(%edx) ; \ + movb %bl, 4(%edx) ; \ + movw $(attrib), 5(%edx) ; \ + movb %bh, 7(%edx) + + APM_SETUP_GDT(APM_INIT_CS_INDEX , CS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_DS_INDEX , DS32_ATTRIB) + APM_SETUP_GDT(APM_INIT_CS16_INDEX, CS16_ATTRIB) + + /* + * Call the initializer: + * + * direct intersegment call to conventional memory code + */ + .byte 0x9a /* actually, lcall $APM_INIT_CS_SEL, $0 */ + .long 0 + .word APM_INIT_CS_SEL + + movw %ax, _apm_version-KERNBASE + movl %ebx, _apm_cs_entry-KERNBASE + movw %cx, _apm_cs32_base-KERNBASE + shrl $16, %ecx + movw %cx, _apm_cs16_base-KERNBASE + movw %dx, _apm_ds_base-KERNBASE + movw %si, _apm_cs_limit-KERNBASE + shrl $16, %esi + movw %si, _apm_ds_limit-KERNBASE + movw %di, _apm_flags-KERNBASE +#endif /* APM */ /* Find out our CPU type. */ diff --git a/sys/i386/i386/machdep.c b/sys/i386/i386/machdep.c index 46df0ca..3242846 100644 --- a/sys/i386/i386/machdep.c +++ b/sys/i386/i386/machdep.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)machdep.c 7.4 (Berkeley) 6/3/91 - * $Id: machdep.c,v 1.65 1994/09/16 05:46:54 phk Exp $ + * $Id: machdep.c,v 1.66 1994/09/24 12:22:47 davidg Exp $ */ #include "npx.h" @@ -1012,7 +1012,7 @@ struct soft_segment_descriptor gdt_segs[] = { 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, /* User LDT Descriptor per process */ -{ (int) ldt, /* segment base address */ +{ (int) ldt, /* segment base address */ (512 * sizeof(union descriptor)-1), /* length */ SDT_SYSLDT, /* segment type */ 0, /* segment descriptor priority level */ @@ -1020,6 +1020,60 @@ struct soft_segment_descriptor gdt_segs[] = { 0, 0, 0, /* unused - default 32 vs 16 bit size */ 0 /* limit granularity (byte/page units)*/ }, +#ifdef APM + /* APM BIOS 32-bit interface (32bit Code) */ +{ 0, /* segment base address (overwritten by APM) */ + 0xffff, /* length */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* APM BIOS 32-bit interface (16bit Code) */ +{ 0, /* segment base address (overwritten by APM) */ + 0xffff, /* length */ + SDT_MEMERA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 0, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, + /* APM BIOS 32-bit interface (Data) */ +{ 0, /* segment base address (overwritten by APM) */ + 0xffff, /* length */ + SDT_MEMRWA, /* segment type */ + 0, /* segment descriptor priority level */ + 1, /* segment descriptor present */ + 0, 0, + 1, /* default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +#else /* APM */ +{ 0, /* segment base address */ + 0, /* length */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0, 0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +{ 0, /* segment base address */ + 0, /* length */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0, 0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +{ 0, /* segment base address */ + 0, /* length */ + 0, /* segment type */ + 0, /* segment descriptor priority level */ + 0, /* segment descriptor present */ + 0, 0, + 0, /* unused - default 32 vs 16 bit size */ + 0 /* limit granularity (byte/page units)*/ }, +#endif /* APMBIOS */ }; struct soft_segment_descriptor ldt_segs[] = { @@ -1103,6 +1157,22 @@ extern idtvec_t int _gsel_tss; +/* added sdtossd() by HOSOKAWA Tatsumi <hosokawa@mt.cs.keio.ac.jp> */ +int +sdtossd(sd, ssd) + struct segment_descriptor *sd; + struct soft_segment_descriptor *ssd; +{ + ssd->ssd_base = (sd->sd_hibase << 24) | sd->sd_lobase; + ssd->ssd_limit = (sd->sd_hilimit << 16) | sd->sd_lolimit; + ssd->ssd_type = sd->sd_type; + ssd->ssd_dpl = sd->sd_dpl; + ssd->ssd_p = sd->sd_p; + ssd->ssd_def32 = sd->sd_def32; + ssd->ssd_gran = sd->sd_gran; + return 0; +} + void init386(first) int first; diff --git a/sys/i386/i386/swtch.s b/sys/i386/i386/swtch.s index 7031c64..ad83a9a 100644 --- a/sys/i386/i386/swtch.s +++ b/sys/i386/i386/swtch.s @@ -33,7 +33,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: swtch.s,v 1.12 1994/09/01 05:12:18 davidg Exp $ + * $Id: swtch.s,v 1.13 1994/09/02 05:58:51 davidg Exp $ */ #include "npx.h" /* for NNPX */ @@ -204,8 +204,13 @@ idle_loop: jne sw1a cmpl $0,_whichqs jne nortqr +#ifdef APM + call _apm_cpu_idle + call _apm_cpu_busy +#else sti hlt /* wait for interrupt */ +#endif jmp idle_loop badsw: diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c index 49b4ffd..fcaa6e9 100644 --- a/sys/i386/i386/trap.c +++ b/sys/i386/i386/trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.33 1994/09/08 11:48:52 bde Exp $ + * $Id: trap.c,v 1.34 1994/09/11 11:26:18 davidg Exp $ */ /* @@ -459,10 +459,12 @@ trap_fatal(frame) struct trapframe *frame; { int code, type, eva; + struct soft_segment_descriptor softseg; code = frame->tf_err; type = frame->tf_trapno; eva = rcr2(); + sdtossd(gdt + IDXSEL(frame->tf_cs & 0xffff), &softseg); if (type <= MAX_TRAP_MSG) printf("\n\nFatal trap %d: %s while in %s mode\n", @@ -475,7 +477,11 @@ trap_fatal(frame) code & PGEX_W ? "write" : "read", code & PGEX_P ? "protection violation" : "page not present"); } - printf("instruction pointer = 0x%x\n", frame->tf_eip); + printf("instruction pointer = 0x%x:0x%x\n", frame->tf_cs & 0xffff, frame->tf_eip); + printf("code segment = base 0x%x, limit 0x%x, type 0x%x\n", + softseg.ssd_base, softseg.ssd_limit, softseg.ssd_type); + printf(" = DPL %d, pres %d, def32 %d, gran %d\n", + softseg.ssd_dpl, softseg.ssd_p, softseg.ssd_def32, softseg.ssd_gran); printf("processor eflags = "); if (frame->tf_eflags & PSL_T) printf("trace/trap, "); diff --git a/sys/i386/include/console.h b/sys/i386/include/console.h index 209baa4..ad441e1 100644 --- a/sys/i386/include/console.h +++ b/sys/i386/include/console.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: console.h,v 1.10 1994/09/15 07:26:04 sos Exp $ + * $Id: console.h,v 1.11 1994/09/29 08:31:39 sos Exp $ */ #ifndef _CONSOLE_H_ @@ -218,6 +218,7 @@ typedef struct ssaver ssaver_t; #define META 0x7f /* meta key */ #define RBT 0x80 /* boot machine */ #define DBG 0x81 /* call debugger */ +#define SUSP 0x82 /* suspend power (APM BIOS) */ #define F(x) ((x)+F_FN-1) #define S(x) ((x)+F_SCR-1) diff --git a/sys/i386/include/segments.h b/sys/i386/include/segments.h index 023a0cf..0e996e6 100644 --- a/sys/i386/include/segments.h +++ b/sys/i386/include/segments.h @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)segments.h 7.1 (Berkeley) 5/9/91 - * $Id: segments.h,v 1.3 1993/11/07 17:43:08 wollman Exp $ + * $Id: segments.h,v 1.4 1994/01/31 10:27:13 davidg Exp $ */ #ifndef _MACHINE_SEGMENTS_H_ @@ -211,7 +211,11 @@ struct region_descriptor { #define GPANIC_SEL 5 /* Task state to consider panic from */ #define GPROC0_SEL 6 /* Task state process slot zero and up */ #define GUSERLDT_SEL 7 /* User LDT */ -#define NGDT GUSERLDT_SEL+1 +#define GAPMCODE32_SEL 8 /* APM BIOS 32-bit interface (32bit Code) */ +#define GAPMCODE16_SEL 9 /* APM BIOS 32-bit interface (16bit Code) */ +#define GAPMDATA_SEL 10 /* APM BIOS 32-bit interface (Data) */ + +#define NGDT (GAPMDATA_SEL+1) /* * Entries in the Local Descriptor Table (LDT) diff --git a/sys/i386/isa/icu.h b/sys/i386/isa/icu.h index 5cecf65..a68269b 100644 --- a/sys/i386/isa/icu.h +++ b/sys/i386/isa/icu.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)icu.h 5.6 (Berkeley) 5/9/91 - * $Id: icu.h,v 1.5 1994/09/18 23:08:56 bde Exp $ + * $Id: icu.h,v 1.6 1994/09/18 23:18:32 bde Exp $ */ /* @@ -52,9 +52,10 @@ */ extern unsigned imen; /* interrupt mask enable */ -#define INTREN(s) (imen &= ~(s), SET_ICUS()) -#define INTRDIS(s) (imen |= (s), SET_ICUS()) -#define INTRMASK(msk,s) (msk |= (s)) +#define INTREN(s) (imen &= ~(s), SET_ICUS()) +#define INTRDIS(s) (imen |= (s), SET_ICUS()) +#define INTRMASK(msk,s) (msk |= (s)) +#define INTRUNMASK(msk,s) (msk &= ~(s)) #if 0 #define SET_ICUS() (outb(IO_ICU1 + 1, imen), outb(IU_ICU2 + 1, imen >> 8)) #else diff --git a/sys/i386/isa/if_ze.c b/sys/i386/isa/if_ze.c index 207ed70..3a16263 100644 --- a/sys/i386/isa/if_ze.c +++ b/sys/i386/isa/if_ze.c @@ -36,6 +36,11 @@ * of this software, nor does the author assume any responsibility * for damages incurred with its use. */ +/* + * I doubled delay loops in this file because it is not enough for some + * laptop machines' PCIC (especially, on my Chaplet ILFA 350 ^^;). + * HOSOKAWA, Tatsumi <hosokawa@mt.cs.keio.ac.jp> + */ #include "ze.h" #if NZE > 0 @@ -77,6 +82,9 @@ #include "i386/isa/icu.h" #include "i386/isa/if_zereg.h" +#ifdef APM +#include "i386/include/apm_bios.h" +#endif /* APM */ /***************************************************************************** @@ -368,7 +376,7 @@ pcic_power_on (int slot) { pcic_putb (slot, PCIC_POWER, pcic_getb (slot, PCIC_POWER) | PCIC_DISRST | PCIC_PCPWRE); - DELAY (50000); + DELAY (100000); pcic_putb (slot, PCIC_POWER, pcic_getb (slot, PCIC_POWER) | PCIC_OUTENA); } @@ -379,7 +387,7 @@ pcic_reset (int slot) /* assert RESET (by clearing a bit!), wait a bit, and de-assert it */ pcic_putb (slot, PCIC_INT_GEN, pcic_getb (slot, PCIC_INT_GEN) & ~PCIC_CARDRESET); - DELAY (50000); + DELAY (100000); pcic_putb (slot, PCIC_INT_GEN, pcic_getb (slot, PCIC_INT_GEN) | PCIC_CARDRESET); } @@ -424,6 +432,8 @@ struct ze_softc { u_char rec_page_start; /* first page of RX ring-buffer */ u_char rec_page_stop; /* last page of RX ring-buffer */ u_char next_packet; /* pointer to next unread RX packet */ + u_char last_alive; /* information for reconfiguration */ + u_char last_up; /* information for reconfiguration */ } ze_softc[NZE]; int ze_attach(), ze_ioctl(), ze_probe(); @@ -502,7 +512,7 @@ ze_check_cis (unsigned char *scratch) */ static int -ze_find_adapter (unsigned char *scratch) +ze_find_adapter (unsigned char *scratch, int reconfig) { int slot; @@ -523,7 +533,9 @@ ze_find_adapter (unsigned char *scratch) continue; } if ((pcic_getb (slot, PCIC_STATUS) & PCIC_CD) != PCIC_CD) { - printf ("ze: slot %d: no card in slot\n", slot); + if (!reconfig) { + printf ("ze: slot %d: no card in slot\n", slot); + } /* no card in slot */ continue; } @@ -539,11 +551,16 @@ ze_find_adapter (unsigned char *scratch) if ((ze_check_cis (scratch)) > 0) { /* found it */ - printf ("ze: found card in slot %d\n", slot); + if (!reconfig) { + printf ("ze: found card in slot %d\n", slot); + } return slot; } - else - printf ("ze: pcmcia slot %d: %s\n", slot, card_info); + else { + if (!reconfig) { + printf ("ze: pcmcia slot %d: %s\n", slot, card_info); + } + } pcic_unmap_memory (slot, 0); } return -1; @@ -577,7 +594,7 @@ ze_probe(isa_dev) u_char iptr, memwidth, sum, tmp; int slot; - if ((slot = ze_find_adapter (isa_dev->id_maddr)) < 0) + if ((slot = ze_find_adapter (isa_dev->id_maddr, isa_dev->id_reconfig)) < 0) return NULL; /* @@ -627,7 +644,7 @@ ze_probe(isa_dev) pcic_map_memory (slot, 0, kvtop (isa_dev->id_maddr), 0x20000, 8L, ATTRIBUTE, 1); POKE(isa_dev->id_maddr, 0x80); /* reset the card (how long?) */ - DELAY (10000); + DELAY (40000); /* * Set the configuration index. According to [1], the adapter won't * respond to any i/o signals until we do this; it uses the @@ -706,9 +723,9 @@ ze_probe(isa_dev) /* reset card to force it into a known state */ tmp = inb (isa_dev->id_iobase + ZE_RESET); - DELAY(5000); + DELAY(20000); outb (isa_dev->id_iobase + ZE_RESET, tmp); - DELAY(5000); + DELAY(20000); /* * query MAM bit in misc register for 10base2 @@ -735,12 +752,38 @@ ze_probe(isa_dev) sc->arpcom.ac_enaddr[i] = enet_addr[i]; isa_dev->id_msize = memsize; + + + /* information for reconfiguration */ + sc->last_alive = 0; + sc->last_up = 0; return 32; } + +#ifdef APM +#define ZEDEVS 4 +static apm_hook_func_t ze_hook; +struct isa_device* ze_devs[ZEDEVS] = {NULL}; + +static int +ze_resume(void) +{ + int i; + + for (i = 0; i < ZEDEVS; i++) { + if (ze_devs[i] != NULL) { + reconfig_isadev(ze_devs[i], &net_imask); + } + } + + return 0; +} +#endif /* APM */ /* * Install interface into kernel networking data structures */ + int ze_attach(isa_dev) struct isa_device *isa_dev; @@ -749,6 +792,26 @@ ze_attach(isa_dev) struct ifnet *ifp = &sc->arpcom.ac_if; struct ifaddr *ifa; struct sockaddr_dl *sdl; + + /* PCMCIA card can be offlined. Reconfiguration is required */ + if (isa_dev->id_reconfig) { + if (!isa_dev->id_alive && sc->last_alive) { + sc->last_up = (ifp->if_flags & IFF_UP); + ifp->if_flags &= ~(IFF_UP); + sc->last_alive = 0; + } + if (isa_dev->id_alive && !sc->last_alive) { + if (sc->last_up) { + ifp->if_flags |= IFF_UP; + } + sc->last_alive = 1; + } + ze_reset(isa_dev->id_unit); + return 1; + } + else { + sc->last_alive = 1; + } /* * Set interface to stopped condition (reset) @@ -822,6 +885,11 @@ ze_attach(isa_dev) #if NBPFILTER > 0 bpfattach(&sc->bpf, ifp, DLT_EN10MB, sizeof(struct ether_header)); #endif + +#ifdef APM + ze_devs[isa_dev->id_unit] = isa_dev; + ze_hook = apm_resume_hook_init(ze_resume, "IBM PCMCIA Ethernet", APM_MID_ORDER); +#endif /* APM */ return 1; } @@ -1660,6 +1728,17 @@ ze_ioctl(ifp, command, data) case SIOCSIFFLAGS: /* + * When the card is offlined, `up' operation can't be permitted + */ + if (!sc->last_alive) { + int tmp; + tmp = (ifp->if_flags & IFF_UP); + if (!sc->last_up && (ifp->if_flags & IFF_UP)) { + ifp->if_flags &= ~(IFF_UP); + } + sc->last_up = tmp; + } + /* * If interface is marked down and it is running, then stop it */ if (((ifp->if_flags & IFF_UP) == 0) && diff --git a/sys/i386/isa/isa.c b/sys/i386/isa/isa.c index 2cd9d23..2f93fcc 100644 --- a/sys/i386/isa/isa.c +++ b/sys/i386/isa/isa.c @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.c 7.2 (Berkeley) 5/13/91 - * $Id: isa.c,v 1.25 1994/09/20 05:07:11 bde Exp $ + * $Id: isa.c,v 1.26 1994/09/30 05:35:55 swallace Exp $ */ /* @@ -317,13 +317,35 @@ isa_configure() { /* * Configure an ISA device. */ + + +static void config_isadev_c(); + static void config_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + config_isadev_c(isdp, mp, 0); +} + +void +reconfig_isadev(isdp, mp) + struct isa_device *isdp; + u_int *mp; +{ + config_isadev_c(isdp, mp, 1); +} + +static void +config_isadev_c(isdp, mp, reconfig) struct isa_device *isdp; u_int *mp; + int reconfig; { u_int checkbits; int id_alive; + int last_alive; struct isa_driver *dp = isdp->id_driver; checkbits = 0; @@ -339,12 +361,18 @@ config_isadev(isdp, mp) #ifndef ALLOW_CONFLICT_MEMADDR checkbits |= CC_MEMADDR; #endif - if (haveseen_isadev(isdp, checkbits)) + if (!reconfig && haveseen_isadev(isdp, checkbits)) return; - if (isdp->id_maddr) { + if (!reconfig && isdp->id_maddr) { isdp->id_maddr -= 0xa0000; /* XXX should be a define */ isdp->id_maddr += atdevbase; } + if (reconfig) { + last_alive = isdp->id_alive; + } + else { + last_alive = 0; + } id_alive = (*dp->probe)(isdp); if (id_alive) { /* @@ -354,50 +382,52 @@ config_isadev(isdp, mp) * 16 it will not report I/O addresses. * Rod Grimes 04/26/94 */ - printf("%s%d", dp->name, isdp->id_unit); - if (id_alive != -1) { - printf(" at 0x%x", isdp->id_iobase); - if ((isdp->id_iobase + id_alive - 1) != - isdp->id_iobase) { - printf("-0x%x", - isdp->id_iobase + id_alive - 1); + if (!isdp->id_reconfig) { + printf("%s%d", dp->name, isdp->id_unit); + if (id_alive != -1) { + printf(" at 0x%x", isdp->id_iobase); + if ((isdp->id_iobase + id_alive - 1) != + isdp->id_iobase) { + printf("-0x%x", + isdp->id_iobase + id_alive - 1); + } } - } - if (isdp->id_irq) - printf(" irq %d", ffs(isdp->id_irq) - 1); - if (isdp->id_drq != -1) - printf(" drq %d", isdp->id_drq); - if (isdp->id_maddr) - printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); - if (isdp->id_msize) - printf(" msize %d", isdp->id_msize); - if (isdp->id_flags) - printf(" flags 0x%x", isdp->id_flags); - if (isdp->id_iobase) { - if (isdp->id_iobase < 0x100) { - printf(" on motherboard\n"); - } else { - if (isdp->id_iobase >= 0x1000) { - printf (" on eisa\n"); + if (isdp->id_irq) + printf(" irq %d", ffs(isdp->id_irq) - 1); + if (isdp->id_drq != -1) + printf(" drq %d", isdp->id_drq); + if (isdp->id_maddr) + printf(" maddr 0x%lx", kvtop(isdp->id_maddr)); + if (isdp->id_msize) + printf(" msize %d", isdp->id_msize); + if (isdp->id_flags) + printf(" flags 0x%x", isdp->id_flags); + if (isdp->id_iobase) { + if (isdp->id_iobase < 0x100) { + printf(" on motherboard\n"); } else { - printf (" on isa\n"); + if (isdp->id_iobase >= 0x1000) { + printf (" on eisa\n"); + } else { + printf (" on isa\n"); + } } } - } - /* - * Check for conflicts again. The driver may have changed - * *dvp. We should weaken the early check since the - * driver may have been able to change *dvp to avoid - * conflicts if given a chance. We already skip the early - * check for IRQs and force a check for IRQs in the next - * group of checks. - */ + /* + * Check for conflicts again. The driver may have + * changed *dvp. We should weaken the early check + * since the driver may have been able to change + * *dvp to avoid conflicts if given a chance. We + * already skip the early check for IRQs and force + * a check for IRQs in the next group of checks. + */ #ifndef ALLOW_CONFLICT_IRQ - checkbits |= CC_IRQ; + checkbits |= CC_IRQ; #endif - if (haveseen_isadev(isdp, checkbits)) - return; - isdp->id_alive = id_alive; + if (haveseen_isadev(isdp, checkbits)) + return; + isdp->id_alive = id_alive; + } (*dp->attach)(isdp); if (isdp->id_irq) { if (mp) @@ -408,11 +438,28 @@ config_isadev(isdp, mp) INTREN(isdp->id_irq); } } else { - printf("%s%d not found", dp->name, isdp->id_unit); - if (isdp->id_iobase) { - printf(" at 0x%x", isdp->id_iobase); + if (isdp->id_reconfig) { + (*dp->attach)(isdp); /* reconfiguration attach */ + } + if (!last_alive) { + if (!isdp->id_reconfig) { + printf("%s%d not found", dp->name, isdp->id_unit); + if (isdp->id_iobase) { + printf(" at 0x%x", isdp->id_iobase); + } + printf("\n"); + } + } + else { + /* This code has not been tested.... */ + if (isdp->id_irq) { + INTRDIS(isdp->id_irq); + unregister_intr(ffs(isdp->id_irq) - 1, + isdp->id_intr); + if (mp) + INTRUNMASK(*mp, isdp->id_irq); + } } - printf("\n"); } } diff --git a/sys/i386/isa/isa.h b/sys/i386/isa/isa.h index e2a26e7..7f6b02a 100644 --- a/sys/i386/isa/isa.h +++ b/sys/i386/isa/isa.h @@ -34,7 +34,7 @@ * SUCH DAMAGE. * * from: @(#)isa.h 5.7 (Berkeley) 5/9/91 - * $Id: isa.h,v 1.4 1994/01/05 15:03:28 rgrimes Exp $ + * $Id: isa.h,v 1.5 1994/04/21 14:20:54 sos Exp $ */ #ifndef _I386_ISA_ISA_H_ @@ -62,6 +62,7 @@ unsigned char rtcin __P((int)); /* CPU Board */ #define IO_DMA1 0x000 /* 8237A DMA Controller #1 */ #define IO_ICU1 0x020 /* 8259A Interrupt Controller #1 */ +#define IO_PMP1 0x026 /* 82347 Power Management Peripheral */ #define IO_TIMER1 0x040 /* 8253 Timer #1 */ #define IO_TIMER2 0x048 /* 8253 Timer #2 */ #define IO_KBD 0x060 /* 8042 Keyboard */ @@ -78,7 +79,9 @@ unsigned char rtcin __P((int)); #define IO_WD2 0x170 /* Secondary Fixed Disk Controller */ - /* 0x178 - 0x1EF Open */ +#define IO_PMP2 0x178 /* 82347 Power Management Peripheral */ + + /* 0x17A - 0x1EF Open */ #define IO_WD1 0x1f0 /* Primary Fixed Disk Controller */ #define IO_GAME 0x200 /* Game Controller */ @@ -146,6 +149,7 @@ unsigned char rtcin __P((int)); #define IO_TMRSIZE 16 /* 8253 programmable timers */ #define IO_NPXSIZE 16 /* 80387/80487 NPX registers */ #define IO_VGASIZE 16 /* VGA controllers */ +#define IO_PMPSIZE 2 /* 82347 power management peripheral */ #endif /* IO_ISASIZES */ diff --git a/sys/i386/isa/isa_device.h b/sys/i386/isa/isa_device.h index 31d6c5d..5da5123 100644 --- a/sys/i386/isa/isa_device.h +++ b/sys/i386/isa/isa_device.h @@ -31,7 +31,7 @@ * SUCH DAMAGE. * * from: @(#)isa_device.h 7.1 (Berkeley) 5/9/91 - * $Id: isa_device.h,v 1.9 1994/09/02 22:13:34 ats Exp $ + * $Id: isa_device.h,v 1.10 1994/09/03 16:03:09 csgr Exp $ */ #ifndef _I386_ISA_ISA_DEVICE_H_ @@ -73,6 +73,7 @@ struct isa_device { int id_alive; /* device is present */ #define RI_FAST 1 /* fast interrupt handler */ u_int id_ri_flags; /* flags for register_intr() */ + int id_reconfig; /* hot eject device support (such as PCMCIA) */ }; /* diff --git a/sys/i386/isa/kbdtables.h b/sys/i386/isa/kbdtables.h index 7e8318f..a48b6a6 100644 --- a/sys/i386/isa/kbdtables.h +++ b/sys/i386/isa/kbdtables.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: kbdtables.h,v 1.14 1994/09/29 08:29:17 sos Exp $ */ #define SET8 0x80 /* eight bit for emacs SET8-key */ @@ -799,7 +799,7 @@ keymap_t key_map = { 0x69, /* US iso8859 keymap */ /* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, -/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00, +/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', SUSP, ' ', 0x02, 0x00, /* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00, /* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00, /* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00, diff --git a/sys/i386/isa/syscons.c b/sys/i386/isa/syscons.c index 0479f76..230c945 100644 --- a/sys/i386/isa/syscons.c +++ b/sys/i386/isa/syscons.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: syscons.c,v 1.59 1994/09/29 08:29:21 sos Exp $ + * $Id: syscons.c,v 1.60 1994/09/29 15:49:09 ache Exp $ */ #include "sc.h" @@ -64,6 +64,9 @@ #include <i386/isa/timerreg.h> #include <i386/isa/kbdtables.h> #include <i386/i386/cons.h> +#ifdef APM +#include <machine/apm_bios.h> +#endif #if !defined(NCONS) #define NCONS 12 @@ -288,6 +291,16 @@ struct isa_driver scdriver = { pcprobe, pcattach, "sc", }; +#ifdef APM +static int +pc_resume(void) +{ + /* when the system wakes up, modifier keys must be re-initialized */ + shfts = ctls = alts = agrs = metas = 0; + return 0; +} +#endif /* APM */ + int pcprobe(struct isa_device *dev) { @@ -391,6 +404,9 @@ pcattach(struct isa_device *dev) #endif cursor_pos(1); update_leds(console[0].status); +#ifdef APM + apm_resume_hook_init(pc_resume, "Syscons console", APM_MID_ORDER); +#endif return 0; } @@ -2081,7 +2097,11 @@ scinit(void) scp->ysize = ROW; scp->bell_pitch = BELL_PITCH; scp->bell_duration = BELL_DURATION; +#ifndef LAPTOP scp->status = NLKED; +#else + scp->status = 0; +#endif scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; @@ -2429,6 +2449,12 @@ next_code: case RBT: shutdown_nice(); break; + case SUSP: +#ifdef APM + apm_suspend_resume(); +#endif /* APM */ + break; + case DBG: #ifdef DDB /* try to switch to console 0 */ if (cur_console->smode.mode == VT_AUTO && diff --git a/sys/i386/isa/wd.c b/sys/i386/isa/wd.c index 4569cc5..c8b92ce 100644 --- a/sys/i386/isa/wd.c +++ b/sys/i386/isa/wd.c @@ -37,7 +37,7 @@ static int wdtest = 0; * SUCH DAMAGE. * * from: @(#)wd.c 7.2 (Berkeley) 5/9/91 - * $Id: wd.c,v 1.45 1994/08/30 14:26:13 ache Exp $ + * $Id: wd.c,v 1.46 1994/09/10 03:19:49 davidg Exp $ */ /* TODO: @@ -80,6 +80,9 @@ static int wdtest = 0; #include <i386/isa/isa.h> #include <i386/isa/isa_device.h> #include <i386/isa/wdreg.h> +#ifdef APM +#include <machine/apm_bios.h> +#endif #include <sys/syslog.h> #include <vm/vm.h> @@ -161,6 +164,9 @@ static struct buf wdutab[NWD]; /* head of queue per drive */ static struct buf rwdbuf[NWD]; /* buffers for raw IO */ #endif static long wdxfer[NWD]; /* count of transfers */ +#ifdef APM +static int wdsuspend_regist = 0; +#endif /* APM */ static void bad144intern(struct disk *); @@ -181,6 +187,9 @@ static void wdsleep(int ctrlr, char *wmesg); static timeout_t wdtimeout; static int wdunwedge(struct disk *du); static int wdwait(struct disk *du, u_char bits_wanted, int timeout); +#ifdef APM +static int wdsuspend(void); +#endif /* APM */ struct isa_driver wdcdriver = { wdprobe, wdattach, "wdc", @@ -337,6 +346,11 @@ wdattach(struct isa_device *dvp) * doesn't work now because the ambient ipl is too high. */ wdtab[dvp->id_unit].b_active = 2; +#ifdef APM + if (!wdsuspend_regist) { + apm_suspend_hook_init(wdsuspend, "IDE HDD", APM_MID_ORDER); + } +#endif /* APM */ return (1); } @@ -1833,4 +1847,13 @@ void bad144intern(struct disk *du) { } } +#ifdef APM +static int wdsuspend(void) +{ + /* Currently, this routine has not be implemented. Sorry... */ + + return 0; +} +#endif /* APM */ + #endif /* NWDC > 0 */ diff --git a/sys/isa/kbdtables.h b/sys/isa/kbdtables.h index 7e8318f..a48b6a6 100644 --- a/sys/isa/kbdtables.h +++ b/sys/isa/kbdtables.h @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id$ + * $Id: kbdtables.h,v 1.14 1994/09/29 08:29:17 sos Exp $ */ #define SET8 0x80 /* eight bit for emacs SET8-key */ @@ -799,7 +799,7 @@ keymap_t key_map = { 0x69, /* US iso8859 keymap */ /* sc=36 */ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, 0xFF, 0x00, /* sc=37 */ '*', '*', 0x0A, 0x0A, '*', '*', 0x0A, 0x0A, 0x33, 0x00, /* sc=38 */ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, 0xFF, 0x00, -/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 0x00, 0x00, +/* sc=39 */ ' ', ' ', ' ', ' ', ' ', ' ', SUSP, ' ', 0x02, 0x00, /* sc=3a */ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, 0xFF, 0x00, /* sc=3b */ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11), 0xFF, 0x00, /* sc=3c */ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12), 0xFF, 0x00, diff --git a/sys/isa/syscons.c b/sys/isa/syscons.c index 0479f76..230c945 100644 --- a/sys/isa/syscons.c +++ b/sys/isa/syscons.c @@ -35,7 +35,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: syscons.c,v 1.59 1994/09/29 08:29:21 sos Exp $ + * $Id: syscons.c,v 1.60 1994/09/29 15:49:09 ache Exp $ */ #include "sc.h" @@ -64,6 +64,9 @@ #include <i386/isa/timerreg.h> #include <i386/isa/kbdtables.h> #include <i386/i386/cons.h> +#ifdef APM +#include <machine/apm_bios.h> +#endif #if !defined(NCONS) #define NCONS 12 @@ -288,6 +291,16 @@ struct isa_driver scdriver = { pcprobe, pcattach, "sc", }; +#ifdef APM +static int +pc_resume(void) +{ + /* when the system wakes up, modifier keys must be re-initialized */ + shfts = ctls = alts = agrs = metas = 0; + return 0; +} +#endif /* APM */ + int pcprobe(struct isa_device *dev) { @@ -391,6 +404,9 @@ pcattach(struct isa_device *dev) #endif cursor_pos(1); update_leds(console[0].status); +#ifdef APM + apm_resume_hook_init(pc_resume, "Syscons console", APM_MID_ORDER); +#endif return 0; } @@ -2081,7 +2097,11 @@ scinit(void) scp->ysize = ROW; scp->bell_pitch = BELL_PITCH; scp->bell_duration = BELL_DURATION; +#ifndef LAPTOP scp->status = NLKED; +#else + scp->status = 0; +#endif scp->pid = 0; scp->proc = NULL; scp->smode.mode = VT_AUTO; @@ -2429,6 +2449,12 @@ next_code: case RBT: shutdown_nice(); break; + case SUSP: +#ifdef APM + apm_suspend_resume(); +#endif /* APM */ + break; + case DBG: #ifdef DDB /* try to switch to console 0 */ if (cur_console->smode.mode == VT_AUTO && diff --git a/sys/kern/subr_trap.c b/sys/kern/subr_trap.c index 49b4ffd..fcaa6e9 100644 --- a/sys/kern/subr_trap.c +++ b/sys/kern/subr_trap.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * from: @(#)trap.c 7.4 (Berkeley) 5/13/91 - * $Id: trap.c,v 1.33 1994/09/08 11:48:52 bde Exp $ + * $Id: trap.c,v 1.34 1994/09/11 11:26:18 davidg Exp $ */ /* @@ -459,10 +459,12 @@ trap_fatal(frame) struct trapframe *frame; { int code, type, eva; + struct soft_segment_descriptor softseg; code = frame->tf_err; type = frame->tf_trapno; eva = rcr2(); + sdtossd(gdt + IDXSEL(frame->tf_cs & 0xffff), &softseg); if (type <= MAX_TRAP_MSG) printf("\n\nFatal trap %d: %s while in %s mode\n", @@ -475,7 +477,11 @@ trap_fatal(frame) code & PGEX_W ? "write" : "read", code & PGEX_P ? "protection violation" : "page not present"); } - printf("instruction pointer = 0x%x\n", frame->tf_eip); + printf("instruction pointer = 0x%x:0x%x\n", frame->tf_cs & 0xffff, frame->tf_eip); + printf("code segment = base 0x%x, limit 0x%x, type 0x%x\n", + softseg.ssd_base, softseg.ssd_limit, softseg.ssd_type); + printf(" = DPL %d, pres %d, def32 %d, gran %d\n", + softseg.ssd_dpl, softseg.ssd_p, softseg.ssd_def32, softseg.ssd_gran); printf("processor eflags = "); if (frame->tf_eflags & PSL_T) printf("trace/trap, "); |