From b278ce626b5c68d53d70a5e027270020fdf42b9a Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Fri, 29 Dec 2017 09:12:08 +0000 Subject: [PATCH] acpi: update AML parser to use the new entities --- src/gopheros/device/acpi/aml/entity/entity.go | 1 + .../device/acpi/aml/entity/entity_test.go | 31 ++ src/gopheros/device/acpi/aml/entity/opcode.go | 12 +- .../device/acpi/aml/entity/opcode_test.go | 8 - .../device/acpi/aml/entity/visitor_test.go | 2 +- .../device/acpi/aml/parser/opcode_table.go | 3 +- .../device/acpi/aml/{ => parser}/parser.go | 379 ++++++++---------- .../acpi/aml/{ => parser}/parser_test.go | 232 ++++++----- .../table/tabletest/parser-testsuite-DSDT.aml | Bin 488 -> 627 bytes .../table/tabletest/parser-testsuite-DSDT.dsl | 185 +++++---- 10 files changed, 441 insertions(+), 412 deletions(-) rename src/gopheros/device/acpi/aml/{ => parser}/parser.go (71%) rename src/gopheros/device/acpi/aml/{ => parser}/parser_test.go (74%) diff --git a/src/gopheros/device/acpi/aml/entity/entity.go b/src/gopheros/device/acpi/aml/entity/entity.go index 94d7ef6..1b7997d 100644 --- a/src/gopheros/device/acpi/aml/entity/entity.go +++ b/src/gopheros/device/acpi/aml/entity/entity.go @@ -47,6 +47,7 @@ type Container interface { Last() Entity } +// FieldAccessTypeProvider is an interface implemented by all field entities. type FieldAccessTypeProvider interface { // DefaultAccessType returns the default FieldAccessType for any field unit // defined by this field. diff --git a/src/gopheros/device/acpi/aml/entity/entity_test.go b/src/gopheros/device/acpi/aml/entity/entity_test.go index 5122cd5..ce6a0bd 100644 --- a/src/gopheros/device/acpi/aml/entity/entity_test.go +++ b/src/gopheros/device/acpi/aml/entity/entity_test.go @@ -79,6 +79,19 @@ func TestEntityMethods(t *testing.T) { t.Fatalf("expected parent not to have any child nodes; got %d", got) } }) + + t.Run("FieldAccessTypeProvider implementers", func(t *testing.T) { + for specIndex, spec := range specs { + provider, ok := spec.ent.(FieldAccessTypeProvider) + if !ok { + continue + } + + if exp, got := FieldAccessTypeAny, provider.DefaultAccessType(); got != exp { + t.Errorf("[spec %d] expected provider to return access type: %d; got %d", specIndex, exp, got) + } + } + }) } func TestEntityArgAssignment(t *testing.T) { @@ -160,6 +173,24 @@ func TestEntityArgAssignment(t *testing.T) { []interface{}{NewConst(OpDwordPrefix, 2, uint64(42))}, false, }, + { + NewField(2), + []interface{}{"REG0", uint64(128)}, + nil, // Field populates its internal state using the first 2 args + true, + }, + { + NewIndexField(2), + []interface{}{"REG0", "DAT0", uint64(128)}, + nil, // IndexField populates its internal state using the first 3 args + true, + }, + { + NewBankField(2), + []interface{}{"REG0", "BNK0", uint64(0xf00f), uint64(128)}, + nil, // BankField populates its internal state using the first 4 args + true, + }, } nextSpec: diff --git a/src/gopheros/device/acpi/aml/entity/opcode.go b/src/gopheros/device/acpi/aml/entity/opcode.go index a9c608c..0a3abf2 100644 --- a/src/gopheros/device/acpi/aml/entity/opcode.go +++ b/src/gopheros/device/acpi/aml/entity/opcode.go @@ -6,6 +6,7 @@ package entity // representation of the opcode values. type AMLOpcode uint16 +// List of AML opcodes const ( // Regular opcode list OpZero = AMLOpcode(0x00) @@ -427,14 +428,3 @@ func OpIsType2(op AMLOpcode) bool { return false } } - -// OpIsBufferField returens true if this opcode describes a -// buffer field creation operation. -func OpIsBufferField(op AMLOpcode) bool { - switch op { - case OpCreateField, OpCreateBitField, OpCreateByteField, OpCreateWordField, OpCreateDWordField, OpCreateQWordField: - return true - default: - return false - } -} diff --git a/src/gopheros/device/acpi/aml/entity/opcode_test.go b/src/gopheros/device/acpi/aml/entity/opcode_test.go index 6f89051..23c0bdd 100644 --- a/src/gopheros/device/acpi/aml/entity/opcode_test.go +++ b/src/gopheros/device/acpi/aml/entity/opcode_test.go @@ -227,14 +227,6 @@ func TestOpcodeIsX(t *testing.T) { {OpPackage, OpIsDataObject, true}, {OpVarPackage, OpIsDataObject, true}, {OpLor, OpIsDataObject, false}, - // OpIsBufferField - {OpCreateField, OpIsBufferField, true}, - {OpCreateBitField, OpIsBufferField, true}, - {OpCreateByteField, OpIsBufferField, true}, - {OpCreateWordField, OpIsBufferField, true}, - {OpCreateDWordField, OpIsBufferField, true}, - {OpCreateQWordField, OpIsBufferField, true}, - {OpRevision, OpIsBufferField, false}, } for specIndex, spec := range specs { diff --git a/src/gopheros/device/acpi/aml/entity/visitor_test.go b/src/gopheros/device/acpi/aml/entity/visitor_test.go index 3c7aa4e..d4368b7 100644 --- a/src/gopheros/device/acpi/aml/entity/visitor_test.go +++ b/src/gopheros/device/acpi/aml/entity/visitor_test.go @@ -8,7 +8,7 @@ func TestScopeVisit(t *testing.T) { stopRecursing := func(Entity) bool { return false } // Append special entities under IDE0 - root := NewScope(tableHandle, "IDE0") + root := NewScope(OpScope, tableHandle, "IDE0") root.Append(NewDevice(tableHandle, "DEV0")) root.Append(NewProcessor(tableHandle, "FOO0")) root.Append(NewProcessor(tableHandle, "FOO0")) diff --git a/src/gopheros/device/acpi/aml/parser/opcode_table.go b/src/gopheros/device/acpi/aml/parser/opcode_table.go index df983dc..404592f 100644 --- a/src/gopheros/device/acpi/aml/parser/opcode_table.go +++ b/src/gopheros/device/acpi/aml/parser/opcode_table.go @@ -55,7 +55,7 @@ const ( // is returns true if f is set in this opFlag. func (fl opFlag) is(f opFlag) bool { - return (fl & f) != 0 + return (fl & f) == f } // opArgFlags encodes up to 7 opArgFlag values in a uint64 value. @@ -99,7 +99,6 @@ const ( opArgTermList opArgTermObj opArgByteList - opArgPackage opArgString opArgByteData opArgWord diff --git a/src/gopheros/device/acpi/aml/parser.go b/src/gopheros/device/acpi/aml/parser/parser.go similarity index 71% rename from src/gopheros/device/acpi/aml/parser.go rename to src/gopheros/device/acpi/aml/parser/parser.go index 2b25bdf..040134c 100644 --- a/src/gopheros/device/acpi/aml/parser.go +++ b/src/gopheros/device/acpi/aml/parser/parser.go @@ -1,6 +1,7 @@ -package aml +package parser import ( + "gopheros/device/acpi/aml/entity" "gopheros/device/acpi/table" "gopheros/kernel" "gopheros/kernel/kfmt" @@ -17,8 +18,8 @@ var ( type Parser struct { r amlStreamReader errWriter io.Writer - root ScopeEntity - scopeStack []ScopeEntity + root entity.Container + scopeStack []entity.Container tableName string tableHandle uint8 @@ -30,7 +31,7 @@ type Parser struct { } // NewParser returns a new AML parser instance. -func NewParser(errWriter io.Writer, rootEntity ScopeEntity) *Parser { +func NewParser(errWriter io.Writer, rootEntity entity.Container) *Parser { return &Parser{ errWriter: errWriter, root: rootEntity, @@ -65,25 +66,29 @@ func (p *Parser) ParseAML(tableHandle uint8, tableName string, header *table.SDT } p.scopeExit() - // Pass 3: check parents and resolve forward references + // Pass 3: check parents and resolve symbol references var resolveFailed bool - scopeVisit(0, p.root, EntityTypeAny, func(_ int, ent Entity) bool { + entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { // Skip method bodies; their contents will be lazily resolved by the interpreter - if _, isMethod := ent.(*Method); isMethod { + if _, isMethod := ent.(*entity.Method); isMethod { return false } // Populate parents for any entity args that are also entities but are not // linked to a parent (e.g. a package inside a named entity). - for _, arg := range ent.getArgs() { - if argEnt, isArgEnt := arg.(Entity); isArgEnt && argEnt.Parent() == nil { - argEnt.setParent(ent.Parent()) + for _, arg := range ent.Args() { + if argEnt, isArgEnt := arg.(entity.Entity); isArgEnt && argEnt.Parent() == nil { + argEnt.SetParent(ent.Parent()) } } - if res, ok := ent.(resolver); ok && !res.Resolve(p.errWriter, p.root) { - resolveFailed = true - return false + // Resolve any symbol references + if lazyRef, ok := ent.(entity.LazyRefResolver); ok { + if err := lazyRef.ResolveSymbolRefs(p.root); err != nil { + kfmt.Fprintf(p.errWriter, "%s\n", err.Message) + resolveFailed = true + return false + } } return true @@ -117,7 +122,7 @@ func (p *Parser) detectMethodDeclarations() { continue } - if next.op != opMethod { + if next.op != entity.OpMethod { continue } @@ -187,11 +192,11 @@ func (p *Parser) parseObj() bool { } // If we encounter a named scope we need to look it up and parse the arg list relative to it - switch info.op { - case opScope: + switch { + case info.op == entity.OpScope: return p.parseScope(curOffset + pkgLen) - case opDevice, opMethod: - return p.parseNamespacedObj(info.op, curOffset+pkgLen) + case info.flags.is(opFlagNamed | opFlagScoped): + return p.parseNamespacedObj(info, curOffset+pkgLen) } // Create appropriate object for opcode type and attach it to current scope unless it is @@ -217,33 +222,22 @@ func (p *Parser) parseObj() bool { } // finalizeObj applies post-parse logic for special object types. -func (p *Parser) finalizeObj(op opcode, obj Entity) bool { - obj.setTableHandle(p.tableHandle) - +func (p *Parser) finalizeObj(op entity.AMLOpcode, obj entity.Entity) bool { switch op { - case opElse: + case entity.OpElse: // If this is an else block we need to append it as an argument to the // If block // Pop Else block of the current scope curScope := p.scopeCurrent() - curScope.removeChild(curScope.lastChild()) - prevObj := curScope.lastChild() - if prevObj.getOpcode() != opIf { + curScope.Remove(curScope.Last()) + prevObj := curScope.Last() + if prevObj.Opcode() != entity.OpIf { kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] encountered else block without a matching if block\n", p.tableName, p.r.Offset()) return false } // If predicate(0) then(1) else(2) - prevObj.setArg(2, obj) - case opDevice: - // Build method map - dev := obj.(*Device) - dev.methodMap = make(map[string]*Method) - scopeVisit(0, dev, EntityTypeMethod, func(_ int, ent Entity) bool { - method := ent.(*Method) - dev.methodMap[method.name] = method - return false - }) + prevObj.SetArg(2, obj) } return true @@ -262,14 +256,14 @@ func (p *Parser) parseScope(maxReadOffset uint32) bool { return false } - target := scopeFind(p.scopeCurrent(), p.root, name) + target := entity.FindInScope(p.scopeCurrent(), p.root, name) if target == nil { kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] undefined scope: %s\n", p.tableName, p.r.Offset(), name) return false } - switch target.getOpcode() { - case opDevice, opProcessor, opThermalZone, opPowerRes: + switch target.Opcode() { + case entity.OpDevice, entity.OpProcessor, entity.OpThermalZone, entity.OpPowerRes: // ok default: // Only allow if this is a named scope @@ -279,7 +273,7 @@ func (p *Parser) parseScope(maxReadOffset uint32) bool { } } - p.scopeEnter(target.(ScopeEntity)) + p.scopeEnter(target.(entity.Container)) ok = p.parseObjList(maxReadOffset) p.scopeExit() @@ -287,48 +281,50 @@ func (p *Parser) parseScope(maxReadOffset uint32) bool { } // parseNamespacedObj reads a scope target name from the AML bytestream, -// attaches the device or method (depending on the opcode) object to the -// correct parent scope, enters the device scope and parses the object list -// contained in the device definition. -func (p *Parser) parseNamespacedObj(op opcode, maxReadOffset uint32) bool { +// attaches the appropriate object depending on the opcode to the correct +// parent scope and then parses any contained objects. The contained objects +// will be appended inside the newly constructed scope. +func (p *Parser) parseNamespacedObj(info *opcodeInfo, maxReadOffset uint32) bool { scopeExpr, ok := p.parseNameString() if !ok { return false } - parent, name := scopeResolvePath(p.scopeCurrent(), p.root, scopeExpr) + parent, name := entity.ResolveScopedPath(p.scopeCurrent(), p.root, scopeExpr) if parent == nil { kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] undefined scope target: %s (current scope: %s)\n", p.tableName, p.r.Offset(), scopeExpr, p.scopeCurrent().Name()) return false } - var obj ScopeEntity - switch op { - case opDevice: - obj = &Device{scopeEntity: scopeEntity{name: name}} - case opMethod: - m := &Method{scopeEntity: scopeEntity{name: name}} - - flags, flagOk := p.parseNumConstant(1) - if !flagOk { - return false - } - m.argCount = (uint8(flags) & 0x7) // bits[0:2] - m.serialized = (uint8(flags)>>3)&0x1 == 0x1 // bit 3 - m.syncLevel = (uint8(flags) >> 4) & 0xf // bits[4:7] - - obj = m + var obj entity.Container + switch info.op { + case entity.OpDevice: + obj = entity.NewDevice(p.tableHandle, name) + case entity.OpProcessor: + obj = entity.NewProcessor(p.tableHandle, name) + case entity.OpPowerRes: + obj = entity.NewPowerResource(p.tableHandle, name) + case entity.OpThermalZone: + obj = entity.NewThermalZone(p.tableHandle, name) + case entity.OpMethod: + obj = entity.NewMethod(p.tableHandle, name) + default: + kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] unsupported namespaced op: %s (current scope: %s)\n", p.tableName, p.r.Offset(), info.op.String(), p.scopeCurrent().Name()) + return false } + // Parse any args that follow the name. The last arg is always an ArgTermList parent.Append(obj) - p.scopeEnter(obj) - ok = p.parseObjList(maxReadOffset) - p.scopeExit() + for argIndex := uint8(1); argIndex < info.argFlags.argCount(); argIndex++ { + if !p.parseArg(info, obj, argIndex, info.argFlags.arg(argIndex), maxReadOffset) { + return false + } + } - return ok && p.finalizeObj(op, obj) + return ok && p.finalizeObj(info.op, obj) } -func (p *Parser) parseArg(info *opcodeInfo, obj Entity, argIndex uint8, argType opArgFlag, maxReadOffset uint32) bool { +func (p *Parser) parseArg(info *opcodeInfo, obj entity.Entity, argIndex uint8, argType opArgFlag, maxReadOffset uint32) bool { var ( arg interface{} ok bool @@ -359,19 +355,20 @@ func (p *Parser) parseArg(info *opcodeInfo, obj Entity, argIndex uint8, argType // If object is a scoped entity enter it's scope before parsing // the term list. Otherwise, create an unnamed scope, attach it // as the next argument to obj and enter that. - if s, isScopeEnt := obj.(ScopeEntity); isScopeEnt { + if s, isScopeEnt := obj.(entity.Container); isScopeEnt { p.scopeEnter(s) } else { - ns := &scopeEntity{op: opScope} + // Create an unnamed scope (e.g if, else, while scope) + ns := entity.NewScope(info.op, p.tableHandle, "") p.scopeEnter(ns) - obj.setArg(argIndex, ns) + obj.SetArg(argIndex, ns) } ok = p.parseObjList(maxReadOffset) p.scopeExit() return ok case opArgFieldList: - return p.parseFieldList(info.op, obj.getArgs(), maxReadOffset) + return p.parseFieldList(obj, maxReadOffset) case opArgByteList: var bl []byte for p.r.Offset() < maxReadOffset { @@ -388,45 +385,68 @@ func (p *Parser) parseArg(info *opcodeInfo, obj Entity, argIndex uint8, argType return false } - return obj.setArg(argIndex, arg) + return obj.SetArg(argIndex, arg) } -func (p *Parser) parseArgObj() (Entity, bool) { +func (p *Parser) parseArgObj() (entity.Entity, bool) { if ok := p.parseObj(); !ok { return nil, false } curScope := p.scopeCurrent() - obj := curScope.lastChild() - curScope.removeChild(obj) + obj := curScope.Last() + curScope.Remove(obj) return obj, true } -func (p *Parser) makeObjForOpcode(info *opcodeInfo) Entity { - var obj Entity +func (p *Parser) makeObjForOpcode(info *opcodeInfo) entity.Entity { + var obj entity.Entity switch { - case info.op == opOpRegion: - obj = new(regionEntity) - case info.op == opBuffer: - obj = new(bufferEntity) - case info.op == opMutex: - obj = new(mutexEntity) - case info.op == opEvent: - obj = new(eventEntity) - case opIsBufferField(info.op): - obj = new(bufferFieldEntity) + case info.op == entity.OpOpRegion: + obj = entity.NewRegion(p.tableHandle) + case info.op == entity.OpBuffer: + obj = entity.NewBuffer(p.tableHandle) + case info.op == entity.OpMutex: + obj = entity.NewMutex(p.tableHandle) + case info.op == entity.OpEvent: + obj = entity.NewEvent(p.tableHandle) + case info.op == entity.OpField: + obj = entity.NewField(p.tableHandle) + case info.op == entity.OpIndexField: + obj = entity.NewIndexField(p.tableHandle) + case info.op == entity.OpBankField: + obj = entity.NewBankField(p.tableHandle) + case info.op == entity.OpCreateField: + obj = entity.NewBufferField(info.op, p.tableHandle, 0) + case info.op == entity.OpCreateBitField: + obj = entity.NewBufferField(info.op, p.tableHandle, 1) + case info.op == entity.OpCreateByteField: + obj = entity.NewBufferField(info.op, p.tableHandle, 8) + case info.op == entity.OpCreateWordField: + obj = entity.NewBufferField(info.op, p.tableHandle, 16) + case info.op == entity.OpCreateDWordField: + obj = entity.NewBufferField(info.op, p.tableHandle, 32) + case info.op == entity.OpCreateQWordField: + obj = entity.NewBufferField(info.op, p.tableHandle, 64) + case info.op == entity.OpZero: + obj = entity.NewConst(info.op, p.tableHandle, uint64(0)) + case info.op == entity.OpOne: + obj = entity.NewConst(info.op, p.tableHandle, uint64(1)) + case info.op == entity.OpOnes: + obj = entity.NewConst(info.op, p.tableHandle, uint64((1<<64)-1)) case info.flags.is(opFlagConstant): - obj = new(constEntity) + obj = entity.NewConst(info.op, p.tableHandle, nil) // will be parsed as an arg + case info.op == entity.OpPackage || info.op == entity.OpVarPackage: + obj = entity.NewPackage(info.op, p.tableHandle) case info.flags.is(opFlagScoped): - obj = new(scopeEntity) + obj = entity.NewScope(info.op, p.tableHandle, "") case info.flags.is(opFlagNamed): - obj = new(namedEntity) + obj = entity.NewGenericNamed(info.op, p.tableHandle) default: - obj = new(unnamedEntity) + obj = entity.NewGeneric(info.op, p.tableHandle) } - obj.setOpcode(info.op) return obj } @@ -447,7 +467,7 @@ func (p *Parser) parseNamedRef() bool { var ( curOffset uint32 argIndex uint8 - arg Entity + arg entity.Entity argList []interface{} ) @@ -459,14 +479,14 @@ func (p *Parser) parseNamedRef() bool { p.r.SetOffset(curOffset) switch { - case ok && (opIsType2(nextOpcode.op) || opIsArg(nextOpcode.op) || opIsDataObject(nextOpcode.op)): + case ok && (entity.OpIsType2(nextOpcode.op) || entity.OpIsArg(nextOpcode.op) || entity.OpIsDataObject(nextOpcode.op)): arg, ok = p.parseArgObj() default: // It may be a nested invocation or named ref ok = p.parseNamedRef() if ok { - arg = p.scopeCurrent().lastChild() - p.scopeCurrent().removeChild(arg) + arg = p.scopeCurrent().Last() + p.scopeCurrent().Remove(arg) } } @@ -486,14 +506,11 @@ func (p *Parser) parseNamedRef() bool { return false } - return p.scopeCurrent().Append(&methodInvocationEntity{ - unnamedEntity: unnamedEntity{args: argList}, - methodName: name, - }) + return p.scopeCurrent().Append(entity.NewInvocation(p.tableHandle, name)) } // Otherwise this is a reference to a named entity - return p.scopeCurrent().Append(&namedReference{targetName: name}) + return p.scopeCurrent().Append(entity.NewReference(p.tableHandle, name)) } func (p *Parser) nextOpcode() (*opcodeInfo, bool) { @@ -533,69 +550,30 @@ func (p *Parser) nextOpcode() (*opcodeInfo, bool) { // AccessField := 0x1 AccessType AccessAttrib // ConnectField := 0x02 NameString | 0x02 BufferData // ExtendedAccessField := 0x3 AccessType ExtendedAccessType AccessLength -func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uint32) bool { +func (p *Parser) parseFieldList(fieldEnt entity.Entity, maxReadOffset uint32) bool { var ( - // for fieldUnit, name0 is the region name and name1 is not used; - // for indexField, - name0, name1 string - flags uint64 + ok bool - ok bool - bitWidth uint32 - curBitOffset uint32 - accessAttrib FieldAccessAttrib - accessByteCount uint8 - unitName string - ) + accessType entity.FieldAccessType - switch op { - case opField: // Field := PkgLength Region AccessFlags FieldList - if len(args) != 2 { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d, opcode 0x%2x] invalid arg count: %d\n", p.tableName, p.r.Offset(), uint32(op), len(args)) - return false - } - - name0, ok = args[0].(string) - if !ok { - return false - } - - flags, ok = args[1].(uint64) - if !ok { - return false - } - case opIndexField: // Field := PkgLength IndexFieldName DataFieldName AccessFlags FieldList - if len(args) != 3 { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d, opcode 0x%2x] invalid arg count: %d\n", p.tableName, p.r.Offset(), uint32(op), len(args)) - return false - } - - name0, ok = args[0].(string) - if !ok { - return false - } - - name1, ok = args[1].(string) - if !ok { - return false - } - - flags, ok = args[2].(uint64) - if !ok { - return false - } - } - - // Decode flags - accessType := FieldAccessType(flags & 0xf) // access type; bits[0:3] - lock := (flags>>4)&0x1 == 0x1 // lock; bit 4 - updateRule := FieldUpdateRule((flags >> 5) & 0x3) // update rule; bits[5:6] - - var ( + bitWidth uint32 + curBitOffset uint32 connectionName string - resolvedConnection Entity + unitName string + resolvedConnection entity.Entity + accessAttrib entity.FieldAccessAttrib + accessByteCount uint8 ) + // Load default field access rule; it applies to all field units unless + // overridden via a directive in the field unit list + if accessProvider, isProvider := fieldEnt.(entity.FieldAccessTypeProvider); isProvider { + accessType = accessProvider.DefaultAccessType() + } else { + // not a field entity + return false + } + for p.r.Offset() < maxReadOffset { next, err := p.r.ReadByte() if err != nil { @@ -616,7 +594,7 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin if err != nil { return false } - accessType = FieldAccessType(next & 0xf) // access type; bits[0:3] + accessType = entity.FieldAccessType(next & 0xf) // access type; bits[0:3] attrib, err := p.r.ReadByte() if err != nil { @@ -626,7 +604,7 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin // To specify AccessAttribBytes, RawBytes and RawProcessBytes // the ASL compiler will emit an ExtendedAccessField opcode. accessByteCount = 0 - accessAttrib = FieldAccessAttrib(attrib) + accessAttrib = entity.FieldAccessAttrib(attrib) continue case 0x2: // ConnectField => <0x2> NameString> | <0x02> TermObj => Buffer @@ -643,7 +621,7 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin if err != nil { return false } - accessType = FieldAccessType(next & 0xf) // access type; bits[0:3] + accessType = entity.FieldAccessType(next & 0xf) // access type; bits[0:3] extAccessAttrib, err := p.r.ReadByte() if err != nil { @@ -657,11 +635,11 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin switch extAccessAttrib { case 0x0b: - accessAttrib = FieldAccessAttribBytes + accessAttrib = entity.FieldAccessAttribBytes case 0xe: - accessAttrib = FieldAccessAttribRawBytes + accessAttrib = entity.FieldAccessAttribRawBytes case 0x0f: - accessAttrib = FieldAccessAttribRawProcessBytes + accessAttrib = entity.FieldAccessAttribRawProcessBytes } default: // NamedField _ = p.r.UnreadByte() @@ -675,55 +653,20 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin } // According to the spec, the field elements are should - // be visible at the same scope as the Field/IndexField - switch op { - case opField: - p.scopeCurrent().Append(&fieldUnitEntity{ - fieldEntity: fieldEntity{ - namedEntity: namedEntity{ - tableHandle: p.tableHandle, - op: op, - name: unitName, - }, - bitOffset: curBitOffset, - bitWidth: bitWidth, - lock: lock, - updateRule: updateRule, - accessType: accessType, - accessAttrib: accessAttrib, - byteCount: accessByteCount, - }, - connectionName: connectionName, - resolvedConnection: resolvedConnection, - regionName: name0, - }) - case opIndexField: - p.scopeCurrent().Append(&indexFieldEntity{ - fieldEntity: fieldEntity{ - namedEntity: namedEntity{ - tableHandle: p.tableHandle, - op: op, - name: unitName, - }, - bitOffset: curBitOffset, - bitWidth: bitWidth, - lock: lock, - updateRule: updateRule, - accessType: accessType, - accessAttrib: accessAttrib, - byteCount: accessByteCount, - }, - connectionName: connectionName, - resolvedConnection: resolvedConnection, - indexRegName: name0, - dataRegName: name1, - }) - } + // be visible at the same scope as the Field that declares them + unit := entity.NewFieldUnit(p.tableHandle, unitName) + unit.Field = fieldEnt + unit.AccessType = accessType + unit.AccessAttrib = accessAttrib + unit.ByteCount = accessByteCount + unit.BitOffset = curBitOffset + unit.BitWidth = bitWidth + unit.ConnectionName = connectionName + unit.Connection = resolvedConnection + p.scopeCurrent().Append(unit) curBitOffset += bitWidth - } - } return ok && p.r.Offset() == maxReadOffset @@ -859,10 +802,8 @@ func (p *Parser) parseSimpleName() (interface{}, bool) { var obj interface{} switch { - case ok && nextOpcode.op >= opLocal0 && nextOpcode.op <= opLocal7: - obj, ok = &unnamedEntity{op: nextOpcode.op}, true - case ok && nextOpcode.op >= opArg0 && nextOpcode.op <= opArg6: - obj, ok = &unnamedEntity{op: nextOpcode.op}, true + case ok && entity.OpIsArg(nextOpcode.op): + obj, ok = entity.NewGeneric(nextOpcode.op, p.tableHandle), true default: // Rewind and try parsing as NameString p.r.SetOffset(curOffset) @@ -890,10 +831,10 @@ func (p *Parser) parseTarget() (interface{}, bool) { if ok { switch { - case nextOpcode.op == opZero: // this is actually a NullName + case nextOpcode.op == entity.OpZero: // this is actually a NullName p.r.SetOffset(curOffset + 1) - return &constEntity{op: opStringPrefix, val: ""}, true - case opIsArg(nextOpcode.op) || nextOpcode.op == opRefOf || nextOpcode.op == opDerefOf || nextOpcode.op == opIndex || nextOpcode.op == opDebug: // LocalObj | ArgObj | Type6 | DebugObj + return entity.NewConst(entity.OpStringPrefix, p.tableHandle, ""), true + case entity.OpIsArg(nextOpcode.op) || nextOpcode.op == entity.OpRefOf || nextOpcode.op == entity.OpDerefOf || nextOpcode.op == entity.OpIndex || nextOpcode.op == entity.OpDebug: // LocalObj | ArgObj | Type6 | DebugObj default: // Unexpected opcode return nil, false @@ -905,8 +846,8 @@ func (p *Parser) parseTarget() (interface{}, bool) { // In this case, this is either a NameString or a control method invocation. if ok := p.parseNamedRef(); ok { - obj := p.scopeCurrent().lastChild() - p.scopeCurrent().removeChild(obj) + obj := p.scopeCurrent().Last() + p.scopeCurrent().Remove(obj) return obj, ok } @@ -996,12 +937,12 @@ func (p *Parser) parseNameString() (string, bool) { } // scopeCurrent returns the currently active scope. -func (p *Parser) scopeCurrent() ScopeEntity { +func (p *Parser) scopeCurrent() entity.Container { return p.scopeStack[len(p.scopeStack)-1] } // scopeEnter enters the given scope. -func (p *Parser) scopeEnter(s ScopeEntity) { +func (p *Parser) scopeEnter(s entity.Container) { p.scopeStack = append(p.scopeStack, s) } diff --git a/src/gopheros/device/acpi/aml/parser_test.go b/src/gopheros/device/acpi/aml/parser/parser_test.go similarity index 74% rename from src/gopheros/device/acpi/aml/parser_test.go rename to src/gopheros/device/acpi/aml/parser/parser_test.go index 654df99..fa223a1 100644 --- a/src/gopheros/device/acpi/aml/parser_test.go +++ b/src/gopheros/device/acpi/aml/parser/parser_test.go @@ -1,6 +1,7 @@ -package aml +package parser import ( + "gopheros/device/acpi/aml/entity" "gopheros/device/acpi/table" "io/ioutil" "os" @@ -23,19 +24,7 @@ func TestParser(t *testing.T) { tableFiles: spec, } - // Create default scopes - rootNS := &scopeEntity{op: opScope, name: `\`} - rootNS.Append(&scopeEntity{op: opScope, name: `_GPE`}) // General events in GPE register block - rootNS.Append(&scopeEntity{op: opScope, name: `_PR_`}) // ACPI 1.0 processor namespace - rootNS.Append(&scopeEntity{op: opScope, name: `_SB_`}) // System bus with all device objects - rootNS.Append(&scopeEntity{op: opScope, name: `_SI_`}) // System indicators - rootNS.Append(&scopeEntity{op: opScope, name: `_TZ_`}) // ACPI 1.0 thermal zone namespace - - // Inject pre-defined OSPM objects - rootNS.Append(&constEntity{name: "_OS_", val: "gopheros"}) - rootNS.Append(&constEntity{name: "_REV", val: uint64(2)}) - - p := NewParser(os.Stderr, rootNS) + p := NewParser(os.Stderr, genDefaultScopes()) for _, tableName := range spec { tableName = strings.Replace(tableName, ".aml", "", -1) @@ -50,25 +39,18 @@ func TestParser(t *testing.T) { func TestTableHandleAssignment(t *testing.T) { var resolver = mockResolver{tableFiles: []string{"parser-testsuite-DSDT.aml"}} - // Create default scopes - rootNS := &scopeEntity{op: opScope, name: `\`} - rootNS.Append(&scopeEntity{op: opScope, name: `_GPE`}) // General events in GPE register block - rootNS.Append(&scopeEntity{op: opScope, name: `_PR_`}) // ACPI 1.0 processor namespace - rootNS.Append(&scopeEntity{op: opScope, name: `_SB_`}) // System bus with all device objects - rootNS.Append(&scopeEntity{op: opScope, name: `_SI_`}) // System indicators - rootNS.Append(&scopeEntity{op: opScope, name: `_TZ_`}) // ACPI 1.0 thermal zone namespace - + rootNS := genDefaultScopes() p := NewParser(ioutil.Discard, rootNS) - expHandle := uint8(42) + expHandle := uint8(0x0f) tableName := "parser-testsuite-DSDT" if err := p.ParseAML(expHandle, tableName, resolver.LookupTable(tableName)); err != nil { t.Error(err) } // Drop all entities that were assigned the handle value - var unloadList []Entity - scopeVisit(0, p.root, EntityTypeAny, func(_ int, ent Entity) bool { + var unloadList []entity.Entity + entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { if ent.TableHandle() == expHandle { unloadList = append(unloadList, ent) return false @@ -78,13 +60,13 @@ func TestTableHandleAssignment(t *testing.T) { for _, ent := range unloadList { if p := ent.Parent(); p != nil { - p.removeChild(ent) + p.Remove(ent) } } // We should end up with the original tree var visitedNodes int - scopeVisit(0, p.root, EntityTypeAny, func(_ int, ent Entity) bool { + entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { visitedNodes++ if ent.TableHandle() == expHandle { t.Errorf("encountered entity that should have been pruned: %#+v", ent) @@ -102,15 +84,7 @@ func TestParserForwardDeclParsing(t *testing.T) { tableFiles: []string{"parser-testsuite-fwd-decls-DSDT.aml"}, } - // Create default scopes - rootNS := &scopeEntity{op: opScope, name: `\`} - rootNS.Append(&scopeEntity{op: opScope, name: `_GPE`}) // General events in GPE register block - rootNS.Append(&scopeEntity{op: opScope, name: `_PR_`}) // ACPI 1.0 processor namespace - rootNS.Append(&scopeEntity{op: opScope, name: `_SB_`}) // System bus with all device objects - rootNS.Append(&scopeEntity{op: opScope, name: `_SI_`}) // System indicators - rootNS.Append(&scopeEntity{op: opScope, name: `_TZ_`}) // ACPI 1.0 thermal zone namespace - - p := NewParser(ioutil.Discard, rootNS) + p := NewParser(ioutil.Discard, genDefaultScopes()) for _, tableName := range resolver.tableFiles { tableName = strings.Replace(tableName, ".aml", "", -1) @@ -172,7 +146,7 @@ func TestParserErrorHandling(t *testing.T) { t.Run("ParseAML errors", func(t *testing.T) { t.Run("parseObjList error", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) // Setup resolver to serve an AML stream containing an invalid opcode header := mockParserPayload(p, []byte{0x5b, 0x00}) @@ -190,12 +164,10 @@ func TestParserErrorHandling(t *testing.T) { }) t.Run("unresolved entities", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) // Inject a reference entity to the tree - p.root.Append(&namedReference{ - targetName: "UNKNOWN", - }) + p.root.Append(entity.NewReference(42, "UNKNOWN")) // Setup resolver to serve an empty AML stream header := mockParserPayload(p, nil) @@ -208,11 +180,11 @@ func TestParserErrorHandling(t *testing.T) { t.Run("parseObj errors", func(t *testing.T) { t.Run("parsePkgLength error", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) // Setup resolver to serve an AML stream containing an incomplete // buffer specification - header := mockParserPayload(p, []byte{byte(opBuffer)}) + header := mockParserPayload(p, []byte{byte(entity.OpBuffer)}) if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { t.Fatal("expected parsePkgLength to return an error") @@ -220,11 +192,11 @@ func TestParserErrorHandling(t *testing.T) { }) t.Run("incomplete object list", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) // Setup resolver to serve an AML stream containing an incomplete // buffer arglist specification - header := mockParserPayload(p, []byte{byte(opBuffer), 0x10}) + header := mockParserPayload(p, []byte{byte(entity.OpBuffer), 0x10}) if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { t.Fatal("expected parsePkgLength to return an error") @@ -234,13 +206,12 @@ func TestParserErrorHandling(t *testing.T) { t.Run("finalizeObj errors", func(t *testing.T) { t.Run("else without matching if", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} - p.root.Append(&constEntity{val: 0x42}) - p.root.Append(&scopeEntity{op: opElse}) + p.root = entity.NewScope(entity.OpScope, 42, `\`) + p.root.Append(entity.NewConst(entity.OpDwordPrefix, 42, uint64(0x42))) // Setup resolver to serve an AML stream containing an // empty else statement without a matching if - header := mockParserPayload(p, []byte{byte(opElse), 0x0}) + header := mockParserPayload(p, []byte{byte(entity.OpElse), 0x0}) if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { t.Fatal("expected finalizeObj to return an error") @@ -251,10 +222,10 @@ func TestParserErrorHandling(t *testing.T) { t.Run("parseScope errors", func(t *testing.T) { t.Run("parseNameString error", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) header := mockParserPayload(p, []byte{ - byte(opScope), + byte(entity.OpScope), 0x10, // pkglen }) @@ -264,10 +235,10 @@ func TestParserErrorHandling(t *testing.T) { }) t.Run("unknown scope", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) header := mockParserPayload(p, []byte{ - byte(opScope), + byte(entity.OpScope), 0x10, // pkglen 'F', 'O', 'O', 'F', }) @@ -278,10 +249,10 @@ func TestParserErrorHandling(t *testing.T) { }) t.Run("nameless scope", func(t *testing.T) { - p.root = &scopeEntity{} + p.root = entity.NewScope(entity.OpScope, 42, ``) header := mockParserPayload(p, []byte{ - byte(opScope), + byte(entity.OpScope), 0x02, // pkglen '\\', // scope name: "\" (root scope) 0x00, // null string @@ -295,58 +266,75 @@ func TestParserErrorHandling(t *testing.T) { t.Run("parseNamespacedObj errors", func(t *testing.T) { t.Run("parseNameString error", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) mockParserPayload(p, nil) - if p.parseNamespacedObj(opDevice, 10) { + devInfo := &opcodeTable[0x6a] + if p.parseNamespacedObj(devInfo, 10) { t.Fatal("expected parseNamespacedObj to return false") } }) t.Run("scope lookup error", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) header := mockParserPayload(p, []byte{'^', 'F', 'A', 'B', 'C'}) p.scopeEnter(p.root) - if p.parseNamespacedObj(opDevice, header.Length) { + devInfo := &opcodeTable[0x6a] + if p.parseNamespacedObj(devInfo, header.Length) { t.Fatal("expected parseNamespacedObj to return false") } }) - t.Run("error parsing method arg count", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + t.Run("unsupported namespaced entity", func(t *testing.T) { + p.root = entity.NewScope(entity.OpScope, 42, `\`) header := mockParserPayload(p, []byte{'F', 'A', 'B', 'C'}) p.scopeEnter(p.root) - if p.parseNamespacedObj(opMethod, header.Length) { + + // We just pass a random non-namespaced opcode table entry to parseNamespacedObj + zeroInfo := &opcodeTable[0x00] + if p.parseNamespacedObj(zeroInfo, header.Length) { + t.Fatal("expected parseNamespacedObj to return false") + } + }) + + t.Run("error parsing args after name", func(t *testing.T) { + p.root = entity.NewScope(entity.OpScope, 42, `\`) + + header := mockParserPayload(p, []byte{'F', 'A', 'B', 'C'}) + + p.scopeEnter(p.root) + methodInfo := &opcodeTable[0x0d] + if p.parseNamespacedObj(methodInfo, header.Length) { t.Fatal("expected parseNamespacedObj to return false") } }) }) t.Run("parseArg bytelist errors", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) mockParserPayload(p, nil) - if p.parseArg(new(opcodeInfo), new(unnamedEntity), 0, opArgByteList, 42) { + if p.parseArg(new(opcodeInfo), entity.NewGeneric(0, 0), 0, opArgByteList, 42) { t.Fatal("expected parseNamespacedObj to return false") } }) t.Run("parseNamedRef errors", func(t *testing.T) { t.Run("missing args", func(t *testing.T) { - p.root = &scopeEntity{op: opScope, name: `\`} + p.root = entity.NewScope(entity.OpScope, 42, `\`) p.methodArgCount = map[string]uint8{ "MTHD": 10, } mockParserPayload(p, []byte{ 'M', 'T', 'H', 'D', - byte(opIf), // Incomplete type2 opcode + byte(entity.OpIf), // Incomplete type2 opcode }) p.scopeEnter(p.root) @@ -358,123 +346,149 @@ func TestParserErrorHandling(t *testing.T) { t.Run("parseFieldList errors", func(t *testing.T) { specs := []struct { - op opcode + op entity.AMLOpcode args []interface{} maxReadOffset uint32 payload []byte }{ - // Invalid arg count for opField + // Invalid arg count for entity.OpField { - opField, + entity.OpField, nil, 0, nil, }, - // Wrong arg type for opField + // Wrong arg type for entity.OpField { - opField, + entity.OpField, []interface{}{0, uint64(42)}, 0, nil, }, { - opField, + entity.OpField, []interface{}{"FLD0", uint32(42)}, 0, nil, }, - // Invalid arg count for opIndexField + // Invalid arg count for entity.OpIndexField { - opIndexField, + entity.OpIndexField, nil, 0, nil, }, - // Wrong arg type for opIndexField + // Wrong arg type for entity.OpIndexField { - opIndexField, + entity.OpIndexField, []interface{}{0, "FLD1", "FLD2"}, 0, nil, }, { - opIndexField, + entity.OpIndexField, []interface{}{"FLD0", 0, "FLD2"}, 0, nil, }, { - opIndexField, + entity.OpIndexField, + []interface{}{"FLD0", "FLD1", 0}, + 0, + nil, + }, + // Invalid arg count for entity.OpBankField + { + entity.OpBankField, + nil, + 0, + nil, + }, + // Wrong arg type for entity.OpBankField + { + entity.OpBankField, + []interface{}{0, "FLD1", "FLD2"}, + 0, + nil, + }, + { + entity.OpBankField, + []interface{}{"FLD0", 0, "FLD2"}, + 0, + nil, + }, + { + entity.OpBankField, []interface{}{"FLD0", "FLD1", 0}, 0, nil, }, // unexpected EOF parsing fields { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, nil, }, // reserved field (0x00) with missing pkgLen { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0x00}, }, // access field (0x01) with missing accessType { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0x01}, }, // access field (0x01) with missing attribute byte { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0x01, 0x01}, }, // connect field (0x02) with incomplete TermObject => Buffer arg { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, - []byte{0x02, byte(opBuffer)}, + []byte{0x02, byte(entity.OpBuffer)}, }, // extended access field (0x03) with missing ext. accessType { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0x03}, }, // extended access field (0x03) with missing ext. attribute byte { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0x03, 0x01}, }, // extended access field (0x03) with missing access byte count value { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0x03, 0x01, 0x02}, }, // named field with invalid name { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{0xff}, }, // named field with invalid pkgLen { - opField, + entity.OpField, []interface{}{"FLD0", uint64(42)}, 128, []byte{'N', 'A', 'M', 'E'}, @@ -484,10 +498,16 @@ func TestParserErrorHandling(t *testing.T) { for specIndex, spec := range specs { mockParserPayload(p, spec.payload) - if p.parseFieldList(spec.op, spec.args, spec.maxReadOffset) { + if p.parseFieldList(entity.NewField(42), spec.maxReadOffset) { t.Errorf("[spec %d] expected parseFieldLis to return false", specIndex) } } + + t.Run("non-field entity argument", func(t *testing.T) { + if p.parseFieldList(entity.NewDevice(42, "DEV0"), 128) { + t.Fatal("expected parseFieldList to return false when a non-field argument is passed to it") + } + }) }) t.Run("parsePkgLength errors", func(t *testing.T) { @@ -532,7 +552,7 @@ func TestParserErrorHandling(t *testing.T) { t.Run("parseTarget errors", func(t *testing.T) { t.Run("unexpected opcode", func(t *testing.T) { // Unexpected opcode - mockParserPayload(p, []byte{byte(opAnd)}) + mockParserPayload(p, []byte{byte(entity.OpAnd)}) if _, ok := p.parseTarget(); ok { t.Error("expected parseTarget to return false") @@ -591,7 +611,7 @@ func TestDetectMethodDeclarations(t *testing.T) { } validMethod := []byte{ - byte(opMethod), + byte(entity.OpMethod), 5, // pkgLen 'M', 'T', 'H', 'D', 2, // flags (2 args) @@ -614,7 +634,7 @@ func TestDetectMethodDeclarations(t *testing.T) { t.Run("bad pkgLen", func(t *testing.T) { mockParserPayload(p, []byte{ - byte(opMethod), + byte(entity.OpMethod), // lead byte bits (6:7) indicate 1 extra byte that is missing byte(1 << 6), }) @@ -625,7 +645,7 @@ func TestDetectMethodDeclarations(t *testing.T) { t.Run("error parsing namestring", func(t *testing.T) { mockParserPayload(p, append([]byte{ - byte(opMethod), + byte(entity.OpMethod), byte(5), // pkgLen 10, // bogus char, not part of namestring }, validMethod...)) @@ -645,7 +665,7 @@ func TestDetectMethodDeclarations(t *testing.T) { t.Run("error parsing method flags", func(t *testing.T) { mockParserPayload(p, []byte{ - byte(opMethod), + byte(entity.OpMethod), byte(5), // pkgLen 'F', 'O', 'O', 'F', // Missing flag byte @@ -678,7 +698,7 @@ type mockResolver struct { } func (m mockResolver) LookupTable(name string) *table.SDTHeader { - pathToDumps := pkgDir() + "/../table/tabletest/" + pathToDumps := pkgDir() + "/../../table/tabletest/" for _, f := range m.tableFiles { if !strings.Contains(f, name) { continue @@ -709,3 +729,23 @@ func (f fixedPayloadResolver) LookupTable(name string) *table.SDTHeader { return hdr } + +func genDefaultScopes() entity.Container { + rootNS := entity.NewScope(entity.OpScope, 42, `\`) + rootNS.Append(entity.NewScope(entity.OpScope, 42, `_GPE`)) // General events in GPE register block + rootNS.Append(entity.NewScope(entity.OpScope, 42, `_PR_`)) // ACPI 1.0 processor namespace + rootNS.Append(entity.NewScope(entity.OpScope, 42, `_SB_`)) // System bus with all device objects + rootNS.Append(entity.NewScope(entity.OpScope, 42, `_SI_`)) // System indicators + rootNS.Append(entity.NewScope(entity.OpScope, 42, `_TZ_`)) // ACPI 1.0 thermal zone namespace + + // Inject pre-defined OSPM objects + rootNS.Append(namedConst(entity.NewConst(entity.OpStringPrefix, 42, "gopheros"), "_OS_")) + rootNS.Append(namedConst(entity.NewConst(entity.OpStringPrefix, 42, uint64(2)), "_REV")) + + return rootNS +} + +func namedConst(ent *entity.Const, name string) *entity.Const { + ent.SetName(name) + return ent +} diff --git a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.aml b/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.aml index 5d278a1ccf09445ba8bc3a0d49c02509eb819b12..5786a1894fb9e026dd40f5ffa583f13bbfc62e00 100644 GIT binary patch delta 187 zcmaFC{F#NzCD2i?D!1OrnJ|7`S+WEK{%`D@f3^AX=W+ z-__TUf!8+@NHg$;Ox9-HD;M3&?Hmwlz^K5;z`z#W!VwT2WWd0{5Z%fe5@iq%0H267 Ae*gdg delta 28 kcmey&@`9PmCD