diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..c7b743c5 --- /dev/null +++ b/.flake8 @@ -0,0 +1,10 @@ +[flake8] + +ignore = + # These are needed to make our license headers pass the linting + E265, + E266, + +# 10% larger than the standard 80 character limit. Conforms to the black +# standard and Bugbear's B950. +max-line-length = 88 diff --git a/.github/workflows/build-esp.yml b/.github/workflows/build-esp.yml index 0def652e..b6efe03f 100644 --- a/.github/workflows/build-esp.yml +++ b/.github/workflows/build-esp.yml @@ -7,7 +7,7 @@ on: branches: ["main"] schedule: # Build on Mondays at 9am PST every week - - cron: '0 17 * * 1' + - cron: '0 17 * * 1' jobs: build-esp: diff --git a/.github/workflows/build-nuttx.yml b/.github/workflows/build-nuttx.yml index 952fc7ec..f9104e52 100644 --- a/.github/workflows/build-nuttx.yml +++ b/.github/workflows/build-nuttx.yml @@ -7,7 +7,7 @@ on: branches: ["main"] schedule: # Build on Mondays at 9am PST every week - - cron: '0 17 * * 1' + - cron: '0 17 * * 1' jobs: build-nuttx: diff --git a/.github/workflows/build-pico-sdk.yml b/.github/workflows/build-pico-sdk.yml index 06283bd6..67b76008 100644 --- a/.github/workflows/build-pico-sdk.yml +++ b/.github/workflows/build-pico-sdk.yml @@ -7,7 +7,7 @@ on: branches: ["main"] schedule: # Build on Mondays at 9am PST every week - - cron: '0 17 * * 1' + - cron: '0 17 * * 1' jobs: build-pico-sdk: diff --git a/.github/workflows/build-zephyr.yml b/.github/workflows/build-zephyr.yml index 0233f150..51b507ed 100644 --- a/.github/workflows/build-zephyr.yml +++ b/.github/workflows/build-zephyr.yml @@ -7,7 +7,7 @@ on: branches: ["main"] schedule: # Build on Mondays at 9am PST every week - - cron: '0 17 * * 1' + - cron: '0 17 * * 1' jobs: build-zephyr: diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 52009c0a..33b86f83 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -7,22 +7,26 @@ on: branches: ["main"] jobs: - lint: - name: Lint + validate_format_config: + name: Validate Format Config runs-on: ubuntu-latest - container: swift:6.0-jammy - steps: - name: Checkout repo uses: actions/checkout@v4 - name: Install apt dependencies - run: apt-get -qq update && apt-get -qq -y install curl + run: sudo apt-get -qq update && sudo apt-get -qq -y install curl - name: Compare against swift-mmio swift-format config run: | curl -sL https://raw.githubusercontent.com/apple/swift-mmio/refs/heads/main/.swift-format -o .swift-format-mmio diff .swift-format .swift-format-mmio - - name: Lint - run: swift-format lint --recursive --strict . + soundness: + name: Soundness + uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main + with: + api_breakage_check_enabled: false # this repo doesn't vend any API + license_header_check_enabled: false # feature: https://github.com/swiftlang/github-workflows/issues/78 + license_header_check_project_name: "Swift.org" # bug: https://github.com/swiftlang/github-workflows/issues/76 + unacceptable_language_check_enabled: false # unfortunately many hardware specs use terms like master/slave in their documentation diff --git a/Tools/macho2bin.py b/Tools/macho2bin.py index 9b348f38..6ba74b3c 100755 --- a/Tools/macho2bin.py +++ b/Tools/macho2bin.py @@ -8,36 +8,45 @@ # See https://swift.org/LICENSE.txt for license information # -# macho2bin -- Converts a statically-linked executable Mach-O into a flat "BIN" file suitable for flashing as a single -# contiguous blob onto some embedded devices. Note that this format assumes the embedded device can boot from a state -# where the entire firmware (all segments) are flashed contigously into one smalle address range. This is true for e.g. -# the STM32F746 devices if we place the vector table at 0x00200000, and code and data right after it, as the vector -# table also contains a pointer to the initial PC. This setup might not work for other devices. +# macho2bin -- Converts a statically-linked executable Mach-O into a flat "BIN" file +# suitable for flashing as a single contiguous blob onto some embedded devices. Note +# that this format assumes the embedded device can boot from a state where the entire +# firmware (all segments) are flashed contigously into one smalle address range. This +# is true for e.g. the STM32F746 devices if we place the vector table at 0x00200000, +# and code and data right after it, as the vector table also contains a pointer to the +# initial PC. This setup might not work for other devices. # # Usage: -# $ macho2bin.py --base-address --segments +# $ macho2bin.py --base-address --segments +# # # Example: -# $ macho2bin.py ./blink ./blink.bin --base-address 0x00200000 --segments '__TEXT,__DATA,__VECTORS' +# $ macho2bin.py ./blink ./blink.bin --base-address 0x00200000 --segments +# '__TEXT,__DATA,__VECTORS' # # Requirements and notes: -# * The output BIN file is a flat contiguous representation of the segments (--segments) based on their VM addresses. -# * The BIN file's first byte corresponds to the specified base address (--base-address). +# * The output BIN file is a flat contiguous representation of the segments +# (--segments) based on their VM addresses. +# * The BIN file's first byte corresponds to the specified base address +# (--base-address). # * Any gaps between segments are filled with zero bytes. -# * Because of that, you want the input Mach-O to have all segments "close", and not have gaps. +# * Because of that, you want the input Mach-O to have all segments "close", and not +# have gaps. # import argparse import os + from macholib import MachO from macholib import mach_o + def main(): parser = argparse.ArgumentParser() - parser.add_argument('input') - parser.add_argument('output') - parser.add_argument('--base-address', required=True) - parser.add_argument('--segments', required=True) + parser.add_argument("input") + parser.add_argument("output") + parser.add_argument("--base-address", required=True) + parser.add_argument("--segments", required=True) args = parser.parse_args() args.base_address = int(args.base_address, 16) args.segments = args.segments.split(",") @@ -49,17 +58,23 @@ def main(): for command in mh.commands: if isinstance(command[1], mach_o.segment_command): (_, segment, sections) = command - segname = segment.segname.decode().strip('\0') - if segname not in args.segments: continue + segname = segment.segname.decode().strip("\0") + if segname not in args.segments: + continue with open(args.input, "rb") as f: f.seek(mh.offset + segment.fileoff) data = f.read(segment.filesize) - segments.append({"vmaddr": segment.vmaddr, "data": data, "name": segname}) - + segments.append( + {"vmaddr": segment.vmaddr, "data": data, "name": segname} + ) + segments = sorted(segments, key=lambda x: x["vmaddr"]) - assert segments[0]["vmaddr"] == args.base_address, f"first segment's vmaddr 0x{segments[0]['vmaddr']:08x} does not match the passed --base-address 0x{args.base_address:08x}" + assert segments[0]["vmaddr"] == args.base_address, ( + f"first segment's vmaddr 0x{segments[0]['vmaddr']:08x} does not match the" + f" passed --base-address 0x{args.base_address:08x}" + ) if os.path.exists(args.output): os.unlink(args.output) @@ -69,15 +84,22 @@ def main(): for segment in segments: gap = segment["vmaddr"] - vmaddr if gap != 0: - print(f"Writing gap of size {gap} (0x{gap:0x}) at vmaddr 0x{vmaddr:08x}") - f.write(b'\0' * gap) + print( + f"Writing gap of size {gap} (0x{gap:0x}) at vmaddr 0x{vmaddr:08x}" + ) + f.write(b"\0" * gap) assert gap >= 0 vmaddr = segment["vmaddr"] - print(f"Writing segment {segment['name']} size {len(segment['data'])} (0x{len(segment['data']):x}) at vmaddr 0x{vmaddr:08x}") + print( + f"Writing segment {segment['name']} size" + f" {len(segment['data'])} (0x{len(segment['data']):x}) at vmaddr" + f" 0x{vmaddr:08x}" + ) f.write(segment["data"]) vmaddr = segment["vmaddr"] + len(segment["data"]) print(f"Produced {args.output} with {vmaddr - args.base_address} bytes") -if __name__ == '__main__': + +if __name__ == "__main__": main() diff --git a/Tools/macho2uf2.py b/Tools/macho2uf2.py index f0812e0b..5043b4a8 100755 --- a/Tools/macho2uf2.py +++ b/Tools/macho2uf2.py @@ -8,39 +8,44 @@ # See https://swift.org/LICENSE.txt for license information # -# macho2uf2 -- Converts a statically-linked executable Mach-O into a flat "UF2" file suitable for flashing as a single -# contiguous blob onto some embedded devices, in particular Raspberry Pi Pico (W). Note that the UF2 format allows for -# discontiguous memory regions, but this utility does not support that. +# macho2uf2 -- Converts a statically-linked executable Mach-O into a flat "UF2" file +# suitable for flashing as a single contiguous blob onto some embedded devices, in +# particular Raspberry Pi Pico (W). Note that the UF2 format allows for discontiguous +# memory regions, but this utility does not support that. # # Usage: -# $ macho2uf2.py --base-address --segments +# $ macho2uf2.py --base-address --segments +# # # Example: -# $ macho2uf2.py ./blink ./blink.uf2 --base-address 0x00200000 --segments '__TEXT,__DATA,__VECTORS' +# $ macho2uf2.py ./blink ./blink.uf2 --base-address 0x00200000 --segments +# '__TEXT,__DATA,__VECTORS' # # Requirements and notes: -# * The output UF2 file is a flat contiguous representation of the segments (--segments) based on their VM addresses. -# * The UF2 file's first byte corresponds to the specified base address (--base-address). +# * The output UF2 file is a flat contiguous representation of the segments +# (--segments) based on their VM addresses. +# * The UF2 file's first byte corresponds to the specified base address +# (--base-address). # * Any gaps between segments are filled with zero bytes. -# * Because of that, you want the input Mach-O to have all segments "close", and not have gaps. +# * Because of that, you want the input Mach-O to have all segments "close", and not +# have gaps. # import argparse import os -import subprocess import struct -from macholib import MachO -from macholib import mach_o +import subprocess MY_DIR = os.path.dirname(os.path.abspath(__file__)) + def main(): parser = argparse.ArgumentParser() - parser.add_argument('input') - parser.add_argument('output') - parser.add_argument('--base-address', required=True) - parser.add_argument('--segments', required=True) - parser.add_argument('--pico-family', required=True) + parser.add_argument("input") + parser.add_argument("output") + parser.add_argument("--base-address", required=True) + parser.add_argument("--segments", required=True) + parser.add_argument("--pico-family", required=True) args = parser.parse_args() args.base_address = int(args.base_address, 16) args.segments = args.segments.split(",") @@ -48,40 +53,52 @@ def main(): family_id = 0xE48BFF56 add_errata_block = False elif args.pico_family == "rp2350": - family_id = 0XE48BFF59 + family_id = 0xE48BFF59 add_errata_block = True else: assert False - subprocess.check_call([MY_DIR + "/macho2bin.py", args.input, args.input + ".bin", "--base-address", "0x%08x" % args.base_address, "--segments", ",".join(args.segments)]) + subprocess.check_call( + [ + MY_DIR + "/macho2bin.py", + args.input, + args.input + ".bin", + "--base-address", + "0x%08x" % args.base_address, + "--segments", + ",".join(args.segments), + ] + ) def emit_block(output, block, vmaddr, block_number, num_blocks, family_id): assert len(block) <= 256 - + if len(block) < 256: - block += b'\0' * (256 - len(block)) - + block += b"\0" * (256 - len(block)) + # UF2_Block header - output += struct.pack("