From owner-freebsd-acpi@FreeBSD.ORG Mon Jun 8 05:12:16 2009 Return-Path: Delivered-To: freebsd-acpi@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 192ED1065674 for ; Mon, 8 Jun 2009 05:12:16 +0000 (UTC) (envelope-from rea-fbsd@codelabs.ru) Received: from 0.mx.codelabs.ru (0.mx.codelabs.ru [144.206.177.45]) by mx1.freebsd.org (Postfix) with ESMTP id 908038FC12 for ; Mon, 8 Jun 2009 05:12:15 +0000 (UTC) (envelope-from rea-fbsd@codelabs.ru) DomainKey-Signature: a=rsa-sha1; q=dns; c=simple; s=one; d=codelabs.ru; h=Received:Date:From:To:Subject:Message-ID:MIME-Version:Content-Type:Content-Disposition:Content-Transfer-Encoding:Sender; b=Wi/mQSCBV63522Tr4zZGFfKFBskGRVDLzISxvTsoOI7bIheYgHfj7hrJZmmUVeFKrYZr0RticSgLoABl7HvsnncVJ2lzZ7BmTMXfLYfnYGTXtbcAr5Pt81u3yyWBiwB49b3Pk9eyacnupUCFGOZ5Hn1FK8dC5dGc9hmuzGmGHQk=; Received: from void.codelabs.ru (void.codelabs.ru [144.206.177.25]) by 0.mx.codelabs.ru with esmtpsa (TLSv1:AES256-SHA:256) id 1MDX9a-00017v-Kt for freebsd-acpi@freebsd.org; Mon, 08 Jun 2009 09:12:14 +0400 Date: Mon, 8 Jun 2009 09:12:12 +0400 From: Eygene Ryabinkin To: freebsd-acpi@freebsd.org Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable Sender: rea-fbsd@codelabs.ru Subject: [PATCH] acpidump: teach to disassemble arbitrary memory locations as AML code X-BeenThere: freebsd-acpi@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: ACPI and power management development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 08 Jun 2009 05:12:16 -0000 It is not uncommon when some chunks of the AML code are loaded by DSDT =66rom the memory locations that aren't part of the DSDT itself, but one wants to see what's inside. It can be achieved with 'dd' and 'iasl', but it is better to implement this machinery inside acpidump to ease the life of both users and develepers that needs to see the full picture of the ACPI stuff from foreign machines. This commit also have some small fixes: - verbose output (going to stderr) isn't mixed with normal output that goes to stdout -- the latter is made unbuffered; - we're using IASL's logics to get the name of the output file and, moreover, we prevent two simultaneous invocations of acpidump to hose other's output; - IASL exit code is checked and if disassembler exited abnormally or was failed to do its job, the warning is produced to give the reader an idea on what's going on. Signed-off-by: Eygene Ryabinkin --- usr.sbin/acpi/acpidump/acpi.c | 165 ++++++++++++++++++++++++++++++++-= ---- usr.sbin/acpi/acpidump/acpidump.8 | 5 + usr.sbin/acpi/acpidump/acpidump.c | 97 +++++++++++++++++++++- usr.sbin/acpi/acpidump/acpidump.h | 2 + 4 files changed, 244 insertions(+), 25 deletions(-) diff --git a/usr.sbin/acpi/acpidump/acpi.c b/usr.sbin/acpi/acpidump/acpi.c index fed0fb2..321f894 100644 --- a/usr.sbin/acpi/acpidump/acpi.c +++ b/usr.sbin/acpi/acpidump/acpi.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 1998 Doug Rabson * Copyright (c) 2000 Mitsuru IWASAKI + * Copyright (c) 2009 Eygene Ryabinkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -31,10 +32,13 @@ #include #include #include +#include +#include #include #include #include #include +#include #include #include =20 @@ -800,47 +804,166 @@ dsdt_save_file(char *outfile, struct ACPIsdt *rsdt, = struct ACPIsdt *dsdp) close(fd); } =20 -void -aml_disassemble(struct ACPIsdt *rsdt, struct ACPIsdt *dsdp) -{ - char tmpstr[32], buf[256]; - FILE *fp; - int fd, len; +#define TMPIN "/tmp/acpidump.XXXXXX.aml" +#define TMPSLEN 4 =20 - strcpy(tmpstr, "/tmp/acpidump.XXXXXX"); - fd =3D mkstemp(tmpstr); - if (fd < 0) { - perror("iasl tmp file"); +/* + * Disassembles contents of a given file and dumps them to the + * specified file descriptor. + */ +static void +invoke_iasl(char *infile, FILE *outfp) +{ + char buf[256], *outfile; + int len, status; + FILE *fp; + pid_t child; + + if (strlen(infile) <=3D TMPSLEN) { + warnx("bad input file name '%s', should be longer " + "than " ##TMPSLEN " characters", infile); return; } - write_dsdt(fd, rsdt, dsdp); - close(fd); + if (strcmp(infile + strlen(infile) - TMPSLEN, ".aml")) { + warnx("bad input file name '%s', should end on '.aml'", + infile); + return; + } + outfile =3D strdup(infile); + if (outfile =3D=3D NULL) { + perror("ASL tmp file"); + return; + } + strcpy(outfile + strlen(outfile) - TMPSLEN, ".dsl"); =20 - /* Run iasl -d on the temp file */ - if (fork() =3D=3D 0) { + /* Run iasl -d on the input file */ + child =3D fork(); + if (child =3D=3D -1) { + warn("fork"); + free(outfile); + return; + } + if (child =3D=3D 0) { close(STDOUT_FILENO); if (vflag =3D=3D 0) close(STDERR_FILENO); - execl("/usr/sbin/iasl", "iasl", "-d", tmpstr, (char *) 0); + execl("/usr/sbin/iasl", "iasl", "-d", "-p", outfile, + infile, (char *) 0); err(1, "exec"); } =20 - wait(NULL); - unlink(tmpstr); + if (waitpid(child, &status, 0) !=3D child) { + warn("waitpid(%lu)", (unsigned long)child); + unlink(outfile); + free(outfile); + return; + } + + if (!WIFEXITED(status)) { + warnx("IASL exited abnormally: status =3D %d", status); + unlink(outfile); + free(outfile); + return; + } + + if (WEXITSTATUS(status) !=3D 0) { + warnx("IASL was not able to disassemble the passed AML code"); + unlink(outfile); + free(outfile); + return; + } =20 /* Dump iasl's output to stdout */ - fp =3D fopen("acpidump.dsl", "r"); - unlink("acpidump.dsl"); + fp =3D fopen(outfile, "r"); + unlink(outfile); + free(outfile); if (fp =3D=3D NULL) { - perror("iasl tmp file (read)"); + perror("ASL tmp file (read)"); return; } while ((len =3D fread(buf, 1, sizeof(buf), fp)) > 0) - fwrite(buf, 1, len, stdout); + fwrite(buf, 1, len, outfp); fclose(fp); } =20 void +mem_disassemble(size_t dumpaddr, size_t dumplen) +{ + char tmpstr[sizeof(TMPIN)]; + char buf[256]; + int fd, memfd, toread, towrite; + + strcpy(tmpstr, TMPIN); + fd =3D mkstemps(tmpstr, TMPSLEN); + if (fd < 0) { + perror("AML tmp file"); + return; + } + memfd =3D open("/dev/mem", O_RDONLY); + if (memfd =3D=3D -1) { + perror("open /dev/mem"); + close(fd); + unlink(tmpstr); + return; + } + if (lseek(memfd, dumpaddr, SEEK_SET) =3D=3D -1) { + perror("seeking /dev/mem"); + close(fd); + close(memfd); + unlink(tmpstr); + return; + } + + while (dumplen > 0) { + toread =3D (dumplen > sizeof(buf) ? sizeof(buf) : dumplen); + towrite =3D read(memfd, buf, toread); + if (towrite =3D=3D -1) { + perror("reading /dev/mem"); + close(fd); + close(memfd); + unlink(tmpstr); + return; + } + if (write(fd, buf, towrite) !=3D towrite) { + perror("writing to AML tmp file"); + close(fd); + close(memfd); + unlink(tmpstr); + return; + } + dumplen -=3D towrite; + } + + close(fd); + close(memfd); + + invoke_iasl(tmpstr, stdout); + unlink(tmpstr); +} + +void +aml_disassemble(struct ACPIsdt *rsdt, struct ACPIsdt *dsdp) +{ + char tmpstr[sizeof(TMPIN)]; + int fd; + + strcpy(tmpstr, TMPIN); + fd =3D mkstemps(tmpstr, TMPSLEN); + if (fd < 0) { + perror("AML tmp file"); + return; + } + write_dsdt(fd, rsdt, dsdp); + close(fd); + + invoke_iasl(tmpstr, stdout); + unlink(tmpstr); +} + +#undef TMPIN +#undef TMPSLEN + +void sdt_print_all(struct ACPIsdt *rsdp) { acpi_handle_rsdt(rsdp); diff --git a/usr.sbin/acpi/acpidump/acpidump.8 b/usr.sbin/acpi/acpidump/acp= idump.8 index 1401e38..ec16e4b 100644 --- a/usr.sbin/acpi/acpidump/acpidump.8 +++ b/usr.sbin/acpi/acpidump/acpidump.8 @@ -4,6 +4,7 @@ .\" Copyright (c) 2000 Mitsuru IWASAKI .\" Copyright (c) 2000 Yasuo YOKOYAMA .\" Copyright (c) 2000 Hiroki Sato +.\" Copyright (c) 2009 Eygene Ryabinkin .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -43,6 +44,7 @@ .Op Fl v .Op Fl f Ar dsdt_input .Op Fl o Ar dsdt_output +.Op Fl a Ar address:length .Sh DESCRIPTION The .Nm @@ -122,6 +124,9 @@ the DSDT consists of free-formatted AML data. The following options are supported by .Nm : .Bl -tag -width indent +.It Fl d Ar address:length +Disassemble the given block of physical memory to the standard output. +This flag can be repeated: multiple blocks will be disassembled. .It Fl d Disassemble the DSDT into ASL using .Xr iasl 8 diff --git a/usr.sbin/acpi/acpidump/acpidump.c b/usr.sbin/acpi/acpidump/acp= idump.c index a601ac2..b10527a 100644 --- a/usr.sbin/acpi/acpidump/acpidump.c +++ b/usr.sbin/acpi/acpidump/acpidump.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2000 Mitsuru IWASAKI + * Copyright (c) 2009 Eygene Ryabinkin * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -32,6 +33,7 @@ #include #include #include +#include #include =20 #include "acpidump.h" @@ -40,23 +42,78 @@ int dflag; /* Disassemble AML using iasl(8) */ int tflag; /* Dump contents of SDT tables */ int vflag; /* Use verbose messages */ =20 +struct aflag { + size_t addr; + size_t size; + struct aflag *next; +}; + static void usage(const char *progname) { =20 - fprintf(stderr, "usage: %s [-d] [-t] [-h] [-v] [-f dsdt_input] " + fprintf(stderr, "usage: %s [-a addr:len] [-d] [-t] [-h] [-v] [-f dsdt_inp= ut] " "[-o dsdt_output]\n", progname); fprintf(stderr, "To send ASL:\n\t%s -dt | gzip -c9 > foo.asl.gz\n", progname); exit(1); } =20 +/* + * Parses pair of address:length from the given string. + * Both numbers can be hexadecimal (prefixed by 0[xX]) + * or plain decimal. + * + * Returns 0 for success, !=3D 0 otherwise. + */ +static int +parse_addr(const char *arg, size_t *addr, size_t *len) +{ + char *c1, *c2, *a, *l; + + c1 =3D strchr(arg, ':'); + c2 =3D strrchr(arg, ':'); + if (c1 !=3D c2 || c1 =3D=3D NULL) { + warnx ("argument to '-a' should have form 'addr:len'"); + return 1; + } + + l =3D c1 + 1; + a =3D strndup(arg, l - arg); + if (a =3D=3D NULL) + err(EX_OSERR, "can't parse address:size tuple"); + + if (sscanf(a, "%zi", addr) !=3D 1) { + warnx("Unable to parse address from argument to '-a'"); + free(a); + return 1; + } + if (sscanf(l, "%zi", len) !=3D 1) { + warnx("Unable to parse length from argument to '-a'"); + free(a); + return 1; + } + + free(a); + return 0; +} + int main(int argc, char *argv[]) { char c, *progname; - char *dsdt_input_file, *dsdt_output_file; - struct ACPIsdt *rsdt, *sdt; + char *dsdt_input_file =3D NULL, *dsdt_output_file =3D NULL; + struct ACPIsdt *rsdt =3D NULL, *sdt =3D NULL; + struct aflag *aroot =3D NULL, *atmp; + + /* + * When stdin/stdout are sent to the same file, stdout shouldn't + * be buffered to prevent mixing two outputs. We won't try to + * check it stdin/stdout are the same files, but will just + * make stdout unbuffered unconditionally. This is most + * useful when we're running in verbose mode. + */ + setbuf(stdout, NULL); =20 dsdt_input_file =3D dsdt_output_file =3D NULL; progname =3D argv[0]; @@ -64,8 +121,17 @@ main(int argc, char *argv[]) if (argc < 2) usage(progname); =20 - while ((c =3D getopt(argc, argv, "dhtvf:o:")) !=3D -1) { + while ((c =3D getopt(argc, argv, "a:dhtvf:o:")) !=3D -1) { switch (c) { + case 'a': + atmp =3D (struct aflag *)malloc(sizeof(*atmp)); + if (atmp =3D=3D NULL) + errx(EX_OSERR, "parsing arguments to '-a'"); + if (parse_addr(optarg, &atmp->addr, &atmp->size)) + usage(progname); + atmp->next =3D aroot; + aroot =3D atmp; + break; case 'd': dflag =3D 1; break; @@ -140,5 +206,28 @@ main(int argc, char *argv[]) warnx("iasl processing complete"); } =20 + if (aroot !=3D NULL) { + struct aflag *nroot =3D NULL; + /* Reverse list and disassemble each memory location */ + while (aroot !=3D NULL) { + atmp =3D aroot->next; + aroot->next =3D nroot; + nroot =3D aroot; + aroot =3D atmp; + } + while (nroot !=3D NULL) { + if (vflag) { + warnx("disassembling memory at 0x%zx, " + "0x%zx bytes", nroot->addr, nroot->size); + } + mem_disassemble(nroot->addr, nroot->size); + if (vflag) + warnx("finished disassembling"); + atmp =3D nroot; + nroot =3D nroot->next; + free(atmp); + } + } + exit(0); } diff --git a/usr.sbin/acpi/acpidump/acpidump.h b/usr.sbin/acpi/acpidump/acp= idump.h index 8d79168..8428b58 100644 --- a/usr.sbin/acpi/acpidump/acpidump.h +++ b/usr.sbin/acpi/acpidump/acpidump.h @@ -332,6 +332,8 @@ void sdt_print_all(struct ACPIsdt *); =20 /* Disassemble the AML in the DSDT */ void aml_disassemble(struct ACPIsdt *, struct ACPIsdt *); +/* Disassemble arbitrary memory chunk */ +void mem_disassemble(size_t dumpaddr, size_t dumplen); =20 /* Routines for accessing tables in physical memory */ struct ACPIrsdp *acpi_find_rsd_ptr(void); --=20 1.6.3.1 --=20 Eygene _ ___ _.--. # \`.|\..----...-'` `-._.-'_.-'` # Remember that it is hard / ' ` , __.--' # to read the on-line manual )/' _/ \ `-_, / # while single-stepping the kernel. `-'" `"\_ ,_.-;_.-\_ ', fsc/as # _.-'_./ {_.' ; / # -- FreeBSD Developers handbook {_.-``-' {_/ #