sparreal_kernel/globals/
mod.rs

1#![allow(unused)]
2
3use core::{
4    cell::UnsafeCell,
5    ops::Range,
6    sync::atomic::{AtomicBool, Ordering},
7};
8
9use alloc::collections::btree_map::BTreeMap;
10use log::debug;
11use percpu::PerCPU;
12use platform::CpuId;
13
14pub use crate::platform::PlatformInfoKind;
15use crate::{
16    mem::PhysAddr,
17    platform::{self, cpu_list},
18};
19
20mod percpu;
21
22pub struct GlobalVal {
23    pub platform_info: PlatformInfoKind,
24    pub kstack_top: PhysAddr,
25    pub main_memory: Range<PhysAddr>,
26    percpu: BTreeMap<CpuId, percpu::PerCPU>,
27}
28
29struct LazyGlobal {
30    g_ok: AtomicBool,
31    cpu_ok: AtomicBool,
32    g: UnsafeCell<Option<GlobalVal>>,
33}
34
35unsafe impl Sync for LazyGlobal {}
36
37static GLOBAL: LazyGlobal = LazyGlobal::new();
38
39pub fn global_val() -> &'static GlobalVal {
40    global_val_meybeuninit().expect("GlobalVal is not init!")
41}
42
43pub fn global_val_meybeuninit() -> Option<&'static GlobalVal> {
44    if !GLOBAL.g_ok.load(Ordering::SeqCst) {
45        return None;
46    }
47    Some(unsafe { (*GLOBAL.g.get()).as_ref().unwrap() })
48}
49
50impl LazyGlobal {
51    const fn new() -> Self {
52        Self {
53            g_ok: AtomicBool::new(false),
54            cpu_ok: AtomicBool::new(false),
55            g: UnsafeCell::new(None),
56        }
57    }
58}
59
60/// 修改全局变量
61///
62/// # Safty
63/// 只能在其他CPU启动前调用
64pub(crate) unsafe fn edit(f: impl FnOnce(&mut GlobalVal)) {
65    unsafe {
66        let global = (*GLOBAL.g.get()).as_mut().unwrap();
67        f(global);
68    }
69}
70
71unsafe fn get_mut() -> &'static mut GlobalVal {
72    unsafe { (*GLOBAL.g.get()).as_mut().unwrap() }
73}
74
75/// # Safty
76/// 只能在其他CPU启动前调用
77pub(crate) unsafe fn setup(platform_info: PlatformInfoKind) -> Result<(), &'static str> {
78    let main_memory = platform_info
79        .main_memory()
80        .ok_or("No memory in platform info")?;
81
82    let g = GlobalVal {
83        platform_info,
84        kstack_top: main_memory.end,
85        main_memory,
86        percpu: Default::default(),
87    };
88
89    unsafe {
90        GLOBAL.g.get().write(Some(g));
91        GLOBAL.g_ok.store(true, Ordering::SeqCst);
92
93        match &mut get_mut().platform_info {
94            PlatformInfoKind::DeviceTree(fdt) => {
95                fdt.setup()?;
96            }
97        }
98    }
99    Ok(())
100}
101
102/// #Safty
103/// 需要在内存初始化完成之后调用
104pub(crate) unsafe fn setup_percpu() {
105    let cpus = cpu_list();
106    let g = unsafe { get_mut() };
107    for cpu in cpus {
108        let percpu = PerCPU::default();
109        g.percpu.insert(cpu.cpu_id, percpu);
110    }
111    GLOBAL.cpu_ok.store(true, Ordering::SeqCst);
112
113    debug!("per cpu data ok");
114}
115
116pub(crate) fn cpu_global() -> &'static PerCPU {
117    cpu_global_meybeuninit().expect("CPU global is not init!")
118}
119
120pub(crate) fn cpu_global_meybeuninit() -> Option<&'static PerCPU> {
121    if !GLOBAL.cpu_ok.load(Ordering::SeqCst) {
122        return None;
123    }
124
125    let g = unsafe { get_mut() };
126    Some(g.percpu.get(&platform::cpu_id()).unwrap())
127}
128
129pub(crate) unsafe fn cpu_global_mut() -> &'static mut PerCPU {
130    unsafe { cpu_global_mut_meybeunint().expect("CPU global is not init!") }
131}
132
133pub(crate) unsafe fn cpu_global_mut_meybeunint() -> Option<&'static mut PerCPU> {
134    if !GLOBAL.cpu_ok.load(Ordering::SeqCst) {
135        return None;
136    }
137
138    let g = unsafe { get_mut() };
139    Some(g.percpu.get_mut(&platform::cpu_id()).unwrap())
140}