Rewrite the ARM entry points to be pure assembly
tomaka opened this issue · 0 comments
tomaka commented
redshirt/kernel/standalone/src/arch/arm.rs
Lines 52 to 137 in d047867
/// This is the main entry point of the kernel for ARM 32bits architectures. | |
#[cfg(target_arch = "arm")] | |
#[export_name = "_start"] | |
#[naked] | |
unsafe extern "C" fn entry_point_arm32() -> ! { | |
// TODO: always fails :-/ | |
/*#[cfg(not(any(target_feature = "armv7-a", target_feature = "armv7-r")))] | |
compile_error!("The ARMv7-A or ARMv7-R instruction sets must be enabled");*/ | |
// Detect which CPU we are. | |
// | |
// See sections B4.1.106 and B6.1.67 of the ARM® Architecture Reference Manual | |
// (ARMv7-A and ARMv7-R edition). | |
// | |
// This is specific to ARMv7-A and ARMv7-R, hence the compile_error! above. | |
asm!( | |
" | |
mrc p15, 0, r5, c0, c0, 5 | |
and r5, r5, #3 | |
cmp r5, #0 | |
bne {} | |
", | |
sym halt, | |
out("r3") _, out("r5") _, | |
options(nomem, nostack, preserves_flags) | |
); | |
// Only one CPU reaches here. | |
// Zero the memory requested to be zero'ed. | |
// TODO: that's illegal ; naked functions must only contain an asm! block (for good reasons) | |
let mut ptr = &mut $memory_zeroing_start as *mut u8; | |
while ptr < &mut $memory_zeroing_end as *mut u8 { | |
ptr.write_volatile(0); | |
ptr = ptr.add(1); | |
} | |
// Set up the stack and jump to the entry point. | |
asm!(" | |
.comm stack, 0x400000, 8 | |
ldr sp, =stack+0x400000 | |
b {} | |
", | |
sym cpu_enter, | |
options(noreturn) | |
) | |
} | |
/// This is the main entry point of the kernel for ARM 64bits architectures. | |
#[cfg(target_arch = "aarch64")] | |
#[export_name = "_start"] | |
#[naked] | |
unsafe extern "C" fn entry_point_arm64() -> ! { | |
// TODO: review this | |
asm!( | |
" | |
mrs x6, MPIDR_EL1 | |
and x6, x6, #0x3 | |
cbz x6, L0 | |
b {} | |
L0: nop | |
", | |
sym halt, | |
out("x6") _, | |
options(nomem, nostack) | |
); | |
// Only one CPU reaches here. | |
// Zero the memory requested to be zero'ed. | |
// TODO: that's illegal ; naked functions must only contain an asm! block (for good reasons) | |
let mut ptr = &mut $memory_zeroing_start as *mut u8; | |
while ptr < &mut $memory_zeroing_end as *mut u8 { | |
ptr.write_volatile(0); | |
ptr = ptr.add(1); | |
} | |
// Set up the stack and jump to `cpu_enter`. | |
asm!( | |
" | |
.comm stack, 0x400000, 8 | |
ldr x5, =stack+0x400000 | |
mov sp, x5 | |
b {} | |
", sym cpu_enter, options(noreturn)) | |
} |
Since they are #[naked]
functions, they can't use Rust code.
The BSS needs to be cleared, but since the BSS includes the stack, this clearing can only be done before jumping to the Rust code, and thus needs to be in assembly.
I personally have a lot of trouble 1) navigating the ARM assembly documentation 2) putting the start and end offsets into registers. For 2), you'd normally use the adrl
pseudo-opcode, but LLVM doesn't support it.