https://github.com/Starry-OS/Starry-Old#53c549a
Starry初始化依次执行以下内容,这里目前只覆盖单核情况
从这里的_start启动
core::arch::asm!("
mv s0, a0 // save hartid
mv s1, a1 // save DTB pointer
la sp, {boot_stack}
li t0, {boot_stack_size}
add sp, sp, t0 // setup boot stack
call {init_boot_page_table}
call {init_mmu} // setup boot page table and enabel MMU
li s2, {phys_virt_offset} // fix up virtual high address
add sp, sp, s2
mv a0, s0
mv a1, s1
la a2, {entry}
add a2, a2, s2
jalr a2 // call rust_entry(hartid, dtb)
j ." // loop forever to prevent undefine behavior
)随后进入rust_entry
unsafe extern "C" fn rust_entry(cpu_id: usize, dtb: usize) {
axhal::mem::clear_bss(); // Fills the `.bss` section with zeros.
axhal::cpu::init_primary(cpu_id); // Initializes the primary CPU for its pointer.
axhal::platform::time::init_board_info(dtb); //Parse DTB, initialize CPU frequency
axtrap::init_interrupt(); // To initialize the trap vector base address(stvec)
axlog::init();
axlog::set_max_level(option_env!("AX_LOG").unwrap_or("")); // no effect if set `log-level-*` features
axruntime::rust_main(cpu_id, dtb); // kernel submodules, i.e. paging/process/fs/net, initialization
while !axruntime::is_init_ok() {
core::hint::spin_loop();
}
unsafe {
main(); // user program
}
axruntime::exit_main();
}接着进入rust_main
pub extern "C" fn rust_main(cpu_id: usize, dtb: usize) {
//
logging...................................................
..........................................................
//
#[cfg(feature = "alloc")]
init_allocator(); // initializes global heap allocator
#[cfg(feature = "paging")]
remap_kernel_memory().expect("remap kernel memoy failed"); //enable paging, remap kernel memory
axhal::platform_init(); // actually nothing to be done "{}"
axprocess::init_kernel_process(); // initializes kernel process management system
#[cfg(any(feature = "fs", feature = "net", feature = "display"))]
{
#[allow(unused_variables)]
let all_devices = axdriver::init_drivers(); // Probes and initializes all device drivers, returns the [`AllDevices`] struct.
#[cfg(feature = "fs")]
axfs::init_filesystems(all_devices.block); // Initializes filesystems by block devices.
#[cfg(feature = "net")]
axnet::init_network(all_devices.net); // Initializes the network subsystem by NIC devices.
}
#[cfg(feature = "irq")]
init_interrupt(); // initializes time interrupt
INITED_CPUS.fetch_add(1, Ordering::Relaxed); // multi cpu
}- 选择最大空闲内存区域:遍历所有内存区域,找到最大的空闲区域作为主堆。
- 初始化主堆:将最大空闲区域的物理地址转换为虚拟地址,并初始化全局分配器。
- 添加其他空闲区域:将剩余的空闲区域添加到分配器的内存池中,扩展可用堆空间。
- 创建新页表并映射内存区域:先创建新的页表结构,然后遍历所有物理内存内存区域,将每个内存区域的物理地址映射到内核虚拟地址空间(虚实地址转换,标志位设置)。
- 映射测试用例内存:如果启用img,还会将测试用例的物理内存(
img_start_addr)映射到指定的虚拟地址。 - 设置全局页表并激活:新页表赋值给全局变量,然后CPU切换到新页表。
- 创建内核进程对象:构造一个包含进程标识、栈大小、内存空间等属性的内核进程。
- 初始化调度器:准备系统的任务调度机制。
- 关联空闲任务:将当前处理器的空闲任务(如空闲线程)绑定到该进程。
- 注册全局进程表:将进程添加到全局的
PID2PC映射中,便于后续管理。
- 初始化虚拟块设备:
- 创建RAM磁盘:根据配置的
TESTCASE_MEMORY_SIZE初始化一个虚拟块设备。 - 逐块拷贝数据:将物理内存中指定区域(
TESTCASE_MEMORY_START)的数据按块大小(如4KB)拷贝到RAM磁盘。 - 地址转换:
PHYS_VIRT_OFFSET是物理地址到内核虚拟地址的偏移量,用于正确访问内存。 - 安全拷贝:
copy_nonoverlapping确保内存区域不重叠,避免数据损坏。 - 注册设备:将RAM磁盘添加到
AllDevices的块设备列表中。
- 创建RAM磁盘:根据配置的
- 探测物理或虚拟设备,将其注册到全局管理结构。
- 扫描硬件总线识别设备。
- 将设备添加到对应的列表(网络、块设备等)。
- 定义定时器间隔/CPU的截止时间变量
- 更新定时器函数:
- 若当前时间超过截止时间(首次启动或处理延迟),则基于当前时间计算新的截止时间。
- 写入新的截止时间:
deadline + PERIODIC_INTERVAL_NANOS,确保下一次中断间隔固定。 - 设置单次定时器:硬件在
deadline时触发中断,中断处理中再次调用此函数,形成周期性触发。
- 注册定时器中断处理函数:
- 更新定时器:调用
update_timer设置下一次中断。 - 任务调度:若启用多任务,调用
on_timer_tick处理时间片轮转或任务切换。
- 更新定时器:调用
- 启用中断
最终进入用户程序
fn main() {
axstarry::fs_init();
let testcase = "busybox sh";
axstarry::run_testcase(testcase);
axstarry::println(format!("System halted with exit code {}", 0).as_str());
}