@@ -25,6 +25,7 @@ import (
25
25
"strings"
26
26
27
27
"github.com/gofrs/flock"
28
+ "github.com/soypat/tinyboot/boot/picobin"
28
29
"github.com/tinygo-org/tinygo/compileopts"
29
30
"github.com/tinygo-org/tinygo/compiler"
30
31
"github.com/tinygo-org/tinygo/goenv"
@@ -804,6 +805,12 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
804
805
return fmt .Errorf ("could not modify stack sizes: %w" , err )
805
806
}
806
807
}
808
+
809
+ // Apply patches of bootloader in the order they appear.
810
+ if len (config .Target .BootPatches ) > 0 {
811
+ err = applyPatches (result .Executable , config .Target .BootPatches )
812
+ }
813
+
807
814
if config .RP2040BootPatch () {
808
815
// Patch the second stage bootloader CRC into the .boot2 section
809
816
err = patchRP2040BootCRC (result .Executable )
@@ -1422,6 +1429,23 @@ func printStacks(calculatedStacks []string, stackSizes map[string]functionStackS
1422
1429
}
1423
1430
}
1424
1431
1432
+ func applyPatches (executable string , bootPatches []string ) (err error ) {
1433
+ for _ , patch := range bootPatches {
1434
+ switch patch {
1435
+ case "rp2040" :
1436
+ err = patchRP2040BootCRC (executable )
1437
+ case "rp2350" :
1438
+ err = patchRP2350BootIMAGE_DEF (executable )
1439
+ default :
1440
+ err = errors .New ("undefined boot patch name" )
1441
+ }
1442
+ if err != nil {
1443
+ return fmt .Errorf ("apply boot patch %q: %w" , patch , err )
1444
+ }
1445
+ }
1446
+ return nil
1447
+ }
1448
+
1425
1449
// RP2040 second stage bootloader CRC32 calculation
1426
1450
//
1427
1451
// Spec: https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
@@ -1433,7 +1457,7 @@ func patchRP2040BootCRC(executable string) error {
1433
1457
}
1434
1458
1435
1459
if len (bytes ) != 256 {
1436
- return fmt .Errorf ("rp2040 .boot2 section must be exactly 256 bytes" )
1460
+ return fmt .Errorf ("rp2040 .boot2 section must be exactly 256 bytes, got %d" , len ( bytes ) )
1437
1461
}
1438
1462
1439
1463
// From the 'official' RP2040 checksum script:
@@ -1462,70 +1486,17 @@ func patchRP2040BootCRC(executable string) error {
1462
1486
1463
1487
// RP2350 block patching.
1464
1488
func patchRP2350BootIMAGE_DEF (executable string ) error {
1465
- const (
1466
- picobinBlockMarkerStart = 0xffffded3
1467
- picobinBlockMarkerEnd = 0xab123579
1468
- picobinBlockItem1BSImageType = 3
1469
- )
1470
- bytes , _ , err := getElfSectionData (executable , ".boot2" )
1489
+ boot2 , _ , err := getElfSectionData (executable , ".boot2" )
1471
1490
if err != nil {
1472
1491
return err
1473
1492
}
1474
- type item struct {
1475
- head uint8 // [0:1]:size_flag(0 means 1 byte size, 1 means 2 byte size) [1:7]: item type.
1476
- s0mod uint8 // s0%256
1477
- s0div uint8 // s0/256 if size_flag==1, or is type specific data for blocks that are never >256 words.
1478
- tpdata uint8 // Type specific data.
1479
- data []byte // item data.
1480
- }
1481
- type block struct {
1482
- items []item
1483
- }
1484
- makeIMAGE_DEF := func (imgType , exeSec , exeCPU , exeChip uint8 , exeTBYB bool ) item {
1485
- return item {
1486
- head : 0x42 , s0mod : 1 , s0div : 0b111 & imgType | (0b11 & exeSec << 4 ),
1487
- tpdata : 0b111 & exeCPU | ((0b111 & exeChip ) << 4 ) | b2u8 (exeTBYB )<< 7 ,
1488
- }
1489
- }
1490
- appendItem := func (dst []byte , it item ) []byte {
1491
- dst = append (dst , it .head , it .s0mod , it .s0div , it .tpdata )
1492
- return append (dst , it .data ... )
1493
- }
1494
- appendBlock := func (dst []byte , blk block ) []byte {
1495
- dst = binary .LittleEndian .AppendUint32 (dst , picobinBlockMarkerStart )
1496
- startSize := len (dst )
1497
- for _ , item := range blk .items {
1498
- dst = appendItem (dst , item )
1499
- }
1500
- itemsSize := len (dst ) - startSize
1501
- // Last item append:
1502
- dst = append (dst ,
1503
- 0xff , // size_flag=1, item_type==blockItemLast
1504
- uint8 ((itemsSize / 4 )% 256 ),
1505
- uint8 ((itemsSize / 4 )/ 256 ),
1506
- 0 , // Pad.
1507
- )
1508
- // Relative position in bytes to next block HEADER relative to this blocks HEADER.
1509
- // Use 0 to denote a loop to this same block.
1510
- dst = binary .LittleEndian .AppendUint32 (dst , 0 )
1511
- dst = binary .LittleEndian .AppendUint32 (dst , picobinBlockMarkerEnd ) // Footer.
1512
- return nil
1513
- }
1514
- boot2IMGDEF := makeIMAGE_DEF (
1515
- 1 , // 1:Executable; 2: Data.
1516
- 2 , // 0:Non-Secure; 1:Run in secure mode.
1517
- 0 , // 0:ARM arch; 1:RISCV arch
1518
- 1 , // 0:RP2040; 1:RP2350
1519
- false , // true: Image is flagged for "Try Before You Buy"
1520
- )
1521
-
1522
- if len (bytes ) != 256 {
1523
- return fmt .Errorf ("rp2040 .boot2 section must be exactly 256 bytes" )
1524
- }
1525
- _ = appendBlock
1526
- _ = boot2IMGDEF
1493
+ item0 := picobin .MakeImageDef (picobin .ImageTypeExecutable , picobin .ExeSecSecure , picobin .ExeCPUARM , picobin .ExeChipRP2350 , false )
1494
+ newBoot := make ([]byte , 256 )
1495
+ newBoot , _ , err = picobin .AppendBlockFromItems (newBoot [:0 ], []picobin.Item {item0 .Item }, boot2 , 0 )
1496
+ off := len (newBoot )
1497
+ newBoot , _ , err = picobin .AppendFinalBlock (newBoot , - off )
1527
1498
// Update the .boot2 section to included the CRC
1528
- return replaceElfSection (executable , ".boot2" , bytes )
1499
+ return replaceElfSection (executable , ".boot2" , newBoot )
1529
1500
}
1530
1501
1531
1502
// lock may acquire a lock at the specified path.
0 commit comments