mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Merge pull request #61 from achilleasa/refactor-aml-parser-into-multiple-packages
Refactor AML parser into multiple packages and fix parser bugs
This commit is contained in:
commit
3396b997e7
@ -1,506 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gopheros/kernel/kfmt"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
type resolver interface {
|
|
||||||
Resolve(io.Writer, ScopeEntity) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Entity is an interface implemented by all AML entities.
|
|
||||||
type Entity interface {
|
|
||||||
Name() string
|
|
||||||
Parent() ScopeEntity
|
|
||||||
TableHandle() uint8
|
|
||||||
|
|
||||||
setTableHandle(uint8)
|
|
||||||
getOpcode() opcode
|
|
||||||
setOpcode(opcode)
|
|
||||||
setParent(ScopeEntity)
|
|
||||||
getArgs() []interface{}
|
|
||||||
setArg(uint8, interface{}) bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// ScopeEntity is an interface that is implemented by entities that define an
|
|
||||||
// AML scope.
|
|
||||||
type ScopeEntity interface {
|
|
||||||
Entity
|
|
||||||
|
|
||||||
Children() []Entity
|
|
||||||
Append(Entity) bool
|
|
||||||
|
|
||||||
removeChild(Entity)
|
|
||||||
lastChild() Entity
|
|
||||||
}
|
|
||||||
|
|
||||||
// unnamedEntity defines an unnamed entity that can be attached to a parent scope.
|
|
||||||
type unnamedEntity struct {
|
|
||||||
tableHandle uint8
|
|
||||||
op opcode
|
|
||||||
args []interface{}
|
|
||||||
parent ScopeEntity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *unnamedEntity) getOpcode() opcode { return ent.op }
|
|
||||||
func (ent *unnamedEntity) setOpcode(op opcode) { ent.op = op }
|
|
||||||
func (ent *unnamedEntity) Name() string { return "" }
|
|
||||||
func (ent *unnamedEntity) Parent() ScopeEntity { return ent.parent }
|
|
||||||
func (ent *unnamedEntity) setParent(parent ScopeEntity) { ent.parent = parent }
|
|
||||||
func (ent *unnamedEntity) getArgs() []interface{} { return ent.args }
|
|
||||||
func (ent *unnamedEntity) setArg(_ uint8, arg interface{}) bool {
|
|
||||||
ent.args = append(ent.args, arg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
func (ent *unnamedEntity) TableHandle() uint8 { return ent.tableHandle }
|
|
||||||
func (ent *unnamedEntity) setTableHandle(h uint8) { ent.tableHandle = h }
|
|
||||||
|
|
||||||
// namedEntity is a named entity that can be attached to the parent scope. The
|
|
||||||
// setArg() implementation for this type expects arg at index 0 to contain the
|
|
||||||
// entity name.
|
|
||||||
type namedEntity struct {
|
|
||||||
tableHandle uint8
|
|
||||||
op opcode
|
|
||||||
args []interface{}
|
|
||||||
parent ScopeEntity
|
|
||||||
|
|
||||||
name string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *namedEntity) getOpcode() opcode { return ent.op }
|
|
||||||
func (ent *namedEntity) setOpcode(op opcode) { ent.op = op }
|
|
||||||
func (ent *namedEntity) Name() string { return ent.name }
|
|
||||||
func (ent *namedEntity) Parent() ScopeEntity { return ent.parent }
|
|
||||||
func (ent *namedEntity) setParent(parent ScopeEntity) { ent.parent = parent }
|
|
||||||
func (ent *namedEntity) getArgs() []interface{} { return ent.args }
|
|
||||||
func (ent *namedEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
// arg 0 is the entity name
|
|
||||||
if argIndex == 0 {
|
|
||||||
var ok bool
|
|
||||||
ent.name, ok = arg.(string)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
ent.args = append(ent.args, arg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
func (ent *namedEntity) TableHandle() uint8 { return ent.tableHandle }
|
|
||||||
func (ent *namedEntity) setTableHandle(h uint8) { ent.tableHandle = h }
|
|
||||||
|
|
||||||
// constEntity is an optionally-named entity which always
|
|
||||||
// evaluates to a constant value. Calls to setArg for
|
|
||||||
// argument index 0 will memoize the argument value that is
|
|
||||||
// stored inside this entity.
|
|
||||||
type constEntity struct {
|
|
||||||
name string
|
|
||||||
tableHandle uint8
|
|
||||||
op opcode
|
|
||||||
args []interface{}
|
|
||||||
parent ScopeEntity
|
|
||||||
|
|
||||||
val interface{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *constEntity) getOpcode() opcode { return ent.op }
|
|
||||||
func (ent *constEntity) setOpcode(op opcode) {
|
|
||||||
ent.op = op
|
|
||||||
|
|
||||||
// special const opcode cases that have an implicit value
|
|
||||||
switch ent.op {
|
|
||||||
case opZero:
|
|
||||||
ent.val = uint64(0)
|
|
||||||
case opOne:
|
|
||||||
ent.val = uint64(1)
|
|
||||||
case opOnes:
|
|
||||||
ent.val = uint64(1<<64 - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (ent *constEntity) Name() string { return ent.name }
|
|
||||||
func (ent *constEntity) Parent() ScopeEntity { return ent.parent }
|
|
||||||
func (ent *constEntity) setParent(parent ScopeEntity) { ent.parent = parent }
|
|
||||||
func (ent *constEntity) getArgs() []interface{} { return ent.args }
|
|
||||||
func (ent *constEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
ent.val = arg
|
|
||||||
return argIndex == 0
|
|
||||||
}
|
|
||||||
func (ent *constEntity) TableHandle() uint8 { return ent.tableHandle }
|
|
||||||
func (ent *constEntity) setTableHandle(h uint8) { ent.tableHandle = h }
|
|
||||||
|
|
||||||
// scopeEntity is an optionally named entity that defines a scope.
|
|
||||||
type scopeEntity struct {
|
|
||||||
tableHandle uint8
|
|
||||||
op opcode
|
|
||||||
args []interface{}
|
|
||||||
parent ScopeEntity
|
|
||||||
|
|
||||||
name string
|
|
||||||
children []Entity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *scopeEntity) getOpcode() opcode { return ent.op }
|
|
||||||
func (ent *scopeEntity) setOpcode(op opcode) { ent.op = op }
|
|
||||||
func (ent *scopeEntity) Name() string { return ent.name }
|
|
||||||
func (ent *scopeEntity) Parent() ScopeEntity { return ent.parent }
|
|
||||||
func (ent *scopeEntity) setParent(parent ScopeEntity) { ent.parent = parent }
|
|
||||||
func (ent *scopeEntity) getArgs() []interface{} { return ent.args }
|
|
||||||
func (ent *scopeEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
// arg 0 *may* be the entity name. If it's not a string just add it to
|
|
||||||
// the arg list.
|
|
||||||
if argIndex == 0 {
|
|
||||||
var ok bool
|
|
||||||
if ent.name, ok = arg.(string); ok {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ent.args = append(ent.args, arg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
func (ent *scopeEntity) Children() []Entity { return ent.children }
|
|
||||||
func (ent *scopeEntity) Append(child Entity) bool {
|
|
||||||
child.setParent(ent)
|
|
||||||
ent.children = append(ent.children, child)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
func (ent *scopeEntity) lastChild() Entity { return ent.children[len(ent.children)-1] }
|
|
||||||
func (ent *scopeEntity) removeChild(child Entity) {
|
|
||||||
for index := 0; index < len(ent.children); index++ {
|
|
||||||
if ent.children[index] == child {
|
|
||||||
ent.children = append(ent.children[:index], ent.children[index+1:]...)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
func (ent *scopeEntity) TableHandle() uint8 { return ent.tableHandle }
|
|
||||||
func (ent *scopeEntity) setTableHandle(h uint8) { ent.tableHandle = h }
|
|
||||||
|
|
||||||
// bufferEntity defines a buffer object.
|
|
||||||
type bufferEntity struct {
|
|
||||||
unnamedEntity
|
|
||||||
|
|
||||||
size interface{}
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *bufferEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
switch argIndex {
|
|
||||||
case 0: // size
|
|
||||||
ent.size = arg
|
|
||||||
return true
|
|
||||||
case 1: // data
|
|
||||||
if byteSlice, ok := arg.([]byte); ok {
|
|
||||||
ent.data = byteSlice
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// bufferFieldEntity describes a bit/byte/word/dword/qword or arbitrary length
|
|
||||||
// buffer field.
|
|
||||||
type bufferFieldEntity struct {
|
|
||||||
namedEntity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *bufferFieldEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
// opCreateField specifies the name using the arg at index 3 while
|
|
||||||
// opCreateXXXField (byte, word e.t.c) specifies the name using the
|
|
||||||
// arg at index 2
|
|
||||||
if (ent.op == opCreateField && argIndex == 3) || argIndex == 2 {
|
|
||||||
var ok bool
|
|
||||||
ent.name, ok = arg.(string)
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
ent.args = append(ent.args, arg)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegionSpace describes the memory space where a region is located.
|
|
||||||
type RegionSpace uint8
|
|
||||||
|
|
||||||
// The list of supported RegionSpace values.
|
|
||||||
const (
|
|
||||||
RegionSpaceSystemMemory RegionSpace = iota
|
|
||||||
RegionSpaceSystemIO
|
|
||||||
RegionSpacePCIConfig
|
|
||||||
RegionSpaceEmbeddedControl
|
|
||||||
RegionSpaceSMBus
|
|
||||||
RegionSpacePCIBarTarget
|
|
||||||
RegionSpaceIPMI
|
|
||||||
)
|
|
||||||
|
|
||||||
// regionEntity defines a region located at a particular space (e.g in memory,
|
|
||||||
// an embedded controller, the SMBus e.t.c).
|
|
||||||
type regionEntity struct {
|
|
||||||
namedEntity
|
|
||||||
|
|
||||||
space RegionSpace
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *regionEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
var ok bool
|
|
||||||
switch argIndex {
|
|
||||||
case 0:
|
|
||||||
ok = ent.namedEntity.setArg(argIndex, arg)
|
|
||||||
case 1:
|
|
||||||
// the parser will convert ByteData types to uint64
|
|
||||||
var space uint64
|
|
||||||
space, ok = arg.(uint64)
|
|
||||||
ent.space = RegionSpace(space)
|
|
||||||
case 2, 3:
|
|
||||||
ent.args = append(ent.args, arg)
|
|
||||||
ok = true
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
||||||
// FieldAccessType specifies the type of access (byte, word, e.t.c) used to
|
|
||||||
// read/write to a field.
|
|
||||||
type FieldAccessType uint8
|
|
||||||
|
|
||||||
// The list of supported FieldAccessType values.
|
|
||||||
const (
|
|
||||||
FieldAccessTypeAny FieldAccessType = iota
|
|
||||||
FieldAccessTypeByte
|
|
||||||
FieldAccessTypeWord
|
|
||||||
FieldAccessTypeDword
|
|
||||||
FieldAccessTypeQword
|
|
||||||
FieldAccessTypeBuffer
|
|
||||||
)
|
|
||||||
|
|
||||||
// FieldUpdateRule specifies how a field value is updated when a write uses
|
|
||||||
// a value with a smaller width than the field.
|
|
||||||
type FieldUpdateRule uint8
|
|
||||||
|
|
||||||
// The list of supported FieldUpdateRule values.
|
|
||||||
const (
|
|
||||||
FieldUpdateRulePreserve FieldUpdateRule = iota
|
|
||||||
FieldUpdateRuleWriteAsOnes
|
|
||||||
FieldUpdateRuleWriteAsZeros
|
|
||||||
)
|
|
||||||
|
|
||||||
// FieldAccessAttrib specifies additional information about a particular field
|
|
||||||
// access.
|
|
||||||
type FieldAccessAttrib uint8
|
|
||||||
|
|
||||||
// The list of supported FieldAccessAttrib values.
|
|
||||||
const (
|
|
||||||
FieldAccessAttribQuick FieldAccessAttrib = 0x02
|
|
||||||
FieldAccessAttribSendReceive = 0x04
|
|
||||||
FieldAccessAttribByte = 0x06
|
|
||||||
FieldAccessAttribWord = 0x08
|
|
||||||
FieldAccessAttribBlock = 0x0a
|
|
||||||
FieldAccessAttribBytes = 0x0b // byteCount contains the number of bytes
|
|
||||||
FieldAccessAttribProcessCall = 0x0c
|
|
||||||
FieldAccessAttribBlockProcessCall = 0x0d
|
|
||||||
FieldAccessAttribRawBytes = 0x0e // byteCount contains the number of bytes
|
|
||||||
FieldAccessAttribRawProcessBytes = 0x0f // byteCount contains the number of bytes
|
|
||||||
)
|
|
||||||
|
|
||||||
// fieldEntity is a named object that encapsulates the data shared between regular
|
|
||||||
// fields and index fields.
|
|
||||||
type fieldEntity struct {
|
|
||||||
namedEntity
|
|
||||||
|
|
||||||
bitOffset uint32
|
|
||||||
bitWidth uint32
|
|
||||||
|
|
||||||
lock bool
|
|
||||||
updateRule FieldUpdateRule
|
|
||||||
|
|
||||||
// accessAttrib is valid if accessType is BufferAcc
|
|
||||||
// for the SMB or GPIO OpRegions.
|
|
||||||
accessAttrib FieldAccessAttrib
|
|
||||||
accessType FieldAccessType
|
|
||||||
|
|
||||||
// byteCount is valid when accessAttrib is one of:
|
|
||||||
// Bytes, RawBytes or RawProcessBytes
|
|
||||||
byteCount uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// fieldUnitEntity is a field defined inside an operating region.
|
|
||||||
type fieldUnitEntity struct {
|
|
||||||
fieldEntity
|
|
||||||
|
|
||||||
// The connection which this field references.
|
|
||||||
connectionName string
|
|
||||||
resolvedConnection Entity
|
|
||||||
|
|
||||||
// The region which this field references.
|
|
||||||
regionName string
|
|
||||||
resolvedRegion *regionEntity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *fieldUnitEntity) Resolve(errWriter io.Writer, rootNs ScopeEntity) bool {
|
|
||||||
var ok bool
|
|
||||||
if ent.connectionName != "" && ent.resolvedConnection == nil {
|
|
||||||
if ent.resolvedConnection = scopeFind(ent.parent, rootNs, ent.connectionName); ent.resolvedConnection == nil {
|
|
||||||
kfmt.Fprintf(errWriter, "[field %s] could not resolve connection reference: %s\n", ent.name, ent.connectionName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ent.resolvedRegion == nil {
|
|
||||||
if ent.resolvedRegion, ok = scopeFind(ent.parent, rootNs, ent.regionName).(*regionEntity); !ok {
|
|
||||||
kfmt.Fprintf(errWriter, "[field %s] could not resolve referenced region: %s\n", ent.name, ent.regionName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ent.resolvedRegion != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// indexFieldEntity is a special field that groups together two field units so a
|
|
||||||
// index/data register pattern can be implemented. To write a value to an
|
|
||||||
// indexField, the interpreter must first write the appropriate offset to
|
|
||||||
// the indexRegister (using the alignment specifid by accessType) and then
|
|
||||||
// write the actual value to the dataRegister.
|
|
||||||
type indexFieldEntity struct {
|
|
||||||
fieldEntity
|
|
||||||
|
|
||||||
// The connection which this field references.
|
|
||||||
connectionName string
|
|
||||||
resolvedConnection Entity
|
|
||||||
|
|
||||||
indexRegName string
|
|
||||||
indexReg *fieldUnitEntity
|
|
||||||
|
|
||||||
dataRegName string
|
|
||||||
dataReg *fieldUnitEntity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *indexFieldEntity) Resolve(errWriter io.Writer, rootNs ScopeEntity) bool {
|
|
||||||
var ok bool
|
|
||||||
if ent.connectionName != "" && ent.resolvedConnection == nil {
|
|
||||||
if ent.resolvedConnection = scopeFind(ent.parent, rootNs, ent.connectionName); ent.resolvedConnection == nil {
|
|
||||||
kfmt.Fprintf(errWriter, "[field %s] could not resolve connection reference: %s\n", ent.name, ent.connectionName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ent.indexReg == nil {
|
|
||||||
if ent.indexReg, ok = scopeFind(ent.parent, rootNs, ent.indexRegName).(*fieldUnitEntity); !ok {
|
|
||||||
kfmt.Fprintf(errWriter, "[indexField %s] could not resolve referenced index register: %s\n", ent.name, ent.indexRegName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ent.dataReg == nil {
|
|
||||||
if ent.dataReg, ok = scopeFind(ent.parent, rootNs, ent.dataRegName).(*fieldUnitEntity); !ok {
|
|
||||||
kfmt.Fprintf(errWriter, "[dataField %s] could not resolve referenced data register: %s\n", ent.name, ent.dataRegName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ent.indexReg != nil && ent.dataReg != nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// namedReference holds a named reference to an AML symbol. The spec allows
|
|
||||||
// the symbol not to be defined at the time when the reference is parsed. In
|
|
||||||
// such a case (forward reference) it will be resolved after the entire AML
|
|
||||||
// stream has successfully been parsed.
|
|
||||||
type namedReference struct {
|
|
||||||
unnamedEntity
|
|
||||||
|
|
||||||
targetName string
|
|
||||||
target Entity
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ref *namedReference) Resolve(errWriter io.Writer, rootNs ScopeEntity) bool {
|
|
||||||
if ref.target == nil {
|
|
||||||
if ref.target = scopeFind(ref.parent, rootNs, ref.targetName); ref.target == nil {
|
|
||||||
kfmt.Fprintf(errWriter, "could not resolve referenced symbol: %s (parent: %s)\n", ref.targetName, ref.parent.Name())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// methodInvocationEntity describes an AML method invocation.
|
|
||||||
type methodInvocationEntity struct {
|
|
||||||
unnamedEntity
|
|
||||||
|
|
||||||
methodName string
|
|
||||||
method *Method
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *methodInvocationEntity) Resolve(errWriter io.Writer, rootNs ScopeEntity) bool {
|
|
||||||
if m.method == nil {
|
|
||||||
var isMethod bool
|
|
||||||
if m.method, isMethod = scopeFind(m.parent, rootNs, m.methodName).(*Method); !isMethod {
|
|
||||||
kfmt.Fprintf(errWriter, "could not resolve merenced method: %s (parent: %s)\n", m.methodName, m.parent.Name())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Method defines an invocable AML method.
|
|
||||||
type Method struct {
|
|
||||||
scopeEntity
|
|
||||||
|
|
||||||
tableHandle uint8
|
|
||||||
argCount uint8
|
|
||||||
serialized bool
|
|
||||||
syncLevel uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *Method) getOpcode() opcode { return opMethod }
|
|
||||||
|
|
||||||
// Device defines a device.
|
|
||||||
type Device struct {
|
|
||||||
scopeEntity
|
|
||||||
|
|
||||||
tableHandle uint8
|
|
||||||
|
|
||||||
// The methodMap keeps track of all methods exposed by this device.
|
|
||||||
methodMap map[string]*Method
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Device) getOpcode() opcode { return opDevice }
|
|
||||||
func (d *Device) setTableHandle(h uint8) { d.tableHandle = h }
|
|
||||||
|
|
||||||
// TableHandle returns the handle of the ACPI table that defines this device.
|
|
||||||
func (d *Device) TableHandle() uint8 { return d.tableHandle }
|
|
||||||
|
|
||||||
// mutexEntity represents a named mutex object
|
|
||||||
type mutexEntity struct {
|
|
||||||
parent ScopeEntity
|
|
||||||
|
|
||||||
// isGlobal is set to true for the pre-defined global mutex (\_GL object)
|
|
||||||
isGlobal bool
|
|
||||||
|
|
||||||
name string
|
|
||||||
syncLevel uint8
|
|
||||||
tableHandle uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ent *mutexEntity) getOpcode() opcode { return opMutex }
|
|
||||||
func (ent *mutexEntity) setOpcode(op opcode) {}
|
|
||||||
func (ent *mutexEntity) Name() string { return ent.name }
|
|
||||||
func (ent *mutexEntity) Parent() ScopeEntity { return ent.parent }
|
|
||||||
func (ent *mutexEntity) setParent(parent ScopeEntity) { ent.parent = parent }
|
|
||||||
func (ent *mutexEntity) getArgs() []interface{} { return nil }
|
|
||||||
func (ent *mutexEntity) setArg(argIndex uint8, arg interface{}) bool {
|
|
||||||
var ok bool
|
|
||||||
switch argIndex {
|
|
||||||
case 0:
|
|
||||||
// arg 0 is the mutex name
|
|
||||||
ent.name, ok = arg.(string)
|
|
||||||
case 1:
|
|
||||||
// arg1 is the sync level (bits 0:3)
|
|
||||||
var syncLevel uint64
|
|
||||||
syncLevel, ok = arg.(uint64)
|
|
||||||
ent.syncLevel = uint8(syncLevel) & 0xf
|
|
||||||
}
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
func (ent *mutexEntity) TableHandle() uint8 { return ent.tableHandle }
|
|
||||||
func (ent *mutexEntity) setTableHandle(h uint8) { ent.tableHandle = h }
|
|
||||||
|
|
||||||
// eventEntity represents a named ACPI sync event.
|
|
||||||
type eventEntity struct {
|
|
||||||
namedEntity
|
|
||||||
}
|
|
1044
src/gopheros/device/acpi/aml/entity/entity.go
Normal file
1044
src/gopheros/device/acpi/aml/entity/entity.go
Normal file
File diff suppressed because it is too large
Load Diff
295
src/gopheros/device/acpi/aml/entity/entity_test.go
Normal file
295
src/gopheros/device/acpi/aml/entity/entity_test.go
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEntityMethods(t *testing.T) {
|
||||||
|
namedConst := NewConst(OpDwordPrefix, 42, "foo")
|
||||||
|
namedConst.SetName("TAG0")
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
ent Entity
|
||||||
|
expOp AMLOpcode
|
||||||
|
expName string
|
||||||
|
}{
|
||||||
|
{NewGeneric(OpNoop, 42), OpNoop, ""},
|
||||||
|
{NewGenericNamed(OpAcquire, 42), OpAcquire, ""},
|
||||||
|
{namedConst, OpDwordPrefix, "TAG0"},
|
||||||
|
{NewScope(OpScope, 42, "_SB_"), OpScope, "_SB_"},
|
||||||
|
{NewBuffer(42), OpBuffer, ""},
|
||||||
|
{NewBufferField(OpCreateByteField, 42, 8), OpCreateByteField, ""},
|
||||||
|
{NewField(42), OpField, ""},
|
||||||
|
{NewIndexField(42), OpIndexField, ""},
|
||||||
|
{NewBankField(42), OpBankField, ""},
|
||||||
|
{NewReference(42, "TRG0"), OpName, ""},
|
||||||
|
{NewMethod(42, "FOO0"), OpMethod, "FOO0"},
|
||||||
|
{NewInvocation(42, NewMethod(42, "MTH0"), nil), OpMethodInvocation, ""},
|
||||||
|
{NewMutex(42), OpMutex, ""},
|
||||||
|
{NewDevice(42, "DEV0"), OpDevice, "DEV0"},
|
||||||
|
{NewProcessor(42, "CPU0"), OpProcessor, "CPU0"},
|
||||||
|
{NewPowerResource(42, "POW0"), OpPowerRes, "POW0"},
|
||||||
|
{NewThermalZone(42, "THE0"), OpThermalZone, "THE0"},
|
||||||
|
{NewEvent(42), OpEvent, ""},
|
||||||
|
{NewRegion(42), OpOpRegion, ""},
|
||||||
|
{NewFieldUnit(42, "FOO0"), OpFieldUnit, "FOO0"},
|
||||||
|
{NewPackage(OpPackage, 42), OpPackage, ""},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("opcode and name getter", func(t *testing.T) {
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
if got := spec.ent.Opcode(); got != spec.expOp {
|
||||||
|
t.Errorf("[spec %d] expected to get back opcode %d; got %d", specIndex, spec.expOp, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := spec.ent.Name(); got != spec.expName {
|
||||||
|
t.Errorf("[spec %d] expected to get name: %q; got %q", specIndex, spec.expName, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("table handle getter", func(t *testing.T) {
|
||||||
|
exp := uint8(42)
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
if got := spec.ent.TableHandle(); got != exp {
|
||||||
|
t.Errorf("[spec %d] expected to get back handle %d; got %d", specIndex, exp, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("append/remove/get parent methods", func(t *testing.T) {
|
||||||
|
parent := NewScope(OpScope, 2, "_SB_")
|
||||||
|
parent.name = `\`
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
parent.Append(spec.ent)
|
||||||
|
if got := spec.ent.Parent(); got != parent {
|
||||||
|
t.Errorf("[spec %d] expected to get back parent %v; got %v", specIndex, parent, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := parent.Last(); got != spec.ent {
|
||||||
|
t.Errorf("[spec %d] expected parent's last entity to be the one just appended", specIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.Remove(spec.ent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := len(parent.Children()); got != 0 {
|
||||||
|
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) {
|
||||||
|
specs := []struct {
|
||||||
|
ent Entity
|
||||||
|
argList []interface{}
|
||||||
|
expArgList []interface{}
|
||||||
|
limitedArgs bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
NewGeneric(1, 2),
|
||||||
|
[]interface{}{"foo", 1, "bar"},
|
||||||
|
[]interface{}{"foo", 1, "bar"},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewGenericNamed(1, 2),
|
||||||
|
[]interface{}{"foo", 1, "bar"},
|
||||||
|
[]interface{}{1, "bar"}, // GenericNamed uses arg0 as the name
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewConst(1, 2, 3),
|
||||||
|
[]interface{}{"foo"},
|
||||||
|
nil, // Const populates its internal state using the arg 0
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewBuffer(2),
|
||||||
|
[]interface{}{1, []byte{}},
|
||||||
|
nil, // Buffer populates its internal state using the first 2 args
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewBufferField(OpCreateDWordField, 2, 32),
|
||||||
|
[]interface{}{"a", "b", "c"},
|
||||||
|
nil, // Buffer populates its internal state using the first 3 args (opCreateDwordField)
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewBufferField(1, 2, 0),
|
||||||
|
[]interface{}{"a", "b", 10, "c"},
|
||||||
|
nil, // Buffer populates its internal state using the first 4 args (opCreateField)
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewRegion(2),
|
||||||
|
[]interface{}{"REG0", uint64(0x4), 0, 10},
|
||||||
|
nil, // Region populates its internal state using the first 4 args
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewMutex(2),
|
||||||
|
[]interface{}{"MUT0", uint64(1)},
|
||||||
|
nil, // Mutex populates its internal state using the first 2 args
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewProcessor(2, "CPU0"),
|
||||||
|
[]interface{}{uint64(1), uint64(0xdeadc0de), uint64(0)},
|
||||||
|
nil, // Processor populates its internal state using the first 3 args
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewPowerResource(2, "POW0"),
|
||||||
|
[]interface{}{uint64(2), uint64(1)},
|
||||||
|
nil, // PowerResource populates its internal state using the first 2 args
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewMethod(2, "MTH0"),
|
||||||
|
[]interface{}{"arg0 ignored", uint64(0x42)},
|
||||||
|
nil, // Method populates its internal state using the first 2 args
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
NewPackage(OpPackage, 2),
|
||||||
|
[]interface{}{uint64(1), NewConst(OpDwordPrefix, 2, uint64(42))},
|
||||||
|
[]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:
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
for i, arg := range spec.argList {
|
||||||
|
if !spec.ent.SetArg(uint8(i), arg) {
|
||||||
|
t.Errorf("[spec %d] error setting arg %d", specIndex, i)
|
||||||
|
continue nextSpec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if spec.limitedArgs {
|
||||||
|
if spec.ent.SetArg(uint8(len(spec.argList)), nil) {
|
||||||
|
t.Errorf("[spec %d] expected additional calls to setArg to return false", specIndex)
|
||||||
|
continue nextSpec
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := spec.ent.Args(); !reflect.DeepEqual(got, spec.expArgList) {
|
||||||
|
t.Errorf("[spec %d] expected to get back arg list %v; got %v", specIndex, spec.expArgList, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLazySymbolResolver(t *testing.T) {
|
||||||
|
root := NewScope(OpScope, 42, `\`)
|
||||||
|
reg0 := NewRegion(42)
|
||||||
|
reg0.SetArg(0, "REG0")
|
||||||
|
root.Append(reg0)
|
||||||
|
root.Append(NewFieldUnit(42, "FLD0"))
|
||||||
|
root.Append(NewMethod(42, "MTH0"))
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
ent Entity
|
||||||
|
expErr string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
&Field{RegionName: "MISSING"},
|
||||||
|
"could not resolve referenced field region: MISSING",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Field{RegionName: "REG0"},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&IndexField{IndexRegName: "UNKNOWN"},
|
||||||
|
"could not resolve referenced index register: UNKNOWN",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&IndexField{IndexRegName: "FLD0", DataRegName: "UNKNOWN"},
|
||||||
|
"could not resolve referenced data register: UNKNOWN",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&IndexField{IndexRegName: "FLD0", DataRegName: "FLD0"},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&BankField{RegionName: "MISSING"},
|
||||||
|
"could not resolve referenced field region: MISSING",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&BankField{RegionName: "REG0", BankFieldUnitName: "UNKNOWN"},
|
||||||
|
"could not resolve referenced bank register field: UNKNOWN",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&BankField{RegionName: "REG0", BankFieldUnitName: "FLD0"},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&FieldUnit{
|
||||||
|
GenericNamed: GenericNamed{name: "FLD0"},
|
||||||
|
ConnectionName: "MISSING",
|
||||||
|
},
|
||||||
|
"[field unit: FLD0] could not resolve connection reference: MISSING",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// No connection reference
|
||||||
|
&FieldUnit{},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&FieldUnit{ConnectionName: "FLD0"},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Reference{TargetName: "MISSING"},
|
||||||
|
`could not resolve referenced symbol: MISSING; parent: \`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
&Reference{TargetName: "FLD0"},
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
root.Append(spec.ent)
|
||||||
|
err := spec.ent.(LazyRefResolver).ResolveSymbolRefs(root)
|
||||||
|
if spec.expErr != "" && (err == nil || err.Message != spec.expErr) {
|
||||||
|
t.Errorf("[spec %d] expected ResolveReferences to return error %q; got: %v", specIndex, spec.expErr, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
430
src/gopheros/device/acpi/aml/entity/opcode.go
Normal file
430
src/gopheros/device/acpi/aml/entity/opcode.go
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
// AMLOpcode describes an AML opcode. While AML supports 256 opcodes, some of
|
||||||
|
// them are specified using a combination of an extension prefix and a code. To
|
||||||
|
// map each opcode into a single unique value the parser uses an uint16
|
||||||
|
// representation of the opcode values.
|
||||||
|
type AMLOpcode uint16
|
||||||
|
|
||||||
|
// List of AML opcodes
|
||||||
|
const (
|
||||||
|
// Regular opcode list
|
||||||
|
OpZero = AMLOpcode(0x00)
|
||||||
|
OpOne = AMLOpcode(0x01)
|
||||||
|
OpAlias = AMLOpcode(0x06)
|
||||||
|
OpName = AMLOpcode(0x08)
|
||||||
|
OpBytePrefix = AMLOpcode(0x0a)
|
||||||
|
OpWordPrefix = AMLOpcode(0x0b)
|
||||||
|
OpDwordPrefix = AMLOpcode(0x0c)
|
||||||
|
OpStringPrefix = AMLOpcode(0x0d)
|
||||||
|
OpQwordPrefix = AMLOpcode(0x0e)
|
||||||
|
OpScope = AMLOpcode(0x10)
|
||||||
|
OpBuffer = AMLOpcode(0x11)
|
||||||
|
OpPackage = AMLOpcode(0x12)
|
||||||
|
OpVarPackage = AMLOpcode(0x13)
|
||||||
|
OpMethod = AMLOpcode(0x14)
|
||||||
|
OpExternal = AMLOpcode(0x15)
|
||||||
|
OpLocal0 = AMLOpcode(0x60)
|
||||||
|
OpLocal1 = AMLOpcode(0x61)
|
||||||
|
OpLocal2 = AMLOpcode(0x62)
|
||||||
|
OpLocal3 = AMLOpcode(0x63)
|
||||||
|
OpLocal4 = AMLOpcode(0x64)
|
||||||
|
OpLocal5 = AMLOpcode(0x65)
|
||||||
|
OpLocal6 = AMLOpcode(0x66)
|
||||||
|
OpLocal7 = AMLOpcode(0x67)
|
||||||
|
OpArg0 = AMLOpcode(0x68)
|
||||||
|
OpArg1 = AMLOpcode(0x69)
|
||||||
|
OpArg2 = AMLOpcode(0x6a)
|
||||||
|
OpArg3 = AMLOpcode(0x6b)
|
||||||
|
OpArg4 = AMLOpcode(0x6c)
|
||||||
|
OpArg5 = AMLOpcode(0x6d)
|
||||||
|
OpArg6 = AMLOpcode(0x6e)
|
||||||
|
OpStore = AMLOpcode(0x70)
|
||||||
|
OpRefOf = AMLOpcode(0x71)
|
||||||
|
OpAdd = AMLOpcode(0x72)
|
||||||
|
OpConcat = AMLOpcode(0x73)
|
||||||
|
OpSubtract = AMLOpcode(0x74)
|
||||||
|
OpIncrement = AMLOpcode(0x75)
|
||||||
|
OpDecrement = AMLOpcode(0x76)
|
||||||
|
OpMultiply = AMLOpcode(0x77)
|
||||||
|
OpDivide = AMLOpcode(0x78)
|
||||||
|
OpShiftLeft = AMLOpcode(0x79)
|
||||||
|
OpShiftRight = AMLOpcode(0x7a)
|
||||||
|
OpAnd = AMLOpcode(0x7b)
|
||||||
|
OpNand = AMLOpcode(0x7c)
|
||||||
|
OpOr = AMLOpcode(0x7d)
|
||||||
|
OpNor = AMLOpcode(0x7e)
|
||||||
|
OpXor = AMLOpcode(0x7f)
|
||||||
|
OpNot = AMLOpcode(0x80)
|
||||||
|
OpFindSetLeftBit = AMLOpcode(0x81)
|
||||||
|
OpFindSetRightBit = AMLOpcode(0x82)
|
||||||
|
OpDerefOf = AMLOpcode(0x83)
|
||||||
|
OpConcatRes = AMLOpcode(0x84)
|
||||||
|
OpMod = AMLOpcode(0x85)
|
||||||
|
OpNotify = AMLOpcode(0x86)
|
||||||
|
OpSizeOf = AMLOpcode(0x87)
|
||||||
|
OpIndex = AMLOpcode(0x88)
|
||||||
|
OpMatch = AMLOpcode(0x89)
|
||||||
|
OpCreateDWordField = AMLOpcode(0x8a)
|
||||||
|
OpCreateWordField = AMLOpcode(0x8b)
|
||||||
|
OpCreateByteField = AMLOpcode(0x8c)
|
||||||
|
OpCreateBitField = AMLOpcode(0x8d)
|
||||||
|
OpObjectType = AMLOpcode(0x8e)
|
||||||
|
OpCreateQWordField = AMLOpcode(0x8f)
|
||||||
|
OpLand = AMLOpcode(0x90)
|
||||||
|
OpLor = AMLOpcode(0x91)
|
||||||
|
OpLnot = AMLOpcode(0x92)
|
||||||
|
OpLEqual = AMLOpcode(0x93)
|
||||||
|
OpLGreater = AMLOpcode(0x94)
|
||||||
|
OpLLess = AMLOpcode(0x95)
|
||||||
|
OpToBuffer = AMLOpcode(0x96)
|
||||||
|
OpToDecimalString = AMLOpcode(0x97)
|
||||||
|
OpToHexString = AMLOpcode(0x98)
|
||||||
|
OpToInteger = AMLOpcode(0x99)
|
||||||
|
OpToString = AMLOpcode(0x9c)
|
||||||
|
OpCopyObject = AMLOpcode(0x9d)
|
||||||
|
OpMid = AMLOpcode(0x9e)
|
||||||
|
OpContinue = AMLOpcode(0x9f)
|
||||||
|
OpIf = AMLOpcode(0xa0)
|
||||||
|
OpElse = AMLOpcode(0xa1)
|
||||||
|
OpWhile = AMLOpcode(0xa2)
|
||||||
|
OpNoop = AMLOpcode(0xa3)
|
||||||
|
OpReturn = AMLOpcode(0xa4)
|
||||||
|
OpBreak = AMLOpcode(0xa5)
|
||||||
|
OpBreakPoint = AMLOpcode(0xcc)
|
||||||
|
OpOnes = AMLOpcode(0xff)
|
||||||
|
// Extended opcodes
|
||||||
|
OpMutex = AMLOpcode(0xff + 0x01)
|
||||||
|
OpEvent = AMLOpcode(0xff + 0x02)
|
||||||
|
OpCondRefOf = AMLOpcode(0xff + 0x12)
|
||||||
|
OpCreateField = AMLOpcode(0xff + 0x13)
|
||||||
|
OpLoadTable = AMLOpcode(0xff + 0x1f)
|
||||||
|
OpLoad = AMLOpcode(0xff + 0x20)
|
||||||
|
OpStall = AMLOpcode(0xff + 0x21)
|
||||||
|
OpSleep = AMLOpcode(0xff + 0x22)
|
||||||
|
OpAcquire = AMLOpcode(0xff + 0x23)
|
||||||
|
OpSignal = AMLOpcode(0xff + 0x24)
|
||||||
|
OpWait = AMLOpcode(0xff + 0x25)
|
||||||
|
OpReset = AMLOpcode(0xff + 0x26)
|
||||||
|
OpRelease = AMLOpcode(0xff + 0x27)
|
||||||
|
OpFromBCD = AMLOpcode(0xff + 0x28)
|
||||||
|
OpToBCD = AMLOpcode(0xff + 0x29)
|
||||||
|
OpUnload = AMLOpcode(0xff + 0x2a)
|
||||||
|
OpRevision = AMLOpcode(0xff + 0x30)
|
||||||
|
OpDebug = AMLOpcode(0xff + 0x31)
|
||||||
|
OpFatal = AMLOpcode(0xff + 0x32)
|
||||||
|
OpTimer = AMLOpcode(0xff + 0x33)
|
||||||
|
OpOpRegion = AMLOpcode(0xff + 0x80)
|
||||||
|
OpField = AMLOpcode(0xff + 0x81)
|
||||||
|
OpDevice = AMLOpcode(0xff + 0x82)
|
||||||
|
OpProcessor = AMLOpcode(0xff + 0x83)
|
||||||
|
OpPowerRes = AMLOpcode(0xff + 0x84)
|
||||||
|
OpThermalZone = AMLOpcode(0xff + 0x85)
|
||||||
|
OpIndexField = AMLOpcode(0xff + 0x86)
|
||||||
|
OpBankField = AMLOpcode(0xff + 0x87)
|
||||||
|
OpDataRegion = AMLOpcode(0xff + 0x88)
|
||||||
|
// Special internal opcodes which are not part of the spec; these are
|
||||||
|
// for internal use by the AML interpreter.
|
||||||
|
OpFieldUnit = AMLOpcode(0xff + 0xfd)
|
||||||
|
OpMethodInvocation = AMLOpcode(0xff + 0xfe)
|
||||||
|
)
|
||||||
|
|
||||||
|
// String implements fmt.Stringer for the AMLOpcode type.
|
||||||
|
func (op AMLOpcode) String() string {
|
||||||
|
switch op {
|
||||||
|
case OpZero:
|
||||||
|
return "Zero"
|
||||||
|
case OpOne:
|
||||||
|
return "One"
|
||||||
|
case OpAlias:
|
||||||
|
return "Alias"
|
||||||
|
case OpName:
|
||||||
|
return "Name"
|
||||||
|
case OpBytePrefix:
|
||||||
|
return "Byte"
|
||||||
|
case OpWordPrefix:
|
||||||
|
return "Word"
|
||||||
|
case OpDwordPrefix:
|
||||||
|
return "Dword"
|
||||||
|
case OpStringPrefix:
|
||||||
|
return "String"
|
||||||
|
case OpQwordPrefix:
|
||||||
|
return "Qword"
|
||||||
|
case OpScope:
|
||||||
|
return "Scope"
|
||||||
|
case OpBuffer:
|
||||||
|
return "Buffer"
|
||||||
|
case OpPackage:
|
||||||
|
return "Package"
|
||||||
|
case OpVarPackage:
|
||||||
|
return "VarPackage"
|
||||||
|
case OpMethod:
|
||||||
|
return "Method"
|
||||||
|
case OpExternal:
|
||||||
|
return "External"
|
||||||
|
case OpLocal0:
|
||||||
|
return "Local0"
|
||||||
|
case OpLocal1:
|
||||||
|
return "Local1"
|
||||||
|
case OpLocal2:
|
||||||
|
return "Local2"
|
||||||
|
case OpLocal3:
|
||||||
|
return "Local3"
|
||||||
|
case OpLocal4:
|
||||||
|
return "Local4"
|
||||||
|
case OpLocal5:
|
||||||
|
return "Local5"
|
||||||
|
case OpLocal6:
|
||||||
|
return "Local6"
|
||||||
|
case OpLocal7:
|
||||||
|
return "Local7"
|
||||||
|
case OpArg0:
|
||||||
|
return "Arg0"
|
||||||
|
case OpArg1:
|
||||||
|
return "Arg1"
|
||||||
|
case OpArg2:
|
||||||
|
return "Arg2"
|
||||||
|
case OpArg3:
|
||||||
|
return "Arg3"
|
||||||
|
case OpArg4:
|
||||||
|
return "Arg4"
|
||||||
|
case OpArg5:
|
||||||
|
return "Arg5"
|
||||||
|
case OpArg6:
|
||||||
|
return "Arg6"
|
||||||
|
case OpStore:
|
||||||
|
return "Store"
|
||||||
|
case OpRefOf:
|
||||||
|
return "RefOf"
|
||||||
|
case OpAdd:
|
||||||
|
return "Add"
|
||||||
|
case OpConcat:
|
||||||
|
return "Concat"
|
||||||
|
case OpSubtract:
|
||||||
|
return "Subtract"
|
||||||
|
case OpIncrement:
|
||||||
|
return "Increment"
|
||||||
|
case OpDecrement:
|
||||||
|
return "Decrement"
|
||||||
|
case OpMultiply:
|
||||||
|
return "Multiply"
|
||||||
|
case OpDivide:
|
||||||
|
return "Divide"
|
||||||
|
case OpShiftLeft:
|
||||||
|
return "ShiftLeft"
|
||||||
|
case OpShiftRight:
|
||||||
|
return "ShiftRight"
|
||||||
|
case OpAnd:
|
||||||
|
return "And"
|
||||||
|
case OpNand:
|
||||||
|
return "Nand"
|
||||||
|
case OpOr:
|
||||||
|
return "Or"
|
||||||
|
case OpNor:
|
||||||
|
return "Nor"
|
||||||
|
case OpXor:
|
||||||
|
return "Xor"
|
||||||
|
case OpNot:
|
||||||
|
return "Not"
|
||||||
|
case OpFindSetLeftBit:
|
||||||
|
return "FindSetLeftBit"
|
||||||
|
case OpFindSetRightBit:
|
||||||
|
return "FindSetRightBit"
|
||||||
|
case OpDerefOf:
|
||||||
|
return "DerefOf"
|
||||||
|
case OpConcatRes:
|
||||||
|
return "ConcatRes"
|
||||||
|
case OpMod:
|
||||||
|
return "Mod"
|
||||||
|
case OpNotify:
|
||||||
|
return "Notify"
|
||||||
|
case OpSizeOf:
|
||||||
|
return "SizeOf"
|
||||||
|
case OpIndex:
|
||||||
|
return "Index"
|
||||||
|
case OpMatch:
|
||||||
|
return "Match"
|
||||||
|
case OpCreateDWordField:
|
||||||
|
return "CreateDWordField"
|
||||||
|
case OpCreateWordField:
|
||||||
|
return "CreateWordField"
|
||||||
|
case OpCreateByteField:
|
||||||
|
return "CreateByteField"
|
||||||
|
case OpCreateBitField:
|
||||||
|
return "CreateBitField"
|
||||||
|
case OpObjectType:
|
||||||
|
return "ObjectType"
|
||||||
|
case OpCreateQWordField:
|
||||||
|
return "CreateQWordField"
|
||||||
|
case OpLand:
|
||||||
|
return "Land"
|
||||||
|
case OpLor:
|
||||||
|
return "Lor"
|
||||||
|
case OpLnot:
|
||||||
|
return "Lnot"
|
||||||
|
case OpLEqual:
|
||||||
|
return "LEqual"
|
||||||
|
case OpLGreater:
|
||||||
|
return "LGreater"
|
||||||
|
case OpLLess:
|
||||||
|
return "LLess"
|
||||||
|
case OpToBuffer:
|
||||||
|
return "ToBuffer"
|
||||||
|
case OpToDecimalString:
|
||||||
|
return "ToDecimalString"
|
||||||
|
case OpToHexString:
|
||||||
|
return "ToHexString"
|
||||||
|
case OpToInteger:
|
||||||
|
return "ToInteger"
|
||||||
|
case OpToString:
|
||||||
|
return "ToString"
|
||||||
|
case OpCopyObject:
|
||||||
|
return "CopyObject"
|
||||||
|
case OpMid:
|
||||||
|
return "Mid"
|
||||||
|
case OpContinue:
|
||||||
|
return "Continue"
|
||||||
|
case OpIf:
|
||||||
|
return "If"
|
||||||
|
case OpElse:
|
||||||
|
return "Else"
|
||||||
|
case OpWhile:
|
||||||
|
return "While"
|
||||||
|
case OpNoop:
|
||||||
|
return "Noop"
|
||||||
|
case OpReturn:
|
||||||
|
return "Return"
|
||||||
|
case OpBreak:
|
||||||
|
return "Break"
|
||||||
|
case OpBreakPoint:
|
||||||
|
return "BreakPoint"
|
||||||
|
case OpOnes:
|
||||||
|
return "Ones"
|
||||||
|
case OpMutex:
|
||||||
|
return "Mutex"
|
||||||
|
case OpEvent:
|
||||||
|
return "Event"
|
||||||
|
case OpCondRefOf:
|
||||||
|
return "CondRefOf"
|
||||||
|
case OpCreateField:
|
||||||
|
return "CreateField"
|
||||||
|
case OpLoadTable:
|
||||||
|
return "LoadTable"
|
||||||
|
case OpLoad:
|
||||||
|
return "Load"
|
||||||
|
case OpStall:
|
||||||
|
return "Stall"
|
||||||
|
case OpSleep:
|
||||||
|
return "Sleep"
|
||||||
|
case OpAcquire:
|
||||||
|
return "Acquire"
|
||||||
|
case OpSignal:
|
||||||
|
return "Signal"
|
||||||
|
case OpWait:
|
||||||
|
return "Wait"
|
||||||
|
case OpReset:
|
||||||
|
return "Reset"
|
||||||
|
case OpRelease:
|
||||||
|
return "Release"
|
||||||
|
case OpFromBCD:
|
||||||
|
return "FromBCD"
|
||||||
|
case OpToBCD:
|
||||||
|
return "ToBCD"
|
||||||
|
case OpUnload:
|
||||||
|
return "Unload"
|
||||||
|
case OpRevision:
|
||||||
|
return "Revision"
|
||||||
|
case OpDebug:
|
||||||
|
return "Debug"
|
||||||
|
case OpFatal:
|
||||||
|
return "Fatal"
|
||||||
|
case OpTimer:
|
||||||
|
return "Timer"
|
||||||
|
case OpOpRegion:
|
||||||
|
return "OpRegion"
|
||||||
|
case OpField:
|
||||||
|
return "Field"
|
||||||
|
case OpDevice:
|
||||||
|
return "Device"
|
||||||
|
case OpProcessor:
|
||||||
|
return "Processor"
|
||||||
|
case OpPowerRes:
|
||||||
|
return "PowerRes"
|
||||||
|
case OpThermalZone:
|
||||||
|
return "ThermalZone"
|
||||||
|
case OpIndexField:
|
||||||
|
return "IndexField"
|
||||||
|
case OpBankField:
|
||||||
|
return "BankField"
|
||||||
|
case OpDataRegion:
|
||||||
|
return "DataRegion"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpIsLocalArg returns true if this opcode represents any of the supported local
|
||||||
|
// function args 0 to 7.
|
||||||
|
func OpIsLocalArg(op AMLOpcode) bool {
|
||||||
|
return op >= OpLocal0 && op <= OpLocal7
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpIsMethodArg returns true if this opcode represents any of the supported
|
||||||
|
// input function args 0 to 6.
|
||||||
|
func OpIsMethodArg(op AMLOpcode) bool {
|
||||||
|
return op >= OpArg0 && op <= OpArg6
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpIsArg returns true if this opcode is either a local or a method arg.
|
||||||
|
func OpIsArg(op AMLOpcode) bool {
|
||||||
|
return OpIsLocalArg(op) || OpIsMethodArg(op)
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpIsDataObject returns true if this opcode is part of a DataObject definition
|
||||||
|
//
|
||||||
|
// Grammar:
|
||||||
|
// DataObject := ComputationalData | DefPackage | DefVarPackage
|
||||||
|
// ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String | ConstObj | RevisionOp | DefBuffer
|
||||||
|
// ConstObj := ZeroOp | OneOp | OnesOp
|
||||||
|
func OpIsDataObject(op AMLOpcode) bool {
|
||||||
|
switch op {
|
||||||
|
case OpBytePrefix, OpWordPrefix, OpDwordPrefix, OpQwordPrefix, OpStringPrefix,
|
||||||
|
OpZero, OpOne, OpOnes, OpRevision, OpBuffer, OpPackage, OpVarPackage:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// OpIsType2 returns true if this is a Type2Opcode.
|
||||||
|
//
|
||||||
|
// Grammar:
|
||||||
|
// Type2Opcode := DefAcquire | DefAdd | DefAnd | DefBuffer | DefConcat |
|
||||||
|
// DefConcatRes | DefCondRefOf | DefCopyObject | DefDecrement |
|
||||||
|
// DefDerefOf | DefDivide | DefFindSetLeftBit | DefFindSetRightBit |
|
||||||
|
// DefFromBCD | DefIncrement | DefIndex | DefLAnd | DefLEqual |
|
||||||
|
// DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual | DefMid |
|
||||||
|
// DefLNot | DefLNotEqual | DefLoadTable | DefLOr | DefMatch | DefMod |
|
||||||
|
// DefMultiply | DefNAnd | DefNOr | DefNot | DefObjectType | DefOr |
|
||||||
|
// DefPackage | DefVarPackage | DefRefOf | DefShiftLeft | DefShiftRight |
|
||||||
|
// DefSizeOf | DefStore | DefSubtract | DefTimer | DefToBCD | DefToBuffer |
|
||||||
|
// DefToDecimalString | DefToHexString | DefToInteger | DefToString |
|
||||||
|
// DefWait | DefXOr
|
||||||
|
func OpIsType2(op AMLOpcode) bool {
|
||||||
|
switch op {
|
||||||
|
case OpAcquire, OpAdd, OpAnd, OpBuffer, OpConcat,
|
||||||
|
OpConcatRes, OpCondRefOf, OpCopyObject, OpDecrement,
|
||||||
|
OpDerefOf, OpDivide, OpFindSetLeftBit, OpFindSetRightBit,
|
||||||
|
OpFromBCD, OpIncrement, OpIndex, OpLand, OpLEqual,
|
||||||
|
OpLGreater, OpLLess, OpMid,
|
||||||
|
OpLnot, OpLoadTable, OpLor, OpMatch, OpMod,
|
||||||
|
OpMultiply, OpNand, OpNor, OpNot, OpObjectType, OpOr,
|
||||||
|
OpPackage, OpVarPackage, OpRefOf, OpShiftLeft, OpShiftRight,
|
||||||
|
OpSizeOf, OpStore, OpSubtract, OpTimer, OpToBCD, OpToBuffer,
|
||||||
|
OpToDecimalString, OpToHexString, OpToInteger, OpToString,
|
||||||
|
OpWait, OpXor:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
237
src/gopheros/device/acpi/aml/entity/opcode_test.go
Normal file
237
src/gopheros/device/acpi/aml/entity/opcode_test.go
Normal file
@ -0,0 +1,237 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestOpcodeToString(t *testing.T) {
|
||||||
|
opcodeList := []AMLOpcode{
|
||||||
|
OpZero,
|
||||||
|
OpOne,
|
||||||
|
OpAlias,
|
||||||
|
OpName,
|
||||||
|
OpBytePrefix,
|
||||||
|
OpWordPrefix,
|
||||||
|
OpDwordPrefix,
|
||||||
|
OpStringPrefix,
|
||||||
|
OpQwordPrefix,
|
||||||
|
OpScope,
|
||||||
|
OpBuffer,
|
||||||
|
OpPackage,
|
||||||
|
OpVarPackage,
|
||||||
|
OpMethod,
|
||||||
|
OpExternal,
|
||||||
|
OpLocal0,
|
||||||
|
OpLocal1,
|
||||||
|
OpLocal2,
|
||||||
|
OpLocal3,
|
||||||
|
OpLocal4,
|
||||||
|
OpLocal5,
|
||||||
|
OpLocal6,
|
||||||
|
OpLocal7,
|
||||||
|
OpArg0,
|
||||||
|
OpArg1,
|
||||||
|
OpArg2,
|
||||||
|
OpArg3,
|
||||||
|
OpArg4,
|
||||||
|
OpArg5,
|
||||||
|
OpArg6,
|
||||||
|
OpStore,
|
||||||
|
OpRefOf,
|
||||||
|
OpAdd,
|
||||||
|
OpConcat,
|
||||||
|
OpSubtract,
|
||||||
|
OpIncrement,
|
||||||
|
OpDecrement,
|
||||||
|
OpMultiply,
|
||||||
|
OpDivide,
|
||||||
|
OpShiftLeft,
|
||||||
|
OpShiftRight,
|
||||||
|
OpAnd,
|
||||||
|
OpNand,
|
||||||
|
OpOr,
|
||||||
|
OpNor,
|
||||||
|
OpXor,
|
||||||
|
OpNot,
|
||||||
|
OpFindSetLeftBit,
|
||||||
|
OpFindSetRightBit,
|
||||||
|
OpDerefOf,
|
||||||
|
OpConcatRes,
|
||||||
|
OpMod,
|
||||||
|
OpNotify,
|
||||||
|
OpSizeOf,
|
||||||
|
OpIndex,
|
||||||
|
OpMatch,
|
||||||
|
OpCreateDWordField,
|
||||||
|
OpCreateWordField,
|
||||||
|
OpCreateByteField,
|
||||||
|
OpCreateBitField,
|
||||||
|
OpObjectType,
|
||||||
|
OpCreateQWordField,
|
||||||
|
OpLand,
|
||||||
|
OpLor,
|
||||||
|
OpLnot,
|
||||||
|
OpLEqual,
|
||||||
|
OpLGreater,
|
||||||
|
OpLLess,
|
||||||
|
OpToBuffer,
|
||||||
|
OpToDecimalString,
|
||||||
|
OpToHexString,
|
||||||
|
OpToInteger,
|
||||||
|
OpToString,
|
||||||
|
OpCopyObject,
|
||||||
|
OpMid,
|
||||||
|
OpContinue,
|
||||||
|
OpIf,
|
||||||
|
OpElse,
|
||||||
|
OpWhile,
|
||||||
|
OpNoop,
|
||||||
|
OpReturn,
|
||||||
|
OpBreak,
|
||||||
|
OpBreakPoint,
|
||||||
|
OpOnes,
|
||||||
|
OpMutex,
|
||||||
|
OpEvent,
|
||||||
|
OpCondRefOf,
|
||||||
|
OpCreateField,
|
||||||
|
OpLoadTable,
|
||||||
|
OpLoad,
|
||||||
|
OpStall,
|
||||||
|
OpSleep,
|
||||||
|
OpAcquire,
|
||||||
|
OpSignal,
|
||||||
|
OpWait,
|
||||||
|
OpReset,
|
||||||
|
OpRelease,
|
||||||
|
OpFromBCD,
|
||||||
|
OpToBCD,
|
||||||
|
OpUnload,
|
||||||
|
OpRevision,
|
||||||
|
OpDebug,
|
||||||
|
OpFatal,
|
||||||
|
OpTimer,
|
||||||
|
OpOpRegion,
|
||||||
|
OpField,
|
||||||
|
OpDevice,
|
||||||
|
OpProcessor,
|
||||||
|
OpPowerRes,
|
||||||
|
OpThermalZone,
|
||||||
|
OpIndexField,
|
||||||
|
OpBankField,
|
||||||
|
OpDataRegion,
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, op := range opcodeList {
|
||||||
|
if op.String() == "unknown" {
|
||||||
|
t.Errorf("[spec %d] op 0x%x String() returned \"unknown\"", specIndex, op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also test invalid opcode
|
||||||
|
if got := AMLOpcode(0xffff).String(); got != "unknown" {
|
||||||
|
t.Fatalf("expected String() for invalid opcode to return \"unknown\"; got: %q", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpcodeIsX(t *testing.T) {
|
||||||
|
specs := []struct {
|
||||||
|
op AMLOpcode
|
||||||
|
testFn func(AMLOpcode) bool
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
// OpIsLocalArg
|
||||||
|
{OpLocal0, OpIsLocalArg, true},
|
||||||
|
{OpLocal1, OpIsLocalArg, true},
|
||||||
|
{OpLocal2, OpIsLocalArg, true},
|
||||||
|
{OpLocal3, OpIsLocalArg, true},
|
||||||
|
{OpLocal4, OpIsLocalArg, true},
|
||||||
|
{OpLocal5, OpIsLocalArg, true},
|
||||||
|
{OpLocal6, OpIsLocalArg, true},
|
||||||
|
{OpLocal7, OpIsLocalArg, true},
|
||||||
|
{OpArg0, OpIsLocalArg, false},
|
||||||
|
{OpDivide, OpIsLocalArg, false},
|
||||||
|
// OpIsMethodArg
|
||||||
|
{OpArg0, OpIsMethodArg, true},
|
||||||
|
{OpArg1, OpIsMethodArg, true},
|
||||||
|
{OpArg2, OpIsMethodArg, true},
|
||||||
|
{OpArg3, OpIsMethodArg, true},
|
||||||
|
{OpArg4, OpIsMethodArg, true},
|
||||||
|
{OpArg5, OpIsMethodArg, true},
|
||||||
|
{OpArg6, OpIsMethodArg, true},
|
||||||
|
{OpLocal7, OpIsMethodArg, false},
|
||||||
|
{OpIf, OpIsMethodArg, false},
|
||||||
|
// OpIsArg
|
||||||
|
{OpLocal5, OpIsArg, true},
|
||||||
|
{OpArg1, OpIsArg, true},
|
||||||
|
{OpDivide, OpIsArg, false},
|
||||||
|
// OpIsType2
|
||||||
|
{OpAcquire, OpIsType2, true},
|
||||||
|
{OpAdd, OpIsType2, true},
|
||||||
|
{OpAnd, OpIsType2, true},
|
||||||
|
{OpBuffer, OpIsType2, true},
|
||||||
|
{OpConcat, OpIsType2, true},
|
||||||
|
{OpConcatRes, OpIsType2, true},
|
||||||
|
{OpCondRefOf, OpIsType2, true},
|
||||||
|
{OpCopyObject, OpIsType2, true},
|
||||||
|
{OpDecrement, OpIsType2, true},
|
||||||
|
{OpDerefOf, OpIsType2, true},
|
||||||
|
{OpDivide, OpIsType2, true},
|
||||||
|
{OpFindSetLeftBit, OpIsType2, true},
|
||||||
|
{OpFindSetRightBit, OpIsType2, true},
|
||||||
|
{OpFromBCD, OpIsType2, true},
|
||||||
|
{OpIncrement, OpIsType2, true},
|
||||||
|
{OpIndex, OpIsType2, true},
|
||||||
|
{OpLand, OpIsType2, true},
|
||||||
|
{OpLEqual, OpIsType2, true},
|
||||||
|
{OpLGreater, OpIsType2, true},
|
||||||
|
{OpLLess, OpIsType2, true},
|
||||||
|
{OpMid, OpIsType2, true},
|
||||||
|
{OpLnot, OpIsType2, true},
|
||||||
|
{OpLoadTable, OpIsType2, true},
|
||||||
|
{OpLor, OpIsType2, true},
|
||||||
|
{OpMatch, OpIsType2, true},
|
||||||
|
{OpMod, OpIsType2, true},
|
||||||
|
{OpMultiply, OpIsType2, true},
|
||||||
|
{OpNand, OpIsType2, true},
|
||||||
|
{OpNor, OpIsType2, true},
|
||||||
|
{OpNot, OpIsType2, true},
|
||||||
|
{OpObjectType, OpIsType2, true},
|
||||||
|
{OpOr, OpIsType2, true},
|
||||||
|
{OpPackage, OpIsType2, true},
|
||||||
|
{OpVarPackage, OpIsType2, true},
|
||||||
|
{OpRefOf, OpIsType2, true},
|
||||||
|
{OpShiftLeft, OpIsType2, true},
|
||||||
|
{OpShiftRight, OpIsType2, true},
|
||||||
|
{OpSizeOf, OpIsType2, true},
|
||||||
|
{OpStore, OpIsType2, true},
|
||||||
|
{OpSubtract, OpIsType2, true},
|
||||||
|
{OpTimer, OpIsType2, true},
|
||||||
|
{OpToBCD, OpIsType2, true},
|
||||||
|
{OpToBuffer, OpIsType2, true},
|
||||||
|
{OpToDecimalString, OpIsType2, true},
|
||||||
|
{OpToHexString, OpIsType2, true},
|
||||||
|
{OpToInteger, OpIsType2, true},
|
||||||
|
{OpToString, OpIsType2, true},
|
||||||
|
{OpWait, OpIsType2, true},
|
||||||
|
{OpXor, OpIsType2, true},
|
||||||
|
{OpBytePrefix, OpIsType2, false},
|
||||||
|
// OpIsDataObject
|
||||||
|
{OpBytePrefix, OpIsDataObject, true},
|
||||||
|
{OpWordPrefix, OpIsDataObject, true},
|
||||||
|
{OpDwordPrefix, OpIsDataObject, true},
|
||||||
|
{OpQwordPrefix, OpIsDataObject, true},
|
||||||
|
{OpStringPrefix, OpIsDataObject, true},
|
||||||
|
{OpZero, OpIsDataObject, true},
|
||||||
|
{OpOne, OpIsDataObject, true},
|
||||||
|
{OpOnes, OpIsDataObject, true},
|
||||||
|
{OpRevision, OpIsDataObject, true},
|
||||||
|
{OpBuffer, OpIsDataObject, true},
|
||||||
|
{OpPackage, OpIsDataObject, true},
|
||||||
|
{OpVarPackage, OpIsDataObject, true},
|
||||||
|
{OpLor, OpIsDataObject, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
if got := spec.testFn(spec.op); got != spec.want {
|
||||||
|
t.Errorf("[spec %d] opcode %q: expected to get %t; got %t", specIndex, spec.op, spec.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,68 +1,14 @@
|
|||||||
package aml
|
package entity
|
||||||
|
|
||||||
import "strings"
|
import "strings"
|
||||||
|
|
||||||
// Visitor is a function invoked by the VM for each AML tree entity that matches
|
// ResolveScopedPath examines a path expression and attempts to break it down
|
||||||
// a particular type. The return value controls whether the children of this
|
|
||||||
// entity should also be visited.
|
|
||||||
type Visitor func(depth int, obj Entity) (keepRecursing bool)
|
|
||||||
|
|
||||||
// EntityType defines the type of entity that visitors should inspect.
|
|
||||||
type EntityType uint8
|
|
||||||
|
|
||||||
// The list of supported EntityType values. EntityTypeAny works as a wildcard
|
|
||||||
// allowing the visitor to inspect all entities in the AML tree.
|
|
||||||
const (
|
|
||||||
EntityTypeAny EntityType = iota
|
|
||||||
EntityTypeDevice
|
|
||||||
EntityTypeProcessor
|
|
||||||
EntityTypePowerResource
|
|
||||||
EntityTypeThermalZone
|
|
||||||
EntityTypeMethod
|
|
||||||
)
|
|
||||||
|
|
||||||
// scopeVisit descends a scope hierarchy and invokes visitorFn for each entity
|
|
||||||
// that matches entType.
|
|
||||||
func scopeVisit(depth int, ent Entity, entType EntityType, visitorFn Visitor) bool {
|
|
||||||
op := ent.getOpcode()
|
|
||||||
switch {
|
|
||||||
case (entType == EntityTypeAny) ||
|
|
||||||
(entType == EntityTypeDevice && op == opDevice) ||
|
|
||||||
(entType == EntityTypeProcessor && op == opProcessor) ||
|
|
||||||
(entType == EntityTypePowerResource && op == opPowerRes) ||
|
|
||||||
(entType == EntityTypeThermalZone && op == opThermalZone) ||
|
|
||||||
(entType == EntityTypeMethod && op == opMethod):
|
|
||||||
// If the visitor returned false we should not visit the children
|
|
||||||
if !visitorFn(depth, ent) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Visit any args that are also entities
|
|
||||||
for _, arg := range ent.getArgs() {
|
|
||||||
if argEnt, isEnt := arg.(Entity); isEnt && !scopeVisit(depth+1, argEnt, entType, visitorFn) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch typ := ent.(type) {
|
|
||||||
case ScopeEntity:
|
|
||||||
// If the entity defines a scope we need to visit the child entities.
|
|
||||||
for _, child := range typ.Children() {
|
|
||||||
_ = scopeVisit(depth+1, child, entType, visitorFn)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// scopeResolvePath examines a path expression and attempts to break it down
|
|
||||||
// into a parent and child segment. The parent segment is looked up via the
|
// into a parent and child segment. The parent segment is looked up via the
|
||||||
// regular scope rules specified in page 252 of the ACPI 6.2 spec. If the
|
// regular scope rules specified in page 252 of the ACPI 6.2 spec. If the
|
||||||
// parent scope is found then the function returns back the parent entity and
|
// parent scope is found then the function returns back the parent entity and
|
||||||
// the name of the child that should be appended to it. If the expression
|
// the name of the child that should be appended to it. If the expression
|
||||||
// lookup fails then the function returns nil, "".
|
// lookup fails then the function returns nil, "".
|
||||||
func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent ScopeEntity, name string) {
|
func ResolveScopedPath(curScope, rootScope Container, expr string) (parent Container, name string) {
|
||||||
if len(expr) <= 1 {
|
if len(expr) <= 1 {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
@ -75,8 +21,8 @@ func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent Scop
|
|||||||
return rootScope, expr[1:]
|
return rootScope, expr[1:]
|
||||||
case '^':
|
case '^':
|
||||||
lastHatIndex := strings.LastIndexByte(expr, '^')
|
lastHatIndex := strings.LastIndexByte(expr, '^')
|
||||||
if target := scopeFind(curScope, rootScope, expr[:lastHatIndex+1]); target != nil {
|
if target := FindInScope(curScope, rootScope, expr[:lastHatIndex+1]); target != nil {
|
||||||
return target.(ScopeEntity), expr[lastHatIndex+1:]
|
return target.(Container), expr[lastHatIndex+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ""
|
return nil, ""
|
||||||
@ -86,14 +32,14 @@ func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent Scop
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Pattern looks like: \FOO.BAR.BAZ or ^+FOO.BAR.BAZ or FOO.BAR.BAZ
|
// Pattern looks like: \FOO.BAR.BAZ or ^+FOO.BAR.BAZ or FOO.BAR.BAZ
|
||||||
if target := scopeFind(curScope, rootScope, expr[:lastDotIndex]); target != nil {
|
if target := FindInScope(curScope, rootScope, expr[:lastDotIndex]); target != nil {
|
||||||
return target.(ScopeEntity), expr[lastDotIndex+1:]
|
return target.(Container), expr[lastDotIndex+1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// scopeFind attempts to find an object with the given name using the rules
|
// FindInScope attempts to find an object with the given name using the rules
|
||||||
// specified in page 252 of the ACPI 6.2 spec:
|
// specified in page 252 of the ACPI 6.2 spec:
|
||||||
//
|
//
|
||||||
// There are two types of namespace paths: an absolute namespace path (that is,
|
// There are two types of namespace paths: an absolute namespace path (that is,
|
||||||
@ -104,7 +50,7 @@ func scopeResolvePath(curScope, rootScope ScopeEntity, expr string) (parent Scop
|
|||||||
// or Parent Prefixes, ‘^’, the search rules do not apply. If the search rules
|
// or Parent Prefixes, ‘^’, the search rules do not apply. If the search rules
|
||||||
// do not apply to a relative namespace path, the namespace object is looked up
|
// do not apply to a relative namespace path, the namespace object is looked up
|
||||||
// relative to the current namespace
|
// relative to the current namespace
|
||||||
func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
func FindInScope(curScope, rootScope Container, name string) Entity {
|
||||||
nameLen := len(name)
|
nameLen := len(name)
|
||||||
if nameLen == 0 {
|
if nameLen == 0 {
|
||||||
return nil
|
return nil
|
||||||
@ -113,7 +59,7 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
switch {
|
switch {
|
||||||
case name[0] == '\\': // relative to the root scope
|
case name[0] == '\\': // relative to the root scope
|
||||||
if nameLen > 1 {
|
if nameLen > 1 {
|
||||||
return scopeFindRelative(rootScope, name[1:])
|
return findRelativeToScope(rootScope, name[1:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Name was just `\`; this matches the root namespace
|
// Name was just `\`; this matches the root namespace
|
||||||
@ -130,7 +76,7 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
// Found the start of the name. Look it up relative to curNs
|
// Found the start of the name. Look it up relative to curNs
|
||||||
return scopeFindRelative(curScope, name[startIndex:])
|
return findRelativeToScope(curScope, name[startIndex:])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +85,7 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
case strings.ContainsRune(name, '.'):
|
case strings.ContainsRune(name, '.'):
|
||||||
// If the name contains any '.' then we still need to look it
|
// If the name contains any '.' then we still need to look it
|
||||||
// up relative to the current scope
|
// up relative to the current scope
|
||||||
return scopeFindRelative(curScope, name)
|
return findRelativeToScope(curScope, name)
|
||||||
default:
|
default:
|
||||||
// We can apply the search rules described by the spec
|
// We can apply the search rules described by the spec
|
||||||
for s := curScope; s != nil; s = s.Parent() {
|
for s := curScope; s != nil; s = s.Parent() {
|
||||||
@ -155,11 +101,11 @@ func scopeFind(curScope, rootScope ScopeEntity, name string) Entity {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// scopeFindRelative returns the Entity referenced by path relative
|
// findRelativeToScope returns the Entity referenced by path relative
|
||||||
// to the provided Namespace. If the name contains dots, each segment
|
// to the provided Namespace. If the name contains dots, each segment
|
||||||
// is used to access a nested namespace. If the path does not point
|
// is used to access a nested namespace. If the path does not point
|
||||||
// to a NamedObject then lookupRelativeTo returns back nil.
|
// to a NamedObject then lookupRelativeTo returns back nil.
|
||||||
func scopeFindRelative(ns ScopeEntity, path string) Entity {
|
func findRelativeToScope(ns Container, path string) Entity {
|
||||||
var matchName string
|
var matchName string
|
||||||
matchNextPathSegment:
|
matchNextPathSegment:
|
||||||
for {
|
for {
|
||||||
@ -170,12 +116,7 @@ matchNextPathSegment:
|
|||||||
|
|
||||||
// Search for a scoped child named "matchName"
|
// Search for a scoped child named "matchName"
|
||||||
for _, child := range ns.Children() {
|
for _, child := range ns.Children() {
|
||||||
childNs, ok := child.(ScopeEntity)
|
if childNs, ok := child.(Container); ok && childNs.Name() == matchName {
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if childNs.Name() == matchName {
|
|
||||||
ns = childNs
|
ns = childNs
|
||||||
continue matchNextPathSegment
|
continue matchNextPathSegment
|
||||||
}
|
}
|
215
src/gopheros/device/acpi/aml/entity/scope_test.go
Normal file
215
src/gopheros/device/acpi/aml/entity/scope_test.go
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolveScopedPath(t *testing.T) {
|
||||||
|
scopeMap := genTestScopes()
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
curScope Container
|
||||||
|
pathExpr string
|
||||||
|
wantParent Entity
|
||||||
|
wantName string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_`,
|
||||||
|
scopeMap[`\`],
|
||||||
|
"_SB_",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^FOO`,
|
||||||
|
scopeMap[`PCI0`],
|
||||||
|
"FOO",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^^FOO`,
|
||||||
|
scopeMap[`_SB_`],
|
||||||
|
"FOO",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`_ADR`,
|
||||||
|
scopeMap[`IDE0`],
|
||||||
|
"_ADR",
|
||||||
|
},
|
||||||
|
// Paths with dots
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_.PCI0.IDE0._ADR`,
|
||||||
|
scopeMap[`IDE0`],
|
||||||
|
"_ADR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`IDE0._ADR`,
|
||||||
|
scopeMap[`IDE0`],
|
||||||
|
"_ADR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`_CRS`,
|
||||||
|
scopeMap[`PCI0`],
|
||||||
|
"_CRS",
|
||||||
|
},
|
||||||
|
// Bad queries
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`FOO.BAR.BAZ`,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
``,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`\`,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`^^^^^^^^^BADPATH`,
|
||||||
|
nil,
|
||||||
|
"",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
root := scopeMap[`\`].(Container)
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
gotParent, gotName := ResolveScopedPath(spec.curScope, root, spec.pathExpr)
|
||||||
|
if !reflect.DeepEqual(gotParent, spec.wantParent) {
|
||||||
|
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.wantParent, gotParent)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if gotName != spec.wantName {
|
||||||
|
t.Errorf("[spec %d] expected lookup to return node name %q; got %q", specIndex, spec.wantName, gotName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFindInScope(t *testing.T) {
|
||||||
|
scopeMap := genTestScopes()
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
curScope Container
|
||||||
|
lookup string
|
||||||
|
want Entity
|
||||||
|
}{
|
||||||
|
// Search rules do not apply for these cases
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
`\`,
|
||||||
|
scopeMap[`\`],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["PCI0"].(Container),
|
||||||
|
"IDE0._ADR",
|
||||||
|
scopeMap["_ADR"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"^^PCI0.IDE0._ADR",
|
||||||
|
scopeMap["_ADR"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_.PCI0.IDE0._ADR`,
|
||||||
|
scopeMap["_ADR"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`\_SB_.PCI0`,
|
||||||
|
scopeMap["PCI0"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^`,
|
||||||
|
scopeMap["PCI0"],
|
||||||
|
},
|
||||||
|
// Bad queries
|
||||||
|
{
|
||||||
|
scopeMap["_SB_"].(Container),
|
||||||
|
"PCI0.USB._CRS",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"^^^^^^^^^^^^^^^^^^^",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
`^^^^^^^^^^^FOO`,
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"FOO",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
// Search rules apply for these cases
|
||||||
|
{
|
||||||
|
scopeMap["IDE0"].(Container),
|
||||||
|
"_CRS",
|
||||||
|
scopeMap["_CRS"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
root := scopeMap[`\`].(Container)
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
if got := FindInScope(spec.curScope, root, spec.lookup); !reflect.DeepEqual(got, spec.want) {
|
||||||
|
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func genTestScopes() map[string]Entity {
|
||||||
|
// Setup the example tree from page 252 of the acpi 6.2 spec
|
||||||
|
// \
|
||||||
|
// SB
|
||||||
|
// \
|
||||||
|
// PCI0
|
||||||
|
// | _CRS
|
||||||
|
// \
|
||||||
|
// IDE0
|
||||||
|
// | _ADR
|
||||||
|
ideScope := NewScope(OpScope, 42, `IDE0`)
|
||||||
|
pciScope := NewScope(OpScope, 42, `PCI0`)
|
||||||
|
sbScope := NewScope(OpScope, 42, `_SB_`)
|
||||||
|
rootScope := NewScope(OpScope, 42, `\`)
|
||||||
|
|
||||||
|
adr := NewMethod(42, `_ADR`)
|
||||||
|
crs := NewMethod(42, `_CRS`)
|
||||||
|
|
||||||
|
// Setup tree
|
||||||
|
ideScope.Append(adr)
|
||||||
|
pciScope.Append(crs)
|
||||||
|
pciScope.Append(ideScope)
|
||||||
|
sbScope.Append(pciScope)
|
||||||
|
rootScope.Append(sbScope)
|
||||||
|
|
||||||
|
return map[string]Entity{
|
||||||
|
"IDE0": ideScope,
|
||||||
|
"PCI0": pciScope,
|
||||||
|
"_SB_": sbScope,
|
||||||
|
"\\": rootScope,
|
||||||
|
"_ADR": adr,
|
||||||
|
"_CRS": crs,
|
||||||
|
}
|
||||||
|
}
|
64
src/gopheros/device/acpi/aml/entity/visitor.go
Normal file
64
src/gopheros/device/acpi/aml/entity/visitor.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
// Visitor is a function invoked by the VM for each AML tree entity that matches
|
||||||
|
// a particular type. The return value controls whether the children of this
|
||||||
|
// entity should also be visited.
|
||||||
|
type Visitor func(depth int, obj Entity) (keepRecursing bool)
|
||||||
|
|
||||||
|
// Type defines the type of entity that visitors should inspect.
|
||||||
|
type Type uint8
|
||||||
|
|
||||||
|
// The list of supported Type values. TypeAny works as a wildcard
|
||||||
|
// allowing the visitor to inspect all entities in the AML tree.
|
||||||
|
const (
|
||||||
|
TypeAny Type = iota
|
||||||
|
TypeDevice
|
||||||
|
TypeProcessor
|
||||||
|
TypePowerResource
|
||||||
|
TypeThermalZone
|
||||||
|
TypeMethod
|
||||||
|
TypeMutex
|
||||||
|
TypeEvent
|
||||||
|
TypeField
|
||||||
|
TypeIndexField
|
||||||
|
TypeBankField
|
||||||
|
)
|
||||||
|
|
||||||
|
// Visit descends a scope hierarchy and invokes visitorFn for each entity
|
||||||
|
// that matches entType.
|
||||||
|
func Visit(depth int, ent Entity, entType Type, visitorFn Visitor) bool {
|
||||||
|
op := ent.Opcode()
|
||||||
|
switch {
|
||||||
|
case (entType == TypeAny) ||
|
||||||
|
(entType == TypeDevice && op == OpDevice) ||
|
||||||
|
(entType == TypeProcessor && op == OpProcessor) ||
|
||||||
|
(entType == TypePowerResource && op == OpPowerRes) ||
|
||||||
|
(entType == TypeThermalZone && op == OpThermalZone) ||
|
||||||
|
(entType == TypeMethod && op == OpMethod) ||
|
||||||
|
(entType == TypeMutex && op == OpMutex) ||
|
||||||
|
(entType == TypeEvent && op == OpEvent) ||
|
||||||
|
(entType == TypeField && op == OpField) ||
|
||||||
|
(entType == TypeIndexField && op == OpIndexField) ||
|
||||||
|
(entType == TypeBankField && op == OpBankField):
|
||||||
|
// If the visitor returned false we should not visit the children
|
||||||
|
if !visitorFn(depth, ent) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Visit any args that are also entities
|
||||||
|
for _, arg := range ent.Args() {
|
||||||
|
if argEnt, isEnt := arg.(Entity); isEnt && !Visit(depth+1, argEnt, entType, visitorFn) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the entity defines a scope we need to visit the child entities.
|
||||||
|
if container, isContainer := ent.(Container); isContainer {
|
||||||
|
for _, child := range container.Children() {
|
||||||
|
_ = Visit(depth+1, child, entType, visitorFn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
93
src/gopheros/device/acpi/aml/entity/visitor_test.go
Normal file
93
src/gopheros/device/acpi/aml/entity/visitor_test.go
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package entity
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestScopeVisit(t *testing.T) {
|
||||||
|
tableHandle := uint8(42)
|
||||||
|
keepRecursing := func(Entity) bool { return true }
|
||||||
|
stopRecursing := func(Entity) bool { return false }
|
||||||
|
|
||||||
|
// Append special entities under IDE0
|
||||||
|
root := NewScope(OpScope, tableHandle, "IDE0")
|
||||||
|
root.Append(NewDevice(tableHandle, "DEV0"))
|
||||||
|
root.Append(NewProcessor(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewProcessor(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewPowerResource(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewPowerResource(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewPowerResource(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewThermalZone(tableHandle, "FOO0"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH0"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH1"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH2"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH3"))
|
||||||
|
root.Append(NewMethod(tableHandle, "MTH4"))
|
||||||
|
root.Append(NewMutex(tableHandle))
|
||||||
|
root.Append(NewMutex(tableHandle))
|
||||||
|
root.Append(NewEvent(tableHandle))
|
||||||
|
root.Append(NewEvent(tableHandle))
|
||||||
|
root.Append(NewEvent(tableHandle))
|
||||||
|
root.Append(NewField(tableHandle))
|
||||||
|
root.Append(NewIndexField(tableHandle))
|
||||||
|
root.Append(NewBankField(tableHandle))
|
||||||
|
root.Append(&Invocation{
|
||||||
|
Generic: Generic{
|
||||||
|
op: OpMethodInvocation,
|
||||||
|
args: []interface{}{
|
||||||
|
NewConst(OpOne, tableHandle, uint64(1)),
|
||||||
|
NewConst(OpDwordPrefix, tableHandle, uint64(2)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
searchType Type
|
||||||
|
keepRecursingFn func(Entity) bool
|
||||||
|
wantHits int
|
||||||
|
}{
|
||||||
|
{TypeAny, keepRecursing, 27},
|
||||||
|
{TypeAny, stopRecursing, 1},
|
||||||
|
{
|
||||||
|
TypeAny,
|
||||||
|
func(ent Entity) bool {
|
||||||
|
// Stop recursing after visiting the Invocation entity
|
||||||
|
_, isInv := ent.(*Invocation)
|
||||||
|
return !isInv
|
||||||
|
},
|
||||||
|
25,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
TypeAny,
|
||||||
|
func(ent Entity) bool {
|
||||||
|
// Stop recursing after visiting the first Const entity
|
||||||
|
_, isConst := ent.(*Const)
|
||||||
|
return !isConst
|
||||||
|
},
|
||||||
|
26,
|
||||||
|
},
|
||||||
|
{TypeDevice, keepRecursing, 1},
|
||||||
|
{TypeProcessor, keepRecursing, 2},
|
||||||
|
{TypePowerResource, keepRecursing, 3},
|
||||||
|
{TypeThermalZone, keepRecursing, 4},
|
||||||
|
{TypeMethod, keepRecursing, 5},
|
||||||
|
{TypeMutex, keepRecursing, 2},
|
||||||
|
{TypeEvent, keepRecursing, 3},
|
||||||
|
{TypeField, keepRecursing, 1},
|
||||||
|
{TypeIndexField, keepRecursing, 1},
|
||||||
|
{TypeBankField, keepRecursing, 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
var hits int
|
||||||
|
Visit(0, root, spec.searchType, func(_ int, obj Entity) bool {
|
||||||
|
hits++
|
||||||
|
return spec.keepRecursingFn(obj)
|
||||||
|
})
|
||||||
|
|
||||||
|
if hits != spec.wantHits {
|
||||||
|
t.Errorf("[spec %d] expected visitor to be called %d times; got %d", specIndex, spec.wantHits, hits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,173 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"io/ioutil"
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestEntityMethods(t *testing.T) {
|
|
||||||
specs := []Entity{
|
|
||||||
&unnamedEntity{},
|
|
||||||
&constEntity{},
|
|
||||||
&scopeEntity{},
|
|
||||||
&bufferEntity{},
|
|
||||||
&fieldUnitEntity{},
|
|
||||||
&indexFieldEntity{},
|
|
||||||
&namedReference{},
|
|
||||||
&methodInvocationEntity{},
|
|
||||||
&Method{},
|
|
||||||
&Device{},
|
|
||||||
&mutexEntity{},
|
|
||||||
&eventEntity{},
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("table handle methods", func(t *testing.T) {
|
|
||||||
exp := uint8(42)
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
spec.setTableHandle(exp)
|
|
||||||
if got := spec.TableHandle(); got != exp {
|
|
||||||
t.Errorf("[spec %d] expected to get back handle %d; got %d", specIndex, exp, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("append/remove/get parent methods", func(t *testing.T) {
|
|
||||||
parent := &scopeEntity{name: `\`}
|
|
||||||
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
parent.Append(spec)
|
|
||||||
if got := spec.Parent(); got != parent {
|
|
||||||
t.Errorf("[spec %d] expected to get back parent %v; got %v", specIndex, parent, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
parent.removeChild(spec)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := len(parent.Children()); got != 0 {
|
|
||||||
t.Fatalf("expected parent not to have any child nodes; got %d", got)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEntityArgAssignment(t *testing.T) {
|
|
||||||
specs := []struct {
|
|
||||||
ent Entity
|
|
||||||
argList []interface{}
|
|
||||||
expArgList []interface{}
|
|
||||||
limitedArgs bool
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
&unnamedEntity{},
|
|
||||||
[]interface{}{"foo", 1, "bar"},
|
|
||||||
[]interface{}{"foo", 1, "bar"},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
&constEntity{},
|
|
||||||
[]interface{}{"foo"},
|
|
||||||
nil, // constEntity populates its internal state using the 1st arg
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
&scopeEntity{},
|
|
||||||
[]interface{}{"foo", 1, 2, 3},
|
|
||||||
[]interface{}{1, 2, 3}, // scopeEntity will treat arg0 as the scope name if it is a string
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
&bufferEntity{},
|
|
||||||
[]interface{}{1, []byte{}},
|
|
||||||
nil, // bufferEntity populates its internal state using the first 2 args
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
®ionEntity{},
|
|
||||||
[]interface{}{"REG0", uint64(0x4), 0, 10},
|
|
||||||
[]interface{}{0, 10}, // region populates its internal state using the first 2 args
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
&mutexEntity{},
|
|
||||||
[]interface{}{"MUT0", uint64(1)},
|
|
||||||
nil, // mutexEntity populates its internal state using the first 2 args
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
nextSpec:
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
for i, arg := range spec.argList {
|
|
||||||
if !spec.ent.setArg(uint8(i), arg) {
|
|
||||||
t.Errorf("[spec %d] error setting arg %d", specIndex, i)
|
|
||||||
continue nextSpec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if spec.limitedArgs {
|
|
||||||
if spec.ent.setArg(uint8(len(spec.argList)), nil) {
|
|
||||||
t.Errorf("[spec %d] expected additional calls to setArg to return false", specIndex)
|
|
||||||
continue nextSpec
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := spec.ent.getArgs(); !reflect.DeepEqual(got, spec.expArgList) {
|
|
||||||
t.Errorf("[spec %d] expected to get back arg list %v; got %v", specIndex, spec.expArgList, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestEntityResolveErrors(t *testing.T) {
|
|
||||||
scope := &scopeEntity{name: `\`}
|
|
||||||
|
|
||||||
specs := []resolver{
|
|
||||||
// Unknown connection entity
|
|
||||||
&fieldUnitEntity{connectionName: "CON0"},
|
|
||||||
// Unknown region
|
|
||||||
&fieldUnitEntity{connectionName: `\`, regionName: "REG0"},
|
|
||||||
// Unknown connection entity
|
|
||||||
&indexFieldEntity{connectionName: "CON0"},
|
|
||||||
// Unknown index register
|
|
||||||
&indexFieldEntity{connectionName: `\`, indexRegName: "IND0"},
|
|
||||||
// Unknown data register
|
|
||||||
&indexFieldEntity{connectionName: `\`, indexRegName: `\`, dataRegName: "DAT0"},
|
|
||||||
// Unknown reference
|
|
||||||
&namedReference{unnamedEntity: unnamedEntity{parent: scope}, targetName: "TRG0"},
|
|
||||||
// Unknown method name
|
|
||||||
&methodInvocationEntity{unnamedEntity: unnamedEntity{parent: scope}, methodName: "MTH0"},
|
|
||||||
}
|
|
||||||
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
if spec.Resolve(ioutil.Discard, scope) {
|
|
||||||
t.Errorf("[spec %d] expected Resolve() to fail", specIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMethodInvocationResolver(t *testing.T) {
|
|
||||||
scope := &scopeEntity{name: `\`}
|
|
||||||
scope.Append(&Method{
|
|
||||||
scopeEntity: scopeEntity{
|
|
||||||
name: "MTH0",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
validInv := &methodInvocationEntity{
|
|
||||||
methodName: "MTH0",
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidInv := &methodInvocationEntity{
|
|
||||||
methodName: "FOO0",
|
|
||||||
}
|
|
||||||
|
|
||||||
scope.Append(validInv)
|
|
||||||
scope.Append(invalidInv)
|
|
||||||
|
|
||||||
if !validInv.Resolve(ioutil.Discard, scope) {
|
|
||||||
t.Fatal("expected method invocation to resolve method", validInv.methodName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if invalidInv.Resolve(ioutil.Discard, scope) {
|
|
||||||
t.Fatal("expected method invocation NOT to resolve method", invalidInv.methodName)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,269 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
// opcode describes an AML opcode. While AML supports 256 opcodes, some of them
|
|
||||||
// are specified using a combination of an extension prefix and a code. To map
|
|
||||||
// each opcode into a single unique value the parser uses an uint16
|
|
||||||
// representation of the opcode values.
|
|
||||||
type opcode uint16
|
|
||||||
|
|
||||||
// String implements fmt.Stringer for opcode.
|
|
||||||
func (op opcode) String() string {
|
|
||||||
for _, entry := range opcodeTable {
|
|
||||||
if entry.op == op {
|
|
||||||
return entry.name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
|
|
||||||
// opIsLocalArg returns true if this opcode represents any of the supported local
|
|
||||||
// function args 0 to 7.
|
|
||||||
func opIsLocalArg(op opcode) bool {
|
|
||||||
return op >= opLocal0 && op <= opLocal7
|
|
||||||
}
|
|
||||||
|
|
||||||
// opIsMethodArg returns true if this opcode represents any of the supported
|
|
||||||
// input function args 0 to 6.
|
|
||||||
func opIsMethodArg(op opcode) bool {
|
|
||||||
return op >= opArg0 && op <= opArg6
|
|
||||||
}
|
|
||||||
|
|
||||||
// opIsArg returns true if this opcode is either a local or a method arg.
|
|
||||||
func opIsArg(op opcode) bool {
|
|
||||||
return opIsLocalArg(op) || opIsMethodArg(op)
|
|
||||||
}
|
|
||||||
|
|
||||||
// opIsDataObject returns true if this opcode is part of a DataObject definition
|
|
||||||
//
|
|
||||||
// Grammar:
|
|
||||||
// DataObject := ComputationalData | DefPackage | DefVarPackage
|
|
||||||
// ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String | ConstObj | RevisionOp | DefBuffer
|
|
||||||
// ConstObj := ZeroOp | OneOp | OnesOp
|
|
||||||
func opIsDataObject(op opcode) bool {
|
|
||||||
switch op {
|
|
||||||
case opBytePrefix, opWordPrefix, opDwordPrefix, opQwordPrefix, opStringPrefix,
|
|
||||||
opZero, opOne, opOnes, opRevision, opBuffer, opPackage, opVarPackage:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// opIsType2 returns true if this is a Type2Opcode.
|
|
||||||
//
|
|
||||||
// Grammar:
|
|
||||||
// Type2Opcode := DefAcquire | DefAdd | DefAnd | DefBuffer | DefConcat |
|
|
||||||
// DefConcatRes | DefCondRefOf | DefCopyObject | DefDecrement |
|
|
||||||
// DefDerefOf | DefDivide | DefFindSetLeftBit | DefFindSetRightBit |
|
|
||||||
// DefFromBCD | DefIncrement | DefIndex | DefLAnd | DefLEqual |
|
|
||||||
// DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual | DefMid |
|
|
||||||
// DefLNot | DefLNotEqual | DefLoadTable | DefLOr | DefMatch | DefMod |
|
|
||||||
// DefMultiply | DefNAnd | DefNOr | DefNot | DefObjectType | DefOr |
|
|
||||||
// DefPackage | DefVarPackage | DefRefOf | DefShiftLeft | DefShiftRight |
|
|
||||||
// DefSizeOf | DefStore | DefSubtract | DefTimer | DefToBCD | DefToBuffer |
|
|
||||||
// DefToDecimalString | DefToHexString | DefToInteger | DefToString |
|
|
||||||
// DefWait | DefXOr
|
|
||||||
func opIsType2(op opcode) bool {
|
|
||||||
switch op {
|
|
||||||
case opAcquire, opAdd, opAnd, opBuffer, opConcat,
|
|
||||||
opConcatRes, opCondRefOf, opCopyObject, opDecrement,
|
|
||||||
opDerefOf, opDivide, opFindSetLeftBit, opFindSetRightBit,
|
|
||||||
opFromBCD, opIncrement, opIndex, opLand, opLEqual,
|
|
||||||
opLGreater, opLLess, opMid,
|
|
||||||
opLnot, opLoadTable, opLor, opMatch, opMod,
|
|
||||||
opMultiply, opNand, opNor, opNot, opObjectType, opOr,
|
|
||||||
opPackage, opVarPackage, opRefOf, opShiftLeft, opShiftRight,
|
|
||||||
opSizeOf, opStore, opSubtract, opTimer, opToBCD, opToBuffer,
|
|
||||||
opToDecimalString, opToHexString, opToInteger, opToString,
|
|
||||||
opWait, opXor:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// opIsBufferField returens true if this opcode describes a
|
|
||||||
// buffer field creation operation.
|
|
||||||
func opIsBufferField(op opcode) bool {
|
|
||||||
switch op {
|
|
||||||
case opCreateField, opCreateBitField, opCreateByteField, opCreateWordField, opCreateDWordField, opCreateQWordField:
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// objType represents the object types that are supported by the AML parser.
|
|
||||||
type objType uint8
|
|
||||||
|
|
||||||
// The list of AML object types.
|
|
||||||
const (
|
|
||||||
objTypeAny objType = iota
|
|
||||||
objTypeInteger
|
|
||||||
objTypeString
|
|
||||||
objTypeBuffer
|
|
||||||
objTypePackage
|
|
||||||
objTypeDevice
|
|
||||||
objTypeEvent
|
|
||||||
objTypeMethod
|
|
||||||
objTypeMutex
|
|
||||||
objTypeRegion
|
|
||||||
objTypePower
|
|
||||||
objTypeProcessor
|
|
||||||
objTypeThermal
|
|
||||||
objTypeBufferField
|
|
||||||
objTypeLocalRegionField
|
|
||||||
objTypeLocalBankField
|
|
||||||
objTypeLocalReference
|
|
||||||
objTypeLocalAlias
|
|
||||||
objTypeLocalScope
|
|
||||||
objTypeLocalVariable
|
|
||||||
objTypeMethodArgument
|
|
||||||
)
|
|
||||||
|
|
||||||
// opFlag specifies a list of OR-able flags that describe the object
|
|
||||||
// type/attributes generated by a particular opcode.
|
|
||||||
type opFlag uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
opFlagNone opFlag = 1 << iota
|
|
||||||
opFlagHasPkgLen
|
|
||||||
opFlagNamed
|
|
||||||
opFlagConstant
|
|
||||||
opFlagReference
|
|
||||||
opFlagArithmetic
|
|
||||||
opFlagCreate
|
|
||||||
opFlagReturn
|
|
||||||
opFlagExecutable
|
|
||||||
opFlagNoOp
|
|
||||||
opFlagScoped
|
|
||||||
)
|
|
||||||
|
|
||||||
// is returns true if f is set in this opFlag.
|
|
||||||
func (fl opFlag) is(f opFlag) bool {
|
|
||||||
return (fl & f) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// opArgFlags encodes up to 7 opArgFlag values in a uint64 value.
|
|
||||||
type opArgFlags uint64
|
|
||||||
|
|
||||||
// argCount returns the number of encoded args in the given flag.
|
|
||||||
func (fl opArgFlags) argCount() (count uint8) {
|
|
||||||
// Each argument is specified using 8 bits with 0x0 indicating the end of the
|
|
||||||
// argument list
|
|
||||||
for ; fl&0xf != 0; fl, count = fl>>8, count+1 {
|
|
||||||
}
|
|
||||||
|
|
||||||
return count
|
|
||||||
}
|
|
||||||
|
|
||||||
// arg returns the arg flags for argument "num" where num is the 0-based index
|
|
||||||
// of the argument to return. The allowed values for num are 0-6.
|
|
||||||
func (fl opArgFlags) arg(num uint8) opArgFlag {
|
|
||||||
return opArgFlag((fl >> (num * 8)) & 0xf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// contains returns true if the arg flags contain any argument with type x.
|
|
||||||
func (fl opArgFlags) contains(x opArgFlag) bool {
|
|
||||||
// Each argument is specified using 8 bits with 0x0 indicating the end of the
|
|
||||||
// argument list
|
|
||||||
for ; fl&0xf != 0; fl >>= 8 {
|
|
||||||
if opArgFlag(fl&0xf) == x {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// opArgFlag represents the type of an argument expected by a particular opcode.
|
|
||||||
type opArgFlag uint8
|
|
||||||
|
|
||||||
// The list of supported opArgFlag values.
|
|
||||||
const (
|
|
||||||
_ opArgFlag = iota
|
|
||||||
opArgTermList
|
|
||||||
opArgTermObj
|
|
||||||
opArgByteList
|
|
||||||
opArgPackage
|
|
||||||
opArgString
|
|
||||||
opArgByteData
|
|
||||||
opArgWord
|
|
||||||
opArgDword
|
|
||||||
opArgQword
|
|
||||||
opArgNameString
|
|
||||||
opArgSuperName
|
|
||||||
opArgSimpleName
|
|
||||||
opArgDataRefObj
|
|
||||||
opArgTarget
|
|
||||||
opArgFieldList
|
|
||||||
)
|
|
||||||
|
|
||||||
// String implements fmt.Stringer for opArgFlag.
|
|
||||||
func (fl opArgFlag) String() string {
|
|
||||||
switch fl {
|
|
||||||
case opArgTermList:
|
|
||||||
return "opArgTermList"
|
|
||||||
case opArgTermObj:
|
|
||||||
return "opArgTermObj"
|
|
||||||
case opArgByteList:
|
|
||||||
return "opArgByteList"
|
|
||||||
case opArgPackage:
|
|
||||||
return "opArgPackage"
|
|
||||||
case opArgString:
|
|
||||||
return "opArgString"
|
|
||||||
case opArgByteData:
|
|
||||||
return "opArgByteData"
|
|
||||||
case opArgWord:
|
|
||||||
return "opArgWord"
|
|
||||||
case opArgDword:
|
|
||||||
return "opArgDword"
|
|
||||||
case opArgQword:
|
|
||||||
return "opArgQword"
|
|
||||||
case opArgNameString:
|
|
||||||
return "opArgNameString"
|
|
||||||
case opArgSuperName:
|
|
||||||
return "opArgSuperName"
|
|
||||||
case opArgSimpleName:
|
|
||||||
return "opArgSimpleName"
|
|
||||||
case opArgDataRefObj:
|
|
||||||
return "opArgDataRefObj"
|
|
||||||
case opArgTarget:
|
|
||||||
return "opArgTarget"
|
|
||||||
case opArgFieldList:
|
|
||||||
return "opArgFieldList"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func makeArg0() opArgFlags { return 0 }
|
|
||||||
func makeArg1(arg0 opArgFlag) opArgFlags { return opArgFlags(arg0) }
|
|
||||||
func makeArg2(arg0, arg1 opArgFlag) opArgFlags { return opArgFlags(arg1)<<8 | opArgFlags(arg0) }
|
|
||||||
func makeArg3(arg0, arg1, arg2 opArgFlag) opArgFlags {
|
|
||||||
return opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
|
||||||
}
|
|
||||||
func makeArg4(arg0, arg1, arg2, arg3 opArgFlag) opArgFlags {
|
|
||||||
return opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
|
||||||
}
|
|
||||||
func makeArg5(arg0, arg1, arg2, arg3, arg4 opArgFlag) opArgFlags {
|
|
||||||
return opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
|
||||||
}
|
|
||||||
func makeArg6(arg0, arg1, arg2, arg3, arg4, arg5 opArgFlag) opArgFlags {
|
|
||||||
return opArgFlags(arg5)<<40 | opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
|
||||||
}
|
|
||||||
func makeArg7(arg0, arg1, arg2, arg3, arg4, arg5, arg6 opArgFlag) opArgFlags {
|
|
||||||
return opArgFlags(arg6)<<48 | opArgFlags(arg5)<<40 | opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// opcodeInfo contains all known information about an opcode,
|
|
||||||
// its argument count and types as well as the type of object
|
|
||||||
// represented by it.
|
|
||||||
type opcodeInfo struct {
|
|
||||||
op opcode
|
|
||||||
name string
|
|
||||||
objType objType
|
|
||||||
|
|
||||||
flags opFlag
|
|
||||||
argFlags opArgFlags
|
|
||||||
}
|
|
@ -1,317 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
const (
|
|
||||||
badOpcode = 0xff
|
|
||||||
extOpPrefix = 0x5b
|
|
||||||
|
|
||||||
// Regular opcode list
|
|
||||||
opZero = opcode(0x00)
|
|
||||||
opOne = opcode(0x01)
|
|
||||||
opAlias = opcode(0x06)
|
|
||||||
opName = opcode(0x08)
|
|
||||||
opBytePrefix = opcode(0x0a)
|
|
||||||
opWordPrefix = opcode(0x0b)
|
|
||||||
opDwordPrefix = opcode(0x0c)
|
|
||||||
opStringPrefix = opcode(0x0d)
|
|
||||||
opQwordPrefix = opcode(0x0e)
|
|
||||||
opScope = opcode(0x10)
|
|
||||||
opBuffer = opcode(0x11)
|
|
||||||
opPackage = opcode(0x12)
|
|
||||||
opVarPackage = opcode(0x13)
|
|
||||||
opMethod = opcode(0x14)
|
|
||||||
opExternal = opcode(0x15)
|
|
||||||
opLocal0 = opcode(0x60)
|
|
||||||
opLocal1 = opcode(0x61)
|
|
||||||
opLocal2 = opcode(0x62)
|
|
||||||
opLocal3 = opcode(0x63)
|
|
||||||
opLocal4 = opcode(0x64)
|
|
||||||
opLocal5 = opcode(0x65)
|
|
||||||
opLocal6 = opcode(0x66)
|
|
||||||
opLocal7 = opcode(0x67)
|
|
||||||
opArg0 = opcode(0x68)
|
|
||||||
opArg1 = opcode(0x69)
|
|
||||||
opArg2 = opcode(0x6a)
|
|
||||||
opArg3 = opcode(0x6b)
|
|
||||||
opArg4 = opcode(0x6c)
|
|
||||||
opArg5 = opcode(0x6d)
|
|
||||||
opArg6 = opcode(0x6e)
|
|
||||||
opStore = opcode(0x70)
|
|
||||||
opRefOf = opcode(0x71)
|
|
||||||
opAdd = opcode(0x72)
|
|
||||||
opConcat = opcode(0x73)
|
|
||||||
opSubtract = opcode(0x74)
|
|
||||||
opIncrement = opcode(0x75)
|
|
||||||
opDecrement = opcode(0x76)
|
|
||||||
opMultiply = opcode(0x77)
|
|
||||||
opDivide = opcode(0x78)
|
|
||||||
opShiftLeft = opcode(0x79)
|
|
||||||
opShiftRight = opcode(0x7a)
|
|
||||||
opAnd = opcode(0x7b)
|
|
||||||
opNand = opcode(0x7c)
|
|
||||||
opOr = opcode(0x7d)
|
|
||||||
opNor = opcode(0x7e)
|
|
||||||
opXor = opcode(0x7f)
|
|
||||||
opNot = opcode(0x80)
|
|
||||||
opFindSetLeftBit = opcode(0x81)
|
|
||||||
opFindSetRightBit = opcode(0x82)
|
|
||||||
opDerefOf = opcode(0x83)
|
|
||||||
opConcatRes = opcode(0x84)
|
|
||||||
opMod = opcode(0x85)
|
|
||||||
opNotify = opcode(0x86)
|
|
||||||
opSizeOf = opcode(0x87)
|
|
||||||
opIndex = opcode(0x88)
|
|
||||||
opMatch = opcode(0x89)
|
|
||||||
opCreateDWordField = opcode(0x8a)
|
|
||||||
opCreateWordField = opcode(0x8b)
|
|
||||||
opCreateByteField = opcode(0x8c)
|
|
||||||
opCreateBitField = opcode(0x8d)
|
|
||||||
opObjectType = opcode(0x8e)
|
|
||||||
opCreateQWordField = opcode(0x8f)
|
|
||||||
opLand = opcode(0x90)
|
|
||||||
opLor = opcode(0x91)
|
|
||||||
opLnot = opcode(0x92)
|
|
||||||
opLEqual = opcode(0x93)
|
|
||||||
opLGreater = opcode(0x94)
|
|
||||||
opLLess = opcode(0x95)
|
|
||||||
opToBuffer = opcode(0x96)
|
|
||||||
opToDecimalString = opcode(0x97)
|
|
||||||
opToHexString = opcode(0x98)
|
|
||||||
opToInteger = opcode(0x99)
|
|
||||||
opToString = opcode(0x9c)
|
|
||||||
opCopyObject = opcode(0x9d)
|
|
||||||
opMid = opcode(0x9e)
|
|
||||||
opContinue = opcode(0x9f)
|
|
||||||
opIf = opcode(0xa0)
|
|
||||||
opElse = opcode(0xa1)
|
|
||||||
opWhile = opcode(0xa2)
|
|
||||||
opNoop = opcode(0xa3)
|
|
||||||
opReturn = opcode(0xa4)
|
|
||||||
opBreak = opcode(0xa5)
|
|
||||||
opBreakPoint = opcode(0xcc)
|
|
||||||
opOnes = opcode(0xff)
|
|
||||||
// Extended opcodes
|
|
||||||
opMutex = opcode(0xff + 0x01)
|
|
||||||
opEvent = opcode(0xff + 0x02)
|
|
||||||
opCondRefOf = opcode(0xff + 0x12)
|
|
||||||
opCreateField = opcode(0xff + 0x13)
|
|
||||||
opLoadTable = opcode(0xff + 0x1f)
|
|
||||||
opLoad = opcode(0xff + 0x20)
|
|
||||||
opStall = opcode(0xff + 0x21)
|
|
||||||
opSleep = opcode(0xff + 0x22)
|
|
||||||
opAcquire = opcode(0xff + 0x23)
|
|
||||||
opSignal = opcode(0xff + 0x24)
|
|
||||||
opWait = opcode(0xff + 0x25)
|
|
||||||
opReset = opcode(0xff + 0x26)
|
|
||||||
opRelease = opcode(0xff + 0x27)
|
|
||||||
opFromBCD = opcode(0xff + 0x28)
|
|
||||||
opToBCD = opcode(0xff + 0x29)
|
|
||||||
opUnload = opcode(0xff + 0x2a)
|
|
||||||
opRevision = opcode(0xff + 0x30)
|
|
||||||
opDebug = opcode(0xff + 0x31)
|
|
||||||
opFatal = opcode(0xff + 0x32)
|
|
||||||
opTimer = opcode(0xff + 0x33)
|
|
||||||
opOpRegion = opcode(0xff + 0x80)
|
|
||||||
opField = opcode(0xff + 0x81)
|
|
||||||
opDevice = opcode(0xff + 0x82)
|
|
||||||
opProcessor = opcode(0xff + 0x83)
|
|
||||||
opPowerRes = opcode(0xff + 0x84)
|
|
||||||
opThermalZone = opcode(0xff + 0x85)
|
|
||||||
opIndexField = opcode(0xff + 0x86)
|
|
||||||
opBankField = opcode(0xff + 0x87)
|
|
||||||
opDataRegion = opcode(0xff + 0x88)
|
|
||||||
)
|
|
||||||
|
|
||||||
// The opcode table contains all opcode-related information that the parser knows.
|
|
||||||
// This table is modeled after a similar table used in the acpica implementation.
|
|
||||||
var opcodeTable = []opcodeInfo{
|
|
||||||
/*0x00*/ {opZero, "Zero", objTypeInteger, opFlagConstant, makeArg0()},
|
|
||||||
/*0x01*/ {opOne, "One", objTypeInteger, opFlagConstant, makeArg0()},
|
|
||||||
/*0x02*/ {opAlias, "Alias", objTypeLocalAlias, opFlagNamed, makeArg2(opArgNameString, opArgNameString)},
|
|
||||||
/*0x03*/ {opName, "Name", objTypeAny, opFlagNamed, makeArg2(opArgNameString, opArgDataRefObj)},
|
|
||||||
/*0x04*/ {opBytePrefix, "Byte", objTypeInteger, opFlagConstant, makeArg1(opArgByteData)},
|
|
||||||
/*0x05*/ {opWordPrefix, "Word", objTypeInteger, opFlagConstant, makeArg1(opArgWord)},
|
|
||||||
/*0x06*/ {opDwordPrefix, "Dword", objTypeInteger, opFlagConstant, makeArg1(opArgDword)},
|
|
||||||
/*0x07*/ {opStringPrefix, "String", objTypeString, opFlagConstant, makeArg1(opArgString)},
|
|
||||||
/*0x08*/ {opQwordPrefix, "Qword", objTypeInteger, opFlagConstant, makeArg1(opArgQword)},
|
|
||||||
/*0x09*/ {opScope, "Scope", objTypeLocalScope, opFlagNamed, makeArg2(opArgNameString, opArgTermList)},
|
|
||||||
/*0x0a*/ {opBuffer, "Buffer", objTypeBuffer, opFlagHasPkgLen, makeArg2(opArgTermObj, opArgByteList)},
|
|
||||||
/*0x0b*/ {opPackage, "Package", objTypePackage, opFlagNone, makeArg2(opArgByteData, opArgTermList)},
|
|
||||||
/*0x0c*/ {opVarPackage, "VarPackage", objTypePackage, opFlagNone, makeArg2(opArgByteData, opArgTermList)},
|
|
||||||
/*0x0d*/ {opMethod, "Method", objTypeMethod, opFlagNamed | opFlagScoped, makeArg3(opArgNameString, opArgByteData, opArgTermList)},
|
|
||||||
/*0x0e*/ {opExternal, "External", objTypeAny, opFlagNamed, makeArg3(opArgNameString, opArgByteData, opArgByteData)},
|
|
||||||
/*0x0f*/ {opLocal0, "Local0", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x10*/ {opLocal1, "Local1", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x11*/ {opLocal2, "Local2", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x12*/ {opLocal3, "Local3", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x13*/ {opLocal4, "Local4", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0120*/ {opLocal5, "Local5", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x15*/ {opLocal6, "Local6", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x16*/ {opLocal7, "Local7", objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x17*/ {opArg0, "Arg0", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x18*/ {opArg1, "Arg1", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x19*/ {opArg2, "Arg2", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x1a*/ {opArg3, "Arg3", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x1b*/ {opArg4, "Arg4", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x1c*/ {opArg5, "Arg5", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x1d*/ {opArg6, "Arg6", objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x1e*/ {opStore, "Store", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgSuperName)},
|
|
||||||
/*0x1f*/ {opRefOf, "RefOf", objTypeAny, opFlagReference | opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x20*/ {opAdd, "Add", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x21*/ {opConcat, "Concat", objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x22*/ {opSubtract, "Subtract", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x23*/ {opIncrement, "Increment", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x24*/ {opDecrement, "Decrement", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x25*/ {opMultiply, "Multiply", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x26*/ {opDivide, "Divide", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTarget, opArgTarget)},
|
|
||||||
/*0x27*/ {opShiftLeft, "ShiftLeft", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x28*/ {opShiftRight, "ShiftRight", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x29*/ {opAnd, "And", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x2a*/ {opNand, "Nand", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x2b*/ {opOr, "Or", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x2c*/ {opNor, "Nor", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x2d*/ {opXor, "Xor", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x2e*/ {opNot, "Not", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x2f*/ {opFindSetLeftBit, "FindSetLeftBit", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x30*/ {opFindSetRightBit, "FindSetRightBit", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x31*/ {opDerefOf, "DerefOf", objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
|
||||||
/*0x32*/ {opConcatRes, "ConcatRes", objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x33*/ {opMod, "Mod", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x34*/ {opNotify, "Notify", objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgTermObj)},
|
|
||||||
/*0x35*/ {opSizeOf, "SizeOf", objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x36*/ {opIndex, "Index", objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x37*/ {opMatch, "Match", objTypeAny, opFlagExecutable, makeArg6(opArgTermObj, opArgByteData, opArgTermObj, opArgByteData, opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x38*/ {opCreateDWordField, "CreateDWordField", objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
|
||||||
/*0x39*/ {opCreateWordField, "CreateWordField", objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
|
||||||
/*0x3a*/ {opCreateByteField, "CreateByteField", objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
|
||||||
/*0x3b*/ {opCreateBitField, "CreateBitField", objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
|
||||||
/*0x3c*/ {opObjectType, "ObjectType", objTypeAny, opFlagNone, makeArg1(opArgSuperName)},
|
|
||||||
/*0x3d*/ {opCreateQWordField, "CreateQWordField", objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
|
||||||
/*0x3e*/ {opLand, "Land", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x3f*/ {opLor, "Lor", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x40*/ {opLnot, "Lnot", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgTermObj)},
|
|
||||||
/*0x41*/ {opLEqual, "LEqual", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x42*/ {opLGreater, "LGreater", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x43*/ {opLLess, "LLess", objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x44*/ {opToBuffer, "ToBuffer", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x45*/ {opToDecimalString, "ToDecimalString", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x46*/ {opToHexString, "ToHexString", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x47*/ {opToInteger, "ToInteger", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x48*/ {opToString, "ToString", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x49*/ {opCopyObject, "CopyObject", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgSimpleName)},
|
|
||||||
/*0x4a*/ {opMid, "Mid", objTypeAny, opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTermObj, opArgTarget)},
|
|
||||||
/*0x4b*/ {opContinue, "Continue", objTypeAny, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x4c*/ {opIf, "If", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTermList)},
|
|
||||||
/*0x4d*/ {opElse, "Else", objTypeAny, opFlagExecutable | opFlagScoped, makeArg1(opArgTermList)},
|
|
||||||
/*0x4e*/ {opWhile, "While", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTermList)},
|
|
||||||
/*0x4f*/ {opNoop, "Noop", objTypeAny, opFlagNoOp, makeArg0()},
|
|
||||||
/*0x50*/ {opReturn, "Return", objTypeAny, opFlagReturn, makeArg1(opArgTermObj)},
|
|
||||||
/*0x51*/ {opBreak, "Break", objTypeAny, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x52*/ {opBreakPoint, "BreakPoint", objTypeAny, opFlagNoOp, makeArg0()},
|
|
||||||
/*0x53*/ {opOnes, "Ones", objTypeInteger, opFlagConstant, makeArg0()},
|
|
||||||
/*0x54*/ {opMutex, "Mutex", objTypeMutex, opFlagNamed, makeArg2(opArgNameString, opArgByteData)},
|
|
||||||
/*0x55*/ {opEvent, "Event", objTypeEvent, opFlagNamed, makeArg1(opArgNameString)},
|
|
||||||
/*0x56*/ {opCondRefOf, "CondRefOf", objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgSuperName)},
|
|
||||||
/*0x57*/ {opCreateField, "CreateField", objTypeBufferField, opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTermObj, opArgNameString)},
|
|
||||||
/*0x58*/ {opLoadTable, "LoadTable", objTypeAny, opFlagExecutable, makeArg7(opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x59*/ {opLoad, "Load", objTypeAny, opFlagExecutable, makeArg2(opArgNameString, opArgSuperName)},
|
|
||||||
/*0x5a*/ {opStall, "Stall", objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
|
||||||
/*0x5b*/ {opSleep, "Sleep", objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
|
||||||
/*0x5c*/ {opAcquire, "Acquire", objTypeAny, opFlagExecutable, makeArg2(opArgNameString, opArgSuperName)},
|
|
||||||
/*0x5d*/ {opSignal, "Signal", objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
|
||||||
/*0x5e*/ {opWait, "Wait", objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgTermObj)},
|
|
||||||
/*0x5f*/ {opReset, "Reset", objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x60*/ {opRelease, "Release", objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x61*/ {opFromBCD, "FromBCD", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x62*/ {opToBCD, "ToBCD", objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
|
||||||
/*0x63*/ {opUnload, "Unload", objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
|
||||||
/*0x64*/ {opRevision, "Revision", objTypeInteger, opFlagConstant | opFlagExecutable, makeArg0()},
|
|
||||||
/*0x65*/ {opDebug, "Debug", objTypeLocalReference, opFlagExecutable, makeArg0()},
|
|
||||||
/*0x66*/ {opFatal, "Fatal", objTypeAny, opFlagExecutable, makeArg3(opArgByteData, opArgDword, opArgTermObj)},
|
|
||||||
/*0x67*/ {opTimer, "Timer", objTypeAny, opFlagNone, makeArg0()},
|
|
||||||
/*0x68*/ {opOpRegion, "OpRegion", objTypeRegion, opFlagNamed, makeArg4(opArgNameString, opArgByteData, opArgTermObj, opArgTermObj)},
|
|
||||||
/*0x69*/ {opField, "Field", objTypeAny, opFlagNone, makeArg3(opArgNameString, opArgByteData, opArgFieldList)},
|
|
||||||
/*0x6a*/ {opDevice, "Device", objTypeDevice, opFlagNamed | opFlagScoped, makeArg2(opArgNameString, opArgTermList)},
|
|
||||||
/*0x6b*/ {opProcessor, "Processor", objTypeProcessor, opFlagNamed | opFlagScoped, makeArg5(opArgNameString, opArgByteData, opArgDword, opArgByteData, opArgTermList)},
|
|
||||||
/*0x6c*/ {opPowerRes, "PowerRes", objTypePower, opFlagNamed | opFlagScoped, makeArg4(opArgNameString, opArgByteData, opArgWord, opArgTermList)},
|
|
||||||
/*0x6d*/ {opThermalZone, "ThermalZone", objTypeThermal, opFlagNamed | opFlagScoped, makeArg2(opArgNameString, opArgTermList)},
|
|
||||||
/*0x6e*/ {opIndexField, "IndexField", objTypeAny, opFlagNone, makeArg4(opArgNameString, opArgNameString, opArgByteData, opArgFieldList)},
|
|
||||||
/*0x6f*/ {opBankField, "BankField", objTypeLocalBankField, opFlagNamed, makeArg5(opArgNameString, opArgNameString, opArgTermObj, opArgByteData, opArgFieldList)},
|
|
||||||
/*0x70*/ {opDataRegion, "DataRegion", objTypeLocalRegionField, opFlagNamed, makeArg4(opArgNameString, opArgTermObj, opArgTermObj, opArgTermObj)},
|
|
||||||
}
|
|
||||||
|
|
||||||
// opcodeMap maps an AML opcode to an entry in the opcode table. Entries with
|
|
||||||
// the value 0xff indicate an invalid/unsupported opcode.
|
|
||||||
var opcodeMap = [256]uint8{
|
|
||||||
/* 0 1 2 3 4 5 6 7*/
|
|
||||||
/*0x00 - 0x07*/ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x02, 0xff,
|
|
||||||
/*0x08 - 0x0f*/ 0x03, 0xff, 0x04, 0x05, 0x06, 0x07, 0x08, 0xff,
|
|
||||||
/*0x10 - 0x17*/ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xff, 0xff,
|
|
||||||
/*0x18 - 0x1f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x20 - 0x27*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x28 - 0x2f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x30 - 0x37*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x38 - 0x3f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x40 - 0x47*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x48 - 0x4f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x50 - 0x57*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x58 - 0x5f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x60 - 0x67*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
|
||||||
/*0x68 - 0x6f*/ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0xff,
|
|
||||||
/*0x70 - 0x77*/ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
|
||||||
/*0x78 - 0x7f*/ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
|
||||||
/*0x80 - 0x87*/ 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
|
||||||
/*0x88 - 0x8f*/ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
|
|
||||||
/*0x90 - 0x97*/ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
|
|
||||||
/*0x98 - 0x9f*/ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x49, 0x4a, 0x4b,
|
|
||||||
/*0xa0 - 0xa7*/ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0xff, 0xff,
|
|
||||||
/*0xa8 - 0xaf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xb0 - 0xb7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xb8 - 0xbf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xc0 - 0xc7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xc8 - 0xcf*/ 0xff, 0xff, 0xff, 0xff, 0x52, 0xff, 0xff, 0xff,
|
|
||||||
/*0xd0 - 0xd7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xd8 - 0xdf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xe0 - 0xe7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xe8 - 0xef*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xf0 - 0xf7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xf8 - 0xff*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53,
|
|
||||||
}
|
|
||||||
|
|
||||||
// extendedOpcodeMap maps an AML extended opcode (extOpPrefix + code) to an
|
|
||||||
// entry in the opcode table. Entries with the value 0xff indicate an
|
|
||||||
// invalid/unsupported opcode.
|
|
||||||
var extendedOpcodeMap = [256]uint8{
|
|
||||||
/* 0 1 2 3 4 5 6 7*/
|
|
||||||
/*0x00 - 0x07*/ 0xff, 0x54, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x08 - 0x0f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x10 - 0x17*/ 0xff, 0xff, 0x56, 0x57, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x18 - 0x1f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x58,
|
|
||||||
/*0x20 - 0x27*/ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
|
||||||
/*0x28 - 0x2f*/ 0x61, 0x62, 0x63, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x30 - 0x37*/ 0x64, 0x65, 0x66, 0x67, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x38 - 0x3f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x40 - 0x47*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x48 - 0x4f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x50 - 0x57*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x58 - 0x5f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x60 - 0x67*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x68 - 0x6f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x70 - 0x77*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x78 - 0x7f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x80 - 0x87*/ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
|
||||||
/*0x88 - 0x8f*/ 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x90 - 0x97*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0x98 - 0x9f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xa0 - 0xa7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xa8 - 0xaf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xb0 - 0xb7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xb8 - 0xbf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xc0 - 0xc7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xc8 - 0xcf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xd0 - 0xd7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xd8 - 0xdf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xe0 - 0xe7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xe8 - 0xef*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xf0 - 0xf7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
|
||||||
/*0xf8 - 0xff*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53,
|
|
||||||
}
|
|
@ -1,187 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
import "testing"
|
|
||||||
|
|
||||||
func TestOpcodeToString(t *testing.T) {
|
|
||||||
if exp, got := "Acquire", opAcquire.String(); got != exp {
|
|
||||||
t.Fatalf("expected opAcquire.toString() to return %q; got %q", exp, got)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp, got := "unknown", opcode(0xffff).String(); got != exp {
|
|
||||||
t.Fatalf("expected opcode.String() to return %q; got %q", exp, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpcodeIsX(t *testing.T) {
|
|
||||||
specs := []struct {
|
|
||||||
op opcode
|
|
||||||
testFn func(opcode) bool
|
|
||||||
want bool
|
|
||||||
}{
|
|
||||||
// opIsLocalArg
|
|
||||||
{opLocal0, opIsLocalArg, true},
|
|
||||||
{opLocal1, opIsLocalArg, true},
|
|
||||||
{opLocal2, opIsLocalArg, true},
|
|
||||||
{opLocal3, opIsLocalArg, true},
|
|
||||||
{opLocal4, opIsLocalArg, true},
|
|
||||||
{opLocal5, opIsLocalArg, true},
|
|
||||||
{opLocal6, opIsLocalArg, true},
|
|
||||||
{opLocal7, opIsLocalArg, true},
|
|
||||||
{opArg0, opIsLocalArg, false},
|
|
||||||
{opDivide, opIsLocalArg, false},
|
|
||||||
// opIsMethodArg
|
|
||||||
{opArg0, opIsMethodArg, true},
|
|
||||||
{opArg1, opIsMethodArg, true},
|
|
||||||
{opArg2, opIsMethodArg, true},
|
|
||||||
{opArg3, opIsMethodArg, true},
|
|
||||||
{opArg4, opIsMethodArg, true},
|
|
||||||
{opArg5, opIsMethodArg, true},
|
|
||||||
{opArg6, opIsMethodArg, true},
|
|
||||||
{opLocal7, opIsMethodArg, false},
|
|
||||||
{opIf, opIsMethodArg, false},
|
|
||||||
// opIsArg
|
|
||||||
{opLocal5, opIsArg, true},
|
|
||||||
{opArg1, opIsArg, true},
|
|
||||||
{opDivide, opIsArg, false},
|
|
||||||
// opIsType2
|
|
||||||
{opAcquire, opIsType2, true},
|
|
||||||
{opAdd, opIsType2, true},
|
|
||||||
{opAnd, opIsType2, true},
|
|
||||||
{opBuffer, opIsType2, true},
|
|
||||||
{opConcat, opIsType2, true},
|
|
||||||
{opConcatRes, opIsType2, true},
|
|
||||||
{opCondRefOf, opIsType2, true},
|
|
||||||
{opCopyObject, opIsType2, true},
|
|
||||||
{opDecrement, opIsType2, true},
|
|
||||||
{opDerefOf, opIsType2, true},
|
|
||||||
{opDivide, opIsType2, true},
|
|
||||||
{opFindSetLeftBit, opIsType2, true},
|
|
||||||
{opFindSetRightBit, opIsType2, true},
|
|
||||||
{opFromBCD, opIsType2, true},
|
|
||||||
{opIncrement, opIsType2, true},
|
|
||||||
{opIndex, opIsType2, true},
|
|
||||||
{opLand, opIsType2, true},
|
|
||||||
{opLEqual, opIsType2, true},
|
|
||||||
{opLGreater, opIsType2, true},
|
|
||||||
{opLLess, opIsType2, true},
|
|
||||||
{opMid, opIsType2, true},
|
|
||||||
{opLnot, opIsType2, true},
|
|
||||||
{opLoadTable, opIsType2, true},
|
|
||||||
{opLor, opIsType2, true},
|
|
||||||
{opMatch, opIsType2, true},
|
|
||||||
{opMod, opIsType2, true},
|
|
||||||
{opMultiply, opIsType2, true},
|
|
||||||
{opNand, opIsType2, true},
|
|
||||||
{opNor, opIsType2, true},
|
|
||||||
{opNot, opIsType2, true},
|
|
||||||
{opObjectType, opIsType2, true},
|
|
||||||
{opOr, opIsType2, true},
|
|
||||||
{opPackage, opIsType2, true},
|
|
||||||
{opVarPackage, opIsType2, true},
|
|
||||||
{opRefOf, opIsType2, true},
|
|
||||||
{opShiftLeft, opIsType2, true},
|
|
||||||
{opShiftRight, opIsType2, true},
|
|
||||||
{opSizeOf, opIsType2, true},
|
|
||||||
{opStore, opIsType2, true},
|
|
||||||
{opSubtract, opIsType2, true},
|
|
||||||
{opTimer, opIsType2, true},
|
|
||||||
{opToBCD, opIsType2, true},
|
|
||||||
{opToBuffer, opIsType2, true},
|
|
||||||
{opToDecimalString, opIsType2, true},
|
|
||||||
{opToHexString, opIsType2, true},
|
|
||||||
{opToInteger, opIsType2, true},
|
|
||||||
{opToString, opIsType2, true},
|
|
||||||
{opWait, opIsType2, true},
|
|
||||||
{opXor, opIsType2, true},
|
|
||||||
{opBytePrefix, opIsType2, false},
|
|
||||||
// opIsDataObject
|
|
||||||
{opBytePrefix, opIsDataObject, true},
|
|
||||||
{opWordPrefix, opIsDataObject, true},
|
|
||||||
{opDwordPrefix, opIsDataObject, true},
|
|
||||||
{opQwordPrefix, opIsDataObject, true},
|
|
||||||
{opStringPrefix, opIsDataObject, true},
|
|
||||||
{opZero, opIsDataObject, true},
|
|
||||||
{opOne, opIsDataObject, true},
|
|
||||||
{opOnes, opIsDataObject, true},
|
|
||||||
{opRevision, opIsDataObject, true},
|
|
||||||
{opBuffer, opIsDataObject, true},
|
|
||||||
{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 {
|
|
||||||
if got := spec.testFn(spec.op); got != spec.want {
|
|
||||||
t.Errorf("[spec %d] opcode %q: expected to get %t; got %t", specIndex, spec.op, spec.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpArgFlagToString(t *testing.T) {
|
|
||||||
specs := map[opArgFlag]string{
|
|
||||||
opArgTermList: "opArgTermList",
|
|
||||||
opArgTermObj: "opArgTermObj",
|
|
||||||
opArgByteList: "opArgByteList",
|
|
||||||
opArgPackage: "opArgPackage",
|
|
||||||
opArgString: "opArgString",
|
|
||||||
opArgByteData: "opArgByteData",
|
|
||||||
opArgWord: "opArgWord",
|
|
||||||
opArgDword: "opArgDword",
|
|
||||||
opArgQword: "opArgQword",
|
|
||||||
opArgNameString: "opArgNameString",
|
|
||||||
opArgSuperName: "opArgSuperName",
|
|
||||||
opArgSimpleName: "opArgSimpleName",
|
|
||||||
opArgDataRefObj: "opArgDataRefObj",
|
|
||||||
opArgTarget: "opArgTarget",
|
|
||||||
opArgFieldList: "opArgFieldList",
|
|
||||||
opArgFlag(0xff): "",
|
|
||||||
}
|
|
||||||
|
|
||||||
for flag, want := range specs {
|
|
||||||
if got := flag.String(); got != want {
|
|
||||||
t.Errorf("expected %q; got %q", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestFindUnmappedOpcodes is a helper test that pinpoints opcodes that have
|
|
||||||
// not yet been mapped via an opcode table. This test will be removed once all
|
|
||||||
// opcodes are supported.
|
|
||||||
func TestFindUnmappedOpcodes(t *testing.T) {
|
|
||||||
//t.SkipNow()
|
|
||||||
for opIndex, opRef := range opcodeMap {
|
|
||||||
if opRef != badOpcode {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for tabIndex, info := range opcodeTable {
|
|
||||||
if uint16(info.op) == uint16(opIndex) {
|
|
||||||
t.Errorf("set opcodeMap[0x%02x] = 0x%02x // %s\n", opIndex, tabIndex, info.op.String())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for opIndex, opRef := range extendedOpcodeMap {
|
|
||||||
// 0xff (opOnes) is defined in opcodeTable
|
|
||||||
if opRef != badOpcode || opIndex == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
opIndex += 0xff
|
|
||||||
for tabIndex, info := range opcodeTable {
|
|
||||||
if uint16(info.op) == uint16(opIndex) {
|
|
||||||
t.Errorf("set extendedOpcodeMap[0x%02x] = 0x%02x // %s\n", opIndex-0xff, tabIndex, info.op.String())
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
341
src/gopheros/device/acpi/aml/parser/opcode_table.go
Normal file
341
src/gopheros/device/acpi/aml/parser/opcode_table.go
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
package parser
|
||||||
|
|
||||||
|
import "gopheros/device/acpi/aml/entity"
|
||||||
|
|
||||||
|
const (
|
||||||
|
badOpcode = 0xff
|
||||||
|
extOpPrefix = 0x5b
|
||||||
|
)
|
||||||
|
|
||||||
|
// objType represents the object types that are supported by the AML parser.
|
||||||
|
type objType uint8
|
||||||
|
|
||||||
|
// The list of AML object types.
|
||||||
|
const (
|
||||||
|
objTypeAny objType = iota
|
||||||
|
objTypeInteger
|
||||||
|
objTypeString
|
||||||
|
objTypeBuffer
|
||||||
|
objTypePackage
|
||||||
|
objTypeDevice
|
||||||
|
objTypeEvent
|
||||||
|
objTypeMethod
|
||||||
|
objTypeMutex
|
||||||
|
objTypeRegion
|
||||||
|
objTypePower
|
||||||
|
objTypeProcessor
|
||||||
|
objTypeThermal
|
||||||
|
objTypeBufferField
|
||||||
|
objTypeLocalRegionField
|
||||||
|
objTypeLocalBankField
|
||||||
|
objTypeLocalReference
|
||||||
|
objTypeLocalAlias
|
||||||
|
objTypeLocalScope
|
||||||
|
objTypeLocalVariable
|
||||||
|
objTypeMethodArgument
|
||||||
|
)
|
||||||
|
|
||||||
|
// opFlag specifies a list of OR-able flags that describe the object
|
||||||
|
// type/attributes generated by a particular opcode.
|
||||||
|
type opFlag uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
opFlagNone opFlag = 1 << iota
|
||||||
|
opFlagHasPkgLen
|
||||||
|
opFlagNamed
|
||||||
|
opFlagConstant
|
||||||
|
opFlagReference
|
||||||
|
opFlagArithmetic
|
||||||
|
opFlagCreate
|
||||||
|
opFlagReturn
|
||||||
|
opFlagExecutable
|
||||||
|
opFlagNoOp
|
||||||
|
opFlagScoped
|
||||||
|
)
|
||||||
|
|
||||||
|
// is returns true if f is set in this opFlag.
|
||||||
|
func (fl opFlag) is(f opFlag) bool {
|
||||||
|
return (fl & f) == f
|
||||||
|
}
|
||||||
|
|
||||||
|
// opArgFlags encodes up to 7 opArgFlag values in a uint64 value.
|
||||||
|
type opArgFlags uint64
|
||||||
|
|
||||||
|
// argCount returns the number of encoded args in the given flag.
|
||||||
|
func (fl opArgFlags) argCount() (count uint8) {
|
||||||
|
// Each argument is specified using 8 bits with 0x0 indicating the end of the
|
||||||
|
// argument list
|
||||||
|
for ; fl&0xf != 0; fl, count = fl>>8, count+1 {
|
||||||
|
}
|
||||||
|
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
|
// arg returns the arg flags for argument "num" where num is the 0-based index
|
||||||
|
// of the argument to return. The allowed values for num are 0-6.
|
||||||
|
func (fl opArgFlags) arg(num uint8) opArgFlag {
|
||||||
|
return opArgFlag((fl >> (num * 8)) & 0xf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// contains returns true if the arg flags contain any argument with type x.
|
||||||
|
func (fl opArgFlags) contains(x opArgFlag) bool {
|
||||||
|
// Each argument is specified using 8 bits with 0x0 indicating the end of the
|
||||||
|
// argument list
|
||||||
|
for ; fl&0xf != 0; fl >>= 8 {
|
||||||
|
if opArgFlag(fl&0xf) == x {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// opArgFlag represents the type of an argument expected by a particular opcode.
|
||||||
|
type opArgFlag uint8
|
||||||
|
|
||||||
|
// The list of supported opArgFlag values.
|
||||||
|
const (
|
||||||
|
_ opArgFlag = iota
|
||||||
|
opArgTermList
|
||||||
|
opArgTermObj
|
||||||
|
opArgByteList
|
||||||
|
opArgString
|
||||||
|
opArgByteData
|
||||||
|
opArgWord
|
||||||
|
opArgDword
|
||||||
|
opArgQword
|
||||||
|
opArgNameString
|
||||||
|
opArgSuperName
|
||||||
|
opArgSimpleName
|
||||||
|
opArgDataRefObj
|
||||||
|
opArgTarget
|
||||||
|
opArgFieldList
|
||||||
|
)
|
||||||
|
|
||||||
|
func makeArg0() opArgFlags { return 0 }
|
||||||
|
func makeArg1(arg0 opArgFlag) opArgFlags { return opArgFlags(arg0) }
|
||||||
|
func makeArg2(arg0, arg1 opArgFlag) opArgFlags { return opArgFlags(arg1)<<8 | opArgFlags(arg0) }
|
||||||
|
func makeArg3(arg0, arg1, arg2 opArgFlag) opArgFlags {
|
||||||
|
return opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
||||||
|
}
|
||||||
|
func makeArg4(arg0, arg1, arg2, arg3 opArgFlag) opArgFlags {
|
||||||
|
return opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
||||||
|
}
|
||||||
|
func makeArg5(arg0, arg1, arg2, arg3, arg4 opArgFlag) opArgFlags {
|
||||||
|
return opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
||||||
|
}
|
||||||
|
func makeArg6(arg0, arg1, arg2, arg3, arg4, arg5 opArgFlag) opArgFlags {
|
||||||
|
return opArgFlags(arg5)<<40 | opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
||||||
|
}
|
||||||
|
func makeArg7(arg0, arg1, arg2, arg3, arg4, arg5, arg6 opArgFlag) opArgFlags {
|
||||||
|
return opArgFlags(arg6)<<48 | opArgFlags(arg5)<<40 | opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// opcodeInfo contains all known information about an opcode,
|
||||||
|
// its argument count and types as well as the type of object
|
||||||
|
// represented by it.
|
||||||
|
type opcodeInfo struct {
|
||||||
|
op entity.AMLOpcode
|
||||||
|
objType objType
|
||||||
|
|
||||||
|
flags opFlag
|
||||||
|
argFlags opArgFlags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used by Parser.parseMethodBody for deferred parsing of method bodies.
|
||||||
|
const methodOpInfoIndex = 0x0d
|
||||||
|
|
||||||
|
// The opcode table contains all opcode-related information that the parser knows.
|
||||||
|
// This table is modeled after a similar table used in the acpica implementation.
|
||||||
|
var opcodeTable = []opcodeInfo{
|
||||||
|
/*0x00*/ {entity.OpZero, objTypeInteger, opFlagConstant, makeArg0()},
|
||||||
|
/*0x01*/ {entity.OpOne, objTypeInteger, opFlagConstant, makeArg0()},
|
||||||
|
/*0x02*/ {entity.OpAlias, objTypeLocalAlias, opFlagNamed, makeArg2(opArgNameString, opArgNameString)},
|
||||||
|
/*0x03*/ {entity.OpName, objTypeAny, opFlagNamed, makeArg2(opArgNameString, opArgDataRefObj)},
|
||||||
|
/*0x04*/ {entity.OpBytePrefix, objTypeInteger, opFlagConstant, makeArg1(opArgByteData)},
|
||||||
|
/*0x05*/ {entity.OpWordPrefix, objTypeInteger, opFlagConstant, makeArg1(opArgWord)},
|
||||||
|
/*0x06*/ {entity.OpDwordPrefix, objTypeInteger, opFlagConstant, makeArg1(opArgDword)},
|
||||||
|
/*0x07*/ {entity.OpStringPrefix, objTypeString, opFlagConstant, makeArg1(opArgString)},
|
||||||
|
/*0x08*/ {entity.OpQwordPrefix, objTypeInteger, opFlagConstant, makeArg1(opArgQword)},
|
||||||
|
/*0x09*/ {entity.OpScope, objTypeLocalScope, opFlagNamed, makeArg2(opArgNameString, opArgTermList)},
|
||||||
|
/*0x0a*/ {entity.OpBuffer, objTypeBuffer, opFlagHasPkgLen, makeArg2(opArgTermObj, opArgByteList)},
|
||||||
|
/*0x0b*/ {entity.OpPackage, objTypePackage, opFlagNone, makeArg2(opArgByteData, opArgTermList)},
|
||||||
|
/*0x0c*/ {entity.OpVarPackage, objTypePackage, opFlagNone, makeArg2(opArgByteData, opArgTermList)},
|
||||||
|
/*0x0d*/ {entity.OpMethod, objTypeMethod, opFlagNamed | opFlagScoped, makeArg3(opArgNameString, opArgByteData, opArgTermList)},
|
||||||
|
/*0x0e*/ {entity.OpExternal, objTypeAny, opFlagNamed, makeArg3(opArgNameString, opArgByteData, opArgByteData)},
|
||||||
|
/*0x0f*/ {entity.OpLocal0, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x10*/ {entity.OpLocal1, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x11*/ {entity.OpLocal2, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x12*/ {entity.OpLocal3, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x13*/ {entity.OpLocal4, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0120*/ {entity.OpLocal5, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x15*/ {entity.OpLocal6, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x16*/ {entity.OpLocal7, objTypeLocalVariable, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x17*/ {entity.OpArg0, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x18*/ {entity.OpArg1, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x19*/ {entity.OpArg2, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x1a*/ {entity.OpArg3, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x1b*/ {entity.OpArg4, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x1c*/ {entity.OpArg5, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x1d*/ {entity.OpArg6, objTypeMethodArgument, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x1e*/ {entity.OpStore, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgSuperName)},
|
||||||
|
/*0x1f*/ {entity.OpRefOf, objTypeAny, opFlagReference | opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x20*/ {entity.OpAdd, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x21*/ {entity.OpConcat, objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x22*/ {entity.OpSubtract, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x23*/ {entity.OpIncrement, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x24*/ {entity.OpDecrement, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x25*/ {entity.OpMultiply, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x26*/ {entity.OpDivide, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTarget, opArgTarget)},
|
||||||
|
/*0x27*/ {entity.OpShiftLeft, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x28*/ {entity.OpShiftRight, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x29*/ {entity.OpAnd, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x2a*/ {entity.OpNand, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x2b*/ {entity.OpOr, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x2c*/ {entity.OpNor, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x2d*/ {entity.OpXor, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x2e*/ {entity.OpNot, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x2f*/ {entity.OpFindSetLeftBit, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x30*/ {entity.OpFindSetRightBit, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x31*/ {entity.OpDerefOf, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
||||||
|
/*0x32*/ {entity.OpConcatRes, objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x33*/ {entity.OpMod, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x34*/ {entity.OpNotify, objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgTermObj)},
|
||||||
|
/*0x35*/ {entity.OpSizeOf, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x36*/ {entity.OpIndex, objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x37*/ {entity.OpMatch, objTypeAny, opFlagExecutable, makeArg6(opArgTermObj, opArgByteData, opArgTermObj, opArgByteData, opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x38*/ {entity.OpCreateDWordField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
||||||
|
/*0x39*/ {entity.OpCreateWordField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
||||||
|
/*0x3a*/ {entity.OpCreateByteField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
||||||
|
/*0x3b*/ {entity.OpCreateBitField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
||||||
|
/*0x3c*/ {entity.OpObjectType, objTypeAny, opFlagNone, makeArg1(opArgSuperName)},
|
||||||
|
/*0x3d*/ {entity.OpCreateQWordField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)},
|
||||||
|
/*0x3e*/ {entity.OpLand, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x3f*/ {entity.OpLor, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x40*/ {entity.OpLnot, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgTermObj)},
|
||||||
|
/*0x41*/ {entity.OpLEqual, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x42*/ {entity.OpLGreater, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x43*/ {entity.OpLLess, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x44*/ {entity.OpToBuffer, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x45*/ {entity.OpToDecimalString, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x46*/ {entity.OpToHexString, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x47*/ {entity.OpToInteger, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x48*/ {entity.OpToString, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x49*/ {entity.OpCopyObject, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgSimpleName)},
|
||||||
|
/*0x4a*/ {entity.OpMid, objTypeAny, opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTermObj, opArgTarget)},
|
||||||
|
/*0x4b*/ {entity.OpContinue, objTypeAny, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x4c*/ {entity.OpIf, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTermList)},
|
||||||
|
/*0x4d*/ {entity.OpElse, objTypeAny, opFlagExecutable | opFlagScoped, makeArg1(opArgTermList)},
|
||||||
|
/*0x4e*/ {entity.OpWhile, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTermList)},
|
||||||
|
/*0x4f*/ {entity.OpNoop, objTypeAny, opFlagNoOp, makeArg0()},
|
||||||
|
/*0x50*/ {entity.OpReturn, objTypeAny, opFlagReturn, makeArg1(opArgTermObj)},
|
||||||
|
/*0x51*/ {entity.OpBreak, objTypeAny, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x52*/ {entity.OpBreakPoint, objTypeAny, opFlagNoOp, makeArg0()},
|
||||||
|
/*0x53*/ {entity.OpOnes, objTypeInteger, opFlagConstant, makeArg0()},
|
||||||
|
/*0x54*/ {entity.OpMutex, objTypeMutex, opFlagNamed, makeArg2(opArgNameString, opArgByteData)},
|
||||||
|
/*0x55*/ {entity.OpEvent, objTypeEvent, opFlagNamed, makeArg1(opArgNameString)},
|
||||||
|
/*0x56*/ {entity.OpCondRefOf, objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgSuperName)},
|
||||||
|
/*0x57*/ {entity.OpCreateField, objTypeBufferField, opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTermObj, opArgNameString)},
|
||||||
|
/*0x58*/ {entity.OpLoadTable, objTypeAny, opFlagExecutable, makeArg7(opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x59*/ {entity.OpLoad, objTypeAny, opFlagExecutable, makeArg2(opArgNameString, opArgSuperName)},
|
||||||
|
/*0x5a*/ {entity.OpStall, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
||||||
|
/*0x5b*/ {entity.OpSleep, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
||||||
|
/*0x5c*/ {entity.OpAcquire, objTypeAny, opFlagExecutable, makeArg2(opArgNameString, opArgSuperName)},
|
||||||
|
/*0x5d*/ {entity.OpSignal, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)},
|
||||||
|
/*0x5e*/ {entity.OpWait, objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgTermObj)},
|
||||||
|
/*0x5f*/ {entity.OpReset, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x60*/ {entity.OpRelease, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x61*/ {entity.OpFromBCD, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x62*/ {entity.OpToBCD, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)},
|
||||||
|
/*0x63*/ {entity.OpUnload, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)},
|
||||||
|
/*0x64*/ {entity.OpRevision, objTypeInteger, opFlagConstant | opFlagExecutable, makeArg0()},
|
||||||
|
/*0x65*/ {entity.OpDebug, objTypeLocalReference, opFlagExecutable, makeArg0()},
|
||||||
|
/*0x66*/ {entity.OpFatal, objTypeAny, opFlagExecutable, makeArg3(opArgByteData, opArgDword, opArgTermObj)},
|
||||||
|
/*0x67*/ {entity.OpTimer, objTypeAny, opFlagNone, makeArg0()},
|
||||||
|
/*0x68*/ {entity.OpOpRegion, objTypeRegion, opFlagNamed, makeArg4(opArgNameString, opArgByteData, opArgTermObj, opArgTermObj)},
|
||||||
|
/*0x69*/ {entity.OpField, objTypeAny, opFlagNone, makeArg3(opArgNameString, opArgByteData, opArgFieldList)},
|
||||||
|
/*0x6a*/ {entity.OpDevice, objTypeDevice, opFlagNamed | opFlagScoped, makeArg2(opArgNameString, opArgTermList)},
|
||||||
|
/*0x6b*/ {entity.OpProcessor, objTypeProcessor, opFlagNamed | opFlagScoped, makeArg5(opArgNameString, opArgByteData, opArgDword, opArgByteData, opArgTermList)},
|
||||||
|
/*0x6c*/ {entity.OpPowerRes, objTypePower, opFlagNamed | opFlagScoped, makeArg4(opArgNameString, opArgByteData, opArgWord, opArgTermList)},
|
||||||
|
/*0x6d*/ {entity.OpThermalZone, objTypeThermal, opFlagNamed | opFlagScoped, makeArg2(opArgNameString, opArgTermList)},
|
||||||
|
/*0x6e*/ {entity.OpIndexField, objTypeAny, opFlagNone, makeArg4(opArgNameString, opArgNameString, opArgByteData, opArgFieldList)},
|
||||||
|
/*0x6f*/ {entity.OpBankField, objTypeLocalBankField, opFlagNamed, makeArg5(opArgNameString, opArgNameString, opArgTermObj, opArgByteData, opArgFieldList)},
|
||||||
|
/*0x70*/ {entity.OpDataRegion, objTypeLocalRegionField, opFlagNamed, makeArg4(opArgNameString, opArgTermObj, opArgTermObj, opArgTermObj)},
|
||||||
|
}
|
||||||
|
|
||||||
|
// opcodeMap maps an AML opcode to an entry in the opcode table. Entries with
|
||||||
|
// the value 0xff indicate an invalid/unsupported opcode.
|
||||||
|
var opcodeMap = [256]uint8{
|
||||||
|
/* 0 1 2 3 4 5 6 7*/
|
||||||
|
/*0x00 - 0x07*/ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x02, 0xff,
|
||||||
|
/*0x08 - 0x0f*/ 0x03, 0xff, 0x04, 0x05, 0x06, 0x07, 0x08, 0xff,
|
||||||
|
/*0x10 - 0x17*/ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xff, 0xff,
|
||||||
|
/*0x18 - 0x1f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x20 - 0x27*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x28 - 0x2f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x30 - 0x37*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x38 - 0x3f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x40 - 0x47*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x48 - 0x4f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x50 - 0x57*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x58 - 0x5f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x60 - 0x67*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
|
||||||
|
/*0x68 - 0x6f*/ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0xff,
|
||||||
|
/*0x70 - 0x77*/ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
|
||||||
|
/*0x78 - 0x7f*/ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
|
||||||
|
/*0x80 - 0x87*/ 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
|
||||||
|
/*0x88 - 0x8f*/ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d,
|
||||||
|
/*0x90 - 0x97*/ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
|
||||||
|
/*0x98 - 0x9f*/ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x49, 0x4a, 0x4b,
|
||||||
|
/*0xa0 - 0xa7*/ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0xff, 0xff,
|
||||||
|
/*0xa8 - 0xaf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xb0 - 0xb7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xb8 - 0xbf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xc0 - 0xc7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xc8 - 0xcf*/ 0xff, 0xff, 0xff, 0xff, 0x52, 0xff, 0xff, 0xff,
|
||||||
|
/*0xd0 - 0xd7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xd8 - 0xdf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xe0 - 0xe7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xe8 - 0xef*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xf0 - 0xf7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xf8 - 0xff*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53,
|
||||||
|
}
|
||||||
|
|
||||||
|
// extendedOpcodeMap maps an AML extended opcode (extOpPrefix + code) to an
|
||||||
|
// entry in the opcode table. Entries with the value 0xff indicate an
|
||||||
|
// invalid/unsupported opcode.
|
||||||
|
var extendedOpcodeMap = [256]uint8{
|
||||||
|
/* 0 1 2 3 4 5 6 7*/
|
||||||
|
/*0x00 - 0x07*/ 0xff, 0x54, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x08 - 0x0f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x10 - 0x17*/ 0xff, 0xff, 0x56, 0x57, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x18 - 0x1f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x58,
|
||||||
|
/*0x20 - 0x27*/ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
|
||||||
|
/*0x28 - 0x2f*/ 0x61, 0x62, 0x63, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x30 - 0x37*/ 0x64, 0x65, 0x66, 0x67, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x38 - 0x3f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x40 - 0x47*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x48 - 0x4f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x50 - 0x57*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x58 - 0x5f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x60 - 0x67*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x68 - 0x6f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x70 - 0x77*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x78 - 0x7f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x80 - 0x87*/ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||||
|
/*0x88 - 0x8f*/ 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x90 - 0x97*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0x98 - 0x9f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xa0 - 0xa7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xa8 - 0xaf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xb0 - 0xb7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xb8 - 0xbf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xc0 - 0xc7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xc8 - 0xcf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xd0 - 0xd7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xd8 - 0xdf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xe0 - 0xe7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xe8 - 0xef*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xf0 - 0xf7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||||
|
/*0xf8 - 0xff*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53,
|
||||||
|
}
|
35
src/gopheros/device/acpi/aml/parser/opcode_test.go
Normal file
35
src/gopheros/device/acpi/aml/parser/opcode_test.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package parser
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// TestFindUnmappedOpcodes is a helper test that pinpoints opcodes that have
|
||||||
|
// not yet been mapped via an opcode table.
|
||||||
|
func TestFindUnmappedOpcodes(t *testing.T) {
|
||||||
|
for opIndex, opRef := range opcodeMap {
|
||||||
|
if opRef != badOpcode {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for tabIndex, info := range opcodeTable {
|
||||||
|
if uint16(info.op) == uint16(opIndex) {
|
||||||
|
t.Errorf("set opcodeMap[0x%02x] = 0x%02x // %s\n", opIndex, tabIndex, info.op.String())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for opIndex, opRef := range extendedOpcodeMap {
|
||||||
|
// 0xff (opOnes) is defined in opcodeTable
|
||||||
|
if opRef != badOpcode || opIndex == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
opIndex += 0xff
|
||||||
|
for tabIndex, info := range opcodeTable {
|
||||||
|
if uint16(info.op) == uint16(opIndex) {
|
||||||
|
t.Errorf("set extendedOpcodeMap[0x%02x] = 0x%02x // %s\n", opIndex-0xff, tabIndex, info.op.String())
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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"
|
||||||
@ -13,28 +14,30 @@ var (
|
|||||||
errResolvingEntities = &kernel.Error{Module: "acpi_aml_parser", Message: "AML bytecode contains unresolvable entities"}
|
errResolvingEntities = &kernel.Error{Module: "acpi_aml_parser", Message: "AML bytecode contains unresolvable entities"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type parseOpt uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
parseOptSkipMethodBodies parseOpt = iota
|
||||||
|
parseOptParseMethodBodies
|
||||||
|
)
|
||||||
|
|
||||||
// Parser implements an AML parser.
|
// Parser implements an AML parser.
|
||||||
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
|
||||||
|
|
||||||
// methodArgCount is initialized in a pre-parse step with the names and expected
|
parseOptions parseOpt
|
||||||
// number of args for each function declaration. This is required as function
|
|
||||||
// invocations do not employ any mechanism to indicate the number of args that
|
|
||||||
// need to be parsed. Moreover, the spec allows for forward function declarations.
|
|
||||||
methodArgCount map[string]uint8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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,
|
||||||
methodArgCount: make(map[string]uint8),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,12 +53,9 @@ func (p *Parser) ParseAML(tableHandle uint8, tableName string, header *table.SDT
|
|||||||
uint32(unsafe.Sizeof(table.SDTHeader{})),
|
uint32(unsafe.Sizeof(table.SDTHeader{})),
|
||||||
)
|
)
|
||||||
|
|
||||||
// Pass 1: scan bytecode and locate all method declarations. This allows us to
|
// Pass 1: decode bytecode and build entitites without recursing into
|
||||||
// properly parse the arguments to method invocations at pass 2 even if the
|
// function bodies.
|
||||||
// the name of the invoked method is a forward reference.
|
p.parseOptions = parseOptSkipMethodBodies
|
||||||
p.detectMethodDeclarations()
|
|
||||||
|
|
||||||
// Pass 2: decode bytecode and build entitites
|
|
||||||
p.scopeStack = nil
|
p.scopeStack = nil
|
||||||
p.scopeEnter(p.root)
|
p.scopeEnter(p.root)
|
||||||
if !p.parseObjList(header.Length) {
|
if !p.parseObjList(header.Length) {
|
||||||
@ -65,25 +65,33 @@ func (p *Parser) ParseAML(tableHandle uint8, tableName string, header *table.SDT
|
|||||||
}
|
}
|
||||||
p.scopeExit()
|
p.scopeExit()
|
||||||
|
|
||||||
// Pass 3: check parents and resolve forward references
|
// Pass 2: parse method bodies, check entity parents and resolve all
|
||||||
|
// 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
|
if method, isMethod := ent.(*entity.Method); isMethod {
|
||||||
if _, isMethod := ent.(*Method); isMethod {
|
resolveFailed = resolveFailed || !p.parseMethodBody(method)
|
||||||
|
|
||||||
|
// Don't recurse into method bodies; their contents
|
||||||
|
// will be lazilly resolved by the VM
|
||||||
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
|
||||||
resolveFailed = true
|
if lazyRef, ok := ent.(entity.LazyRefResolver); ok {
|
||||||
return false
|
if err := lazyRef.ResolveSymbolRefs(p.root); err != nil {
|
||||||
|
kfmt.Fprintf(p.errWriter, "%s\n", err.Message)
|
||||||
|
resolveFailed = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
@ -96,57 +104,6 @@ func (p *Parser) ParseAML(tableHandle uint8, tableName string, header *table.SDT
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// detectMethodDeclarations scans the AML byte-stream looking for function
|
|
||||||
// declarations. For each discovered function, the method will parse its flags
|
|
||||||
// and update the methodArgCount map with the number of required arguments.
|
|
||||||
func (p *Parser) detectMethodDeclarations() {
|
|
||||||
var (
|
|
||||||
next *opcodeInfo
|
|
||||||
method string
|
|
||||||
startOffset = p.r.Offset()
|
|
||||||
curOffset, pkgLen uint32
|
|
||||||
flags uint64
|
|
||||||
ok bool
|
|
||||||
)
|
|
||||||
|
|
||||||
for !p.r.EOF() {
|
|
||||||
if next, ok = p.nextOpcode(); !ok {
|
|
||||||
// Skip one byte to the right and try again. Maybe we are stuck inside
|
|
||||||
// the contents of a string or buffer
|
|
||||||
_, _ = p.r.ReadByte()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if next.op != opMethod {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse pkg len; if this fails then this is not a method declaration
|
|
||||||
curOffset = p.r.Offset()
|
|
||||||
if pkgLen, ok = p.parsePkgLength(); !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse method name
|
|
||||||
if method, ok = p.parseNameString(); !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// The next byte encodes the method flags which also contains the arg count
|
|
||||||
// at bits 0:2
|
|
||||||
if flags, ok = p.parseNumConstant(1); !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
p.methodArgCount[method] = uint8(flags) & 0x7
|
|
||||||
|
|
||||||
// At this point we can use the pkg length to skip over the term list
|
|
||||||
p.r.SetOffset(curOffset + pkgLen)
|
|
||||||
}
|
|
||||||
|
|
||||||
p.r.SetOffset(startOffset)
|
|
||||||
}
|
|
||||||
|
|
||||||
// parseObjList tries to parse an AML object list. Object lists are usually
|
// parseObjList tries to parse an AML object list. Object lists are usually
|
||||||
// specified together with a pkgLen block which is used to calculate the max
|
// specified together with a pkgLen block which is used to calculate the max
|
||||||
// read offset that the parser may reach.
|
// read offset that the parser may reach.
|
||||||
@ -169,8 +126,7 @@ func (p *Parser) parseObj() bool {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// If we cannot decode the next opcode then this may be a method
|
// If we cannot decode the next opcode then this may be a method
|
||||||
// invocation or a name reference. If neither is the case, we need to
|
// invocation or a name reference.
|
||||||
// rewind the stream and parse a method invocation before giving up.
|
|
||||||
curOffset = p.r.Offset()
|
curOffset = p.r.Offset()
|
||||||
if info, ok = p.nextOpcode(); !ok {
|
if info, ok = p.nextOpcode(); !ok {
|
||||||
p.r.SetOffset(curOffset)
|
p.r.SetOffset(curOffset)
|
||||||
@ -187,11 +143,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 +173,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 +207,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 +224,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 +232,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:
|
||||||
return false
|
obj = entity.NewThermalZone(p.tableHandle, name)
|
||||||
}
|
case entity.OpMethod:
|
||||||
m.argCount = (uint8(flags) & 0x7) // bits[0:2]
|
obj = entity.NewMethod(p.tableHandle, name)
|
||||||
m.serialized = (uint8(flags)>>3)&0x1 == 0x1 // bit 3
|
default:
|
||||||
m.syncLevel = (uint8(flags) >> 4) & 0xf // bits[4:7]
|
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
|
||||||
obj = m
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse any args that follow the name. The last arg is always an ArgTermList
|
||||||
parent.Append(obj)
|
parent.Append(obj)
|
||||||
p.scopeEnter(obj)
|
for argIndex := uint8(1); argIndex < info.argFlags.argCount(); argIndex++ {
|
||||||
ok = p.parseObjList(maxReadOffset)
|
if !p.parseArg(info, obj, argIndex, info.argFlags.arg(argIndex), maxReadOffset) {
|
||||||
p.scopeExit()
|
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 (
|
var (
|
||||||
arg interface{}
|
arg interface{}
|
||||||
ok bool
|
ok bool
|
||||||
@ -356,22 +303,33 @@ func (p *Parser) parseArg(info *opcodeInfo, obj Entity, argIndex uint8, argType
|
|||||||
case opArgTarget:
|
case opArgTarget:
|
||||||
arg, ok = p.parseTarget()
|
arg, ok = p.parseTarget()
|
||||||
case opArgTermList:
|
case opArgTermList:
|
||||||
|
// If this is a method and the SkipMethodBodies option is set
|
||||||
|
// then record the body start and end offset so we can parse
|
||||||
|
// it at a later stage.
|
||||||
|
if method, isMethod := obj.(*entity.Method); isMethod && p.parseOptions == parseOptSkipMethodBodies {
|
||||||
|
method.BodyStartOffset = p.r.Offset()
|
||||||
|
method.BodyEndOffset = maxReadOffset
|
||||||
|
p.r.SetOffset(maxReadOffset)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// 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,48 +346,90 @@ 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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// parseMethodBody parses the entities that make up a method's body. After the
|
||||||
|
// entire AML tree has been parsed, the parser makes a second pass and calls
|
||||||
|
// parseMethodBody for each Method entity.
|
||||||
|
//
|
||||||
|
// By deferring the parsing of the method body, we ensure that the parser can
|
||||||
|
// lookup the method declarations (even if forward declarations are used) for
|
||||||
|
// each method invocation. As method declarations contain information about the
|
||||||
|
// expected argument count, the parser can use this information to properly
|
||||||
|
// parse the invocation arguments. For more details see: parseNamedRef
|
||||||
|
func (p *Parser) parseMethodBody(method *entity.Method) bool {
|
||||||
|
p.parseOptions = parseOptParseMethodBodies
|
||||||
|
p.scopeEnter(method)
|
||||||
|
p.r.SetOffset(method.BodyStartOffset)
|
||||||
|
ok := p.parseArg(&opcodeTable[methodOpInfoIndex], method, 2, opArgTermList, method.BodyEndOffset)
|
||||||
|
p.scopeExit()
|
||||||
|
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
// parseNamedRef attempts to parse either a method invocation or a named
|
// parseNamedRef attempts to parse either a method invocation or a named
|
||||||
// reference. As AML allows for forward references, the actual contents for
|
// reference. As AML allows for forward references, the actual contents for
|
||||||
// this entity will not be known until the entire AML stream has been parsed.
|
// this entity will not be known until the entire AML stream has been parsed.
|
||||||
@ -444,29 +444,31 @@ func (p *Parser) parseNamedRef() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
// Check if this is a method invocation
|
||||||
curOffset uint32
|
ent := entity.FindInScope(p.scopeCurrent(), p.root, name)
|
||||||
argIndex uint8
|
if methodDef, isMethod := ent.(*entity.Method); isMethod {
|
||||||
arg Entity
|
var (
|
||||||
argList []interface{}
|
curOffset uint32
|
||||||
)
|
argIndex uint8
|
||||||
|
arg entity.Entity
|
||||||
|
argList []interface{}
|
||||||
|
)
|
||||||
|
|
||||||
if argCount, isMethod := p.methodArgCount[name]; isMethod {
|
for argIndex < methodDef.ArgCount && !p.r.EOF() {
|
||||||
for argIndex < argCount && !p.r.EOF() {
|
|
||||||
// Peek next opcode
|
// Peek next opcode
|
||||||
curOffset = p.r.Offset()
|
curOffset = p.r.Offset()
|
||||||
nextOpcode, ok := p.nextOpcode()
|
nextOpcode, ok := p.nextOpcode()
|
||||||
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,19 +483,16 @@ func (p *Parser) parseNamedRef() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check whether all expected arguments have been parsed
|
// Check whether all expected arguments have been parsed
|
||||||
if argIndex != argCount {
|
if argIndex != methodDef.ArgCount {
|
||||||
kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] unexpected arglist end for method %s invocation: expected %d; got %d\n", p.tableName, p.r.Offset(), name, argCount, argIndex)
|
kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] unexpected arglist end for method %s invocation: expected %d; got %d\n", p.tableName, p.r.Offset(), name, methodDef.ArgCount, argIndex)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.scopeCurrent().Append(&methodInvocationEntity{
|
return p.scopeCurrent().Append(entity.NewInvocation(p.tableHandle, methodDef, argList))
|
||||||
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 +532,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;
|
ok bool
|
||||||
// for indexField,
|
|
||||||
name0, name1 string
|
|
||||||
flags uint64
|
|
||||||
|
|
||||||
ok bool
|
accessType entity.FieldAccessType
|
||||||
bitWidth uint32
|
|
||||||
curBitOffset uint32
|
|
||||||
accessAttrib FieldAccessAttrib
|
|
||||||
accessByteCount uint8
|
|
||||||
unitName string
|
|
||||||
)
|
|
||||||
|
|
||||||
switch op {
|
bitWidth uint32
|
||||||
case opField: // Field := PkgLength Region AccessFlags FieldList
|
curBitOffset uint32
|
||||||
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 +576,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 +586,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 +603,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 +617,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 +635,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 +784,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 +813,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 +828,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 +919,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)
|
||||||
@ -47,28 +36,78 @@ func TestParser(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestParsingOfMethodBodies(t *testing.T) {
|
||||||
|
var resolver = mockResolver{
|
||||||
|
tableFiles: []string{"parser-testsuite-fwd-decls-DSDT.aml"},
|
||||||
|
}
|
||||||
|
|
||||||
|
p := NewParser(os.Stderr, genDefaultScopes())
|
||||||
|
tableName := strings.Replace(resolver.tableFiles[0], ".aml", "", -1)
|
||||||
|
if err := p.ParseAML(0, tableName, resolver.LookupTable(tableName)); err != nil {
|
||||||
|
t.Fatalf("[%s]: %v", tableName, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Collect invocations
|
||||||
|
var invocations []*entity.Invocation
|
||||||
|
entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool {
|
||||||
|
if inv, isInv := ent.(*entity.Invocation); isInv {
|
||||||
|
invocations = append(invocations, inv)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
specs := []struct {
|
||||||
|
expParentName string
|
||||||
|
expArgCount int
|
||||||
|
}{
|
||||||
|
// Call to `\NST1`
|
||||||
|
{`\`, 1},
|
||||||
|
// Call to `\_SB.NST1`
|
||||||
|
{`_SB_`, 2},
|
||||||
|
// Call to `\NST1` (first argument of above invocation)
|
||||||
|
{`\`, 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
if exp, got := len(specs), len(invocations); exp != got {
|
||||||
|
t.Fatalf("expected parser to produce %d method invocations; got %d", exp, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
for specIndex, spec := range specs {
|
||||||
|
if got := invocations[specIndex].Method.Parent().Name(); got != spec.expParentName {
|
||||||
|
t.Errorf(
|
||||||
|
"[spec %d] expected invocation to target %s.%s; got %s.%s",
|
||||||
|
specIndex,
|
||||||
|
spec.expParentName, invocations[specIndex].Method.Name(),
|
||||||
|
got, invocations[specIndex].Method.Name(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := len(invocations[specIndex].Args()); got != spec.expArgCount {
|
||||||
|
t.Errorf(
|
||||||
|
"[spec %d] expected invocation to target %s.%s to receive %d args; got %d",
|
||||||
|
specIndex,
|
||||||
|
spec.expParentName, invocations[specIndex].Method.Name(), spec.expArgCount,
|
||||||
|
got,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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 +117,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 +141,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 +203,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 +221,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 +237,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 +249,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 +263,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 +279,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 +292,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 +306,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 +323,76 @@ 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("incorrect args for method", func(t *testing.T) {
|
||||||
p.root = &scopeEntity{op: opScope, name: `\`}
|
p.root = entity.NewScope(entity.OpScope, 42, `\`)
|
||||||
p.methodArgCount = map[string]uint8{
|
|
||||||
"MTHD": 10,
|
methodDecl := entity.NewMethod(42, "MTHD")
|
||||||
}
|
methodDecl.ArgCount = 5
|
||||||
|
p.root.Append(methodDecl)
|
||||||
|
|
||||||
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 +404,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 +556,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 +610,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")
|
||||||
@ -585,77 +663,6 @@ func TestParserErrorHandling(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDetectMethodDeclarations(t *testing.T) {
|
|
||||||
p := &Parser{
|
|
||||||
errWriter: ioutil.Discard,
|
|
||||||
}
|
|
||||||
|
|
||||||
validMethod := []byte{
|
|
||||||
byte(opMethod),
|
|
||||||
5, // pkgLen
|
|
||||||
'M', 'T', 'H', 'D',
|
|
||||||
2, // flags (2 args)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run("success", func(t *testing.T) {
|
|
||||||
mockParserPayload(p, validMethod)
|
|
||||||
p.methodArgCount = make(map[string]uint8)
|
|
||||||
p.detectMethodDeclarations()
|
|
||||||
|
|
||||||
argCount, inMap := p.methodArgCount["MTHD"]
|
|
||||||
if !inMap {
|
|
||||||
t.Error(`detectMethodDeclarations failed to parse method "MTHD"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp := uint8(2); argCount != exp {
|
|
||||||
t.Errorf(`expected arg count for "MTHD" to be %d; got %d`, exp, argCount)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("bad pkgLen", func(t *testing.T) {
|
|
||||||
mockParserPayload(p, []byte{
|
|
||||||
byte(opMethod),
|
|
||||||
// lead byte bits (6:7) indicate 1 extra byte that is missing
|
|
||||||
byte(1 << 6),
|
|
||||||
})
|
|
||||||
|
|
||||||
p.methodArgCount = make(map[string]uint8)
|
|
||||||
p.detectMethodDeclarations()
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("error parsing namestring", func(t *testing.T) {
|
|
||||||
mockParserPayload(p, append([]byte{
|
|
||||||
byte(opMethod),
|
|
||||||
byte(5), // pkgLen
|
|
||||||
10, // bogus char, not part of namestring
|
|
||||||
}, validMethod...))
|
|
||||||
|
|
||||||
p.methodArgCount = make(map[string]uint8)
|
|
||||||
p.detectMethodDeclarations()
|
|
||||||
|
|
||||||
argCount, inMap := p.methodArgCount["MTHD"]
|
|
||||||
if !inMap {
|
|
||||||
t.Error(`detectMethodDeclarations failed to parse method "MTHD"`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if exp := uint8(2); argCount != exp {
|
|
||||||
t.Errorf(`expected arg count for "MTHD" to be %d; got %d`, exp, argCount)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("error parsing method flags", func(t *testing.T) {
|
|
||||||
mockParserPayload(p, []byte{
|
|
||||||
byte(opMethod),
|
|
||||||
byte(5), // pkgLen
|
|
||||||
'F', 'O', 'O', 'F',
|
|
||||||
// Missing flag byte
|
|
||||||
})
|
|
||||||
|
|
||||||
p.methodArgCount = make(map[string]uint8)
|
|
||||||
p.detectMethodDeclarations()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func mockParserPayload(p *Parser, payload []byte) *table.SDTHeader {
|
func mockParserPayload(p *Parser, payload []byte) *table.SDTHeader {
|
||||||
resolver := fixedPayloadResolver{payload}
|
resolver := fixedPayloadResolver{payload}
|
||||||
header := resolver.LookupTable("DSDT")
|
header := resolver.LookupTable("DSDT")
|
||||||
@ -678,7 +685,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 +716,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
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package aml
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
@ -80,5 +80,8 @@ func (r *amlStreamReader) Offset() uint32 {
|
|||||||
|
|
||||||
// SetOffset sets the reader offset to the supplied value.
|
// SetOffset sets the reader offset to the supplied value.
|
||||||
func (r *amlStreamReader) SetOffset(off uint32) {
|
func (r *amlStreamReader) SetOffset(off uint32) {
|
||||||
|
if max := uint32(len(r.data)); off > max {
|
||||||
|
off = max
|
||||||
|
}
|
||||||
r.offset = off
|
r.offset = off
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
package aml
|
package parser
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
@ -1,294 +0,0 @@
|
|||||||
package aml
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestScopeVisit(t *testing.T) {
|
|
||||||
scopeMap := genTestScopes()
|
|
||||||
root := scopeMap[`\`].(*scopeEntity)
|
|
||||||
|
|
||||||
keepRecursing := func(Entity) bool { return true }
|
|
||||||
stopRecursing := func(Entity) bool { return false }
|
|
||||||
|
|
||||||
// Append special entities under IDE0
|
|
||||||
ide := scopeMap["IDE0"].(*scopeEntity)
|
|
||||||
ide.Append(&Device{})
|
|
||||||
ide.Append(&namedEntity{op: opProcessor})
|
|
||||||
ide.Append(&namedEntity{op: opProcessor})
|
|
||||||
ide.Append(&namedEntity{op: opPowerRes})
|
|
||||||
ide.Append(&namedEntity{op: opPowerRes})
|
|
||||||
ide.Append(&namedEntity{op: opPowerRes})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&namedEntity{op: opThermalZone})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&Method{})
|
|
||||||
ide.Append(&methodInvocationEntity{
|
|
||||||
unnamedEntity: unnamedEntity{
|
|
||||||
args: []interface{}{
|
|
||||||
&constEntity{val: uint64(1)},
|
|
||||||
&constEntity{val: uint64(2)},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
specs := []struct {
|
|
||||||
searchType EntityType
|
|
||||||
keepRecursingFn func(Entity) bool
|
|
||||||
wantHits int
|
|
||||||
}{
|
|
||||||
{EntityTypeAny, keepRecursing, 24},
|
|
||||||
{EntityTypeAny, stopRecursing, 1},
|
|
||||||
{
|
|
||||||
EntityTypeAny,
|
|
||||||
func(ent Entity) bool {
|
|
||||||
// Stop recursing after visiting the methodInvocationEntity
|
|
||||||
_, isInv := ent.(*methodInvocationEntity)
|
|
||||||
return !isInv
|
|
||||||
},
|
|
||||||
22,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
EntityTypeAny,
|
|
||||||
func(ent Entity) bool {
|
|
||||||
// Stop recursing after visiting the first constEntity
|
|
||||||
_, isConst := ent.(*constEntity)
|
|
||||||
return !isConst
|
|
||||||
},
|
|
||||||
23,
|
|
||||||
},
|
|
||||||
{EntityTypeDevice, keepRecursing, 1},
|
|
||||||
{EntityTypeProcessor, keepRecursing, 2},
|
|
||||||
{EntityTypePowerResource, keepRecursing, 3},
|
|
||||||
{EntityTypeThermalZone, keepRecursing, 4},
|
|
||||||
{EntityTypeMethod, keepRecursing, 5},
|
|
||||||
}
|
|
||||||
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
var hits int
|
|
||||||
scopeVisit(0, root, spec.searchType, func(_ int, obj Entity) bool {
|
|
||||||
hits++
|
|
||||||
return spec.keepRecursingFn(obj)
|
|
||||||
})
|
|
||||||
|
|
||||||
if hits != spec.wantHits {
|
|
||||||
t.Errorf("[spec %d] expected visitor to be called %d times; got %d", specIndex, spec.wantHits, hits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScopeResolvePath(t *testing.T) {
|
|
||||||
scopeMap := genTestScopes()
|
|
||||||
|
|
||||||
specs := []struct {
|
|
||||||
curScope ScopeEntity
|
|
||||||
pathExpr string
|
|
||||||
wantParent Entity
|
|
||||||
wantName string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_`,
|
|
||||||
scopeMap[`\`],
|
|
||||||
"_SB_",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^FOO`,
|
|
||||||
scopeMap[`PCI0`],
|
|
||||||
"FOO",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^^FOO`,
|
|
||||||
scopeMap[`_SB_`],
|
|
||||||
"FOO",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`_ADR`,
|
|
||||||
scopeMap[`IDE0`],
|
|
||||||
"_ADR",
|
|
||||||
},
|
|
||||||
// Paths with dots
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_.PCI0.IDE0._ADR`,
|
|
||||||
scopeMap[`IDE0`],
|
|
||||||
"_ADR",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`IDE0._ADR`,
|
|
||||||
scopeMap[`IDE0`],
|
|
||||||
"_ADR",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`_CRS`,
|
|
||||||
scopeMap[`PCI0`],
|
|
||||||
"_CRS",
|
|
||||||
},
|
|
||||||
// Bad queries
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`FOO.BAR.BAZ`,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
``,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`\`,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`^^^^^^^^^BADPATH`,
|
|
||||||
nil,
|
|
||||||
"",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
root := scopeMap[`\`].(*scopeEntity)
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
gotParent, gotName := scopeResolvePath(spec.curScope, root, spec.pathExpr)
|
|
||||||
if !reflect.DeepEqual(gotParent, spec.wantParent) {
|
|
||||||
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.wantParent, gotParent)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if gotName != spec.wantName {
|
|
||||||
t.Errorf("[spec %d] expected lookup to return node name %q; got %q", specIndex, spec.wantName, gotName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestScopeFind(t *testing.T) {
|
|
||||||
scopeMap := genTestScopes()
|
|
||||||
|
|
||||||
specs := []struct {
|
|
||||||
curScope ScopeEntity
|
|
||||||
lookup string
|
|
||||||
want Entity
|
|
||||||
}{
|
|
||||||
// Search rules do not apply for these cases
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
`\`,
|
|
||||||
scopeMap[`\`],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["PCI0"].(*scopeEntity),
|
|
||||||
"IDE0._ADR",
|
|
||||||
scopeMap["_ADR"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"^^PCI0.IDE0._ADR",
|
|
||||||
scopeMap["_ADR"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_.PCI0.IDE0._ADR`,
|
|
||||||
scopeMap["_ADR"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`\_SB_.PCI0`,
|
|
||||||
scopeMap["PCI0"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^`,
|
|
||||||
scopeMap["PCI0"],
|
|
||||||
},
|
|
||||||
// Bad queries
|
|
||||||
{
|
|
||||||
scopeMap["_SB_"].(*scopeEntity),
|
|
||||||
"PCI0.USB._CRS",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"^^^^^^^^^^^^^^^^^^^",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
`^^^^^^^^^^^FOO`,
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"FOO",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"",
|
|
||||||
nil,
|
|
||||||
},
|
|
||||||
// Search rules apply for these cases
|
|
||||||
{
|
|
||||||
scopeMap["IDE0"].(*scopeEntity),
|
|
||||||
"_CRS",
|
|
||||||
scopeMap["_CRS"],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
root := scopeMap[`\`].(*scopeEntity)
|
|
||||||
for specIndex, spec := range specs {
|
|
||||||
if got := scopeFind(spec.curScope, root, spec.lookup); !reflect.DeepEqual(got, spec.want) {
|
|
||||||
t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func genTestScopes() map[string]Entity {
|
|
||||||
// Setup the example tree from page 252 of the acpi 6.2 spec
|
|
||||||
// \
|
|
||||||
// SB
|
|
||||||
// \
|
|
||||||
// PCI0
|
|
||||||
// | _CRS
|
|
||||||
// \
|
|
||||||
// IDE0
|
|
||||||
// | _ADR
|
|
||||||
ideScope := &scopeEntity{name: `IDE0`}
|
|
||||||
pciScope := &scopeEntity{name: `PCI0`}
|
|
||||||
sbScope := &scopeEntity{name: `_SB_`}
|
|
||||||
rootScope := &scopeEntity{name: `\`}
|
|
||||||
|
|
||||||
adr := &namedEntity{name: `_ADR`}
|
|
||||||
crs := &namedEntity{name: `_CRS`}
|
|
||||||
|
|
||||||
// Setup tree
|
|
||||||
ideScope.Append(adr)
|
|
||||||
pciScope.Append(crs)
|
|
||||||
pciScope.Append(ideScope)
|
|
||||||
sbScope.Append(pciScope)
|
|
||||||
rootScope.Append(sbScope)
|
|
||||||
|
|
||||||
return map[string]Entity{
|
|
||||||
"IDE0": ideScope,
|
|
||||||
"PCI0": pciScope,
|
|
||||||
"_SB_": sbScope,
|
|
||||||
"\\": rootScope,
|
|
||||||
"_ADR": adr,
|
|
||||||
"_CRS": crs,
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
@ -6,112 +6,147 @@
|
|||||||
// virtualbox.
|
// virtualbox.
|
||||||
DefinitionBlock ("parser-testsuite-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002)
|
DefinitionBlock ("parser-testsuite-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002)
|
||||||
{
|
{
|
||||||
OperationRegion (DBG0, SystemIO, 0x3000, 0x04)
|
OperationRegion (DBG0, SystemIO, 0x3000, 0x04)
|
||||||
Field (DBG0, ByteAcc, NoLock, Preserve)
|
Field (DBG0, ByteAcc, NoLock, Preserve)
|
||||||
{
|
|
||||||
DHE1, 8
|
|
||||||
}
|
|
||||||
|
|
||||||
Device (DRV0)
|
|
||||||
{
|
{
|
||||||
Name (_ADR, Ones)
|
DHE1, 8
|
||||||
|
|
||||||
// named entity containing qword const
|
|
||||||
Name (H15F, 0xBADC0FEEDEADC0DE)
|
|
||||||
Method (_GTF, 0, NotSerialized) // _GTF: Get Task File
|
|
||||||
{
|
|
||||||
Return (H15F)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// example from p. 268 of ACPI 6.2 spec
|
Device (DRV0)
|
||||||
Scope(\_SB){
|
{
|
||||||
OperationRegion(TOP1, GenericSerialBus, 0x00, 0x100) // GenericSerialBus device at command offset 0x00
|
Name (_ADR, Ones)
|
||||||
|
|
||||||
Name (SDB0, ResourceTemplate() {})
|
// named entity containing qword const
|
||||||
Field(TOP1, BufferAcc, NoLock, Preserve){
|
Name (H15F, 0xBADC0FEEDEADC0DE)
|
||||||
Connection(SDB0), // Use the Resource Descriptor defined above
|
Method (_GTF, 0, NotSerialized) // _GTF: Get Task File
|
||||||
AccessAs(BufferAcc, AttribWord),
|
{
|
||||||
FLD0, 8,
|
Return (H15F)
|
||||||
FLD1, 8
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Field(TOP1, BufferAcc, NoLock, Preserve){
|
// example from p. 268 of ACPI 6.2 spec
|
||||||
Connection(I2cSerialBus(0x5b,,100000,, "\\_SB",,,,RawDataBuffer(){3,9})),
|
Scope(\_SB){
|
||||||
AccessAs(BufferAcc, AttribBytes(4)),
|
OperationRegion(TOP1, GenericSerialBus, 0x00, 0x100) // GenericSerialBus device at command offset 0x00
|
||||||
FLD2, 8,
|
|
||||||
AccessAs(BufferAcc, AttribRawBytes(3)),
|
Name (SDB0, ResourceTemplate() {})
|
||||||
FLD3, 8,
|
Field(TOP1, BufferAcc, NoLock, Preserve){
|
||||||
AccessAs(BufferAcc, AttribRawProcessBytes(2)),
|
Connection(SDB0), // Use the Resource Descriptor defined above
|
||||||
FLD4, 8
|
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
|
// Other entity types
|
||||||
Event(HLO0)
|
Event(HLO0)
|
||||||
Mutex(MUT0,1)
|
Mutex(MUT0,1)
|
||||||
Signal(HLO0)
|
Signal(HLO0)
|
||||||
|
|
||||||
// Other executable bits
|
// Other executable bits
|
||||||
Method (EXE0, 1, Serialized)
|
Method (EXE0, 1, Serialized)
|
||||||
{
|
{
|
||||||
Local0 = Revision
|
Local0 = Revision
|
||||||
|
|
||||||
// NameString target
|
// NameString target
|
||||||
Local1 = SizeOf(GLB1)
|
Local1 = SizeOf(GLB1)
|
||||||
|
|
||||||
Local0 = "my-handle"
|
Local0 = "my-handle"
|
||||||
Load(DBG0, Local0)
|
Load(DBG0, Local0)
|
||||||
Unload(Local0)
|
Unload(Local0)
|
||||||
|
|
||||||
// Example from p. 951 of the spec
|
CreateBitField(Arg0, 0, WFL0)
|
||||||
Store (
|
if(Arg0==0){
|
||||||
LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD",
|
Return(WFL0)
|
||||||
Package () {0,"\\_SB.PCI0"}
|
}
|
||||||
), Local0
|
|
||||||
)
|
|
||||||
|
|
||||||
FromBCD(9, Arg0)
|
CreateByteField(Arg0, 0, WFL1)
|
||||||
ToBCD(Arg0, Local1)
|
if(Arg0==1){
|
||||||
|
Return(WFL1)
|
||||||
|
}
|
||||||
|
|
||||||
Breakpoint
|
CreateWordField(Arg0, 0, WFL2)
|
||||||
Debug = "test"
|
if(Arg0==2){
|
||||||
Fatal(0xf0, 0xdeadc0de, 1)
|
Return(WFL2)
|
||||||
|
}
|
||||||
|
|
||||||
Reset(HLO0)
|
CreateDwordField(Arg0, 0, WFL3)
|
||||||
|
if(Arg0==3){
|
||||||
|
Return(WFL3)
|
||||||
|
}
|
||||||
|
|
||||||
// Mutex support
|
CreateQwordField(Arg0, 0, WFL4)
|
||||||
Acquire(MUT0, 0xffff) // no timeout
|
if(Arg0==4){
|
||||||
Release(MUT0)
|
Return(WFL4)
|
||||||
|
}
|
||||||
|
|
||||||
// Signal/Wait
|
CreateField(Arg0, 0, 13, WFL5)
|
||||||
Wait(HLO0, 0xffff)
|
if(Arg0==5){
|
||||||
|
Return(WFL5)
|
||||||
|
}
|
||||||
|
|
||||||
// Get monotonic timer value
|
// Example from p. 951 of the spec
|
||||||
Local0 = Timer
|
Store (
|
||||||
|
LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD",
|
||||||
|
Package () {0,"\\_SB.PCI0"}
|
||||||
|
), Local0
|
||||||
|
)
|
||||||
|
|
||||||
CopyObject(Local0, Local1)
|
FromBCD(9, Arg0)
|
||||||
Return(ObjectType(Local1))
|
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
|
// BankField example from p. 899 of the spec
|
||||||
// Define a 256-byte operational region in SystemIO space and name it GIO0
|
// Define a 256-byte operational region in SystemIO space and name it GIO0
|
||||||
OperationRegion (GIO0, SystemIO, 0x125, 0x100)
|
OperationRegion (GIO0, SystemIO, 0x125, 0x100)
|
||||||
Field (GIO0, ByteAcc, NoLock, Preserve) {
|
Field (GIO0, ByteAcc, NoLock, Preserve) {
|
||||||
GLB1, 1,
|
GLB1, 1,
|
||||||
GLB2, 1,
|
GLB2, 1,
|
||||||
Offset (1), // Move to offset for byte 1
|
Offset (1), // Move to offset for byte 1
|
||||||
BNK1, 4
|
BNK1, 4
|
||||||
}
|
}
|
||||||
|
|
||||||
BankField (GIO0, BNK1, 0, ByteAcc, NoLock, Preserve) {
|
BankField (GIO0, BNK1, 0, ByteAcc, NoLock, Preserve) {
|
||||||
Offset (0x30),
|
Offset (0x30),
|
||||||
FET0, 1,
|
FET0, 1,
|
||||||
FET1, 1
|
FET1, 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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){}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
@ -1,10 +1,21 @@
|
|||||||
DefinitionBlock ("parser-testsuite-fwd-decls-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002)
|
DefinitionBlock ("parser-testsuite-fwd-decls-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002)
|
||||||
{
|
{
|
||||||
|
Scope(\_SB){
|
||||||
|
Method (NST1, 2, NotSerialized)
|
||||||
|
{
|
||||||
|
Return ("something")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Method(NST0, 1, NotSerialized)
|
Method(NST0, 1, NotSerialized)
|
||||||
{
|
{
|
||||||
// Invoke a method which has not been defined at the time the parser
|
// NST1 is declared after NST0 (forward declaration)
|
||||||
// reaches this block (forward declaration)
|
NST1(Arg0)
|
||||||
Return(NST1(Arg0))
|
|
||||||
|
// This version of NST1 is defined above and has a different signature.
|
||||||
|
// The parser should be able to resolve it to the correct method and
|
||||||
|
// parse the correct number of arguments
|
||||||
|
Return(\_SB.NST1(NST1(123), "arg"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// The declaration of NST1 in the AML stream occurs after the declaration
|
// The declaration of NST1 in the AML stream occurs after the declaration
|
||||||
|
Loading…
x
Reference in New Issue
Block a user