github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/contrib/flash/flash.go (about) 1 // Copyright 2021 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 // flash reads and writes to a flash chip. 6 // 7 // Synopsis: 8 // 9 // flash -p PROGRAMMER[:parameter[,parameter[...]]] [-r FILE|-w FILE] 10 // 11 // Options: 12 // 13 // -p PROGRAMMER: Specify the programmer with zero or more parameters (see 14 // below). 15 // -r FILE: Read flash data into the file. 16 // -w FILE: Write the file to the flash chip. First, the flash chip is read 17 // and then diffed against the file. The differing blocks are 18 // erased and written. Finally, the contents are verified. 19 // 20 // Programmers: 21 // 22 // dummy 23 // Virtual flash programmer for testing in a memory buffer. 24 // 25 // dummy:image=image.rom 26 // File to memmap for the memory buffer. 27 // 28 // linux_spi:dev=/dev/spidev0.0 29 // Use Linux's spidev driver. This is only supported on Linux. The dev 30 // parameter is required. 31 // 32 // linux_spi:dev=/dev/spidev0.0,spispeed=5000 33 // Set the SPI controller's speed. The frequency is in kilohertz. 34 // 35 // Description: 36 // 37 // flash is u-root's implementation of flashrom. It has a very limited 38 // feature set and depends on the the flash chip implementing the SFDP. 39 package main 40 41 import ( 42 "errors" 43 "fmt" 44 "io" 45 "log" 46 "os" 47 "sort" 48 "strings" 49 50 flag "github.com/spf13/pflag" 51 ) 52 53 type programmer interface { 54 io.ReaderAt 55 io.WriterAt 56 Size() int64 57 Close() error 58 } 59 60 type ( 61 programmerParams map[string]string 62 programmerInit func(programmerParams) (programmer, error) 63 ) 64 65 // supportedProgrammers is populated by the other files in this package. 66 var supportedProgrammers = map[string]programmerInit{} 67 68 func parseProgrammerParams(arg string) (string, map[string]string) { 69 params := map[string]string{} 70 71 colon := strings.IndexByte(arg, ':') 72 if colon == -1 { 73 return arg, params 74 } 75 for _, p := range strings.Split(arg[colon+1:], ",") { 76 equal := strings.IndexByte(p, '=') 77 if equal == -1 { 78 params[p] = "" 79 continue 80 } 81 params[p[:equal]] = p[equal+1:] 82 } 83 return arg[:colon], params 84 } 85 86 func run(args []string, supportedProgrammers map[string]programmerInit) (reterr error) { 87 // Make a human readable list of supported programmers. 88 programmerList := []string{} 89 for k := range supportedProgrammers { 90 programmerList = append(programmerList, k) 91 } 92 sort.Strings(programmerList) 93 94 // Parse args. 95 fs := flag.NewFlagSet("flash", flag.ContinueOnError) 96 var ( 97 p = fs.StringP("programmer", "p", "", fmt.Sprintf("programmer (%s)", strings.Join(programmerList, ","))) 98 r = fs.StringP("read", "r", "", "read flash data into the file") 99 w = fs.StringP("write", "w", "", "write the file to flash") 100 ) 101 if err := fs.Parse(args); err != nil { 102 return err 103 } 104 if fs.NArg() != 0 { 105 flag.Usage() 106 return errors.New("unexpected positional arguments") 107 } 108 109 if *p == "" { 110 return errors.New("-p needs to be set") 111 } 112 113 if *r == "" && *w == "" { 114 return errors.New("either -r or -w need to be set") 115 } 116 if *r != "" && *w != "" { 117 return errors.New("both -r and -w cannot be set") 118 } 119 120 programmerName, params := parseProgrammerParams(*p) 121 init, ok := supportedProgrammers[programmerName] 122 if !ok { 123 return fmt.Errorf("unrecognized programmer %q", programmerName) 124 } 125 126 programmer, err := init(params) 127 if err != nil { 128 return err 129 } 130 defer func() { 131 err := programmer.Close() 132 if reterr == nil { 133 reterr = err 134 } 135 }() 136 137 // Create a buffer to hold the contents of the image. 138 buf := make([]byte, programmer.Size()) 139 140 if *r != "" { 141 f, err := os.Create(*r) 142 if err != nil { 143 return err 144 } 145 defer func() { 146 err := f.Close() 147 if reterr == nil { 148 reterr = err 149 } 150 }() 151 if _, err := programmer.ReadAt(buf, 0); err != nil { 152 return err 153 } 154 if _, err := f.Write(buf); err != nil { 155 return err 156 } 157 } else if *w != "" { 158 f, err := os.Open(*w) 159 if err != nil { 160 return err 161 } 162 defer f.Close() 163 if _, err := io.ReadFull(f, buf); err != nil { 164 return err 165 } 166 if leftover, err := io.Copy(io.Discard, f); err != nil { 167 return err 168 } else if leftover != 0 { 169 return fmt.Errorf("flash size (%#x) unequal to file size (%#x)", len(buf), int64(len(buf))+leftover) 170 } 171 172 return errors.New("write not yet supported") 173 } 174 175 return nil 176 } 177 178 func main() { 179 if err := run(os.Args[1:], supportedProgrammers); err != nil { 180 log.Fatalf("Error: %v", err) 181 } 182 }