Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RISC-V 64 support for RVM #1

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
10 changes: 8 additions & 2 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: CI

on: [push, pull_request]
on: [push, pull_request, workflow_dispatch]

jobs:
check:
Expand Down Expand Up @@ -32,11 +32,17 @@ jobs:
profile: minimal
toolchain: nightly-2021-03-01
components: rust-src
- name: Build
target: riscv64imac-unknown-none-elf
- name: Build x86_64
uses: actions-rs/cargo@v1
with:
command: build
args: --all-features
- name: Build RISC-V 64
uses: actions-rs/cargo@v1
with:
command: build
args: --target riscv64imac-unknown-none-elf --all-features
- name: Build example UEFI
run: cd examples/uefi && make build
- name: Build example KO
Expand Down
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,8 @@ rvm_macros = { path = "./rvm_macros" }

[target.'cfg(target_arch = "x86_64")'.dependencies]
x86 = "0.36"
x86_64 = "0.13.2"
x86_64 = "0.11.7"
raw-cpuid = "9.0"

[target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies]
riscv = { git = "https://github.com/rcore-riscv-hypervisor-dev/riscv.git", rev = "3f5efb1", features = ["inline-asm", "hypervisor"] }
4 changes: 4 additions & 0 deletions rvm_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ use syn::{Abi, Attribute, ItemFn};
const ALLOWED_FN_LIST: &[&str] = &[
"alloc_frame",
"dealloc_frame",
"alloc_frame_x4",
"dealloc_frame_x4",
"phys_to_virt",
"is_host_timer_interrupt",
"is_host_serial_interrupt",
"riscv_check_hypervisor_extension",
"riscv_trap_handler_no_frame",
];

#[proc_macro_attribute]
Expand Down
8 changes: 8 additions & 0 deletions src/arch/aarch64/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#[repr(C)]
#[derive(Debug, Default)]
pub struct VcpuState {
pub x: [u64; 31],
pub sp: u64,
pub cpsr: u64,
pub _padding1: [u8; 4],
}
155 changes: 155 additions & 0 deletions src/arch/riscv/decode.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//! Decode riscv instructions, only for load/store.
//! Note that only general registers are supported. No float registers.
use bit_field::*;
#[derive(Debug, Copy, Clone)]
pub struct MemOp {
pub access_size: u8,
pub is_store: bool,
pub src: u8, // for read.
pub dst: u8, // for write.
pub is_rvc: bool,
pub sign_extension: bool,
}
fn transform_general_reg(r: u8) -> u8 {
if r <= 7 {
return r + 8;
}
unreachable!()
}
enum RVLS {
Load { rd: u8, access_size: u8 },
Store { rs2: u8, access_size: u8 },
}
use RVLS::*;
fn parse_rvc_mem(insn: u16) -> Option<RVLS> {
let r = |hi: usize, lo: usize| insn.get_bits(lo..(hi + 1)) as usize;
if r(1, 0) == 0b10 {
let rd = r(11, 7) as u8;
//let rs1 = rd;
let rs2 = r(6, 2) as u8;

return match r(15, 13) {
0b010 if rd != 0 => Some(Load { rd, access_size: 4 }),
0b011 if rd != 0 => Some(Load { rd, access_size: 8 }),
0b110 => Some(Store {
rs2,
access_size: 4,
}),
0b111 => Some(Store {
rs2,
access_size: 8,
}),
_ => None,
};
}
if r(1, 0) == 0b00 {
//let rs1 = transform_general_reg(r(9,7) as u8);
let rs2 = transform_general_reg(r(4, 2) as u8);
//let rs = rs1;
let rd = rs2;
return match r(15, 13) {
0b010 => Some(Load { rd, access_size: 4 }),
0b011 => Some(Load { rd, access_size: 8 }),
0b110 => Some(Store {
rs2,
access_size: 4,
}),
0b111 => Some(Store {
rs2,
access_size: 8,
}),
_ => None,
};
}
None
}

// Some(Some(op)) for success, Some(None) for please-try-rvi, and None for unknown rvc.
pub fn decode_memory_ops_rvc(insn: u16) -> Option<Option<MemOp>> {
if insn.get_bits(0..2) == 0b00 {
match parse_rvc_mem(insn)? {
Load { rd, access_size } => Some(Some(MemOp {
is_store: false,
access_size,
dst: rd,
is_rvc: true,
src: 0,
sign_extension: true,
})),
Store { rs2, access_size } => Some(Some(MemOp {
is_store: true,
access_size,
src: rs2,
is_rvc: true,
dst: 0,
sign_extension: true,
})),
}
} else {
Some(None)
}
}

pub fn decode_memory_ops_rvi(insn: u32) -> Option<MemOp> {
let opcode = insn.get_bits(0..7);
//let funct = insn.get_bits(12..15);
//let rs1 = insn.get_bits(15..20);
let rd = insn.get_bits(7..12) as u8;
let rs2 = insn.get_bits(20..25) as u8;
let access_size = match insn.get_bits(12..14) {
0b00 => 1,
0b01 => 2,
0b10 => 4,
0b11 => 8,
_ => unreachable!(),
};
if opcode == 0b0000011 {
// load
let sign_extension = !insn.get_bit(14);
return Some(MemOp {
is_store: false,
access_size,
dst: rd,
is_rvc: false,
src: 0,
sign_extension,
});
} else if insn.get_bits(0..7) == 0b0100011 {
if !insn.get_bit(14) {
return Some(MemOp {
is_store: false,
access_size,
src: rs2,
is_rvc: false,
dst: 0,
sign_extension: false,
});
}
}
None
}

pub fn load_half(epc: usize) -> u16 {
(unsafe { riscv::asm::hlvx_hu(epc) }) as u16
}
pub fn load_word(epc: usize) -> u32 {
(load_half(epc) as u32) | ((load_half(epc + 2) as u32) << 16)
}

pub enum Insn {
C(u16),
I(u32),
}
pub use Insn::*;
pub fn read_instruction(epc: usize) -> Option<Insn> {
let insn_16 = load_half(epc);
if insn_16 & 0b11 == 0b00 {
Some(C(insn_16))
} else if insn_16 & 0b11 == 0b11 {
let insn_32 = load_word(epc);
Some(I(insn_32))
} else {
error!("bad instruction: at epc {:x}: {}", epc, insn_16);
None
}
}
Loading