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

     1  // Copyright 2010-2020 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  // io reads and writes to physical memory and ports.
     6  //
     7  // Synopsis:
     8  //
     9  //	io (r{b,w,l,q} address)...
    10  //	io (w{b,w,l,q} address value)...
    11  //	# x86 only:
    12  //	io (in{b,w,l} address)
    13  //	io (out{b,w,l} address value)
    14  //	io (cr index}
    15  //	io {cw index value}...
    16  //
    17  // Description:
    18  //
    19  //	io lets you read/write 1/2/4/8-bytes to memory with the {r,w}{b,w,l,q}
    20  //	commands respectively.
    21  //
    22  //	On x86 platforms, {in,out}{b,w,l} allow for port io.
    23  //
    24  //	Use cr / cw to write to cmos registers
    25  //
    26  // Examples:
    27  //
    28  //	# Read 8-bytes from address 0x10000 and 0x10000
    29  //	io rq 0x10000 rq 0x10008
    30  //	# Write to the serial port on x86
    31  //	io outb 0x3f8 50
    32  package main
    33  
    34  import (
    35  	"fmt"
    36  	"log"
    37  	"os"
    38  	"strconv"
    39  
    40  	"github.com/mvdan/u-root-coreutils/pkg/memio"
    41  )
    42  
    43  type (
    44  	cmdFunc func(addr int64, data memio.UintN) error
    45  	cmd     struct {
    46  		f                 cmdFunc
    47  		addrBits, valBits int
    48  	}
    49  )
    50  
    51  var (
    52  	readCmds  = map[string]*cmd{}
    53  	writeCmds = map[string]*cmd{}
    54  	usageMsg  string
    55  )
    56  
    57  func addCmd(cmds map[string]*cmd, n string, f *cmd) {
    58  	if _, ok := cmds[n]; ok {
    59  		log.Fatalf("Command %q is defined twice", n)
    60  	}
    61  	cmds[n] = f
    62  }
    63  
    64  func usage() {
    65  	fmt.Print(usageMsg)
    66  	os.Exit(1)
    67  }
    68  
    69  // newInt constructs a UintN with the specified value and bits.
    70  func newInt(val uint64, bits int) memio.UintN {
    71  	switch bits {
    72  	case 8:
    73  		val := memio.Uint8(int8(val))
    74  		return &val
    75  	case 16:
    76  		val := memio.Uint16(uint16(val))
    77  		return &val
    78  	case 32:
    79  		val := memio.Uint32(uint32(val))
    80  		return &val
    81  	case 64:
    82  		val := memio.Uint64(uint64(val))
    83  		return &val
    84  	default:
    85  		panic(fmt.Sprintf("invalid number of bits %d", bits))
    86  	}
    87  }
    88  
    89  func main() {
    90  	if len(os.Args) < 3 {
    91  		usage()
    92  	}
    93  	os.Args = os.Args[1:]
    94  
    95  	// To avoid the command list from being partially executed when the
    96  	// args fail to parse, queue them up and run all at once at the end.
    97  	queue := []func(){}
    98  
    99  	for len(os.Args) > 0 {
   100  		var cmdStr string
   101  		cmdStr, os.Args = os.Args[0], os.Args[1:]
   102  		if c, ok := readCmds[cmdStr]; ok {
   103  			// Parse arguments.
   104  			if len(os.Args) < 1 {
   105  				usage()
   106  			}
   107  			var addrStr string
   108  			addrStr, os.Args = os.Args[0], os.Args[1:]
   109  			addr, err := strconv.ParseUint(addrStr, 0, c.addrBits)
   110  			if err != nil {
   111  				log.Fatal(err)
   112  			}
   113  
   114  			queue = append(queue, func() {
   115  				// Read from addr and print.
   116  				data := newInt(0, c.valBits)
   117  				if err := c.f(int64(addr), data); err != nil {
   118  					log.Fatal(err)
   119  				}
   120  				fmt.Printf("%s\n", data)
   121  			})
   122  		} else if c, ok := writeCmds[cmdStr]; ok {
   123  			// Parse arguments.
   124  			if len(os.Args) < 2 {
   125  				usage()
   126  			}
   127  			var addrStr, dataStr string
   128  			addrStr, dataStr, os.Args = os.Args[0], os.Args[1], os.Args[2:]
   129  			addr, err := strconv.ParseUint(addrStr, 0, c.addrBits)
   130  			if err != nil {
   131  				log.Fatal(err)
   132  			}
   133  			value, err := strconv.ParseUint(dataStr, 0, c.valBits)
   134  			if err != nil {
   135  				log.Fatal(err)
   136  			}
   137  
   138  			queue = append(queue, func() {
   139  				// Write data to addr.
   140  				data := newInt(value, c.valBits)
   141  				if err := c.f(int64(addr), data); err != nil {
   142  					log.Fatal(err)
   143  				}
   144  			})
   145  		} else {
   146  			usage()
   147  		}
   148  	}
   149  
   150  	// Run all commands.
   151  	for _, c := range queue {
   152  		c()
   153  	}
   154  }