diff --git a/.github/workflows/build-rpi-baremetal.yml b/.github/workflows/build-rpi-baremetal.yml index 6f3e6913..d556946d 100644 --- a/.github/workflows/build-rpi-baremetal.yml +++ b/.github/workflows/build-rpi-baremetal.yml @@ -2,7 +2,7 @@ name: Raspberry Pi Baremetal on: push: - branches: ["main"] + branches: ["main", "RPi-4B-BCM2711"] pull_request: types: [opened, reopened, synchronize, ready_for_review] @@ -29,3 +29,11 @@ jobs: - name: Build ${{ matrix.example }} working-directory: ${{ matrix.example }} run: make + + - name: Upload build files artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.example }}-binary + path: | + ${{ matrix.example }}/kernel8* + retention-days: 30 diff --git a/Tools/Toolsets/rpi-5-elf.json b/Tools/Toolsets/rpi-5-elf.json new file mode 100644 index 00000000..88d9a133 --- /dev/null +++ b/Tools/Toolsets/rpi-5-elf.json @@ -0,0 +1,19 @@ +{ + "schemaVersion": "1.0", + "swiftCompiler": { + "extraCLIOptions": [ + "-Xfrontend", "-disable-stack-protector", + "-Xfrontend", "-function-sections", + "-enable-experimental-feature", "Embedded", + "-Xfrontend", "-mergeable-symbols", + "-Xclang-linker", "-fuse-ld=lld", + "-Xclang-linker", "-nostdlib" + ] + }, + "linker": { + "extraCLIOptions": [ + "-T", "Sources/Support/linkerscript.ld", + "--unresolved-symbols=ignore-in-object-files" + ] + } +} diff --git a/rpi-4b-blink/Makefile b/rpi-4b-blink/Makefile index da37442b..77b7f29d 100644 --- a/rpi-4b-blink/Makefile +++ b/rpi-4b-blink/Makefile @@ -1,28 +1,47 @@ -SWIFT_EXEC ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f swift; else which swift; fi) -CLANG ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f clang; else which clang; fi) -LLVM_OBJCOPY ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f llvm-objcopy; else which llvm-objcopy; fi) +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) 2025 Apple Inc. and the Swift project authors. +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## +##===----------------------------------------------------------------------===## -BUILDROOT := $(shell $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector --show-bin-path) +# Paths +REPOROOT := $(shell git rev-parse --show-toplevel) +TOOLSROOT := $(REPOROOT)/Tools +TOOLSET := $(TOOLSROOT)/Toolsets/rpi-5-elf.json +LLVM_OBJCOPY := llvm-objcopy +SWIFT_BUILD := swift build -.PHONY: all clean +# Flags +ARCH := aarch64 +TARGET := $(ARCH)-none-none-elf +SWIFT_BUILD_ARGS := \ + --configuration release \ + --triple $(TARGET) \ + --toolset $(TOOLSET) \ + --disable-local-rpath +BUILDROOT := $(shell $(SWIFT_BUILD) $(SWIFT_BUILD_ARGS) --show-bin-path) -all: kernel8.img +.PHONY: build +build: + @echo "building..." + $(SWIFT_BUILD) \ + $(SWIFT_BUILD_ARGS) \ + --verbose -kernel8.img: kernel8.elf - @echo "💾 Converting to binary kernel image with llvm-objcopy..." - $(LLVM_OBJCOPY) -O binary kernel8.elf kernel8.img - @echo "" - @echo "🥳 Done! kernel8.img was saved to this directory." + @echo "extracting binary..." + $(LLVM_OBJCOPY) \ + -O binary \ + "$(BUILDROOT)/Application" \ + "$(BUILDROOT)/Application.bin" \ -kernel8.elf: $(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o link.ld - @echo "🔗 Linking with clang..." - $(CLANG) --target=aarch64-elf -o kernel8.elf $< $^ -fuse-ld=lld -nostdlib -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-T ./link.ld - @echo "" - -$(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o: - @echo "🛠️ Building with Swift Package Manager..." - $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector - @echo "" +.PHONY: clean clean: - rm -rf kernel8.elf kernel8.img .build \ No newline at end of file + @echo "cleaning..." + @swift package clean + @rm -rf .build diff --git a/rpi-4b-blink/Package.resolved b/rpi-4b-blink/Package.resolved index 6b4a420f..bfffc5ae 100644 --- a/rpi-4b-blink/Package.resolved +++ b/rpi-4b-blink/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "34c5bcbd964b6dde904b1ee02c0f89612b6ec5884ebfe47bfe412daefc0becd4", + "originHash" : "d0330fea11b0fbdacbddd4f13debd9a4fe72ed5b628ad4959a93972f3572bf1f", "pins" : [ { "identity" : "swift-argument-parser", @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-mmio.git", "state" : { - "branch" : "swift-embedded-examples", - "revision" : "06d96ed4916739f2edafde87f3951b2d2a04df65" + "branch" : "main", + "revision" : "5232c5129a8c70beafc3d6acfbae2716c1b6822a" } }, { diff --git a/rpi-4b-blink/Package.swift b/rpi-4b-blink/Package.swift index 05fd6188..9ecee432 100644 --- a/rpi-4b-blink/Package.swift +++ b/rpi-4b-blink/Package.swift @@ -3,33 +3,18 @@ import PackageDescription let package = Package( - name: "RPi4B-Blink", - platforms: [ - .macOS(.v14) - ], + name: "rpi-4b-blink", products: [ - .library( - name: "MainApp", - type: .static, - targets: ["MainApp"]) + .executable(name: "Application", targets: ["Application"]) ], dependencies: [ - .package( - url: "https://github.com/apple/swift-mmio.git", - branch: "swift-embedded-examples") + .package(url: "https://github.com/apple/swift-mmio.git", branch: "main") ], targets: [ - .target( - name: "MainApp", + .executableTarget( + name: "Application", dependencies: [ .product(name: "MMIO", package: "swift-mmio") - ], - swiftSettings: [ - .enableExperimentalFeature("Embedded"), - .unsafeFlags(["-Xfrontend", "-function-sections"]), - ] - ), + ]), .target(name: "Support"), - - ] -) + ]) diff --git a/rpi-4b-blink/README.md b/rpi-4b-blink/README.md index 1afa751a..a2613709 100644 --- a/rpi-4b-blink/README.md +++ b/rpi-4b-blink/README.md @@ -14,11 +14,9 @@ - Build the program, then copy the kernel image to the SD card. ``` console $ cd rpi-4b-blink -$ export TOOLCHAINS='' # Your Swift nightly toolchain identifier $ make $ cp kernel8.img /Volumes/bootfs ``` - If your original OS is not 64-bit, make sure to set `arm_64bit=1` in `config.txt`. - Place the SD card in your Raspberry Pi 4B, and connect it to power. - After the boot sequence, the green (ACT) led will start blinking in a regular pattern. - diff --git a/rpi-4b-blink/Sources/Application/Application.swift b/rpi-4b-blink/Sources/Application/Application.swift new file mode 100644 index 00000000..77da587a --- /dev/null +++ b/rpi-4b-blink/Sources/Application/Application.swift @@ -0,0 +1,80 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +import MMIO + +@Register(bitWidth: 32) +struct GPSET1 { + @ReadWrite(bits: 10..<11, as: Bool.self) + var set: SET +} + +@Register(bitWidth: 32) +struct GPCLR1 { + @ReadWrite(bits: 10..<11, as: Bool.self) + var clear: CLEAR +} + +@Register(bitWidth: 32) +struct GPFSEL4 { + @ReadWrite(bits: 6..<7, as: Bool.self) + var fsel42b1: FSEL42b1 + @ReadWrite(bits: 7..<8, as: Bool.self) + var fsel42b2: FSEL42b2 + @ReadWrite(bits: 8..<9, as: Bool.self) + var fsel42b3: FSEL42b3 +} + +@RegisterBlock +struct GPIO { + @RegisterBlock(offset: 0x200020) + var gpset1: Register + @RegisterBlock(offset: 0x20002c) + var gpclr1: Register + @RegisterBlock(offset: 0x200010) + var gpfsel4: Register +} + +let gpio = GPIO(unsafeAddress: 0xFE00_0000) + +func setLedOutput() { + gpio.gpfsel4.modify { + // setFunction Select 42 (fsel42) to 001 + $0.fsel42b1 = true + $0.fsel42b2 = false + $0.fsel42b3 = false + } +} + +func ledOn() { + gpio.gpset1.modify { + $0.set = true + } +} + +func ledOff() { + gpio.gpclr1.modify { + $0.clear = true + } +} + +@main +struct Application { + static func main() { + setLedOutput() + while true { + ledOn() + for _ in 1..<100000 {} // just a delay + ledOff() + for _ in 1..<100000 {} // just a delay + } + } +} diff --git a/rpi-4b-blink/link.ld b/rpi-4b-blink/Sources/Support/linkerscript.ld similarity index 100% rename from rpi-4b-blink/link.ld rename to rpi-4b-blink/Sources/Support/linkerscript.ld diff --git a/rpi-5-blink/Makefile b/rpi-5-blink/Makefile index da37442b..77b7f29d 100644 --- a/rpi-5-blink/Makefile +++ b/rpi-5-blink/Makefile @@ -1,28 +1,47 @@ -SWIFT_EXEC ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f swift; else which swift; fi) -CLANG ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f clang; else which clang; fi) -LLVM_OBJCOPY ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f llvm-objcopy; else which llvm-objcopy; fi) +##===----------------------------------------------------------------------===## +## +## This source file is part of the Swift open source project +## +## Copyright (c) 2025 Apple Inc. and the Swift project authors. +## Licensed under Apache License v2.0 with Runtime Library Exception +## +## See https://swift.org/LICENSE.txt for license information +## +##===----------------------------------------------------------------------===## -BUILDROOT := $(shell $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector --show-bin-path) +# Paths +REPOROOT := $(shell git rev-parse --show-toplevel) +TOOLSROOT := $(REPOROOT)/Tools +TOOLSET := $(TOOLSROOT)/Toolsets/rpi-5-elf.json +LLVM_OBJCOPY := llvm-objcopy +SWIFT_BUILD := swift build -.PHONY: all clean +# Flags +ARCH := aarch64 +TARGET := $(ARCH)-none-none-elf +SWIFT_BUILD_ARGS := \ + --configuration release \ + --triple $(TARGET) \ + --toolset $(TOOLSET) \ + --disable-local-rpath +BUILDROOT := $(shell $(SWIFT_BUILD) $(SWIFT_BUILD_ARGS) --show-bin-path) -all: kernel8.img +.PHONY: build +build: + @echo "building..." + $(SWIFT_BUILD) \ + $(SWIFT_BUILD_ARGS) \ + --verbose -kernel8.img: kernel8.elf - @echo "💾 Converting to binary kernel image with llvm-objcopy..." - $(LLVM_OBJCOPY) -O binary kernel8.elf kernel8.img - @echo "" - @echo "🥳 Done! kernel8.img was saved to this directory." + @echo "extracting binary..." + $(LLVM_OBJCOPY) \ + -O binary \ + "$(BUILDROOT)/Application" \ + "$(BUILDROOT)/Application.bin" \ -kernel8.elf: $(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o link.ld - @echo "🔗 Linking with clang..." - $(CLANG) --target=aarch64-elf -o kernel8.elf $< $^ -fuse-ld=lld -nostdlib -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-T ./link.ld - @echo "" - -$(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o: - @echo "🛠️ Building with Swift Package Manager..." - $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector - @echo "" +.PHONY: clean clean: - rm -rf kernel8.elf kernel8.img .build \ No newline at end of file + @echo "cleaning..." + @swift package clean + @rm -rf .build diff --git a/rpi-5-blink/Package.resolved b/rpi-5-blink/Package.resolved index 1a6f57c0..4cf1835e 100644 --- a/rpi-5-blink/Package.resolved +++ b/rpi-5-blink/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "193ca3f107e2c8dd2da5d091f6259f64b2cbfd6776d1c26bbcfb195b3a0b5045", + "originHash" : "5bb00fe2bf59115297c70799769d8080cf6ce836d32f4a41d42e7c420afddec6", "pins" : [ { "identity" : "swift-argument-parser", @@ -15,8 +15,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-mmio.git", "state" : { - "branch" : "swift-embedded-examples", - "revision" : "06d96ed4916739f2edafde87f3951b2d2a04df65" + "branch" : "main", + "revision" : "5232c5129a8c70beafc3d6acfbae2716c1b6822a" } }, { diff --git a/rpi-5-blink/Package.swift b/rpi-5-blink/Package.swift index 90371cef..ff8d614e 100644 --- a/rpi-5-blink/Package.swift +++ b/rpi-5-blink/Package.swift @@ -3,33 +3,19 @@ import PackageDescription let package = Package( - name: "RPi5-Blink", - platforms: [ - .macOS(.v14) - ], + name: "rpi-5-blink", products: [ - .library( - name: "MainApp", - type: .static, - targets: ["MainApp"]) + .executable(name: "Application", targets: ["Application"]) ], dependencies: [ - .package( - url: "https://github.com/apple/swift-mmio.git", - branch: "swift-embedded-examples") + .package(url: "https://github.com/apple/swift-mmio.git", branch: "main") ], targets: [ - .target( - name: "MainApp", + .executableTarget( + name: "Application", dependencies: [ - .product(name: "MMIO", package: "swift-mmio") - ], - swiftSettings: [ - .enableExperimentalFeature("Embedded"), - .unsafeFlags(["-Xfrontend", "-function-sections"]), - ] - ), + .product(name: "MMIO", package: "swift-mmio"), + "Support" + ]), .target(name: "Support"), - - ] -) + ]) diff --git a/rpi-5-blink/README.md b/rpi-5-blink/README.md index 09872c0c..bed37e98 100644 --- a/rpi-5-blink/README.md +++ b/rpi-5-blink/README.md @@ -14,7 +14,6 @@ - Build the program, then copy the kernel image to the SD card. ``` console $ cd rpi-5-blink -$ export TOOLCHAINS='' # Your Swift nightly toolchain identifier $ make $ cp kernel8.img /Volumes/bootfs # Copy kernel image to SD card $ rm /Volumes/bootfs/kernel_2712.img # Delete this kernel image so our kernel8.img is used @@ -22,4 +21,3 @@ $ # You can also rename our kernel8.img to kernel_2712.img, or set it to anythin ``` - Place the SD card in your Raspberry Pi 5, and connect it to power. - After the boot sequence, the green (ACT) led will start blinking in a regular pattern. - diff --git a/rpi-5-blink/Sources/Application/Application.swift b/rpi-5-blink/Sources/Application/Application.swift new file mode 100644 index 00000000..d0f98eb4 --- /dev/null +++ b/rpi-5-blink/Sources/Application/Application.swift @@ -0,0 +1,54 @@ +import MMIO + +@Register(bitWidth: 32) +struct GIOIODIR { + @ReadWrite(bits: 9..<10, as: Bool.self) + var direction: DIRECTION +} + +@Register(bitWidth: 32) +struct GIODATA { + @ReadWrite(bits: 9..<10, as: Bool.self) + var value: VALUE +} + +@RegisterBlock +struct GPIO { + @RegisterBlock(offset: 0x00008) + var gioiodir: Register + @RegisterBlock(offset: 0x00004) + var giodata: Register +} + +let gpio = GPIO(unsafeAddress: 0x10_7d51_7c00) + +func setLedOutput() { + gpio.gioiodir.modify { + $0.direction = false // 0 is output, 1 is input + } +} + +func ledOn() { + gpio.giodata.modify { + $0.value = true // pin on + } +} + +func ledOff() { + gpio.giodata.modify { + $0.value = false // pin off + } +} + +@main +struct Application { + static func main() { + setLedOutput() + while true { + ledOn() + for _ in 1..<100000 {} // just a delay + ledOff() + for _ in 1..<100000 {} // just a delay + } + } +} diff --git a/rpi-5-blink/link.ld b/rpi-5-blink/Sources/Support/linkerscript.ld similarity index 100% rename from rpi-5-blink/link.ld rename to rpi-5-blink/Sources/Support/linkerscript.ld diff --git a/rpi4b-blink/Makefile b/rpi4b-blink/Makefile new file mode 100644 index 00000000..da37442b --- /dev/null +++ b/rpi4b-blink/Makefile @@ -0,0 +1,28 @@ +SWIFT_EXEC ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f swift; else which swift; fi) +CLANG ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f clang; else which clang; fi) +LLVM_OBJCOPY ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f llvm-objcopy; else which llvm-objcopy; fi) + +BUILDROOT := $(shell $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector --show-bin-path) + +.PHONY: all clean + +all: kernel8.img + +kernel8.img: kernel8.elf + @echo "💾 Converting to binary kernel image with llvm-objcopy..." + $(LLVM_OBJCOPY) -O binary kernel8.elf kernel8.img + @echo "" + @echo "🥳 Done! kernel8.img was saved to this directory." + +kernel8.elf: $(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o link.ld + @echo "🔗 Linking with clang..." + $(CLANG) --target=aarch64-elf -o kernel8.elf $< $^ -fuse-ld=lld -nostdlib -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-T ./link.ld + @echo "" + +$(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o: + @echo "🛠️ Building with Swift Package Manager..." + $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector + @echo "" + +clean: + rm -rf kernel8.elf kernel8.img .build \ No newline at end of file diff --git a/rpi4b-blink/Package.swift b/rpi4b-blink/Package.swift new file mode 100644 index 00000000..f004c0b8 --- /dev/null +++ b/rpi4b-blink/Package.swift @@ -0,0 +1,36 @@ +// swift-tools-version: 6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "RPi4B-Blink", + platforms: [ + .macOS(.v14) + ], + products: [ + .library( + name: "MainApp", + type: .static, + targets: ["MainApp"]) + ], + dependencies: [ + .package( + url: "https://github.com/apple/swift-mmio.git", + branch: "swift-embedded-examples") + ], + targets: [ + .target( + name: "MainApp", + dependencies: [ + .product(name: "MMIO", package: "swift-mmio") + ], + swiftSettings: [ + .enableExperimentalFeature("Embedded"), + .unsafeFlags(["-Xfrontend", "-function-sections"]), + ] + ), + .target(name: "Support"), + + ] +) diff --git a/rpi4b-blink/README.md b/rpi4b-blink/README.md new file mode 100644 index 00000000..b68de6a5 --- /dev/null +++ b/rpi4b-blink/README.md @@ -0,0 +1,24 @@ +# rpi4b-blink + + + +## Requirements + +- A Raspberry Pi 4B board +- An SD Card, with a Raspberry Pi OS installed (this way, we don't need to create the configuration files from scratch). You may backup `kernel8.img` and `config.txt` if you need the Linux install later, since we will change these files. +- LLVM installed (`brew install llvm`) and added to PATH. This is needed to convert the resulted ELF file to binary image format using `llvm-objcopy`. + +## How to build and run this example: + +- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support. +- Build the program, then copy the kernel image to the SD card. +``` console +$ cd rpi4b-blink +$ export TOOLCHAINS='' # Your Swift nightly toolchain identifier +$ make +$ cp kernel8.img /Volumes/bootfs +``` +- If your original OS is not 64-bit, make sure to set `arm_64bit=1` in `config.txt`. +- Place the SD card in your Raspberry Pi 4B, and connect it to power. +- After the boot sequence, the green (ACT) led will start blinking in a regular pattern. + diff --git a/rpi-4b-blink/Sources/MainApp/MainApp.swift b/rpi4b-blink/Sources/MainApp/MainApp.swift similarity index 100% rename from rpi-4b-blink/Sources/MainApp/MainApp.swift rename to rpi4b-blink/Sources/MainApp/MainApp.swift diff --git a/rpi4b-blink/Sources/Support/boot.S b/rpi4b-blink/Sources/Support/boot.S new file mode 100644 index 00000000..0a8f8c39 --- /dev/null +++ b/rpi4b-blink/Sources/Support/boot.S @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +.section ".text.boot" + +.global _start + +_start: + // Check processor ID is zero (executing on main core), else hang + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // We're not on the main core, so hang in an infinite wait loop +1: wfe + b 1b +2: // We're on the main core! + + // Set stack to start below our code + ldr x1, =_start + mov sp, x1 + + // Clean the BSS section + ldr x1, =__bss_start // Start address + ldr w2, =__bss_size // Size of the section +3: cbz w2, 4f // Quit loop if zero + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b // Loop if non-zero + + // Jump to Swift! +4: bl main + // Halt if Swift returns + b 1b diff --git a/rpi4b-blink/Sources/Support/include/boot.h b/rpi4b-blink/Sources/Support/include/boot.h new file mode 100644 index 00000000..e69de29b diff --git a/rpi4b-blink/assets/rpi4.png b/rpi4b-blink/assets/rpi4.png new file mode 100644 index 00000000..1df6f1c3 Binary files /dev/null and b/rpi4b-blink/assets/rpi4.png differ diff --git a/rpi4b-blink/link.ld b/rpi4b-blink/link.ld new file mode 100644 index 00000000..dfbf0227 --- /dev/null +++ b/rpi4b-blink/link.ld @@ -0,0 +1,19 @@ +SECTIONS +{ + . = 0x80000; /* Kernel load address for AArch64 */ + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3; diff --git a/rpi5-blink/Makefile b/rpi5-blink/Makefile new file mode 100644 index 00000000..a86daf9f --- /dev/null +++ b/rpi5-blink/Makefile @@ -0,0 +1,28 @@ +SWIFT_EXEC ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f swift; else which swift; fi) +CLANG ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f clang; else which clang; fi) +LLVM_OBJCOPY ?= $(shell if [ "$(shell uname)" = "Darwin" ]; then xcrun -f llvm-objcopy; else which llvm-objcopy; fi) + +BUILDROOT := $(shell $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector --show-bin-path) + +.PHONY: all clean + +all: kernel8.img + +kernel8.img: kernel8.elf + @echo "💾 Converting to binary kernel image with llvm-objcopy..." + $(LLVM_OBJCOPY) -O binary kernel8.elf kernel8.img + @echo "" + @echo "🥳 Done! kernel8.img was saved to this directory." + +kernel8.elf: $(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o link.ld + @echo "🔗 Linking with clang..." + $(CLANG) -c release --target=aarch64-elf -o kernel8.elf $< $^ -fuse-ld=lld -nostdlib -Wl,--unresolved-symbols=ignore-in-object-files -Wl,-T ./link.ld + @echo "" + +$(BUILDROOT)/libMainApp.a $(BUILDROOT)/Support.build/boot.S.o: + @echo "🛠️ Building with Swift Package Manager..." + $(SWIFT_EXEC) build --triple aarch64-none-none-elf -Xswiftc -Xfrontend -Xswiftc -disable-stack-protector + @echo "" + +clean: + rm -rf kernel8.elf kernel8.img .build diff --git a/rpi5-blink/Package.resolved b/rpi5-blink/Package.resolved new file mode 100644 index 00000000..1a6f57c0 --- /dev/null +++ b/rpi5-blink/Package.resolved @@ -0,0 +1,33 @@ +{ + "originHash" : "193ca3f107e2c8dd2da5d091f6259f64b2cbfd6776d1c26bbcfb195b3a0b5045", + "pins" : [ + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "41982a3656a71c768319979febd796c6fd111d5c", + "version" : "1.5.0" + } + }, + { + "identity" : "swift-mmio", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-mmio.git", + "state" : { + "branch" : "swift-embedded-examples", + "revision" : "06d96ed4916739f2edafde87f3951b2d2a04df65" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/swiftlang/swift-syntax.git", + "state" : { + "revision" : "0687f71944021d616d34d922343dcef086855920", + "version" : "600.0.1" + } + } + ], + "version" : 3 +} diff --git a/rpi5-blink/Package.swift b/rpi5-blink/Package.swift new file mode 100644 index 00000000..a01f42ef --- /dev/null +++ b/rpi5-blink/Package.swift @@ -0,0 +1,36 @@ +// swift-tools-version: 6.1 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "RPi5-Blink", + platforms: [ + .macOS(.v14) + ], + products: [ + .library( + name: "MainApp", + type: .static, + targets: ["MainApp"]) + ], + dependencies: [ + .package( + url: "https://github.com/apple/swift-mmio.git", + branch: "swift-embedded-examples") + ], + targets: [ + .target( + name: "MainApp", + dependencies: [ + .product(name: "MMIO", package: "swift-mmio") + ], + swiftSettings: [ + .enableExperimentalFeature("Embedded"), + .unsafeFlags(["-Xfrontend", "-function-sections"]), + ] + ), + .target(name: "Support"), + + ] +) diff --git a/rpi5-blink/README.md b/rpi5-blink/README.md new file mode 100644 index 00000000..49c200b2 --- /dev/null +++ b/rpi5-blink/README.md @@ -0,0 +1,25 @@ +# rpi5-blink + + + +## Requirements + +- A Raspberry Pi 5 board +- An SD Card, with a Raspberry Pi OS installed (this way, we don't need to create the configuration files from scratch). You may backup `kernel8.img` and `kernel_2712.img` if you need the Linux install later, since we will change these files. +- LLVM installed (`brew install llvm`) and added to PATH. This is needed to convert the resulted ELF file to binary image format using `llvm-objcopy`. + +## How to build and run this example: + +- Make sure you have a recent nightly Swift toolchain that has Embedded Swift support. +- Build the program, then copy the kernel image to the SD card. +``` console +$ cd rpi5-blink +$ export TOOLCHAINS='' # Your Swift nightly toolchain identifier +$ make +$ cp kernel8.img /Volumes/bootfs # Copy kernel image to SD card +$ rm /Volumes/bootfs/kernel_2712.img # Delete this kernel image so our kernel8.img is used +$ # You can also rename our kernel8.img to kernel_2712.img, or set it to anything you want and specify "kernel=[your-img-name]" in config.txt. +``` +- Place the SD card in your Raspberry Pi 5, and connect it to power. +- After the boot sequence, the green (ACT) led will start blinking in a regular pattern. + diff --git a/rpi-5-blink/Sources/MainApp/MainApp.swift b/rpi5-blink/Sources/MainApp/MainApp.swift similarity index 100% rename from rpi-5-blink/Sources/MainApp/MainApp.swift rename to rpi5-blink/Sources/MainApp/MainApp.swift diff --git a/rpi5-blink/Sources/Support/boot.S b/rpi5-blink/Sources/Support/boot.S new file mode 100644 index 00000000..0a8f8c39 --- /dev/null +++ b/rpi5-blink/Sources/Support/boot.S @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift open source project +// +// Copyright (c) 2024 Apple Inc. and the Swift project authors. +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// +//===----------------------------------------------------------------------===// + +.section ".text.boot" + +.global _start + +_start: + // Check processor ID is zero (executing on main core), else hang + mrs x1, mpidr_el1 + and x1, x1, #3 + cbz x1, 2f + // We're not on the main core, so hang in an infinite wait loop +1: wfe + b 1b +2: // We're on the main core! + + // Set stack to start below our code + ldr x1, =_start + mov sp, x1 + + // Clean the BSS section + ldr x1, =__bss_start // Start address + ldr w2, =__bss_size // Size of the section +3: cbz w2, 4f // Quit loop if zero + str xzr, [x1], #8 + sub w2, w2, #1 + cbnz w2, 3b // Loop if non-zero + + // Jump to Swift! +4: bl main + // Halt if Swift returns + b 1b diff --git a/rpi5-blink/Sources/Support/include/boot.h b/rpi5-blink/Sources/Support/include/boot.h new file mode 100644 index 00000000..e69de29b diff --git a/rpi5-blink/assets/raspi5.png b/rpi5-blink/assets/raspi5.png new file mode 100644 index 00000000..3fb4451f Binary files /dev/null and b/rpi5-blink/assets/raspi5.png differ diff --git a/rpi5-blink/link.ld b/rpi5-blink/link.ld new file mode 100644 index 00000000..dfbf0227 --- /dev/null +++ b/rpi5-blink/link.ld @@ -0,0 +1,19 @@ +SECTIONS +{ + . = 0x80000; /* Kernel load address for AArch64 */ + .text : { KEEP(*(.text.boot)) *(.text .text.* .gnu.linkonce.t*) } + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r*) } + PROVIDE(_data = .); + .data : { *(.data .data.* .gnu.linkonce.d*) } + .bss (NOLOAD) : { + . = ALIGN(16); + __bss_start = .; + *(.bss .bss.*) + *(COMMON) + __bss_end = .; + } + _end = .; + + /DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) } +} +__bss_size = (__bss_end - __bss_start)>>3;