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

acpi: implement AML helpers for detecting argument types

The list of AML types is described on $p. 876 of ACPI 6.2 standard
This commit is contained in:
Achilleas Anagnostopoulos 2017-11-27 07:24:43 +00:00
parent dfaf068735
commit d6a825fc02
2 changed files with 307 additions and 0 deletions

View File

@ -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
}
}
}

View File

@ -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,
&regionEntity{},
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)
}
}
}