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@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.
On Wed, Sep 21, 2011 at 05:27:32PM +0300, Gleb Natapov wrote:
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.
OK, rewriting that in python should be easy. I'll wait a bit for more comments on the design 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.
There are three requirements now: 1. don't use the name EJ0_ anywhere if you don't want it patches 2. _ADR must be an integer constant 3. put _ADR name immediately before EJ0_ method I tried to make it easy to obey these rules by adding comments in source code.
I don't believe a generic mechanism that does not place any restrictions on language use is possible without adding an AML interpreter in bios.
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).
Right. So that would be an easy extension. We could also add some directives for the tool (e.g. in C comments) so that you can e.g. find more names just by adding such a directive in dsl.
I'll be happy to work on that preferably after we merge a simple version of the tool first.