Skip to main content

init/
lib.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#![no_std]
8
9pub use paste::paste;
10
11#[repr(transparent)]
12#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
13pub struct LkInitLevel(pub u32);
14
15pub type LkInitHook = extern "C" fn(level: LkInitLevel);
16
17pub const LK_INIT_LEVEL_EARLIEST: LkInitLevel = LkInitLevel(1);
18
19// Arch and platform specific init required to get system into a known state
20// and parsing the kernel command line.
21//
22// Most code should be deferred to later stages if possible, after the command
23// line is parsed and a debug UART is available.
24pub const LK_INIT_LEVEL_ARCH_EARLY: LkInitLevel = LkInitLevel(0x10000);
25pub const LK_INIT_LEVEL_PLATFORM_EARLY: LkInitLevel = LkInitLevel(0x20000);
26
27// Arch and platform specific code that needs to run prior to heap/virtual
28// memory being set up.
29//
30// The kernel command line and a UART is available, but no heap or VM.
31pub const LK_INIT_LEVEL_ARCH_PREVM: LkInitLevel = LkInitLevel(0x30000);
32pub const LK_INIT_LEVEL_PLATFORM_PREVM: LkInitLevel = LkInitLevel(0x40000);
33
34// Heap and VM initialization.
35pub const LK_INIT_LEVEL_VM_PREHEAP: LkInitLevel = LkInitLevel(0x50000);
36pub const LK_INIT_LEVEL_HEAP: LkInitLevel = LkInitLevel(0x60000);
37pub const LK_INIT_LEVEL_VM: LkInitLevel = LkInitLevel(0x70000);
38
39// Interrupt controller is available.
40pub const LK_INIT_LEVEL_INTC: LkInitLevel = LkInitLevel(0x78000);
41
42// Kernel and threading setup.
43pub const LK_INIT_LEVEL_TOPOLOGY: LkInitLevel = LkInitLevel(0x80000);
44pub const LK_INIT_LEVEL_KERNEL: LkInitLevel = LkInitLevel(0x90000);
45pub const LK_INIT_LEVEL_THREADING: LkInitLevel = LkInitLevel(0xa0000);
46
47// Arch and platform specific set up.
48//
49// Kernel heap, VM, and threads are available. Most init code should go
50// in these stages.
51pub const LK_INIT_LEVEL_ARCH: LkInitLevel = LkInitLevel(0xb0000);
52pub const LK_INIT_LEVEL_PLATFORM: LkInitLevel = LkInitLevel(0xc0000);
53pub const LK_INIT_LEVEL_ARCH_LATE: LkInitLevel = LkInitLevel(0xd0000);
54
55// At this level we wait for secondary CPUs to finish booting and "check-in" as ready.
56//
57// See also mp_wait_for_all_cpus_ready.
58pub const LK_INIT_LEVEL_SMP_WAIT: LkInitLevel = LkInitLevel(0xd4000);
59
60// At this level the secondary CPUs have checked-in.
61pub const LK_INIT_LEVEL_SMP_READY: LkInitLevel = LkInitLevel(0xd8000);
62
63// Userspace started.
64pub const LK_INIT_LEVEL_USER: LkInitLevel = LkInitLevel(0xe0000);
65pub const LK_INIT_LEVEL_LAST: LkInitLevel = LkInitLevel(u32::MAX);
66
67#[repr(u32)]
68#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)]
69pub enum LkInitFlags {
70    PrimaryCpu = 0x1,
71    SecondaryCpus = 0x2,
72    AllCpus = 0x3,
73}
74
75#[repr(C)]
76pub struct LkInitStruct {
77    pub level: LkInitLevel,
78    pub flags: LkInitFlags,
79    pub hook: LkInitHook,
80    pub name: *const core::ffi::c_char,
81}
82
83// Safety: LkInitStruct structures placed in the lk_init section are read-only
84// after boot and safe to share between threads.
85unsafe impl core::marker::Sync for LkInitStruct {}
86
87// Verify size and alignment compatibility with C++ structs.
88zr::static_assert!(core::mem::size_of::<LkInitStruct>() == 24);
89zr::static_assert!(core::mem::align_of::<LkInitStruct>() == 8);
90
91#[macro_export]
92macro_rules! lk_init_hook_flags {
93    ($var_name:ident, $hook:expr, $level:expr, $flags:expr) => {
94        $crate::paste! {
95        extern "C" fn [< _init_struct_fn_wrapper_ $var_name >](level: $crate::LkInitLevel) {
96            ($hook)(level)
97        }
98        #[used]
99        #[unsafe(link_section = ".data.rel.ro.lk_init")]
100        pub static [<  _init_struct_ $var_name >]: $crate::LkInitStruct = $crate::LkInitStruct {
101            level: $level,
102            flags: $flags,
103            hook: [< _init_struct_fn_wrapper_ $var_name >],
104            name: core::concat!(core::stringify!($var_name), "\0").as_ptr()
105                as *const core::ffi::c_char,
106        };
107        }
108    };
109}
110
111#[macro_export]
112macro_rules! lk_init_hook {
113    ($var_name:ident, $hook:expr, $level:expr) => {
114        $crate::lk_init_hook_flags!($var_name, $hook, $level, $crate::LkInitFlags::PrimaryCpu);
115    };
116}