Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ default = []
fp-simd = []
tls = []
uspace = []
arm-el2 = []

[dependencies]
linkme = "0.3"
Expand Down
72 changes: 66 additions & 6 deletions src/aarch64/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,26 @@ pub fn halt() {

/// Reads the current page table root register for kernel space (`TTBR1_EL1`).
///
/// When the "arm-el2" feature is enabled,
/// TTBR0_EL2 is dedicated to the Hypervisor's Stage-2 page table base address.
///
/// Returns the physical address of the page table root.
#[inline]
pub fn read_kernel_page_table() -> PhysAddr {
#[cfg(not(feature = "arm-el2"))]
let root = TTBR1_EL1.get();

#[cfg(feature = "arm-el2")]
let root = TTBR0_EL2.get();

pa!(root as usize)
}

/// 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
///
/// Returns the physical address of the page table root.
#[inline]
pub fn read_user_page_table() -> PhysAddr {
Expand All @@ -65,19 +76,33 @@ pub fn read_user_page_table() -> PhysAddr {
/// Writes the register to update the current page table root for kernel space
/// (`TTBR1_EL1`).
///
/// When the "arm-el2" feature is enabled,
/// TTBR0_EL2 is dedicated to the Hypervisor's Stage-2 page table base address.
///
/// Note that the TLB is **NOT** flushed after this operation.
///
/// # Safety
///
/// This function is unsafe as it changes the virtual memory address space.
#[inline]
pub unsafe fn write_kernel_page_table(root_paddr: PhysAddr) {
// kernel space page table use TTBR1 (0xffff_0000_0000_0000..0xffff_ffff_ffff_ffff)
TTBR1_EL1.set(root_paddr.as_usize() as _);
#[cfg(not(feature = "arm-el2"))]
{
// 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)
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
///
/// Note that the TLB is **NOT** flushed after this operation.
///
Expand All @@ -93,14 +118,46 @@ pub unsafe fn write_user_page_table(root_paddr: PhysAddr) {
///
/// If `vaddr` is [`None`], flushes the entire TLB. Otherwise, flushes the TLB
/// entry that maps the given virtual address.
///
/// Moreover, The reason for shifting vaddr right by 12 bits here is to clear
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Remove meaningless comments

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thanks, useless comments have been removed

/// the address offset of the current position and obtain the aligned page number.
///
/// Other functions do not use page numbers(no need to shift right by 12 bits)?
///
/// ​Cache refresh: Data cache is in cache lines, and the full address is required
/// to locate a specific cache line, not the page number.
///
/// Page table register write: When directly operating the TTBRx_ELx register,
/// the physical address of the page table base address is required, and no virtual
/// address displacement is required.
///
/// ​Exception vector table: When setting the exception handling entry, just write
/// the base address directly.
#[inline]
pub fn flush_tlb(vaddr: Option<VirtAddr>) {
unsafe {
if let Some(vaddr) = vaddr {
asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) vaddr.as_usize())
const VA_MASK: usize = (1 << 44) - 1; // 0xFFFF_FFFF_FFFF
let operand = (vaddr.as_usize() >> 12) & VA_MASK;

#[cfg(not(feature = "arm-el2"))]
{
asm!("tlbi vaae1is, {}; dsb sy; isb", in(reg) operand)
}
#[cfg(feature = "arm-el2")]
{
asm!("tlbi vae2is, {}; dsb sy; isb", in(reg) operand)
}
} else {
// flush the entire TLB
asm!("tlbi vmalle1; dsb sy; isb")
#[cfg(not(feature = "arm-el2"))]
{
asm!("tlbi vmalle1; dsb sy; isb")
}
#[cfg(feature = "arm-el2")]
{
asm!("tlbi alle2; dsb sy; isb")
}
}
}
}
Expand All @@ -124,8 +181,11 @@ pub fn flush_dcache_line(vaddr: VirtAddr) {
/// This function is unsafe as it changes the exception handling behavior of the
/// current CPU.
#[inline]
pub unsafe fn write_exception_vector_base(vbar_el1: usize) {
VBAR_EL1.set(vbar_el1 as _);
pub unsafe fn write_exception_vector_base(vbar: usize) {
#[cfg(not(feature = "arm-el2"))]
VBAR_EL1.set(vbar as _);
#[cfg(feature = "arm-el2")]
VBAR_EL2.set(vbar as _);
}

/// Reads the thread pointer of the current CPU (`TPIDR_EL0`).
Expand Down