Merge branch 'aarch64-stuff' into 'master'

Improve aarch64 code + memory management and crush some bugs

See merge request redox-os/kernel!220
This commit is contained in:
Jeremy Soller
2023-06-12 15:17:51 +00:00
13 changed files with 52 additions and 210 deletions
+1 -1
Submodule rmm updated: 7aeb9f0ac8...e24e8485ba
+2 -2
View File
@@ -1,5 +1,5 @@
use rmm::Flusher;
use crate::paging::{KernelMapper, Page, PageFlags, VirtualAddress, mapper::PageFlushAll, entry::EntryFlags};
use crate::paging::{KernelMapper, Page, PageFlags, VirtualAddress, mapper::PageFlushAll};
#[cfg(not(feature="slab"))]
pub use self::linked_list::Allocator;
@@ -20,7 +20,7 @@ unsafe fn map_heap(mapper: &mut KernelMapper, offset: usize, size: usize) {
let heap_start_page = Page::containing_address(VirtualAddress::new(offset));
let heap_end_page = Page::containing_address(VirtualAddress::new(offset + size-1));
for page in Page::range_inclusive(heap_start_page, heap_end_page) {
let result = mapper.map(page.start_address(), PageFlags::new().write(true).custom_flag(EntryFlags::GLOBAL.bits(), cfg!(not(feature = "pti"))))
let result = mapper.map(page.start_address(), PageFlags::new().write(true).global(cfg!(not(feature = "pti"))))
.expect("failed to map kernel heap");
flush_all.consume(result);
}
+30 -30
View File
@@ -2,41 +2,41 @@
// The lower 256 PML4 entries are reserved for userspace
// Each PML4 entry references up to 512 GB of memory
// The second from the top (510) PML4 is reserved for the kernel
/// The size of a single PML4
pub const PML4_SIZE: usize = 0x0000_0080_0000_0000;
pub const PML4_MASK: usize = 0x0000_ff80_0000_0000;
/// The size of a single PML4
pub const PML4_SIZE: usize = 0x0000_0080_0000_0000;
pub const PML4_MASK: usize = 0x0000_ff80_0000_0000;
/// Offset of recursive paging (deprecated, but still reserved)
pub const RECURSIVE_PAGE_OFFSET: usize = (-(PML4_SIZE as isize)) as usize;
pub const RECURSIVE_PAGE_PML4: usize = (RECURSIVE_PAGE_OFFSET & PML4_MASK)/PML4_SIZE;
/// Offset of recursive paging (deprecated, but still reserved)
pub const RECURSIVE_PAGE_OFFSET: usize = (-(PML4_SIZE as isize)) as usize;
pub const RECURSIVE_PAGE_PML4: usize = (RECURSIVE_PAGE_OFFSET & PML4_MASK)/PML4_SIZE;
/// Offset of kernel
pub const KERNEL_OFFSET: usize = RECURSIVE_PAGE_OFFSET - PML4_SIZE;
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK)/PML4_SIZE;
/// Offset of kernel
pub const KERNEL_OFFSET: usize = RECURSIVE_PAGE_OFFSET - PML4_SIZE;
pub const KERNEL_PML4: usize = (KERNEL_OFFSET & PML4_MASK)/PML4_SIZE;
/// Offset to kernel heap
pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE;
/// Size of kernel heap
pub const KERNEL_HEAP_SIZE: usize = 1 * 1024 * 1024; // 1 MB
/// Offset to kernel heap
pub const KERNEL_HEAP_OFFSET: usize = KERNEL_OFFSET - PML4_SIZE;
pub const KERNEL_HEAP_PML4: usize = (KERNEL_HEAP_OFFSET & PML4_MASK)/PML4_SIZE;
/// Size of kernel heap
pub const KERNEL_HEAP_SIZE: usize = 1 * 1024 * 1024; // 1 MB
/// Offset of temporary mapping for misc kernel bring-up actions
pub const KERNEL_TMP_MISC_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE;
/// Offset of temporary mapping for misc kernel bring-up actions
pub const KERNEL_TMP_MISC_OFFSET: usize = KERNEL_HEAP_OFFSET - PML4_SIZE;
/// Offset to kernel percpu variables
pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_TMP_MISC_OFFSET - PML4_SIZE;
pub const KERNEL_PERCPU_PML4: usize = (KERNEL_PERCPU_OFFSET & PML4_MASK)/PML4_SIZE;
/// Size of kernel percpu variables
pub const KERNEL_PERCPU_SHIFT: u8 = 16; // 2^16 = 64 KiB
pub const KERNEL_PERCPU_SIZE: usize = 1_usize << KERNEL_PERCPU_SHIFT;
/// Offset to kernel percpu variables
pub const KERNEL_PERCPU_OFFSET: usize = KERNEL_TMP_MISC_OFFSET - PML4_SIZE;
pub const KERNEL_PERCPU_PML4: usize = (KERNEL_PERCPU_OFFSET & PML4_MASK)/PML4_SIZE;
/// Size of kernel percpu variables
pub const KERNEL_PERCPU_SHIFT: u8 = 16; // 2^16 = 64 KiB
pub const KERNEL_PERCPU_SIZE: usize = 1_usize << KERNEL_PERCPU_SHIFT;
/// Offset of physmap
// This needs to match RMM's PHYS_OFFSET
pub const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000;
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK)/PML4_SIZE;
/// Offset of physmap
// This needs to match RMM's PHYS_OFFSET
pub const PHYS_OFFSET: usize = 0xFFFF_8000_0000_0000;
pub const PHYS_PML4: usize = (PHYS_OFFSET & PML4_MASK)/PML4_SIZE;
/// Offset to user image
pub const USER_OFFSET: usize = 0;
/// Offset to user image
pub const USER_OFFSET: usize = 0;
/// End offset of the user image, i.e. kernel start
pub const USER_END_OFFSET: usize = 256 * PML4_SIZE;
/// End offset of the user image, i.e. kernel start
pub const USER_END_OFFSET: usize = 256 * PML4_SIZE;
@@ -4,9 +4,9 @@ use core::arch::asm;
bitflags! {
pub struct MairEl1: u64 {
const DEVICE_MEMORY = 0x00;
const DEVICE_MEMORY = 0x00 << 16;
const NORMAL_UNCACHED_MEMORY = 0x44 << 8;
const NORMAL_WRITEBACK_MEMORY = 0xff << 16;
const NORMAL_WRITEBACK_MEMORY = 0xff;
}
}
+2 -2
View File
@@ -240,7 +240,7 @@ macro_rules! function {
macro_rules! push_scratch {
() => { "
// Push scratch registers
stp x18, x18, [sp, #-16]!
str x18, [sp, #-16]!
stp x16, x17, [sp, #-16]!
stp x14, x15, [sp, #-16]!
stp x12, x13, [sp, #-16]!
@@ -266,7 +266,7 @@ macro_rules! pop_scratch {
ldp x12, x13, [sp], #16
ldp x14, x15, [sp], #16
ldp x16, x17, [sp], #16
ldp x18, x18, [sp], #16
ldr x18, [sp], #16
" };
}
-155
View File
@@ -1,155 +0,0 @@
//! # Page table entry
//! Some code borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)
use crate::memory::Frame;
use super::{PageFlags, PhysicalAddress, RmmA, RmmArch};
/// A page table entry
#[derive(Debug)]
pub struct Entry(u64);
/// A page descriptor
#[derive(Debug)]
pub struct PageDescriptor(u64);
bitflags! {
pub struct TableDescriptorFlags: u64 {
const PRESENT = 1 << 0;
const VALID = 1 << 0;
const TABLE = 1 << 1;
const AF = 1 << 10; /* NOTE: TableDescriptors don't actually have an AF bit! */
const PXNTABLE = 1 << 59;
const UXNTABLE = 1 << 60;
const APTABLE_0 = 1 << 61;
const APTABLE_1 = 1 << 62;
const SUBLEVEL_NO_EL0_ACCESS = (0 << 62) | (1 << 61);
const SUBLEVEL_NO_WANY_ACCESS = (1 << 62) | (0 << 61);
const SUBLEVEL_NO_WANY_NO_REL0 = (1 << 62) | (1 << 61);
const NSTABLE = 1 << 63;
}
}
bitflags! {
pub struct PageDescriptorFlags: u64 {
const PRESENT = 1 << 0;
const VALID = 1 << 0;
const PAGE = 1 << 1;
const ATTR_INDEX_0 = 1 << 2;
const ATTR_INDEX_1 = 1 << 3;
const ATTR_INDEX_2 = 1 << 4;
const NS = 1 << 5;
const AP_1 = 1 << 6;
const AP_2 = 1 << 7;
const SH_0 = 1 << 8;
const SH_1 = 1 << 9;
const AF = 1 << 10;
const NG = 1 << 11;
const DBM = 1 << 51;
const CONTIGUOUS = 1 << 52;
const PXN = 1 << 53;
const UXN = 1 << 54;
}
}
// These are 'virtual' flags that are used to minimise changes to the generic paging code.
// These are translated to AArch64 specific Page and Table descriptors as and when needed.
bitflags! {
#[derive(Default)]
pub struct EntryFlags: usize {
const PRESENT = 1 << 0;
const HUGE_PAGE = 1 << 1;
const GLOBAL = 1 << 2;
const NO_EXECUTE = 1 << 3;
const USER_ACCESSIBLE = 1 << 4;
const WRITABLE = 1 << 5;
const TLS = 1 << 6;
const AF = 1 << 10;
}
}
pub const ADDRESS_MASK: usize = 0x0000_ffff_ffff_f000;
pub const COUNTER_MASK: u64 = 0x0008_0000_0000_0000;
impl Entry {
/// Clear entry
pub fn set_zero(&mut self) {
self.0 = 0;
}
/// Is the entry unused?
pub fn is_unused(&self) -> bool {
self.0 == (self.0 & COUNTER_MASK)
}
/// Make the entry unused
pub fn set_unused(&mut self) {
self.0 &= COUNTER_MASK;
}
/// Get the address this page references
pub fn address(&self) -> PhysicalAddress {
PhysicalAddress::new(self.0 as usize & ADDRESS_MASK)
}
/// Get the current entry flags
pub fn page_table_entry_flags(&self) -> TableDescriptorFlags {
TableDescriptorFlags::from_bits_truncate(self.0)
}
pub fn page_descriptor_entry_flags(&self) -> PageDescriptorFlags {
PageDescriptorFlags::from_bits_truncate(self.0)
}
/// Get the current entry flags
pub fn flags(&self) -> PageFlags<RmmA> {
unsafe { PageFlags::from_data((self.0 as usize & RmmA::ENTRY_FLAGS_MASK) & !(COUNTER_MASK as usize)) }
}
/// Get the associated frame, if available, for a level 4, 3, or 2 page
pub fn pointed_frame(&self) -> Option<Frame> {
if self.page_table_entry_flags().contains(TableDescriptorFlags::VALID) {
Some(Frame::containing_address(self.address()))
} else {
None
}
}
/// Get the associated frame, if available, for a level 1 page
pub fn pointed_frame_at_l1(&self) -> Option<Frame> {
if self.page_descriptor_entry_flags().contains(PageDescriptorFlags::VALID) {
Some(Frame::containing_address(self.address()))
} else {
None
}
}
pub fn page_table_entry_set(&mut self, frame: Frame, flags: TableDescriptorFlags) {
debug_assert!(frame.start_address().data() & !ADDRESS_MASK == 0);
// ODDNESS Alert: We need to set the AF bit - despite this being a TableDescriptor!!!
// The Arm ARM says this bit (bit 10) is IGNORED in Table Descriptors so hopefully this is OK
let access_flag = TableDescriptorFlags::AF;
self.0 = (frame.start_address().data() as u64) | flags.bits() | access_flag.bits() | (self.0 & COUNTER_MASK);
}
pub fn page_descriptor_entry_set(&mut self, frame: Frame, flags: PageDescriptorFlags) {
debug_assert!(frame.start_address().data() & !ADDRESS_MASK == 0);
let access_flag = PageDescriptorFlags::AF;
self.0 = (frame.start_address().data() as u64) | flags.bits() | access_flag.bits() | (self.0 & COUNTER_MASK);
}
pub fn set(&mut self, frame: Frame, flags: PageFlags<RmmA>) {
debug_assert!(frame.start_address().data() & !ADDRESS_MASK == 0);
self.0 = (frame.start_address().data() as u64) | (flags.data() as u64) | (self.0 & COUNTER_MASK);
}
/// Get bit 51 in entry, used as 1 of 9 bits (in 9 entries) used as a counter for the page table
pub fn counter_bits(&self) -> u64 {
(self.0 & COUNTER_MASK) >> 51
}
/// Set bit 51 in entry, used as 1 of 9 bits (in 9 entries) used as a counter for the page table
pub fn set_counter_bits(&mut self, count: u64) {
self.0 = (self.0 & !COUNTER_MASK) | ((count & 0x1) << 51);
}
}
+1 -3
View File
@@ -5,7 +5,6 @@ use core::{mem, ptr};
use crate::device::cpu::registers::{control_regs, tlb};
use self::entry::EntryFlags;
use self::mapper::PageFlushAll;
pub use rmm::{
@@ -21,7 +20,6 @@ pub use super::CurrentRmmArch as RmmA;
pub type PageMapper = rmm::PageMapper<RmmA, crate::arch::rmm::LockedAllocator>;
pub use crate::rmm::KernelMapper;
pub mod entry;
pub mod mapper;
/// Number of entries per page table
@@ -64,7 +62,7 @@ unsafe fn map_percpu(cpu_id: usize, mapper: &mut PageMapper) -> PageFlushAll<Rmm
for page in Page::range_inclusive(start_page, end_page) {
let result = mapper.map(
page.start_address(),
PageFlags::new().write(true).custom_flag(EntryFlags::GLOBAL.bits(), cfg!(not(feature = "pti"))),
PageFlags::new().write(true).global(cfg!(not(feature = "pti"))),
)
.expect("failed to allocate page table frames while mapping percpu");
flush_all.consume(result);
-1
View File
@@ -178,7 +178,6 @@ unsafe fn inner<A: Arch>(
#[cfg(feature = "graphical_debug")]
{
use crate::devices::graphical_debug::FRAMEBUFFER;
use super::paging::entry::EntryFlags;
let (phys, virt, size) = *FRAMEBUFFER.lock();
+4 -7
View File
@@ -58,7 +58,7 @@ pub struct KernelArgs {
/// The entry to Rust, all things must be initialized
#[no_mangle]
pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
pub unsafe extern "C" fn kstart(args_ptr: *const KernelArgs) -> ! {
let bootstrap = {
let args = &*args_ptr;
@@ -113,15 +113,12 @@ pub unsafe extern fn kstart(args_ptr: *const KernelArgs) -> ! {
info!("Bootstrap entry point: {:X}", {args.bootstrap_entry});
// Setup interrupt handlers
extern "C" {
fn exception_vector_base();
}
core::arch::asm!(
"
ldr x0, =exception_vector_base
msr vbar_el1, x0
ldr {tmp}, =exception_vector_base
msr vbar_el1, {tmp}
",
out("x0") _,
tmp = out(reg) _,
);
/* NOT USED WITH UEFI
+1 -2
View File
@@ -4,7 +4,6 @@
use core::{mem, ptr};
use x86::msr;
use self::entry::EntryFlags;
use self::mapper::PageFlushAll;
pub use rmm::{
@@ -84,7 +83,7 @@ unsafe fn map_percpu(cpu_id: usize, mapper: &mut PageMapper) -> PageFlushAll<Rmm
for page in Page::range_inclusive(start_page, end_page) {
let result = mapper.map(
page.start_address(),
PageFlags::new().write(true).custom_flag(EntryFlags::GLOBAL.bits(), cfg!(not(feature = "pti"))),
PageFlags::new().write(true).global(cfg!(not(feature = "pti"))),
)
.expect("failed to allocate page table frames while mapping percpu");
flush_all.consume(result);
+1 -2
View File
@@ -4,7 +4,6 @@
use core::{mem, ptr};
use x86::msr;
use self::entry::EntryFlags;
use self::mapper::PageFlushAll;
pub use rmm::{
@@ -84,7 +83,7 @@ unsafe fn map_percpu(cpu_id: usize, mapper: &mut PageMapper) -> PageFlushAll<Rmm
for page in Page::range_inclusive(start_page, end_page) {
let result = mapper.map(
page.start_address(),
PageFlags::new().write(true).custom_flag(EntryFlags::GLOBAL.bits(), cfg!(not(feature = "pti"))),
PageFlags::new().write(true).global(cfg!(not(feature = "pti"))),
)
.expect("failed to allocate page table frames while mapping percpu");
flush_all.consume(result);
+5 -2
View File
@@ -91,11 +91,12 @@ impl ContextList {
let _ = context.set_addr_space(super::memory::new_addrspace()?);
let mut stack = vec![0; 65_536].into_boxed_slice();
let offset = stack.len() - mem::size_of::<usize>();
let mut offset = stack.len();
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
unsafe {
let offset = stack.len() - mem::size_of::<usize>();
// Space for return address on stack
offset -= mem::size_of::<usize>();
let func_ptr = stack.as_mut_ptr().add(offset);
*(func_ptr as *mut usize) = func as usize;
}
@@ -105,6 +106,8 @@ impl ContextList {
let context_id = context.id.into();
context.arch.set_lr(func as usize);
context.arch.set_context_handle();
// Stack should be 16 byte aligned
offset -= (stack.as_ptr() as usize + offset) % 16;
}
context.arch.set_stack(stack.as_ptr() as usize + offset);
+3 -1
View File
@@ -1,12 +1,14 @@
use crate::interrupt::InterruptStack;
use crate::memory::{allocate_frames_complex, deallocate_frames, Frame, PAGE_SIZE};
use crate::paging::{PageFlags, PhysicalAddress, VirtualAddress, mapper::PageFlushAll};
use crate::paging::entry::EntryFlags;
use crate::context;
use crate::context::memory::{Grant, Region};
use crate::syscall::error::{Error, EFAULT, EINVAL, ENOMEM, EPERM, ESRCH, Result};
use crate::syscall::flag::{PhysallocFlags, PartialAllocStrategy, PhysmapFlags, PHYSMAP_WRITE, PHYSMAP_WRITE_COMBINE, PHYSMAP_NO_CACHE};
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
use crate::paging::entry::EntryFlags;
use alloc::sync::Arc;
fn enforce_root() -> Result<()> {