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:
parent
61597cff56
commit
64f3dae485
119
src/gopheros/device/acpi/aml/vm.go
Normal file
119
src/gopheros/device/acpi/aml/vm.go
Normal 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
|
||||||
|
}
|
33
src/gopheros/device/acpi/aml/vm_test.go
Normal file
33
src/gopheros/device/acpi/aml/vm_test.go
Normal 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)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user