From 0a271b206bbd4b36f385077fd5503bc81c0cfb8c Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Aug 2017 07:25:39 +0100 Subject: [PATCH 1/5] pmm: implement FrameFromAddress This is equivalent to vmm.PageFromAddress but returns back a pmm.Frame --- src/gopheros/kernel/mem/pmm/frame.go | 9 +++++++++ src/gopheros/kernel/mem/pmm/frame_test.go | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/src/gopheros/kernel/mem/pmm/frame.go b/src/gopheros/kernel/mem/pmm/frame.go index 10d5df7..0189013 100644 --- a/src/gopheros/kernel/mem/pmm/frame.go +++ b/src/gopheros/kernel/mem/pmm/frame.go @@ -24,3 +24,12 @@ func (f Frame) Valid() bool { func (f Frame) Address() uintptr { return uintptr(f << mem.PageShift) } + +// FrameFromAddress returns a Frame that corresponds to +// the given physical address. This function can handle +// both page-aligned and not aligned addresses. in the +// latter case, the input address will be rounded down +// to the frame that contains it. +func FrameFromAddress(physAddr uintptr) Frame { + return Frame((physAddr & ^(uintptr(mem.PageSize - 1))) >> mem.PageShift) +} diff --git a/src/gopheros/kernel/mem/pmm/frame_test.go b/src/gopheros/kernel/mem/pmm/frame_test.go index f05968f..59c1988 100644 --- a/src/gopheros/kernel/mem/pmm/frame_test.go +++ b/src/gopheros/kernel/mem/pmm/frame_test.go @@ -23,3 +23,21 @@ func TestFrameMethods(t *testing.T) { t.Error("expected InvalidFrame.Valid() to return false") } } + +func TestFrameFromAddress(t *testing.T) { + specs := []struct { + input uintptr + expFrame Frame + }{ + {0, Frame(0)}, + {4095, Frame(0)}, + {4096, Frame(1)}, + {4123, Frame(1)}, + } + + for specIndex, spec := range specs { + if got := FrameFromAddress(spec.input); got != spec.expFrame { + t.Errorf("[spec %d] expected returned frame to be %v; got %v", specIndex, spec.expFrame, got) + } + } +} From 7bcaf0ee8d024ff4fd58a24411126c64f0132806 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Aug 2017 07:27:35 +0100 Subject: [PATCH 2/5] vmm: implement identity mapping function for contiguous physical mem regions vmm.IdentityMapRegion can be used by device drivers that want to establish an identity mapping for a contiguous physical memory block in order to access some hardware or table. --- src/gopheros/kernel/mem/vmm/map.go | 18 +++++++++++++ src/gopheros/kernel/mem/vmm/map_test.go | 34 ++++++++++++++++++++++++ src/gopheros/kernel/mem/vmm/translate.go | 9 +++++-- 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/gopheros/kernel/mem/vmm/map.go b/src/gopheros/kernel/mem/vmm/map.go index fe56f3b..ddc4b80 100644 --- a/src/gopheros/kernel/mem/vmm/map.go +++ b/src/gopheros/kernel/mem/vmm/map.go @@ -130,6 +130,24 @@ func MapRegion(frame pmm.Frame, size mem.Size, flags PageTableEntryFlag) (Page, return PageFromAddress(startPage), nil } +// IdentityMapRegion establishes an identity mapping to the physical memory +// region which starts at the given frame and ends at frame + pages(size). The +// size argument is always rounded up to the nearest page boundary. +// IdentityMapRegion returns back the Page that corresponds to the region +// start. +func IdentityMapRegion(startFrame pmm.Frame, size mem.Size, flags PageTableEntryFlag) (Page, *kernel.Error) { + startPage := Page(startFrame) + pageCount := Page(((size + (mem.PageSize - 1)) & ^(mem.PageSize - 1)) >> mem.PageShift) + + for curPage := startPage; curPage < startPage+pageCount; curPage++ { + if err := mapFn(curPage, pmm.Frame(curPage), flags); err != nil { + return 0, err + } + } + + return startPage, nil +} + // MapTemporary establishes a temporary RW mapping of a physical memory frame // to a fixed virtual address overwriting any previous mapping. The temporary // mapping mechanism is primarily used by the kernel to access and initialize diff --git a/src/gopheros/kernel/mem/vmm/map_test.go b/src/gopheros/kernel/mem/vmm/map_test.go index 7a0d0f8..e5a68e9 100644 --- a/src/gopheros/kernel/mem/vmm/map_test.go +++ b/src/gopheros/kernel/mem/vmm/map_test.go @@ -164,6 +164,40 @@ func TestMapRegion(t *testing.T) { }) } +func TestIdentityMapRegion(t *testing.T) { + defer func() { + mapFn = Map + }() + + t.Run("success", func(t *testing.T) { + mapCallCount := 0 + mapFn = func(_ Page, _ pmm.Frame, flags PageTableEntryFlag) *kernel.Error { + mapCallCount++ + return nil + } + + if _, err := IdentityMapRegion(pmm.Frame(0xdf0000), 4097, FlagPresent|FlagRW); err != nil { + t.Fatal(err) + } + + if exp := 2; mapCallCount != exp { + t.Errorf("expected Map to be called %d time(s); got %d", exp, mapCallCount) + } + }) + + t.Run("Map fails", func(t *testing.T) { + expErr := &kernel.Error{Module: "test", Message: "map failed"} + + mapFn = func(_ Page, _ pmm.Frame, flags PageTableEntryFlag) *kernel.Error { + return expErr + } + + if _, err := IdentityMapRegion(pmm.Frame(0xdf0000), 128000, FlagPresent|FlagRW); err != expErr { + t.Fatalf("expected error: %v; got %v", expErr, err) + } + }) +} + func TestMapTemporaryErrorsAmd64(t *testing.T) { if runtime.GOARCH != "amd64" { t.Skip("test requires amd64 runtime; skipping") diff --git a/src/gopheros/kernel/mem/vmm/translate.go b/src/gopheros/kernel/mem/vmm/translate.go index 4493f32..e1f07cf 100644 --- a/src/gopheros/kernel/mem/vmm/translate.go +++ b/src/gopheros/kernel/mem/vmm/translate.go @@ -13,7 +13,12 @@ func Translate(virtAddr uintptr) (uintptr, *kernel.Error) { // Calculate the physical address by taking the physical frame address and // appending the offset from the virtual address - physAddr := pte.Frame().Address() + (virtAddr & ((1 << pageLevelShifts[pageLevels-1]) - 1)) - + physAddr := pte.Frame().Address() + PageOffset(virtAddr) return physAddr, nil } + +// PageOffset returns the offset within the page specified by a virtual +// address. +func PageOffset(virtAddr uintptr) uintptr { + return (virtAddr & ((1 << pageLevelShifts[pageLevels-1]) - 1)) +} From 49dfc5c9ded4bf7a2b6014e477ee75fcaffd863b Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Aug 2017 07:16:33 +0100 Subject: [PATCH 3/5] acpi: define structs for standard header and various ACPI tables --- src/gopheros/device/acpi/table/tables.go | 264 +++++++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 src/gopheros/device/acpi/table/tables.go diff --git a/src/gopheros/device/acpi/table/tables.go b/src/gopheros/device/acpi/table/tables.go new file mode 100644 index 0000000..915a12d --- /dev/null +++ b/src/gopheros/device/acpi/table/tables.go @@ -0,0 +1,264 @@ +package table + +// Resolver is an interface implemented by objects that can lookup an ACPI table +// by its name. +// +// LookupTable attempts to locate a table by name returning back a pointer to +// its standard header or nil if the table could not be found. The resolver +// must make sure that the entire table contents are mapped so they can be +// accessed by the caller. +type Resolver interface { + LookupTable(string) *SDTHeader +} + +// RSDPDescriptor defines the root system descriptor pointer for ACPI 1.0. This +// is used as the entry-point for parsing ACPI data. +type RSDPDescriptor struct { + // The signature must contain "RSD PTR " (last byte is a space). + Signature [8]byte + + // A value that when added to the sum of all other bytes contained in + // this descriptor should result in the value 0. + Checksum uint8 + + OEMID [6]byte + + // ACPI revision number. It is 0 for ACPI1.0 and 2 for versions 2.0 to 6.2. + Revision uint8 + + // Physical address of 32-bit root system descriptor table. + RSDTAddr uint32 +} + +// ExtRSDPDescriptor extends RSDPDescriptor with additional fields. It is used +// when RSDPDescriptor.revision > 1. +type ExtRSDPDescriptor struct { + RSDPDescriptor + + // The size of the 64-bit root system descriptor table. + Length uint32 + + // Physical address of 64-bit root system descriptor table. + XSDTAddr uint64 + + // A value that when added to the sum of all other bytes contained in + // this descriptor should result in the value 0. + ExtendedChecksum uint8 + + reserved [3]byte +} + +// SDTHeader defines the common header for all ACPI-related tables. +type SDTHeader struct { + // The signature defines the table type. + Signature [4]byte + + // The length of the table + Length uint32 + + // If this header belongs to a DSDT/SSDT table, the revision is also + // used to indicate whether the AML VM should treat integers as 32-bits + // (revision < 2) or 64-bits (revision >= 2). + Revision uint8 + + // A value that when added to the sum of all other bytes in the table + // should result in the value 0. + Checksum uint8 + + // OEM specific information + OEMID [6]byte + OEMTableID [8]byte + OEMRevision uint32 + + // Information about the ASL compiler that generated this table + CreatorID uint32 + CreatorRevision uint32 +} + +// AddressSpace defines the location where a set of registers resides. +type AddressSpace uint8 + +// The list of supported address space types. +const ( + AddressSpaceSysMemory AddressSpace = iota + AddressSpaceSysIO + AddressSpacePCI + AddressSpaceEmbController + AddressSpaceSMBus + AddressSpaceFuncFixedHW = 0x7f +) + +// GenericAddress specifies a register range located in a particular address +// space. +type GenericAddress struct { + Space AddressSpace + BitWidth uint8 + BitOffset uint8 + AccessSize uint8 + Address uint64 +} + +// PowerProfileType describes a power profile referenced by the FADT table. +type PowerProfileType uint8 + +// The list of supported power profile types +const ( + PowerProfileUnspecified PowerProfileType = iota + PowerProfileDesktop + PowerProfileMobile + PowerProfileWorkstation + PowerProfileEnterpriseServer + PowerProfileSOHOServer + PowerProfileAppliancePC + PowerProfilePerformanceServer +) + +// FADT64 contains the 64-bit FADT extensions which are used by ACPI2+ +type FADT64 struct { + FirmwareControl uint64 + + Dsdt uint64 + + PM1aEventBlock GenericAddress + PM1bEventBlock GenericAddress + PM1aControlBlock GenericAddress + PM1bControlBlock GenericAddress + PM2ControlBlock GenericAddress + PMTimerBlock GenericAddress + GPE0Block GenericAddress + GPE1Block GenericAddress +} + +// FADT (Fixed ACPI Description Table) is an ACPI table containing information +// about fixed register blocks used for power management. +type FADT struct { + SDTHeader + + FirmwareCtrl uint32 + Dsdt uint32 + + reserved uint8 + + PreferredPowerManagementProfile PowerProfileType + SCIInterrupt uint16 + SMICommandPort uint32 + AcpiEnable uint8 + AcpiDisable uint8 + S4BIOSReq uint8 + PSTATEControl uint8 + PM1aEventBlock uint32 + PM1bEventBlock uint32 + PM1aControlBlock uint32 + PM1bControlBlock uint32 + PM2ControlBlock uint32 + PMTimerBlock uint32 + GPE0Block uint32 + GPE1Block uint32 + PM1EventLength uint8 + PM1ControlLength uint8 + PM2ControlLength uint8 + PMTimerLength uint8 + GPE0Length uint8 + GPE1Length uint8 + GPE1Base uint8 + CStateControl uint8 + WorstC2Latency uint16 + WorstC3Latency uint16 + FlushSize uint16 + FlushStride uint16 + DutyOffset uint8 + DutyWidth uint8 + DayAlarm uint8 + MonthAlarm uint8 + Century uint8 + + // Reserved in ACPI 1.0; used since ACPI 2.0+ + BootArchitectureFlags uint16 + + reserved2 uint8 + Flags uint32 + + ResetReg GenericAddress + + ResetValue uint8 + reserved3 [3]uint8 + + // 64-bit pointers to the above structures used by ACPI 2.0+ + Ext FADT64 +} + +// MADT (Multiple APIC Description Table) is an ACPI table containing +// information about the interrupt controllers and the number of installed +// CPUs. Following the table header are a series of variable sized records +// (MADTEntry) which contain additional information. +type MADT struct { + SDTHeader + + LocalControllerAddress uint32 + Flags uint32 +} + +// MADTEntryLocalAPIC describes a single physical processor and its local +// interrupt controller. +type MADTEntryLocalAPIC struct { + ProcessorID uint8 + APICID uint8 + Flags uint32 +} + +// MADTEntryIOAPIC describes an I/O Advanced Programmable Interrupt Controller. +type MADTEntryIOAPIC struct { + APICID uint8 + reserved uint8 + + // Address contains the address of the controller. + Address uint32 + + // SysInterruptBase defines the first interrupt number that this + // controller handles. + SysInterruptBase uint32 +} + +// MADTEntryInterruptSrcOverride contains the data for an Interrupt Source +// Override. This mechanism is used to map IRQ sources to global system +// interrupts. +type MADTEntryInterruptSrcOverride struct { + BusSrc uint8 + IRQSrc uint8 + GlobalInterrupt uint32 + Flags uint16 +} + +// MADTEntryNMI describes a non-maskable interrupt that we need to set up for +// a single processor or all processors. +type MADTEntryNMI struct { + // Processor specifies the local APIC that we need to configure for + // this NMI. If set to 0xff we need to configure all processor APICs. + Processor uint8 + + Flags uint16 + + // This value will be either 0 or 1 and specifies which entry in the + // local vector table of the processor's local APIC we need to setup. + LINT uint8 +} + +// MADTEntryType describes the type of a MADT record. +type MADTEntryType uint8 + +// The list of supported MADT entry types. +const ( + MADTEntryTypeLocalAPIC MADTEntryType = iota + MADTEntryTypeIOAPIC + MADTEntryTypeIntSrcOverride + MADTEntryTypeNMI +) + +// MADTEntry describes a MADT table entry that follows the MADT definition. As +// MADT entries are variable sized records, this struct works as a union. The +// consumer of this struct must check the type value before accessing the union +// values. +type MADTEntry struct { + Type MADTEntryType + Length uint8 +} From 78d5fac5507610e9a311afaec8ece1c1b7645983 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Aug 2017 07:18:13 +0100 Subject: [PATCH 4/5] acpi: probe for RSDT and enumerate/map other ACPI tables (inc. DSDT) --- src/gopheros/device/acpi/acpi.go | 277 ++++++++++ src/gopheros/device/acpi/acpi_test.go | 487 ++++++++++++++++++ .../device/acpi/table/tabletest/APIC.aml | Bin 0 -> 84 bytes .../device/acpi/table/tabletest/DSDT.aml | Bin 0 -> 8648 bytes .../device/acpi/table/tabletest/FACP.aml | Bin 0 -> 244 bytes .../device/acpi/table/tabletest/SSDT.aml | Bin 0 -> 460 bytes 6 files changed, 764 insertions(+) create mode 100644 src/gopheros/device/acpi/acpi.go create mode 100644 src/gopheros/device/acpi/acpi_test.go create mode 100644 src/gopheros/device/acpi/table/tabletest/APIC.aml create mode 100644 src/gopheros/device/acpi/table/tabletest/DSDT.aml create mode 100644 src/gopheros/device/acpi/table/tabletest/FACP.aml create mode 100644 src/gopheros/device/acpi/table/tabletest/SSDT.aml diff --git a/src/gopheros/device/acpi/acpi.go b/src/gopheros/device/acpi/acpi.go new file mode 100644 index 0000000..5042bd0 --- /dev/null +++ b/src/gopheros/device/acpi/acpi.go @@ -0,0 +1,277 @@ +package acpi + +import ( + "gopheros/device" + "gopheros/device/acpi/table" + "gopheros/kernel" + "gopheros/kernel/kfmt" + "gopheros/kernel/mem" + "gopheros/kernel/mem/pmm" + "gopheros/kernel/mem/vmm" + "io" + "unsafe" +) + +const ( + acpiRev1 uint8 = 0 + acpiRev2Plus uint8 = 2 +) + +var ( + errMissingRSDP = &kernel.Error{Module: "acpi", Message: "could not locate ACPI RSDP"} + errTableChecksumMismatch = &kernel.Error{Module: "acpi", Message: "detected checksum mismatch while parsing ACPI table header"} + + mapFn = vmm.Map + identityMapFn = vmm.IdentityMapRegion + unmapFn = vmm.Unmap + + // RDSP must be located in the physical memory region 0xe0000 to 0xfffff + rsdpLocationLow uintptr = 0xe0000 + rsdpLocationHi uintptr = 0xfffff + rsdpAlignment uintptr = 16 + + rsdpSignature = [8]byte{'R', 'S', 'D', ' ', 'P', 'T', 'R', ' '} + fadtSignature = "FACP" +) + +type acpiDriver struct { + // rsdtAddr holds the address to the root system descriptor table. + rsdtAddr uintptr + + // useXSDT specifies if the driver must use the XSDT or the RSDT table. + useXSDT bool + + // The ACPI table map allows the driver to lookup an ACPI table header + // by the table name. All tables included in this map are mapped into + // memory. + tableMap map[string]*table.SDTHeader +} + +// DriverInit initializes this driver. +func (drv *acpiDriver) DriverInit(w io.Writer) *kernel.Error { + if err := drv.enumerateTables(w); err != nil { + return err + } + + drv.printTableInfo(w) + + return nil +} + +// DriverName returns the name of this driver. +func (*acpiDriver) DriverName() string { + return "ACPI" +} + +// DriverVersion returns the version of this driver. +func (*acpiDriver) DriverVersion() (uint16, uint16, uint16) { + return 0, 0, 1 +} + +func (drv *acpiDriver) printTableInfo(w io.Writer) { + for name, header := range drv.tableMap { + kfmt.Fprintf(w, "%s at 0x%16x %6x (%6s %8s)\n", + name, + uintptr(unsafe.Pointer(header)), + header.Length, + string(header.OEMID[:]), + string(header.OEMTableID[:]), + ) + } +} + +// enumerateTables detects and maps all ACPI tables that are present. Besides +// 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 { + header, sizeofHeader, err := mapACPITable(drv.rsdtAddr) + if err != nil { + return err + } + + drv.tableMap = make(map[string]*table.SDTHeader) + + var ( + acpiRev = header.Revision + payloadLen = header.Length - uint32(sizeofHeader) + sdtAddresses []uintptr + ) + + // RSDT uses 4-byte long pointers whereas the XSDT uses 8-byte long. + switch drv.useXSDT { + case true: + sdtAddresses = make([]uintptr, payloadLen>>3) + for curPtr, i := drv.rsdtAddr+sizeofHeader, 0; i < len(sdtAddresses); curPtr, i = curPtr+8, i+1 { + sdtAddresses[i] = uintptr(*(*uint64)(unsafe.Pointer(curPtr))) + } + default: + sdtAddresses = make([]uintptr, payloadLen>>2) + for curPtr, i := drv.rsdtAddr+sizeofHeader, 0; i < len(sdtAddresses); curPtr, i = curPtr+4, i+1 { + sdtAddresses[i] = uintptr(*(*uint32)(unsafe.Pointer(curPtr))) + } + } + + for _, addr := range sdtAddresses { + if header, _, err = mapACPITable(addr); err != nil { + switch err { + case errTableChecksumMismatch: + kfmt.Fprintf(w, "%s at 0x%16x %6x [checksum mismatch; skipping]\n", + string(header.Signature[:]), + uintptr(unsafe.Pointer(header)), + header.Length, + ) + continue + default: + return err + } + } + + signature := string(header.Signature[:]) + drv.tableMap[signature] = header + + // The FADT allows us to lookup the DSDT table address + if signature == fadtSignature { + fadt := (*table.FADT)(unsafe.Pointer(header)) + + dsdtAddr := uintptr(fadt.Dsdt) + if acpiRev >= acpiRev2Plus { + dsdtAddr = uintptr(fadt.Ext.Dsdt) + } + + if header, _, err = mapACPITable(dsdtAddr); err != nil { + switch err { + case errTableChecksumMismatch: + kfmt.Fprintf(w, "%s at 0x%16x %6x [checksum mismatch; skipping]\n", + string(header.Signature[:]), + uintptr(unsafe.Pointer(header)), + header.Length, + ) + continue + default: + return err + } + } + + drv.tableMap[string(header.Signature[:])] = header + } + + } + + return nil +} + +// mapACPITable attempts to map and parse the header for the ACPI table starting +// at the given address. It then uses the length field for the header to expand +// the mapping to cover the table contents and verifies the checksum before +// returning a pointer to the table header. +func mapACPITable(tableAddr uintptr) (header *table.SDTHeader, sizeofHeader uintptr, err *kernel.Error) { + var headerPage vmm.Page + + // Identity-map the table header so we can access its length field + sizeofHeader = unsafe.Sizeof(table.SDTHeader{}) + if headerPage, err = identityMapFn(pmm.FrameFromAddress(tableAddr), mem.Size(sizeofHeader), vmm.FlagPresent); err != nil { + return nil, sizeofHeader, err + } + + // Expand mapping to cover the table contents + headerPageAddr := headerPage.Address() + vmm.PageOffset(tableAddr) + header = (*table.SDTHeader)(unsafe.Pointer(headerPageAddr)) + if _, err = identityMapFn(pmm.FrameFromAddress(tableAddr), mem.Size(header.Length), vmm.FlagPresent); err != nil { + return nil, sizeofHeader, err + } + + if !validTable(headerPageAddr, header.Length) { + err = errTableChecksumMismatch + } + + return header, sizeofHeader, err +} + +// locateRSDT scans the memory region [rsdpLocationLow, rsdpLocationHi] looking +// for the signature of the root system descriptor pointer (RSDP). If the RSDP +// is found and is valid, locateRSDT returns the physical address of the root +// system descriptor table (RSDT) or the extended system descriptor table (XSDT) +// if the system supports ACPI 2.0+. +func locateRSDT() (uintptr, bool, *kernel.Error) { + var ( + rsdp *table.RSDPDescriptor + rsdp2 *table.ExtRSDPDescriptor + ) + + // Cleanup temporary identity mappings when the function returns + defer func() { + for curPage := vmm.PageFromAddress(rsdpLocationLow); curPage <= vmm.PageFromAddress(rsdpLocationHi); curPage++ { + unmapFn(curPage) + } + }() + + // Setup temporary identity mapping so we can scan for the header + for curPage := vmm.PageFromAddress(rsdpLocationLow); curPage <= vmm.PageFromAddress(rsdpLocationHi); curPage++ { + if err := mapFn(curPage, pmm.Frame(curPage), vmm.FlagPresent); err != nil { + return 0, false, err + } + } + + // The RSDP should be aligned on a 16-byte boundary +checkNextBlock: + for curPtr := rsdpLocationLow; curPtr < rsdpLocationHi; curPtr += rsdpAlignment { + rsdp = (*table.RSDPDescriptor)(unsafe.Pointer(curPtr)) + for i, b := range rsdpSignature { + if rsdp.Signature[i] != b { + continue checkNextBlock + } + } + + if rsdp.Revision == acpiRev1 { + if !validTable(curPtr, uint32(unsafe.Sizeof(*rsdp))) { + continue + } + + return uintptr(rsdp.RSDTAddr), false, nil + } + + // System uses ACPI revision > 1 and provides an extended RSDP + // which can be accessed at the same place. + rsdp2 = (*table.ExtRSDPDescriptor)(unsafe.Pointer(curPtr)) + if !validTable(curPtr, uint32(unsafe.Sizeof(*rsdp2))) { + continue + } + + return uintptr(rsdp2.XSDTAddr), true, nil + } + + return 0, false, errMissingRSDP +} + +// validTable calculates the checksum for an ACPI table of length tableLength +// that starts at tablePtr and returns true if the table is valid. +func validTable(tablePtr uintptr, tableLength uint32) bool { + var ( + i uint32 + sum uint8 + ) + + for i = 0; i < tableLength; i++ { + sum += *(*uint8)(unsafe.Pointer(tablePtr + uintptr(i))) + } + + return sum == 0 +} + +func probeForACPI() device.Driver { + if rsdtAddr, useXSDT, err := locateRSDT(); err == nil { + return &acpiDriver{ + rsdtAddr: rsdtAddr, + useXSDT: useXSDT, + } + } + + return nil +} + +func init() { + device.RegisterDriver(&device.DriverInfo{ + Order: device.DetectOrderBeforeACPI, + Probe: probeForACPI, + }) +} diff --git a/src/gopheros/device/acpi/acpi_test.go b/src/gopheros/device/acpi/acpi_test.go new file mode 100644 index 0000000..de235d3 --- /dev/null +++ b/src/gopheros/device/acpi/acpi_test.go @@ -0,0 +1,487 @@ +package acpi + +import ( + "gopheros/device/acpi/table" + "gopheros/kernel" + "gopheros/kernel/mem" + "gopheros/kernel/mem/pmm" + "gopheros/kernel/mem/vmm" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "testing" + "unsafe" +) + +var ( + dsdtSignature = "DSDT" +) + +func TestProbe(t *testing.T) { + defer func(rsdpLow, rsdpHi, rsdpAlign uintptr) { + mapFn = vmm.Map + unmapFn = vmm.Unmap + rsdpLocationLow = rsdpLow + rsdpLocationHi = rsdpHi + rsdpAlignment = rsdpAlign + }(rsdpLocationLow, rsdpLocationHi, rsdpAlignment) + + t.Run("ACPI1", func(t *testing.T) { + mapFn = func(_ vmm.Page, _ pmm.Frame, _ vmm.PageTableEntryFlag) *kernel.Error { return nil } + unmapFn = func(_ vmm.Page) *kernel.Error { return nil } + + // Allocate space for 2 descriptors; leave the first entry + // blank to test that locateRSDT will jump over it and populate + // the second descriptor + sizeofRSDP := unsafe.Sizeof(table.RSDPDescriptor{}) + buf := make([]byte, 2*sizeofRSDP) + rsdpHeader := (*table.RSDPDescriptor)(unsafe.Pointer(&buf[sizeofRSDP])) + rsdpHeader.Signature = rsdpSignature + rsdpHeader.Revision = acpiRev1 + rsdpHeader.RSDTAddr = 0xbadf00 + rsdpHeader.Checksum = -calcChecksum(uintptr(unsafe.Pointer(rsdpHeader)), uintptr(sizeofRSDP)) + + rsdpLocationLow = uintptr(unsafe.Pointer(&buf[0])) + rsdpLocationHi = uintptr(unsafe.Pointer(&buf[2*sizeofRSDP-1])) + // As we cannot ensure 16-byte alignment for our buffer we need to override the + // alignment so we scan all bytes in the buffer for the descriptor signature + rsdpAlignment = 1 + + drv := probeForACPI() + if drv == nil { + t.Fatal("ACPI probe failed") + } + + drv.DriverName() + drv.DriverVersion() + + acpiDrv := drv.(*acpiDriver) + + if acpiDrv.rsdtAddr != uintptr(rsdpHeader.RSDTAddr) { + t.Fatalf("expected probed RSDT address to be 0x%x; got 0x%x", uintptr(rsdpHeader.RSDTAddr), acpiDrv.rsdtAddr) + } + + if exp := false; acpiDrv.useXSDT != exp { + t.Fatal("expected probe to locate the RSDT and not the XSDT") + } + }) + + t.Run("ACPI2+", func(t *testing.T) { + mapFn = func(_ vmm.Page, _ pmm.Frame, _ vmm.PageTableEntryFlag) *kernel.Error { return nil } + unmapFn = func(_ vmm.Page) *kernel.Error { return nil } + + // Allocate space for 2 descriptors; leave the first entry + // blank to test that locateRSDT will jump over it and populate + // the second descriptor + sizeofRSDP := unsafe.Sizeof(table.RSDPDescriptor{}) + sizeofExtRSDP := unsafe.Sizeof(table.ExtRSDPDescriptor{}) + buf := make([]byte, 2*sizeofExtRSDP) + rsdpHeader := (*table.ExtRSDPDescriptor)(unsafe.Pointer(&buf[sizeofExtRSDP])) + rsdpHeader.Signature = rsdpSignature + rsdpHeader.Revision = acpiRev2Plus + rsdpHeader.RSDTAddr = 0xbadf00 // we should ignore this and use XSDT instrad + rsdpHeader.Checksum = -calcChecksum(uintptr(unsafe.Pointer(rsdpHeader)), uintptr(sizeofRSDP)) + + rsdpHeader.XSDTAddr = 0xc0ffee + rsdpHeader.ExtendedChecksum = -calcChecksum(uintptr(unsafe.Pointer(rsdpHeader)), uintptr(sizeofExtRSDP)) + + rsdpLocationLow = uintptr(unsafe.Pointer(&buf[0])) + rsdpLocationHi = uintptr(unsafe.Pointer(&buf[2*sizeofExtRSDP-1])) + // As we cannot ensure 16-byte alignment for our buffer we need to override the + // alignment so we scan all bytes in the buffer for the descriptor signature + rsdpAlignment = 1 + + drv := probeForACPI() + if drv == nil { + t.Fatal("ACPI probe failed") + } + + acpiDrv := drv.(*acpiDriver) + + if acpiDrv.rsdtAddr != uintptr(rsdpHeader.XSDTAddr) { + t.Fatalf("expected probed RSDT address to be 0x%x; got 0x%x", uintptr(rsdpHeader.XSDTAddr), acpiDrv.rsdtAddr) + } + + if exp := true; acpiDrv.useXSDT != exp { + t.Fatal("expected probe to locate the XSDT and not the RSDT") + } + }) + + t.Run("RSDP ACPI1 checksum mismatch", func(t *testing.T) { + mapFn = func(_ vmm.Page, _ pmm.Frame, _ vmm.PageTableEntryFlag) *kernel.Error { return nil } + unmapFn = func(_ vmm.Page) *kernel.Error { return nil } + + sizeofRSDP := unsafe.Sizeof(table.RSDPDescriptor{}) + buf := make([]byte, sizeofRSDP) + rsdpHeader := (*table.RSDPDescriptor)(unsafe.Pointer(&buf[0])) + rsdpHeader.Signature = rsdpSignature + rsdpHeader.Revision = acpiRev1 + + // Set wrong checksum + rsdpHeader.Checksum = 0 + + // As we cannot ensure 16-byte alignment for our buffer we need to override the + // alignment so we scan all bytes in the buffer for the descriptor signature + rsdpLocationLow = uintptr(unsafe.Pointer(&buf[0])) + rsdpLocationHi = uintptr(unsafe.Pointer(&buf[sizeofRSDP-1])) + rsdpAlignment = 1 + + drv := probeForACPI() + if drv != nil { + t.Fatal("expected ACPI probe to fail") + } + }) + + t.Run("RSDP ACPI2+ checksum mismatch", func(t *testing.T) { + mapFn = func(_ vmm.Page, _ pmm.Frame, _ vmm.PageTableEntryFlag) *kernel.Error { return nil } + unmapFn = func(_ vmm.Page) *kernel.Error { return nil } + + sizeofExtRSDP := unsafe.Sizeof(table.ExtRSDPDescriptor{}) + buf := make([]byte, sizeofExtRSDP) + rsdpHeader := (*table.ExtRSDPDescriptor)(unsafe.Pointer(&buf[0])) + rsdpHeader.Signature = rsdpSignature + rsdpHeader.Revision = acpiRev2Plus + + // Set wrong checksum for extended rsdp + rsdpHeader.ExtendedChecksum = 0 + + // As we cannot ensure 16-byte alignment for our buffer we need to override the + // alignment so we scan all bytes in the buffer for the descriptor signature + rsdpLocationLow = uintptr(unsafe.Pointer(&buf[0])) + rsdpLocationHi = uintptr(unsafe.Pointer(&buf[sizeofExtRSDP-1])) + rsdpAlignment = 1 + + drv := probeForACPI() + if drv != nil { + t.Fatal("expected ACPI probe to fail") + } + }) + + t.Run("error mapping rsdp memory block", func(t *testing.T) { + expErr := &kernel.Error{Module: "test", Message: "vmm.Map failed"} + mapFn = func(_ vmm.Page, _ pmm.Frame, _ vmm.PageTableEntryFlag) *kernel.Error { return expErr } + unmapFn = func(_ vmm.Page) *kernel.Error { return nil } + + drv := probeForACPI() + if drv != nil { + t.Fatal("expected ACPI probe to fail") + } + }) +} + +func TestDriverInit(t *testing.T) { + defer func() { + identityMapFn = vmm.IdentityMapRegion + }() + + t.Run("success", 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, + } + + if err := drv.DriverInit(os.Stderr); err != nil { + t.Fatal(err) + } + }) + + t.Run("map errors in enumerateTables", func(t *testing.T) { + rsdtAddr, tableList := genTestRDST(t, acpiRev2Plus) + + var ( + expErr = &kernel.Error{Module: "test", Message: "vmm.Map failed"} + callCount int + ) + + drv := &acpiDriver{ + rsdtAddr: rsdtAddr, + useXSDT: true, + } + + specs := []func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error){ + func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + // fail while trying to map RSDT + return 0, expErr + }, + func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + // fail while trying to map any other ACPI table + callCount++ + if callCount > 2 { + return 0, expErr + } + return vmm.Page(frame), nil + }, + func(frame pmm.Frame, size mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + // fail while trying to map DSDT + for _, header := range tableList { + if header.Length == uint32(size) && string(header.Signature[:]) == dsdtSignature { + return 0, expErr + } + } + return vmm.Page(frame), nil + }, + } + + // Test map errors for all map calls in enumerateTables + for specIndex, spec := range specs { + identityMapFn = spec + if err := drv.DriverInit(os.Stderr); err != expErr { + t.Errorf("[spec %d]; expected to get an error\n", specIndex) + } + } + }) + +} + +func TestEnumerateTables(t *testing.T) { + defer func() { + identityMapFn = vmm.IdentityMapRegion + }() + + var expTables = []string{"SSDT", "APIC", "FACP", "DSDT"} + + t.Run("ACPI1", func(t *testing.T) { + rsdtAddr, tableList := genTestRDST(t, acpiRev1) + + identityMapFn = func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + // The frame encodes the table index we need to lookup (see genTestRDST) + nextTableIndex := int(frame) + if nextTableIndex >= len(tableList) { + // This is the RSDT + return vmm.Page(frame), nil + } + + header := tableList[nextTableIndex] + return vmm.PageFromAddress(uintptr(unsafe.Pointer(header))), nil + } + + drv := &acpiDriver{ + rsdtAddr: rsdtAddr, + useXSDT: false, + } + + if err := drv.enumerateTables(os.Stderr); err != nil { + t.Fatal(err) + } + + if exp, got := len(expTables), len(drv.tableMap); got != exp { + t.Fatalf("expected enumerateTables to discover %d tables; got %d\n", exp, got) + } + + for _, tableName := range expTables { + if drv.tableMap[tableName] == nil { + t.Fatalf("expected enumerateTables to discover table %q", tableName) + } + } + + drv.printTableInfo(os.Stderr) + }) + + t.Run("ACPI2+", 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, + } + + if err := drv.enumerateTables(os.Stderr); err != nil { + t.Fatal(err) + } + + if exp, got := len(expTables), len(drv.tableMap); got != exp { + t.Fatalf("expected enumerateTables to discover %d tables; got %d\n", exp, got) + } + + for _, tableName := range expTables { + if drv.tableMap[tableName] == nil { + t.Fatalf("expected enumerateTables to discover table %q", tableName) + } + } + }) + + t.Run("checksum mismatch", func(t *testing.T) { + rsdtAddr, tableList := genTestRDST(t, acpiRev2Plus) + identityMapFn = func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + return vmm.Page(frame), nil + } + + // Set bad checksum for "SSDT" and "DSDT" + for _, header := range tableList { + switch string(header.Signature[:]) { + case "SSDT", dsdtSignature: + header.Checksum++ + } + } + + drv := &acpiDriver{ + rsdtAddr: rsdtAddr, + useXSDT: true, + } + + if err := drv.enumerateTables(os.Stderr); err != nil { + t.Fatal(err) + } + + expTables := []string{"APIC", "FACP"} + + if exp, got := len(expTables), len(drv.tableMap); got != exp { + t.Fatalf("expected enumerateTables to discover %d tables; got %d\n", exp, got) + } + + for _, tableName := range expTables { + if drv.tableMap[tableName] == nil { + t.Fatalf("expected enumerateTables to discover table %q", tableName) + } + } + }) +} + +func TestMapACPITableErrors(t *testing.T) { + defer func() { + identityMapFn = vmm.IdentityMapRegion + }() + + var ( + callCount int + expErr = &kernel.Error{Module: "test", Message: "identityMapRegion failed"} + header table.SDTHeader + ) + + identityMapFn = func(frame pmm.Frame, _ mem.Size, _ vmm.PageTableEntryFlag) (vmm.Page, *kernel.Error) { + callCount++ + if callCount >= 2 { + return 0, expErr + } + + return vmm.PageFromAddress(uintptr(unsafe.Pointer(&header))), nil + } + + // Test errors while mapping the table contents and the table header + for i := 0; i < 2; i++ { + if _, _, err := mapACPITable(0xf00); err != expErr { + t.Errorf("[spec %d]; expected to get an error\n", i) + } + } +} + +func genTestRDST(t *testing.T, acpiVersion uint8) (rsdtAddr uintptr, tableList []*table.SDTHeader) { + dumpFiles, err := filepath.Glob(pkgDir() + "/table/tabletest/*.aml") + if err != nil { + t.Fatal(err) + } + + var fadt, dsdt *table.SDTHeader + var dsdtIndex int + + for index, df := range dumpFiles { + dumpData, err := ioutil.ReadFile(df) + if err != nil { + t.Fatal(err) + } + + header := (*table.SDTHeader)(unsafe.Pointer(&dumpData[0])) + tableName := string(header.Signature[:]) + switch tableName { + case dsdtSignature, fadtSignature: + if tableName == dsdtSignature { + dsdt = header + dsdtIndex = index + } else { + fadt = header + } + } + + tableList = append(tableList, header) + } + + // Setup the pointer to the DSDT + if fadt != nil && dsdt != nil { + fadtHeader := (*table.FADT)(unsafe.Pointer(fadt)) + if acpiVersion == acpiRev1 { + // Since the tests run in 64-bit mode these 32-bit addresses + // will be invalid and cause a page fault. So we cheat and + // encode the table index and page offset as the pointer. + // The test code will hook identityMapFn to reconstruct the + // correct pointer to the table contents. + offset := vmm.PageOffset(uintptr(unsafe.Pointer(dsdt))) + encodedTableLoc := (uintptr(dsdtIndex) << mem.PageShift) + offset + fadtHeader.Dsdt = uint32(encodedTableLoc) + } else { + fadtHeader.Ext.Dsdt = uint64(uintptr(unsafe.Pointer(dsdt))) + } + updateChecksum(fadt) + } + + // Assemble the RDST + var ( + sizeofSDTHeader = unsafe.Sizeof(table.SDTHeader{}) + rsdtHeader *table.SDTHeader + ) + + switch acpiVersion { + case acpiRev1: + buf := make([]byte, int(sizeofSDTHeader)+4*len(tableList)) + rsdtHeader = (*table.SDTHeader)(unsafe.Pointer(&buf[0])) + rsdtHeader.Signature = [4]byte{'R', 'S', 'D', 'T'} + rsdtHeader.Revision = acpiVersion + rsdtHeader.Length = uint32(sizeofSDTHeader) + + // Since the tests run in 64-bit mode these 32-bit addresses + // will be invalid and cause a page fault. So we cheat and + // encode the table index and page offset as the pointer. + // The test code will hook identityMapFn to reconstruct the + // correct pointer to the table contents. + for index, tableHeader := range tableList { + offset := vmm.PageOffset(uintptr(unsafe.Pointer(tableHeader))) + encodedTableLoc := (uintptr(index) << mem.PageShift) + offset + + *(*uint32)(unsafe.Pointer(&buf[rsdtHeader.Length])) = uint32(encodedTableLoc) + rsdtHeader.Length += 4 + } + default: + buf := make([]byte, int(sizeofSDTHeader)+8*len(tableList)) + rsdtHeader = (*table.SDTHeader)(unsafe.Pointer(&buf[0])) + rsdtHeader.Signature = [4]byte{'R', 'S', 'D', 'T'} + rsdtHeader.Revision = acpiVersion + rsdtHeader.Length = uint32(sizeofSDTHeader) + for _, tableHeader := range tableList { + // Do not include DSDT. This will be referenced via FADT + if string(tableHeader.Signature[:]) == dsdtSignature { + continue + } + *(*uint64)(unsafe.Pointer(&buf[rsdtHeader.Length])) = uint64(uintptr(unsafe.Pointer(tableHeader))) + rsdtHeader.Length += 8 + } + } + + updateChecksum(rsdtHeader) + return uintptr(unsafe.Pointer(rsdtHeader)), tableList +} + +func updateChecksum(header *table.SDTHeader) { + header.Checksum = -calcChecksum(uintptr(unsafe.Pointer(header)), uintptr(header.Length)) +} + +func calcChecksum(tableAddr, length uintptr) uint8 { + var checksum uint8 + for ptr := tableAddr; ptr < tableAddr+length; ptr++ { + checksum += *(*uint8)(unsafe.Pointer(ptr)) + } + + return checksum +} + +func pkgDir() string { + _, f, _, _ := runtime.Caller(1) + return filepath.Dir(f) +} diff --git a/src/gopheros/device/acpi/table/tabletest/APIC.aml b/src/gopheros/device/acpi/table/tabletest/APIC.aml new file mode 100644 index 0000000000000000000000000000000000000000..a7a3661b8df11e252ffa99b1465037303c7ef13a GIT binary patch literal 84 zcmZ<^@N^DgU|?WM4s-I4P*4DojzBR+pqOK@k3u4lW?*>m55#BU0%9;9$l~M#vUnL7 RI2af}a*RA6^1wfkGyq8<3jqKC literal 0 HcmV?d00001 diff --git a/src/gopheros/device/acpi/table/tabletest/DSDT.aml b/src/gopheros/device/acpi/table/tabletest/DSDT.aml new file mode 100644 index 0000000000000000000000000000000000000000..dda299580f9a7a17e1f79517c5e5262d0a8baa14 GIT binary patch literal 8648 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 PHqGsuYis^s_SgRdhEg|q literal 0 HcmV?d00001 diff --git a/src/gopheros/device/acpi/table/tabletest/FACP.aml b/src/gopheros/device/acpi/table/tabletest/FACP.aml new file mode 100644 index 0000000000000000000000000000000000000000..82d0a7ddc22f53f3375baadac58285d19b932fe1 GIT binary patch literal 244 zcmYk0F%E+;3`M^~D#6APe1cwqgjP&QAR$#$EOZxaJ>V+FInJa_>e72&0LSSci;iu_*c1T!Yp0@sUdUN kX=}#*X8R1*6|VF*UP4;9^Sr{(E{e+bu;70w`($v)2EZZ|0RR91 literal 0 HcmV?d00001 diff --git a/src/gopheros/device/acpi/table/tabletest/SSDT.aml b/src/gopheros/device/acpi/table/tabletest/SSDT.aml new file mode 100644 index 0000000000000000000000000000000000000000..e659e096abc7a873656a13f3b7ff402001c32d36 GIT binary patch literal 460 zcmWFzb_qGd$iTojH_XXDLO}sUItPS?FflMNc>0C-Xs`+>2)Ikd#0Lb$M>lf=r3`>F MK(Kfe47Lye0G?P45C8xG literal 0 HcmV?d00001 From 7d959af0a9e3ac41478f1be6e33643251d650017 Mon Sep 17 00:00:00 2001 From: Achilleas Anagnostopoulos Date: Mon, 28 Aug 2017 07:18:43 +0100 Subject: [PATCH 5/5] acpi: import and register ACPI driver with hal --- src/gopheros/kernel/hal/hal.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/gopheros/kernel/hal/hal.go b/src/gopheros/kernel/hal/hal.go index 713759f..02cbce9 100644 --- a/src/gopheros/kernel/hal/hal.go +++ b/src/gopheros/kernel/hal/hal.go @@ -10,6 +10,9 @@ import ( "gopheros/kernel/hal/multiboot" "gopheros/kernel/kfmt" "sort" + + // import and register acpi driver + _ "gopheros/device/acpi" ) // managedDevices contains the devices discovered by the HAL. @@ -44,7 +47,7 @@ func DetectHardware() { // probe executes the probe function for each driver and invokes // onDriverInit for each successfully initialized driver. func probe(driverInfoList device.DriverInfoList) { - var w = kfmt.PrefixWriter{Sink: kfmt.GetOutputSink()} + var w kfmt.PrefixWriter for _, info := range driverInfoList { drv := info.Probe() @@ -56,6 +59,7 @@ func probe(driverInfoList device.DriverInfoList) { major, minor, patch := drv.DriverVersion() kfmt.Fprintf(&strBuf, "[hal] %s(%d.%d.%d): ", drv.DriverName(), major, minor, patch) w.Prefix = strBuf.Bytes() + w.Sink = kfmt.GetOutputSink() if err := drv.DriverInit(&w); err != nil { kfmt.Fprintf(&w, "init failed: %s\n", err.Message)