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

acpi: implement minimal helper for reading AML operand values

The helper only supports reading a subset of the available AML operands:
- constants (uint64, strings and bools; bools are auto-casted to uint64)
- local and method args

The implementation will recursively drill down into the operand values
till it reaches a value that can be mapped to a Go uint64 or string
type. For example, if arg0 contains a constant with the value "foo",
vmRead will recurse into the arg0 value and return "foo"
This commit is contained in:
Achilleas Anagnostopoulos 2017-10-30 08:59:30 +00:00
parent fd2f4a72ad
commit 1a2d075aa2
3 changed files with 118 additions and 1 deletions

View File

@ -34,7 +34,8 @@ type execContext struct {
ctrlFlow ctrlFlowType
// retVal holds the return value from a method if ctrlFlow is set to
// the value ctrlFlowTypeFnReturn.
// the value ctrlFlowTypeFnReturn or the intermediate value of an AML
// opcode execution.
retVal interface{}
vm *VM

View File

@ -0,0 +1,35 @@
package aml
// vmLoad returns the value contained inside arg. To obtain the actual stored
// value vmLoad will automatically peek into const entities and lookup
// local/global args.
func vmLoad(ctx *execContext, arg interface{}) (interface{}, *Error) {
// We need to keep evaluating types till we reach a type that can be
// returned. For example, a local arg may contain a const entity for
// which we want to fetch the contained value.
for {
switch typ := arg.(type) {
case *constEntity:
arg = typ.val
case Entity:
op := typ.getOpcode()
switch {
case opIsLocalArg(op):
arg = ctx.localArg[op-opLocal0]
case opIsMethodArg(op):
arg = ctx.methodArg[op-opArg0]
default:
return nil, &Error{message: "readArg: unsupported entity type: " + op.String()}
}
case bool:
// Convert boolean results to ints so they can be used
// by the ALU comparators.
if typ {
return uint64(1), nil
}
return uint64(0), nil
default:
return typ, nil
}
}
}

View File

@ -0,0 +1,81 @@
package aml
import (
"reflect"
"testing"
)
func TestVMLoad(t *testing.T) {
specs := []struct {
ctx *execContext
argIn interface{}
valOut interface{}
err *Error
}{
{
nil,
&constEntity{val: uint64(123)},
uint64(123),
nil,
},
{
nil,
&constEntity{val: "a string"},
"a string",
nil,
},
{
nil,
&constEntity{
val: &constEntity{val: true},
},
uint64(1),
nil,
},
{
nil,
&constEntity{
val: &constEntity{val: false},
},
uint64(0),
nil,
},
{
&execContext{
localArg: [maxLocalArgs]interface{}{"foo"},
},
&unnamedEntity{op: opLocal0},
"foo",
nil,
},
{
&execContext{
methodArg: [maxMethodArgs]interface{}{"bar", "foo"},
},
&unnamedEntity{op: opArg1},
"foo",
nil,
},
// Unsupported reads
{
nil,
&unnamedEntity{op: opBuffer},
nil,
&Error{message: "readArg: unsupported entity type: Buffer"},
},
}
for specIndex, spec := range specs {
got, err := vmLoad(spec.ctx, spec.argIn)
switch {
case !reflect.DeepEqual(spec.err, err):
t.Errorf("[spec %d] expected error: %v; got: %v", specIndex, spec.err, err)
case got != spec.valOut:
t.Errorf("[spec %d] expected to get value %v (type: %v); got %v (type %v)", specIndex,
spec.valOut, reflect.TypeOf(spec.valOut),
got, reflect.TypeOf(got),
)
}
}
}