8
8
# See https://swift.org/LICENSE.txt for license information
9
9
10
10
#
11
- # macho2uf2 -- Converts a statically-linked executable Mach-O into a flat "UF2" file suitable for flashing as a single
12
- # contiguous blob onto some embedded devices, in particular Raspberry Pi Pico (W). Note that the UF2 format allows for
13
- # discontiguous memory regions, but this utility does not support that.
11
+ # macho2uf2 -- Converts a statically-linked executable Mach-O into a flat "UF2" file
12
+ # suitable for flashing as a single contiguous blob onto some embedded devices, in
13
+ # particular Raspberry Pi Pico (W). Note that the UF2 format allows for discontiguous
14
+ # memory regions, but this utility does not support that.
14
15
#
15
16
# Usage:
16
- # $ macho2uf2.py <input> <output> --base-address <base-address> --segments <segment-list>
17
+ # $ macho2uf2.py <input> <output> --base-address <base-address> --segments
18
+ # <segment-list>
17
19
#
18
20
# Example:
19
- # $ macho2uf2.py ./blink ./blink.uf2 --base-address 0x00200000 --segments '__TEXT,__DATA,__VECTORS'
21
+ # $ macho2uf2.py ./blink ./blink.uf2 --base-address 0x00200000 --segments
22
+ # '__TEXT,__DATA,__VECTORS'
20
23
#
21
24
# Requirements and notes:
22
- # * The output UF2 file is a flat contiguous representation of the segments (--segments) based on their VM addresses.
23
- # * The UF2 file's first byte corresponds to the specified base address (--base-address).
25
+ # * The output UF2 file is a flat contiguous representation of the segments
26
+ # (--segments) based on their VM addresses.
27
+ # * The UF2 file's first byte corresponds to the specified base address
28
+ # (--base-address).
24
29
# * Any gaps between segments are filled with zero bytes.
25
- # * Because of that, you want the input Mach-O to have all segments "close", and not have gaps.
30
+ # * Because of that, you want the input Mach-O to have all segments "close", and not
31
+ # have gaps.
26
32
#
27
33
28
34
import argparse
29
35
import os
30
- import subprocess
31
36
import struct
32
- from macholib import MachO
33
- from macholib import mach_o
37
+ import subprocess
34
38
35
39
MY_DIR = os .path .dirname (os .path .abspath (__file__ ))
36
40
41
+
37
42
def main ():
38
43
parser = argparse .ArgumentParser ()
39
- parser .add_argument (' input' )
40
- parser .add_argument (' output' )
41
- parser .add_argument (' --base-address' , required = True )
42
- parser .add_argument (' --segments' , required = True )
43
- parser .add_argument (' --pico-family' , required = True )
44
+ parser .add_argument (" input" )
45
+ parser .add_argument (" output" )
46
+ parser .add_argument (" --base-address" , required = True )
47
+ parser .add_argument (" --segments" , required = True )
48
+ parser .add_argument (" --pico-family" , required = True )
44
49
args = parser .parse_args ()
45
50
args .base_address = int (args .base_address , 16 )
46
51
args .segments = args .segments .split ("," )
47
52
if args .pico_family == "rp2040" :
48
53
family_id = 0xE48BFF56
49
54
add_errata_block = False
50
55
elif args .pico_family == "rp2350" :
51
- family_id = 0XE48BFF59
56
+ family_id = 0xE48BFF59
52
57
add_errata_block = True
53
58
else :
54
59
assert False
55
60
56
- subprocess .check_call ([MY_DIR + "/macho2bin.py" , args .input , args .input + ".bin" , "--base-address" , "0x%08x" % args .base_address , "--segments" , "," .join (args .segments )])
61
+ subprocess .check_call (
62
+ [
63
+ MY_DIR + "/macho2bin.py" ,
64
+ args .input ,
65
+ args .input + ".bin" ,
66
+ "--base-address" ,
67
+ "0x%08x" % args .base_address ,
68
+ "--segments" ,
69
+ "," .join (args .segments ),
70
+ ]
71
+ )
57
72
58
73
def emit_block (output , block , vmaddr , block_number , num_blocks , family_id ):
59
74
assert len (block ) <= 256
60
-
75
+
61
76
if len (block ) < 256 :
62
- block += b' \0 ' * (256 - len (block ))
63
-
77
+ block += b" \0 " * (256 - len (block ))
78
+
64
79
# UF2_Block header
65
- output += struct .pack ("<I" , 0x0A324655 ) # magicStart0
66
- output += struct .pack ("<I" , 0x9E5D5157 ) # magicStart1
67
- output += struct .pack ("<I" , 0x2000 ) # flags: familyID present
68
- output += struct .pack ("<I" , vmaddr ) # targetAddr
69
- output += struct .pack ("<I" , 256 ) # payloadSize
70
- output += struct .pack ("<I" , block_number ) # blockNo
71
- output += struct .pack ("<I" , num_blocks ) # numBlocks
72
- output += struct .pack ("<I" , family_id ) # fileSize / familyID: rp2040/rp2350 family ID
80
+ output += struct .pack ("<I" , 0x0A324655 ) # magicStart0
81
+ output += struct .pack ("<I" , 0x9E5D5157 ) # magicStart1
82
+ output += struct .pack ("<I" , 0x2000 ) # flags: familyID present
83
+ output += struct .pack ("<I" , vmaddr ) # targetAddr
84
+ output += struct .pack ("<I" , 256 ) # payloadSize
85
+ output += struct .pack ("<I" , block_number ) # blockNo
86
+ output += struct .pack ("<I" , num_blocks ) # numBlocks
87
+ output += struct .pack (
88
+ "<I" , family_id
89
+ ) # fileSize / familyID: rp2040/rp2350 family ID
73
90
74
91
# Data
75
92
if len (block ) < 476 :
76
- block += b' \0 ' * (476 - len (block ))
93
+ block += b" \0 " * (476 - len (block ))
77
94
output += block
78
95
79
96
# UF2_Block footer
80
- output += struct .pack ("<I" , 0x0AB16F30 ) # magicEnd
81
-
97
+ output += struct .pack ("<I" , 0x0AB16F30 ) # magicEnd
98
+
82
99
return output
83
100
84
- output = b''
101
+ output = b""
85
102
with open (args .input + ".bin" , "rb" ) as f :
86
103
if add_errata_block :
87
104
# RP2350-E10 errata
@@ -97,14 +114,20 @@ def emit_block(output, block, vmaddr, block_number, num_blocks, family_id):
97
114
block = f .read (256 )
98
115
if len (block ) == 0 :
99
116
break
100
- output = emit_block (output , block , vmaddr , block_number , num_blocks , family_id )
117
+ output = emit_block (
118
+ output , block , vmaddr , block_number , num_blocks , family_id
119
+ )
101
120
block_number += 1
102
121
vmaddr += 256
103
122
104
123
with open (args .output , "wb" ) as f :
105
124
f .write (output )
106
-
107
- print (f"Produced { args .output } with total size { len (output )} (0x{ len (output ):0x} ) bytes, payload size { total_size } (0x{ total_size :0x} ) bytes" )
108
125
109
- if __name__ == '__main__' :
126
+ print (
127
+ f"Produced { args .output } with total size { len (output )} (0x{ len (output ):0x} )"
128
+ f" bytes, payload size { total_size } (0x{ total_size :0x} ) bytes"
129
+ )
130
+
131
+
132
+ if __name__ == "__main__" :
110
133
main ()
0 commit comments