Skip to content
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions src/aarch64/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ pub fn read_kernel_page_table() -> PhysAddr {
/// Reads the current page table root register for user space (`TTBR0_EL1`).
///
/// When the "arm-el2" feature is enabled, for user-mode programs,
/// virtualization is completely transparent to them, so there is no need to modify
/// virtualization is completely transparent to them, so there is no need to
/// modify
///
/// Returns the physical address of the page table root.
#[inline]
Expand All @@ -88,21 +89,24 @@ pub fn read_user_page_table() -> PhysAddr {
pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
#[cfg(not(feature = "arm-el2"))]
{
// kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff)
// kernel space page table use TTBR1
// (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff)
TTBR1_EL1.set(root_paddr.as_usize() as _);
}

#[cfg(feature = "arm-el2")]
{
// kernel space page table at EL2 use TTBR0_EL2 (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff)
// kernel space page table at EL2 use TTBR0_EL2
// (0x0000_0000_0000_0000..0x0000_ffff_ffff_ffff)
TTBR0_EL2.set(root_paddr.as_usize() as _);
}
}

/// Writes the register to update the current page table root for user space
/// (`TTBR1_EL0`).
/// When the "arm-el2" feature is enabled, for user-mode programs,
/// virtualization is completely transparent to them, so there is no need to modify
/// virtualization is completely transparent to them, so there is no need to
/// modify
///
/// Note that the TLB is **NOT** flushed after this operation.
///
Expand Down Expand Up @@ -201,3 +205,19 @@ pub fn enable_fp() {
CPACR_EL1.write(CPACR_EL1::FPEN::TrapNothing);
barrier::isb(barrier::SY);
}

core::arch::global_asm!(include_str!("user_copy.S"));

extern "C" {
/// Copy data from user space to kernel space safely.
///
/// # Arguments
/// * `dst` - Destination pointer in kernel space
/// * `src` - Source pointer in user space
/// * `size` - Number of bytes to copy
///
/// # Returns
/// * `0` - Success, all bytes copied
/// * `>0` - Number of bytes that could not be copied due to page fault
pub fn user_copy(dst: *mut u8, src: *const u8, size: usize) -> usize;
}
5 changes: 5 additions & 0 deletions src/aarch64/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,11 @@ impl TrapFrame {
self.r[0] as _
}

// TODO:
pub const fn sysno(&self) -> usize {
self.r[8] as usize
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And also add set_sysno

/// Sets the return value register.
pub const fn set_retval(&mut self, r0: usize) {
self.r[0] = r0 as _;
Expand Down
73 changes: 47 additions & 26 deletions src/aarch64/trap.S
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.macro SAVE_REGS
sub sp, sp, {trapframe_size}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep the sub code here because the RESTORE_REGS calls add code so you need to keep them consistent

stp x0, x1, [sp]
stp x2, x3, [sp, 2 * 8]
stp x4, x5, [sp, 4 * 8]
Expand Down Expand Up @@ -36,7 +35,7 @@
# backup kernel tpidr_el0
mrs x1, tpidr_el0
msr tpidrro_el0, x1

ldp x11, x12, [sp, 33 * 8]
ldp x9, x10, [sp, 31 * 8]
msr sp_el0, x9
Expand Down Expand Up @@ -65,6 +64,7 @@

.macro INVALID_EXCP, kind, source
.p2align 7
sub sp, sp, {trapframe_size}
SAVE_REGS
mov x0, sp
mov x1, \kind
Expand All @@ -73,8 +73,20 @@
b .Lexception_return
.endm

.macro TASK_EXIT, kind
.p2align 7
SAVE_REGS
mov x0, \kind
b _user_trap_entry

.endm

.Ldeadloop:
b .Ldeadloop
Comment on lines +84 to +85

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used at all? I suspect it's there for debugging...?


.macro HANDLE_SYNC
.p2align 7
sub sp, sp, {trapframe_size}
SAVE_REGS
mov x0, sp
bl handle_sync_exception
Expand All @@ -83,6 +95,7 @@

.macro HANDLE_IRQ
.p2align 7
sub sp, sp, {trapframe_size}
SAVE_REGS
mov x0, sp
bl handle_irq_exception
Expand All @@ -93,30 +106,38 @@
.p2align 11
.global exception_vector_base
exception_vector_base:
// current EL, with SP_EL0
INVALID_EXCP 0 0
INVALID_EXCP 1 0
INVALID_EXCP 2 0
INVALID_EXCP 3 0

// current EL, with SP_ELx
HANDLE_SYNC
HANDLE_IRQ
INVALID_EXCP 2 1
INVALID_EXCP 3 1

// TODO: handle user trap
// lower EL, aarch64
HANDLE_SYNC
HANDLE_IRQ
INVALID_EXCP 2 2
INVALID_EXCP 3 2

// lower EL, aarch32
INVALID_EXCP 0 3
INVALID_EXCP 1 3
INVALID_EXCP 2 3
INVALID_EXCP 3 3
curr_el_sp0_sync:
INVALID_EXCP 0 0
curr_el_sp0_irq:
INVALID_EXCP 1 0
curr_el_sp0_fiq:
INVALID_EXCP 2 0
curr_el_sp0_serror:
INVALID_EXCP 3 0
curr_el_spx_sync:
HANDLE_SYNC
curr_el_spx_irq:
HANDLE_IRQ
curr_el_spx_fiq:
INVALID_EXCP 2 1
curr_el_spx_serror:
INVALID_EXCP 3 1
lower_el_aarch64_sync:
TASK_EXIT {kind_sync}
lower_el_aarch64_irq:
TASK_EXIT {kind_irq}
lower_el_aarch64_fiq:
INVALID_EXCP 2 2
lower_el_aarch64_serror:
INVALID_EXCP 3 2
lower_el_aarch32_sync:
INVALID_EXCP 0 3
lower_el_aarch32_irq:
INVALID_EXCP 1 3
lower_el_aarch32_fiq:
INVALID_EXCP 2 3
lower_el_aarch32_serror:
INVALID_EXCP 3 3

.Lexception_return:
RESTORE_REGS
Expand Down
12 changes: 7 additions & 5 deletions src/aarch64/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ use crate::trap::PageFaultFlags;

core::arch::global_asm!(
include_str!("trap.S"),
trapframe_size = const core::mem::size_of::<TrapFrame>()
trapframe_size = const core::mem::size_of::<TrapFrame>(),
kind_irq = const TrapKind::Irq as u8,
kind_sync = const TrapKind::Synchronous as u8,
);

#[repr(u8)]
#[derive(Debug)]
#[allow(dead_code)]
enum TrapKind {
pub(crate) enum TrapKind {
Synchronous = 0,
Irq = 1,
Fiq = 2,
SError = 3,
Irq = 1,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add the padding here?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rustfmt

Fiq = 2,
SError = 3,
}

#[repr(u8)]
Expand Down
76 changes: 76 additions & 0 deletions src/aarch64/user_copy.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// AArch64 user space safe memory copy
// Based on RISC-V implementation and optimized for AArch64
Comment on lines +1 to +2

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but where did this code come from? I can't find any reference, and it doesn't look like it was implemented by porting axcpu's user_copy implementation on RISC-V to AArch64...

It should account for possible page faults and set up the exception table.


.section .text
.global user_copy
user_copy:
// x0 = dst, x1 = src, x2 = size
// Return: 0 on success, remaining bytes on fault
// Quick exit for zero size
cbz x2, .Lsuccess
// Save the end address for fault handling
add x3, x0, x2 // x3 = dst_end
mov x4, x2 // x4 = original_size (for fault calculation)
// Use different strategies based on size
cmp x2, #64
b.lo .Lbyte_copy
// For larger copies, try to align and use word copy
// First align dst to 8-byte boundary
and x5, x0, #7
cbz x5, .Laligned_copy
// Copy bytes until dst is 8-byte aligned
sub x5, x2, x5 // remaining after alignment
.Lalign_loop:
ldrb w6, [x1], #1
strb w6, [x0], #1
tbnz x0, #0, .Lalign_loop
tbnz x0, #1, .Lalign_loop
tbnz x0, #2, .Lalign_loop
mov x2, x5 // update remaining size
.Laligned_copy:
// Now dst is 8-byte aligned, do word copy
cmp x2, #8
b.lo .Lbyte_copy
// Unrolled 8-word (64-byte) copy loop
sub x5, x2, #64
.Lword_loop:
ldp x6, x7, [x1], #16
ldp x8, x9, [x1], #16
ldp x10, x11, [x1], #16
ldp x12, x13, [x1], #16
stp x6, x7, [x0], #16
stp x8, x9, [x0], #16
stp x10, x11, [x0], #16
stp x12, x13, [x0], #16
subs x2, x2, #64
cmp x2, #64
b.hs .Lword_loop
// Handle remaining words (8-byte chunks)
.Lword_remainder:
cmp x2, #8
b.lo .Lbyte_copy
ldr x6, [x1], #8
str x6, [x0], #8
sub x2, x2, #8
b .Lword_remainder
.Lbyte_copy:
// Copy remaining bytes
cbz x2, .Lsuccess
.Lbyte_loop:
ldrb w6, [x1], #1
strb w6, [x0], #1
subs x2, x2, #1
b.ne .Lbyte_loop
.Lsuccess:
mov x0, #0
ret
Loading