diff --git a/usr.sbin/acpi/amldb/Makefile b/usr.sbin/acpi/amldb/Makefile new file mode 100644 index 000000000000..e683e1c5ae84 --- /dev/null +++ b/usr.sbin/acpi/amldb/Makefile @@ -0,0 +1,13 @@ +# $Id: Makefile,v 1.5 2000/07/14 18:16:30 iwasaki Exp $ +# $FreeBSD$ + +PROG= amldb +SRCS= amldb.c debug.c region.c +SRCS+= aml_parse.c aml_name.c aml_amlmem.c aml_memman.c aml_store.c aml_obj.c aml_evalobj.c aml_common.c +NOMAN= yes +#MAN8= amldb.8 +#DEBUG_FLAGS= -g +CFLAGS+= -I${.CURDIR}/../../../sys -I${.CURDIR} + +.include +.PATH: ${.CURDIR}/../../../sys/dev/acpi/aml diff --git a/usr.sbin/acpi/amldb/amldb.c b/usr.sbin/acpi/amldb/amldb.c new file mode 100644 index 000000000000..007a1ab5c5a9 --- /dev/null +++ b/usr.sbin/acpi/amldb/amldb.c @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 1999 Mitsuru IWASAKI + * 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: amldb.c,v 1.8 2000/08/08 14:12:24 iwasaki Exp $ + * $FreeBSD$ + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "debug.h" + +int regdump_enabled = 0; +int memstat_enabled = 0; +int showtree_enabled = 0; + +static void aml_init_namespace(); + +void +aml_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"; +} + +static int +load_dsdt(const char *dsdtfile) +{ + struct aml_environ env; + u_int8_t *code; + struct stat sb; + int fd; + + printf("Loading %s...", dsdtfile); + + fd = open(dsdtfile, O_RDONLY, 0); + if (fd == -1) { + perror("open"); + exit(-1); + } + if (fstat(fd, &sb) == -1) { + perror("fstat"); + exit(-1); + } + if ((code = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0)) == NULL) { + perror("mmap"); + exit(-1); + } + aml_init_namespace(); + + aml_new_name_group((int)code); + bzero(&env, sizeof(env)); + + /* + * Microsoft asl.exe generates 0x23 byte additional info. + * at the begining of the file, so just ignore it. + */ + if (strncmp(code, "DSDT", 4) == 0) { + env.dp = code + 0x23; + } else { + env.dp = code; + } + env.end = code + sb.st_size; + env.curname = aml_get_rootname(); + + aml_local_stack_push(aml_local_stack_create()); + aml_parse_objectlist(&env, 0); + aml_local_stack_delete(aml_local_stack_pop()); + + assert(env.dp == env.end); + env.dp = code; + env.end = code + sb.st_size; + + printf("done\n"); + + aml_debug = 1; /* debug print enabled */ + + if (showtree_enabled == 1) { + aml_showtree(env.curname, 0); + } + do { + aml_dbgr(&env, &env); + } while (env.stat != aml_stat_panic); + + aml_debug = 0; /* debug print disabled */ + + if (regdump_enabled == 1) { + aml_simulation_regdump("region.dmp"); + } + while (name_group_list->id != AML_NAME_GROUP_ROOT) { + aml_delete_name_group(name_group_list); + } + + if (memstat_enabled == 1) { + memman_statistics(aml_memman); + } + memman_freeall(aml_memman); + + return (0); +} + +static void +usage(const char *progname) +{ + + printf("usage: %s [-d] [-s] [-t] [-h] dsdt_files...\n", progname); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + char c, *progname; + int i; + + progname = argv[0]; + while ((c = getopt(argc, argv, "dsth")) != -1) { + switch (c) { + case 'd': + regdump_enabled = 1; + break; + case 's': + memstat_enabled = 1; + break; + case 't': + showtree_enabled = 1; + break; + case 'h': + default: + usage(progname); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc == 0) { + usage(progname); + } + for (i = 0; i < argc; i++) { + load_dsdt(argv[i]); + } + + return (0); +} diff --git a/usr.sbin/acpi/amldb/debug.c b/usr.sbin/acpi/amldb/debug.c new file mode 100644 index 000000000000..794c3d62d572 --- /dev/null +++ b/usr.sbin/acpi/amldb/debug.c @@ -0,0 +1,311 @@ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI + * 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.c,v 1.19 2000/08/16 18:15:00 iwasaki Exp $ + * $FreeBSD$ + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "debug.h" + +static int +print_named_object(struct aml_name *name, va_list ap) +{ + + aml_print_curname(name); + printf("\n"); + + return (0); /* always return success to continue the search */ +} + +void +aml_dbgr(struct aml_environ *env1, struct aml_environ *env2) +{ +#define CMDBUFLEN 512 +#define ARGBUFLEN 512 + static char lastcommand[CMDBUFLEN]; + char commandline[CMDBUFLEN]; + char argbuf[7][ARGBUFLEN]; + char *ptr, *method; + char *np, *ep; + int i; + int argnum; + struct aml_name *name; + union aml_object argv[7], *retval; + + while (1) { + fputs("AML>", stderr); + fgets(commandline, 512, stdin); + commandline[512 - 1] = '\n'; /* safety */ + if (feof(stdin)) { + commandline[0] = 'q'; + } + if (commandline[0] == '\n') { + memcpy(commandline, lastcommand, sizeof commandline); + } + memcpy(lastcommand, commandline, sizeof commandline); + switch (commandline[0]) { + case 's': + if (env2 != NULL) { + env2->stat = aml_stat_step; + } + /* FALLTHROUGH */ + case 'n': + env1->stat = aml_stat_step; + return; + case 'c': + env1->stat = aml_stat_none; + return; + case 'q': + env1->stat = aml_stat_panic; + return; + case 't': + /* NULL terminate */ + ptr = &commandline[1]; + while (ptr[0] != '\n') + ptr++; + ptr[0] = '\0'; + + /* move pointer to object name */ + ptr = &commandline[1]; + while (ptr[0] == ' ') + ptr++; + + /* show current tree if no argument */ + if (ptr[0] == '\0') { + aml_showtree(env1->curname, 0); + goto show_variables; + } + /* start from root? */ + if (ptr[0] == '\\') { + if (ptr[1] == '\0') { + aml_showtree(aml_get_rootname(), 0); + goto show_variables; + } + if ((name = aml_find_from_namespace(aml_get_rootname(), ptr))) { + aml_showtree(name, 0); + goto show_variables; + } + } + if ((name = aml_find_from_namespace(env1->curname, ptr))) { + aml_showtree(name, 0); + } +show_variables: + for (i = 0; i < 7; i++) { + struct aml_name *tmp = + aml_local_stack_getArgX(NULL, i); + + if (tmp == NULL || tmp->property == NULL) { + break; + } + printf(" Arg%d ", i); + aml_showobject(tmp->property); + } + for (i = 0; i < 8; i++) { + struct aml_name *tmp = + aml_local_stack_getLocalX(i); + + if (tmp == NULL || tmp->property == NULL) { + continue; + } + printf(" Local%d ", i); + aml_showobject(tmp->property); + } + break; + case 'i': + aml_debug_prompt_reginput = + (aml_debug_prompt_reginput == 0) ? 1 : 0; + if (aml_debug_prompt_reginput) + fputs("REGION INPUT ON\n", stderr); + else + fputs("REGION INPUT OFF\n", stderr); + break; + case 'o': + aml_debug_prompt_regoutput = + (aml_debug_prompt_regoutput == 0) ? 1 : 0; + if (aml_debug_prompt_regoutput) + fputs("REGION OUTPUT ON\n", stderr); + else + fputs("REGION OUTPUT OFF\n", stderr); + break; + case 'm': + memman_statistics(aml_memman); + break; + case 'r': + /* NULL terminate */ + ptr = &commandline[1]; + while (ptr[0] != '\n') + ptr++; + ptr[0] = '\0'; + + /* move pointer to method name */ + ptr = &commandline[1]; + while (ptr[0] == ' ') + ptr++; + + if (ptr[0] == '\0') { + break; + } + name = aml_find_from_namespace(aml_get_rootname(), ptr); + if (name == NULL) { + printf("%s:%d:aml_dbgr: not found name %s\n", + __FILE__, __LINE__, ptr); + break; + } + if (name->property == NULL || + name->property->type != aml_t_method) { + printf("%s:%d:aml_dbgr: not method %s\n", + __FILE__, __LINE__, ptr); + break; + } + aml_showobject(name->property); + method = ptr; + + argnum = name->property->meth.argnum & 0x07; + if (argnum) { + fputs(" Enter argument values " + "(ex. number 1 / string foo). " + "'q' to quit.\n", stderr); + } + /* get and parse argument values */ + for (i = 0; i < argnum; i++) { +retry: + fprintf(stderr, " Arg%d ? ", i); + if (read(0, argbuf[i], ARGBUFLEN) == 0) { + fputs("\n", stderr); + goto retry; + } + argbuf[i][ARGBUFLEN - 1] = '\n'; + if (argbuf[i][0] == 'q') { + goto finish_execution; + } + if (argbuf[i][0] == '\n') { + goto retry; + } + /* move pointer to the value */ + ptr = &argbuf[i][0]; + while (ptr[0] != ' ' && ptr[0] != '\n') { + ptr++; + } + while (ptr[0] == ' ') { + ptr++; + } + if (ptr[0] == '\n') { + goto retry; + } + switch (argbuf[i][0]) { + case 'n': + argv[i].type = aml_t_num; + np = ptr; + if (ptr[0] == '0' && + ptr[1] == 'x') { + argv[i].num.number = strtoq(ptr, &ep, 16); + } else { + argv[i].num.number = strtoq(ptr, &ep, 10); + } + if (np == ep) { + fputs("Wrong value for number.\n", + stderr); + goto retry; + } + break; + case 's': + argv[i].type = aml_t_string; + argv[i].str.needfree = 0; + argv[i].str.string = ptr; + /* NULL ternimate */ + while (ptr[0] != '\n') { + ptr++; + } + ptr[0] = '\0'; + break; + default: + fputs("Invalid data type " + "(supports number or string only)\n", + stderr); + goto retry; + } + } + bzero(lastcommand, sizeof lastcommand); + fprintf(stderr, "==== Running %s. ====\n", method); + aml_local_stack_push(aml_local_stack_create()); + retval = aml_invoke_method_by_name(method, argnum, argv); + aml_showobject(retval); + aml_local_stack_delete(aml_local_stack_pop()); + fprintf(stderr, "==== %s finished. ====\n", method); +finish_execution: + break; + case 'f': + /* NULL terminate */ + ptr = &commandline[1]; + while (ptr[0] != '\n') + ptr++; + ptr[0] = '\0'; + + /* move pointer to object name */ + ptr = &commandline[1]; + while (ptr[0] == ' ') + ptr++; + + aml_apply_foreach_found_objects(aml_get_rootname(), + ptr, print_named_object); + break; + case 'h': + fputs("s Single step\n" + "n Step program\n" + "c Continue program being debugged\n" + "q Quit method execution\n" + "t Show local name space tree and variables\n" + "i Toggle region input prompt\n" + "o Toggle region output prompt\n" + "m Show memory management statistics\n" + "r Run specified method\n" + "f Find named objects from namespace.\n" + "h Show this messsage\n", stderr); + break; + } + } +} diff --git a/usr.sbin/acpi/amldb/debug.h b/usr.sbin/acpi/amldb/debug.h new file mode 100644 index 000000000000..3e84efa3cc7a --- /dev/null +++ b/usr.sbin/acpi/amldb/debug.h @@ -0,0 +1,36 @@ +/*- + * Copyright (c) 1999 Takanori Watanabe + * Copyright (c) 1999, 2000 Mitsuru IWASAKI + * 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.8 2000/08/09 14:47:57 iwasaki Exp $ + * $FreeBSD$ + */ + +#ifndef _DEBUG_H_ +#define _DEBUG_H_ + +void aml_dbgr(struct aml_environ *, struct aml_environ *); + +#endif /* !_DEBUG_H_ */ diff --git a/usr.sbin/acpi/amldb/region.c b/usr.sbin/acpi/amldb/region.c new file mode 100644 index 000000000000..94a5d79f54ca --- /dev/null +++ b/usr.sbin/acpi/amldb/region.c @@ -0,0 +1,538 @@ +/*- + * Copyright (c) 1999 Mitsuru IWASAKI + * 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: region.c,v 1.14 2000/08/08 14:12:25 iwasaki Exp $ + * $FreeBSD$ + */ + +/* + * Region I/O subroutine + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "debug.h" + +int aml_debug_prompt_regoutput = 0; +int aml_debug_prompt_reginput = 1; + +static void aml_simulation_regload(const char *dumpfile); + +struct ACPIRegionContent { + TAILQ_ENTRY(ACPIRegionContent) links; + int regtype; + u_int32_t addr; + u_int8_t value; +}; + +TAILQ_HEAD(ACPIRegionContentList, ACPIRegionContent); +struct ACPIRegionContentList RegionContentList; + +static int aml_simulation_initialized = 0; + +static void +aml_simulation_init() +{ + + aml_simulation_initialized = 1; + TAILQ_INIT(&RegionContentList); + aml_simulation_regload("region.ini"); +} + +static int +aml_simulate_regcontent_add(int regtype, u_int32_t addr, u_int8_t value) +{ + struct ACPIRegionContent *rc; + + rc = malloc(sizeof(struct ACPIRegionContent)); + if (rc == NULL) { + return (-1); /* malloc fail */ + } + rc->regtype = regtype; + rc->addr = addr; + rc->value = value; + + TAILQ_INSERT_TAIL(&RegionContentList, rc, links); + return (0); +} + +static int +aml_simulate_regcontent_read(int regtype, u_int32_t addr, u_int8_t *valuep) +{ + struct ACPIRegionContent *rc; + + if (!aml_simulation_initialized) { + aml_simulation_init(); + } + TAILQ_FOREACH(rc, &RegionContentList, links) { + if (rc->regtype == regtype && rc->addr == addr) { + *valuep = rc->value; + return (1); /* found */ + } + } + + return (aml_simulate_regcontent_add(regtype, addr, 0)); +} + +static int +aml_simulate_regcontent_write(int regtype, u_int32_t addr, u_int8_t *valuep) +{ + struct ACPIRegionContent *rc; + + if (!aml_simulation_initialized) { + aml_simulation_init(); + } + TAILQ_FOREACH(rc, &RegionContentList, links) { + if (rc->regtype == regtype && rc->addr == addr) { + rc->value = *valuep; + return (1); /* exists */ + } + } + + return (aml_simulate_regcontent_add(regtype, addr, *valuep)); +} + +static u_int32_t +aml_simulate_prompt(char *msg, u_int32_t def_val) +{ + char buf[16], *ep; + u_int32_t val; + + val = def_val; + printf("DEBUG"); + if (msg != NULL) { + printf("%s", msg); + } + printf("(default: 0x%x / %u) >>", val, val); + fflush(stdout); + + bzero(buf, sizeof buf); + while (1) { + if (read(0, buf, sizeof buf) == 0) { + continue; + } + if (buf[0] == '\n') { + break; /* use default value */ + } + if (buf[0] == '0' && buf[1] == 'x') { + val = strtoq(buf, &ep, 16); + } else { + val = strtoq(buf, &ep, 10); + } + break; + } + return (val); +} + +static void +aml_simulation_regload(const char *dumpfile) +{ + char buf[256], *np, *ep; + struct ACPIRegionContent rc; + FILE *fp; + + if (!aml_simulation_initialized) { + return; + } + if ((fp = fopen(dumpfile, "r")) == NULL) { + warn(dumpfile); + return; + } + while (fgets(buf, sizeof buf, fp) != NULL) { + np = buf; + /* reading region type */ + rc.regtype = strtoq(np, &ep, 10); + if (np == ep) { + continue; + } + np = ep; + + /* reading address */ + rc.addr = strtoq(np, &ep, 16); + if (np == ep) { + continue; + } + np = ep; + + /* reading value */ + rc.value = strtoq(np, &ep, 16); + if (np == ep) { + continue; + } + aml_simulate_regcontent_write(rc.regtype, rc.addr, &rc.value); + } + + fclose(fp); +} + +#define ACPI_REGION_INPUT 0 +#define ACPI_REGION_OUTPUT 1 + +static int +aml_simulate_region_io(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 prompt) +{ + char buf[64]; + u_int8_t val, tmp, masklow, maskhigh; + u_int8_t offsetlow, offsethigh; + u_int32_t addr, byteoffset, bytelen; + int value, readval; + int state, i; + + value = *valuep; + val = readval = 0; + masklow = maskhigh = 0xff; + state = 0; + + byteoffset = bitoffset / 8; + bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0); + addr = baseaddr + byteoffset; + offsetlow = bitoffset % 8; + if (bytelen > 1) { + offsethigh = (bitlen - (8 - offsetlow)) % 8; + } else { + offsethigh = 0; + } + + if (offsetlow) { + masklow = (~((1 << bitlen) - 1) << offsetlow) | \ + ~(0xff << offsetlow); + printf("\t[offsetlow = 0x%x, masklow = 0x%x, ~masklow = 0x%x]\n", + offsetlow, masklow, ~masklow & 0xff); + } + if (offsethigh) { + maskhigh = 0xff << offsethigh; + printf("\t[offsethigh = 0x%x, maskhigh = 0x%x, ~maskhigh = 0x%x]\n", + offsethigh, maskhigh, ~maskhigh & 0xff); + } + for (i = bytelen; i > 0; i--, addr++) { + val = 0; + state = aml_simulate_regcontent_read(regtype, addr, &val); + if (state == -1) { + goto finish; + } + printf("\t[%d:0x%02x@0x%x]", regtype, val, addr); + + switch (io) { + case ACPI_REGION_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; + } + + printf("\n"); + /* goto to next byte... */ + if (i > 1) { + continue; + } + /* final adjustment before finishing region access */ + if (offsetlow) { + readval = readval >> offsetlow; + } + sprintf(buf, "[read(%d, 0x%x)&mask:0x%x]", + regtype, addr, readval); + if (prompt) { + value = aml_simulate_prompt(buf, readval); + if (readval != value) { + state = aml_simulate_region_io(ACPI_REGION_OUTPUT, + regtype, flags, &value, baseaddr, + bitoffset, bitlen, 0); + if (state == -1) { + goto finish; + } + } + } else { + printf("\t%s\n", buf); + value = readval; + } + *valuep = value; + + break; + case ACPI_REGION_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; + } + + if (prompt) { + printf("\n"); + sprintf(buf, "[write(%d, 0x%02x, 0x%x)]", + regtype, tmp, addr); + val = aml_simulate_prompt(buf, tmp); + } else { + printf("->[%d:0x%02x@0x%x]\n", + regtype, tmp, addr); + val = tmp; + } + state = aml_simulate_regcontent_write(regtype, + addr, &val); + if (state == -1) { + goto finish; + } + break; + } + } +finish: + return (state); +} + +static int +aml_simulate_region_io_buffer(int io, int regtype, u_int32_t flags, + u_int8_t *buffer, u_int32_t baseaddr, u_int32_t bitoffset, u_int32_t bitlen) +{ + u_int8_t val; + u_int8_t offsetlow, offsethigh; + u_int32_t addr, byteoffset, bytelen; + int state, i; + + val = 0; + offsetlow = offsethigh = 0; + state = 0; + + byteoffset = bitoffset / 8; + bytelen = bitlen / 8 + ((bitlen % 8) ? 1 : 0); + addr = baseaddr + byteoffset; + offsetlow = bitoffset % 8; + assert(offsetlow == 0); + + if (bytelen > 1) { + offsethigh = (bitlen - (8 - offsetlow)) % 8; + } + assert(offsethigh == 0); + + for (i = bytelen; i > 0; i--, addr++) { + switch (io) { + case ACPI_REGION_INPUT: + val = 0; + state = aml_simulate_regcontent_read(regtype, addr, &val); + if (state == -1) { + goto finish; + } + buffer[bytelen - i] = val; + break; + case ACPI_REGION_OUTPUT: + val = buffer[bytelen - i]; + state = aml_simulate_regcontent_write(regtype, + addr, &val); + if (state == -1) { + goto finish; + } + break; + } + } +finish: + return (state); +} + +static u_int32_t +aml_simulate_region_read(int regtype, u_int32_t flags, u_int32_t addr, + u_int32_t bitoffset, u_int32_t bitlen) +{ + int value; + int state; + + AML_DEBUGPRINT("\n[aml_region_read(%d, %d, 0x%x, 0x%x, 0x%x)]\n", + regtype, flags, addr, bitoffset, bitlen); + state = aml_simulate_region_io(ACPI_REGION_INPUT, regtype, flags, &value, + addr, bitoffset, bitlen, aml_debug_prompt_reginput); + assert(state != -1); + return (value); +} + +int +aml_simulate_region_read_into_buffer(int regtype, u_int32_t flags, + u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen, u_int8_t *buffer) +{ + int state; + + AML_DEBUGPRINT("\n[aml_region_read_into_buffer(%d, %d, 0x%x, 0x%x, 0x%x)]\n", + regtype, flags, addr, bitoffset, bitlen); + state = aml_simulate_region_io_buffer(ACPI_REGION_INPUT, regtype, flags, + buffer, addr, bitoffset, bitlen); + assert(state != -1); + return (state); +} + +int +aml_simulate_region_write(int regtype, u_int32_t flags, u_int32_t value, + u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) +{ + int state; + + AML_DEBUGPRINT("\n[aml_region_write(%d, %d, 0x%x, 0x%x, 0x%x, 0x%x)]\n", + regtype, flags, value, addr, bitoffset, bitlen); + state = aml_simulate_region_io(ACPI_REGION_OUTPUT, regtype, flags, + &value, addr, bitoffset, bitlen, aml_debug_prompt_regoutput); + assert(state != -1); + return (state); +} + +int +aml_simulate_region_write_from_buffer(int regtype, u_int32_t flags, + u_int8_t *buffer, u_int32_t addr, u_int32_t bitoffset, u_int32_t bitlen) +{ + int state; + + AML_DEBUGPRINT("\n[aml_region_write_from_buffer(%d, %d, 0x%x, 0x%x, 0x%x)]\n", + regtype, flags, addr, bitoffset, bitlen); + state = aml_simulate_region_io_buffer(ACPI_REGION_OUTPUT, regtype, + flags, buffer, addr, bitoffset, bitlen); + assert(state != -1); + return (state); +} + +int +aml_simulate_region_bcopy(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) +{ + u_int32_t len, i; + u_int32_t value; + int state; + + 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); + + len = (bitlen > dbitlen) ? dbitlen : bitlen; + len = len / 8 + ((len % 8) ? 1 : 0); + + for (i = 0; i < len; i++) { + state = aml_simulate_region_io(ACPI_REGION_INPUT, regtype, + flags, &value, addr, bitoffset + i * 8, 8, 0); + assert(state != -1); + state = aml_simulate_region_io(ACPI_REGION_OUTPUT, regtype, + dflags, &value, daddr, dbitoffset + i * 8, 8, 0); + assert(state != -1); + } + + 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 (aml_simulate_region_read(regtype, flags, addr, + bitoffset, bitlen)); +} + +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 (aml_simulate_region_read_into_buffer(regtype, flags, addr, + bitoffset, bitlen, buffer)); +} + +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 (aml_simulate_region_write(regtype, flags, value, addr, + bitoffset, bitlen)); +} + +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 (aml_simulate_region_write_from_buffer(regtype, flags, buffer, + addr, bitoffset, bitlen)); +} + +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 (aml_simulate_region_bcopy(regtype, flags, addr, bitoffset, + bitlen, dflags, daddr, dbitoffset, dbitlen)); +} + +void +aml_simulation_regdump(const char *dumpfile) +{ + struct ACPIRegionContent *rc; + FILE *fp; + + if (!aml_simulation_initialized) { + return; + } + if ((fp = fopen(dumpfile, "w")) == NULL) { + warn(dumpfile); + return; + } + while (!TAILQ_EMPTY(&RegionContentList)) { + rc = TAILQ_FIRST(&RegionContentList); + fprintf(fp, "%d 0x%x 0x%x\n", + rc->regtype, rc->addr, rc->value); + TAILQ_REMOVE(&RegionContentList, rc, links); + free(rc); + } + + fclose(fp); + TAILQ_INIT(&RegionContentList); +}