hypervisor: add more port packets, implemented sys_vcpu_resume

This commit is contained in:
equation314 2020-07-15 20:38:00 +08:00
parent 97cd1e2e54
commit afac963748
7 changed files with 257 additions and 41 deletions

View File

@ -93,6 +93,16 @@ impl GuestPhysMemorySetTrait for GuestPhysMemorySet {
self.vmar.unmap(gpaddr, size).map_err(From::from)
}
/// Read from guest address space.
fn read_memory(&self, gpaddr: GuestPhysAddr, buf: &mut [u8]) -> RvmResult<usize> {
self.vmar.read_memory(gpaddr, buf).map_err(From::from)
}
/// Write to guest address space.
fn write_memory(&self, gpaddr: GuestPhysAddr, buf: &[u8]) -> RvmResult<usize> {
self.vmar.write_memory(gpaddr, buf).map_err(From::from)
}
/// Called when accessed a non-mapped guest physical adderss `gpaddr`.
fn handle_page_fault(&self, gpaddr: GuestPhysAddr) -> RvmResult {
if let Some(mapping) = self.vmar.find_mapping(gpaddr) {

View File

@ -1,7 +1,8 @@
use {
crate::{hypervisor::Guest, object::*},
crate::{hypervisor::Guest, object::*, signal::*},
alloc::sync::Arc,
rvm::Vcpu as VcpuInner,
core::convert::TryInto,
rvm::{self, Vcpu as VcpuInner},
spin::Mutex,
};
@ -29,4 +30,57 @@ impl Vcpu {
.virtual_interrupt(vector)
.map_err(From::from)
}
pub fn resume(&self) -> ZxResult<PortPacket> {
self.inner.lock().resume()?.try_into()
}
}
impl From<rvm::IoPacket> for PacketGuestIo {
fn from(io: rvm::IoPacket) -> Self {
Self {
port: io.port,
access_size: io.access_size,
input: io.input,
data: io.data,
..Default::default()
}
}
}
impl From<rvm::MmioPacket> for PacketGuestMem {
fn from(mem: rvm::MmioPacket) -> Self {
#[cfg(target_arch = "x86_64")]
Self {
addr: mem.addr,
inst_len: mem.inst_len,
inst_buf: mem.inst_buf,
default_operand_size: mem.default_operand_size,
..Default::default()
}
}
}
impl TryInto<PortPacket> for rvm::RvmExitPacket {
type Error = ZxError;
#[allow(unsafe_code)]
fn try_into(self) -> ZxResult<PortPacket> {
use rvm::RvmExitPacketKind;
match self.kind {
RvmExitPacketKind::GuestIo => Ok(PortPacketRepr {
key: self.key,
status: ZxError::OK,
data: PayloadRepr::GuestIo(unsafe { self.inner.io.into() }),
}
.into()),
RvmExitPacketKind::GuestMmio => Ok(PortPacketRepr {
key: self.key,
status: ZxError::OK,
data: PayloadRepr::GuestMem(unsafe { self.inner.mmio.into() }),
}
.into()),
_ => Err(ZxError::NOT_SUPPORTED),
}
}
}

View File

@ -322,6 +322,7 @@ impl dyn KernelObject {
observed: current_signal,
count: 1,
timestamp: 0,
_reserved1: 0,
}),
});
return;
@ -340,6 +341,7 @@ impl dyn KernelObject {
observed: s,
count: 1,
timestamp: 0,
_reserved1: 0,
}),
});
true

View File

@ -47,9 +47,9 @@ impl From<PortInterruptPacket> for PacketInterrupt {
fn from(packet: PortInterruptPacket) -> Self {
PacketInterrupt {
timestamp: packet.timestamp,
reserved0: 0,
reserved1: 0,
reserved2: 0,
_reserved0: 0,
_reserved1: 0,
_reserved2: 0,
}
}
}
@ -177,6 +177,7 @@ mod tests {
observed: Signal::WRITABLE,
count: 1,
timestamp: 0,
_reserved1: 0,
}),
};
async_std::task::spawn({
@ -201,6 +202,7 @@ mod tests {
observed: Signal::READABLE,
count: 1,
timestamp: 0,
_reserved1: 0,
}),
}
);

View File

@ -10,16 +10,13 @@ use core::fmt::{Debug, Formatter};
pub struct PortPacket {
pub key: u64,
pub type_: PacketType,
exception_num: u8,
_padding: u16,
pub status: ZxError,
pub data: Payload,
}
// reference: zircon/system/public/zircon/syscalls/port.h ZX_PKT_TYPE_*
#[repr(u8)]
#[repr(u32)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
#[allow(dead_code)]
pub enum PacketType {
User = 0,
SignalOne = 1,
@ -29,18 +26,23 @@ pub enum PacketType {
GuestIo = 5,
GuestVcpu = 6,
Interrupt = 7,
Exception = 8,
PageRequest = 9,
}
#[repr(C)]
pub union Payload {
user: PacketUser,
signal: PacketSignal,
exception: PacketException,
guest_bell: PacketGuestBell,
guest_mem: PacketGuestMem,
guest_io: PacketGuestIo,
guest_vcpu: PacketGuestVcpu,
interrupt: PacketInterrupt,
user: [u8; 32],
// TODO: PacketPageRequest
}
pub type PacketUser = [u8; 32];
#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketSignal {
@ -48,23 +50,99 @@ pub struct PacketSignal {
pub observed: Signal,
pub count: u64,
pub timestamp: u64,
pub _reserved1: u64,
}
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestBell {
pub addr: u64,
pub _reserved0: u64,
pub _reserved1: u64,
pub _reserved2: u64,
}
#[cfg(target_arch = "x86_64")]
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestMem {
pub addr: u64,
pub inst_len: u8,
pub inst_buf: [u8; 15],
pub default_operand_size: u8,
pub _reserved: [u8; 7],
}
#[cfg(target_arch = "aarch64")]
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestMem {
pub addr: u64,
pub access_size: u8,
pub sign_extend: bool,
pub xt: u8,
pub read: bool,
pub _padding1: [u8; 4],
pub data: u64,
pub _reserved: u64,
}
#[repr(C)]
#[derive(Default, Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestIo {
pub port: u16,
pub access_size: u8,
pub input: bool,
pub data: [u8; 4],
pub _reserved0: u64,
pub _reserved1: u64,
pub _reserved2: u64,
}
#[repr(u8)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum PacketGuestVcpuType {
VcpuInterrupt = 0,
VcpuStartup = 1,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub union PacketGuestVcpuData {
interrupt: PacketGuestVcpuInterrupt,
startup: PacketGuestVcpuStartup,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketException {
pub pid: KoID,
pub tid: KoID,
pub num: u8,
pub struct PacketGuestVcpuInterrupt {
mask: u64,
vector: u8,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketGuestVcpuStartup {
id: u64,
entry: u64,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct PacketGuestVcpu {
pub data: PacketGuestVcpuData,
pub type_: PacketGuestVcpuType,
pub _padding1: [u8; 7],
pub _reserved: u64,
}
#[repr(C)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PacketInterrupt {
pub timestamp: i64,
pub reserved0: u64,
pub reserved1: u64,
pub reserved2: u64,
pub _reserved0: u64,
pub _reserved1: u64,
pub _reserved2: u64,
}
// Rust struct: for internal constructing and debugging
@ -80,46 +158,49 @@ pub struct PortPacketRepr {
/// A high-level representation of a packet payload.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum PayloadRepr {
User(PacketUser),
Signal(PacketSignal),
Exception(PacketException),
GuestBell(PacketGuestBell),
GuestMem(PacketGuestMem),
GuestIo(PacketGuestIo),
GuestVcpu(PacketGuestVcpu),
Interrupt(PacketInterrupt),
User([u8; 32]),
}
impl PayloadRepr {
fn exception_num(&self) -> u8 {
match self {
PayloadRepr::Exception(exception) => exception.num,
_ => 0,
}
}
fn type_(&self) -> PacketType {
match self {
PayloadRepr::User(_) => PacketType::User,
PayloadRepr::Signal(_) => PacketType::SignalOne,
PayloadRepr::Exception(_) => PacketType::Exception,
PayloadRepr::GuestBell(_) => PacketType::GuestBell,
PayloadRepr::GuestMem(_) => PacketType::GuestMem,
PayloadRepr::GuestIo(_) => PacketType::GuestIo,
PayloadRepr::GuestVcpu(_) => PacketType::GuestVcpu,
PayloadRepr::Interrupt(_) => PacketType::Interrupt,
}
}
fn encode(&self) -> Payload {
match *self {
PayloadRepr::Signal(signal) => Payload { signal },
PayloadRepr::Exception(exception) => Payload { exception },
PayloadRepr::Interrupt(interrupt) => Payload { interrupt },
PayloadRepr::User(user) => Payload { user },
PayloadRepr::Signal(signal) => Payload { signal },
PayloadRepr::GuestBell(guest_bell) => Payload { guest_bell },
PayloadRepr::GuestMem(guest_mem) => Payload { guest_mem },
PayloadRepr::GuestIo(guest_io) => Payload { guest_io },
PayloadRepr::GuestVcpu(guest_vcpu) => Payload { guest_vcpu },
PayloadRepr::Interrupt(interrupt) => Payload { interrupt },
}
}
#[allow(unsafe_code)]
fn decode(type_: PacketType, exception_num: u8, data: &Payload) -> Self {
fn decode(type_: PacketType, data: &Payload) -> Self {
unsafe {
match type_ {
PacketType::User => PayloadRepr::User(data.user),
PacketType::SignalOne => PayloadRepr::Signal(data.signal),
PacketType::SignalRep => PayloadRepr::Signal(data.signal),
PacketType::Exception => PayloadRepr::Exception(PacketException {
num: exception_num,
..data.exception
}),
PacketType::GuestBell => PayloadRepr::GuestBell(data.guest_bell),
PacketType::GuestMem => PayloadRepr::GuestMem(data.guest_mem),
PacketType::GuestIo => PayloadRepr::GuestIo(data.guest_io),
PacketType::GuestVcpu => PayloadRepr::GuestVcpu(data.guest_vcpu),
PacketType::Interrupt => PayloadRepr::Interrupt(data.interrupt),
_ => unimplemented!(),
}
@ -132,8 +213,6 @@ impl From<PortPacketRepr> for PortPacket {
PortPacket {
key: r.key,
type_: r.data.type_(),
exception_num: r.data.exception_num(),
_padding: 0,
status: r.status,
data: r.data.encode(),
}
@ -145,13 +224,67 @@ impl From<&PortPacket> for PortPacketRepr {
PortPacketRepr {
key: p.key,
status: p.status,
data: PayloadRepr::decode(p.type_, p.exception_num, &p.data),
data: PayloadRepr::decode(p.type_, &p.data),
}
}
}
impl PartialEq for PacketGuestVcpu {
#[allow(unsafe_code)]
fn eq(&self, other: &Self) -> bool {
if !self.type_.eq(&other.type_)
|| self._padding1.eq(&other._padding1)
|| self._reserved.eq(&other._reserved)
{
return false;
}
unsafe {
match self.type_ {
PacketGuestVcpuType::VcpuInterrupt => self.data.interrupt.eq(&other.data.interrupt),
PacketGuestVcpuType::VcpuStartup => self.data.startup.eq(&other.data.startup),
}
}
}
}
impl Eq for PacketGuestVcpu {}
impl Debug for PacketGuestVcpu {
#[allow(unsafe_code)]
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
let mut out = f.debug_struct("PacketGuestVcpu");
unsafe {
match self.type_ {
PacketGuestVcpuType::VcpuInterrupt => out.field("data", &self.data.interrupt),
PacketGuestVcpuType::VcpuStartup => out.field("data", &self.data.startup),
};
}
out.field("type_", &self.type_)
.field("_padding1", &self._padding1)
.field("_reserved", &self._reserved)
.finish()
}
}
impl Debug for PortPacket {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
PortPacketRepr::from(self).fmt(f)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn port_packet_size() {
use core::mem::size_of;
assert_eq!(size_of::<PacketUser>(), 32);
assert_eq!(size_of::<PacketSignal>(), 32);
assert_eq!(size_of::<PacketGuestBell>(), 32);
assert_eq!(size_of::<PacketGuestMem>(), 32);
assert_eq!(size_of::<PacketGuestIo>(), 32);
assert_eq!(size_of::<PacketGuestVcpu>(), 32);
assert_eq!(size_of::<PacketInterrupt>(), 32);
}
}

View File

@ -3,7 +3,7 @@ use {
zircon_object::{
dev::{Resource, ResourceKind},
hypervisor::{Guest, Vcpu},
signal::Port,
signal::{Port, PortPacket},
vm::VmarFlags,
},
};
@ -93,8 +93,21 @@ impl Syscall<'_> {
Ok(())
}
pub fn sys_vcpu_resume(
&self,
handle: HandleValue,
mut user_packet: UserOutPtr<PortPacket>,
) -> ZxResult {
error!("hypervisor.vcpu_resume: handle={:#x?}", handle);
let proc = self.thread.proc();
let vcpu = proc.get_object_with_rights::<Vcpu>(handle, Rights::EXECUTE)?;
let packet = vcpu.resume()?;
user_packet.write(packet)?;
Ok(())
}
pub fn sys_vcpu_interrupt(&self, handle: HandleValue, vector: u32) -> ZxResult {
error!(
info!(
"hypervisor.vcpu_interrupt: handle={:#x?}, vector={:?}",
handle, vector
);

View File

@ -364,6 +364,8 @@ impl Syscall<'_> {
#[cfg(feature = "hypervisor")]
Sys::VCPU_CREATE => self.sys_vcpu_create(a0 as _, a1 as _, a2 as _, a3.into()),
#[cfg(feature = "hypervisor")]
Sys::VCPU_RESUME => self.sys_vcpu_resume(a0 as _, a1.into()),
#[cfg(feature = "hypervisor")]
Sys::VCPU_INTERRUPT => self.sys_vcpu_interrupt(a0 as _, a1 as _),
_ => {
error!("syscall unimplemented: {:?}", sys_type);