From def7e1bda051583fcc3525070ac5429f314f7fcf Mon Sep 17 00:00:00 2001 From: mdodd Date: Fri, 17 Jan 2003 08:10:18 +0000 Subject: A driver for the System Management Application Program Interface (SMAPI) BIOS, which is present on some IBM Thinkpad models (560, 600, 770 to name a few.) The SMAPI BIOS provides access to System Information, System Configuration, and Power Management. --- sys/i386/bios/smapi.c | 167 +++++++++++++++++++++++++++ sys/i386/bios/smapi_bios.S | 54 +++++++++ sys/i386/bios/smapi_isa.c | 274 ++++++++++++++++++++++++++++++++++++++++++++ sys/i386/bios/smapi_var.h | 51 +++++++++ sys/i386/include/smapi.h | 91 +++++++++++++++ sys/i386/smapi/smapi.c | 167 +++++++++++++++++++++++++++ sys/i386/smapi/smapi_bios.S | 54 +++++++++ sys/i386/smapi/smapi_isa.c | 274 ++++++++++++++++++++++++++++++++++++++++++++ sys/i386/smapi/smapi_var.h | 51 +++++++++ 9 files changed, 1183 insertions(+) create mode 100644 sys/i386/bios/smapi.c create mode 100644 sys/i386/bios/smapi_bios.S create mode 100644 sys/i386/bios/smapi_isa.c create mode 100644 sys/i386/bios/smapi_var.h create mode 100644 sys/i386/include/smapi.h create mode 100644 sys/i386/smapi/smapi.c create mode 100644 sys/i386/smapi/smapi_bios.S create mode 100644 sys/i386/smapi/smapi_isa.c create mode 100644 sys/i386/smapi/smapi_var.h (limited to 'sys/i386') diff --git a/sys/i386/bios/smapi.c b/sys/i386/bios/smapi.c new file mode 100644 index 0000000..e2e96ad --- /dev/null +++ b/sys/i386/bios/smapi.c @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +u_long smapi32_offset; +u_short smapi32_segment; +#define SMAPI32_SEGMENT 0x18 + +devclass_t smapi_devclass; + +static d_open_t smapi_open; +static d_close_t smapi_close; +static d_ioctl_t smapi_ioctl; + +#define CDEV_MAJOR 183 + +static struct cdevsw smapi_cdevsw = { + /* open */ smapi_open, + /* close */ smapi_close, + /* read */ noread, + /* write */ nowrite, + /* ioctl */ smapi_ioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "smapi", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ D_MEM, + /* kqfilter */ NULL, +}; + +static int +smapi_open (dev, oflags, devtype, td) + dev_t dev; + int oflags; + int devtype; + d_thread_t * td; +{ + + return (0); +} + +static int +smapi_close (dev, fflag, devtype, td) + dev_t dev; + int fflag; + int devtype; + d_thread_t * td; +{ + + return (0); +} + +static int +smapi_ioctl (dev, cmd, data, fflag, td) + dev_t dev; + u_long cmd; + caddr_t data; + int fflag; + d_thread_t * td; +{ + struct smapi_softc *sc; + int error; + + error = 0; + sc = devclass_get_softc(smapi_devclass, minor(dev)); + if (sc == NULL) { + error = ENXIO; + goto fail; + } + + switch (cmd) { + case SMAPIOGHEADER: + bcopy((caddr_t)sc->header, data, + sizeof(struct smapi_bios_header)); + error = 0; + break; + case SMAPIOCGFUNCTION: + smapi32_segment = SMAPI32_SEGMENT; + smapi32_offset = sc->smapi32_entry; + error = smapi32((struct smapi_bios_parameter *)data, + (struct smapi_bios_parameter *)data); + break; + default: + error = ENOTTY; + } + +fail: + return (error); +} + +int +smapi_attach (struct smapi_softc *sc) +{ + struct smapi_bios_parameter input_param; + struct smapi_bios_parameter output_param; + int retval; + + sc->cdev = make_dev(&smapi_cdevsw, + device_get_unit(sc->dev), + UID_ROOT, GID_WHEEL, 0600, + "%s%d", + smapi_cdevsw.d_name, + device_get_unit(sc->dev)); + + bzero(&input_param, sizeof(struct smapi_bios_parameter)); + bzero(&output_param, sizeof(struct smapi_bios_parameter)); + smapi32_segment = SMAPI32_SEGMENT; + smapi32_offset = sc->smapi32_entry; + retval = smapi32(&output_param, &output_param); + +#if 0 + retval = smapi32_new(sc->smapi32_entry, SMAPI32_SEGMENT, + &output_param, &output_param); +#endif + + return (0); +} + +int +smapi_detach (struct smapi_softc *sc) +{ + + destroy_dev(sc->cdev); + return (0); +} diff --git a/sys/i386/bios/smapi_bios.S b/sys/i386/bios/smapi_bios.S new file mode 100644 index 0000000..2ada5c6 --- /dev/null +++ b/sys/i386/bios/smapi_bios.S @@ -0,0 +1,54 @@ +/* $FreeBSD$ */ + +#include + + .data +smapi32_segment_tmp: .word 0 +smapi32_offset_tmp: .long 0 + .text +/* + * smapi32(input_param, output_param) + * struct smapi_bios_parameter *input_parm; + * struct smapi_bios_parameter *output_parm; + */ +ENTRY(smapi32) + pushl %ebp /* Save frame */ + movl %esp,%ebp + + pushl %ds + pushl 0x0c(%ebp) /* Output Param */ + pushl %ds + pushl 0x08(%ebp) /* Input Param */ + + movl $0,%eax /* Clear EAX (return 0) */ + movw %cs,smapi32_segment /* Save CS */ + lcall *(smapi32_offset) + + leave + ret + +/* + * smapi32(offset, segment, input_param, output_param) + * u_int offset; + * u_short segment; + * struct smapi_bios_parameter *input_parm; + * struct smapi_bios_parameter *output_parm; + */ +ENTRY(smapi32_new) + pushl %ebp /* Save frame */ + movl 0x08(%esp),%ebp + movl %ebp,smapi32_offset_tmp + movw 0x0c(%esp),%bp + movw %bp,smapi32_segment_tmp + + pushl %ds + pushl 0x20(%ebp) /* Output Param */ + pushl %ds + pushl 0x10(%ebp) /* Input Param */ + + movl $0,%eax + movw %cs,smapi32_segment_tmp + lcall *(smapi32_offset_tmp) + + leave + ret diff --git a/sys/i386/bios/smapi_isa.c b/sys/i386/bios/smapi_isa.c new file mode 100644 index 0000000..bd6bfd3 --- /dev/null +++ b/sys/i386/bios/smapi_isa.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +/* And all this for BIOS_PADDRTOVADDR() */ +#include +#include +#include +#include + +#include +#include + +static void smapi_isa_identify (driver_t *, device_t); +static int smapi_isa_probe (device_t); +static int smapi_isa_attach (device_t); +static int smapi_isa_detach (device_t); +static int smapi_modevent (module_t, int, void *); + +static int smapi_header_cksum (struct smapi_bios_header *); + +#define SMAPI_ID 0x0000a24d + +static struct isa_pnp_id smapi_ids[] = { + { SMAPI_ID, NULL }, /* SMB0000 */ + { 0, NULL }, +}; + +#define SMAPI_START 0xf0000 +#define SMAPI_END 0xffff0 +#define SMAPI_STEP 0x10 + +#define SMAPI_SIGNATURE(h) ((h->signature[0] == '$') && \ + (h->signature[1] == 'S') && \ + (h->signature[2] == 'M') && \ + (h->signature[3] == 'B')) + +static void +smapi_isa_identify (driver_t *driver, device_t parent) +{ + device_t child; + struct resource *res; + struct smapi_bios_header *header; + u_int32_t chunk; + int rid; + + rid = 0; + chunk = SMAPI_START; + + child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, "smapi", -1); + device_set_driver(child, driver); + isa_set_logicalid(child, SMAPI_ID); + isa_set_vendorid(child, SMAPI_ID); + + while (chunk < SMAPI_END) { + bus_set_resource(child, SYS_RES_MEMORY, rid, chunk, + sizeof(struct smapi_bios_header)); + res = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, + 0ul, ~0ul, 1, RF_ACTIVE); + if (res == NULL) { + bus_delete_resource(child, SYS_RES_MEMORY, rid); + chunk += SMAPI_STEP; + continue; + } + header = (struct smapi_bios_header *)rman_get_virtual(res); + + if (SMAPI_SIGNATURE(header)) { + if (smapi_header_cksum(header)) { + device_printf(child, "SMAPI header checksum failed.\n"); + } else { + goto found; + } + } else { + bus_release_resource(child, SYS_RES_MEMORY, rid, res); + bus_delete_resource(child, SYS_RES_MEMORY, rid); + } + + chunk += SMAPI_STEP; + } + + device_delete_child(parent, child); + return; + +found: + device_set_desc(child, "SMAPI BIOS"); + return; +} + +static int +smapi_isa_probe (device_t dev) +{ + return (ISA_PNP_PROBE(device_get_parent(dev), dev, smapi_ids)); +} + +static int +smapi_isa_attach (device_t dev) +{ + struct smapi_softc *sc; + int error; + + sc = device_get_softc(dev); + error = 0; + + sc->dev = dev; + sc->rid = 0; + sc->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid, + 0ul, ~0ul, 1, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "Unable to allocate memory resource.\n"); + error = ENOMEM; + goto bad; + } + sc->header = (struct smapi_bios_header *)rman_get_virtual(sc->res); + sc->smapi32_entry = (u_int32_t)BIOS_PADDRTOVADDR( + sc->header->prot32_segment + + sc->header->prot32_offset); + + if (smapi_header_cksum(sc->header)) { + device_printf(dev, "SMAPI header checksum failed.\n"); + error = ENXIO; + goto bad; + } + + if (smapi_attach(sc)) { + device_printf(dev, "SMAPI attach failed.\n"); + error = ENXIO; + goto bad; + } + + device_printf(dev, "Version %02d.%02d, Length %d, Checksum 0x%02x\n", + sc->header->version_major, sc->header->version_minor, + sc->header->length, sc->header->checksum); + device_printf(dev, "Information=0x%b\n", + sc->header->information, + "\020" + "\001REAL_VM86" + "\002PROTECTED_16" + "\003PROTECTED_32"); + + if (bootverbose) { + if (sc->header->information & SMAPI_REAL_VM86) + device_printf(dev, "Real/VM86 mode: Segment 0x%04x, Offset 0x%04x\n", + sc->header->real16_segment, + sc->header->real16_offset); + if (sc->header->information & SMAPI_PROT_16BIT) + device_printf(dev, "16-bit Protected mode: Segment 0x%08x, Offset 0x%04x\n", + sc->header->prot16_segment, + sc->header->prot16_offset); + if (sc->header->information & SMAPI_PROT_32BIT) + device_printf(dev, "32-bit Protected mode: Segment 0x%08x, Offset 0x%08x\n", + sc->header->prot32_segment, + sc->header->prot32_offset); + } + + return (0); +bad: + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + return (error); +} + +static int +smapi_isa_detach (device_t dev) +{ + struct smapi_softc *sc; + + sc = device_get_softc(dev); + + (void)smapi_detach(sc); + + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + + return (0); +} + +static int +smapi_modevent (mod, what, arg) + module_t mod; + int what; + void * arg; +{ + device_t * devs; + int count; + int i; + + switch (what) { + case MOD_LOAD: + break; + case MOD_UNLOAD: + devclass_get_devices(smapi_devclass, &devs, &count); + for (i = 0; i < count; i++) { + device_delete_child(device_get_parent(devs[i]), devs[i]); + } + break; + default: + break; + } + + return (0); +} + +static device_method_t smapi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, smapi_isa_identify), + DEVMETHOD(device_probe, smapi_isa_probe), + DEVMETHOD(device_attach, smapi_isa_attach), + DEVMETHOD(device_detach, smapi_isa_detach), + { 0, 0 } +}; + +static driver_t smapi_driver = { + "smapi", + smapi_methods, + sizeof(struct smapi_softc), +}; + +DRIVER_MODULE(smapi, isa, smapi_driver, smapi_devclass, smapi_modevent, 0); +MODULE_VERSION(smapi, 1); + +static int +smapi_header_cksum (struct smapi_bios_header *header) +{ + u_int8_t *ptr; + u_int8_t cksum; + int i; + + ptr = (u_int8_t *)header; + cksum = 0; + for (i = 0; i < header->length; i++) { + cksum += ptr[i]; + } + + return (cksum); +} diff --git a/sys/i386/bios/smapi_var.h b/sys/i386/bios/smapi_var.h new file mode 100644 index 0000000..c05ae8f --- /dev/null +++ b/sys/i386/bios/smapi_var.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +struct smapi_softc { + dev_t cdev; + device_t dev; + struct resource * res; + int rid; + + u_int32_t smapi32_entry; + + struct smapi_bios_header *header; +}; + +extern u_long smapi32_offset; +extern u_short smapi32_segment; +extern devclass_t smapi_devclass; + +int smapi_attach (struct smapi_softc *); +int smapi_detach (struct smapi_softc *); + +extern int smapi32 (struct smapi_bios_parameter *, + struct smapi_bios_parameter *); +extern int smapi32_new (u_long, u_short, + struct smapi_bios_parameter *, + struct smapi_bios_parameter *); diff --git a/sys/i386/include/smapi.h b/sys/i386/include/smapi.h new file mode 100644 index 0000000..6123526 --- /dev/null +++ b/sys/i386/include/smapi.h @@ -0,0 +1,91 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _MACHINE_SMAPI_H_ +#define _MACHINE_SMAPI_H_ + +#ifndef _KERNEL +#include +#endif +#include + +struct smapi_bios_header { + u_int8_t signature[4]; /* '$SMB' */ + u_int8_t version_major; + u_int8_t version_minor; + u_int8_t length; + u_int8_t checksum; + u_int16_t information; +#define SMAPI_REAL_VM86 0x0001 +#define SMAPI_PROT_16BIT 0x0002 +#define SMAPI_PROT_32BIT 0x0004 + u_int16_t reserved1; + + u_int16_t real16_offset; + u_int16_t real16_segment; + + u_int16_t reserved2; + + u_int16_t prot16_offset; + u_int32_t prot16_segment; + + u_int32_t prot32_offset; + u_int32_t prot32_segment; + +}; + +struct smapi_bios_parameter { + union { + struct { + u_int8_t func; + u_int8_t sub_func; + } in; + struct { + u_int8_t rc; + u_int8_t sub_rc; + } out; + } type; + + u_int16_t param1; + u_int16_t param2; + u_int16_t param3; + + u_int32_t param4; + u_int32_t param5; + +}; + +#define cmd_func type.in.func +#define cmd_sub_func type.in.sub_func +#define rsp_rc type.out.rc +#define rsp_sub_rc type.out.sub_rc + +#define SMAPIOGHEADER _IOR('$', 0, struct smapi_bios_header) +#define SMAPIOCGFUNCTION _IOWR('$', 1, struct smapi_bios_parameter) + +#endif /* _MACHINE_SMAPI_H_ */ diff --git a/sys/i386/smapi/smapi.c b/sys/i386/smapi/smapi.c new file mode 100644 index 0000000..e2e96ad --- /dev/null +++ b/sys/i386/smapi/smapi.c @@ -0,0 +1,167 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +u_long smapi32_offset; +u_short smapi32_segment; +#define SMAPI32_SEGMENT 0x18 + +devclass_t smapi_devclass; + +static d_open_t smapi_open; +static d_close_t smapi_close; +static d_ioctl_t smapi_ioctl; + +#define CDEV_MAJOR 183 + +static struct cdevsw smapi_cdevsw = { + /* open */ smapi_open, + /* close */ smapi_close, + /* read */ noread, + /* write */ nowrite, + /* ioctl */ smapi_ioctl, + /* poll */ nopoll, + /* mmap */ nommap, + /* strategy */ nostrategy, + /* name */ "smapi", + /* maj */ CDEV_MAJOR, + /* dump */ nodump, + /* psize */ nopsize, + /* flags */ D_MEM, + /* kqfilter */ NULL, +}; + +static int +smapi_open (dev, oflags, devtype, td) + dev_t dev; + int oflags; + int devtype; + d_thread_t * td; +{ + + return (0); +} + +static int +smapi_close (dev, fflag, devtype, td) + dev_t dev; + int fflag; + int devtype; + d_thread_t * td; +{ + + return (0); +} + +static int +smapi_ioctl (dev, cmd, data, fflag, td) + dev_t dev; + u_long cmd; + caddr_t data; + int fflag; + d_thread_t * td; +{ + struct smapi_softc *sc; + int error; + + error = 0; + sc = devclass_get_softc(smapi_devclass, minor(dev)); + if (sc == NULL) { + error = ENXIO; + goto fail; + } + + switch (cmd) { + case SMAPIOGHEADER: + bcopy((caddr_t)sc->header, data, + sizeof(struct smapi_bios_header)); + error = 0; + break; + case SMAPIOCGFUNCTION: + smapi32_segment = SMAPI32_SEGMENT; + smapi32_offset = sc->smapi32_entry; + error = smapi32((struct smapi_bios_parameter *)data, + (struct smapi_bios_parameter *)data); + break; + default: + error = ENOTTY; + } + +fail: + return (error); +} + +int +smapi_attach (struct smapi_softc *sc) +{ + struct smapi_bios_parameter input_param; + struct smapi_bios_parameter output_param; + int retval; + + sc->cdev = make_dev(&smapi_cdevsw, + device_get_unit(sc->dev), + UID_ROOT, GID_WHEEL, 0600, + "%s%d", + smapi_cdevsw.d_name, + device_get_unit(sc->dev)); + + bzero(&input_param, sizeof(struct smapi_bios_parameter)); + bzero(&output_param, sizeof(struct smapi_bios_parameter)); + smapi32_segment = SMAPI32_SEGMENT; + smapi32_offset = sc->smapi32_entry; + retval = smapi32(&output_param, &output_param); + +#if 0 + retval = smapi32_new(sc->smapi32_entry, SMAPI32_SEGMENT, + &output_param, &output_param); +#endif + + return (0); +} + +int +smapi_detach (struct smapi_softc *sc) +{ + + destroy_dev(sc->cdev); + return (0); +} diff --git a/sys/i386/smapi/smapi_bios.S b/sys/i386/smapi/smapi_bios.S new file mode 100644 index 0000000..2ada5c6 --- /dev/null +++ b/sys/i386/smapi/smapi_bios.S @@ -0,0 +1,54 @@ +/* $FreeBSD$ */ + +#include + + .data +smapi32_segment_tmp: .word 0 +smapi32_offset_tmp: .long 0 + .text +/* + * smapi32(input_param, output_param) + * struct smapi_bios_parameter *input_parm; + * struct smapi_bios_parameter *output_parm; + */ +ENTRY(smapi32) + pushl %ebp /* Save frame */ + movl %esp,%ebp + + pushl %ds + pushl 0x0c(%ebp) /* Output Param */ + pushl %ds + pushl 0x08(%ebp) /* Input Param */ + + movl $0,%eax /* Clear EAX (return 0) */ + movw %cs,smapi32_segment /* Save CS */ + lcall *(smapi32_offset) + + leave + ret + +/* + * smapi32(offset, segment, input_param, output_param) + * u_int offset; + * u_short segment; + * struct smapi_bios_parameter *input_parm; + * struct smapi_bios_parameter *output_parm; + */ +ENTRY(smapi32_new) + pushl %ebp /* Save frame */ + movl 0x08(%esp),%ebp + movl %ebp,smapi32_offset_tmp + movw 0x0c(%esp),%bp + movw %bp,smapi32_segment_tmp + + pushl %ds + pushl 0x20(%ebp) /* Output Param */ + pushl %ds + pushl 0x10(%ebp) /* Input Param */ + + movl $0,%eax + movw %cs,smapi32_segment_tmp + lcall *(smapi32_offset_tmp) + + leave + ret diff --git a/sys/i386/smapi/smapi_isa.c b/sys/i386/smapi/smapi_isa.c new file mode 100644 index 0000000..bd6bfd3 --- /dev/null +++ b/sys/i386/smapi/smapi_isa.c @@ -0,0 +1,274 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +/* And all this for BIOS_PADDRTOVADDR() */ +#include +#include +#include +#include + +#include +#include + +static void smapi_isa_identify (driver_t *, device_t); +static int smapi_isa_probe (device_t); +static int smapi_isa_attach (device_t); +static int smapi_isa_detach (device_t); +static int smapi_modevent (module_t, int, void *); + +static int smapi_header_cksum (struct smapi_bios_header *); + +#define SMAPI_ID 0x0000a24d + +static struct isa_pnp_id smapi_ids[] = { + { SMAPI_ID, NULL }, /* SMB0000 */ + { 0, NULL }, +}; + +#define SMAPI_START 0xf0000 +#define SMAPI_END 0xffff0 +#define SMAPI_STEP 0x10 + +#define SMAPI_SIGNATURE(h) ((h->signature[0] == '$') && \ + (h->signature[1] == 'S') && \ + (h->signature[2] == 'M') && \ + (h->signature[3] == 'B')) + +static void +smapi_isa_identify (driver_t *driver, device_t parent) +{ + device_t child; + struct resource *res; + struct smapi_bios_header *header; + u_int32_t chunk; + int rid; + + rid = 0; + chunk = SMAPI_START; + + child = BUS_ADD_CHILD(parent, ISA_ORDER_SENSITIVE, "smapi", -1); + device_set_driver(child, driver); + isa_set_logicalid(child, SMAPI_ID); + isa_set_vendorid(child, SMAPI_ID); + + while (chunk < SMAPI_END) { + bus_set_resource(child, SYS_RES_MEMORY, rid, chunk, + sizeof(struct smapi_bios_header)); + res = bus_alloc_resource(child, SYS_RES_MEMORY, &rid, + 0ul, ~0ul, 1, RF_ACTIVE); + if (res == NULL) { + bus_delete_resource(child, SYS_RES_MEMORY, rid); + chunk += SMAPI_STEP; + continue; + } + header = (struct smapi_bios_header *)rman_get_virtual(res); + + if (SMAPI_SIGNATURE(header)) { + if (smapi_header_cksum(header)) { + device_printf(child, "SMAPI header checksum failed.\n"); + } else { + goto found; + } + } else { + bus_release_resource(child, SYS_RES_MEMORY, rid, res); + bus_delete_resource(child, SYS_RES_MEMORY, rid); + } + + chunk += SMAPI_STEP; + } + + device_delete_child(parent, child); + return; + +found: + device_set_desc(child, "SMAPI BIOS"); + return; +} + +static int +smapi_isa_probe (device_t dev) +{ + return (ISA_PNP_PROBE(device_get_parent(dev), dev, smapi_ids)); +} + +static int +smapi_isa_attach (device_t dev) +{ + struct smapi_softc *sc; + int error; + + sc = device_get_softc(dev); + error = 0; + + sc->dev = dev; + sc->rid = 0; + sc->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid, + 0ul, ~0ul, 1, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "Unable to allocate memory resource.\n"); + error = ENOMEM; + goto bad; + } + sc->header = (struct smapi_bios_header *)rman_get_virtual(sc->res); + sc->smapi32_entry = (u_int32_t)BIOS_PADDRTOVADDR( + sc->header->prot32_segment + + sc->header->prot32_offset); + + if (smapi_header_cksum(sc->header)) { + device_printf(dev, "SMAPI header checksum failed.\n"); + error = ENXIO; + goto bad; + } + + if (smapi_attach(sc)) { + device_printf(dev, "SMAPI attach failed.\n"); + error = ENXIO; + goto bad; + } + + device_printf(dev, "Version %02d.%02d, Length %d, Checksum 0x%02x\n", + sc->header->version_major, sc->header->version_minor, + sc->header->length, sc->header->checksum); + device_printf(dev, "Information=0x%b\n", + sc->header->information, + "\020" + "\001REAL_VM86" + "\002PROTECTED_16" + "\003PROTECTED_32"); + + if (bootverbose) { + if (sc->header->information & SMAPI_REAL_VM86) + device_printf(dev, "Real/VM86 mode: Segment 0x%04x, Offset 0x%04x\n", + sc->header->real16_segment, + sc->header->real16_offset); + if (sc->header->information & SMAPI_PROT_16BIT) + device_printf(dev, "16-bit Protected mode: Segment 0x%08x, Offset 0x%04x\n", + sc->header->prot16_segment, + sc->header->prot16_offset); + if (sc->header->information & SMAPI_PROT_32BIT) + device_printf(dev, "32-bit Protected mode: Segment 0x%08x, Offset 0x%08x\n", + sc->header->prot32_segment, + sc->header->prot32_offset); + } + + return (0); +bad: + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + return (error); +} + +static int +smapi_isa_detach (device_t dev) +{ + struct smapi_softc *sc; + + sc = device_get_softc(dev); + + (void)smapi_detach(sc); + + if (sc->res) + bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res); + + return (0); +} + +static int +smapi_modevent (mod, what, arg) + module_t mod; + int what; + void * arg; +{ + device_t * devs; + int count; + int i; + + switch (what) { + case MOD_LOAD: + break; + case MOD_UNLOAD: + devclass_get_devices(smapi_devclass, &devs, &count); + for (i = 0; i < count; i++) { + device_delete_child(device_get_parent(devs[i]), devs[i]); + } + break; + default: + break; + } + + return (0); +} + +static device_method_t smapi_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, smapi_isa_identify), + DEVMETHOD(device_probe, smapi_isa_probe), + DEVMETHOD(device_attach, smapi_isa_attach), + DEVMETHOD(device_detach, smapi_isa_detach), + { 0, 0 } +}; + +static driver_t smapi_driver = { + "smapi", + smapi_methods, + sizeof(struct smapi_softc), +}; + +DRIVER_MODULE(smapi, isa, smapi_driver, smapi_devclass, smapi_modevent, 0); +MODULE_VERSION(smapi, 1); + +static int +smapi_header_cksum (struct smapi_bios_header *header) +{ + u_int8_t *ptr; + u_int8_t cksum; + int i; + + ptr = (u_int8_t *)header; + cksum = 0; + for (i = 0; i < header->length; i++) { + cksum += ptr[i]; + } + + return (cksum); +} diff --git a/sys/i386/smapi/smapi_var.h b/sys/i386/smapi/smapi_var.h new file mode 100644 index 0000000..c05ae8f --- /dev/null +++ b/sys/i386/smapi/smapi_var.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2003 Matthew N. Dodd + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +struct smapi_softc { + dev_t cdev; + device_t dev; + struct resource * res; + int rid; + + u_int32_t smapi32_entry; + + struct smapi_bios_header *header; +}; + +extern u_long smapi32_offset; +extern u_short smapi32_segment; +extern devclass_t smapi_devclass; + +int smapi_attach (struct smapi_softc *); +int smapi_detach (struct smapi_softc *); + +extern int smapi32 (struct smapi_bios_parameter *, + struct smapi_bios_parameter *); +extern int smapi32_new (u_long, u_short, + struct smapi_bios_parameter *, + struct smapi_bios_parameter *); -- cgit v1.1