mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: update AML parser to use the new entities
This commit is contained in:
parent
12ad177381
commit
b278ce626b
@ -47,6 +47,7 @@ type Container interface {
|
|||||||
Last() Entity
|
Last() Entity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FieldAccessTypeProvider is an interface implemented by all field entities.
|
||||||
type FieldAccessTypeProvider interface {
|
type FieldAccessTypeProvider interface {
|
||||||
// DefaultAccessType returns the default FieldAccessType for any field unit
|
// DefaultAccessType returns the default FieldAccessType for any field unit
|
||||||
// defined by this field.
|
// defined by this field.
|
||||||
|
@ -79,6 +79,19 @@ func TestEntityMethods(t *testing.T) {
|
|||||||
t.Fatalf("expected parent not to have any child nodes; got %d", got)
|
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) {
|
func TestEntityArgAssignment(t *testing.T) {
|
||||||
@ -160,6 +173,24 @@ func TestEntityArgAssignment(t *testing.T) {
|
|||||||
[]interface{}{NewConst(OpDwordPrefix, 2, uint64(42))},
|
[]interface{}{NewConst(OpDwordPrefix, 2, uint64(42))},
|
||||||
false,
|
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:
|
nextSpec:
|
||||||
|
@ -6,6 +6,7 @@ package entity
|
|||||||
// representation of the opcode values.
|
// representation of the opcode values.
|
||||||
type AMLOpcode uint16
|
type AMLOpcode uint16
|
||||||
|
|
||||||
|
// List of AML opcodes
|
||||||
const (
|
const (
|
||||||
// Regular opcode list
|
// Regular opcode list
|
||||||
OpZero = AMLOpcode(0x00)
|
OpZero = AMLOpcode(0x00)
|
||||||
@ -427,14 +428,3 @@ func OpIsType2(op AMLOpcode) bool {
|
|||||||
return false
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -227,14 +227,6 @@ func TestOpcodeIsX(t *testing.T) {
|
|||||||
{OpPackage, OpIsDataObject, true},
|
{OpPackage, OpIsDataObject, true},
|
||||||
{OpVarPackage, OpIsDataObject, true},
|
{OpVarPackage, OpIsDataObject, true},
|
||||||
{OpLor, OpIsDataObject, false},
|
{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 {
|
for specIndex, spec := range specs {
|
||||||
|
@ -8,7 +8,7 @@ func TestScopeVisit(t *testing.T) {
|
|||||||
stopRecursing := func(Entity) bool { return false }
|
stopRecursing := func(Entity) bool { return false }
|
||||||
|
|
||||||
// Append special entities under IDE0
|
// Append special entities under IDE0
|
||||||
root := NewScope(tableHandle, "IDE0")
|
root := NewScope(OpScope, tableHandle, "IDE0")
|
||||||
root.Append(NewDevice(tableHandle, "DEV0"))
|
root.Append(NewDevice(tableHandle, "DEV0"))
|
||||||
root.Append(NewProcessor(tableHandle, "FOO0"))
|
root.Append(NewProcessor(tableHandle, "FOO0"))
|
||||||
root.Append(NewProcessor(tableHandle, "FOO0"))
|
root.Append(NewProcessor(tableHandle, "FOO0"))
|
||||||
|
@ -55,7 +55,7 @@ const (
|
|||||||
|
|
||||||
// is returns true if f is set in this opFlag.
|
// is returns true if f is set in this opFlag.
|
||||||
func (fl opFlag) is(f opFlag) bool {
|
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.
|
// opArgFlags encodes up to 7 opArgFlag values in a uint64 value.
|
||||||
@ -99,7 +99,6 @@ const (
|
|||||||
opArgTermList
|
opArgTermList
|
||||||
opArgTermObj
|
opArgTermObj
|
||||||
opArgByteList
|
opArgByteList
|
||||||
opArgPackage
|
|
||||||
opArgString
|
opArgString
|
||||||
opArgByteData
|
opArgByteData
|
||||||
opArgWord
|
opArgWord
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package aml
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"gopheros/device/acpi/aml/entity"
|
||||||
"gopheros/device/acpi/table"
|
"gopheros/device/acpi/table"
|
||||||
"gopheros/kernel"
|
"gopheros/kernel"
|
||||||
"gopheros/kernel/kfmt"
|
"gopheros/kernel/kfmt"
|
||||||
@ -17,8 +18,8 @@ var (
|
|||||||
type Parser struct {
|
type Parser struct {
|
||||||
r amlStreamReader
|
r amlStreamReader
|
||||||
errWriter io.Writer
|
errWriter io.Writer
|
||||||
root ScopeEntity
|
root entity.Container
|
||||||
scopeStack []ScopeEntity
|
scopeStack []entity.Container
|
||||||
tableName string
|
tableName string
|
||||||
tableHandle uint8
|
tableHandle uint8
|
||||||
|
|
||||||
@ -30,7 +31,7 @@ type Parser struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewParser returns a new AML parser instance.
|
// 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{
|
return &Parser{
|
||||||
errWriter: errWriter,
|
errWriter: errWriter,
|
||||||
root: rootEntity,
|
root: rootEntity,
|
||||||
@ -65,26 +66,30 @@ func (p *Parser) ParseAML(tableHandle uint8, tableName string, header *table.SDT
|
|||||||
}
|
}
|
||||||
p.scopeExit()
|
p.scopeExit()
|
||||||
|
|
||||||
// Pass 3: check parents and resolve forward references
|
// Pass 3: check parents and resolve symbol references
|
||||||
var resolveFailed bool
|
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
|
// 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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate parents for any entity args that are also entities but are not
|
// 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).
|
// linked to a parent (e.g. a package inside a named entity).
|
||||||
for _, arg := range ent.getArgs() {
|
for _, arg := range ent.Args() {
|
||||||
if argEnt, isArgEnt := arg.(Entity); isArgEnt && argEnt.Parent() == nil {
|
if argEnt, isArgEnt := arg.(entity.Entity); isArgEnt && argEnt.Parent() == nil {
|
||||||
argEnt.setParent(ent.Parent())
|
argEnt.SetParent(ent.Parent())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if res, ok := ent.(resolver); ok && !res.Resolve(p.errWriter, p.root) {
|
// 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
|
resolveFailed = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@ -117,7 +122,7 @@ func (p *Parser) detectMethodDeclarations() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if next.op != opMethod {
|
if next.op != entity.OpMethod {
|
||||||
continue
|
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
|
// If we encounter a named scope we need to look it up and parse the arg list relative to it
|
||||||
switch info.op {
|
switch {
|
||||||
case opScope:
|
case info.op == entity.OpScope:
|
||||||
return p.parseScope(curOffset + pkgLen)
|
return p.parseScope(curOffset + pkgLen)
|
||||||
case opDevice, opMethod:
|
case info.flags.is(opFlagNamed | opFlagScoped):
|
||||||
return p.parseNamespacedObj(info.op, curOffset+pkgLen)
|
return p.parseNamespacedObj(info, curOffset+pkgLen)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create appropriate object for opcode type and attach it to current scope unless it is
|
// 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.
|
// finalizeObj applies post-parse logic for special object types.
|
||||||
func (p *Parser) finalizeObj(op opcode, obj Entity) bool {
|
func (p *Parser) finalizeObj(op entity.AMLOpcode, obj entity.Entity) bool {
|
||||||
obj.setTableHandle(p.tableHandle)
|
|
||||||
|
|
||||||
switch op {
|
switch op {
|
||||||
case opElse:
|
case entity.OpElse:
|
||||||
// If this is an else block we need to append it as an argument to the
|
// If this is an else block we need to append it as an argument to the
|
||||||
// If block
|
// If block
|
||||||
// Pop Else block of the current scope
|
// Pop Else block of the current scope
|
||||||
curScope := p.scopeCurrent()
|
curScope := p.scopeCurrent()
|
||||||
curScope.removeChild(curScope.lastChild())
|
curScope.Remove(curScope.Last())
|
||||||
prevObj := curScope.lastChild()
|
prevObj := curScope.Last()
|
||||||
if prevObj.getOpcode() != opIf {
|
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())
|
kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] encountered else block without a matching if block\n", p.tableName, p.r.Offset())
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// If predicate(0) then(1) else(2)
|
// If predicate(0) then(1) else(2)
|
||||||
prevObj.setArg(2, obj)
|
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
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -262,14 +256,14 @@ func (p *Parser) parseScope(maxReadOffset uint32) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
target := scopeFind(p.scopeCurrent(), p.root, name)
|
target := entity.FindInScope(p.scopeCurrent(), p.root, name)
|
||||||
if target == nil {
|
if target == nil {
|
||||||
kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] undefined scope: %s\n", p.tableName, p.r.Offset(), name)
|
kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] undefined scope: %s\n", p.tableName, p.r.Offset(), name)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
switch target.getOpcode() {
|
switch target.Opcode() {
|
||||||
case opDevice, opProcessor, opThermalZone, opPowerRes:
|
case entity.OpDevice, entity.OpProcessor, entity.OpThermalZone, entity.OpPowerRes:
|
||||||
// ok
|
// ok
|
||||||
default:
|
default:
|
||||||
// Only allow if this is a named scope
|
// 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)
|
ok = p.parseObjList(maxReadOffset)
|
||||||
p.scopeExit()
|
p.scopeExit()
|
||||||
|
|
||||||
@ -287,48 +281,50 @@ func (p *Parser) parseScope(maxReadOffset uint32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// parseNamespacedObj reads a scope target name from the AML bytestream,
|
// parseNamespacedObj reads a scope target name from the AML bytestream,
|
||||||
// attaches the device or method (depending on the opcode) object to the
|
// attaches the appropriate object depending on the opcode to the correct
|
||||||
// correct parent scope, enters the device scope and parses the object list
|
// parent scope and then parses any contained objects. The contained objects
|
||||||
// contained in the device definition.
|
// will be appended inside the newly constructed scope.
|
||||||
func (p *Parser) parseNamespacedObj(op opcode, maxReadOffset uint32) bool {
|
func (p *Parser) parseNamespacedObj(info *opcodeInfo, maxReadOffset uint32) bool {
|
||||||
scopeExpr, ok := p.parseNameString()
|
scopeExpr, ok := p.parseNameString()
|
||||||
if !ok {
|
if !ok {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
parent, name := scopeResolvePath(p.scopeCurrent(), p.root, scopeExpr)
|
parent, name := entity.ResolveScopedPath(p.scopeCurrent(), p.root, scopeExpr)
|
||||||
if parent == nil {
|
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())
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var obj ScopeEntity
|
var obj entity.Container
|
||||||
switch op {
|
switch info.op {
|
||||||
case opDevice:
|
case entity.OpDevice:
|
||||||
obj = &Device{scopeEntity: scopeEntity{name: name}}
|
obj = entity.NewDevice(p.tableHandle, name)
|
||||||
case opMethod:
|
case entity.OpProcessor:
|
||||||
m := &Method{scopeEntity: scopeEntity{name: name}}
|
obj = entity.NewProcessor(p.tableHandle, name)
|
||||||
|
case entity.OpPowerRes:
|
||||||
flags, flagOk := p.parseNumConstant(1)
|
obj = entity.NewPowerResource(p.tableHandle, name)
|
||||||
if !flagOk {
|
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
|
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
|
// Parse any args that follow the name. The last arg is always an ArgTermList
|
||||||
|
parent.Append(obj)
|
||||||
|
for argIndex := uint8(1); argIndex < info.argFlags.argCount(); argIndex++ {
|
||||||
|
if !p.parseArg(info, obj, argIndex, info.argFlags.arg(argIndex), maxReadOffset) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.Append(obj)
|
return ok && p.finalizeObj(info.op, obj)
|
||||||
p.scopeEnter(obj)
|
|
||||||
ok = p.parseObjList(maxReadOffset)
|
|
||||||
p.scopeExit()
|
|
||||||
|
|
||||||
return ok && p.finalizeObj(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 (
|
var (
|
||||||
arg interface{}
|
arg interface{}
|
||||||
ok bool
|
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
|
// If object is a scoped entity enter it's scope before parsing
|
||||||
// the term list. Otherwise, create an unnamed scope, attach it
|
// the term list. Otherwise, create an unnamed scope, attach it
|
||||||
// as the next argument to obj and enter that.
|
// 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)
|
p.scopeEnter(s)
|
||||||
} else {
|
} 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)
|
p.scopeEnter(ns)
|
||||||
obj.setArg(argIndex, ns)
|
obj.SetArg(argIndex, ns)
|
||||||
}
|
}
|
||||||
|
|
||||||
ok = p.parseObjList(maxReadOffset)
|
ok = p.parseObjList(maxReadOffset)
|
||||||
p.scopeExit()
|
p.scopeExit()
|
||||||
return ok
|
return ok
|
||||||
case opArgFieldList:
|
case opArgFieldList:
|
||||||
return p.parseFieldList(info.op, obj.getArgs(), maxReadOffset)
|
return p.parseFieldList(obj, maxReadOffset)
|
||||||
case opArgByteList:
|
case opArgByteList:
|
||||||
var bl []byte
|
var bl []byte
|
||||||
for p.r.Offset() < maxReadOffset {
|
for p.r.Offset() < maxReadOffset {
|
||||||
@ -388,45 +385,68 @@ func (p *Parser) parseArg(info *opcodeInfo, obj Entity, argIndex uint8, argType
|
|||||||
return false
|
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 {
|
if ok := p.parseObj(); !ok {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
curScope := p.scopeCurrent()
|
curScope := p.scopeCurrent()
|
||||||
obj := curScope.lastChild()
|
obj := curScope.Last()
|
||||||
curScope.removeChild(obj)
|
curScope.Remove(obj)
|
||||||
return obj, true
|
return obj, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Parser) makeObjForOpcode(info *opcodeInfo) Entity {
|
func (p *Parser) makeObjForOpcode(info *opcodeInfo) entity.Entity {
|
||||||
var obj Entity
|
var obj entity.Entity
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case info.op == opOpRegion:
|
case info.op == entity.OpOpRegion:
|
||||||
obj = new(regionEntity)
|
obj = entity.NewRegion(p.tableHandle)
|
||||||
case info.op == opBuffer:
|
case info.op == entity.OpBuffer:
|
||||||
obj = new(bufferEntity)
|
obj = entity.NewBuffer(p.tableHandle)
|
||||||
case info.op == opMutex:
|
case info.op == entity.OpMutex:
|
||||||
obj = new(mutexEntity)
|
obj = entity.NewMutex(p.tableHandle)
|
||||||
case info.op == opEvent:
|
case info.op == entity.OpEvent:
|
||||||
obj = new(eventEntity)
|
obj = entity.NewEvent(p.tableHandle)
|
||||||
case opIsBufferField(info.op):
|
case info.op == entity.OpField:
|
||||||
obj = new(bufferFieldEntity)
|
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):
|
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):
|
case info.flags.is(opFlagScoped):
|
||||||
obj = new(scopeEntity)
|
obj = entity.NewScope(info.op, p.tableHandle, "")
|
||||||
case info.flags.is(opFlagNamed):
|
case info.flags.is(opFlagNamed):
|
||||||
obj = new(namedEntity)
|
obj = entity.NewGenericNamed(info.op, p.tableHandle)
|
||||||
default:
|
default:
|
||||||
obj = new(unnamedEntity)
|
obj = entity.NewGeneric(info.op, p.tableHandle)
|
||||||
}
|
}
|
||||||
|
|
||||||
obj.setOpcode(info.op)
|
|
||||||
return obj
|
return obj
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -447,7 +467,7 @@ func (p *Parser) parseNamedRef() bool {
|
|||||||
var (
|
var (
|
||||||
curOffset uint32
|
curOffset uint32
|
||||||
argIndex uint8
|
argIndex uint8
|
||||||
arg Entity
|
arg entity.Entity
|
||||||
argList []interface{}
|
argList []interface{}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -459,14 +479,14 @@ func (p *Parser) parseNamedRef() bool {
|
|||||||
p.r.SetOffset(curOffset)
|
p.r.SetOffset(curOffset)
|
||||||
|
|
||||||
switch {
|
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()
|
arg, ok = p.parseArgObj()
|
||||||
default:
|
default:
|
||||||
// It may be a nested invocation or named ref
|
// It may be a nested invocation or named ref
|
||||||
ok = p.parseNamedRef()
|
ok = p.parseNamedRef()
|
||||||
if ok {
|
if ok {
|
||||||
arg = p.scopeCurrent().lastChild()
|
arg = p.scopeCurrent().Last()
|
||||||
p.scopeCurrent().removeChild(arg)
|
p.scopeCurrent().Remove(arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -486,14 +506,11 @@ func (p *Parser) parseNamedRef() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.scopeCurrent().Append(&methodInvocationEntity{
|
return p.scopeCurrent().Append(entity.NewInvocation(p.tableHandle, name))
|
||||||
unnamedEntity: unnamedEntity{args: argList},
|
|
||||||
methodName: name,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise this is a reference to a named entity
|
// 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) {
|
func (p *Parser) nextOpcode() (*opcodeInfo, bool) {
|
||||||
@ -533,69 +550,30 @@ func (p *Parser) nextOpcode() (*opcodeInfo, bool) {
|
|||||||
// AccessField := 0x1 AccessType AccessAttrib
|
// AccessField := 0x1 AccessType AccessAttrib
|
||||||
// ConnectField := 0x02 NameString | 0x02 BufferData
|
// ConnectField := 0x02 NameString | 0x02 BufferData
|
||||||
// ExtendedAccessField := 0x3 AccessType ExtendedAccessType AccessLength
|
// 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 (
|
var (
|
||||||
// for fieldUnit, name0 is the region name and name1 is not used;
|
|
||||||
// for indexField,
|
|
||||||
name0, name1 string
|
|
||||||
flags uint64
|
|
||||||
|
|
||||||
ok bool
|
ok bool
|
||||||
|
|
||||||
|
accessType entity.FieldAccessType
|
||||||
|
|
||||||
bitWidth uint32
|
bitWidth uint32
|
||||||
curBitOffset uint32
|
curBitOffset uint32
|
||||||
accessAttrib FieldAccessAttrib
|
|
||||||
accessByteCount uint8
|
|
||||||
unitName string
|
|
||||||
)
|
|
||||||
|
|
||||||
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 (
|
|
||||||
connectionName string
|
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 {
|
for p.r.Offset() < maxReadOffset {
|
||||||
next, err := p.r.ReadByte()
|
next, err := p.r.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -616,7 +594,7 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
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()
|
attrib, err := p.r.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -626,7 +604,7 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin
|
|||||||
// To specify AccessAttribBytes, RawBytes and RawProcessBytes
|
// To specify AccessAttribBytes, RawBytes and RawProcessBytes
|
||||||
// the ASL compiler will emit an ExtendedAccessField opcode.
|
// the ASL compiler will emit an ExtendedAccessField opcode.
|
||||||
accessByteCount = 0
|
accessByteCount = 0
|
||||||
accessAttrib = FieldAccessAttrib(attrib)
|
accessAttrib = entity.FieldAccessAttrib(attrib)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
case 0x2: // ConnectField => <0x2> NameString> | <0x02> TermObj => Buffer
|
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 {
|
if err != nil {
|
||||||
return false
|
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()
|
extAccessAttrib, err := p.r.ReadByte()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -657,11 +635,11 @@ func (p *Parser) parseFieldList(op opcode, args []interface{}, maxReadOffset uin
|
|||||||
|
|
||||||
switch extAccessAttrib {
|
switch extAccessAttrib {
|
||||||
case 0x0b:
|
case 0x0b:
|
||||||
accessAttrib = FieldAccessAttribBytes
|
accessAttrib = entity.FieldAccessAttribBytes
|
||||||
case 0xe:
|
case 0xe:
|
||||||
accessAttrib = FieldAccessAttribRawBytes
|
accessAttrib = entity.FieldAccessAttribRawBytes
|
||||||
case 0x0f:
|
case 0x0f:
|
||||||
accessAttrib = FieldAccessAttribRawProcessBytes
|
accessAttrib = entity.FieldAccessAttribRawProcessBytes
|
||||||
}
|
}
|
||||||
default: // NamedField
|
default: // NamedField
|
||||||
_ = p.r.UnreadByte()
|
_ = 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
|
// According to the spec, the field elements are should
|
||||||
// be visible at the same scope as the Field/IndexField
|
// be visible at the same scope as the Field that declares them
|
||||||
switch op {
|
unit := entity.NewFieldUnit(p.tableHandle, unitName)
|
||||||
case opField:
|
unit.Field = fieldEnt
|
||||||
p.scopeCurrent().Append(&fieldUnitEntity{
|
unit.AccessType = accessType
|
||||||
fieldEntity: fieldEntity{
|
unit.AccessAttrib = accessAttrib
|
||||||
namedEntity: namedEntity{
|
unit.ByteCount = accessByteCount
|
||||||
tableHandle: p.tableHandle,
|
unit.BitOffset = curBitOffset
|
||||||
op: op,
|
unit.BitWidth = bitWidth
|
||||||
name: unitName,
|
unit.ConnectionName = connectionName
|
||||||
},
|
unit.Connection = resolvedConnection
|
||||||
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,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
p.scopeCurrent().Append(unit)
|
||||||
curBitOffset += bitWidth
|
curBitOffset += bitWidth
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok && p.r.Offset() == maxReadOffset
|
return ok && p.r.Offset() == maxReadOffset
|
||||||
@ -859,10 +802,8 @@ func (p *Parser) parseSimpleName() (interface{}, bool) {
|
|||||||
var obj interface{}
|
var obj interface{}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case ok && nextOpcode.op >= opLocal0 && nextOpcode.op <= opLocal7:
|
case ok && entity.OpIsArg(nextOpcode.op):
|
||||||
obj, ok = &unnamedEntity{op: nextOpcode.op}, true
|
obj, ok = entity.NewGeneric(nextOpcode.op, p.tableHandle), true
|
||||||
case ok && nextOpcode.op >= opArg0 && nextOpcode.op <= opArg6:
|
|
||||||
obj, ok = &unnamedEntity{op: nextOpcode.op}, true
|
|
||||||
default:
|
default:
|
||||||
// Rewind and try parsing as NameString
|
// Rewind and try parsing as NameString
|
||||||
p.r.SetOffset(curOffset)
|
p.r.SetOffset(curOffset)
|
||||||
@ -890,10 +831,10 @@ func (p *Parser) parseTarget() (interface{}, bool) {
|
|||||||
|
|
||||||
if ok {
|
if ok {
|
||||||
switch {
|
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)
|
p.r.SetOffset(curOffset + 1)
|
||||||
return &constEntity{op: opStringPrefix, val: ""}, true
|
return entity.NewConst(entity.OpStringPrefix, p.tableHandle, ""), true
|
||||||
case opIsArg(nextOpcode.op) || nextOpcode.op == opRefOf || nextOpcode.op == opDerefOf || nextOpcode.op == opIndex || nextOpcode.op == opDebug: // LocalObj | ArgObj | Type6 | DebugObj
|
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:
|
default:
|
||||||
// Unexpected opcode
|
// Unexpected opcode
|
||||||
return nil, false
|
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.
|
// In this case, this is either a NameString or a control method invocation.
|
||||||
if ok := p.parseNamedRef(); ok {
|
if ok := p.parseNamedRef(); ok {
|
||||||
obj := p.scopeCurrent().lastChild()
|
obj := p.scopeCurrent().Last()
|
||||||
p.scopeCurrent().removeChild(obj)
|
p.scopeCurrent().Remove(obj)
|
||||||
return obj, ok
|
return obj, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -996,12 +937,12 @@ func (p *Parser) parseNameString() (string, bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// scopeCurrent returns the currently active scope.
|
// scopeCurrent returns the currently active scope.
|
||||||
func (p *Parser) scopeCurrent() ScopeEntity {
|
func (p *Parser) scopeCurrent() entity.Container {
|
||||||
return p.scopeStack[len(p.scopeStack)-1]
|
return p.scopeStack[len(p.scopeStack)-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// scopeEnter enters the given scope.
|
// scopeEnter enters the given scope.
|
||||||
func (p *Parser) scopeEnter(s ScopeEntity) {
|
func (p *Parser) scopeEnter(s entity.Container) {
|
||||||
p.scopeStack = append(p.scopeStack, s)
|
p.scopeStack = append(p.scopeStack, s)
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
|||||||
package aml
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"gopheros/device/acpi/aml/entity"
|
||||||
"gopheros/device/acpi/table"
|
"gopheros/device/acpi/table"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
@ -23,19 +24,7 @@ func TestParser(t *testing.T) {
|
|||||||
tableFiles: spec,
|
tableFiles: spec,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create default scopes
|
p := NewParser(os.Stderr, genDefaultScopes())
|
||||||
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)
|
|
||||||
|
|
||||||
for _, tableName := range spec {
|
for _, tableName := range spec {
|
||||||
tableName = strings.Replace(tableName, ".aml", "", -1)
|
tableName = strings.Replace(tableName, ".aml", "", -1)
|
||||||
@ -50,25 +39,18 @@ func TestParser(t *testing.T) {
|
|||||||
func TestTableHandleAssignment(t *testing.T) {
|
func TestTableHandleAssignment(t *testing.T) {
|
||||||
var resolver = mockResolver{tableFiles: []string{"parser-testsuite-DSDT.aml"}}
|
var resolver = mockResolver{tableFiles: []string{"parser-testsuite-DSDT.aml"}}
|
||||||
|
|
||||||
// Create default scopes
|
rootNS := genDefaultScopes()
|
||||||
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, rootNS)
|
||||||
|
|
||||||
expHandle := uint8(42)
|
expHandle := uint8(0x0f)
|
||||||
tableName := "parser-testsuite-DSDT"
|
tableName := "parser-testsuite-DSDT"
|
||||||
if err := p.ParseAML(expHandle, tableName, resolver.LookupTable(tableName)); err != nil {
|
if err := p.ParseAML(expHandle, tableName, resolver.LookupTable(tableName)); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Drop all entities that were assigned the handle value
|
// Drop all entities that were assigned the handle value
|
||||||
var unloadList []Entity
|
var unloadList []entity.Entity
|
||||||
scopeVisit(0, p.root, EntityTypeAny, func(_ int, ent Entity) bool {
|
entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool {
|
||||||
if ent.TableHandle() == expHandle {
|
if ent.TableHandle() == expHandle {
|
||||||
unloadList = append(unloadList, ent)
|
unloadList = append(unloadList, ent)
|
||||||
return false
|
return false
|
||||||
@ -78,13 +60,13 @@ func TestTableHandleAssignment(t *testing.T) {
|
|||||||
|
|
||||||
for _, ent := range unloadList {
|
for _, ent := range unloadList {
|
||||||
if p := ent.Parent(); p != nil {
|
if p := ent.Parent(); p != nil {
|
||||||
p.removeChild(ent)
|
p.Remove(ent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should end up with the original tree
|
// We should end up with the original tree
|
||||||
var visitedNodes int
|
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++
|
visitedNodes++
|
||||||
if ent.TableHandle() == expHandle {
|
if ent.TableHandle() == expHandle {
|
||||||
t.Errorf("encountered entity that should have been pruned: %#+v", ent)
|
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"},
|
tableFiles: []string{"parser-testsuite-fwd-decls-DSDT.aml"},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create default scopes
|
p := NewParser(ioutil.Discard, genDefaultScopes())
|
||||||
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)
|
|
||||||
|
|
||||||
for _, tableName := range resolver.tableFiles {
|
for _, tableName := range resolver.tableFiles {
|
||||||
tableName = strings.Replace(tableName, ".aml", "", -1)
|
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("ParseAML errors", func(t *testing.T) {
|
||||||
t.Run("parseObjList error", 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
|
// Setup resolver to serve an AML stream containing an invalid opcode
|
||||||
header := mockParserPayload(p, []byte{0x5b, 0x00})
|
header := mockParserPayload(p, []byte{0x5b, 0x00})
|
||||||
@ -190,12 +164,10 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("unresolved entities", func(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
|
// Inject a reference entity to the tree
|
||||||
p.root.Append(&namedReference{
|
p.root.Append(entity.NewReference(42, "UNKNOWN"))
|
||||||
targetName: "UNKNOWN",
|
|
||||||
})
|
|
||||||
|
|
||||||
// Setup resolver to serve an empty AML stream
|
// Setup resolver to serve an empty AML stream
|
||||||
header := mockParserPayload(p, nil)
|
header := mockParserPayload(p, nil)
|
||||||
@ -208,11 +180,11 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("parseObj errors", func(t *testing.T) {
|
t.Run("parseObj errors", func(t *testing.T) {
|
||||||
t.Run("parsePkgLength error", 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
|
// Setup resolver to serve an AML stream containing an incomplete
|
||||||
// buffer specification
|
// 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 {
|
if err := p.ParseAML(uint8(42), "DSDT", header); err == nil {
|
||||||
t.Fatal("expected parsePkgLength to return an error")
|
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) {
|
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
|
// Setup resolver to serve an AML stream containing an incomplete
|
||||||
// buffer arglist specification
|
// 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 {
|
if err := p.ParseAML(uint8(42), "DSDT", header); err == nil {
|
||||||
t.Fatal("expected parsePkgLength to return an error")
|
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("finalizeObj errors", func(t *testing.T) {
|
||||||
t.Run("else without matching if", func(t *testing.T) {
|
t.Run("else without matching if", func(t *testing.T) {
|
||||||
p.root = &scopeEntity{op: opScope, name: `\`}
|
p.root = entity.NewScope(entity.OpScope, 42, `\`)
|
||||||
p.root.Append(&constEntity{val: 0x42})
|
p.root.Append(entity.NewConst(entity.OpDwordPrefix, 42, uint64(0x42)))
|
||||||
p.root.Append(&scopeEntity{op: opElse})
|
|
||||||
|
|
||||||
// Setup resolver to serve an AML stream containing an
|
// Setup resolver to serve an AML stream containing an
|
||||||
// empty else statement without a matching if
|
// 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 {
|
if err := p.ParseAML(uint8(42), "DSDT", header); err == nil {
|
||||||
t.Fatal("expected finalizeObj to return an error")
|
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("parseScope errors", func(t *testing.T) {
|
||||||
t.Run("parseNameString error", 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{
|
header := mockParserPayload(p, []byte{
|
||||||
byte(opScope),
|
byte(entity.OpScope),
|
||||||
0x10, // pkglen
|
0x10, // pkglen
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -264,10 +235,10 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("unknown scope", func(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{
|
header := mockParserPayload(p, []byte{
|
||||||
byte(opScope),
|
byte(entity.OpScope),
|
||||||
0x10, // pkglen
|
0x10, // pkglen
|
||||||
'F', 'O', 'O', 'F',
|
'F', 'O', 'O', 'F',
|
||||||
})
|
})
|
||||||
@ -278,10 +249,10 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("nameless scope", func(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{
|
header := mockParserPayload(p, []byte{
|
||||||
byte(opScope),
|
byte(entity.OpScope),
|
||||||
0x02, // pkglen
|
0x02, // pkglen
|
||||||
'\\', // scope name: "\" (root scope)
|
'\\', // scope name: "\" (root scope)
|
||||||
0x00, // null string
|
0x00, // null string
|
||||||
@ -295,58 +266,75 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("parseNamespacedObj errors", func(t *testing.T) {
|
t.Run("parseNamespacedObj errors", func(t *testing.T) {
|
||||||
t.Run("parseNameString error", 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)
|
mockParserPayload(p, nil)
|
||||||
|
|
||||||
if p.parseNamespacedObj(opDevice, 10) {
|
devInfo := &opcodeTable[0x6a]
|
||||||
|
if p.parseNamespacedObj(devInfo, 10) {
|
||||||
t.Fatal("expected parseNamespacedObj to return false")
|
t.Fatal("expected parseNamespacedObj to return false")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("scope lookup error", func(t *testing.T) {
|
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'})
|
header := mockParserPayload(p, []byte{'^', 'F', 'A', 'B', 'C'})
|
||||||
|
|
||||||
p.scopeEnter(p.root)
|
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.Fatal("expected parseNamespacedObj to return false")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("error parsing method arg count", func(t *testing.T) {
|
t.Run("unsupported namespaced entity", 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'})
|
header := mockParserPayload(p, []byte{'F', 'A', 'B', 'C'})
|
||||||
|
|
||||||
p.scopeEnter(p.root)
|
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.Fatal("expected parseNamespacedObj to return false")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("parseArg bytelist errors", func(t *testing.T) {
|
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)
|
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.Fatal("expected parseNamespacedObj to return false")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("parseNamedRef errors", func(t *testing.T) {
|
t.Run("parseNamedRef errors", func(t *testing.T) {
|
||||||
t.Run("missing args", 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{
|
p.methodArgCount = map[string]uint8{
|
||||||
"MTHD": 10,
|
"MTHD": 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
mockParserPayload(p, []byte{
|
mockParserPayload(p, []byte{
|
||||||
'M', 'T', 'H', 'D',
|
'M', 'T', 'H', 'D',
|
||||||
byte(opIf), // Incomplete type2 opcode
|
byte(entity.OpIf), // Incomplete type2 opcode
|
||||||
})
|
})
|
||||||
|
|
||||||
p.scopeEnter(p.root)
|
p.scopeEnter(p.root)
|
||||||
@ -358,123 +346,149 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("parseFieldList errors", func(t *testing.T) {
|
t.Run("parseFieldList errors", func(t *testing.T) {
|
||||||
specs := []struct {
|
specs := []struct {
|
||||||
op opcode
|
op entity.AMLOpcode
|
||||||
args []interface{}
|
args []interface{}
|
||||||
maxReadOffset uint32
|
maxReadOffset uint32
|
||||||
payload []byte
|
payload []byte
|
||||||
}{
|
}{
|
||||||
// Invalid arg count for opField
|
// Invalid arg count for entity.OpField
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
nil,
|
nil,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
// Wrong arg type for opField
|
// Wrong arg type for entity.OpField
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{0, uint64(42)},
|
[]interface{}{0, uint64(42)},
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint32(42)},
|
[]interface{}{"FLD0", uint32(42)},
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
// Invalid arg count for opIndexField
|
// Invalid arg count for entity.OpIndexField
|
||||||
{
|
{
|
||||||
opIndexField,
|
entity.OpIndexField,
|
||||||
nil,
|
nil,
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
// Wrong arg type for opIndexField
|
// Wrong arg type for entity.OpIndexField
|
||||||
{
|
{
|
||||||
opIndexField,
|
entity.OpIndexField,
|
||||||
[]interface{}{0, "FLD1", "FLD2"},
|
[]interface{}{0, "FLD1", "FLD2"},
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
opIndexField,
|
entity.OpIndexField,
|
||||||
[]interface{}{"FLD0", 0, "FLD2"},
|
[]interface{}{"FLD0", 0, "FLD2"},
|
||||||
0,
|
0,
|
||||||
nil,
|
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},
|
[]interface{}{"FLD0", "FLD1", 0},
|
||||||
0,
|
0,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
// unexpected EOF parsing fields
|
// unexpected EOF parsing fields
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
nil,
|
nil,
|
||||||
},
|
},
|
||||||
// reserved field (0x00) with missing pkgLen
|
// reserved field (0x00) with missing pkgLen
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x00},
|
[]byte{0x00},
|
||||||
},
|
},
|
||||||
// access field (0x01) with missing accessType
|
// access field (0x01) with missing accessType
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x01},
|
[]byte{0x01},
|
||||||
},
|
},
|
||||||
// access field (0x01) with missing attribute byte
|
// access field (0x01) with missing attribute byte
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x01, 0x01},
|
[]byte{0x01, 0x01},
|
||||||
},
|
},
|
||||||
// connect field (0x02) with incomplete TermObject => Buffer arg
|
// connect field (0x02) with incomplete TermObject => Buffer arg
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x02, byte(opBuffer)},
|
[]byte{0x02, byte(entity.OpBuffer)},
|
||||||
},
|
},
|
||||||
// extended access field (0x03) with missing ext. accessType
|
// extended access field (0x03) with missing ext. accessType
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x03},
|
[]byte{0x03},
|
||||||
},
|
},
|
||||||
// extended access field (0x03) with missing ext. attribute byte
|
// extended access field (0x03) with missing ext. attribute byte
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x03, 0x01},
|
[]byte{0x03, 0x01},
|
||||||
},
|
},
|
||||||
// extended access field (0x03) with missing access byte count value
|
// extended access field (0x03) with missing access byte count value
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0x03, 0x01, 0x02},
|
[]byte{0x03, 0x01, 0x02},
|
||||||
},
|
},
|
||||||
// named field with invalid name
|
// named field with invalid name
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{0xff},
|
[]byte{0xff},
|
||||||
},
|
},
|
||||||
// named field with invalid pkgLen
|
// named field with invalid pkgLen
|
||||||
{
|
{
|
||||||
opField,
|
entity.OpField,
|
||||||
[]interface{}{"FLD0", uint64(42)},
|
[]interface{}{"FLD0", uint64(42)},
|
||||||
128,
|
128,
|
||||||
[]byte{'N', 'A', 'M', 'E'},
|
[]byte{'N', 'A', 'M', 'E'},
|
||||||
@ -484,10 +498,16 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
for specIndex, spec := range specs {
|
for specIndex, spec := range specs {
|
||||||
mockParserPayload(p, spec.payload)
|
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.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) {
|
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("parseTarget errors", func(t *testing.T) {
|
||||||
t.Run("unexpected opcode", func(t *testing.T) {
|
t.Run("unexpected opcode", func(t *testing.T) {
|
||||||
// Unexpected opcode
|
// Unexpected opcode
|
||||||
mockParserPayload(p, []byte{byte(opAnd)})
|
mockParserPayload(p, []byte{byte(entity.OpAnd)})
|
||||||
|
|
||||||
if _, ok := p.parseTarget(); ok {
|
if _, ok := p.parseTarget(); ok {
|
||||||
t.Error("expected parseTarget to return false")
|
t.Error("expected parseTarget to return false")
|
||||||
@ -591,7 +611,7 @@ func TestDetectMethodDeclarations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validMethod := []byte{
|
validMethod := []byte{
|
||||||
byte(opMethod),
|
byte(entity.OpMethod),
|
||||||
5, // pkgLen
|
5, // pkgLen
|
||||||
'M', 'T', 'H', 'D',
|
'M', 'T', 'H', 'D',
|
||||||
2, // flags (2 args)
|
2, // flags (2 args)
|
||||||
@ -614,7 +634,7 @@ func TestDetectMethodDeclarations(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("bad pkgLen", func(t *testing.T) {
|
t.Run("bad pkgLen", func(t *testing.T) {
|
||||||
mockParserPayload(p, []byte{
|
mockParserPayload(p, []byte{
|
||||||
byte(opMethod),
|
byte(entity.OpMethod),
|
||||||
// lead byte bits (6:7) indicate 1 extra byte that is missing
|
// lead byte bits (6:7) indicate 1 extra byte that is missing
|
||||||
byte(1 << 6),
|
byte(1 << 6),
|
||||||
})
|
})
|
||||||
@ -625,7 +645,7 @@ func TestDetectMethodDeclarations(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("error parsing namestring", func(t *testing.T) {
|
t.Run("error parsing namestring", func(t *testing.T) {
|
||||||
mockParserPayload(p, append([]byte{
|
mockParserPayload(p, append([]byte{
|
||||||
byte(opMethod),
|
byte(entity.OpMethod),
|
||||||
byte(5), // pkgLen
|
byte(5), // pkgLen
|
||||||
10, // bogus char, not part of namestring
|
10, // bogus char, not part of namestring
|
||||||
}, validMethod...))
|
}, validMethod...))
|
||||||
@ -645,7 +665,7 @@ func TestDetectMethodDeclarations(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("error parsing method flags", func(t *testing.T) {
|
t.Run("error parsing method flags", func(t *testing.T) {
|
||||||
mockParserPayload(p, []byte{
|
mockParserPayload(p, []byte{
|
||||||
byte(opMethod),
|
byte(entity.OpMethod),
|
||||||
byte(5), // pkgLen
|
byte(5), // pkgLen
|
||||||
'F', 'O', 'O', 'F',
|
'F', 'O', 'O', 'F',
|
||||||
// Missing flag byte
|
// Missing flag byte
|
||||||
@ -678,7 +698,7 @@ type mockResolver struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m mockResolver) LookupTable(name string) *table.SDTHeader {
|
func (m mockResolver) LookupTable(name string) *table.SDTHeader {
|
||||||
pathToDumps := pkgDir() + "/../table/tabletest/"
|
pathToDumps := pkgDir() + "/../../table/tabletest/"
|
||||||
for _, f := range m.tableFiles {
|
for _, f := range m.tableFiles {
|
||||||
if !strings.Contains(f, name) {
|
if !strings.Contains(f, name) {
|
||||||
continue
|
continue
|
||||||
@ -709,3 +729,23 @@ func (f fixedPayloadResolver) LookupTable(name string) *table.SDTHeader {
|
|||||||
|
|
||||||
return hdr
|
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
|
||||||
|
}
|
Binary file not shown.
@ -64,6 +64,36 @@ DefinitionBlock ("parser-testsuite-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0
|
|||||||
Load(DBG0, Local0)
|
Load(DBG0, Local0)
|
||||||
Unload(Local0)
|
Unload(Local0)
|
||||||
|
|
||||||
|
CreateBitField(Arg0, 0, WFL0)
|
||||||
|
if(Arg0==0){
|
||||||
|
Return(WFL0)
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateByteField(Arg0, 0, WFL1)
|
||||||
|
if(Arg0==1){
|
||||||
|
Return(WFL1)
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateWordField(Arg0, 0, WFL2)
|
||||||
|
if(Arg0==2){
|
||||||
|
Return(WFL2)
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateDwordField(Arg0, 0, WFL3)
|
||||||
|
if(Arg0==3){
|
||||||
|
Return(WFL3)
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateQwordField(Arg0, 0, WFL4)
|
||||||
|
if(Arg0==4){
|
||||||
|
Return(WFL4)
|
||||||
|
}
|
||||||
|
|
||||||
|
CreateField(Arg0, 0, 13, WFL5)
|
||||||
|
if(Arg0==5){
|
||||||
|
Return(WFL5)
|
||||||
|
}
|
||||||
|
|
||||||
// Example from p. 951 of the spec
|
// Example from p. 951 of the spec
|
||||||
Store (
|
Store (
|
||||||
LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD",
|
LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD",
|
||||||
@ -114,4 +144,9 @@ DefinitionBlock ("parser-testsuite-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0
|
|||||||
|
|
||||||
// Data Region
|
// Data Region
|
||||||
DataTableRegion (REG0, "FOOF", "BAR", "BAZ")
|
DataTableRegion (REG0, "FOOF", "BAR", "BAZ")
|
||||||
|
|
||||||
|
// Other resources
|
||||||
|
Processor(CPU0, 1, 0x120, 6){}
|
||||||
|
PowerResource(PWR0, 0, 0){}
|
||||||
|
ThermalZone(TZ0){}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user