1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

acpi: define VM type and structs to maintain execution state

This commit is contained in:
Achilleas Anagnostopoulos 2017-10-11 19:58:00 +01:00
parent 61597cff56
commit 64f3dae485
2 changed files with 152 additions and 0 deletions

View File

@ -0,0 +1,119 @@
package aml
import (
"gopheros/device/acpi/table"
"io"
)
const (
// According to the ACPI spec, methods can use up to 8 local args and
// can receive up to 7 method args.
maxLocalArgs = 8
maxMethodArgs = 7
)
// ctrlFlowType describes the different ways that the control flow can be altered
// while executing a set of AML opcodes.
type ctrlFlowType uint8
// The list of supported control flows.
const (
ctrlFlowTypeNextOpcode ctrlFlowType = iota
ctrlFlowTypeBreak
ctrlFlowTypeContinue
ctrlFlowTypeFnReturn
)
// execContext encapsulates
type execContext struct {
localArg [maxLocalArgs]interface{}
methodArg [maxMethodArgs]interface{}
// ctrlFlow specifies how the VM should select the next instruction to
// execute.
ctrlFlow ctrlFlowType
// retVal holds the return value from a method if ctrlFlow is set to
// the value ctrlFlowTypeFnReturn.
retVal interface{}
vm *VM
}
// Error describes errors that occur while executing AML code.
type Error struct {
message string
}
// Error implements the error interface.
func (e *Error) Error() string {
return e.message
}
// VM is a structure that stores the output of the AML bytecode parser and
// provides methods for interpreting any executable opcode.
type VM struct {
errWriter io.Writer
tableResolver table.Resolver
tableParser *Parser
// rootNS holds a pointer to the root of the ACPI tree.
rootNS ScopeEntity
// According to the ACPI spec, the Revision field in the DSDT specifies
// whether integers are treated as 32 or 64-bits. The VM memoizes this
// value so that it can be used by the data conversion helpers.
sizeOfIntInBits int
}
// NewVM creates a new AML VM and initializes it with the default scope
// hierarchy and pre-defined objects contained in the ACPI specification.
func NewVM(errWriter io.Writer, resolver table.Resolver) *VM {
root := defaultACPIScopes()
return &VM{
rootNS: root,
errWriter: errWriter,
tableResolver: resolver,
tableParser: NewParser(errWriter, root),
}
}
// Init attempts to locate and parse the AML byte-code contained in the
// system's DSDT and SSDT tables.
func (vm *VM) Init() *Error {
for tableHandle, tableName := range []string{"DSDT", "SSDT"} {
header := vm.tableResolver.LookupTable(tableName)
if header == nil {
continue
}
if err := vm.tableParser.ParseAML(uint8(tableHandle+1), tableName, header); err != nil {
return &Error{message: err.Module + ": " + err.Error()}
}
if tableName == "DSDT" {
vm.sizeOfIntInBits = 32
if header.Revision >= 2 {
vm.sizeOfIntInBits = 64
}
}
}
return nil
}
// defaultACPIScopes constructs a tree of scoped entities that correspond to
// the predefined scopes contained in the ACPI specification and returns back
// its root node.
func defaultACPIScopes() ScopeEntity {
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
return rootNS
}

View File

@ -0,0 +1,33 @@
package aml
import (
"os"
"reflect"
"testing"
)
func TestVMInit(t *testing.T) {
t.Run("success", func(t *testing.T) {
resolver := &mockResolver{
tableFiles: []string{"DSDT.aml"},
}
vm := NewVM(os.Stderr, resolver)
if err := vm.Init(); err != nil {
t.Fatal(err)
}
})
t.Run("parse error", func(t *testing.T) {
resolver := &fixedPayloadResolver{
// invalid payload (incomplete opcode)
payload: []byte{extOpPrefix},
}
expErr := &Error{message: errParsingAML.Module + ": " + errParsingAML.Error()}
vm := NewVM(os.Stderr, resolver)
if err := vm.Init(); !reflect.DeepEqual(err, expErr) {
t.Fatalf("expected Init() to return errParsingAML; got %v", err)
}
})
}