Skip to content

Adopt swiftlang soundness workflow #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jan 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion .github/workflows/build-esp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-nuttx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-pico-sdk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build-zephyr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
18 changes: 11 additions & 7 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
68 changes: 45 additions & 23 deletions Tools/macho2bin.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 <input> <output> --base-address <base-address> --segments <segment-list>
# $ macho2bin.py <input> <output> --base-address <base-address> --segments
# <segment-list>
#
# 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(",")
Expand All @@ -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)
Expand All @@ -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()
97 changes: 60 additions & 37 deletions Tools/macho2uf2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,80 +8,97 @@
# 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 <input> <output> --base-address <base-address> --segments <segment-list>
# $ macho2uf2.py <input> <output> --base-address <base-address> --segments
# <segment-list>
#
# 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(",")
if args.pico_family == "rp2040":
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("<I", 0x0A324655) # magicStart0
output += struct.pack("<I", 0x9E5D5157) # magicStart1
output += struct.pack("<I", 0x2000) # flags: familyID present
output += struct.pack("<I", vmaddr) # targetAddr
output += struct.pack("<I", 256) # payloadSize
output += struct.pack("<I", block_number) # blockNo
output += struct.pack("<I", num_blocks) # numBlocks
output += struct.pack("<I", family_id) # fileSize / familyID: rp2040/rp2350 family ID
output += struct.pack("<I", 0x0A324655) # magicStart0
output += struct.pack("<I", 0x9E5D5157) # magicStart1
output += struct.pack("<I", 0x2000) # flags: familyID present
output += struct.pack("<I", vmaddr) # targetAddr
output += struct.pack("<I", 256) # payloadSize
output += struct.pack("<I", block_number) # blockNo
output += struct.pack("<I", num_blocks) # numBlocks
output += struct.pack(
"<I", family_id
) # fileSize / familyID: rp2040/rp2350 family ID

# Data
if len(block) < 476:
block += b'\0' * (476 - len(block))
block += b"\0" * (476 - len(block))
output += block

# UF2_Block footer
output += struct.pack("<I", 0x0AB16F30) # magicEnd
output += struct.pack("<I", 0x0AB16F30) # magicEnd

return output

output = b''
output = b""
with open(args.input + ".bin", "rb") as f:
if add_errata_block:
# RP2350-E10 errata
Expand All @@ -97,14 +114,20 @@ def emit_block(output, block, vmaddr, block_number, num_blocks, family_id):
block = f.read(256)
if len(block) == 0:
break
output = emit_block(output, block, vmaddr, block_number, num_blocks, family_id)
output = emit_block(
output, block, vmaddr, block_number, num_blocks, family_id
)
block_number += 1
vmaddr += 256

with open(args.output, "wb") as f:
f.write(output)

print(f"Produced {args.output} with total size {len(output)} (0x{len(output):0x}) bytes, payload size {total_size} (0x{total_size:0x}) bytes")

if __name__ == '__main__':
print(
f"Produced {args.output} with total size {len(output)} (0x{len(output):0x})"
f" bytes, payload size {total_size} (0x{total_size:0x}) bytes"
)


if __name__ == "__main__":
main()
4 changes: 2 additions & 2 deletions nrfx-blink-sdk/west.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ manifest:
revision: main
import:
name-allowlist:
- cmsis # required by the ARM port
- hal_nordic # required by the custom_plank board (Nordic based)
- cmsis # required by the ARM port
- hal_nordic # required by the custom_plank board (Nordic based)
Loading
Loading