diff options
Diffstat (limited to 'crosvm_plugin')
-rw-r--r-- | crosvm_plugin/crosvm.h | 27 | ||||
-rw-r--r-- | crosvm_plugin/src/lib.rs | 83 |
2 files changed, 98 insertions, 12 deletions
diff --git a/crosvm_plugin/crosvm.h b/crosvm_plugin/crosvm.h index 700ab0c..63763f1 100644 --- a/crosvm_plugin/crosvm.h +++ b/crosvm_plugin/crosvm.h @@ -47,7 +47,7 @@ extern "C" { * do not indicate anything about what version of crosvm is running. */ #define CROSVM_API_MAJOR 0 -#define CROSVM_API_MINOR 18 +#define CROSVM_API_MINOR 19 #define CROSVM_API_PATCH 0 enum crosvm_address_space { @@ -175,6 +175,23 @@ int crosvm_reserve_range(struct crosvm*, uint32_t __space, uint64_t __start, uint64_t __length); /* + * Registers a range in the given address space that, when accessed via write, + * will cause a notification in crosvm_vcpu_wait() but the VM will continue + * running. + * For this type of notification (where |no_resume| is set) the next call + * should be crosvm_vcpu_wait() (without an inbetween call to + * crosvm_vcpu_resume() ). + * + * The requested range must not overlap any prior (and currently active) + * reservation to crosvm_reserve_range() or crosvm_reserve_async_write_range(). + * + * To unreserve a range previously reserved by this function, pass the |__space| + * and |__start| of the old reservation with a 0 |__length|. + */ +int crosvm_reserve_async_write_range(struct crosvm*, uint32_t __space, + uint64_t __start, uint64_t __length); + +/* * Sets the state of the given irq pin. */ int crosvm_set_irq(struct crosvm*, uint32_t __irq_id, bool __active); @@ -509,7 +526,13 @@ struct crosvm_vcpu_event { */ uint8_t is_write; - uint8_t _reserved[3]; + /* + * Valid when |is_write| is true -- indicates that VM has continued + * to run. The only next valid call for the vcpu is crosvm_vcpu_wait(). + */ + uint8_t no_resume; + + uint8_t _reserved[2]; } io_access; /* CROSVM_VCPU_EVENT_KIND_PAUSED */ diff --git a/crosvm_plugin/src/lib.rs b/crosvm_plugin/src/lib.rs index 8def28d..53a8569 100644 --- a/crosvm_plugin/src/lib.rs +++ b/crosvm_plugin/src/lib.rs @@ -171,6 +171,7 @@ pub enum Stat { GetMsrIndexList, NetGetConfig, ReserveRange, + ReserveAsyncWriteRange, SetIrq, SetIrqRouting, GetPicState, @@ -466,12 +467,19 @@ impl crosvm { Ok(()) } - fn reserve_range(&mut self, space: u32, start: u64, length: u64) -> result::Result<(), c_int> { + fn reserve_range( + &mut self, + space: u32, + start: u64, + length: u64, + async_write: bool, + ) -> result::Result<(), c_int> { let mut r = MainRequest::new(); let reserve: &mut MainRequest_ReserveRange = r.mut_reserve_range(); reserve.space = AddressSpace::from_i32(space as i32).ok_or(EINVAL)?; reserve.start = start; reserve.length = length; + reserve.async_write = async_write; self.main_transaction(&r, &[])?; Ok(()) @@ -910,7 +918,8 @@ struct anon_io_access { data: *mut u8, length: u32, is_write: u8, - __reserved1: u8, + no_resume: u8, + __reserved1: [u8; 2], } #[repr(C)] @@ -949,6 +958,8 @@ pub struct crosvm_vcpu { send_init: bool, request_buffer: Vec<u8>, response_buffer: Vec<u8>, + response_base: usize, + response_length: usize, resume_data: Vec<u8>, regs: crosvm_vcpu_reg_cache, @@ -956,6 +967,25 @@ pub struct crosvm_vcpu { debugregs: crosvm_vcpu_reg_cache, } +fn read_varint32(data: &[u8]) -> (u32, usize) { + let mut value: u32 = 0; + let mut shift: u32 = 0; + for (i, &b) in data.iter().enumerate() { + if b < 0x80 { + return match (b as u32).checked_shl(shift) { + None => (0, 0), + Some(b) => (value | b, i + 1), + }; + } + match ((b as u32) & 0x7F).checked_shl(shift) { + None => return (0, 0), + Some(b) => value |= b, + } + shift += 7; + } + (0, 0) +} + impl crosvm_vcpu { fn new(read_pipe: File, write_pipe: File) -> crosvm_vcpu { crosvm_vcpu { @@ -964,6 +994,8 @@ impl crosvm_vcpu { send_init: true, request_buffer: Vec::new(), response_buffer: vec![0; MAX_DATAGRAM_SIZE], + response_base: 0, + response_length: 0, resume_data: Vec::new(), regs: crosvm_vcpu_reg_cache { get: false, @@ -994,13 +1026,30 @@ impl crosvm_vcpu { } fn vcpu_recv(&mut self) -> result::Result<VcpuResponse, c_int> { - let msg_size = self - .read_pipe - .read(&mut self.response_buffer) - .map_err(|e| -e.raw_os_error().unwrap_or(EINVAL))?; - - let response: VcpuResponse = - parse_from_bytes(&self.response_buffer[..msg_size]).map_err(proto_error_to_int)?; + if self.response_length == 0 { + let msg_size = self + .read_pipe + .read(&mut self.response_buffer) + .map_err(|e| -e.raw_os_error().unwrap_or(EINVAL))?; + self.response_base = 0; + self.response_length = msg_size; + } + if self.response_length == 0 { + return Err(EINVAL); + } + let (value, bytes) = read_varint32( + &self.response_buffer[self.response_base..self.response_base + self.response_length], + ); + let total_size: usize = bytes + value as usize; + if bytes == 0 || total_size > self.response_length { + return Err(EINVAL); + } + let response: VcpuResponse = parse_from_bytes( + &self.response_buffer[self.response_base + bytes..self.response_base + total_size], + ) + .map_err(proto_error_to_int)?; + self.response_base += total_size; + self.response_length -= total_size; if response.errno != 0 { return Err(response.errno); } @@ -1041,6 +1090,7 @@ impl crosvm_vcpu { data: io.data.as_mut_ptr(), length: io.data.len() as u32, is_write: io.is_write as u8, + no_resume: io.no_resume as u8, __reserved1: Default::default(), }; self.resume_data = io.data; @@ -1359,7 +1409,20 @@ pub unsafe extern "C" fn crosvm_reserve_range( ) -> c_int { let _u = record(Stat::ReserveRange); let self_ = &mut (*self_); - let ret = self_.reserve_range(space, start, length); + let ret = self_.reserve_range(space, start, length, false); + to_crosvm_rc(ret) +} + +#[no_mangle] +pub unsafe extern "C" fn crosvm_reserve_async_write_range( + self_: *mut crosvm, + space: u32, + start: u64, + length: u64, +) -> c_int { + let _u = record(Stat::ReserveAsyncWriteRange); + let self_ = &mut (*self_); + let ret = self_.reserve_range(space, start, length, true); to_crosvm_rc(ret) } |