mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
acpi: define structs for basic AML entities
This commit is contained in:
parent
5171822ba6
commit
130e11507c
399
src/gopheros/device/acpi/aml/entity.go
Normal file
399
src/gopheros/device/acpi/aml/entity.go
Normal file
@ -0,0 +1,399 @@
|
|||||||
|
package aml
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gopheros/kernel/kfmt"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
type resolver interface {
|
||||||
|
Resolve(io.Writer, ScopeEntity) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type Entity interface {
|
||||||
|
getOpcode() opcode
|
||||||
|
setOpcode(opcode)
|
||||||
|
Name() string
|
||||||
|
Parent() ScopeEntity
|
||||||
|
setParent(ScopeEntity)
|
||||||
|
getArgs() []interface{}
|
||||||
|
setArg(uint8, interface{}) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type ScopeEntity interface {
|
||||||
|
Entity
|
||||||
|
|
||||||
|
Children() []Entity
|
||||||
|
Append(Entity) bool
|
||||||
|
removeLastChild() Entity
|
||||||
|
lastChild() Entity
|
||||||
|
}
|
||||||
|
|
||||||
|
// unnamedEntity defines an unnamed entity that can be attached to a parent scope.
|
||||||
|
type unnamedEntity struct {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// constEntity is an unnamedEntity 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 {
|
||||||
|
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 "" }
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
// scopeEntity is an optionally named entity that defines a scope.
|
||||||
|
type scopeEntity struct {
|
||||||
|
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) removeLastChild() Entity {
|
||||||
|
lastIndex := len(ent.children) - 1
|
||||||
|
child := ent.children[lastIndex]
|
||||||
|
ent.children = ent.children[:lastIndex]
|
||||||
|
return child
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 region which this field references.
|
||||||
|
regionName string
|
||||||
|
resolvedRegion *regionEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ent *fieldUnitEntity) Resolve(errWriter io.Writer, rootNs ScopeEntity) bool {
|
||||||
|
var ok bool
|
||||||
|
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
|
||||||
|
|
||||||
|
indexRegName string
|
||||||
|
indexReg *fieldUnitEntity
|
||||||
|
|
||||||
|
dataRegName string
|
||||||
|
dataReg *fieldUnitEntity
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ent *indexFieldEntity) Resolve(errWriter io.Writer, rootNs ScopeEntity) bool {
|
||||||
|
var ok bool
|
||||||
|
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 = scopeFind(ref.parent, rootNs, ref.targetName); ref.target == nil {
|
||||||
|
kfmt.Fprintf(errWriter, "could not resolve referenced symbol: %s\n", ref.targetName)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// methodInvocationEntity describes an AML method invocation.
|
||||||
|
type methodInvocationEntity struct {
|
||||||
|
unnamedEntity
|
||||||
|
|
||||||
|
methodDef *Method
|
||||||
|
}
|
||||||
|
|
||||||
|
// Method defines an invocable AML method.
|
||||||
|
type Method struct {
|
||||||
|
scopeEntity
|
||||||
|
|
||||||
|
argCount uint8
|
||||||
|
serialized bool
|
||||||
|
syncLevel uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Method) getOpcode() opcode { return opMethod }
|
||||||
|
|
||||||
|
// Device defines a device.
|
||||||
|
type Device struct {
|
||||||
|
scopeEntity
|
||||||
|
|
||||||
|
// The methodMap keeps track of all methods exposed by this device.
|
||||||
|
methodMap map[string]*Method
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Device) getOpcode() opcode { return opDevice }
|
Loading…
x
Reference in New Issue
Block a user