rust-embedded/rust-raspberrypi-OS-tutorials · error

Invalid KERNEL_STATE

Error message

Invalid KERNEL_STATE

What it means

The kernel state machine stores its state in an AtomicU8 with sentinel values (INIT, SINGLE_CORE_MAIN, MULTI_CORE_MAIN). state() loads the atomic and panics if the raw value matches none of the known sentinels, indicating corrupted or uninitialized KERNEL_STATE memory. is_init() calls state(), so any state query on corrupted state panics.

Source

Thrown at 20_timer_callbacks/kernel/src/state.rs:68

impl StateManager {
    const INIT: u8 = 0;
    const SINGLE_CORE_MAIN: u8 = 1;
    const MULTI_CORE_MAIN: u8 = 2;

    /// Create a new instance.
    pub const fn new() -> Self {
        Self(AtomicU8::new(Self::INIT))
    }

    /// Return the current state.
    fn state(&self) -> State {
        let state = self.0.load(Ordering::Acquire);

        match state {
            Self::INIT => State::Init,
            Self::SINGLE_CORE_MAIN => State::SingleCoreMain,
            Self::MULTI_CORE_MAIN => State::MultiCoreMain,
            _ => panic!("Invalid KERNEL_STATE"),
        }
    }

    /// Return if the kernel is init state.
    pub fn is_init(&self) -> bool {
        self.state() == State::Init
    }

    /// Transition from Init to SingleCoreMain.
    pub fn transition_to_single_core_main(&self) {
        if self
            .0
            .compare_exchange(
                Self::INIT,
                Self::SINGLE_CORE_MAIN,
                Ordering::Acquire,
                Ordering::Relaxed,
            )

View on GitHub (pinned to 644474cc09)

Solutions

  1. Ensure KERNEL_STATE is initialized (to INIT) at/before its first use — check static initialization in state.rs.
  2. Find any code writing raw values into the atomic and validate it uses the defined constants only.
  3. Initialize the atomic with Self::INIT as its default value so it can never hold a sentinel-unknown value.
  4. Check linker script / memory layout for overlap with other statics that could corrupt this cell.
  5. Gate early-boot callers so is_init() isn't invoked before state setup.

Example fix

// before
static KERNEL_STATE: AtomicU8 = AtomicU8::new(0xff);
// after
static KERNEL_STATE: AtomicU8 = AtomicU8::new(KernelState::INIT as u8);
Defensive patterns

Strategy: validation

Validate before calling

fn state_is_known(raw: u8) -> bool {
    matches!(raw, s if s == INIT || s == SINGLE_CORE_MAIN || s == MULTI_CORE_MAIN)
}

Type guard

fn valid_kernel_state(raw: u8) -> Option<State> {
    match raw {
        x if x == INIT => Some(State::Init),
        x if x == SINGLE_CORE_MAIN => Some(State::SingleCoreMain),
        x if x == MULTI_CORE_MAIN => Some(State::MultiCoreMain),
        _ => None,
    }
}

Try / catch

// Panic aborts in no_std; validate raw value before querying:
let raw = KERNEL_STATE.load(Ordering::Acquire);
if valid_kernel_state(raw).is_none() {
    log::error!("corrupted KERNEL_STATE: {}", raw);
    halt();
}

Prevention

When it happens

Trigger: Reading kernel state before the static KERNEL_STATE was initialized with a valid value (memory not zeroed/initialized to INIT); memory corruption overwriting the atomic; a bad transmute/write to the static from elsewhere; calling is_init()/state() on a wrongly constructed StateProvider.

Common situations: Early-boot code querying state before state initialization in .bss/.data setup; linker/script changes that clobber the static; concurrent unynchronized writes to the state cell; hand-edited sentinel constants.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of rust-embedded/rust-raspberrypi-OS-tutorials@644474cc09 (2026-09-06). Data as JSON: /api/errors/06e09030f1214d4c. Report an issue: GitHub.