Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ version = "0.1.1"
edition = "2024"

[dependencies]
axerrno = { git = "https://github.com/Starry-OS/axerrno.git", rev = "f1e2bca" }
axerrno = "0.2"
axplat = "0.2"
log = "0.4"
xmas-elf = "0.9"
rand_pcg = { version = "0.3", default-features = false }
rand_core = { version = "0.6", default-features = false }
kernel-elf-parser = { git = "https://github.com/Starry-OS/kernel_elf_parser.git", rev = "fdcce74" }
memory_addr = "0.4"
cfg-if = "1.0"
145 changes: 140 additions & 5 deletions src/vdso.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
//! vDSO data management.
extern crate alloc;
extern crate log;
use alloc::alloc::alloc_zeroed;
use alloc::{alloc::alloc_zeroed, vec::Vec};
use core::alloc::Layout;

use axerrno::{AxError, AxResult};
use axplat::{mem::virt_to_phys, time::monotonic_time_nanos};

const PAGE_SIZE_4K: usize = 4096;
use kernel_elf_parser::{AuxEntry, AuxType};
use log::{info, warn};
use memory_addr::{MemoryAddr, PAGE_SIZE_4K};

/// Global vDSO data instance
#[unsafe(link_section = ".data")]
Expand All @@ -18,11 +19,15 @@ pub fn init_vdso_data() {
unsafe {
let data_ptr = core::ptr::addr_of_mut!(VDSO_DATA);
(*data_ptr).time_update();
log::info!("vDSO data initialized at {:#x}", data_ptr as usize);
info!("vDSO data initialized at {:#x}", data_ptr as usize);
#[cfg(target_arch = "aarch64")]
{
crate::vdso_data::enable_cntvct_access();
log::info!("vDSO CNTVCT access enabled");
info!("vDSO CNTVCT access enabled");
}
#[cfg(target_arch = "x86_64")]
{
(*data_ptr).enable_pvclock();
}
#[cfg(target_arch = "x86_64")]
{
Expand Down Expand Up @@ -122,3 +127,133 @@ pub fn calculate_vdso_aslr_addr(

(base_addr, vdso_addr)
}

/// Load vDSO into the given user address space and update auxv accordingly.
pub fn load_vdso_data<F1, F2, F3>(auxv: &mut Vec<AuxEntry>, f1: F1, f2: F2, f3: F3) -> AxResult<()>
where
F1: FnOnce(usize, axplat::mem::PhysAddr, usize) -> AxResult<()>,
F2: FnOnce(usize, usize) -> AxResult<()>,
F3: FnMut(
usize,
axplat::mem::PhysAddr,
usize,
&xmas_elf::program::ProgramHeader64,
) -> AxResult<()>,
{
unsafe extern "C" {
static vdso_start: u8;
static vdso_end: u8;
}
let (vdso_kstart, vdso_kend) = unsafe {
(
&vdso_start as *const u8 as usize,
&vdso_end as *const u8 as usize,
)
};
info!("vdso_kstart: {vdso_kstart:#x}, vdso_kend: {vdso_kend:#x}");

if vdso_kend <= vdso_kstart {
warn!(
"vDSO binary is missing or invalid: vdso_kstart={vdso_kstart:#x}, \
vdso_kend={vdso_kend:#x}. vDSO will not be loaded and AT_SYSINFO_EHDR will not be \
set."
);
return Err(AxError::InvalidExecutable);
}

let (vdso_paddr_page, vdso_bytes, vdso_size, vdso_page_offset, alloc_info) =
prepare_vdso_pages(vdso_kstart, vdso_kend).map_err(|_| AxError::InvalidExecutable)?;

let mut alloc_guard = crate::guard::VdsoAllocGuard::new(alloc_info);

let (_base_addr, vdso_user_addr) =
calculate_vdso_aslr_addr(vdso_kstart, vdso_kend, vdso_page_offset);

match kernel_elf_parser::ELFHeadersBuilder::new(vdso_bytes).and_then(|b| {
let range = b.ph_range();
b.build(&vdso_bytes[range.start as usize..range.end as usize])
}) {
Ok(headers) => {
map_vdso_segments(
headers,
vdso_user_addr,
vdso_paddr_page,
vdso_page_offset,
f3,
)?;
alloc_guard.disarm();
}
Err(_) => {
info!("vDSO ELF parsing failed, using fallback mapping");
let map_user_start = if vdso_page_offset == 0 {
vdso_user_addr
} else {
vdso_user_addr - vdso_page_offset
};
f1(map_user_start, vdso_paddr_page, vdso_size)?;
alloc_guard.disarm();
}
}

map_vvar_and_push_aux(auxv, vdso_user_addr, f2)?;

Ok(())
}

fn map_vvar_and_push_aux<F>(auxv: &mut Vec<AuxEntry>, vdso_user_addr: usize, f: F) -> AxResult<()>
where
F: FnOnce(usize, usize) -> AxResult<()>,
{
use crate::config::VVAR_PAGES;
let vvar_user_addr = vdso_user_addr - VVAR_PAGES * PAGE_SIZE_4K;
let vvar_paddr = vdso_data_paddr();

f(vvar_user_addr, vvar_paddr)?;

info!(
"Mapped vvar pages at user {:#x}..{:#x} -> paddr {:#x}",
vvar_user_addr,
vvar_user_addr + VVAR_PAGES * PAGE_SIZE_4K,
vvar_paddr,
);

let aux_entry = AuxEntry::new(AuxType::SYSINFO_EHDR, vdso_user_addr);
auxv.push(aux_entry);

Ok(())
}

fn map_vdso_segments<F>(
headers: kernel_elf_parser::ELFHeaders,
vdso_user_addr: usize,
vdso_paddr_page: axplat::mem::PhysAddr,
vdso_page_offset: usize,
mut f: F,
) -> AxResult<()>
where
F: FnMut(
usize,
axplat::mem::PhysAddr,
usize,
&xmas_elf::program::ProgramHeader64,
) -> AxResult<()>,
{
info!("vDSO ELF parsed successfully, mapping segments");
for ph in headers
.ph
.iter()
.filter(|ph| ph.get_type() == Ok(xmas_elf::program::Type::Load))
{
let vaddr = ph.virtual_addr as usize;
let seg_pad = vaddr.align_offset_4k() + vdso_page_offset;
let seg_align_size =
(ph.mem_size as usize + seg_pad + PAGE_SIZE_4K - 1) & !(PAGE_SIZE_4K - 1);

let map_base_user = vdso_user_addr & !(PAGE_SIZE_4K - 1);
let seg_user_start = map_base_user + vaddr.align_down_4k();
let seg_paddr = vdso_paddr_page + vaddr.align_down_4k();

f(seg_user_start, seg_paddr, seg_align_size, ph)?;
}
Ok(())
}
6 changes: 6 additions & 0 deletions src/vdso_time_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ pub struct VdsoClock {
pub _unused: u32,
}

impl Default for VdsoClock {
fn default() -> Self {
Self::new()
}
}

impl VdsoClock {
/// Create a new VdsoClock with default values.
pub const fn new() -> Self {
Expand Down
2 changes: 1 addition & 1 deletion src/x86_64/vdso_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,5 +106,5 @@ fn register_pvclock(cpu_id: usize) {
let offset = cpu_id * core::mem::size_of::<crate::x86_64::pvclock_data::PvClockTimeInfo>();
let paddr = base + offset as u64;
crate::x86_64::pvclock_data::register_kvm_clock(paddr);
log::info!("PVCLOCK registered for cpu {} at {:#x}", cpu_id, paddr);
log::info!("PVCLOCK registered for cpu {cpu_id} at {paddr:#x}");
}