diff --git a/src/gopheros/device/acpi/aml/entity/entity.go b/src/gopheros/device/acpi/aml/entity/entity.go deleted file mode 100644 index 5e2b85e..0000000 --- a/src/gopheros/device/acpi/aml/entity/entity.go +++ /dev/null @@ -1,1044 +0,0 @@ -package entity - -import ( - "gopheros/kernel" -) - -// Entity is an interface implemented by all AML entities. -type Entity interface { - // Opcode returns the AML op associated with this entity. - Opcode() AMLOpcode - - // Name returns the entity's name or an empty string if no name is - // associated with the entity. - Name() string - - // Parent returns the Container of this entity. - Parent() Container - - // SetParent updates the parent container reference. - SetParent(Container) - - // TableHandle returns the handle of the ACPI table where this entity - // was defined. - TableHandle() uint8 - - // Args returns the argument list for this entity. - Args() []interface{} - - // SetArg adds an argument value at the specified argument index. - SetArg(uint8, interface{}) bool -} - -// Container is an interface that is implemented by entities contain a -// collection of other Entities and define an AML scope. -type Container interface { - Entity - - // Children returns the list of entities that are children of this - // container. - Children() []Entity - - // Append adds an entity to a container. - Append(Entity) bool - - // Remove searches the child list for an entity and removes it if found. - Remove(Entity) - - // Last returns the last entity that was added to this container. - Last() Entity -} - -// FieldAccessTypeProvider is an interface implemented by all field entities. -type FieldAccessTypeProvider interface { - // DefaultAccessType returns the default FieldAccessType for any field unit - // defined by this field. - DefaultAccessType() FieldAccessType -} - -// LazyRefResolver is an interface implemented by entities that contain symbol -// references that are lazily resolved after the full AML entity tree has been -// parsed. -type LazyRefResolver interface { - // ResolveSymbolRefs receives as input the root of the AML entity tree and - // attempts to resolve any symbol references using the scope searching rules - // defined by the ACPI spec. - ResolveSymbolRefs(Container) *kernel.Error -} - -// Generic describes an entity without a name. -type Generic struct { - _ uint8 - tableHandle uint8 - op AMLOpcode - args []interface{} - parent Container -} - -// NewGeneric returns a new generic AML entity. -func NewGeneric(op AMLOpcode, tableHandle uint8) *Generic { - return &Generic{ - op: op, - tableHandle: tableHandle, - } -} - -// Opcode returns the AML op associated with this entity. -func (ent *Generic) Opcode() AMLOpcode { return ent.op } - -// Name returns the entity's name. For this type of entity it always returns -// an empty string. -func (ent *Generic) Name() string { return "" } - -// Parent returns the Container of this entity. -func (ent *Generic) Parent() Container { return ent.parent } - -// SetParent updates the parent container reference. -func (ent *Generic) SetParent(parent Container) { ent.parent = parent } - -// TableHandle returns the handle of the ACPI table where this entity was -// defined. -func (ent *Generic) TableHandle() uint8 { return ent.tableHandle } - -// Args returns the argument list for this entity. -func (ent *Generic) Args() []interface{} { return ent.args } - -// SetArg adds an argument value at the specified argument index. -func (ent *Generic) SetArg(_ uint8, arg interface{}) bool { - ent.args = append(ent.args, arg) - return true -} - -// GenericNamed describes an entity whose name is specified as the argument at -// index zero. -type GenericNamed struct { - Generic - name string -} - -// NewGenericNamed returns a new generic named AML entity. -func NewGenericNamed(op AMLOpcode, tableHandle uint8) *GenericNamed { - return &GenericNamed{ - Generic: Generic{ - op: op, - tableHandle: tableHandle, - }, - } -} - -// Name returns the entity's name. -func (ent *GenericNamed) Name() string { return ent.name } - -// SetArg adds an argument value at the specified argument index. -func (ent *GenericNamed) SetArg(argIndex uint8, arg interface{}) bool { - // arg 0 is the entity name - if argIndex == 0 { - var ok bool - ent.name, ok = arg.(string) - return ok - } - - ent.args = append(ent.args, arg) - return true -} - -// Const is an optionally named entity that contains a constant uint64 or -// string value. -type Const struct { - GenericNamed - Value interface{} -} - -// NewConst creates a new AML constant entity. -func NewConst(op AMLOpcode, tableHandle uint8, initialValue interface{}) *Const { - return &Const{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: op, - tableHandle: tableHandle, - }, - }, - Value: initialValue, - } -} - -// SetName allows the caller to override the name for a Const entity. -func (ent *Const) SetName(name string) { ent.name = name } - -// SetArg adds an argument value at the specified argument index. -func (ent *Const) SetArg(argIndex uint8, arg interface{}) bool { - // Const entities accept at most one arg - ent.Value = arg - return argIndex == 0 -} - -// Scope is an optionally named entity that groups together multiple entities. -type Scope struct { - GenericNamed - children []Entity -} - -// NewScope creates a new AML named scope entity. -func NewScope(op AMLOpcode, tableHandle uint8, name string) *Scope { - return &Scope{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: op, - tableHandle: tableHandle, - }, - name: name, - }, - } -} - -// Children returns the list of entities that are children of this container. -func (ent *Scope) Children() []Entity { return ent.children } - -// Append adds an entity to a container. -func (ent *Scope) Append(child Entity) bool { - child.SetParent(ent) - ent.children = append(ent.children, child) - return true -} - -// Remove searches the child list for an entity and removes it if found. -func (ent *Scope) Remove(child Entity) { - for index := 0; index < len(ent.children); index++ { - if ent.children[index] == child { - ent.children = append(ent.children[:index], ent.children[index+1:]...) - return - } - } -} - -// Last returns the last entity that was added to this container. -func (ent *Scope) Last() Entity { return ent.children[len(ent.children)-1] } - -// Buffer defines an AML buffer entity. The entity fields specify a size (arg -// 0) and an optional initializer. -type Buffer struct { - Generic - - size interface{} - data []byte -} - -// NewBuffer creates a new AML buffer entity. -func NewBuffer(tableHandle uint8) *Buffer { - return &Buffer{ - Generic: Generic{ - op: OpBuffer, - tableHandle: tableHandle, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Buffer) SetArg(argIndex uint8, arg interface{}) bool { - switch argIndex { - case 0: // size - ent.size = arg - return true - case 1: // data - if byteSlice, ok := arg.([]byte); ok { - ent.data = byteSlice - return true - } - } - - return false -} - -// BufferField describes a bit/byte/word/dword/qword or arbitrary length -// region within a Buffer. -type BufferField struct { - GenericNamed - - SourceBuf interface{} - Index interface{} - NumBits interface{} -} - -// NewBufferField creates a new AML buffer field entity. -func NewBufferField(op AMLOpcode, tableHandle uint8, bits uint64) *BufferField { - return &BufferField{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: op, - tableHandle: tableHandle, - }, - }, - NumBits: bits, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *BufferField) SetArg(argIndex uint8, arg interface{}) bool { - switch argIndex { - case 0: - ent.SourceBuf = arg - case 1: - ent.Index = arg - case 2, 3: - // opCreateField specifies the name using the arg at index 3 - // while opCreateXXXField (byte, word e.t.c) specifies the name - // using the arg at index 2 - var ok bool - if ent.name, ok = arg.(string); !ok { - ent.NumBits = arg - } - } - return argIndex <= 3 -} - -// RegionSpace describes the memory space where a region is located. -type RegionSpace uint8 - -// The list of supported RegionSpace values. -const ( - RegionSpaceSystemMemory RegionSpace = iota - RegionSpaceSystemIO - RegionSpacePCIConfig - RegionSpaceEmbeddedControl - RegionSpaceSMBus - RegionSpacePCIBarTarget - RegionSpaceIPMI -) - -// Region defines a region located at a particular space (e.g in memory, an -// embedded controller, the SMBus e.t.c). -type Region struct { - GenericNamed - - Space RegionSpace - Offset interface{} - Len interface{} -} - -// NewRegion creates a new AML region entity. -func NewRegion(tableHandle uint8) *Region { - return &Region{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpOpRegion, - tableHandle: tableHandle, - }, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Region) SetArg(argIndex uint8, arg interface{}) bool { - var ok bool - switch argIndex { - case 0: - ok = ent.GenericNamed.SetArg(argIndex, arg) - case 1: - // the parser will convert ByteData types to uint64 - var space uint64 - space, ok = arg.(uint64) - ent.Space = RegionSpace(space) - case 2: - ent.Offset = arg - ok = true - case 3: - ent.Len = arg - ok = true - } - - return ok -} - -// FieldAccessType specifies the type of access (byte, word, e.t.c) used to -// read/write to a field. -type FieldAccessType uint8 - -// The list of supported FieldAccessType values. -const ( - FieldAccessTypeAny FieldAccessType = iota - FieldAccessTypeByte - FieldAccessTypeWord - FieldAccessTypeDword - FieldAccessTypeQword - FieldAccessTypeBuffer -) - -// FieldLockRule specifies what type of locking is required when accesing field. -type FieldLockRule uint8 - -// The list of supported FieldLockRule values. -const ( - FieldLockRuleNoLock FieldLockRule = iota - FieldLockRuleLock -) - -// FieldUpdateRule specifies how a field value is updated when a write uses -// a value with a smaller width than the field. -type FieldUpdateRule uint8 - -// The list of supported FieldUpdateRule values. -const ( - FieldUpdateRulePreserve FieldUpdateRule = iota - FieldUpdateRuleWriteAsOnes - FieldUpdateRuleWriteAsZeros -) - -// FieldAccessAttrib specifies additional information about a particular field -// access. -type FieldAccessAttrib uint8 - -// The list of supported FieldAccessAttrib values. -const ( - FieldAccessAttribQuick FieldAccessAttrib = 0x02 - FieldAccessAttribSendReceive = 0x04 - FieldAccessAttribByte = 0x06 - FieldAccessAttribWord = 0x08 - FieldAccessAttribBlock = 0x0a - FieldAccessAttribBytes = 0x0b // byteCount contains the number of bytes - FieldAccessAttribProcessCall = 0x0c - FieldAccessAttribBlockProcessCall = 0x0d - FieldAccessAttribRawBytes = 0x0e // byteCount contains the number of bytes - FieldAccessAttribRawProcessBytes = 0x0f // byteCount contains the number of bytes -) - -// Field is anobject that controls access to a host operating region. It is -// referenced by a list of FieldUnit objects that appear as siblings of a Field -// in the same scope. -type Field struct { - Generic - - // The region which this field references. - RegionName string - Region *Region - - AccessType FieldAccessType - LockRule FieldLockRule - UpdateRule FieldUpdateRule -} - -// NewField creates a new AML field entity. -func NewField(tableHandle uint8) *Field { - return &Field{ - Generic: Generic{ - op: OpField, - tableHandle: tableHandle, - }, - } -} - -// DefaultAccessType returns the default FieldAccessType for any field unit -// defined by this field. -func (ent *Field) DefaultAccessType() FieldAccessType { - return ent.AccessType -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Field) SetArg(argIndex uint8, arg interface{}) bool { - var ( - ok bool - uintVal uint64 - ) - - switch argIndex { - case 0: - ent.RegionName, ok = arg.(string) - case 1: - uintVal, ok = arg.(uint64) - - ent.AccessType = FieldAccessType(uintVal & 0xf) // access type; bits[0:3] - ent.LockRule = FieldLockRule((uintVal >> 4) & 0x1) // lock; bit 4 - ent.UpdateRule = FieldUpdateRule((uintVal >> 5) & 0x3) // update rule; bits[5:6] - } - - return ok -} - -// ResolveSymbolRefs receives as input the root of the AML entity tree and -// attempts to resolve any symbol references using the scope searching rules -// defined by the ACPI spec. -func (ent *Field) ResolveSymbolRefs(rootNS Container) *kernel.Error { - var ok bool - if ent.Region, ok = FindInScope(ent.Parent(), rootNS, ent.RegionName).(*Region); !ok { - return &kernel.Error{ - Module: "acpi_aml_resolver", - Message: "could not resolve referenced field region: " + ent.RegionName, - } - } - - return nil -} - -// IndexField is a special field that groups together two field units so a -// index/data register pattern can be implemented. To write a value to an -// IndexField, the interpreter must first write the appropriate offset to -// the IndexRegister (using the alignment specifid by AccessType) and then -// write the actual value to the DataRegister. -type IndexField struct { - Generic - - IndexRegName string - IndexReg *FieldUnit - - DataRegName string - DataReg *FieldUnit - - AccessType FieldAccessType - LockRule FieldLockRule - UpdateRule FieldUpdateRule -} - -// NewIndexField creates a new AML index field entity. -func NewIndexField(tableHandle uint8) *IndexField { - return &IndexField{ - Generic: Generic{ - op: OpIndexField, - tableHandle: tableHandle, - }, - } -} - -// DefaultAccessType returns the default FieldAccessType for any field unit -// defined by this field. -func (ent *IndexField) DefaultAccessType() FieldAccessType { - return ent.AccessType -} - -// SetArg adds an argument value at the specified argument index. -func (ent *IndexField) SetArg(argIndex uint8, arg interface{}) bool { - var ( - ok bool - uintVal uint64 - ) - - switch argIndex { - case 0: - ent.IndexRegName, ok = arg.(string) - case 1: - ent.DataRegName, ok = arg.(string) - case 2: - uintVal, ok = arg.(uint64) - - ent.AccessType = FieldAccessType(uintVal & 0xf) // access type; bits[0:3] - ent.LockRule = FieldLockRule((uintVal >> 4) & 0x1) // lock; bit 4 - ent.UpdateRule = FieldUpdateRule((uintVal >> 5) & 0x3) // update rule; bits[5:6] - } - return ok -} - -// ResolveSymbolRefs receives as input the root of the AML entity tree and -// attempts to resolve any symbol references using the scope searching rules -// defined by the ACPI spec. -func (ent *IndexField) ResolveSymbolRefs(rootNS Container) *kernel.Error { - var ok bool - - if ent.IndexReg, ok = FindInScope(ent.Parent(), rootNS, ent.IndexRegName).(*FieldUnit); !ok { - return &kernel.Error{ - Module: "acpi_aml_resolver", - Message: "could not resolve referenced index register: " + ent.IndexRegName, - } - } - - if ent.DataReg, ok = FindInScope(ent.Parent(), rootNS, ent.DataRegName).(*FieldUnit); !ok { - return &kernel.Error{ - Module: "acpi_aml_resolver", - Message: "could not resolve referenced data register: " + ent.DataRegName, - } - } - - return nil -} - -// BankField is a special field where a bank register must be used to select -// the appropriate bank region before accessing its contents. -type BankField struct { - Generic - - // The region which this field references. - RegionName string - Region *Region - - // The bank name which controls access to field units defined within this field. - BankFieldUnitName string - BankFieldUnit *FieldUnit - - // The value that needs to be written to the bank field before accessing any field unit. - BankFieldUnitValue interface{} - - AccessType FieldAccessType - LockRule FieldLockRule - UpdateRule FieldUpdateRule -} - -// NewBankField creates a new AML bank field entity. -func NewBankField(tableHandle uint8) *BankField { - return &BankField{ - Generic: Generic{ - op: OpBankField, - tableHandle: tableHandle, - }, - } -} - -// DefaultAccessType returns the default FieldAccessType for any field unit -// defined by this field. -func (ent *BankField) DefaultAccessType() FieldAccessType { - return ent.AccessType -} - -// SetArg adds an argument value at the specified argument index. -func (ent *BankField) SetArg(argIndex uint8, arg interface{}) bool { - var ( - ok bool - uintVal uint64 - ) - - switch argIndex { - case 0: - ent.RegionName, ok = arg.(string) - case 1: - ent.BankFieldUnitName, ok = arg.(string) - case 2: - ent.BankFieldUnitValue, ok = arg, true - case 3: - uintVal, ok = arg.(uint64) - - ent.AccessType = FieldAccessType(uintVal & 0xf) // access type; bits[0:3] - ent.LockRule = FieldLockRule((uintVal >> 4) & 0x1) // lock; bit 4 - ent.UpdateRule = FieldUpdateRule((uintVal >> 5) & 0x3) // update rule; bits[5:6] - } - return ok -} - -// ResolveSymbolRefs receives as input the root of the AML entity tree and -// attempts to resolve any symbol references using the scope searching rules -// defined by the ACPI spec. -func (ent *BankField) ResolveSymbolRefs(rootNS Container) *kernel.Error { - var ok bool - - if ent.Region, ok = FindInScope(ent.Parent(), rootNS, ent.RegionName).(*Region); !ok { - return &kernel.Error{ - Module: "acpi_aml_resolver", - Message: "could not resolve referenced field region: " + ent.RegionName, - } - } - - if ent.BankFieldUnit, ok = FindInScope(ent.Parent(), rootNS, ent.BankFieldUnitName).(*FieldUnit); !ok { - return &kernel.Error{ - Module: "acpi_aml_resolver", - Message: "could not resolve referenced bank register field: " + ent.BankFieldUnitName, - } - } - - return nil -} - -// FieldUnit describes a sub-region inside a parent field. -type FieldUnit struct { - GenericNamed - - // Depending on what field this unit belongs to this will be a pointer - // to one of: Field, BankField, IndexField - Field interface{} - - // The access type to use. Inherited by parent field unless explicitly - // changed via a directive in the field unit definition list. - AccessType FieldAccessType - - // AccessAttrib is valid if AccessType is BufferAcc for the SMB or GPIO OpRegions. - AccessAttrib FieldAccessAttrib - - // ByteCount is valid when AccessAttrib is one of: Bytes, RawBytes or RawProcessBytes - ByteCount uint8 - - // Field offset in parent region and its width. - BitOffset uint32 - BitWidth uint32 - - // The connection resource for field access references (serial bus or GPIO). - ConnectionName string - Connection Entity -} - -// NewFieldUnit creates a new field unit entity. -func NewFieldUnit(tableHandle uint8, name string) *FieldUnit { - return &FieldUnit{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpFieldUnit, - tableHandle: tableHandle, - }, - name: name, - }, - } -} - -// ResolveSymbolRefs receives as input the root of the AML entity tree and -// attempts to resolve any symbol references using the scope searching rules -// defined by the ACPI spec. -func (ent *FieldUnit) ResolveSymbolRefs(rootNS Container) *kernel.Error { - if ent.ConnectionName == "" { - return nil - } - - if ent.Connection = FindInScope(ent.Parent(), rootNS, ent.ConnectionName); ent.Connection == nil { - return &kernel.Error{ - Module: "acpi_aml_resolver", - Message: "[field unit: " + ent.Name() + "] could not resolve connection reference: " + ent.ConnectionName, - } - } - - return nil -} - -// Reference holds a named reference to an AML symbol. The spec allows the -// symbol not to be defined at the time when the reference is parsed. In such a -// case (forward reference) it will be resolved after the entire AML stream has -// successfully been parsed. -type Reference struct { - Generic - - TargetName string - Target Entity -} - -// NewReference creates a new reference to a named entity. -func NewReference(tableHandle uint8, target string) *Reference { - return &Reference{ - Generic: Generic{ - op: OpName, - tableHandle: tableHandle, - }, - TargetName: target, - } -} - -// ResolveSymbolRefs receives as input the root of the AML entity tree and -// attempts to resolve any symbol references using the scope searching rules -// defined by the ACPI spec. -func (ent *Reference) ResolveSymbolRefs(rootNS Container) *kernel.Error { - if ent.Target = FindInScope(ent.Parent(), rootNS, ent.TargetName); ent.Target == nil { - return &kernel.Error{ - Module: "acpi_aml_vm", - Message: "could not resolve referenced symbol: " + ent.TargetName + "; parent: " + ent.Parent().Name(), - } - } - - return nil -} - -// Method describes an invocable AML method. -type Method struct { - Scope - - ArgCount uint8 - Serialized bool - SyncLevel uint8 - - BodyStartOffset uint32 - BodyEndOffset uint32 -} - -// NewMethod creats a new AML method entity. -func NewMethod(tableHandle uint8, name string) *Method { - return &Method{ - Scope: Scope{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpMethod, - tableHandle: tableHandle, - }, - name: name, - }, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Method) SetArg(argIndex uint8, arg interface{}) bool { - var ( - ok bool - uintVal uint64 - ) - - switch argIndex { - case 0: - // Arg0 is the name but it is actually defined when creating the entity - ok = true - case 1: - // arg1 is the method flags - uintVal, ok = arg.(uint64) - - ent.ArgCount = (uint8(uintVal) & 0x7) // bits[0:2] - ent.Serialized = (uint8(uintVal)>>3)&0x1 == 0x1 // bit 3 - ent.SyncLevel = (uint8(uintVal) >> 4) & 0xf // bits[4:7] - - } - return ok -} - -// Invocation describes an AML method invocation. -type Invocation struct { - Generic - - Method *Method -} - -// NewInvocation creates a new method invocation object. -func NewInvocation(tableHandle uint8, method *Method, args []interface{}) *Invocation { - return &Invocation{ - Generic: Generic{ - op: OpMethodInvocation, - tableHandle: tableHandle, - args: args, - }, - Method: method, - } -} - -// Device defines an AML device entity. -type Device struct { - Scope -} - -// NewDevice creates a new device object. -func NewDevice(tableHandle uint8, name string) *Device { - return &Device{ - Scope: Scope{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpDevice, - tableHandle: tableHandle, - }, - name: name, - }, - }, - } -} - -// Processor describes a AML processor entity. According to the spec, the use -// of processor operators is deprecated and processors should be declared as -// Device entities instead. -type Processor struct { - Scope - - // A unique ID for this processor. - ID uint8 - - // The length of the processor register block. According to the spec, - // this field may be zero. - RegBlockLen uint8 - - // The I/O address of the process register block. - RegBlockAddr uint32 -} - -// NewProcessor creates a new processor object. -func NewProcessor(tableHandle uint8, name string) *Processor { - return &Processor{ - Scope: Scope{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpProcessor, - tableHandle: tableHandle, - }, - name: name, - }, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Processor) SetArg(argIndex uint8, arg interface{}) bool { - var ( - ok bool - uintVal uint64 - ) - - switch argIndex { - case 0: - // Arg0 is the name but it is actually defined when creating the entity - ok = true - case 1: - // arg1 is the processor ID (ByteData) - uintVal, ok = arg.(uint64) - ent.ID = uint8(uintVal) - case 2: - // arg2 is the processor I/O reg block address (Dword) - uintVal, ok = arg.(uint64) - ent.RegBlockAddr = uint32(uintVal) - case 3: - // arg3 is the processor I/O reg block address len (ByteData) - uintVal, ok = arg.(uint64) - ent.RegBlockLen = uint8(uintVal) - } - return ok -} - -// PowerResource describes a AML power resource entity. -type PowerResource struct { - Scope - - // The deepest system sleep level OSPM must maintain to keep this power - // resource on (0 equates to S0, 1 equates to S1, and so on). - SystemLevel uint8 - - // ResourceOrder provides the system with the order in which Power - // Resources must be enabled or disabled. Each unique resourceorder - // value represents a level, and any number of power resources may have - // the same level. Power Resource levels are enabled from low values to - // high values and are disabled from high values to low values. - ResourceOrder uint16 -} - -// NewPowerResource creates a new power resource object. -func NewPowerResource(tableHandle uint8, name string) *PowerResource { - return &PowerResource{ - Scope: Scope{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpPowerRes, - tableHandle: tableHandle, - }, - name: name, - }, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *PowerResource) SetArg(argIndex uint8, arg interface{}) bool { - var ( - ok bool - uintVal uint64 - ) - - switch argIndex { - case 0: - // Arg0 is the name but it is actually defined when creating the entity - ok = true - case 1: - // arg1 is the system level (ByteData) - uintVal, ok = arg.(uint64) - ent.SystemLevel = uint8(uintVal) - case 2: - // arg2 is the resource order (WordData) - uintVal, ok = arg.(uint64) - ent.ResourceOrder = uint16(uintVal) - } - return ok -} - -// ThermalZone describes a AML thermal zone entity. -type ThermalZone struct { - Scope -} - -// NewThermalZone creates a new thermal zone object. -func NewThermalZone(tableHandle uint8, name string) *ThermalZone { - return &ThermalZone{ - Scope: Scope{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpThermalZone, - tableHandle: tableHandle, - }, - name: name, - }, - }, - } -} - -// Mutex describes a AML mutex entity. -type Mutex struct { - GenericNamed - - // IsGlobal is set to true for the pre-defined global mutex (\_GL object) - IsGlobal bool - - SyncLevel uint8 -} - -// NewMutex creates a new mutex object. -func NewMutex(tableHandle uint8) *Mutex { - return &Mutex{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpMutex, - tableHandle: tableHandle, - }, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Mutex) SetArg(argIndex uint8, arg interface{}) bool { - var ok bool - switch argIndex { - case 0: - // arg 0 is the mutex name - ent.name, ok = arg.(string) - case 1: - // arg1 is the sync level (bits 0:3) - var syncLevel uint64 - syncLevel, ok = arg.(uint64) - ent.SyncLevel = uint8(syncLevel) & 0xf - } - return ok -} - -// Event represents a named ACPI sync event. -type Event struct { - GenericNamed -} - -// NewEvent creates a new event object. -func NewEvent(tableHandle uint8) *Event { - return &Event{ - GenericNamed: GenericNamed{ - Generic: Generic{ - op: OpEvent, - tableHandle: tableHandle, - }, - }, - } -} - -// Package is an entity that contains one of the following entity types: -// - constant data objects (int, string, buffer or package) -// - named references to data objects (int, string, buffer, buffer field, -// field unit or package) -// - named references to non-data objects (device, event, method, mutex, region -// power resource, processor or thermal zone) -type Package struct { - Generic - - // The number of elements in the package. In most cases, the package - // length is known at compile-time and will be emitted as a const - // value. However, the standard also allows dynamic definition of - // package elements (e.g. inside a method). In the latter case (or if - // the package contains more that 255 elements) this will be a - // expression that the VM needs to evaluate as an integer value. - NumElements interface{} -} - -// NewPackage creates a new package entity with the OpPackage or the -// OpVarPackage opcodes. -func NewPackage(op AMLOpcode, tableHandle uint8) *Package { - return &Package{ - Generic: Generic{ - op: op, - tableHandle: tableHandle, - }, - } -} - -// SetArg adds an argument value at the specified argument index. -func (ent *Package) SetArg(argIndex uint8, arg interface{}) bool { - // Package entities define the number of elements as the first arg. - if argIndex == 0 { - ent.NumElements = arg - return true - } - - return ent.Generic.SetArg(argIndex, arg) -} diff --git a/src/gopheros/device/acpi/aml/entity/entity_test.go b/src/gopheros/device/acpi/aml/entity/entity_test.go deleted file mode 100644 index 9df2eed..0000000 --- a/src/gopheros/device/acpi/aml/entity/entity_test.go +++ /dev/null @@ -1,295 +0,0 @@ -package entity - -import ( - "reflect" - "testing" -) - -func TestEntityMethods(t *testing.T) { - namedConst := NewConst(OpDwordPrefix, 42, "foo") - namedConst.SetName("TAG0") - - specs := []struct { - ent Entity - expOp AMLOpcode - expName string - }{ - {NewGeneric(OpNoop, 42), OpNoop, ""}, - {NewGenericNamed(OpAcquire, 42), OpAcquire, ""}, - {namedConst, OpDwordPrefix, "TAG0"}, - {NewScope(OpScope, 42, "_SB_"), OpScope, "_SB_"}, - {NewBuffer(42), OpBuffer, ""}, - {NewBufferField(OpCreateByteField, 42, 8), OpCreateByteField, ""}, - {NewField(42), OpField, ""}, - {NewIndexField(42), OpIndexField, ""}, - {NewBankField(42), OpBankField, ""}, - {NewReference(42, "TRG0"), OpName, ""}, - {NewMethod(42, "FOO0"), OpMethod, "FOO0"}, - {NewInvocation(42, NewMethod(42, "MTH0"), nil), OpMethodInvocation, ""}, - {NewMutex(42), OpMutex, ""}, - {NewDevice(42, "DEV0"), OpDevice, "DEV0"}, - {NewProcessor(42, "CPU0"), OpProcessor, "CPU0"}, - {NewPowerResource(42, "POW0"), OpPowerRes, "POW0"}, - {NewThermalZone(42, "THE0"), OpThermalZone, "THE0"}, - {NewEvent(42), OpEvent, ""}, - {NewRegion(42), OpOpRegion, ""}, - {NewFieldUnit(42, "FOO0"), OpFieldUnit, "FOO0"}, - {NewPackage(OpPackage, 42), OpPackage, ""}, - } - - t.Run("opcode and name getter", func(t *testing.T) { - for specIndex, spec := range specs { - if got := spec.ent.Opcode(); got != spec.expOp { - t.Errorf("[spec %d] expected to get back opcode %d; got %d", specIndex, spec.expOp, got) - } - - if got := spec.ent.Name(); got != spec.expName { - t.Errorf("[spec %d] expected to get name: %q; got %q", specIndex, spec.expName, got) - } - } - }) - - t.Run("table handle getter", func(t *testing.T) { - exp := uint8(42) - for specIndex, spec := range specs { - if got := spec.ent.TableHandle(); got != exp { - t.Errorf("[spec %d] expected to get back handle %d; got %d", specIndex, exp, got) - } - } - }) - - t.Run("append/remove/get parent methods", func(t *testing.T) { - parent := NewScope(OpScope, 2, "_SB_") - parent.name = `\` - - for specIndex, spec := range specs { - parent.Append(spec.ent) - if got := spec.ent.Parent(); got != parent { - t.Errorf("[spec %d] expected to get back parent %v; got %v", specIndex, parent, got) - } - - if got := parent.Last(); got != spec.ent { - t.Errorf("[spec %d] expected parent's last entity to be the one just appended", specIndex) - } - - parent.Remove(spec.ent) - } - - if got := len(parent.Children()); got != 0 { - t.Fatalf("expected parent not to have any child nodes; got %d", got) - } - }) - - t.Run("FieldAccessTypeProvider implementers", func(t *testing.T) { - for specIndex, spec := range specs { - provider, ok := spec.ent.(FieldAccessTypeProvider) - if !ok { - continue - } - - if exp, got := FieldAccessTypeAny, provider.DefaultAccessType(); got != exp { - t.Errorf("[spec %d] expected provider to return access type: %d; got %d", specIndex, exp, got) - } - } - }) -} - -func TestEntityArgAssignment(t *testing.T) { - specs := []struct { - ent Entity - argList []interface{} - expArgList []interface{} - limitedArgs bool - }{ - { - NewGeneric(1, 2), - []interface{}{"foo", 1, "bar"}, - []interface{}{"foo", 1, "bar"}, - false, - }, - { - NewGenericNamed(1, 2), - []interface{}{"foo", 1, "bar"}, - []interface{}{1, "bar"}, // GenericNamed uses arg0 as the name - false, - }, - { - NewConst(1, 2, 3), - []interface{}{"foo"}, - nil, // Const populates its internal state using the arg 0 - true, - }, - { - NewBuffer(2), - []interface{}{1, []byte{}}, - nil, // Buffer populates its internal state using the first 2 args - true, - }, - { - NewBufferField(OpCreateDWordField, 2, 32), - []interface{}{"a", "b", "c"}, - nil, // Buffer populates its internal state using the first 3 args (opCreateDwordField) - false, - }, - { - NewBufferField(1, 2, 0), - []interface{}{"a", "b", 10, "c"}, - nil, // Buffer populates its internal state using the first 4 args (opCreateField) - true, - }, - { - NewRegion(2), - []interface{}{"REG0", uint64(0x4), 0, 10}, - nil, // Region populates its internal state using the first 4 args - true, - }, - { - NewMutex(2), - []interface{}{"MUT0", uint64(1)}, - nil, // Mutex populates its internal state using the first 2 args - true, - }, - { - NewProcessor(2, "CPU0"), - []interface{}{uint64(1), uint64(0xdeadc0de), uint64(0)}, - nil, // Processor populates its internal state using the first 3 args - true, - }, - { - NewPowerResource(2, "POW0"), - []interface{}{uint64(2), uint64(1)}, - nil, // PowerResource populates its internal state using the first 2 args - true, - }, - { - NewMethod(2, "MTH0"), - []interface{}{"arg0 ignored", uint64(0x42)}, - nil, // Method populates its internal state using the first 2 args - true, - }, - { - NewPackage(OpPackage, 2), - []interface{}{uint64(1), NewConst(OpDwordPrefix, 2, uint64(42))}, - []interface{}{NewConst(OpDwordPrefix, 2, uint64(42))}, - false, - }, - { - NewField(2), - []interface{}{"REG0", uint64(128)}, - nil, // Field populates its internal state using the first 2 args - true, - }, - { - NewIndexField(2), - []interface{}{"REG0", "DAT0", uint64(128)}, - nil, // IndexField populates its internal state using the first 3 args - true, - }, - { - NewBankField(2), - []interface{}{"REG0", "BNK0", uint64(0xf00f), uint64(128)}, - nil, // BankField populates its internal state using the first 4 args - true, - }, - } - -nextSpec: - for specIndex, spec := range specs { - for i, arg := range spec.argList { - if !spec.ent.SetArg(uint8(i), arg) { - t.Errorf("[spec %d] error setting arg %d", specIndex, i) - continue nextSpec - } - } - - if spec.limitedArgs { - if spec.ent.SetArg(uint8(len(spec.argList)), nil) { - t.Errorf("[spec %d] expected additional calls to setArg to return false", specIndex) - continue nextSpec - } - } - - if got := spec.ent.Args(); !reflect.DeepEqual(got, spec.expArgList) { - t.Errorf("[spec %d] expected to get back arg list %v; got %v", specIndex, spec.expArgList, got) - } - } -} - -func TestLazySymbolResolver(t *testing.T) { - root := NewScope(OpScope, 42, `\`) - reg0 := NewRegion(42) - reg0.SetArg(0, "REG0") - root.Append(reg0) - root.Append(NewFieldUnit(42, "FLD0")) - root.Append(NewMethod(42, "MTH0")) - - specs := []struct { - ent Entity - expErr string - }{ - { - &Field{RegionName: "MISSING"}, - "could not resolve referenced field region: MISSING", - }, - { - &Field{RegionName: "REG0"}, - "", - }, - { - &IndexField{IndexRegName: "UNKNOWN"}, - "could not resolve referenced index register: UNKNOWN", - }, - { - &IndexField{IndexRegName: "FLD0", DataRegName: "UNKNOWN"}, - "could not resolve referenced data register: UNKNOWN", - }, - { - &IndexField{IndexRegName: "FLD0", DataRegName: "FLD0"}, - "", - }, - { - &BankField{RegionName: "MISSING"}, - "could not resolve referenced field region: MISSING", - }, - { - &BankField{RegionName: "REG0", BankFieldUnitName: "UNKNOWN"}, - "could not resolve referenced bank register field: UNKNOWN", - }, - { - &BankField{RegionName: "REG0", BankFieldUnitName: "FLD0"}, - "", - }, - { - &FieldUnit{ - GenericNamed: GenericNamed{name: "FLD0"}, - ConnectionName: "MISSING", - }, - "[field unit: FLD0] could not resolve connection reference: MISSING", - }, - { - // No connection reference - &FieldUnit{}, - "", - }, - { - &FieldUnit{ConnectionName: "FLD0"}, - "", - }, - { - &Reference{TargetName: "MISSING"}, - `could not resolve referenced symbol: MISSING; parent: \`, - }, - { - &Reference{TargetName: "FLD0"}, - "", - }, - } - - for specIndex, spec := range specs { - root.Append(spec.ent) - err := spec.ent.(LazyRefResolver).ResolveSymbolRefs(root) - if spec.expErr != "" && (err == nil || err.Message != spec.expErr) { - t.Errorf("[spec %d] expected ResolveReferences to return error %q; got: %v", specIndex, spec.expErr, err) - } - } -} diff --git a/src/gopheros/device/acpi/aml/entity/opcode.go b/src/gopheros/device/acpi/aml/entity/opcode.go deleted file mode 100644 index 0a3abf2..0000000 --- a/src/gopheros/device/acpi/aml/entity/opcode.go +++ /dev/null @@ -1,430 +0,0 @@ -package entity - -// AMLOpcode describes an AML opcode. While AML supports 256 opcodes, some of -// them are specified using a combination of an extension prefix and a code. To -// map each opcode into a single unique value the parser uses an uint16 -// representation of the opcode values. -type AMLOpcode uint16 - -// List of AML opcodes -const ( - // Regular opcode list - OpZero = AMLOpcode(0x00) - OpOne = AMLOpcode(0x01) - OpAlias = AMLOpcode(0x06) - OpName = AMLOpcode(0x08) - OpBytePrefix = AMLOpcode(0x0a) - OpWordPrefix = AMLOpcode(0x0b) - OpDwordPrefix = AMLOpcode(0x0c) - OpStringPrefix = AMLOpcode(0x0d) - OpQwordPrefix = AMLOpcode(0x0e) - OpScope = AMLOpcode(0x10) - OpBuffer = AMLOpcode(0x11) - OpPackage = AMLOpcode(0x12) - OpVarPackage = AMLOpcode(0x13) - OpMethod = AMLOpcode(0x14) - OpExternal = AMLOpcode(0x15) - OpLocal0 = AMLOpcode(0x60) - OpLocal1 = AMLOpcode(0x61) - OpLocal2 = AMLOpcode(0x62) - OpLocal3 = AMLOpcode(0x63) - OpLocal4 = AMLOpcode(0x64) - OpLocal5 = AMLOpcode(0x65) - OpLocal6 = AMLOpcode(0x66) - OpLocal7 = AMLOpcode(0x67) - OpArg0 = AMLOpcode(0x68) - OpArg1 = AMLOpcode(0x69) - OpArg2 = AMLOpcode(0x6a) - OpArg3 = AMLOpcode(0x6b) - OpArg4 = AMLOpcode(0x6c) - OpArg5 = AMLOpcode(0x6d) - OpArg6 = AMLOpcode(0x6e) - OpStore = AMLOpcode(0x70) - OpRefOf = AMLOpcode(0x71) - OpAdd = AMLOpcode(0x72) - OpConcat = AMLOpcode(0x73) - OpSubtract = AMLOpcode(0x74) - OpIncrement = AMLOpcode(0x75) - OpDecrement = AMLOpcode(0x76) - OpMultiply = AMLOpcode(0x77) - OpDivide = AMLOpcode(0x78) - OpShiftLeft = AMLOpcode(0x79) - OpShiftRight = AMLOpcode(0x7a) - OpAnd = AMLOpcode(0x7b) - OpNand = AMLOpcode(0x7c) - OpOr = AMLOpcode(0x7d) - OpNor = AMLOpcode(0x7e) - OpXor = AMLOpcode(0x7f) - OpNot = AMLOpcode(0x80) - OpFindSetLeftBit = AMLOpcode(0x81) - OpFindSetRightBit = AMLOpcode(0x82) - OpDerefOf = AMLOpcode(0x83) - OpConcatRes = AMLOpcode(0x84) - OpMod = AMLOpcode(0x85) - OpNotify = AMLOpcode(0x86) - OpSizeOf = AMLOpcode(0x87) - OpIndex = AMLOpcode(0x88) - OpMatch = AMLOpcode(0x89) - OpCreateDWordField = AMLOpcode(0x8a) - OpCreateWordField = AMLOpcode(0x8b) - OpCreateByteField = AMLOpcode(0x8c) - OpCreateBitField = AMLOpcode(0x8d) - OpObjectType = AMLOpcode(0x8e) - OpCreateQWordField = AMLOpcode(0x8f) - OpLand = AMLOpcode(0x90) - OpLor = AMLOpcode(0x91) - OpLnot = AMLOpcode(0x92) - OpLEqual = AMLOpcode(0x93) - OpLGreater = AMLOpcode(0x94) - OpLLess = AMLOpcode(0x95) - OpToBuffer = AMLOpcode(0x96) - OpToDecimalString = AMLOpcode(0x97) - OpToHexString = AMLOpcode(0x98) - OpToInteger = AMLOpcode(0x99) - OpToString = AMLOpcode(0x9c) - OpCopyObject = AMLOpcode(0x9d) - OpMid = AMLOpcode(0x9e) - OpContinue = AMLOpcode(0x9f) - OpIf = AMLOpcode(0xa0) - OpElse = AMLOpcode(0xa1) - OpWhile = AMLOpcode(0xa2) - OpNoop = AMLOpcode(0xa3) - OpReturn = AMLOpcode(0xa4) - OpBreak = AMLOpcode(0xa5) - OpBreakPoint = AMLOpcode(0xcc) - OpOnes = AMLOpcode(0xff) - // Extended opcodes - OpMutex = AMLOpcode(0xff + 0x01) - OpEvent = AMLOpcode(0xff + 0x02) - OpCondRefOf = AMLOpcode(0xff + 0x12) - OpCreateField = AMLOpcode(0xff + 0x13) - OpLoadTable = AMLOpcode(0xff + 0x1f) - OpLoad = AMLOpcode(0xff + 0x20) - OpStall = AMLOpcode(0xff + 0x21) - OpSleep = AMLOpcode(0xff + 0x22) - OpAcquire = AMLOpcode(0xff + 0x23) - OpSignal = AMLOpcode(0xff + 0x24) - OpWait = AMLOpcode(0xff + 0x25) - OpReset = AMLOpcode(0xff + 0x26) - OpRelease = AMLOpcode(0xff + 0x27) - OpFromBCD = AMLOpcode(0xff + 0x28) - OpToBCD = AMLOpcode(0xff + 0x29) - OpUnload = AMLOpcode(0xff + 0x2a) - OpRevision = AMLOpcode(0xff + 0x30) - OpDebug = AMLOpcode(0xff + 0x31) - OpFatal = AMLOpcode(0xff + 0x32) - OpTimer = AMLOpcode(0xff + 0x33) - OpOpRegion = AMLOpcode(0xff + 0x80) - OpField = AMLOpcode(0xff + 0x81) - OpDevice = AMLOpcode(0xff + 0x82) - OpProcessor = AMLOpcode(0xff + 0x83) - OpPowerRes = AMLOpcode(0xff + 0x84) - OpThermalZone = AMLOpcode(0xff + 0x85) - OpIndexField = AMLOpcode(0xff + 0x86) - OpBankField = AMLOpcode(0xff + 0x87) - OpDataRegion = AMLOpcode(0xff + 0x88) - // Special internal opcodes which are not part of the spec; these are - // for internal use by the AML interpreter. - OpFieldUnit = AMLOpcode(0xff + 0xfd) - OpMethodInvocation = AMLOpcode(0xff + 0xfe) -) - -// String implements fmt.Stringer for the AMLOpcode type. -func (op AMLOpcode) String() string { - switch op { - case OpZero: - return "Zero" - case OpOne: - return "One" - case OpAlias: - return "Alias" - case OpName: - return "Name" - case OpBytePrefix: - return "Byte" - case OpWordPrefix: - return "Word" - case OpDwordPrefix: - return "Dword" - case OpStringPrefix: - return "String" - case OpQwordPrefix: - return "Qword" - case OpScope: - return "Scope" - case OpBuffer: - return "Buffer" - case OpPackage: - return "Package" - case OpVarPackage: - return "VarPackage" - case OpMethod: - return "Method" - case OpExternal: - return "External" - case OpLocal0: - return "Local0" - case OpLocal1: - return "Local1" - case OpLocal2: - return "Local2" - case OpLocal3: - return "Local3" - case OpLocal4: - return "Local4" - case OpLocal5: - return "Local5" - case OpLocal6: - return "Local6" - case OpLocal7: - return "Local7" - case OpArg0: - return "Arg0" - case OpArg1: - return "Arg1" - case OpArg2: - return "Arg2" - case OpArg3: - return "Arg3" - case OpArg4: - return "Arg4" - case OpArg5: - return "Arg5" - case OpArg6: - return "Arg6" - case OpStore: - return "Store" - case OpRefOf: - return "RefOf" - case OpAdd: - return "Add" - case OpConcat: - return "Concat" - case OpSubtract: - return "Subtract" - case OpIncrement: - return "Increment" - case OpDecrement: - return "Decrement" - case OpMultiply: - return "Multiply" - case OpDivide: - return "Divide" - case OpShiftLeft: - return "ShiftLeft" - case OpShiftRight: - return "ShiftRight" - case OpAnd: - return "And" - case OpNand: - return "Nand" - case OpOr: - return "Or" - case OpNor: - return "Nor" - case OpXor: - return "Xor" - case OpNot: - return "Not" - case OpFindSetLeftBit: - return "FindSetLeftBit" - case OpFindSetRightBit: - return "FindSetRightBit" - case OpDerefOf: - return "DerefOf" - case OpConcatRes: - return "ConcatRes" - case OpMod: - return "Mod" - case OpNotify: - return "Notify" - case OpSizeOf: - return "SizeOf" - case OpIndex: - return "Index" - case OpMatch: - return "Match" - case OpCreateDWordField: - return "CreateDWordField" - case OpCreateWordField: - return "CreateWordField" - case OpCreateByteField: - return "CreateByteField" - case OpCreateBitField: - return "CreateBitField" - case OpObjectType: - return "ObjectType" - case OpCreateQWordField: - return "CreateQWordField" - case OpLand: - return "Land" - case OpLor: - return "Lor" - case OpLnot: - return "Lnot" - case OpLEqual: - return "LEqual" - case OpLGreater: - return "LGreater" - case OpLLess: - return "LLess" - case OpToBuffer: - return "ToBuffer" - case OpToDecimalString: - return "ToDecimalString" - case OpToHexString: - return "ToHexString" - case OpToInteger: - return "ToInteger" - case OpToString: - return "ToString" - case OpCopyObject: - return "CopyObject" - case OpMid: - return "Mid" - case OpContinue: - return "Continue" - case OpIf: - return "If" - case OpElse: - return "Else" - case OpWhile: - return "While" - case OpNoop: - return "Noop" - case OpReturn: - return "Return" - case OpBreak: - return "Break" - case OpBreakPoint: - return "BreakPoint" - case OpOnes: - return "Ones" - case OpMutex: - return "Mutex" - case OpEvent: - return "Event" - case OpCondRefOf: - return "CondRefOf" - case OpCreateField: - return "CreateField" - case OpLoadTable: - return "LoadTable" - case OpLoad: - return "Load" - case OpStall: - return "Stall" - case OpSleep: - return "Sleep" - case OpAcquire: - return "Acquire" - case OpSignal: - return "Signal" - case OpWait: - return "Wait" - case OpReset: - return "Reset" - case OpRelease: - return "Release" - case OpFromBCD: - return "FromBCD" - case OpToBCD: - return "ToBCD" - case OpUnload: - return "Unload" - case OpRevision: - return "Revision" - case OpDebug: - return "Debug" - case OpFatal: - return "Fatal" - case OpTimer: - return "Timer" - case OpOpRegion: - return "OpRegion" - case OpField: - return "Field" - case OpDevice: - return "Device" - case OpProcessor: - return "Processor" - case OpPowerRes: - return "PowerRes" - case OpThermalZone: - return "ThermalZone" - case OpIndexField: - return "IndexField" - case OpBankField: - return "BankField" - case OpDataRegion: - return "DataRegion" - default: - return "unknown" - } -} - -// OpIsLocalArg returns true if this opcode represents any of the supported local -// function args 0 to 7. -func OpIsLocalArg(op AMLOpcode) bool { - return op >= OpLocal0 && op <= OpLocal7 -} - -// OpIsMethodArg returns true if this opcode represents any of the supported -// input function args 0 to 6. -func OpIsMethodArg(op AMLOpcode) bool { - return op >= OpArg0 && op <= OpArg6 -} - -// OpIsArg returns true if this opcode is either a local or a method arg. -func OpIsArg(op AMLOpcode) bool { - return OpIsLocalArg(op) || OpIsMethodArg(op) -} - -// OpIsDataObject returns true if this opcode is part of a DataObject definition -// -// Grammar: -// DataObject := ComputationalData | DefPackage | DefVarPackage -// ComputationalData := ByteConst | WordConst | DWordConst | QWordConst | String | ConstObj | RevisionOp | DefBuffer -// ConstObj := ZeroOp | OneOp | OnesOp -func OpIsDataObject(op AMLOpcode) bool { - switch op { - case OpBytePrefix, OpWordPrefix, OpDwordPrefix, OpQwordPrefix, OpStringPrefix, - OpZero, OpOne, OpOnes, OpRevision, OpBuffer, OpPackage, OpVarPackage: - return true - default: - return false - } -} - -// OpIsType2 returns true if this is a Type2Opcode. -// -// Grammar: -// Type2Opcode := DefAcquire | DefAdd | DefAnd | DefBuffer | DefConcat | -// DefConcatRes | DefCondRefOf | DefCopyObject | DefDecrement | -// DefDerefOf | DefDivide | DefFindSetLeftBit | DefFindSetRightBit | -// DefFromBCD | DefIncrement | DefIndex | DefLAnd | DefLEqual | -// DefLGreater | DefLGreaterEqual | DefLLess | DefLLessEqual | DefMid | -// DefLNot | DefLNotEqual | DefLoadTable | DefLOr | DefMatch | DefMod | -// DefMultiply | DefNAnd | DefNOr | DefNot | DefObjectType | DefOr | -// DefPackage | DefVarPackage | DefRefOf | DefShiftLeft | DefShiftRight | -// DefSizeOf | DefStore | DefSubtract | DefTimer | DefToBCD | DefToBuffer | -// DefToDecimalString | DefToHexString | DefToInteger | DefToString | -// DefWait | DefXOr -func OpIsType2(op AMLOpcode) bool { - switch op { - case OpAcquire, OpAdd, OpAnd, OpBuffer, OpConcat, - OpConcatRes, OpCondRefOf, OpCopyObject, OpDecrement, - OpDerefOf, OpDivide, OpFindSetLeftBit, OpFindSetRightBit, - OpFromBCD, OpIncrement, OpIndex, OpLand, OpLEqual, - OpLGreater, OpLLess, OpMid, - OpLnot, OpLoadTable, OpLor, OpMatch, OpMod, - OpMultiply, OpNand, OpNor, OpNot, OpObjectType, OpOr, - OpPackage, OpVarPackage, OpRefOf, OpShiftLeft, OpShiftRight, - OpSizeOf, OpStore, OpSubtract, OpTimer, OpToBCD, OpToBuffer, - OpToDecimalString, OpToHexString, OpToInteger, OpToString, - OpWait, OpXor: - return true - default: - return false - } -} diff --git a/src/gopheros/device/acpi/aml/entity/opcode_test.go b/src/gopheros/device/acpi/aml/entity/opcode_test.go deleted file mode 100644 index 23c0bdd..0000000 --- a/src/gopheros/device/acpi/aml/entity/opcode_test.go +++ /dev/null @@ -1,237 +0,0 @@ -package entity - -import "testing" - -func TestOpcodeToString(t *testing.T) { - opcodeList := []AMLOpcode{ - OpZero, - OpOne, - OpAlias, - OpName, - OpBytePrefix, - OpWordPrefix, - OpDwordPrefix, - OpStringPrefix, - OpQwordPrefix, - OpScope, - OpBuffer, - OpPackage, - OpVarPackage, - OpMethod, - OpExternal, - OpLocal0, - OpLocal1, - OpLocal2, - OpLocal3, - OpLocal4, - OpLocal5, - OpLocal6, - OpLocal7, - OpArg0, - OpArg1, - OpArg2, - OpArg3, - OpArg4, - OpArg5, - OpArg6, - OpStore, - OpRefOf, - OpAdd, - OpConcat, - OpSubtract, - OpIncrement, - OpDecrement, - OpMultiply, - OpDivide, - OpShiftLeft, - OpShiftRight, - OpAnd, - OpNand, - OpOr, - OpNor, - OpXor, - OpNot, - OpFindSetLeftBit, - OpFindSetRightBit, - OpDerefOf, - OpConcatRes, - OpMod, - OpNotify, - OpSizeOf, - OpIndex, - OpMatch, - OpCreateDWordField, - OpCreateWordField, - OpCreateByteField, - OpCreateBitField, - OpObjectType, - OpCreateQWordField, - OpLand, - OpLor, - OpLnot, - OpLEqual, - OpLGreater, - OpLLess, - OpToBuffer, - OpToDecimalString, - OpToHexString, - OpToInteger, - OpToString, - OpCopyObject, - OpMid, - OpContinue, - OpIf, - OpElse, - OpWhile, - OpNoop, - OpReturn, - OpBreak, - OpBreakPoint, - OpOnes, - OpMutex, - OpEvent, - OpCondRefOf, - OpCreateField, - OpLoadTable, - OpLoad, - OpStall, - OpSleep, - OpAcquire, - OpSignal, - OpWait, - OpReset, - OpRelease, - OpFromBCD, - OpToBCD, - OpUnload, - OpRevision, - OpDebug, - OpFatal, - OpTimer, - OpOpRegion, - OpField, - OpDevice, - OpProcessor, - OpPowerRes, - OpThermalZone, - OpIndexField, - OpBankField, - OpDataRegion, - } - - for specIndex, op := range opcodeList { - if op.String() == "unknown" { - t.Errorf("[spec %d] op 0x%x String() returned \"unknown\"", specIndex, op) - } - } - - // Also test invalid opcode - if got := AMLOpcode(0xffff).String(); got != "unknown" { - t.Fatalf("expected String() for invalid opcode to return \"unknown\"; got: %q", got) - } -} - -func TestOpcodeIsX(t *testing.T) { - specs := []struct { - op AMLOpcode - testFn func(AMLOpcode) bool - want bool - }{ - // OpIsLocalArg - {OpLocal0, OpIsLocalArg, true}, - {OpLocal1, OpIsLocalArg, true}, - {OpLocal2, OpIsLocalArg, true}, - {OpLocal3, OpIsLocalArg, true}, - {OpLocal4, OpIsLocalArg, true}, - {OpLocal5, OpIsLocalArg, true}, - {OpLocal6, OpIsLocalArg, true}, - {OpLocal7, OpIsLocalArg, true}, - {OpArg0, OpIsLocalArg, false}, - {OpDivide, OpIsLocalArg, false}, - // OpIsMethodArg - {OpArg0, OpIsMethodArg, true}, - {OpArg1, OpIsMethodArg, true}, - {OpArg2, OpIsMethodArg, true}, - {OpArg3, OpIsMethodArg, true}, - {OpArg4, OpIsMethodArg, true}, - {OpArg5, OpIsMethodArg, true}, - {OpArg6, OpIsMethodArg, true}, - {OpLocal7, OpIsMethodArg, false}, - {OpIf, OpIsMethodArg, false}, - // OpIsArg - {OpLocal5, OpIsArg, true}, - {OpArg1, OpIsArg, true}, - {OpDivide, OpIsArg, false}, - // OpIsType2 - {OpAcquire, OpIsType2, true}, - {OpAdd, OpIsType2, true}, - {OpAnd, OpIsType2, true}, - {OpBuffer, OpIsType2, true}, - {OpConcat, OpIsType2, true}, - {OpConcatRes, OpIsType2, true}, - {OpCondRefOf, OpIsType2, true}, - {OpCopyObject, OpIsType2, true}, - {OpDecrement, OpIsType2, true}, - {OpDerefOf, OpIsType2, true}, - {OpDivide, OpIsType2, true}, - {OpFindSetLeftBit, OpIsType2, true}, - {OpFindSetRightBit, OpIsType2, true}, - {OpFromBCD, OpIsType2, true}, - {OpIncrement, OpIsType2, true}, - {OpIndex, OpIsType2, true}, - {OpLand, OpIsType2, true}, - {OpLEqual, OpIsType2, true}, - {OpLGreater, OpIsType2, true}, - {OpLLess, OpIsType2, true}, - {OpMid, OpIsType2, true}, - {OpLnot, OpIsType2, true}, - {OpLoadTable, OpIsType2, true}, - {OpLor, OpIsType2, true}, - {OpMatch, OpIsType2, true}, - {OpMod, OpIsType2, true}, - {OpMultiply, OpIsType2, true}, - {OpNand, OpIsType2, true}, - {OpNor, OpIsType2, true}, - {OpNot, OpIsType2, true}, - {OpObjectType, OpIsType2, true}, - {OpOr, OpIsType2, true}, - {OpPackage, OpIsType2, true}, - {OpVarPackage, OpIsType2, true}, - {OpRefOf, OpIsType2, true}, - {OpShiftLeft, OpIsType2, true}, - {OpShiftRight, OpIsType2, true}, - {OpSizeOf, OpIsType2, true}, - {OpStore, OpIsType2, true}, - {OpSubtract, OpIsType2, true}, - {OpTimer, OpIsType2, true}, - {OpToBCD, OpIsType2, true}, - {OpToBuffer, OpIsType2, true}, - {OpToDecimalString, OpIsType2, true}, - {OpToHexString, OpIsType2, true}, - {OpToInteger, OpIsType2, true}, - {OpToString, OpIsType2, true}, - {OpWait, OpIsType2, true}, - {OpXor, OpIsType2, true}, - {OpBytePrefix, OpIsType2, false}, - // OpIsDataObject - {OpBytePrefix, OpIsDataObject, true}, - {OpWordPrefix, OpIsDataObject, true}, - {OpDwordPrefix, OpIsDataObject, true}, - {OpQwordPrefix, OpIsDataObject, true}, - {OpStringPrefix, OpIsDataObject, true}, - {OpZero, OpIsDataObject, true}, - {OpOne, OpIsDataObject, true}, - {OpOnes, OpIsDataObject, true}, - {OpRevision, OpIsDataObject, true}, - {OpBuffer, OpIsDataObject, true}, - {OpPackage, OpIsDataObject, true}, - {OpVarPackage, OpIsDataObject, true}, - {OpLor, OpIsDataObject, false}, - } - - for specIndex, spec := range specs { - if got := spec.testFn(spec.op); got != spec.want { - t.Errorf("[spec %d] opcode %q: expected to get %t; got %t", specIndex, spec.op, spec.want, got) - } - } -} diff --git a/src/gopheros/device/acpi/aml/entity/scope.go b/src/gopheros/device/acpi/aml/entity/scope.go deleted file mode 100644 index 8537950..0000000 --- a/src/gopheros/device/acpi/aml/entity/scope.go +++ /dev/null @@ -1,138 +0,0 @@ -package entity - -import "strings" - -// ResolveScopedPath examines a path expression and attempts to break it down -// into a parent and child segment. The parent segment is looked up via the -// regular scope rules specified in page 252 of the ACPI 6.2 spec. If the -// parent scope is found then the function returns back the parent entity and -// the name of the child that should be appended to it. If the expression -// lookup fails then the function returns nil, "". -func ResolveScopedPath(curScope, rootScope Container, expr string) (parent Container, name string) { - if len(expr) <= 1 { - return nil, "" - } - - // Pattern looks like \FOO or ^+BAR or BAZ (relative to curScope) - lastDotIndex := strings.LastIndexByte(expr, '.') - if lastDotIndex == -1 { - switch expr[0] { - case '\\': - return rootScope, expr[1:] - case '^': - lastHatIndex := strings.LastIndexByte(expr, '^') - if target := FindInScope(curScope, rootScope, expr[:lastHatIndex+1]); target != nil { - return target.(Container), expr[lastHatIndex+1:] - } - - return nil, "" - default: - return curScope, expr - } - } - - // Pattern looks like: \FOO.BAR.BAZ or ^+FOO.BAR.BAZ or FOO.BAR.BAZ - if target := FindInScope(curScope, rootScope, expr[:lastDotIndex]); target != nil { - return target.(Container), expr[lastDotIndex+1:] - } - - return nil, "" -} - -// FindInScope attempts to find an object with the given name using the rules -// specified in page 252 of the ACPI 6.2 spec: -// -// There are two types of namespace paths: an absolute namespace path (that is, -// one that starts with a ‘\’ prefix), and a relative namespace path (that is, -// one that is relative to the current namespace). The namespace search rules -// discussed above, only apply to single NameSeg paths, which is a relative -// namespace path. For those relative name paths that contain multiple NameSegs -// or Parent Prefixes, ‘^’, the search rules do not apply. If the search rules -// do not apply to a relative namespace path, the namespace object is looked up -// relative to the current namespace -func FindInScope(curScope, rootScope Container, name string) Entity { - nameLen := len(name) - if nameLen == 0 { - return nil - } - - switch { - case name[0] == '\\': // relative to the root scope - if nameLen > 1 { - return findRelativeToScope(rootScope, name[1:]) - } - - // Name was just `\`; this matches the root namespace - return rootScope - case name[0] == '^': // relative to the parent scope(s) - for startIndex := 0; startIndex < nameLen; startIndex++ { - switch name[startIndex] { - case '^': - curScope = curScope.Parent() - - // No parent to visit - if curScope == nil { - return nil - } - default: - // Found the start of the name. Look it up relative to curNs - return findRelativeToScope(curScope, name[startIndex:]) - } - } - - // Name was just a sequence of '^'; this matches the last curScope value - return curScope - case strings.ContainsRune(name, '.'): - // If the name contains any '.' then we still need to look it - // up relative to the current scope - return findRelativeToScope(curScope, name) - default: - // We can apply the search rules described by the spec - for s := curScope; s != nil; s = s.Parent() { - for _, child := range s.Children() { - if child.Name() == name { - return child - } - } - } - } - - // Not found - return nil -} - -// findRelativeToScope returns the Entity referenced by path relative -// to the provided Namespace. If the name contains dots, each segment -// is used to access a nested namespace. If the path does not point -// to a NamedObject then lookupRelativeTo returns back nil. -func findRelativeToScope(ns Container, path string) Entity { - var matchName string -matchNextPathSegment: - for { - dotSepIndex := strings.IndexRune(path, '.') - if dotSepIndex != -1 { - matchName = path[:dotSepIndex] - path = path[dotSepIndex+1:] - - // Search for a scoped child named "matchName" - for _, child := range ns.Children() { - if childNs, ok := child.(Container); ok && childNs.Name() == matchName { - ns = childNs - continue matchNextPathSegment - } - } - } else { - // Search for a child named "name" - for _, child := range ns.Children() { - if child.Name() == path { - return child - } - } - } - - // Next segment in the path was not found or last segment not found - break - } - - return nil -} diff --git a/src/gopheros/device/acpi/aml/entity/scope_test.go b/src/gopheros/device/acpi/aml/entity/scope_test.go deleted file mode 100644 index 5d22117..0000000 --- a/src/gopheros/device/acpi/aml/entity/scope_test.go +++ /dev/null @@ -1,215 +0,0 @@ -package entity - -import ( - "reflect" - "testing" -) - -func TestResolveScopedPath(t *testing.T) { - scopeMap := genTestScopes() - - specs := []struct { - curScope Container - pathExpr string - wantParent Entity - wantName string - }{ - { - scopeMap["IDE0"].(Container), - `\_SB_`, - scopeMap[`\`], - "_SB_", - }, - { - scopeMap["IDE0"].(Container), - `^FOO`, - scopeMap[`PCI0`], - "FOO", - }, - { - scopeMap["IDE0"].(Container), - `^^FOO`, - scopeMap[`_SB_`], - "FOO", - }, - { - scopeMap["IDE0"].(Container), - `_ADR`, - scopeMap[`IDE0`], - "_ADR", - }, - // Paths with dots - { - scopeMap["IDE0"].(Container), - `\_SB_.PCI0.IDE0._ADR`, - scopeMap[`IDE0`], - "_ADR", - }, - { - scopeMap["PCI0"].(Container), - `IDE0._ADR`, - scopeMap[`IDE0`], - "_ADR", - }, - { - scopeMap["PCI0"].(Container), - `_CRS`, - scopeMap[`PCI0`], - "_CRS", - }, - // Bad queries - { - scopeMap["PCI0"].(Container), - `FOO.BAR.BAZ`, - nil, - "", - }, - { - scopeMap["PCI0"].(Container), - ``, - nil, - "", - }, - { - scopeMap["PCI0"].(Container), - `\`, - nil, - "", - }, - { - scopeMap["PCI0"].(Container), - `^^^^^^^^^BADPATH`, - nil, - "", - }, - } - - root := scopeMap[`\`].(Container) - for specIndex, spec := range specs { - gotParent, gotName := ResolveScopedPath(spec.curScope, root, spec.pathExpr) - if !reflect.DeepEqual(gotParent, spec.wantParent) { - t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.wantParent, gotParent) - continue - } - - if gotName != spec.wantName { - t.Errorf("[spec %d] expected lookup to return node name %q; got %q", specIndex, spec.wantName, gotName) - } - } -} - -func TestFindInScope(t *testing.T) { - scopeMap := genTestScopes() - - specs := []struct { - curScope Container - lookup string - want Entity - }{ - // Search rules do not apply for these cases - { - scopeMap["PCI0"].(Container), - `\`, - scopeMap[`\`], - }, - { - scopeMap["PCI0"].(Container), - "IDE0._ADR", - scopeMap["_ADR"], - }, - { - scopeMap["IDE0"].(Container), - "^^PCI0.IDE0._ADR", - scopeMap["_ADR"], - }, - { - scopeMap["IDE0"].(Container), - `\_SB_.PCI0.IDE0._ADR`, - scopeMap["_ADR"], - }, - { - scopeMap["IDE0"].(Container), - `\_SB_.PCI0`, - scopeMap["PCI0"], - }, - { - scopeMap["IDE0"].(Container), - `^`, - scopeMap["PCI0"], - }, - // Bad queries - { - scopeMap["_SB_"].(Container), - "PCI0.USB._CRS", - nil, - }, - { - scopeMap["IDE0"].(Container), - "^^^^^^^^^^^^^^^^^^^", - nil, - }, - { - scopeMap["IDE0"].(Container), - `^^^^^^^^^^^FOO`, - nil, - }, - { - scopeMap["IDE0"].(Container), - "FOO", - nil, - }, - { - scopeMap["IDE0"].(Container), - "", - nil, - }, - // Search rules apply for these cases - { - scopeMap["IDE0"].(Container), - "_CRS", - scopeMap["_CRS"], - }, - } - - root := scopeMap[`\`].(Container) - for specIndex, spec := range specs { - if got := FindInScope(spec.curScope, root, spec.lookup); !reflect.DeepEqual(got, spec.want) { - t.Errorf("[spec %d] expected lookup to return %#v; got %#v", specIndex, spec.want, got) - } - } -} - -func genTestScopes() map[string]Entity { - // Setup the example tree from page 252 of the acpi 6.2 spec - // \ - // SB - // \ - // PCI0 - // | _CRS - // \ - // IDE0 - // | _ADR - ideScope := NewScope(OpScope, 42, `IDE0`) - pciScope := NewScope(OpScope, 42, `PCI0`) - sbScope := NewScope(OpScope, 42, `_SB_`) - rootScope := NewScope(OpScope, 42, `\`) - - adr := NewMethod(42, `_ADR`) - crs := NewMethod(42, `_CRS`) - - // Setup tree - ideScope.Append(adr) - pciScope.Append(crs) - pciScope.Append(ideScope) - sbScope.Append(pciScope) - rootScope.Append(sbScope) - - return map[string]Entity{ - "IDE0": ideScope, - "PCI0": pciScope, - "_SB_": sbScope, - "\\": rootScope, - "_ADR": adr, - "_CRS": crs, - } -} diff --git a/src/gopheros/device/acpi/aml/entity/visitor.go b/src/gopheros/device/acpi/aml/entity/visitor.go deleted file mode 100644 index 0b82550..0000000 --- a/src/gopheros/device/acpi/aml/entity/visitor.go +++ /dev/null @@ -1,64 +0,0 @@ -package entity - -// Visitor is a function invoked by the VM for each AML tree entity that matches -// a particular type. The return value controls whether the children of this -// entity should also be visited. -type Visitor func(depth int, obj Entity) (keepRecursing bool) - -// Type defines the type of entity that visitors should inspect. -type Type uint8 - -// The list of supported Type values. TypeAny works as a wildcard -// allowing the visitor to inspect all entities in the AML tree. -const ( - TypeAny Type = iota - TypeDevice - TypeProcessor - TypePowerResource - TypeThermalZone - TypeMethod - TypeMutex - TypeEvent - TypeField - TypeIndexField - TypeBankField -) - -// Visit descends a scope hierarchy and invokes visitorFn for each entity -// that matches entType. -func Visit(depth int, ent Entity, entType Type, visitorFn Visitor) bool { - op := ent.Opcode() - switch { - case (entType == TypeAny) || - (entType == TypeDevice && op == OpDevice) || - (entType == TypeProcessor && op == OpProcessor) || - (entType == TypePowerResource && op == OpPowerRes) || - (entType == TypeThermalZone && op == OpThermalZone) || - (entType == TypeMethod && op == OpMethod) || - (entType == TypeMutex && op == OpMutex) || - (entType == TypeEvent && op == OpEvent) || - (entType == TypeField && op == OpField) || - (entType == TypeIndexField && op == OpIndexField) || - (entType == TypeBankField && op == OpBankField): - // If the visitor returned false we should not visit the children - if !visitorFn(depth, ent) { - return false - } - - // Visit any args that are also entities - for _, arg := range ent.Args() { - if argEnt, isEnt := arg.(Entity); isEnt && !Visit(depth+1, argEnt, entType, visitorFn) { - return false - } - } - } - - // If the entity defines a scope we need to visit the child entities. - if container, isContainer := ent.(Container); isContainer { - for _, child := range container.Children() { - _ = Visit(depth+1, child, entType, visitorFn) - } - } - - return true -} diff --git a/src/gopheros/device/acpi/aml/entity/visitor_test.go b/src/gopheros/device/acpi/aml/entity/visitor_test.go deleted file mode 100644 index d4368b7..0000000 --- a/src/gopheros/device/acpi/aml/entity/visitor_test.go +++ /dev/null @@ -1,93 +0,0 @@ -package entity - -import "testing" - -func TestScopeVisit(t *testing.T) { - tableHandle := uint8(42) - keepRecursing := func(Entity) bool { return true } - stopRecursing := func(Entity) bool { return false } - - // Append special entities under IDE0 - root := NewScope(OpScope, tableHandle, "IDE0") - root.Append(NewDevice(tableHandle, "DEV0")) - root.Append(NewProcessor(tableHandle, "FOO0")) - root.Append(NewProcessor(tableHandle, "FOO0")) - root.Append(NewPowerResource(tableHandle, "FOO0")) - root.Append(NewPowerResource(tableHandle, "FOO0")) - root.Append(NewPowerResource(tableHandle, "FOO0")) - root.Append(NewThermalZone(tableHandle, "FOO0")) - root.Append(NewThermalZone(tableHandle, "FOO0")) - root.Append(NewThermalZone(tableHandle, "FOO0")) - root.Append(NewThermalZone(tableHandle, "FOO0")) - root.Append(NewMethod(tableHandle, "MTH0")) - root.Append(NewMethod(tableHandle, "MTH1")) - root.Append(NewMethod(tableHandle, "MTH2")) - root.Append(NewMethod(tableHandle, "MTH3")) - root.Append(NewMethod(tableHandle, "MTH4")) - root.Append(NewMutex(tableHandle)) - root.Append(NewMutex(tableHandle)) - root.Append(NewEvent(tableHandle)) - root.Append(NewEvent(tableHandle)) - root.Append(NewEvent(tableHandle)) - root.Append(NewField(tableHandle)) - root.Append(NewIndexField(tableHandle)) - root.Append(NewBankField(tableHandle)) - root.Append(&Invocation{ - Generic: Generic{ - op: OpMethodInvocation, - args: []interface{}{ - NewConst(OpOne, tableHandle, uint64(1)), - NewConst(OpDwordPrefix, tableHandle, uint64(2)), - }, - }, - }) - - specs := []struct { - searchType Type - keepRecursingFn func(Entity) bool - wantHits int - }{ - {TypeAny, keepRecursing, 27}, - {TypeAny, stopRecursing, 1}, - { - TypeAny, - func(ent Entity) bool { - // Stop recursing after visiting the Invocation entity - _, isInv := ent.(*Invocation) - return !isInv - }, - 25, - }, - { - TypeAny, - func(ent Entity) bool { - // Stop recursing after visiting the first Const entity - _, isConst := ent.(*Const) - return !isConst - }, - 26, - }, - {TypeDevice, keepRecursing, 1}, - {TypeProcessor, keepRecursing, 2}, - {TypePowerResource, keepRecursing, 3}, - {TypeThermalZone, keepRecursing, 4}, - {TypeMethod, keepRecursing, 5}, - {TypeMutex, keepRecursing, 2}, - {TypeEvent, keepRecursing, 3}, - {TypeField, keepRecursing, 1}, - {TypeIndexField, keepRecursing, 1}, - {TypeBankField, keepRecursing, 1}, - } - - for specIndex, spec := range specs { - var hits int - Visit(0, root, spec.searchType, func(_ int, obj Entity) bool { - hits++ - return spec.keepRecursingFn(obj) - }) - - if hits != spec.wantHits { - t.Errorf("[spec %d] expected visitor to be called %d times; got %d", specIndex, spec.wantHits, hits) - } - } -} diff --git a/src/gopheros/device/acpi/aml/parser/opcode_table.go b/src/gopheros/device/acpi/aml/parser/opcode_table.go deleted file mode 100644 index e1333d8..0000000 --- a/src/gopheros/device/acpi/aml/parser/opcode_table.go +++ /dev/null @@ -1,341 +0,0 @@ -package parser - -import "gopheros/device/acpi/aml/entity" - -const ( - badOpcode = 0xff - extOpPrefix = 0x5b -) - -// objType represents the object types that are supported by the AML parser. -type objType uint8 - -// The list of AML object types. -const ( - objTypeAny objType = iota - objTypeInteger - objTypeString - objTypeBuffer - objTypePackage - objTypeDevice - objTypeEvent - objTypeMethod - objTypeMutex - objTypeRegion - objTypePower - objTypeProcessor - objTypeThermal - objTypeBufferField - objTypeLocalRegionField - objTypeLocalBankField - objTypeLocalReference - objTypeLocalAlias - objTypeLocalScope - objTypeLocalVariable - objTypeMethodArgument -) - -// opFlag specifies a list of OR-able flags that describe the object -// type/attributes generated by a particular opcode. -type opFlag uint16 - -const ( - opFlagNone opFlag = 1 << iota - opFlagHasPkgLen - opFlagNamed - opFlagConstant - opFlagReference - opFlagArithmetic - opFlagCreate - opFlagReturn - opFlagExecutable - opFlagNoOp - opFlagScoped -) - -// is returns true if f is set in this opFlag. -func (fl opFlag) is(f opFlag) bool { - return (fl & f) == f -} - -// opArgFlags encodes up to 7 opArgFlag values in a uint64 value. -type opArgFlags uint64 - -// argCount returns the number of encoded args in the given flag. -func (fl opArgFlags) argCount() (count uint8) { - // Each argument is specified using 8 bits with 0x0 indicating the end of the - // argument list - for ; fl&0xf != 0; fl, count = fl>>8, count+1 { - } - - return count -} - -// arg returns the arg flags for argument "num" where num is the 0-based index -// of the argument to return. The allowed values for num are 0-6. -func (fl opArgFlags) arg(num uint8) opArgFlag { - return opArgFlag((fl >> (num * 8)) & 0xf) -} - -// contains returns true if the arg flags contain any argument with type x. -func (fl opArgFlags) contains(x opArgFlag) bool { - // Each argument is specified using 8 bits with 0x0 indicating the end of the - // argument list - for ; fl&0xf != 0; fl >>= 8 { - if opArgFlag(fl&0xf) == x { - return true - } - } - - return false -} - -// opArgFlag represents the type of an argument expected by a particular opcode. -type opArgFlag uint8 - -// The list of supported opArgFlag values. -const ( - _ opArgFlag = iota - opArgTermList - opArgTermObj - opArgByteList - opArgString - opArgByteData - opArgWord - opArgDword - opArgQword - opArgNameString - opArgSuperName - opArgSimpleName - opArgDataRefObj - opArgTarget - opArgFieldList -) - -func makeArg0() opArgFlags { return 0 } -func makeArg1(arg0 opArgFlag) opArgFlags { return opArgFlags(arg0) } -func makeArg2(arg0, arg1 opArgFlag) opArgFlags { return opArgFlags(arg1)<<8 | opArgFlags(arg0) } -func makeArg3(arg0, arg1, arg2 opArgFlag) opArgFlags { - return opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0) -} -func makeArg4(arg0, arg1, arg2, arg3 opArgFlag) opArgFlags { - return opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0) -} -func makeArg5(arg0, arg1, arg2, arg3, arg4 opArgFlag) opArgFlags { - return opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0) -} -func makeArg6(arg0, arg1, arg2, arg3, arg4, arg5 opArgFlag) opArgFlags { - return opArgFlags(arg5)<<40 | opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0) -} -func makeArg7(arg0, arg1, arg2, arg3, arg4, arg5, arg6 opArgFlag) opArgFlags { - return opArgFlags(arg6)<<48 | opArgFlags(arg5)<<40 | opArgFlags(arg4)<<32 | opArgFlags(arg3)<<24 | opArgFlags(arg2)<<16 | opArgFlags(arg1)<<8 | opArgFlags(arg0) -} - -// opcodeInfo contains all known information about an opcode, -// its argument count and types as well as the type of object -// represented by it. -type opcodeInfo struct { - op entity.AMLOpcode - objType objType - - flags opFlag - argFlags opArgFlags -} - -// Used by Parser.parseMethodBody for deferred parsing of method bodies. -const methodOpInfoIndex = 0x0d - -// The opcode table contains all opcode-related information that the parser knows. -// This table is modeled after a similar table used in the acpica implementation. -var opcodeTable = []opcodeInfo{ - /*0x00*/ {entity.OpZero, objTypeInteger, opFlagConstant, makeArg0()}, - /*0x01*/ {entity.OpOne, objTypeInteger, opFlagConstant, makeArg0()}, - /*0x02*/ {entity.OpAlias, objTypeLocalAlias, opFlagNamed, makeArg2(opArgNameString, opArgNameString)}, - /*0x03*/ {entity.OpName, objTypeAny, opFlagNamed, makeArg2(opArgNameString, opArgDataRefObj)}, - /*0x04*/ {entity.OpBytePrefix, objTypeInteger, opFlagConstant, makeArg1(opArgByteData)}, - /*0x05*/ {entity.OpWordPrefix, objTypeInteger, opFlagConstant, makeArg1(opArgWord)}, - /*0x06*/ {entity.OpDwordPrefix, objTypeInteger, opFlagConstant, makeArg1(opArgDword)}, - /*0x07*/ {entity.OpStringPrefix, objTypeString, opFlagConstant, makeArg1(opArgString)}, - /*0x08*/ {entity.OpQwordPrefix, objTypeInteger, opFlagConstant, makeArg1(opArgQword)}, - /*0x09*/ {entity.OpScope, objTypeLocalScope, opFlagNamed, makeArg2(opArgNameString, opArgTermList)}, - /*0x0a*/ {entity.OpBuffer, objTypeBuffer, opFlagHasPkgLen, makeArg2(opArgTermObj, opArgByteList)}, - /*0x0b*/ {entity.OpPackage, objTypePackage, opFlagNone, makeArg2(opArgByteData, opArgTermList)}, - /*0x0c*/ {entity.OpVarPackage, objTypePackage, opFlagNone, makeArg2(opArgByteData, opArgTermList)}, - /*0x0d*/ {entity.OpMethod, objTypeMethod, opFlagNamed | opFlagScoped, makeArg3(opArgNameString, opArgByteData, opArgTermList)}, - /*0x0e*/ {entity.OpExternal, objTypeAny, opFlagNamed, makeArg3(opArgNameString, opArgByteData, opArgByteData)}, - /*0x0f*/ {entity.OpLocal0, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x10*/ {entity.OpLocal1, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x11*/ {entity.OpLocal2, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x12*/ {entity.OpLocal3, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x13*/ {entity.OpLocal4, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0120*/ {entity.OpLocal5, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x15*/ {entity.OpLocal6, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x16*/ {entity.OpLocal7, objTypeLocalVariable, opFlagExecutable, makeArg0()}, - /*0x17*/ {entity.OpArg0, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x18*/ {entity.OpArg1, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x19*/ {entity.OpArg2, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x1a*/ {entity.OpArg3, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x1b*/ {entity.OpArg4, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x1c*/ {entity.OpArg5, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x1d*/ {entity.OpArg6, objTypeMethodArgument, opFlagExecutable, makeArg0()}, - /*0x1e*/ {entity.OpStore, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgSuperName)}, - /*0x1f*/ {entity.OpRefOf, objTypeAny, opFlagReference | opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x20*/ {entity.OpAdd, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x21*/ {entity.OpConcat, objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x22*/ {entity.OpSubtract, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x23*/ {entity.OpIncrement, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x24*/ {entity.OpDecrement, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x25*/ {entity.OpMultiply, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x26*/ {entity.OpDivide, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTarget, opArgTarget)}, - /*0x27*/ {entity.OpShiftLeft, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x28*/ {entity.OpShiftRight, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x29*/ {entity.OpAnd, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x2a*/ {entity.OpNand, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x2b*/ {entity.OpOr, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x2c*/ {entity.OpNor, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x2d*/ {entity.OpXor, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x2e*/ {entity.OpNot, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x2f*/ {entity.OpFindSetLeftBit, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x30*/ {entity.OpFindSetRightBit, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x31*/ {entity.OpDerefOf, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)}, - /*0x32*/ {entity.OpConcatRes, objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x33*/ {entity.OpMod, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x34*/ {entity.OpNotify, objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgTermObj)}, - /*0x35*/ {entity.OpSizeOf, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x36*/ {entity.OpIndex, objTypeAny, opFlagExecutable, makeArg3(opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x37*/ {entity.OpMatch, objTypeAny, opFlagExecutable, makeArg6(opArgTermObj, opArgByteData, opArgTermObj, opArgByteData, opArgTermObj, opArgTermObj)}, - /*0x38*/ {entity.OpCreateDWordField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)}, - /*0x39*/ {entity.OpCreateWordField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)}, - /*0x3a*/ {entity.OpCreateByteField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)}, - /*0x3b*/ {entity.OpCreateBitField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)}, - /*0x3c*/ {entity.OpObjectType, objTypeAny, opFlagNone, makeArg1(opArgSuperName)}, - /*0x3d*/ {entity.OpCreateQWordField, objTypeBufferField, opFlagNamed | opFlagCreate, makeArg3(opArgTermObj, opArgTermObj, opArgNameString)}, - /*0x3e*/ {entity.OpLand, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)}, - /*0x3f*/ {entity.OpLor, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)}, - /*0x40*/ {entity.OpLnot, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg1(opArgTermObj)}, - /*0x41*/ {entity.OpLEqual, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)}, - /*0x42*/ {entity.OpLGreater, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)}, - /*0x43*/ {entity.OpLLess, objTypeAny, opFlagArithmetic | opFlagExecutable, makeArg2(opArgTermObj, opArgTermObj)}, - /*0x44*/ {entity.OpToBuffer, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x45*/ {entity.OpToDecimalString, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x46*/ {entity.OpToHexString, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x47*/ {entity.OpToInteger, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x48*/ {entity.OpToString, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x49*/ {entity.OpCopyObject, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgSimpleName)}, - /*0x4a*/ {entity.OpMid, objTypeAny, opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTermObj, opArgTarget)}, - /*0x4b*/ {entity.OpContinue, objTypeAny, opFlagExecutable, makeArg0()}, - /*0x4c*/ {entity.OpIf, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTermList)}, - /*0x4d*/ {entity.OpElse, objTypeAny, opFlagExecutable | opFlagScoped, makeArg1(opArgTermList)}, - /*0x4e*/ {entity.OpWhile, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTermList)}, - /*0x4f*/ {entity.OpNoop, objTypeAny, opFlagNoOp, makeArg0()}, - /*0x50*/ {entity.OpReturn, objTypeAny, opFlagReturn, makeArg1(opArgTermObj)}, - /*0x51*/ {entity.OpBreak, objTypeAny, opFlagExecutable, makeArg0()}, - /*0x52*/ {entity.OpBreakPoint, objTypeAny, opFlagNoOp, makeArg0()}, - /*0x53*/ {entity.OpOnes, objTypeInteger, opFlagConstant, makeArg0()}, - /*0x54*/ {entity.OpMutex, objTypeMutex, opFlagNamed, makeArg2(opArgNameString, opArgByteData)}, - /*0x55*/ {entity.OpEvent, objTypeEvent, opFlagNamed, makeArg1(opArgNameString)}, - /*0x56*/ {entity.OpCondRefOf, objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgSuperName)}, - /*0x57*/ {entity.OpCreateField, objTypeBufferField, opFlagExecutable, makeArg4(opArgTermObj, opArgTermObj, opArgTermObj, opArgNameString)}, - /*0x58*/ {entity.OpLoadTable, objTypeAny, opFlagExecutable, makeArg7(opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj, opArgTermObj)}, - /*0x59*/ {entity.OpLoad, objTypeAny, opFlagExecutable, makeArg2(opArgNameString, opArgSuperName)}, - /*0x5a*/ {entity.OpStall, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)}, - /*0x5b*/ {entity.OpSleep, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)}, - /*0x5c*/ {entity.OpAcquire, objTypeAny, opFlagExecutable, makeArg2(opArgNameString, opArgSuperName)}, - /*0x5d*/ {entity.OpSignal, objTypeAny, opFlagExecutable, makeArg1(opArgTermObj)}, - /*0x5e*/ {entity.OpWait, objTypeAny, opFlagExecutable, makeArg2(opArgSuperName, opArgTermObj)}, - /*0x5f*/ {entity.OpReset, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x60*/ {entity.OpRelease, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x61*/ {entity.OpFromBCD, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x62*/ {entity.OpToBCD, objTypeAny, opFlagExecutable, makeArg2(opArgTermObj, opArgTarget)}, - /*0x63*/ {entity.OpUnload, objTypeAny, opFlagExecutable, makeArg1(opArgSuperName)}, - /*0x64*/ {entity.OpRevision, objTypeInteger, opFlagConstant | opFlagExecutable, makeArg0()}, - /*0x65*/ {entity.OpDebug, objTypeLocalReference, opFlagExecutable, makeArg0()}, - /*0x66*/ {entity.OpFatal, objTypeAny, opFlagExecutable, makeArg3(opArgByteData, opArgDword, opArgTermObj)}, - /*0x67*/ {entity.OpTimer, objTypeAny, opFlagNone, makeArg0()}, - /*0x68*/ {entity.OpOpRegion, objTypeRegion, opFlagNamed, makeArg4(opArgNameString, opArgByteData, opArgTermObj, opArgTermObj)}, - /*0x69*/ {entity.OpField, objTypeAny, opFlagNone, makeArg3(opArgNameString, opArgByteData, opArgFieldList)}, - /*0x6a*/ {entity.OpDevice, objTypeDevice, opFlagNamed | opFlagScoped, makeArg2(opArgNameString, opArgTermList)}, - /*0x6b*/ {entity.OpProcessor, objTypeProcessor, opFlagNamed | opFlagScoped, makeArg5(opArgNameString, opArgByteData, opArgDword, opArgByteData, opArgTermList)}, - /*0x6c*/ {entity.OpPowerRes, objTypePower, opFlagNamed | opFlagScoped, makeArg4(opArgNameString, opArgByteData, opArgWord, opArgTermList)}, - /*0x6d*/ {entity.OpThermalZone, objTypeThermal, opFlagNamed | opFlagScoped, makeArg2(opArgNameString, opArgTermList)}, - /*0x6e*/ {entity.OpIndexField, objTypeAny, opFlagNone, makeArg4(opArgNameString, opArgNameString, opArgByteData, opArgFieldList)}, - /*0x6f*/ {entity.OpBankField, objTypeLocalBankField, opFlagNamed, makeArg5(opArgNameString, opArgNameString, opArgTermObj, opArgByteData, opArgFieldList)}, - /*0x70*/ {entity.OpDataRegion, objTypeLocalRegionField, opFlagNamed, makeArg4(opArgNameString, opArgTermObj, opArgTermObj, opArgTermObj)}, -} - -// opcodeMap maps an AML opcode to an entry in the opcode table. Entries with -// the value 0xff indicate an invalid/unsupported opcode. -var opcodeMap = [256]uint8{ - /* 0 1 2 3 4 5 6 7*/ - /*0x00 - 0x07*/ 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x02, 0xff, - /*0x08 - 0x0f*/ 0x03, 0xff, 0x04, 0x05, 0x06, 0x07, 0x08, 0xff, - /*0x10 - 0x17*/ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0xff, 0xff, - /*0x18 - 0x1f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x20 - 0x27*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x28 - 0x2f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x30 - 0x37*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x38 - 0x3f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x40 - 0x47*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x48 - 0x4f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x50 - 0x57*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x58 - 0x5f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x60 - 0x67*/ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - /*0x68 - 0x6f*/ 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0xff, - /*0x70 - 0x77*/ 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, - /*0x78 - 0x7f*/ 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, - /*0x80 - 0x87*/ 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - /*0x88 - 0x8f*/ 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, - /*0x90 - 0x97*/ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - /*0x98 - 0x9f*/ 0x46, 0x47, 0x48, 0x49, 0x4a, 0x49, 0x4a, 0x4b, - /*0xa0 - 0xa7*/ 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0xff, 0xff, - /*0xa8 - 0xaf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xb0 - 0xb7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xb8 - 0xbf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xc0 - 0xc7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xc8 - 0xcf*/ 0xff, 0xff, 0xff, 0xff, 0x52, 0xff, 0xff, 0xff, - /*0xd0 - 0xd7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xd8 - 0xdf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xe0 - 0xe7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xe8 - 0xef*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xf0 - 0xf7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xf8 - 0xff*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53, -} - -// extendedOpcodeMap maps an AML extended opcode (extOpPrefix + code) to an -// entry in the opcode table. Entries with the value 0xff indicate an -// invalid/unsupported opcode. -var extendedOpcodeMap = [256]uint8{ - /* 0 1 2 3 4 5 6 7*/ - /*0x00 - 0x07*/ 0xff, 0x54, 0x55, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x08 - 0x0f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x10 - 0x17*/ 0xff, 0xff, 0x56, 0x57, 0xff, 0xff, 0xff, 0xff, - /*0x18 - 0x1f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x58, - /*0x20 - 0x27*/ 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, - /*0x28 - 0x2f*/ 0x61, 0x62, 0x63, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x30 - 0x37*/ 0x64, 0x65, 0x66, 0x67, 0xff, 0xff, 0xff, 0xff, - /*0x38 - 0x3f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x40 - 0x47*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x48 - 0x4f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x50 - 0x57*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x58 - 0x5f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x60 - 0x67*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x68 - 0x6f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x70 - 0x77*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x78 - 0x7f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x80 - 0x87*/ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - /*0x88 - 0x8f*/ 0x70, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x90 - 0x97*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0x98 - 0x9f*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xa0 - 0xa7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xa8 - 0xaf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xb0 - 0xb7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xb8 - 0xbf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xc0 - 0xc7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xc8 - 0xcf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xd0 - 0xd7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xd8 - 0xdf*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xe0 - 0xe7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xe8 - 0xef*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xf0 - 0xf7*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /*0xf8 - 0xff*/ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x53, -} diff --git a/src/gopheros/device/acpi/aml/parser/opcode_test.go b/src/gopheros/device/acpi/aml/parser/opcode_test.go deleted file mode 100644 index ee5bdd5..0000000 --- a/src/gopheros/device/acpi/aml/parser/opcode_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package parser - -import "testing" - -// TestFindUnmappedOpcodes is a helper test that pinpoints opcodes that have -// not yet been mapped via an opcode table. -func TestFindUnmappedOpcodes(t *testing.T) { - for opIndex, opRef := range opcodeMap { - if opRef != badOpcode { - continue - } - - for tabIndex, info := range opcodeTable { - if uint16(info.op) == uint16(opIndex) { - t.Errorf("set opcodeMap[0x%02x] = 0x%02x // %s\n", opIndex, tabIndex, info.op.String()) - break - } - } - } - - for opIndex, opRef := range extendedOpcodeMap { - // 0xff (opOnes) is defined in opcodeTable - if opRef != badOpcode || opIndex == 0 { - continue - } - - opIndex += 0xff - for tabIndex, info := range opcodeTable { - if uint16(info.op) == uint16(opIndex) { - t.Errorf("set extendedOpcodeMap[0x%02x] = 0x%02x // %s\n", opIndex-0xff, tabIndex, info.op.String()) - break - } - } - } -} diff --git a/src/gopheros/device/acpi/aml/parser/parser.go b/src/gopheros/device/acpi/aml/parser/parser.go deleted file mode 100644 index 8f4d495..0000000 --- a/src/gopheros/device/acpi/aml/parser/parser.go +++ /dev/null @@ -1,934 +0,0 @@ -package parser - -import ( - "gopheros/device/acpi/aml/entity" - "gopheros/device/acpi/table" - "gopheros/kernel" - "gopheros/kernel/kfmt" - "io" - "unsafe" -) - -var ( - errParsingAML = &kernel.Error{Module: "acpi_aml_parser", Message: "could not parse AML bytecode"} - errResolvingEntities = &kernel.Error{Module: "acpi_aml_parser", Message: "AML bytecode contains unresolvable entities"} -) - -type parseOpt uint8 - -const ( - parseOptSkipMethodBodies parseOpt = iota - parseOptParseMethodBodies -) - -// Parser implements an AML parser. -type Parser struct { - r amlStreamReader - errWriter io.Writer - root entity.Container - scopeStack []entity.Container - tableName string - tableHandle uint8 - - parseOptions parseOpt -} - -// NewParser returns a new AML parser instance. -func NewParser(errWriter io.Writer, rootEntity entity.Container) *Parser { - return &Parser{ - errWriter: errWriter, - root: rootEntity, - } -} - -// ParseAML attempts to parse the AML byte-code contained in the supplied ACPI -// table tagging each scoped entity with the supplied table handle. The parser -// emits any encountered errors to the specified errWriter. -func (p *Parser) ParseAML(tableHandle uint8, tableName string, header *table.SDTHeader) *kernel.Error { - p.tableHandle = tableHandle - p.tableName = tableName - p.r.Init( - uintptr(unsafe.Pointer(header)), - header.Length, - uint32(unsafe.Sizeof(table.SDTHeader{})), - ) - - // Pass 1: decode bytecode and build entitites without recursing into - // function bodies. - p.parseOptions = parseOptSkipMethodBodies - p.scopeStack = nil - p.scopeEnter(p.root) - if !p.parseObjList(header.Length) { - lastOp, _ := p.r.LastByte() - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] error parsing AML bytecode (last op 0x%x)\n", p.tableName, p.r.Offset()-1, lastOp) - return errParsingAML - } - p.scopeExit() - - // Pass 2: parse method bodies, check entity parents and resolve all - // symbol references - var resolveFailed bool - entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { - if method, isMethod := ent.(*entity.Method); isMethod { - resolveFailed = resolveFailed || !p.parseMethodBody(method) - - // Don't recurse into method bodies; their contents - // will be lazilly resolved by the VM - return false - } - - // Populate parents for any entity args that are also entities but are not - // linked to a parent (e.g. a package inside a named entity). - for _, arg := range ent.Args() { - if argEnt, isArgEnt := arg.(entity.Entity); isArgEnt && argEnt.Parent() == nil { - argEnt.SetParent(ent.Parent()) - } - } - - // Resolve any symbol references - if lazyRef, ok := ent.(entity.LazyRefResolver); ok { - if err := lazyRef.ResolveSymbolRefs(p.root); err != nil { - kfmt.Fprintf(p.errWriter, "%s\n", err.Message) - resolveFailed = true - return false - } - } - - return true - }) - - if resolveFailed { - return errResolvingEntities - } - - return nil -} - -// parseObjList tries to parse an AML object list. Object lists are usually -// specified together with a pkgLen block which is used to calculate the max -// read offset that the parser may reach. -func (p *Parser) parseObjList(maxOffset uint32) bool { - for !p.r.EOF() && p.r.Offset() < maxOffset { - if !p.parseObj() { - return false - } - } - - return true -} - -func (p *Parser) parseObj() bool { - var ( - curOffset uint32 - pkgLen uint32 - info *opcodeInfo - ok bool - ) - - // If we cannot decode the next opcode then this may be a method - // invocation or a name reference. - curOffset = p.r.Offset() - if info, ok = p.nextOpcode(); !ok { - p.r.SetOffset(curOffset) - return p.parseNamedRef() - } - - hasPkgLen := info.flags.is(opFlagHasPkgLen) || info.argFlags.contains(opArgTermList) || info.argFlags.contains(opArgFieldList) - - if hasPkgLen { - curOffset = p.r.Offset() - if pkgLen, ok = p.parsePkgLength(); !ok { - return false - } - } - - // If we encounter a named scope we need to look it up and parse the arg list relative to it - switch { - case info.op == entity.OpScope: - return p.parseScope(curOffset + pkgLen) - case info.flags.is(opFlagNamed | opFlagScoped): - return p.parseNamespacedObj(info, curOffset+pkgLen) - } - - // Create appropriate object for opcode type and attach it to current scope unless it is - // a device named scope in which case it may define a relative scope name - obj := p.makeObjForOpcode(info) - p.scopeCurrent().Append(obj) - - if argCount := info.argFlags.argCount(); argCount > 0 { - for argIndex := uint8(0); argIndex < argCount; argIndex++ { - if !p.parseArg( - info, - obj, - argIndex, - info.argFlags.arg(argIndex), - curOffset+pkgLen, - ) { - return false - } - } - } - - return p.finalizeObj(info.op, obj) -} - -// finalizeObj applies post-parse logic for special object types. -func (p *Parser) finalizeObj(op entity.AMLOpcode, obj entity.Entity) bool { - switch op { - case entity.OpElse: - // If this is an else block we need to append it as an argument to the - // If block - // Pop Else block of the current scope - curScope := p.scopeCurrent() - curScope.Remove(curScope.Last()) - prevObj := curScope.Last() - if prevObj.Opcode() != entity.OpIf { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] encountered else block without a matching if block\n", p.tableName, p.r.Offset()) - return false - } - - // If predicate(0) then(1) else(2) - prevObj.SetArg(2, obj) - } - - return true -} - -// parseScope reads a scope name from the AML bytestream, enters it and parses -// an objlist relative to it. The referenced scope must be one of: -// - one of the pre-defined scopes -// - device -// - processor -// - thermal zone -// - power resource -func (p *Parser) parseScope(maxReadOffset uint32) bool { - name, ok := p.parseNameString() - if !ok { - return false - } - - target := entity.FindInScope(p.scopeCurrent(), p.root, name) - if target == nil { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] undefined scope: %s\n", p.tableName, p.r.Offset(), name) - return false - } - - switch target.Opcode() { - case entity.OpDevice, entity.OpProcessor, entity.OpThermalZone, entity.OpPowerRes: - // ok - default: - // Only allow if this is a named scope - if target.Name() == "" { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] %s does not refer to a scoped object\n", p.tableName, p.r.Offset(), name) - return false - } - } - - p.scopeEnter(target.(entity.Container)) - ok = p.parseObjList(maxReadOffset) - p.scopeExit() - - return ok -} - -// parseNamespacedObj reads a scope target name from the AML bytestream, -// attaches the appropriate object depending on the opcode to the correct -// parent scope and then parses any contained objects. The contained objects -// will be appended inside the newly constructed scope. -func (p *Parser) parseNamespacedObj(info *opcodeInfo, maxReadOffset uint32) bool { - scopeExpr, ok := p.parseNameString() - if !ok { - return false - } - - parent, name := entity.ResolveScopedPath(p.scopeCurrent(), p.root, scopeExpr) - if parent == nil { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] undefined scope target: %s (current scope: %s)\n", p.tableName, p.r.Offset(), scopeExpr, p.scopeCurrent().Name()) - return false - } - - var obj entity.Container - switch info.op { - case entity.OpDevice: - obj = entity.NewDevice(p.tableHandle, name) - case entity.OpProcessor: - obj = entity.NewProcessor(p.tableHandle, name) - case entity.OpPowerRes: - obj = entity.NewPowerResource(p.tableHandle, name) - case entity.OpThermalZone: - obj = entity.NewThermalZone(p.tableHandle, name) - case entity.OpMethod: - obj = entity.NewMethod(p.tableHandle, name) - default: - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] unsupported namespaced op: %s (current scope: %s)\n", p.tableName, p.r.Offset(), info.op.String(), p.scopeCurrent().Name()) - return false - } - - // Parse any args that follow the name. The last arg is always an ArgTermList - parent.Append(obj) - for argIndex := uint8(1); argIndex < info.argFlags.argCount(); argIndex++ { - if !p.parseArg(info, obj, argIndex, info.argFlags.arg(argIndex), maxReadOffset) { - return false - } - } - - return ok && p.finalizeObj(info.op, obj) -} - -func (p *Parser) parseArg(info *opcodeInfo, obj entity.Entity, argIndex uint8, argType opArgFlag, maxReadOffset uint32) bool { - var ( - arg interface{} - ok bool - ) - - switch argType { - case opArgNameString: - arg, ok = p.parseNameString() - case opArgByteData: - arg, ok = p.parseNumConstant(1) - case opArgWord: - arg, ok = p.parseNumConstant(2) - case opArgDword: - arg, ok = p.parseNumConstant(4) - case opArgQword: - arg, ok = p.parseNumConstant(8) - case opArgString: - arg, ok = p.parseString() - case opArgTermObj, opArgDataRefObj: - arg, ok = p.parseArgObj() - case opArgSimpleName: - arg, ok = p.parseSimpleName() - case opArgSuperName: - arg, ok = p.parseSuperName() - case opArgTarget: - arg, ok = p.parseTarget() - case opArgTermList: - // If this is a method and the SkipMethodBodies option is set - // then record the body start and end offset so we can parse - // it at a later stage. - if method, isMethod := obj.(*entity.Method); isMethod && p.parseOptions == parseOptSkipMethodBodies { - method.BodyStartOffset = p.r.Offset() - method.BodyEndOffset = maxReadOffset - p.r.SetOffset(maxReadOffset) - return true - } - - // If object is a scoped entity enter it's scope before parsing - // the term list. Otherwise, create an unnamed scope, attach it - // as the next argument to obj and enter that. - if s, isScopeEnt := obj.(entity.Container); isScopeEnt { - p.scopeEnter(s) - } else { - // Create an unnamed scope (e.g if, else, while scope) - ns := entity.NewScope(info.op, p.tableHandle, "") - p.scopeEnter(ns) - obj.SetArg(argIndex, ns) - } - - ok = p.parseObjList(maxReadOffset) - p.scopeExit() - return ok - case opArgFieldList: - return p.parseFieldList(obj, maxReadOffset) - case opArgByteList: - var bl []byte - for p.r.Offset() < maxReadOffset { - b, err := p.r.ReadByte() - if err != nil { - return false - } - bl = append(bl, b) - } - arg, ok = bl, true - } - - if !ok { - return false - } - - return obj.SetArg(argIndex, arg) -} - -func (p *Parser) parseArgObj() (entity.Entity, bool) { - if ok := p.parseObj(); !ok { - return nil, false - } - - curScope := p.scopeCurrent() - obj := curScope.Last() - curScope.Remove(obj) - return obj, true -} - -func (p *Parser) makeObjForOpcode(info *opcodeInfo) entity.Entity { - var obj entity.Entity - - switch { - case info.op == entity.OpOpRegion: - obj = entity.NewRegion(p.tableHandle) - case info.op == entity.OpBuffer: - obj = entity.NewBuffer(p.tableHandle) - case info.op == entity.OpMutex: - obj = entity.NewMutex(p.tableHandle) - case info.op == entity.OpEvent: - obj = entity.NewEvent(p.tableHandle) - case info.op == entity.OpField: - obj = entity.NewField(p.tableHandle) - case info.op == entity.OpIndexField: - obj = entity.NewIndexField(p.tableHandle) - case info.op == entity.OpBankField: - obj = entity.NewBankField(p.tableHandle) - case info.op == entity.OpCreateField: - obj = entity.NewBufferField(info.op, p.tableHandle, 0) - case info.op == entity.OpCreateBitField: - obj = entity.NewBufferField(info.op, p.tableHandle, 1) - case info.op == entity.OpCreateByteField: - obj = entity.NewBufferField(info.op, p.tableHandle, 8) - case info.op == entity.OpCreateWordField: - obj = entity.NewBufferField(info.op, p.tableHandle, 16) - case info.op == entity.OpCreateDWordField: - obj = entity.NewBufferField(info.op, p.tableHandle, 32) - case info.op == entity.OpCreateQWordField: - obj = entity.NewBufferField(info.op, p.tableHandle, 64) - case info.op == entity.OpZero: - obj = entity.NewConst(info.op, p.tableHandle, uint64(0)) - case info.op == entity.OpOne: - obj = entity.NewConst(info.op, p.tableHandle, uint64(1)) - case info.op == entity.OpOnes: - obj = entity.NewConst(info.op, p.tableHandle, uint64((1<<64)-1)) - case info.flags.is(opFlagConstant): - obj = entity.NewConst(info.op, p.tableHandle, nil) // will be parsed as an arg - case info.op == entity.OpPackage || info.op == entity.OpVarPackage: - obj = entity.NewPackage(info.op, p.tableHandle) - case info.flags.is(opFlagScoped): - obj = entity.NewScope(info.op, p.tableHandle, "") - case info.flags.is(opFlagNamed): - obj = entity.NewGenericNamed(info.op, p.tableHandle) - default: - obj = entity.NewGeneric(info.op, p.tableHandle) - } - - return obj -} - -// parseMethodBody parses the entities that make up a method's body. After the -// entire AML tree has been parsed, the parser makes a second pass and calls -// parseMethodBody for each Method entity. -// -// By deferring the parsing of the method body, we ensure that the parser can -// lookup the method declarations (even if forward declarations are used) for -// each method invocation. As method declarations contain information about the -// expected argument count, the parser can use this information to properly -// parse the invocation arguments. For more details see: parseNamedRef -func (p *Parser) parseMethodBody(method *entity.Method) bool { - p.parseOptions = parseOptParseMethodBodies - p.scopeEnter(method) - p.r.SetOffset(method.BodyStartOffset) - ok := p.parseArg(&opcodeTable[methodOpInfoIndex], method, 2, opArgTermList, method.BodyEndOffset) - p.scopeExit() - - return ok -} - -// parseNamedRef attempts to parse either a method invocation or a named -// reference. As AML allows for forward references, the actual contents for -// this entity will not be known until the entire AML stream has been parsed. -// -// Grammar: -// MethodInvocation := NameString TermArgList -// TermArgList = Nothing | TermArg TermArgList -// TermArg = Type2Opcode | DataObject | ArgObj | LocalObj | MethodInvocation -func (p *Parser) parseNamedRef() bool { - name, ok := p.parseNameString() - if !ok { - return false - } - - // Check if this is a method invocation - ent := entity.FindInScope(p.scopeCurrent(), p.root, name) - if methodDef, isMethod := ent.(*entity.Method); isMethod { - var ( - curOffset uint32 - argIndex uint8 - arg entity.Entity - argList []interface{} - ) - - for argIndex < methodDef.ArgCount && !p.r.EOF() { - // Peek next opcode - curOffset = p.r.Offset() - nextOpcode, ok := p.nextOpcode() - p.r.SetOffset(curOffset) - - switch { - case ok && (entity.OpIsType2(nextOpcode.op) || entity.OpIsArg(nextOpcode.op) || entity.OpIsDataObject(nextOpcode.op)): - arg, ok = p.parseArgObj() - default: - // It may be a nested invocation or named ref - ok = p.parseNamedRef() - if ok { - arg = p.scopeCurrent().Last() - p.scopeCurrent().Remove(arg) - } - } - - // No more TermArgs to parse - if !ok { - p.r.SetOffset(curOffset) - break - } - - argList = append(argList, arg) - argIndex++ - } - - // Check whether all expected arguments have been parsed - if argIndex != methodDef.ArgCount { - kfmt.Fprintf(p.errWriter, "[table: %s, offset: %d] unexpected arglist end for method %s invocation: expected %d; got %d\n", p.tableName, p.r.Offset(), name, methodDef.ArgCount, argIndex) - return false - } - - return p.scopeCurrent().Append(entity.NewInvocation(p.tableHandle, methodDef, argList)) - } - - // Otherwise this is a reference to a named entity - return p.scopeCurrent().Append(entity.NewReference(p.tableHandle, name)) -} - -func (p *Parser) nextOpcode() (*opcodeInfo, bool) { - next, err := p.r.ReadByte() - if err != nil { - return nil, false - } - - if next != extOpPrefix { - index := opcodeMap[next] - if index == badOpcode { - return nil, false - } - return &opcodeTable[index], true - } - - // Scan next byte to figure out the opcode - if next, err = p.r.ReadByte(); err != nil { - return nil, false - } - - index := extendedOpcodeMap[next] - if index == badOpcode { - return nil, false - } - return &opcodeTable[index], true -} - -// parseFieldList parses a list of FieldElements until the reader reaches -// maxReadOffset and appends them to the current scope. Depending on the opcode -// this method will emit either fieldUnit objects or indexField objects -// -// Grammar: -// FieldElement := NamedField | ReservedField | AccessField | ExtendedAccessField | ConnectField -// NamedField := NameSeg PkgLength -// ReservedField := 0x00 PkgLength -// AccessField := 0x1 AccessType AccessAttrib -// ConnectField := 0x02 NameString | 0x02 BufferData -// ExtendedAccessField := 0x3 AccessType ExtendedAccessType AccessLength -func (p *Parser) parseFieldList(fieldEnt entity.Entity, maxReadOffset uint32) bool { - var ( - ok bool - - accessType entity.FieldAccessType - - bitWidth uint32 - curBitOffset uint32 - connectionName string - unitName string - resolvedConnection entity.Entity - accessAttrib entity.FieldAccessAttrib - accessByteCount uint8 - ) - - // Load default field access rule; it applies to all field units unless - // overridden via a directive in the field unit list - if accessProvider, isProvider := fieldEnt.(entity.FieldAccessTypeProvider); isProvider { - accessType = accessProvider.DefaultAccessType() - } else { - // not a field entity - return false - } - - for p.r.Offset() < maxReadOffset { - next, err := p.r.ReadByte() - if err != nil { - return false - } - - switch next { - case 0x00: // ReservedField; generated by the Offset() command - bitWidth, ok = p.parsePkgLength() - if !ok { - return false - } - - curBitOffset += bitWidth - continue - case 0x1: // AccessField; set access attributes for following fields - next, err := p.r.ReadByte() - if err != nil { - return false - } - accessType = entity.FieldAccessType(next & 0xf) // access type; bits[0:3] - - attrib, err := p.r.ReadByte() - if err != nil { - return false - } - - // To specify AccessAttribBytes, RawBytes and RawProcessBytes - // the ASL compiler will emit an ExtendedAccessField opcode. - accessByteCount = 0 - accessAttrib = entity.FieldAccessAttrib(attrib) - - continue - case 0x2: // ConnectField => <0x2> NameString> | <0x02> TermObj => Buffer - curOffset := p.r.Offset() - if connectionName, ok = p.parseNameString(); !ok { - // Rewind and try parsing it as an object - p.r.SetOffset(curOffset) - if resolvedConnection, ok = p.parseArgObj(); !ok { - return false - } - } - case 0x3: // ExtendedAccessField => <0x03> AccessType ExtendedAccessAttrib AccessLength - next, err := p.r.ReadByte() - if err != nil { - return false - } - accessType = entity.FieldAccessType(next & 0xf) // access type; bits[0:3] - - extAccessAttrib, err := p.r.ReadByte() - if err != nil { - return false - } - - accessByteCount, err = p.r.ReadByte() - if err != nil { - return false - } - - switch extAccessAttrib { - case 0x0b: - accessAttrib = entity.FieldAccessAttribBytes - case 0xe: - accessAttrib = entity.FieldAccessAttribRawBytes - case 0x0f: - accessAttrib = entity.FieldAccessAttribRawProcessBytes - } - default: // NamedField - _ = p.r.UnreadByte() - if unitName, ok = p.parseNameString(); !ok { - return false - } - - bitWidth, ok = p.parsePkgLength() - if !ok { - return false - } - - // According to the spec, the field elements are should - // be visible at the same scope as the Field that declares them - unit := entity.NewFieldUnit(p.tableHandle, unitName) - unit.Field = fieldEnt - unit.AccessType = accessType - unit.AccessAttrib = accessAttrib - unit.ByteCount = accessByteCount - unit.BitOffset = curBitOffset - unit.BitWidth = bitWidth - unit.ConnectionName = connectionName - unit.Connection = resolvedConnection - - p.scopeCurrent().Append(unit) - curBitOffset += bitWidth - } - } - - return ok && p.r.Offset() == maxReadOffset -} - -// parsePkgLength parses a PkgLength value from the AML bytestream. -func (p *Parser) parsePkgLength() (uint32, bool) { - lead, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - // The high 2 bits of the lead byte indicate how many bytes follow. - var pkgLen uint32 - switch lead >> 6 { - case 0: - pkgLen = uint32(lead) - case 1: - b1, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - // lead bits 0-3 are the lsb of the length nybble - pkgLen = uint32(b1)<<4 | uint32(lead&0xf) - case 2: - b1, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - b2, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - // lead bits 0-3 are the lsb of the length nybble - pkgLen = uint32(b2)<<12 | uint32(b1)<<4 | uint32(lead&0xf) - case 3: - b1, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - b2, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - b3, err := p.r.ReadByte() - if err != nil { - return 0, false - } - - // lead bits 0-3 are the lsb of the length nybble - pkgLen = uint32(b3)<<20 | uint32(b2)<<12 | uint32(b1)<<4 | uint32(lead&0xf) - } - - return pkgLen, true -} - -// parseNumConstant parses a byte/word/dword or qword value from the AML bytestream. -func (p *Parser) parseNumConstant(numBytes uint8) (uint64, bool) { - var ( - next byte - err error - res uint64 - ) - - for c := uint8(0); c < numBytes; c++ { - if next, err = p.r.ReadByte(); err != nil { - return 0, false - } - - res = res | (uint64(next) << (8 * c)) - } - - return res, true -} - -// parseString parses a string from the AML bytestream. -func (p *Parser) parseString() (string, bool) { - // Read ASCII chars till we reach a null byte - var ( - next byte - err error - str []byte - ) - - for { - next, err = p.r.ReadByte() - if err != nil { - return "", false - } - - if next == 0x00 { - break - } else if next >= 0x01 && next <= 0x7f { // AsciiChar - str = append(str, next) - } else { - return "", false - } - } - return string(str), true -} - -// parseSuperName attempts to pass a SuperName from the AML bytestream. -// -// Grammar: -// SuperName := SimpleName | DebugObj | Type6Opcode -// SimpleName := NameString | ArgObj | LocalObj -func (p *Parser) parseSuperName() (interface{}, bool) { - // Try parsing as SimpleName - curOffset := p.r.Offset() - if obj, ok := p.parseSimpleName(); ok { - return obj, ok - } - - // Rewind and try parsing as object - p.r.SetOffset(curOffset) - return p.parseArgObj() -} - -// parseSimpleName attempts to pass a SimpleName from the AML bytestream. -// -// Grammar: -// SimpleName := NameString | ArgObj | LocalObj -func (p *Parser) parseSimpleName() (interface{}, bool) { - // Peek next opcode - curOffset := p.r.Offset() - nextOpcode, ok := p.nextOpcode() - - var obj interface{} - - switch { - case ok && entity.OpIsArg(nextOpcode.op): - obj, ok = entity.NewGeneric(nextOpcode.op, p.tableHandle), true - default: - // Rewind and try parsing as NameString - p.r.SetOffset(curOffset) - obj, ok = p.parseNameString() - } - - return obj, ok -} - -// parseTarget attempts to pass a Target from the AML bytestream. -// -// Grammar: -// Target := SuperName | NullName -// NullName := 0x00 -// SuperName := SimpleName | DebugObj | Type6Opcode -// Type6Opcode := DefRefOf | DefDerefOf | DefIndex | UserTermObj -// SimpleName := NameString | ArgObj | LocalObj -// -// UserTermObj is a control method invocation. -func (p *Parser) parseTarget() (interface{}, bool) { - // Peek next opcode - curOffset := p.r.Offset() - nextOpcode, ok := p.nextOpcode() - p.r.SetOffset(curOffset) - - if ok { - switch { - case nextOpcode.op == entity.OpZero: // this is actually a NullName - p.r.SetOffset(curOffset + 1) - return entity.NewConst(entity.OpStringPrefix, p.tableHandle, ""), true - case entity.OpIsArg(nextOpcode.op) || nextOpcode.op == entity.OpRefOf || nextOpcode.op == entity.OpDerefOf || nextOpcode.op == entity.OpIndex || nextOpcode.op == entity.OpDebug: // LocalObj | ArgObj | Type6 | DebugObj - default: - // Unexpected opcode - return nil, false - } - - // We can use parseObj for parsing - return p.parseArgObj() - } - - // In this case, this is either a NameString or a control method invocation. - if ok := p.parseNamedRef(); ok { - obj := p.scopeCurrent().Last() - p.scopeCurrent().Remove(obj) - return obj, ok - } - - return nil, false -} - -// parseNameString parses a NameString from the AML bytestream. -// -// Grammar: -// NameString := RootChar NamePath | PrefixPath NamePath -// PrefixPath := Nothing | '^' PrefixPath -// NamePath := NameSeg | DualNamePath | MultiNamePath | NullName -func (p *Parser) parseNameString() (string, bool) { - var str []byte - - // NameString := RootChar NamePath | PrefixPath NamePath - next, err := p.r.PeekByte() - if err != nil { - return "", false - } - - switch next { - case '\\': // RootChar - str = append(str, next) - _, _ = p.r.ReadByte() - case '^': // PrefixPath := Nothing | '^' PrefixPath - str = append(str, next) - _, _ = p.r.ReadByte() - for { - next, err = p.r.PeekByte() - if err != nil { - return "", false - } - - if next != '^' { - break - } - - str = append(str, next) - _, _ = p.r.ReadByte() - } - } - - // NamePath := NameSeg | DualNamePath | MultiNamePath | NullName - next, err = p.r.ReadByte() - if err != nil { - return "", false - } - var readCount int - switch next { - case 0x00: // NullName - case 0x2e: // DualNamePath := DualNamePrefix NameSeg NameSeg - readCount = 8 // NameSeg x 2 - case 0x2f: // MultiNamePath := MultiNamePrefix SegCount NameSeg(SegCount) - segCount, err := p.r.ReadByte() - if segCount == 0 || err != nil { - return "", false - } - - readCount = int(segCount) * 4 - default: // NameSeg := LeadNameChar NameChar NameChar NameChar - // LeadNameChar := 'A' - 'Z' | '_' - if (next < 'A' || next > 'Z') && next != '_' { - return "", false - } - - str = append(str, next) // LeadNameChar - readCount = 3 // NameChar x 3 - } - - for index := 0; readCount > 0; readCount, index = readCount-1, index+1 { - next, err := p.r.ReadByte() - if err != nil { - return "", false - } - - // Inject a '.' every 4 chars except for the last segment so - // scoped lookups can work properly. - if index > 0 && index%4 == 0 && readCount > 1 { - str = append(str, '.') - } - - str = append(str, next) - } - - return string(str), true -} - -// scopeCurrent returns the currently active scope. -func (p *Parser) scopeCurrent() entity.Container { - return p.scopeStack[len(p.scopeStack)-1] -} - -// scopeEnter enters the given scope. -func (p *Parser) scopeEnter(s entity.Container) { - p.scopeStack = append(p.scopeStack, s) -} - -// scopeExit exits the current scope. -func (p *Parser) scopeExit() { - p.scopeStack = p.scopeStack[:len(p.scopeStack)-1] -} diff --git a/src/gopheros/device/acpi/aml/parser/parser_test.go b/src/gopheros/device/acpi/aml/parser/parser_test.go deleted file mode 100644 index 78d3bbf..0000000 --- a/src/gopheros/device/acpi/aml/parser/parser_test.go +++ /dev/null @@ -1,738 +0,0 @@ -package parser - -import ( - "gopheros/device/acpi/aml/entity" - "gopheros/device/acpi/table" - "io/ioutil" - "os" - "path/filepath" - "runtime" - "strings" - "testing" - "unsafe" -) - -func TestParser(t *testing.T) { - specs := [][]string{ - []string{"DSDT.aml", "SSDT.aml"}, - []string{"parser-testsuite-DSDT.aml"}, - []string{"parser-testsuite-fwd-decls-DSDT.aml"}, - } - - for specIndex, spec := range specs { - var resolver = mockResolver{ - tableFiles: spec, - } - - p := NewParser(os.Stderr, genDefaultScopes()) - - for _, tableName := range spec { - tableName = strings.Replace(tableName, ".aml", "", -1) - if err := p.ParseAML(0, tableName, resolver.LookupTable(tableName)); err != nil { - t.Errorf("[spec %d] [%s]: %v", specIndex, tableName, err) - break - } - } - } -} - -func TestParsingOfMethodBodies(t *testing.T) { - var resolver = mockResolver{ - tableFiles: []string{"parser-testsuite-fwd-decls-DSDT.aml"}, - } - - p := NewParser(os.Stderr, genDefaultScopes()) - tableName := strings.Replace(resolver.tableFiles[0], ".aml", "", -1) - if err := p.ParseAML(0, tableName, resolver.LookupTable(tableName)); err != nil { - t.Fatalf("[%s]: %v", tableName, err) - } - - // Collect invocations - var invocations []*entity.Invocation - entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { - if inv, isInv := ent.(*entity.Invocation); isInv { - invocations = append(invocations, inv) - } - return true - }) - - specs := []struct { - expParentName string - expArgCount int - }{ - // Call to `\NST1` - {`\`, 1}, - // Call to `\_SB.NST1` - {`_SB_`, 2}, - // Call to `\NST1` (first argument of above invocation) - {`\`, 1}, - } - - if exp, got := len(specs), len(invocations); exp != got { - t.Fatalf("expected parser to produce %d method invocations; got %d", exp, got) - } - - for specIndex, spec := range specs { - if got := invocations[specIndex].Method.Parent().Name(); got != spec.expParentName { - t.Errorf( - "[spec %d] expected invocation to target %s.%s; got %s.%s", - specIndex, - spec.expParentName, invocations[specIndex].Method.Name(), - got, invocations[specIndex].Method.Name(), - ) - } - - if got := len(invocations[specIndex].Args()); got != spec.expArgCount { - t.Errorf( - "[spec %d] expected invocation to target %s.%s to receive %d args; got %d", - specIndex, - spec.expParentName, invocations[specIndex].Method.Name(), spec.expArgCount, - got, - ) - } - } -} - -func TestTableHandleAssignment(t *testing.T) { - var resolver = mockResolver{tableFiles: []string{"parser-testsuite-DSDT.aml"}} - - rootNS := genDefaultScopes() - p := NewParser(ioutil.Discard, rootNS) - - expHandle := uint8(0x0f) - tableName := "parser-testsuite-DSDT" - if err := p.ParseAML(expHandle, tableName, resolver.LookupTable(tableName)); err != nil { - t.Error(err) - } - - // Drop all entities that were assigned the handle value - var unloadList []entity.Entity - entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { - if ent.TableHandle() == expHandle { - unloadList = append(unloadList, ent) - return false - } - return true - }) - - for _, ent := range unloadList { - if p := ent.Parent(); p != nil { - p.Remove(ent) - } - } - - // We should end up with the original tree - var visitedNodes int - entity.Visit(0, p.root, entity.TypeAny, func(_ int, ent entity.Entity) bool { - visitedNodes++ - if ent.TableHandle() == expHandle { - t.Errorf("encountered entity that should have been pruned: %#+v", ent) - } - return true - }) - - if exp := len(rootNS.Children()) + 1; visitedNodes != exp { - t.Errorf("expected to visit %d nodes; visited %d", exp, visitedNodes) - } -} - -func TestParserForwardDeclParsing(t *testing.T) { - var resolver = mockResolver{ - tableFiles: []string{"parser-testsuite-fwd-decls-DSDT.aml"}, - } - - p := NewParser(ioutil.Discard, genDefaultScopes()) - - for _, tableName := range resolver.tableFiles { - tableName = strings.Replace(tableName, ".aml", "", -1) - if err := p.ParseAML(0, tableName, resolver.LookupTable(tableName)); err != nil { - t.Errorf("[%s]: %v", tableName, err) - break - } - } -} - -func TestParsePkgLength(t *testing.T) { - specs := []struct { - payload []byte - exp uint32 - }{ - // lead byte bits (6:7) indicate 1 extra byte for the len. The - // parsed length will use bits 0:3 from the lead byte plus - // the full 8 bits of the following byte. - { - []byte{1<<6 | 7, 255}, - 4087, - }, - // lead byte bits (6:7) indicate 2 extra bytes for the len. The - // parsed length will use bits 0:3 from the lead byte plus - // the full 8 bits of the following bytes. - { - []byte{2<<6 | 8, 255, 128}, - 528376, - }, - // lead byte bits (6:7) indicate 3 extra bytes for the len. The - // parsed length will use bits 0:3 from the lead byte plus - // the full 8 bits of the following bytes. - { - []byte{3<<6 | 6, 255, 128, 42}, - 44568566, - }, - } - - p := &Parser{errWriter: ioutil.Discard} - - for specIndex, spec := range specs { - mockParserPayload(p, spec.payload) - got, ok := p.parsePkgLength() - if !ok { - t.Errorf("[spec %d] parsePkgLength returned false", specIndex) - continue - } - - if got != spec.exp { - t.Errorf("[spec %d] expected parsePkgLength to return %d; got %d", specIndex, spec.exp, got) - } - } -} - -func TestParserErrorHandling(t *testing.T) { - p := &Parser{ - errWriter: ioutil.Discard, - } - - t.Run("ParseAML errors", func(t *testing.T) { - t.Run("parseObjList error", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - // Setup resolver to serve an AML stream containing an invalid opcode - header := mockParserPayload(p, []byte{0x5b, 0x00}) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected ParseAML to return an error") - } - - // Setup resolver to serve an AML stream containing an incomplete extended opcode - header = mockParserPayload(p, []byte{0x5b}) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected ParseAML to return an error") - } - }) - - t.Run("unresolved entities", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - // Inject a reference entity to the tree - p.root.Append(entity.NewReference(42, "UNKNOWN")) - - // Setup resolver to serve an empty AML stream - header := mockParserPayload(p, nil) - - if err := p.ParseAML(uint8(42), "DSDT", header); err != errResolvingEntities { - t.Fatalf("expected ParseAML to return errResolvingEntities; got %v", err) - } - }) - }) - - t.Run("parseObj errors", func(t *testing.T) { - t.Run("parsePkgLength error", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - // Setup resolver to serve an AML stream containing an incomplete - // buffer specification - header := mockParserPayload(p, []byte{byte(entity.OpBuffer)}) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected parsePkgLength to return an error") - } - }) - - t.Run("incomplete object list", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - // Setup resolver to serve an AML stream containing an incomplete - // buffer arglist specification - header := mockParserPayload(p, []byte{byte(entity.OpBuffer), 0x10}) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected parsePkgLength to return an error") - } - }) - }) - - t.Run("finalizeObj errors", func(t *testing.T) { - t.Run("else without matching if", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - p.root.Append(entity.NewConst(entity.OpDwordPrefix, 42, uint64(0x42))) - - // Setup resolver to serve an AML stream containing an - // empty else statement without a matching if - header := mockParserPayload(p, []byte{byte(entity.OpElse), 0x0}) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected finalizeObj to return an error") - } - }) - - }) - - t.Run("parseScope errors", func(t *testing.T) { - t.Run("parseNameString error", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - header := mockParserPayload(p, []byte{ - byte(entity.OpScope), - 0x10, // pkglen - }) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected parseScope to return an error") - } - }) - - t.Run("unknown scope", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - header := mockParserPayload(p, []byte{ - byte(entity.OpScope), - 0x10, // pkglen - 'F', 'O', 'O', 'F', - }) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected parseScope to return an error") - } - }) - - t.Run("nameless scope", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, ``) - - header := mockParserPayload(p, []byte{ - byte(entity.OpScope), - 0x02, // pkglen - '\\', // scope name: "\" (root scope) - 0x00, // null string - }) - - if err := p.ParseAML(uint8(42), "DSDT", header); err == nil { - t.Fatal("expected parseScope to return an error") - } - }) - }) - - t.Run("parseNamespacedObj errors", func(t *testing.T) { - t.Run("parseNameString error", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - mockParserPayload(p, nil) - - devInfo := &opcodeTable[0x6a] - if p.parseNamespacedObj(devInfo, 10) { - t.Fatal("expected parseNamespacedObj to return false") - } - }) - - t.Run("scope lookup error", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - header := mockParserPayload(p, []byte{'^', 'F', 'A', 'B', 'C'}) - - p.scopeEnter(p.root) - devInfo := &opcodeTable[0x6a] - if p.parseNamespacedObj(devInfo, header.Length) { - t.Fatal("expected parseNamespacedObj to return false") - } - }) - - t.Run("unsupported namespaced entity", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - header := mockParserPayload(p, []byte{'F', 'A', 'B', 'C'}) - - p.scopeEnter(p.root) - - // We just pass a random non-namespaced opcode table entry to parseNamespacedObj - zeroInfo := &opcodeTable[0x00] - if p.parseNamespacedObj(zeroInfo, header.Length) { - t.Fatal("expected parseNamespacedObj to return false") - } - }) - - t.Run("error parsing args after name", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - header := mockParserPayload(p, []byte{'F', 'A', 'B', 'C'}) - - p.scopeEnter(p.root) - methodInfo := &opcodeTable[0x0d] - if p.parseNamespacedObj(methodInfo, header.Length) { - t.Fatal("expected parseNamespacedObj to return false") - } - }) - }) - - t.Run("parseArg bytelist errors", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - mockParserPayload(p, nil) - - if p.parseArg(new(opcodeInfo), entity.NewGeneric(0, 0), 0, opArgByteList, 42) { - t.Fatal("expected parseNamespacedObj to return false") - } - }) - - t.Run("parseNamedRef errors", func(t *testing.T) { - t.Run("incorrect args for method", func(t *testing.T) { - p.root = entity.NewScope(entity.OpScope, 42, `\`) - - methodDecl := entity.NewMethod(42, "MTHD") - methodDecl.ArgCount = 5 - p.root.Append(methodDecl) - - mockParserPayload(p, []byte{ - 'M', 'T', 'H', 'D', - byte(entity.OpIf), // Incomplete type2 opcode - }) - - p.scopeEnter(p.root) - if p.parseNamedRef() { - t.Fatal("expected parseNamedRef to return false") - } - }) - }) - - t.Run("parseFieldList errors", func(t *testing.T) { - specs := []struct { - op entity.AMLOpcode - args []interface{} - maxReadOffset uint32 - payload []byte - }{ - // Invalid arg count for entity.OpField - { - entity.OpField, - nil, - 0, - nil, - }, - // Wrong arg type for entity.OpField - { - entity.OpField, - []interface{}{0, uint64(42)}, - 0, - nil, - }, - { - entity.OpField, - []interface{}{"FLD0", uint32(42)}, - 0, - nil, - }, - // Invalid arg count for entity.OpIndexField - { - entity.OpIndexField, - nil, - 0, - nil, - }, - // Wrong arg type for entity.OpIndexField - { - entity.OpIndexField, - []interface{}{0, "FLD1", "FLD2"}, - 0, - nil, - }, - { - entity.OpIndexField, - []interface{}{"FLD0", 0, "FLD2"}, - 0, - nil, - }, - { - entity.OpIndexField, - []interface{}{"FLD0", "FLD1", 0}, - 0, - nil, - }, - // Invalid arg count for entity.OpBankField - { - entity.OpBankField, - nil, - 0, - nil, - }, - // Wrong arg type for entity.OpBankField - { - entity.OpBankField, - []interface{}{0, "FLD1", "FLD2"}, - 0, - nil, - }, - { - entity.OpBankField, - []interface{}{"FLD0", 0, "FLD2"}, - 0, - nil, - }, - { - entity.OpBankField, - []interface{}{"FLD0", "FLD1", 0}, - 0, - nil, - }, - // unexpected EOF parsing fields - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - nil, - }, - // reserved field (0x00) with missing pkgLen - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x00}, - }, - // access field (0x01) with missing accessType - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x01}, - }, - // access field (0x01) with missing attribute byte - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x01, 0x01}, - }, - // connect field (0x02) with incomplete TermObject => Buffer arg - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x02, byte(entity.OpBuffer)}, - }, - // extended access field (0x03) with missing ext. accessType - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x03}, - }, - // extended access field (0x03) with missing ext. attribute byte - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x03, 0x01}, - }, - // extended access field (0x03) with missing access byte count value - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0x03, 0x01, 0x02}, - }, - // named field with invalid name - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{0xff}, - }, - // named field with invalid pkgLen - { - entity.OpField, - []interface{}{"FLD0", uint64(42)}, - 128, - []byte{'N', 'A', 'M', 'E'}, - }, - } - - for specIndex, spec := range specs { - mockParserPayload(p, spec.payload) - - if p.parseFieldList(entity.NewField(42), spec.maxReadOffset) { - t.Errorf("[spec %d] expected parseFieldLis to return false", specIndex) - } - } - - t.Run("non-field entity argument", func(t *testing.T) { - if p.parseFieldList(entity.NewDevice(42, "DEV0"), 128) { - t.Fatal("expected parseFieldList to return false when a non-field argument is passed to it") - } - }) - }) - - t.Run("parsePkgLength errors", func(t *testing.T) { - specs := [][]byte{ - // lead byte bits (6:7) indicate 1 extra byte that is missing - []byte{1 << 6}, - // lead byte bits (6:7) indicate 2 extra bytes with the 1st and then 2nd missing - []byte{2 << 6}, - []byte{2 << 6, 0x1}, - // lead byte bits (6:7) indicate 3 extra bytes with the 1st and then 2nd and then 3rd missing - []byte{3 << 6}, - []byte{3 << 6, 0x1}, - []byte{3 << 6, 0x1, 0x2}, - } - - for specIndex, spec := range specs { - mockParserPayload(p, spec) - - if _, ok := p.parsePkgLength(); ok { - t.Errorf("[spec %d] expected parsePkgLength to return false", specIndex) - } - } - }) - - t.Run("parseString errors", func(t *testing.T) { - specs := [][]byte{ - // Unexpected EOF before terminating null byte - []byte{'A'}, - // Characters outside the allowed [0x01, 0x7f] range - []byte{'A', 0xba, 0xdf, 0x00}, - } - - for specIndex, spec := range specs { - mockParserPayload(p, spec) - - if _, ok := p.parseString(); ok { - t.Errorf("[spec %d] expected parseString to return false", specIndex) - } - } - }) - - t.Run("parseTarget errors", func(t *testing.T) { - t.Run("unexpected opcode", func(t *testing.T) { - // Unexpected opcode - mockParserPayload(p, []byte{byte(entity.OpAnd)}) - - if _, ok := p.parseTarget(); ok { - t.Error("expected parseTarget to return false") - } - }) - - t.Run("corrupted data", func(t *testing.T) { - // Invalid opcode and not a method invocation nor a namestring - mockParserPayload(p, []byte{0xba, 0xad}) - - if _, ok := p.parseTarget(); ok { - t.Error("expected parseTarget to return false") - } - }) - }) - - t.Run("parseNameString errors", func(t *testing.T) { - t.Run("EOF while parsing path prefix", func(t *testing.T) { - mockParserPayload(p, []byte{'^'}) - - if _, ok := p.parseNameString(); ok { - t.Error("expected parseNameString to return false") - } - }) - - t.Run("EOF while parsing multiname path", func(t *testing.T) { - specs := [][]byte{ - // multiname path prefix but no data following - []byte{0x2f}, - []byte{ - 0x2f, // multiname path prefix - 0x0, // no segments (segments must be > 0) - }, - []byte{ - 0x2f, // multiname path prefix - 0x1, // 1 expected segment but no more data available - }, - []byte{ - '\\', // RootChar and no more data - }, - } - - for specIndex, spec := range specs { - mockParserPayload(p, spec) - if _, ok := p.parseNameString(); ok { - t.Errorf("[spec %d] expected parseNameString to return false", specIndex) - } - } - }) - }) -} - -func mockParserPayload(p *Parser, payload []byte) *table.SDTHeader { - resolver := fixedPayloadResolver{payload} - header := resolver.LookupTable("DSDT") - p.r.Init( - uintptr(unsafe.Pointer(header)), - header.Length, - uint32(unsafe.Sizeof(table.SDTHeader{})), - ) - - return resolver.LookupTable("DSDT") -} - -func pkgDir() string { - _, f, _, _ := runtime.Caller(1) - return filepath.Dir(f) -} - -type mockResolver struct { - tableFiles []string -} - -func (m mockResolver) LookupTable(name string) *table.SDTHeader { - pathToDumps := pkgDir() + "/../../table/tabletest/" - for _, f := range m.tableFiles { - if !strings.Contains(f, name) { - continue - } - - data, err := ioutil.ReadFile(pathToDumps + f) - if err != nil { - panic(err) - } - - return (*table.SDTHeader)(unsafe.Pointer(&data[0])) - } - - return nil -} - -type fixedPayloadResolver struct { - payload []byte -} - -func (f fixedPayloadResolver) LookupTable(name string) *table.SDTHeader { - hdrLen := int(unsafe.Sizeof(table.SDTHeader{})) - buf := make([]byte, len(f.payload)+hdrLen) - copy(buf[hdrLen:], f.payload) - - hdr := (*table.SDTHeader)(unsafe.Pointer(&buf[0])) - hdr.Length = uint32(len(buf)) - - return hdr -} - -func genDefaultScopes() entity.Container { - rootNS := entity.NewScope(entity.OpScope, 42, `\`) - rootNS.Append(entity.NewScope(entity.OpScope, 42, `_GPE`)) // General events in GPE register block - rootNS.Append(entity.NewScope(entity.OpScope, 42, `_PR_`)) // ACPI 1.0 processor namespace - rootNS.Append(entity.NewScope(entity.OpScope, 42, `_SB_`)) // System bus with all device objects - rootNS.Append(entity.NewScope(entity.OpScope, 42, `_SI_`)) // System indicators - rootNS.Append(entity.NewScope(entity.OpScope, 42, `_TZ_`)) // ACPI 1.0 thermal zone namespace - - // Inject pre-defined OSPM objects - rootNS.Append(namedConst(entity.NewConst(entity.OpStringPrefix, 42, "gopheros"), "_OS_")) - rootNS.Append(namedConst(entity.NewConst(entity.OpStringPrefix, 42, uint64(2)), "_REV")) - - return rootNS -} - -func namedConst(ent *entity.Const, name string) *entity.Const { - ent.SetName(name) - return ent -} diff --git a/src/gopheros/device/acpi/aml/parser/stream_reader.go b/src/gopheros/device/acpi/aml/parser/stream_reader.go deleted file mode 100644 index fc151e3..0000000 --- a/src/gopheros/device/acpi/aml/parser/stream_reader.go +++ /dev/null @@ -1,87 +0,0 @@ -package parser - -import ( - "errors" - "io" - "reflect" - "unsafe" -) - -var ( - errInvalidUnreadByte = errors.New("amlStreamReader: invalid use of UnreadByte") -) - -type amlStreamReader struct { - offset uint32 - data []byte -} - -// Init sets up the reader so it can read up to dataLen bytes from the virtual -// memory address dataAddr. If a non-zero initialOffset is specified, it will -// be used as the current offset in the stream. -func (r *amlStreamReader) Init(dataAddr uintptr, dataLen, initialOffset uint32) { - // Overlay a byte slice on top of the memory block to be accessed. - r.data = *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ - Len: int(dataLen), - Cap: int(dataLen), - Data: dataAddr, - })) - - r.SetOffset(initialOffset) -} - -// EOF returns true if the end of the stream has been reached. -func (r *amlStreamReader) EOF() bool { - return r.offset == uint32(len(r.data)) -} - -// ReadByte returns the next byte from the stream. -func (r *amlStreamReader) ReadByte() (byte, error) { - if r.EOF() { - return 0, io.EOF - } - - r.offset++ - return r.data[r.offset-1], nil -} - -// PeekByte returns the next byte from the stream without advancing the read pointer. -func (r *amlStreamReader) PeekByte() (byte, error) { - if r.EOF() { - return 0, io.EOF - } - - return r.data[r.offset], nil -} - -// LastByte returns the last byte read off the stream -func (r *amlStreamReader) LastByte() (byte, error) { - if r.offset == 0 { - return 0, io.EOF - } - - return r.data[r.offset-1], nil -} - -// UnreadByte moves back the read pointer by one byte. -func (r *amlStreamReader) UnreadByte() error { - if r.offset == 0 { - return errInvalidUnreadByte - } - - r.offset-- - return nil -} - -// Offset returns the current offset. -func (r *amlStreamReader) Offset() uint32 { - return r.offset -} - -// SetOffset sets the reader offset to the supplied value. -func (r *amlStreamReader) SetOffset(off uint32) { - if max := uint32(len(r.data)); off > max { - off = max - } - r.offset = off -} diff --git a/src/gopheros/device/acpi/aml/parser/stream_reader_test.go b/src/gopheros/device/acpi/aml/parser/stream_reader_test.go deleted file mode 100644 index 8c6c701..0000000 --- a/src/gopheros/device/acpi/aml/parser/stream_reader_test.go +++ /dev/null @@ -1,97 +0,0 @@ -package parser - -import ( - "io" - "testing" - "unsafe" -) - -func TestAMLStreamReader(t *testing.T) { - buf := make([]byte, 16) - for i := 0; i < len(buf); i++ { - buf[i] = byte(i) - } - - t.Run("without offset", func(t *testing.T) { - var r amlStreamReader - r.Init( - uintptr(unsafe.Pointer(&buf[0])), - uint32(len(buf)), - 0, - ) - - if r.EOF() { - t.Fatal("unexpected EOF") - } - - if err := r.UnreadByte(); err != errInvalidUnreadByte { - t.Fatalf("expected errInvalidUnreadByte; got %v", err) - } - - if _, err := r.LastByte(); err != io.EOF { - t.Fatalf("unexpected error: %v", err) - } - - for i := 0; i < len(buf); i++ { - exp := byte(i) - - next, err := r.PeekByte() - if err != nil { - t.Fatal(err) - } - if next != exp { - t.Fatalf("expected PeekByte to return %d; got %d", exp, next) - } - - next, err = r.ReadByte() - if err != nil { - t.Fatal(err) - } - if next != exp { - t.Fatalf("expected ReadByte to return %d; got %d", exp, next) - } - - last, err := r.LastByte() - if err != nil { - t.Fatal(err) - } - if last != exp { - t.Fatalf("expected LastByte to return %d; got %d", exp, last) - } - } - - if _, err := r.PeekByte(); err != io.EOF { - t.Fatalf("unexpected error: %v", err) - } - if _, err := r.ReadByte(); err != io.EOF { - t.Fatalf("unexpected error: %v", err) - } - exp := byte(len(buf) - 1) - if last, _ := r.LastByte(); last != exp { - t.Fatalf("expected LastByte to return %d; got %d", exp, last) - } - - }) - - t.Run("with offset", func(t *testing.T) { - var r amlStreamReader - r.Init( - uintptr(unsafe.Pointer(&buf[0])), - uint32(len(buf)), - 8, - ) - - if r.EOF() { - t.Fatal("unexpected EOF") - } - - if exp, got := uint32(8), r.Offset(); got != exp { - t.Fatalf("expected Offset() to return %d; got %d", exp, got) - } - - exp := byte(8) - if next, _ := r.ReadByte(); next != exp { - t.Fatalf("expected ReadByte to return %d; got %d", exp, next) - } - }) -} diff --git a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.aml b/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.aml deleted file mode 100644 index 5786a18..0000000 Binary files a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.aml and /dev/null differ diff --git a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.dsl b/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.dsl deleted file mode 100644 index ad8509d..0000000 --- a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-DSDT.dsl +++ /dev/null @@ -1,152 +0,0 @@ -// DSDT-parser-testsuite -// -// This file contains various ASL constructs to ensure that the AML parser -// properly handles all possible ASL opcodes it may encounter. This test file -// is used in addition to the DSDT.aml file obtained by running acpidump inside -// virtualbox. -DefinitionBlock ("parser-testsuite-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002) -{ - OperationRegion (DBG0, SystemIO, 0x3000, 0x04) - Field (DBG0, ByteAcc, NoLock, Preserve) - { - DHE1, 8 - } - - Device (DRV0) - { - Name (_ADR, Ones) - - // named entity containing qword const - Name (H15F, 0xBADC0FEEDEADC0DE) - Method (_GTF, 0, NotSerialized) // _GTF: Get Task File - { - Return (H15F) - } - } - - // example from p. 268 of ACPI 6.2 spec - Scope(\_SB){ - OperationRegion(TOP1, GenericSerialBus, 0x00, 0x100) // GenericSerialBus device at command offset 0x00 - - Name (SDB0, ResourceTemplate() {}) - Field(TOP1, BufferAcc, NoLock, Preserve){ - Connection(SDB0), // Use the Resource Descriptor defined above - AccessAs(BufferAcc, AttribWord), - FLD0, 8, - FLD1, 8 - } - - Field(TOP1, BufferAcc, NoLock, Preserve){ - Connection(I2cSerialBus(0x5b,,100000,, "\\_SB",,,,RawDataBuffer(){3,9})), - AccessAs(BufferAcc, AttribBytes(4)), - FLD2, 8, - AccessAs(BufferAcc, AttribRawBytes(3)), - FLD3, 8, - AccessAs(BufferAcc, AttribRawProcessBytes(2)), - FLD4, 8 - } - } - - // Other entity types - Event(HLO0) - Mutex(MUT0,1) - Signal(HLO0) - - // Other executable bits - Method (EXE0, 1, Serialized) - { - Local0 = Revision - - // NameString target - Local1 = SizeOf(GLB1) - - Local0 = "my-handle" - Load(DBG0, Local0) - Unload(Local0) - - CreateBitField(Arg0, 0, WFL0) - if(Arg0==0){ - Return(WFL0) - } - - CreateByteField(Arg0, 0, WFL1) - if(Arg0==1){ - Return(WFL1) - } - - CreateWordField(Arg0, 0, WFL2) - if(Arg0==2){ - Return(WFL2) - } - - CreateDwordField(Arg0, 0, WFL3) - if(Arg0==3){ - Return(WFL3) - } - - CreateQwordField(Arg0, 0, WFL4) - if(Arg0==4){ - Return(WFL4) - } - - CreateField(Arg0, 0, 13, WFL5) - if(Arg0==5){ - Return(WFL5) - } - - // Example from p. 951 of the spec - Store ( - LoadTable ("OEM1", "MYOEM", "TABLE1", "\\_SB.PCI0","MYD", - Package () {0,"\\_SB.PCI0"} - ), Local0 - ) - - FromBCD(9, Arg0) - ToBCD(Arg0, Local1) - - Breakpoint - Debug = "test" - Fatal(0xf0, 0xdeadc0de, 1) - - Reset(HLO0) - - // Mutex support - Acquire(MUT0, 0xffff) // no timeout - Release(MUT0) - - // Signal/Wait - Wait(HLO0, 0xffff) - - // Get monotonic timer value - Local0 = Timer - - CopyObject(Local0, Local1) - Return(ObjectType(Local1)) - } - - // Misc regions - - // BankField example from p. 899 of the spec - // Define a 256-byte operational region in SystemIO space and name it GIO0 - OperationRegion (GIO0, SystemIO, 0x125, 0x100) - Field (GIO0, ByteAcc, NoLock, Preserve) { - GLB1, 1, - GLB2, 1, - Offset (1), // Move to offset for byte 1 - BNK1, 4 - } - - BankField (GIO0, BNK1, 0, ByteAcc, NoLock, Preserve) { - Offset (0x30), - FET0, 1, - FET1, 1 - } - - // Data Region - DataTableRegion (REG0, "FOOF", "BAR", "BAZ") - - // Other resources - Processor(CPU0, 1, 0x120, 6){} - PowerResource(PWR0, 0, 0){} - ThermalZone(TZ0){} -} diff --git a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-fwd-decls-DSDT.aml b/src/gopheros/device/acpi/table/tabletest/parser-testsuite-fwd-decls-DSDT.aml deleted file mode 100644 index 68fbecc..0000000 Binary files a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-fwd-decls-DSDT.aml and /dev/null differ diff --git a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-fwd-decls-DSDT.dsl b/src/gopheros/device/acpi/table/tabletest/parser-testsuite-fwd-decls-DSDT.dsl deleted file mode 100644 index 81ebdc1..0000000 --- a/src/gopheros/device/acpi/table/tabletest/parser-testsuite-fwd-decls-DSDT.dsl +++ /dev/null @@ -1,27 +0,0 @@ -DefinitionBlock ("parser-testsuite-fwd-decls-DSDT.aml", "DSDT", 2, "GOPHER", "GOPHEROS", 0x00000002) -{ - Scope(\_SB){ - Method (NST1, 2, NotSerialized) - { - Return ("something") - } - } - - Method(NST0, 1, NotSerialized) - { - // NST1 is declared after NST0 (forward declaration) - NST1(Arg0) - - // This version of NST1 is defined above and has a different signature. - // The parser should be able to resolve it to the correct method and - // parse the correct number of arguments - Return(\_SB.NST1(NST1(123), "arg")) - } - - // The declaration of NST1 in the AML stream occurs after the declaration - // of NST0 method above. - Method(NST1, 1, NotSerialized) - { - Return(Arg0+42) - } -}