From 1a2d075aa2c4555f092cf21786430ab9b65b70d1 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 30 Oct 2017 08:59:30 +0000 Subject: [PATCH] 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" --- src/gopheros/device/acpi/aml/vm.go | 3 +- src/gopheros/device/acpi/aml/vm_load_store.go | 35 ++++++++ .../device/acpi/aml/vm_load_store_test.go | 81 +++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 src/gopheros/device/acpi/aml/vm_load_store.go create mode 100644 src/gopheros/device/acpi/aml/vm_load_store_test.go diff --git a/src/gopheros/device/acpi/aml/vm.go b/src/gopheros/device/acpi/aml/vm.go index 55899cf..8a1865a 100644 --- a/src/gopheros/device/acpi/aml/vm.go +++ b/src/gopheros/device/acpi/aml/vm.go @@ -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 diff --git a/src/gopheros/device/acpi/aml/vm_load_store.go b/src/gopheros/device/acpi/aml/vm_load_store.go new file mode 100644 index 0000000..318e74e --- /dev/null +++ b/src/gopheros/device/acpi/aml/vm_load_store.go @@ -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 + } + } +} diff --git a/src/gopheros/device/acpi/aml/vm_load_store_test.go b/src/gopheros/device/acpi/aml/vm_load_store_test.go new file mode 100644 index 0000000..c9d711c --- /dev/null +++ b/src/gopheros/device/acpi/aml/vm_load_store_test.go @@ -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), + ) + } + + } +}