extensive changes to how VMs are configured and launched
This commit is contained in:
parent
2568a30440
commit
5a1c62d473
@ -378,6 +378,7 @@ impl SyntheticFS {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn add_executable<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, dirpath: P, filename: &str, realpath: Q) -> io::Result<()> {
|
pub fn add_executable<P: AsRef<Path>, Q: AsRef<Path>>(&mut self, dirpath: P, filename: &str, realpath: Q) -> io::Result<()> {
|
||||||
let realpath = realpath.as_ref();
|
let realpath = realpath.as_ref();
|
||||||
self.add_library_dependencies(realpath)?;
|
self.add_library_dependencies(realpath)?;
|
||||||
|
@ -66,7 +66,7 @@ pub struct VirtioBlock<D: DiskImage+'static> {
|
|||||||
|
|
||||||
const VIRTIO_ID_BLOCK: u16 = 2;
|
const VIRTIO_ID_BLOCK: u16 = 2;
|
||||||
impl <D: DiskImage + 'static> VirtioBlock<D> {
|
impl <D: DiskImage + 'static> VirtioBlock<D> {
|
||||||
fn new(disk_image: D) -> Self {
|
pub fn new(disk_image: D) -> Self {
|
||||||
let mut config = DeviceConfigArea::new(8);
|
let mut config = DeviceConfigArea::new(8);
|
||||||
config.write_u64(0, disk_image.sector_count());
|
config.write_u64(0, disk_image.sector_count());
|
||||||
VirtioBlock {
|
VirtioBlock {
|
||||||
@ -192,7 +192,6 @@ impl <'a, D: DiskImage> MessageHandler<'a, D> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fn sector_round(sz: usize) -> usize {
|
fn sector_round(sz: usize) -> usize {
|
||||||
(sz / SECTOR_SIZE) * SECTOR_SIZE
|
(sz / SECTOR_SIZE) * SECTOR_SIZE
|
||||||
}
|
}
|
||||||
@ -204,7 +203,7 @@ impl <'a, D: DiskImage> MessageHandler<'a, D> {
|
|||||||
|
|
||||||
self.disk.read_sectors(self.sector, buffer)
|
self.disk.read_sectors(self.sector, buffer)
|
||||||
.map_err(Error::DiskRead)?;
|
.map_err(Error::DiskRead)?;
|
||||||
self.chain.inc_offset(len);
|
self.chain.inc_offset(len, true);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +214,7 @@ impl <'a, D: DiskImage> MessageHandler<'a, D> {
|
|||||||
|
|
||||||
self.disk.write_sectors(self.sector, buffer)
|
self.disk.write_sectors(self.sector, buffer)
|
||||||
.map_err(Error::DiskWrite)?;
|
.map_err(Error::DiskWrite)?;
|
||||||
self.chain.inc_offset(len);
|
self.chain.inc_offset(len, false);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,14 +25,15 @@ pub enum OpenType {
|
|||||||
pub trait DiskImage: Sync+Send {
|
pub trait DiskImage: Sync+Send {
|
||||||
fn read_only(&self) -> bool;
|
fn read_only(&self) -> bool;
|
||||||
fn sector_count(&self) -> u64;
|
fn sector_count(&self) -> u64;
|
||||||
fn disk_file(&self) -> &File;
|
fn disk_file(&mut self) -> Result<&mut File>;
|
||||||
|
|
||||||
fn seek_to_sector(&self, sector: u64) -> Result<()> {
|
fn seek_to_sector(&mut self, sector: u64) -> Result<()> {
|
||||||
if sector > self.sector_count() {
|
if sector > self.sector_count() {
|
||||||
return Err(Error::BadSectorOffset(sector));
|
return Err(Error::BadSectorOffset(sector));
|
||||||
}
|
}
|
||||||
let offset = SeekFrom::Start(sector * SECTOR_SIZE as u64);
|
let offset = SeekFrom::Start(sector * SECTOR_SIZE as u64);
|
||||||
self.disk_file().seek(offset)
|
let file = self.disk_file()?;
|
||||||
|
file.seek(offset)
|
||||||
.map_err(Error::DiskSeek)?;
|
.map_err(Error::DiskSeek)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -67,6 +68,7 @@ pub enum Error {
|
|||||||
DiskSeek(io::Error),
|
DiskSeek(io::Error),
|
||||||
BadSectorOffset(u64),
|
BadSectorOffset(u64),
|
||||||
MemoryOverlayCreate(system::Error),
|
MemoryOverlayCreate(system::Error),
|
||||||
|
NotOpen,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl error::Error for Error {}
|
impl error::Error for Error {}
|
||||||
@ -83,6 +85,7 @@ impl fmt::Display for Error {
|
|||||||
DiskSeek(err) => write!(f, "error seeking to offset on disk image: {}", err),
|
DiskSeek(err) => write!(f, "error seeking to offset on disk image: {}", err),
|
||||||
BadSectorOffset(sector) => write!(f, "attempt to access invalid sector offset {}", sector),
|
BadSectorOffset(sector) => write!(f, "attempt to access invalid sector offset {}", sector),
|
||||||
MemoryOverlayCreate(err) => write!(f, "failed to create memory overlay: {}", err),
|
MemoryOverlayCreate(err) => write!(f, "failed to create memory overlay: {}", err),
|
||||||
|
NotOpen => write!(f, "disk not open"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -3,81 +3,84 @@ use std::fs::{File, OpenOptions};
|
|||||||
use std::io::{Write, Read, SeekFrom, Seek};
|
use std::io::{Write, Read, SeekFrom, Seek};
|
||||||
use crate::disk::Error::DiskRead;
|
use crate::disk::Error::DiskRead;
|
||||||
use crate::disk::memory::MemoryOverlay;
|
use crate::disk::memory::MemoryOverlay;
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
|
||||||
pub struct RawDiskImage {
|
pub struct RawDiskImage {
|
||||||
file: File,
|
path: PathBuf,
|
||||||
|
open_type: OpenType,
|
||||||
|
file: Option<File>,
|
||||||
offset: usize,
|
offset: usize,
|
||||||
nsectors: u64,
|
nsectors: u64,
|
||||||
read_only: bool,
|
|
||||||
disk_image_id: Vec<u8>,
|
disk_image_id: Vec<u8>,
|
||||||
overlay: Option<MemoryOverlay>,
|
overlay: Option<MemoryOverlay>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RawDiskImage {
|
impl RawDiskImage {
|
||||||
#[allow(dead_code)]
|
pub fn new<P: Into<PathBuf>>(path: P, open_type: OpenType) -> Self {
|
||||||
pub fn open<P: AsRef<Path>>(path: P, open_type: OpenType) -> Result<Self> {
|
Self::new_with_offset(path, open_type, 0)
|
||||||
Self::open_with_offset(path, open_type, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_with_offset<P: AsRef<Path>>(path: P, open_type: OpenType, offset: usize) -> Result<Self> {
|
pub fn new_with_offset<P: Into<PathBuf>>(path: P, open_type: OpenType, offset: usize) -> Self {
|
||||||
let path = path.as_ref();
|
let path = path.into();
|
||||||
let meta = path.metadata()
|
RawDiskImage {
|
||||||
.map_err(|e| Error::DiskOpen(path.into(), e))?;
|
path,
|
||||||
|
open_type,
|
||||||
|
file: None,
|
||||||
|
offset,
|
||||||
|
nsectors: 0,
|
||||||
|
disk_image_id: Vec::new(),
|
||||||
|
overlay: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if meta.len() < offset as u64 {
|
pub fn open(&mut self) -> Result<()> {
|
||||||
return Err(Error::DiskOpenTooShort(path.into()))
|
let meta = self.path.metadata()
|
||||||
|
.map_err(|e| Error::DiskOpen(self.path.clone(), e))?;
|
||||||
|
|
||||||
|
if meta.len() < self.offset as u64 {
|
||||||
|
return Err(Error::DiskOpenTooShort(self.path.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
let nsectors = (meta.len() - offset as u64) / SECTOR_SIZE as u64;
|
self.nsectors = (meta.len() - self.offset as u64) / SECTOR_SIZE as u64;
|
||||||
|
|
||||||
let file = OpenOptions::new()
|
let file = OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(open_type == OpenType::ReadWrite)
|
.write(self.open_type == OpenType::ReadWrite)
|
||||||
.open(path)
|
.open(&self.path)
|
||||||
.map_err(|e| Error::DiskOpen(path.into(), e))?;
|
.map_err(|e| Error::DiskOpen(self.path.clone(), e))?;
|
||||||
|
|
||||||
|
self.disk_image_id = generate_disk_image_id(&file);
|
||||||
|
self.file = Some(file);
|
||||||
|
|
||||||
let disk = match open_type {
|
if self.open_type == OpenType::MemoryOverlay {
|
||||||
OpenType::MemoryOverlay => {
|
let overlay = MemoryOverlay::new()?;
|
||||||
let overlay = MemoryOverlay::new()?;
|
self.overlay = Some(overlay);
|
||||||
Self::new(file, nsectors, offset, false, Some(overlay))
|
}
|
||||||
}
|
Ok(())
|
||||||
OpenType::ReadOnly => {
|
|
||||||
Self::new(file, nsectors, offset, true, None)
|
|
||||||
}
|
|
||||||
OpenType::ReadWrite => {
|
|
||||||
Self::new(file, nsectors, offset, false, None)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(disk)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new(file: File, nsectors: u64, offset: usize, read_only: bool, overlay: Option<MemoryOverlay>) -> Self {
|
|
||||||
let disk_image_id = generate_disk_image_id(&file);
|
|
||||||
RawDiskImage { file, nsectors, read_only, offset, disk_image_id, overlay }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DiskImage for RawDiskImage {
|
impl DiskImage for RawDiskImage {
|
||||||
fn read_only(&self) -> bool {
|
fn read_only(&self) -> bool {
|
||||||
self.read_only
|
self.open_type == OpenType::ReadOnly
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sector_count(&self) -> u64 {
|
fn sector_count(&self) -> u64 {
|
||||||
self.nsectors
|
self.nsectors
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disk_file(&self) -> &File {
|
fn disk_file(&mut self) -> Result<&mut File> {
|
||||||
&self.file
|
self.file.as_mut().ok_or(Error::NotOpen)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek_to_sector(&self, sector: u64) -> Result<()> {
|
fn seek_to_sector(&mut self, sector: u64) -> Result<()> {
|
||||||
if sector > self.sector_count() {
|
if sector > self.sector_count() {
|
||||||
return Err(Error::BadSectorOffset(sector));
|
return Err(Error::BadSectorOffset(sector));
|
||||||
}
|
}
|
||||||
let offset = SeekFrom::Start(sector * SECTOR_SIZE as u64 + self.offset as u64);
|
let offset = SeekFrom::Start(sector * SECTOR_SIZE as u64 + self.offset as u64);
|
||||||
self.disk_file().seek(offset)
|
let disk = self.disk_file()?;
|
||||||
|
disk.seek(offset)
|
||||||
.map_err(Error::DiskSeek)?;
|
.map_err(Error::DiskSeek)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -86,12 +89,13 @@ impl DiskImage for RawDiskImage {
|
|||||||
if let Some(ref mut overlay) = self.overlay {
|
if let Some(ref mut overlay) = self.overlay {
|
||||||
return overlay.write_sectors(start_sector, buffer);
|
return overlay.write_sectors(start_sector, buffer);
|
||||||
}
|
}
|
||||||
if self.read_only {
|
if self.read_only() {
|
||||||
return Err(Error::ReadOnly)
|
return Err(Error::ReadOnly)
|
||||||
}
|
}
|
||||||
self.seek_to_sector(start_sector)?;
|
self.seek_to_sector(start_sector)?;
|
||||||
let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE;
|
let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE;
|
||||||
self.file.write_all(&buffer[..len])
|
let file = self.disk_file()?;
|
||||||
|
file.write_all(&buffer[..len])
|
||||||
.map_err(Error::DiskWrite)?;
|
.map_err(Error::DiskWrite)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -105,7 +109,8 @@ impl DiskImage for RawDiskImage {
|
|||||||
|
|
||||||
self.seek_to_sector(start_sector)?;
|
self.seek_to_sector(start_sector)?;
|
||||||
let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE;
|
let len = (buffer.len() / SECTOR_SIZE) * SECTOR_SIZE;
|
||||||
self.file.read_exact(&mut buffer[..len])
|
let file = self.disk_file()?;
|
||||||
|
file.read_exact(&mut buffer[..len])
|
||||||
.map_err(DiskRead)?;
|
.map_err(DiskRead)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::disk::{Result, DiskImage, SECTOR_SIZE, RawDiskImage, OpenType};
|
use crate::disk::{Result, DiskImage, SECTOR_SIZE, RawDiskImage, OpenType};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::path::Path;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
// skip 4096 byte realmfs header
|
// skip 4096 byte realmfs header
|
||||||
const HEADER_SECTOR_COUNT: usize = 8;
|
const HEADER_SECTOR_COUNT: usize = 8;
|
||||||
@ -11,10 +11,13 @@ pub struct RealmFSImage {
|
|||||||
|
|
||||||
// Just pass everything through to raw image for now
|
// Just pass everything through to raw image for now
|
||||||
impl RealmFSImage {
|
impl RealmFSImage {
|
||||||
pub fn open<P: AsRef<Path>>(path: P, read_only: bool) -> Result<Self> {
|
pub fn new<P: Into<PathBuf>>(path: P, open_type: OpenType) -> Self {
|
||||||
let open_type = if read_only { OpenType::ReadOnly } else { OpenType::MemoryOverlay };
|
let offset = HEADER_SECTOR_COUNT * SECTOR_SIZE;
|
||||||
let raw = RawDiskImage::open_with_offset(path, open_type, HEADER_SECTOR_COUNT * SECTOR_SIZE)?;
|
let raw = RawDiskImage::new_with_offset(path, open_type, offset);
|
||||||
Ok(RealmFSImage { raw })
|
RealmFSImage { raw }
|
||||||
|
}
|
||||||
|
pub fn open(&mut self) -> Result<()> {
|
||||||
|
self.raw.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,7 +30,7 @@ impl DiskImage for RealmFSImage {
|
|||||||
self.raw.sector_count()
|
self.raw.sector_count()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disk_file(&self) -> &File {
|
fn disk_file(&mut self) -> Result<&mut File> {
|
||||||
self.raw.disk_file()
|
self.raw.disk_file()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,11 +13,9 @@ mod virtio;
|
|||||||
mod disk;
|
mod disk;
|
||||||
|
|
||||||
pub use log::{Logger,LogLevel};
|
pub use log::{Logger,LogLevel};
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
vm::VmConfig::new(env::args())
|
vm::VmConfig::new()
|
||||||
.ram_size_megs(1024)
|
.ram_size_megs(1024)
|
||||||
.use_realmfs("/home/user/Shared/main-realmfs.img")
|
|
||||||
.boot();
|
.boot();
|
||||||
}
|
}
|
||||||
|
@ -1,39 +1,47 @@
|
|||||||
use std::path::{PathBuf, Path};
|
use std::path::{PathBuf, Path};
|
||||||
use crate::vm::{Vm, Result, ErrorKind};
|
use crate::vm::Vm;
|
||||||
use std::{env, process};
|
use std::{env, process};
|
||||||
|
use crate::devices::SyntheticFS;
|
||||||
pub enum RootFS {
|
use crate::disk::{RawDiskImage, RealmFSImage, OpenType};
|
||||||
SelfRoot,
|
use libcitadel::Realms;
|
||||||
RealmFSImage(PathBuf),
|
use libcitadel::terminal::{TerminalPalette, AnsiTerminal};
|
||||||
RawImage(PathBuf),
|
|
||||||
RawOffset(PathBuf, usize),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct VmConfig {
|
pub struct VmConfig {
|
||||||
ram_size: usize,
|
ram_size: usize,
|
||||||
ncpus: usize,
|
ncpus: usize,
|
||||||
verbose: bool,
|
verbose: bool,
|
||||||
|
rootshell: bool,
|
||||||
|
home: String,
|
||||||
launch_systemd: bool,
|
launch_systemd: bool,
|
||||||
kernel_path: Option<PathBuf>,
|
kernel_path: Option<PathBuf>,
|
||||||
init_path: Option<PathBuf>,
|
init_path: Option<PathBuf>,
|
||||||
init_cmd: Option<String>,
|
init_cmd: Option<String>,
|
||||||
rootfs: RootFS,
|
raw_disks: Vec<RawDiskImage>,
|
||||||
|
|
||||||
|
realmfs_images: Vec<RealmFSImage>,
|
||||||
|
realm_name: Option<String>,
|
||||||
|
synthetic: Option<SyntheticFS>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl VmConfig {
|
impl VmConfig {
|
||||||
pub fn new(args: env::Args) -> VmConfig {
|
pub fn new() -> VmConfig {
|
||||||
let mut config = VmConfig {
|
let mut config = VmConfig {
|
||||||
ram_size: 256 * 1024 * 1024,
|
ram_size: 256 * 1024 * 1024,
|
||||||
ncpus: 1,
|
ncpus: 1,
|
||||||
verbose: false,
|
verbose: false,
|
||||||
|
rootshell: false,
|
||||||
|
home: String::from("/home/user"),
|
||||||
launch_systemd: false,
|
launch_systemd: false,
|
||||||
kernel_path: None,
|
kernel_path: None,
|
||||||
init_path: None,
|
init_path: None,
|
||||||
init_cmd: None,
|
init_cmd: None,
|
||||||
rootfs: RootFS::SelfRoot,
|
realm_name: None,
|
||||||
|
raw_disks: Vec::new(),
|
||||||
|
realmfs_images: Vec::new(),
|
||||||
|
synthetic: None,
|
||||||
};
|
};
|
||||||
config.parse_args(args);
|
config.parse_args();
|
||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,6 +50,21 @@ impl VmConfig {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn raw_disk_image<P: Into<PathBuf>>(mut self, path: P, open_type: OpenType) -> Self {
|
||||||
|
self.raw_disks.push(RawDiskImage::new(path, open_type));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw_disk_image_with_offset<P: Into<PathBuf>>(mut self, path: P, open_type: OpenType, offset: usize) -> Self {
|
||||||
|
self.raw_disks.push(RawDiskImage::new_with_offset(path, open_type, offset));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn realmfs_image<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
||||||
|
self.realmfs_images.push(RealmFSImage::new(path, OpenType::MemoryOverlay));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn num_cpus(mut self, ncpus: usize) -> Self {
|
pub fn num_cpus(mut self, ncpus: usize) -> Self {
|
||||||
self.ncpus = ncpus;
|
self.ncpus = ncpus;
|
||||||
self
|
self
|
||||||
@ -62,27 +85,20 @@ impl VmConfig {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn use_realmfs<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
|
||||||
self.rootfs = RootFS::RealmFSImage(path.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_rawdisk<P: Into<PathBuf>>(mut self, path: P) -> Self {
|
|
||||||
self.rootfs = RootFS::RawImage(path.into());
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_rawdisk_with_offset<P: Into<PathBuf>>(mut self, path: P, offset: usize) -> Self {
|
|
||||||
self.rootfs = RootFS::RawOffset(path.into(), offset);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn use_systemd(mut self) -> Self {
|
pub fn use_systemd(mut self) -> Self {
|
||||||
self.launch_systemd = true;
|
self.launch_systemd = true;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn synthetic_fs(mut self, sfs: SyntheticFS) -> Self {
|
||||||
|
self.synthetic = Some(sfs);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn boot(self) {
|
pub fn boot(self) {
|
||||||
|
|
||||||
|
let _terminal_restore = TerminalRestore::save();
|
||||||
|
|
||||||
match Vm::open(self) {
|
match Vm::open(self) {
|
||||||
Ok(vm) => if let Err(err) = vm.start() {
|
Ok(vm) => if let Err(err) = vm.start() {
|
||||||
notify!("Error starting VM: {}", err);
|
notify!("Error starting VM: {}", err);
|
||||||
@ -103,83 +119,155 @@ impl VmConfig {
|
|||||||
self.verbose
|
self.verbose
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rootshell(&self) -> bool {
|
||||||
|
self.rootshell
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn homedir(&self) -> &str {
|
||||||
|
&self.home
|
||||||
|
}
|
||||||
|
|
||||||
pub fn launch_systemd(&self) -> bool {
|
pub fn launch_systemd(&self) -> bool {
|
||||||
self.launch_systemd
|
self.launch_systemd
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_kernel_path(&self) -> Result<PathBuf> {
|
pub fn has_block_image(&self) -> bool {
|
||||||
match self.kernel_path {
|
!(self.realmfs_images.is_empty() && self.raw_disks.is_empty())
|
||||||
Some(ref path) if path.exists() => return Ok(path.to_path_buf()),
|
|
||||||
None => if let Some(path) = Self::search_kernel() {
|
|
||||||
return Ok(path)
|
|
||||||
}
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
Err(ErrorKind::KernelNotFound.into())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_init_path(&self) -> Result<PathBuf> {
|
pub fn get_realmfs_images(&mut self) -> Vec<RealmFSImage> {
|
||||||
match self.init_path {
|
self.realmfs_images.drain(..).collect()
|
||||||
Some(ref path) if path.exists() => return Ok(path.to_path_buf()),
|
}
|
||||||
None => if let Some(path) = Self::search_init() {
|
|
||||||
return Ok(path)
|
pub fn get_raw_disk_images(&mut self) -> Vec<RawDiskImage> {
|
||||||
}
|
self.raw_disks.drain(..).collect()
|
||||||
_ => {},
|
}
|
||||||
}
|
|
||||||
Err(ErrorKind::InitNotFound.into())
|
pub fn get_synthetic_fs(&self) -> Option<SyntheticFS> {
|
||||||
|
self.synthetic.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_init_cmdline(&self) -> Option<&str> {
|
pub fn get_init_cmdline(&self) -> Option<&str> {
|
||||||
self.init_cmd.as_ref().map(|s| s.as_str())
|
self.init_cmd.as_ref().map(|s| s.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rootfs(&self) -> &RootFS {
|
pub fn realm_name(&self) -> Option<&str> {
|
||||||
&self.rootfs
|
self.realm_name.as_ref().map(|s| s.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_init() -> Option<PathBuf> {
|
fn add_realmfs_by_name(&mut self, realmfs: &str) {
|
||||||
Self::search_binary("ph-init", &[
|
let path = Path::new("/realms/realmfs-images")
|
||||||
"rust/target/release", "rust/target/debug",
|
.join(format!("{}-realmfs.img", realmfs));
|
||||||
"target/debug", "target/release"
|
if !path.exists() {
|
||||||
])
|
eprintln!("Realmfs image does not exist at {}", path.display());
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
self.realmfs_images.push(RealmFSImage::new(path, OpenType::MemoryOverlay));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_kernel() -> Option<PathBuf> {
|
fn add_realm_by_name(&mut self, realm: &str) {
|
||||||
Self::search_binary("ph_linux", &["kernel", "../kernel"])
|
let realms = Realms::load().unwrap();
|
||||||
|
if let Some(realm) = realms.by_name(realm) {
|
||||||
|
let config = realm.config();
|
||||||
|
let realmfs = config.realmfs();
|
||||||
|
self.add_realmfs_by_name(realmfs);
|
||||||
|
self.home = realm.base_path().join("home").display().to_string();
|
||||||
|
self.realm_name = Some(realm.name().to_string())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn search_binary(name: &str, paths: &[&str]) -> Option<PathBuf> {
|
fn parse_args(&mut self) {
|
||||||
let cwd = match env::current_dir() {
|
let args = ProgramArgs::new();
|
||||||
Ok(cwd) => cwd,
|
if args.has_arg("-v") {
|
||||||
_ => return None,
|
self.verbose = true;
|
||||||
};
|
}
|
||||||
|
if args.has_arg("--root") {
|
||||||
|
self.rootshell = true;
|
||||||
|
}
|
||||||
|
if let Some(home) = args.arg_with_value("--home") {
|
||||||
|
self.home = home.to_string();
|
||||||
|
}
|
||||||
|
if let Some(realmfs) = args.arg_with_value("--realmfs") {
|
||||||
|
self.add_realmfs_by_name(realmfs);
|
||||||
|
}
|
||||||
|
if let Some(realm) = args.arg_with_value("--realm") {
|
||||||
|
self.add_realm_by_name(realm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for p in paths {
|
struct ProgramArgs {
|
||||||
let p = Path::new(p).join(name);
|
args: Vec<String>,
|
||||||
let current = if p.is_absolute() {
|
}
|
||||||
p
|
|
||||||
} else {
|
impl ProgramArgs {
|
||||||
cwd.join(p)
|
fn new() -> Self {
|
||||||
};
|
ProgramArgs {
|
||||||
if current.exists() {
|
args: env::args().skip(1).collect(),
|
||||||
return Some(current);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_arg(&self, name: &str) -> bool {
|
||||||
|
self.args.iter().any(|arg| arg.as_str() == name)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arg_with_value(&self, name: &str) -> Option<&str> {
|
||||||
|
let mut iter = self.args.iter();
|
||||||
|
while let Some(arg) = iter.next() {
|
||||||
|
if arg.as_str() == name {
|
||||||
|
match iter.next() {
|
||||||
|
Some(val) => return Some(val.as_str()),
|
||||||
|
None => {
|
||||||
|
eprintln!("Expected value for {} argument", name);
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn parse_args(&mut self, args: env::Args) {
|
pub struct TerminalRestore {
|
||||||
for arg in args.skip(1) {
|
saved: Option<TerminalPalette>,
|
||||||
self.parse_one_arg(&arg);
|
}
|
||||||
|
|
||||||
|
impl TerminalRestore {
|
||||||
|
pub fn save() -> Self {
|
||||||
|
let mut term = match AnsiTerminal::new() {
|
||||||
|
Ok(term) => term,
|
||||||
|
Err(e) => {
|
||||||
|
warn!("failed to open terminal: {}", e);
|
||||||
|
return TerminalRestore { saved: None }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut palette = TerminalPalette::default();
|
||||||
|
if let Err(e) = palette.load(&mut term) {
|
||||||
|
warn!("failed to load palette: {}", e);
|
||||||
|
return TerminalRestore { saved: None }
|
||||||
|
}
|
||||||
|
if let Err(e) = term.clear_screen() {
|
||||||
|
warn!("failed to clear screen: {}", e);
|
||||||
|
return TerminalRestore { saved: None }
|
||||||
|
}
|
||||||
|
TerminalRestore { saved: Some(palette) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn restore(&self) {
|
||||||
|
if let Some(p) = self.saved.as_ref() {
|
||||||
|
let mut term = match AnsiTerminal::new() {
|
||||||
|
Ok(term) => term,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let _ = p.apply(&mut term);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_one_arg(&mut self, arg: &str) {
|
}
|
||||||
if arg == "-v" {
|
|
||||||
self.verbose = true;
|
impl Drop for TerminalRestore {
|
||||||
} else {
|
fn drop(&mut self) {
|
||||||
eprintln!("Unrecognized command line argument: {}", arg);
|
self.restore();
|
||||||
process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,6 @@ pub type Result<T> = result::Result<T, Error>;
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ErrorKind {
|
pub enum ErrorKind {
|
||||||
KernelNotFound,
|
|
||||||
InitNotFound,
|
|
||||||
InvalidAddress(u64),
|
InvalidAddress(u64),
|
||||||
InvalidMappingOffset(usize),
|
InvalidMappingOffset(usize),
|
||||||
RegisterMemoryFailed,
|
RegisterMemoryFailed,
|
||||||
@ -26,13 +24,12 @@ pub enum ErrorKind {
|
|||||||
EventFdError,
|
EventFdError,
|
||||||
DiskImageOpen(disk::Error),
|
DiskImageOpen(disk::Error),
|
||||||
TerminalTermios(io::Error),
|
TerminalTermios(io::Error),
|
||||||
|
IoError(io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ErrorKind {
|
impl ErrorKind {
|
||||||
fn as_str(&self) -> &'static str {
|
fn as_str(&self) -> &'static str {
|
||||||
match *self {
|
match *self {
|
||||||
ErrorKind::KernelNotFound => "Could not find kernel image",
|
|
||||||
ErrorKind::InitNotFound => "Could not find init image",
|
|
||||||
ErrorKind::InvalidAddress(..) => "Invalid guest memory address",
|
ErrorKind::InvalidAddress(..) => "Invalid guest memory address",
|
||||||
ErrorKind::InvalidMappingOffset(..) => "Invalid memory mapping offset",
|
ErrorKind::InvalidMappingOffset(..) => "Invalid memory mapping offset",
|
||||||
ErrorKind::RegisterMemoryFailed => "Failed to register memory region",
|
ErrorKind::RegisterMemoryFailed => "Failed to register memory region",
|
||||||
@ -47,6 +44,7 @@ impl ErrorKind {
|
|||||||
ErrorKind::EventFdError => "eventfd error",
|
ErrorKind::EventFdError => "eventfd error",
|
||||||
ErrorKind::DiskImageOpen(_) => "failed to open disk image",
|
ErrorKind::DiskImageOpen(_) => "failed to open disk image",
|
||||||
ErrorKind::TerminalTermios(_) => "failed termios",
|
ErrorKind::TerminalTermios(_) => "failed termios",
|
||||||
|
ErrorKind::IoError(_) => "i/o error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,11 +57,18 @@ impl fmt::Display for ErrorKind {
|
|||||||
ErrorKind::IoctlFailed(name) => write!(f, "Ioctl {} failed", name),
|
ErrorKind::IoctlFailed(name) => write!(f, "Ioctl {} failed", name),
|
||||||
ErrorKind::DiskImageOpen(ref e) => write!(f, "failed to open disk image: {}", e),
|
ErrorKind::DiskImageOpen(ref e) => write!(f, "failed to open disk image: {}", e),
|
||||||
ErrorKind::TerminalTermios(ref e) => write!(f, "error reading/restoring terminal state: {}", e),
|
ErrorKind::TerminalTermios(ref e) => write!(f, "error reading/restoring terminal state: {}", e),
|
||||||
|
ErrorKind::IoError(ref e) => write!(f, "i/o error: {}", e),
|
||||||
_ => write!(f, "{}", self.as_str()),
|
_ => write!(f, "{}", self.as_str()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<io::Error> for Error {
|
||||||
|
fn from(err: io::Error) -> Error {
|
||||||
|
ErrorKind::IoError(err).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
impl From<ErrorKind> for Error {
|
impl From<ErrorKind> for Error {
|
||||||
fn from(kind: ErrorKind) -> Error {
|
fn from(kind: ErrorKind) -> Error {
|
||||||
Error { repr: Repr::Simple(kind) }
|
Error { repr: Repr::Simple(kind) }
|
||||||
|
@ -12,20 +12,16 @@ fn add_defaults(cmdline: &mut KernelCmdLine) {
|
|||||||
// keyboard reboot
|
// keyboard reboot
|
||||||
.push("reboot=k")
|
.push("reboot=k")
|
||||||
.push_set_true("panic")
|
.push_set_true("panic")
|
||||||
.push_set_val("tsc", "reliable")
|
|
||||||
.push("no_timer_check")
|
.push("init_on_alloc=0")
|
||||||
// faster rcu updates
|
.push("init_on_free=0")
|
||||||
.push_set_true("rcuupdate.rcu_expedited")
|
|
||||||
// then restore to normal after booting
|
|
||||||
.push_set_true("rcuupdate.rcu_normal_after_boot")
|
|
||||||
.push_set_val("console", "hvc0")
|
.push_set_val("console", "hvc0")
|
||||||
|
|
||||||
.push_set_true("i8042.direct")
|
.push_set_true("i8042.direct")
|
||||||
.push_set_true("i8042.dumbkbd")
|
.push_set_true("i8042.dumbkbd")
|
||||||
.push_set_true("i8042.nopnp")
|
.push_set_true("i8042.nopnp")
|
||||||
.push_set_true("i8042.noaux")
|
.push_set_true("i8042.noaux")
|
||||||
.push("noreplace-smp")
|
// .push("initcall_debug")
|
||||||
//.push("initcall_debug")
|
|
||||||
.push_set_val("iommu", "off")
|
.push_set_val("iommu", "off")
|
||||||
.push("cryptomgr.notests")
|
.push("cryptomgr.notests")
|
||||||
|
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
use std::thread;
|
use std::{thread, fs};
|
||||||
|
|
||||||
use self::io::IoDispatcher;
|
use self::io::IoDispatcher;
|
||||||
|
|
||||||
use crate::virtio::VirtioBus;
|
use crate::virtio::VirtioBus;
|
||||||
use crate::devices;
|
use crate::devices;
|
||||||
use crate::disk;
|
|
||||||
|
|
||||||
use crate::memory::{GuestRam, KVM_KERNEL_LOAD_ADDRESS, MemoryManager, SystemAllocator, AddressRange};
|
use crate::memory::{GuestRam, KVM_KERNEL_LOAD_ADDRESS, MemoryManager, SystemAllocator, AddressRange};
|
||||||
use crate::kvm::*;
|
use crate::kvm::*;
|
||||||
|
|
||||||
|
static KERNEL: &[u8] = include_bytes!("../../kernel/ph_linux");
|
||||||
|
static PHINIT: &[u8] = include_bytes!("../../target/release/ph-init");
|
||||||
|
static SOMMELIER: &[u8] = include_bytes!("../../sommelier/sommelier");
|
||||||
|
|
||||||
mod run;
|
mod run;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
mod setup;
|
mod setup;
|
||||||
@ -25,11 +28,8 @@ use self::run::KvmRunArea;
|
|||||||
use self::kernel_cmdline::KernelCmdLine;
|
use self::kernel_cmdline::KernelCmdLine;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
use crate::disk::OpenType;
|
|
||||||
use termios::Termios;
|
use termios::Termios;
|
||||||
use crate::vm::config::RootFS;
|
use crate::devices::SyntheticFS;
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
|
|
||||||
pub struct Vm {
|
pub struct Vm {
|
||||||
_config: VmConfig,
|
_config: VmConfig,
|
||||||
@ -76,61 +76,66 @@ impl Vm {
|
|||||||
Ok(MemoryManager::new(kvm, ram, allocator))
|
Ok(MemoryManager::new(kvm, ram, allocator))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_virtio(config: &VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus) -> Result<()> {
|
fn setup_virtio(config: &mut VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus) -> Result<()> {
|
||||||
devices::VirtioSerial::create(virtio)?;
|
devices::VirtioSerial::create(virtio)?;
|
||||||
devices::VirtioRandom::create(virtio)?;
|
devices::VirtioRandom::create(virtio)?;
|
||||||
devices::VirtioWayland::create(virtio)?;
|
devices::VirtioWayland::create(virtio)?;
|
||||||
let init_path = config.get_init_path()?;
|
devices::VirtioP9::create(virtio, "home", config.homedir(), false, false)?;
|
||||||
devices::VirtioP9::create(virtio, "home", "/home/user", &init_path)?;
|
|
||||||
|
|
||||||
Self::setup_rootfs(config, cmdline, virtio, &init_path)
|
let mut block_root = false;
|
||||||
|
|
||||||
|
for mut disk in config.get_realmfs_images() {
|
||||||
|
disk.open().map_err(ErrorKind::DiskImageOpen)?;
|
||||||
|
devices::VirtioBlock::create(virtio, disk)?;
|
||||||
|
block_root = true;
|
||||||
|
}
|
||||||
|
for mut disk in config.get_raw_disk_images() {
|
||||||
|
disk.open().map_err(ErrorKind::DiskImageOpen)?;
|
||||||
|
devices::VirtioBlock::create(virtio, disk)?;
|
||||||
|
block_root = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if block_root {
|
||||||
|
cmdline.push("phinit.root=/dev/vda");
|
||||||
|
cmdline.push("phinit.rootfstype=ext4");
|
||||||
|
} else {
|
||||||
|
devices::VirtioP9::create(virtio, "9proot", "/", true, false)?;
|
||||||
|
cmdline.push_set_val("phinit.root", "9proot");
|
||||||
|
cmdline.push_set_val("phinit.rootfstype", "9p");
|
||||||
|
cmdline.push_set_val("phinit.rootflags", "trans=virtio");
|
||||||
|
}
|
||||||
|
|
||||||
|
Self::setup_synthetic_bootfs(cmdline, virtio)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_rootfs(config: &VmConfig, cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus, init_path: &Path) -> Result<()> {
|
fn setup_synthetic_bootfs(cmdline: &mut KernelCmdLine, virtio: &mut VirtioBus) -> Result<()> {
|
||||||
match config.rootfs() {
|
let mut s = SyntheticFS::new();
|
||||||
RootFS::SelfRoot => {
|
s.mkdirs(&["/tmp", "/proc", "/sys", "/dev", "/home/user", "/bin", "/etc"]);
|
||||||
devices::VirtioP9::create(virtio, "/dev/root", "/", &init_path)?;
|
|
||||||
notify!("9p root");
|
fs::write("/tmp/ph-init", PHINIT)?;
|
||||||
cmdline.push_set_val("root", "/dev/root");
|
s.add_library_dependencies("/tmp/ph-init")?;
|
||||||
cmdline.push("ro");
|
fs::remove_file("/tmp/ph-init")?;
|
||||||
cmdline.push_set_val("rootfstype", "9p");
|
|
||||||
cmdline.push_set_val("rootflags", "trans=virtio,version=9p2000.L,cache=loose");
|
s.add_memory_file("/usr/bin", "ph-init", 0o755, PHINIT)?;
|
||||||
cmdline.push_set_val("init", "/phinit");
|
s.add_memory_file("/usr/bin", "sommelier", 0o755, SOMMELIER)?;
|
||||||
},
|
|
||||||
RootFS::RealmFSImage(ref path) => {
|
s.add_file("/etc", "ld.so.cache", 0o644, "/etc/ld.so.cache");
|
||||||
let disk = disk::RealmFSImage::open(path, false)
|
devices::VirtioP9::create_with_filesystem(s, virtio, "/dev/root", "/", false)?;
|
||||||
.map_err(ErrorKind::DiskImageOpen)?;
|
cmdline.push_set_val("init", "/usr/bin/ph-init");
|
||||||
devices::VirtioBlock::create(virtio, disk)?;
|
cmdline.push_set_val("root", "/dev/root");
|
||||||
cmdline.push_set_val("root", "/dev/vda");
|
cmdline.push("ro");
|
||||||
cmdline.push("rw");
|
cmdline.push_set_val("rootfstype", "9p");
|
||||||
cmdline.push_set_val("init", "/usr/bin/ph-init");
|
cmdline.push_set_val("rootflags", "trans=virtio");
|
||||||
},
|
|
||||||
RootFS::RawImage(ref path) => {
|
|
||||||
let disk = disk::RawDiskImage::open(path, OpenType::MemoryOverlay).map_err(ErrorKind::DiskImageOpen)?;
|
|
||||||
devices::VirtioBlock::create(virtio, disk)?;
|
|
||||||
cmdline.push_set_val("root", "/dev/vda");
|
|
||||||
cmdline.push("rw");
|
|
||||||
},
|
|
||||||
RootFS::RawOffset(path, offset) => {
|
|
||||||
let disk = disk::RawDiskImage::open_with_offset(path, OpenType::ReadWrite, *offset)
|
|
||||||
.map_err(ErrorKind::DiskImageOpen)?;
|
|
||||||
devices::VirtioBlock::create(virtio, disk)?;
|
|
||||||
cmdline.push_set_val("root", "/dev/vda");
|
|
||||||
cmdline.push("rw");
|
|
||||||
cmdline.push_set_val("init", "/usr/bin/ph-init");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open(config: VmConfig) -> Result<Vm> {
|
pub fn open(mut config: VmConfig) -> Result<Vm> {
|
||||||
let kernel_path = config.get_kernel_path()?;
|
|
||||||
|
|
||||||
let mut memory = Self::create_memory_manager(config.ram_size())?;
|
let mut memory = Self::create_memory_manager(config.ram_size())?;
|
||||||
|
|
||||||
let mut cmdline = KernelCmdLine::new_default();
|
let mut cmdline = KernelCmdLine::new_default();
|
||||||
|
|
||||||
setup::kernel::load_pm_kernel(memory.guest_ram(), &kernel_path, cmdline.address(), cmdline.size())?;
|
setup::kernel::load_pm_kernel(memory.guest_ram(), cmdline.address(), cmdline.size())?;
|
||||||
|
|
||||||
let io_dispatch = IoDispatcher::new();
|
let io_dispatch = IoDispatcher::new();
|
||||||
|
|
||||||
@ -144,13 +149,19 @@ impl Vm {
|
|||||||
} else {
|
} else {
|
||||||
cmdline.push("quiet");
|
cmdline.push("quiet");
|
||||||
}
|
}
|
||||||
|
if config.rootshell() {
|
||||||
|
cmdline.push("phinit.rootshell");
|
||||||
|
}
|
||||||
|
if let Some(realm) = config.realm_name() {
|
||||||
|
cmdline.push_set_val("phinit.realm", realm);
|
||||||
|
}
|
||||||
|
|
||||||
let saved= Termios::from_fd(0)
|
let saved= Termios::from_fd(0)
|
||||||
.map_err(ErrorKind::TerminalTermios)?;
|
.map_err(ErrorKind::TerminalTermios)?;
|
||||||
let termios = Some(saved);
|
let termios = Some(saved);
|
||||||
|
|
||||||
let mut virtio = VirtioBus::new(memory.clone(), io_dispatch.clone(), memory.kvm().clone());
|
let mut virtio = VirtioBus::new(memory.clone(), io_dispatch.clone(), memory.kvm().clone());
|
||||||
Self::setup_virtio(&config, &mut cmdline, &mut virtio)?;
|
Self::setup_virtio(&mut config, &mut cmdline, &mut virtio)?;
|
||||||
|
|
||||||
if config.launch_systemd() {
|
if config.launch_systemd() {
|
||||||
cmdline.push("phinit.run_systemd");
|
cmdline.push("phinit.run_systemd");
|
||||||
@ -191,6 +202,5 @@ impl Vm {
|
|||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
|
|
||||||
use std::path::Path;
|
use std::io::{self, Read, SeekFrom, Seek, Cursor};
|
||||||
use std::fs::{File};
|
|
||||||
use std::io::{self, Read,SeekFrom,Seek};
|
|
||||||
use byteorder::{LittleEndian,ReadBytesExt};
|
use byteorder::{LittleEndian,ReadBytesExt};
|
||||||
|
|
||||||
use crate::memory::{self,GuestRam,KERNEL_ZERO_PAGE};
|
use crate::memory::{self,GuestRam,KERNEL_ZERO_PAGE};
|
||||||
use crate::vm::{Result,Error,ErrorKind};
|
use crate::vm::{Result, Error, ErrorKind, KERNEL};
|
||||||
|
|
||||||
|
|
||||||
// Documentation/x86/boot.txt
|
// Documentation/x86/boot.txt
|
||||||
@ -64,13 +62,13 @@ fn setup_zero_page(memory: &GuestRam, cmdline_addr: u64, cmdline_size: usize) ->
|
|||||||
setup_e820(memory, base)
|
setup_e820(memory, base)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_pm_kernel(memory: &GuestRam, path: &Path, cmdline_addr: u64, cmdline_size: usize) -> Result<()> {
|
pub fn load_pm_kernel(memory: &GuestRam, cmdline_addr: u64, cmdline_size: usize) -> Result<()> {
|
||||||
load_elf_kernel(memory, path).map_err(|_| Error::from(ErrorKind::ReadKernelFailed))?;
|
load_elf_kernel(memory).map_err(|_| Error::from(ErrorKind::ReadKernelFailed))?;
|
||||||
setup_zero_page(memory, cmdline_addr, cmdline_size)
|
setup_zero_page(memory, cmdline_addr, cmdline_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_elf_kernel(memory: &GuestRam, path: &Path) -> io::Result<()> {
|
pub fn load_elf_kernel(memory: &GuestRam) -> io::Result<()> {
|
||||||
let mut f = File::open(&path)?;
|
let mut f = Cursor::new(KERNEL);
|
||||||
f.seek(SeekFrom::Start(32))?;
|
f.seek(SeekFrom::Start(32))?;
|
||||||
let phoff = f.read_u64::<LittleEndian>()?;
|
let phoff = f.read_u64::<LittleEndian>()?;
|
||||||
f.seek(SeekFrom::Current(16))?;
|
f.seek(SeekFrom::Current(16))?;
|
||||||
@ -78,7 +76,7 @@ pub fn load_elf_kernel(memory: &GuestRam, path: &Path) -> io::Result<()> {
|
|||||||
f.seek(SeekFrom::Start(phoff))?;
|
f.seek(SeekFrom::Start(phoff))?;
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
for _ in 0..phnum {
|
for _ in 0..phnum {
|
||||||
let hdr = load_phdr(&f)?;
|
let hdr = load_phdr(&mut f)?;
|
||||||
if hdr.p_type == 1 {
|
if hdr.p_type == 1 {
|
||||||
v.push(hdr);
|
v.push(hdr);
|
||||||
}
|
}
|
||||||
@ -92,7 +90,7 @@ pub fn load_elf_kernel(memory: &GuestRam, path: &Path) -> io::Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_phdr<R: Read+Sized>(mut r: R) -> io::Result<ElfPhdr> {
|
fn load_phdr<R: Read+Sized>(r: &mut R) -> io::Result<ElfPhdr> {
|
||||||
let mut phdr: ElfPhdr = Default::default();
|
let mut phdr: ElfPhdr = Default::default();
|
||||||
phdr.p_type = r.read_u32::<LittleEndian>()?;
|
phdr.p_type = r.read_u32::<LittleEndian>()?;
|
||||||
phdr.p_flags = r.read_u32::<LittleEndian>()?;
|
phdr.p_flags = r.read_u32::<LittleEndian>()?;
|
||||||
|
Loading…
Reference in New Issue
Block a user