mirror of
https://github.com/google/alioth.git
synced 2024-11-28 09:26:21 +00:00
feat: skeleton for running VMs on Apple silicon
Signed-off-by: Changyuan Lyu <changyuanl@google.com>
This commit is contained in:
parent
7065002d42
commit
78e4f92e96
7 changed files with 257 additions and 14 deletions
|
@ -17,12 +17,18 @@ use std::fs::File;
|
|||
use std::path::PathBuf;
|
||||
|
||||
use alioth::board::BoardConfig;
|
||||
#[cfg(target_os = "macos")]
|
||||
use alioth::hv::Hvf;
|
||||
#[cfg(target_os = "linux")]
|
||||
use alioth::hv::{Kvm, KvmConfig};
|
||||
use alioth::loader::{ExecType, Payload};
|
||||
use alioth::virtio::dev::blk::BlockParam;
|
||||
use alioth::virtio::dev::entropy::EntropyParam;
|
||||
#[cfg(target_os = "linux")]
|
||||
use alioth::virtio::dev::fs::VuFsParam;
|
||||
#[cfg(target_os = "linux")]
|
||||
use alioth::virtio::dev::net::NetParam;
|
||||
#[cfg(target_os = "linux")]
|
||||
use alioth::virtio::dev::vsock::VhostVsockParam;
|
||||
use alioth::vm::Machine;
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
|
@ -57,23 +63,34 @@ enum Command {
|
|||
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
enum Hypervisor {
|
||||
#[cfg(target_os = "linux")]
|
||||
#[serde(alias = "kvm")]
|
||||
Kvm(KvmConfig),
|
||||
#[cfg(target_os = "macos")]
|
||||
Hvf,
|
||||
}
|
||||
|
||||
impl Default for Hypervisor {
|
||||
fn default() -> Self {
|
||||
#[cfg(target_os = "linux")]
|
||||
Hypervisor::Kvm(KvmConfig::default())
|
||||
{
|
||||
Hypervisor::Kvm(KvmConfig::default())
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
Hypervisor::Hvf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
enum FsParam {
|
||||
#[serde(alias = "vu")]
|
||||
Vu(VuFsParam),
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[derive(Debug, Deserialize, Clone)]
|
||||
enum VsockParam {
|
||||
#[serde(alias = "vhost")]
|
||||
|
@ -169,8 +186,11 @@ fn main_run(args: RunArgs) -> Result<(), Error> {
|
|||
Hypervisor::default()
|
||||
};
|
||||
let hypervisor = match hv_config {
|
||||
Hypervisor::Kvm(kvm_config) => Kvm::new(kvm_config).context(error::Hypervisor),
|
||||
}?;
|
||||
#[cfg(target_os = "linux")]
|
||||
Hypervisor::Kvm(kvm_config) => Kvm::new(kvm_config).context(error::Hypervisor)?,
|
||||
#[cfg(target_os = "macos")]
|
||||
Hypervisor::Hvf => Hvf {},
|
||||
};
|
||||
let coco = match args.coco {
|
||||
None => None,
|
||||
Some(c) => Some(serde_aco::from_arg(&c).context(error::ParseArg { arg: c })?),
|
||||
|
@ -227,6 +247,7 @@ fn main_run(args: RunArgs) -> Result<(), Error> {
|
|||
vm.add_virtio_dev("virtio-entropy".to_owned(), EntropyParam)
|
||||
.context(error::CreateDevice)?;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
for (index, net_opt) in args.net.into_iter().enumerate() {
|
||||
let net_param: NetParam =
|
||||
serde_aco::from_arg(&net_opt).context(error::ParseArg { arg: net_opt })?;
|
||||
|
@ -238,6 +259,7 @@ fn main_run(args: RunArgs) -> Result<(), Error> {
|
|||
vm.add_virtio_dev(format!("virtio-blk-{index}"), param)
|
||||
.context(error::CreateDevice)?;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
for (index, fs) in args.fs.into_iter().enumerate() {
|
||||
let param: FsParam = serde_aco::from_arg(&fs).context(error::ParseArg { arg: fs })?;
|
||||
match param {
|
||||
|
@ -246,6 +268,7 @@ fn main_run(args: RunArgs) -> Result<(), Error> {
|
|||
.context(error::CreateDevice)?,
|
||||
};
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
if let Some(vsock) = args.vsock {
|
||||
let param = serde_aco::from_arg(&vsock).context(error::ParseArg { arg: vsock })?;
|
||||
match param {
|
||||
|
|
|
@ -12,22 +12,23 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
#[path = "hvf/hvf.rs"]
|
||||
mod hvf;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "kvm/kvm.rs"]
|
||||
mod kvm;
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use kvm::{Kvm, KvmConfig, KvmError};
|
||||
use macros::trace_error;
|
||||
use serde::Deserialize;
|
||||
use snafu::Snafu;
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::os::fd::AsFd;
|
||||
use std::sync::Arc;
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use macros::trace_error;
|
||||
use serde::Deserialize;
|
||||
use snafu::Snafu;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::cpuid::Cpuid;
|
||||
use crate::arch::reg::Reg;
|
||||
|
@ -36,6 +37,11 @@ use crate::arch::reg::{DtReg, DtRegVal, SReg, SegReg, SegRegVal};
|
|||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::arch::sev::{SevPolicy, SnpPageType, SnpPolicy};
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use hvf::Hvf;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use kvm::{Kvm, KvmConfig, KvmError};
|
||||
|
||||
#[trace_error]
|
||||
#[derive(Snafu)]
|
||||
#[snafu(module, context(suffix(false)))]
|
||||
|
@ -85,6 +91,7 @@ pub enum Error {
|
|||
RunVcpu { error: std::io::Error },
|
||||
#[snafu(display("Failed to stop a VCPU"))]
|
||||
StopVcpu { error: std::io::Error },
|
||||
#[cfg(target_os = "linux")]
|
||||
#[snafu(display("KVM internal error"), context(false))]
|
||||
KvmErr { source: Box<KvmError> },
|
||||
}
|
||||
|
|
200
alioth/src/hv/hvf/hvf.rs
Normal file
200
alioth/src/hv/hvf/hvf.rs
Normal file
|
@ -0,0 +1,200 @@
|
|||
// Copyright 2024 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::os::fd::{AsFd, BorrowedFd};
|
||||
use std::thread::JoinHandle;
|
||||
|
||||
use crate::arch::reg::Reg;
|
||||
use crate::hv::{
|
||||
Hypervisor, IntxSender, IoeventFd, IoeventFdRegistry, IrqFd, MemMapOption, MsiSender, Result,
|
||||
Vcpu, Vm, VmEntry, VmExit, VmMemory,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfVcpu {}
|
||||
|
||||
impl Vcpu for HvfVcpu {
|
||||
fn dump(&self) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn get_reg(&self, _reg: Reg) -> Result<u64> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn run(&mut self, _entry: VmEntry) -> Result<VmExit> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn set_regs(&mut self, _vals: &[(Reg, u64)]) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfMemory {}
|
||||
|
||||
impl VmMemory for HvfMemory {
|
||||
fn deregister_encrypted_range(&self, _range: &[u8]) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn max_mem_slots(&self) -> Result<u32> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn mem_map(
|
||||
&self,
|
||||
_slot: u32,
|
||||
_gpa: usize,
|
||||
_size: usize,
|
||||
_hva: usize,
|
||||
_option: MemMapOption,
|
||||
) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn register_encrypted_range(&self, _range: &[u8]) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn unmap(&self, _slot: u32, _gpa: usize, _size: usize) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn mark_private_memory(&self, _gpa: u64, _size: u64, _private: bool) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfIntxSender {}
|
||||
impl IntxSender for HvfIntxSender {
|
||||
fn send(&self) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfIrqFd {}
|
||||
impl AsFd for HvfIrqFd {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
impl IrqFd for HvfIrqFd {
|
||||
fn get_addr_hi(&self) -> u32 {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_addr_lo(&self) -> u32 {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_data(&self) -> u32 {
|
||||
unimplemented!()
|
||||
}
|
||||
fn get_masked(&self) -> bool {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_addr_hi(&self, _val: u32) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_addr_lo(&self, _val: u32) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_data(&self, _val: u32) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn set_masked(&self, _val: bool) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfMsiSender {}
|
||||
|
||||
impl MsiSender for HvfMsiSender {
|
||||
type IrqFd = HvfIrqFd;
|
||||
fn create_irqfd(&self) -> Result<Self::IrqFd> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn send(&self, _addr: u64, _data: u32) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfIoeventFd {}
|
||||
|
||||
impl IoeventFd for HvfIoeventFd {}
|
||||
|
||||
impl AsFd for HvfIoeventFd {
|
||||
fn as_fd(&self) -> BorrowedFd<'_> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfIoeventFdRegistry {}
|
||||
|
||||
impl IoeventFdRegistry for HvfIoeventFdRegistry {
|
||||
type IoeventFd = HvfIoeventFd;
|
||||
fn create(&self) -> Result<Self::IoeventFd> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn deregister(&self, _fd: &Self::IoeventFd) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn register(
|
||||
&self,
|
||||
_fd: &Self::IoeventFd,
|
||||
_gpa: usize,
|
||||
_len: u8,
|
||||
_data: Option<u64>,
|
||||
) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct HvfVm {}
|
||||
|
||||
impl Vm for HvfVm {
|
||||
type Vcpu = HvfVcpu;
|
||||
type Memory = HvfMemory;
|
||||
type MsiSender = HvfMsiSender;
|
||||
type IoeventFdRegistry = HvfIoeventFdRegistry;
|
||||
fn create_ioeventfd_registry(&self) -> Result<Self::IoeventFdRegistry> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn create_msi_sender(&self) -> Result<Self::MsiSender> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn create_vcpu(&self, _id: u32) -> Result<Self::Vcpu> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn create_vm_memory(&mut self) -> Result<Self::Memory> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn stop_vcpu<T>(_id: u32, _handle: &JoinHandle<T>) -> Result<()> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Hvf {}
|
||||
|
||||
impl Hypervisor for Hvf {
|
||||
type Vm = HvfVm;
|
||||
fn create_vm(&self, _config: &super::VmConfig) -> Result<Self::Vm> {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
|
@ -13,20 +13,25 @@
|
|||
// limitations under the License.
|
||||
|
||||
use std::cell::UnsafeCell;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::ffi::CStr;
|
||||
use std::fmt::Debug;
|
||||
use std::fs::File;
|
||||
use std::io::{IoSlice, IoSliceMut, Read, Write};
|
||||
use std::mem::{align_of, size_of};
|
||||
use std::ops::Deref;
|
||||
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::fd::FromRawFd;
|
||||
use std::os::fd::{AsFd, AsRawFd, BorrowedFd};
|
||||
use std::ptr::{null_mut, NonNull};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use libc::MFD_CLOEXEC;
|
||||
use libc::{
|
||||
c_void, mmap, msync, munmap, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, MFD_CLOEXEC,
|
||||
MS_ASYNC, PROT_EXEC, PROT_READ, PROT_WRITE,
|
||||
c_void, mmap, msync, munmap, MAP_ANONYMOUS, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, MS_ASYNC,
|
||||
PROT_EXEC, PROT_READ, PROT_WRITE,
|
||||
};
|
||||
use parking_lot::{RwLock, RwLockReadGuard};
|
||||
use zerocopy::{AsBytes, FromBytes};
|
||||
|
@ -109,6 +114,7 @@ impl ArcMemPages {
|
|||
Ok(Self::from_raw(addr, len, Some(file)))
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn from_memfd(size: usize, prot: Option<i32>, name: Option<&CStr>) -> Result<Self> {
|
||||
let name = name.unwrap_or(c"anon");
|
||||
let fd = ffi!(unsafe { libc::memfd_create(name.as_ptr(), MFD_CLOEXEC) })?;
|
||||
|
@ -610,8 +616,8 @@ mod test {
|
|||
fn test_ram_bus_read() {
|
||||
let bus = RamBus::new(FakeVmMemory);
|
||||
let prot = PROT_READ | PROT_WRITE;
|
||||
let mem1 = ArcMemPages::from_memfd(PAGE_SIZE, Some(prot), None).unwrap();
|
||||
let mem2 = ArcMemPages::from_memfd(PAGE_SIZE, Some(prot), None).unwrap();
|
||||
let mem1 = ArcMemPages::from_anonymous(PAGE_SIZE, Some(prot)).unwrap();
|
||||
let mem2 = ArcMemPages::from_anonymous(PAGE_SIZE, Some(prot)).unwrap();
|
||||
|
||||
if mem1.addr > mem2.addr {
|
||||
bus.add(0x0, mem1).unwrap();
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod ioctls;
|
||||
|
||||
#[macro_export]
|
||||
|
|
|
@ -35,9 +35,12 @@ use crate::virtio::{DeviceId, IrqSender, Result, VirtioFeature};
|
|||
|
||||
pub mod blk;
|
||||
pub mod entropy;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod fs;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "net/net.rs"]
|
||||
pub mod net;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "vsock/vsock.rs"]
|
||||
pub mod vsock;
|
||||
|
||||
|
|
|
@ -25,8 +25,10 @@ pub mod dev;
|
|||
pub mod pci;
|
||||
#[path = "queue/queue.rs"]
|
||||
pub mod queue;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "vhost/vhost.rs"]
|
||||
pub mod vhost;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub mod vu;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
|
@ -70,6 +72,7 @@ pub enum Error {
|
|||
#[error("vhost-user backend is missing device feature {0:#x}")]
|
||||
VuMissingDeviceFeature(u64),
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[error("vhost-user backend is missing protocol feature {0:x?}")]
|
||||
VuMissingProtocolFeature(vu::VuFeature),
|
||||
|
||||
|
|
Loading…
Reference in a new issue