Skip to content

Commit cf2d4a6

Browse files
authored
Refactor: loadvdso (#7)
* fix: fix pvclock support * refactor: run cargo fmt * refactor: run cargo clippy * refactor: update * refactor: run cargo fmt
1 parent e487e1c commit cf2d4a6

File tree

4 files changed

+150
-7
lines changed

4 files changed

+150
-7
lines changed

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ version = "0.1.1"
44
edition = "2024"
55

66
[dependencies]
7-
axerrno = { git = "https://github.com/Starry-OS/axerrno.git", rev = "f1e2bca" }
7+
axerrno = "0.2"
88
axplat = "0.2"
99
log = "0.4"
1010
xmas-elf = "0.9"
1111
rand_pcg = { version = "0.3", default-features = false }
1212
rand_core = { version = "0.6", default-features = false }
13+
kernel-elf-parser = { git = "https://github.com/Starry-OS/kernel_elf_parser.git", rev = "fdcce74" }
14+
memory_addr = "0.4"
1315
cfg-if = "1.0"

src/vdso.rs

Lines changed: 140 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
//! vDSO data management.
22
extern crate alloc;
33
extern crate log;
4-
use alloc::alloc::alloc_zeroed;
4+
use alloc::{alloc::alloc_zeroed, vec::Vec};
55
use core::alloc::Layout;
66

77
use axerrno::{AxError, AxResult};
88
use axplat::{mem::virt_to_phys, time::monotonic_time_nanos};
9-
10-
const PAGE_SIZE_4K: usize = 4096;
9+
use kernel_elf_parser::{AuxEntry, AuxType};
10+
use log::{info, warn};
11+
use memory_addr::{MemoryAddr, PAGE_SIZE_4K};
1112

1213
/// Global vDSO data instance
1314
#[unsafe(link_section = ".data")]
@@ -18,11 +19,15 @@ pub fn init_vdso_data() {
1819
unsafe {
1920
let data_ptr = core::ptr::addr_of_mut!(VDSO_DATA);
2021
(*data_ptr).time_update();
21-
log::info!("vDSO data initialized at {:#x}", data_ptr as usize);
22+
info!("vDSO data initialized at {:#x}", data_ptr as usize);
2223
#[cfg(target_arch = "aarch64")]
2324
{
2425
crate::vdso_data::enable_cntvct_access();
25-
log::info!("vDSO CNTVCT access enabled");
26+
info!("vDSO CNTVCT access enabled");
27+
}
28+
#[cfg(target_arch = "x86_64")]
29+
{
30+
(*data_ptr).enable_pvclock();
2631
}
2732
#[cfg(target_arch = "x86_64")]
2833
{
@@ -122,3 +127,133 @@ pub fn calculate_vdso_aslr_addr(
122127

123128
(base_addr, vdso_addr)
124129
}
130+
131+
/// Load vDSO into the given user address space and update auxv accordingly.
132+
pub fn load_vdso_data<F1, F2, F3>(auxv: &mut Vec<AuxEntry>, f1: F1, f2: F2, f3: F3) -> AxResult<()>
133+
where
134+
F1: FnOnce(usize, axplat::mem::PhysAddr, usize) -> AxResult<()>,
135+
F2: FnOnce(usize, usize) -> AxResult<()>,
136+
F3: FnMut(
137+
usize,
138+
axplat::mem::PhysAddr,
139+
usize,
140+
&xmas_elf::program::ProgramHeader64,
141+
) -> AxResult<()>,
142+
{
143+
unsafe extern "C" {
144+
static vdso_start: u8;
145+
static vdso_end: u8;
146+
}
147+
let (vdso_kstart, vdso_kend) = unsafe {
148+
(
149+
&vdso_start as *const u8 as usize,
150+
&vdso_end as *const u8 as usize,
151+
)
152+
};
153+
info!("vdso_kstart: {vdso_kstart:#x}, vdso_kend: {vdso_kend:#x}");
154+
155+
if vdso_kend <= vdso_kstart {
156+
warn!(
157+
"vDSO binary is missing or invalid: vdso_kstart={vdso_kstart:#x}, \
158+
vdso_kend={vdso_kend:#x}. vDSO will not be loaded and AT_SYSINFO_EHDR will not be \
159+
set."
160+
);
161+
return Err(AxError::InvalidExecutable);
162+
}
163+
164+
let (vdso_paddr_page, vdso_bytes, vdso_size, vdso_page_offset, alloc_info) =
165+
prepare_vdso_pages(vdso_kstart, vdso_kend).map_err(|_| AxError::InvalidExecutable)?;
166+
167+
let mut alloc_guard = crate::guard::VdsoAllocGuard::new(alloc_info);
168+
169+
let (_base_addr, vdso_user_addr) =
170+
calculate_vdso_aslr_addr(vdso_kstart, vdso_kend, vdso_page_offset);
171+
172+
match kernel_elf_parser::ELFHeadersBuilder::new(vdso_bytes).and_then(|b| {
173+
let range = b.ph_range();
174+
b.build(&vdso_bytes[range.start as usize..range.end as usize])
175+
}) {
176+
Ok(headers) => {
177+
map_vdso_segments(
178+
headers,
179+
vdso_user_addr,
180+
vdso_paddr_page,
181+
vdso_page_offset,
182+
f3,
183+
)?;
184+
alloc_guard.disarm();
185+
}
186+
Err(_) => {
187+
info!("vDSO ELF parsing failed, using fallback mapping");
188+
let map_user_start = if vdso_page_offset == 0 {
189+
vdso_user_addr
190+
} else {
191+
vdso_user_addr - vdso_page_offset
192+
};
193+
f1(map_user_start, vdso_paddr_page, vdso_size)?;
194+
alloc_guard.disarm();
195+
}
196+
}
197+
198+
map_vvar_and_push_aux(auxv, vdso_user_addr, f2)?;
199+
200+
Ok(())
201+
}
202+
203+
fn map_vvar_and_push_aux<F>(auxv: &mut Vec<AuxEntry>, vdso_user_addr: usize, f: F) -> AxResult<()>
204+
where
205+
F: FnOnce(usize, usize) -> AxResult<()>,
206+
{
207+
use crate::config::VVAR_PAGES;
208+
let vvar_user_addr = vdso_user_addr - VVAR_PAGES * PAGE_SIZE_4K;
209+
let vvar_paddr = vdso_data_paddr();
210+
211+
f(vvar_user_addr, vvar_paddr)?;
212+
213+
info!(
214+
"Mapped vvar pages at user {:#x}..{:#x} -> paddr {:#x}",
215+
vvar_user_addr,
216+
vvar_user_addr + VVAR_PAGES * PAGE_SIZE_4K,
217+
vvar_paddr,
218+
);
219+
220+
let aux_entry = AuxEntry::new(AuxType::SYSINFO_EHDR, vdso_user_addr);
221+
auxv.push(aux_entry);
222+
223+
Ok(())
224+
}
225+
226+
fn map_vdso_segments<F>(
227+
headers: kernel_elf_parser::ELFHeaders,
228+
vdso_user_addr: usize,
229+
vdso_paddr_page: axplat::mem::PhysAddr,
230+
vdso_page_offset: usize,
231+
mut f: F,
232+
) -> AxResult<()>
233+
where
234+
F: FnMut(
235+
usize,
236+
axplat::mem::PhysAddr,
237+
usize,
238+
&xmas_elf::program::ProgramHeader64,
239+
) -> AxResult<()>,
240+
{
241+
info!("vDSO ELF parsed successfully, mapping segments");
242+
for ph in headers
243+
.ph
244+
.iter()
245+
.filter(|ph| ph.get_type() == Ok(xmas_elf::program::Type::Load))
246+
{
247+
let vaddr = ph.virtual_addr as usize;
248+
let seg_pad = vaddr.align_offset_4k() + vdso_page_offset;
249+
let seg_align_size =
250+
(ph.mem_size as usize + seg_pad + PAGE_SIZE_4K - 1) & !(PAGE_SIZE_4K - 1);
251+
252+
let map_base_user = vdso_user_addr & !(PAGE_SIZE_4K - 1);
253+
let seg_user_start = map_base_user + vaddr.align_down_4k();
254+
let seg_paddr = vdso_paddr_page + vaddr.align_down_4k();
255+
256+
f(seg_user_start, seg_paddr, seg_align_size, ph)?;
257+
}
258+
Ok(())
259+
}

src/vdso_time_data.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ pub struct VdsoClock {
3939
pub _unused: u32,
4040
}
4141

42+
impl Default for VdsoClock {
43+
fn default() -> Self {
44+
Self::new()
45+
}
46+
}
47+
4248
impl VdsoClock {
4349
/// Create a new VdsoClock with default values.
4450
pub const fn new() -> Self {

src/x86_64/vdso_data.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,5 +106,5 @@ fn register_pvclock(cpu_id: usize) {
106106
let offset = cpu_id * core::mem::size_of::<crate::x86_64::pvclock_data::PvClockTimeInfo>();
107107
let paddr = base + offset as u64;
108108
crate::x86_64::pvclock_data::register_kvm_clock(paddr);
109-
log::info!("PVCLOCK registered for cpu {} at {:#x}", cpu_id, paddr);
109+
log::info!("PVCLOCK registered for cpu {cpu_id} at {paddr:#x}");
110110
}

0 commit comments

Comments
 (0)