21 KiB
21 KiB
NOS Bootloader 内联注释指南
本文档提供NOS引导加载程序关键算法和实现细节的内联注释说明,帮助开发者理解复杂代码的工作原理。
目录
内存分配器
双级分配器设计
双级分配器结合了bump分配器和分离空闲列表的优势:
// 双级分配器结构
pub struct DualLevelAllocator {
heap: UnsafeCell<[u8; BOOTLOADER_HEAP_SIZE]>, // 4MB堆空间
offset: AtomicUsize, // 当前分配偏移
free_list: UnsafeCell<[Option<*mut FreeNode>; NUM_BUCKETS]>, // 分离空闲列表
free_list_size: AtomicUsize, // 空闲列表大小
}
设计原理:
- 大块分配(>256字节): 使用bump分配器,快速简单
- 小块分配(≤256字节): 使用分离空闲列表,支持重用
- 内存对齐: 所有分配64字节对齐,提高缓存效率
分配算法
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let needed_size = layout.size();
// 小块优先从空闲列表分配
if needed_size <= SMALL_BLOCK_THRESHOLD {
if let Some(ptr) = self.alloc_from_free_list(needed_size) {
return ptr;
}
}
// 回退到bump分配器
let current = self.offset.load(Ordering::Relaxed);
let heap_ptr = self.heap.get() as *mut u8;
let aligned = Self::align_up(current, BOOTLOADER_HEAP_ALIGN);
let new_offset = aligned + needed_size;
// 检查是否超出堆边界
if new_offset > BOOTLOADER_HEAP_SIZE {
return core::ptr::null_mut();
}
// 原子更新偏移量
match self.offset.compare_exchange(
current,
new_offset,
Ordering::Release,
Ordering::Relaxed,
) {
Ok(_) => heap_ptr.add(aligned),
Err(actual) => {
// 重试一次
let aligned = Self::align_up(actual, BOOTLOADER_HEAP_ALIGN);
let new_offset = aligned + needed_size;
if new_offset > BOOTLOADER_HEAP_SIZE {
return core::ptr::null_mut();
}
if self.offset.compare_exchange(
actual,
new_offset,
Ordering::Release,
Ordering::Relaxed,
).is_ok() {
heap_ptr.add(aligned)
} else {
core::ptr::null_mut()
}
}
}
}
关键点:
- 原子操作: 使用
compare_exchange确保线程安全 - 内存对齐: 64字节对齐提高缓存效率
- 快速路径: 小块优先从空闲列表分配
- 重试机制: 失败时重试一次,避免死循环
释放与合并算法
unsafe fn add_to_free_list(&self, ptr: *mut u8, size: usize) {
// 检查空闲列表容量
if self.free_list_size.load(Ordering::Relaxed) >= MAX_FREE_LIST_SIZE {
return; // 空闲列表已满,直接丢弃
}
// 步骤1: 检查相邻空闲块并合并
let mut merged_ptr = ptr;
let mut merged_size = size;
let heap_start = self.heap.get() as *mut u8;
let heap_end = heap_start.add(BOOTLOADER_HEAP_SIZE);
// 遍历所有桶查找相邻块
for bucket_index in 0..NUM_BUCKETS {
let bucket_ptr = &mut (*self.free_list.get())[bucket_index];
let mut current = *bucket_ptr;
let mut prev: Option<*mut FreeNode> = None;
while let Some(node) = current {
let node_ptr = node as *mut u8;
let node_ref = node.as_ref().unwrap();
let node_end = node_ptr.add(node_ref.size);
// 检查当前块是否在合并块之前相邻
if node_end == merged_ptr {
// 与前一个块合并
merged_size += node_ref.size;
merged_ptr = node_ptr;
// 从列表中取消链接
if let Some(prev_node) = prev {
(*prev_node).next = node_ref.next;
} else {
*bucket_ptr = node_ref.next;
}
self.free_list_size.fetch_sub(1, Ordering::Relaxed);
break; // 重新开始合并检查
}
// 检查当前块是否在合并块之后相邻
else if merged_ptr.add(merged_size) == node_ptr {
// 与后一个块合并
merged_size += node_ref.size;
// 从列表中取消链接
if let Some(prev_node) = prev {
(*prev_node).next = node_ref.next;
} else {
*bucket_ptr = node_ref.next;
}
self.free_list_size.fetch_sub(1, Ordering::Relaxed);
// 继续检查下一个块
current = node_ref.next;
}
else {
// 移动到列表中的下一个节点
prev = Some(current);
current = node_ref.next;
}
}
}
// 步骤2: 将合并后的块插入适当的桶中
let new_node = merged_ptr as *mut FreeNode;
let new_node_ref = new_node.as_mut().unwrap();
new_node_ref.size = merged_size;
let target_bucket = Self::get_bucket_index(merged_size);
let bucket_ptr = &mut (*self.free_list.get())[target_bucket];
if bucket_ptr.is_none() {
// 空桶,直接插入
(*new_node).next = None;
*bucket_ptr = Some(new_node);
} else {
// 插入桶中,按大小升序排列
let mut current = bucket_ptr.as_ref().copied().unwrap();
let mut prev: Option<*mut FreeNode> = None;
// 查找插入点
while current.as_ref().unwrap().size < merged_size {
prev = Some(current);
match current.as_ref().unwrap().next {
Some(next) => current = next,
None => break,
}
}
// 插入新节点
(*new_node).next = Some(current);
if let Some(prev_node) = prev {
(*prev_node).next = Some(new_node);
} else {
// 在桶开头插入
*bucket_ptr = Some(new_node);
}
}
// 增加空闲列表大小
self.free_list_size.fetch_add(1, Ordering::Relaxed);
}
关键点:
- 相邻块合并: 检查前后相邻块并合并,减少碎片
- 有序插入: 按大小有序插入,便于查找最佳匹配
- 容量限制: 限制空闲列表大小,避免内存浪费
- 原子更新: 使用原子操作更新列表大小
图形渲染系统
双缓冲渲染流程
pub fn swap_buffers(&mut self) -> Result<(), &'static str> {
if self.rendering {
return Err("Cannot swap buffers while rendering");
}
if self.dirty_tracking_enabled && !self.dirty_regions.is_empty() {
// 只更新脏区域
self.update_dirty_regions()?;
} else {
// 全屏更新
self.copy_full_buffer()?;
}
Ok(())
}
设计原理:
- 无闪烁渲染: 后台缓冲区绘制,前台缓冲区显示
- 脏区域跟踪: 只更新变化区域,提高性能
- 全屏回退: 脏区域过多时回退到全屏更新
脏区域合并算法
impl DirtyRect {
/// 合并两个脏区域,返回包含两者的最小矩形
pub fn merge(&self, other: &DirtyRect) -> DirtyRect {
let x1 = self.x.min(other.x);
let y1 = self.y.min(other.y);
let x2 = (self.x + self.width).max(other.x + other.width);
let y2 = (self.y + self.height).max(other.y + other.height);
DirtyRect {
x: x1,
y: y1,
width: x2 - x1,
height: y2 - y1,
}
}
}
关键点:
- 最小包围盒: 计算包含两个区域的最小矩形
- 简单快速: O(1)时间复杂度
- 可能扩大: 合并后的区域可能比原区域总和大
SIMD优化清屏
pub fn clear_screen(&mut self, color: Color) -> Result<(), &'static str> {
let color_val = color.as_argb8888();
let total_pixels = (self.fb.width * self.fb.height) as usize;
let fb_ptr = self.get_draw_buffer();
unsafe {
// 尝试使用SIMD优化(x86_64平台)
#[cfg(target_arch = "x86_64")]
{
use core::arch::x86_64::{_mm_set1_epi32, _mm_storeu_si128};
// 创建4个颜色值的SIMD向量(16字节)
let simd_color = _mm_set1_epi32(color_val as i32);
// 计算可被4整除的像素数
let simd_pixels = total_pixels & !3;
let simd_end = fb_ptr.add(simd_pixels);
// 使用SIMD批量填充
let mut current_ptr = fb_ptr as *mut core::arch::x86_64::__m128i;
while current_ptr < simd_end as *mut _ {
_mm_storeu_si128(current_ptr, simd_color);
current_ptr = current_ptr.add(1);
}
// 处理剩余像素
let remaining = fb_ptr.add(simd_pixels);
let end = fb_ptr.add(total_pixels);
let mut ptr = remaining;
while ptr < end {
ptr::write(ptr, color_val);
ptr = ptr.add(1);
}
}
// 非x86_64平台使用常规块填充
#[cfg(not(target_arch = "x86_64"))]
{
let fb_slice = core::slice::from_raw_parts_mut(fb_ptr, total_pixels);
fb_slice.fill(color_val);
}
}
// 添加脏区域
if self.double_buffer.is_some() {
self.add_dirty_region(0, 0, self.fb.width, self.fb.height);
}
Ok(())
}
优化原理:
- SIMD并行: 一次处理4个像素,提高4倍速度
- 对齐访问: 128位对齐访问,最大化内存带宽
- 平台适配: 非SIMD平台回退到常规填充
- 剩余处理: 处理不能被4整除的剩余像素
VBE实现
VBE模式缓存
pub struct VbeController {
controller_info: Option<VbeControllerInfo>,
supported_modes: Vec<u16>,
mode_cache: hashbrown::HashMap<u16, CachedModeInfo>, // O(1)查找
initialized: bool,
}
缓存优势:
- O(1)查找: 哈希表提供常数时间查找
- 减少BIOS调用: 避免重复的硬件查询
- 预加载: 预先加载常用模式
- 内存换时间: 用少量内存换取性能提升
VBE中断调用
unsafe fn vbe_interrupt(&self, interrupt: u8, regs: &mut VbeRegisters) -> VbeRegisters {
let mut result = VbeRegisters {
ax: regs.ax,
bx: regs.bx,
cx: regs.cx,
dx: regs.dx,
si: regs.si,
di: regs.di,
es: regs.es,
};
// 执行BIOS中断0x10进行VBE调用
asm!(
"int $0x10",
// 输入输出寄存器
inout("ax") result.ax,
inout("bx") result.bx,
inout("cx") result.cx,
inout("dx") result.dx,
inout("si") result.si,
inout("di") result.di,
inout("es") result.es,
// 内存可能被修改
clobber("memory"),
options(att_syntax),
);
result
}
关键点:
- 内联汇编: 直接调用BIOS中断
- 寄存器约束: 正确设置输入输出寄存器
- 内存屏障: 告诉编译器内存可能被修改
- AT&T语法: 使用AT&T汇编语法
引导编排器
引导流程控制
pub fn boot_system(&mut self, cmdline: Option<&str>) -> BootResult<BootInfo> {
// 阶段1: 加载配置
let config = self.load_boot_configuration(cmdline)?;
// 阶段2: 检测硬件
let hw_info = self.hardware_detection.detect_hardware()
.map_err(|e| BootError::HardwareError(e))?;
// 阶段3: 验证先决条件
BootValidator::validate_prerequisites(&config, &hw_info)?;
// 阶段4: 初始化图形
if config.graphics_mode.is_some() {
self.initialize_graphics(&config)?;
}
// 阶段5: 创建引导信息
let mut boot_info = BootInfo::new(self.di_container.protocol_type());
// 阶段6: 加载内核
boot_info.kernel_address = 0x100000;
boot_info.kernel_size = 0x500000;
boot_info.boot_timestamp = 0;
// 阶段7: 验证引导信息
boot_info.validate()?;
Ok(boot_info)
}
设计原则:
- 阶段分离: 明确的引导阶段,便于调试
- 错误处理: 每个阶段都有适当的错误处理
- 可扩展性: 易于添加新的引导阶段
- 依赖管理: 正确的阶段依赖关系
硬件检测
CPU特性检测
pub fn detect_cpu_features(&self) -> CpuFeatures {
let mut features = CpuFeatures::new();
// 使用CPUID指令检测CPU特性
unsafe {
let mut eax: u32;
let mut ebx: u32;
let mut ecx: u32;
let mut edx: u32;
// 基本CPUID信息
asm!(
"cpuid",
in("eax") 1,
out("eax") eax,
out("ebx") ebx,
out("ecx") ecx,
out("edx") edx,
);
// 解析特性标志
if edx & (1 << 23) != 0 { features.set_mmx(); }
if edx & (1 << 25) != 0 { features.set_sse(); }
if edx & (1 << 26) != 0 { features.set_sse2(); }
if ecx & (1 << 0) != 0 { features.set_sse3(); }
if ecx & (1 << 9) != 0 { features.set_ssse3(); }
if ecx & (1 << 19) != 0 { features.set_sse4_1(); }
if ecx & (1 << 20) != 0 { features.set_sse4_2(); }
// 扩展特性检测
asm!(
"cpuid",
in("eax") 0x80000001,
out("eax") eax,
out("ebx") ebx,
out("ecx") ecx,
out("edx") edx,
);
if edx & (1 << 29) != 0 { features.set_long_mode(); }
}
features
}
检测原理:
- CPUID指令: 使用标准CPUID指令获取特性
- 位标志解析: 解析特性寄存器中的位标志
- 扩展检测: 检测扩展特性(如长模式)
- 安全汇编: 使用安全的内联汇编语法
双缓冲机制
脏区域更新算法
fn update_dirty_regions(&self) -> Result<(), &'static str> {
for region in &self.dirty_regions {
self.copy_region(region)?;
}
Ok(())
}
fn copy_region(&self, region: &DirtyRect) -> Result<(), &'static str> {
let fb = &self.fb_info;
// 边界检查
if region.x >= fb.width || region.y >= fb.height {
return Ok(()); // 超出边界的区域忽略
}
// 计算实际复制的区域(裁剪到屏幕边界)
let x_end = (region.x + region.width).min(fb.width);
let y_end = (region.y + region.height).min(fb.height);
let actual_width = x_end - region.x;
let actual_height = y_end - region.y;
unsafe {
for y in region.y..y_end {
let src_offset = (y * fb.width + region.x) as usize;
let dst_offset = (y * fb.width + region.x) as usize;
let src_ptr = self.back_buffer.add(src_offset);
let dst_ptr = self.front_buffer.add(dst_offset);
ptr::copy_nonoverlapping(src_ptr, dst_ptr, actual_width as usize);
}
}
Ok(())
}
优化原理:
- 区域裁剪: 只复制屏幕内的区域
- 逐行复制: 按行复制,提高缓存命中率
- 非重叠复制: 使用
copy_nonoverlapping确保安全 - 边界检查: 防止越界访问
SIMD优化
批量像素绘制
pub fn draw_pixels_batch(&mut self, pixels: &[(u32, u32, Color)]) -> Result<(), &'static str> {
if pixels.is_empty() {
return Ok(());
}
let fb_ptr = self.get_draw_buffer();
// 计算脏区域边界
let mut min_x = u32::MAX;
let mut min_y = u32::MAX;
let mut max_x = 0u32;
let mut max_y = 0u32;
unsafe {
for &(x, y, color) in pixels {
if self.fb.in_bounds(x, y) {
let offset = (y * self.fb.width + x) as usize;
ptr::write(fb_ptr.add(offset), color.as_argb8888());
// 更新脏区域边界
min_x = min_x.min(x);
min_y = min_y.min(y);
max_x = max_x.max(x);
max_y = max_y.max(y);
}
}
}
// 添加脏区域
if self.double_buffer.is_some() && min_x != u32::MAX {
let width = max_x - min_x + 1;
let height = max_y - min_y + 1;
self.add_dirty_region(min_x, min_y, width, height);
}
Ok(())
}
优化原理:
- 批量处理: 减少函数调用开销
- 边界计算: 一次计算所有像素的边界
- 条件检查: 只在需要时添加脏区域
- 内存局部性: 连续访问内存,提高缓存效率
内存对齐优化
64字节对齐策略
fn align_up(addr: usize, align: usize) -> usize {
(addr + align - 1) & !(align - 1)
}
pub fn scanline_bytes(&self) -> usize {
let bytes_per_pixel = (self.bits_per_pixel as usize + 7) / 8;
let raw = self.width as usize * bytes_per_pixel;
// 对齐到64字节边界以提高缓存效率
((raw + 63) / 64) * 64
}
对齐原理:
- 缓存行大小: 64字节是常见缓存行大小
- 对齐公式:
(addr + align - 1) & !(align - 1) - 性能提升: 对齐访问提高内存带宽利用率
- SIMD友好: 对齐内存更适合SIMD操作
错误处理策略
统一错误处理
#[derive(Debug)]
pub enum BootError {
HardwareError(&'static str),
ProtocolInitializationFailed(&'static str),
NotInitialized,
DeviceError(&'static str),
InvalidParameter(&'static str),
}
impl fmt::Display for BootError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
BootError::HardwareError(msg) => write!(f, "硬件错误: {}", msg),
BootError::ProtocolInitializationFailed(msg) => write!(f, "协议初始化失败: {}", msg),
BootError::NotInitialized => write!(f, "组件未初始化"),
BootError::DeviceError(msg) => write!(f, "设备错误: {}", msg),
BootError::InvalidParameter(msg) => write!(f, "无效参数: {}", msg),
}
}
}
错误处理原则:
- 明确分类: 按错误类型分类
- 详细信息: 提供有意义的错误信息
- 可转换性: 实现标准错误特征
- 链式传播: 使用
?操作符传播错误
性能分析
关键路径优化
- 内存分配: 双级分配器减少碎片
- 图形渲染: 双缓冲+脏区域跟踪
- SIMD优化: 利用向量指令加速
- 缓存策略: 模式缓存减少硬件调用
内存使用优化
- 64字节对齐: 提高缓存效率
- 批量操作: 减少函数调用开销
- 延迟初始化: 按需初始化组件
- 资源池: 重用频繁分配的对象
安全考虑
内存安全
- 边界检查: 所有数组访问都进行边界检查
- 生命周期: 正确管理对象生命周期
- 并发安全: 使用原子操作保护共享数据
- unsafe代码: 最小化unsafe代码块
输入验证
- 参数验证: 验证所有输入参数
- 范围检查: 检查数值范围
- 格式验证: 验证数据格式
- 长度检查: 防止缓冲区溢出
调试支持
日志记录
pub fn log_boot_phase(phase: BootPhase, details: &str) {
match phase {
BootPhase::Initialization => println!("[boot] 初始化: {}", details),
BootPhase::HardwareDetection => println!("[boot] 硬件检测: {}", details),
BootPhase::MemoryInitialization => println!("[boot] 内存初始化: {}", details),
BootPhase::GraphicsInitialization => println!("[boot] 图形初始化: {}", details),
BootPhase::KernelLoading => println!("[boot] 内核加载: {}", details),
BootPhase::KernelLoadComplete => println!("[boot] 内核加载完成: {}", details),
BootPhase::ReadyForKernel => println!("[boot] 准备跳转到内核: {}", details),
}
}
性能测量
pub struct BootTimer {
start_time: u64,
}
impl BootTimer {
pub fn new() -> Self {
Self {
start_time: rdtsc(),
}
}
pub fn elapsed(&self) -> u64 {
rdtsc() - self.start_time
}
pub fn elapsed_ms(&self) -> f64 {
let cycles = self.elapsed();
let mhz = cpu_frequency() as f64 / 1_000_000.0;
cycles as f64 / mhz / 1_000.0
}
}
这些内联注释提供了NOS引导加载程序关键算法和实现细节的详细说明,帮助开发者理解代码的工作原理和设计决策。