feat: PoC higher-half kernel
This commit is contained in:
parent
45055998bd
commit
a8b7e88cfe
7
Makefile
7
Makefile
@ -40,6 +40,13 @@ QEMU_OPTS+=-kernel $(O)/kernel.bin \
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(QEMU_DINT),1)
|
||||
QEMU_OPTS+=-d int
|
||||
endif
|
||||
ifeq ($(QEMU_PAUSE),1)
|
||||
QEMU_OPTS+=-S
|
||||
endif
|
||||
|
||||
.PHONY: address error etc kernel src
|
||||
|
||||
all: kernel
|
||||
|
@ -9,7 +9,7 @@
|
||||
"llvm-target": "aarch64-unknown-none",
|
||||
"max-atomic-width": 128,
|
||||
"panic-strategy": "abort",
|
||||
"relocation-model": "static",
|
||||
"relocation-model": "pic",
|
||||
"target-pointer-width": "64",
|
||||
"pre-link-args": {
|
||||
"ld.lld": [ "-Tetc/aarch64-qemu.ld" ]
|
||||
|
@ -1,14 +1,22 @@
|
||||
ENTRY(_entry);
|
||||
|
||||
KERNEL_OFFSET = 0; /* 0xFFFFFF8000000000; */
|
||||
KERNEL_OFFSET = 0xFFFFFF8000000000;
|
||||
BASE_OFFSET = 0x40080000;
|
||||
|
||||
SECTIONS {
|
||||
. = 0x40080000 + KERNEL_OFFSET;
|
||||
. = BASE_OFFSET;
|
||||
|
||||
.text.lower : {
|
||||
*(.text._entry)
|
||||
}
|
||||
|
||||
. = ALIGN(16);
|
||||
. = . + KERNEL_OFFSET;
|
||||
|
||||
PROVIDE(__kernel_start = .);
|
||||
|
||||
.text : AT(. - KERNEL_OFFSET) {
|
||||
*(.text._entry)
|
||||
*(.text._entry_upper)
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,13 @@
|
||||
add \reg, \reg, #:lo12:\sym
|
||||
.endm
|
||||
|
||||
.macro ADR_ABS reg, sym
|
||||
movz \reg, #:abs_g3:\sym
|
||||
movk \reg, #:abs_g2_nc:\sym
|
||||
movk \reg, #:abs_g1_nc:\sym
|
||||
movk \reg, #:abs_g0_nc:\sym
|
||||
.endm
|
||||
|
||||
.section .text._entry
|
||||
.global _entry
|
||||
_entry:
|
||||
@ -19,22 +26,24 @@ _entry:
|
||||
b 1b
|
||||
|
||||
2:
|
||||
// TODO leave EL2 if running in it
|
||||
|
||||
// Zero .bss
|
||||
ADR_REL x0, __bss_start
|
||||
ADR_REL x1, __bss_end
|
||||
1:
|
||||
cmp x0, x1
|
||||
beq 2f
|
||||
stp xzr, xzr, [x0], #16
|
||||
b 1b
|
||||
2:
|
||||
// TODO zero .bss
|
||||
|
||||
ADR_REL x0, bsp_stack_top
|
||||
mov sp, x0
|
||||
ADR_ABS x9, __aa64_entry_upper
|
||||
b __aa64_enter_upper
|
||||
|
||||
mov x0, x8
|
||||
b __aa64_bsp_main
|
||||
.section .text._entry_upper
|
||||
__aa64_entry_upper:
|
||||
// x0 -- FDT base address
|
||||
|
||||
ADR_REL x1, bsp_stack_top
|
||||
mov sp, x1
|
||||
|
||||
mov lr, xzr
|
||||
bl __aa64_bsp_main
|
||||
|
||||
b .
|
||||
|
||||
.section .bss
|
||||
.p2align 4
|
||||
|
@ -4,8 +4,8 @@ use crate::arch::{aarch64::asm::CPACR_EL1, machine};
|
||||
use crate::dev::{Device, fdt::DeviceTree};
|
||||
use crate::mem::virt;
|
||||
use cortex_a::asm::barrier::{self, dsb, isb};
|
||||
use cortex_a::registers::{DAIF, SCTLR_EL1, VBAR_EL1};
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable};
|
||||
use cortex_a::registers::{DAIF, SCTLR_EL1, VBAR_EL1, CurrentEL};
|
||||
use tock_registers::interfaces::{ReadWriteable, Writeable, Readable};
|
||||
|
||||
#[no_mangle]
|
||||
fn __aa64_bsp_main(fdt_base: usize) {
|
||||
@ -34,7 +34,7 @@ fn __aa64_bsp_main(fdt_base: usize) {
|
||||
|
||||
machine::init_board().unwrap();
|
||||
|
||||
let fdt = DeviceTree::from_phys(fdt_base).expect("Failed to obtain a device tree");
|
||||
let fdt = DeviceTree::from_phys(fdt_base + 0xFFFFFF8000000000).expect("Failed to obtain a device tree");
|
||||
fdt.dump();
|
||||
|
||||
unsafe {
|
||||
@ -43,6 +43,7 @@ fn __aa64_bsp_main(fdt_base: usize) {
|
||||
|
||||
loop {
|
||||
DAIF.modify(DAIF::I::CLEAR);
|
||||
cortex_a::asm::wfi();
|
||||
}
|
||||
}
|
||||
|
||||
@ -53,3 +54,5 @@ cfg_if! {
|
||||
global_asm!(include_str!("entry.S"));
|
||||
}
|
||||
}
|
||||
|
||||
global_asm!(include_str!("upper.S"));
|
||||
|
95
kernel/src/arch/aarch64/boot/upper.S
Normal file
95
kernel/src/arch/aarch64/boot/upper.S
Normal file
@ -0,0 +1,95 @@
|
||||
// vi:ft=a64asm:
|
||||
|
||||
.set PTE_BLOCK_AF, 1 << 10
|
||||
.set PTE_BLOCK_ISH, 3 << 8
|
||||
.set PTE_PRESENT, 1 << 0
|
||||
|
||||
.set MAIR_EL1_Attr0_Normal_Inner_NC, (4 << 0)
|
||||
.set MAIR_EL1_Attr0_Normal_Outer_NC, (4 << 4)
|
||||
.set MAIR_EL1_Attr1_Device, (0 << 4)
|
||||
.set MAIR_EL1_Attr1_Device_nGnRnE, (0 << 4)
|
||||
|
||||
.set ID_AA64MMFR0_EL1_TGran4, (0xF << 28)
|
||||
|
||||
.set TCR_EL1_IPS_SHIFT, 32
|
||||
|
||||
.set TCR_EL1_TG1_4K, (2 << 30)
|
||||
.set TCR_EL1_SH1_Outer, (2 << 28)
|
||||
.set TCR_EL1_ORGN1_NC, (0 << 26)
|
||||
.set TCR_EL1_IRGN1_NC, (0 << 24)
|
||||
.set TCR_EL1_T1SZ_SHIFT, 16
|
||||
|
||||
.set TCR_EL1_TG0_4K, (0 << 14)
|
||||
.set TCR_EL1_SH0_Outer, (2 << 12)
|
||||
.set TCR_EL1_ORGN0_NC, (0 << 10)
|
||||
.set TCR_EL1_IRGN0_NC, (0 << 8)
|
||||
.set TCR_EL1_T0SZ_SHIFT, 0
|
||||
|
||||
.set TCR_EL1_ATTRS, (TCR_EL1_TG1_4K | TCR_EL1_SH1_Outer | TCR_EL1_TG0_4K | TCR_EL1_SH0_Outer | (25 << TCR_EL1_T1SZ_SHIFT) | (25 << TCR_EL1_T0SZ_SHIFT))
|
||||
|
||||
.set SCTLR_EL1_M, (1 << 0)
|
||||
|
||||
.macro MOV_L reg, value
|
||||
mov \reg, #((\value) & 0xFFFF)
|
||||
movk \reg, #((\value) >> 16), lsl #16
|
||||
.endm
|
||||
|
||||
.section .text._entry
|
||||
.global __aa64_enter_upper
|
||||
.type __aa64_enter_upper, %function
|
||||
__aa64_enter_upper:
|
||||
// x8 -- FDT base
|
||||
// x9 -- upper entry point
|
||||
|
||||
// Setup TTBR1_EL1
|
||||
// TODO fix macros
|
||||
ADR_ABS x5, KERNEL_TTBR1
|
||||
ADR_ABS x6, KERNEL_OFFSET
|
||||
|
||||
// x5 = KERNEL_TTBR1 physical address
|
||||
sub x5, x5, x6
|
||||
|
||||
// Fill KERNEL_TTBR1 table with upper-mapped Normal memory
|
||||
.fill_ttbr1:
|
||||
mov x2, #256
|
||||
1:
|
||||
sub x2, x2, #1
|
||||
|
||||
// x0 = (x2 << 30) | attrs...
|
||||
lsl x1, x2, #30
|
||||
mov x0, #(PTE_BLOCK_ISH | PTE_BLOCK_AF | PTE_PRESENT)
|
||||
orr x0, x0, x1
|
||||
|
||||
str x0, [x5, x2, lsl #3]
|
||||
|
||||
cbnz x2, 1b
|
||||
|
||||
.init_mmu_regs:
|
||||
mov x0, #(MAIR_EL1_Attr0_Normal_Outer_NC | MAIR_EL1_Attr0_Normal_Inner_NC | MAIR_EL1_Attr1_Device | MAIR_EL1_Attr1_Device_nGnRnE)
|
||||
// Test for 4KiB page support
|
||||
mrs x0, ID_AA64MMFR0_EL1
|
||||
mov x1, ID_AA64MMFR0_EL1_TGran4
|
||||
tst x0, x1
|
||||
bne .no_4k_gran
|
||||
|
||||
// x0 = PARange
|
||||
and x0, x0, #0xF
|
||||
lsl x0, x0, #TCR_EL1_IPS_SHIFT
|
||||
MOV_L x1, TCR_EL1_ATTRS
|
||||
orr x0, x0, x1
|
||||
msr tcr_el1, x0
|
||||
|
||||
msr mair_el1, x0
|
||||
|
||||
msr ttbr0_el1, x5
|
||||
msr ttbr1_el1, x5
|
||||
|
||||
mrs x0, sctlr_el1
|
||||
orr x0, x0, #SCTLR_EL1_M
|
||||
msr sctlr_el1, x0
|
||||
|
||||
mov x0, x8
|
||||
br x9
|
||||
.no_4k_gran:
|
||||
b .
|
||||
.size __aa64_enter_upper, . - __aa64_enter_upper
|
@ -2,6 +2,9 @@
|
||||
|
||||
pub mod virt;
|
||||
|
||||
/// Virtual offset applied to kernel address space
|
||||
pub const KERNEL_OFFSET: usize = 0xFFFFFF8000000000;
|
||||
|
||||
/// See memcpy(3p).
|
||||
///
|
||||
/// # Safety
|
||||
|
@ -1,5 +1,6 @@
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use crate::mem::KERNEL_OFFSET;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::Deref;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
@ -18,15 +19,6 @@ const PTE_PRESENT: u64 = 1 << 0;
|
||||
struct Table([u64; 512]);
|
||||
|
||||
#[no_mangle]
|
||||
static mut KERNEL_TTBR0: Table = {
|
||||
let mut table = [0; 512];
|
||||
// TODO fine-grained mapping
|
||||
table[0] = (0 << 30) | PTE_BLOCK_AF | PTE_BLOCK_ISH | PTE_PRESENT;
|
||||
table[1] = (1 << 30) | PTE_BLOCK_AF | PTE_BLOCK_ISH | PTE_PRESENT;
|
||||
|
||||
Table(table)
|
||||
};
|
||||
|
||||
static mut KERNEL_TTBR1: Table = Table([0; 512]);
|
||||
// 1GiB
|
||||
static mut KERNEL_L1: Table = Table([0; 512]);
|
||||
@ -36,6 +28,8 @@ static mut COUNT: usize = 0;
|
||||
static mut BIG_COUNT: usize = 1;
|
||||
static mut HUGE_COUNT: usize = 1;
|
||||
|
||||
const DEVICE_MAP_OFFSET: usize = KERNEL_OFFSET + (256 << 30);
|
||||
|
||||
pub struct DeviceMemory {
|
||||
name: &'static str,
|
||||
base: usize,
|
||||
@ -64,10 +58,11 @@ impl DeviceMemory {
|
||||
}
|
||||
HUGE_COUNT += 1;
|
||||
|
||||
KERNEL_TTBR1.0[count + 256] = (phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
|
||||
KERNEL_TTBR1.0[count + 256] =
|
||||
(phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
|
||||
|
||||
0xFFFFFFC000000000 + (count << 30)
|
||||
},
|
||||
DEVICE_MAP_OFFSET + (count << 30)
|
||||
}
|
||||
512 => {
|
||||
let count = BIG_COUNT;
|
||||
if count == 512 {
|
||||
@ -77,8 +72,8 @@ impl DeviceMemory {
|
||||
|
||||
KERNEL_L1.0[count] = (phys as u64) | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
|
||||
|
||||
0xFFFFFFC000000000 + (count << 21)
|
||||
},
|
||||
DEVICE_MAP_OFFSET + (count << 21)
|
||||
}
|
||||
1 => {
|
||||
let count = COUNT;
|
||||
if count == 512 {
|
||||
@ -89,9 +84,9 @@ impl DeviceMemory {
|
||||
KERNEL_L2.0[count] =
|
||||
(phys as u64) | PTE_TABLE | PTE_PRESENT | PTE_BLOCK_OSH | PTE_BLOCK_AF;
|
||||
|
||||
0xFFFFFFC000000000 + count * 0x1000
|
||||
},
|
||||
_ => unimplemented!()
|
||||
DEVICE_MAP_OFFSET + (count << 12)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
};
|
||||
|
||||
@ -130,43 +125,25 @@ impl<T> Deref for DeviceMemoryIo<T> {
|
||||
}
|
||||
|
||||
pub fn enable() -> Result<(), Errno> {
|
||||
MAIR_EL1.write(
|
||||
MAIR_EL1::Attr0_Normal_Outer::NonCacheable + MAIR_EL1::Attr0_Normal_Inner::NonCacheable,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
KERNEL_L1.0[0] = (&KERNEL_L2 as *const _ as u64) | PTE_TABLE | PTE_PRESENT;
|
||||
KERNEL_TTBR1.0[256] = (&KERNEL_L1 as *const _ as u64) | PTE_TABLE | PTE_PRESENT;
|
||||
}
|
||||
// TODO function to translate kernel addresses to physical ones
|
||||
let l1_base = (&KERNEL_L1 as *const _ as u64) - KERNEL_OFFSET as u64;
|
||||
let l2_base = (&KERNEL_L2 as *const _ as u64) - KERNEL_OFFSET as u64;
|
||||
|
||||
TTBR0_EL1.set(unsafe { &mut KERNEL_TTBR0 as *mut _ as u64 });
|
||||
TTBR1_EL1.set(unsafe { &mut KERNEL_TTBR1 as *mut _ as u64 });
|
||||
KERNEL_L1.0[0] = l2_base | PTE_TABLE | PTE_PRESENT;
|
||||
KERNEL_TTBR1.0[256] = l1_base | PTE_TABLE | PTE_PRESENT;
|
||||
|
||||
if ID_AA64MMFR0_EL1.matches_all(ID_AA64MMFR0_EL1::TGran4::NotSupported) {
|
||||
return Err(Errno::InvalidArgument);
|
||||
// NOTE don't think tlb needs to be invalidated when new entries are created
|
||||
}
|
||||
let parange = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange);
|
||||
|
||||
unsafe {
|
||||
dsb(barrier::ISH);
|
||||
isb(barrier::SY);
|
||||
}
|
||||
|
||||
TCR_EL1.write(
|
||||
TCR_EL1::IPS.val(parange)
|
||||
+ TCR_EL1::T0SZ.val(25)
|
||||
+ TCR_EL1::TG0::KiB_4
|
||||
+ TCR_EL1::SH0::Outer
|
||||
+ TCR_EL1::IRGN0::NonCacheable
|
||||
+ TCR_EL1::ORGN0::NonCacheable
|
||||
+ TCR_EL1::T1SZ.val(25)
|
||||
+ TCR_EL1::TG1::KiB_4
|
||||
+ TCR_EL1::SH1::Outer
|
||||
+ TCR_EL1::IRGN1::NonCacheable
|
||||
+ TCR_EL1::ORGN1::NonCacheable,
|
||||
);
|
||||
|
||||
SCTLR_EL1.modify(SCTLR_EL1::M::SET);
|
||||
// Disable lower-half translation
|
||||
TTBR0_EL1.set(0);
|
||||
TCR_EL1.modify(TCR_EL1::EPD0::SET);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user