github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/pci/pci.go (about)

     1  // Copyright 2012-2017 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  //go:build !plan9
     6  // +build !plan9
     7  
     8  // pci: show pci bus vendor ids and other info
     9  //
    10  // Description:
    11  //
    12  //	List the PCI bus, with names if possible.
    13  //
    14  // Options:
    15  //
    16  //	-n: just show numbers
    17  //	-c: dump config space
    18  //	-s: specify glob for choosing devices.
    19  package main
    20  
    21  import (
    22  	"encoding/json"
    23  	"fmt"
    24  	"io"
    25  	"log"
    26  	"os"
    27  	"strconv"
    28  	"strings"
    29  
    30  	flag "github.com/pborman/getopt/v2"
    31  	"github.com/mvdan/u-root-coreutils/pkg/pci"
    32  )
    33  
    34  var (
    35  	numbers   = flag.Bool('n', "Show numeric IDs")
    36  	devs      = flag.StringLong("select", 's', "*", "Devices to match")
    37  	dumpJSON  = flag.BoolLong("json", 'j', "Dump the bus in JSON")
    38  	verbosity = flag.Counter('v', "verbosity")
    39  	hexdump   = flag.Counter('x', "hexdump the config space")
    40  	readJSON  = flag.StringLong("JSON", 'J', "", "Read JSON in instead of /sys")
    41  )
    42  
    43  var format = map[int]string{
    44  	32: "%08x:%08x",
    45  	16: "%08x:%04x",
    46  	8:  "%08x:%02x",
    47  }
    48  
    49  // maybe we need a better syntax than the standard pcitools?
    50  func registers(d pci.Devices, cmds ...string) {
    51  	var justCheck bool
    52  	for _, c := range cmds {
    53  		// TODO: replace this nonsense with a state machine.
    54  		// Split into register and value
    55  		rv := strings.Split(c, "=")
    56  		if len(rv) != 1 && len(rv) != 2 {
    57  			log.Printf("%v: only one = allowed. Due to this error no more commands will be issued", c)
    58  			justCheck = true
    59  			continue
    60  		}
    61  
    62  		// Split into register offset and size
    63  		rs := strings.Split(rv[0], ".")
    64  		if len(rs) != 1 && len(rs) != 2 {
    65  			log.Printf("%v: only one . allowed. Due to this error no more commands will be issued", rv[1])
    66  			justCheck = true
    67  			continue
    68  		}
    69  		s := 32
    70  		if len(rs) == 2 {
    71  			switch rs[1] {
    72  			default:
    73  				log.Printf("Bad size: %v. Due to this error no more commands will be issued", rs[1])
    74  				justCheck = true
    75  				continue
    76  			case "l":
    77  			case "w":
    78  				s = 16
    79  			case "b":
    80  				s = 8
    81  			}
    82  		}
    83  		if justCheck {
    84  			continue
    85  		}
    86  		reg, err := strconv.ParseUint(rs[0], 0, 16)
    87  		if err != nil {
    88  			log.Printf("%v:%v. Due to this error no more commands will be issued", rs[0], err)
    89  			justCheck = true
    90  			continue
    91  		}
    92  		if len(rv) == 1 {
    93  			v, err := d.ReadConfigRegister(int64(reg), int64(s))
    94  			if err != nil {
    95  				log.Printf("%v:%v. Due to this error no more commands will be issued", rv[0], err)
    96  				justCheck = true
    97  				continue
    98  			}
    99  			// Should this go in the package somewhere? Not sure.
   100  			for i := range v {
   101  				d[i].ExtraInfo = append(d[i].ExtraInfo, fmt.Sprintf(format[s], reg, v[i]))
   102  			}
   103  		}
   104  		if len(rv) == 2 {
   105  			val, err := strconv.ParseUint(rv[1], 0, s)
   106  			if err != nil {
   107  				log.Printf("%v. Due to this error no more commands will be issued", err)
   108  				justCheck = true
   109  				continue
   110  			}
   111  			if err := d.WriteConfigRegister(int64(reg), int64(s), val); err != nil {
   112  				log.Printf("%v:%v. Due to this error no more commands will be issued", rv[1], err)
   113  				justCheck = true
   114  				continue
   115  			}
   116  		}
   117  
   118  	}
   119  }
   120  
   121  func pciExecution(w io.Writer, args ...string) error {
   122  	var dumpSize int
   123  	switch *hexdump {
   124  	case 4:
   125  		dumpSize = 4096
   126  	case 3:
   127  		dumpSize = 256
   128  	case 2: // lspci disallows this value
   129  		dumpSize = 256
   130  	case 1:
   131  		dumpSize = 64
   132  	}
   133  	r, err := pci.NewBusReader(strings.Split(*devs, ",")...)
   134  	if err != nil {
   135  		return err
   136  	}
   137  
   138  	var d pci.Devices
   139  	if len(*readJSON) != 0 {
   140  		b, err := os.ReadFile(*readJSON)
   141  		if err != nil {
   142  			return err
   143  		}
   144  		if err := json.Unmarshal(b, &d); err != nil {
   145  			return err
   146  		}
   147  
   148  	} else {
   149  		if d, err = r.Read(); err != nil {
   150  			return err
   151  		}
   152  	}
   153  
   154  	if !*numbers || *dumpJSON {
   155  		d.SetVendorDeviceName()
   156  	}
   157  	if len(args) > 0 {
   158  		registers(d, args...)
   159  	}
   160  	if *dumpJSON {
   161  		o, err := json.MarshalIndent(d, "", "\t")
   162  		if err != nil {
   163  			return err
   164  		}
   165  		fmt.Fprintf(w, "%s", string(o))
   166  		return nil
   167  	}
   168  	if err := d.Print(w, *verbosity, dumpSize); err != nil {
   169  		return err
   170  	}
   171  	return nil
   172  }
   173  
   174  func main() {
   175  	flag.Parse()
   176  	if err := pciExecution(os.Stdout, flag.Args()...); err != nil {
   177  		log.Fatal(err)
   178  	}
   179  }