diff options
author | Thorsten Lockert <tholo@cvs.openbsd.org> | 2005-06-02 20:09:40 +0000 |
---|---|---|
committer | Thorsten Lockert <tholo@cvs.openbsd.org> | 2005-06-02 20:09:40 +0000 |
commit | c2b861c0e32dd295ee7538db6b2aac4dd7c87de2 (patch) | |
tree | 7da2e9ae4792b3d3765f32971ba6c6c0ad4de685 | |
parent | 204533b59784a2ed890ea3c6aad96531b3989704 (diff) |
Start on a basic ACPI framework -- does not do much more than read out the
ACPI tables into kernel memory and attach ACPI and HPET timers currently.
In order to test this code, enabling the devices in GENERIC as well as
the ACPI_ENABLE option is needed. This code does not do any thermal
control yet, so this should be done with care depending on the platform.
In the tree so more people can contribute to making this more fully
featured.
Ok niklas@ grange@ tedu@
65 files changed, 10673 insertions, 26 deletions
diff --git a/etc/MAKEDEV.common b/etc/MAKEDEV.common index 724487b91ed..661ea719849 100644 --- a/etc/MAKEDEV.common +++ b/etc/MAKEDEV.common @@ -1,4 +1,4 @@ -vers(a, {-$OpenBSD: MAKEDEV.common,v 1.17 2005/03/29 16:40:08 miod Exp $-})dnl +vers(a, {-$OpenBSD: MAKEDEV.common,v 1.18 2005/06/02 20:09:38 tholo Exp $-})dnl divert(1)dnl dnl dnl Common device definitions. @@ -125,6 +125,7 @@ target(all, pctr0)dnl target(all, pf)dnl twrget(all, cry, crypto)dnl target(all, apm)dnl +target(all, acpi)dnl twrget(all, tth, ttyh, 0, 1)dnl target(all, ttyA, 0, 1)dnl target(all, ttyB, 0, 1, 2, 3, 4, 5)dnl @@ -441,6 +442,7 @@ __devitem(scc, scc*, 82530 serial interface,scc)dnl __devtitle(spec, Special purpose devices)dnl _mkdev(apm, apm*, {-M apm c major_apm_c 0 644 M apmctl c major_apm_c 8 644-})dnl +_mkdev(acpi, acpi*, {-M acpi c major_acpi_c 0 644-})dnl __devitem(pctr, pctr*, PC Performance Tuning Register access device)dnl _mkdev(pctr, pctr, {-M pctr c major_pctr_c 0 644-})dnl __devitem(systrace, systrace*, System call tracing device)dnl diff --git a/etc/etc.amd64/MAKEDEV.md b/etc/etc.amd64/MAKEDEV.md index 9ba75562876..9c8d2434782 100644 --- a/etc/etc.amd64/MAKEDEV.md +++ b/etc/etc.amd64/MAKEDEV.md @@ -1,5 +1,5 @@ vers(__file__, - {-$OpenBSD: MAKEDEV.md,v 1.10 2005/04/21 00:26:30 krw Exp $-}, + {-$OpenBSD: MAKEDEV.md,v 1.11 2005/06/02 20:09:38 tholo Exp $-}, etc.MACHINE)dnl dnl dnl Copyright (c) 2001-2004 Todd T. Fries <todd@OpenBSD.org> @@ -17,6 +17,7 @@ dnl ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. dnl dnl +__devitem(acpi, acpi, Advanced Configuration and Power Interface)dnl _TITLE(make) _DEV(all) _DEV(ramdisk) @@ -64,6 +65,7 @@ _DEV(usb, 61) _DEV(uscan, 77) _TITLE(spec) dnl _DEV(apm, 21) +_DEV(acpi, 83) _DEV(au, 42) _DEV(bktr, 49) _DEV(bpf, 23) diff --git a/etc/etc.i386/MAKEDEV.md b/etc/etc.i386/MAKEDEV.md index 6c94753a569..5844546a341 100644 --- a/etc/etc.i386/MAKEDEV.md +++ b/etc/etc.i386/MAKEDEV.md @@ -1,5 +1,5 @@ vers(__file__, - {-$OpenBSD: MAKEDEV.md,v 1.30 2005/04/21 00:26:30 krw Exp $-}, + {-$OpenBSD: MAKEDEV.md,v 1.31 2005/06/02 20:09:38 tholo Exp $-}, etc.MACHINE)dnl dnl dnl Copyright (c) 2001-2004 Todd T. Fries <todd@OpenBSD.org> @@ -18,6 +18,7 @@ dnl OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. dnl dnl __devitem(apm, apm, Power management device)dnl +__devitem(acpi, acpi, Advanced Configuration and Power Interface)dnl __devitem(nvram, nvram, NVRAM access)dnl _mkdev(nvram, nvram, {-M nvram c major_nvram_c 0 440 kmem-})dnl _TITLE(make) @@ -67,6 +68,7 @@ _DEV(usb, 61) _DEV(uscan, 77) _TITLE(spec) _DEV(apm, 21) +_DEV(acpi, 85) _DEV(au, 42) _DEV(bktr, 49) _DEV(bpf, 23) diff --git a/etc/mtree/4.4BSD.dist b/etc/mtree/4.4BSD.dist index b1679b2120e..b91516d55d7 100644 --- a/etc/mtree/4.4BSD.dist +++ b/etc/mtree/4.4BSD.dist @@ -1,4 +1,4 @@ -# $OpenBSD: 4.4BSD.dist,v 1.174 2005/04/02 17:21:06 jmc Exp $ +# $OpenBSD: 4.4BSD.dist,v 1.175 2005/06/02 20:09:38 tholo Exp $ /set type=dir uname=root gname=wheel mode=0755 # . @@ -23,6 +23,11 @@ dev # ./etc etc +# ./etc/acpi +acpi +# ./etc/acpi +.. + # ./etc/afs afs # ./etc/afs diff --git a/etc/mtree/special b/etc/mtree/special index b08d4094ced..41ad7a0d3bb 100644 --- a/etc/mtree/special +++ b/etc/mtree/special @@ -1,4 +1,4 @@ -# $OpenBSD: special,v 1.64 2005/02/19 11:56:54 henning Exp $ +# $OpenBSD: special,v 1.65 2005/06/02 20:09:38 tholo Exp $ # $NetBSD: special,v 1.4 1996/05/08 21:30:18 pk Exp $ # @(#)special 8.2 (Berkeley) 1/23/94 # @@ -16,6 +16,8 @@ mem type=char mode=0640 uname=root gname=kmem .. #dev etc type=dir mode=0755 uname=root gname=wheel +acpi type=dir mode=0755 uname=root gname=wheel ignore +.. #acpi bgpd.conf type=file mode=0600 uname=root gname=wheel crontab type=file mode=0644 uname=root gname=wheel optional csh.cshrc type=file mode=0644 uname=root gname=wheel @@ -1,4 +1,4 @@ -# $OpenBSD: rc,v 1.267 2005/05/19 01:58:49 millert Exp $ +# $OpenBSD: rc,v 1.268 2005/06/02 20:09:38 tholo Exp $ # System startup script run by init on autoboot # or after single-user. @@ -713,6 +713,10 @@ if [ X"${apmd_flags}" != X"NO" -a -x /usr/sbin/apmd ]; then echo -n ' apmd'; /usr/sbin/apmd ${apmd_flags} fi +if [ X"${acpid_flags}" != X"NO" -a -x /usr/sbin/acpid ]; then + echo -n ' acpid'; /usr/sbin/acpid ${acpid_flags} +fi + if [ X"${sensorsd_flags}" != X"NO" ]; then echo -n ' sensorsd'; /usr/sbin/sensorsd ${sensorsd_flags} fi diff --git a/etc/rc.conf b/etc/rc.conf index 616abce743e..5fc50a5129a 100644 --- a/etc/rc.conf +++ b/etc/rc.conf @@ -1,6 +1,6 @@ #!/bin/sh - # -# $OpenBSD: rc.conf,v 1.105 2005/03/22 22:24:38 henning Exp $ +# $OpenBSD: rc.conf,v 1.106 2005/06/02 20:09:38 tholo Exp $ # set these to "NO" to turn them off. otherwise, they're used as flags routed_flags=NO # for normal use: "-q" @@ -19,6 +19,7 @@ ntpd_flags=NO # for normal use: "" isakmpd_flags=NO # for normal use: "" mopd_flags=NO # for normal use: "-a" apmd_flags=NO # for normal use: "" +acpid_flags=NO # for normal use: "" dhcpd_flags=NO # for normal use: "" rtadvd_flags=NO # for normal use: list of interfaces # be sure to set net.inet6.ip6.forwarding=1 diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c new file mode 100644 index 00000000000..c9596fe5368 --- /dev/null +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -0,0 +1,154 @@ +/* $OpenBSD: acpi_machdep.c,v 1.1 2005/06/02 20:09:38 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <machine/biosvar.h> + +#include <dev/isa/isareg.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +#define ACPI_BIOS_RSDP_WINDOW_BASE 0xe0000 +#define ACPI_BIOS_RSDP_WINDOW_SIZE 0x20000 + +u_int8_t *acpi_scan(struct acpi_mem_map *, paddr_t, size_t); + +int +acpi_map(paddr_t pa, size_t len, struct acpi_mem_map *handle) +{ + paddr_t pgpa = x86_trunc_page(pa); + paddr_t endpa = x86_round_page(pa + len); + vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa); + + if (va == 0) + return (ENOMEM); + + handle->baseva = va; + handle->va = (u_int8_t *)(va + (pa & PGOFSET)); + handle->vsize = endpa - pgpa; + handle->pa = pa; + + do { + pmap_kenter_pa(va, pgpa, VM_PROT_READ); + va += NBPG; + pgpa += NBPG; + } while (pgpa < endpa); + + return 0; +} + +void +acpi_unmap(struct acpi_mem_map *handle) +{ + pmap_kremove(handle->baseva, handle->vsize); + uvm_km_free(kernel_map, handle->baseva, handle->vsize); +} + +u_int8_t * +acpi_scan(struct acpi_mem_map *handle, paddr_t pa, size_t len) +{ + size_t i; + u_int8_t *ptr; + struct acpi_rsdp1 *rsdp; + + if (acpi_map(pa, len, handle)) + return (NULL); + for (ptr = handle->va, i = 0; + i < len; + ptr += 16, i += 16) + if (memcmp(ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0) { + rsdp = (struct acpi_rsdp1 *)ptr; + /* + * Only checksum whichever portion of the + * RSDP that is actually present + */ + if (rsdp->revision == 0 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp1)) == 0) + return (ptr); + else if (rsdp->revision == 2 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp)) == 0) + return (ptr); + } + acpi_unmap(handle); + + return (NULL); +} + +int +acpi_probe(struct device *parent, struct cfdata *match, struct acpi_attach_args *aaa) +{ + struct acpi_mem_map handle; + u_int8_t *ptr; + paddr_t ebda; + bios_memmap_t *im; + + /* + * First look for ACPI entries in the BIOS memory map + */ + for (im = bios_memmap; im->type != BIOS_MAP_END; im++) + if (im->type == BIOS_MAP_ACPI) { + if ((ptr = acpi_scan(&handle, im->addr, im->size))) + goto havebase; + } + + /* + * Next try to find ACPI table entries in the EBDA + */ + if (acpi_map(0, NBPG, &handle)) + printf("acpi: failed to map BIOS data area\n"); + else { + ebda = *(const u_int16_t *)(&handle.va[0x40e]); + ebda <<= 4; + acpi_unmap(&handle); + + if (ebda && ebda < IOM_BEGIN) { + if ((ptr = acpi_scan(&handle, ebda, 1024))) + goto havebase; + } + } + + /* + * Finally try to find the ACPI table entries in the + * BIOS memory + */ + if ((ptr = acpi_scan(&handle, ACPI_BIOS_RSDP_WINDOW_BASE, + ACPI_BIOS_RSDP_WINDOW_SIZE))) + goto havebase; + + return (0); + +havebase: + aaa->aaa_pbase = ptr - handle.va + handle.pa; + acpi_unmap(&handle); + + return (1); +} + +void +acpi_attach_machdep(struct acpi_softc *sc) +{ + sc->sc_interrupt = intr_establish(sc->sc_fadt->sci_int, &i8259_pic, sc->sc_fadt->sci_int, + IST_LEVEL, IPL_TTY, acpi_interrupt, sc, "acpi"); +} diff --git a/sys/arch/amd64/amd64/conf.c b/sys/arch/amd64/amd64/conf.c index ffa6fb787c9..d2fa2a4e57d 100644 --- a/sys/arch/amd64/amd64/conf.c +++ b/sys/arch/amd64/amd64/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.6 2004/05/30 08:11:26 grange Exp $ */ +/* $OpenBSD: conf.c,v 1.7 2005/06/02 20:09:38 tholo Exp $ */ /* * Copyright (c) 1994, 1995 Charles M. Hannum. All rights reserved. @@ -159,6 +159,7 @@ cdev_decl(mcd); #include "midi.h" #include "sequencer.h" cdev_decl(music); +#include "acpi.h" #include "iop.h" #ifdef XFS #include <xfs/nxfs.h> @@ -297,6 +298,7 @@ struct cdevsw cdevsw[] = cdev_notdef(), /* 80: gpr? XXX */ cdev_ptm_init(NPTY,ptm), /* 81: pseudo-tty ptm device */ cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */ + cdev_acpi_init(NACPI,acpi), /* 83: ACPI */ }; int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 7ce605412d7..cdd4ffa0843 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.30 2004/08/03 00:56:22 art Exp $ */ +/* $OpenBSD: machdep.c,v 1.31 2005/06/02 20:09:38 tholo Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -131,16 +131,22 @@ #include <dev/isa/isareg.h> #include <machine/isa_machdep.h> #include <dev/ic/i8042reg.h> +#include <dev/acpi/acpivar.h> #ifdef DDB #include <machine/db_machdep.h> #include <ddb/db_extern.h> #endif +#include "acpi.h" #include "isa.h" #include "isadma.h" #include "ksyms.h" +#if NACPI > 0 +extern struct acpi_softc *acpi_softc; +#endif + /* the following is used externally (sysctl_hw) */ char machine[] = "amd64"; /* cpu "architecture" */ char machine_arch[] = "amd64"; /* machine == machine_arch */ @@ -893,9 +899,11 @@ haltsys: if (howto & RB_HALT) { if (howto & RB_POWERDOWN) { #if NACPI > 0 - delay(500000); - acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); - printf("WARNING: powerdown failed!\n"); + if (acpi_softc) { + delay(500000); + acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); + printf("WARNING: powerdown failed!\n"); + } #endif } diff --git a/sys/arch/amd64/amd64/mainbus.c b/sys/arch/amd64/amd64/mainbus.c index e4c5e6d32fd..8625cb64de5 100644 --- a/sys/arch/amd64/amd64/mainbus.c +++ b/sys/arch/amd64/amd64/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: mainbus.c,v 1.2 2005/06/02 20:09:38 tholo Exp $ */ /* $NetBSD: mainbus.c,v 1.1 2003/04/26 18:39:29 fvdl Exp $ */ /* @@ -44,14 +44,16 @@ #include "pci.h" #include "isa.h" +#include "acpi.h" #include <machine/cpuvar.h> #include <machine/i82093var.h> #include <machine/mpbiosvar.h> -/* - * XXXfvdl ACPI - */ +#if NACPI > 0 +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#endif int mainbus_match(struct device *, void *, void *); void mainbus_attach(struct device *, struct device *, void *); @@ -72,6 +74,9 @@ union mainbus_attach_args { struct isabus_attach_args mba_iba; struct cpu_attach_args mba_caa; struct apic_attach_args aaa_caa; +#if NACPI > 0 + struct acpi_attach_args mba_aaa; +#endif }; /* @@ -131,6 +136,17 @@ mainbus_attach(parent, self, aux) printf("\n"); +#if NACPI > 0 + { + memset(&mba.mba_aaa, 0, sizeof(mba.mba_aaa)); + mba.mba_aaa.aaa_name = "acpi"; + mba.mba_aaa.aaa_iot = X86_BUS_SPACE_IO; + mba.mba_aaa.aaa_memt = X86_BUS_SPACE_MEM; + + config_found(self, &mba.mba_aaa, mainbus_print); + } +#endif + #ifdef MPBIOS mpbios_present = mpbios_probe(self); #endif diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index c213f546627..8d9be42b133 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.70 2005/05/27 06:36:23 jason Exp $ +# $OpenBSD: GENERIC,v 1.71 2005/06/02 20:09:39 tholo Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -41,6 +41,13 @@ isa0 at mainbus0 #isa0 at pcib? pci* at mainbus0 +#acpi0 at mainbus? +#acpitimer* at acpi? +#hpet* at acpi? + +#option ACPIVERBOSE +#option ACPI_ENABLE + option PCIVERBOSE option USBVERBOSE diff --git a/sys/arch/amd64/conf/files.amd64 b/sys/arch/amd64/conf/files.amd64 index e77341ac1b3..f45e713e16f 100644 --- a/sys/arch/amd64/conf/files.amd64 +++ b/sys/arch/amd64/conf/files.amd64 @@ -1,4 +1,4 @@ -# $OpenBSD: files.amd64,v 1.11 2005/05/27 06:28:41 jason Exp $ +# $OpenBSD: files.amd64,v 1.12 2005/06/02 20:09:39 tholo Exp $ maxpartitions 16 maxusers 2 16 128 @@ -142,6 +142,12 @@ file dev/isa/fd.c fd needs-flag include "dev/usb/files.usb" # +# ACPI +# +include "../../../dev/acpi/files.acpi" +file arch/amd64/amd64/acpi_machdep.c acpi + +# # device major numbers # diff --git a/sys/arch/amd64/include/conf.h b/sys/arch/amd64/include/conf.h index 0eeee30a029..688c8eda04d 100644 --- a/sys/arch/amd64/include/conf.h +++ b/sys/arch/amd64/include/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.1 2004/01/28 01:39:39 mickey Exp $ */ +/* $OpenBSD: conf.h,v 1.2 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */ /* @@ -43,3 +43,10 @@ cdev_decl(spkr); #define biosselect seltrue cdev_decl(bios); + +#define cdev_acpi_init(c,n) {\ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } +cdev_decl(acpi); diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 42a9a622555..43c2cca9c6e 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.416 2005/05/27 02:08:14 martin Exp $ +# $OpenBSD: GENERIC,v 1.417 2005/06/02 20:09:39 tholo Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -56,6 +56,13 @@ isa0 at gscpcib? eisa0 at mainbus0 pci* at mainbus0 +#acpi0 at mainbus? +#acpitimer* at acpi? +#hpet* at acpi? + +option ACPIVERBOSE +#option ACPI_ENABLE + option PCIVERBOSE option EISAVERBOSE option USBVERBOSE diff --git a/sys/arch/i386/conf/files.i386 b/sys/arch/i386/conf/files.i386 index c92ad29ca6c..a61bfa4fbf7 100644 --- a/sys/arch/i386/conf/files.i386 +++ b/sys/arch/i386/conf/files.i386 @@ -1,4 +1,4 @@ -# $OpenBSD: files.i386,v 1.134 2005/05/21 19:13:55 brad Exp $ +# $OpenBSD: files.i386,v 1.135 2005/06/02 20:09:39 tholo Exp $ # # new style config file for i386 architecture # @@ -396,3 +396,6 @@ include "dev/i2c/files.i2c" # Machine-independent GPIO drivers # include "dev/gpio/files.gpio" + +include "../../../dev/acpi/files.acpi" +file arch/i386/i386/acpi_machdep.c acpi diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c new file mode 100644 index 00000000000..51f674c2cd0 --- /dev/null +++ b/sys/arch/i386/i386/acpi_machdep.c @@ -0,0 +1,175 @@ +/* $OpenBSD: acpi_machdep.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/malloc.h> + +#include <uvm/uvm_extern.h> + +#include <machine/bus.h> +#include <i386/isa/isa_machdep.h> + +#include <dev/isa/isareg.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +#include "bios.h" +#include "apm.h" + +#if NBIOS > 0 +#include <machine/biosvar.h> +#endif + +#define ACPI_BIOS_RSDP_WINDOW_BASE 0xe0000 +#define ACPI_BIOS_RSDP_WINDOW_SIZE 0x20000 + +#if NAPM > 0 && NBIOS > 0 +extern bios_apminfo_t *apm; +#endif + +u_int8_t *acpi_scan(struct acpi_mem_map *, paddr_t, size_t); + +int +acpi_map(paddr_t pa, size_t len, struct acpi_mem_map *handle) +{ + paddr_t pgpa = i386_trunc_page(pa); + paddr_t endpa = i386_round_page(pa + len); + vaddr_t va = uvm_km_valloc(kernel_map, endpa - pgpa); + + if (va == 0) + return (ENOMEM); + + handle->baseva = va; + handle->va = (u_int8_t *)(va + (pa & PGOFSET)); + handle->vsize = endpa - pgpa; + handle->pa = pa; + + do { + pmap_kenter_pa(va, pgpa, VM_PROT_READ); + va += NBPG; + pgpa += NBPG; + } while (pgpa < endpa); + + return 0; +} + +void +acpi_unmap(struct acpi_mem_map *handle) +{ + pmap_kremove(handle->baseva, handle->vsize); + uvm_km_free(kernel_map, handle->baseva, handle->vsize); +} + +u_int8_t * +acpi_scan(struct acpi_mem_map *handle, paddr_t pa, size_t len) +{ + size_t i; + u_int8_t *ptr; + struct acpi_rsdp1 *rsdp; + + if (acpi_map(pa, len, handle)) + return (NULL); + for (ptr = handle->va, i = 0; + i < len; + ptr += 16, i += 16) + if (memcmp(ptr, RSDP_SIG, sizeof(RSDP_SIG) - 1) == 0) { + rsdp = (struct acpi_rsdp1 *)ptr; + /* + * Only checksum whichever portion of the + * RSDP that is actually present + */ + if (rsdp->revision == 0 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp1)) == 0) + return (ptr); + else if (rsdp->revision == 2 && + acpi_checksum(ptr, sizeof(struct acpi_rsdp)) == 0) + return (ptr); + } + acpi_unmap(handle); + + return (NULL); +} + +int +acpi_probe(struct device *parent, struct cfdata *match, struct acpi_attach_args *aaa) +{ + struct acpi_mem_map handle; + u_int8_t *ptr; + paddr_t ebda; +#if NBIOS > 0 + bios_memmap_t *im; + + /* + * First look for ACPI entries in the BIOS memory map + */ + for (im = bios_memmap; im->type != BIOS_MAP_END; im++) + if (im->type == BIOS_MAP_ACPI) { + if ((ptr = acpi_scan(&handle, im->addr, im->size))) + goto havebase; + } +#endif + + /* + * Next try to find ACPI table entries in the EBDA + */ + if (acpi_map(0, NBPG, &handle)) + printf("acpi: failed to map BIOS data area\n"); + else { + ebda = *(const u_int16_t *)(&handle.va[0x40e]); + ebda <<= 4; + acpi_unmap(&handle); + + if (ebda && ebda < IOM_BEGIN) { + if ((ptr = acpi_scan(&handle, ebda, 1024))) + goto havebase; + } + } + + /* + * Finally try to find the ACPI table entries in the + * BIOS memory + */ + if ((ptr = acpi_scan(&handle, ACPI_BIOS_RSDP_WINDOW_BASE, + ACPI_BIOS_RSDP_WINDOW_SIZE))) + goto havebase; + + return (0); + +havebase: + aaa->aaa_pbase = ptr - handle.va + handle.pa; + acpi_unmap(&handle); + +#ifdef notyet + /* + * Disable APM if we are using ACPI + */ +#if NAPM > 0 && NBIOS > 0 + apm = NULL; +#endif +#endif + return (1); +} + +void +acpi_attach_machdep(struct acpi_softc *sc) +{ + sc->sc_interrupt = isa_intr_establish(NULL, sc->sc_fadt->sci_int, IST_LEVEL, + IPL_TTY, acpi_interrupt, sc, "acpi"); +} diff --git a/sys/arch/i386/i386/conf.c b/sys/arch/i386/i386/conf.c index 38072585d96..8a5ead04876 100644 --- a/sys/arch/i386/i386/conf.c +++ b/sys/arch/i386/i386/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.109 2004/10/03 21:28:34 jcs Exp $ */ +/* $OpenBSD: conf.c,v 1.110 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: conf.c,v 1.75 1996/05/03 19:40:20 christos Exp $ */ /* @@ -168,6 +168,7 @@ cdev_decl(mcd); #include "sequencer.h" cdev_decl(music); #include "joy.h" +#include "acpi.h" #include "apm.h" #include "pctr.h" #include "bios.h" @@ -324,6 +325,7 @@ struct cdevsw cdevsw[] = cdev_hotplug_init(NHOTPLUG,hotplug), /* 82: devices hot plugging */ cdev_gpio_init(NGPIO,gpio), /* 83: GPIO interface */ cdev_nvram_init(NNVRAM,nvram), /* 84: NVRAM interface */ + cdev_acpi_init(NACPI,acpi), /* 85: ACPI */ }; int nchrdev = sizeof(cdevsw) / sizeof(cdevsw[0]); diff --git a/sys/arch/i386/i386/mainbus.c b/sys/arch/i386/i386/mainbus.c index c242f14e5da..053a78ee8d5 100644 --- a/sys/arch/i386/i386/mainbus.c +++ b/sys/arch/i386/i386/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.16 2004/06/13 21:49:15 niklas Exp $ */ +/* $OpenBSD: mainbus.c,v 1.17 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: mainbus.c,v 1.21 1997/06/06 23:14:20 thorpej Exp $ */ /* @@ -50,6 +50,7 @@ #include "apm.h" #include "bios.h" #include "mpbios.h" +#include "acpi.h" #include <machine/cpuvar.h> #include <machine/i82093var.h> @@ -59,6 +60,11 @@ #include <machine/biosvar.h> #endif +#if NACPI > 0 +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#endif + #if 0 #ifdef SMP /* XXX MULTIPROCESSOR */ #include <machine/mp.h> @@ -88,6 +94,9 @@ union mainbus_attach_args { #endif struct cpu_attach_args mba_caa; struct apic_attach_args aaa_caa; +#if NACPI > 0 + struct acpi_attach_args mba_aaa; +#endif }; /* @@ -121,6 +130,16 @@ mainbus_attach(parent, self, aux) printf("\n"); +#if NACPI > 0 + { + memset(&mba.mba_aaa, 0, sizeof(mba.mba_aaa)); + mba.mba_aaa.aaa_name = "acpi"; + mba.mba_aaa.aaa_iot = I386_BUS_SPACE_IO; + mba.mba_aaa.aaa_memt = I386_BUS_SPACE_MEM; + + config_found(self, &mba.mba_aaa, mainbus_print); + } +#endif #if NBIOS > 0 { mba.mba_bios.bios_dev = "bios"; diff --git a/sys/arch/i386/include/conf.h b/sys/arch/i386/include/conf.h index 82a4f670620..33276008ce1 100644 --- a/sys/arch/i386/include/conf.h +++ b/sys/arch/i386/include/conf.h @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.h,v 1.10 2003/09/23 16:51:11 millert Exp $ */ +/* $OpenBSD: conf.h,v 1.11 2005/06/02 20:09:39 tholo Exp $ */ /* $NetBSD: conf.h,v 1.2 1996/05/05 19:28:34 christos Exp $ */ /* @@ -55,6 +55,12 @@ cdev_decl(pc); (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } +#define cdev_acpi_init(c,n) {\ + dev_init(c,n,open), dev_init(c,n,close), (dev_type_read((*))) enodev, \ + (dev_type_write((*))) enodev, dev_init(c,n,ioctl), \ + (dev_type_stop((*))) enodev, 0, (dev_type_poll((*))) enodev, \ + (dev_type_mmap((*))) enodev, D_KQFILTER, dev_init(c,n,kqfilter) } + cdev_decl(spkr); cdev_decl(mms); @@ -68,6 +74,8 @@ cdev_decl(joy); #define biospoll seltrue cdev_decl(bios); +cdev_decl(acpi); + cdev_decl(apm); #define pctrpoll seltrue diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c new file mode 100644 index 00000000000..77cdcc04ec1 --- /dev/null +++ b/sys/dev/acpi/acpi.c @@ -0,0 +1,597 @@ +/* $OpenBSD: acpi.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/fcntl.h> +#include <sys/ioccom.h> +#include <sys/event.h> + +#include <machine/conf.h> +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +int acpimatch(struct device *, void *, void *); +void acpiattach(struct device *, struct device *, void *); +int acpi_submatch(struct device *, void *, void *); +int acpi_print(void *, const char *); +int acpi_loadtables(struct acpi_softc *, struct acpi_rsdp *); +void acpi_load_table(paddr_t, size_t, acpi_qhead_t *); +void acpi_load_dsdt(paddr_t, struct acpi_q **); +void acpi_softintr(void *); +void acpi_filtdetach(struct knote *); +int acpi_filtread(struct knote *, long); + +#define ACPI_LOCK(sc) +#define ACPI_UNLOCK(sc) + +struct filterops acpiread_filtops = { + 1, NULL, acpi_filtdetach, acpi_filtread +}; + +struct cfattach acpi_ca = { + sizeof(struct acpi_softc), acpimatch, acpiattach +}; + +struct cfdriver acpi_cd = { + NULL, "acpi", DV_DULL +}; + +int acpi_evindex; +struct acpi_softc *acpi_softc; + +int +acpimatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct cfdata *cf = match; + + /* sanity */ + if (strcmp(aaa->aaa_name, cf->cf_driver->cd_name)) + return (0); + + if (!acpi_probe(parent, cf, aaa)) + return (0); + + return (1); +} + +void +acpiattach(struct device *parent, struct device *self, void *aux) +{ +#ifdef ACPI_ENABLE + bus_space_handle_t ioh; +#endif + struct acpi_attach_args *aaa = aux; + struct acpi_softc *sc = (struct acpi_softc *)self; + struct acpi_mem_map handle; + struct acpi_rsdp *rsdp; + struct acpi_q *entry; + paddr_t facspa; + + sc->sc_iot = aaa->aaa_iot; + sc->sc_memt = aaa->aaa_memt; + + printf(": "); + if (acpi_map(aaa->aaa_pbase, sizeof(struct acpi_rsdp), &handle)) + goto fail; + + rsdp = (struct acpi_rsdp *)handle.va; + printf("revision %d ", (int)rsdp->rsdp_revision); + + SIMPLEQ_INIT(&sc->sc_tables); + + sc->sc_fadt = NULL; + sc->sc_facs = NULL; + sc->sc_powerbtn = 0; + sc->sc_sleepbtn = 0; + + sc->sc_note = malloc(sizeof(struct klist), M_DEVBUF, M_NOWAIT); + memset(sc->sc_note, 0, sizeof(struct klist)); + + if (acpi_loadtables(sc, rsdp)) { + acpi_unmap(&handle); + return; + } + + acpi_unmap(&handle); + + /* + * Find the FADT + */ + SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { + if (memcmp(entry->q_table, FADT_SIG, sizeof(FADT_SIG) - 1) == 0) { + sc->sc_fadt = entry->q_table; + break; + } + } + if (sc->sc_fadt == NULL) + goto fail; + + /* + * Check if we are able to enable ACPI control + */ + if (!sc->sc_fadt->smi_cmd || + (!sc->sc_fadt->acpi_enable && !sc->sc_fadt->acpi_disable)) + goto fail; + + /* + * Load the DSDT from the FADT pointer -- use the + * extended (64-bit) pointer if it exists + */ + if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_dsdt == 0) + acpi_load_dsdt(sc->sc_fadt->dsdt, &entry); + else + acpi_load_dsdt(sc->sc_fadt->x_dsdt, &entry); + + if (entry == NULL) + printf("!DSDT "); + SIMPLEQ_INSERT_HEAD(&sc->sc_tables, entry, q_next); + + /* + * Set up a pointer to the firmware control structure + */ + if (sc->sc_fadt->hdr_revision < 3 || sc->sc_fadt->x_firmware_ctl == 0) + facspa = sc->sc_fadt->firmware_ctl; + else + facspa = sc->sc_fadt->x_firmware_ctl; + + if (acpi_map(facspa, sizeof(struct acpi_facs), &handle)) + printf("!FACS "); + else + sc->sc_facs = (struct acpi_facs *)handle.va; + + /* + * Take over ACPI control. Note that once we do this, we + * effectively tell the system that we have ownership of + * the ACPI hardware registers, and that SMI should leave + * them alone + * + * This may prevent thermal control on some systems where + * that actually does work + */ +#ifdef ACPI_ENABLE + bus_space_map(sc->sc_iot, sc->sc_fadt->smi_cmd, 1, 0, &ioh); + bus_space_write_1(sc->sc_iot, ioh, 0, sc->sc_fadt->acpi_enable); + bus_space_unmap(sc->sc_iot, ioh, 1); +#endif + + bus_space_map(sc->sc_iot, + sc->sc_fadt->pm1a_evt_blk, sc->sc_fadt->pm1_evt_len, + 0, &sc->sc_ioh_pm1a_evt); + +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + sc->sc_softih = softintr_establish(IPL_TTY, acpi_softintr, sc); +#else + timeout_set(&sc->sc_timeout, acpi_softintr, sc); +#endif + acpi_attach_machdep(sc); + + /* + * If we have an interrupt handler, we can get notification + * when certain status bits changes in the ACPI registers, + * so let us enable some events we can forward to userland + */ + if (sc->sc_interrupt) { + int16_t flags; + + flags = bus_space_read_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + sc->sc_fadt->pm1_evt_len / 2); + flags |= ACPI_PM1_PWRBTN_EN | ACPI_PM1_SLPBTN_EN; + bus_space_write_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + sc->sc_fadt->pm1_evt_len / 2, flags); + } + + printf("attached\n"); + + /* + * ACPI is enabled now -- attach timer + */ + { + struct acpi_attach_args aaa; + + memset(&aaa, 0, sizeof(aaa)); + aaa.aaa_name = "acpitimer"; + aaa.aaa_iot = sc->sc_iot; + aaa.aaa_memt = sc->sc_memt; +#if 0 + aaa.aaa_pcit = sc->sc_pcit; + aaa.aaa_smbust = sc->sc_smbust; +#endif + config_found(self, &aaa, acpi_print); + } + + /* + * Attach table-defined devices + */ + SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { + struct acpi_attach_args aaa; + + memset(&aaa, 0, sizeof(aaa)); + aaa.aaa_iot = sc->sc_iot; + aaa.aaa_memt = sc->sc_memt; +#if 0 + aaa.aaa_pcit = sc->sc_pcit; + aaa.aaa_smbust = sc->sc_smbust; +#endif + aaa.aaa_table = entry->q_table; + + config_found_sm(self, &aaa, acpi_print, acpi_submatch); + } + + acpi_softc = sc; + + return; + +fail: + printf(" failed attach\n"); +} + +int +acpi_submatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = (struct acpi_attach_args *)aux; + struct cfdata *cf = match; + + if (aaa->aaa_table == NULL) + return (0); + return ((*cf->cf_attach->ca_match)(parent, match, aux)); +} + +int +acpi_print(void *aux, const char *pnp) +{ + struct acpi_attach_args *aa = aux; +#ifdef ACPIVERBOSE + struct acpi_table_header *hdr = (struct acpi_table_header *)aa->aaa_table; +#endif + + if (pnp) { + if (aa->aaa_name) + printf("%s at %s", aa->aaa_name, pnp); +#ifdef ACPIVERBOSE + else + printf("acpi device at %s from", pnp); +#endif + } +#ifdef ACPIVERBOSE + if (hdr) + printf(" table %c%c%c%c", + hdr->signature[0], hdr->signature[1], + hdr->signature[2], hdr->signature[3]); +#endif + + return (UNCONF); +} + +int +acpi_loadtables(struct acpi_softc *sc, struct acpi_rsdp *rsdp) +{ + struct acpi_mem_map hrsdt, handle; + struct acpi_table_header *hdr; + int i, ntables; + size_t len; + + if (rsdp->rsdp_revision == 2) { + struct acpi_xsdt *xsdt; + + if (acpi_map(rsdp->rsdp_xsdt, sizeof(*hdr), &handle)) { + printf("couldn't map rsdt\n"); + return (ENOMEM); + } + + hdr = (struct acpi_table_header *)handle.va; + len = hdr->length; + acpi_unmap(&handle); + hdr = NULL; + + acpi_map(rsdp->rsdp_xsdt, len, &hrsdt); + xsdt = (struct acpi_xsdt *)hrsdt.va; + + ntables = (len - sizeof(struct acpi_table_header)) / + sizeof(xsdt->table_offsets[0]); + + for (i = 0; i < ntables; i++) { + acpi_map(xsdt->table_offsets[i], sizeof(*hdr), &handle); + hdr = (struct acpi_table_header *)handle.va; + acpi_load_table(xsdt->table_offsets[i], hdr->length, &sc->sc_tables); + acpi_unmap(&handle); + } + acpi_unmap(&hrsdt); + } + else { + struct acpi_rsdt *rsdt; + + if (acpi_map(rsdp->rsdp_rsdt, sizeof(*hdr), &handle)) { + printf("couldn't map rsdt\n"); + return (ENOMEM); + } + + hdr = (struct acpi_table_header *)handle.va; + len = hdr->length; + acpi_unmap(&handle); + hdr = NULL; + + acpi_map(rsdp->rsdp_rsdt, len, &hrsdt); + rsdt = (struct acpi_rsdt *)hrsdt.va; + + ntables = (len - sizeof(struct acpi_table_header)) / + sizeof(rsdt->table_offsets[0]); + + for (i = 0; i < ntables; i++) { + acpi_map(rsdt->table_offsets[i], sizeof(*hdr), &handle); + hdr = (struct acpi_table_header *)handle.va; + acpi_load_table(rsdt->table_offsets[i], hdr->length, &sc->sc_tables); + acpi_unmap(&handle); + } + acpi_unmap(&hrsdt); + } + + return (0); +} + +void +acpi_load_table(paddr_t pa, size_t len, acpi_qhead_t *queue) +{ + struct acpi_mem_map handle; + struct acpi_q *entry; + + entry = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT); + + if (entry != NULL) { + if (acpi_map(pa, len, &handle)) { + free(entry, M_DEVBUF); + return; + } + memcpy(entry->q_data, handle.va, len); + entry->q_table = entry->q_data; + acpi_unmap(&handle); + SIMPLEQ_INSERT_TAIL(queue, entry, q_next); + } +} + +void +acpi_load_dsdt(paddr_t pa, struct acpi_q **dsdt) +{ + struct acpi_mem_map handle; + struct acpi_table_header *hdr; + size_t len; + + if (acpi_map(pa, sizeof(*hdr), &handle)) + return; + hdr = (struct acpi_table_header *)handle.va; + len = hdr->length; + acpi_unmap(&handle); + + *dsdt = malloc(len + sizeof(struct acpi_q), M_DEVBUF, M_NOWAIT); + + if (*dsdt != NULL) { + if (acpi_map(pa, len, &handle)) { + free(*dsdt, M_DEVBUF); + *dsdt = NULL; + return; + } + memcpy((*dsdt)->q_data, handle.va, len); + (*dsdt)->q_table = (*dsdt)->q_data; + acpi_unmap(&handle); + } +} + +int +acpi_interrupt(void *arg) +{ + struct acpi_softc *sc = (struct acpi_softc *)arg; + u_int16_t flags; + + flags = bus_space_read_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, ACPI_PM1_STATUS); + if (flags & (ACPI_PM1_PWRBTN_STS | ACPI_PM1_SLPBTN_STS)) { + if (flags & ACPI_PM1_PWRBTN_STS) { + bus_space_write_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + ACPI_PM1_STATUS, ACPI_PM1_PWRBTN_STS); + /* + * Power-button has been pressed, do something! + */ + sc->sc_powerbtn = 1; + } + if (flags & ACPI_PM1_SLPBTN_STS) { + bus_space_write_2(sc->sc_iot, sc->sc_ioh_pm1a_evt, + ACPI_PM1_STATUS, ACPI_PM1_SLPBTN_STS); + /* + * Sleep-button has been pressed, do something! + */ + sc->sc_sleepbtn = 1; + } +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + softintr_schedule(sc->sc_softih); +#else + if (!timeout_pending(&sc->sc_timeout)) + timeout_add(&sc->sc_timeout, 0); +#endif + return (1); + } + return (0); +} + +void +acpi_softintr(void *arg) +{ + struct acpi_softc *sc = arg; + + if (sc->sc_powerbtn) { + sc->sc_powerbtn = 0; + acpi_evindex++; + KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_PWRBTN, acpi_evindex)); + } + if (sc->sc_sleepbtn) { + sc->sc_sleepbtn = 0; + acpi_evindex++; + KNOTE(sc->sc_note, ACPI_EVENT_COMPOSE(ACPI_EV_SLPBTN, acpi_evindex)); + } +} + +int +acpiopen(dev_t dev, int flag, int mode, struct proc *p) +{ + struct acpi_softc *sc; + int error = 0; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + if (!(flag & FREAD) || (flag & FWRITE)) + error = EINVAL; + + return (error); +} + +void +acpi_enter_sleep_state(struct acpi_softc *sc, int state) +{ +#ifdef ACPI_ENABLE + bus_space_handle_t ioh; + u_int16_t bits; + + bus_space_map(sc->sc_iot, + sc->sc_fadt->pm1a_cnt_blk, sc->sc_fadt->pm1_cnt_len, + 0, &ioh); + bits = bus_space_read_2(sc->sc_iot, ioh, 0); + bits |= state << 10; /* XXX This is sick and wrong and illegal! */ + bus_space_write_2(sc->sc_iot, ioh, 0, bits); + bits |= ACPI_PM1_SLP_EN; + bus_space_write_2(sc->sc_iot, ioh, 0, bits); + bus_space_unmap(sc->sc_iot, ioh, sc->sc_fadt->pm1_cnt_len); +#endif +} + +int +acpiclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct acpi_softc *sc; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + return (0); +} + +int +acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct acpi_softc *sc; + int error = 0; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + ACPI_LOCK(sc); + switch (cmd) { + case ACPI_IOC_GETFACS: + if (suser(p, 0) != 0) + error = EPERM; + else { + struct acpi_facs *facs = (struct acpi_facs *)data; + + bcopy(sc->sc_facs, facs, sc->sc_facs->length); + } + break; + + case ACPI_IOC_GETTABLE: + if (suser(p, 0) != 0) + error = EPERM; + else { + struct acpi_table *table = (struct acpi_table *)data; + struct acpi_table_header *hdr; + struct acpi_q *entry; + + error = ENOENT; + SIMPLEQ_FOREACH(entry, &sc->sc_tables, q_next) { + if (table->offset-- == 0) { + hdr = (struct acpi_table_header *)entry->q_table; + if (table->table == NULL) { + table->size = hdr->length; + error = 0; + } + else if (hdr->length > table->size) + error = ENOSPC; + else + error = copyout(hdr, table->table, hdr->length); + break; + } + } + } + break; + + default: + error = ENOTTY; + } + + ACPI_UNLOCK(sc); + return (error); +} + +void +acpi_filtdetach(struct knote *kn) +{ + struct acpi_softc *sc = kn->kn_hook; + + ACPI_LOCK(sc); + SLIST_REMOVE(sc->sc_note, kn, knote, kn_selnext); + ACPI_UNLOCK(sc); +} + +int +acpi_filtread(struct knote *kn, long hint) +{ + /* XXX weird kqueue_scan() semantics */ + if (hint & !kn->kn_data) + kn->kn_data = hint; + + return(1); +} + +int +acpikqfilter(dev_t dev, struct knote *kn) +{ + struct acpi_softc *sc; + + if (!acpi_cd.cd_ndevs || minor(dev) != 0 || + !(sc = acpi_cd.cd_devs[minor(dev)])) + return (ENXIO); + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &acpiread_filtops; + break; + default: + return (1); + } + + kn->kn_hook = sc; + + ACPI_LOCK(sc); + SLIST_INSERT_HEAD(sc->sc_note, kn, kn_selnext); + ACPI_UNLOCK(sc); + + return (0); +} diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h new file mode 100644 index 00000000000..9b3c965ffe8 --- /dev/null +++ b/sys/dev/acpi/acpireg.h @@ -0,0 +1,428 @@ +/* $OpenBSD: acpireg.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Root System Descriptor Pointer */ +struct acpi_rsdp1 { + u_int8_t signature[8]; +#define RSDP_SIG "RSD PTR " +#define rsdp_signaturee rsdp1.signature + u_int8_t checksum; /* make sum == 0 */ +#define rsdp_checksum rsdp1.checksum + u_int8_t oemid[6]; +#define rsdp_oemid rsdp1.oemid + u_int8_t revision; /* 0 for 1, 2 for 2 */ +#define rsdp_revision rsdp1.revision + u_int32_t rsdt; /* physical */ +#define rsdp_rsdt rsdp1.rsdt +} __packed; + +struct acpi_rsdp { + struct acpi_rsdp1 rsdp1; + /* + * The following values are only valid + * when rsdp_revision == 2 + */ + u_int32_t rsdp_length; /* length of rsdp */ + u_int64_t rsdp_xsdt; /* physical */ + u_int8_t rsdp_extchecksum; /* entire table */ + u_int8_t rsdp_reserved[3]; /* must be zero */ +} __packed; + +struct acpi_table_header { + u_int8_t signature[4]; +#define hdr_signature hdr.signature + u_int32_t length; +#define hdr_length hdr.length + u_int8_t revision; +#define hdr_revision hdr.revision + u_int8_t checksum; +#define hdr_checksum hdr.checksum + u_int8_t oemid[6]; +#define hdr_oemid hdr.oemid + u_int8_t oemtableid[8]; +#define hdr_oemtableid hdr.oemtableid + u_int32_t oemrevision; +#define hdr_oemrevision hdr.oemrevision + u_int8_t aslcompilerid[4]; +#define hdr_aslcompilerid hdr.aslcompilerid + u_int32_t aslcompilerrevision; +#define hdr_aslcompilerrevision hdr.aslcompilerrevision +} __packed; + +struct acpi_rsdt { + struct acpi_table_header hdr; +#define RSDT_SIG "RSDT" + u_int32_t table_offsets[1]; +} __packed; + +struct acpi_xsdt { + struct acpi_table_header hdr; +#define XSDT_SIG "XSDT" + u_int64_t table_offsets[1]; +} __packed; + +struct acpi_gas { + u_int8_t address_space_id; +#define GAS_SYSTEM_MEMORY 0 +#define GAS_SYSTEM_IOSPACE 1 +#define GAS_PCI_CFG_SPACE 2 +#define GAS_EMBEDDED 3 +#define GAS_SMBUS 4 +#define GAS_FUNCTIONAL_FIXED 127 + u_int8_t register_bit_width; + u_int8_t register_bit_offset; + u_int8_t access_size; +#define GAS_ACCESS_UNDEFINED 0 +#define GAS_ACCESS_BYTE 1 +#define GAS_ACCESS_WORD 2 +#define GAS_ACCESS_DWORD 3 +#define GAS_ACCESS_QWORD 4 + u_int64_t address; +} __packed; + +struct acpi_fadt { + struct acpi_table_header hdr; +#define FADT_SIG "FACP" + u_int32_t firmware_ctl; /* phys addr FACS */ + u_int32_t dsdt; /* phys addr DSDT */ + u_int8_t int_model; /* interrupt model (hdr_revision < 3) */ +#define FADT_INT_DUAL_PIC 0 +#define FADT_INT_MULTI_APIC 1 + u_int8_t pm_profile; /* power mgmt profile */ +#define FADT_PM_UNSPEC 0 +#define FADT_PM_DESKTOP 1 +#define FADT_PM_MOBILE 2 +#define FADT_PM_WORKSTATION 3 +#define FADT_PM_ENT_SERVER 4 +#define FADT_PM_SOHO_SERVER 5 +#define FADT_PM_APPLIANCE 6 +#define FADT_PM_PERF_SERVER 7 + u_int16_t sci_int; /* SCI interrupt */ + u_int32_t smi_cmd; /* SMI command port */ + u_int8_t acpi_enable; /* value to enable */ + u_int8_t acpi_disable; /* value to disable */ + u_int8_t s4bios_req; /* value for S4 */ + u_int8_t pstate_cnt; /* value for performance (hdr_revision > 2) */ + u_int32_t pm1a_evt_blk; /* power management 1a */ + u_int32_t pm1b_evt_blk; /* power mangement 1b */ + u_int32_t pm1a_cnt_blk; /* pm control 1a */ + u_int32_t pm1b_cnt_blk; /* pm control 1b */ + u_int32_t pm2_cnt_blk; /* pm control 2 */ + u_int32_t pm_tmr_blk; + u_int32_t gpe0_blk; + u_int32_t gpe1_blk; + u_int8_t pm1_evt_len; + u_int8_t pm1_cnt_len; + u_int8_t pm2_cnt_len; + u_int8_t pm_tmr_len; + u_int8_t gpe0_blk_len; + u_int8_t gpe1_blk_len; + u_int8_t gpe1_base; + u_int8_t cst_cnt; /* (hdr_revision > 2) */ + u_int16_t p_lvl2_lat; + u_int16_t p_lvl3_lat; + u_int16_t flush_size; + u_int16_t flush_stride; + u_int8_t duty_offset; + u_int8_t duty_width; + u_int8_t day_alrm; + u_int8_t mon_alrm; + u_int8_t century; + u_int16_t iapc_boot_arch; /* (hdr_revision > 2) */ +#define FADT_LEGACY_DEVICES 0x0001 /* Legacy devices supported */ +#define FADT_i8042 0x0002 /* Keyboard controller present */ +#define FADT_NO_VGA 0x0004 /* Do not probe VGA */ + u_int8_t reserved1; + u_int32_t flags; +#define FADT_WBINVD 0x00000001 +#define FADT_WBINVD_FLUSH 0x00000002 +#define FADT_PROC_C1 0x00000004 +#define FADT_P_LVL2_UP 0x00000008 +#define FADT_PWR_BUTTON 0x00000010 +#define FADT_SLP_BUTTON 0x00000020 +#define FADT_FIX_RTC 0x00000040 +#define FADT_RTC_S4 0x00000080 +#define FADT_TMR_VAL_EXT 0x00000100 +#define FADT_DCK_CAP 0x00000200 +#define FADT_RESET_REG_SUP 0x00000400 +#define FADT_SEALED_CASE 0x00000800 +#define FADT_HEADLESS 0x00001000 +#define FADT_CPU_SW_SLP 0x00002000 +#define FADT_PCI_EXP_WAK 0x00004000 +#define FADT_USE_PLATFORM_CLOCK 0x00008000 +#define FADT_S4_RTC_STS_VALID 0x00010000 +#define FADT_REMOTE_POWER_ON_CAPABLE 0x00020000 +#define FADT_FORCE_APIC_CLUSTER_MODEL 0x00040000 +#define FADT_FORCE_APIC_PHYS_DEST_MODE 0x00080000 + /* + * Following values only exist when rev > 1 + * If the extended addresses exists, they + * must be used in preferense to the non- + * extended values above + */ + struct acpi_gas reset_reg; + u_int8_t reset_value; + u_int8_t reserved2a; + u_int8_t reserved2b; + u_int8_t reserved2c; + u_int64_t x_firmware_ctl; + u_int64_t x_dsdt; + struct acpi_gas x_pm1a_evt_blk; + struct acpi_gas x_pm1b_evt_blk; + struct acpi_gas x_pm1a_cnt_blk; + struct acpi_gas x_pm1b_cnt_blk; + struct acpi_gas x_pm2_cnt_blk; + struct acpi_gas x_pm_tmr_blk; + struct acpi_gas x_gpe0_blk; + struct acpi_gas x_gpe1_blk; +} __packed; + +struct acpi_dsdt { + struct acpi_table_header hdr; +#define DSDT_SIG "DSDT" + u_int8_t aml[1]; +} __packed; + +struct acpi_ssdt { + struct acpi_table_header hdr; +#define SSDT_SIG "SSDT" + u_int8_t aml[1]; +} __packed; + +/* + * Table deprecated by ACPI 2.0 + */ +struct acpi_psdt { + struct acpi_table_header hdr; +#define PSDT_SIG "PSDT" +} __packed; + +struct acpi_madt { + struct acpi_table_header hdr; +#define MADT_SIG "APIC" + u_int32_t local_apic_address; + u_int32_t flags; +#define ACPI_APIC_PCAT_COMPAT 0x00000001 +} __packed; + +struct acpi_madt_lapic { + u_int8_t apic_type; +#define ACPI_MADT_LAPIC 0 + u_int8_t length; + u_int8_t acpi_proc_id; + u_int8_t apic_id; + u_int32_t flags; +#define ACPI_PROC_ENABLE 0x00000001 +} __packed; + +struct acpi_madt_ioapic { + u_int8_t apic_type; +#define ACPI_MADT_IOAPIC 1 + u_int8_t length; + u_int8_t acpi_ioapic_id; + u_int8_t reserved; + u_int32_t address; + u_int32_t global_int_base; +} __packed; + +struct acpi_madt_override { + u_int8_t apic_type; +#define ACPI_MADT_OVERRIDE 2 + u_int8_t length; + u_int8_t bus; +#define ACPI_OVERRIDE_BUS_ISA 0 + u_int8_t source; + u_int32_t global_int; + u_int16_t flags; +#define ACPI_OVERRIDE_POLARITY_BITS 0x3 +#define ACPI_OVERRIDE_POLARITY_BUS 0x0 +#define ACPI_OVERRIDE_POLARITY_HIGH 0x1 +#define ACPI_OVERRIDE_POLARITY_LOW 0x3 +#define ACPI_OVERRIDE_TRIGGER_BITS 0xc +#define ACPI_OVERRIDE_TRIGGER_BUS 0x0 +#define ACPI_OVERRIDE_TRIGGER_EDGE 0x4 +#define ACPI_OVERRIDE_TRIGGER_LEVEL 0xc +} __packed; + +struct acpi_madt_nmi { + u_int8_t apic_type; +#define ACPI_MADT_NMI 3 + u_int8_t length; + u_int16_t flags; /* Same flags as acpi_madt_override */ + u_int32_t global_int; +} __packed; + +struct acpi_madt_lapic_nmi { + u_int8_t apic_type; +#define ACPI_MADT_LAPIC_NMI 4 + u_int8_t length; + u_int8_t acpi_proc_id; + u_int16_t flags; /* Same flags as acpi_madt_override */ + u_int8_t local_apic_lint; +} __packed; + +struct acpi_madt_lapic_override { + u_int8_t apic_type; +#define ACPI_MADT_LAPIC_OVERRIDE 5 + u_int8_t length; + u_int16_t reserved; + u_int64_t lapic_address; +} __packed; + +struct acpi_madt_io_sapic { + u_int8_t apic_type; +#define ACPI_MADT_IO_SAPIC 6 + u_int8_t length; + u_int8_t iosapic_id; + u_int8_t reserved; + u_int32_t global_int_base; + u_int64_t iosapic_address; +} __packed; + +struct acpi_madt_local_sapic { + u_int8_t apic_type; +#define ACPI_MADT_LOCAL_SAPIC 7 + u_int8_t length; + u_int8_t acpi_proc_id; + u_int8_t local_sapic_id; + u_int8_t local_sapic_eid; + u_int8_t reserved[3]; + u_int32_t flags; /* Same flags as acpi_madt_lapic */ + u_int32_t acpi_proc_uid; + u_int8_t acpi_proc_uid_string[1]; +} __packed; + +struct acpi_madt_platform_int { + u_int8_t apic_type; +#define ACPI_MADT_PLATFORM_INT 8 + u_int8_t length; + u_int16_t flags; /* Same flags as acpi_madt_override */ + u_int8_t int_type; +#define ACPI_MADT_PLATFORM_PMI 1 +#define ACPI_MADT_PLATFORM_INIT 2 +#define ACPI_MADT_PLATFORM_CORR_ERROR 3 + u_int8_t proc_id; + u_int8_t proc_eid; + u_int8_t io_sapic_vec; + u_int32_t global_int; + u_int32_t platform_int_flags; +#define ACPI_MADT_PLATFORM_CPEI 0x00000001 +} __packed; + +union acpi_madt_entry { + struct acpi_madt_lapic madt_lapic; + struct acpi_madt_ioapic madt_ioapic; + struct acpi_madt_override madt_override; + struct acpi_madt_nmi madt_nmi; + struct acpi_madt_lapic_nmi madt_lapic_nmi; + struct acpi_madt_lapic_override madt_lapic_override; + struct acpi_madt_io_sapic madt_io_sapic; + struct acpi_madt_local_sapic madt_local_sapic; + struct acpi_madt_platform_int madt_platform_int; +} __packed; + +struct acpi_sbst { + struct acpi_table_header hdr; +#define SBST_SIG "SBST" + u_int32_t warning_energy_level; + u_int32_t low_energy_level; + u_int32_t critical_energy_level; +} __packed; + +struct acpi_ecdt { + struct acpi_table_header hdr; +#define ECDT_SIG "ECDT" + struct acpi_gas ec_control; + struct acpi_gas ec_data; + u_int32_t uid; + u_int8_t gpe_bit; + u_int8_t ec_id[1]; +} __packed; + +struct acpi_srat { + struct acpi_table_header hdr; +#define SRAT_SIG "SRAT" + u_int32_t reserved1; + u_int64_t reserved2; +} __packed; + +struct acpi_slit { + struct acpi_table_header hdr; +#define SLIT_SIG "SLIT" + u_int64_t number_of_localities; +} __packed; + +struct acpi_hpet { + struct acpi_table_header hdr; +#define HPET_SIG "HPET" + u_int32_t event_timer_block_id; + struct acpi_gas base_address; + u_int8_t hpet_number; + u_int16_t main_counter_min_clock_tick; + u_int8_t page_protection; +} __packed; + +struct acpi_facs { + u_int8_t signature[4]; +#define FACS_SIG "FACS" + u_int32_t length; + u_int32_t hardware_signature; + u_int32_t wakeup_vector; + u_int32_t global_lock; +#define FACS_LOCK_PENDING 0x00000001 +#define FACS_LOCK_OWNED 0x00000002 + u_int32_t flags; +#define FACS_S4BIOS_F 0x00000001 /* S4BIOS_REQ supported */ + struct acpi_gas x_wakeup_vector; + u_int8_t version; + u_int8_t reserved[31]; +} __packed; + +#define ACPI_FREQUENCY 3579545 /* Per ACPI spec */ + +/* + * PM1 Status Registers Fixed Hardware Feature Status Bits + */ +#define ACPI_PM1_STATUS 0x00 +#define ACPI_PM1_TMR_STS 0x0001 +#define ACPI_PM1_BM_STS 0x0010 +#define ACPI_PM1_GBL_STS 0x0020 +#define ACPI_PM1_PWRBTN_STS 0x0100 +#define ACPI_PM1_SLPBTN_STS 0x0200 +#define ACPI_PM1_RTC_STS 0x0400 +#define ACPI_PM1_PCIEXP_WAKE_STS 0x4000 +#define ACPI_PM1_WAK_STS 0x8000 + +/* + * PM1 Enable Registers + */ +#define ACPI_PM1_ENABLE 0x02 +#define ACPI_PM1_TMR_EN 0x0001 +#define ACPI_PM1_GBL_EN 0x0020 +#define ACPI_PM1_PWRBTN_EN 0x0100 +#define ACPI_PM1_SLPBTN_EN 0x0200 +#define ACPI_PM1_RTC_EN 0x0400 +#define ACPI_PM1_PCIEXP_WAKE_DIS 0x4000 + +/* + * PM1 Control Registers + */ +#define ACPI_PM1_CONTROL 0x00 +#define ACPI_PM1_SCI_EN 0x0001 +#define ACPI_PM1_BM_RLD 0x0002 +#define ACPI_PM1_GBL_RLS 0x0004 +#define ACPI_PM1_SLP_EN 0x2000 diff --git a/sys/dev/acpi/acpitimer.c b/sys/dev/acpi/acpitimer.c new file mode 100644 index 00000000000..2cf89d6efda --- /dev/null +++ b/sys/dev/acpi/acpitimer.c @@ -0,0 +1,152 @@ +/* $OpenBSD: acpitimer.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#ifdef __HAVE_TIMECOUNTER +#include <sys/timetc.h> +#endif + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +int acpitimermatch(struct device *, void *, void *); +void acpitimerattach(struct device *, struct device *, void *); + +#ifdef __HAVE_TIMECOUNTER +u_int acpi_get_timecount(struct timecounter *tc); + +static struct timecounter acpi_timecounter = { + acpi_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + 0x00ffffff, /* counter_mask (24 bits) */ + ACPI_FREQUENCY, /* frequency */ + 0, /* name */ + 1000 /* quality */ +}; +#endif + +struct acpitimer_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct cfattach acpitimer_ca = { + sizeof(struct acpitimer_softc), acpitimermatch, acpitimerattach +}; + +struct cfdriver acpitimer_cd = { + NULL, "acpitimer", DV_DULL +}; + +int +acpitimermatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aa = aux; + struct cfdata *cf = match; + + /* sanity */ + if (aa->aaa_name == NULL || + strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 || + aa->aaa_table != NULL) + return (0); + + return (1); +} + +void +acpitimerattach(struct device *parent, struct device *self, void *aux) +{ + struct acpitimer_softc *sc = (struct acpitimer_softc *) self; + struct acpi_softc *psc = (struct acpi_softc *) parent; + struct acpi_attach_args *aa = aux; + bus_addr_t address; + bus_size_t size; + + if (psc->sc_fadt->hdr_revision > 1) { + switch (psc->sc_fadt->x_pm_tmr_blk.address_space_id) { + case GAS_SYSTEM_MEMORY: + sc->sc_iot = aa->aaa_memt; + break; + + case GAS_SYSTEM_IOSPACE: + sc->sc_iot = aa->aaa_iot; + break; + +#if 0 + case GAS_SYSTEM_PCI_CFG_SPACE: + sc->sc_iot = aa->aaa_pcit; + break; + + case GAS_SYSTEM_SMBUS: + sc->sc_iot = aa->aaa_smbust; + break; +#endif + + default: + printf(": can't identify bus\n"); + return; + } + address = psc->sc_fadt->x_pm_tmr_blk.address; + } + else { + sc->sc_iot = aa->aaa_iot; + address = psc->sc_fadt->pm_tmr_blk; + } + size = psc->sc_fadt->pm_tmr_len; + + if (bus_space_map(sc->sc_iot, address, size, 0, &sc->sc_ioh)) { + printf(": can't map i/o space\n"); + return; + } + + printf(": %ld Hz, %d bits\n", ACPI_FREQUENCY, + psc->sc_fadt->flags & FADT_TMR_VAL_EXT ? 32 : 24); + +#ifdef __HAVE_TIMECOUNTER + if (psc->sc_fadt->flags & FADT_TMR_VAL_EXT) + acpi_timecounter.tc_counter_mask = 0xffffffffU; + acpi_timecounter.tc_priv = sc; + acpi_timecounter.tc_name = sc->sc_dev.dv_xname; + tc_init(&acpi_timecounter); +#endif +} + + +#ifdef __HAVE_TIMECOUNTER +u_int +acpi_get_timecount(struct timecounter *tc) +{ + struct acpitimer_softc *sc = tc->tc_priv; + u_int u1, u2, u3; + + u2 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); + u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); + do { + u1 = u2; + u2 = u3; + u3 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 0); + } while (u1 > u2 || u2 > u3); + return (u2); +} +#endif diff --git a/sys/dev/acpi/acpiutil.c b/sys/dev/acpi/acpiutil.c new file mode 100644 index 00000000000..c364c97d03b --- /dev/null +++ b/sys/dev/acpi/acpiutil.c @@ -0,0 +1,42 @@ +/* $OpenBSD: acpiutil.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +u_int +acpi_checksum(const void *v, size_t len) +{ + const u_char *p = v; + u_char s; + int i; + + s = 0; + for (i = 0; i < len; i++) + s += p[i]; + + if (s) + printf("acpi: bad checksum at %p\n", v); + + return (s); +} diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h new file mode 100644 index 00000000000..b654a45bba4 --- /dev/null +++ b/sys/dev/acpi/acpivar.h @@ -0,0 +1,111 @@ +/* $OpenBSD: acpivar.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/timeout.h> + +struct klist; + +struct acpi_attach_args { + char *aaa_name; + bus_space_tag_t aaa_iot; + bus_space_tag_t aaa_memt; + void *aaa_table; + paddr_t aaa_pbase; /* Physical base address of ACPI tables */ +}; + +struct acpi_mem_map { + vaddr_t baseva; + u_int8_t *va; + size_t vsize; + paddr_t pa; +}; + +struct acpi_q { + SIMPLEQ_ENTRY(acpi_q) q_next; + void *q_table; + u_int8_t q_data[0]; +}; + +typedef SIMPLEQ_HEAD(, acpi_q) acpi_qhead_t; + +struct acpi_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_tag_t sc_memt; +#if 0 + bus_space_tag_t sc_pcit; + bus_space_tag_t sc_smbust; +#endif + + /* + * First-level ACPI tables + */ + struct acpi_fadt *sc_fadt; + acpi_qhead_t sc_tables; + + /* + * Second-level information from FADT + */ + struct acpi_facs *sc_facs; /* Shared with firmware! */ + + struct klist *sc_note; + bus_space_handle_t sc_ioh_pm1a_evt; + + void *sc_interrupt; +#ifdef __HAVE_GENERIC_SOFT_INTERRUPTS + void *sc_softih; +#else + struct timeout sc_timeout; +#endif + + int sc_powerbtn; + int sc_sleepbtn; +}; + +struct acpi_table { + int offset; + size_t size; + void *table; +}; + +#define ACPI_IOC_GETFACS _IOR('A', 0, struct acpi_facs) +#define ACPI_IOC_GETTABLE _IOWR('A', 1, struct acpi_table) + +#define ACPI_EV_PWRBTN 0x0001 /* Power button was pushed */ +#define ACPI_EV_SLPBTN 0x0002 /* Sleep button was pushed */ + +#define ACPI_EVENT_MASK 0x0003 + +#define ACPI_EVENT_COMPOSE(t,i) (((i) & 0x7fff) << 16 | ((t) & ACPI_EVENT_MASK)) +#define ACPI_EVENT_TYPE(e) ((e) & ACPI_EVENT_MASK) +#define ACPI_EVENT_INDEX(e) ((e) >> 16) + +/* + * Sleep states + */ +#define ACPI_STATE_S5 5 + +#if defined(_KERNEL) +int acpi_map(paddr_t, size_t, struct acpi_mem_map *); +void acpi_unmap(struct acpi_mem_map *); +int acpi_probe(struct device *, struct cfdata *, struct acpi_attach_args *); +u_int acpi_checksum(const void *, size_t); +void acpi_attach_machdep(struct acpi_softc *); +int acpi_interrupt(void *); +void acpi_enter_sleep_state(struct acpi_softc *, int); +#endif diff --git a/sys/dev/acpi/files.acpi b/sys/dev/acpi/files.acpi new file mode 100644 index 00000000000..c03ba10e83e --- /dev/null +++ b/sys/dev/acpi/files.acpi @@ -0,0 +1,20 @@ +# $OpenBSD: files.acpi,v 1.1 2005/06/02 20:09:39 tholo Exp $ +# +# Config file and device description for machine-independent ACPI code. +# Included by ports that need it. + +define acpi {} +device acpi +attach acpi at mainbus +file dev/acpi/acpi.c acpi needs-flag +file dev/acpi/acpiutil.c acpi + +# ACPI timer +device acpitimer +attach acpitimer at acpi +file dev/acpi/acpitimer.c acpitimer + +# High Precision Event Timer +device hpet +attach hpet at acpi +file dev/acpi/hpet.c hpet
\ No newline at end of file diff --git a/sys/dev/acpi/hpet.c b/sys/dev/acpi/hpet.c new file mode 100644 index 00000000000..e79e7a42627 --- /dev/null +++ b/sys/dev/acpi/hpet.c @@ -0,0 +1,144 @@ +/* $OpenBSD: hpet.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#ifdef __HAVE_TIMECOUNTER +#include <sys/timetc.h> +#endif + +#include <machine/bus.h> + +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#include <dev/acpi/hpetreg.h> + +int hpetmatch(struct device *, void *, void *); +void hpetattach(struct device *, struct device *, void *); + +#ifdef __HAVE_TIMECOUNTER +u_int hpet_get_timecount(struct timecounter *tc); + +static struct timecounter hpet_timecounter = { + hpet_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + 0xffffffff, /* counter_mask (24 bits) */ + 0, /* frequency */ + 0, /* name */ + 1000 /* quality */ +}; +#endif + +struct hpet_softc { + struct device sc_dev; + + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct cfattach hpet_ca = { + sizeof(struct hpet_softc), hpetmatch, hpetattach +}; + +struct cfdriver hpet_cd = { + NULL, "hpet", DV_DULL +}; + +int +hpetmatch(struct device *parent, void *match, void *aux) +{ + struct acpi_attach_args *aaa = aux; + struct acpi_table_header *hdr; + + /* + * If we do not have a table, it is not us + */ + if (aaa->aaa_table == NULL) + return (0); + + /* + * If it is an HPET table, we can attach + */ + hdr = (struct acpi_table_header *)aaa->aaa_table; + if (memcmp(hdr->signature, HPET_SIG, sizeof(HPET_SIG) - 1) != 0) + return (0); + + return (1); +} + +void +hpetattach(struct device *parent, struct device *self, void *aux) +{ + struct hpet_softc *sc = (struct hpet_softc *) self; + struct acpi_attach_args *aa = aux; + struct acpi_hpet *hpet = (struct acpi_hpet *)aa->aaa_table; + u_int64_t period, freq; /* timer period in femtoseconds (10^-15) */ + + switch (hpet->base_address.address_space_id) { + case GAS_SYSTEM_MEMORY: + sc->sc_iot = aa->aaa_memt; + break; + + case GAS_SYSTEM_IOSPACE: + sc->sc_iot = aa->aaa_iot; + break; + +#if 0 + case GAS_SYSTEM_PCI_CFG_SPACE: + sc->sc_iot = aa->aaa_pcit; + break; + + case GAS_SYSTEM_SMBUS: + sc->sc_iot = aa->aaa_smbust; + break; +#endif + + default: + printf(": can't identify bus\n"); + return; + } + + if (bus_space_map(sc->sc_iot, hpet->base_address.address, HPET_REG_SIZE, + 0, &sc->sc_ioh)) { + printf(": can't map i/o space\n"); + return; + } + + period = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + HPET_CAPABILITIES + sizeof(u_int32_t)); + freq = 1000000000000000ull / period; + printf(": %lld Hz\n", freq); + +#ifdef __HAVE_TIMECOUNTER + hpet_timecounter.tc_frequency = (u_int32_t)freq; + hpet_timecounter.tc_priv = sc; + hpet_timecounter.tc_name = sc->sc_dev.dv_xname; + tc_init(&hpet_timecounter); +#endif +} + +#ifdef __HAVE_TIMECOUNTER +u_int +hpet_get_timecount(struct timecounter *tc) +{ + struct hpet_softc *sc = tc->tc_priv; + + return (bus_space_read_4(sc->sc_iot, sc->sc_ioh, HPET_MAIN_COUNTER)); +} +#endif diff --git a/sys/dev/acpi/hpetreg.h b/sys/dev/acpi/hpetreg.h new file mode 100644 index 00000000000..7c5bae72a82 --- /dev/null +++ b/sys/dev/acpi/hpetreg.h @@ -0,0 +1,32 @@ +/* $OpenBSD: hpetreg.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define HPET_REG_SIZE 1024 + +#define HPET_CAPABILITIES 0x000 +#define HPET_CONFIGURATION 0x010 +#define HPET_INTERRUPT_STATUS 0x020 +#define HPET_MAIN_COUNTER 0x0F0 +#define HPET_TIMER0_CONFIG 0x100 +#define HPET_TIMER0_COMPARE 0x108 +#define HPET_TIMER0_INTERRUPT 0x110 +#define HPET_TIMER1_CONFIG 0x200 +#define HPET_TIMER1_COMPARE 0x208 +#define HPET_TIMER1_INTERRUPT 0x310 +#define HPET_TIMER2_CONFIG 0x400 +#define HPET_TIMER2_COMPARE 0x408 +#define HPET_TIMER2_INTERRUPT 0x510 diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 5a5e534a034..bda04d16a03 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.119 2005/05/28 01:38:14 ho Exp $ +# $OpenBSD: Makefile,v 1.120 2005/06/02 20:09:39 tholo Exp $ .include <bsd.own.mk> @@ -17,7 +17,7 @@ SUBDIR= ac accton adduser amd arp authpf bgpctl bgpd bind chroot \ SUBDIR+=faithd ndp rip6query route6d rtadvd rtsold traceroute6 # Arch dependent tools, with manpages -SUBDIR+=bad144 apm apmd fdformat memconfig +SUBDIR+=bad144 acpid acpidump apm apmd fdformat memconfig SUBDIR+=eeprom gpioctl hotplugd SUBDIR+=wsconscfg wsfontload diff --git a/usr.sbin/acpid/Makefile b/usr.sbin/acpid/Makefile new file mode 100644 index 00000000000..98dd722d6da --- /dev/null +++ b/usr.sbin/acpid/Makefile @@ -0,0 +1,23 @@ +# $OpenBSD: Makefile,v 1.1 2005/06/02 20:09:39 tholo Exp $ + +.if (${MACHINE} == "i386") || (${MACHINE} == "amd64") +PROG= acpid +SRCS= main.c script.c +CFLAGS+= -Wall -pedantic +CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes +CFLAGS+= -Wmissing-declarations +CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual +CFLAGS+= -Wsign-compare +.else +NOPROG= yes +.endif + +MAN= acpid.8 +MANSUBDIR= i386 amd64 + +.if make(install) +SUBDIR+= samples +.endif + +.include <bsd.prog.mk> +.include <bsd.subdir.mk> diff --git a/usr.sbin/acpid/acpi.h b/usr.sbin/acpid/acpi.h new file mode 100644 index 00000000000..b03a17a4c34 --- /dev/null +++ b/usr.sbin/acpid/acpi.h @@ -0,0 +1,18 @@ +/* $OpenBSD: acpi.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +void run_script(const char *); diff --git a/usr.sbin/acpid/acpid.8 b/usr.sbin/acpid/acpid.8 new file mode 100644 index 00000000000..99343062685 --- /dev/null +++ b/usr.sbin/acpid/acpid.8 @@ -0,0 +1,83 @@ +.\" $OpenBSD: acpid.8,v 1.1 2005/06/02 20:09:39 tholo Exp $ +.\" +.\" Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd May 27, 2005 +.Dt ACPID 8 +.Os +.Sh NAME +.Nm acpid +.Nd Advanced Configuration and Power Interface daemon +.Sh SYNOPSIS +.Nm acpid +.Op Fl d +.Sh DESCRIPTION +.Nm +monitors the advanced configuration and power interface (ACPI) device, +acting of signaled events. +For suspend and poweroff request events delivered by the BIOS, +.Nm +runs the appropriate program (if one exists). +.Pp +If the +.Fl d +flag is specified, +.Nm +enters debug mode, logging to facility +.Dv LOG_LOCAL1 +and staying in the foreground on the controlling terminal. +.Pp +Actions can be configured for the following two events: +.Cm suspend +and +.Cm powerdown . +The suspend actions are run when the sleep button is pressed, while +the powerdown action is run when the power button is pressed. +.Sh FILES +.Pa /etc/acpi/suspend +and +.Pa /etc/acpi/powerdown +are the files that contain the host's customized actions. +Each file must be an executable binary or shell script suitable +for execution by the +.Xr execve 2 +function. +If you wish to have the same program or script control all transitions, it +may determine which transition is in progress by examining its +.Va argv[0] +which is set to one of +.Ar suspend +and +.Ar powerdown . +.Pp +.Pa /dev/acpi +is the default device used to control the ACPI kernel driver. +.Sh SEE ALSO +.Xr execve 2 , +.Xr syslog 3 , +.Xr apm 4 , +.Xr speaker 4 , +.Xr apm 8 , +.Xr apmd 8 , +.Xr syslogd 8 +.Sh REFERENCES +Advanced Configuration and Power Interface Specification (Revision 3.0), +Hewlett-Packard Corporation, Intel Corporation, Microsoft Corporation, +Phoenix Technologies Ltd and Toshiba Corporation. +.Sh HISTORY +The +.Nm +command appeared in +.Ox 3.8 . diff --git a/usr.sbin/acpid/main.c b/usr.sbin/acpid/main.c new file mode 100644 index 00000000000..787f0a3c884 --- /dev/null +++ b/usr.sbin/acpid/main.c @@ -0,0 +1,135 @@ +/* $OpenBSD: main.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/event.h> +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <signal.h> +#include <err.h> +#include <syslog.h> +#include <machine/bus.h> +#include <sys/device.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> + +#include "pathnames.h" +#include "acpi.h" + +void sigexit(int); +void usage(void); +void run_script(const char *); + +int debug = 0; + +const char acpidev[] = _PATH_ACPI_DEV; + +extern char *__progname; + +void +sigexit(int sig) +{ +} + +void +usage(void) +{ + fprintf(stderr, + "usage: %s [-d]\n", + __progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + const char *fname = acpidev; + int acpi_fd, ch; + int kq; + struct kevent ev[2]; + + while ((ch = getopt(argc, argv, "qadsepmf:t:S:")) != -1) + switch(ch) { + case 'd': + debug = 1; + break; + case '?': + default: + usage(); + } + + argc -= optind; + argv += optind; + + if (debug) + openlog(__progname, LOG_CONS, LOG_LOCAL1); + else { + daemon(0, 0); + openlog(__progname, LOG_CONS, LOG_DAEMON); + setlogmask(LOG_UPTO(LOG_NOTICE)); + } + + (void) signal(SIGTERM, sigexit); + (void) signal(SIGHUP, sigexit); + (void) signal(SIGINT, sigexit); + + if ((acpi_fd = open(fname, O_RDONLY)) == -1) + err(1, "open"); + + if (fcntl(acpi_fd, F_SETFD, 1) == -1) + err(1, "fcntl"); + + kq = kqueue(); + if (kq <= 0) + err(1, "kqueue"); + + EV_SET(&ev[0], acpi_fd, EVFILT_READ, EV_ADD | EV_ENABLE | EV_CLEAR, + 0, 0, NULL); + if (kevent(kq, ev, 1, NULL, 0, NULL) < 0) + err(1, "kevent"); + + for (;;) { + int rv; + + if ((rv = kevent(kq, NULL, 0, ev, 1, NULL)) < 0) + break; + + if (!rv) + continue; + + if (ev->ident == (u_int)acpi_fd) { + syslog(LOG_DEBUG, "acpi event %04x index %d", + ACPI_EVENT_TYPE(ev->data), + ACPI_EVENT_INDEX(ev->data)); + + switch (ACPI_EVENT_TYPE(ev->data)) { + case ACPI_EV_PWRBTN: + run_script("power-button"); + break; + case ACPI_EV_SLPBTN: + run_script("sleep-button"); + break; + default: + break; + } + + } + } + err(1, "kevent"); +} diff --git a/usr.sbin/acpid/pathnames.h b/usr.sbin/acpid/pathnames.h new file mode 100644 index 00000000000..17d8d24415d --- /dev/null +++ b/usr.sbin/acpid/pathnames.h @@ -0,0 +1,19 @@ +/* $OpenBSD: pathnames.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define _PATH_ACPI_DEV "/dev/acpi" +#define _PATH_ETC_ACPI "/etc/acpi" diff --git a/usr.sbin/acpid/samples/Makefile b/usr.sbin/acpid/samples/Makefile new file mode 100644 index 00000000000..d722dd75343 --- /dev/null +++ b/usr.sbin/acpid/samples/Makefile @@ -0,0 +1,7 @@ +# $OpenBSD: Makefile,v 1.1 2005/06/02 20:09:39 tholo Exp $ + +FILES= power-button +TARGETDIR= /etc/acpi + +install: + $(INSTALL) -c -m 0755 ${FILES} ${DESTDIR}${TARGETDIR} diff --git a/usr.sbin/acpid/samples/power-button b/usr.sbin/acpid/samples/power-button new file mode 100644 index 00000000000..38d6b6ab921 --- /dev/null +++ b/usr.sbin/acpid/samples/power-button @@ -0,0 +1,3 @@ +#! /bin/sh + +shutdown -hp now diff --git a/usr.sbin/acpid/script.c b/usr.sbin/acpid/script.c new file mode 100644 index 00000000000..2100582a199 --- /dev/null +++ b/usr.sbin/acpid/script.c @@ -0,0 +1,54 @@ +/* $OpenBSD: script.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <string.h> +#include <unistd.h> +#include <sys/wait.h> +#include "pathnames.h" +#include "acpi.h" + +void +run_script(const char *script) +{ + char path[MAXPATHLEN]; + int status; + pid_t pid; + + strlcpy(path, _PATH_ETC_ACPI, sizeof(path)); + strlcat(path, "/", sizeof(path)); + strlcat(path, script, sizeof(path)); + + if (access(path, X_OK)) { + strlcpy(path, _PATH_ETC_ACPI, sizeof(path)); + strlcat(path, "/default", sizeof(path)); + + if (access(path, X_OK)) + return; + } + + switch (pid = fork()) { + case -1: + return; + case 0: + execl(path, script, (char *)NULL); + break; + default: + wait4(pid, &status, 0, NULL); + break; + } +} diff --git a/usr.sbin/acpidump/Makefile b/usr.sbin/acpidump/Makefile new file mode 100644 index 00000000000..ebd0ae5776d --- /dev/null +++ b/usr.sbin/acpidump/Makefile @@ -0,0 +1,14 @@ +# $OpenBSD: Makefile,v 1.1 2005/06/02 20:09:39 tholo Exp $ + +PROG= acpidump +SRCS= acpi.c acpi_user.c asl_dump.c aml_dump.c acpidump.c +SRCS+= aml_name.c aml_parse.c aml_amlmem.c aml_memman.c aml_obj.c +SRCS+= aml_common.c aml_evalobj.c aml_store.c +MAN= acpidump.8 + +VPATH= ${.CURDIR}/aml +CFLAGS= -I${.CURDIR} + +BINDIR?=/usr/sbin + +.include <bsd.prog.mk> diff --git a/usr.sbin/acpidump/acpi.c b/usr.sbin/acpidump/acpi.c new file mode 100644 index 00000000000..f26cd57695f --- /dev/null +++ b/usr.sbin/acpidump/acpi.c @@ -0,0 +1,440 @@ +/* $OpenBSD: acpi.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1998 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: acpi.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/acpidump/acpi.c,v 1.3 2000/11/08 02:37:00 iwasaki Exp $ + */ +#include <sys/types.h> +#include <sys/stat.h> + +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> + +#include "acpidump.h" + +#include "aml/aml_env.h" +#include "aml/aml_common.h" + +#define BEGIN_COMMENT "/*\n" +#define END_COMMENT " */\n" + +struct ACPIsdt dsdt_header = { + "DSDT", 0, 1, 0, "OEMID", "OEMTBLID", 0x12345678, "CRTR", 0x12345678 +}; + +static void +acpi_trim_string(char *s, size_t length) +{ + + /* Trim trailing spaces and NULLs */ + while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) + s[length-- - 1] = '\0'; +} + +static void +acpi_print_dsdt_definition(void) +{ + int len; + char *p; + char oemid[6 + 1]; + char oemtblid[8 + 1]; + + acpi_trim_string(dsdt_header.oemid, 6); + acpi_trim_string(dsdt_header.oemtblid, 8); + strncpy(oemid, dsdt_header.oemid, 6); + oemid[6] = '\0'; + strncpy(oemtblid, dsdt_header.oemtblid, 8); + oemtblid[8] = '\0'; + + printf("DefinitionBlock (\n" + "\"acpi_dsdt.aml\",\t//Output filename\n" + "\"DSDT\",\t\t\t//Signature\n" + "0x%x,\t\t\t//DSDT Revision\n" + "\"%s\",\t\t\t//OEMID\n" + "\"%s\",\t\t//TABLE ID\n" + "0x%x\t\t\t//OEM Revision\n)\n", + dsdt_header.rev, oemid, oemtblid, dsdt_header.oemrev); +} + +static void +acpi_print_string(char *s, size_t length) +{ + int c; + + /* Trim trailing spaces and NULLs */ + while (length > 0 && (s[length - 1] == ' ' || s[length - 1] == '\0')) + length--; + + while (length--) { + c = *s++; + putchar(c); + } +} + +static void +acpi_handle_dsdt(struct ACPIsdt *dsdp) +{ + u_int8_t *dp; + u_int8_t *end; + extern struct aml_environ asl_env; + + acpi_print_dsdt(dsdp); + + dp = (u_int8_t *)dsdp->body; + end = (u_int8_t *)dsdp + dsdp->len; + + acpi_dump_dsdt(dp, end); +} + +static void +acpi_handle_facp(struct FACPbody *facp) +{ + struct ACPIsdt *dsdp; + + acpi_print_facp(facp); + dsdp = (struct ACPIsdt *) acpi_map_sdt(facp->dsdt_ptr); + if (acpi_checksum(dsdp, dsdp->len)) + errx(1, "DSDT is corrupt\n"); + acpi_handle_dsdt(dsdp); + aml_dump(dsdp); +} + +static void +init_namespace() +{ + struct aml_environ env; + struct aml_name *newname; + + aml_new_name_group(AML_NAME_GROUP_OS_DEFINED); + env.curname = aml_get_rootname(); + newname = aml_create_name(&env, "\\_OS_"); + newname->property = aml_alloc_object(aml_t_string, NULL); + newname->property->str.needfree = 0; + newname->property->str.string = "Microsoft Windows NT"; +} + +/* + * Public interfaces + */ + +void +acpi_dump_dsdt(u_int8_t *dp, u_int8_t *end) +{ + extern struct aml_environ asl_env; + + acpi_print_dsdt_definition(); + + /* 1st stage: parse only w/o printing */ + init_namespace(); + aml_new_name_group((long)dp); + bzero(&asl_env, sizeof(asl_env)); + + asl_env.dp = dp; + asl_env.end = end; + asl_env.curname = aml_get_rootname(); + + aml_local_stack_push(aml_local_stack_create()); + aml_parse_objectlist(&asl_env, 0); + aml_local_stack_delete(aml_local_stack_pop()); + + assert(asl_env.dp == asl_env.end); + asl_env.dp = dp; + + /* 2nd stage: dump whole object list */ + printf("\n{\n"); + asl_dump_objectlist(&dp, end, 0); + printf("\n}\n"); + assert(dp == end); +} +void +acpi_print_sdt(struct ACPIsdt *sdp) +{ + + printf(BEGIN_COMMENT); + acpi_print_string(sdp->signature, 4); + printf(": Length=%d, Revision=%d, Checksum=%d,\n", + sdp->len, sdp->rev, sdp->check); + printf("\tOEMID="); + acpi_print_string(sdp->oemid, 6); + printf(", OEM Table ID="); + acpi_print_string(sdp->oemtblid, 8); + printf(", OEM Revision=0x%x,\n", sdp->oemrev); + printf("\tCreator ID="); + acpi_print_string(sdp->creator, 4); + printf(", Creator Revision=0x%x\n", sdp->crerev); + printf(END_COMMENT); + if (!memcmp(sdp->signature, "DSDT", 4)) { + memcpy(&dsdt_header, sdp, sizeof(dsdt_header)); + } +} + +void +acpi_print_rsdt(struct ACPIsdt *rsdp) +{ + int i, entries; + + acpi_print_sdt(rsdp); + entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t); + printf(BEGIN_COMMENT); + printf("\tEntries={ "); + for (i = 0; i < entries; i++) { + if (i > 0) + printf(", "); + printf("0x%08x", rsdp->body[i]); + } + printf(" }\n"); + printf(END_COMMENT); +} + +void +acpi_print_facp(struct FACPbody *facp) +{ + char sep; + + printf(BEGIN_COMMENT); + printf("\tDSDT=0x%x\n", facp->dsdt_ptr); + printf("\tINT_MODEL=%s\n", facp->int_model ? "APIC" : "PIC"); + printf("\tSCI_INT=%d\n", facp->sci_int); + printf("\tSMI_CMD=0x%x, ", facp->smi_cmd); + printf("ACPI_ENABLE=0x%x, ", facp->acpi_enable); + printf("ACPI_DISABLE=0x%x, ", facp->acpi_disable); + printf("S4BIOS_REQ=0x%x\n", facp->s4biosreq); + if (facp->pm1a_evt_blk) + printf("\tPM1a_EVT_BLK=0x%x-0x%x\n", + facp->pm1a_evt_blk, + facp->pm1a_evt_blk + facp->pm1_evt_len - 1); + if (facp->pm1b_evt_blk) + printf("\tPM1b_EVT_BLK=0x%x-0x%x\n", + facp->pm1b_evt_blk, + facp->pm1b_evt_blk + facp->pm1_evt_len - 1); + if (facp->pm1a_cnt_blk) + printf("\tPM1a_CNT_BLK=0x%x-0x%x\n", + facp->pm1a_cnt_blk, + facp->pm1a_cnt_blk + facp->pm1_cnt_len - 1); + if (facp->pm1b_cnt_blk) + printf("\tPM1b_CNT_BLK=0x%x-0x%x\n", + facp->pm1b_cnt_blk, + facp->pm1b_cnt_blk + facp->pm1_cnt_len - 1); + if (facp->pm2_cnt_blk) + printf("\tPM2_CNT_BLK=0x%x-0x%x\n", + facp->pm2_cnt_blk, + facp->pm2_cnt_blk + facp->pm2_cnt_len - 1); + if (facp->pm_tmr_blk) + printf("\tPM2_TMR_BLK=0x%x-0x%x\n", + facp->pm_tmr_blk, + facp->pm_tmr_blk + facp->pm_tmr_len - 1); + if (facp->gpe0_blk) + printf("\tPM2_GPE0_BLK=0x%x-0x%x\n", + facp->gpe0_blk, + facp->gpe0_blk + facp->gpe0_len - 1); + if (facp->gpe1_blk) + printf("\tPM2_GPE1_BLK=0x%x-0x%x, GPE1_BASE=%d\n", + facp->gpe1_blk, + facp->gpe1_blk + facp->gpe1_len - 1, + facp->gpe1_base); + printf("\tP_LVL2_LAT=%dms, P_LVL3_LAT=%dms\n", + facp->p_lvl2_lat, facp->p_lvl3_lat); + printf("\tFLUSH_SIZE=%d, FLUSH_STRIDE=%d\n", + facp->flush_size, facp->flush_stride); + printf("\tDUTY_OFFSET=%d, DUTY_WIDTH=%d\n", + facp->duty_off, facp->duty_width); + printf("\tDAY_ALRM=%d, MON_ALRM=%d, CENTURY=%d\n", + facp->day_alrm, facp->mon_alrm, facp->century); + printf("\tFlags="); + sep = '{'; + +#define PRINTFLAG(xx) do { \ + if (facp->flags & ACPI_FACP_FLAG_## xx) { \ + printf("%c%s", sep, #xx); sep = ','; \ + } \ +} while (0) + + PRINTFLAG(WBINVD); + PRINTFLAG(WBINVD_FLUSH); + PRINTFLAG(PROC_C1); + PRINTFLAG(P_LVL2_UP); + PRINTFLAG(PWR_BUTTON); + PRINTFLAG(SLP_BUTTON); + PRINTFLAG(FIX_RTC); + PRINTFLAG(RTC_S4); + PRINTFLAG(TMR_VAL_EXT); + PRINTFLAG(DCK_CAP); + +#undef PRINTFLAG + + printf("}\n"); + printf(END_COMMENT); +} + +void +acpi_print_dsdt(struct ACPIsdt *dsdp) +{ + + acpi_print_sdt(dsdp); +} + +int +acpi_checksum(void *p, size_t length) +{ + u_int8_t *bp; + u_int8_t sum; + + bp = p; + sum = 0; + while (length--) + sum += *bp++; + + return (sum); +} + +struct ACPIsdt * +acpi_map_sdt(vm_offset_t pa) +{ + struct ACPIsdt *sp; + + sp = acpi_map_physical(pa, sizeof(struct ACPIsdt)); + sp = acpi_map_physical(pa, sp->len); + return (sp); +} + +void +acpi_print_rsd_ptr(struct ACPIrsdp *rp) +{ + + printf(BEGIN_COMMENT); + printf("RSD PTR: Checksum=%d, OEMID=", rp->sum); + acpi_print_string(rp->oem, 6); + printf(", RsdtAddress=0x%08x\n", rp->addr); + printf(END_COMMENT); +} + +void +acpi_handle_rsdt(struct ACPIsdt *rsdp) +{ + int i; + int entries; + struct ACPIsdt *sdp; + + entries = (rsdp->len - SIZEOF_SDT_HDR) / sizeof(u_int32_t); + acpi_print_rsdt(rsdp); + for (i = 0; i < entries; i++) { + sdp = (struct ACPIsdt *) acpi_map_sdt(rsdp->body[i]); + if (acpi_checksum(sdp, sdp->len)) + errx(1, "RSDT entry %d is corrupt\n", i); + if (!memcmp(sdp->signature, "FACP", 4)) { + acpi_handle_facp((struct FACPbody *) sdp->body); + } else { + acpi_print_sdt(sdp); + } + } +} + +/* + * Dummy functions + */ + +void +aml_dbgr(struct aml_environ *env1, struct aml_environ *env2) +{ + /* do nothing */ +} + +int +aml_region_read_simple(struct aml_region_handle *h, vm_offset_t offset, + u_int32_t *valuep) +{ + return (0); +} + +int +aml_region_write_simple(struct aml_region_handle *h, vm_offset_t offset, + u_int32_t value) +{ + return (0); +} + +u_int32_t +aml_region_prompt_read(struct aml_region_handle *h, u_int32_t value) +{ + return (0); +} + +u_int32_t +aml_region_prompt_write(struct aml_region_handle *h, u_int32_t value) +{ + return (0); +} + +int +aml_region_prompt_update_value(u_int32_t orgval, u_int32_t value, + struct aml_region_handle *h) +{ + return (0); +} + +u_int32_t +aml_region_read(struct aml_environ *env, int regtype, u_int32_t flags, + u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) +{ + return (0); +} + +int +aml_region_write(struct aml_environ *env, int regtype, u_int32_t flags, + u_int32_t value, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) +{ + return (0); +} + +int +aml_region_write_from_buffer(struct aml_environ *env, int regtype, + u_int32_t flags, u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, + u_int32_t bitlen) +{ + return (0); +} + +int +aml_region_bcopy(struct aml_environ *env, int regtype, u_int32_t flags, + u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, + u_int32_t dflags, u_int32_t daddr, + u_int32_t dbitoffset, u_int32_t dbitlen) +{ + return (0); +} + +int +aml_region_read_into_buffer(struct aml_environ *env, int regtype, + u_int32_t flags, u_int32_t addr, u_int32_t bitoffset, + u_int32_t bitlen, u_int8_t *buffer) +{ + return (0); +} + diff --git a/usr.sbin/acpidump/acpi_user.c b/usr.sbin/acpidump/acpi_user.c new file mode 100644 index 00000000000..bd924fa4393 --- /dev/null +++ b/usr.sbin/acpidump/acpi_user.c @@ -0,0 +1,169 @@ +/* $OpenBSD: acpi_user.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: acpi_user.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/acpidump/acpi_user.c,v 1.3 2000/11/08 02:37:00 iwasaki Exp $ + */ +#ifdef __FreeBSD__ +#include <sys/param.h> +#else +#include <sys/types.h> +#define PAGE_MASK (0x1000-1) /*For I386*/ +#define trunc_page(x) ((x) & ~PAGE_MASK) +#define round_page(x) (((x) + PAGE_MASK) & ~PAGE_MASK) +#endif + +#include <sys/mman.h> +#include <sys/queue.h> +#include <sys/stat.h> + +#include <err.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "acpidump.h" + +static int acpi_mem_fd = -1; + +struct acpi_user_mapping { + LIST_ENTRY(acpi_user_mapping) link; + vm_offset_t pa; + caddr_t va; + size_t size; +}; + +LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist; + +static void +acpi_user_init() +{ + + if (acpi_mem_fd == -1) { + acpi_mem_fd = open("/dev/mem", O_RDONLY); + if (acpi_mem_fd == -1) + err(1, "opening /dev/mem"); + LIST_INIT(&maplist); + } +} + +static struct acpi_user_mapping * +acpi_user_find_mapping(vm_offset_t pa, size_t size) +{ + struct acpi_user_mapping *map; + + /* First search for an existing mapping */ + for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) { + if (map->pa <= pa && map->size >= pa + size - map->pa) + return (map); + } + + /* Then create a new one */ + size = round_page(pa + size) - trunc_page(pa); + pa = trunc_page(pa); + map = malloc(sizeof(struct acpi_user_mapping)); + if (!map) + errx(1, "out of memory"); + map->pa = pa; + map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa); + map->size = size; + if ((long) map->va == -1) + err(1, "can't map address"); + LIST_INSERT_HEAD(&maplist, map, link); + + return (map); +} + +/* + * Public interfaces + */ + +struct ACPIrsdp * +acpi_find_rsd_ptr() +{ + int i; + u_int8_t buf[sizeof(struct ACPIrsdp)]; + + acpi_user_init(); + for (i = 0; i < 1024 * 1024; i += 16) { + read(acpi_mem_fd, buf, 16); + if (!memcmp(buf, "RSD PTR ", 8)) { + /* Read the rest of the structure */ + read(acpi_mem_fd, buf + 16, sizeof(struct ACPIrsdp) - 16); + + /* Verify checksum before accepting it. */ + if (acpi_checksum(buf, sizeof(struct ACPIrsdp))) + continue; + return (acpi_map_physical(i, sizeof(struct ACPIrsdp))); + } + } + + return (0); +} + +void * +acpi_map_physical(vm_offset_t pa, size_t size) +{ + struct acpi_user_mapping *map; + + map = acpi_user_find_mapping(pa, size); + return (map->va + (pa - map->pa)); +} + +void +acpi_load_dsdt(char *dumpfile, u_int8_t **dpp, u_int8_t **endp) +{ + u_int8_t *dp; + u_int8_t *end; + struct stat sb; + + if ((acpi_mem_fd = open(dumpfile, O_RDONLY)) == -1) { + errx(1, "opening %s\n", dumpfile); + } + + LIST_INIT(&maplist); + + if (fstat(acpi_mem_fd, &sb) == -1) { + errx(1, "fstat %s\n", dumpfile); + } + + dp = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, acpi_mem_fd, 0); + if (dp == NULL) { + errx(1, "mmap %s\n", dumpfile); + } + + if (strncmp(dp, "DSDT", 4) == 0) { + memcpy(&dsdt_header, dp, SIZEOF_SDT_HDR); + dp += SIZEOF_SDT_HDR; + sb.st_size -= SIZEOF_SDT_HDR; + } + + end = (u_int8_t *) dp + sb.st_size; + *dpp = dp; + *endp = end; +} diff --git a/usr.sbin/acpidump/acpidump.8 b/usr.sbin/acpidump/acpidump.8 new file mode 100644 index 00000000000..bf235989f9e --- /dev/null +++ b/usr.sbin/acpidump/acpidump.8 @@ -0,0 +1,170 @@ +.\" $OpenBSD: acpidump.8,v 1.1 2005/06/02 20:09:39 tholo Exp $ +.\" +.\" Copyright (c) 1999 Doug Rabson <dfr@FreeBSD.org> +.\" Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> +.\" Copyright (c) 2000 Yasuo YOKOYAMA <yokoyama@jp.FreeBSD.org> +.\" Copyright (c) 2000 Hiroki Sato <hrs@FreeBSD.org> +.\" 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 REGENTS 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 REGENTS 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: src/usr.sbin/acpi/acpidump/acpidump.8,v 1.9 2001/09/05 19:21:25 dd Exp $ +.\" +.Dd August 31, 2000 +.Dt ACPIDUMP 8 +.Os +.Sh NAME +.Nm acpidump +.Nd dump ACPI tables +.Sh SYNOPSIS +.Nm +.Nm +.Op Fl o Ar dsdt_file_for_output +.Nm +.Op Fl f Ar dsdt_file_for_input +.Sh DESCRIPTION +The +.Nm +command analyzes ACPI tables in physical memory and dumps them to standard output. +In addition, +.Nm +can disassemble some contents of the tables in AML +(ACPI Machine Language) +and dump them in ASL +(ACPI Source Language). +.Pp +ACPI tables have an notably essential data block called DSDT +(Differentiated System Description Table), +that includes information used on the kernel side such as +detail information about PnP hardware, procedures for controlling +a power management support and so on. +.Nm +can extract a DSDT data block from physical memory and store it into +a DSDT data file, and also can generate an output in ASL +from a given DSDT data file. +.Pp +When +.Nm +is invoked with no option, it will search ACPI tables from physical +memory via a special file +.Pa /dev/mem +and dump them. First, it searches Root System Description Pointer, +that has a signature +.Qq RSD PTR\ \& , +and then gets RSDT +(Root System Description Table), +which includes a list of pointers to physical memory addresses +for other tables. +RSDT itself and all other tables linked from RSDT are generically +called SDT +(System Description Table) +and their header has the common format which consists of items +such as Signature, Length, Revision, Checksum, OEMID, OEM Table ID, +OEM Revision, Creator ID and Creator Revision. +.Nm +dumps contents of these SDTs. +For further information about formats of each table, +see chapter 5: ACPI Software Programming Model, +.Dq Advanced Configuration and Power Interface Specification Revision 1.0b +from Intel/Microsoft/Toshiba. +.Pp +There is always a pointer to a physical memory address in RSDT for FACP +(Fixed ACPI Description Table). +FACP defines static system information about power management support +(ACPI Hardware Register Implementation) +such as interrupt mode +(INT_MODEL), +SCI interrupt number, SMI command port +(SMI_CMD) +and location of ACPI registers. +FACP also has a pointer to a physical memory address for DSDT, +which includes information used on the kernel side such as +PnP, power management support and so on. +While the other tables are described in fixed format, +DSDT consists of AML data which compiled from sources +written in free formated ASL, description language for ACPI. +When +.Nm +outputs DSDT, it disassembles the AML data and +translates them into ASL. +.Sh OPTIONS +The following options are supported by +.Nm : +.Bl -tag -width indent +.It Fl o Ar dsdt_file_for_output +Stores DSDT data block from physical memory into a file specified in +.Ar dsdt_file_for_output +in addition to behavior with no option. +.It Fl f Ar dsdt_file_for_input +Interprets AML data in DSDT from a file specified in +.Ar dsdt_file_for_input +and dumps them in ASL to standard output. +.It Fl h +Displays usage and exit. +.El +.Sh EXAMPLES +This is an example to get a dump of SDTs and a DSDT data file +simultaneously on a machine that supports ACPI BIOS. +.Bd -literal -offset indent +# acpidump -o foo.dsdt > foo.asl +.Ed +.Sh BUGS +In the current implementation, +.Nm +doesn't dump any information of Firmware ACPI Control Structure +(FACS) +specified by a pointer in FACP. +.Sh FILES +.Bl -tag -width /dev/mem +.It Pa /dev/mem +.El +.Sh SEE ALSO +.\" .Xr acpi 4 , +.Xr mem 4 , +.\" .Xr acpiconf 8 , +..\" Xr amldb 8 +.Pp +.Dq Advanced Configuration and Power Interface Specification +.Bd -literal -offset indent -compact +Intel +Microsoft +Toshiba +Revision 1.0b +.Ed +<URL:http://www.teleport.com/~acpi/> +.Sh AUTHORS +.An Doug Rabson Aq dfr@FreeBSD.org +.An Mitsuru IWASAKI Aq iwasaki@FreeBSD.org +.An Yasuo YOKOYAMA Aq yokoyama@jp.FreeBSD.org +.Pp +Some contributions made by +.An Chitoshi Ohsawa Aq ohsawa@catv1.ccn-net.ne.jp , +.An Takayasu IWANASHI Aq takayasu@wendy.a.perfect-liberty.or.jp , +.An Yoshihiko SARUMARU Aq mistral@imasy.or.jp , +.An Hiroki Sato Aq hrs@FreeBSD.org , +and +.An Michael Lucas Aq mwlucas@blackhelicopters.org . +.Sh HISTORY +The +.Nm +command appeared in +.Fx 5.0 . diff --git a/usr.sbin/acpidump/acpidump.c b/usr.sbin/acpidump/acpidump.c new file mode 100644 index 00000000000..82c562efc32 --- /dev/null +++ b/usr.sbin/acpidump/acpidump.c @@ -0,0 +1,105 @@ +/* $OpenBSD: acpidump.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: acpidump.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/acpidump/acpidump.c,v 1.3 2000/11/08 02:37:00 iwasaki Exp $ + */ + +#include <sys/types.h> + +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <unistd.h> + +#include "acpidump.h" + +static void +asl_dump_from_file(char *file) +{ + u_int8_t *dp; + u_int8_t *end; + struct ACPIsdt *dsdt; + + acpi_load_dsdt(file, &dp, &end); + acpi_dump_dsdt(dp, end); +} + +static void +asl_dump_from_devmem() +{ + struct ACPIrsdp *rp; + struct ACPIsdt *rsdp; + + rp = acpi_find_rsd_ptr(); + if (!rp) + errx(1, "Can't find ACPI information\n"); + + acpi_print_rsd_ptr(rp); + rsdp = (struct ACPIsdt *) acpi_map_sdt(rp->addr); + if (memcmp(rsdp->signature, "RSDT", 4) || + acpi_checksum(rsdp, rsdp->len)) + errx(1, "RSDT is corrupted\n"); + + acpi_handle_rsdt(rsdp); +} + +static void +usage(const char *progname) +{ + + printf("usage:\t%s [-o dsdt_file_for_output]\n", progname); + printf("\t%s [-f dsdt_file_for_input]\n", progname); + printf("\t%s [-h]\n", progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + char c, *progname; + + progname = argv[0]; + while ((c = getopt(argc, argv, "f:o:h")) != -1) { + switch (c) { + case 'f': + asl_dump_from_file(optarg); + return (0); + case 'o': + aml_dumpfile = optarg; + break; + case 'h': + usage(progname); + break; + default: + argc -= optind; + argv += optind; + } + } + + asl_dump_from_devmem(); + return (0); +} diff --git a/usr.sbin/acpidump/acpidump.h b/usr.sbin/acpidump/acpidump.h new file mode 100644 index 00000000000..4d1ce79966e --- /dev/null +++ b/usr.sbin/acpidump/acpidump.h @@ -0,0 +1,184 @@ +/* $OpenBSD: acpidump.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: acpidump.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/acpidump/acpidump.h,v 1.2 2000/11/08 02:37:00 iwasaki Exp $ + */ + +#ifndef _ACPIDUMP_H_ +#define _ACPIDUMP_H_ +#include <stdlib.h> + +typedef unsigned long vm_offset_t; + +/* Generic Address structure */ +struct ACPIgas { + u_int8_t address_space_id; +#define ACPI_GAS_MEMORY 0 +#define ACPI_GAS_IO 1 +#define ACPI_GAS_PCI 2 +#define ACPI_GAS_EMBEDDED 3 +#define ACPI_GAS_SMBUS 4 +#define ACPI_GAS_FIXED 0x7f + u_int8_t register_bit_width; + u_int8_t register_bit_offset; + u_int8_t res; + u_int64_t address; +} __attribute__((packed)); + +/* Root System Description Pointer */ +struct ACPIrsdp { + u_char signature[8]; + u_char sum; + u_char oem[6]; + u_char res; + u_int32_t addr; +} __attribute__((packed)); + +/* System Description Table */ +struct ACPIsdt { + u_char signature[4]; + u_int32_t len; + u_char rev; + u_char check; + u_char oemid[6]; + u_char oemtblid[8]; + u_int32_t oemrev; + u_char creator[4]; + u_int32_t crerev; +#define SIZEOF_SDT_HDR 36 /* struct size except body */ + u_int32_t body[1];/* This member should be casted */ +} __attribute__((packed)); + +/* Fixed ACPI Description Table (body) */ +struct FACPbody { + u_int32_t facs_ptr; + u_int32_t dsdt_ptr; + u_int8_t int_model; +#define ACPI_FACP_INTMODEL_PIC 0 /* Standard PC-AT PIC */ +#define ACPI_FACP_INTMODEL_APIC 1 /* Multiple APIC */ + u_char reserved1; + u_int16_t sci_int; + u_int32_t smi_cmd; + u_int8_t acpi_enable; + u_int8_t acpi_disable; + u_int8_t s4biosreq; + u_int8_t reserved2; + u_int32_t pm1a_evt_blk; + u_int32_t pm1b_evt_blk; + u_int32_t pm1a_cnt_blk; + u_int32_t pm1b_cnt_blk; + u_int32_t pm2_cnt_blk; + u_int32_t pm_tmr_blk; + u_int32_t gpe0_blk; + u_int32_t gpe1_blk; + u_int8_t pm1_evt_len; + u_int8_t pm1_cnt_len; + u_int8_t pm2_cnt_len; + u_int8_t pm_tmr_len; + u_int8_t gpe0_len; + u_int8_t gpe1_len; + u_int8_t gpe1_base; + u_int8_t reserved3; + u_int16_t p_lvl2_lat; + u_int16_t p_lvl3_lat; + u_int16_t flush_size; + u_int16_t flush_stride; + u_int8_t duty_off; + u_int8_t duty_width; + u_int8_t day_alrm; + u_int8_t mon_alrm; + u_int8_t century; + u_int16_t iapc_boot_arch; + u_char reserved4[1]; + u_int32_t flags; +#define ACPI_FACP_FLAG_WBINVD 1 /* WBINVD is correctly supported */ +#define ACPI_FACP_FLAG_WBINVD_FLUSH 2 /* WBINVD flushes caches */ +#define ACPI_FACP_FLAG_PROC_C1 4 /* C1 power state supported */ +#define ACPI_FACP_FLAG_P_LVL2_UP 8 /* C2 power state works on SMP */ +#define ACPI_FACP_FLAG_PWR_BUTTON 16 /* Power button uses control method */ +#define ACPI_FACP_FLAG_SLP_BUTTON 32 /* Sleep button uses control method */ +#define ACPI_FACP_FLAG_FIX_RTC 64 /* RTC wakeup not supported */ +#define ACPI_FACP_FLAG_RTC_S4 128 /* RTC can wakeup from S4 state */ +#define ACPI_FACP_FLAG_TMR_VAL_EXT 256 /* TMR_VAL is 32bit */ +#define ACPI_FACP_FLAG_DCK_CAP 512 /* Can support docking */ + struct ACPIgas reset_reg; + u_int8_t reset_value; + u_int8_t reserved5[3]; + u_int64_t x_firmware_ctrl; + u_int64_t x_dsdt; + struct ACPIgas x_pm1a_evt_blk; + struct ACPIgas x_pm1b_evt_blk; + struct ACPIgas x_pm1a_cnt_blk; + struct ACPIgas x_pm1b_cnt_blk; + struct ACPIgas x_pm2_cnt_blk; + struct ACPIgas x_pm_tmr_blk; + struct ACPIgas x_gpe0_blk; + struct ACPIgas x_gpe1_blk; +} __attribute__((packed)); + +/* Firmware ACPI Control Structure */ +struct FACS { + u_char signature[4]; + u_int32_t len; + u_char hard_sig[4]; + /* + * NOTE This should be filled with physical address below 1MB!! + * sigh.... + */ + u_int32_t firm_wake_vec; + u_int32_t g_lock; /* bit field */ + /* 5.2.6.1 Global Lock */ +#define ACPI_GLOBAL_LOCK_PENDING 1 +#define ACPI_GLOBAL_LOCK_OWNED 2 + u_int32_t flags; /* bit field */ +#define ACPI_FACS_FLAG_S4BIOS_F 1 /* Supports S4BIOS_SEQ */ + char reserved[40]; +} __attribute__((packed)); + +void *acpi_map_physical(vm_offset_t, size_t); +struct ACPIrsdp *acpi_find_rsd_ptr(void); +int acpi_checksum(void *, size_t); +struct ACPIsdt *acpi_map_sdt(vm_offset_t); +void acpi_print_rsd_ptr(struct ACPIrsdp *); +void acpi_print_sdt(struct ACPIsdt *); +void acpi_print_rsdt(struct ACPIsdt *); +void acpi_print_facp(struct FACPbody *); +void acpi_print_dsdt(struct ACPIsdt *); + +void asl_dump_termobj(u_int8_t **, int); +void asl_dump_objectlist(u_int8_t **, u_int8_t *, int); + +void aml_dump(struct ACPIsdt *); + +void acpi_handle_rsdt(struct ACPIsdt *); +void acpi_load_dsdt(char *, u_int8_t **, u_int8_t **); +void acpi_dump_dsdt(u_int8_t *, u_int8_t *); +extern char *aml_dumpfile; +extern struct ACPIsdt dsdt_header; + +#endif /* !_ACPIDUMP_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_amlmem.c b/usr.sbin/acpidump/aml/aml_amlmem.c new file mode 100644 index 00000000000..b696465ba64 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_amlmem.c @@ -0,0 +1,91 @@ +/* $OpenBSD: aml_amlmem.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_amlmem.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_amlmem.c,v 1.2 2000/11/09 06:24:45 iwasaki Exp $ + */ + +/* + * AML Namespace Memory Management + */ +#include <sys/types.h> +#include <aml/aml_env.h> +#include <aml/aml_memman.h> +#include <aml/aml_name.h> + +MEMMAN_INITIALSTORAGE_DESC(struct aml_namestr, _aml_namestr_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_num, _aml_num_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_string, _aml_string_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_buffer, _aml_buffer_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_package, _aml_package_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_field, _aml_field_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_method, _aml_method_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_mutex, _aml_mutex_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_opregion, _aml_opregion_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_powerres, _aml_powerres_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_processor, _aml_processor_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_bufferfield, _aml_bufferfield_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_event, _aml_event_storage); +MEMMAN_INITIALSTORAGE_DESC(enum aml_objtype, _aml_objtype_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_name, _aml_name_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_name_group, _aml_name_group_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_objref, _aml_objref_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_regfield, _aml_regfield_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_environ, _aml_environ_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_local_stack, _aml_local_stack_storage); +MEMMAN_INITIALSTORAGE_DESC(struct aml_mutex_queue, _aml_mutex_queue_storage); + +struct memman_blockman aml_blockman[] = { + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_namestr), _aml_namestr_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_num), _aml_num_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_string), _aml_string_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_buffer), _aml_buffer_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_package), _aml_package_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_field), _aml_field_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_method), _aml_method_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_mutex), _aml_mutex_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_opregion), _aml_opregion_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_powerres), _aml_powerres_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_processor), _aml_processor_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_bufferfield), _aml_bufferfield_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_event), _aml_event_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(enum aml_objtype), _aml_objtype_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_name), _aml_name_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_name_group), _aml_name_group_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_objref), _aml_objref_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_regfield), _aml_regfield_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_environ), _aml_environ_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_local_stack), _aml_local_stack_storage), + MEMMAN_MEMBLOCK_DESC(sizeof(struct aml_mutex_queue), _aml_mutex_queue_storage), +}; + +struct memman_histogram aml_histogram[MEMMAN_HISTOGRAM_SIZE]; + +static struct memman _aml_memman = MEMMAN_MEMMANAGER_DESC(aml_blockman, 21, + aml_histogram, 1); + +struct memman *aml_memman = &_aml_memman; + diff --git a/usr.sbin/acpidump/aml/aml_amlmem.h b/usr.sbin/acpidump/aml/aml_amlmem.h new file mode 100644 index 00000000000..354c6522547 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_amlmem.h @@ -0,0 +1,66 @@ +/* $OpenBSD: aml_amlmem.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_amlmem.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_amlmem.h,v 1.2 2000/11/09 06:24:45 iwasaki Exp $ + */ + +#ifndef _AML_AMLMEM_H_ +#define _AML_AMLMEM_H_ + +/* + * AML Namespace Memory Management + */ + +#include <aml/aml_memman.h> + +enum { + memid_aml_namestr = 0, + memid_aml_num, + memid_aml_string, + memid_aml_buffer, + memid_aml_package, + memid_aml_field, + memid_aml_method, + memid_aml_mutex, + memid_aml_opregion, + memid_aml_powerres, + memid_aml_processor, + memid_aml_bufferfield, + memid_aml_event, + memid_aml_objtype, + memid_aml_name, + memid_aml_name_group, + memid_aml_objref, + memid_aml_regfield, + memid_aml_environ, + memid_aml_local_stack, + memid_aml_mutex_queue, +}; + +extern struct memman *aml_memman; + +#endif /* !_AML_AMLMEM_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_common.c b/usr.sbin/acpidump/aml/aml_common.c new file mode 100644 index 00000000000..32a97d9ac78 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_common.c @@ -0,0 +1,734 @@ +/* $OpenBSD: aml_common.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_common.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_common.c,v 1.6 2000/11/09 06:24:45 iwasaki Exp $ + */ +#include <sys/types.h> +#ifndef _KERNEL +#include <assert.h> +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#else /* _KERNEL */ +#include "opt_acpi.h" +#include <sys/kernel.h> +#include <sys/sysctl.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#ifndef ACPI_NO_OSDFUNC_INLINE +#include <machine/acpica_osd.h> +#endif /* !ACPI_NO_OSDFUNC_INLINE */ +#endif /* !_KERNEL */ + +#include <aml/aml_common.h> +#include <aml/aml_env.h> +#include <aml/aml_evalobj.h> +#include <aml/aml_name.h> +#include <aml/aml_obj.h> +#include <aml/aml_parse.h> +#include <aml/aml_status.h> +#include <aml/aml_store.h> + +/* for debugging */ +#ifdef AML_DEBUG +int aml_debug = 1; +#else /* !AML_DEBUG */ +int aml_debug = 0; +#endif /* AML_DEBUG */ +#ifdef _KERNEL +SYSCTL_INT(_debug, OID_AUTO, aml_debug, CTLFLAG_RW, &aml_debug, 1, ""); +#endif /* _KERNEL */ + +static void aml_print_nameseg(u_int8_t *dp); + +static void +aml_print_nameseg(u_int8_t *dp) +{ + + if (dp[3] != '_') { + AML_DEBUGPRINT("%c%c%c%c", dp[0], dp[1], dp[2], dp[3]); + } else if (dp[2] != '_') { + AML_DEBUGPRINT("%c%c%c_", dp[0], dp[1], dp[2]); + } else if (dp[1] != '_') { + AML_DEBUGPRINT("%c%c__", dp[0], dp[1]); + } else if (dp[0] != '_') { + AML_DEBUGPRINT("%c___", dp[0]); + } +} + +void +aml_print_namestring(u_int8_t *dp) +{ + int segcount; + int i; + + if (dp[0] == '\\') { + AML_DEBUGPRINT("%c", dp[0]); + dp++; + } else if (dp[0] == '^') { + while (dp[0] == '^') { + AML_DEBUGPRINT("%c", dp[0]); + dp++; + } + } + if (dp[0] == 0x00) { /* NullName */ + /* AML_DEBUGPRINT("<null>"); */ + dp++; + } else if (dp[0] == 0x2e) { /* DualNamePrefix */ + aml_print_nameseg(dp + 1); + AML_DEBUGPRINT("%c", '.'); + aml_print_nameseg(dp + 5); + } else if (dp[0] == 0x2f) { /* MultiNamePrefix */ + segcount = dp[1]; + for (i = 0, dp += 2; i < segcount; i++, dp += 4) { + if (i > 0) { + AML_DEBUGPRINT("%c", '.'); + } + aml_print_nameseg(dp); + } + } else /* NameSeg */ + aml_print_nameseg(dp); +} + +int +aml_print_curname(struct aml_name *name) +{ + struct aml_name *root; + + root = aml_get_rootname(); + if (name == root) { + AML_DEBUGPRINT("\\"); + return (0); + } else { + aml_print_curname(name->parent); + } + aml_print_nameseg(name->name); + AML_DEBUGPRINT("."); + return (0); +} + +void +aml_print_indent(int indent) +{ + int i; + + for (i = 0; i < indent; i++) + AML_DEBUGPRINT(" "); +} + +void +aml_showobject(union aml_object * obj) +{ + int debug; + int i; + + if (obj == NULL) { + printf("NO object\n"); + return; + } + debug = aml_debug; + aml_debug = 1; + switch (obj->type) { + case aml_t_num: + printf("Num:0x%x\n", obj->num.number); + break; + case aml_t_processor: + printf("Processor:No %d,Port 0x%x length 0x%x\n", + obj->proc.id, obj->proc.addr, obj->proc.len); + break; + case aml_t_mutex: + printf("Mutex:Level %d\n", obj->mutex.level); + break; + case aml_t_powerres: + printf("PowerResource:Level %d Order %d\n", + obj->pres.level, obj->pres.order); + break; + case aml_t_opregion: + printf("OprationRegion:Busspace%d, Offset 0x%x Length 0x%x\n", + obj->opregion.space, obj->opregion.offset, + obj->opregion.length); + break; + case aml_t_field: + printf("Fieldelement:flag 0x%x offset 0x%x len 0x%x {", + obj->field.flags, obj->field.bitoffset, + obj->field.bitlen); + switch (obj->field.f.ftype) { + case f_t_field: + aml_print_namestring(obj->field.f.fld.regname); + break; + case f_t_index: + aml_print_namestring(obj->field.f.ifld.indexname); + printf(" "); + aml_print_namestring(obj->field.f.ifld.dataname); + break; + case f_t_bank: + aml_print_namestring(obj->field.f.bfld.regname); + printf(" "); + aml_print_namestring(obj->field.f.bfld.bankname); + printf("0x%x", obj->field.f.bfld.bankvalue); + break; + } + printf("}\n"); + break; + case aml_t_method: + printf("Method: Arg %d From %p To %p\n", obj->meth.argnum, + obj->meth.from, obj->meth.to); + break; + case aml_t_buffer: + printf("Buffer: size:0x%x Data %p\n", obj->buffer.size, + obj->buffer.data); + break; + case aml_t_device: + printf("Device\n"); + break; + case aml_t_bufferfield: + printf("Bufferfield:offset 0x%x len 0x%x Origin %p\n", + obj->bfld.bitoffset, obj->bfld.bitlen, obj->bfld.origin); + break; + case aml_t_string: + printf("String:%s\n", obj->str.string); + break; + case aml_t_package: + printf("Package:elements %d \n", obj->package.elements); + for (i = 0; i < obj->package.elements; i++) { + if (obj->package.objects[i] == NULL) { + break; + } + if (obj->package.objects[i]->type < 0) { + continue; + } + printf(" "); + aml_showobject(obj->package.objects[i]); + } + break; + case aml_t_therm: + printf("Thermalzone\n"); + break; + case aml_t_event: + printf("Event\n"); + break; + case aml_t_ddbhandle: + printf("DDBHANDLE\n"); + break; + case aml_t_objref: + if (obj->objref.alias == 1) { + printf("Alias"); + } else { + printf("Object reference"); + if (obj->objref.offset >= 0) { + printf(" (offset 0x%x)", obj->objref.offset); + } + } + printf(" of "); + aml_showobject(obj->objref.ref); + break; + default: + printf("UNK ID=%d\n", obj->type); + } + + aml_debug = debug; +} + +void +aml_showtree(struct aml_name * aname, int lev) +{ + int i; + struct aml_name *ptr; + char name[5]; + + for (i = 0; i < lev; i++) { + printf(" "); + } + strncpy(name, aname->name, 4); + name[4] = 0; + printf("%s ", name); + if (aname->property != NULL) { + aml_showobject(aname->property); + } else { + printf("\n"); + } + for (ptr = aname->child; ptr; ptr = ptr->brother) + aml_showtree(ptr, lev + 1); +} + +/* + * Common Region I/O Stuff + */ + +static __inline u_int64_t +aml_adjust_bitmask(u_int32_t flags, u_int32_t bitlen) +{ + u_int64_t bitmask; + + switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) { + case AML_FIELDFLAGS_ACCESS_ANYACC: + if (bitlen <= 8) { + bitmask = 0x000000ff; + break; + } + if (bitlen <= 16) { + bitmask = 0x0000ffff; + break; + } + bitmask = 0xffffffff; + break; + case AML_FIELDFLAGS_ACCESS_BYTEACC: + bitmask = 0x000000ff; + break; + case AML_FIELDFLAGS_ACCESS_WORDACC: + bitmask = 0x0000ffff; + break; + case AML_FIELDFLAGS_ACCESS_DWORDACC: + default: + bitmask = 0xffffffff; + break; + } + + switch (bitlen) { + case 16: + bitmask |= 0x0000ffff; + break; + case 32: + bitmask |= 0xffffffff; + break; + } + + return (bitmask); +} + +u_int32_t +aml_adjust_readvalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen, + u_int32_t orgval) +{ + u_int32_t offset, retval; + u_int64_t bitmask; + + offset = bitoffset; /* XXX bitoffset may change in this function! */ + bitmask = aml_adjust_bitmask(flags, bitlen); + retval = (orgval >> offset) & (~(bitmask << bitlen)) & bitmask; + + return (retval); +} + +u_int32_t +aml_adjust_updatevalue(u_int32_t flags, u_int32_t bitoffset, u_int32_t bitlen, + u_int32_t orgval, u_int32_t value) +{ + u_int32_t offset, retval; + u_int64_t bitmask; + + offset = bitoffset; /* XXX bitoffset may change in this function! */ + bitmask = aml_adjust_bitmask(flags, bitlen); + retval = orgval; + switch (AML_FIELDFLAGS_UPDATERULE(flags)) { + case AML_FIELDFLAGS_UPDATE_PRESERVE: + retval &= (~(((u_int64_t)1 << bitlen) - 1) << offset) | + (~(bitmask << offset)); + break; + case AML_FIELDFLAGS_UPDATE_WRITEASONES: + retval = (~(((u_int64_t)1 << bitlen) - 1) << offset) | + (~(bitmask << offset)); + retval &= bitmask; /* trim the upper bits */ + break; + case AML_FIELDFLAGS_UPDATE_WRITEASZEROS: + retval = 0; + break; + default: + printf("illegal update rule: %d\n", flags); + return (orgval); + } + + retval |= (value << (offset & bitmask)); + return (retval); +} + +/* + * BufferField I/O + */ + +#define AML_BUFFER_INPUT 0 +#define AML_BUFFER_OUTPUT 1 + +static int aml_bufferfield_io(int io, u_int32_t *valuep, + u_int8_t *origin, u_int32_t bitoffset, + u_int32_t bitlen); + +static int +aml_bufferfield_io(int io, u_int32_t *valuep, u_int8_t *origin, + u_int32_t bitoffset, u_int32_t bitlen) +{ + u_int8_t val, tmp, masklow, maskhigh; + u_int8_t offsetlow, offsethigh; + u_int8_t *addr; + int i; + u_int32_t value, readval; + u_int32_t byteoffset, bytelen; + + masklow = maskhigh = 0xff; + val = readval = 0; + value = *valuep; + + byteoffset = bitoffset / 8; + bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0); + addr = origin + byteoffset; + + /* simple I/O ? */ + if (bitlen <= 8 || bitlen == 16 || bitlen == 32) { + bcopy(addr, &readval, bytelen); + AML_DEBUGPRINT("\n\t[bufferfield:0x%x@%p:%d,%d]", + readval, addr, bitoffset % 8, bitlen); + switch (io) { + case AML_BUFFER_INPUT: + value = aml_adjust_readvalue(AML_FIELDFLAGS_ACCESS_BYTEACC, + bitoffset % 8, bitlen, readval); + *valuep = value; + AML_DEBUGPRINT("\n[read(bufferfield, %p)&mask:0x%x]\n", + addr, value); + break; + case AML_BUFFER_OUTPUT: + value = aml_adjust_updatevalue(AML_FIELDFLAGS_ACCESS_BYTEACC, + bitoffset % 8, bitlen, readval, value); + bcopy(&value, addr, bytelen); + AML_DEBUGPRINT("->[bufferfield:0x%x@%p:%d,%d]", + value, addr, bitoffset % 8, bitlen); + break; + } + goto out; + } + + offsetlow = bitoffset % 8; + if (bytelen > 1) { + offsethigh = (bitlen - (8 - offsetlow)) % 8; + } else { + offsethigh = 0; + } + + if (offsetlow) { + masklow = (~((1 << bitlen) - 1) << offsetlow) | ~(0xff << offsetlow); + AML_DEBUGPRINT("\t[offsetlow = 0x%x, masklow = 0x%x, ~masklow = 0x%x]\n", + offsetlow, masklow, ~masklow & 0xff); + } + if (offsethigh) { + maskhigh = 0xff << offsethigh; + AML_DEBUGPRINT("\t[offsethigh = 0x%x, maskhigh = 0x%x, ~maskhigh = 0x%x]\n", + offsethigh, maskhigh, ~maskhigh & 0xff); + } + for (i = bytelen; i > 0; i--, addr++) { + val = *addr; + + AML_DEBUGPRINT("\t[bufferfield:0x%02x@%p]", val, addr); + + switch (io) { + case AML_BUFFER_INPUT: + tmp = val; + /* the lowest byte? */ + if (i == bytelen) { + if (offsetlow) { + readval = tmp & ~masklow; + } else { + readval = tmp; + } + } else { + if (i == 1 && offsethigh) { + tmp = tmp & ~maskhigh; + } + readval = (tmp << (8 * (bytelen - i))) | readval; + } + + AML_DEBUGPRINT("\n"); + /* goto to next byte... */ + if (i > 1) { + continue; + } + /* final adjustment before finishing region access */ + if (offsetlow) { + readval = readval >> offsetlow; + } + AML_DEBUGPRINT("[read(bufferfield, %p)&mask:0x%x]\n", + addr, readval); + *valuep = readval; + + break; + + case AML_BUFFER_OUTPUT: + tmp = value & 0xff; + /* the lowest byte? */ + if (i == bytelen) { + if (offsetlow) { + tmp = (val & masklow) | tmp << offsetlow; + } + value = value >> (8 - offsetlow); + } else { + if (i == 1 && offsethigh) { + tmp = (val & maskhigh) | tmp; + } + value = value >> 8; + } + + AML_DEBUGPRINT("->[bufferfield:0x%02x@%p]\n", + tmp, addr); + *addr = tmp; + } + } +out: + return (0); +} + +u_int32_t +aml_bufferfield_read(u_int8_t *origin, u_int32_t bitoffset, + u_int32_t bitlen) +{ + int value; + + value = 0; + aml_bufferfield_io(AML_BUFFER_INPUT, &value, origin, + bitoffset, bitlen); + return (value); +} + +int +aml_bufferfield_write(u_int32_t value, u_int8_t *origin, + u_int32_t bitoffset, u_int32_t bitlen) +{ + int status; + + status = aml_bufferfield_io(AML_BUFFER_OUTPUT, &value, + origin, bitoffset, bitlen); + return (status); +} + +int +aml_region_handle_alloc(struct aml_environ *env, int regtype, u_int32_t flags, + u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen, + struct aml_region_handle *h) +{ + int state; + struct aml_name *pci_info; + + state = 0; + pci_info = NULL; + bzero(h, sizeof(struct aml_region_handle)); + + h->env = env; + h->regtype = regtype; + h->flags = flags; + h->baseaddr = baseaddr; + h->bitoffset = bitoffset; + h->bitlen = bitlen; + + switch (AML_FIELDFLAGS_ACCESSTYPE(flags)) { + case AML_FIELDFLAGS_ACCESS_ANYACC: + if (bitlen <= 8) { + h->unit = 1; + break; + } + if (bitlen <= 16) { + h->unit = 2; + break; + } + h->unit = 4; + break; + case AML_FIELDFLAGS_ACCESS_BYTEACC: + h->unit = 1; + break; + case AML_FIELDFLAGS_ACCESS_WORDACC: + h->unit = 2; + break; + case AML_FIELDFLAGS_ACCESS_DWORDACC: + h->unit = 4; + break; + default: + h->unit = 1; + break; + } + + h->addr = baseaddr + h->unit * ((bitoffset / 8) / h->unit); + h->bytelen = baseaddr + ((bitoffset + bitlen) / 8) - h->addr + + ((bitlen % 8) ? 1 : 0); + +#ifdef _KERNEL + switch (h->regtype) { + case AML_REGION_SYSMEM: + OsdMapMemory((void *)h->addr, h->bytelen, (void **)&h->vaddr); + break; + + case AML_REGION_PCICFG: + /* Obtain PCI bus number */ + pci_info = aml_search_name(env, "_BBN"); + if (pci_info == NULL || pci_info->property->type != aml_t_num) { + AML_DEBUGPRINT("Cannot locate _BBN. Using default 0\n"); + h->pci_bus = 0; + } else { + AML_DEBUGPRINT("found _BBN: %d\n", + pci_info->property->num.number); + h->pci_bus = pci_info->property->num.number & 0xff; + } + + /* Obtain device & function number */ + pci_info = aml_search_name(env, "_ADR"); + if (pci_info == NULL || pci_info->property->type != aml_t_num) { + printf("Cannot locate: _ADR\n"); + state = -1; + goto out; + } + h->pci_devfunc = pci_info->property->num.number; + + AML_DEBUGPRINT("[pci%d.%d]", h->pci_bus, h->pci_devfunc); + break; + + default: + break; + } + +out: +#endif /* _KERNEL */ + return (state); +} + +void +aml_region_handle_free(struct aml_region_handle *h) +{ +#ifdef _KERNEL + switch (h->regtype) { + case AML_REGION_SYSMEM: + OsdUnMapMemory((void *)h->vaddr, h->bytelen); + break; + + default: + break; + } +#endif /* _KERNEL */ +} + +static int +aml_region_io_simple(struct aml_environ *env, int io, int regtype, + u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr, + u_int32_t bitoffset, u_int32_t bitlen) +{ + int i, state; + u_int32_t readval, value, offset, bytelen; + struct aml_region_handle handle; + + state = aml_region_handle_alloc(env, regtype, flags, + baseaddr, bitoffset, bitlen, &handle); + if (state == -1) { + goto out; + } + + readval = 0; + offset = bitoffset % (handle.unit * 8); + /* limitation of 32 bits alignment */ + bytelen = (handle.bytelen > 4) ? 4 : handle.bytelen; + + if (io == AML_REGION_INPUT || + AML_FIELDFLAGS_UPDATERULE(flags) == AML_FIELDFLAGS_UPDATE_PRESERVE) { + for (i = 0; i < bytelen; i += handle.unit) { + state = aml_region_read_simple(&handle, i, &value); + if (state == -1) { + goto out; + } + readval |= (value << (i * 8)); + } + AML_DEBUGPRINT("\t[%d:0x%x@0x%x:%d,%d]", + regtype, readval, handle.addr, offset, bitlen); + } + + switch (io) { + case AML_REGION_INPUT: + AML_DEBUGPRINT("\n"); + readval = aml_adjust_readvalue(flags, offset, bitlen, readval); + value = readval; + value = aml_region_prompt_read(&handle, value); + state = aml_region_prompt_update_value(readval, value, &handle); + if (state == -1) { + goto out; + } + + *valuep = value; + break; + case AML_REGION_OUTPUT: + value = *valuep; + value = aml_adjust_updatevalue(flags, offset, + bitlen, readval, value); + value = aml_region_prompt_write(&handle, value); + AML_DEBUGPRINT("\t->[%d:0x%x@0x%x:%d,%d]\n", regtype, value, + handle.addr, offset, bitlen); + for (i = 0; i < bytelen; i += handle.unit) { + state = aml_region_write_simple(&handle, i, value); + if (state == -1) { + goto out; + } + value = value >> (handle.unit * 8); + } + break; + } + + aml_region_handle_free(&handle); +out: + return (state); +} + +int +aml_region_io(struct aml_environ *env, int io, int regtype, + u_int32_t flags, u_int32_t *valuep, u_int32_t baseaddr, + u_int32_t bitoffset, u_int32_t bitlen) +{ + u_int32_t unit, offset; + u_int32_t offadj, bitadj; + u_int32_t value, readval; + int state, i; + + readval = 0; + state = 0; + unit = 4; /* limitation of 32 bits alignment */ + offset = bitoffset % (unit * 8); + offadj = 0; + bitadj = 0; + if (offset + bitlen > unit * 8) { + bitadj = bitlen - (unit * 8 - offset); + } + for (i = 0; i < offset + bitlen; i += unit * 8) { + value = (*valuep) >> offadj; + state = aml_region_io_simple(env, io, regtype, flags, + &value, baseaddr, bitoffset + offadj, bitlen - bitadj); + if (state == -1) { + goto out; + } + readval |= value << offadj; + bitadj = offadj = bitlen - bitadj; + } + *valuep = readval; + +out: + return (state); +} diff --git a/usr.sbin/acpidump/aml/aml_common.h b/usr.sbin/acpidump/aml/aml_common.h new file mode 100644 index 00000000000..5ea32924a4a --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_common.h @@ -0,0 +1,162 @@ +/* $OpenBSD: aml_common.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_common.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_common.h,v 1.4 2000/10/02 08:58:47 iwasaki Exp $ + */ + +#ifndef _AML_COMMON_H_ +#define _AML_COMMON_H_ + +#include "acpidump.h" + +/* + * General Stuff + */ +#ifdef _KERNEL +#define AML_SYSABORT() do { \ + printf("aml: fatal errer at %s:%d\n", __FILE__, __LINE__); \ + panic("panic in AML interpreter!"); \ +} while(0) +#define AML_SYSASSERT(x) do { \ + if (!(x)) { \ + AML_SYSABORT(); \ + } \ +} while(0) +#define AML_SYSERRX(eval, fmt, args...) do { \ + printf(fmt, args); \ +} while(0) +#define AML_DEBUGGER(x, y) /* no debugger in kernel */ +#define AML_STALL(micro) OsdSleepUsec(micro) +#define AML_SLEEP(sec, milli) OsdSleep(sec, milli) +#else /* !_KERNEL */ +#define AML_SYSASSERT(x) assert(x) +#define AML_SYSABORT() abort() +#define AML_SYSERRX(eval, fmt, args...) errx(eval, fmt, args) +#define AML_DEBUGGER(x, y) aml_dbgr(x, y) +#define AML_STALL(micro) /* not required in userland */ +#define AML_SLEEP(sec, milli) /* not required in userland */ +#endif /* _KERNEL */ + +union aml_object; +struct aml_name; + +extern int aml_debug; + +#define AML_DEBUGPRINT(args...) do { \ + if (aml_debug) { \ + printf(args); \ + } \ +} while(0) + +void aml_showobject(union aml_object *); +void aml_showtree(struct aml_name *, int); +int aml_print_curname(struct aml_name *); +void aml_print_namestring(u_int8_t *); +void aml_print_indent(int); + +/* + * Reigion I/O Stuff for both kernel/userland. + */ + +/* + * Field Flags + */ +/* bit 0 -3: AccessType */ +#define AML_FIELDFLAGS_ACCESS_ANYACC 0x00 +#define AML_FIELDFLAGS_ACCESS_BYTEACC 0x01 +#define AML_FIELDFLAGS_ACCESS_WORDACC 0x02 +#define AML_FIELDFLAGS_ACCESS_DWORDACC 0x03 +#define AML_FIELDFLAGS_ACCESS_BLOCKACC 0x04 +#define AML_FIELDFLAGS_ACCESS_SMBSENDRECVACC 0x05 +#define AML_FIELDFLAGS_ACCESS_SMBQUICKACC 0x06 +#define AML_FIELDFLAGS_ACCESSTYPE(flags) (flags & 0x0f) +/* bit 4: LockRule */ +#define AML_FIELDFLAGS_LOCK_NOLOCK 0x00 +#define AML_FIELDFLAGS_LOCK_LOCK 0x10 +#define AML_FIELDFLAGS_LOCKRULE(flags) (flags & 0x10) +/* bit 5 - 6: UpdateRule */ +#define AML_FIELDFLAGS_UPDATE_PRESERVE 0x00 +#define AML_FIELDFLAGS_UPDATE_WRITEASONES 0x20 +#define AML_FIELDFLAGS_UPDATE_WRITEASZEROS 0x40 +#define AML_FIELDFLAGS_UPDATERULE(flags) (flags & 0x60) +/* bit 7: reserved (must be 0) */ + +#define AML_REGION_INPUT 0 +#define AML_REGION_OUTPUT 1 + +#define AML_REGION_SYSMEM 0 +#define AML_REGION_SYSIO 1 +#define AML_REGION_PCICFG 2 +#define AML_REGION_EMBCTL 3 +#define AML_REGION_SMBUS 4 + +struct aml_region_handle { + /* These are copies of values used on initialization */ + struct aml_environ *env; + int regtype; + u_int32_t flags; + u_int32_t baseaddr; + u_int32_t bitoffset; + u_int32_t bitlen; + + /* following is determined on initialization */ + vm_offset_t addr, bytelen; + u_int32_t unit; /* access unit in bytes */ + + /* region type dependant */ + vm_offset_t vaddr; /* SystemMemory */ + u_int32_t pci_bus, pci_devfunc; /* PCI_Config */ +}; + +u_int32_t aml_adjust_readvalue(u_int32_t, u_int32_t, u_int32_t, + u_int32_t); +u_int32_t aml_adjust_updatevalue(u_int32_t, u_int32_t, u_int32_t, + u_int32_t, u_int32_t); + +u_int32_t aml_bufferfield_read(u_int8_t *, u_int32_t, u_int32_t); +int aml_bufferfield_write(u_int32_t, u_int8_t *, + u_int32_t, u_int32_t); + +int aml_region_handle_alloc(struct aml_environ *, int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, + struct aml_region_handle *); +void aml_region_handle_free(struct aml_region_handle *); + +int aml_region_io(struct aml_environ *, int, int, + u_int32_t, u_int32_t *, u_int32_t, + u_int32_t, u_int32_t); +extern int aml_region_read_simple(struct aml_region_handle *, vm_offset_t, + u_int32_t *); +extern int aml_region_write_simple(struct aml_region_handle *, vm_offset_t, + u_int32_t); +extern u_int32_t aml_region_prompt_read(struct aml_region_handle *, + u_int32_t); +extern u_int32_t aml_region_prompt_write(struct aml_region_handle *, + u_int32_t); +extern int aml_region_prompt_update_value(u_int32_t, u_int32_t, + struct aml_region_handle *); +#endif /* !_AML_COMMON_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_env.h b/usr.sbin/acpidump/aml/aml_env.h new file mode 100644 index 00000000000..fe85f362458 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_env.h @@ -0,0 +1,47 @@ +/* $OpenBSD: aml_env.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * 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. + * + * $Id: aml_env.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_env.h,v 1.2 2000/11/09 06:24:45 iwasaki Exp $ + */ + +#ifndef _AML_ENV_H_ +#define _AML_ENV_H_ + +#include <aml/aml_name.h> +#include <aml/aml_obj.h> +#include <aml/aml_status.h> + +struct aml_environ { + u_int8_t *dp; + u_int8_t *end; + enum aml_status stat; + struct aml_name *curname; + struct aml_name tempname; + union aml_object tempobject; +}; + +#endif /* !_AML_ENV_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_evalobj.c b/usr.sbin/acpidump/aml/aml_evalobj.c new file mode 100644 index 00000000000..48109bd88c5 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_evalobj.c @@ -0,0 +1,436 @@ +/* $OpenBSD: aml_evalobj.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_evalobj.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_evalobj.c,v 1.4 2000/11/09 06:24:45 iwasaki Exp $ + */ + +#include <sys/types.h> + +#include <aml/aml_amlmem.h> +#include <aml/aml_common.h> +#include <aml/aml_env.h> +#include <aml/aml_evalobj.h> +#include <aml/aml_name.h> +#include <aml/aml_obj.h> +#include <aml/aml_parse.h> +#include <aml/aml_region.h> +#include <aml/aml_status.h> +#include <aml/aml_store.h> + +#ifndef _KERNEL +#include <sys/stat.h> +#include <sys/mman.h> + +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "debug.h" +#else /* _KERNEL */ +#include <sys/systm.h> +#endif /* !_KERNEL */ + +static union aml_object *aml_eval_fieldobject(struct aml_environ *env, + struct aml_name *name); + +static union aml_object * +aml_eval_fieldobject(struct aml_environ *env, struct aml_name *name) +{ + int num; + struct aml_name *oname,*wname; + struct aml_field *field; + struct aml_opregion *or; + union aml_object tobj; + + num = 0; + /* CANNOT OCCUR! */ + if (name == NULL || name->property == NULL || + name->property->type != aml_t_field) { + printf("????\n"); + env->stat = aml_stat_panic; + return (NULL); + } + field = &name->property->field; + oname = env->curname; + if (field->bitlen > 32) { + env->tempobject.type = aml_t_regfield; + } else { + env->tempobject.type = aml_t_num; + } + env->curname = name; + if (field->f.ftype == f_t_field) { + wname = aml_search_name(env, field->f.fld.regname); + if (wname == NULL || wname->property == NULL || + wname->property->type != aml_t_opregion) { + AML_DEBUGPRINT("Inappropreate Type\n"); + env->stat = aml_stat_panic; + env->curname = oname; + return (NULL); + } + or = &wname->property->opregion; + if (env->tempobject.type == aml_t_regfield) { + env->tempobject.regfield.space = or->space; + env->tempobject.regfield.flags = field->flags; + env->tempobject.regfield.offset = or->offset; + env->tempobject.regfield.bitoffset = field->bitoffset; + env->tempobject.regfield.bitlen = field->bitlen; + } else { + env->tempobject.type = aml_t_num; + env->tempobject.num.number = aml_region_read(env, + or->space, field->flags, or->offset, + field->bitoffset, field->bitlen); + AML_DEBUGPRINT("[read(%d, 0x%x)->0x%x]", + or->space, or->offset + field->bitoffset / 8, + env->tempobject.num.number); + } + } else if (field->f.ftype == f_t_index) { + wname = aml_search_name(env, field->f.ifld.indexname); + tobj.type = aml_t_num; + tobj.num.number = field->bitoffset / 8;/* AccessType Boundary */ + aml_store_to_name(env, &tobj, wname); + wname = aml_search_name(env, field->f.ifld.dataname); + num = aml_objtonum(env, aml_eval_name(env, wname)); + env->tempobject.type = aml_t_num; + env->tempobject.num.number = (num >> (field->bitoffset & 7)) & + ((1 << field->bitlen) - 1); + } + env->curname = oname; + return (&env->tempobject); +} + +union aml_object * +aml_eval_objref(struct aml_environ *env, union aml_object *obj) +{ + int offset; + union aml_object num1; + union aml_object *ref, *ret; + + ret = obj; + if (obj->objref.deref == 1) { + num1.type = aml_t_num; + offset = obj->objref.offset; + ref = obj->objref.ref; + if (ref == NULL) { + goto out; + } + switch (ref->type) { + case aml_t_package: + if (ref->package.elements > offset) { + ret = ref->package.objects[offset]; + } else { + num1.num.number = 0; + env->tempobject = num1; + ret = &env->tempobject; + } + break; + case aml_t_buffer: + if (ref->buffer.size > offset) { + num1.num.number = ref->buffer.data[offset] & 0xff; + } else { + num1.num.number = 0; + } + env->tempobject = num1; + ret = &env->tempobject; + break; + default: + break; + } + } + if (obj->objref.alias == 1) { + ret = aml_eval_name(env, obj->objref.nameref); + goto out; + } +out: + return (ret); +} + +/* + * Eval named object. + */ +union aml_object * +aml_eval_name(struct aml_environ *env, struct aml_name *aname) +{ + int argnum, i; + int num; + struct aml_name *tmp; + struct aml_environ *copy; + struct aml_local_stack *stack; + union aml_object *obj, *ret; + union aml_object *src; + + ret = NULL; + if (aname == NULL || aname->property == NULL) { + return (NULL); + } + if (env->stat == aml_stat_panic) { + return (NULL); + } + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + return (NULL); + } + ret = aname->property; + i = 0; +reevaluate: + if (i > 10) { + env->stat = aml_stat_panic; + printf("TOO MANY LOOP\n"); + ret = NULL; + goto out; + } + switch (aname->property->type) { + case aml_t_namestr: + tmp = aname; + aname = aml_search_name(env, aname->property->nstr.dp); + if (aname == NULL) { + aname = tmp; + } + i++; + goto reevaluate; + case aml_t_objref: + ret = aml_eval_objref(env, aname->property); + goto out; + case aml_t_num: + case aml_t_string: + case aml_t_buffer: + case aml_t_package: + case aml_t_debug: + ret = aname->property; + goto out; + case aml_t_field: + aml_free_objectcontent(&env->tempobject); + ret = aml_eval_fieldobject(env, aname); + goto out; + case aml_t_method: + aml_free_objectcontent(&env->tempobject); + argnum = aname->property->meth.argnum & 7; + *copy = *env; + copy->curname = aname; + copy->dp = aname->property->meth.from; + copy->end = aname->property->meth.to; + copy->stat = aml_stat_none; + stack = aml_local_stack_create(); + AML_DEBUGPRINT("("); + for (i = 0; i < argnum; i++) { + aml_local_stack_getArgX(stack, i)->property = + aml_copy_object(env, + aml_eval_name(env, + aml_parse_termobj(env, 0))); + if (i < argnum - 1) + AML_DEBUGPRINT(", "); + } + AML_DEBUGPRINT(")\n"); + aml_local_stack_push(stack); + if (env->stat == aml_stat_step) { + AML_DEBUGGER(env, copy); + } + tmp = aml_execute_method(copy); + obj = aml_eval_name(env, tmp); + if (copy->stat == aml_stat_panic) { + AML_DEBUGPRINT("PANIC OCCURED IN METHOD"); + env->stat = aml_stat_panic; + ret = NULL; + aml_local_stack_delete(aml_local_stack_pop()); + goto out; + } + if (aml_debug) { + aml_showobject(obj); + } + + if (tmp) + tmp->property = NULL; + aml_local_stack_delete(aml_local_stack_pop()); + if (obj) { + aml_create_local_object()->property = obj; + ret = obj; + } else { + env->tempobject.type = aml_t_num; + env->tempobject.num.number = 0; + } + + goto out; + case aml_t_bufferfield: + aml_free_objectcontent(&env->tempobject); + if (aname->property->bfld.bitlen > 32) { + ret = aname->property; + } else { + src = aname->property; + num = aml_bufferfield_read(src->bfld.origin, + src->bfld.bitoffset, src->bfld.bitlen); + env->tempobject.type = aml_t_num; + env->tempobject.num.number = num; + ret = &env->tempobject; + } + goto out; + default: + AML_DEBUGPRINT("I eval the object that I should not eval, %s%d", + aname->name, aname->property->type); + AML_SYSABORT(); + ret = NULL; + goto out; + } +out: + memman_free(aml_memman, memid_aml_environ, copy); + return (ret); +} + +/* + * Eval named object but env variable is not required and return + * status of evaluation (success is zero). This function is assumed + * to be called by aml_apply_foreach_found_objects(). + * Note that no arguments are passed if object is a method. + */ + +int +aml_eval_name_simple(struct aml_name *name, va_list ap) +{ + struct aml_environ *env; + union aml_object *ret; + + if (name == NULL || name->property == NULL) { + return (1); + } + + env = memman_alloc(aml_memman, memid_aml_environ); + if (env == NULL) { + return (1); + } + bzero(env, sizeof(struct aml_environ)); + + aml_local_stack_push(aml_local_stack_create()); + + AML_DEBUGPRINT("Evaluating "); + aml_print_curname(name); + ret = aml_eval_name(env, name); + if (name->property->type != aml_t_method) { + AML_DEBUGPRINT("\n"); + if (aml_debug) { + aml_showobject(ret); + } + } + + aml_local_stack_delete(aml_local_stack_pop()); + + memman_free(aml_memman, memid_aml_environ, env); + return (0); +} + +int +aml_objtonum(struct aml_environ *env, union aml_object *obj) +{ + + if (obj != NULL && obj->type == aml_t_num) { + return (obj->num.number); + } else { + env->stat = aml_stat_panic; + return (-1); + } +} + +struct aml_name * +aml_execute_method(struct aml_environ *env) +{ + struct aml_name *name; + struct aml_name_group *newgrp; + + newgrp = aml_new_name_group(AML_NAME_GROUP_IN_METHOD); + + AML_DEBUGPRINT("["); + aml_print_curname(env->curname); + AML_DEBUGPRINT(" START]\n"); + + name = aml_parse_objectlist(env, 0); + AML_DEBUGPRINT("["); + aml_print_curname(env->curname); + AML_DEBUGPRINT(" END]\n"); + + aml_delete_name_group(newgrp); + return (name); +} + +union aml_object * +aml_invoke_method(struct aml_name *name, int argc, union aml_object *argv) +{ + int i; + struct aml_name *tmp; + struct aml_environ *env; + struct aml_local_stack *stack; + union aml_object *retval; + union aml_object *obj; + + retval = NULL; + env = memman_alloc(aml_memman, memid_aml_environ); + if (env == NULL) { + return (NULL); + } + bzero(env, sizeof(struct aml_environ)); + + if (name != NULL && name->property != NULL && + name->property->type == aml_t_method) { + env->curname = name; + env->dp = name->property->meth.from; + env->end = name->property->meth.to; + AML_DEBUGGER(env, env); + stack = aml_local_stack_create(); + for (i = 0; i < argc; i++) { + aml_local_stack_getArgX(stack, i)->property = + aml_alloc_object(argv[i].type, &argv[i]); + } + aml_local_stack_push(stack); + obj = aml_eval_name(env, tmp = aml_execute_method(env)); + if (aml_debug) { + aml_showtree(name, 0); + } + + if (tmp) + tmp->property = NULL; + aml_local_stack_delete(aml_local_stack_pop()); + if (obj) { + aml_create_local_object()->property = obj; + retval = obj; + } + } + memman_free(aml_memman, memid_aml_environ, env); + return (retval); +} + +union aml_object * +aml_invoke_method_by_name(char *method, int argc, union aml_object *argv) +{ + struct aml_name *name; + + name = aml_find_from_namespace(aml_get_rootname(), method); + if (name == NULL) { + return (NULL); + } + + return (aml_invoke_method(name, argc, argv)); +} diff --git a/usr.sbin/acpidump/aml/aml_evalobj.h b/usr.sbin/acpidump/aml/aml_evalobj.h new file mode 100644 index 00000000000..e951abbe2b5 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_evalobj.h @@ -0,0 +1,49 @@ +/* $OpenBSD: aml_evalobj.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * 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. + * + * $Id: aml_evalobj.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_evalobj.h,v 1.2 2000/09/20 22:53:39 iwasaki Exp $ + */ + +#ifndef _AML_EVALOBJ_H_ +#define _AML_EVALOBJ_H_ + +#include <stdarg.h> + +union aml_object *aml_eval_objref(struct aml_environ *, + union aml_object *); +union aml_object *aml_eval_name(struct aml_environ *, + struct aml_name *); +int aml_eval_name_simple(struct aml_name *, va_list); +int aml_objtonum(struct aml_environ *, + union aml_object *); +struct aml_name *aml_execute_method(struct aml_environ *); +union aml_object *aml_invoke_method(struct aml_name *, + int, union aml_object *); +union aml_object *aml_invoke_method_by_name(char *, + int, union aml_object *); + +#endif /* !_AML_EVALOBJ_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_memman.c b/usr.sbin/acpidump/aml/aml_memman.c new file mode 100644 index 00000000000..942251be2da --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_memman.c @@ -0,0 +1,477 @@ +/* $OpenBSD: aml_memman.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_memman.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_memman.c,v 1.2 2000/11/09 06:24:45 iwasaki Exp $ + */ + +/* + * Generic Memory Management + */ +#include <sys/types.h> +#include <aml/aml_memman.h> +#ifndef roundup +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) /* to any y */ +#endif +#ifndef _KERNEL +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#else /* _KERNEL */ +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/malloc.h> +MALLOC_DEFINE(M_MEMMAN, "memman", "Generic and Simple Memory Management"); +#endif /* !_KERNEL */ + +unsigned int memid_unkown = 255; + +static int manage_block(struct memman *memman, unsigned int id, + void *block, unsigned static_mem, + unsigned entries); +static int blockman_init(struct memman *memman, unsigned int id); +static void memman_flexsize_add_histogram(struct memman *memman, + size_t size, + int tolerance); +static int memman_comp_histogram_size(const void *a, + const void *b); +static void memman_sort_histogram_by_size(struct memman *memman); +static unsigned int memman_guess_memid(struct memman *memman, void *chunk); +static void memman_statistics_fixedsize(struct memman *memman); +static void memman_statistics_flexsize(struct memman *memman); + +static int +manage_block(struct memman *memman, unsigned int id, void *block, + unsigned static_mem, unsigned entries) +{ + unsigned int i; + size_t alloc_size; + void *tmp, *realblock; + struct memman_blockman *bmp; + struct memman_block *memblock; + struct memman_node *memnodes; + + bmp = &memman->blockman[id]; + alloc_size = MEMMAN_BLOCKNODE_SIZE(entries); + + if (static_mem) { + tmp = (void *)block; + realblock = (char *)block + alloc_size; + } else { + tmp = MEMMAN_SYSMALLOC(alloc_size); + if (!tmp) { + return (-1); + } + realblock = block; + + memman->allocated_mem += alloc_size; + memman->salloc_called++; + } + + memblock = (struct memman_block *)tmp; + memnodes = (struct memman_node *)((char *)tmp + sizeof(struct memman_block)); + + memblock->block = realblock; + memblock->static_mem = static_mem; + memblock->allocated = entries; + memblock->available = entries; + if (!static_mem) { + alloc_size += roundup(bmp->size * entries, ROUNDUP_UNIT); + } + memblock->allocated_mem = alloc_size; + LIST_INSERT_HEAD(&bmp->block_list, memblock, links); + + for (i = 0; i < entries; ++i) { + memnodes[i].node = ((char *)realblock + (i * (bmp->size))); + memnodes[i].memblock = memblock; + LIST_INSERT_HEAD(&bmp->free_node_list, &memnodes[i], links); + } + bmp->available = entries; + + return (0); +} + +static int +blockman_init(struct memman *memman, unsigned int id) +{ + int status; + struct memman_blockman *bmp; + + bmp = &memman->blockman[id]; + bmp->initialized = 1; + LIST_INIT(&bmp->block_list); + LIST_INIT(&bmp->free_node_list); + LIST_INIT(&bmp->occupied_node_list); + status = manage_block(memman, id, bmp->initial_block, + 1, MEMMAN_INITIAL_SIZE); + return (status); +} + +void * +memman_alloc(struct memman *memman, unsigned int id) +{ + size_t alloc_size; + void *chunk, *block; + struct memman_blockman *bmp; + struct memman_node *memnode; + + if (memman->max_memid <= id) { + printf("memman_alloc: invalid memory type id\n"); + return (NULL); + } + bmp = &memman->blockman[id]; + if (!bmp->initialized) { + if (blockman_init(memman, id)) { + goto malloc_fail; + } + } + memman->alloc_called++; + + if (bmp->available == 0) { + alloc_size = roundup(bmp->size * MEMMAN_INCR_SIZE, + ROUNDUP_UNIT); + block = MEMMAN_SYSMALLOC(alloc_size); + if (!block) { + goto malloc_fail; + } + memman->required_mem += bmp->size * MEMMAN_INCR_SIZE; + memman->allocated_mem += alloc_size; + memman->salloc_called++; + + if (manage_block(memman, id, block, 0, MEMMAN_INCR_SIZE)) { + goto malloc_fail; + } + } + memnode = LIST_FIRST(&bmp->free_node_list); + LIST_REMOVE(memnode, links); + chunk = memnode->node; + LIST_INSERT_HEAD(&bmp->occupied_node_list, memnode, links); + memnode->memblock->available--; + bmp->available--; + + return (chunk); + +malloc_fail: + printf("memman_alloc: could not allocate memory\n"); + return (NULL); +} + +static void +memman_flexsize_add_histogram(struct memman *memman, size_t size, + int tolerance) +{ + int i; + int gap; + + if (size == 0) { + return; + } + for (i = 0; i < memman->flex_mem_histogram_ptr; i++) { + gap = memman->flex_mem_histogram[i].mem_size - size; + if (gap >= (tolerance * -1) && gap <= tolerance) { + memman->flex_mem_histogram[i].count++; + if (memman->flex_mem_histogram[i].mem_size < size) { + memman->flex_mem_histogram[i].mem_size = size; + } + return; + } + } + + if (memman->flex_mem_histogram_ptr == MEMMAN_HISTOGRAM_SIZE) { + memman_flexsize_add_histogram(memman, size, tolerance + 1); + return; + } + i = memman->flex_mem_histogram_ptr; + memman->flex_mem_histogram[i].mem_size = size; + memman->flex_mem_histogram[i].count = 1; + memman->flex_mem_histogram_ptr++; +} + +static int +memman_comp_histogram_size(const void *a, const void *b) +{ + int delta; + + delta = ((const struct memman_histogram *)a)->mem_size - + ((const struct memman_histogram *)b)->mem_size; + return (delta); +} + +static void +memman_sort_histogram_by_size(struct memman *memman) +{ + qsort(memman->flex_mem_histogram, memman->flex_mem_histogram_ptr, + sizeof(struct memman_histogram), memman_comp_histogram_size); +} + +void * +memman_alloc_flexsize(struct memman *memman, size_t size) +{ + void *mem; + struct memman_flexmem_info *info; + + if (size == 0) { + return (NULL); + } + if ((mem = MEMMAN_SYSMALLOC(size)) != NULL) { /* XXX */ + + info = MEMMAN_SYSMALLOC(sizeof(struct memman_flexmem_info)); + if (info) { + if (!memman->flex_mem_initialized) { + LIST_INIT(&memman->flexmem_info_list); + bzero(memman->flex_mem_histogram, + sizeof(struct memman_histogram)); + memman->flex_mem_initialized = 1; + } + info->addr = mem; + info->mem_size = size; + LIST_INSERT_HEAD(&memman->flexmem_info_list, info, links); + } + memman->flex_alloc_called++; + memman->flex_salloc_called++; + memman->flex_required_mem += size; + memman->flex_allocated_mem += size; + if (memman->flex_mem_size_min == 0 || + memman->flex_mem_size_min > size) { + memman->flex_mem_size_min = size; + } + if (memman->flex_mem_size_max < size) { + memman->flex_mem_size_max = size; + } + if (memman->flex_peak_mem_usage < + (memman->flex_allocated_mem - memman->flex_reclaimed_mem)) { + memman->flex_peak_mem_usage = + (memman->flex_allocated_mem - memman->flex_reclaimed_mem); + } + memman_flexsize_add_histogram(memman, size, + memman->flex_mem_histogram_initial_tolerance); + } + return (mem); +} + +static unsigned int +memman_guess_memid(struct memman *memman, void *chunk) +{ + unsigned int id; + struct memman_blockman *bmp; + struct memman_node *memnode; + + for (id = 0; id < memman->max_memid; id++) { + bmp = &memman->blockman[id]; + if (!bmp->initialized) { + if (blockman_init(memman, id)) { + printf("memman_free: could not initialized\n"); + } + } + LIST_FOREACH(memnode, &bmp->occupied_node_list, links) { + if (memnode->node == chunk) { + return (id); /* got it! */ + } + } + } + return (memid_unkown); /* gave up */ +} + +void +memman_free(struct memman *memman, unsigned int memid, void *chunk) +{ + unsigned int id; + unsigned found; + void *block; + struct memman_blockman *bmp; + struct memman_block *memblock; + struct memman_node *memnode; + + id = memid; + if (memid == memid_unkown) { + id = memman_guess_memid(memman, chunk); + } + if (memman->max_memid <= id) { + printf("memman_free: invalid memory type id\n"); + MEMMAN_SYSABORT(); + return; + } + bmp = &memman->blockman[id]; + if (!bmp->initialized) { + if (blockman_init(memman, id)) { + printf("memman_free: could not initialized\n"); + } + } + found = 0; + LIST_FOREACH(memnode, &bmp->occupied_node_list, links) { + if (memnode->node == chunk) { + found = 1; + break; + } + } + if (!found) { + printf("memman_free: invalid address\n"); + return; + } + memman->free_called++; + + LIST_REMOVE(memnode, links); + memblock = memnode->memblock; + memblock->available++; + LIST_INSERT_HEAD(&bmp->free_node_list, memnode, links); + bmp->available++; + + if (!memblock->static_mem && + memblock->available == memblock->allocated) { + LIST_FOREACH(memnode, &bmp->free_node_list, links) { + if (memnode->memblock != memblock) { + continue; + } + LIST_REMOVE(memnode, links); + bmp->available--; + } + block = memblock->block; + MEMMAN_SYSFREE(block); + memman->sfree_called++; + + LIST_REMOVE(memblock, links); + memman->sfree_called++; + memman->reclaimed_mem += memblock->allocated_mem; + MEMMAN_SYSFREE(memblock); + } +} + +void +memman_free_flexsize(struct memman *memman, void *chunk) +{ + struct memman_flexmem_info *info; + + LIST_FOREACH(info, &memman->flexmem_info_list, links) { + if (info->addr == chunk) { + memman->flex_reclaimed_mem += info->mem_size; + LIST_REMOVE(info, links); + MEMMAN_SYSFREE(info); + break; + } + } + /* XXX */ + memman->flex_free_called++; + memman->flex_sfree_called++; + MEMMAN_SYSFREE(chunk); +} + +void +memman_freeall(struct memman *memman) +{ + int id; + void *chunk; + struct memman_blockman *bmp; + struct memman_node *memnode; + struct memman_block *memblock; + struct memman_flexmem_info *info; + + for (id = 0; id < memman->max_memid; id++) { + bmp = &memman->blockman[id]; + + while ((memnode = LIST_FIRST(&bmp->occupied_node_list))) { + chunk = memnode->node; + printf("memman_freeall: fixed size (id = %d)\n", id); + memman_free(memman, id, chunk); + } + while ((memblock = LIST_FIRST(&bmp->block_list))) { + LIST_REMOVE(memblock, links); + if (!memblock->static_mem) { + memman->sfree_called++; + memman->reclaimed_mem += memblock->allocated_mem; + MEMMAN_SYSFREE(memblock); + } + } + bmp->initialized = 0; + } + + LIST_FOREACH(info, &memman->flexmem_info_list, links) { + printf("memman_freeall: flex size (size = %d, addr = %p)\n", + info->mem_size, info->addr); + memman_free_flexsize(memman, info->addr); + } +} + +static void +memman_statistics_fixedsize(struct memman *memman) +{ + printf(" fixed size memory blocks\n"); + printf(" alloc(): %d times\n", memman->alloc_called); + printf(" system malloc(): %d times\n", memman->salloc_called); + printf(" free(): %d times\n", memman->free_called); + printf(" system free(): %d times\n", memman->sfree_called); + printf(" required memory: %d bytes\n", memman->required_mem); + printf(" allocated memory: %d bytes\n", memman->allocated_mem); + printf(" reclaimed memory: %d bytes\n", memman->reclaimed_mem); +} + +static void +memman_statistics_flexsize(struct memman *memman) +{ + int i; + + printf(" flexible size memory blocks\n"); + printf(" alloc(): %d times\n", memman->flex_alloc_called); + printf(" system malloc(): %d times\n", memman->flex_salloc_called); + printf(" free(): %d times\n", memman->flex_free_called); + printf(" system free(): %d times\n", memman->flex_sfree_called); + printf(" required memory: %d bytes\n", memman->flex_required_mem); + printf(" allocated memory: %d bytes\n", memman->flex_allocated_mem); + printf(" reclaimed memory: %d bytes\n", memman->flex_reclaimed_mem); + printf(" peak memory usage: %d bytes\n", memman->flex_peak_mem_usage); + printf(" min memory size: %d bytes\n", memman->flex_mem_size_min); + printf(" max memory size: %d bytes\n", memman->flex_mem_size_max); + printf(" avg memory size: %d bytes\n", + (memman->flex_alloc_called) ? + memman->flex_allocated_mem / memman->flex_alloc_called : 0); + + printf(" memory size histogram (%d entries):\n", + memman->flex_mem_histogram_ptr); + printf(" size count\n"); + memman_sort_histogram_by_size(memman); + for (i = 0; i < memman->flex_mem_histogram_ptr; i++) { + printf(" %d %d\n", + memman->flex_mem_histogram[i].mem_size, + memman->flex_mem_histogram[i].count); + } +} + +void +memman_statistics(struct memman *memman) +{ + printf("memman: reporting statistics\n"); + memman_statistics_fixedsize(memman); + memman_statistics_flexsize(memman); +} + +size_t +memman_memid2size(struct memman *memman, unsigned int id) +{ + if (memman->max_memid <= id) { + printf("memman_alloc: invalid memory type id\n"); + return (0); + } + return (memman->blockman[id].size); +} diff --git a/usr.sbin/acpidump/aml/aml_memman.h b/usr.sbin/acpidump/aml/aml_memman.h new file mode 100644 index 00000000000..fce68328e72 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_memman.h @@ -0,0 +1,172 @@ +/* $OpenBSD: aml_memman.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_memman.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_memman.h,v 1.1 2000/08/24 09:33:08 takawata Exp $ + */ + +#ifndef _MEMMAN_H_ +#define _MEMMAN_H_ + +/* + * Generic Memory Management + */ + +#include <sys/types.h> +#include <sys/queue.h> + +/* memory block */ +struct memman_block { + LIST_ENTRY(memman_block) links; + void *block; + unsigned static_mem; /* static memory or not */ + unsigned int allocated; /* number of allocated chunks */ + unsigned int available; /* number of available chunks */ + unsigned int allocated_mem; /* block + misc (in bytes) */ + +}__attribute__((packed)); + +LIST_HEAD(memman_block_list, memman_block); + +/* memory node in block */ +struct memman_node { + LIST_ENTRY(memman_node) links; + void *node; + struct memman_block *memblock; +}__attribute__((packed)); + +LIST_HEAD(memman_node_list, memman_node); + +/* memory type id */ +extern unsigned int memid_unkown; + +/* memory block manager */ +struct memman_blockman { + unsigned int size; /* size of chunk */ + unsigned int available; /* total # of available chunks */ + void *initial_block; /* initial memory storage */ + unsigned initialized; /* initialized or not */ + + struct memman_block_list block_list; + struct memman_node_list free_node_list; + struct memman_node_list occupied_node_list; +}; + +/* memory size histogram */ +#define MEMMAN_HISTOGRAM_SIZE 20 +struct memman_histogram { + int mem_size; + int count; +}; + +/* flex size memory allocation info */ +struct memman_flexmem_info { + LIST_ENTRY(memman_flexmem_info) links; + void *addr; + size_t mem_size; +}__attribute__((packed)); + +LIST_HEAD(memman_flexmem_info_list, memman_flexmem_info); + +/* memory manager */ +struct memman { + struct memman_blockman *blockman; + unsigned int max_memid; /* max number of valid memid */ + + /* fixed size memory blocks */ + unsigned int alloc_called; /* memman_alloc() calling */ + unsigned int free_called; /* memman_free() calling */ + unsigned int salloc_called; /* malloc() calling */ + unsigned int sfree_called; /* free() calling */ + size_t required_mem; /* total required memory (in bytes) */ + size_t allocated_mem; /* total malloc()ed memory */ + size_t reclaimed_mem; /* total free()ed memory */ + /* flex size memory blocks */ + unsigned int flex_alloc_called; /* memman_alloc_flexsize() calling */ + unsigned int flex_free_called; /* memman_free_flexsize() calling */ + unsigned int flex_salloc_called;/* malloc() calling */ + unsigned int flex_sfree_called; /* free() calling */ + size_t flex_required_mem; /* total required memory (in bytes) */ + size_t flex_allocated_mem;/* total malloc()ed memory */ + size_t flex_reclaimed_mem;/* total free()ed memory */ + size_t flex_mem_size_min; /* min size of allocated memory */ + size_t flex_mem_size_max; /* max size of allocated memory */ + size_t flex_peak_mem_usage;/* memory usage at a peak period */ + + /* stuff for more detailed statistical information */ + struct memman_histogram *flex_mem_histogram; + unsigned int flex_mem_histogram_ptr; + int flex_mem_histogram_initial_tolerance; + unsigned flex_mem_initialized; + struct memman_flexmem_info_list flexmem_info_list; +}; + +#define MEMMAN_BLOCKNODE_SIZE(entries) sizeof(struct memman_block) + \ + sizeof(struct memman_node) * entries + +#ifndef ROUNDUP_UNIT +#define ROUNDUP_UNIT 4 +#endif + +#if !defined(MEMMAN_INITIAL_SIZE) || MEMMAN_INITIAL_SIZE < 2048 +#define MEMMAN_INITIAL_SIZE 2048 +#endif + +#if !defined(MEMMAN_INCR_SIZE) || MEMMAN_INCR_SIZE < 512 +#define MEMMAN_INCR_SIZE 512 +#endif + +#define MEMMAN_INITIALSTORAGE_DESC(type, name) \ +static struct { \ + char blocknodes[MEMMAN_BLOCKNODE_SIZE(MEMMAN_INITIAL_SIZE)]; \ + type realblock[MEMMAN_INITIAL_SIZE]; \ +} name + +#define MEMMAN_MEMBLOCK_DESC(size, initial_storage) \ + { size, MEMMAN_INITIAL_SIZE, &initial_storage, 0 } + +#define MEMMAN_MEMMANAGER_DESC(blockman, max_memid, histogram, tolerance) \ + { blockman, max_memid, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, histogram, 0, tolerance, 0} + +void *memman_alloc(struct memman *, unsigned int); +void *memman_alloc_flexsize(struct memman *, size_t); +void memman_free(struct memman *, unsigned int, void *); +void memman_free_flexsize(struct memman *, void *); +void memman_freeall(struct memman *); +void memman_statistics(struct memman *); +size_t memman_memid2size(struct memman *, unsigned int); + +#ifdef _KERNEL +#define MEMMAN_SYSMALLOC(size) malloc(size, M_MEMMAN, M_WAITOK) +#define MEMMAN_SYSFREE(ptr) free(ptr, M_MEMMAN) +#define MEMMAN_SYSABORT() /* no abort in kernel */ +#else /* !_KERNEL */ +#define MEMMAN_SYSMALLOC(size) malloc(size) +#define MEMMAN_SYSFREE(ptr) free(ptr) +#define MEMMAN_SYSABORT() abort() +#endif /* _KERNEL */ +#endif /* !_MEMMAN_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_name.c b/usr.sbin/acpidump/aml/aml_name.c new file mode 100644 index 00000000000..b41698d7e2c --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_name.c @@ -0,0 +1,481 @@ +/* $OpenBSD: aml_name.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Yasuo Yokoyama + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_name.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_name.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ + */ +#include <sys/types.h> + +#include <aml/aml_amlmem.h> +#include <aml/aml_common.h> +#include <aml/aml_env.h> +#include <aml/aml_name.h> + +#ifndef _KERNEL +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "debug.h" +#else /* _KERNEL */ +#include <sys/systm.h> +#endif /* !_KERNEL */ + +static struct aml_name *aml_find_name(struct aml_name *, char *); +static struct aml_name *aml_new_name(struct aml_name *, char *); +static void aml_delete_name(struct aml_name *); + +static struct aml_name rootname = {"\\", NULL, NULL, NULL, NULL, NULL}; + +static struct aml_name_group root_group = { + AML_NAME_GROUP_ROOT, + &rootname, + NULL +}; + +struct aml_name_group *name_group_list = &root_group; +struct aml_local_stack *stack_top = NULL; + +struct aml_name * +aml_get_rootname() +{ + + return (&rootname); +} + +static struct aml_name * +aml_find_name(struct aml_name *parent, char *name) +{ + struct aml_name *result; + + if (!parent) + parent = &rootname; + for (result = parent->child; result; result = result->brother) + if (!strncmp(result->name, name, 4)) + break; + return (result); +} + +/* + * Parse given namesppace expression and find a first matched object + * under given level of the tree by depth first search. + */ + +struct aml_name * +aml_find_from_namespace(struct aml_name *parent, char *name) +{ + char *ptr; + int len; + struct aml_name *result; + + ptr = name; + if (!parent) + parent = &rootname; + + if (ptr[0] == '\\') { + ptr++; + parent = &rootname; + } + for (len = 0; ptr[len] != '.' && ptr[len] != '\0'; len++) + ; + + for (result = parent->child; result; result = result->brother) { + if (!strncmp(result->name, ptr, len)) { + if (ptr[len] == '\0' || ptr[len + 1] == '\0') { + return (result); + } + ptr += len; + if (ptr[0] != '.') { + return (NULL); + } + ptr++; + return (aml_find_from_namespace(result, ptr)); + } + } + + return (NULL); +} + +static void +_aml_apply_foreach_found_objects(struct aml_name *parent, char *name, + int len, int shallow, int (*func)(struct aml_name *, va_list), va_list ap) +{ + struct aml_name *child, *ptr; + + child = ptr = NULL; + + /* function to apply must be specified */ + if (func == NULL) { + return; + } + + for (child = parent->child; child; child = child->brother) { + if (!strncmp(child->name, name, len)) { + /* if function call was failed, stop searching */ + if (func(child, ap) != 0) { + return; + } + } + } + + if (shallow == 1) { + return; + } + + for (ptr = parent->child; ptr; ptr = ptr->brother) { + /* do more searching */ + _aml_apply_foreach_found_objects(ptr, name, len, 0, func, ap); + } +} + +/* + * Find named objects as many as possible under given level of + * namespace, and apply given callback function for each + * named objects found. If the callback function returns non-zero + * value, then the search terminates immediately. + * Note that object name expression is used as forward substring match, + * not exact match. The name expression "_L" will match for objects + * which have name starting with "_L" such as "\_SB_.LID_._LID" and + * "\_GPE._L00" and so on. The name expression can include parent object + * name in it like "\_GPE._L". In this case, GPE X level wake handlers + * will be found under "\_GPE" in shallow level. + */ + +void +aml_apply_foreach_found_objects(struct aml_name *start, char *name, + int (*func)(struct aml_name *, va_list), ...) +{ + int i, len, has_dot, last_is_dot, shallow; + struct aml_name *child, *parent; + va_list ap; + + shallow = 0; + if (start == NULL) { + parent = &rootname; + } else { + parent = start; + } + if (name[0] == '\\') { + name++; + parent = &rootname; + shallow = 1; + } + + len = strlen(name); + last_is_dot = 0; + /* the last dot should be ignored */ + if (len > 0 && name[len - 1] == '.') { + len--; + last_is_dot = 1; + } + + has_dot = 0; + for (i = 0; i < len - 1; i++) { + if (name[i] == '.') { + has_dot = 1; + break; + } + } + + /* try to parse expression and find any matched object. */ + if (has_dot == 1) { + child = aml_find_from_namespace(parent, name); + if (child == NULL) { + return; + } + + /* + * we have at least one object matched, search all objects + * under upper level of the found object. + */ + parent = child->parent; + + /* find the last `.' */ + for (name = name + len - 1; *name != '.'; name--) + ; + name++; + len = strlen(name) - last_is_dot; + shallow = 1; + } + + if (len > 4) { + return; + } + + va_start(ap, func); + _aml_apply_foreach_found_objects(parent, name, len, shallow, func, ap); + va_end(ap); +} + +struct aml_name_group * +aml_new_name_group(int id) +{ + struct aml_name_group *result; + + result = memman_alloc(aml_memman, memid_aml_name_group); + result->id = id; + result->head = NULL; + result->next = name_group_list; + name_group_list = result; + return (result); +} + +void +aml_delete_name_group(struct aml_name_group *target) +{ + struct aml_name_group *previous; + + previous = name_group_list; + if (previous == target) + name_group_list = target->next; + else { + while (previous && previous->next != target) + previous = previous->next; + if (previous) + previous->next = target->next; + } + target->next = NULL; + if (target->head) + aml_delete_name(target->head); + memman_free(aml_memman, memid_aml_name_group, target); +} + +static struct aml_name * +aml_new_name(struct aml_name *parent, char *name) +{ + struct aml_name *newname; + + if ((newname = aml_find_name(parent, name)) != NULL) + return (newname); + + newname = memman_alloc(aml_memman, memid_aml_name); + strncpy(newname->name, name, 4); + newname->parent = parent; + newname->child = NULL; + newname->property = NULL; + if (parent->child) + newname->brother = parent->child; + else + newname->brother = NULL; + parent->child = newname; + + newname->chain = name_group_list->head; + name_group_list->head = newname; + + return (newname); +} + +/* + * NOTE: + * aml_delete_name() doesn't maintain aml_name_group::{head,tail}. + */ +static void +aml_delete_name(struct aml_name *target) +{ + struct aml_name *next; + struct aml_name *ptr; + + for (; target; target = next) { + next = target->chain; + if (target->child) { + target->chain = NULL; + continue; + } + if (target->brother) { + if (target->parent) { + if (target->parent->child == target) { + target->parent->child = target->brother; + } else { + ptr = target->parent->child; + while (ptr && ptr->brother != target) + ptr = ptr->brother; + if (ptr) + ptr->brother = target->brother; + } + target->brother = NULL; + } + } else if (target->parent) { + target->parent->child = NULL; + } + aml_free_object(&target->property); + memman_free(aml_memman, memid_aml_name, target); + } +} + +#define AML_SEARCH_NAME 0 +#define AML_CREATE_NAME 1 +static struct aml_name *aml_nameman(struct aml_environ *, u_int8_t *, int); + +struct aml_name * +aml_search_name(struct aml_environ *env, u_int8_t *dp) +{ + + return (aml_nameman(env, dp, AML_SEARCH_NAME)); +} + +struct aml_name * +aml_create_name(struct aml_environ *env, u_int8_t *dp) +{ + + return (aml_nameman(env, dp, AML_CREATE_NAME)); +} + +static struct aml_name * +aml_nameman(struct aml_environ *env, u_int8_t *dp, int flag) +{ + int segcount; + int i; + struct aml_name *newname, *curname; + struct aml_name *(*searchfunc) (struct aml_name *, char *); + +#define CREATECHECK() do { \ + if (newname == NULL) { \ + AML_DEBUGPRINT("ERROR CANNOT FIND NAME\n"); \ + env->stat = aml_stat_panic; \ + return (NULL); \ + } \ +} while(0) + + searchfunc = (flag == AML_CREATE_NAME) ? aml_new_name : aml_find_name; + newname = env->curname; + if (dp[0] == '\\') { + newname = &rootname; + dp++; + } else if (dp[0] == '^') { + while (dp[0] == '^') { + newname = newname->parent; + CREATECHECK(); + dp++; + } + } + if (dp[0] == 0x00) { /* NullName */ + dp++; + } else if (dp[0] == 0x2e) { /* DualNamePrefix */ + newname = (*searchfunc) (newname, dp + 1); + CREATECHECK(); + newname = (*searchfunc) (newname, dp + 5); + CREATECHECK(); + } else if (dp[0] == 0x2f) { /* MultiNamePrefix */ + segcount = dp[1]; + for (i = 0, dp += 2; i < segcount; i++, dp += 4) { + newname = (*searchfunc) (newname, dp); + CREATECHECK(); + } + } else if (flag == AML_CREATE_NAME) { /* NameSeg */ + newname = aml_new_name(newname, dp); + CREATECHECK(); + } else { + curname = newname; + for (;;) { + newname = aml_find_name(curname, dp); + if (newname != NULL) + break; + if (curname == &rootname) + break; + curname = curname->parent; + } + } + return (newname); +} + +#undef CREATECHECK + +struct aml_local_stack * +aml_local_stack_create() +{ + struct aml_local_stack *result; + + result = memman_alloc(aml_memman, memid_aml_local_stack); + memset(result, 0, sizeof(struct aml_local_stack)); + return (result); +} + +void +aml_local_stack_push(struct aml_local_stack *stack) +{ + + stack->next = stack_top; + stack_top = stack; +} + +struct aml_local_stack * +aml_local_stack_pop() +{ + struct aml_local_stack *result; + + result = stack_top; + stack_top = result->next; + result->next = NULL; + return (result); +} + +void +aml_local_stack_delete(struct aml_local_stack *stack) +{ + int i; + + for (i = 0; i < 8; i++) + aml_free_object(&stack->localvalue[i].property); + for (i = 0; i < 7; i++) + aml_free_object(&stack->argumentvalue[i].property); + aml_delete_name(stack->temporary); + memman_free(aml_memman, memid_aml_local_stack, stack); +} + +struct aml_name * +aml_local_stack_getLocalX(int index) +{ + + if (stack_top == NULL) + return (NULL); + return (&stack_top->localvalue[index]); +} + +struct aml_name * +aml_local_stack_getArgX(struct aml_local_stack *stack, int index) +{ + + if (!stack) + stack = stack_top; + if (stack == NULL) + return (NULL); + return (&stack->argumentvalue[index]); +} + +struct aml_name * +aml_create_local_object() +{ + struct aml_name *result; + + result = memman_alloc(aml_memman, memid_aml_name); + result->child = result->brother = result->parent = NULL; + result->property = NULL; + result->chain = stack_top->temporary; + stack_top->temporary = result; + return (result); +} diff --git a/usr.sbin/acpidump/aml/aml_name.h b/usr.sbin/acpidump/aml/aml_name.h new file mode 100644 index 00000000000..87b89ba1c0e --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_name.h @@ -0,0 +1,89 @@ +/* $OpenBSD: aml_name.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Yasuo Yokoyama + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_name.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_name.h,v 1.2 2000/11/09 06:24:45 iwasaki Exp $ + */ + +#ifndef _AML_NAME_H_ +#define _AML_NAME_H_ + + +#include <aml/aml_obj.h> +#include <stdarg.h> + +struct aml_name { + char name[4]; + union aml_object *property; + struct aml_name *parent; + struct aml_name *brother; + struct aml_name *child; + struct aml_name *chain; +}; + +#define AML_NAME_GROUP_ROOT 0 +#define AML_NAME_GROUP_OS_DEFINED 1 +#define AML_NAME_GROUP_IN_METHOD 2 + +struct aml_name_group { + int id; /* DSDT address or DBHANDLE */ + struct aml_name *head; + struct aml_name_group *next; +}; + +struct aml_local_stack { + struct aml_name localvalue[8]; + struct aml_name argumentvalue[7]; + struct aml_name *temporary; + struct aml_local_stack *next; +}; + +/* forward declarement */ +struct aml_envrion; + +struct aml_name *aml_get_rootname(void); +struct aml_name_group *aml_new_name_group(int); +void aml_delete_name_group(struct aml_name_group *); + +struct aml_name *aml_find_from_namespace(struct aml_name *, char *); +void aml_apply_foreach_found_objects(struct aml_name *, + char *, int (*)(struct aml_name *, va_list), ...); +struct aml_name *aml_search_name(struct aml_environ *, u_int8_t *); +struct aml_name *aml_create_name(struct aml_environ *, u_int8_t *); + +struct aml_local_stack *aml_local_stack_create(void); +void aml_local_stack_push(struct aml_local_stack *); +struct aml_local_stack *aml_local_stack_pop(void); +void aml_local_stack_delete(struct aml_local_stack *); +struct aml_name *aml_local_stack_getLocalX(int); +struct aml_name *aml_local_stack_getArgX(struct aml_local_stack *, int); +struct aml_name *aml_create_local_object(void); + +extern struct aml_name_group *name_group_list; + +#endif /* !_AML_NAME_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_obj.c b/usr.sbin/acpidump/aml/aml_obj.c new file mode 100644 index 00000000000..e1de8967d48 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_obj.c @@ -0,0 +1,265 @@ +/* $OpenBSD: aml_obj.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_obj.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_obj.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ + */ + +#include <sys/types.h> + +#include <aml/aml_amlmem.h> +#include <aml/aml_env.h> +#include <aml/aml_name.h> +#include <aml/aml_obj.h> +#include <aml/aml_status.h> +#include <aml/aml_store.h> + +#ifndef _KERNEL +#include <sys/stat.h> +#include <sys/mman.h> + +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#else /* _KERNEL */ +#include <sys/systm.h> +#endif /* !_KERNEL */ + +union aml_object * +aml_copy_object(struct aml_environ *env, union aml_object *orig) +{ + int i; + union aml_object *ret; + + if (orig == NULL) + return (NULL); + switch (orig->type) { + case aml_t_regfield: + ret = aml_alloc_object(aml_t_buffer, 0); + ret->buffer.size = (orig->regfield.bitlen / 8) + + ((orig->regfield.bitlen % 8) ? 1 : 0); + if (ret->buffer.size == 0) { + goto out; + } + ret->buffer.data = memman_alloc_flexsize(aml_memman, ret->buffer.size); + aml_store_to_object(env, orig, ret); + break; + + default: + ret = aml_alloc_object(0, orig); + break; + } + + if (1 || orig != &env->tempobject) { /* XXX */ + if (orig->type == aml_t_buffer) { + if (orig->buffer.size == 0) { + goto out; + } + ret->buffer.data = memman_alloc_flexsize(aml_memman, + orig->buffer.size); + bcopy(orig->buffer.data, ret->buffer.data, orig->buffer.size); + } else if (orig->type == aml_t_package) { + if (ret->package.elements == 0) { + goto out; + } + ret->package.objects = memman_alloc_flexsize(aml_memman, + ret->package.elements * sizeof(union aml_object *)); + for (i = 0; i < ret->package.elements; i++) { + ret->package.objects[i] = aml_copy_object(env, orig->package.objects[i]); + } + } else if (orig->type == aml_t_string && orig->str.needfree != 0) { + ret->str.string = memman_alloc_flexsize(aml_memman, + strlen(orig->str.string) + 1); + strcpy(orig->str.string, ret->str.string); + } else if (orig->type == aml_t_num) { + ret->num.constant = 0; + } + } else { + printf("%s:%d\n", __FILE__, __LINE__); + env->tempobject.type = aml_t_null; + } +out: + return ret; +} + +/* + * This function have two function: copy or allocate. if orig != NULL, + * orig is duplicated. + */ + +union aml_object * +aml_alloc_object(enum aml_objtype type, union aml_object *orig) +{ + unsigned int memid; + union aml_object *ret; + + if (orig != NULL) { + type = orig->type; + } + switch (type) { + case aml_t_namestr: + memid = memid_aml_namestr; + break; + case aml_t_buffer: + memid = memid_aml_buffer; + break; + case aml_t_string: + memid = memid_aml_string; + break; + case aml_t_bufferfield: + memid = memid_aml_bufferfield; + break; + case aml_t_package: + memid = memid_aml_package; + break; + case aml_t_num: + memid = memid_aml_num; + break; + case aml_t_powerres: + memid = memid_aml_powerres; + break; + case aml_t_opregion: + memid = memid_aml_opregion; + break; + case aml_t_method: + memid = memid_aml_method; + break; + case aml_t_processor: + memid = memid_aml_processor; + break; + case aml_t_field: + memid = memid_aml_field; + break; + case aml_t_mutex: + memid = memid_aml_mutex; + break; + case aml_t_device: + memid = memid_aml_objtype; + break; + case aml_t_objref: + memid = memid_aml_objref; + break; + default: + memid = memid_aml_objtype; + break; + } + ret = memman_alloc(aml_memman, memid); + ret->type = type; + + if (orig != NULL) { + bcopy(orig, ret, memman_memid2size(aml_memman, memid)); + } + return (ret); +} + +void +aml_free_objectcontent(union aml_object *obj) +{ + int i; + + if (obj->type == aml_t_buffer && obj->buffer.data != NULL) { + memman_free_flexsize(aml_memman, obj->buffer.data); + obj->buffer.data = NULL; + } + if (obj->type == aml_t_string && obj->str.string != NULL) { + if (obj->str.needfree != 0) { + memman_free_flexsize(aml_memman, obj->str.string); + obj->str.string = NULL; + } + } + if (obj->type == aml_t_package && obj->package.objects != NULL) { + for (i = 0; i < obj->package.elements; i++) { + aml_free_object(&obj->package.objects[i]); + } + memman_free_flexsize(aml_memman, obj->package.objects); + obj->package.objects = NULL; + } +} + +void +aml_free_object(union aml_object **obj) +{ + union aml_object *body; + + body = *obj; + if (body == NULL) { + return; + } + aml_free_objectcontent(*obj); + memman_free(aml_memman, memid_unkown, *obj); + *obj = NULL; +} + +void +aml_realloc_object(union aml_object *obj, int size) +{ + int i; + enum aml_objtype type; + union aml_object tmp; + + type = obj->type; + switch (type) { + case aml_t_buffer: + if (obj->buffer.size >= size) { + return; + } + tmp.buffer.size = size; + tmp.buffer.data = memman_alloc_flexsize(aml_memman, size); + bzero(tmp.buffer.data, size); + bcopy(obj->buffer.data, tmp.buffer.data, obj->buffer.size); + aml_free_objectcontent(obj); + *obj = tmp; + break; + case aml_t_string: + if (strlen(obj->str.string) >= size) { + return; + } + tmp.str.string = memman_alloc_flexsize(aml_memman, size + 1); + strcpy(tmp.str.string, obj->str.string); + aml_free_objectcontent(obj); + *obj = tmp; + break; + case aml_t_package: + if (obj->package.elements >= size) { + return; + } + tmp.package.objects = memman_alloc_flexsize(aml_memman, + size * sizeof(union aml_object *)); + bzero(tmp.package.objects, size * sizeof(union aml_object *)); + for (i = 0; i < obj->package.elements; i++) { + tmp.package.objects[i] = obj->package.objects[i]; + } + memman_free_flexsize(aml_memman, obj->package.objects); + obj->package.objects = tmp.package.objects; + break; + default: + break; + } +} diff --git a/usr.sbin/acpidump/aml/aml_obj.h b/usr.sbin/acpidump/aml/aml_obj.h new file mode 100644 index 00000000000..c38404184ed --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_obj.h @@ -0,0 +1,232 @@ +/* $OpenBSD: aml_obj.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_obj.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_obj.h,v 1.1 2000/08/24 09:33:08 takawata Exp $ + */ + +#ifndef _AML_OBJ_H_ +#define _AML_OBJ_H_ + +#include <sys/queue.h> + +struct aml_environ; +enum aml_objtype { + aml_t_namestr = -3, + aml_t_regfield, + aml_t_objref, + aml_t_null = 0, + aml_t_num, + aml_t_string, + aml_t_buffer, + aml_t_package, + aml_t_device, + aml_t_field, + aml_t_event, + aml_t_method, + aml_t_mutex, + aml_t_opregion, + aml_t_powerres, + aml_t_processor, + aml_t_therm, + aml_t_bufferfield, + aml_t_ddbhandle, + aml_t_debug +}; + +struct aml_namestr { + enum aml_objtype type; /* =aml_t_namestr */ + u_int8_t *dp; +}; + +struct aml_opregion { + enum aml_objtype type; + int space; + int offset; + int length; +}; + +struct aml_num { + enum aml_objtype type; /* =aml_t_num */ + int number; + int constant; +}; + +struct aml_package { + enum aml_objtype type; + int elements; + union aml_object **objects; +}; + +struct aml_string { + enum aml_objtype type; /* =aml_t_string */ + int needfree; + u_int8_t *string; +}; + +struct aml_buffer { + enum aml_objtype type; /* =aml_t_buffer */ + int size; + u_int8_t *data; /* This should be free when + * this object is free. + */ +}; + +enum fieldtype { + f_t_field, + f_t_index, + f_t_bank +}; + +struct nfieldd { + enum fieldtype ftype; /* f_t_field */ + u_int8_t *regname; /* Namestring */ +}; + +struct ifieldd { + enum fieldtype ftype; /* f_t_index */ + u_int8_t *indexname; + u_int8_t *dataname; +}; + +struct bfieldd { + enum fieldtype ftype; /* f_t_bank */ + u_int8_t *regname; + u_int8_t *bankname; + u_int32_t bankvalue; +}; + +struct aml_field { + enum aml_objtype type; + u_int32_t flags; + int bitoffset; /* Not Byte offset but bitoffset */ + int bitlen; + union { + enum fieldtype ftype; + struct nfieldd fld; + struct ifieldd ifld; + struct bfieldd bfld; + } f; +}; + +struct aml_bufferfield { + enum aml_objtype type; /* aml_t_bufferfield */ + int bitoffset; + int bitlen; + u_int8_t *origin; /* This should not be free + * when this object is free + * (Within Buffer object) + */ +}; + +struct aml_method { + enum aml_objtype type; + int argnum; /* Not argnum but argnum|frag */ + u_int8_t *from; + u_int8_t *to; +}; + +struct aml_powerres { + enum aml_objtype type; + int level; + int order; +}; + +struct aml_processor { + enum aml_objtype type; + int id; + int addr; + int len; +}; + +struct aml_mutex_queue { +#if 0 + STAILQ_ENTRY(aml_mutex_queue) entry; +#endif +}; + +struct aml_mutex { + enum aml_objtype type; + int level; + volatile void *cookie; /* In kernel, struct proc? */ +#if 0 + STAILQ_HEAD(, aml_mutex_queue) queue; +#endif +}; + +struct aml_objref { + enum aml_objtype type; + struct aml_name *nameref; + union aml_object *ref; + int offset; /* of aml_buffer.data or aml_package.objects. */ + /* if negative value, not ready to dereference for element access. */ + unsigned deref; /* indicates whether dereffenced or not */ + unsigned alias; /* true if this is an alias object reference */ +}; + +struct aml_regfield { + enum aml_objtype type; + int space; + u_int32_t flags; + int offset; + int bitoffset; + int bitlen; +}; + +struct aml_event { + enum aml_objtype type; /* aml_t_event */ + int inuse; +}; + +union aml_object { + enum aml_objtype type; + struct aml_num num; + struct aml_processor proc; + struct aml_powerres pres; + struct aml_opregion opregion; + struct aml_method meth; + struct aml_field field; + struct aml_mutex mutex; + struct aml_namestr nstr; + struct aml_buffer buffer; + struct aml_bufferfield bfld; + struct aml_package package; + struct aml_string str; + struct aml_objref objref; + struct aml_event event; + struct aml_regfield regfield; +}; + +union aml_object *aml_copy_object(struct aml_environ *, + union aml_object *); +union aml_object *aml_alloc_object(enum aml_objtype, + union aml_object *); +void aml_free_objectcontent(union aml_object *); +void aml_free_object(union aml_object **); +void aml_realloc_object(union aml_object *, int); + +#endif /* !_AML_OBJ_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_parse.c b/usr.sbin/acpidump/aml/aml_parse.c new file mode 100644 index 00000000000..0da801de5cd --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_parse.c @@ -0,0 +1,2023 @@ +/* $OpenBSD: aml_parse.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Doug Rabson + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_parse.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_parse.c,v 1.7 2001/10/23 14:54:15 takawata Exp $ + */ + +#include <sys/param.h> + +#include <aml/aml_amlmem.h> +#include <aml/aml_common.h> +#include <aml/aml_env.h> +#include <aml/aml_evalobj.h> +#include <aml/aml_name.h> +#include <aml/aml_obj.h> +#include <aml/aml_parse.h> +#include <aml/aml_status.h> +#include <aml/aml_store.h> + +#ifndef _KERNEL +#include <sys/stat.h> +#include <sys/mman.h> + +#include <assert.h> +#include <err.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "debug.h" +#else /* _KERNEL */ +#include <sys/systm.h> +#include <sys/bus.h> +#include <machine/bus.h> +#include <dev/acpi/acpireg.h> +#include <dev/acpi/acpivar.h> +#ifndef ACPI_NO_OSDFUNC_INLINE +#include <machine/acpica_osd.h> +#endif +#endif /* !_KERNEL */ + +static int findsetleftbit(int num); +static int findsetrightbit(int num); +static int frombcd(int num); +static int tobcd(int num); + +static u_int32_t aml_parse_pkglength(struct aml_environ *env); +static u_int8_t aml_parse_bytedata(struct aml_environ *env); +static u_int16_t aml_parse_worddata(struct aml_environ *env); +static u_int32_t aml_parse_dworddata(struct aml_environ *env); +static u_int8_t *aml_parse_namestring(struct aml_environ *env); +static void aml_parse_defscope(struct aml_environ *env, + int indent); +static union aml_object *aml_parse_defbuffer(struct aml_environ *env, + int indent); +static struct aml_name *aml_parse_concat_number(struct aml_environ *env, + int num1, int indent); +static struct aml_name *aml_parse_concat_buffer(struct aml_environ *env, + union aml_object *obj, + int indent); +static struct aml_name *aml_parse_concat_string(struct aml_environ *env, + union aml_object *obj, + int indent); +static struct aml_name *aml_parse_concatop(struct aml_environ *env, + int indent); +static union aml_object *aml_parse_defpackage(struct aml_environ *env, + int indent); +static void aml_parse_defmethod(struct aml_environ *env, + int indent); +static void aml_parse_defopregion(struct aml_environ *env, + int indent); +static int aml_parse_field(struct aml_environ *env, + struct aml_field *template); +static void aml_parse_fieldlist(struct aml_environ *env, + struct aml_field *template, + int indent); +static void aml_parse_deffield(struct aml_environ *env, + int indent); +static void aml_parse_defindexfield(struct aml_environ *env, + int indent); +static void aml_parse_defbankfield(struct aml_environ *env, + int indent); +static void aml_parse_defdevice(struct aml_environ *env, + int indent); +static void aml_parse_defprocessor(struct aml_environ *env, + int indent); +static void aml_parse_defpowerres(struct aml_environ *env, + int indent); +static void aml_parse_defthermalzone(struct aml_environ *env, + int indent); +static struct aml_name *aml_parse_defelse(struct aml_environ *env, + int indent, int num); +static struct aml_name *aml_parse_defif(struct aml_environ *env, + int indent); +static struct aml_name *aml_parse_defwhile(struct aml_environ *env, + int indent); +static void aml_parse_defmutex(struct aml_environ *env, + int indent); +static void aml_createfield_generic(struct aml_environ *env, + union aml_object *srcbuf, + int index, int len, + char *newname); +static void aml_parse_defcreatefield(struct aml_environ *env, + int indent); + +static int +findsetleftbit(int num) +{ + int i, filter; + + filter = 0; + for (i = 0; i < 32; i++) { + filter = filter >> 1; + filter |= 1 << 31; + if (filter & num) { + break; + } + } + i = (i == 32) ? 0 : i + 1; + return (i); +} + +static int +findsetrightbit(int num) +{ + int i, filter; + + filter = 0; + for (i = 0; i < 32; i++) { + filter = filter << 1; + filter |= 1; + if (filter & num) { + break; + } + } + i = (i == 32) ? 0 : i + 1; + return (i); +} + +static int +frombcd(int num) +{ + int res, factor; + + res = 0; + factor = 1; + while (num != 0) { + res += ((num & 0xf) * factor); + num = num / 16; + factor *= 10; + } + return (res); +} + +static int +tobcd(int num) +{ + int res, factor; + + res = 0; + factor = 1; + while (num != 0) { + res += ((num % 10) * factor); + num = num / 10; + factor *= 16; + } + return (res); +} + +static u_int32_t +aml_parse_pkglength(struct aml_environ *env) +{ + u_int8_t *dp; + u_int32_t pkglength; + + dp = env->dp; + pkglength = *dp++; + switch (pkglength >> 6) { + case 0: + break; + case 1: + pkglength = (pkglength & 0xf) + (dp[0] << 4); + dp += 1; + break; + case 2: + pkglength = (pkglength & 0xf) + (dp[0] << 4) + (dp[1] << 12); + dp += 2; + break; + case 3: + pkglength = (pkglength & 0xf) + + (dp[0] << 4) + (dp[1] << 12) + (dp[2] << 20); + dp += 3; + break; + } + + env->dp = dp; + return (pkglength); +} + +static u_int8_t +aml_parse_bytedata(struct aml_environ *env) +{ + u_int8_t data; + + data = env->dp[0]; + env->dp++; + return (data); +} + +static u_int16_t +aml_parse_worddata(struct aml_environ *env) +{ + u_int16_t data; + + data = env->dp[0] + (env->dp[1] << 8); + env->dp += 2; + return (data); +} + +static u_int32_t +aml_parse_dworddata(struct aml_environ *env) +{ + u_int32_t data; + + data = env->dp[0] + (env->dp[1] << 8) + + (env->dp[2] << 16) + (env->dp[3] << 24); + env->dp += 4; + return (data); +} + +static u_int8_t * +aml_parse_namestring(struct aml_environ *env) +{ + u_int8_t *name; + int segcount; + + name = env->dp; + if (env->dp[0] == '\\') + env->dp++; + else if (env->dp[0] == '^') + while (env->dp[0] == '^') + env->dp++; + if (env->dp[0] == 0x00) /* NullName */ + env->dp++; + else if (env->dp[0] == 0x2e) /* DualNamePrefix */ + env->dp += 1 + 4 + 4; /* NameSeg, NameSeg */ + else if (env->dp[0] == 0x2f) { /* MultiNamePrefix */ + segcount = env->dp[1]; + env->dp += 1 + 1 + segcount * 4; /* segcount * NameSeg */ + } else + env->dp += 4; /* NameSeg */ + + return (name); +} + +struct aml_name * +aml_parse_objectlist(struct aml_environ *env, int indent) +{ + union aml_object *obj; + + obj = NULL; + while (env->dp < env->end) { + aml_print_indent(indent); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); + AML_DEBUGPRINT("\n"); + if (env->stat == aml_stat_step) { + AML_DEBUGGER(env, env); + continue; + } + if (env->stat != aml_stat_none) { + env->tempname.property = obj; + return (&env->tempname); + } + } + return (NULL); +} + +#define AML_CREATE_NAME(amlname, env, namestr, ret) do { \ + amlname = aml_create_name(env, namestr); \ + if (env->stat == aml_stat_panic) \ + return ret; \ +} while(0) + +#define AML_COPY_OBJECT(dest, env, src, ret) do { \ + dest = aml_copy_object(env, src); \ + if (dest == NULL) { \ + env->stat = aml_stat_panic; \ + return ret; \ + } \ +} while(0) + +#define AML_ALLOC_OBJECT(dest, env, type, ret) do { \ + dest = aml_alloc_object(type, NULL); \ + if (dest == NULL) { \ + env->stat= aml_stat_panic; \ + return ret; \ + } \ +} while(0) + +static void +aml_parse_defscope(struct aml_environ *env, int indent) +{ + u_int8_t *start, *end, *oend; + u_int8_t *name; + u_int32_t pkglength; + struct aml_name *oname; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + + AML_DEBUGPRINT("Scope("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_DEBUGPRINT(") {\n"); + oname = env->curname; + AML_CREATE_NAME(env->curname, env, name,); + oend = env->end; + env->end = end = start + pkglength; + aml_parse_objectlist(env, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + AML_SYSASSERT(env->dp == env->end); + env->dp = end; + env->end = oend; + env->curname = oname; + env->stat = aml_stat_none; +} + +static union aml_object * +aml_parse_defbuffer(struct aml_environ *env, int indent) +{ + u_int8_t *start; + u_int8_t *end; + u_int8_t *buffer; + u_int32_t pkglength; + int size1, size2, size; + union aml_object *obj; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + end = start + pkglength; + + AML_DEBUGPRINT("Buffer("); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); + size1 = aml_objtonum(env, obj); + size2 = end - env->dp; + size = (size1 < size2) ? size1 : size2; + if (size1 > 0) { + buffer = memman_alloc_flexsize(aml_memman, size1); + if (buffer == NULL) { + AML_DEBUGPRINT("NO MEMORY\n"); + env->stat = aml_stat_panic; + return (NULL); + } + bzero(buffer, size1); + bcopy(env->dp, buffer, size); + } else { + buffer = NULL; + } + + obj = &env->tempobject; + obj->type = aml_t_buffer; + obj->buffer.size = size1; + obj->buffer.data = buffer; + AML_DEBUGPRINT(") "); + env->dp = end; + + return (obj); +} + +static struct aml_name * +aml_parse_concat_number(struct aml_environ *env, int num1, int indent) +{ + int num2; + struct aml_name *destname; + union aml_object *obj; + + num2 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(", "); + destname = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + obj = &env->tempobject; + obj->type = aml_t_buffer; + obj->buffer.size = 2; + obj->buffer.data = memman_alloc_flexsize(aml_memman, 2); + if (obj->buffer.data == NULL) { + env->stat = aml_stat_panic; + return (NULL); + } + obj->buffer.data[0] = num1 & 0xff; + obj->buffer.data[1] = num2 & 0xff; + aml_store_to_name(env, obj, destname); + return (&env->tempname); +} + +static struct aml_name * +aml_parse_concat_buffer(struct aml_environ *env, union aml_object *obj, + int indent) +{ + union aml_object *tmpobj, *tmpobj2, *resobj; + struct aml_name *destname; + + tmpobj = aml_eval_name(env, aml_parse_termobj(env, indent)); + AML_DEBUGPRINT(", "); + if (tmpobj->type != aml_t_buffer) { + env->stat = aml_stat_panic; + return (NULL); + } + AML_COPY_OBJECT(tmpobj2, env, tmpobj, NULL); + destname = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + resobj = &env->tempobject; + env->tempname.property = resobj; + resobj->buffer.type = aml_t_buffer; + resobj->buffer.size = tmpobj2->buffer.size + obj->buffer.size; + if (resobj->buffer.size > 0) { + resobj->buffer.data = memman_alloc_flexsize(aml_memman, + resobj->buffer.size); + if (resobj->buffer.data == NULL) { + env->stat = aml_stat_panic; + return (NULL); + } + bcopy(obj->buffer.data, resobj->buffer.data, obj->buffer.size); + bcopy(tmpobj2->buffer.data, + resobj->buffer.data + obj->buffer.size, + tmpobj2->buffer.size); + } else { + resobj->buffer.data = NULL; + } + aml_free_object(&tmpobj2); + aml_store_to_name(env, resobj, destname); + return (&env->tempname); +} + +static struct aml_name * +aml_parse_concat_string(struct aml_environ *env, union aml_object *obj, + int indent) +{ + int len; + union aml_object *tmpobj, *tmpobj2, *resobj; + struct aml_name *destname; + + tmpobj = aml_eval_name(env, aml_parse_termobj(env, indent)); + AML_DEBUGPRINT(", "); + if (tmpobj->type != aml_t_string) { + env->stat = aml_stat_panic; + return (NULL); + } + AML_COPY_OBJECT(tmpobj2, env, tmpobj, NULL); + destname = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + resobj = &env->tempobject; + env->tempname.property = resobj; + resobj->type = aml_t_buffer; + resobj->str.needfree = 1; + len = strlen(obj->str.string) + strlen(tmpobj2->str.string) + 1; + if (len > 0) { + resobj->str.string = memman_alloc_flexsize(aml_memman, len); + if (resobj->str.string == NULL) { + env->stat = aml_stat_panic; + return (NULL); + } + strncpy(resobj->str.string, obj->str.string, len); + strcat(resobj->str.string, tmpobj->str.string); + } else { + resobj->str.string = NULL; + } + aml_free_object(&tmpobj2); + aml_store_to_name(env, resobj, destname); + return (&env->tempname); +} + +static struct aml_name * +aml_parse_concatop(struct aml_environ *env, int indent) +{ + union aml_object *obj, *tmpobj; + struct aml_name *aname; + + AML_DEBUGPRINT("Concat("); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); + AML_DEBUGPRINT(", "); + switch (obj->type) { + case aml_t_num: + aname = aml_parse_concat_number(env, aml_objtonum(env, obj), indent); + break; + + case aml_t_buffer: + /* obj may be temporal object */ + AML_COPY_OBJECT(tmpobj, env, obj, NULL); + aname = aml_parse_concat_buffer(env, obj, indent); + aml_free_object(&tmpobj); + break; + + case aml_t_string: + /* obj may be temporal object */ + AML_COPY_OBJECT(tmpobj, env, obj, NULL); + aname = aml_parse_concat_string(env, obj, indent); + aml_free_object(&tmpobj); + break; + + default: + env->stat = aml_stat_panic; + aname = NULL; + break; + } + + AML_DEBUGPRINT("\n"); + return (aname); +} + +static union aml_object * +aml_parse_defpackage(struct aml_environ *env, int indent) +{ + u_int8_t numelements; + u_int8_t *start; + u_int32_t pkglength; + int i; + struct aml_environ *copy; + struct aml_name *tmpname; + union aml_object *obj, **objects; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + numelements = aml_parse_bytedata(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return (NULL); + } + if (numelements > 0) { + objects = memman_alloc_flexsize(aml_memman, + numelements * sizeof(union aml_object *)); + if (objects == NULL) { + env->stat = aml_stat_panic; + return (NULL); + } else { + bzero(objects, numelements * sizeof(union aml_object *)); + } + } else { + objects = NULL; + } + + *copy = *env; + env->dp = copy->end = start + pkglength; + AML_DEBUGPRINT("Package() {\n"); + i = 0; + while ((copy->dp < copy->end) && (i < numelements)) { + aml_print_indent(indent + 1); + tmpname = aml_parse_termobj(copy, indent + 1); + + if (tmpname != NULL) { + objects[i] = aml_copy_object(copy, tmpname->property); + } + AML_DEBUGPRINT(",\n"); + i++; + } + aml_free_objectcontent(©->tempobject); + + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + obj = &env->tempobject; + obj->type = aml_t_package; + obj->package.elements = numelements; + obj->package.objects = objects; + + memman_free(aml_memman, memid_aml_environ, copy); + return (obj); +} + +static void +aml_parse_defmethod(struct aml_environ *env, int indent) +{ + u_int8_t flags; + u_int8_t *start; + u_int32_t pkglength; + char *name; + struct aml_environ *copy; + struct aml_method *meth; + struct aml_name *aname; + union aml_object *aobj; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("Method("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name,); + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + goto out; + } + AML_ALLOC_OBJECT(aobj, env, aml_t_method,); + meth = &aobj->meth; + aname->property = aobj; + flags = *env->dp++; + + if (flags) { + AML_DEBUGPRINT(", %d", flags); + } + AML_DEBUGPRINT(") {\n"); + *copy = *env; + meth->argnum = flags; + meth->from = env->dp; + meth->to = env->dp = copy->end = start + pkglength; + aml_print_indent(indent); + AML_DEBUGPRINT("}"); +out: + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defopregion(struct aml_environ *env, int indent) +{ + u_int8_t *name; + struct aml_name *aname; + struct aml_opregion *opregion; + union aml_object *obj; + const char *regions[] = { + "SystemMemory", + "SystemIO", + "PCI_Config", + "EmbeddedControl", + "SMBus", + }; + + AML_DEBUGPRINT("OperationRegion("); + /* Name */ + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name,); + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + return; + } + AML_ALLOC_OBJECT(aname->property, env, aml_t_opregion,); + opregion = &aname->property->opregion; + opregion->space = *env->dp; + AML_DEBUGPRINT(", %s, ", regions[*env->dp]); /* Space */ + env->dp++; + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); /* Offset */ + opregion->offset = aml_objtonum(env, obj); + AML_DEBUGPRINT(", "); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); /* Length */ + opregion->length = aml_objtonum(env, obj); + AML_DEBUGPRINT(")"); +} + +static const char *accessnames[] = { + "AnyAcc", + "ByteAcc", + "WordAcc", + "DWordAcc", + "BlockAcc", + "SMBSendRecvAcc", + "SMBQuickAcc" +}; + +static int +aml_parse_field(struct aml_environ *env, struct aml_field *template) +{ + u_int8_t *name; + u_int8_t access, attribute; + u_int32_t width; + struct aml_name *aname; + struct aml_field *prop; + + switch (*env->dp) { + case '\\': + case '^': + case 'A'...'Z': + case '_': + case '.': + case '/': + name = aml_parse_namestring(env); + width = aml_parse_pkglength(env); + template->bitlen = width; + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name, NULL); + /* Allignment */ + if (width == 16) { + template->bitoffset += 15; + template->bitoffset &= (~15); + } + if (width == 32) { + template->bitoffset += 31; + template->bitoffset &= (~31); + } else if ((width & 7) == 0) { + template->bitoffset += 7; + template->bitoffset &= (~7); + } else if ((width > 32) && (width & 7) != 0) { + AML_DEBUGPRINT("??? Can I treat it?\n"); + } + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + return (NULL); + } + AML_ALLOC_OBJECT(aname->property, env, aml_t_field, NULL); + prop = &aname->property->field; + *prop = *template; + template->bitoffset += width; + AML_DEBUGPRINT(",\t%d", width); + break; + case 0x00: + env->dp++; + width = aml_parse_pkglength(env); + template->bitoffset += width; + AML_DEBUGPRINT("Offset(0x%x)", template->bitoffset); + break; + case 0x01: + access = env->dp[1]; + attribute = env->dp[2]; + env->dp += 3; + AML_DEBUGPRINT("AccessAs(%s, %d)", accessnames[access], attribute); + template->bitoffset = attribute; + template->flags = (template->flags | 0xf0) | access; + break; + } + return (template->bitoffset); +} + +static void +aml_parse_fieldlist(struct aml_environ *env, struct aml_field *template, + int indent) +{ + u_int32_t offset; + + offset = 0; + while (env->dp < env->end) { + aml_print_indent(indent); + offset = aml_parse_field(env, template); + if (env->dp < env->end) { + AML_DEBUGPRINT(",\n"); + } else { + AML_DEBUGPRINT("\n"); + } + } +} + +static void +aml_parse_deffield(struct aml_environ *env, int indent) +{ + u_int8_t flags; + u_int8_t *start, *name; + u_int32_t pkglength; + struct aml_environ *copy; + struct aml_field fieldtemplate; + static const char *lockrules[] = {"NoLock", "Lock"}; + static const char *updaterules[] = {"Preserve", "WriteAsOnes", + "WriteAsZeros", "*Error*"}; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("Field("); + aml_print_namestring(name = aml_parse_namestring(env)); + fieldtemplate.type = aml_t_field; + flags = aml_parse_bytedata(env); + fieldtemplate.flags = fieldtemplate.flags = flags; + + *copy = *env; + env->dp = copy->end = start + pkglength; + fieldtemplate.bitoffset = 0; + fieldtemplate.bitlen = 0; + fieldtemplate.f.ftype = f_t_field; + fieldtemplate.f.fld.regname = name; + AML_DEBUGPRINT(", %s, %s, %s) {\n", + accessnames[flags & 0xf], + lockrules[(flags >> 4) & 1], + updaterules[(flags >> 5) & 3]); + aml_parse_fieldlist(copy, &fieldtemplate, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + aml_free_objectcontent(©->tempobject); + + AML_SYSASSERT(copy->dp == copy->end); + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defindexfield(struct aml_environ *env, int indent) +{ + u_int8_t flags; + u_int8_t *start, *iname, *dname; + u_int32_t pkglength; + struct aml_environ *copy; + struct aml_field template; + static const char *lockrules[] = {"NoLock", "Lock"}; + static const char *updaterules[] = {"Preserve", "WriteAsOnes", + "WriteAsZeros", "*Error*"}; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("IndexField("); + aml_print_namestring(iname = aml_parse_namestring(env)); /* Name1 */ + AML_DEBUGPRINT(", "); + aml_print_namestring(dname = aml_parse_namestring(env)); /* Name2 */ + template.type = aml_t_field; + template.flags = flags = aml_parse_bytedata(env); + template.bitoffset = 0; + template.bitlen = 0; + template.f.ftype = f_t_index; + template.f.ifld.indexname = iname; + template.f.ifld.dataname = dname; + AML_DEBUGPRINT(", %s, %s, %s) {\n", + accessnames[flags & 0xf], + lockrules[(flags >> 4) & 1], + updaterules[(flags >> 5) & 3]); + *copy = *env; + env->dp = copy->end = start + pkglength; + aml_parse_fieldlist(copy, &template, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + aml_free_objectcontent(©->tempobject); + + AML_SYSASSERT(copy->dp == copy->end); + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defbankfield(struct aml_environ *env, int indent) +{ + u_int8_t flags; + u_int8_t *start, *rname, *bname; + u_int32_t pkglength, bankvalue; + struct aml_environ *copy; + struct aml_field template; + union aml_object *obj; + static const char *lockrules[] = {"NoLock", "Lock"}; + static const char *updaterules[] = {"Preserve", "WriteAsOnes", + "WriteAsZeros", "*Error*"}; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("BankField("); + aml_print_namestring(rname = aml_parse_namestring(env)); /* Name1 */ + AML_DEBUGPRINT(", "); + aml_print_namestring(bname = aml_parse_namestring(env)); /* Name2 */ + AML_DEBUGPRINT(", "); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); /* BankValue */ + bankvalue = aml_objtonum(env, obj); + template.type = aml_t_field; + template.flags = flags = aml_parse_bytedata(env); + template.bitoffset = 0; + template.bitlen = 0; + template.f.ftype = f_t_bank; + template.f.bfld.regname = rname; + template.f.bfld.bankname = bname; + template.f.bfld.bankvalue = bankvalue; + *copy = *env; + env->dp = copy->end = start + pkglength; + AML_DEBUGPRINT(", %s, %s, %s) {\n", + accessnames[flags & 0xf], + lockrules[(flags >> 4) & 1], + updaterules[(flags >> 5) & 3]); + aml_parse_fieldlist(copy, &template, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + + aml_free_objectcontent(©->tempobject); + AML_SYSASSERT(copy->dp == copy->end); + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defdevice(struct aml_environ *env, int indent) +{ + u_int8_t *start; + u_int8_t *name; + u_int32_t pkglength; + struct aml_environ *copy; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("Device("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_DEBUGPRINT(") {\n"); + *copy = *env; + AML_CREATE_NAME(copy->curname, env, name,); + if (copy->curname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + goto out; + } + AML_ALLOC_OBJECT(copy->curname->property, env, aml_t_device,); + env->dp = copy->end = start + pkglength; + aml_parse_objectlist(copy, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + aml_free_objectcontent(©->tempobject); + + AML_SYSASSERT(copy->dp == copy->end); +out: + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defprocessor(struct aml_environ *env, int indent) +{ + u_int8_t *start; + u_int8_t *name; + u_int32_t pkglength; + struct aml_environ *copy; + struct aml_processor *proc; + union aml_object *obj; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_ALLOC_OBJECT(obj, env, aml_t_processor,); + proc = &obj->proc; + AML_DEBUGPRINT("Processor("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + proc->id = aml_parse_bytedata(env); + proc->addr = aml_parse_dworddata(env); + proc->len = aml_parse_bytedata(env); + AML_DEBUGPRINT(", %d, 0x%x, 0x%x) {\n", proc->id, proc->addr, proc->len); + *copy = *env; + AML_CREATE_NAME(copy->curname, env, name,); + if (copy->curname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + goto out; + } + copy->curname->property = obj; + env->dp = copy->end = start + pkglength; + aml_parse_objectlist(copy, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + aml_free_objectcontent(©->tempobject); + + AML_SYSASSERT(copy->dp == copy->end); +out: + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defpowerres(struct aml_environ *env, int indent) +{ + u_int8_t *start; + u_int8_t *name; + u_int32_t pkglength; + struct aml_environ *copy; + struct aml_powerres *pres; + union aml_object *obj; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("PowerResource("); + AML_ALLOC_OBJECT(obj, env, aml_t_powerres,); + name = aml_parse_namestring(env); + aml_print_namestring(name); + pres = &obj->pres; + pres->level = aml_parse_bytedata(env); + pres->order = aml_parse_worddata(env); + AML_DEBUGPRINT(", %d, %d) {\n", pres->level, pres->order); + *copy = *env; + AML_CREATE_NAME(copy->curname, env, name,); + if (copy->curname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + goto out; + } + copy->curname->property = obj; + env->dp = copy->end = start + pkglength; + + aml_parse_objectlist(copy, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + aml_free_objectcontent(©->tempobject); + + AML_SYSASSERT(copy->dp == copy->end); +out: + memman_free(aml_memman, memid_aml_environ, copy); +} + +static void +aml_parse_defthermalzone(struct aml_environ *env, int indent) +{ + u_int8_t *start; + u_int8_t *name; + u_int32_t pkglength; + struct aml_environ *copy; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + copy = memman_alloc(aml_memman, memid_aml_environ); + if (copy == NULL) { + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT("ThermalZone("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_DEBUGPRINT(") {\n"); + *copy = *env; + AML_CREATE_NAME(copy->curname, env, name,); + if (copy->curname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + goto out; + } + AML_ALLOC_OBJECT(copy->curname->property, env, aml_t_therm,); + env->dp = copy->end = start + pkglength; + aml_parse_objectlist(copy, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + aml_free_objectcontent(©->tempobject); + AML_SYSASSERT(copy->dp == copy->end); +out: + memman_free(aml_memman, memid_aml_environ, copy); +} + +static struct aml_name * +aml_parse_defelse(struct aml_environ *env, int indent, int num) +{ + u_int8_t *start, *end, *oend; + u_int32_t pkglength; + struct aml_name *aname; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + oend = env->end; + env->end = end = start + pkglength; + aname = NULL; + + AML_DEBUGPRINT("Else {\n"); + if (num == 0) { + aname = aml_parse_objectlist(env, indent + 1); + aml_print_indent(indent); + } + AML_DEBUGPRINT("}"); + + env->dp = end; + env->end = oend; + return (aname); +} + +static struct aml_name * +aml_parse_defif(struct aml_environ *env, int indent) +{ + u_int8_t *start, *end, *oend; + u_int32_t pkglength; + int num; + struct aml_name *aname, *aname1; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + aname = NULL; + + AML_DEBUGPRINT("If("); + num = aml_objtonum(env, aml_eval_name + (env, aml_parse_termobj(env, indent))); + oend = env->end; + end = start + pkglength; + AML_DEBUGPRINT(")"); + if (num) { + AML_DEBUGPRINT("{\n"); + env->end = end; + aname = aml_parse_objectlist(env, indent + 1); + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + } + env->dp = end; + env->end = oend; + if ((end < oend) && *(env->dp) == 0xa1) { + env->dp++; + aname1 = aml_parse_defelse(env, indent, num); + aname = (num == 0) ? aname1 : aname; + } + return (aname); +} + +static struct aml_name * +aml_parse_defwhile(struct aml_environ *env, int indent) +{ + u_int8_t *start, *end, *oend; + u_int32_t pkglength; + int num; + struct aml_name *aname; + + start = env->dp; + pkglength = aml_parse_pkglength(env); + oend = env->end; + end = start + pkglength; + aname = NULL; + for (;;) { + env->dp = start; + aml_parse_pkglength(env); + AML_DEBUGPRINT("While("); + num = aml_objtonum(env, aml_eval_name + (env, aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(")"); + if (num == 0) { + break; + } + AML_DEBUGPRINT(" {\n"); + env->end = end; + aname = aml_parse_objectlist(env, indent + 1); + if (env->stat == aml_stat_step) { + AML_DEBUGGER(env, env); + continue; + } + if (env->stat != aml_stat_none) + break; + aml_print_indent(indent); + AML_DEBUGPRINT("}"); + } + AML_DEBUGPRINT("\n"); + env->dp = end; + env->end = oend; + if (env->stat == aml_stat_break) { + env->stat = aml_stat_none; + aname = NULL; + } + return (aname); +} + +static void +aml_parse_defmutex(struct aml_environ *env, int indent) +{ + char *name; + struct aml_name *aname; + struct aml_mutex *mut; + + /* MutexOp */ + AML_DEBUGPRINT("Mutex("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name,); + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + return; + } + AML_ALLOC_OBJECT(aname->property, env, aml_t_mutex,); + mut = &aname->property->mutex; + mut->level = *env->dp++; +#if 0 + STAILQ_INIT(&mut->queue); +#endif + AML_DEBUGPRINT(", %d)", mut->level); +} + +static void +aml_createfield_generic(struct aml_environ *env, + union aml_object *srcbuf, int index, + int len, char *newname) +{ + struct aml_bufferfield *field; + struct aml_name *aname; + + if (srcbuf == NULL || srcbuf->type != aml_t_buffer) { + AML_DEBUGPRINT("Not Buffer assigned,"); + env->stat = aml_stat_panic; + return; + } + AML_CREATE_NAME(aname, env, newname,); + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + return; + } + AML_ALLOC_OBJECT(aname->property, env, aml_t_bufferfield,); + field = &aname->property->bfld; + field->bitoffset = index; + field->bitlen = len; + field->origin = srcbuf->buffer.data; +} + +static void +aml_parse_defcreatefield(struct aml_environ *env, int indent) +{ + int index, len; + char *newname; + union aml_object *obj, *srcbuf; + + /* CreateFieldOp */ + AML_DEBUGPRINT("CreateField("); + srcbuf = aml_eval_name(env, aml_parse_termobj(env, indent)); + if (srcbuf == &env->tempobject) { + AML_DEBUGPRINT("NONAMED BUFFER\n"); + env->stat = aml_stat_panic; + return; + } + AML_DEBUGPRINT(", "); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); + index = aml_objtonum(env, obj); + AML_DEBUGPRINT(", "); + obj = aml_eval_name(env, aml_parse_termobj(env, indent)); + len = aml_objtonum(env, obj); + AML_DEBUGPRINT(", "); + newname = aml_parse_namestring(env); + aml_print_namestring(newname); + aml_createfield_generic(env, srcbuf, index, len, newname); + AML_DEBUGPRINT(") "); +} + +/* + * Returns Named object or parser buffer. The object need not be free because + * it returns preallocated buffer in env or Contain of named object. If You + * need to preserve object, create a copy and then store. And The object + * returned from this function is not valid after another call is + * shared, tempolary buffer may be shared. + */ +struct aml_name * +aml_parse_termobj(struct aml_environ *env, int indent) +{ + u_int8_t opcode; + u_int8_t *name; + int value; + int num1, num2; + int len; + int match1, match2, i, pkgval, start; + int widthindex, index; + char *newname; + struct aml_name *aname; + struct aml_name *destname1, *destname2; + struct aml_name *tmpname, *srcname; + struct aml_name *src; + union aml_object *ret; + union aml_object *tmpobj; + union aml_object anum; + union aml_object *objref; + union aml_object *srcobj; + union aml_object *obj; + union aml_object *srcbuf; + static int widthtbl[4] = {32, 16, 8, 1}; + const char *opname[4] = {"CreateDWordField", "CreateWordField", + "CreateByteField", "CreateBitField"}; + + aname = &env->tempname; + ret = &env->tempobject; + anum.type = aml_t_num; + aname->property = ret; + aml_free_objectcontent(ret); + if (env->stat == aml_stat_panic) { + /* + * If previosuly parser panic , parsing next instruction is + * prohibited. + */ + return (NULL); + } + aname = NULL; + opcode = *env->dp++; + switch (opcode) { + case '\\': + case '^': + case 'A' ... 'Z': + case '_': + case '.': + case '/': + env->dp--; + ret->type = aml_t_namestr; + ret->nstr.dp = aml_parse_namestring(env); + aml_print_namestring(ret->nstr.dp); + aname = &env->tempname; + break; + case 0x0a: /* BytePrefix */ + ret->type = aml_t_num; + value = aml_parse_bytedata(env); + ret->num.number = value; + AML_DEBUGPRINT("0x%x", value); + aname = &env->tempname; + break; + case 0x0b: /* WordPrefix */ + ret->type = aml_t_num; + value = aml_parse_worddata(env); + ret->num.number = value; + AML_DEBUGPRINT("0x%x", value); + aname = &env->tempname; + break; + case 0x0c: /* DWordPrefix */ + ret->type = aml_t_num; + value = aml_parse_dworddata(env); + ret->num.number = value; + AML_DEBUGPRINT("0x%x", value); + aname = &env->tempname; + break; + case 0x0d: /* StringPrefix */ + ret->type = aml_t_string; + ret->str.string = env->dp; + len = strlen(env->dp); + ret->str.needfree = 0; + AML_DEBUGPRINT("\"%s\"", (const char *)ret->str.string); + env->dp += (len + 1); + aname = &env->tempname; + break; + case 0x00: /* ZeroOp */ + ret->type = aml_t_num; + ret->num.number = 0; + ret->num.constant = 1; + AML_DEBUGPRINT("Zero"); + aname = &env->tempname; + break; + case 0x01: /* OneOp */ + ret->type = aml_t_num; + ret->num.number = 1; + ret->num.constant = 1; + AML_DEBUGPRINT("One"); + aname = &env->tempname; + break; + case 0xff: /* OnesOp */ + ret->type = aml_t_num; + ret->num.number = 0xffffffff; + ret->num.constant = 1; + AML_DEBUGPRINT("Ones"); + aname = &env->tempname; + break; + case 0x06: /* AliasOp */ + AML_DEBUGPRINT("Alias("); + tmpname = aml_parse_termobj(env, indent); + if (env->stat == aml_stat_panic) { + return (NULL); + } + if (tmpname->property == NULL || + tmpname->property->type != aml_t_namestr) { + env->stat = aml_stat_panic; + return (NULL); + } + /* + * XXX if srcname is deleted after this object, what + * shall I do? + */ + srcname = aml_search_name(env, tmpname->property->nstr.dp); + AML_DEBUGPRINT(", "); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name, NULL); + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + aml_print_curname(aname); + return (NULL); + } + AML_ALLOC_OBJECT(aname->property, env, aml_t_objref, NULL); + objref = aname->property; + objref->objref.nameref = srcname; + objref->objref.ref = srcname->property; + objref->objref.offset = -1; + objref->objref.alias = 1; /* Yes, this is an alias */ + AML_DEBUGPRINT(")"); + /* shut the interpreter up during the namespace initializing */ + return (NULL); + case 0x08: /* NameOp */ + AML_DEBUGPRINT("Name("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name, NULL); + if (env->stat == aml_stat_panic) { + AML_DEBUGPRINT("Already Defined \n"); + aml_print_curname(aname); + return (NULL); + } + AML_DEBUGPRINT(", "); + AML_COPY_OBJECT(aname->property, env, + aml_eval_name(env, + aml_parse_termobj(env, indent)), + NULL); + AML_DEBUGPRINT(")"); + break; + case 0x10: /* ScopeOp */ + aml_parse_defscope(env, indent); + break; + case 0x11: /* BufferOp */ + aname = &env->tempname; + aname->property = aml_parse_defbuffer(env, indent); + break; + case 0x12: /* PackageOp */ + aname = &env->tempname; + aname->property = aml_parse_defpackage(env, indent); + break; + case 0x14: /* MethodOp */ + aml_parse_defmethod(env, indent); + break; + case 0x5b: /* ExtOpPrefix */ + opcode = *env->dp++; + switch (opcode) { + case 0x01: + aml_parse_defmutex(env, indent); + break; + case 0x02: /* EventOp */ + AML_DEBUGPRINT("Event("); + name = aml_parse_namestring(env); + aml_print_namestring(name); + AML_CREATE_NAME(aname, env, name, NULL); + if (aname->property != NULL) { + env->stat = aml_stat_panic; + AML_DEBUGPRINT("Already Defined \n"); + return (NULL); + } + AML_ALLOC_OBJECT(aname->property, env, aml_t_event, NULL); + AML_DEBUGPRINT(")"); + return (NULL); + break; + case 0x12: /* CondRefOfOp */ + AML_DEBUGPRINT("CondRefOf("); + src = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(", "); + if (src == &env->tempname || src == NULL) { + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + anum.num.number = 0xffffffff; + env->tempobject.num = anum.num; + aname = &env->tempname; + break; + } + AML_ALLOC_OBJECT(objref, env, aml_t_objref, NULL); + if (src->property == NULL || + src->property->type != aml_t_namestr) { + objref->objref.nameref = src; + } else { + objref->objref.nameref = aml_create_local_object(); + } + objref->objref.ref = src->property; + objref->objref.offset = -1; /* different from IndexOp */ + + destname1 = aml_parse_termobj(env, indent); + aml_store_to_name(env, objref, destname1); + anum.num.number = 0; + env->tempobject.num = anum.num; + aname = &env->tempname; + AML_DEBUGPRINT(")"); + break; + case 0x13: + aml_parse_defcreatefield(env, indent); + break; + case 0x20: /* LoadOp *//* XXX Not Impremented */ + AML_DEBUGPRINT("Load("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(", "); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; + case 0x21: /* StallOp */ + AML_DEBUGPRINT("Stall("); + num1 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(")"); + AML_STALL(num1); + break; + case 0x22: /* SleepOp */ + AML_DEBUGPRINT("Sleep("); + num1 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_SLEEP(0, num1); + AML_DEBUGPRINT(")"); + break; + case 0x23: /* AcquireOp *//* XXX Not yet */ + AML_DEBUGPRINT("Acquire("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(", 0x%x)", aml_parse_worddata(env)); + break; + case 0x24: /* SignalOp *//* XXX Not yet */ + AML_DEBUGPRINT("Signal("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; + case 0x25: /* WaitOp *//* XXX Not yet impremented */ + AML_DEBUGPRINT("Wait("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(", "); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; + case 0x26: /* ResetOp *//* XXX Not yet impremented */ + AML_DEBUGPRINT("Reset("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; + case 0x27: /* ReleaseOp *//* XXX Not yet impremented */ + AML_DEBUGPRINT("Release("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; +#define NUMOP2(opname, operation) do { \ + AML_DEBUGPRINT(opname); \ + AML_DEBUGPRINT("("); \ + num1 = aml_objtonum(env, aml_eval_name(env, \ + aml_parse_termobj(env, indent))); \ + AML_DEBUGPRINT(", "); \ + anum.num.number = operation (num1); \ + destname1 = aml_parse_termobj(env, indent); \ + AML_DEBUGPRINT(")"); \ + aml_store_to_name(env, &anum, destname1); \ + env->tempobject.num = anum.num; \ + env->tempname.property = &env->tempobject; \ + aname = &env->tempname; \ +} while(0) + + case 0x28: /* FromBCDOp */ + NUMOP2("FromBCD", frombcd); + break; + case 0x29: /* ToBCDOp */ + NUMOP2("ToBCD", tobcd); + break; + case 0x2a: /* UnloadOp *//* XXX Not yet impremented */ + AML_DEBUGPRINT("Unload("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; + case 0x30: + env->tempobject.type = aml_t_num; + env->tempobject.num.number = 0; + env->tempobject.num.constant = 1; + AML_DEBUGPRINT("Revision"); + break; + case 0x31: + env->tempobject.type = aml_t_debug; + aname = &env->tempname; + AML_DEBUGPRINT("Debug"); + break; + case 0x32: /* FatalOp */ + AML_DEBUGPRINT("Fatal("); + AML_DEBUGPRINT("0x%x, ", aml_parse_bytedata(env)); + AML_DEBUGPRINT("0x%x, ", aml_parse_dworddata(env)); + aml_parse_termobj(env, indent); + env->stat = aml_stat_panic; + AML_DEBUGPRINT(")"); + break; + case 0x80: /* OpRegionOp */ + aml_parse_defopregion(env, indent); + break; + case 0x81: /* FieldOp */ + aml_parse_deffield(env, indent); + break; + case 0x82: /* DeviceOp */ + aml_parse_defdevice(env, indent); + break; + case 0x83: /* ProcessorOp */ + aml_parse_defprocessor(env, indent); + break; + case 0x84: /* PowerResOp */ + aml_parse_defpowerres(env, indent); + break; + case 0x85: /* ThermalZoneOp */ + aml_parse_defthermalzone(env, indent); + break; + case 0x86: /* IndexFieldOp */ + aml_parse_defindexfield(env, indent); + break; + case 0x87: /* BankFieldOp */ + aml_parse_defbankfield(env, indent); + break; + default: + AML_SYSERRX(1, "strange opcode 0x5b, 0x%x\n", opcode); + AML_SYSABORT(); + } + break; + case 0x68 ... 0x6e: /* ArgN */ + AML_DEBUGPRINT("Arg%d", opcode - 0x68); + return (aml_local_stack_getArgX(NULL, opcode - 0x68)); + break; + case 0x60 ... 0x67: + AML_DEBUGPRINT("Local%d", opcode - 0x60); + return (aml_local_stack_getLocalX(opcode - 0x60)); + break; + case 0x70: /* StoreOp */ + AML_DEBUGPRINT("Store("); + aname = aml_create_local_object(); + AML_COPY_OBJECT(tmpobj, env, + aml_eval_name(env, aml_parse_termobj(env, indent)), NULL); + aname->property = tmpobj; + AML_DEBUGPRINT(", "); + destname1 = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + /* XXX + * temporary object may change during aml_store_to_name() + * operation, so we make a copy of it on stack. + */ + if (destname1 == &env->tempname && + destname1->property == &env->tempobject) { + destname1 = aml_create_local_object(); + AML_COPY_OBJECT(destname1->property, env, + &env->tempobject, NULL); + } + aml_store_to_name(env, tmpobj, destname1); + if (env->stat == aml_stat_panic) { + AML_DEBUGPRINT("StoreOp failed"); + return (NULL); + } + aname = aml_create_local_object(); + AML_COPY_OBJECT(tmpobj, env, destname1->property, NULL); + aname->property = tmpobj; + if (tmpobj == NULL) { + printf("???"); + break; + } + break; + case 0x71: /* RefOfOp */ + AML_DEBUGPRINT("RefOf("); + src = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + + aname = aml_create_local_object(); + AML_ALLOC_OBJECT(aname->property, env, aml_t_objref, NULL); + objref = aname->property; + if (src->property == NULL || + src->property->type != aml_t_namestr) { + objref->objref.nameref = src; + } else { + objref->objref.nameref = aml_create_local_object(); + } + objref->objref.ref = src->property; + objref->objref.offset = -1; /* different from IndexOp */ + break; + +#define NUMOP3_2(opname, oparation, ope2) do { \ + AML_DEBUGPRINT(opname); \ + AML_DEBUGPRINT("("); \ + num1 = aml_objtonum(env, aml_eval_name(env, \ + aml_parse_termobj(env, indent))); \ + AML_DEBUGPRINT(", "); \ + num2 = aml_objtonum(env, aml_eval_name(env, \ + aml_parse_termobj(env, indent))); \ + AML_DEBUGPRINT(", "); \ + anum.num.number = ope2(num1 oparation num2); \ + destname1 = aml_parse_termobj(env, indent); \ + AML_DEBUGPRINT(")"); \ + aml_store_to_name(env, &anum, destname1); \ + env->tempobject.num = anum.num; \ + env->tempname.property = &env->tempobject; \ + aname = &env->tempname; \ +} while(0) + +#define NUMOP3(opname, operation) NUMOP3_2(opname, operation, ) +#define NUMOPN3(opname, operation) NUMOP3_2(opname, operation, ~) + + case 0x72: /* AddOp */ + NUMOP3("Add", +); + break; + case 0x73: /* ConcatOp */ + aname = aml_parse_concatop(env, indent); + break; + case 0x74: /* SubtractOp */ + NUMOP3("Subtract", -); + break; + case 0x75: /* IncrementOp */ + AML_DEBUGPRINT("Increment("); + aname = aml_parse_termobj(env, indent); + num1 = aml_objtonum(env, aml_eval_name(env, aname)); + num1++; + anum.num.number = num1; + AML_DEBUGPRINT(")"); + aml_store_to_name(env, &anum, aname); + aname = &env->tempname; + env->tempobject.num = anum.num; + break; + case 0x76: /* DecrementOp */ + AML_DEBUGPRINT("Decrement("); + aname = aml_parse_termobj(env, indent); + num1 = aml_objtonum(env, aml_eval_name(env, aname)); + num1--; + anum.num.number = num1; + AML_DEBUGPRINT(")"); + aml_store_to_name(env, &anum, aname); + aname = &env->tempname; + env->tempobject.num = anum.num; + break; + case 0x77: /* MultiplyOp */ + NUMOP3("Multiply", *); + break; + case 0x78: /* DivideOp */ + AML_DEBUGPRINT("Divide("); + num1 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(", "); + num2 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(", "); + anum.num.number = num1 % num2; + destname1 = aml_parse_termobj(env, indent); + aml_store_to_name(env, &anum, destname1); + AML_DEBUGPRINT(", "); + anum.num.number = num1 / num2; + destname2 = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + aml_store_to_name(env, &anum, destname2); + env->tempobject.num = anum.num; + aname = &env->tempname; + break; + case 0x79: /* ShiftLeftOp */ + NUMOP3("ShiftLeft", <<); + break; + case 0x7a: /* ShiftRightOp */ + NUMOP3("ShiftRight", >>); + break; + case 0x7b: /* AndOp */ + NUMOP3("And", &); + break; + case 0x7c: /* NAndOp */ + NUMOPN3("NAnd", &); + break; + case 0x7d: /* OrOp */ + NUMOP3("Or", |); + break; + case 0x7e: /* NOrOp */ + NUMOPN3("NOr", |); + break; + case 0x7f: /* XOrOp */ + NUMOP3("XOr", ^); + break; + case 0x80: /* NotOp */ + NUMOP2("Not", ~); + break; + case 0x81: /* FindSetLeftBitOp */ + NUMOP2("FindSetLeftBit", findsetleftbit); + break; + case 0x82: /* FindSetRightBitOp */ + NUMOP2("FindSetRightBit", findsetrightbit); + break; + case 0x83: /* DerefOp */ + AML_DEBUGPRINT("DerefOf("); + objref = aml_eval_name(env, aml_parse_termobj(env, indent)); + AML_DEBUGPRINT(")"); + + if (objref->objref.ref == NULL) { + env->tempname.property = objref->objref.ref; + aname = &env->tempname; + break; + } + switch (objref->objref.ref->type) { + case aml_t_package: + case aml_t_buffer: + if (objref->objref.offset < 0) { + env->tempname.property = objref->objref.ref; + } else { + objref->objref.deref = 1; + env->tempname.property = objref; + } + break; + default: + env->tempname.property = objref->objref.ref; + break; + } + + aname = &env->tempname; + break; + case 0x86: /* NotifyOp *//* XXX Not yet impremented */ + AML_DEBUGPRINT("Notify("); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(", "); + aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + break; + case 0x87: /* SizeOfOp */ + AML_DEBUGPRINT("SizeOf("); + aname = aml_parse_termobj(env, indent); + tmpobj = aml_eval_name(env, aname); + + AML_DEBUGPRINT(")"); + num1 = 0; + switch (tmpobj->type) { + case aml_t_buffer: + num1 = tmpobj->buffer.size; + break; + case aml_t_string: + num1 = strlen(tmpobj->str.string); + break; + case aml_t_package: + num1 = tmpobj->package.elements; + break; + default: + AML_DEBUGPRINT("Args of SizeOf should be " + "buffer/string/package only\n"); + break; + } + + anum.num.number = num1; + env->tempobject.num = anum.num; + aname = &env->tempname; + break; + case 0x88: /* IndexOp */ + AML_DEBUGPRINT("Index("); + srcobj = aml_eval_name(env, aml_parse_termobj(env, indent)); + AML_DEBUGPRINT(", "); + num1 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(", "); + destname1 = aml_parse_termobj(env, indent); + AML_DEBUGPRINT(")"); + aname = aml_create_local_object(); + switch (srcobj->type) { + case aml_t_package: + case aml_t_buffer: + AML_ALLOC_OBJECT(objref, env, aml_t_objref, NULL); + aname->property = objref; + objref->objref.ref = srcobj; + objref->objref.offset = num1; + objref->objref.deref = 0; + break; + default: + AML_DEBUGPRINT("Arg0 of Index should be either " + "buffer or package\n"); + return (aname); + } + + aml_store_to_name(env, objref, destname1); + break; + case 0x89: /* MatchOp *//* XXX Not yet Impremented */ + AML_DEBUGPRINT("Match("); + AML_COPY_OBJECT(obj, env, aml_eval_name(env, + aml_parse_termobj(env, indent)), NULL); + if (obj->type != aml_t_package) { + env->stat = aml_stat_panic; + return (NULL); + } + anum.num.number = 0xffffffff; + match1 = *env->dp; + AML_DEBUGPRINT(", %d", *env->dp); + env->dp++; + num1 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + match2 = *env->dp; + AML_DEBUGPRINT(", %d", *env->dp); + env->dp++; + num2 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + AML_DEBUGPRINT(", "); + start = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + +#define MATCHOP(opnum, arg1, arg2) ((opnum == 0) ? (1) : \ + (opnum == 1) ? ((arg1) == (arg2)) : \ + (opnum == 2) ? ((arg1) <= (arg2)) : \ + (opnum == 3) ? ((arg1) < (arg2)) : \ + (opnum == 4) ? ((arg1) >= (arg2)) : \ + (opnum == 5) ? ((arg1) > (arg2)) : 0 ) + + for (i = start; i < obj->package.elements; i++) { + pkgval = aml_objtonum(env, obj->package.objects[i]); + if (MATCHOP(match1, pkgval, num1) && + MATCHOP(match2, pkgval, num2)) { + anum.num.number = i; + break; + } + } + AML_DEBUGPRINT(")"); + aml_free_object(&obj); + aname = &env->tempname; + env->tempname.property = &env->tempobject; + env->tempobject.num = anum.num; + break; +#undef MATCHOP + case 0x8a ... 0x8d: /* CreateDWordFieldOp */ + widthindex = *(env->dp - 1) - 0x8a; + AML_DEBUGPRINT("%s(", opname[widthindex]); + srcbuf = aml_eval_name(env, aml_parse_termobj(env, indent)); + if (srcbuf == &env->tempobject) { + AML_DEBUGPRINT("NOT NAMEDBUF\n"); + env->stat = aml_stat_panic; + return (NULL); + } + AML_DEBUGPRINT(", "); + index = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + if (widthindex != 3) { + index *= 8; + } + AML_DEBUGPRINT(", "); + newname = aml_parse_namestring(env); + aml_print_namestring(newname); + aml_createfield_generic(env, srcbuf, index, + widthtbl[widthindex], newname); + AML_DEBUGPRINT(")"); + break; + case 0x8e: /* ObjectTypeOp */ + AML_DEBUGPRINT("ObjectType("); + aname = aml_parse_termobj(env, indent); + if (aname == NULL) { + env->tempobject.type = aml_t_num; + env->tempobject.num.number = aml_t_null; + } else { + env->tempobject.type = aml_t_num; + env->tempobject.num.number = aname->property->type; + } + aname = &env->tempname; + AML_DEBUGPRINT(")"); + break; + +#define CMPOP(opname,operation) do { \ + AML_DEBUGPRINT(opname); \ + AML_DEBUGPRINT("("); \ + num1 = aml_objtonum(env, aml_eval_name(env, \ + aml_parse_termobj(env, indent))); \ + AML_DEBUGPRINT(", "); \ + num2 = aml_objtonum(env, aml_eval_name(env, \ + aml_parse_termobj(env, indent))); \ + aname = &env->tempname; \ + env->tempobject.type = aml_t_num; \ + env->tempobject.num.number = (num1 operation num2) ? 0xffffffff : 0; \ + aname->property = &env->tempobject; \ + AML_DEBUGPRINT(")"); \ +} while(0) + + case 0x90: + CMPOP("LAnd", &&); + break; + case 0x91: + CMPOP("LOr", ||); + break; + case 0x92: + AML_DEBUGPRINT("LNot("); + num1 = aml_objtonum(env, aml_eval_name(env, + aml_parse_termobj(env, indent))); + aname = &env->tempname; + env->tempobject.type = aml_t_num; + env->tempobject.num.number = (!num1) ? 0xffffffff : 0; + aname->property = &env->tempobject; + AML_DEBUGPRINT(")"); + break; + case 0x93: + CMPOP("LEqual", ==); + break; + case 0x94: + CMPOP("LGreater", >); + break; + case 0x95: + CMPOP("LLess", <); + break; + case 0xa0: /* IfOp */ + aname = aml_parse_defif(env, indent); + break; +#if 0 + + case 0xa1: /* ElseOp should not be treated in Main parser + * But If Op */ + aml_parse_defelse(env, indent); + break; +#endif + case 0xa2: /* WhileOp */ + aname = aml_parse_defwhile(env, indent); + break; + case 0xa3: /* NoopOp */ + AML_DEBUGPRINT("Noop"); + break; + case 0xa5: /* BreakOp */ + AML_DEBUGPRINT("Break"); + env->stat = aml_stat_break; + break; + case 0xa4: /* ReturnOp */ + AML_DEBUGPRINT("Return("); + AML_COPY_OBJECT(env->tempname.property, env, aml_eval_name(env, + aml_parse_termobj(env, indent)), NULL); + aname = &env->tempname; + env->stat = aml_stat_return; + AML_DEBUGPRINT(")"); + break; + case 0xcc: /* BreakPointOp */ + /* XXX Not Yet Impremented (Not need?) */ + AML_DEBUGPRINT("BreakPoint"); + break; + default: + AML_SYSERRX(1, "strange opcode 0x%x\n", opcode); + AML_SYSABORT(); + } + + return (aname); +} diff --git a/usr.sbin/acpidump/aml/aml_parse.h b/usr.sbin/acpidump/aml/aml_parse.h new file mode 100644 index 00000000000..b9b55b3eb5c --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_parse.h @@ -0,0 +1,37 @@ +/* $OpenBSD: aml_parse.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Doug Rabson + * 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. + * + * $Id: aml_parse.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_parse.h,v 1.1 2000/08/24 09:33:08 takawata Exp $ + */ + +#ifndef _AML_PARSE_H_ +#define _AML_PARSE_H_ + +struct aml_name *aml_parse_objectlist(struct aml_environ *, int); +struct aml_name *aml_parse_termobj(struct aml_environ *, int); + +#endif /* !_AML_PARSE_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_region.h b/usr.sbin/acpidump/aml/aml_region.h new file mode 100644 index 00000000000..97c78cfabc4 --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_region.h @@ -0,0 +1,93 @@ +/* $OpenBSD: aml_region.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_region.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_region.h,v 1.2 2000/09/20 01:01:27 iwasaki Exp $ + */ + +#ifndef _AML_REGION_H_ +#define _AML_REGION_H_ + +/* + * Note that common part of region I/O is implemented in aml_common.c. + */ + +/* + * Debug macros for region I/O + */ + +#define AML_REGION_READ_DEBUG(regtype, flags, addr, bitoffset, bitlen) \ + AML_DEBUGPRINT("\n[aml_region_read(%d, %d, 0x%x, 0x%x, 0x%x)]\n",\ + regtype, flags, addr, bitoffset, bitlen) + +#define AML_REGION_READ_INTO_BUFFER_DEBUG(regtype, flags, \ + addr, bitoffset, bitlen) \ + AML_DEBUGPRINT("\n[aml_region_read_into_buffer(%d, %d, 0x%x, 0x%x, 0x%x)]\n",\ + regtype, flags, addr, bitoffset, bitlen) + +#define AML_REGION_WRITE_DEBUG(regtype, flags, value, \ + addr, bitoffset, bitlen) \ + AML_DEBUGPRINT("\n[aml_region_write(%d, %d, 0x%x, 0x%x, 0x%x, 0x%x)]\n",\ + regtype, flags, value, addr, bitoffset, bitlen) + +#define AML_REGION_WRITE_FROM_BUFFER_DEBUG(regtype, flags, \ + addr, bitoffset, bitlen) \ + AML_DEBUGPRINT("\n[aml_region_write_from_buffer(%d, %d, 0x%x, 0x%x, 0x%x)]\n",\ + regtype, flags, addr, bitoffset, bitlen) + +#define AML_REGION_BCOPY_DEBUG(regtype, flags, addr, bitoffset, bitlen, \ + dflags, daddr, dbitoffset, dbitlen) \ + AML_DEBUGPRINT("\n[aml_region_bcopy(%d, %d, 0x%x, 0x%x, 0x%x, %d, 0x%x, 0x%x, 0x%x)]\n",\ + regtype, flags, addr, bitoffset, bitlen, \ + dflags, daddr, dbitoffset, dbitlen) + +/* + * Region I/O subroutine + */ + +struct aml_environ; + +u_int32_t aml_region_read(struct aml_environ *, int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t); +int aml_region_write(struct aml_environ *, int, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, u_int32_t); +int aml_region_read_into_buffer(struct aml_environ *, int, + u_int32_t, u_int32_t, u_int32_t, + u_int32_t, u_int8_t *); +int aml_region_write_from_buffer(struct aml_environ *, int, + u_int32_t, u_int8_t *, u_int32_t, + u_int32_t, u_int32_t); +int aml_region_bcopy(struct aml_environ *, int, + u_int32_t, u_int32_t, u_int32_t, u_int32_t, + u_int32_t, u_int32_t, u_int32_t, u_int32_t); + +#ifndef _KERNEL +void aml_simulation_regdump(const char *); +extern int aml_debug_prompt_regoutput; +extern int aml_debug_prompt_reginput; +#endif /* !_KERNEL */ + +#endif /* !_AML_REGION_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_status.h b/usr.sbin/acpidump/aml/aml_status.h new file mode 100644 index 00000000000..d6d09be618a --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_status.h @@ -0,0 +1,42 @@ +/* $OpenBSD: aml_status.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * 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. + * + * $Id: aml_status.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_status.h,v 1.1 2000/08/24 09:33:08 takawata Exp $ + */ + +#ifndef _AML_STATUS_H_ +#define _AML_STATUS_H_ + +enum aml_status { + aml_stat_none = 0, + aml_stat_return, + aml_stat_break, + aml_stat_panic, + aml_stat_step +}; + +#endif /* !_AML_STATUS_H_ */ diff --git a/usr.sbin/acpidump/aml/aml_store.c b/usr.sbin/acpidump/aml/aml_store.c new file mode 100644 index 00000000000..0fcae246eff --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_store.c @@ -0,0 +1,350 @@ +/* $OpenBSD: aml_store.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_store.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_store.c,v 1.3 2000/11/09 06:24:45 iwasaki Exp $ + */ + +#include <sys/types.h> + +#include <aml/aml_amlmem.h> +#include <aml/aml_common.h> +#include <aml/aml_env.h> +#include <aml/aml_evalobj.h> +#include <aml/aml_name.h> +#include <aml/aml_obj.h> +#include <aml/aml_region.h> +#include <aml/aml_status.h> +#include <aml/aml_store.h> + +#ifndef _KERNEL +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include "debug.h" +#else /* _KERNEL */ +#include <sys/systm.h> +#endif /* !_KERNEL */ + +static void +aml_store_to_fieldname(struct aml_environ *env, union aml_object *obj, + struct aml_name *name) +{ + char *buffer; + struct aml_name *wname, *oname, *iname; + struct aml_field *field; + struct aml_opregion *or; + union aml_object tobj, iobj, *tmpobj; + + field = &name->property->field; + oname = env->curname; + iname = NULL; + env->curname = name->parent; + if (field->f.ftype == f_t_field) { + wname = aml_search_name(env, field->f.fld.regname); + if (wname == NULL || + wname->property == NULL || + wname->property->type != aml_t_opregion) { + AML_DEBUGPRINT("Inappropreate Type\n"); + env->stat = aml_stat_panic; + env->curname = oname; + return; + } + or = &wname->property->opregion; + switch (obj->type) { + case aml_t_num: + aml_region_write(env, or->space, field->flags, + obj->num.number, or->offset, + field->bitoffset, field->bitlen); + AML_DEBUGPRINT("[write(%d, 0x%x, 0x%x)]", + or->space, obj->num.number, + or->offset + field->bitoffset / 8); + break; + case aml_t_buffer: + case aml_t_bufferfield: + if (obj->type == aml_t_buffer) { + buffer = obj->buffer.data; + } else { + buffer = obj->bfld.origin; + buffer += obj->bfld.bitoffset / 8; + } + aml_region_write_from_buffer(env, or->space, + field->flags, buffer, or->offset, field->bitoffset, + field->bitlen); + break; + case aml_t_regfield: + if (or->space != obj->regfield.space) { + AML_DEBUGPRINT("aml_store_to_fieldname: " + "Different type of space\n"); + break; + } + aml_region_bcopy(env, obj->regfield.space, + obj->regfield.flags, obj->regfield.offset, + obj->regfield.bitoffset, obj->regfield.bitlen, + field->flags, or->offset, field->bitoffset, + field->bitlen); + break; + default: + AML_DEBUGPRINT("aml_store_to_fieldname: " + "Inappropreate Type of src object\n"); + break; + } + } else if (field->f.ftype == f_t_index) { + iname = aml_search_name(env, field->f.ifld.indexname); + wname = aml_search_name(env, field->f.ifld.dataname); + iobj.type = aml_t_num; + iobj.num.number = field->bitoffset / 8; /* AccessType Boundary */ + + /* read whole values of IndexField */ + aml_store_to_name(env, &iobj, iname); + tmpobj = aml_eval_name(env, wname); + + /* make the values to be written */ + tobj.num = obj->num; + tobj.num.number = aml_adjust_updatevalue(field->flags, + field->bitoffset & 7, field->bitlen, + tmpobj->num.number, obj->num.number); + + /* write the values to IndexField */ + aml_store_to_name(env, &iobj, iname); + aml_store_to_name(env, &tobj, wname); + } + env->curname = oname; +} + +static void +aml_store_to_buffer(struct aml_environ *env, union aml_object *obj, + union aml_object *buf, int offset) +{ + int size; + int bitlen; + + switch (obj->type) { + case aml_t_num: + if (offset > buf->buffer.size) { + aml_realloc_object(buf, offset); + } + buf->buffer.data[offset] = obj->num.number & 0xff; + AML_DEBUGPRINT("[Store number 0x%x to buffer]", + obj->num.number & 0xff); + break; + case aml_t_string: + size = strlen(obj->str.string); + if (buf->buffer.size - offset < size) { + aml_realloc_object(buf, offset + size + 1); + } + strcpy(&buf->buffer.data[offset], obj->str.string); + AML_DEBUGPRINT("[Store string to buffer]"); + break; + case aml_t_buffer: + bzero(buf->buffer.data, buf->buffer.size); + if (obj->buffer.size > buf->buffer.size) { + size = buf->buffer.size; + } else { + size = obj->buffer.size; + } + bcopy(obj->buffer.data, buf->buffer.data, size); + break; + case aml_t_regfield: + bitlen = (buf->buffer.size - offset) * 8; + if (bitlen > obj->regfield.bitlen) { + bitlen = obj->regfield.bitlen; + } + aml_region_read_into_buffer(env, obj->regfield.space, + obj->regfield.flags, obj->regfield.offset, + obj->regfield.bitoffset, bitlen, + buf->buffer.data + offset); + break; + default: + goto not_yet; + } + return; +not_yet: + AML_DEBUGPRINT("[XXX not supported yet]"); +} + + +void +aml_store_to_object(struct aml_environ *env, union aml_object *src, + union aml_object * dest) +{ + char *buffer, *srcbuf; + int offset, bitlen; + + switch (dest->type) { + case aml_t_num: + if (src->type == aml_t_num) { + dest->num = src->num; + AML_DEBUGPRINT("[Store number 0x%x]", src->num.number); + } else { + env->stat = aml_stat_panic; + } + break; + case aml_t_string: + case aml_t_package: + break; + case aml_t_buffer: + aml_store_to_buffer(env, src, dest, 0); + break; + case aml_t_bufferfield: + buffer = dest->bfld.origin; + offset = dest->bfld.bitoffset; + bitlen = dest->bfld.bitlen; + + switch (src->type) { + case aml_t_num: + if (aml_bufferfield_write(src->num.number, buffer, offset, bitlen)) { + AML_DEBUGPRINT("aml_bufferfield_write() failed\n"); + } + break; + case aml_t_buffer: + case aml_t_bufferfield: + if (src->type == aml_t_buffer) { + srcbuf = src->buffer.data; + } else { + srcbuf = src->bfld.origin; + srcbuf += src->bfld.bitoffset / 8; + } + bcopy(srcbuf, buffer, bitlen / 8); + break; + case aml_t_regfield: + aml_region_read_into_buffer(env, src->regfield.space, + src->regfield.flags, src->regfield.offset, + src->regfield.bitoffset, src->regfield.bitlen, + buffer); + break; + default: + AML_DEBUGPRINT("not implemented yet"); + break; + } + break; + case aml_t_debug: + aml_showobject(src); + break; + default: + AML_DEBUGPRINT("[Unimplemented %d]", dest->type); + break; + } +} + +static void +aml_store_to_objref(struct aml_environ *env, union aml_object *obj, + union aml_object *r) +{ + int offset; + union aml_object *ref; + + if (r->objref.ref == NULL) { + r->objref.ref = aml_alloc_object(obj->type, NULL); /* XXX */ + r->objref.nameref->property = r->objref.ref; + } + ref = r->objref.ref; + + switch (ref->type) { + case aml_t_buffer: + offset = r->objref.offset; + aml_store_to_buffer(env, obj, ref, r->objref.offset); + break; + case aml_t_package: + offset = r->objref.offset; + if (r->objref.ref->package.elements < offset) { + aml_realloc_object(ref, offset); + } + if (ref->package.objects[offset] == NULL) { + ref->package.objects[offset] = aml_copy_object(env, obj); + } else { + aml_store_to_object(env, obj, ref->package.objects[offset]); + } + break; + default: + aml_store_to_object(env, obj, ref); + break; + } +} + +/* + * Store to Named object + */ +void +aml_store_to_name(struct aml_environ *env, union aml_object *obj, + struct aml_name *name) +{ + struct aml_name *wname; + + if (env->stat == aml_stat_panic) { + return; + } + if (name == NULL || obj == NULL) { + AML_DEBUGPRINT("[Try to store no existant name ]"); + return; + } + if (name->property == NULL) { + name->property = aml_copy_object(env, obj); + AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number); + return; + } + if (name->property->type == aml_t_namestr) { + wname = aml_search_name(env, name->property->nstr.dp); + name = wname; + } + if (name == NULL) { + env->stat = aml_stat_panic; + return; + } + if (name->property == NULL || name->property->type == aml_t_null) { + name->property = aml_copy_object(env, obj); + AML_DEBUGPRINT("[Copy number 0x%x]", obj->num.number); + return; + } + /* Writes to constant object are not allowed */ + if (name->property != NULL && name->property->type == aml_t_num && + name->property->num.constant == 1) { + return; + } + /* try to dereference */ + if (obj->type == aml_t_objref && obj->objref.deref == 0) { + AML_DEBUGPRINT("Source object isn't dereferenced yet, " + "try to dereference anyway\n"); + obj->objref.deref = 1; + obj = aml_eval_objref(env, obj); + } + switch (name->property->type) { + case aml_t_field: + aml_store_to_fieldname(env, obj, name); + break; + case aml_t_objref: + aml_store_to_objref(env, obj, name->property); + break; + case aml_t_num: + if (name == &env->tempname) + break; + default: + aml_store_to_object(env, obj, name->property); + break; + } +} diff --git a/usr.sbin/acpidump/aml/aml_store.h b/usr.sbin/acpidump/aml/aml_store.h new file mode 100644 index 00000000000..7dbaf70b84e --- /dev/null +++ b/usr.sbin/acpidump/aml/aml_store.h @@ -0,0 +1,40 @@ +/* $OpenBSD: aml_store.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_store.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/aml/aml_store.h,v 1.1 2000/08/24 09:33:08 takawata Exp $ + */ + +#ifndef _AML_STORE_H_ +#define _AML_STORE_H_ + +void aml_store_to_name(struct aml_environ *, union aml_object *, + struct aml_name *); +void aml_store_to_object(struct aml_environ *, union aml_object *, + union aml_object *); + +#endif /* _AML_STORE_H_ */ diff --git a/usr.sbin/acpidump/aml_dump.c b/usr.sbin/acpidump/aml_dump.c new file mode 100644 index 00000000000..11acc4858e1 --- /dev/null +++ b/usr.sbin/acpidump/aml_dump.c @@ -0,0 +1,61 @@ +/* $OpenBSD: aml_dump.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: aml_dump.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/acpidump/aml_dump.c,v 1.3 2000/11/08 02:37:00 iwasaki Exp $ + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <fcntl.h> +#include <stdio.h> +#include <unistd.h> + +#include "acpidump.h" + +char *aml_dumpfile = NULL; + +void +aml_dump(struct ACPIsdt *dsdp) +{ + int fd; + mode_t mode; + + if (aml_dumpfile == NULL) { + return; + } + + mode = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + fd = open(aml_dumpfile, O_WRONLY | O_CREAT | O_TRUNC, mode); + if (fd == -1) { + return; + } + write(fd, dsdp, SIZEOF_SDT_HDR); + write(fd, dsdp->body, dsdp->len - SIZEOF_SDT_HDR); + close(fd); +} + diff --git a/usr.sbin/acpidump/asl_dump.c b/usr.sbin/acpidump/asl_dump.c new file mode 100644 index 00000000000..25cea02bb05 --- /dev/null +++ b/usr.sbin/acpidump/asl_dump.c @@ -0,0 +1,1281 @@ +/* $OpenBSD: asl_dump.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Doug Rabson + * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: asl_dump.c,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/acpidump/asl_dump.c,v 1.5 2001/10/23 14:53:58 takawata Exp $ + */ + +#include <sys/param.h> + +#include <assert.h> +#include <err.h> +#include <stdio.h> + +#include "acpidump.h" + +#include "aml/aml_env.h" + +struct aml_environ asl_env; + +static u_int32_t +asl_dump_pkglength(u_int8_t **dpp) +{ + u_int8_t *dp; + u_int32_t pkglength; + + dp = *dpp; + pkglength = *dp++; + switch (pkglength >> 6) { + case 0: + break; + case 1: + pkglength = (pkglength & 0xf) + (dp[0] << 4); + dp += 1; + break; + case 2: + pkglength = (pkglength & 0xf) + (dp[0] << 4) + (dp[1] << 12); + dp += 2; + break; + case 3: + pkglength = (pkglength & 0xf) + + (dp[0] << 4) + (dp[1] << 12) + (dp[2] << 20); + dp += 3; + break; + } + + *dpp = dp; + return (pkglength); +} + +static void +print_nameseg(u_int8_t *dp) +{ + + if (dp[3] != '_') + printf("%c%c%c%c", dp[0], dp[1], dp[2], dp[3]); + else if (dp[2] != '_') + printf("%c%c%c_", dp[0], dp[1], dp[2]); + else if (dp[1] != '_') + printf("%c%c__", dp[0], dp[1]); + else if (dp[0] != '_') + printf("%c___", dp[0]); +} + +static u_int8_t +asl_dump_bytedata(u_int8_t **dpp) +{ + u_int8_t *dp; + u_int8_t data; + + dp = *dpp; + data = dp[0]; + *dpp = dp + 1; + return (data); +} + +static u_int16_t +asl_dump_worddata(u_int8_t **dpp) +{ + u_int8_t *dp; + u_int16_t data; + + dp = *dpp; + data = dp[0] + (dp[1] << 8); + *dpp = dp + 2; + return (data); +} + +static u_int32_t +asl_dump_dworddata(u_int8_t **dpp) +{ + u_int8_t *dp; + u_int32_t data; + + dp = *dpp; + data = dp[0] + (dp[1] << 8) + (dp[2] << 16) + (dp[3] << 24); + *dpp = dp + 4; + return (data); +} + +static u_int8_t * +asl_dump_namestring(u_int8_t **dpp) +{ + u_int8_t *dp; + u_int8_t *name; + + dp = *dpp; + name = dp; + if (dp[0] == '\\') + dp++; + else if (dp[0] == '^') + while (dp[0] == '^') + dp++; + if (dp[0] == 0x00) /* NullName */ + dp++; + else if (dp[0] == 0x2e) /* DualNamePrefix */ + dp += 1 + 4 + 4;/* NameSeg, NameSeg */ + else if (dp[0] == 0x2f) { /* MultiNamePrefix */ + int segcount = dp[1]; + dp += 1 + 1 + segcount * 4; /* segcount * NameSeg */ + } else + dp += 4; /* NameSeg */ + + *dpp = dp; + return (name); +} + +static void +print_namestring(u_int8_t *dp) +{ + + if (dp[0] == '\\') { + putchar(dp[0]); + dp++; + } else if (dp[0] == '^') { + while (dp[0] == '^') { + putchar(dp[0]); + dp++; + } + } + if (dp[0] == 0x00) { /* NullName */ + /* printf("<null>"); */ + dp++; + } else if (dp[0] == 0x2e) { /* DualNamePrefix */ + print_nameseg(dp + 1); + putchar('.'); + print_nameseg(dp + 5); + } else if (dp[0] == 0x2f) { /* MultiNamePrefix */ + int segcount = dp[1]; + int i; + for (i = 0, dp += 2; i < segcount; i++, dp += 4) { + if (i > 0) + putchar('.'); + print_nameseg(dp); + } + } else /* NameSeg */ + print_nameseg(dp); +} + +static void +print_indent(int indent) +{ + int i; + + for (i = 0; i < indent; i++) + printf(" "); +} + +#define ASL_ENTER_SCOPE(dp_orig, old_name) do { \ + u_int8_t *dp_copy; \ + u_int8_t *name; \ + old_name = asl_env.curname; \ + dp_copy = dp_orig; \ + name = asl_dump_namestring(&dp_copy); \ + asl_env.curname = aml_search_name(&asl_env, name); \ +} while(0) + +#define ASL_LEAVE_SCOPE(old_name) do { \ + asl_env.curname = old_name; \ +} while(0) + +#define ASL_CREATE_LOCALNAMEOBJ(dp) do { \ + if(scope_within_method){ \ + aml_create_name(&asl_env, dp); \ + } \ +}while(0); + +static void +asl_dump_defscope(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + struct aml_name *oname; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + + printf("Scope("); + ASL_ENTER_SCOPE(dp, oname); + asl_dump_termobj(&dp, indent); + printf(") {\n"); + end = start + pkglength; + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + ASL_LEAVE_SCOPE(oname); + *dpp = dp; +} + +static void +asl_dump_defbuffer(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + printf("Buffer("); + asl_dump_termobj(&dp, indent); + printf(") {"); + while (dp < end) { + printf("0x%x", *dp++); + if (dp < end) + printf(", "); + } + printf(" }"); + + *dpp = dp; +} + +static void +asl_dump_defpackage(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t numelements; + u_int32_t pkglength; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + numelements = asl_dump_bytedata(&dp); + end = start + pkglength; + printf("Package(0x%x) {\n", numelements); + while (dp < end) { + print_indent(indent + 1); + asl_dump_termobj(&dp, indent + 1); + printf(",\n"); + } + + print_indent(indent); + printf("}"); + + dp = end; + + *dpp = dp; +} + +int scope_within_method = 0; + +static void +asl_dump_defmethod(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t flags; + u_int32_t pkglength; + struct aml_name *oname; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + + printf("Method("); + ASL_ENTER_SCOPE(dp, oname); + asl_dump_termobj(&dp, indent); + flags = *dp++; + if (flags) { + printf(", %d", flags & 7); + if (flags & 8) { + printf(", Serialized"); + } + } + printf(") {\n"); + end = start + pkglength; + scope_within_method = 1; + asl_dump_objectlist(&dp, end, indent + 1); + scope_within_method = 0; + print_indent(indent); + printf("}"); + + assert(dp == end); + ASL_LEAVE_SCOPE(oname); + *dpp = dp; +} + + +static void +asl_dump_defopregion(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + const char *regions[] = { + "SystemMemory", + "SystemIO", + "PCI_Config", + "EmbeddedControl", + "SMBus", + }; + + dp = *dpp; + printf("OperationRegion("); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); /* Name */ + printf(", %s, ", regions[*dp++]); /* Space */ + asl_dump_termobj(&dp, indent); /* Offset */ + printf(", "); + asl_dump_termobj(&dp, indent); /* Length */ + printf(")"); + + *dpp = dp; +} + +static const char *accessnames[] = { + "AnyAcc", + "ByteAcc", + "WordAcc", + "DWordAcc", + "BlockAcc", + "SMBSendRecvAcc", + "SMBQuickAcc" +}; + +static int +asl_dump_field(u_int8_t **dpp, u_int32_t offset) +{ + u_int8_t *dp; + u_int8_t *name; + u_int8_t access, attribute; + u_int32_t width; + + dp = *dpp; + switch (*dp) { + case '\\': + case '^': + case 'A' ... 'Z': + case '_': + case '.': + case '/': + ASL_CREATE_LOCALNAMEOBJ(dp); + name = asl_dump_namestring(&dp); + width = asl_dump_pkglength(&dp); + offset += width; + print_namestring(name); + printf(",\t%d", width); + break; + case 0x00: + dp++; + width = asl_dump_pkglength(&dp); + offset += width; + if ((offset % 8) == 0) { + printf("Offset(0x%x)", offset / 8); + } else { + printf(",\t%d", width); + } + break; + case 0x01: + access = dp[1]; + attribute = dp[2]; + dp += 3; + printf("AccessAs(%s, %d)", accessnames[access], attribute); + break; + } + + *dpp = dp; + return (offset); +} + +static void +asl_dump_fieldlist(u_int8_t **dpp, u_int8_t *end, int indent) +{ + u_int8_t *dp; + u_int32_t offset; + + dp = *dpp; + offset = 0; + while (dp < end) { + print_indent(indent); + offset = asl_dump_field(&dp, offset); + if (dp < end) + printf(",\n"); + else + printf("\n"); + } + + *dpp = dp; +} + +static void +asl_dump_deffield(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t flags; + u_int32_t pkglength; + static const char *lockrules[] = {"NoLock", "Lock"}; + static const char *updaterules[] = {"Preserve", "WriteAsOnes", + "WriteAsZeros", "*Error*"}; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("Field("); + asl_dump_termobj(&dp, indent); /* Name */ + flags = asl_dump_bytedata(&dp); + printf(", %s, %s, %s) {\n", + accessnames[flags & 0xf], + lockrules[(flags >> 4) & 1], + updaterules[(flags >> 5) & 3]); + asl_dump_fieldlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + *dpp = dp; +} + +static void +asl_dump_defindexfield(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t flags; + u_int32_t pkglength; + static const char *lockrules[] = {"NoLock", "Lock"}; + static const char *updaterules[] = {"Preserve", "WriteAsOnes", + "WriteAsZeros", "*Error*"}; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("IndexField("); + asl_dump_termobj(&dp, indent); /* Name1 */ + printf(", "); + asl_dump_termobj(&dp, indent); /* Name2 */ + flags = asl_dump_bytedata(&dp); + printf(", %s, %s, %s) {\n", + accessnames[flags & 0xf], + lockrules[(flags >> 4) & 1], + updaterules[(flags >> 5) & 3]); + asl_dump_fieldlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + *dpp = dp; +} + +static void +asl_dump_defbankfield(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t flags; + u_int32_t pkglength; + static const char *lockrules[] = {"NoLock", "Lock"}; + static const char *updaterules[] = {"Preserve", "WriteAsOnes", + "WriteAsZeros", "*Error*"}; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + printf("BankField("); + asl_dump_termobj(&dp, indent); /* Name1 */ + printf(", "); + asl_dump_termobj(&dp, indent); /* Name2 */ + printf(", "); + asl_dump_termobj(&dp, indent); /* BankValue */ + flags = asl_dump_bytedata(&dp); + printf(", %s, %s, %s) {\n", + accessnames[flags & 0xf], + lockrules[(flags >> 4) & 1], + updaterules[(flags >> 5) & 3]); + asl_dump_fieldlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + *dpp = dp; +} + +static void +asl_dump_defdevice(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + struct aml_name *oname; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("Device("); + ASL_ENTER_SCOPE(dp, oname); + asl_dump_termobj(&dp, indent); + printf(") {\n"); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + ASL_LEAVE_SCOPE(oname); + *dpp = dp; +} + +static void +asl_dump_defprocessor(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t procid; + u_int8_t pblklen; + u_int32_t pkglength; + u_int32_t pblkaddr; + struct aml_name *oname; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("Processor("); + ASL_ENTER_SCOPE(dp, oname); + asl_dump_termobj(&dp, indent); + procid = asl_dump_bytedata(&dp); + pblkaddr = asl_dump_dworddata(&dp); + pblklen = asl_dump_bytedata(&dp); + printf(", %d, 0x%x, 0x%x) {\n", procid, pblkaddr, pblklen); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + ASL_LEAVE_SCOPE(oname); + *dpp = dp; +} + +static void +asl_dump_defpowerres(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int8_t systemlevel; + u_int16_t resourceorder; + u_int32_t pkglength; + struct aml_name *oname; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("PowerResource("); + ASL_ENTER_SCOPE(dp, oname); + asl_dump_termobj(&dp, indent); + systemlevel = asl_dump_bytedata(&dp); + resourceorder = asl_dump_worddata(&dp); + printf(", %d, %d) {\n", systemlevel, resourceorder); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + ASL_LEAVE_SCOPE(oname); + *dpp = dp; +} + +static void +asl_dump_defthermalzone(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + struct aml_name *oname; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("ThermalZone("); + ASL_ENTER_SCOPE(dp, oname); + asl_dump_termobj(&dp, indent); + printf(") {\n"); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + ASL_LEAVE_SCOPE(oname); + *dpp = dp; +} + +static void +asl_dump_defif(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("If("); + asl_dump_termobj(&dp, indent); + printf(") {\n"); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + *dpp = dp; +} + +static void +asl_dump_defelse(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("Else {\n"); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + *dpp = dp; +} + +static void +asl_dump_defwhile(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *start; + u_int8_t *end; + u_int32_t pkglength; + + dp = *dpp; + start = dp; + pkglength = asl_dump_pkglength(&dp); + end = start + pkglength; + + printf("While("); + asl_dump_termobj(&dp, indent); + printf(") {\n"); + asl_dump_objectlist(&dp, end, indent + 1); + print_indent(indent); + printf("}"); + + assert(dp == end); + + *dpp = dp; +} + +/* + * Public interfaces + */ +void +asl_dump_termobj(u_int8_t **dpp, int indent) +{ + u_int8_t *dp; + u_int8_t *name; + u_int8_t opcode; + struct aml_name *method; + const char *matchstr[] = { + "MTR", "MEQ", "MLE", "MLT", "MGE", "MGT", + }; + +#define OPTARG() do { \ + printf(", "); \ + if (*dp == 0x00) { \ + dp++; \ + } else { \ + asl_dump_termobj(&dp, indent); \ + } \ +} while (0) + + dp = *dpp; + opcode = *dp++; + switch (opcode) { + case '\\': + case '^': + case 'A' ... 'Z': + case '_': + case '.': + case '/': + dp--; + print_namestring((name = asl_dump_namestring(&dp))); + if (scope_within_method == 1) { + method = aml_search_name(&asl_env, name); + if (method != NULL && method->property != NULL && + method->property->type == aml_t_method) { + int i, argnum; + + argnum = method->property->meth.argnum & 7; + printf("("); + for (i = 0; i < argnum; i++) { + asl_dump_termobj(&dp, indent); + if (i < (argnum-1)) { + printf(", "); + } + } + printf(")"); + } + } + break; + case 0x0a: /* BytePrefix */ + printf("0x%x", asl_dump_bytedata(&dp)); + break; + case 0x0b: /* WordPrefix */ + printf("0x%04x", asl_dump_worddata(&dp)); + break; + case 0x0c: /* DWordPrefix */ + printf("0x%08x", asl_dump_dworddata(&dp)); + break; + case 0x0d: /* StringPrefix */ + printf("\"%s\"", (const char *) dp); + while (*dp) + dp++; + dp++; /* NUL terminate */ + break; + case 0x00: /* ZeroOp */ + printf("Zero"); + break; + case 0x01: /* OneOp */ + printf("One"); + break; + case 0xff: /* OnesOp */ + printf("Ones"); + break; + case 0x06: /* AliasOp */ + printf("Alias("); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x08: /* NameOp */ + printf("Name("); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x10: /* ScopeOp */ + asl_dump_defscope(&dp, indent); + break; + case 0x11: /* BufferOp */ + asl_dump_defbuffer(&dp, indent); + break; + case 0x12: /* PackageOp */ + asl_dump_defpackage(&dp, indent); + break; + case 0x14: /* MethodOp */ + asl_dump_defmethod(&dp, indent); + break; + case 0x5b: /* ExtOpPrefix */ + opcode = *dp++; + switch (opcode) { + case 0x01: /* MutexOp */ + printf("Mutex("); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(", %d)", *dp++); + break; + case 0x02: /* EventOp */ + printf("Event("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x12: /* CondRefOfOp */ + printf("CondRefOf("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x13: /* CreateFieldOp */ + printf("CreateField("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x20: /* LoadOp */ + printf("Load("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x21: /* StallOp */ + printf("Stall("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x22: /* SleepOp */ + printf("Sleep("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x23: /* AcquireOp */ + printf("Acquire("); + asl_dump_termobj(&dp, indent); + printf(", 0x%x)", asl_dump_worddata(&dp)); + break; + case 0x24: /* SignalOp */ + printf("Signal("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x25: /* WaitOp */ + printf("Wait("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x26: /* ResetOp */ + printf("Reset("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x27: /* ReleaseOp */ + printf("Release("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x28: /* FromBCDOp */ + printf("FromBCD("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x29: /* ToBCDOp */ + printf("ToBCD("); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x2a: /* UnloadOp */ + printf("Unload("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x30: + printf("Revision"); + break; + case 0x31: + printf("Debug"); + break; + case 0x32: /* FatalOp */ + printf("Fatal("); + printf("0x%x, ", asl_dump_bytedata(&dp)); + printf("0x%x, ", asl_dump_dworddata(&dp)); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x80: /* OpRegionOp */ + asl_dump_defopregion(&dp, indent); + break; + case 0x81: /* FieldOp */ + asl_dump_deffield(&dp, indent); + break; + case 0x82: /* DeviceOp */ + asl_dump_defdevice(&dp, indent); + break; + case 0x83: /* ProcessorOp */ + asl_dump_defprocessor(&dp, indent); + break; + case 0x84: /* PowerResOp */ + asl_dump_defpowerres(&dp, indent); + break; + case 0x85: /* ThermalZoneOp */ + asl_dump_defthermalzone(&dp, indent); + break; + case 0x86: /* IndexFieldOp */ + asl_dump_defindexfield(&dp, indent); + break; + case 0x87: /* BankFieldOp */ + asl_dump_defbankfield(&dp, indent); + break; + default: + errx(1, "strange opcode 0x5b, 0x%x\n", opcode); + } + break; + case 0x68 ... 0x6e: /* ArgN */ + printf("Arg%d", opcode - 0x68); + break; + case 0x60 ... 0x67: + printf("Local%d", opcode - 0x60); + break; + case 0x70: /* StoreOp */ + printf("Store("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x71: /* RefOfOp */ + printf("RefOf("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x72: /* AddOp */ + printf("Add("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x73: /* ConcatenateOp */ + printf("Concatenate("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x74: /* SubtractOp */ + printf("Subtract("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x75: /* IncrementOp */ + printf("Increment("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x76: /* DecrementOp */ + printf("Decrement("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x77: /* MultiplyOp */ + printf("Multiply("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x78: /* DivideOp */ + printf("Divide("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + OPTARG(); + printf(")"); + break; + case 0x79: /* ShiftLeftOp */ + printf("ShiftLeft("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x7a: /* ShiftRightOp */ + printf("ShiftRight("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x7b: /* AndOp */ + printf("And("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x7c: /* NAndOp */ + printf("NAnd("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x7d: /* OrOp */ + printf("Or("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x7e: /* NOrOp */ + printf("NOr("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x7f: /* XOrOp */ + printf("XOr("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x80: /* NotOp */ + printf("Not("); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x81: /* FindSetLeftBitOp */ + printf("FindSetLeftBit("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x82: /* FindSetRightBitOp */ + printf("FindSetRightBit("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x83: /* DerefOp */ + printf("DerefOf("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x86: /* NotifyOp */ + printf("Notify("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x87: /* SizeOfOp */ + printf("SizeOf("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x88: /* IndexOp */ + printf("Index("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + OPTARG(); + printf(")"); + break; + case 0x89: /* MatchOp */ + printf("Match("); + asl_dump_termobj(&dp, indent); + printf(", %s, ", matchstr[*dp++]); + asl_dump_termobj(&dp, indent); + printf(", %s, ", matchstr[*dp++]); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x8a: /* CreateDWordFieldOp */ + printf("CreateDWordField("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x8b: /* CreateWordFieldOp */ + printf("CreateWordField("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x8c: /* CreateByteFieldOp */ + printf("CreateByteField("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x8d: /* CreateBitFieldOp */ + printf("CreateBitField("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(", "); + ASL_CREATE_LOCALNAMEOBJ(dp); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x8e: /* ObjectTypeOp */ + printf("ObjectType("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x90: + printf("LAnd("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x91: + printf("LOr("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x92: + printf("LNot("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x93: + printf("LEqual("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x94: + printf("LGreater("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0x95: + printf("LLess("); + asl_dump_termobj(&dp, indent); + printf(", "); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0xa0: /* IfOp */ + asl_dump_defif(&dp, indent); + break; + case 0xa1: /* ElseOp */ + asl_dump_defelse(&dp, indent); + break; + case 0xa2: /* WhileOp */ + asl_dump_defwhile(&dp, indent); + break; + case 0xa3: /* NoopOp */ + printf("Noop"); + break; + case 0xa5: /* BreakOp */ + printf("Break"); + break; + case 0xa4: /* ReturnOp */ + printf("Return("); + asl_dump_termobj(&dp, indent); + printf(")"); + break; + case 0xcc: /* BreakPointOp */ + printf("BreakPoint"); + break; + default: + errx(1, "strange opcode 0x%x\n", opcode); + } + + *dpp = dp; +} + +void +asl_dump_objectlist(u_int8_t **dpp, u_int8_t *end, int indent) +{ + u_int8_t *dp; + + dp = *dpp; + while (dp < end) { + print_indent(indent); + asl_dump_termobj(&dp, indent); + printf("\n"); + } + + *dpp = dp; +} diff --git a/usr.sbin/acpidump/debug.h b/usr.sbin/acpidump/debug.h new file mode 100644 index 00000000000..db645ca1405 --- /dev/null +++ b/usr.sbin/acpidump/debug.h @@ -0,0 +1,37 @@ +/* $OpenBSD: debug.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ */ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> + * 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. + * + * $Id: debug.h,v 1.1 2005/06/02 20:09:39 tholo Exp $ + * $FreeBSD: src/usr.sbin/acpi/amldb/debug.h,v 1.1.1.1 2000/08/31 14:45:00 iwasaki Exp $ + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +void aml_dbgr(struct aml_environ *, struct aml_environ *); + +#endif /* !_DEBUG_H_ */ |