Skip to content

Commit bd0263e

Browse files
committed
attempt at removing cloning of VcpuFd from GDB
Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 592b3a6 commit bd0263e

File tree

3 files changed

+82
-51
lines changed

3 files changed

+82
-51
lines changed

src/vmm/src/gdb/target.rs

Lines changed: 80 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -39,38 +39,47 @@ use crate::utils::u64_to_usize;
3939
use crate::vstate::vcpu::VcpuSendEventError;
4040
use crate::{FcExitCode, VcpuEvent, VcpuResponse, Vmm};
4141

42-
#[derive(Debug)]
42+
#[derive(Debug, Clone, Copy)]
4343
/// Stores the current state of a Vcpu with a copy of the Vcpu file descriptor
4444
struct VcpuState {
4545
single_step: bool,
4646
paused: bool,
47-
vcpu_fd: VcpuFd,
47+
// vcpu_fd: VcpuFd,
4848
}
4949

50-
impl VcpuState {
51-
/// Constructs a new instance of a VcpuState from a VcpuFd
52-
fn from_vcpu_fd(vcpu_fd: VcpuFd) -> Self {
50+
impl Default for VcpuState {
51+
fn default() -> Self {
5352
Self {
5453
single_step: false,
5554
paused: false,
56-
vcpu_fd,
5755
}
5856
}
57+
}
58+
59+
impl VcpuState {
60+
/// Constructs a new instance of a VcpuState from a VcpuFd
61+
// fn from_vcpu_fd(vcpu_fd: VcpuFd) -> Self {
62+
// Self {
63+
// single_step: false,
64+
// paused: false,
65+
// vcpu_fd,
66+
// }
67+
// }
5968

6069
/// Disables single stepping on the Vcpu state
6170
fn reset_vcpu_state(&mut self) {
6271
self.single_step = false;
6372
}
6473

65-
/// Updates the kvm debug flags set against the Vcpu with a check
66-
fn update_kvm_debug(&self, hw_breakpoints: &[GuestAddress]) -> Result<(), GdbTargetError> {
67-
if !self.paused {
68-
info!("Attempted to update kvm debug on a non paused Vcpu");
69-
return Ok(());
70-
}
71-
72-
arch::vcpu_set_debug(&self.vcpu_fd, hw_breakpoints, self.single_step)
73-
}
74+
// // Updates the kvm debug flags set against the Vcpu with a check
75+
// fn update_kvm_debug(&self, hw_breakpoints: &[GuestAddress]) -> Result<(), GdbTargetError> {
76+
// if !self.paused {
77+
// info!("Attempted to update kvm debug on a non paused Vcpu");
78+
// return Ok(());
79+
// }
80+
//
81+
// arch::vcpu_set_debug(&self.vcpu_fd, hw_breakpoints, self.single_step)
82+
// }
7483
}
7584

7685
/// Errors from interactions between GDB and the VMM
@@ -185,7 +194,7 @@ impl FirecrackerTarget {
185194
gdb_event: Receiver<usize>,
186195
entry_addr: GuestAddress,
187196
) -> Self {
188-
let mut vcpu_state: Vec<_> = vcpu_fds.into_iter().map(VcpuState::from_vcpu_fd).collect();
197+
let mut vcpu_state = vec![VcpuState::default(); vmm.lock().unwrap().vcpus_handles.len()];
189198
// By default vcpu 1 will be paused at the entry point
190199
vcpu_state[0].paused = true;
191200

@@ -202,16 +211,34 @@ impl FirecrackerTarget {
202211
}
203212
}
204213

214+
fn update_vcpu_kvm_debug(
215+
&self,
216+
vcpu_idx: usize,
217+
hw_breakpoints: &[GuestAddress],
218+
) -> Result<(), GdbTargetError> {
219+
let state = &self.vcpu_state[vcpu_idx];
220+
if !state.paused {
221+
info!("Attempted to update kvm debug on a non paused Vcpu");
222+
return Ok(());
223+
}
224+
225+
let vcpu_fd = &self.vmm.lock().unwrap().vcpus_handles[vcpu_idx].vcpu_fd;
226+
arch::vcpu_set_debug(vcpu_fd, hw_breakpoints, state.single_step)
227+
}
228+
205229
/// Retrieves the currently paused Vcpu id returns an error if there is no currently paused Vcpu
206230
fn get_paused_vcpu_id(&self) -> Result<Tid, GdbTargetError> {
207231
self.paused_vcpu.ok_or(GdbTargetError::NoPausedVcpu)
208232
}
209233

210-
/// Retrieves the currently paused Vcpu state returns an error if there is no currently paused
211-
/// Vcpu
212-
fn get_paused_vcpu(&self) -> Result<&VcpuState, GdbTargetError> {
213-
let vcpu_index = tid_to_vcpuid(self.get_paused_vcpu_id()?);
214-
Ok(&self.vcpu_state[vcpu_index])
234+
fn get_paused_vcpu_idx(&self) -> Result<usize, GdbTargetError> {
235+
Ok(tid_to_vcpuid(self.get_paused_vcpu_id()?))
236+
}
237+
238+
fn get_vcpu_fd(&self, vcpu_idx: usize) -> Result<&VcpuFd, GdbTargetError> {
239+
// let vcpu_index = tid_to_vcpuid(self.get_paused_vcpu_id()?);
240+
// Ok(&self.vcpu_state[vcpu_index])
241+
Ok(&self.vmm.lock().unwrap().vcpus_handles[vcpu_idx].vcpu_fd)
215242
}
216243

217244
/// Updates state to reference the currently paused Vcpu and store that the cpu is currently
@@ -224,9 +251,9 @@ impl FirecrackerTarget {
224251
/// Resumes execution of all paused Vcpus, update them with current kvm debug info
225252
/// and resumes
226253
fn resume_all_vcpus(&mut self) -> Result<(), GdbTargetError> {
227-
self.vcpu_state
228-
.iter()
229-
.try_for_each(|state| state.update_kvm_debug(&self.hw_breakpoints))?;
254+
for idx in 0..self.vcpu_state.len() {
255+
self.update_vcpu_kvm_debug(idx, &self.hw_breakpoints)?;
256+
}
230257

231258
for cpu_id in 0..self.vcpu_state.len() {
232259
let tid = vcpuid_to_tid(cpu_id)?;
@@ -274,8 +301,8 @@ impl FirecrackerTarget {
274301

275302
/// A helper function to allow the event loop to inject this breakpoint back into the Vcpu
276303
pub fn inject_bp_to_guest(&mut self, tid: Tid) -> Result<(), GdbTargetError> {
277-
let vcpu_state = &mut self.vcpu_state[tid_to_vcpuid(tid)];
278-
arch::vcpu_inject_bp(&vcpu_state.vcpu_fd, &self.hw_breakpoints, false)
304+
let vcpu_fd = self.get_vcpu_fd(tid_to_vcpuid(tid))?;
305+
arch::vcpu_inject_bp(vcpu_fd, &self.hw_breakpoints, false)
279306
}
280307

281308
/// Resumes the Vcpu, will return early if the Vcpu is already running
@@ -307,21 +334,23 @@ impl FirecrackerTarget {
307334
&self,
308335
tid: Tid,
309336
) -> Result<Option<BaseStopReason<Tid, u64>>, GdbTargetError> {
310-
let vcpu_state = &self.vcpu_state[tid_to_vcpuid(tid)];
337+
let vcpu_idx = tid_to_vcpuid(tid);
338+
let vcpu_state = &self.vcpu_state[vcpu_idx];
311339
if vcpu_state.single_step {
312340
return Ok(Some(MultiThreadStopReason::SignalWithThread {
313341
tid,
314342
signal: Signal::SIGTRAP,
315343
}));
316344
}
317345

318-
let Ok(ip) = arch::get_instruction_pointer(&vcpu_state.vcpu_fd) else {
346+
let vcpu_fd = self.get_vcpu_fd(vcpu_idx)?;
347+
let Ok(ip) = arch::get_instruction_pointer(vcpu_fd) else {
319348
// If we error here we return an arbitrary Software Breakpoint, GDB will handle
320349
// this gracefully
321350
return Ok(Some(MultiThreadStopReason::SwBreak(tid)));
322351
};
323352

324-
let gpa = arch::translate_gva(&vcpu_state.vcpu_fd, ip, &self.vmm.lock().unwrap())?;
353+
let gpa = arch::translate_gva(vcpu_fd, ip, &self.vmm.lock().unwrap())?;
325354
if self.sw_breakpoints.contains_key(&gpa) {
326355
return Ok(Some(MultiThreadStopReason::SwBreak(tid)));
327356
}
@@ -364,14 +393,18 @@ impl Target for FirecrackerTarget {
364393
impl MultiThreadBase for FirecrackerTarget {
365394
/// Reads the registers for the Vcpu
366395
fn read_registers(&mut self, regs: &mut CoreRegs, tid: Tid) -> TargetResult<(), Self> {
367-
arch::read_registers(&self.vcpu_state[tid_to_vcpuid(tid)].vcpu_fd, regs)?;
396+
let vcpu_idx = tid_to_vcpuid(tid);
397+
let vcpu_fd = self.get_vcpu_fd(vcpu_idx)?;
398+
arch::read_registers(vcpu_fd, regs)?;
368399

369400
Ok(())
370401
}
371402

372403
/// Writes to the registers for the Vcpu
373404
fn write_registers(&mut self, regs: &CoreRegs, tid: Tid) -> TargetResult<(), Self> {
374-
arch::write_registers(&self.vcpu_state[tid_to_vcpuid(tid)].vcpu_fd, regs)?;
405+
let vcpu_idx = tid_to_vcpuid(tid);
406+
let vcpu_fd = self.get_vcpu_fd(vcpu_idx)?;
407+
arch::write_registers(vcpu_fd, regs)?;
375408

376409
Ok(())
377410
}
@@ -384,12 +417,14 @@ impl MultiThreadBase for FirecrackerTarget {
384417
tid: Tid,
385418
) -> TargetResult<usize, Self> {
386419
let data_len = data.len();
387-
let vcpu_state = &self.vcpu_state[tid_to_vcpuid(tid)];
420+
let vcpu_idx = tid_to_vcpuid(tid);
421+
let vcpu_state = &self.vcpu_state[vcpu_idx];
422+
let vcpu_fd = self.get_vcpu_fd(vcpu_idx)?;
388423

389424
let vmm = &self.vmm.lock().expect("Error locking vmm in read addr");
390425

391426
while !data.is_empty() {
392-
let gpa = arch::translate_gva(&vcpu_state.vcpu_fd, gva, &vmm).map_err(|e| {
427+
let gpa = arch::translate_gva(vcpu_fd, gva, &vmm).map_err(|e| {
393428
error!("Error {e:?} translating gva on read address: {gva:#X}");
394429
})?;
395430

@@ -420,11 +455,13 @@ impl MultiThreadBase for FirecrackerTarget {
420455
mut data: &[u8],
421456
tid: Tid,
422457
) -> TargetResult<(), Self> {
423-
let vcpu_state = &self.vcpu_state[tid_to_vcpuid(tid)];
458+
let vcpu_idx = tid_to_vcpuid(tid);
459+
let vcpu_state = &self.vcpu_state[vcpu_idx];
460+
let vcpu_fd = self.get_vcpu_fd(vcpu_idx)?;
424461
let vmm = &self.vmm.lock().expect("Error locking vmm in write addr");
425462

426463
while !data.is_empty() {
427-
let gpa = arch::translate_gva(&vcpu_state.vcpu_fd, gva, &vmm).map_err(|e| {
464+
let gpa = arch::translate_gva(vcpu_fd, gva, &vmm).map_err(|e| {
428465
error!("Error {e:?} translating gva on read address: {gva:#X}");
429466
})?;
430467

@@ -546,8 +583,8 @@ impl HwBreakpoint for FirecrackerTarget {
546583
return Ok(false);
547584
}
548585

549-
let state = self.get_paused_vcpu()?;
550-
state.update_kvm_debug(&self.hw_breakpoints)?;
586+
let vcpu_idx = self.get_paused_vcpu_idx()?;
587+
self.update_vcpu_kvm_debug(vcpu_idx, &self.hw_breakpoints)?;
551588

552589
Ok(true)
553590
}
@@ -563,8 +600,8 @@ impl HwBreakpoint for FirecrackerTarget {
563600
Some(pos) => self.hw_breakpoints.remove(pos),
564601
};
565602

566-
let state = self.get_paused_vcpu()?;
567-
state.update_kvm_debug(&self.hw_breakpoints)?;
603+
let vcpu_idx = self.get_paused_vcpu_idx()?;
604+
self.update_vcpu_kvm_debug(vcpu_idx, &self.hw_breakpoints)?;
568605

569606
Ok(true)
570607
}
@@ -580,11 +617,8 @@ impl SwBreakpoint for FirecrackerTarget {
580617
addr: <Self::Arch as Arch>::Usize,
581618
_kind: <Self::Arch as Arch>::BreakpointKind,
582619
) -> TargetResult<bool, Self> {
583-
let gpa = arch::translate_gva(
584-
&self.get_paused_vcpu()?.vcpu_fd,
585-
addr,
586-
&self.vmm.lock().unwrap(),
587-
)?;
620+
let vcpu_fd = self.get_vcpu_fd(self.get_paused_vcpu_idx()?)?;
621+
let gpa = arch::translate_gva(vcpu_fd, addr, &self.vmm.lock().unwrap())?;
588622

589623
if self.sw_breakpoints.contains_key(&gpa) {
590624
return Ok(true);
@@ -608,11 +642,8 @@ impl SwBreakpoint for FirecrackerTarget {
608642
addr: <Self::Arch as Arch>::Usize,
609643
_kind: <Self::Arch as Arch>::BreakpointKind,
610644
) -> TargetResult<bool, Self> {
611-
let gpa = arch::translate_gva(
612-
&self.get_paused_vcpu()?.vcpu_fd,
613-
addr,
614-
&self.vmm.lock().unwrap(),
615-
)?;
645+
let vcpu_fd = self.get_vcpu_fd(self.get_paused_vcpu_idx()?)?;
646+
let gpa = arch::translate_gva(vcpu_fd, addr, &self.vmm.lock().unwrap())?;
616647

617648
if let Some(removed) = self.sw_breakpoints.remove(&gpa) {
618649
self.write_addrs(addr, &removed, self.get_paused_vcpu_id()?)?;

src/vmm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ pub struct Vmm {
297297
// Save UFFD in order to keep it open in the Firecracker process, as well.
298298
#[allow(unused)]
299299
uffd: Option<Uffd>,
300-
vcpus_handles: Vec<VcpuHandle>,
300+
pub vcpus_handles: Vec<VcpuHandle>,
301301
// Used by Vcpus and devices to initiate teardown; Vmm should never write here.
302302
vcpus_exit_evt: EventFd,
303303
// Device manager

src/vmm/src/vstate/vcpu.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -598,7 +598,7 @@ pub struct VcpuHandle {
598598
response_receiver: Receiver<VcpuResponse>,
599599
// Rust JoinHandles have to be wrapped in Option if you ever plan on 'join()'ing them.
600600
// We want to be able to join these threads in tests.
601-
vcpu_fd: VcpuFd,
601+
pub vcpu_fd: VcpuFd,
602602
vcpu_thread: Option<thread::JoinHandle<()>>,
603603
}
604604

0 commit comments

Comments
 (0)