|
|
1.1 ! root 1: #!/usr/bin/python ! 2: # Copyright (C) 2011 Red Hat, Inc., Michael S. Tsirkin <[email protected]> ! 3: # ! 4: # This file may be distributed under the terms of the GNU GPLv3 license. ! 5: ! 6: # Process mixed ASL/AML listing (.lst file) produced by iasl -l ! 7: # Locate and execute ACPI_EXTRACT directives, output offset info ! 8: # ! 9: # Documentation of ACPI_EXTRACT_* directive tags: ! 10: # ! 11: # These directive tags output offset information from AML for BIOS runtime ! 12: # table generation. ! 13: # Each directive is of the form: ! 14: # ACPI_EXTRACT_<TYPE> <array_name> <Operator> (...) ! 15: # and causes the extractor to create an array ! 16: # named <array_name> with offset, in the generated AML, ! 17: # of an object of a given type in the following <Operator>. ! 18: # ! 19: # A directive must fit on a single code line. ! 20: # ! 21: # Object type in AML is verified, a mismatch causes a build failure. ! 22: # ! 23: # Directives and operators currently supported are: ! 24: # ACPI_EXTRACT_NAME_DWORD_CONST - extract a Dword Const object from Name() ! 25: # ACPI_EXTRACT_NAME_WORD_CONST - extract a Word Const object from Name() ! 26: # ACPI_EXTRACT_NAME_BYTE_CONST - extract a Byte Const object from Name() ! 27: # ACPI_EXTRACT_METHOD_STRING - extract a NameString from Method() ! 28: # ACPI_EXTRACT_NAME_STRING - extract a NameString from Name() ! 29: # ACPI_EXTRACT_PROCESSOR_START - start of Processor() block ! 30: # ACPI_EXTRACT_PROCESSOR_STRING - extract a NameString from Processor() ! 31: # ACPI_EXTRACT_PROCESSOR_END - offset at last byte of Processor() + 1 ! 32: # ! 33: # ACPI_EXTRACT_ALL_CODE - create an array storing the generated AML bytecode ! 34: # ! 35: # ACPI_EXTRACT is not allowed anywhere else in code, except in comments. ! 36: ! 37: import re; ! 38: import sys; ! 39: import fileinput; ! 40: ! 41: aml = [] ! 42: asl = [] ! 43: output = {} ! 44: debug = "" ! 45: ! 46: class asl_line: ! 47: line = None ! 48: lineno = None ! 49: aml_offset = None ! 50: ! 51: def die(diag): ! 52: sys.stderr.write("Error: %s; %s\n" % (diag, debug)) ! 53: sys.exit(1) ! 54: ! 55: #Store an ASL command, matching AML offset, and input line (for debugging) ! 56: def add_asl(lineno, line): ! 57: l = asl_line() ! 58: l.line = line ! 59: l.lineno = lineno ! 60: l.aml_offset = len(aml) ! 61: asl.append(l) ! 62: ! 63: #Store an AML byte sequence ! 64: #Verify that offset output by iasl matches # of bytes so far ! 65: def add_aml(offset, line): ! 66: o = int(offset, 16); ! 67: # Sanity check: offset must match size of code so far ! 68: if (o != len(aml)): ! 69: die("Offset 0x%x != 0x%x" % (o, len(aml))) ! 70: # Strip any trailing dots and ASCII dump after " ! 71: line = re.sub(r'\s*\.*\s*".*$',"", line) ! 72: # Strip traling whitespace ! 73: line = re.sub(r'\s+$',"", line) ! 74: # Strip leading whitespace ! 75: line = re.sub(r'^\s+',"", line) ! 76: # Split on whitespace ! 77: code = re.split(r'\s+', line) ! 78: for c in code: ! 79: # Require a legal hex number, two digits ! 80: if (not(re.search(r'^[0-9A-Fa-f][0-9A-Fa-f]$', c))): ! 81: die("Unexpected octet %s" % c); ! 82: aml.append(int(c, 16)); ! 83: ! 84: # Process aml bytecode array, decoding AML ! 85: def aml_pkglen_bytes(offset): ! 86: # PkgLength can be multibyte. Bits 8-7 give the # of extra bytes. ! 87: pkglenbytes = aml[offset] >> 6; ! 88: return pkglenbytes + 1 ! 89: ! 90: def aml_pkglen(offset): ! 91: pkgstart = offset ! 92: pkglenbytes = aml_pkglen_bytes(offset) ! 93: pkglen = aml[offset] & 0x3F ! 94: # If multibyte, first nibble only uses bits 0-3 ! 95: if ((pkglenbytes > 0) and (pkglen & 0x30)): ! 96: die("PkgLen bytes 0x%x but first nibble 0x%x expected 0x0X" % ! 97: (pkglen, pkglen)) ! 98: offset += 1 ! 99: pkglenbytes -= 1 ! 100: for i in range(pkglenbytes): ! 101: pkglen |= aml[offset + i] << (i * 8 + 4) ! 102: if (len(aml) < pkgstart + pkglen): ! 103: die("PckgLen 0x%x at offset 0x%x exceeds AML size 0x%x" % ! 104: (pkglen, offset, len(aml))) ! 105: return pkglen ! 106: ! 107: # Given method offset, find its NameString offset ! 108: def aml_method_string(offset): ! 109: #0x14 MethodOp PkgLength NameString MethodFlags TermList ! 110: if (aml[offset] != 0x14): ! 111: die( "Method offset 0x%x: expected 0x14 actual 0x%x" % ! 112: (offset, aml[offset])); ! 113: offset += 1; ! 114: pkglenbytes = aml_pkglen_bytes(offset) ! 115: offset += pkglenbytes; ! 116: return offset; ! 117: ! 118: # Given name offset, find its NameString offset ! 119: def aml_name_string(offset): ! 120: #0x08 NameOp NameString DataRef ! 121: if (aml[offset] != 0x08): ! 122: die( "Name offset 0x%x: expected 0x08 actual 0x%x" % ! 123: (offset, aml[offset])); ! 124: return offset + 1; ! 125: ! 126: # Given data offset, find dword const offset ! 127: def aml_data_dword_const(offset): ! 128: #0x08 NameOp NameString DataRef ! 129: if (aml[offset] != 0x0C): ! 130: die( "Name offset 0x%x: expected 0x0C actual 0x%x" % ! 131: (offset, aml[offset])); ! 132: return offset + 1; ! 133: ! 134: # Given data offset, find word const offset ! 135: def aml_data_word_const(offset): ! 136: #0x08 NameOp NameString DataRef ! 137: if (aml[offset] != 0x0B): ! 138: die( "Name offset 0x%x: expected 0x0B actual 0x%x" % ! 139: (offset, aml[offset])); ! 140: return offset + 1; ! 141: ! 142: # Given data offset, find byte const offset ! 143: def aml_data_byte_const(offset): ! 144: #0x08 NameOp NameString DataRef ! 145: if (aml[offset] != 0x0A): ! 146: die( "Name offset 0x%x: expected 0x0A actual 0x%x" % ! 147: (offset, aml[offset])); ! 148: return offset + 1; ! 149: ! 150: # Given name offset, find dword const offset ! 151: def aml_name_dword_const(offset): ! 152: return aml_data_dword_const(aml_name_string(offset) + 4) ! 153: ! 154: # Given name offset, find word const offset ! 155: def aml_name_word_const(offset): ! 156: return aml_data_word_const(aml_name_string(offset) + 4) ! 157: ! 158: # Given name offset, find byte const offset ! 159: def aml_name_byte_const(offset): ! 160: return aml_data_byte_const(aml_name_string(offset) + 4) ! 161: ! 162: def aml_processor_start(offset): ! 163: #0x5B 0x83 ProcessorOp PkgLength NameString ProcID ! 164: if ((aml[offset] != 0x5B) or (aml[offset + 1] != 0x83)): ! 165: die( "Name offset 0x%x: expected 0x5B 0x83 actual 0x%x 0x%x" % ! 166: (offset, aml[offset], aml[offset + 1])); ! 167: return offset ! 168: ! 169: def aml_processor_string(offset): ! 170: #0x5B 0x83 ProcessorOp PkgLength NameString ProcID ! 171: start = aml_processor_start(offset) ! 172: offset += 2 ! 173: pkglenbytes = aml_pkglen_bytes(offset) ! 174: offset += pkglenbytes ! 175: return offset ! 176: ! 177: def aml_processor_end(offset): ! 178: start = aml_processor_start(offset) ! 179: offset += 2 ! 180: pkglenbytes = aml_pkglen_bytes(offset) ! 181: pkglen = aml_pkglen(offset) ! 182: return offset + pkglen ! 183: ! 184: lineno = 0 ! 185: for line in fileinput.input(): ! 186: # Strip trailing newline ! 187: line = line.rstrip(); ! 188: # line number and debug string to output in case of errors ! 189: lineno = lineno + 1 ! 190: debug = "input line %d: %s" % (lineno, line) ! 191: #ASL listing: space, then line#, then ...., then code ! 192: pasl = re.compile('^\s+([0-9]+)\.\.\.\.\s*') ! 193: m = pasl.search(line) ! 194: if (m): ! 195: add_asl(lineno, pasl.sub("", line)); ! 196: # AML listing: offset in hex, then ...., then code ! 197: paml = re.compile('^([0-9A-Fa-f]+)\.\.\.\.\s*') ! 198: m = paml.search(line) ! 199: if (m): ! 200: add_aml(m.group(1), paml.sub("", line)) ! 201: ! 202: # Now go over code ! 203: # Track AML offset of a previous non-empty ASL command ! 204: prev_aml_offset = -1 ! 205: for i in range(len(asl)): ! 206: debug = "input line %d: %s" % (asl[i].lineno, asl[i].line) ! 207: ! 208: l = asl[i].line ! 209: ! 210: # skip if not an extract directive ! 211: a = len(re.findall(r'ACPI_EXTRACT', l)) ! 212: if (not a): ! 213: # If not empty, store AML offset. Will be used for sanity checks ! 214: # IASL seems to put {}. at random places in the listing. ! 215: # Ignore any non-words for the purpose of this test. ! 216: m = re.search(r'\w+', l) ! 217: if (m): ! 218: prev_aml_offset = asl[i].aml_offset ! 219: continue ! 220: ! 221: if (a > 1): ! 222: die("Expected at most one ACPI_EXTRACT per line, actual %d" % a) ! 223: ! 224: mext = re.search(r''' ! 225: ^\s* # leading whitespace ! 226: /\*\s* # start C comment ! 227: (ACPI_EXTRACT_\w+) # directive: group(1) ! 228: \s+ # whitspace separates directive from array name ! 229: (\w+) # array name: group(2) ! 230: \s*\*/ # end of C comment ! 231: \s*$ # trailing whitespace ! 232: ''', l, re.VERBOSE) ! 233: if (not mext): ! 234: die("Stray ACPI_EXTRACT in input") ! 235: ! 236: # previous command must have produced some AML, ! 237: # otherwise we are in a middle of a block ! 238: if (prev_aml_offset == asl[i].aml_offset): ! 239: die("ACPI_EXTRACT directive in the middle of a block") ! 240: ! 241: directive = mext.group(1) ! 242: array = mext.group(2) ! 243: offset = asl[i].aml_offset ! 244: ! 245: if (directive == "ACPI_EXTRACT_ALL_CODE"): ! 246: if array in output: ! 247: die("%s directive used more than once" % directive) ! 248: output[array] = aml ! 249: continue ! 250: if (directive == "ACPI_EXTRACT_NAME_DWORD_CONST"): ! 251: offset = aml_name_dword_const(offset) ! 252: elif (directive == "ACPI_EXTRACT_NAME_WORD_CONST"): ! 253: offset = aml_name_word_const(offset) ! 254: elif (directive == "ACPI_EXTRACT_NAME_BYTE_CONST"): ! 255: offset = aml_name_byte_const(offset) ! 256: elif (directive == "ACPI_EXTRACT_NAME_STRING"): ! 257: offset = aml_name_string(offset) ! 258: elif (directive == "ACPI_EXTRACT_METHOD_STRING"): ! 259: offset = aml_method_string(offset) ! 260: elif (directive == "ACPI_EXTRACT_PROCESSOR_START"): ! 261: offset = aml_processor_start(offset) ! 262: elif (directive == "ACPI_EXTRACT_PROCESSOR_STRING"): ! 263: offset = aml_processor_string(offset) ! 264: elif (directive == "ACPI_EXTRACT_PROCESSOR_END"): ! 265: offset = aml_processor_end(offset) ! 266: else: ! 267: die("Unsupported directive %s" % directive) ! 268: ! 269: if array not in output: ! 270: output[array] = [] ! 271: output[array].append(offset) ! 272: ! 273: debug = "at end of file" ! 274: ! 275: def get_value_type(maxvalue): ! 276: #Use type large enough to fit the table ! 277: if (maxvalue >= 0x10000): ! 278: return "int" ! 279: elif (maxvalue >= 0x100): ! 280: return "short" ! 281: else: ! 282: return "char" ! 283: ! 284: # Pretty print output ! 285: for array in output.keys(): ! 286: otype = get_value_type(max(output[array])) ! 287: odata = [] ! 288: for value in output[array]: ! 289: odata.append("0x%x" % value) ! 290: sys.stdout.write("static unsigned %s %s[] = {\n" % (otype, array)) ! 291: sys.stdout.write(",\n".join(odata)) ! 292: sys.stdout.write('\n};\n');
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.