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