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