From 10ba4f7ad6143da0cca89d43131817bf9be998ca Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Fri, 29 Dec 2017 09:11:09 +0000 Subject: [PATCH] acpi: implement LazyRefResolver for entities that use lazy symbol references --- src/gopheros/device/acpi/aml/entity/entity.go | 108 ++++++++++++++++++ .../device/acpi/aml/entity/entity_test.go | 87 ++++++++++++++ 2 files changed, 195 insertions(+) diff --git a/src/gopheros/device/acpi/aml/entity/entity.go b/src/gopheros/device/acpi/aml/entity/entity.go index 03a81ad..285382c 100644 --- a/src/gopheros/device/acpi/aml/entity/entity.go +++ b/src/gopheros/device/acpi/aml/entity/entity.go @@ -451,6 +451,21 @@ func (ent *Field) SetArg(argIndex uint8, arg interface{}) bool { 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 @@ -508,6 +523,29 @@ func (ent *IndexField) SetArg(argIndex uint8, arg interface{}) bool { 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 { @@ -569,6 +607,29 @@ func (ent *BankField) SetArg(argIndex uint8, arg interface{}) bool { 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 @@ -609,6 +670,24 @@ func NewFieldUnit(tableHandle uint8, name string) *FieldUnit { } } +// 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 @@ -631,6 +710,20 @@ func NewReference(tableHandle uint8, target string) *Reference { } } +// 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 @@ -698,6 +791,21 @@ func NewInvocation(tableHandle uint8, name string, args []interface{}) *Invocati } } +// 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 *Invocation) ResolveSymbolRefs(rootNS Container) *kernel.Error { + var ok bool + if ent.MethodDef, ok = FindInScope(ent.Parent(), rootNS, ent.MethodName).(*Method); !ok { + return &kernel.Error{ + Module: "acpi_aml_vm", + Message: "could not resolve method invocation to: " + ent.MethodName + "; parent: " + ent.Parent().Name(), + } + } + + return nil +} + // Device defines an AML device entity. type Device struct { Scope diff --git a/src/gopheros/device/acpi/aml/entity/entity_test.go b/src/gopheros/device/acpi/aml/entity/entity_test.go index 97d26f3..a4efcd7 100644 --- a/src/gopheros/device/acpi/aml/entity/entity_test.go +++ b/src/gopheros/device/acpi/aml/entity/entity_test.go @@ -214,3 +214,90 @@ nextSpec: } } } + +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"}, + "", + }, + { + &Invocation{MethodName: "UNKNOWN"}, + `could not resolve method invocation to: UNKNOWN; parent: \`, + }, + { + &Invocation{MethodName: "MTH0"}, + "", + }, + } + + 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) + } + } +}