165285Siwasaki/*- 265285Siwasaki * Copyright (c) 1999 Doug Rabson 365285Siwasaki * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 465285Siwasaki * All rights reserved. 565285Siwasaki * 665285Siwasaki * Redistribution and use in source and binary forms, with or without 765285Siwasaki * modification, are permitted provided that the following conditions 865285Siwasaki * are met: 965285Siwasaki * 1. Redistributions of source code must retain the above copyright 1065285Siwasaki * notice, this list of conditions and the following disclaimer. 1165285Siwasaki * 2. Redistributions in binary form must reproduce the above copyright 1265285Siwasaki * notice, this list of conditions and the following disclaimer in the 1365285Siwasaki * documentation and/or other materials provided with the distribution. 1465285Siwasaki * 1565285Siwasaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1665285Siwasaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1765285Siwasaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1865285Siwasaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1965285Siwasaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2065285Siwasaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2165285Siwasaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2265285Siwasaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2365285Siwasaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2465285Siwasaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2565285Siwasaki * SUCH DAMAGE. 2665285Siwasaki * 2765285Siwasaki * $FreeBSD$ 2865285Siwasaki */ 2965285Siwasaki 3065285Siwasaki#include <sys/param.h> 3165285Siwasaki#include <sys/mman.h> 3265285Siwasaki#include <sys/queue.h> 3365285Siwasaki#include <sys/stat.h> 34119515Snjl#include <sys/sysctl.h> 3565285Siwasaki 3665285Siwasaki#include <err.h> 3765285Siwasaki#include <fcntl.h> 38167814Sjkim#include <kenv.h> 3965285Siwasaki#include <stdlib.h> 4065285Siwasaki#include <string.h> 4165285Siwasaki#include <unistd.h> 4265285Siwasaki 4365285Siwasaki#include "acpidump.h" 4465285Siwasaki 45167814Sjkimstatic char hint_acpi_0_rsdp[] = "hint.acpi.0.rsdp"; 46119515Snjlstatic char machdep_acpi_root[] = "machdep.acpi_root"; 4765285Siwasakistatic int acpi_mem_fd = -1; 4865285Siwasaki 4965285Siwasakistruct acpi_user_mapping { 5065285Siwasaki LIST_ENTRY(acpi_user_mapping) link; 5165285Siwasaki vm_offset_t pa; 5265285Siwasaki caddr_t va; 5365285Siwasaki size_t size; 5465285Siwasaki}; 5565285Siwasaki 56241737Sedstatic LIST_HEAD(acpi_user_mapping_list, acpi_user_mapping) maplist; 5765285Siwasaki 5865285Siwasakistatic void 59119515Snjlacpi_user_init(void) 6065285Siwasaki{ 6165285Siwasaki 6265285Siwasaki if (acpi_mem_fd == -1) { 6365285Siwasaki acpi_mem_fd = open("/dev/mem", O_RDONLY); 6465285Siwasaki if (acpi_mem_fd == -1) 6565285Siwasaki err(1, "opening /dev/mem"); 6665285Siwasaki LIST_INIT(&maplist); 6765285Siwasaki } 6865285Siwasaki} 6965285Siwasaki 7065285Siwasakistatic struct acpi_user_mapping * 7165285Siwasakiacpi_user_find_mapping(vm_offset_t pa, size_t size) 7265285Siwasaki{ 7365285Siwasaki struct acpi_user_mapping *map; 7465285Siwasaki 7565285Siwasaki /* First search for an existing mapping */ 7665285Siwasaki for (map = LIST_FIRST(&maplist); map; map = LIST_NEXT(map, link)) { 7765285Siwasaki if (map->pa <= pa && map->size >= pa + size - map->pa) 7865285Siwasaki return (map); 7965285Siwasaki } 8065285Siwasaki 8165285Siwasaki /* Then create a new one */ 8265285Siwasaki size = round_page(pa + size) - trunc_page(pa); 8365285Siwasaki pa = trunc_page(pa); 8465285Siwasaki map = malloc(sizeof(struct acpi_user_mapping)); 8565285Siwasaki if (!map) 8665285Siwasaki errx(1, "out of memory"); 8765285Siwasaki map->pa = pa; 8865285Siwasaki map->va = mmap(0, size, PROT_READ, MAP_SHARED, acpi_mem_fd, pa); 8965285Siwasaki map->size = size; 9065285Siwasaki if ((intptr_t) map->va == -1) 9165285Siwasaki err(1, "can't map address"); 9265285Siwasaki LIST_INSERT_HEAD(&maplist, map, link); 9365285Siwasaki 9465285Siwasaki return (map); 9565285Siwasaki} 9665285Siwasaki 97196555Sjhbstatic ACPI_TABLE_RSDP * 98129230Snjlacpi_get_rsdp(u_long addr) 99129230Snjl{ 100196555Sjhb ACPI_TABLE_RSDP rsdp; 101129278Snjl size_t len; 102129230Snjl 103129272Snjl /* Read in the table signature and check it. */ 104129230Snjl pread(acpi_mem_fd, &rsdp, 8, addr); 105196555Sjhb if (memcmp(rsdp.Signature, "RSD PTR ", 8)) 106129230Snjl return (NULL); 107129272Snjl 108129230Snjl /* Read the entire table. */ 109129272Snjl pread(acpi_mem_fd, &rsdp, sizeof(rsdp), addr); 110129272Snjl 111196555Sjhb /* Check the standard checksum. */ 112196555Sjhb if (acpi_checksum(&rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) 113129230Snjl return (NULL); 114129278Snjl 115196555Sjhb /* Check extended checksum if table version >= 2. */ 116196555Sjhb if (rsdp.Revision >= 2 && 117196555Sjhb acpi_checksum(&rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) 118196555Sjhb return (NULL); 119196555Sjhb 120129278Snjl /* If the revision is 0, assume a version 1 length. */ 121196555Sjhb if (rsdp.Revision == 0) 122209746Sjkim len = sizeof(ACPI_RSDP_COMMON); 123129278Snjl else 124196555Sjhb len = rsdp.Length; 125129272Snjl 126129278Snjl return (acpi_map_physical(addr, len)); 127129230Snjl} 128129230Snjl 129196555Sjhbstatic ACPI_TABLE_RSDP * 130129702Snjlacpi_scan_rsd_ptr(void) 131129702Snjl{ 132167814Sjkim#if defined(__amd64__) || defined(__i386__) 133196555Sjhb ACPI_TABLE_RSDP *rsdp; 134129702Snjl u_long addr, end; 135129702Snjl 136129702Snjl /* 137129702Snjl * On ia32, scan physical memory for the RSD PTR if above failed. 138129702Snjl * According to section 5.2.2 of the ACPI spec, we only consider 139129702Snjl * two regions for the base address: 140129702Snjl * 1. EBDA (1 KB area addressed by the 16 bit pointer at 0x40E 141129702Snjl * 2. High memory (0xE0000 - 0xFFFFF) 142129702Snjl */ 143196555Sjhb addr = ACPI_EBDA_PTR_LOCATION; 144129702Snjl pread(acpi_mem_fd, &addr, sizeof(uint16_t), addr); 145129702Snjl addr <<= 4; 146196555Sjhb end = addr + ACPI_EBDA_WINDOW_SIZE; 147129702Snjl for (; addr < end; addr += 16) 148129702Snjl if ((rsdp = acpi_get_rsdp(addr)) != NULL) 149129702Snjl return (rsdp); 150196555Sjhb addr = ACPI_HI_RSDP_WINDOW_BASE; 151196555Sjhb end = addr + ACPI_HI_RSDP_WINDOW_SIZE; 152129808Snjl for (; addr < end; addr += 16) 153129702Snjl if ((rsdp = acpi_get_rsdp(addr)) != NULL) 154129702Snjl return (rsdp); 155167814Sjkim#endif /* __amd64__ || __i386__ */ 156129702Snjl return (NULL); 157129702Snjl} 158129702Snjl 15965285Siwasaki/* 16065285Siwasaki * Public interfaces 16165285Siwasaki */ 162196555SjhbACPI_TABLE_RSDP * 163129102Sdesacpi_find_rsd_ptr(void) 16465285Siwasaki{ 165196555Sjhb ACPI_TABLE_RSDP *rsdp; 166167814Sjkim char buf[20]; 167108082Smarcel u_long addr; 168119515Snjl size_t len; 16965285Siwasaki 17065285Siwasaki acpi_user_init(); 17165285Siwasaki 172171642Smarcel addr = 0; 173171642Smarcel 174167814Sjkim /* Attempt to use kenv or sysctl to find RSD PTR record. */ 175251186Sjkim if (kenv(KENV_GET, hint_acpi_0_rsdp, buf, 20) > 0) 176167814Sjkim addr = strtoul(buf, NULL, 0); 177167814Sjkim if (addr == 0) { 178167814Sjkim len = sizeof(addr); 179167814Sjkim if (sysctlbyname(machdep_acpi_root, &addr, &len, NULL, 0) != 0) 180167814Sjkim addr = 0; 18165285Siwasaki } 182167814Sjkim if (addr != 0 && (rsdp = acpi_get_rsdp(addr)) != NULL) 183167814Sjkim return (rsdp); 18465285Siwasaki 185129702Snjl return (acpi_scan_rsd_ptr()); 18665285Siwasaki} 18765285Siwasaki 18865285Siwasakivoid * 18965285Siwasakiacpi_map_physical(vm_offset_t pa, size_t size) 19065285Siwasaki{ 19165285Siwasaki struct acpi_user_mapping *map; 19265285Siwasaki 19365285Siwasaki map = acpi_user_find_mapping(pa, size); 19465285Siwasaki return (map->va + (pa - map->pa)); 19565285Siwasaki} 19665285Siwasaki 197196555SjhbACPI_TABLE_HEADER * 198119515Snjldsdt_load_file(char *infile) 19965285Siwasaki{ 200196555Sjhb ACPI_TABLE_HEADER *sdt; 201119515Snjl uint8_t *dp; 202119515Snjl struct stat sb; 20365285Siwasaki 204119515Snjl if ((acpi_mem_fd = open(infile, O_RDONLY)) == -1) 205119515Snjl errx(1, "opening %s", infile); 20665285Siwasaki 20765285Siwasaki LIST_INIT(&maplist); 20865285Siwasaki 209119515Snjl if (fstat(acpi_mem_fd, &sb) == -1) 210119515Snjl errx(1, "fstat %s", infile); 21165285Siwasaki 21265285Siwasaki dp = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, acpi_mem_fd, 0); 213119515Snjl if (dp == NULL) 214119515Snjl errx(1, "mmap %s", infile); 21565285Siwasaki 216196555Sjhb sdt = (ACPI_TABLE_HEADER *)dp; 217196555Sjhb if (strncmp(dp, ACPI_SIG_DSDT, 4) != 0 || 218196555Sjhb acpi_checksum(sdt, sdt->Length) != 0) 219119515Snjl return (NULL); 22065285Siwasaki 221119515Snjl return (sdt); 22265285Siwasaki} 223