github.com/system-transparency/u-root@v6.0.1-0.20190919065413-ed07a650de4c+incompatible/pkg/acpi/rsdp.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 6 7 import ( 8 "bufio" 9 "encoding/binary" 10 "fmt" 11 "io/ioutil" 12 "log" 13 "os" 14 "strconv" 15 "strings" 16 17 "github.com/u-root/u-root/pkg/memio" 18 ) 19 20 const ( 21 // Revision marks lowest ACPI revision we support. 22 Revision = 2 23 cSUM1Off = 8 // Checksum1 offset in packet. 24 cSUM2Off = 32 // Checksum2 offset 25 xSDTLenOff = 20 26 xSDTAddrOff = 24 27 ) 28 29 var pageMask = uint64(os.Getpagesize() - 1) 30 31 // RSDP is the v2 version of the RSDP struct, containing 32 and 64 32 // bit pointers. 33 // RSDP don't quite follow the ACPI table standard, 34 // so some things return empty values. It has nevertheless proven 35 // useful to have them. 36 // We just define the RSDP for v2 and later here. It's the only 37 // one that matters. This whole layout is typical of the overall 38 // Failure Of Vision that is ACPI. 64-bit micros had existed for 10 years 39 // when ACPI was defined, and they still wired in 32-bit pointer assumptions, 40 // and had to backtrack and fix it later. We don't use this struct below, 41 // it's only worthwhile as documentation. The RSDP has not changed in 20 years. 42 type RSDP struct { 43 sign [8]byte `Align:"16" Default:"RSDP PTR "` 44 v1CSUM uint8 // This was the checksum, which we are pretty sure is ignored now. 45 oemid [6]byte 46 revision uint8 `Default:"2"` 47 obase uint32 // was RSDT, but you're not supposed to use it any more. 48 length uint32 49 base uint64 // XSDT address, the only one you should use 50 checksum uint8 51 _ [3]uint8 52 data [HeaderLength]byte 53 } 54 55 var ( 56 defaultRSDP = []byte("RSDP PTR U-ROOT\x02") 57 _ = Tabler(&RSDP{}) 58 ) 59 60 // Marshal fails to marshal an RSDP. 61 func (r *RSDP) Marshal() ([]byte, error) { 62 return nil, fmt.Errorf("Marshal RSDP: not yet") 63 } 64 65 // NewRSDP returns a new and partially initialized RSDP, setting only 66 // the defaultRSDP values, address, length, and signature. 67 func NewRSDP(addr uintptr, len uint) []byte { 68 var r [HeaderLength]byte 69 copy(r[:], defaultRSDP) 70 // This is a bit of a cheat. All the fields are 0. 71 // So we get a checksum, set up the 72 // XSDT fields, get the second checksum. 73 r[cSUM1Off] = gencsum(r[:]) 74 binary.LittleEndian.PutUint32(r[xSDTLenOff:], uint32(len)) 75 binary.LittleEndian.PutUint64(r[xSDTAddrOff:], uint64(addr)) 76 r[cSUM2Off] = gencsum(r[:]) 77 return r[:] 78 } 79 80 // Len returns the RSDP length 81 func (r *RSDP) Len() uint32 { 82 return uint32(len(r.data)) 83 } 84 85 // AllData returns the RSDP as a []byte 86 func (r *RSDP) AllData() []byte { 87 return r.data[:] 88 } 89 90 // TableData returns the RSDP table data as a []byte 91 func (r *RSDP) TableData() []byte { 92 return r.data[36:] 93 } 94 95 // Sig returns the RSDP signature 96 func (r *RSDP) Sig() string { 97 return string(r.data[:8]) 98 } 99 100 // OEMID returns the RSDP OEMID 101 func (r *RSDP) OEMID() string { 102 return string(r.data[9:15]) 103 } 104 105 // OEMTableID returns the RSDP OEMTableID 106 func (r *RSDP) OEMTableID() string { 107 return "rsdp?" 108 } 109 110 // Revision returns the RSDP revision, which 111 // after 2002 should be >= 2 112 func (r *RSDP) Revision() uint8 { 113 return r.revision 114 } 115 116 // OEMRevision returns the table OEMRevision. 117 func (r *RSDP) OEMRevision() uint32 { 118 return 0 119 } 120 121 // CheckSum returns the table CheckSum. 122 func (r *RSDP) CheckSum() uint8 { 123 return uint8(r.checksum) 124 } 125 126 // CreatorID returns the table CreatorID. 127 func (r *RSDP) CreatorID() uint32 { 128 return uint32(0) 129 } 130 131 // CreatorRevision returns the table CreatorRevision. 132 func (r *RSDP) CreatorRevision() uint32 { 133 return 0 134 } 135 136 // Base returns a base address or the [RX]SDT. 137 // It will preferentially return the XSDT, but if that is 138 // 0 it will return the RSDT address. 139 func (r *RSDP) Base() int64 { 140 Debug("Base %v data len %d", r, len(r.data)) 141 b := int64(binary.LittleEndian.Uint32(r.data[16:20])) 142 if b != 0 { 143 return b 144 } 145 return int64(binary.LittleEndian.Uint64(r.data[24:32])) 146 } 147 148 func readRSDP(base int64) (*RSDP, error) { 149 r := &RSDP{} 150 r.base = uint64(base) 151 dat := memio.ByteSlice(make([]byte, len(r.data))) 152 if err := memio.Read(base, &dat); err != nil { 153 return nil, err 154 } 155 copy(r.data[:], dat) 156 return r, nil 157 } 158 159 func getRSDPEFI() (int64, *RSDP, error) { 160 file, err := os.Open("/sys/firmware/efi/systab") 161 if err != nil { 162 return -1, nil, err 163 } 164 defer file.Close() 165 166 const ( 167 acpi20 = "ACPI20=" 168 acpi = "ACPI=" 169 ) 170 171 scanner := bufio.NewScanner(file) 172 for scanner.Scan() { 173 line := scanner.Text() 174 start := "" 175 if strings.HasPrefix(line, acpi20) { 176 start = strings.TrimPrefix(line, acpi20) 177 } 178 if strings.HasPrefix(line, acpi) { 179 start = strings.TrimPrefix(line, acpi) 180 } 181 if start == "" { 182 continue 183 } 184 base, err := strconv.ParseInt(start, 0, 64) 185 if err != nil { 186 continue 187 } 188 rsdp, err := readRSDP(base) 189 if err != nil { 190 continue 191 } 192 return base, rsdp, nil 193 } 194 if err := scanner.Err(); err != nil { 195 log.Printf("error while reading EFI systab: %v", err) 196 } 197 return -1, nil, fmt.Errorf("invalid efi/systab file") 198 } 199 200 func num(n string, i int) (uint64, error) { 201 b, err := ioutil.ReadFile(fmt.Sprintf("/sys/firmware/memmap/%d/%s", i, n)) 202 if err != nil { 203 return 0, err 204 } 205 start, err := strconv.ParseUint(string(b), 0, 64) 206 return start, err 207 } 208 209 // getRSDPmem is the option of last choice, it just grovels through 210 // the e0000-ffff0 area, 16 bytes at a time, trying to find an RSDP. 211 // These are well-known addresses for 20+ years. 212 func getRSDPmem() (int64, *RSDP, error) { 213 for base := int64(0xe0000); base < 0xffff0; base += 16 { 214 var r memio.Uint64 215 if err := memio.Read(base, &r); err != nil { 216 continue 217 } 218 if r != 0x2052545020445352 { 219 continue 220 } 221 rsdp, err := readRSDP(base) 222 if err != nil { 223 return -1, nil, err 224 } 225 return base, rsdp, nil 226 } 227 return -1, nil, fmt.Errorf("No ACPI RSDP via /dev/mem") 228 } 229 230 // You can change the getters if you wish for testing. 231 var getters = []func() (int64, *RSDP, error){getRSDPEFI, getRSDPmem} 232 233 // GetRSDP gets an RSDP. 234 // It is able to use several methods, because there is no consistency 235 // about how it is done. The base is also returned. 236 func GetRSDP() (base int64, rsdp *RSDP, err error) { 237 for _, f := range getters { 238 base, r, err := f() 239 if err != nil { 240 log.Print(err) 241 } 242 if err == nil { 243 return base, r, nil 244 } 245 } 246 return -1, nil, fmt.Errorf("Can't find an RSDP") 247 }