[SeaBIOS] [PATCH 2/4] acpi: add aml/asl parsing script

Gleb Natapov gleb at redhat.com
Wed Sep 21 16:27:32 CEST 2011


On Wed, Sep 21, 2011 at 03:44:29PM +0300, Michael S. Tsirkin wrote:
> script ./src/find_ej0.pl finds all instances of
> method named EJ0_ and the matching _ADR information,
> and outputs the AML offset and slot mask of each.
> 
There is tools/ directory for such kind of scripts. Most (if not all) of
scripts there are in python though. Perl should die painful death.

This approach delivers nice result, but since the script does not really
decodes AML, but tries to match ASL source code with regular expressions,
it introduces some assumptions to the code that make DSDT code less
hackable. I'll hate to be the one who will have to change PCI device
definitions in DSDT next time.

Generally speaking finding an offset of some scope in AML is useful not
only for PCI hotplug. For instance we want to make S3/S4 capability
configurable by a command line switch, but this also requires DSDT
patching and having automatic way to find _S3_/_S4_ offset is required
for that too (we do not what to find it by hand each time DSDT is
recompiled).

> Signed-off-by: Michael S. Tsirkin <mst at redhat.com>
> ---
>  src/find_ej0.pl |  136 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 136 insertions(+), 0 deletions(-)
>  create mode 100755 src/find_ej0.pl
> 
> diff --git a/src/find_ej0.pl b/src/find_ej0.pl
> new file mode 100755
> index 0000000..37e8a8c
> --- /dev/null
> +++ b/src/find_ej0.pl
> @@ -0,0 +1,136 @@
> +#!/usr/bin/perl
> +
> +# Process mixed ASL/AML listing (.lst file) produced by iasl -l
> +# Locate all occurences of Name _ADR followed by Method EJ0_
> +# Output slot info from _ADR and offset of method name in AML
> +
> +use strict;
> +
> +my @aml = ();
> +my @asl = ();
> +my @asl_lineno = ();
> +my @asl_to_aml_offset = ();
> +my @output = ();
> +
> +#Store an ASL command, matching AML offset, and input line (for debugging)
> +sub add_asl {
> +    my $srcline = shift(@_);
> +    my $line = shift(@_);
> +    push @asl, $line;
> +    push @asl_lineno, $.;
> +    push @asl_to_aml_offset, $#aml + 1;
> +}
> +
> +#Store an AML byte sequence
> +#Verify that offset output by iasl matches # of bytes so far
> +sub add_aml {
> +    my $offset = shift(@_);
> +    my $line = shift(@_);
> +    my $o = hex($offset);
> +    # Sanity check: offset must match
> +    die "Offset $o != " .($#aml + 1) if ($o != $#aml + 1);
> +    # Strip any traling dots and ASCII dump after "
> +    $line =~ s/\s*\.*\s*".*//;
> +
> +    my @code = split(' ', $line);
> +    foreach my $c (@code) {
> +        if (not($c =~ m/^[0-9A-Fa-f][0-9A-Fa-f]$/)) {
> +            die "Unexpected octet $c";
> +        }
> +        push @aml, hex($c);
> +    }
> +}
> +
> +# Process aml bytecode array, decoding AML
> +# Given method offset, find its name offset
> +sub aml_method_name {
> +    my $lineno = shift(@_);
> +    my $offset = shift(@_);
> +    #0x14 MethodOp PkgLength NameString MethodFlags TermList
> +    if ($aml[$offset] != 0x14) {
> +        die "Method after input line $lineno offset $offset: " .
> +            " expected 0x14 actual ". sprintf("0x%x", $aml[$offset]);
> +    }
> +    $offset += 1;
> +    # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes.
> +    my $pkglenbytes = $aml[$offset] >> 6;
> +    $offset += 1 + $pkglenbytes;
> +    return $offset;
> +}
> +
> +while (<>) {
> +        #Strip trailing newline
> +        chomp;
> +	#ASL listing: space, then line#, then ...., then code
> +	if (s#^\s+([0-9]+)\.\.\.\.\s*##) {
> +            add_asl($1, $_);
> +	}
> +        # AML listing: offset in hex, then ...., then code
> +	if (s#^([0-9A-F]+)\.\.\.\.\s*##) {
> +            add_aml($1, $_);
> +        }
> +	# Ignore everything else
> +}
> +
> +# Now go over code, look for EJ0_ methods
> +# For each such method, output slot mask from the
> +# preceding _ADR line, as well as the method name offset.
> +for (my $i = 0; $i <= $#asl; $i++) {
> +    my $l = $asl[$i];
> +    # match: Method (EJ0_,1)
> +    if (not $l =~ m#^Method\s*\(\s*EJ0_\s*[,)]#) {
> +        # Make sure we do not miss any EJ0_:
> +        # die if EJ0_ is found anywhere else in source code
> +        if ($l =~ m#EJ0_#) {
> +            die "Stray EJ0_ detected at input line $asl_lineno[$i]: $asl[$i]";
> +        }
> +        next;
> +    }
> +    # EJ0_ found. Previous line must be _ADR
> +    my $p = $i > 0 ? $asl[$i - 1] : "";
> +    # match: Name (_ADR, 0x<address>)
> +    if (not ($p =~ m#Name\s*\(\s*_ADR\s*,\s*0x([0-9A-Fa-f]+)\s*\)#)) {
> +        die "_ADR not found before EJ0_ ".
> +            "at input line $asl_lineno[$i]: $asl[$i]";
> +    }
> +    my $adr = hex($1);
> +    my $slot = $adr >> 16;
> +    if ($slot > 31) {
> +        die "_ADR device out of range: actual $slot " .
> +            "expected 0 to 31 at input line $asl_lineno[$i]: $asl[$i]";
> +    }
> +
> +    # We have offset of EJ0_ method in code
> +    # Now find EJ0_ itself
> +    my $offset = $asl_to_aml_offset[$i];
> +    my $ej0 = aml_method_name($asl_lineno[$i], $offset);
> +    # Verify AML: name must be EJ0_:
> +    if (($aml[$ej0 + 0] != ord('E')) or
> +        ($aml[$ej0 + 1] != ord('J')) or
> +        ($aml[$ej0 + 2] != ord('0')) or
> +        ($aml[$ej0 + 3] != ord('_'))) {
> +        die "AML after input line $asl_lineno[$i] offset $ej0 " .
> +            "does not match EJ0_";
> +    }
> +
> +    # OK we are done. Output slot mask and offset
> +    push @output, sprintf("    {.slot_mask = 0x%x, .offset = 0x%x}",
> +                          0x1 << $slot, $ej0);
> +}
> +
> +# Pretty print output
> +if ($#output < 0) {
> +    die "No EJ0_ Method found!"
> +}
> +print <<EOF;
> +static struct aml_ej0_data {
> +    unsigned slot_mask;
> +    unsigned offset;
> +} aml_ej0_data[] = {
> +EOF
> +print join(",\n", @output);
> +print <<EOF;
> +
> +};
> +EOF
> +
> -- 
> 1.7.5.53.gc233e

--
			Gleb.



More information about the SeaBIOS mailing list