内核入口
我们知道,当内核被引导时,我们唯一可以确定的通用寄存器是 pc,包括 sp 在内的其他可写通用寄存器是没有意义的。也就是说,我们甚至没有函数栈。因此,在执行到内核的第一条指令时,我们无法使用任何常规的高级语言,必须使用机器码或者汇编。并利用这些代码设置函数栈。
此外,由于 qemu 会从 0x80000000 开始执行,所以我们还必须将入口点的代码放到单独的一个段里面,并在 linker script 中保证这个段的地址从 0x80000000 开始。
编写内核入口的代码
我们可以先编写一个简单的内核入口代码,然后再将其放到一个单独的段中。这个代码的功能很简单,就是设置函数栈,然后调用高级语言的函数(我们这里以 rust_main
命名)。
.section .text.entry
.globl _start
_start:
la sp, boot_stack_top
call rust_main
.section .bss.stack
.globl boot_stack_lower_bound
boot_stack_lower_bound:
.space 4096 * 16
.globl boot_stack_top
boot_stack_top:
由于 RISCV 中栈是向下生长的,所以我们将栈的起始地址设置为 boot_stack_top
。
嵌入代码到内核
利用 core::arch::global_asm
宏,我们可以将上面的汇编代码嵌入到内核中。具体来说,我们需要在一个 rust 源文件中加入如下代码:(假设上述代码保存在 entry.asm
文件中)
use core::arch::global_asm;
global_asm!(include_str!("entry.asm"));