Skip to content

Commit

Permalink
Version 0.3.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Manami Mori authored and fukai-t committed Mar 7, 2022
1 parent 6a02574 commit 19474a8
Show file tree
Hide file tree
Showing 23 changed files with 775 additions and 47 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on:
branches: [ main ]
pull_request:
branches: [ main ]
schedule:
- cron: '15 4 */1 * *'

env:
CARGO_TERM_COLOR: always
Expand Down
44 changes: 44 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Contributing
We welcome your issue reports and pull requests.
The following describes issues and pull requests for contributing MilvusVisor.

## Issues
We will receive the following kind of issues.

- Bug report
- Documentation error

You also feel free to create issues about feature requests and discuss them. However, we may not be able to respond to them because of our limited development resources.


In creating issues about a bug, please write the following information.

- Machine information that you tested (Product name of the machine, and CPU, and devices)
- The way to reproduce the problem.

### Pull requests

We will receive the following kind of PRs.

- New feature
- Bugfix
- New documentation
- Fix documentation (typo, better sentences)


In creating PR of a new feature, please write the following information.

- Summary of the new feature
- Machine information that you tested (Product name of the machine, and CPU, and devices)
- The way to test the new feature


In creating PR for a bugfix, please write the following information.

- Summary of the bug fix
- Machine information that you tested (Product name of the machine, and CPU, and devices)
- The way to reproduce the problem without the bugfix or the link to the original issue
- The way to test the bugfix

Note that we will assume that your uploaded code is under the MIT license.
If you want to provide your code under other license, please ask us whether there is license problem or not on an issue before you create a PR.
98 changes: 83 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,111 @@
# How to build the hypervisor
# MilvusVisor
MilvusVisor is a thin hypervisor that runs on aarch64 CPUs.

## By Rust toolchain
(TBD)
The features of the MilvusVisor are the following.

- (Theoretically) Smaller footprint and overhead than typical VMM (e.g. QEMU/KVM, Xen)
- Support running only one guest OS simultaneously for keeping it simple and thin
- Written in Rust

## By docker
### Requirements

MilvusVisor allows providing functions OS-independently without the overhead of device virtualization.
We are currently developing MilvusVisor as a research activity to achieve HPC environments that provide root privilege to the users without virtualization overhead.

## Functions

Currently, MilvusVisor provides the following function.

- Protecting non-volatile data in devices from guest OS (e.g. Firmware, MAC address)
- Supported device: Intel I210
- Protecting MilvusVisor itself against DMA attack
- Using SMMUv3 Stage 2 Page Translation to protect from DMA attack

## Tested machines

We have tested MilvusVisor on the following machines.

- FX700
- AML-S805X-AC
- QEMU

The following table shows which feature worked on which machines.

| Test items \\ Machine | FX700 | AML | QEMU |
|:-------------------------------------------------|:-----:|:---:|:----:|
| Booting Linux on MilvusVisor (Multi-core) | o | o | o |
| Protecting non-volatile data of Intel I210 | o | - | - |
| Protecting MilvusVisor itself against DMA attack | o | - | - |


## How to build the hypervisor

### By Rust toolchain

#### Requirements
- `rustup` command-line tool (you can install from https://rustup.rs/)

#### Steps (commands list)
```
rustup component add rust-src
cd path/to/repo-root/src
make
```

Next (How to run the hypervisor)[#How to run the hypervisor]

### By docker
#### Requirements
- Docker (Tested by `Docker version 20.10.8, build 3967b7d28e`)
- I tested by non-root users (See [this](https://docs.docker.com/engine/install/linux-postinstall/#manage-docker-as-a-non-root-user) to run docker command by non-root user)

### Steps (commands list)
#### Steps (commands list)

```bash
cd path/to/repo-root/src
./build_docker_image.sh #Build docker image to build
./build_hypervisor_by_docker.sh #Build the hypervisor by the docker image
```
More detail, please see the scripts.
For more detail, please see the scripts.

# How to run the hypervisor
## On QEMU
First, please install QEMU that support to emulate `QEMU 2.12 ARM Virtual Machine`, `cortex-a53` CPU.
## How to run the hypervisor
### On QEMU
First, please install QEMU that supports emulating `QEMU ARM Virtual Machine`, `a64fx` CPU.
Then, run the following command to run the built hypervisor.

```bash
cd path/to/repo-root/src
make QEMU_EFI=/usr/share/qemu-efi/QEMU_EFI.fd run #Please set the path of your QEMU_EFI.fd to QEMU_EFI
```

## On a physical machine from an USB memory stick
### Requirement
- Prepare a USB memory which has an EFI (FAT) partition that has `/EFI/BOOT/` directory. Please confirm that there is no important file in the partition.
### On a physical machine from a USB memory stick
#### Requirement
- Prepare a USB memory that has an EFI (FAT) partition that has `/EFI/BOOT/` directory. Please confirm that there is no important file in the partition.
- Prepare a physical machine that has ARMv8-A or later, and UEFI firmware.

### Steps
#### Steps
1. Attach your USB memory stick to the development machine which built the hypervisor binary.
2. Identify the EFI partition (in the following description, `/dev/sdX1` is the EFI partition).
3. Run `sudo make DEVICE=/dev/sdX1 write` to copy the binary.
!! Please be carefully not to specifying a wrong partition as `DEVICE` because the script mount/unmount the partition and copy the binary file with root privilege.!!
!! Please be careful not to specify a wrong partition as `DEVICE` because the script mount/unmount the partition and copies the binary file with root privilege.!!
4. Detach the USB memory from the development machine, and attach it to the physical machine to run the hypervisor.
5. Boot the physical machine with UEFI, and specify `BOOTAA64.EFI` in the EFI partition as the EFI application to boot.

## How to generate the documentation
You can generate the document by `cargo doc` in each cargo project directory.

If you want to see bootloader's document, please run the following command.

```bash
cd path/to/repo-root/src/hypervisor_bootloader
cargo doc --open # Browser will open
```

If you want to see kernel's document, please run the following command.

```bash
cd path/to/repo-root/src/hypervisor_kernel
cargo doc --open # Browser will open
```

## Acknowledgment
This work was supported by JSPS KAKENHI Grant Number 21K17727.
4 changes: 2 additions & 2 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ fmt:
$(CD) $(KERNEL) && $(CARGO) fmt

run: all
$(QEMU) -m 1G -cpu cortex-a53 -machine virt-2.12,virtualization=on -smp 4 -nographic -bios $(QEMU_EFI) -drive file=fat:rw:bin/,format=raw,media=disk
$(QEMU) -m 1G -cpu a64fx -machine virt,virtualization=on,iommu=smmuv3 -smp 4 -nographic -bios $(QEMU_EFI) -drive file=fat:rw:bin/,format=raw,media=disk

debug: all
$(QEMU) -m 1G -cpu cortex-a53 -machine virt-2.12,virtualization=on -smp 4 -monitor stdio -bios $(QEMU_EFI) -drive file=fat:rw:bin/,format=raw,media=disk
$(QEMU) -m 1G -cpu a64fx -machine virt,virtualization=on,iommu=smmuv3 -smp 4 -monitor stdio -bios $(QEMU_EFI) -drive file=fat:rw:bin/,format=raw,media=disk

write:
$(MOUNT) $(DEVICE) /mnt
Expand Down
1 change: 1 addition & 0 deletions src/common/src/acpi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//!
//! Supported ACPI Version 6.4
pub mod iort;
pub mod madt;

const RSDP_SIGNATURE: [u8; 8] = *b"RSD PTR ";
Expand Down
109 changes: 109 additions & 0 deletions src/common/src/acpi/iort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (c) 2022 RIKEN
// All rights reserved.
//
// This software is released under the MIT License.
// http://opensource.org/licenses/mit-license.php

//!
//! I/O Remapping Table
//!
const SMMU_V3_NODE_TYPE: u8 = 0x04;

#[repr(C, packed)]
pub struct IORT {
signature: [u8; 4],
length: u32,
revision: u8,
checksum: u8,
oem_id: [u8; 6],
oem_table_id: [u8; 8],
oem_revision: u32,
creator_id: [u8; 4],
creator_revision: u32,
number_of_iort_nodes: u32,
offset_to_array_of_iort_nodes: u32,
reserved: u32,
}

#[repr(C, packed)]
pub struct SmmuV3Node {
s_type: u8,
length: u16,
revision: u8,
id: u32,
pub number_of_id_mappings: u32,
reference_to_id_array: u32,
pub base_address: u64,
flag: u32,
reserved: u32,
vatos_address: u64,
model: u32,
event: u32,
pri: u32,
gerr: u32,
sync: u32,
proximity_domain: u32,
device_id_mapping_index: u32,
}

pub struct IdMappingIter {
p: usize,
n: u32,
}

#[derive(Clone)]
pub struct IdMapping {
pub input_base: u32,
pub number_of_ids: u32,
pub output_base: u32,
pub output_reference: u32,
pub flags: u32,
}

impl IORT {
pub const SIGNATURE: [u8; 4] = *b"IORT";

pub fn get_smmu_v3_information(&self) -> Option<&SmmuV3Node> {
let mut node_address =
self as *const Self as usize + self.offset_to_array_of_iort_nodes as usize;
let num_of_entries = self.number_of_iort_nodes;
for _ in 0..num_of_entries {
if unsafe { *(node_address as *const u8) } == SMMU_V3_NODE_TYPE {
return Some(unsafe { &*(node_address as *const SmmuV3Node) });
}
node_address += unsafe { *((node_address + 1) as *const u16) } as usize;
}
return None;
}
}

impl SmmuV3Node {
pub fn get_array_of_id_mappings(&self) -> IdMappingIter {
IdMappingIter {
p: self as *const _ as usize + self.reference_to_id_array as usize,
n: self.number_of_id_mappings,
}
}
}

impl Iterator for IdMappingIter {
type Item = IdMapping;

fn next(&mut self) -> Option<Self::Item> {
if self.n == 0 {
None
} else {
let a = self.p;
self.n -= 1;
self.p += core::mem::size_of::<Self::Item>();
Some(unsafe { &*(a as *const Self::Item) }.clone())
}
}
}

impl IdMapping {
pub const fn is_single_map(&self) -> bool {
(self.flags & 1) != 0
}
}
1 change: 1 addition & 0 deletions src/common/src/cpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub const HCR_EL2_VM: u64 = 1 << 0;
pub const VTCR_EL2_RES1: u64 = 1 << 31;
pub const VTCR_EL2_HWU_BITS_OFFSET: u64 = 25;
pub const VTCR_EL2_PS_BITS_OFFSET: u64 = 16;
pub const VTCR_EL2_PS: u64 = 0b111 << VTCR_EL2_PS_BITS_OFFSET;
pub const VTCR_EL2_TG0_BITS_OFFSET: u64 = 14;
pub const VTCR_EL2_SH0_BITS_OFFSET: u64 = 12;
pub const VTCR_EL2_ORG0_BITS_OFFSET: u64 = 10;
Expand Down
3 changes: 3 additions & 0 deletions src/common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod acpi;
pub mod cpu;
pub mod paging;
pub mod serial_port;
pub mod smmu;

use crate::serial_port::SerialPortInfo;

Expand Down Expand Up @@ -53,7 +54,9 @@ pub struct EcamInfo {
/// For communicating about system registers between hypervisor_bootloader and hypervisor_kernel
pub struct SystemInformation {
pub vbar_el2: u64,
pub acpi_rsdp_address: Option<usize>,
pub memory_pool: &'static ([MaybeUninit<usize>; ALLOC_SIZE / PAGE_SIZE], usize),
pub serial_port: Option<SerialPortInfo>,
pub ecam_info: Option<EcamInfo>,
pub smmu_v3_base_address: Option<usize>,
}
7 changes: 7 additions & 0 deletions src/common/src/paging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@ const STAGE_2_PAGE_ENTRY_ATTRIBUTE: u64 =
0b11 << 8 /* SH bits (Inner sharable) */|
0b1111 << 2 /* MemAttr(Write-back) */;

#[derive(Copy, Clone, Eq, PartialEq)]
pub enum Shareability {
NonShareable,
OuterShareable,
InterShareable,
}

#[derive(Copy, Clone)]
pub struct TTBR(u64); /* Translation Table Base Register */

Expand Down
Loading

0 comments on commit 19474a8

Please sign in to comment.