Documentation ¶
Overview ¶
Package acpi began life as a relatively simple set of functions. At some point we wanted to be able to extend the ACPI table over a kexec and that's when it all went nasty. A few issues crop up. In theory, one should be able to put tables anywhere. In practice, even in the EFI age, this is not simple. The root pointer for tables, RSDP, Root Services Data Pointer, is in memory protected by the southbridge/ICH/PCH with lockdown bits (disable writes once, can not be reset until power on/reset). Writes to it are transparently discarded. (This makes sense, as crap DOS programs probably tried to write that area all the time. Everything -- everything! -- about x86 and BIOS is explainable by DOS, 16 bit addresses, 4 bit segments, 20 bits, and the incredible failure of vision in 1999 of building a bunch of tables with 32 bit pointers in them. The x86 world is nothing if not consistent: short-sighted decisions for 40+ years). The two-byte EBDA pointer (16 bits) is shifted left 4 bits to get a 20-bit address which points to *the range of memory* containing, maybe, the RSDP. The RSDP has to live in the low 20 bits of address space (remember 20 bits, right?) (Yes, I know about the EFI tables which make this restriction less of a problem,
but for now all the firmware I've seen adheres to the "RSDP in e or f segment" rule.)
The RSDP has two pointers in it, one or both containing a value: 32 bit pointer or 64 bit pointer to the RSDT or XSDT. (see "failure of vision" above.) RSDT has 32-bit pointers, XSDT 64-bit pointers. The spec recommends you ignore the 32-bit pointer variants but as of 2019, I still see use of them; this package will read and write the variants but the internal structs are defined with 64-bit pointers (oh, if only the ACPICA code had gotten this right, but that code is pretty bad too). What's really fun: when you generate the [RX]SDT, you need to generate pointers too. It's best to keep those tables in a physically contiguous area, so we do; not all systems follow this rule, which is asking for trouble. Finally, not all tables are generated in a consistent way, e.g. the IBFT is not like most other tables containing variable length data, because the people who created it are Klever. IBFT has its own heap, and the elements in the heap follow rules unlike all other tables. Nice! If you really look at ACPI closely, you can kind of see that it's optimized for NASM, which is part of what makes it so unpleasant. But, it's what we have.
Index ¶
- Constants
- Variables
- func Marshal(t Tabler) ([]byte, error)
- func NewRSDP(addr uintptr, len uint) []byte
- func ShowTable(t Tabler) string
- type Generic
- func (g *Generic) AllData() []byte
- func (g *Generic) CheckSum() uint8
- func (g *Generic) CreatorID() uint32
- func (g *Generic) CreatorRevision() uint32
- func (g *Generic) Len() uint32
- func (g *Generic) Marshal() ([]byte, error)
- func (g *Generic) OEMID() string
- func (g *Generic) OEMRevision() uint32
- func (g *Generic) OEMTableID() string
- func (g *Generic) Revision() uint8
- func (g *Generic) Sig() string
- func (g *Generic) TableData() []byte
- type Header
- type HeapTable
- type IBFT
- type IBFTInitiator
- type IBFTNIC
- type IBFTTarget
- type RSDP
- func (r *RSDP) AllData() []byte
- func (r *RSDP) Base() int64
- func (r *RSDP) CheckSum() uint8
- func (r *RSDP) CreatorID() uint32
- func (r *RSDP) CreatorRevision() uint32
- func (r *RSDP) Len() uint32
- func (r *RSDP) Marshal() ([]byte, error)
- func (r *RSDP) OEMID() string
- func (r *RSDP) OEMRevision() uint32
- func (r *RSDP) OEMTableID() string
- func (r *RSDP) Revision() uint8
- func (r *RSDP) Sig() string
- func (r *RSDP) TableData() []byte
- type Raw
- func (r *Raw) AllData() []byte
- func (r *Raw) CheckSum() uint8
- func (r *Raw) CreatorID() uint32
- func (r *Raw) CreatorRevision() uint32
- func (r *Raw) Len() uint32
- func (r *Raw) Marshal() ([]byte, error)
- func (r *Raw) OEMID() string
- func (r *Raw) OEMRevision() uint32
- func (r *Raw) OEMTableID() string
- func (r *Raw) Revision() uint8
- func (r *Raw) Sig() string
- func (r *Raw) TableData() []byte
- type SDT
- type Tabler
Constants ¶
const ( // LengthOffset is the offset of the table length LengthOffset = 4 // CSUMOffset is the offset of the single byte checksum in *most* ACPI tables CSUMOffset = 9 // MinTableLength is the minimum length: 4 byte tag, 4 byte length, 1 byte revision, 1 byte checksum, MinTableLength = 10 )
const ( // HeaderLength is a common header length for (almost) // all ACPI tables. HeaderLength = 36 )
const (
// Revision marks lowest ACPI revision we support.
Revision = 2
)
Variables ¶
var ( // Debug implements fmt.Sprintf and can be used for debug printing Debug = func(string, ...interface{}) {} )
Functions ¶
func Marshal ¶
Marshal marshals a Tabler into a byte slice. Once marshaling is done, it inserts the length into the standard place at LengthOffset, and then generates and inserts a checksum at CSUMOffset.
Types ¶
type Generic ¶
type Generic struct { Header // contains filtered or unexported fields }
Generic is the generic ACPI table, with a Header and data This makes it possible for users to change certain parts of the Header (e.g. vendor id) without touching the data. When the table is Marshal'ed out checksums are regenerated.
func (*Generic) CreatorRevision ¶
CreatorRevision returns the table CreatorRevision.
func (*Generic) Marshal ¶
Marshal marshals Generic tables. The main use of this function is when you want to tweak the header a bit; you can convert a Raw table to a Generic table, do what you wish, and write it out.
func (*Generic) OEMRevision ¶
OEMRevision returns the table OEMRevision.
func (*Generic) OEMTableID ¶
OEMTableID returns the table OEMTableID.
type Header ¶
type Header struct { Sig sig Length uint32 Revision uint8 CheckSum uint8 OEMID oem OEMTableID tableid OEMRevision uint32 CreatorID uint32 CreatorRevision uint32 }
Header is the standard header for all ACPI tables, except the ones that don't use it. (That's a joke. So is ACPI.) We use types that we hope are easy to read; they in turn make writing marshal code with type switches very convenient.
type HeapTable ¶
HeapTable is for ACPI tables that have a heap, i.e. the strings are not subtables, as in most ACPI, but are contained in an area at the end of the tables, after the other table elements. So far, we only know of one such table, the IBFT.
type IBFT ¶
type IBFT struct { Generic // Control Multi flag Initiator IBFTInitiator NIC0 IBFTNIC Target0 IBFTTarget NIC1 IBFTNIC Target1 IBFTTarget }
IBFT defines all the bits of an IBFT users might want to set.
type IBFTInitiator ¶
type IBFTInitiator struct { Valid flag Boot flag SNSServer ipaddr SLPServer ipaddr PrimaryRadiusServer ipaddr SecondaryRadiusServer ipaddr Name sheap }
IBFTInitiator defines an initiator
type IBFTNIC ¶
type IBFTNIC struct { Valid flag Boot flag Global flag Index flag IPAddress ipaddr SubNet u8 Origin u8 Gateway ipaddr PrimaryDNS ipaddr SecondaryDNS ipaddr DHCP ipaddr VLAN u16 MACAddress mac PCIBDF bdf HostName sheap }
IBFTNIC defines an IBFT NIC structure.
type IBFTTarget ¶
type IBFTTarget struct { Valid flag Boot flag CHAP flag RCHAP flag // can you do both? Standard implies yes. Index flag // 0 or 1 TargetIP sockaddr // in host:port format BootLUN u64 ChapType u8 Association u8 TargetName sheap CHAPName sheap CHAPSecret sheap ReverseCHAPName sheap ReverseCHAPSecret sheap }
IBFTTarget defines an IBFT target, a.k.a. server
type RSDP ¶
type RSDP struct {
// contains filtered or unexported fields
}
RSDP is the v2 version of the RSDP struct, containing 32 and 64 bit pointers. RSDP don't quite follow the ACPI table standard, so some things return empty values. It has nevertheless proven useful to have them. We just define the RSDP for v2 and later here. It's the only one that matters. This whole layout is typical of the overall Failure Of Vision that is ACPI. 64-bit micros had existed for 10 years when ACPI was defined, and they still wired in 32-bit pointer assumptions, and had to backtrack and fix it later. We don't use this struct below, it's only worthwhile as documentation. The RSDP has not changed in 20 years.
func GetRSDP ¶
GetRSDP gets an RSDP. It is able to use several methods, because there is no consistency about how it is done. The base is also returned.
func (*RSDP) Base ¶
Base returns a base address or the [RX]SDT. It will preferentially return the XSDT, but if that is 0 it will return the RSDT address.
func (*RSDP) CreatorRevision ¶
CreatorRevision returns the table CreatorRevision.
func (*RSDP) OEMRevision ¶
OEMRevision returns the table OEMRevision.
type Raw ¶
type Raw struct {
// contains filtered or unexported fields
}
Raw is just a table embedded in a []byte. Operations on Raw are useful for unpacking into a more refined table or just figuring out how to skip a table you don't care about.
func (*Raw) CreatorRevision ¶
CreatorRevision returns the table CreatorRevision.
func (*Raw) OEMRevision ¶
OEMRevision returns the table OEMRevision.
type SDT ¶
SDT represents either an RSDT or XSDT. It has a Generic header and Tables, which are pointers. In the RSDT they are 32 bits; in the XSDT, 64. We unmarshal to 64 bits, and when we marshal, we use the signature to determine whether the table is 32 or 64.
func ReadSDT ¶
ReadSDT reads an SDT in from memory, using UnMarshalSDT, which uses the io package. This is increasingly unlikely to work over time.
func UnMarshalSDT ¶
UnMarshalSDT unmarshals an SDT. It's pretty much impossible for the RSDP to point to anything else so we mainly do the unmarshal and type assertion.
func (*SDT) Marshal ¶
Marshal marshals an [RX]SDT. If it has tables, it marshals them too. Note that tables are just pointers in this case. Most users will likely remove the tables (s->Tables = nil) and add their own in the call to MarshalAll.
func (*SDT) MarshalAll ¶
MarshalAll marshals out an SDT, and all the tables, in a blob suitable for kexec. The most common use of this call would be to set s->Tables = nil and then pass in the desired Tables as parameters to this function. For passed-in tables, all addresses are recomputed, as there may be more tables. Further, even if tables were scattered all over, we unify them into one segment. There is one potential problem, which we can fix if needed: it is possible the [XR]SDT is placed so close to the top of memory there is no room for the table. In the unlikely event that ever happens, we will just figure out how to place the tables in memory lower than the [XR]SDT.
type Tabler ¶
type Tabler interface { Sig() string Len() uint32 Revision() uint8 CheckSum() uint8 OEMID() string OEMTableID() string OEMRevision() uint32 CreatorID() uint32 CreatorRevision() uint32 AllData() []byte TableData() []byte Marshal() ([]byte, error) }
Tabler is the interface to ACPI tables, be they held in memory as a byte slice, header and byte slice, or more complex struct.
func NewGeneric ¶
NewGeneric creates a new Generic table from a byte slice.
func RawFromFile ¶
RawFromFile reads a raw table in from a file.
func ReadRaw ¶
ReadRaw reads a full table in, given an address. ReadRaw uses the io package. This may not always work if the kernel has restrictions on reading memory above the 1M boundary, and the tables are above boundary.
func UnMarshal ¶
UnMarshal unmarshals a single table and returns a Tabler. If the table is one of the many we don't care about we just return a Raw table, which can be easily written out again if needed. If it has an UnMarshal registered we use that instead once the Raw is unmarshaled.
func UnMarshalAll ¶
UnMarshalAll takes an SDT and unmarshals all the tables using UnMarshal. It returns a []Tabler. In most cases, the tables will be Raw, but in a few cases they might be further converted.