blob: 0aaf6a9db37099545d38d35b530c44f103a59f59 [file] [log] [blame]
Vladimir Serbinenko3129f792014-10-15 21:51:47 +02001package main
2
3import (
4 "bufio"
5 "flag"
6 "fmt"
7 "log"
8 "os"
Arthur Heymans8bd25ab2018-08-12 00:21:08 +02009 "regexp"
Vladimir Serbinenko3129f792014-10-15 21:51:47 +020010 "strconv"
11 "strings"
12)
13
14type LogDevReader struct {
15 InputDirectory string
16 ACPITables map[string][]byte
17 EC []byte
18}
19
20func isXDigit(x uint8) bool {
21 if x >= '0' && x <= '9' {
22 return true
23 }
24 if x >= 'a' && x <= 'f' {
25 return true
26 }
27 if x >= 'A' && x <= 'F' {
28 return true
29 }
30 return false
31}
32
33type HexLine struct {
34 length uint
35 values [16]byte
36 start uint
37}
38
39func (l *LogDevReader) ReadHexLine(line string) (hex HexLine) {
40 hex.start = 0
41 line = strings.Trim(line, " ")
42 fmt.Sscanf(line, "%x:", &hex.start)
43 ll, _ := fmt.Sscanf(line, "%x: %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x", &hex.start,
44 &hex.values[0], &hex.values[1], &hex.values[2],
45 &hex.values[3], &hex.values[4], &hex.values[5],
46 &hex.values[6], &hex.values[7], &hex.values[8],
47 &hex.values[9], &hex.values[10], &hex.values[11],
48 &hex.values[12], &hex.values[13], &hex.values[14],
49 &hex.values[15])
50 hex.length = uint(ll - 1)
51 return
52}
53
54func (l *LogDevReader) AssignHexLine(inp string, target []byte) []byte {
55 hex := l.ReadHexLine(inp)
56 if hex.start+hex.length > uint(len(target)) {
57 target = target[0 : hex.start+hex.length]
58 }
59 copy(target[hex.start:hex.start+hex.length], hex.values[0:hex.length])
60 return target
61}
62
63func (l *LogDevReader) GetEC() []byte {
64 if l.EC != nil {
65 return l.EC
66 }
67 l.EC = make([]byte, 0x100, 0x100)
68
69 file, err := os.Open(l.InputDirectory + "/ectool.log")
70 if err != nil {
71 log.Fatal(err)
72 }
73 defer file.Close()
74
75 scanner := bufio.NewScanner(file)
76
77 for scanner.Scan() {
78 line := scanner.Text()
79 if len(line) > 7 && isXDigit(line[0]) && isXDigit(line[1]) && line[2] == ':' {
80 l.EC = l.AssignHexLine(line, l.EC)
81 }
82 }
83
84 if err := scanner.Err(); err != nil {
85 log.Fatal(err)
86 }
87
88 return l.EC
89}
90
91func (l *LogDevReader) GetACPI() (Tables map[string][]byte) {
92 if l.ACPITables != nil {
93 return l.ACPITables
94 }
95 l.ACPITables = Tables
96
97 file, err := os.Open(l.InputDirectory + "/acpidump.log")
98 if err != nil {
99 log.Fatal(err)
100 }
101 defer file.Close()
102
103 scanner := bufio.NewScanner(file)
104
105 Tables = map[string][]byte{}
106
107 curTable := ""
108 for scanner.Scan() {
109 line := scanner.Text()
Iru Caib95a1a42019-03-05 15:56:39 +0800110 /* Only supports ACPI tables up to 0x100000 in size, FIXME if needed */
111 is_hexline, _ := regexp.MatchString(" *[0-9A-Fa-f]{4,5}: ", line)
Vladimir Serbinenko3129f792014-10-15 21:51:47 +0200112 switch {
113 case len(line) >= 6 && line[5] == '@':
114 curTable = line[0:4]
Iru Caib95a1a42019-03-05 15:56:39 +0800115 Tables[curTable] = make([]byte, 0, 0x100000)
Arthur Heymans8bd25ab2018-08-12 00:21:08 +0200116 case is_hexline:
Vladimir Serbinenko3129f792014-10-15 21:51:47 +0200117 Tables[curTable] = l.AssignHexLine(line, Tables[curTable])
118 }
119 }
120
121 if err := scanner.Err(); err != nil {
122 log.Fatal(err)
123 }
124
125 return
126}
127
128func (l *LogDevReader) GetPCIList() (PCIList []PCIDevData) {
129 file, err := os.Open(l.InputDirectory + "/lspci.log")
130 if err != nil {
131 log.Fatal(err)
132 }
133 defer file.Close()
134
135 scanner := bufio.NewScanner(file)
136
137 PCIList = []PCIDevData{}
138
139 for scanner.Scan() {
140 line := scanner.Text()
141 switch {
142 case !(len(line) < 7 || !isXDigit(line[0]) || !isXDigit(line[1]) || line[2] != ':' || !isXDigit(line[3]) || !isXDigit(line[4]) || line[5] != '.' || !isXDigit(line[6])):
143 cur := PCIDevData{}
144 fmt.Sscanf(line, "%x:%x.%x", &cur.Bus, &cur.Dev, &cur.Func)
145 lc := strings.LastIndex(line, ":")
146 li := strings.LastIndex(line[0:lc], "[")
147 if li < 0 {
148 continue
149 }
150 ven := 0
151 dev := 0
152 fmt.Sscanf(line[li+1:], "%x:%x", &ven, &dev)
153 cur.PCIDevID = uint16(dev)
154 cur.PCIVenID = uint16(ven)
155 cur.ConfigDump = make([]byte, 0x100, 0x1000)
156 PCIList = append(PCIList, cur)
157 case len(line) > 7 && isXDigit(line[0]) && line[1] == '0' && line[2] == ':':
158 start := 0
159 fmt.Sscanf(line, "%x:", &start)
160 cur := &PCIList[len(PCIList)-1]
161 cur.ConfigDump = l.AssignHexLine(line, cur.ConfigDump)
162 }
163 }
164
165 if err := scanner.Err(); err != nil {
166 log.Fatal(err)
167 }
168
169 return
170}
171
172func (l *LogDevReader) GetInteltool() (ret InteltoolData) {
173 file, err := os.Open(l.InputDirectory + "/inteltool.log")
174 if err != nil {
175 log.Fatal(err)
176 }
177 defer file.Close()
178
179 scanner := bufio.NewScanner(file)
180 paragraph := ""
181 ret.GPIO = map[uint16]uint32{}
182 ret.RCBA = map[uint16]uint32{}
183 ret.IGD = map[uint32]uint32{}
184 for scanner.Scan() {
185 line := scanner.Text()
186 switch {
187 case len(line) > 7 && line[0] == '0' && line[1] == 'x' && line[6] == ':' && paragraph == "RCBA":
188 addr, value := 0, 0
189 fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
190 ret.RCBA[uint16(addr)] = uint32(value)
191 case len(line) > 9 && line[0] == '0' && line[1] == 'x' && line[8] == ':' && paragraph == "IGD":
192 addr, value := 0, 0
193 fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
194 ret.IGD[uint32(addr)] = uint32(value)
195 case strings.Contains(line, "DEFAULT"):
196 continue
197 case strings.Contains(line, "DIFF"):
198 continue
199 case strings.HasPrefix(line, "gpiobase"):
200 addr, value := 0, 0
201 fmt.Sscanf(line, "gpiobase+0x%x: 0x%x", &addr, &value)
202 ret.GPIO[uint16(addr)] = uint32(value)
203 case strings.HasPrefix(line, "============="):
204 paragraph = strings.Trim(line, "= ")
205 }
206 }
207
208 if err := scanner.Err(); err != nil {
209 log.Fatal(err)
210 }
211 return
212}
213
214func (l *LogDevReader) GetDMI() (ret DMIData) {
215 file, err := os.Open(l.InputDirectory + "/dmidecode.log")
216 if err != nil {
217 log.Fatal(err)
218 }
219 defer file.Close()
220
221 scanner := bufio.NewScanner(file)
222 paragraph := ""
223 for scanner.Scan() {
224 line := scanner.Text()
225 if !strings.HasPrefix(line, "\t") {
226 paragraph = strings.TrimSpace(line)
227 continue
228 }
229 idx := strings.Index(line, ":")
230 if idx < 0 {
231 continue
232 }
233 name := strings.TrimSpace(line[0:idx])
234 value := strings.TrimSpace(line[idx+1:])
235 switch paragraph + ":" + name {
236 case "System Information:Manufacturer":
237 ret.Vendor = value
238 case "System Information:Product Name":
239 ret.Model = value
240 case "System Information:Version":
241 ret.Version = value
242 case "Chassis Information:Type":
243 ret.IsLaptop = (value == "Notebook" || value == "Laptop")
244 }
245 }
246
247 if err := scanner.Err(); err != nil {
248 log.Fatal(err)
249 }
250 return
251}
252
253func (l *LogDevReader) GetAzaliaCodecs() (ret []AzaliaCodec) {
254 for codecno := 0; codecno < 10; codecno++ {
255 cur := AzaliaCodec{CodecNo: codecno, PinConfig: map[int]uint32{}}
256 codec, err := os.Open(l.InputDirectory + "/codec#" + strconv.Itoa(codecno))
257 if err != nil {
258 continue
259 }
260 defer codec.Close()
261 pin, err := os.Open(l.InputDirectory + "/pin_hwC0D" + strconv.Itoa(codecno))
262 if err != nil {
263 continue
264 }
265 defer pin.Close()
266
267 scanner := bufio.NewScanner(codec)
268 for scanner.Scan() {
269 line := scanner.Text()
270 if strings.HasPrefix(line, "Codec:") {
271 fmt.Sscanf(line, "Codec: %s", &cur.Name)
272 continue
273 }
274 if strings.HasPrefix(line, "Vendor Id:") {
275 fmt.Sscanf(line, "Vendor Id: 0x%x", &cur.VendorID)
276 continue
277 }
278 if strings.HasPrefix(line, "Subsystem Id:") {
279 fmt.Sscanf(line, "Subsystem Id: 0x%x", &cur.SubsystemID)
280 continue
281 }
282 }
283
284 scanner = bufio.NewScanner(pin)
285 for scanner.Scan() {
286 line := scanner.Text()
287 addr := 0
288 val := uint32(0)
289 fmt.Sscanf(line, "0x%x 0x%x", &addr, &val)
290 cur.PinConfig[addr] = val
291 }
292 ret = append(ret, cur)
293 }
294 return
295}
296
297func (l *LogDevReader) GetIOPorts() []IOPorts {
298 file, err := os.Open(l.InputDirectory + "/ioports.log")
299 if err != nil {
300 log.Fatal(err)
301 }
302 defer file.Close()
303 scanner := bufio.NewScanner(file)
304 ret := make([]IOPorts, 0, 100)
305 for scanner.Scan() {
306 line := scanner.Text()
307 el := IOPorts{}
308 fmt.Sscanf(line, " %x-%x : %s", &el.Start, &el.End, &el.Usage)
309 ret = append(ret, el)
310 }
311
312 if err := scanner.Err(); err != nil {
313 log.Fatal(err)
314 }
315 return ret
316
317}
318
319func (l *LogDevReader) GetCPUModel() (ret []uint32) {
320 file, err := os.Open(l.InputDirectory + "/cpuinfo.log")
321 if err != nil {
322 log.Fatal(err)
323 }
324 defer file.Close()
325
326 scanner := bufio.NewScanner(file)
327 ret = make([]uint32, 0, 100)
328 proc := 0
329 for scanner.Scan() {
330 line := scanner.Text()
331 sep := strings.Index(line, ":")
332 if sep < 0 {
333 continue
334 }
335 key := strings.TrimSpace(line[0:sep])
336 val := strings.TrimSpace(line[sep+1:])
337
338 if key == "processor" {
339 proc, _ := strconv.Atoi(val)
340 if len(ret) <= proc {
341 ret = ret[0 : proc+1]
342 }
343 continue
344 }
345 if key == "cpu family" {
346 family, _ := strconv.Atoi(val)
347 ret[proc] |= uint32(((family & 0xf) << 8) | ((family & 0xff0) << 16))
348 }
349 if key == "model" {
350 model, _ := strconv.Atoi(val)
351 ret[proc] |= uint32(((model & 0xf) << 4) | ((model & 0xf0) << 12))
352 }
353 if key == "stepping" {
354 stepping, _ := strconv.Atoi(val)
355 ret[proc] |= uint32(stepping & 0xf)
356 }
357 }
358
359 if err := scanner.Err(); err != nil {
360 log.Fatal(err)
361 }
362 return
363}
364
Vladimir Serbinenko91195c62015-05-29 23:53:37 +0200365func (l *LogDevReader) HasPS2() bool {
366 file, err := os.Open(l.InputDirectory + "/input_bustypes.log")
367 if err != nil {
368 log.Fatal(err)
369 }
370 defer file.Close()
371 scanner := bufio.NewScanner(file)
372 for scanner.Scan() {
373 line := scanner.Text()
374 if strings.Index(line, "0011") >= 0 {
375 return true
376 }
377 }
378 return false
379}
380
Vladimir Serbinenko3129f792014-10-15 21:51:47 +0200381var FlagLogInput = flag.String("input_log", ".", "Input log directory")
382var FlagLogMkLogs = flag.Bool("make_logs", false, "Dump logs")
383
384func MakeLogReader() *LogDevReader {
385 if *FlagLogMkLogs {
386 MakeLogs(*FlagLogInput)
387 }
388 return &LogDevReader{InputDirectory: *FlagLogInput}
389}