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@xxxxxxxxxx> > --- > 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. -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html