diff --git a/src/gopheros/device/acpi/acpi.go b/src/gopheros/device/acpi/acpi.go index 5042bd0..373be72 100644 --- a/src/gopheros/device/acpi/acpi.go +++ b/src/gopheros/device/acpi/acpi.go @@ -2,6 +2,7 @@ package acpi import ( "gopheros/device" + "gopheros/device/acpi/aml" "gopheros/device/acpi/table" "gopheros/kernel" "gopheros/kernel/kfmt" @@ -45,17 +46,33 @@ type acpiDriver struct { // by the table name. All tables included in this map are mapped into // memory. tableMap map[string]*table.SDTHeader + + // The AML interpreter used by the ACPI driver to execute various + // ACPI-related methods. + amlVM *aml.VM } // DriverInit initializes this driver. func (drv *acpiDriver) DriverInit(w io.Writer) *kernel.Error { - if err := drv.enumerateTables(w); err != nil { + var err *kernel.Error + + if err = drv.enumerateTables(w); err != nil { return err } - drv.printTableInfo(w) - return nil + // Now that we have enumerated the available ACPI tables we can + // initialize the AML interpreter passing the driver instance as + // a table.Resolver. + drv.amlVM = aml.NewVM(w, drv) + if vmErr := drv.amlVM.Init(); vmErr != nil { + return &kernel.Error{ + Module: "acpi", + Message: vmErr.Error(), + } + } + + return err } // DriverName returns the name of this driver. @@ -68,6 +85,11 @@ func (*acpiDriver) DriverVersion() (uint16, uint16, uint16) { return 0, 0, 1 } +// LookupTable implements the table.Resolver interface. +func (drv *acpiDriver) LookupTable(name string) *table.SDTHeader { + return drv.tableMap[name] +} + func (drv *acpiDriver) printTableInfo(w io.Writer) { for name, header := range drv.tableMap { kfmt.Fprintf(w, "%s at 0x%16x %6x (%6s %8s)\n", @@ -84,6 +106,10 @@ func (drv *acpiDriver) printTableInfo(w io.Writer) { // the table list defined by the RSDP, this method will also peek into the // FADT (if found) looking for the address of DSDT. func (drv *acpiDriver) enumerateTables(w io.Writer) *kernel.Error { + if len(drv.tableMap) != 0 { + return nil + } + header, sizeofHeader, err := mapACPITable(drv.rsdtAddr) if err != nil { return err diff --git a/src/gopheros/device/acpi/acpi_test.go b/src/gopheros/device/acpi/acpi_test.go index de235d3..c5a2029 100644 --- a/src/gopheros/device/acpi/acpi_test.go +++ b/src/gopheros/device/acpi/acpi_test.go @@ -9,6 +9,7 @@ import ( "io/ioutil" "os" "path/filepath" + "reflect" "runtime" "testing" "unsafe" @@ -237,6 +238,33 @@ func TestDriverInit(t *testing.T) { } }) + t.Run("AML interpreter init error", func(t *testing.T) { + rsdtAddr, _ := genTestRDST(t, acpiRev2Plus) + identityMapFn = func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + return vmm.Page(frame), nil + } + + drv := &acpiDriver{ + rsdtAddr: rsdtAddr, + useXSDT: true, + } + + // Patch the DSDT with an incomplete extOpPrefix opcode; this + // will trigger an error when trying to parse its AML contents + drv.enumerateTables(ioutil.Discard) + header := drv.LookupTable("DSDT") + rawData := *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ + Len: int(header.Length), + Cap: int(header.Length), + Data: uintptr(unsafe.Pointer(header)) + unsafe.Sizeof(table.SDTHeader{}), + })) + rawData[0] = 0x1b // extOpPrefix + + expErr := "acpi_aml_parser: could not parse AML bytecode" + if err := drv.DriverInit(os.Stderr); err == nil || err.Error() != expErr { + t.Fatalf("expected to get an AML parse error; got %v", err) + } + }) } func TestEnumerateTables(t *testing.T) { diff --git a/src/gopheros/device/acpi/aml/vm.go b/src/gopheros/device/acpi/aml/vm.go index 51f5c40..55899cf 100644 --- a/src/gopheros/device/acpi/aml/vm.go +++ b/src/gopheros/device/acpi/aml/vm.go @@ -90,7 +90,6 @@ func (vm *VM) Init() *Error { if header == nil { continue } - if err := vm.tableParser.ParseAML(uint8(tableHandle+1), tableName, header); err != nil { return &Error{message: err.Module + ": " + err.Error()} }