|
@@ -39,43 +39,44 @@ pub const R_RISCV_RELATIVE: usize = 3;
|
|
|
|
|
|
#[no_mangle]
|
|
#[no_mangle]
|
|
extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
- // parse dynamic information
|
|
|
|
|
|
+ // Track whether SBI is initialized and ready.
|
|
static SBI_READY: AtomicBool = AtomicBool::new(false);
|
|
static SBI_READY: AtomicBool = AtomicBool::new(false);
|
|
|
|
|
|
let boot_hart_info = platform::get_boot_hart(opaque, nonstandard_a2);
|
|
let boot_hart_info = platform::get_boot_hart(opaque, nonstandard_a2);
|
|
- // boot hart task entry
|
|
|
|
|
|
+ // boot hart task entry.
|
|
if boot_hart_info.is_boot_hart {
|
|
if boot_hart_info.is_boot_hart {
|
|
let fdt_addr = boot_hart_info.fdt_address;
|
|
let fdt_addr = boot_hart_info.fdt_address;
|
|
|
|
|
|
// 1. Init FDT
|
|
// 1. Init FDT
|
|
- // parse the device tree
|
|
|
|
- // TODO: shoule remove `fail:device_tree_format`
|
|
|
|
|
|
+ // parse the device tree.
|
|
|
|
+ // TODO: shoule remove `fail:device_tree_format`.
|
|
let dtb = dt::parse_device_tree(fdt_addr).unwrap_or_else(fail::device_tree_format);
|
|
let dtb = dt::parse_device_tree(fdt_addr).unwrap_or_else(fail::device_tree_format);
|
|
let dtb = dtb.share();
|
|
let dtb = dtb.share();
|
|
|
|
|
|
- // TODO: should remove `fail:device_tree_deserialize`
|
|
|
|
|
|
+ // TODO: should remove `fail:device_tree_deserialize`.
|
|
let tree =
|
|
let tree =
|
|
serde_device_tree::from_raw_mut(&dtb).unwrap_or_else(fail::device_tree_deserialize);
|
|
serde_device_tree::from_raw_mut(&dtb).unwrap_or_else(fail::device_tree_deserialize);
|
|
|
|
|
|
// 2. Init device
|
|
// 2. Init device
|
|
- // TODO: The device base address should be find in a better way
|
|
|
|
|
|
+ // TODO: The device base address should be find in a better way.
|
|
let console_base = tree.soc.serial.unwrap().iter().next().unwrap();
|
|
let console_base = tree.soc.serial.unwrap().iter().next().unwrap();
|
|
let clint_device = tree.soc.clint.unwrap().iter().next().unwrap();
|
|
let clint_device = tree.soc.clint.unwrap().iter().next().unwrap();
|
|
let cpu_num = tree.cpus.cpu.len();
|
|
let cpu_num = tree.cpus.cpu.len();
|
|
let console_base_address = console_base.at();
|
|
let console_base_address = console_base.at();
|
|
let ipi_base_address = clint_device.at();
|
|
let ipi_base_address = clint_device.at();
|
|
|
|
|
|
- // Set reset device if found it
|
|
|
|
|
|
+ // Initialize reset device if present.
|
|
if let Some(test) = tree.soc.test {
|
|
if let Some(test) = tree.soc.test {
|
|
let reset_device = test.iter().next().unwrap();
|
|
let reset_device = test.iter().next().unwrap();
|
|
let reset_base_address = reset_device.at();
|
|
let reset_base_address = reset_device.at();
|
|
board::reset_dev_init(usize::from_str_radix(reset_base_address, 16).unwrap());
|
|
board::reset_dev_init(usize::from_str_radix(reset_base_address, 16).unwrap());
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Initialize console and IPI devices.
|
|
board::console_dev_init(usize::from_str_radix(console_base_address, 16).unwrap());
|
|
board::console_dev_init(usize::from_str_radix(console_base_address, 16).unwrap());
|
|
board::ipi_dev_init(usize::from_str_radix(ipi_base_address, 16).unwrap());
|
|
board::ipi_dev_init(usize::from_str_radix(ipi_base_address, 16).unwrap());
|
|
|
|
|
|
- // 3. Init SBI
|
|
|
|
|
|
+ // 3. Init the SBI implementation
|
|
unsafe {
|
|
unsafe {
|
|
SBI_IMPL = MaybeUninit::new(SBI {
|
|
SBI_IMPL = MaybeUninit::new(SBI {
|
|
console: Some(SbiConsole::new(&UART)),
|
|
console: Some(SbiConsole::new(&UART)),
|
|
@@ -85,12 +86,14 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
rfence: Some(SbiRFence),
|
|
rfence: Some(SbiRFence),
|
|
});
|
|
});
|
|
}
|
|
}
|
|
- // 设置陷入栈
|
|
|
|
|
|
+
|
|
|
|
+ // Setup trap handling.
|
|
trap_stack::prepare_for_trap();
|
|
trap_stack::prepare_for_trap();
|
|
extensions::init(&tree.cpus.cpu);
|
|
extensions::init(&tree.cpus.cpu);
|
|
SBI_READY.swap(true, Ordering::AcqRel);
|
|
SBI_READY.swap(true, Ordering::AcqRel);
|
|
|
|
+
|
|
// 4. Init Logger
|
|
// 4. Init Logger
|
|
- logger::Logger::init();
|
|
|
|
|
|
+ logger::Logger::init().unwrap();
|
|
|
|
|
|
info!("RustSBI version {}", rustsbi::VERSION);
|
|
info!("RustSBI version {}", rustsbi::VERSION);
|
|
rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
|
|
rustsbi::LOGO.lines().for_each(|line| info!("{}", line));
|
|
@@ -120,9 +123,11 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
pmpaddr1::write(usize::MAX >> 2);
|
|
pmpaddr1::write(usize::MAX >> 2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Get boot information and prepare for kernel entry.
|
|
let boot_info = platform::get_boot_info(nonstandard_a2);
|
|
let boot_info = platform::get_boot_info(nonstandard_a2);
|
|
let (mpp, next_addr) = (boot_info.mpp, boot_info.next_address);
|
|
let (mpp, next_addr) = (boot_info.mpp, boot_info.next_address);
|
|
- // 设置内核入口
|
|
|
|
|
|
+
|
|
|
|
+ // Start kernel.
|
|
local_remote_hsm().start(NextStage {
|
|
local_remote_hsm().start(NextStage {
|
|
start_addr: next_addr,
|
|
start_addr: next_addr,
|
|
next_mode: mpp,
|
|
next_mode: mpp,
|
|
@@ -136,7 +141,9 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
mpp
|
|
mpp
|
|
);
|
|
);
|
|
} else {
|
|
} else {
|
|
- // TODO: PMP configuration needs to be obtained through the memory range in the device tree
|
|
|
|
|
|
+ // Non-boot hart initialization path.
|
|
|
|
+
|
|
|
|
+ // TODO: PMP configuration needs to be obtained through the memory range in the device tree.
|
|
use riscv::register::*;
|
|
use riscv::register::*;
|
|
unsafe {
|
|
unsafe {
|
|
pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
|
|
pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false);
|
|
@@ -145,23 +152,29 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
pmpaddr1::write(usize::MAX >> 2);
|
|
pmpaddr1::write(usize::MAX >> 2);
|
|
}
|
|
}
|
|
|
|
|
|
- // 设置陷入栈
|
|
|
|
|
|
+ // Setup trap handling.
|
|
trap_stack::prepare_for_trap();
|
|
trap_stack::prepare_for_trap();
|
|
|
|
|
|
- // waiting for sbi ready
|
|
|
|
|
|
+ // Wait for boot hart to complete SBI initialization.
|
|
while !SBI_READY.load(Ordering::Relaxed) {
|
|
while !SBI_READY.load(Ordering::Relaxed) {
|
|
core::hint::spin_loop()
|
|
core::hint::spin_loop()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ // Clear all pending IPIs.
|
|
ipi::clear_all();
|
|
ipi::clear_all();
|
|
|
|
+
|
|
|
|
+ // Configure CSRs and trap handling.
|
|
unsafe {
|
|
unsafe {
|
|
|
|
+ // Delegate all interrupts and exceptions to supervisor mode.
|
|
asm!("csrw mideleg, {}", in(reg) !0);
|
|
asm!("csrw mideleg, {}", in(reg) !0);
|
|
asm!("csrw medeleg, {}", in(reg) !0);
|
|
asm!("csrw medeleg, {}", in(reg) !0);
|
|
asm!("csrw mcounteren, {}", in(reg) !0);
|
|
asm!("csrw mcounteren, {}", in(reg) !0);
|
|
use riscv::register::{medeleg, mtvec};
|
|
use riscv::register::{medeleg, mtvec};
|
|
|
|
+ // Keep supervisor environment calls and illegal instructions in M-mode.
|
|
medeleg::clear_supervisor_env_call();
|
|
medeleg::clear_supervisor_env_call();
|
|
medeleg::clear_illegal_instruction();
|
|
medeleg::clear_illegal_instruction();
|
|
|
|
+ // Configure environment features based on available extensions.
|
|
if hart_extension_probe(current_hartid(), Extension::Sstc) {
|
|
if hart_extension_probe(current_hartid(), Extension::Sstc) {
|
|
menvcfg::set_bits(
|
|
menvcfg::set_bits(
|
|
menvcfg::STCE | menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE,
|
|
menvcfg::STCE | menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE,
|
|
@@ -169,6 +182,7 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
} else {
|
|
} else {
|
|
menvcfg::set_bits(menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE);
|
|
menvcfg::set_bits(menvcfg::CBIE_INVALIDATE | menvcfg::CBCFE | menvcfg::CBZE);
|
|
}
|
|
}
|
|
|
|
+ // Set up vectored trap handling.
|
|
mtvec::write(trap_vec as _, mtvec::TrapMode::Vectored);
|
|
mtvec::write(trap_vec as _, mtvec::TrapMode::Vectored);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -178,39 +192,39 @@ extern "C" fn rust_main(_hart_id: usize, opaque: usize, nonstandard_a2: usize) {
|
|
#[export_name = "_start"]
|
|
#[export_name = "_start"]
|
|
unsafe extern "C" fn start() -> ! {
|
|
unsafe extern "C" fn start() -> ! {
|
|
core::arch::asm!(
|
|
core::arch::asm!(
|
|
- // 1. Turn off interrupt
|
|
|
|
|
|
+ // 1. Turn off interrupt.
|
|
" csrw mie, zero",
|
|
" csrw mie, zero",
|
|
- // 2. Initialize programming langauge runtime
|
|
|
|
- // only clear bss if hartid matches preferred boot hart id
|
|
|
|
|
|
+ // 2. Initialize programming langauge runtime.
|
|
|
|
+ // only clear bss if hartid matches preferred boot hart id.
|
|
" csrr t0, mhartid",
|
|
" csrr t0, mhartid",
|
|
" bne t0, zero, 4f",
|
|
" bne t0, zero, 4f",
|
|
" call {relocation_update}",
|
|
" call {relocation_update}",
|
|
"1:",
|
|
"1:",
|
|
- // 3. Hart 0 clear bss segment
|
|
|
|
|
|
+ // 3. Hart 0 clear bss segment.
|
|
" lla t0, sbss
|
|
" lla t0, sbss
|
|
lla t1, ebss
|
|
lla t1, ebss
|
|
2: bgeu t0, t1, 3f
|
|
2: bgeu t0, t1, 3f
|
|
sd zero, 0(t0)
|
|
sd zero, 0(t0)
|
|
addi t0, t0, 8
|
|
addi t0, t0, 8
|
|
j 2b",
|
|
j 2b",
|
|
- "3: ", // Hart 0 set bss ready signal
|
|
|
|
|
|
+ "3: ", // Hart 0 set bss ready signal.
|
|
" lla t0, 6f
|
|
" lla t0, 6f
|
|
li t1, 1
|
|
li t1, 1
|
|
amoadd.w t0, t1, 0(t0)
|
|
amoadd.w t0, t1, 0(t0)
|
|
j 5f",
|
|
j 5f",
|
|
- "4:", // Other harts are waiting for bss ready signal
|
|
|
|
|
|
+ "4:", // Other harts are waiting for bss ready signal.
|
|
" li t1, 1
|
|
" li t1, 1
|
|
lla t0, 6f
|
|
lla t0, 6f
|
|
lw t0, 0(t0)
|
|
lw t0, 0(t0)
|
|
bne t0, t1, 4b",
|
|
bne t0, t1, 4b",
|
|
"5:",
|
|
"5:",
|
|
- // 4. Prepare stack for each hart
|
|
|
|
|
|
+ // 4. Prepare stack for each hart.
|
|
" call {locate_stack}",
|
|
" call {locate_stack}",
|
|
" call {main}",
|
|
" call {main}",
|
|
" csrw mscratch, sp",
|
|
" csrw mscratch, sp",
|
|
" j {hart_boot}",
|
|
" j {hart_boot}",
|
|
" .balign 4",
|
|
" .balign 4",
|
|
- "6:", // bss ready signal
|
|
|
|
|
|
+ "6:", // bss ready signal.
|
|
" .word 0",
|
|
" .word 0",
|
|
relocation_update = sym relocation_update,
|
|
relocation_update = sym relocation_update,
|
|
locate_stack = sym trap_stack::locate,
|
|
locate_stack = sym trap_stack::locate,
|
|
@@ -220,15 +234,16 @@ unsafe extern "C" fn start() -> ! {
|
|
)
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+// Handle relocations for position-independent code
|
|
#[naked]
|
|
#[naked]
|
|
unsafe extern "C" fn relocation_update() {
|
|
unsafe extern "C" fn relocation_update() {
|
|
asm!(
|
|
asm!(
|
|
- // Get load offset
|
|
|
|
|
|
+ // Get load offset.
|
|
" li t0, {START_ADDRESS}",
|
|
" li t0, {START_ADDRESS}",
|
|
" lla t1, .text.entry",
|
|
" lla t1, .text.entry",
|
|
" sub t2, t1, t0",
|
|
" sub t2, t1, t0",
|
|
|
|
|
|
- // Foreach rela.dyn and update relocation
|
|
|
|
|
|
+ // Foreach rela.dyn and update relocation.
|
|
" lla t0, __rel_dyn_start",
|
|
" lla t0, __rel_dyn_start",
|
|
" lla t1, __rel_dyn_end",
|
|
" lla t1, __rel_dyn_end",
|
|
" li t3, {R_RISCV_RELATIVE}",
|
|
" li t3, {R_RISCV_RELATIVE}",
|