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

acpi: probe for RSDT and enumerate/map other ACPI tables (inc. DSDT)

This commit is contained in:
Achilleas Anagnostopoulos 2017-08-28 07:18:13 +01:00
parent 49dfc5c9de
commit 78d5fac550
6 changed files with 764 additions and 0 deletions

View File

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

View File

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.