github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/pkg/boot/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 can find and parse the RSDP pointer and struct. 6 package acpi 7 8 import ( 9 "bufio" 10 "encoding/binary" 11 "fmt" 12 "log" 13 "os" 14 "strconv" 15 "strings" 16 17 "github.com/u-root/u-root/pkg/boot/ebda" 18 "github.com/u-root/u-root/pkg/memio" 19 ) 20 21 const ( 22 // checksum1 offset in RSDP struct. 23 cSUM1Off = 8 24 25 // checksum2 offset in RSDP struct. 26 cSUM2Off = 32 27 xSDTLenOff = 20 28 xSDTAddrOff = 24 29 30 // headerLength is a common header length for (almost) 31 // all ACPI tables. 32 headerLength = 36 33 ) 34 35 var ( 36 defaultRSDP = []byte("RSDP PTR U-ROOT\x02") 37 ) 38 39 // gencsum generates a uint8 checksum of a []uint8 40 func gencsum(b []uint8) uint8 { 41 var csum uint8 42 for _, bb := range b { 43 csum += bb 44 } 45 return ^csum + 1 46 } 47 48 // RSDP is the v2 version of the ACPI RSDP struct. 49 type RSDP struct { 50 // base is the base address of the RSDP struct in physical memory. 51 base uint64 52 53 data [headerLength]byte 54 } 55 56 // NewRSDP returns a new and partially initialized RSDP, setting only 57 // the defaultRSDP values, address, length, and signature. 58 func NewRSDP(addr uintptr, len uint) []byte { 59 var r [headerLength]byte 60 copy(r[:], defaultRSDP) 61 62 // This is a bit of a cheat. All the fields are 0. So we get a 63 // checksum, set up the XSDT fields, get the second checksum. 64 r[cSUM1Off] = gencsum(r[:]) 65 binary.LittleEndian.PutUint32(r[xSDTLenOff:], uint32(len)) 66 binary.LittleEndian.PutUint64(r[xSDTAddrOff:], uint64(addr)) 67 r[cSUM2Off] = gencsum(r[:]) 68 return r[:] 69 } 70 71 // Len returns the RSDP length 72 func (r *RSDP) Len() uint32 { 73 return uint32(len(r.data)) 74 } 75 76 // AllData returns the RSDP as a []byte 77 func (r *RSDP) AllData() []byte { 78 return r.data[:] 79 } 80 81 // TableData returns the RSDP table data as a []byte 82 func (r *RSDP) TableData() []byte { 83 return r.data[36:] 84 } 85 86 // Sig returns the RSDP signature 87 func (r *RSDP) Sig() string { 88 return string(r.data[:8]) 89 } 90 91 // OEMID returns the RSDP OEMID 92 func (r *RSDP) OEMID() string { 93 return string(r.data[9:15]) 94 } 95 96 // RSDPAddr returns the physical base address of the RSDP. 97 func (r *RSDP) RSDPAddr() uint64 { 98 return r.base 99 } 100 101 // SDTAddr returns a base address or the [RX]SDT. 102 // 103 // It will preferentially return the XSDT, but if that is 104 // 0 it will return the RSDT address. 105 func (r *RSDP) SDTAddr() uint64 { 106 b := uint64(binary.LittleEndian.Uint32(r.data[16:20])) 107 if b != 0 { 108 return b 109 } 110 return uint64(binary.LittleEndian.Uint64(r.data[24:32])) 111 } 112 113 func readRSDP(base uint64) (*RSDP, error) { 114 r := &RSDP{} 115 r.base = base 116 117 dat := memio.ByteSlice(make([]byte, len(r.data))) 118 if err := memio.Read(int64(base), &dat); err != nil { 119 return nil, err 120 } 121 copy(r.data[:], dat) 122 return r, nil 123 } 124 125 // GetRSDPEFI finds the RSDP in the EFI System Table. 126 func GetRSDPEFI() (*RSDP, error) { 127 file, err := os.Open("/sys/firmware/efi/systab") 128 if err != nil { 129 return nil, err 130 } 131 defer file.Close() 132 133 const ( 134 acpi20 = "ACPI20=" 135 acpi = "ACPI=" 136 ) 137 138 scanner := bufio.NewScanner(file) 139 for scanner.Scan() { 140 line := scanner.Text() 141 start := "" 142 if strings.HasPrefix(line, acpi20) { 143 start = strings.TrimPrefix(line, acpi20) 144 } 145 if strings.HasPrefix(line, acpi) { 146 start = strings.TrimPrefix(line, acpi) 147 } 148 if start == "" { 149 continue 150 } 151 base, err := strconv.ParseUint(start, 0, 64) 152 if err != nil { 153 continue 154 } 155 rsdp, err := readRSDP(base) 156 if err != nil { 157 continue 158 } 159 return rsdp, nil 160 } 161 if err := scanner.Err(); err != nil { 162 log.Printf("error while reading EFI systab: %v", err) 163 } 164 return nil, fmt.Errorf("invalid /sys/firmware/efi/systab file") 165 } 166 167 // GetRSDPEBDA finds the RSDP in the EBDA. 168 func GetRSDPEBDA() (*RSDP, error) { 169 f, err := os.OpenFile("/dev/mem", os.O_RDONLY, 0) 170 if err != nil { 171 return nil, err 172 } 173 defer f.Close() 174 175 e, err := ebda.ReadEBDA(f) 176 if err != nil { 177 return nil, err 178 } 179 180 return getRSDPMem(uint64(e.BaseOffset), uint64(e.BaseOffset+e.Length)) 181 } 182 183 func getRSDPMem(start, end uint64) (*RSDP, error) { 184 for base := start; base < end; base += 16 { 185 var r memio.Uint64 186 if err := memio.Read(int64(base), &r); err != nil { 187 continue 188 } 189 if r != 0x2052545020445352 { 190 continue 191 } 192 rsdp, err := readRSDP(base) 193 if err != nil { 194 return nil, err 195 } 196 return rsdp, nil 197 } 198 return nil, fmt.Errorf("could not find ACPI RSDP via /dev/mem from %#08x to %#08x", start, end) 199 } 200 201 // GetRSDPMem is the option of last choice, it just grovels through 202 // the e0000-ffff0 area, 16 bytes at a time, trying to find an RSDP. 203 // These are well-known addresses for 20+ years. 204 func GetRSDPMem() (*RSDP, error) { 205 return getRSDPMem(0xe0000, 0xffff0) 206 } 207 208 // You can change the getters if you wish for testing. 209 var getters = []func() (*RSDP, error){GetRSDPEFI, GetRSDPEBDA, GetRSDPMem} 210 211 // GetRSDP finds the RSDP pointer and struct in memory. 212 // 213 // It is able to use several methods, because there is no consistency 214 // about how it is done. 215 func GetRSDP() (*RSDP, error) { 216 for _, f := range getters { 217 r, err := f() 218 if err != nil { 219 log.Print(err) 220 } 221 if err == nil { 222 return r, nil 223 } 224 } 225 return nil, fmt.Errorf("cannot find an RSDP") 226 }