kernel: add new kernel build target
Used for testing the kernel on qemu, add an entry point that (for now)
assumes cortex-m and calls into a new kernel crate that starts an init
sequence.
Begin to fill in an architecture layer by creating a architecture
interface trait that currently one arch fills in (cortex-m).
Fill in all of the exception handlers in the arch, since we will want to
eventually override all of them anyway, and now we can see if one fires.
build and run the //build/kernel:kernel target
Change-Id: I2fc7841b33f6f78c68bdba28fd01524c6edeed91
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/maize/+/260070
Reviewed-by: Erik Gilling <konkers@google.com>
Lint: Lint 🤖 <android-build-ayeaye@system.gserviceaccount.com>
Commit-Queue: Travis Geiselbrecht <travisg@google.com>
Presubmit-Verified: CQ Bot Account <pigweed-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/arch/BUILD.bazel b/arch/BUILD.bazel
new file mode 100644
index 0000000..41a5a97
--- /dev/null
+++ b/arch/BUILD.bazel
@@ -0,0 +1,36 @@
+# Copyright 2025 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load("@rules_rust//rust:defs.bzl", "rust_library")
+
+package(default_visibility = ["//visibility:public"])
+
+rust_library(
+ name = "arch_interface",
+ srcs = ["arch_interface.rs"],
+)
+
+rust_library(
+ name = "arch",
+ srcs = ["arch.rs"],
+ deps = [
+ ":arch_backend",
+ ":arch_interface",
+ ],
+)
+
+label_flag(
+ name = "arch_backend",
+ build_setting_default = "//arch/arm_cortex_m:arm_cortex_m",
+)
diff --git a/arch/arch.rs b/arch/arch.rs
new file mode 100644
index 0000000..adfc97d
--- /dev/null
+++ b/arch/arch.rs
@@ -0,0 +1,20 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#![no_std]
+
+// Re-export the appropriate architecture as the Arch module.
+pub use arch_backend::Arch;
+pub use arch_interface::ArchInterface;
+
+// TODO: put any generic Arch routines here.
diff --git a/arch/arch_interface.rs b/arch/arch_interface.rs
new file mode 100644
index 0000000..9c3c7e5
--- /dev/null
+++ b/arch/arch_interface.rs
@@ -0,0 +1,24 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#![no_std]
+
+pub trait ArchInterface {
+ fn early_init() {}
+ fn init() {}
+
+ // fill in more arch implementation functions from the kernel here:
+ // TODO: interrupt management
+ // context switching, thread creation, management
+ // arch-specific backtracing
+}
diff --git a/arch/arm_cortex_m/BUILD.bazel b/arch/arm_cortex_m/BUILD.bazel
index e14d276..f90f483 100644
--- a/arch/arm_cortex_m/BUILD.bazel
+++ b/arch/arm_cortex_m/BUILD.bazel
@@ -25,3 +25,21 @@
"@rust_crates//:cortex-m",
],
)
+
+rust_library(
+ name = "arm_cortex_m",
+ srcs = [
+ "arm_cortex_m.rs",
+ "exceptions.rs",
+ ],
+ crate_name = "arch_backend",
+ deps = [
+ "//arch:arch_interface",
+ "//target:linker_script",
+ "@pigweed//pw_log/rust:pw_log",
+ "@rust_crates//:cortex-m",
+ "@rust_crates//:cortex-m-rt",
+ "@rust_crates//:cortex-m-semihosting",
+ "@rust_crates//:panic-halt",
+ ],
+)
diff --git a/arch/arm_cortex_m/arm_cortex_m.rs b/arch/arm_cortex_m/arm_cortex_m.rs
new file mode 100644
index 0000000..b824f1d
--- /dev/null
+++ b/arch/arm_cortex_m/arm_cortex_m.rs
@@ -0,0 +1,33 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#![no_std]
+
+mod exceptions;
+
+use arch_interface::ArchInterface;
+
+pub struct Arch {}
+
+impl ArchInterface for Arch {
+ fn early_init() {
+ // TODO: set up the cpu here:
+ // interrupt vector table
+ // irq priority levels
+ // clear pending interrupts
+ // FPU initial state
+ // enable cache (if present)
+ // enable cycle counter?
+ }
+ fn init() {}
+}
diff --git a/arch/arm_cortex_m/exceptions.rs b/arch/arm_cortex_m/exceptions.rs
new file mode 100644
index 0000000..83d15aa
--- /dev/null
+++ b/arch/arm_cortex_m/exceptions.rs
@@ -0,0 +1,107 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#![allow(non_snake_case)]
+
+//use core::sync::atomic::{self, Ordering};
+use cortex_m_rt::ExceptionFrame;
+use pw_log::info;
+
+fn dump_exception_frame(frame: &ExceptionFrame) {
+ info!("Exception frame:");
+ info!(
+ "r0 {} r1 {} r2 {} r3 {}",
+ frame.r0(),
+ frame.r1(),
+ frame.r2(),
+ frame.r3()
+ );
+ info!(
+ "r12 {} lr {} pc {} xpsr {}",
+ frame.r12(),
+ frame.lr(),
+ frame.pc(),
+ frame.xpsr()
+ );
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn HardFault(frame: &ExceptionFrame) -> ! {
+ info!("HardFault");
+ dump_exception_frame(frame);
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn DefaultHandler() -> ! {
+ info!("DefaultHandler");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn NonMaskableInt() -> ! {
+ info!("NonMaskableInt");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn MemoryManagement() -> ! {
+ info!("MemoryManagement");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn BusFault() -> ! {
+ info!("BusFault");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn UsageFault() -> ! {
+ info!("UsageFault");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn SVCall() -> ! {
+ info!("SVCall");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn DebugMonitor() -> ! {
+ info!("DebugMonitor");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn PendSV() -> ! {
+ info!("PendSV");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn SysTick() -> ! {
+ info!("SysTick");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
diff --git a/build/kernel/BUILD.bazel b/build/kernel/BUILD.bazel
new file mode 100644
index 0000000..577e30b
--- /dev/null
+++ b/build/kernel/BUILD.bazel
@@ -0,0 +1,35 @@
+# Copyright 2025 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load("@rules_rust//rust:defs.bzl", "rust_binary")
+
+package(default_visibility = ["//visibility:public"])
+
+rust_binary(
+ name = "kernel",
+ srcs = ["kernel_cortex_m_entry.rs"],
+ edition = "2021",
+ target_compatible_with = select({
+ "@pigweed//pw_build/constraints/chipset:lm3s6965evb": [],
+ "@pigweed//pw_build/constraints/chipset:nrf52833": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
+ deps = [
+ "//target:linker_script",
+ "//kernel",
+ "@rust_crates//:cortex-m-rt",
+ "@rust_crates//:cortex-m-semihosting",
+ "@rust_crates//:panic-halt",
+ ],
+)
\ No newline at end of file
diff --git a/build/kernel/kernel_cortex_m_entry.rs b/build/kernel/kernel_cortex_m_entry.rs
new file mode 100644
index 0000000..3bbd664
--- /dev/null
+++ b/build/kernel/kernel_cortex_m_entry.rs
@@ -0,0 +1,31 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#![no_main]
+#![no_std]
+
+// TODO: move this entry point into the arch module, possibly.
+
+// Panic handler that halts the CPU on panic.
+use panic_halt as _;
+
+// Cortex M runtime entry macro.
+use cortex_m_rt::entry;
+
+use kernel;
+
+#[entry]
+fn main() -> ! {
+ kernel::kernel_main();
+}
diff --git a/kernel/BUILD.bazel b/kernel/BUILD.bazel
new file mode 100644
index 0000000..d3451a7
--- /dev/null
+++ b/kernel/BUILD.bazel
@@ -0,0 +1,26 @@
+# Copyright 2025 The Pigweed Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+load("@rules_rust//rust:defs.bzl", "rust_library")
+
+package(default_visibility = ["//visibility:public"])
+
+rust_library(
+ name = "kernel",
+ srcs = ["kernel.rs"],
+ deps = [
+ "//arch",
+ "@pigweed//pw_log/rust:pw_log",
+ ]
+)
\ No newline at end of file
diff --git a/kernel/kernel.rs b/kernel/kernel.rs
new file mode 100644
index 0000000..32b1147
--- /dev/null
+++ b/kernel/kernel.rs
@@ -0,0 +1,30 @@
+// Copyright 2025 The Pigweed Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+#![no_std]
+
+use arch::{Arch, ArchInterface};
+use pw_log::info;
+
+pub fn kernel_main() -> ! {
+ info!("Welcome to Maize!");
+ Arch::early_init();
+
+ info!("hello!");
+
+ Arch::init();
+
+ info!("End of kernel test");
+ #[allow(clippy::empty_loop)]
+ loop {}
+}
diff --git a/target/qemu/BUILD.bazel b/target/qemu/BUILD.bazel
index 43d64be..2c56756 100644
--- a/target/qemu/BUILD.bazel
+++ b/target/qemu/BUILD.bazel
@@ -26,6 +26,7 @@
"@rust_crates//:no_std",
],
flags = flags_from_dict({
+ "//arch:arch_backend": "//arch/arm_cortex_m:arm_cortex_m",
"//lib/unittest:unittest_runner": "//lib/unittest:unittest_runner_cortex_m",
"//kernel/sync:spinlock_backend": "//arch/arm_cortex_m:spinlock_backend_cortex_m",
"//target:linker_script": "//target/qemu/linker_scripts:qemu_lm3s6965_linker_script",
@@ -43,6 +44,7 @@
"@rust_crates//:no_std",
],
flags = flags_from_dict({
+ "//arch:arch_backend": "//arch/arm_cortex_m:arm_cortex_m",
"//kernel/sync:spinlock_backend": "//arch/arm_cortex_m:spinlock_backend_cortex_m",
"//target:linker_script": "//target/qemu/linker_scripts:qemu_nrf51823_linker_script",
"//subsys/console:console_backend": "//subsys/console:console_backend_semihosting",
diff --git a/target/qemu/linker_scripts/qemu-lm3s6965.ld b/target/qemu/linker_scripts/qemu-lm3s6965.ld
index f9f4ca6..65bb4d3 100644
--- a/target/qemu/linker_scripts/qemu-lm3s6965.ld
+++ b/target/qemu/linker_scripts/qemu-lm3s6965.ld
@@ -245,16 +245,16 @@
__edata = _pw_static_init_ram_end;
__sidata = LOADADDR(.static_init_ram);
__pre_init = DefaultPreInit;
-DefaultHandler = DefaultHandler_;
-NonMaskableInt = DefaultHandler;
-MemoryManagement = DefaultHandler;
-BusFault = DefaultHandler;
-UsageFault = DefaultHandler;
-SVCall = DefaultHandler;
-DebugMonitor = DefaultHandler;
-PendSV = DefaultHandler;
-SysTick = DefaultHandler;
-HardFault = HardFault_;
+PROVIDE(DefaultHandler = DefaultHandler_);
+PROVIDE(NonMaskableInt = DefaultHandler);
+PROVIDE(MemoryManagement = DefaultHandler);
+PROVIDE(BusFault = DefaultHandler);
+PROVIDE(UsageFault = DefaultHandler);
+PROVIDE(SVCall = DefaultHandler);
+PROVIDE(DebugMonitor = DefaultHandler);
+PROVIDE(PendSV = DefaultHandler);
+PROVIDE(SysTick = DefaultHandler);
+PROVIDE(HardFault = HardFault_);
/* arm-none-eabi expects `end` symbol to point to start of heap for sbrk. */
PROVIDE(end = _pw_zero_init_ram_end);
diff --git a/target/qemu/linker_scripts/qemu-nrf51823.ld b/target/qemu/linker_scripts/qemu-nrf51823.ld
index 44bc37d..eed9203 100644
--- a/target/qemu/linker_scripts/qemu-nrf51823.ld
+++ b/target/qemu/linker_scripts/qemu-nrf51823.ld
@@ -245,16 +245,16 @@
__edata = _pw_static_init_ram_end;
__sidata = LOADADDR(.static_init_ram);
__pre_init = DefaultPreInit;
-DefaultHandler = DefaultHandler_;
-NonMaskableInt = DefaultHandler;
-MemoryManagement = DefaultHandler;
-BusFault = DefaultHandler;
-UsageFault = DefaultHandler;
-SVCall = DefaultHandler;
-DebugMonitor = DefaultHandler;
-PendSV = DefaultHandler;
-SysTick = DefaultHandler;
-HardFault = HardFault_;
+PROVIDE(DefaultHandler = DefaultHandler_);
+PROVIDE(NonMaskableInt = DefaultHandler);
+PROVIDE(MemoryManagement = DefaultHandler);
+PROVIDE(BusFault = DefaultHandler);
+PROVIDE(UsageFault = DefaultHandler);
+PROVIDE(SVCall = DefaultHandler);
+PROVIDE(DebugMonitor = DefaultHandler);
+PROVIDE(PendSV = DefaultHandler);
+PROVIDE(SysTick = DefaultHandler);
+PROVIDE(HardFault = HardFault_);
/* arm-none-eabi expects `end` symbol to point to start of heap for sbrk. */
PROVIDE(end = _pw_zero_init_ram_end);