diff --git a/.cargo/config.toml b/.cargo/config.toml index 20f8233cf..93879653c 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,9 +1,9 @@ [alias] -x86 = "build --package awkernel --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -aarch64 = "build --package awkernel --no-default-features --features aarch64 --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -rv32 = "build --package awkernel --no-default-features --features rv32 --target riscv32imac-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -rv64 = "build --package awkernel --no-default-features --features rv64 --target riscv64gc-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -std = "build --package awkernel --no-default-features --features std" +x86 = "build --package userland --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +aarch64 = "build --package userland --no-default-features --features aarch64 --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +rv32 = "build --package userland --no-default-features --features rv32 --target riscv32imac-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +rv64 = "build --package userland --no-default-features --features rv64 --target riscv64gc-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +std = "build --package userland --no-default-features --features std" test_awkernel_lib = "test --package awkernel_lib --no-default-features --features std" test_awkernel_async_lib = "test --package awkernel_async_lib --no-default-features --features std" @@ -12,25 +12,25 @@ test_smoltcp = "test --package smoltcp --no-default-features --features std --fe test_affinity_btree_queue = "test --package affinity_btree_queue" test_rd_gen_to_dags = "test --package rd_gen_to_dags --no-default-features --features std --features milliseconds" -clippy_x86 = "clippy --package awkernel --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -clippy_raspi = "clippy --package awkernel --no-default-features --features raspi --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -clippy_raspi5 = "clippy --package awkernel --no-default-features --features raspi5 --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -clippy_aarch64_virt = "clippy --package awkernel --no-default-features --features aarch64_virt --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -clippy_std = "clippy --package awkernel --no-default-features --features std" -clippy_rv32 = "clippy --package awkernel --no-default-features --features rv32 --target riscv32imac-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -clippy_rv64 = "clippy --package awkernel --no-default-features --features rv64 --target riscv64gc-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +clippy_x86 = "clippy --package userland --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +clippy_raspi = "clippy --package userland --no-default-features --features raspi --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +clippy_raspi5 = "clippy --package userland --no-default-features --features raspi5 --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +clippy_aarch64_virt = "clippy --package userland --no-default-features --features aarch64_virt --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +clippy_std = "clippy --package userland --no-default-features --features std" +clippy_rv32 = "clippy --package userland --no-default-features --features rv32 --target riscv32imac-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +clippy_rv64 = "clippy --package userland --no-default-features --features rv64 --target riscv64gc-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" clippy_rd_gen_to_dags = "clippy --package rd_gen_to_dags --no-default-features --features std --features milliseconds" -check_aarch64 = "check --package awkernel --no-default-features --features aarch64 --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -check_x86 = "check --package awkernel --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -check_rv32 = "check --package awkernel --no-default-features --features rv32 --target riscv32imac-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -check_rv64 = "check --package awkernel --no-default-features --features rv64 --target riscv64gc-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -check_no_std = "check --package awkernel -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem --quiet --message-format=json -Zjson-target-spec" -check_std = "check --package awkernel --no-default-features --features std" +check_aarch64 = "check --package userland --no-default-features --features aarch64 --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +check_x86 = "check --package userland --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +check_rv32 = "check --package userland --no-default-features --features rv32 --target riscv32imac-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +check_rv64 = "check --package userland --no-default-features --features rv64 --target riscv64gc-unknown-none-elf -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +check_no_std = "check --package userland -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem --quiet --message-format=json -Zjson-target-spec" +check_std = "check --package userland --no-default-features --features std" -doc_raspi = "doc --package awkernel --no-default-features --features raspi --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -doc_aarch64_virt = "doc --package awkernel --no-default-features --features aarch64_virt --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" -doc_x86 = "doc --package awkernel --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +doc_raspi = "doc --package userland --no-default-features --features raspi --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +doc_aarch64_virt = "doc --package userland --no-default-features --features aarch64_virt --target targets/aarch64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" +doc_x86 = "doc --package userland --no-default-features --features x86 --target targets/x86_64-kernel.json -Zbuild-std=core,alloc,compiler_builtins -Zbuild-std-features=compiler-builtins-mem -Zjson-target-spec" udeps_x86 = "udeps --package awkernel --no-default-features --features x86 --target x86_64-unknown-linux-gnu" udeps_raspi = "udeps --package awkernel --no-default-features --features x86 --target x86_64-unknown-linux-gnu" diff --git a/.vscode/settings.json b/.vscode/settings.json index 44a84d156..39b9509f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,18 +2,22 @@ "rust-analyzer.showUnlinkedFileNotification": false, "tlaplus.tlc.modelChecker.options": "-workers auto", "editor.formatOnSave": true, + // The cargo aliases build `--package userland`, which has no default + // architecture: pass it explicitly (the features are forwarded to `awkernel`). // For AArch64 Virt // "rust-analyzer.cargo.buildScripts.overrideCommand": [ // "cargo", // "+nightly-2026-07-20", // "check_no_std", // "--target=targets/aarch64-kernel.json", + // "--features=aarch64_virt", // ], // "rust-analyzer.check.overrideCommand": [ // "cargo", // "+nightly-2026-07-20", // "check_no_std", // "--target=targets/aarch64-kernel.json", + // "--features=aarch64_virt", // ], // "rust-analyzer.cargo.features": [ // "aarch64_virt" @@ -24,12 +28,14 @@ "+nightly-2026-07-20", "check_no_std", "--target=targets/x86_64-kernel.json", + "--features=x86", ], "rust-analyzer.check.overrideCommand": [ "cargo", "+nightly-2026-07-20", "check_no_std", "--target=targets/x86_64-kernel.json", + "--features=x86", ], "rust-analyzer.cargo.features": [ "x86" @@ -39,6 +45,7 @@ // "cargo", // "+nightly-2026-07-20", // "check_std", + // "--features=std", // "--quiet", // "--message-format=json" // ], @@ -46,10 +53,11 @@ // "cargo", // "+nightly-2026-07-20", // "check_std", + // "--features=std", // "--quiet", // "--message-format=json" // ], // "rust-analyzer.cargo.features": [ // "std" // ], -} +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 65a89b195..b58acb6ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ members = [ "applications/tests/*", "smoltcp", "awkernel_futures_macro", + "awkernel_macros", ] resolver = "2" diff --git a/Makefile b/Makefile index 28a00f6b5..8f9b6f703 100644 --- a/Makefile +++ b/Makefile @@ -6,39 +6,22 @@ else OPT = --features debug endif -# 2MiB Stack -STACKSIZE = 1024 * 1024 * 2 - ifeq ($(BSP),raspi3) RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 - INITADDR = 0x80000 AARCH64_OPT = $(OPT) --features raspi else ifeq ($(BSP),raspi4) RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 - INITADDR = 0x80000 AARCH64_OPT = $(OPT) --features raspi else ifeq ($(BSP),raspi5) RUSTC_MISC_ARGS = -C target-cpu=cortex-a76 - INITADDR = 0x80000 AARCH64_OPT = $(OPT) --features raspi5 else ifeq ($(BSP),aarch64_virt) RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 - INITADDR = 0x40080000 AARCH64_OPT = $(OPT) --features aarch64_virt endif RUSTC_MISC_ARGS += -C panic=unwind -ASM_FILE_DEP_AARCH64=kernel/asm/aarch64/exception.S -ASM_FILE_AARCH64=kernel/asm/aarch64/boot.S -ASM_OBJ_AARCH64=boot_aarch64.o - -X86ASM=kernel/asm/x86 - -ifndef $(CC) - CC = clang -endif - ifndef $(LD) LD = rust-lld -flavor gnu # LD = ld.gold @@ -49,8 +32,6 @@ QEMUPORT=5556 # Link scripts LINKERDIR=kernel/ld -AARCH64_LD=$(LINKERDIR)/aarch64-link.lds -AARCH64_BSP_LD=$(LINKERDIR)/aarch64-link-bsp.lds X86_64_LD=$(LINKERDIR)/x86_64-link.lds RV32_LD=$(LINKERDIR)/rv32-link.lds RV64_LD=$(LINKERDIR)/rv64-link.lds @@ -61,7 +42,7 @@ all: aarch64 x86_64 riscv32 riscv64 std check: check_aarch64 check_x86_64 check_std check_riscv32 check_riscv64 -clippy: $(X86ASM) +clippy: cargo +$(RUSTV) clippy_x86 cargo +$(RUSTV) clippy_raspi cargo +$(RUSTV) clippy_raspi5 @@ -71,7 +52,7 @@ clippy: $(X86ASM) cargo +$(RUSTV) clippy_std cargo +$(RUSTV) clippy_rd_gen_to_dags -udeps: $(X86ASM) +udeps: cargo +$(RUSTV) udeps_x86 cargo: target/aarch64-kernel/$(BUILD)/awkernel kernel-x86_64.elf std @@ -84,19 +65,13 @@ aarch64: kernel8.img check_aarch64: FORCE cargo +$(RUSTV) check_aarch64 $(AARCH64_OPT) -target/aarch64-kernel/$(BUILD)/awkernel: $(ASM_OBJ_AARCH64) $(AARCH64_BSP_LD) FORCE +target/aarch64-kernel/$(BUILD)/awkernel: FORCE RUSTFLAGS="$(RUSTC_MISC_ARGS)" cargo +$(RUSTV) aarch64 $(AARCH64_OPT) python3 scripts/embed_debug_info.py $@ kernel8.img: target/aarch64-kernel/$(BUILD)/awkernel rust-objcopy -O binary target/aarch64-kernel/$(BUILD)/awkernel $@ -$(ASM_OBJ_AARCH64): $(ASM_FILE_AARCH64) $(ASM_FILE_DEP_AARCH64) - $(CC) --target=aarch64-elf -c $< -o $@ -DSTACKSIZE="$(STACKSIZE)" - -$(AARCH64_BSP_LD): $(AARCH64_LD) - sed "s/#INITADDR#/$(INITADDR)/" $(AARCH64_LD) > $@ - QEMU_AARCH64_ARGS= -kernel kernel8.img QEMU_AARCH64_ARGS+= -serial stdio QEMU_AARCH64_ARGS+= -monitor telnet::$(QEMUPORT),server,nowait # -d int @@ -139,10 +114,10 @@ gdb-aarch64-virt: x86_64: x86_64_uefi.img -check_x86_64: $(X86ASM) +check_x86_64: cargo +$(RUSTV) check_x86 -kernel-x86_64.elf: $(X86ASM) FORCE +kernel-x86_64.elf: FORCE RUSTFLAGS="$(RUSTC_MISC_ARGS)" cargo +$(RUSTV) x86 $(OPT) python3 scripts/embed_debug_info.py $@ @@ -152,9 +127,6 @@ x86_64_boot.img: kernel-x86_64.elf x86_64_uefi.img: kernel-x86_64.elf RUSTFLAGS="$(RUSTC_MISC_ARGS)" cargo +$(RUSTV) run --release --package x86bootdisk --no-default-features --features uefi -- --kernel $< --output $@ --pxe x86_64_uefi_pxe_boot --boot-type uefi -$(X86ASM): FORCE - $(MAKE) -C $@ - OVMF_PATH := $(shell cat ${HOME}/.ovmfpath) QEMU_X86_ARGS= -drive if=pflash,format=raw,readonly=on,file=${OVMF_PATH}/code.fd @@ -247,7 +219,7 @@ check_std: FORCE cargo +$(RUSTV) check_std run-std: - cargo +$(RUSTV) run --package awkernel --no-default-features --features std $(OPT) + cargo +$(RUSTV) run --package userland --no-default-features --features std $(OPT) # Docs docs: FORCE @@ -271,9 +243,8 @@ fmt: FORCE # Clean clean: FORCE - rm -rf *.o *.elf $(AARCH64_BSP_LD) *.img kernel/asm/x86/*.o x86_64_uefi_pxe_boot + rm -rf *.o *.elf *.img x86_64_uefi_pxe_boot cargo clean - $(MAKE) -C $(X86ASM) clean ## QEMU Monitor diff --git a/README.md b/README.md index b87090200..d24b011e5 100644 --- a/README.md +++ b/README.md @@ -41,6 +41,8 @@ $ cargo binstall mdbook-mermaid - verified library for awkernel_async_lib - pure Rust (no dependencies on external functions and no inline assembly) - [awkernel_futures_macro](./awkernel_futures_macro/) +- [awkernel_macros](./awkernel_macros/) + - `#[awkernel::main]` entry-point macro - [awkernel_drivers](./awkernel_drivers/) - [awkernel_aarch64](./awkernel_aarch64/) - [userland](./userland/) @@ -60,7 +62,8 @@ graph TD; kernel-->awkernel_aarch64; kernel-->awkernel_drivers; awkernel_drivers-->awkernel_lib; - kernel-->userland; + userland-->kernel; + kernel-->awkernel_macros; ``` Applications can use `awkernel_async_lib`, `awkernel_lib`, and `awkernel_drivers`. @@ -95,7 +98,6 @@ etc ### x86_64 ```text -$ make kernel/asm/x86 $ cargo doc_x86 $ ls target/x86_64-kernel/doc/awkernel/index.html $ ls target/aarch64-kernel/doc/awkernel_lib/index.html @@ -120,28 +122,29 @@ Debug build. $ make x86_64 ``` -#### Developing for x86_64 on macOS +#### Building x86_64 on Apple Silicon (or another non-x86_64 host) -`kernel/asm/x86/mpboot.S` mixes 16/32/64-bit code and needs a real GNU assembler and linker. -By default, Apple systems provide an alias so `gcc` points to `clang`. -Also, modern Apple Silicon processors are aarch64. -Therefore, we must install a GNU x86_64 ELF cross toolchain: +The x86_64 build includes `kernel/asm/x86/mpboot.S`, an assembly file that mixes 16-, 32-, and 64-bit code. The build script assembles and links it with GNU tools, then uses `objcopy` to create a binary image. A Rust target alone does not provide these tools. + +On Apple Silicon, install an x86_64 ELF GNU toolchain: ```text $ brew install x86_64-elf-gcc x86_64-elf-binutils ``` -Then, when building your application, point to this specific cross toolchain: +The build script automatically uses the `x86_64-elf-` tool prefix if `x86_64-elf-gcc` is available. Otherwise, it tries the host tools (`gcc`, `ld`, and `objcopy`), which may not support this build on a non-x86_64 host. + +To select a toolchain with a different prefix, pass that prefix as `CROSS_COMPILE`. For example, if its tools are named `my-x86_64-elf-gcc`, `my-x86_64-elf-ld`, and `my-x86_64-elf-objcopy`, run: ```text -$ make x86_64 RELEASE=1 CROSS_COMPILE=x86_64-elf- +$ make x86_64 RELEASE=1 CROSS_COMPILE=my-x86_64-elf- ``` > [!IMPORTANT] > -> Do not remove the trailing `-` - -This way, Awkernel will use the `x86_64-elf-gcc` compiler and the `x86_64-elf-ld` linker. +> `CROSS_COMPILE` is a prefix, not a path to the compiler. Keep the trailing `-` so the build can append `gcc`, `ld`, and `objcopy` to it. +> +> For example, `CROSS_COMPILE=x86_64-elf-` selects `x86_64-elf-gcc`, `x86_64-elf-ld`, and `x86_64-elf-objcopy`. ### Boot diff --git a/awkernel_macros/Cargo.toml b/awkernel_macros/Cargo.toml new file mode 100644 index 000000000..dbe89a4eb --- /dev/null +++ b/awkernel_macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "awkernel_macros" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.60" +quote = "1.0" +syn = { version = "2.0.52", features = ["full"] } diff --git a/awkernel_macros/src/lib.rs b/awkernel_macros/src/lib.rs new file mode 100644 index 000000000..913133362 --- /dev/null +++ b/awkernel_macros/src/lib.rs @@ -0,0 +1,74 @@ +//! Procedural macros for Awkernel. + +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, spanned::Spanned, ItemFn}; + +/// Marks an `async fn` as the entry point of the userland. +/// +/// The kernel spawns it as the first task once it has booted. +/// The function must be `async`, take no arguments, and return +/// `Result<(), Cow<'static, str>>`. +/// +/// ```ignore +/// #[awkernel::main] +/// async fn main() -> Result<(), alloc::borrow::Cow<'static, str>> { +/// Ok(()) +/// } +/// ``` +#[proc_macro_attribute] +pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { + let func = parse_macro_input!(item as ItemFn); + + if !args.is_empty() { + return syn::Error::new( + proc_macro2::TokenStream::from(args).span(), + "`#[awkernel::main]` takes no arguments", + ) + .to_compile_error() + .into(); + } + if func.sig.asyncness.is_none() { + return syn::Error::new(func.sig.span(), "the entry point must be an `async fn`") + .to_compile_error() + .into(); + } + if !func.sig.inputs.is_empty() { + return syn::Error::new( + func.sig.inputs.span(), + "the entry point must not take arguments", + ) + .to_compile_error() + .into(); + } + if !func.sig.generics.params.is_empty() { + return syn::Error::new( + func.sig.generics.span(), + "the entry point must not be generic", + ) + .to_compile_error() + .into(); + } + + let name = &func.sig.ident; + + // The symbol is resolved at link time by the kernel (`awkernel::UserMain`). + quote! { + #func + + #[no_mangle] + pub fn __awkernel_user_main() -> ::core::pin::Pin< + ::alloc::boxed::Box< + dyn ::core::future::Future< + Output = ::core::result::Result< + (), + ::alloc::borrow::Cow<'static, str>, + >, + > + ::core::marker::Send, + >, + > { + ::alloc::boxed::Box::pin(#name()) + } + } + .into() +} diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 92f90438d..b65065e90 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -43,8 +43,8 @@ optional = true version = "0.2" optional = true -[dependencies.userland] -path = "../userland" +[dependencies.awkernel_macros] +path = "../awkernel_macros" [dependencies.awkernel_async_lib] path = "../awkernel_async_lib" @@ -79,7 +79,7 @@ optional = true default = ["x86"] heap-tlsf = ["awkernel_lib/heap-tlsf"] heap-wf-alloc = ["awkernel_lib/heap-wf-alloc"] -perf = ["awkernel_async_lib/perf", "userland/perf"] +perf = ["awkernel_async_lib/perf"] period-index-propagation = [ "perf", "awkernel_async_lib/period-index-propagation", @@ -150,6 +150,3 @@ aarch64_virt = [ ] spinlock = ["awkernel_lib/spinlock"] linux = [] -test_clustered_edf = ["userland/test_clustered_edf"] -test_dvfs = ["userland/test_dvfs"] -test_raspi_dvfs = ["userland/test_raspi_dvfs"] diff --git a/kernel/asm/aarch64/boot.S b/kernel/asm/aarch64/boot.S index c3b5092e1..b99f052de 100644 --- a/kernel/asm/aarch64/boot.S +++ b/kernel/asm/aarch64/boot.S @@ -10,7 +10,7 @@ _start: and x2, x2, #0xFF add x3, x2, #1 - mov x4, #(STACKSIZE) + mov x4, #({STACKSIZE}) mul x3, x3, x4 ldr x1, =__stack_memory @@ -91,5 +91,3 @@ _start: .loop: wfe b .loop - -#include "exception.S" diff --git a/kernel/asm/x86/Makefile b/kernel/asm/x86/Makefile deleted file mode 100644 index 7d779142c..000000000 --- a/kernel/asm/x86/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -ASM_FILE_X86=mpboot.S -ASM_OBJ_X86=mpboot.o -ASM_ELF_X86=mpboot.elf -ASM_IMG_X86=mpboot.img - -CROSS_COMPILE ?= - -all: $(ASM_IMG_X86) - -$(ASM_OBJ_X86): $(ASM_FILE_X86) - $(CROSS_COMPILE)gcc -m32 -fno-pie -nostdlib -c $< -o $@ - -# See kernel::arch::x86_64::kernel_main::NON_PRIMARY_START -$(ASM_ELF_X86): $(ASM_OBJ_X86) - $(CROSS_COMPILE)ld -m elf_i386 -N -e _start_cpu -Ttext 0 $< -o $@ - -%.img: %.elf - rust-objcopy -O binary $< $@ - -clean: - rm -f *.o *.img *.elf diff --git a/kernel/build.rs b/kernel/build.rs new file mode 100644 index 000000000..cef2429de --- /dev/null +++ b/kernel/build.rs @@ -0,0 +1,156 @@ +//! Publishes the linker script of the selected architecture as `awkernel.ld`. +//! +//! The script is copied to `OUT_DIR`, which is added to the native library +//! search path. Cargo forwards that path to the final link of every crate that +//! depends on `awkernel`, so a userland crate only has to pass +//! `-Tawkernel.ld`, e.g. with `println!("cargo:rustc-link-arg-bins=-Tawkernel.ld")` +//! in its own `build.rs`. +//! +//! The AArch64 script is a template: `#INITADDR#` is replaced by the load +//! address of the selected board (`raspi`, `raspi5` or `aarch64_virt`), or by +//! the `INITADDR` environment variable if no board is selected. +//! Its startup code (`boot.S`) is assembled by `global_asm!`. + +use std::{ + env, fs, + path::{Path, PathBuf}, + process::Command, +}; + +fn has_feature(name: &str) -> bool { + env::var_os(format!("CARGO_FEATURE_{name}")).is_some() +} + +fn run_command(cmd: &mut Command) { + let status = cmd + .status() + .unwrap_or_else(|e| panic!("failed to run {cmd:?}: {e}")); + assert!(status.success(), "{cmd:?} failed"); +} + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=ld"); + + if has_feature("AARCH64") { + aarch64(); + } else if has_feature("X86") { + x86_64(); + } else if has_feature("RV32") { + riscv32(); + } else if has_feature("RV64") { + riscv64(); + } +} + +fn x86_64() { + println!("cargo:rerun-if-env-changed=CROSS_COMPILE"); + + build_x86_64_mpboot(); + publish_linker_script("x86_64-link.lds", None); +} + +fn aarch64() { + println!("cargo:rerun-if-env-changed=INITADDR"); + + // The script is a template that needs the load address of the board. + // Without a board feature, it is taken from the `INITADDR` environment variable. + let init_addr = if has_feature("AARCH64_VIRT") { + "0x40080000".to_string() + } else if has_feature("RASPI") || has_feature("RASPI5") { + "0x80000".to_string() + } else if let Ok(addr) = env::var("INITADDR") { + addr + } else { + // Without a board or `INITADDR` (e.g. a plain `cargo check`), no script is published. + return; + }; + + publish_linker_script("aarch64-link.lds", Some(("#INITADDR#", &init_addr))); +} + +fn riscv32() { + publish_linker_script("rv32-link.lds", None); +} + +fn riscv64() { + publish_linker_script("rv64-link.lds", None); +} + +/// Copies `ld/