1
0
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:
Achilleas Anagnostopoulos 2017-12-29 09:12:08 +00:00
parent 12ad177381
commit b278ce626b
10 changed files with 441 additions and 412 deletions

View File

@ -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.

View File

@ -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:

View File

@ -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
}
}

View File

@ -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 {

View File

@ -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"))

View File

@ -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

View File

@ -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)
}

View File

@ -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
}

View File

@ -6,112 +6,147 @@
// virtualbox.
DefinitionBlock ("parser-testsuite-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002)
{
OperationRegion (DBG0, SystemIO, 0x3000, 0x04)
Field (DBG0, ByteAcc, NoLock, Preserve)
{
DHE1, 8
}
Device (DRV0)
OperationRegion (DBG0, SystemIO, 0x3000, 0x04)
Field (DBG0, ByteAcc, NoLock, Preserve)
{
Name (_ADR, Ones)
// named entity containing qword const
Name (H15F, 0xBADC0FEEDEADC0DE)
Method (_GTF, 0, NotSerialized) // _GTF: Get Task File
{
Return (H15F)
}
DHE1, 8
}
// example from p. 268 of ACPI 6.2 spec
Scope(\_SB){
OperationRegion(TOP1, GenericSerialBus, 0x00, 0x100) // GenericSerialBus device at command offset 0x00
Device (DRV0)
{
Name (_ADR, Ones)
Name (SDB0, ResourceTemplate() {})
Field(TOP1, BufferAcc, NoLock, Preserve){
Connection(SDB0), // Use the Resource Descriptor defined above
AccessAs(BufferAcc, AttribWord),
FLD0, 8,
FLD1, 8
}
// named entity containing qword const
Name (H15F, 0xBADC0FEEDEADC0DE)
Method (_GTF, 0, NotSerialized) // _GTF: Get Task File
{
Return (H15F)
}
}
Field(TOP1, BufferAcc, NoLock, Preserve){
Connection(I2cSerialBus(0x5b,,100000,, "\\_SB",,,,RawDataBuffer(){3,9})),
AccessAs(BufferAcc, AttribBytes(4)),
FLD2, 8,
AccessAs(BufferAcc, AttribRawBytes(3)),
FLD3, 8,
AccessAs(BufferAcc, AttribRawProcessBytes(2)),
FLD4, 8
}
// example from p. 268 of ACPI 6.2 spec
Scope(\_SB){
OperationRegion(TOP1, GenericSerialBus, 0x00, 0x100) // GenericSerialBus device at command offset 0x00
Name (SDB0, ResourceTemplate() {})
Field(TOP1, BufferAcc, NoLock, Preserve){
Connection(SDB0), // Use the Resource Descriptor defined above
AccessAs(BufferAcc, AttribWord),
FLD0, 8,
FLD1, 8
}
Field(TOP1, BufferAcc, NoLock, Preserve){
Connection(I2cSerialBus(0x5b,,100000,, "\\_SB",,,,RawDataBuffer(){3,9})),
AccessAs(BufferAcc, AttribBytes(4)),
FLD2, 8,
AccessAs(BufferAcc, AttribRawBytes(3)),
FLD3, 8,
AccessAs(BufferAcc, AttribRawProcessBytes(2)),
FLD4, 8
}
}
// Other entity types
Event(HLO0)
// Other entity types
Event(HLO0)
Mutex(MUT0,1)
Signal(HLO0)
// Other executable bits
Method (EXE0, 1, Serialized)
{
Local0 = Revision
Local0 = Revision
// NameString target
Local1 = SizeOf(GLB1)
// NameString target
Local1 = SizeOf(GLB1)
Local0 = "my-handle"
Load(DBG0, Local0)
Unload(Local0)
Local0 = "my-handle"
Load(DBG0, Local0)
Unload(Local0)
// Example from p. 951 of the spec
Store (
LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD",
Package () {0,"\\_SB.PCI0"}
), Local0
)
CreateBitField(Arg0, 0, WFL0)
if(Arg0==0){
Return(WFL0)
}
FromBCD(9, Arg0)
ToBCD(Arg0, Local1)
CreateByteField(Arg0, 0, WFL1)
if(Arg0==1){
Return(WFL1)
}
Breakpoint
Debug = "test"
Fatal(0xf0, 0xdeadc0de, 1)
CreateWordField(Arg0, 0, WFL2)
if(Arg0==2){
Return(WFL2)
}
Reset(HLO0)
CreateDwordField(Arg0, 0, WFL3)
if(Arg0==3){
Return(WFL3)
}
// Mutex support
Acquire(MUT0, 0xffff) // no timeout
Release(MUT0)
CreateQwordField(Arg0, 0, WFL4)
if(Arg0==4){
Return(WFL4)
}
// Signal/Wait
Wait(HLO0, 0xffff)
CreateField(Arg0, 0, 13, WFL5)
if(Arg0==5){
Return(WFL5)
}
// Get monotonic timer value
Local0 = Timer
// Example from p. 951 of the spec
Store (
LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD",
Package () {0,"\\_SB.PCI0"}
), Local0
)
CopyObject(Local0, Local1)
Return(ObjectType(Local1))
FromBCD(9, Arg0)
ToBCD(Arg0, Local1)
Breakpoint
Debug = "test"
Fatal(0xf0, 0xdeadc0de, 1)
Reset(HLO0)
// Mutex support
Acquire(MUT0, 0xffff) // no timeout
Release(MUT0)
// Signal/Wait
Wait(HLO0, 0xffff)
// Get monotonic timer value
Local0 = Timer
CopyObject(Local0, Local1)
Return(ObjectType(Local1))
}
// Misc regions
// Misc regions
// BankField example from p. 899 of the spec
// Define a 256-byte operational region in SystemIO space and name it GIO0
OperationRegion (GIO0, SystemIO, 0x125, 0x100)
// BankField example from p. 899 of the spec
// Define a 256-byte operational region in SystemIO space and name it GIO0
OperationRegion (GIO0, SystemIO, 0x125, 0x100)
Field (GIO0, ByteAcc, NoLock, Preserve) {
GLB1, 1,
GLB1, 1,
GLB2, 1,
Offset (1), // Move to offset for byte 1
BNK1, 4
}
BankField (GIO0, BNK1, 0, ByteAcc, NoLock, Preserve) {
Offset (0x30),
FET0, 1,
FET1, 1
}
BankField (GIO0, BNK1, 0, ByteAcc, NoLock, Preserve) {
Offset (0x30),
FET0, 1,
FET1, 1
}
// Data Region
DataTableRegion (REG0, "FOOF", "BAR", "BAZ")
// Data Region
DataTableRegion (REG0, "FOOF", "BAR", "BAZ")
// Other resources
Processor(CPU0, 1, 0x120, 6){}
PowerResource(PWR0, 0, 0){}
ThermalZone(TZ0){}
}