/ util / autoport / log_reader.go
log_reader.go
  1  package main
  2  
  3  import (
  4  	"bufio"
  5  	"flag"
  6  	"fmt"
  7  	"log"
  8  	"os"
  9  	"regexp"
 10  	"strconv"
 11  	"strings"
 12  )
 13  
 14  type LogDevReader struct {
 15  	InputDirectory string
 16  	ACPITables     map[string][]byte
 17  	EC             []byte
 18  }
 19  
 20  func 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  
 33  type HexLine struct {
 34  	length uint
 35  	values [16]byte
 36  	start  uint
 37  }
 38  
 39  func (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  
 54  func (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  
 63  func (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  
 91  func (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  
128  func (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  
172  func (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  
229  func (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  
268  func (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  
325  func (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  
347  func (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  
393  func (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  
409  var FlagLogInput = flag.String("input_log", ".", "Input log directory")
410  var FlagLogMkLogs = flag.Bool("make_logs", false, "Dump logs")
411  
412  func MakeLogReader() *LogDevReader {
413  	if *FlagLogMkLogs {
414  		MakeLogs(*FlagLogInput)
415  	}
416  	return &LogDevReader{InputDirectory: *FlagLogInput}
417  }