Skip to main content

proka_bootloader/
lib.rs

1//! # Proka Bootloader - The bootloader of ProkaOS
2//!
3//! [![Rust Nightly](https://img.shields.io/badge/rust-nightly-orange?style=flat-square&logo=rust)](https://www.rust-lang.org/)
4//! [![License: GPLv3](https://img.shields.io/badge/License-GPLv3-yellow.svg?style=flat-square)](https://opensource.org/license/gpl-3.0)
5//! [![GitHub Stars](https://img.shields.io/github/stars/RainSTR-Studio/proka-bootloader?style=flat-square)](https://github.com/RainSTR-Studio/proka-bootloader/stargazers)
6//! [![GitHub Issues](https://img.shields.io/github/issues/RainSTR-Studio/proka-bootloader?style=flat-square)](https://github.com/RainSTR-Studio/proka-bootloader/issues)
7//! [![GitHub Pull Requests](https://img.shields.io/github/issues-pr/RainSTR-Studio/proka-bootloader?style=flat-square)](https://github.com/RainSTR-Studio/proka-bootloader/pulls)
8//! [![Documentation](https://img.shields.io/badge/docs-prokadoc-brightgreen?style=flat-square)](https://prokadoc.pages.dev/)
9//!
10//!**Copyright (C) 2026 RainSTR Studio. All rights reserved.**
11//!
12//!---
13//!
14//! ## Introduction
15//! This crate provides the struct, enums about the Proka
16//! bootloader, including the boot information, and so on.
17//!
18//! # Example
19//! Here's an example to use this crateb
20//!
21//! ```rust
22//! #![no_std]
23//! #![no_main]
24//! #![feature(custom_test_frameworks)]
25//! #![test_runner(self::test_runner)]
26//! #![reexport_test_harness_main = "test_main"]
27//!
28//! use proka_bootloader::BootInfo;
29//! use core::panic::PanicInfo;
30//!
31//! // Panic handler
32//! #[panic_handler]
33//! pub fn panic(_: &PanicInfo) -> ! {
34//!     loop {}
35//! }
36//! #[unsafe(no_mangle)]
37//! #[unsafe(link_section = ".text")]
38//! pub extern "C" fn kernel_main() -> ! {
39//!     let info = proka_bootloader::get_bootinfo();
40//!     let framebuffer = info.framebuffer();
41//!     unsafe {
42//!         let ptr = framebuffer.address() as *mut u8;     
43//!         for i in 0..500 {   
44//!             let offset = framebuffer.pitch() * i + i * framebuffer.bpp();
45//!             ptr.add(offset as usize).cast::<u32>().write(0x00FFFFFF);
46//!         }
47//!     }
48//!     loop {}
49//! }
50//! // Test runner
51//! #[cfg(test)]
52//! fn test_runner(tests: &[&'static dyn Fn()]) {
53//!     for test in tests {
54//!         test();
55//!     }
56//! }
57//! ```
58//!
59//! //! # LICENSE
60//! This crate is under license [GPL-v3](https://github.com/RainSTR-Studio/proka-exec/blob/main/LICENSE),
61//! and you must follow its rules.
62//!
63//! See [LICENSE](https://github.com/RainSTR-Studio/proka-exec/blob/main/LICENSE) file for more details.
64//!
65//! ## MSRV
66//! This crate's MSRV is `1.85.0` stable.
67#![no_std]
68#![no_main]
69#![feature(custom_test_frameworks)]
70#![test_runner(self::test_runner)]
71#![reexport_test_harness_main = "test_main"]
72
73pub mod header;
74#[cfg(feature = "loader_main")]
75pub mod loader_main;
76pub mod memory;
77pub mod output;
78mod version;
79use self::memory::MemoryMap;
80use self::output::Framebuffer;
81
82/// This struct is the boot information struct, which provides
83/// the basic information, *memory map*, and so on.
84#[repr(C)]
85#[derive(Debug, Clone, PartialEq, Eq)]
86pub struct BootInfo {
87    boot_mode: BootMode,
88    framebuffer: Framebuffer,
89    memmap: MemoryMap,
90    acpi_addr: u64,
91}
92
93impl BootInfo {
94    /// Initialize a new boot info object.
95    ///
96    /// Note: this object will be initialized by loader
97    /// automatically, so if you are a kernel developer, do
98    /// not use this method, because you needn't and unusable.
99    #[cfg(feature = "loader_main")]
100    pub fn new(boot_mode: BootMode, memmap: MemoryMap, fb: Framebuffer, acpi_addr: u64) -> Self {
101        Self {
102            boot_mode,
103            acpi_addr,
104            memmap,
105            framebuffer: fb,
106        }
107    }
108
109    /// Get the boot mode.
110    pub const fn boot_mode(&self) -> &BootMode {
111        &self.boot_mode
112    }
113
114    /// Get the framebuffer info.
115    pub const fn framebuffer(&self) -> &Framebuffer {
116        &self.framebuffer
117    }
118
119    /// Get the memory map.
120    pub const fn memory(&self) -> &MemoryMap {
121        &self.memmap
122    }
123
124    /// Get the ACPI RSDP's address.
125    pub const fn acpi(&self) -> u64 {
126        self.acpi_addr
127    }
128}
129
130/// This is the boot mode, only support 2 modes, which are legacy(BIOS) and UEFI.
131#[repr(C)]
132#[derive(Debug, Clone, Copy, PartialEq, Eq)]
133pub enum BootMode {
134    /// The Legacy boot mode, also called BIOS boot mode.
135    ///
136    /// This mode is for older machine, and we needs implement
137    /// lots of things in it.
138    Legacy,
139
140    /// The UEFI boot mode, which is the newer mode. Lots of
141    /// new machines uses it.
142    ///
143    /// Also, some machine only support it (such as mine awa).
144    Uefi,
145}
146
147/// Get the bootinfo.
148///
149/// The BootInfo is pre-copied & fixed at the dedicated constant physical address
150/// 0x10000 by UEFI boot stage, never modified nor released in kernel lifetime.
151///
152/// # Safety
153/// Caller must ensure **before invoking**:
154/// 1. Address `0x10000` is allocated & filled with valid initialized BootInfo;
155/// 2. This range is reserved, never overwritten/freed by kernel/UEFI;
156/// 3. No mutable aliasing exists for this memory region.
157///
158/// These steps are already guaranteed by the bootloader, so invocation is generally safe
159/// in normal kernel runtime.
160///
161/// # Returns
162/// - `&'static BootInfo`: immutable static reference to the pre-filled BootInfo
163pub const fn get_bootinfo() -> &'static BootInfo {
164    const BI_PHYS: u64 = 0x10000;
165    unsafe { &*(BI_PHYS as *const BootInfo) }
166}
167
168#[cfg(test)]
169fn test_runner(tests: &[&dyn Fn()]) {
170    for test in tests {
171        test();
172    }
173}