diff --git a/README.md b/README.md index d8b59fe..efc37ca 100644 --- a/README.md +++ b/README.md @@ -3,63 +3,13 @@ An introduction to the Ferrocene toolchain, what is is (and isn't) and what it can do. -## Introduction - -In our one hour session on _Why Ferrocene?_ you will learn what Ferrocene is -about, where it is from and where it is going, and whether it is right for you -to look at Ferrocene for your next security-related or safety-critical project. -The agenda includes a short lecture, a live programming demonstration, and a -Q&A session. - -We conduct all training sessions remotely using modern video-conferencing tools -to ensure the best learning experience. - -This repository contains the teaching material for this course. +The table of contents is at [`./book/src/SUMMARY.md`](./src/SUMMARY.md). ## Booking See to book or to discuss customising this material to your needs. -## Learning Goals - -These are the questions you will be able to answer after attending this course: - -- What is Ferrocene? -- Is Ferrocene a fork of Rust? -- What support is available for Ferrocene? -- What is it like using Ferrocene? - -## Timetable - -Our standard timetable for this course is as follows: - -| Duration | Contents | -| :------: | :--------------------------------------------------- | -| 0:05 | Room open, meet and greet | -| 0:20 | Session 1 - [What is Ferrocene?](#what-is-ferrocene) | -| 0:20 | Session 2 - [A Live Demo](#a-live-demo) | -| 0:15 | Q&A | - -## Content - -### What is Ferrocene? - -- Ferrocene is just Rust -- The downstream model -- The supported host platforms -- The supported target platforms -- ISO 26262 Qualification -- Commercial Support -- The supported platforms - -### A Live Demo - -- Installing Ferrocene today -- Exploring the installation -- Writing and running an `aarch64-unknown-none` program -- Q&A - ## Licence Ferrous Systems offers our training material under diff --git a/build.sh b/build.sh index 14c76a0..36337d7 100755 --- a/build.sh +++ b/build.sh @@ -3,8 +3,16 @@ set -euo pipefail rm -rf ./slides || true +rm -rf ./book || true mkdir ./slides mkdir ./slides/images -mdslides --output-dir ./slides --template ./template.html --index-template ./index-template.html -cp ./src/images/*.png ./slides/images +# Check the examples are OK +mdbook test +# book goes into ./book mdbook build +# slides go into ./slides +mdslides \ + --output-dir ./slides \ + --template ./template.html \ + --index-template ./index-template.html +cp ./src/images/*.png ./slides/images diff --git a/example-code/README.md b/example-code/README.md index 5ce425a..3c0d9cf 100644 --- a/example-code/README.md +++ b/example-code/README.md @@ -169,18 +169,8 @@ $ qemu-system-aarch64 \ -nographic \ -kernel ./target/production/basic-rust Hello, world! -PANIC: PanicInfo { - payload: Any { .. }, - message: Some( - Let's try a panic?, - ), - location: Location { - file: "src/main.rs", - line: 28, - col: 5, - }, - can_unwind: true, -} +PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), +location: Location { file: "src/main.rs", line: 72, col: 5 }, can_unwind: true } ``` ## Creating a Docker Container diff --git a/example-code/src/boot.S b/example-code/src/boot.S index 67c7462..57fe659 100644 --- a/example-code/src/boot.S +++ b/example-code/src/boot.S @@ -10,7 +10,6 @@ _start: // Set FPEN bits [21:20] to 0b11 to prevent trapping. mov x0, #3 << 20 msr cpacr_el1, x0 -0: // Clear interrupt bit msr daifclr, #0x4 // Jump to application diff --git a/example-code/src/main.rs b/example-code/src/main.rs index c52c027..89770da 100644 --- a/example-code/src/main.rs +++ b/example-code/src/main.rs @@ -80,7 +80,7 @@ fn main() -> Result<(), core::fmt::Error> { fn panic(info: &core::panic::PanicInfo) -> ! { const SYS_REPORTEXC: u64 = 0x18; let mut c = Uart::uart0(); - let _ = writeln!(c, "PANIC: {:#?}", info); + let _ = writeln!(c, "PANIC: {:?}", info); loop { // Exit, using semihosting unsafe { diff --git a/index-template.html b/index-template.html index 7062f27..2163d9d 100644 --- a/index-template.html +++ b/index-template.html @@ -2462,11 +2462,6 @@

$TITLE

-

Credits

-

The development of this course is financed by Ferrous Systems. They are open sourced as a contribution to - the growth of the Rust language.

-

If you wish to fund further development of the course, book a training!

License

@@ -2479,7 +2474,6 @@

License

delivery of commercial or open-source Rust training programmes.

Copyright (c) Ferrous Systems, 2023

- diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 06de2eb..5548732 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -2,12 +2,23 @@ [Front Matter](./front-matter.md) +# What is Ferrocene? + - [Ferrocene is just Rust](./just-rust.md) - [The downstream model](./downstream-model.md) - [The supported host platforms](./supported-hosts.md) - [The supported target platforms](./supported-targets.md) - [ISO 26262 Qualification](./iso26262.md) - [Commercial Support](./support.md) -- [The Demo](./demo.md) + +# A Live Demo + +- [Installing Ferrocene today](./installing.md) +- [Exploring the installation](./exploring.md) +- [Writing and running a program](./writing.md) + +# Q&A + +- [Q&A](./q-and-a.md) [Wash-up](./wash-up.md) diff --git a/src/demo.md b/src/demo.md deleted file mode 100644 index 9927712..0000000 --- a/src/demo.md +++ /dev/null @@ -1 +0,0 @@ -# The Demo diff --git a/src/downstream-model.md b/src/downstream-model.md index 521152c..50473c9 100644 --- a/src/downstream-model.md +++ b/src/downstream-model.md @@ -1 +1,36 @@ # The downstream model + +## Some examples + +* Enterprise Linux Distributions are a downstream of The Linux Kernel +* The Linux Kernel makes kernel releases +* The Enterprise Linux Vendor then: + * takes the source code, + * runs their test suite, + * adds any required fixes or backports, + * publishes it as open source, and + * sells their customers binaries with a long-term support package + +Note: + +They are a downstream of a whole bunch of open source packages - GCC, glibc, LibreOffice, bash, etc. + +## It's the same model + +* Ferrocene is a downstream of The Rust Project +* The Rust Project makes toolchain releases +* Ferrous Systems then: + * takes the source code, + * runs their test suite, + * adds any required fixes or backports, + * publishes it as open source, and + * sells their customers binaries with a long-term support package + +## Yes, Ferrocene is Open Source + +We think it's the world's first open-source qualified toolchain + +## Yes, there's Long Term Support + +* You can buy support on a commercial basis +* More on this later diff --git a/src/exploring.md b/src/exploring.md new file mode 100644 index 0000000..52485a8 --- /dev/null +++ b/src/exploring.md @@ -0,0 +1,45 @@ +# Exploring the installation + +## What do you get? + +```console +$ ls -F /opt/ferrocene-23.06 +bin/ etc/ lib/ libexec/ share/ +$ ls -F /opt/ferrocene-23.06/bin +cargo* ferrocene-self-test* rust-gdb* rust-gdbgui* rust-lldb* rustc* rustdoc* +$ ls -F /opt/ferrocene-23.06/etc +bash_completion.d/ +$ ls -F /opt/ferrocene-23.06/lib +librustc_driver-c3ee1e25139c0393.so libstd-8aa647671c2dc036.so +libtest-eab3dde10cbeff80.so rustlib/ +$ ls -F /opt/ferrocene-23.06/libexec +cargo-credential-1password* rust-analyzer-proc-macro-srv* +$ ls -F /opt/ferrocene-23.06/share +doc/ man/ zsh/ +``` + +## Is that docs? + +```console +$ ls -F /opt/ferrocene-23.06/share/doc/ +cargo/ ferrocene/ rust/ +$ ls -F /opt/ferrocene-23.06/share/doc/cargo/ +LICENSE-APACHE LICENSE-MIT LICENSE-THIRD-PARTY README.md +$ ls -F /opt/ferrocene-23.06/share/doc/rust/ +COPYRIGHT LICENSE-APACHE LICENSE-MIT README.md +$ ls -F /opt/ferrocene-23.06/share/doc/ferrocene/ +html/ +$ open /opt/ferrocene-23.06/share/doc/ferrocene/html/index.html +``` + +--- + +![The docs page](./images/docs1.png) + +--- + +![The docs page](./images/docs2.png) + +--- + +![The docs page](./images/docs3.png) diff --git a/src/front-matter.md b/src/front-matter.md index 58f39b2..29459a3 100644 --- a/src/front-matter.md +++ b/src/front-matter.md @@ -1 +1,34 @@ # Front Matter + +## Introduction + +In our one hour session on _Why Ferrocene?_ you will learn what Ferrocene is +about, where it is from and where it is going, and whether it is right for you +to look at Ferrocene for your next security-related or safety-critical project. +The agenda includes a short lecture, a live programming demonstration, and a +Q&A session. + +We conduct all training sessions remotely using modern video-conferencing tools +to ensure the best learning experience. + +This repository contains the teaching material for this course. + +## Learning Goals + +These are the questions you will be able to answer after attending this course: + +- What is Ferrocene? +- Is Ferrocene a fork of Rust? +- What support is available for Ferrocene? +- What is it like using Ferrocene? + +## Timetable + +Our standard timetable for this course is as follows: + +| Duration | Contents | +| :------: | :--------------------------------------------------- | +| 0:05 | Room open, meet and greet | +| 0:20 | Session 1 - What is Ferrocene? | +| 0:20 | Session 2 - A Live Demo | +| 0:15 | Q&A | diff --git a/src/images/docs1.png b/src/images/docs1.png new file mode 100644 index 0000000..c704552 Binary files /dev/null and b/src/images/docs1.png differ diff --git a/src/images/docs2.png b/src/images/docs2.png new file mode 100644 index 0000000..df3cab8 Binary files /dev/null and b/src/images/docs2.png differ diff --git a/src/images/docs3.png b/src/images/docs3.png new file mode 100644 index 0000000..0962c46 Binary files /dev/null and b/src/images/docs3.png differ diff --git a/src/images/rolling.png b/src/images/rolling.png new file mode 100644 index 0000000..b09fda7 Binary files /dev/null and b/src/images/rolling.png differ diff --git a/src/installing.md b/src/installing.md new file mode 100644 index 0000000..ed1bea3 --- /dev/null +++ b/src/installing.md @@ -0,0 +1,27 @@ +# Installing Ferrocene today + +## Ferrocene 23.06 + +* Ships as tarballs +* Unpack tarballs into, e.g. `/opt/ferrocene-23.06` + +## Step-by-step + +1. Set up Ubuntu 18.04 for AMD64 +2. Install: + * `gcc-aarch64-linux-gnu` + * `gcc` and `build-essential` + * `xz-utils` +3. `mkdir /opt/ferrocene-23.06` +4. `tar xvf -C /opt/ferrocene-23.06` +5. Modify `~/.bashrc` to put `/opt/ferrocene-23.06/bin` in your `$PATH` + +I use Docker for this. YMMV. + +## Installing in the future + +We have `criticalup` - like `rustup` but for fetching, verifying and installing +digitally signed Ferrocene tarballs using your subscriber credentials. + +You can also use `criticalup` to fetch and verify the install tarballs, ready +for transfer to a non-Internet-connected computer for installation there. diff --git a/src/iso26262.md b/src/iso26262.md index 30701ad..3d3931c 100644 --- a/src/iso26262.md +++ b/src/iso26262.md @@ -1 +1,72 @@ # ISO 26262 Qualification + +## Quality is a process + +* You can't pour a bucket of quality into a finished product +* It's a process you follow throughout the product life-cycle +* You might follow a process that is in accordance with a published ISO standard + +## Certification and Qualification + +* You are responsible for __certifying__ that the development of *your* product + was in accordance with such a standard. +* You might choose tools that are __qualified__ as being suitable for use with + such a standards compliant process. + +## What is ISO 26262? + +> (ISO 26262-1:2018) is intended to be applied to safety-related systems that +> include one or more electrical and/or electronic (E/E) systems and that are +> installed in series production road vehicles, excluding mopeds. +> +> The document addresses possible hazards caused by malfunctioning behaviour of +> safety-related E/E systems, including interaction of these systems. + +From [iso.org](https://www.iso.org/standard/68383.html) + +## And that has qualified tools? + +ISO 26262-8:2018(E), Section 11.1.b says: + +> to provide means for the qualification of the software tool when applicable, +> in order to create evidence that the software tool is suitable to be used to +> support the activities or tasks required by the ISO 26262 series of standards +> (i.e. the user can rely on the correct functioning of a software tool for +> those activities or tasks required by the ISO 26262 series of standards). + +## Confidence in your Tools + +* What is the tool supposed to do? +* Does it do what it is supposed to do? +* Does someone I trust believe it does what it is supposed to do? + +## What is the tool supposed to do? + +* Rust doesn't have a written specification ... yet. +* So we wrote the Ferrocene Language Specification + * + +## Does it do what it is supposed to do? + +* Rust already had an __excellent__ test suite +* Our work was mainly __joining the dots__ between the tests and the + specification, and __automating everything__ +* Nothing hits our main branch unless the tests pass +* We then documented everything in a Safety Manual + +## Does someone I trust believe it does what it is supposed to do? + +We sent all our evidence to TÜV SÜD for ISO 26262 and IEC 61508 qualification. + +So, far they say: + +> ...from the general approach, structure, format and contents of the +> provided artifacts there no major questions or anything missing. + +The final qualification results will be announced in due course. + +## And I get? + +You can purchase from us the digitally-signed Qualification Documents. You can +then provide these to *your* assessor when certifying *your* development +process. diff --git a/src/just-rust.md b/src/just-rust.md index 3711594..9f9fd8d 100644 --- a/src/just-rust.md +++ b/src/just-rust.md @@ -1 +1,58 @@ # Ferrocene is just Rust + +## No, really... + +* We didn't write a new Rust toolchain +* We qualified The Rust Toolchain + +## Non-divergence + +One of the Ferrocene pillars is that the standard library and the compiler must not diverge from upstream. + +## The model works + +We've been doing this since 2021, backporting the `master` branch of `rust-lang/rust` into our tree. + +## Patches + +* Of course, some changes were required +* So, we upstreamed all of them +* Like [#93717], [#108659], [#111936], [#108898]... +* [#111992], [#112314], [#112418], [#112454], ... + +[#93717]: https://github.com/rust-lang/rust/pull/93717 +[#108659]: https://github.com/rust-lang/rust/pull/108659 +[#111936]: https://github.com/rust-lang/rust/pull/111936 +[#108898]: https://github.com/rust-lang/rust/pull/108898 +[#111992]: https://github.com/rust-lang/rust/pull/111992 +[#112314]: https://github.com/rust-lang/rust/pull/112314 +[#112418]: https://github.com/rust-lang/rust/pull/112418 +[#112454]: https://github.com/rust-lang/rust/pull/112454 + +## Virtuous Cycle + +* Sometimes we find bugs that upstream missed +* So we upstreamed the fixes +* Like [#108905] or [#114613]. + +[#108905]: https://github.com/rust-lang/rust/pull/108905 +[#114613]: https://github.com/rust-lang/rust/pull/114613 + +## So what's left? + +* Support for the [LynxOS-178] target + * A proprietary safety-critical focussed RTOS +* the temporary implementation [of a feature we proposed] and will implement upstream +* Our build and test infrastructure + +[LynxOS-178]: https://www.lynx.com/products/lynxos-178-do-178c-certified-posix-rtos +[of a feature we proposed]: https://github.com/rust-lang/compiler-team/issues/659 + +## Continuous Test + +* We developed our own *Continuous Integration* infrastructure + * Separate and parallel to that used by The Rust Project + * They have different goals! +* Having multiple independent, parallel, rock solid CI pipelines can only + benefit Rust +* Ours produces the artefacts we need for qualification diff --git a/src/q-and-a.md b/src/q-and-a.md new file mode 100644 index 0000000..6dd6547 --- /dev/null +++ b/src/q-and-a.md @@ -0,0 +1,2 @@ +# Any Questions? + diff --git a/src/support.md b/src/support.md index e3ce779..724876a 100644 --- a/src/support.md +++ b/src/support.md @@ -1 +1,62 @@ # Commercial Support + +## Ferrocene is open source + +* The Source Code is MIT/Apache-2.0 +* The [Ferrocene Language Specification] is MIT/Apache-2.0 +* You can even read the Qualification Documents in source form + +[Ferrocene Language Specification]: https://spec.ferrocene.dev + +## And you sell? + +* Binaries +* Long-term Support + * for Ferrocene + * for third-party crates (as an add-on) +* Includes digitally-signed Qualification Documents for your assessor + +## How long is long-term? + +* Upstream Rust only supports each release for six weeks +* There are no backports to old stable releases +* We pick a *rolling* release, *stabilise* it, and support it for 2 years + * We give subscribers bug-fix releases as we fix bugs +* After 2 years it goes into Extended Support + * We tell subscribers about issues and give possible workarounds + +## Roadmap + +![Ferrocene Release Model](./images/rolling.png) + +## Terminology + +* What upstream calls *stable* Ferrocene renames to *rolling*. +* What upstream calls *beta* Ferrocene renames *pre-rolling*. +* Ferrocene has its own *beta* channel, cut from *rolling*. +* Ferrocene has its own *stable* channel, cut from *beta*. + +## How much is it? + +* Access to the open-source code is free + * Includes the source code of the Qualification Documentation +* A Binary Subscription is €25/month + * Includes pre-rolling, rolling, beta and stable + * If you cancel, you can keep the binaries you already have +* Pricing for support and access to the signed Qualification Documents is POA + * We will be happy to discuss your project and your exact needs + +Note: + +Ferrocene 23.06 was developed in conjunction with a third-party and the source +code for this release cannot be open-sourced at this time. We hope to +open-source any subsequent 23.06 patch releases. We commit to making all future +releases open-source. + +## Is there a USB dongle? + +* No +* You get a username and password to a download area +* You (will) get a tool `criticalup` for downloading your binaries +* Your binaries are legally restricted but not physically restricted + * They are designed to be used in your CI system! diff --git a/src/supported-hosts.md b/src/supported-hosts.md index 6364c1b..8c44a56 100644 --- a/src/supported-hosts.md +++ b/src/supported-hosts.md @@ -1 +1,24 @@ # The supported host platforms + +## Host Platform? + +* The machine you can run the toolchain on +* It also has to compile code *for itself*, e.g. proc-macros and `build.rs` files +* A combination of CPU architecture, Operating System and ABI + +## The List + +* Just `x86_64-unknown-linux-gnu` for now + +## `x86_64-unknown-linux-gnu` + +* We qualified on Ubuntu 18.04 for x86-64 +* This was driven by the needs of our first client +* It comes with GCC 7.5 which is the linker we used for qualification +* More Operating Systems and linkers will be supported in due course + +## But what about $MY_FAVOURITE host + +* Get in touch! +* If Rust already runs on there, it's a case of porting our test suite +* If Rust doesn't already run on there ... we can probably fix that for you diff --git a/src/supported-targets.md b/src/supported-targets.md index 2143abc..1e675f6 100644 --- a/src/supported-targets.md +++ b/src/supported-targets.md @@ -1 +1,26 @@ # The supported target platforms + +## Target Platform? + +* The machine you can run the compiled code on +* A combination of CPU architecture, Operating System and ABI + +## The List + +* `x86_64-unknown-linux-gnu` (the supported host) +* `aarch64-unknown-none` + +## `aarch64-unknown-none` + +* Aarch64 mode (A64 instructions) Armv8-A +* `no-std` mode - no Rust `libstd`, only `libcore` and `liballoc` +* Driven by our lead client's requirements +* Bring your existing OS and call its C API from Rust +* Must use the `aarch64-unknown-linux-gnu` GCC 7.5 linker from Ubuntu 18.04 + * With `-ffreestanding` and the other flags in our User Manual + +## But what about $MY_FAVOURITE target + +* Get in touch! +* If Rust already targets it, it's a case of porting our test suite +* If Rust doesn't already target it ... we can probably fix that for you diff --git a/src/writing.md b/src/writing.md new file mode 100644 index 0000000..314a263 --- /dev/null +++ b/src/writing.md @@ -0,0 +1,182 @@ +# Writing and running a program + +## The demo + +* I have the `aarch64-unknown-none` target +* I want run to run a binary on an ARMv8-A machine in Aarch64 mode +* I'm using QEMU +* I'll need a UART driver so you can see the output +* I'll need some assembly code to boot the chip +* All the demo source code is available + +## Building the demo + +* You can build this with `cargo build` +* You can drive `rustc` manually with `$MY_FAVOURITE` build system +* I show both + +## The boot.S file + +Set the stack pointer, jump to a symbol called `kmain`. + +```asm +.section .text.startup +.global _start + +_start: + ldr x30, =stack_top + mov sp, x30 + mov x0, #3 << 20 + msr cpacr_el1, x0 + msr daifclr, #0x4 + bl kmain + b . +``` + +## The skeleton + +```rust [] ignore +#![no_std] +#![no_main] + +#[no_mangle] +pub extern "C" fn kmain() { + todo!() +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { } +``` + +Note: + +We turned off name-mangling with `#[no_mangle]` so `boot.S` could jump to +`kmain`. We also set the function to have `C` linkage (i.e. use a C compatible +ABI), like assembly branch assumed. + +## The UART + +```rust [] +struct Uart { base: *mut u32 } + +impl Uart { + pub fn uart0() -> Uart { + const UART0_ADDR: usize = 0x0000_0000_0900_0000; + Uart { base: UART0_ADDR as *mut u32 } + } + + pub fn putchar(&mut self, byte: u8) { + unsafe { self.base.write_volatile(u32::from(byte)); } + } +} +``` + +## Writing to the UART + +```rust [] ignore +impl core::fmt::Write for Uart { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for b in s.bytes() { + self.putchar(b); + } + Ok(()) + } +} +``` + +## Handling panics + +```rust [] ignore +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + const SYS_REPORTEXC: u64 = 0x18; + let mut c = Uart::uart0(); + let _ = writeln!(c, "PANIC: {:?}", info); + loop { + unsafe { + core::arch::asm!( + "hlt 0xf000", + in("x0") SYS_REPORTEXC + ) + } + } +} +``` + +## Some application code + +```rust [] ignore +fn main() -> Result<(), core::fmt::Error> { + let mut c = Uart::uart0(); + writeln!(c, "Hello, this is Rust!")?; + for x in 1..=10 { + for y in 1..=10 { + let z = x * y; + write!(c, "{z:4}")?; + } + writeln!(c)?; + } + panic!("I am a panic"); +} +``` + +## And fixing up kmain + +```rust [] ignore +#[no_mangle] +pub extern "C" fn kmain() { + if let Err(e) = main() { + panic!("main returned {:?}", e); + } +} +``` + +## Let's run it + +```console +$ cargo run + Compiling basic-rust v0.1.0 (/work) + Finished dev [unoptimized + debuginfo] target(s) in 12.17s + Running `qemu-system-aarch64 -machine virt -cpu cortex-a57 -semihosting + -nographic -kernel target/aarch64-unknown-none/debug/basic-rust` +Hello, this is Rust! + 1 2 3 4 5 6 7 8 9 10 + 2 4 6 8 10 12 14 16 18 20 + 3 6 9 12 15 18 21 24 27 30 + 4 8 12 16 20 24 28 32 36 40 + 5 10 15 20 25 30 35 40 45 50 + 6 12 18 24 30 36 42 48 54 60 + 7 14 21 28 35 42 49 56 63 70 + 8 16 24 32 40 48 56 64 72 80 + 9 18 27 36 45 54 63 72 81 90 + 10 20 30 40 50 60 70 80 90 100 +PANIC: PanicInfo { payload: Any { .. }, message: Some(I am a panic), +location: Location { file: "src/main.rs", line: 72, col: 5 }, can_unwind: true } +$ +``` + +## Wait, how did boot.S get assembled? + +There's a long and boring `build.rs` file which shells out to `as` and `ar` to +assemble `boot.S` into `libboot.a`. + +## If you don't want to use cargo + +```sh + # snip some variable set up... +RUSTC="rustc \ + --target aarch64-unknown-none \ + -Clinker=${CC} \ + -Clinker-flavor=gcc \ + -Clink-arg=-ffreestanding \ + -Clink-arg=-nostdlib \ + -L ${TARGET_DIR}" +${AS} src/boot.S -o ${TARGET_DIR}/boot.o +${AR} rcs ${TARGET_DIR}/libboot.a ${TARGET_DIR}/boot.o +${RUSTC} src/main.rs \ + --edition 2021 \ + -Clink-arg=-Tlinker.ld \ + -Copt-level=s \ + -lboot \ + -o ${OUTPUT_BINARY} +```