xref: /aosp_15_r20/external/coreboot/util/autoport/log_reader.go (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1package main
2
3import (
4	"bufio"
5	"flag"
6	"fmt"
7	"log"
8	"os"
9	"regexp"
10	"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()
110		/* Only supports ACPI tables up to 0x100000 in size, FIXME if needed */
111		is_hexline, _ := regexp.MatchString(" *[0-9A-Fa-f]{4,5}: ", line)
112		switch {
113		case len(line) >= 6 && line[5] == '@':
114			curTable = line[0:4]
115			Tables[curTable] = make([]byte, 0, 0x100000)
116		case is_hexline:
117			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.IOBP = map[uint32]uint32{}
184	ret.IGD = map[uint32]uint32{}
185	ret.MCHBAR = map[uint16]uint32{}
186	ret.PMBASE = map[uint16]uint32{}
187	for scanner.Scan() {
188		line := scanner.Text()
189		switch {
190		case len(line) > 7 && line[0] == '0' && line[1] == 'x' && line[6] == ':' && paragraph == "RCBA":
191			addr, value := 0, 0
192			fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
193			ret.RCBA[uint16(addr)] = uint32(value)
194		case len(line) > 11 && line[0] == '0' && line[1] == 'x' && line[10] == ':' && paragraph == "IOBP":
195			addr, value := 0, 0
196			fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
197			ret.IOBP[uint32(addr)] = uint32(value)
198		case len(line) > 9 && line[0] == '0' && line[1] == 'x' && line[8] == ':' && paragraph == "IGD":
199			addr, value := 0, 0
200			fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
201			ret.IGD[uint32(addr)] = uint32(value)
202		case len(line) > 7 && line[0] == '0' && line[1] == 'x' && line[6] == ':' && paragraph == "MCHBAR":
203			addr, value := 0, 0
204			fmt.Sscanf(line, "0x%x: 0x%x", &addr, &value)
205			ret.MCHBAR[uint16(addr)] = uint32(value)
206		case strings.Contains(line, "DEFAULT"):
207			continue
208		case strings.Contains(line, "DIFF"):
209			continue
210		case strings.HasPrefix(line, "gpiobase"):
211			addr, value := 0, 0
212			fmt.Sscanf(line, "gpiobase+0x%x: 0x%x", &addr, &value)
213			ret.GPIO[uint16(addr)] = uint32(value)
214		case strings.HasPrefix(line, "pmbase"):
215			addr, value := 0, 0
216			fmt.Sscanf(line, "pmbase+0x%x: 0x%x", &addr, &value)
217			ret.PMBASE[uint16(addr)] = uint32(value)
218		case strings.HasPrefix(line, "============="):
219			paragraph = strings.Trim(line, "= ")
220		}
221	}
222
223	if err := scanner.Err(); err != nil {
224		log.Fatal(err)
225	}
226	return
227}
228
229func (l *LogDevReader) GetDMI() (ret DMIData) {
230	file, err := os.Open(l.InputDirectory + "/dmidecode.log")
231	if err != nil {
232		log.Fatal(err)
233	}
234	defer file.Close()
235
236	scanner := bufio.NewScanner(file)
237	paragraph := ""
238	for scanner.Scan() {
239		line := scanner.Text()
240		if !strings.HasPrefix(line, "\t") {
241			paragraph = strings.TrimSpace(line)
242			continue
243		}
244		idx := strings.Index(line, ":")
245		if idx < 0 {
246			continue
247		}
248		name := strings.TrimSpace(line[0:idx])
249		value := strings.TrimSpace(line[idx+1:])
250		switch paragraph + ":" + name {
251		case "System Information:Manufacturer":
252			ret.Vendor = value
253		case "System Information:Product Name":
254			ret.Model = value
255		case "System Information:Version":
256			ret.Version = value
257		case "Chassis Information:Type":
258			ret.IsLaptop = (value == "Notebook" || value == "Laptop")
259		}
260	}
261
262	if err := scanner.Err(); err != nil {
263		log.Fatal(err)
264	}
265	return
266}
267
268func (l *LogDevReader) GetAzaliaCodecs() (ret []AzaliaCodec) {
269	cardno := -1
270	for i := 0; i < 10; i++ {
271		pin, err := os.Open(l.InputDirectory + "/pin_hwC" + strconv.Itoa(i) + "D0")
272		if err == nil {
273			pin.Close()
274			cardno = i
275			break
276		}
277	}
278	if cardno == -1 {
279		return
280	}
281	for codecno := 0; codecno < 10; codecno++ {
282		cur := AzaliaCodec{CodecNo: codecno, PinConfig: map[int]uint32{}}
283		codec, err := os.Open(l.InputDirectory + "/codec#" + strconv.Itoa(codecno))
284		if err != nil {
285			continue
286		}
287		defer codec.Close()
288		pin, err := os.Open(l.InputDirectory + "/pin_hwC" + strconv.Itoa(cardno) +
289			"D" + strconv.Itoa(codecno))
290		if err != nil {
291			continue
292		}
293		defer pin.Close()
294
295		scanner := bufio.NewScanner(codec)
296		for scanner.Scan() {
297			line := scanner.Text()
298			if strings.HasPrefix(line, "Codec:") {
299				fmt.Sscanf(line, "Codec: %s", &cur.Name)
300				continue
301			}
302			if strings.HasPrefix(line, "Vendor Id:") {
303				fmt.Sscanf(line, "Vendor Id: 0x%x", &cur.VendorID)
304				continue
305			}
306			if strings.HasPrefix(line, "Subsystem Id:") {
307				fmt.Sscanf(line, "Subsystem Id: 0x%x", &cur.SubsystemID)
308				continue
309			}
310		}
311
312		scanner = bufio.NewScanner(pin)
313		for scanner.Scan() {
314			line := scanner.Text()
315			addr := 0
316			val := uint32(0)
317			fmt.Sscanf(line, "0x%x 0x%x", &addr, &val)
318			cur.PinConfig[addr] = val
319		}
320		ret = append(ret, cur)
321	}
322	return
323}
324
325func (l *LogDevReader) GetIOPorts() []IOPorts {
326	file, err := os.Open(l.InputDirectory + "/ioports.log")
327	if err != nil {
328		log.Fatal(err)
329	}
330	defer file.Close()
331	scanner := bufio.NewScanner(file)
332	ret := make([]IOPorts, 0, 100)
333	for scanner.Scan() {
334		line := scanner.Text()
335		el := IOPorts{}
336		fmt.Sscanf(line, " %x-%x : %s", &el.Start, &el.End, &el.Usage)
337		ret = append(ret, el)
338	}
339
340	if err := scanner.Err(); err != nil {
341		log.Fatal(err)
342	}
343	return ret
344
345}
346
347func (l *LogDevReader) GetCPUModel() (ret []uint32) {
348	file, err := os.Open(l.InputDirectory + "/cpuinfo.log")
349	if err != nil {
350		log.Fatal(err)
351	}
352	defer file.Close()
353
354	scanner := bufio.NewScanner(file)
355	ret = make([]uint32, 0, 100)
356	proc := 0
357	for scanner.Scan() {
358		line := scanner.Text()
359		sep := strings.Index(line, ":")
360		if sep < 0 {
361			continue
362		}
363		key := strings.TrimSpace(line[0:sep])
364		val := strings.TrimSpace(line[sep+1:])
365
366		if key == "processor" {
367			proc, _ := strconv.Atoi(val)
368			if len(ret) <= proc {
369				ret = ret[0 : proc+1]
370			}
371			continue
372		}
373		if key == "cpu family" {
374			family, _ := strconv.Atoi(val)
375			ret[proc] |= uint32(((family & 0xf) << 8) | ((family & 0xff0) << 16))
376		}
377		if key == "model" {
378			model, _ := strconv.Atoi(val)
379			ret[proc] |= uint32(((model & 0xf) << 4) | ((model & 0xf0) << 12))
380		}
381		if key == "stepping" {
382			stepping, _ := strconv.Atoi(val)
383			ret[proc] |= uint32(stepping & 0xf)
384		}
385	}
386
387	if err := scanner.Err(); err != nil {
388		log.Fatal(err)
389	}
390	return
391}
392
393func (l *LogDevReader) HasPS2() bool {
394	file, err := os.Open(l.InputDirectory + "/input_bustypes.log")
395	if err != nil {
396		log.Fatal(err)
397	}
398	defer file.Close()
399	scanner := bufio.NewScanner(file)
400	for scanner.Scan() {
401		line := scanner.Text()
402		if strings.Index(line, "0011") >= 0 {
403			return true
404		}
405	}
406	return false
407}
408
409var FlagLogInput = flag.String("input_log", ".", "Input log directory")
410var FlagLogMkLogs = flag.Bool("make_logs", false, "Dump logs")
411
412func MakeLogReader() *LogDevReader {
413	if *FlagLogMkLogs {
414		MakeLogs(*FlagLogInput)
415	}
416	return &LogDevReader{InputDirectory: *FlagLogInput}
417}
418