github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/acpi/acpi.go (about) 1 // Copyright 2019 the u-root Authors. All rights reserved 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package acpi began life as a relatively simple set of functions. 6 // At some point we wanted to be able to extend the ACPI table over a 7 // kexec and that's when it all went nasty. 8 // A few issues crop up. 9 // In theory, one should be able to put tables anywhere. In practice, 10 // even in the EFI age, this is not simple. The root pointer 11 // for tables, RSDP, Root Services Data Pointer, is in memory protected by 12 // the southbridge/ICH/PCH with lockdown bits (disable writes once, can 13 // not be reset until power on/reset). Writes to it are transparently discarded. 14 // (This makes sense, as crap DOS programs probably tried to write that area all 15 // the time. Everything -- everything! -- about x86 and BIOS is explainable 16 // by DOS, 16 bit addresses, 4 bit segments, 20 bits, and the incredible failure 17 // of vision in 1999 of building a bunch of tables with 32 bit pointers in them. 18 // The x86 world is nothing if not consistent: short-sighted decisions for 40+ years). 19 // The two-byte EBDA pointer (16 bits) is shifted left 4 bits to get a 20-bit address 20 // which points to *the range of memory* containing, maybe, the RSDP. 21 // The RSDP has to live in the low 20 bits of address space (remember 20 bits, right?) 22 // (Yes, I know about the EFI tables which make this restriction less of a problem, 23 // but for now all the firmware I've seen adheres to the "RSDP in e or f segment" rule.) 24 // The RSDP has two pointers in it, one or both containing a value: 32 bit pointer or 64 bit 25 // pointer to the RSDT or XSDT. (see "failure of vision" above.) 26 // RSDT has 32-bit pointers, XSDT 64-bit pointers. 27 // The spec recommends you ignore the 32-bit pointer variants but as of 2019, 28 // I still see use of them; this package will read and write the variants but the 29 // internal structs are defined with 64-bit pointers (oh, if only the ACPICA code 30 // had gotten this right, but that code is pretty bad too). 31 // What's really fun: when you generate the [RX]SDT, you need to generate pointers 32 // too. It's best to keep those tables in a physically contiguous area, so we do; 33 // not all systems follow this rule, which is asking for trouble. 34 // Finally, not all tables are generated in a consistent way, e.g. the IBFT is not like 35 // most other tables containing variable length data, because the people who created it 36 // are Klever. IBFT has its own heap, and the elements in the heap follow rules unlike 37 // all other tables. Nice! 38 // If you really look at ACPI closely, you can kind of see that it's optimized for NASM, 39 // which is part of what makes it so unpleasant. But, it's what we have. 40 package acpi 41 42 import ( 43 "bytes" 44 "encoding/binary" 45 "fmt" 46 "log" 47 "strconv" 48 ) 49 50 const ( 51 // LengthOffset is the offset of the table length 52 LengthOffset = 4 53 // CSUMOffset is the offset of the single byte checksum in *most* ACPI tables 54 CSUMOffset = 9 55 // MinTableLength is the minimum length: 4 byte tag, 4 byte length, 1 byte revision, 1 byte checksum, 56 MinTableLength = 10 57 ) 58 59 var ( 60 // Debug implements fmt.Sprintf and can be used for debug printing 61 Debug = func(string, ...interface{}) {} 62 unmarshalers = map[sig]func(Tabler) (Tabler, error){} 63 ) 64 65 // addUnMarshaler is intended to be called by init functions 66 // in this package. It adds an UnMarshaler for a given 67 // ACPI signature. 68 func addUnMarshaler(n string, f func(Tabler) (Tabler, error)) { 69 if _, ok := unmarshalers[sig(n)]; ok { 70 log.Fatalf("Can't add %s; already in use", n) 71 } 72 unmarshalers[sig(n)] = f 73 } 74 75 // GetHeader extracts a Header from a Tabler and returns a reference to it. 76 func GetHeader(t Tabler) *Header { 77 return &Header{ 78 Sig: sig(t.Sig()), 79 Length: t.Len(), 80 Revision: t.Revision(), 81 CheckSum: t.CheckSum(), 82 OEMID: oem(t.OEMID()), 83 OEMTableID: tableid(t.OEMTableID()), 84 OEMRevision: t.OEMRevision(), 85 CreatorID: t.CreatorID(), 86 CreatorRevision: t.CreatorRevision(), 87 } 88 } 89 90 // Flags takes 0 or more flags and produces a uint8 value. 91 // Each argument represents one bit position, with the first flag 92 // being bit 0. For each flag with a value of "1", the bit for that 93 // flag will be set. For each flag with a value of "0", that bit in 94 // the flag will be cleared. 95 // This is mainly for consistency but it would allow 96 // us in future to pass in an initial value and set or clear bits in it 97 // depending on flags. 98 // Current allowed values are "0" and "1". In future, if the flags are 99 // not contiguous, we can allow "ignore" in future to ignore a flag. 100 func flags(s ...flag) (uint8, error) { 101 var i, bit uint8 102 for _, f := range s { 103 switch f { 104 case "1": 105 i |= 1 << bit 106 case "0": 107 i &= ^(1 << bit) 108 default: 109 return 0, fmt.Errorf("%s is not a valid value: only 0 or 1 are valid", f) 110 } 111 bit++ 112 } 113 return i, nil 114 } 115 116 // w writes 0 or more values to a bytes.Buffer, in LittleEndian order. 117 func w(b *bytes.Buffer, val ...interface{}) { 118 for _, v := range val { 119 binary.Write(b, binary.LittleEndian, v) 120 Debug("\t %T %v b is %d bytes", v, v, b.Len()) 121 } 122 Debug("w: done: b is %d bytes", b.Len()) 123 } 124 125 // uw writes strings as unsigned words to a bytes.Buffer. 126 // Currently it only supports 16, 32, and 64 bit writes. 127 func uw(b *bytes.Buffer, s string, bits int) error { 128 // convenience case: if they don't set it, it comes in as "", 129 // take that to mean 0. 130 var v uint64 131 if s != "" { 132 var err error 133 if v, err = strconv.ParseUint(string(s), 0, bits); err != nil { 134 return err 135 } 136 } 137 switch bits { 138 case 8: 139 w(b, uint8(v)) 140 case 16: 141 w(b, uint16(v)) 142 case 32: 143 w(b, uint32(v)) 144 case 64: 145 w(b, uint64(v)) 146 default: 147 return fmt.Errorf("Invalid bit length for uw: %d, only supoprt 8, 16, 32, 64", bits) 148 } 149 return nil 150 } 151 152 // Marshal marshals a Tabler into a byte slice. 153 // Once marshaling is done, it inserts the length into 154 // the standard place at LengthOffset, and then generates and inserts 155 // a checksum at CSUMOffset. 156 func Marshal(t Tabler) ([]byte, error) { 157 Debug("Marshal %T", t) 158 b, err := t.Marshal() 159 if err != nil { 160 return nil, err 161 } 162 163 if len(b) < MinTableLength { 164 return nil, fmt.Errorf("%v is too short to contain a table", b) 165 } 166 167 binary.LittleEndian.PutUint32(b[LengthOffset:], uint32(len(b))) 168 c := gencsum(b) 169 Debug("CSUM is %#x", c) 170 b[CSUMOffset] = c 171 172 return b, nil 173 } 174 175 // UnMarshal unmarshals a single table and returns a Tabler. 176 // If the table is one of the many we don't care about we 177 // just return a Raw table, which can be easily written out 178 // again if needed. If it has an UnMarshal registered we use 179 // that instead once the Raw is unmarshaled. 180 func UnMarshal(a int64) (Tabler, error) { 181 r, err := ReadRaw(a) 182 if err != nil { 183 return nil, err 184 } 185 Debug("Raw table: %q", r) 186 if m, ok := unmarshalers[sig(r.Sig())]; ok { 187 return m(r) 188 } 189 190 return r, nil 191 } 192 193 // UnMarshalSDT unmarshals an SDT. 194 // It's pretty much impossible for the RSDP to point to 195 // anything else so we mainly do the unmarshal and type assertion. 196 func UnMarshalSDT(r *RSDP) (*SDT, error) { 197 s, err := UnMarshal(r.Base()) 198 if err != nil { 199 return nil, err 200 } 201 Debug("SDT: %q", s) 202 return s.(*SDT), nil 203 } 204 205 // UnMarshalAll takes an SDT and unmarshals all the tables 206 // using UnMarshal. It returns a []Tabler. In most cases, 207 // the tables will be Raw, but in a few cases they might be 208 // further converted. 209 func UnMarshalAll(s *SDT) ([]Tabler, error) { 210 var tab []Tabler 211 for _, a := range s.Tables { 212 t, err := UnMarshal(a) 213 if err != nil { 214 return nil, err 215 } 216 tab = append(tab, t) 217 } 218 219 return tab, nil 220 }