Skip to content

Commit 9f1e0cd

Browse files
NunoDasNevesjinankjain
authored andcommitted
ioctls/bindings: Implement new MSHV_GET/SET_VP_STATE ioctls
Rework XSave and LapicState, replace their From<T> implementations to convert to/from Buffer with TryFrom<T>. Replace existing MSHV_GET/SET_VP_STATE implementations with the new kernel interface. Signed-off-by: Nuno Das Neves <nudasnev@microsoft.com>
1 parent 2fdd254 commit 9f1e0cd

File tree

5 files changed

+111
-227
lines changed

5 files changed

+111
-227
lines changed

mshv-bindings/src/regs.rs

Lines changed: 69 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
use crate::bindings::*;
77
#[cfg(feature = "with-serde")]
88
use serde_derive::{Deserialize, Serialize};
9-
use std::cmp;
9+
use std::convert::TryFrom;
1010
use std::fmt;
1111
use std::ptr;
1212
use vmm_sys_util::errno;
1313
use zerocopy::{AsBytes, FromBytes, FromZeroes};
1414

15+
pub const HV_PAGE_SIZE: usize = HV_HYP_PAGE_SIZE as usize;
16+
1517
#[repr(C)]
1618
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)]
1719
#[cfg_attr(feature = "with-serde", derive(Deserialize, Serialize))]
@@ -463,7 +465,7 @@ impl Buffer {
463465
Ok(buf)
464466
}
465467

466-
pub fn dealloc(self) {
468+
pub fn dealloc(&mut self) {
467469
// SAFETY: buf was allocated with layout
468470
unsafe {
469471
std::alloc::dealloc(self.buf, self.layout);
@@ -477,15 +479,13 @@ impl Buffer {
477479

478480
impl Drop for Buffer {
479481
fn drop(&mut self) {
480-
// SAFETY: buf was allocated with layout
481-
unsafe {
482-
std::alloc::dealloc(self.buf, self.layout);
483-
}
482+
self.dealloc();
484483
}
485484
}
486485

487486
#[repr(C)]
488487
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
488+
/// Fixed buffer for lapic state
489489
pub struct LapicState {
490490
pub regs: [::std::os::raw::c_char; 1024usize],
491491
}
@@ -494,25 +494,12 @@ impl Default for LapicState {
494494
unsafe { ::std::mem::zeroed() }
495495
}
496496
}
497-
/*
498-
impl Default for hv_register_value {
499-
fn default() -> Self {
500-
unsafe { ::std::mem::zeroed() }
501-
}
502-
} */
497+
503498
#[repr(C)]
504499
#[derive(Copy, Clone, Debug, AsBytes, FromBytes, FromZeroes)]
505-
/// This struct normalizes the actual mhsv XSave structure
506-
/// XSave only used in save and restore functionalities, serilization and
507-
/// deserialization are needed. Putting all the fields into a single buffer makes
508-
/// it easier to serialize and deserialize
509-
/// Total buffer size: 4120
510-
/// flags: 8 bytes
511-
/// states: 8 bytes
512-
/// data_size: 8 bytes
513-
/// Actual xsave buffer: 4096 bytes
500+
/// Fixed buffer for xsave state
514501
pub struct XSave {
515-
pub buffer: [::std::os::raw::c_char; 4120usize],
502+
pub buffer: [u8; 4096usize],
516503
}
517504

518505
impl Default for XSave {
@@ -521,69 +508,45 @@ impl Default for XSave {
521508
}
522509
}
523510

524-
impl From<mshv_vp_state> for XSave {
525-
fn from(reg: mshv_vp_state) -> Self {
526-
let ret = XSave {
511+
impl TryFrom<Buffer> for XSave {
512+
type Error = errno::Error;
513+
fn try_from(buf: Buffer) -> Result<Self, Self::Error> {
514+
let mut ret = XSave {
527515
..Default::default()
528516
};
529-
let mut bs = reg.xsave.flags.to_le_bytes();
530-
unsafe {
531-
ptr::copy(
532-
bs.as_ptr() as *mut u8,
533-
ret.buffer.as_ptr().offset(0) as *mut u8,
534-
8,
535-
)
536-
};
537-
bs = unsafe { reg.xsave.states.as_uint64.to_le_bytes() };
538-
unsafe {
539-
ptr::copy(
540-
bs.as_ptr() as *mut u8,
541-
ret.buffer.as_ptr().offset(8) as *mut u8,
542-
8,
543-
)
544-
};
545-
bs = reg.buf_size.to_le_bytes();
546-
unsafe {
547-
ptr::copy(
548-
bs.as_ptr() as *mut u8,
549-
ret.buffer.as_ptr().offset(16) as *mut u8,
550-
8,
551-
)
552-
};
553-
let min: usize = cmp::min(4096, reg.buf_size as u32) as usize;
554-
unsafe {
555-
ptr::copy(
556-
reg.buf.bytes,
557-
ret.buffer.as_ptr().offset(24) as *mut u8,
558-
min,
559-
)
560-
};
561-
ret
517+
let ret_size = std::mem::size_of_val(&ret.buffer);
518+
if ret_size < buf.size() {
519+
return Err(errno::Error::new(libc::EINVAL));
520+
}
521+
// SAFETY: ret is large enough to hold buffer
522+
unsafe { ptr::copy(buf.buf, ret.buffer.as_mut_ptr(), buf.size()) };
523+
Ok(ret)
562524
}
563525
}
564526

565-
impl From<XSave> for mshv_vp_state {
566-
fn from(reg: XSave) -> Self {
567-
let flags = reg.flags();
568-
let states = reg.states();
569-
let buffer_size = reg.data_size();
570-
let mut ret = mshv_vp_state {
571-
type_: hv_get_set_vp_state_type_HV_GET_SET_VP_STATE_XSAVE,
572-
buf_size: buffer_size,
573-
..Default::default()
574-
};
575-
ret.xsave.flags = flags;
576-
ret.xsave.states.as_uint64 = states;
577-
ret.buf.bytes = reg.data_buffer() as *mut u8;
578-
ret
527+
impl TryFrom<&XSave> for Buffer {
528+
type Error = errno::Error;
529+
fn try_from(reg: &XSave) -> Result<Self, Self::Error> {
530+
let reg_size = std::mem::size_of_val(&reg.buffer);
531+
let num_pages = (reg_size + HV_PAGE_SIZE - 1) >> HV_HYP_PAGE_SHIFT;
532+
let buffer = Buffer::new(num_pages * HV_PAGE_SIZE, HV_PAGE_SIZE)?;
533+
// SAFETY: buffer is large enough to hold reg
534+
unsafe { ptr::copy(reg.buffer.as_ptr(), buffer.buf, reg_size) };
535+
Ok(buffer)
579536
}
580537
}
581-
impl From<mshv_vp_state> for LapicState {
582-
fn from(reg: mshv_vp_state) -> Self {
538+
539+
impl TryFrom<Buffer> for LapicState {
540+
type Error = errno::Error;
541+
fn try_from(buf: Buffer) -> Result<Self, Self::Error> {
583542
let mut ret: LapicState = LapicState::default();
584543
let state = ret.regs.as_mut_ptr();
585-
let hv_state = unsafe { *reg.buf.lapic };
544+
if buf.size() < std::mem::size_of::<hv_local_interrupt_controller_state>() {
545+
return Err(errno::Error::new(libc::EINVAL));
546+
}
547+
// SAFETY: buf is large enough for hv_local_interrupt_controller_state
586548
unsafe {
549+
let hv_state = &*(buf.buf as *const hv_local_interrupt_controller_state);
587550
*(state.offset(LOCAL_APIC_OFFSET_APIC_ID) as *mut u32) = hv_state.apic_id;
588551
*(state.offset(LOCAL_APIC_OFFSET_VERSION) as *mut u32) = hv_state.apic_version;
589552
*(state.offset(LOCAL_APIC_OFFSET_REMOTE_READ) as *mut u32) = hv_state.apic_remote_read;
@@ -605,45 +568,46 @@ impl From<mshv_vp_state> for LapicState {
605568
hv_state.apic_counter_value;
606569
*(state.offset(LOCAL_APIC_OFFSET_DIVIDER) as *mut u32) =
607570
hv_state.apic_divide_configuration;
608-
}
609571

610-
/* vectors ISR TMR IRR */
611-
for i in 0..8 {
612-
unsafe {
572+
/* vectors ISR TMR IRR */
573+
for i in 0..8 {
613574
*(state.offset(LOCAL_APIC_OFFSET_ISR + i * 16) as *mut u32) =
614575
hv_state.apic_isr[i as usize];
615576
*(state.offset(LOCAL_APIC_OFFSET_TMR + i * 16) as *mut u32) =
616577
hv_state.apic_tmr[i as usize];
617578
*(state.offset(LOCAL_APIC_OFFSET_IRR + i * 16) as *mut u32) =
618579
hv_state.apic_irr[i as usize];
619580
}
620-
}
621581

622-
// Highest priority interrupt (isr = in service register) this is how WHP computes it
623-
let mut isrv: u32 = 0;
624-
for i in (0..8).rev() {
625-
let val: u32 = hv_state.apic_isr[i as usize];
626-
if val != 0 {
627-
isrv = 31 - val.leading_zeros(); // index of most significant set bit
628-
isrv += i * 4 * 8; // i don't know
629-
break;
582+
// Highest priority interrupt (isr = in service register) this is how WHP computes it
583+
let mut isrv: u32 = 0;
584+
for i in (0..8).rev() {
585+
let val: u32 = hv_state.apic_isr[i as usize];
586+
if val != 0 {
587+
isrv = 31 - val.leading_zeros(); // index of most significant set bit
588+
isrv += i * 4 * 8; // i don't know
589+
break;
590+
}
630591
}
631-
}
632592

633-
// TODO This is meant to be max(tpr, isrv), but tpr is not populated!
634-
unsafe {
593+
// TODO This is meant to be max(tpr, isrv), but tpr is not populated!
635594
*(state.offset(LOCAL_APIC_OFFSET_PPR) as *mut u32) = isrv;
636595
}
637-
ret
596+
Ok(ret)
638597
}
639598
}
640599

641-
impl From<LapicState> for mshv_vp_state {
642-
fn from(reg: LapicState) -> Self {
643-
let state = reg.regs.as_ptr();
644-
let mut vp_state: mshv_vp_state = mshv_vp_state::default();
600+
impl TryFrom<&LapicState> for Buffer {
601+
type Error = errno::Error;
602+
fn try_from(reg: &LapicState) -> Result<Self, Self::Error> {
603+
let hv_state_size = std::mem::size_of::<hv_local_interrupt_controller_state>();
604+
let num_pages = (hv_state_size + HV_PAGE_SIZE - 1) >> HV_HYP_PAGE_SHIFT;
605+
let buffer = Buffer::new(num_pages * HV_PAGE_SIZE, HV_PAGE_SIZE)?;
606+
// SAFETY: buf is large enough for hv_local_interrupt_controller_state
645607
unsafe {
646-
let mut lapic_state = hv_local_interrupt_controller_state {
608+
let state = reg.regs.as_ptr();
609+
let hv_state = &mut *(buffer.buf as *mut hv_local_interrupt_controller_state);
610+
*hv_state = hv_local_interrupt_controller_state {
647611
apic_id: *(state.offset(LOCAL_APIC_OFFSET_APIC_ID) as *mut u32),
648612
apic_version: *(state.offset(LOCAL_APIC_OFFSET_VERSION) as *mut u32),
649613
apic_remote_read: *(state.offset(LOCAL_APIC_OFFSET_REMOTE_READ) as *mut u32),
@@ -671,75 +635,30 @@ impl From<LapicState> for mshv_vp_state {
671635

672636
/* vectors ISR TMR IRR */
673637
for i in 0..8 {
674-
lapic_state.apic_isr[i as usize] =
638+
hv_state.apic_isr[i as usize] =
675639
*(state.offset(LOCAL_APIC_OFFSET_ISR + i * 16) as *mut u32);
676-
lapic_state.apic_tmr[i as usize] =
640+
hv_state.apic_tmr[i as usize] =
677641
*(state.offset(LOCAL_APIC_OFFSET_TMR + i * 16) as *mut u32);
678-
lapic_state.apic_irr[i as usize] =
642+
hv_state.apic_irr[i as usize] =
679643
*(state.offset(LOCAL_APIC_OFFSET_IRR + i * 16) as *mut u32);
680644
}
681-
vp_state.type_ =
682-
hv_get_set_vp_state_type_HV_GET_SET_VP_STATE_LOCAL_INTERRUPT_CONTROLLER_STATE;
683-
vp_state.buf_size = 1024;
684-
let boxed_obj = Box::new(lapic_state);
685-
vp_state.buf.lapic = Box::into_raw(boxed_obj);
686645
}
687-
vp_state
646+
647+
Ok(buffer)
688648
}
689649
}
650+
690651
// implement `Display` for `XSave`
691652
impl fmt::Display for XSave {
692653
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
693654
write!(
694655
f,
695-
"flags: {}, states: {}, buffer_size: {}, buffer: {:?}\n data: {:02X?}",
696-
self.flags(),
697-
self.states(),
698-
self.data_size(),
699-
self.data_buffer(),
656+
"buffer: {:?}\n data: {:02X?}",
657+
self.buffer.as_ptr(),
700658
self.buffer,
701659
)
702660
}
703661
}
704-
// Implement XSave to retrieve each field from the buffer
705-
impl XSave {
706-
pub fn flags(&self) -> u64 {
707-
let array: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
708-
unsafe {
709-
ptr::copy(
710-
self.buffer.as_ptr().offset(0) as *mut u8,
711-
array.as_ptr() as *mut u8,
712-
8,
713-
)
714-
};
715-
u64::from_le_bytes(array)
716-
}
717-
pub fn states(&self) -> u64 {
718-
let array: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
719-
unsafe {
720-
ptr::copy(
721-
self.buffer.as_ptr().offset(8) as *mut u8,
722-
array.as_ptr() as *mut u8,
723-
8,
724-
)
725-
};
726-
u64::from_le_bytes(array)
727-
}
728-
pub fn data_size(&self) -> u64 {
729-
let array: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
730-
unsafe {
731-
ptr::copy(
732-
self.buffer.as_ptr().offset(16) as *mut u8,
733-
array.as_ptr() as *mut u8,
734-
8,
735-
)
736-
};
737-
u64::from_le_bytes(array)
738-
}
739-
pub fn data_buffer(&self) -> *const u8 {
740-
unsafe { self.buffer.as_ptr().offset(24) as *mut u8 }
741-
}
742-
}
743662

744663
#[repr(C)]
745664
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, AsBytes, FromBytes, FromZeroes)]

mshv-bindings/src/serializers.rs

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl<'de> Deserialize<'de> for XSave {
3636
where
3737
D: Deserializer<'de>,
3838
{
39-
let data_buffer: Vec<::std::os::raw::c_char> = Vec::deserialize(deserializer)?;
39+
let data_buffer: Vec<u8> = Vec::deserialize(deserializer)?;
4040
let mut val = XSave::default();
4141
// This panics if the source and destination have different lengths.
4242
val.buffer.copy_from_slice(&data_buffer[..]);
@@ -57,15 +57,12 @@ impl Serialize for XSave {
5757
mod tests {
5858
use super::*;
5959
use random_number::random;
60-
use std::ptr;
6160

6261
#[test]
6362
fn test_lapic_state_serialization_deserialization() {
6463
let mut state = LapicState::default();
65-
let mut n1: u8 = random!();
6664
for i in 0..1024 {
67-
state.regs[i] = n1 as ::std::os::raw::c_char;
68-
n1 = random!();
65+
state.regs[i] = random!();
6966
}
7067
let serialized = serde_json::to_string(&state).expect("err ser");
7168
let d_state: LapicState = serde_json::from_str(&serialized).expect("err unser");
@@ -80,44 +77,11 @@ mod tests {
8077
let mut xsave = XSave {
8178
..Default::default()
8279
};
83-
let flags: u64 = 0x12345678;
84-
let states: u64 = 0x87654321;
85-
let data_size: u64 = 4096;
86-
87-
let mut n1: u8 = random!();
8880
for i in 0..4096 {
89-
xsave.buffer[i + 24] = n1 as ::std::os::raw::c_char;
90-
n1 = random!();
81+
xsave.buffer[i] = random!();
9182
}
92-
let mut _bs = flags.to_le_bytes();
93-
unsafe {
94-
ptr::copy(
95-
_bs.as_ptr() as *mut u8,
96-
xsave.buffer.as_ptr().offset(0) as *mut u8,
97-
8,
98-
)
99-
};
100-
_bs = states.to_le_bytes();
101-
unsafe {
102-
ptr::copy(
103-
_bs.as_ptr() as *mut u8,
104-
xsave.buffer.as_ptr().offset(8) as *mut u8,
105-
8,
106-
)
107-
};
108-
_bs = data_size.to_le_bytes();
109-
unsafe {
110-
ptr::copy(
111-
_bs.as_ptr() as *mut u8,
112-
xsave.buffer.as_ptr().offset(16) as *mut u8,
113-
8,
114-
)
115-
};
11683
let serialized = serde_json::to_string(&xsave).expect("err ser");
11784
let d_xsave: XSave = serde_json::from_str(&serialized).expect("err unser");
118-
assert!(xsave.flags() == d_xsave.flags());
119-
assert!(xsave.states() == d_xsave.states());
120-
assert!(xsave.data_size() == d_xsave.data_size());
12185
assert!(xsave
12286
.buffer
12387
.iter()

0 commit comments

Comments
 (0)