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

View File

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

View File

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

View File

@@ -34,9 +34,9 @@ pub static TCR_EL1_CONF: u64 = IPS | TG0 | TG1 | T0SZ | T1SZ | SH0 | SH1 | AS;
pub mod mmu { pub mod mmu {
use crate::{ use crate::{
aarch64::mmu::{ aarch64::mmu::{
alloc_block_l2_explicit, allocate_memory, map_l2_block, reserve_range, PhysSource, alloc_block_l2_explicit, allocate_memory, map_l2_block, map_page, reserve_range,
DEVICE_MEM, EL0_ACCESSIBLE, KERNEL_VIRTUAL_MEM_SPACE, LEVEL1_BLOCK_SIZE, PhysSource, DEVICE_MEM, EL0_ACCESSIBLE, GRANULARITY, KERNEL_VIRTUAL_MEM_SPACE,
LEVEL2_BLOCK_SIZE, NORMAL_MEM, PXN, READ_ONLY, STACK_START_ADDR, LEVEL1_BLOCK_SIZE, LEVEL2_BLOCK_SIZE, NORMAL_MEM, PXN, READ_ONLY, STACK_START_ADDR,
TRANSLATIONTABLE_TTBR0, UXN, WRITABLE, TRANSLATIONTABLE_TTBR0, UXN, WRITABLE,
}, },
PERIPHERAL_BASE, PERIPHERAL_BASE,
@@ -45,22 +45,24 @@ pub mod mmu {
#[no_mangle] #[no_mangle]
static EL1_STACK_TOP: usize = STACK_START_ADDR | KERNEL_VIRTUAL_MEM_SPACE; static EL1_STACK_TOP: usize = STACK_START_ADDR | KERNEL_VIRTUAL_MEM_SPACE;
const EL1_STACK_SIZE: usize = LEVEL2_BLOCK_SIZE * 2; 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" { extern "C" {
static _data: u64; static __text_end: u64;
static _end: u64; static __share_end: u64;
static __kernel_end: u64; static __kernel_end: u64;
} }
pub fn initialize_mmu_translation_tables() { 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 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) { for addr in (0..text_end).step_by(GRANULARITY) {
map_l2_block( map_page(
addr, addr,
addr, addr,
core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR0), core::ptr::addr_of_mut!(TRANSLATIONTABLE_TTBR0),
@@ -69,6 +71,16 @@ pub mod mmu {
.unwrap(); .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) { for addr in (shared_segment_end..kernel_end).step_by(LEVEL2_BLOCK_SIZE) {
map_l2_block( map_l2_block(
addr, addr,
@@ -79,16 +91,6 @@ pub mod mmu {
.unwrap(); .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) { for addr in (PERIPHERAL_BASE..LEVEL1_BLOCK_SIZE).step_by(LEVEL2_BLOCK_SIZE) {
alloc_block_l2_explicit( alloc_block_l2_explicit(
addr, addr,
@@ -99,6 +101,15 @@ pub mod mmu {
.unwrap(); .unwrap();
} }
// Frame Buffer memory range
allocate_memory(
0x3c100000,
1080 * 1920 * 4,
PhysSource::Explicit(0x3c100000),
NORMAL_MEM | PXN | UXN | WRITABLE | EL0_ACCESSIBLE,
)
.unwrap();
allocate_memory( allocate_memory(
EL1_STACK_TOP - EL1_STACK_SIZE + 0x10, EL1_STACK_TOP - EL1_STACK_SIZE + 0x10,
EL1_STACK_SIZE, EL1_STACK_SIZE,
@@ -106,5 +117,13 @@ pub mod mmu {
WRITABLE | NORMAL_MEM, WRITABLE | NORMAL_MEM,
) )
.unwrap(); .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 alloc::vec::Vec;
use nova::{ use nova::{
aarch64::{ aarch64::registers::{daif, read_id_aa64mmfr0_el1},
mmu::{allocate_memory, PhysSource, EL0_ACCESSIBLE, NORMAL_MEM, PXN, UXN, WRITABLE},
registers::{daif, read_id_aa64mmfr0_el1},
},
configuration::mmu::initialize_mmu_translation_tables, configuration::mmu::initialize_mmu_translation_tables,
framebuffer::{FrameBuffer, BLUE, GREEN, RED}, framebuffer::{FrameBuffer, BLUE, GREEN, RED},
get_current_el, get_current_el,
@@ -26,13 +23,14 @@ use nova::{
}, },
uart::uart_init, uart::uart_init,
}, },
pi3::mailbox,
println, println,
}; };
global_asm!(include_str!("vector.S")); global_asm!(include_str!("vector.S"));
global_asm!(include_str!("config.S")); global_asm!(include_str!("config.S"));
static mut FRAMEBUFFER: Option<FrameBuffer> = None;
extern "C" { extern "C" {
fn el2_to_el1(); fn el2_to_el1();
fn el1_to_el0(); fn el1_to_el0();
@@ -74,6 +72,8 @@ pub extern "C" fn main() -> ! {
println!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1()); println!("Register: AA64MMFR0_EL1: {:064b}", read_id_aa64mmfr0_el1());
println!("Moving El2->EL1"); println!("Moving El2->EL1");
unsafe { FRAMEBUFFER = Some(FrameBuffer::default()) };
unsafe { unsafe {
el2_to_el1(); el2_to_el1();
} }
@@ -100,15 +100,6 @@ pub extern "C" fn kernel_main() -> ! {
} }
println!("heap allocation test: {:?}", test_vector); 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()); println!("Exception Level: {}", get_current_el());
daif::unmask_all(); daif::unmask_all();
@@ -132,8 +123,7 @@ pub extern "C" fn el0() -> ! {
enable_irq_source(IRQSource::UartInt); enable_irq_source(IRQSource::UartInt);
let fb = FrameBuffer::default(); if let Some(fb) = unsafe { FRAMEBUFFER.as_mut() } {
for i in 0..1080 { for i in 0..1080 {
fb.draw_pixel(50, i, BLUE); 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_string("Hello World! :D\nTest next Line", 500, 5, 3, BLUE);
fb.draw_function(cos, 0, 101, RED); fb.draw_function(cos, 0, 101, RED);
}
loop { loop {
let temp = mailbox::read_soc_temp([0]).unwrap(); // TODO: Mailbox requires a physical address. The stack is now in VA space causing an issue.
println!("{} °C", temp[1] / 1000); // Fix with SVCs ?
// let temp = mailbox::read_soc_temp([0]).unwrap();
// println!("{} °C", temp[1] / 1000);
blink_gpio(SpecificGpio::OnboardLed as u8, 500); blink_gpio(SpecificGpio::OnboardLed as u8, 500);
} }