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 }