Skip to content

Commit d569ff3

Browse files
ShadowCurseroypat
authored andcommitted
refactor: remove duplicate VcpuFds from GDB
Since we store VcpuFds in VcpuHandles inside Vmm, and GDB stub has access to Vmm, remove redundant duplication of VcpuFds. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 4d66b7d commit d569ff3

File tree

6 files changed

+92
-100
lines changed

6 files changed

+92
-100
lines changed

src/vmm/src/builder.rs

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -182,18 +182,6 @@ pub fn build_microvm_for_boot(
182182
let entry_point = load_kernel(&boot_config.kernel_file, vm.guest_memory())?;
183183
let initrd = InitrdConfig::from_config(boot_config, vm.guest_memory())?;
184184

185-
#[cfg(feature = "gdb")]
186-
let (gdb_tx, gdb_rx) = mpsc::channel();
187-
#[cfg(feature = "gdb")]
188-
vcpus
189-
.iter_mut()
190-
.for_each(|vcpu| vcpu.attach_debug_info(gdb_tx.clone()));
191-
#[cfg(feature = "gdb")]
192-
let vcpu_fds = vcpus
193-
.iter()
194-
.map(|vcpu| vcpu.copy_kvm_vcpu_fd(&vm))
195-
.collect::<Result<Vec<_>, _>>()?;
196-
197185
if vm_resources.pci_enabled {
198186
device_manager.enable_pci(&vm)?;
199187
} else {
@@ -294,17 +282,18 @@ pub fn build_microvm_for_boot(
294282
let vmm = Arc::new(Mutex::new(vmm));
295283

296284
#[cfg(feature = "gdb")]
297-
if let Some(gdb_socket_path) = &vm_resources.machine_config.gdb_socket_path {
298-
gdb::gdb_thread(
299-
vmm.clone(),
300-
vcpu_fds,
301-
gdb_rx,
302-
entry_point.entry_addr,
303-
gdb_socket_path,
304-
)
305-
.map_err(StartMicrovmError::GdbServer)?;
306-
} else {
307-
debug!("No GDB socket provided not starting gdb server.");
285+
{
286+
let (gdb_tx, gdb_rx) = mpsc::channel();
287+
vcpus
288+
.iter_mut()
289+
.for_each(|vcpu| vcpu.attach_debug_info(gdb_tx.clone()));
290+
291+
if let Some(gdb_socket_path) = &vm_resources.machine_config.gdb_socket_path {
292+
gdb::gdb_thread(vmm.clone(), gdb_rx, entry_point.entry_addr, gdb_socket_path)
293+
.map_err(StartMicrovmError::GdbServer)?;
294+
} else {
295+
debug!("No GDB socket provided not starting gdb server.");
296+
}
308297
}
309298

310299
// Move vcpus to their own threads and start their state machine in the 'Paused' state.

src/vmm/src/gdb/event_loop.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use gdbstub::conn::{Connection, ConnectionExt};
1111
use gdbstub::stub::run_blocking::{self, WaitForStopReasonError};
1212
use gdbstub::stub::{DisconnectReason, GdbStub, MultiThreadStopReason};
1313
use gdbstub::target::Target;
14-
use kvm_ioctls::VcpuFd;
1514
use vm_memory::GuestAddress;
1615

1716
use super::target::{FirecrackerTarget, GdbTargetError, vcpuid_to_tid};
@@ -22,11 +21,10 @@ use crate::logger::{error, trace};
2221
pub fn event_loop(
2322
connection: UnixStream,
2423
vmm: Arc<Mutex<Vmm>>,
25-
vcpu_fds: Vec<VcpuFd>,
2624
gdb_event_receiver: Receiver<usize>,
2725
entry_addr: GuestAddress,
2826
) {
29-
let target = FirecrackerTarget::new(vmm, vcpu_fds, gdb_event_receiver, entry_addr);
27+
let target = FirecrackerTarget::new(vmm, gdb_event_receiver, entry_addr);
3028
let connection: Box<dyn ConnectionExt<Error = std::io::Error>> = { Box::new(connection) };
3129
let debugger = GdbStub::new(connection);
3230

src/vmm/src/gdb/mod.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use std::sync::{Arc, Mutex};
1515

1616
use arch::vcpu_set_debug;
1717
use event_loop::event_loop;
18-
use kvm_ioctls::VcpuFd;
1918
use target::GdbTargetError;
2019
use vm_memory::GuestAddress;
2120

@@ -35,7 +34,6 @@ use crate::logger::trace;
3534
/// communcation to the GDB server
3635
pub fn gdb_thread(
3736
vmm: Arc<Mutex<Vmm>>,
38-
vcpu_fds: Vec<VcpuFd>,
3937
gdb_event_receiver: Receiver<usize>,
4038
entry_addr: GuestAddress,
4139
socket_addr: &str,
@@ -44,10 +42,12 @@ pub fn gdb_thread(
4442
// to be stopped as it connects. This also allows us to set breakpoints before kernel starts.
4543
// This entry adddress is automatically used as it is not tracked inside the target state, so
4644
// when resumed will be removed
47-
vcpu_set_debug(&vcpu_fds[0], &[entry_addr], false)?;
48-
49-
for vcpu_fd in &vcpu_fds[1..] {
50-
vcpu_set_debug(vcpu_fd, &[], false)?;
45+
{
46+
let vmm = vmm.lock().unwrap();
47+
vcpu_set_debug(&vmm.vcpus_handles[0].vcpu_fd, &[entry_addr], false)?;
48+
for handle in &vmm.vcpus_handles[1..] {
49+
vcpu_set_debug(&handle.vcpu_fd, &[], false)?;
50+
}
5151
}
5252

5353
let path = Path::new(socket_addr);
@@ -59,7 +59,7 @@ pub fn gdb_thread(
5959

6060
std::thread::Builder::new()
6161
.name("gdb".into())
62-
.spawn(move || event_loop(connection, vmm, vcpu_fds, gdb_event_receiver, entry_addr))
62+
.spawn(move || event_loop(connection, vmm, gdb_event_receiver, entry_addr))
6363
.map_err(|_| GdbTargetError::GdbThreadError)?;
6464

6565
Ok(())

src/vmm/src/gdb/target.rs

Lines changed: 68 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use gdbstub_arch::aarch64::reg::AArch64CoreRegs as CoreRegs;
2727
use gdbstub_arch::x86::X86_64_SSE as GdbArch;
2828
#[cfg(target_arch = "x86_64")]
2929
use gdbstub_arch::x86::reg::X86_64CoreRegs as CoreRegs;
30-
use kvm_ioctls::VcpuFd;
3130
use vm_memory::{Bytes, GuestAddress, GuestMemoryError};
3231

3332
use super::arch;
@@ -39,38 +38,18 @@ use crate::utils::u64_to_usize;
3938
use crate::vstate::vcpu::VcpuSendEventError;
4039
use crate::{FcExitCode, VcpuEvent, VcpuResponse, Vmm};
4140

42-
#[derive(Debug)]
41+
#[derive(Debug, Default, Clone, Copy)]
4342
/// Stores the current state of a Vcpu with a copy of the Vcpu file descriptor
4443
struct VcpuState {
4544
single_step: bool,
4645
paused: bool,
47-
vcpu_fd: VcpuFd,
4846
}
4947

5048
impl VcpuState {
51-
/// Constructs a new instance of a VcpuState from a VcpuFd
52-
fn from_vcpu_fd(vcpu_fd: VcpuFd) -> Self {
53-
Self {
54-
single_step: false,
55-
paused: false,
56-
vcpu_fd,
57-
}
58-
}
59-
6049
/// Disables single stepping on the Vcpu state
6150
fn reset_vcpu_state(&mut self) {
6251
self.single_step = false;
6352
}
64-
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-
}
7453
}
7554

7655
/// Errors from interactions between GDB and the VMM
@@ -179,13 +158,8 @@ impl FirecrackerTarget {
179158
/// Creates a new Target for GDB stub. This is used as the layer between GDB and the VMM it
180159
/// will handle requests from GDB and perform the appropriate actions, while also updating GDB
181160
/// with the state of the VMM / Vcpu's as we hit debug events
182-
pub fn new(
183-
vmm: Arc<Mutex<Vmm>>,
184-
vcpu_fds: Vec<VcpuFd>,
185-
gdb_event: Receiver<usize>,
186-
entry_addr: GuestAddress,
187-
) -> Self {
188-
let mut vcpu_state: Vec<_> = vcpu_fds.into_iter().map(VcpuState::from_vcpu_fd).collect();
161+
pub fn new(vmm: Arc<Mutex<Vmm>>, gdb_event: Receiver<usize>, entry_addr: GuestAddress) -> Self {
162+
let mut vcpu_state = vec![VcpuState::default(); vmm.lock().unwrap().vcpus_handles.len()];
189163
// By default vcpu 1 will be paused at the entry point
190164
vcpu_state[0].paused = true;
191165

@@ -202,16 +176,37 @@ impl FirecrackerTarget {
202176
}
203177
}
204178

179+
// Update KVM debug info for a specific vcpu index.
180+
fn update_vcpu_kvm_debug(
181+
&self,
182+
vcpu_idx: usize,
183+
hw_breakpoints: &[GuestAddress],
184+
) -> Result<(), GdbTargetError> {
185+
let state = &self.vcpu_state[vcpu_idx];
186+
if !state.paused {
187+
info!("Attempted to update kvm debug on a non paused Vcpu");
188+
return Ok(());
189+
}
190+
191+
let vcpu_fd = &self.vmm.lock().unwrap().vcpus_handles[vcpu_idx].vcpu_fd;
192+
arch::vcpu_set_debug(vcpu_fd, hw_breakpoints, state.single_step)
193+
}
194+
195+
/// Translate guest virtual address to guest pysical address.
196+
fn translate_gva(&self, vcpu_idx: usize, addr: u64) -> Result<u64, GdbTargetError> {
197+
let vmm = self.vmm.lock().unwrap();
198+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
199+
arch::translate_gva(vcpu_fd, addr, &vmm)
200+
}
201+
205202
/// Retrieves the currently paused Vcpu id returns an error if there is no currently paused Vcpu
206203
fn get_paused_vcpu_id(&self) -> Result<Tid, GdbTargetError> {
207204
self.paused_vcpu.ok_or(GdbTargetError::NoPausedVcpu)
208205
}
209206

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])
207+
/// Returns the index of the paused vcpu.
208+
fn get_paused_vcpu_idx(&self) -> Result<usize, GdbTargetError> {
209+
Ok(tid_to_vcpuid(self.get_paused_vcpu_id()?))
215210
}
216211

217212
/// Updates state to reference the currently paused Vcpu and store that the cpu is currently
@@ -224,9 +219,9 @@ impl FirecrackerTarget {
224219
/// Resumes execution of all paused Vcpus, update them with current kvm debug info
225220
/// and resumes
226221
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))?;
222+
for idx in 0..self.vcpu_state.len() {
223+
self.update_vcpu_kvm_debug(idx, &self.hw_breakpoints)?;
224+
}
230225

231226
for cpu_id in 0..self.vcpu_state.len() {
232227
let tid = vcpuid_to_tid(cpu_id)?;
@@ -263,7 +258,7 @@ impl FirecrackerTarget {
263258
return Ok(());
264259
}
265260

266-
let cpu_handle = &self.vmm.lock()?.vcpus_handles[tid_to_vcpuid(tid)];
261+
let cpu_handle = &mut self.vmm.lock()?.vcpus_handles[tid_to_vcpuid(tid)];
267262

268263
cpu_handle.send_event(VcpuEvent::Pause)?;
269264
let _ = cpu_handle.response_receiver().recv()?;
@@ -274,8 +269,10 @@ impl FirecrackerTarget {
274269

275270
/// A helper function to allow the event loop to inject this breakpoint back into the Vcpu
276271
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)
272+
let vmm = self.vmm.lock().unwrap();
273+
let vcpu_idx = tid_to_vcpuid(tid);
274+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
275+
arch::vcpu_inject_bp(vcpu_fd, &self.hw_breakpoints, false)
279276
}
280277

281278
/// Resumes the Vcpu, will return early if the Vcpu is already running
@@ -288,7 +285,7 @@ impl FirecrackerTarget {
288285
return Ok(());
289286
}
290287

291-
let cpu_handle = &self.vmm.lock()?.vcpus_handles[tid_to_vcpuid(tid)];
288+
let cpu_handle = &mut self.vmm.lock()?.vcpus_handles[tid_to_vcpuid(tid)];
292289
cpu_handle.send_event(VcpuEvent::Resume)?;
293290

294291
let response = cpu_handle.response_receiver().recv()?;
@@ -307,21 +304,24 @@ impl FirecrackerTarget {
307304
&self,
308305
tid: Tid,
309306
) -> Result<Option<BaseStopReason<Tid, u64>>, GdbTargetError> {
310-
let vcpu_state = &self.vcpu_state[tid_to_vcpuid(tid)];
307+
let vcpu_idx = tid_to_vcpuid(tid);
308+
let vcpu_state = &self.vcpu_state[vcpu_idx];
311309
if vcpu_state.single_step {
312310
return Ok(Some(MultiThreadStopReason::SignalWithThread {
313311
tid,
314312
signal: Signal::SIGTRAP,
315313
}));
316314
}
317315

318-
let Ok(ip) = arch::get_instruction_pointer(&vcpu_state.vcpu_fd) else {
316+
let vmm = self.vmm.lock().unwrap();
317+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
318+
let Ok(ip) = arch::get_instruction_pointer(vcpu_fd) else {
319319
// If we error here we return an arbitrary Software Breakpoint, GDB will handle
320320
// this gracefully
321321
return Ok(Some(MultiThreadStopReason::SwBreak(tid)));
322322
};
323323

324-
let gpa = arch::translate_gva(&vcpu_state.vcpu_fd, ip, &self.vmm.lock().unwrap())?;
324+
let gpa = arch::translate_gva(vcpu_fd, ip, &vmm)?;
325325
if self.sw_breakpoints.contains_key(&gpa) {
326326
return Ok(Some(MultiThreadStopReason::SwBreak(tid)));
327327
}
@@ -364,14 +364,20 @@ impl Target for FirecrackerTarget {
364364
impl MultiThreadBase for FirecrackerTarget {
365365
/// Reads the registers for the Vcpu
366366
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)?;
367+
let vmm = self.vmm.lock().unwrap();
368+
let vcpu_idx = tid_to_vcpuid(tid);
369+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
370+
arch::read_registers(vcpu_fd, regs)?;
368371

369372
Ok(())
370373
}
371374

372375
/// Writes to the registers for the Vcpu
373376
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)?;
377+
let vmm = self.vmm.lock().unwrap();
378+
let vcpu_idx = tid_to_vcpuid(tid);
379+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
380+
arch::write_registers(vcpu_fd, regs)?;
375381

376382
Ok(())
377383
}
@@ -384,12 +390,14 @@ impl MultiThreadBase for FirecrackerTarget {
384390
tid: Tid,
385391
) -> TargetResult<usize, Self> {
386392
let data_len = data.len();
387-
let vcpu_state = &self.vcpu_state[tid_to_vcpuid(tid)];
393+
let vmm = self.vmm.lock().unwrap();
394+
let vcpu_idx = tid_to_vcpuid(tid);
395+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
388396

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

391399
while !data.is_empty() {
392-
let gpa = arch::translate_gva(&vcpu_state.vcpu_fd, gva, &vmm).map_err(|e| {
400+
let gpa = arch::translate_gva(vcpu_fd, gva, &vmm).map_err(|e| {
393401
error!("Error {e:?} translating gva on read address: {gva:#X}");
394402
})?;
395403

@@ -420,11 +428,12 @@ impl MultiThreadBase for FirecrackerTarget {
420428
mut data: &[u8],
421429
tid: Tid,
422430
) -> TargetResult<(), Self> {
423-
let vcpu_state = &self.vcpu_state[tid_to_vcpuid(tid)];
424-
let vmm = &self.vmm.lock().expect("Error locking vmm in write addr");
431+
let vmm = self.vmm.lock().unwrap();
432+
let vcpu_idx = tid_to_vcpuid(tid);
433+
let vcpu_fd = &vmm.vcpus_handles[vcpu_idx].vcpu_fd;
425434

426435
while !data.is_empty() {
427-
let gpa = arch::translate_gva(&vcpu_state.vcpu_fd, gva, &vmm).map_err(|e| {
436+
let gpa = arch::translate_gva(vcpu_fd, gva, &vmm).map_err(|e| {
428437
error!("Error {e:?} translating gva on read address: {gva:#X}");
429438
})?;
430439

@@ -546,8 +555,8 @@ impl HwBreakpoint for FirecrackerTarget {
546555
return Ok(false);
547556
}
548557

549-
let state = self.get_paused_vcpu()?;
550-
state.update_kvm_debug(&self.hw_breakpoints)?;
558+
let vcpu_idx = self.get_paused_vcpu_idx()?;
559+
self.update_vcpu_kvm_debug(vcpu_idx, &self.hw_breakpoints)?;
551560

552561
Ok(true)
553562
}
@@ -563,8 +572,8 @@ impl HwBreakpoint for FirecrackerTarget {
563572
Some(pos) => self.hw_breakpoints.remove(pos),
564573
};
565574

566-
let state = self.get_paused_vcpu()?;
567-
state.update_kvm_debug(&self.hw_breakpoints)?;
575+
let vcpu_idx = self.get_paused_vcpu_idx()?;
576+
self.update_vcpu_kvm_debug(vcpu_idx, &self.hw_breakpoints)?;
568577

569578
Ok(true)
570579
}
@@ -580,11 +589,8 @@ impl SwBreakpoint for FirecrackerTarget {
580589
addr: <Self::Arch as Arch>::Usize,
581590
_kind: <Self::Arch as Arch>::BreakpointKind,
582591
) -> TargetResult<bool, Self> {
583-
let gpa = arch::translate_gva(
584-
&self.get_paused_vcpu()?.vcpu_fd,
585-
addr,
586-
&self.vmm.lock().unwrap(),
587-
)?;
592+
let vcpu_idx = self.get_paused_vcpu_idx()?;
593+
let gpa = self.translate_gva(vcpu_idx, addr)?;
588594

589595
if self.sw_breakpoints.contains_key(&gpa) {
590596
return Ok(true);
@@ -608,11 +614,8 @@ impl SwBreakpoint for FirecrackerTarget {
608614
addr: <Self::Arch as Arch>::Usize,
609615
_kind: <Self::Arch as Arch>::BreakpointKind,
610616
) -> TargetResult<bool, Self> {
611-
let gpa = arch::translate_gva(
612-
&self.get_paused_vcpu()?.vcpu_fd,
613-
addr,
614-
&self.vmm.lock().unwrap(),
615-
)?;
617+
let vcpu_idx = self.get_paused_vcpu_idx()?;
618+
let gpa = self.translate_gva(vcpu_idx, addr)?;
616619

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

0 commit comments

Comments
 (0)