/* $OpenBSD: acpi_machdep.c,v 1.13 2008/06/01 17:59:55 marco Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include "bios.h" #include "apm.h" #if NBIOS > 0 #include #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 = trunc_page(pa); paddr_t endpa = 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 + (u_long)(pa & PGOFSET)); handle->vsize = endpa - pgpa; handle->pa = pa; do { pmap_kenter_pa(va, pgpa, VM_PROT_READ | VM_PROT_WRITE); 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 && rsdp->revision <= 3 && 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 bios_attach_args *ba) { struct acpi_mem_map handle; u_int8_t *ptr; paddr_t ebda; #if NAPM > 0 extern int apm_attached; if (apm_attached) return (0); #endif #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: ba->ba_acpipbase = ptr - handle.va + handle.pa; acpi_unmap(&handle); return (1); } #ifndef SMALL_KERNEL void acpi_attach_machdep(struct acpi_softc *sc) { extern void (*cpuresetfn)(void); sc->sc_interrupt = isa_intr_establish(NULL, sc->sc_fadt->sci_int, IST_LEVEL, IPL_TTY, acpi_interrupt, sc, sc->sc_dev.dv_xname); acpiapm_open = acpiopen; acpiapm_close = acpiclose; acpiapm_ioctl = acpiioctl; acpiapm_kqfilter = acpikqfilter; cpuresetfn = acpi_reset; } #endif /* SMALL_KERNEL */