Skip to content

Commit a84235b

Browse files
authored
Merge pull request #95 from sruffell/config-file-for-default-vm
Use config file for default VM
2 parents 51ef7dd + b6fb7ab commit a84235b

File tree

11 files changed

+194
-45
lines changed

11 files changed

+194
-45
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
/target
33
mythril/target
44
mythril/src/blob/bios.bin
5+
mythril/.cargo
56
_boot.img
67
**/*.rs.bk
78
debug.log
89
os.iso
910
_isofiles
1011
scripts/initramfs
11-
scripts/vmlinuz
12+
scripts/vmlinuz

Makefile

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ TEST_IMAGE_REPO=https://github.com/mythril-hypervisor/build
77
TEST_INITRAMFS_URL=$(TEST_IMAGE_REPO)/releases/download/$(BUILD_REPO_TAG)/test-initramfs.img
88
TEST_KERNEL_URL=$(TEST_IMAGE_REPO)/releases/download/$(BUILD_REPO_TAG)/test-bzImage
99

10+
CARGO_BUILD_JOBS?=$(shell grep -c '^processor' /proc/cpuinfo)
11+
KVM_GROUP_ID?=$(shell grep kvm /etc/group | cut -f 3 -d:)
12+
1013
mythril_binary = mythril/target/mythril_target/$(BUILD_TYPE)/mythril
1114
mythril_src = $(shell find mythril* -type f -name '*.rs' -or -name '*.S' -or -name '*.ld' \
1215
-name 'Cargo.toml')
@@ -48,13 +51,16 @@ $(guest_initramfs):
4851
curl -L $(TEST_INITRAMFS_URL) -o $(guest_initramfs)
4952

5053
docker-%:
51-
docker run --privileged -it --rm -w $(CURDIR) -v $(CURDIR):$(CURDIR) \
52-
-u $(shell id -u):$(shell id -g) $(DOCKER_IMAGE) \
53-
/bin/bash -c '$(MAKE) $*'
54+
docker run --privileged -ti --rm -w $(CURDIR) -v $(CURDIR):$(CURDIR) \
55+
-u $(shell id -u):$(shell id -g) \
56+
--group-add=$(KVM_GROUP_ID) \
57+
-e CARGO_HOME=$(CURDIR)/mythril/.cargo \
58+
-e CARGO_BUILD_JOBS=$(CARGO_BUILD_JOBS) \
59+
$(DOCKER_IMAGE) /bin/bash -c '$(MAKE) $*'
5460

5561
$(seabios):
5662
cp scripts/seabios.config seabios/.config
57-
make -C seabios
63+
make -j $(CARGO_BUILD_JOBS) -C seabios
5864

5965
$(seabios_blob): $(seabios)
6066
cp $(seabios) $(seabios_blob)

mythril/Cargo.lock

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mythril/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ multiboot = "0.3.0"
2323
multiboot2 = "0.9.0"
2424
raw-cpuid = "8.1.1"
2525
rlibc = "1.0.0"
26+
serde = {version = "^1", default-features = false, features = ["alloc", "derive"] }
27+
serde_json = {version = "^1", default-features = false, features = ["alloc"] }
2628
spin = "0.5"
2729
ux = { version = "0.1.3", default-features = false }
2830
managed = { version = "0.8.0", features = ["map", "alloc"], default-features = false }

mythril/src/config.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#![deny(missing_docs)]
2+
3+
use crate::percore;
4+
5+
use alloc::string::String;
6+
use core::fmt;
7+
use serde::de::{self, Visitor};
8+
use serde::export::Vec;
9+
use serde::{Deserialize, Deserializer};
10+
11+
/// A description of a single virtual machine configuration
12+
#[derive(Deserialize, Debug)]
13+
pub struct UserVmConfig {
14+
/// Memory in MB available to the virtual machine
15+
pub memory: u64,
16+
17+
/// The multiboot identifier for the kernel this virtual machine will use
18+
pub kernel: String,
19+
20+
/// The multiboot identifier for the initramfs this virtual machine will use
21+
pub initramfs: String,
22+
23+
/// The kernel commandline for this virtual machine
24+
pub cmdline: String,
25+
26+
/// A list of core ID's (starting from 0) used by this machine
27+
pub cpus: Vec<percore::CoreId>,
28+
}
29+
30+
/// The top level Mythril configuration
31+
#[derive(Deserialize, Debug)]
32+
pub struct UserConfig {
33+
/// Version number for this configuration
34+
pub version: u64,
35+
36+
/// A list of virtual machine configurations
37+
pub vms: Vec<UserVmConfig>,
38+
}
39+
40+
struct CoreIdVisitor;
41+
42+
impl<'de> Visitor<'de> for CoreIdVisitor {
43+
type Value = percore::CoreId;
44+
45+
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
46+
write!(formatter, "a core id")
47+
}
48+
49+
fn visit_u64<E>(self, value: u64) -> core::result::Result<Self::Value, E>
50+
where
51+
E: de::Error,
52+
{
53+
Ok((value as u32).into())
54+
}
55+
}
56+
57+
impl<'de> Deserialize<'de> for percore::CoreId {
58+
fn deserialize<D>(
59+
deserializer: D,
60+
) -> core::result::Result<percore::CoreId, D::Error>
61+
where
62+
D: Deserializer<'de>,
63+
{
64+
deserializer.deserialize_u64(CoreIdVisitor)
65+
}
66+
}

mythril/src/ioapic.rs

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -616,26 +616,26 @@ impl TryFrom<u64> for IoRedTblEntry {
616616
}
617617
}
618618

619-
impl Into<u64> for IoRedTblEntry {
620-
fn into(self) -> u64 {
621-
let mut bits = self.vector as u64;
619+
impl From<IoRedTblEntry> for u64 {
620+
fn from(entry: IoRedTblEntry) -> u64 {
621+
let mut bits = entry.vector as u64;
622622

623-
bits |= (self.delivery_mode as u64) << 8;
624-
bits |= (self.destination_mode as u64) << 11;
625-
bits |= (self.delivery_status as u64) << 12;
626-
bits |= (self.pin_polarity as u64) << 13;
623+
bits |= (entry.delivery_mode as u64) << 8;
624+
bits |= (entry.destination_mode as u64) << 11;
625+
bits |= (entry.delivery_status as u64) << 12;
626+
bits |= (entry.pin_polarity as u64) << 13;
627627

628-
if self.remote_irr {
628+
if entry.remote_irr {
629629
bits |= 1 << 14;
630630
}
631631

632-
bits |= (self.trigger_mode as u64) << 15;
632+
bits |= (entry.trigger_mode as u64) << 15;
633633

634-
if self.interrupt_mask {
634+
if entry.interrupt_mask {
635635
bits |= 1 << 16;
636636
}
637637

638-
bits |= (self.destination as u64) << 56;
638+
bits |= (entry.destination as u64) << 56;
639639
bits
640640
}
641641
}
@@ -657,16 +657,19 @@ mod test {
657657
#[test]
658658
fn ioredtblentry_roundtrip() {
659659
let all_edge = IOREDTBL_KNOWN_BITS_MASK ^ (1 << 15);
660-
assert_eq!(all_edge, IoRedTblEntry::try_from(all_edge).unwrap().into());
660+
assert_eq!(
661+
all_edge,
662+
u64::from(IoRedTblEntry::try_from(all_edge).unwrap())
663+
);
661664

662665
let all_level = IOREDTBL_KNOWN_BITS_MASK ^ 0x700;
663666
assert_eq!(
664667
all_level,
665-
IoRedTblEntry::try_from(all_level).unwrap().into()
668+
u64::from(IoRedTblEntry::try_from(all_level).unwrap())
666669
);
667670

668671
let none = 0x00000000_00000000;
669-
assert_eq!(none, IoRedTblEntry::try_from(none).unwrap().into());
672+
assert_eq!(none, u64::from(IoRedTblEntry::try_from(none).unwrap()));
670673
}
671674

672675
#[test]

mythril/src/kmain.rs

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::acpi;
22
use crate::ap;
33
use crate::apic;
44
use crate::boot_info::BootInfo;
5+
use crate::config;
56
use crate::interrupt;
67
use crate::ioapic;
78
use crate::linux;
@@ -33,10 +34,9 @@ extern "C" {
3334
static IS_MULTIBOOT2_BOOT: u8;
3435
}
3536

36-
// Temporary helper function to create a vm for a single core
37-
fn default_vm(
38-
core: percore::CoreId,
39-
mem: u64,
37+
// Temporary helper function to create a vm
38+
fn build_vm(
39+
cfg: &config::UserVmConfig,
4040
info: &BootInfo,
4141
add_uart: bool,
4242
) -> Arc<RwLock<vm::VirtualMachine>> {
@@ -52,8 +52,11 @@ fn default_vm(
5252
}
5353
};
5454

55-
let mut config =
56-
vm::VirtualMachineConfig::new(vec![core], mem, physical_config);
55+
let mut config = vm::VirtualMachineConfig::new(
56+
cfg.cpus.clone(),
57+
cfg.memory,
58+
physical_config,
59+
);
5760

5861
let mut acpi = acpi::rsdp::RSDPBuilder::<[_; 1024]>::new(
5962
ManagedMap::Owned(BTreeMap::new()),
@@ -112,7 +115,7 @@ fn default_vm(
112115
.register_device(virtdev::pos::ProgrammableOptionSelect::new())
113116
.unwrap();
114117
device_map
115-
.register_device(virtdev::rtc::CmosRtc::new(mem))
118+
.register_device(virtdev::rtc::CmosRtc::new(cfg.memory))
116119
.unwrap();
117120

118121
//TODO: this should actually be per-vcpu
@@ -141,24 +144,18 @@ fn default_vm(
141144
.expect("Failed to build ACPI tables");
142145

143146
linux::load_linux(
144-
"kernel",
145-
"initramfs",
146-
core::concat!(
147-
"rodata=0 nopti disableapic ",
148-
"earlyprintk=serial,0x3f8,115200 ",
149-
"console=ttyS0 debug nokaslr noapic mitigations=off ",
150-
"root=/dev/ram0 rdinit=/bin/sh\0"
151-
)
152-
.as_bytes(),
153-
mem,
147+
&cfg.kernel,
148+
&cfg.initramfs,
149+
cfg.cmdline.as_bytes(),
150+
cfg.memory,
154151
&mut fw_cfg_builder,
155152
info,
156153
)
157154
.unwrap();
158155

159156
device_map.register_device(fw_cfg_builder.build()).unwrap();
160157

161-
vm::VirtualMachine::new(core.raw, config, info)
158+
vm::VirtualMachine::new(cfg.cpus[0].raw, config, info)
162159
.expect("Failed to create vm")
163160
}
164161

@@ -254,21 +251,28 @@ unsafe fn kmain(mut boot_info: BootInfo) -> ! {
254251

255252
let mut builder = vm::VirtualMachineBuilder::new();
256253

257-
for apic_id in apic_ids.iter() {
254+
let raw_cfg = boot_info
255+
.find_module("mythril.cfg")
256+
.expect("Failed to find 'mythril.cfg' in boot information")
257+
.data();
258+
259+
let mythril_cfg: config::UserConfig = serde_json::from_slice(&raw_cfg)
260+
.expect("Failed to parse 'mythril.cfg'");
261+
262+
debug!("mythril.cfg: {:?}", mythril_cfg);
263+
264+
for (num, vm) in mythril_cfg.vms.into_iter().enumerate() {
258265
builder
259-
.insert_machine(default_vm(
260-
percore::CoreId::from(apic_id.raw),
261-
256,
262-
&boot_info,
263-
apic_id.is_bsp(),
264-
))
266+
.insert_machine(build_vm(&vm, &boot_info, num == 0))
265267
.expect("Failed to insert new vm");
266268
}
267269

268270
vm::init_virtual_machines(builder.finalize());
269271

270272
debug!("AP_STARTUP address: 0x{:x}", AP_STARTUP_ADDR);
271273

274+
//TODO(alschwalm): Only the cores that are actually associated with a VM
275+
// should be started
272276
for (idx, apic_id) in apic_ids.into_iter().enumerate() {
273277
if apic_id == local_apic.id() {
274278
continue;

mythril/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ pub mod ap;
2828
/// Support for the local APIC.
2929
pub mod apic;
3030
pub mod boot_info;
31-
31+
/// User configuration format
32+
pub mod config;
3233
pub mod emulate;
3334
pub mod error;
3435
pub mod global_alloc;

scripts/grub.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ menuentry 'Mythril' {
55
echo 'Loading Mythril'
66
acpi -2
77
multiboot2 /boot/mythril.bin
8+
module2 /boot/mythril.cfg mythril.cfg
89
module2 /boot/vmlinuz kernel
910
module2 /boot/initramfs initramfs
1011
}

scripts/mythril-run.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ cp scripts/grub.cfg _isofiles/boot/grub/
1616
cp scripts/vmlinuz _isofiles/boot/vmlinuz
1717
cp scripts/initramfs _isofiles/boot/initramfs
1818
cp "$1" _isofiles/boot/mythril.bin
19+
cp scripts/mythril.cfg _isofiles/boot/mythril.cfg
1920

2021
# Explicitly avoid using grub efi for now
2122
grub-mkrescue -d /usr/lib/grub/i386-pc -o os.iso _isofiles

0 commit comments

Comments
 (0)