forked from rcore-os/zCore
hypervisor: add more port packets, implemented sys_vcpu_resume
This commit is contained in:
parent
97cd1e2e54
commit
afac963748
|
@ -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) {
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}),
|
||||
}
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue