Skip to content

Commit cf67f5f

Browse files
committed
Add flash-write command for ESP
Params are address and file name ("-" for stdin). ``` $ mos flash-write --platform esp8266 0 flash.bin ``` CL: mos: Add flash-write command for ESP
1 parent 463a002 commit cf67f5f

File tree

6 files changed

+228
-75
lines changed

6 files changed

+228
-75
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,4 @@ Build the binary:
7676
$ make
7777
```
7878

79-
It will produce `mos/mos` (or mos/mos.exe` on Windows.
79+
It will produce `mos/mos` (or `mos/mos.exe` on Windows).

mos/flash/esp/flasher/flash.go

Lines changed: 104 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,19 @@ const (
4343
)
4444

4545
type image struct {
46-
addr uint32
47-
data []byte
48-
part *fwbundle.FirmwarePart
46+
Name string
47+
Type string
48+
Addr uint32
49+
Data []byte
50+
ESP32Encrypt bool
4951
}
5052

5153
type imagesByAddr []*image
5254

5355
func (pp imagesByAddr) Len() int { return len(pp) }
5456
func (pp imagesByAddr) Swap(i, j int) { pp[i], pp[j] = pp[j], pp[i] }
5557
func (pp imagesByAddr) Less(i, j int) bool {
56-
return pp[i].addr < pp[j].addr
58+
return pp[i].Addr < pp[j].Addr
5759
}
5860

5961
func enDis(enabled bool) string {
@@ -75,32 +77,9 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
7577
}
7678
defer cfr.rc.Disconnect()
7779

78-
common.Reportf("Flash size: %d, params: %s", cfr.flashParams.Size(), cfr.flashParams)
79-
80-
encryptionEnabled := false
81-
secureBootEnabled := false
82-
var esp32EncryptionKey []byte
83-
var fusesByName map[string]*esp32.Fuse
84-
kcs := esp32.KeyEncodingSchemeNone
8580
if ct == esp.ChipESP8266 {
8681
// Based on our knowledge of flash size, adjust type=sys_params image.
8782
adjustSysParamsLocation(fw, cfr.flashParams.Size())
88-
} else {
89-
_, _, fusesByName, err = esp32.ReadFuses(cfr.fc)
90-
if err != nil {
91-
return errors.Annotatef(err, "failed to read eFuses")
92-
}
93-
94-
if fcnt, err := fusesByName[esp32.FlashCryptCntFuseName].Value(true /* withDiffs */); err == nil {
95-
encryptionEnabled = (bits.OnesCount64(fcnt.Uint64())%2 != 0)
96-
kcs = esp32.GetKeyEncodingScheme(fusesByName)
97-
common.Reportf("Flash encryption: %s, scheme: %s", enDis(encryptionEnabled), kcs)
98-
}
99-
100-
if abs0, err := fusesByName[esp32.AbstractDone0FuseName].Value(true /* withDiffs */); err == nil {
101-
secureBootEnabled = (abs0.Int64() != 0)
102-
common.Reportf("Secure boot: %s", enDis(secureBootEnabled))
103-
}
10483
}
10584

10685
// Sort images by address
@@ -122,11 +101,52 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
122101
glog.V(1).Infof("%s -> %s -> 0x%x", p.Name, p.ESP32PartitionName, pti.Pos.Offset)
123102
p.Addr = pti.Pos.Offset
124103
}
125-
im := &image{addr: p.Addr, data: data, part: p}
126-
if im.addr == 0 || im.addr == 0x1000 && len(data) >= 4 && data[0] == 0xe9 {
127-
im.data[2], im.data[3] = cfr.flashParams.Bytes()
104+
im := &image{
105+
Name: p.Name,
106+
Type: p.Type,
107+
Addr: p.Addr,
108+
Data: data,
109+
ESP32Encrypt: p.ESP32Encrypt,
128110
}
129-
if ct == esp.ChipESP32 && p.ESP32Encrypt && encryptionEnabled {
111+
images = append(images, im)
112+
}
113+
114+
return errors.Trace(writeImages(ct, cfr, images, opts, true))
115+
}
116+
117+
func writeImages(ct esp.ChipType, cfr *cfResult, images []*image, opts *esp.FlashOpts, sanityCheck bool) error {
118+
var err error
119+
120+
common.Reportf("Flash size: %d, params: %s", cfr.flashParams.Size(), cfr.flashParams)
121+
122+
encryptionEnabled := false
123+
secureBootEnabled := false
124+
var esp32EncryptionKey []byte
125+
var fusesByName map[string]*esp32.Fuse
126+
kcs := esp32.KeyEncodingSchemeNone
127+
if ct == esp.ChipESP32 {
128+
_, _, fusesByName, err = esp32.ReadFuses(cfr.fc)
129+
if err != nil {
130+
return errors.Annotatef(err, "failed to read eFuses")
131+
}
132+
133+
if fcnt, err := fusesByName[esp32.FlashCryptCntFuseName].Value(true /* withDiffs */); err == nil {
134+
encryptionEnabled = (bits.OnesCount64(fcnt.Uint64())%2 != 0)
135+
kcs = esp32.GetKeyEncodingScheme(fusesByName)
136+
common.Reportf("Flash encryption: %s, scheme: %s", enDis(encryptionEnabled), kcs)
137+
}
138+
139+
if abs0, err := fusesByName[esp32.AbstractDone0FuseName].Value(true /* withDiffs */); err == nil {
140+
secureBootEnabled = (abs0.Int64() != 0)
141+
common.Reportf("Secure boot: %s", enDis(secureBootEnabled))
142+
}
143+
}
144+
145+
for _, im := range images {
146+
if im.Addr == 0 || im.Addr == 0x1000 && len(im.Data) >= 4 && im.Data[0] == 0xe9 {
147+
im.Data[2], im.Data[3] = cfr.flashParams.Bytes()
148+
}
149+
if ct == esp.ChipESP32 && im.ESP32Encrypt && encryptionEnabled {
130150
if esp32EncryptionKey == nil {
131151
if opts.ESP32EncryptionKeyFile != "" {
132152
mac := strings.ToUpper(strings.Replace(fusesByName[esp32.MACAddressFuseName].MACAddressString(), ":", "", -1))
@@ -154,19 +174,20 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
154174
encrKey = append(encrKey, encrKey[8:16]...)
155175
}
156176
encData, err := esp32.ESP32EncryptImageData(
157-
im.data, encrKey, im.addr, opts.ESP32FlashCryptConf)
177+
im.Data, encrKey, im.Addr, opts.ESP32FlashCryptConf)
158178
if err != nil {
159-
return errors.Annotatef(err, "%s: failed to encrypt", p.Name)
179+
return errors.Annotatef(err, "%s: failed to encrypt", im.Name)
160180
}
161-
im.data = encData
181+
im.Data = encData
162182
}
163-
images = append(images, im)
164183
}
165184
sort.Sort(imagesByAddr(images))
166185

167-
err = sanityCheckImages(ct, images, cfr.flashParams.Size(), flashSectorSize)
168-
if err != nil {
169-
return errors.Trace(err)
186+
if sanityCheck {
187+
err = sanityCheckImages(ct, images, cfr.flashParams.Size(), flashSectorSize)
188+
if err != nil {
189+
return errors.Trace(err)
190+
}
170191
}
171192

172193
imagesToWrite := images
@@ -188,10 +209,10 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
188209
start := time.Now()
189210
totalBytesWritten := 0
190211
for _, im := range imagesToWrite {
191-
data := im.data
212+
data := im.Data
192213
numAttempts := 3
193214
imageBytesWritten := 0
194-
addr := im.addr
215+
addr := im.Addr
195216
if len(data)%flashSectorSize != 0 {
196217
newData := make([]byte, len(data))
197218
copy(newData, data)
@@ -201,7 +222,7 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
201222
}
202223
data = newData
203224
}
204-
for i := 1; imageBytesWritten < len(im.data); i++ {
225+
for i := 1; imageBytesWritten < len(im.Data); i++ {
205226
common.Reportf(" %7d @ 0x%x", len(data), addr)
206227
bytesWritten, err := cfr.fc.Write(addr, data, true /* erase */, opts.EnableCompression)
207228
if err != nil {
@@ -211,7 +232,7 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
211232
}
212233
err = errors.Annotatef(err, "write error (attempt %d/%d)", i, numAttempts)
213234
if i >= numAttempts {
214-
return errors.Annotatef(err, "%s: failed to write", im.part.Name)
235+
return errors.Annotatef(err, "%s: failed to write", im.Name)
215236
}
216237
glog.Warningf("%s", err)
217238
if err := cfr.fc.Sync(); err != nil {
@@ -224,7 +245,7 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
224245
imageBytesWritten += bytesWritten
225246
addr += uint32(bytesWritten)
226247
}
227-
totalBytesWritten += len(im.data)
248+
totalBytesWritten += len(im.Data)
228249
}
229250
seconds := time.Since(start).Seconds()
230251
bytesPerSecond := float64(totalBytesWritten) / seconds
@@ -233,19 +254,19 @@ func Flash(ct esp.ChipType, fw *fwbundle.FirmwareBundle, opts *esp.FlashOpts) er
233254

234255
common.Reportf("Verifying...")
235256
for _, im := range images {
236-
common.Reportf(" %7d @ 0x%x", len(im.data), im.addr)
237-
digest, err := cfr.fc.Digest(im.addr, uint32(len(im.data)), 0 /* blockSize */)
257+
common.Reportf(" %7d @ 0x%x", len(im.Data), im.Addr)
258+
digest, err := cfr.fc.Digest(im.Addr, uint32(len(im.Data)), 0 /* blockSize */)
238259
if err != nil {
239-
return errors.Annotatef(err, "%s: failed to compute digest %d @ 0x%x", im.part.Name, len(im.data), im.addr)
260+
return errors.Annotatef(err, "%s: failed to compute digest %d @ 0x%x", im.Name, len(im.Data), im.Addr)
240261
}
241262
if len(digest) != 1 || len(digest[0]) != 16 {
242263
return errors.Errorf("unexpected digest packetresult %+v", digest)
243264
}
244265
digestHex := strings.ToLower(hex.EncodeToString(digest[0]))
245-
expectedDigest := md5.Sum(im.data)
266+
expectedDigest := md5.Sum(im.Data)
246267
expectedDigestHex := strings.ToLower(hex.EncodeToString(expectedDigest[:]))
247268
if digestHex != expectedDigestHex {
248-
return errors.Errorf("%d @ 0x%x: digest mismatch: expected %s, got %s", len(im.data), im.addr, expectedDigestHex, digestHex)
269+
return errors.Errorf("%d @ 0x%x: digest mismatch: expected %s, got %s", len(im.Data), im.Addr, expectedDigestHex, digestHex)
249270
}
250271
}
251272
if opts.BootFirmware {
@@ -274,34 +295,34 @@ func sanityCheckImages(ct esp.ChipType, images []*image, flashSize, flashSectorS
274295
// Note: we require that images are sorted by address.
275296
sort.Sort(imagesByAddr(images))
276297
for i, im := range images {
277-
imageBegin := int(im.addr)
278-
imageEnd := imageBegin + len(im.data)
298+
imageBegin := int(im.Addr)
299+
imageEnd := imageBegin + len(im.Data)
279300
if imageBegin >= flashSize || imageEnd > flashSize {
280301
return errors.Errorf(
281-
"Image %d @ 0x%x will not fit in flash (size %d)", len(im.data), imageBegin, flashSize)
302+
"Image %d @ 0x%x will not fit in flash (size %d)", len(im.Data), imageBegin, flashSize)
282303
}
283304
if imageBegin%flashSectorSize != 0 {
284305
return errors.Errorf("Image starting address (0x%x) is not on flash sector boundary (sector size %d)",
285306
imageBegin,
286307
flashSectorSize)
287308
}
288-
if imageBegin == 0 && len(im.data) > 0 {
289-
if im.data[0] != espImageMagicByte {
309+
if imageBegin == 0 && len(im.Data) > 0 {
310+
if im.Data[0] != espImageMagicByte {
290311
return errors.Errorf("Invalid magic byte in the first image")
291312
}
292313
}
293314
if ct == esp.ChipESP8266 {
294315
sysParamsBegin := flashSize - sysParamsAreaSize
295-
if imageBegin == sysParamsBegin && im.part.Type == sysParamsPartType {
316+
if imageBegin == sysParamsBegin && im.Type == sysParamsPartType {
296317
// Ok, a sys_params image.
297318
} else if imageEnd > sysParamsBegin {
298319
return errors.Errorf("Image 0x%x overlaps with system params area (%d @ 0x%x)",
299320
imageBegin, sysParamsAreaSize, sysParamsBegin)
300321
}
301322
}
302323
if i > 0 {
303-
prevImageBegin := int(images[i-1].addr)
304-
prevImageEnd := prevImageBegin + len(images[i-1].data)
324+
prevImageBegin := int(images[i-1].Addr)
325+
prevImageEnd := prevImageBegin + len(images[i-1].Data)
305326
// We traverse the list in order, so a simple check will suffice.
306327
if prevImageEnd > imageBegin {
307328
return errors.Errorf("Images 0x%x and 0x%x overlap", prevImageBegin, imageBegin)
@@ -314,29 +335,35 @@ func sanityCheckImages(ct esp.ChipType, images []*image, flashSize, flashSectorS
314335
func dedupImages(fc *FlasherClient, images []*image) ([]*image, error) {
315336
var dedupedImages []*image
316337
for _, im := range images {
317-
glog.V(2).Infof("%d @ 0x%x", len(im.data), im.addr)
318-
imAddr := int(im.addr)
319-
digests, err := fc.Digest(im.addr, uint32(len(im.data)), flashSectorSize)
338+
glog.V(2).Infof("%d @ 0x%x", len(im.Data), im.Addr)
339+
imAddr := int(im.Addr)
340+
digests, err := fc.Digest(im.Addr, uint32(len(im.Data)), flashSectorSize)
320341
if err != nil {
321-
return nil, errors.Annotatef(err, "%s: failed to compute digest %d @ 0x%x", im.part.Name, len(im.data), im.addr)
342+
return nil, errors.Annotatef(err, "%s: failed to compute digest %d @ 0x%x", im.Name, len(im.Data), im.Addr)
322343
}
323344
i, offset := 0, 0
324345
var newImages []*image
325346
newAddr, newLen, newTotalLen := imAddr, 0, 0
326-
for offset < len(im.data) {
347+
for offset < len(im.Data) {
327348
blockLen := flashSectorSize
328-
if offset+blockLen > len(im.data) {
329-
blockLen = len(im.data) - offset
349+
if offset+blockLen > len(im.Data) {
350+
blockLen = len(im.Data) - offset
330351
}
331352
digestHex := strings.ToLower(hex.EncodeToString(digests[i]))
332-
expectedDigest := md5.Sum(im.data[offset : offset+blockLen])
353+
expectedDigest := md5.Sum(im.Data[offset : offset+blockLen])
333354
expectedDigestHex := strings.ToLower(hex.EncodeToString(expectedDigest[:]))
334355
glog.V(2).Infof("0x%06x %4d %s %s %t", imAddr+offset, blockLen, expectedDigestHex, digestHex, expectedDigestHex == digestHex)
335356
if expectedDigestHex == digestHex {
336357
// Found a matching sector. If we've been building an image, commit it.
337358
if newLen > 0 {
338-
nim := &image{addr: uint32(newAddr), data: im.data[newAddr-imAddr : newAddr-imAddr+newLen], part: im.part}
339-
glog.V(2).Infof("%d @ 0x%x", len(nim.data), nim.addr)
359+
nim := &image{
360+
Name: im.Name,
361+
Type: im.Type,
362+
Addr: uint32(newAddr),
363+
Data: im.Data[newAddr-imAddr : newAddr-imAddr+newLen],
364+
ESP32Encrypt: im.ESP32Encrypt,
365+
}
366+
glog.V(2).Infof("%d @ 0x%x", len(nim.Data), nim.Addr)
340367
newImages = append(newImages, nim)
341368
newTotalLen += newLen
342369
newAddr, newLen = 0, 0
@@ -352,19 +379,25 @@ func dedupImages(fc *FlasherClient, images []*image) ([]*image, error) {
352379
i++
353380
}
354381
if newLen > 0 {
355-
nim := &image{addr: uint32(newAddr), data: im.data[newAddr-imAddr : newAddr-imAddr+newLen], part: im.part}
382+
nim := &image{
383+
Name: im.Name,
384+
Type: im.Type,
385+
Addr: uint32(newAddr),
386+
Data: im.Data[newAddr-imAddr : newAddr-imAddr+newLen],
387+
ESP32Encrypt: im.ESP32Encrypt,
388+
}
356389
newImages = append(newImages, nim)
357-
glog.V(2).Infof("%d @ %x", len(nim.data), nim.addr)
390+
glog.V(2).Infof("%d @ %x", len(nim.Data), nim.Addr)
358391
newTotalLen += newLen
359392
newAddr, newLen = 0, 0
360393
}
361-
glog.V(2).Infof("%d @ 0x%x -> %d", len(im.data), im.addr, newTotalLen)
394+
glog.V(2).Infof("%d @ 0x%x -> %d", len(im.Data), im.Addr, newTotalLen)
362395
// There's a price for fragmenting a large image: erasing many individual
363396
// sectors is slower than erasing a whole block. So unless the difference
364397
// is substantial, don't bother.
365-
if newTotalLen < len(im.data) && (newTotalLen < flashBlockSize || len(im.data)-newTotalLen >= flashBlockSize) {
398+
if newTotalLen < len(im.Data) && (newTotalLen < flashBlockSize || len(im.Data)-newTotalLen >= flashBlockSize) {
366399
dedupedImages = append(dedupedImages, newImages...)
367-
common.Reportf(" %7d @ 0x%x -> %d", len(im.data), im.addr, newTotalLen)
400+
common.Reportf(" %7d @ 0x%x -> %d", len(im.Data), im.Addr, newTotalLen)
368401
} else {
369402
dedupedImages = append(dedupedImages, im)
370403
}

mos/flash/esp/flasher/write_flash.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// Copyright (c) 2014-2019 Cesanta Software Limited
3+
// All rights reserved
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
18+
package flasher
19+
20+
import (
21+
"github.com/juju/errors"
22+
23+
"github.com/mongoose-os/mos/mos/flash/esp"
24+
)
25+
26+
func WriteFlash(ct esp.ChipType, addr uint32, data []byte, opts *esp.FlashOpts) error {
27+
cfr, err := ConnectToFlasherClient(ct, opts)
28+
if err != nil {
29+
return errors.Trace(err)
30+
}
31+
defer cfr.rc.Disconnect()
32+
im := &image{
33+
Name: "image",
34+
Type: "user",
35+
Addr: addr,
36+
Data: data,
37+
ESP32Encrypt: (opts.ESP32EncryptionKeyFile != ""),
38+
}
39+
return errors.Trace(writeImages(ct, cfr, []*image{im}, opts, false))
40+
}

mos/flash_read.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@ func flashRead(ctx context.Context, devConn dev.DevConn) error {
7171
var data []byte
7272
platform := flags.Platform()
7373
switch platform {
74-
case "cc3200":
75-
err = errors.NotImplementedf("flash reading for %s", platform)
7674
case "esp32":
7775
espFlashOpts.ControlPort = port
7876
data, err = espFlasher.ReadFlash(esp.ChipESP32, uint32(addr), int(length), &espFlashOpts)
@@ -82,7 +80,7 @@ func flashRead(ctx context.Context, devConn dev.DevConn) error {
8280
case "stm32":
8381
err = errors.NotImplementedf("flash reading for %s", platform)
8482
default:
85-
err = errors.Errorf("unsupported platform '%s'", platform)
83+
err = errors.NotImplementedf("flash reading for %s", platform)
8684
}
8785

8886
if err == nil {

0 commit comments

Comments
 (0)