diff --git a/src/gopheros/device/acpi/aml/vm_convert.go b/src/gopheros/device/acpi/aml/vm_convert.go new file mode 100644 index 0000000..180133f --- /dev/null +++ b/src/gopheros/device/acpi/aml/vm_convert.go @@ -0,0 +1,133 @@ +package aml + +// valueType represents the data types that the AML interpreter can process. +type valueType uint8 + +// The list of supporte AML value types (see p. 876 of ACPI 6.2 standard) +const ( + valueTypeUninitialized valueType = iota + valueTypeBuffer + valueTypeBufferField + valueTypeDDBHandle + valueTypeDebugObject + valueTypeDevice + valueTypeEvent + valueTypeFieldUnit + valueTypeInteger // we also treat constants as integers + valueTypeMethod + valueTypeMutex + valueTypeObjectRef + valueTypeRegion + valueTypePackage + valueTypeString + valueTypePowerResource + valueTypeProcessor + valueTypeRawDataBuffer + valueTypeThermalZone +) + +// String implements fmt.Stringer for valueType. +func (vt valueType) String() string { + switch vt { + case valueTypeBuffer: + return "Buffer" + case valueTypeBufferField: + return "BufferField" + case valueTypeDDBHandle: + return "DDBHandle" + case valueTypeDebugObject: + return "DebugObject" + case valueTypeDevice: + return "Device" + case valueTypeEvent: + return "Event" + case valueTypeFieldUnit: + return "FieldUnit" + case valueTypeInteger: + return "Integer" + case valueTypeMethod: + return "Method" + case valueTypeMutex: + return "Mutex" + case valueTypeObjectRef: + return "ObjectRef" + case valueTypeRegion: + return "Region" + case valueTypePackage: + return "Package" + case valueTypeString: + return "String" + case valueTypePowerResource: + return "PowerResource" + case valueTypeProcessor: + return "Processor" + case valueTypeRawDataBuffer: + return "RawDataBuffer" + case valueTypeThermalZone: + return "ThermalZone" + default: + return "Uninitialized" + } +} + +// vmTypeOf returns the type of data stored inside the supplied argument. +func vmTypeOf(ctx *execContext, arg interface{}) valueType { + // Some objects (e.g args, constEntity contents) may require to perform + // more than one pass to figure out their type + for { + switch typ := arg.(type) { + case *constEntity: + // check the value stored inside + arg = typ.val + case *Device: + return valueTypeDevice + case *Method: + return valueTypeMethod + case *bufferEntity: + return valueTypeBuffer + case *bufferFieldEntity: + return valueTypeBufferField + case *fieldUnitEntity, *indexFieldEntity: + return valueTypeFieldUnit + case *regionEntity: + return valueTypeRegion + case *objRef: + return valueTypeObjectRef + case *eventEntity: + return valueTypeEvent + case *mutexEntity: + return valueTypeMutex + case Entity: + op := typ.getOpcode() + + switch op { + case opPackage: + return valueTypePackage + case opPowerRes: + return valueTypePowerResource + case opProcessor: + return valueTypeProcessor + case opThermalZone: + return valueTypeThermalZone + } + + // Check if this a local or method arg; if so we need to + // fetch the arg and check its type + if op >= opLocal0 && op <= opLocal7 { + arg = ctx.localArg[op-opLocal0] + } else if op >= opArg0 && op <= opArg6 { + arg = ctx.methodArg[op-opArg0] + } else { + return valueTypeUninitialized + } + case string: + return valueTypeString + case uint64, bool: + return valueTypeInteger + case []byte: + return valueTypeRawDataBuffer + default: + return valueTypeUninitialized + } + } +} diff --git a/src/gopheros/device/acpi/aml/vm_convert_test.go b/src/gopheros/device/acpi/aml/vm_convert_test.go new file mode 100644 index 0000000..446e9d6 --- /dev/null +++ b/src/gopheros/device/acpi/aml/vm_convert_test.go @@ -0,0 +1,174 @@ +package aml + +import ( + "testing" +) + +func TestValueTypeToString(t *testing.T) { + specs := map[valueType]string{ + valueTypeBuffer: "Buffer", + valueTypeBufferField: "BufferField", + valueTypeDDBHandle: "DDBHandle", + valueTypeDebugObject: "DebugObject", + valueTypeDevice: "Device", + valueTypeEvent: "Event", + valueTypeFieldUnit: "FieldUnit", + valueTypeInteger: "Integer", + valueTypeMethod: "Method", + valueTypeMutex: "Mutex", + valueTypeObjectRef: "ObjectRef", + valueTypeRegion: "Region", + valueTypePackage: "Package", + valueTypeString: "String", + valueTypePowerResource: "PowerResource", + valueTypeProcessor: "Processor", + valueTypeRawDataBuffer: "RawDataBuffer", + valueTypeThermalZone: "ThermalZone", + valueTypeUninitialized: "Uninitialized", + } + + for vt, exp := range specs { + if got := vt.String(); got != exp { + t.Errorf("expected valueType %d string representation to be %q; got %q", vt, exp, got) + } + } +} + +func TestVMTypeOf(t *testing.T) { + specs := []struct { + ctx *execContext + in interface{} + expType valueType + }{ + { + nil, + &constEntity{val: uint64(42)}, + valueTypeInteger, + }, + { + nil, + &constEntity{val: "some string"}, + valueTypeString, + }, + { + nil, + &Device{}, + valueTypeDevice, + }, + { + nil, + &Method{}, + valueTypeMethod, + }, + { + nil, + &bufferEntity{}, + valueTypeBuffer, + }, + { + nil, + &bufferFieldEntity{}, + valueTypeBufferField, + }, + { + nil, + &fieldUnitEntity{}, + valueTypeFieldUnit, + }, + { + nil, + &indexFieldEntity{}, + valueTypeFieldUnit, + }, + { + nil, + ®ionEntity{}, + valueTypeRegion, + }, + { + nil, + &objRef{}, + valueTypeObjectRef, + }, + { + nil, + &eventEntity{}, + valueTypeEvent, + }, + { + nil, + &mutexEntity{}, + valueTypeMutex, + }, + { + nil, + &unnamedEntity{op: opPackage}, + valueTypePackage, + }, + { + nil, + &unnamedEntity{op: opPowerRes}, + valueTypePowerResource, + }, + { + nil, + &unnamedEntity{op: opProcessor}, + valueTypeProcessor, + }, + { + nil, + &unnamedEntity{op: opThermalZone}, + valueTypeThermalZone, + }, + { + &execContext{ + localArg: [maxLocalArgs]interface{}{ + uint64(42), + }, + }, + &unnamedEntity{op: opLocal0}, + valueTypeInteger, + }, + { + &execContext{ + methodArg: [maxMethodArgs]interface{}{ + uint64(42), + "foo", + }, + }, + &unnamedEntity{op: opArg1}, + valueTypeString, + }, + { + nil, + "foo", + valueTypeString, + }, + { + nil, + uint64(42), + valueTypeInteger, + }, + { + nil, + []byte("some data"), + valueTypeRawDataBuffer, + }, + { + nil, + &unnamedEntity{op: opAdd}, + valueTypeUninitialized, + }, + { + nil, + int64(0xbadf00d), + valueTypeUninitialized, + }, + } + + for specIndex, spec := range specs { + if got := vmTypeOf(spec.ctx, spec.in); got != spec.expType { + t.Errorf("[spec %d] expected to get value type %s; got %s", specIndex, spec.expType, got) + } + } +}