Skip to content

Commit

Permalink
feat(dev): implement QEMU's pvpanic-pci device
Browse files Browse the repository at this point in the history
Ref: https://www.qemu.org/docs/master/specs/pvpanic.html

Signed-off-by: Changyuan Lyu <changyuanl@google.com>
  • Loading branch information
Lencerf committed May 6, 2024
1 parent 6fb887e commit d29e0ff
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 0 deletions.
6 changes: 6 additions & 0 deletions alioth-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct RunArgs {

#[arg(long, default_value = "1G")]
mem_size: String,

#[arg(long)]
pvpanic: bool,
}

fn parse_mem(s: &str) -> Result<usize> {
Expand Down Expand Up @@ -112,6 +115,9 @@ fn main_run(args: RunArgs) -> Result<()> {
if let Some(payload) = payload {
vm.add_payload(payload);
}
if args.pvpanic {
vm.add_pvpanic()?;
}
vm.boot()?;
for result in vm.wait() {
result?;
Expand Down
1 change: 1 addition & 0 deletions alioth/src/device/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
// See the License for the specific language governing permissions and
// limitations under the License.

pub mod pvpanic;
pub mod serial;
105 changes: 105 additions & 0 deletions alioth/src/device/pvpanic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// 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::sync::Arc;

use bitflags::bitflags;

use crate::mem::emulated::Mmio;
use crate::mem::{self, Action, MemRegion};
use crate::pci::cap::PciCapList;
use crate::pci::config::{
CommonHeader, DeviceHeader, EmulatedConfig, HeaderType, PciConfig, BAR_MEM64, BAR_PREFETCHABLE,
};
use crate::pci::{self, Pci, PciBar};

bitflags! {
#[derive(Debug)]
struct PvPanicByte: u8 {
const PANICKED = 1 << 0;
const CRASH_LOADED = 1 << 1;
}
}

const PVPANIC_VENDOR_ID: u16 = 0x1b36;
const PVPANIC_DEVICE_ID: u16 = 0x0011;

#[derive(Debug)]
struct PvPanicBar<const N: usize>;

impl<const N: usize> Mmio for PvPanicBar<N> {
fn size(&self) -> usize {
N
}

fn read(&self, _offset: usize, _size: u8) -> mem::Result<u64> {
Ok(PvPanicByte::all().bits() as u64)
}

fn write(&self, _offset: usize, _size: u8, val: u64) -> mem::Result<()> {
log::info!("pvpanic: {:x?}", PvPanicByte::from_bits_retain(val as u8));
Err(mem::Error::Action(Action::Shutdown))
}
}

#[derive(Debug)]
pub struct PvPanic {
pub config: Arc<EmulatedConfig>,
}

impl PvPanic {
pub fn new() -> Self {
const BAR_SIZE: usize = 0x1000;
let header = DeviceHeader {
common: CommonHeader {
vendor: PVPANIC_VENDOR_ID,
device: PVPANIC_DEVICE_ID,
revision: 1,
header_type: HeaderType::Device as u8,
class: 0x08,
subclass: 0x80,
..Default::default()
},
bars: [BAR_MEM64 | BAR_PREFETCHABLE, 0, 0, 0, 0, 0],
..Default::default()
};
let bar_masks = [!(BAR_SIZE as u32 - 1), 0xffff_ffff, 0, 0, 0, 0];
let bar0 = PciBar::Mem64(Arc::new(MemRegion::with_emulated(
Arc::new(PvPanicBar::<BAR_SIZE>),
mem::MemRegionType::Hidden,
)));
let mut bars = PciBar::empty_6();
bars[0] = bar0;
let config = EmulatedConfig::new_device(header, bar_masks, bars, PciCapList::new());
PvPanic {
config: Arc::new(config),
}
}
}

impl Default for PvPanic {
fn default() -> Self {
PvPanic::new()
}
}

impl Pci for PvPanic {
fn config(&self) -> Arc<dyn PciConfig> {
self.config.clone()
}

fn reset(&self) -> pci::Result<()> {
Ok(())
}
}
7 changes: 7 additions & 0 deletions alioth/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use parking_lot::{Condvar, Mutex, RwLock};
use thiserror::Error;

use crate::board::{self, ArchBoard, Board, BoardConfig, STATE_CREATED, STATE_RUNNING};
use crate::device::pvpanic::PvPanic;
use crate::device::serial::Serial;
use crate::hv::{self, Hypervisor, Vm};
use crate::loader::{self, Payload};
Expand Down Expand Up @@ -119,6 +120,12 @@ where
Ok(())
}

pub fn add_pvpanic(&mut self) -> Result<(), Error> {
let dev = PvPanic::new();
let pci_dev = PciDevice::new("pvpanic".to_owned().into(), Arc::new(dev));
self.add_pci_dev(pci_dev)
}

pub fn add_payload(&mut self, payload: Payload) {
*self.board.payload.write() = Some(payload)
}
Expand Down

0 comments on commit d29e0ff

Please sign in to comment.