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