feat: move EL0 stack to virtual space

This commit is contained in:
2026-03-19 10:43:45 +01:00
parent cba7073ae5
commit 778b3ed80c
5 changed files with 76 additions and 73 deletions

18
link.ld
View File

@@ -4,14 +4,15 @@ SECTIONS {
.text ALIGN(4) : {
KEEP(*(.text._start))
*(.text .text.*)
. = ALIGN(4K);
__text_end = .;
}
.rodata : {
*(.rodata .rodata.*)
}
.data ALIGN(2M) : {
_data = .;
.data : {
*(.data .data.*)
}
@@ -21,6 +22,10 @@ SECTIONS {
__bss_end = .;
}
. = ALIGN(2M);
__share_end = .;
.vector_table ALIGN(2K) : {
KEEP(*(.vector_table))
}
@@ -36,15 +41,6 @@ SECTIONS {
. = ALIGN(2M);
__kernel_end = .;
.stack_el0 : {
__stack_start_el0 = .;
. += 10K; #10kB stack
__stack_end_el0 = .;
}
. = ALIGN(2M);
_end = .;
}
__bss_size = (__bss_end - __bss_start) >> 3;

View File

@@ -8,13 +8,6 @@ use crate::{
get_current_el,
};
unsafe extern "C" {
static mut __translation_table_l2_start: u64;
static __stack_start_el0: u64;
static __kernel_end: u64;
static _data: u64;
}
const BLOCK: u64 = 0b01;
const TABLE: u64 = 0b11;
const PAGE: u64 = 0b11;
@@ -111,21 +104,21 @@ fn map_range_explicit(
while virt % LEVEL2_BLOCK_SIZE != 0 {
map_page(virt, phys, base, flags)?;
virt += GRANULARITY;
(virt, _) = virt.overflowing_add(GRANULARITY);
phys += GRANULARITY;
remaining -= GRANULARITY;
}
while remaining >= LEVEL2_BLOCK_SIZE {
map_l2_block(virt, phys, base, flags)?;
virt += LEVEL2_BLOCK_SIZE;
(virt, _) = virt.overflowing_add(LEVEL2_BLOCK_SIZE);
phys += LEVEL2_BLOCK_SIZE;
remaining -= LEVEL2_BLOCK_SIZE;
}
while remaining > 0 {
map_page(virt, phys, base, flags)?;
virt += GRANULARITY;
(virt, _) = virt.overflowing_add(GRANULARITY);
phys += GRANULARITY;
remaining -= GRANULARITY;
}
@@ -143,13 +136,13 @@ fn map_range_dynamic(
while remaining >= LEVEL2_BLOCK_SIZE {
map_l2_block(virt, reserve_block(), base, flags)?;
virt += LEVEL2_BLOCK_SIZE;
(virt, _) = virt.overflowing_add(LEVEL2_BLOCK_SIZE);
remaining -= LEVEL2_BLOCK_SIZE;
}
while remaining > 0 {
map_page(virt, reserve_page(), base, flags)?;
virt += GRANULARITY;
(virt, _) = virt.overflowing_add(GRANULARITY);
remaining -= GRANULARITY;
}
@@ -186,7 +179,7 @@ pub fn alloc_page_explicit(
)
}
fn map_page(
pub fn map_page(
virtual_address: usize,
physical_address: usize,
base_table_ptr: *mut PageTable,

View File

@@ -87,8 +87,9 @@ el1_to_el0:
msr ELR_EL1, x0
// Set SP_EL1 to stack base
ldr x0, =__stack_end_el0
msr SP_EL0, x0
adrp x0, EL0_STACK_TOP
ldr x1, [x0, :lo12:EL0_STACK_TOP]
msr SP_EL0, x1
isb

View File

@@ -34,9 +34,9 @@ pub static TCR_EL1_CONF: u64 = IPS | TG0 | TG1 | T0SZ | T1SZ | SH0 | SH1 | AS;
pub mod mmu {
use crate::{
aarch64::mmu::{
alloc_block_l2_explicit, allocate_memory, map_l2_block, reserve_range, PhysSource,
DEVICE_MEM, EL0_ACCESSIBLE, KERNEL_VIRTUAL_MEM_SPACE, LEVEL1_BLOCK_SIZE,
LEVEL2_BLOCK_SIZE, NORMAL_MEM, PXN, READ_ONLY, STACK_START_ADDR,
alloc_block_l2_explicit, allocate_memory, map_l2_block, map_page, reserve_range,
PhysSource, DEVICE_MEM, EL0_ACCESSIBLE, GRANULARITY, KERNEL_VIRTUAL_MEM_SPACE,
LEVEL1_BLOCK_SIZE, LEVEL2_BLOCK_SIZE, NORMAL_MEM, PXN, READ_ONLY, STACK_START_ADDR,
TRANSLATIONTABLE_TTBR0, UXN, WRITABLE,
},
PERIPHERAL_BASE,
@@ -45,22 +45,24 @@ pub mod mmu {
#[no_mangle]
static EL1_STACK_TOP: usize = STACK_START_ADDR | KERNEL_VIRTUAL_MEM_SPACE;
const EL1_STACK_SIZE: usize = LEVEL2_BLOCK_SIZE * 2;
#[no_mangle]
static EL0_STACK_TOP: usize = STACK_START_ADDR;
const EL0_STACK_SIZE: usize = LEVEL2_BLOCK_SIZE * 2;
extern "C" {
static _data: u64;
static _end: u64;
static __text_end: u64;
static __share_end: u64;
static __kernel_end: u64;
}
pub fn initialize_mmu_translation_tables() {
let shared_segment_end = unsafe { &_data } as *const _ as usize;
let text_end = unsafe { &__text_end } as *const _ as usize;
let shared_segment_end = unsafe { &__share_end } as *const _ as usize;
let kernel_end = unsafe { &__kernel_end } as *const _ as usize;
let user_space_end = unsafe { &_end } as *const _ as usize;
reserve_range(0x0, user_space_end).unwrap();
reserve_range(0x0, kernel_end).unwrap();
for addr in (0..shared_segment_end).step_by(LEVEL2_BLOCK_SIZE) {
map_l2_block(
for addr in (0..text_end).step_by(GRANULARITY) {
map_page(
addr,
addr,
core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR0),
@@ -69,6 +71,16 @@ pub mod mmu {
.unwrap();
}
for addr in (text_end..shared_segment_end).step_by(GRANULARITY) {
map_page(
addr,
addr,
core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR0),
EL0_ACCESSIBLE | WRITABLE | NORMAL_MEM,
)
.unwrap();
}
for addr in (shared_segment_end..kernel_end).step_by(LEVEL2_BLOCK_SIZE) {
map_l2_block(
addr,
@@ -79,16 +91,6 @@ pub mod mmu {
.unwrap();
}
for addr in (kernel_end..user_space_end).step_by(LEVEL2_BLOCK_SIZE) {
map_l2_block(
addr,
addr,
core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR0),
EL0_ACCESSIBLE | WRITABLE | PXN | NORMAL_MEM,
)
.unwrap();
}
for addr in (PERIPHERAL_BASE..LEVEL1_BLOCK_SIZE).step_by(LEVEL2_BLOCK_SIZE) {
alloc_block_l2_explicit(
addr,
@@ -99,6 +101,15 @@ pub mod mmu {
.unwrap();
}
// Frame Buffer memory range
allocate_memory(
0x3c100000,
1080 * 1920 * 4,
PhysSource::Explicit(0x3c100000),
NORMAL_MEM | PXN | UXN | WRITABLE | EL0_ACCESSIBLE,
)
.unwrap();
allocate_memory(
EL1_STACK_TOP - EL1_STACK_SIZE + 0x10,
EL1_STACK_SIZE,
@@ -106,5 +117,13 @@ pub mod mmu {
WRITABLE | NORMAL_MEM,
)
.unwrap();
allocate_memory(
EL0_STACK_TOP - EL0_STACK_SIZE + 0x10,
EL0_STACK_SIZE,
PhysSource::Any,
WRITABLE | EL0_ACCESSIBLE | NORMAL_MEM,
)
.unwrap();
}
}

View File

@@ -11,10 +11,7 @@ extern crate alloc;
use alloc::vec::Vec;
use nova::{
aarch64::{
mmu::{allocate_memory, PhysSource, EL0_ACCESSIBLE, NORMAL_MEM, PXN, UXN, WRITABLE},
registers::{daif, read_id_aa64mmfr0_el1},
},
aarch64::registers::{daif, read_id_aa64mmfr0_el1},
configuration::mmu::initialize_mmu_translation_tables,
framebuffer::{FrameBuffer, BLUE, GREEN, RED},
get_current_el,
@@ -26,13 +23,14 @@ use nova::{
},
uart::uart_init,
},
pi3::mailbox,
println,
};
global_asm!(include_str!("vector.S"));
global_asm!(include_str!("config.S"));
static mut FRAMEBUFFER: Option<FrameBuffer> = None;
extern "C" {
fn el2_to_el1();
fn el1_to_el0();
@@ -74,6 +72,8 @@ pub extern "C" fn main() -> ! {
println!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1());
println!("Moving El2->EL1");
unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) };
unsafe {
el2_to_el1();
}
@@ -100,15 +100,6 @@ pub extern "C" fn kernel_main() -> ! {
}
println!("heap allocation test: {:?}", test_vector);
// Frame Buffer memory range
// TODO: this is just temporary
allocate_memory(
0x3c100000,
1080 * 1920 * 4,
PhysSource::Explicit(0x3c100000),
NORMAL_MEM | PXN | UXN | WRITABLE | EL0_ACCESSIBLE,
)
.unwrap();
println!("Exception Level: {}", get_current_el());
daif::unmask_all();
@@ -132,8 +123,7 @@ pub extern "C" fn el0() -> ! {
enable_irq_source(IRQSource::UartInt);
let fb = FrameBuffer::default();
if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } {
for i in 0..1080 {
fb.draw_pixel(50, i, BLUE);
}
@@ -144,10 +134,14 @@ pub extern "C" fn el0() -> ! {
fb.draw_string("Hello World! :D\nTest next Line", 500, 5, 3, BLUE);
fb.draw_function(cos, 0, 101, RED);
}
loop {
let temp = mailbox::read_soc_temp([0]).unwrap();
println!("{} °C", temp[1] / 1000);
// TODO: Mailbox requires a physical address. The stack is now in VA space causing an issue.
// Fix with SVCs ?
// let temp = mailbox::read_soc_temp([0]).unwrap();
// println!("{} °C", temp[1] / 1000);
blink_gpio(SpecificGpio::OnboardLed as u8, 500);
}