Skip to content

Commit

Permalink
Initializes AArch64 supports on Linux (#997)
Browse files Browse the repository at this point in the history
  • Loading branch information
ultimaweapon authored Sep 24, 2024
1 parent 8d11ba0 commit 80c2b3a
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 48 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ if(WIN32)
else()
if(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "x86_64")
set(KERNEL_TARGET x86_64-unknown-none)
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64")
elseif(${CMAKE_SYSTEM_PROCESSOR} STREQUAL "arm64" OR ${CMAKE_SYSTEM_PROCESSOR} STREQUAL "aarch64")
# Pre-compiled core crate for aarch64-unknown-none-softfloat does not support
# Position-Independent Executable so we need nightly toolchain for build-std feature to
# re-build core crate to support Position-Independent Executable.
Expand Down
67 changes: 67 additions & 0 deletions src/core/src/vmm/hv/linux/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use crate::vmm::hv::{CpuStates, Pstate, Sctlr, Tcr};
use std::os::fd::OwnedFd;
use thiserror::Error;

/// Implementation of [`Cpu::States`] for KVM.
pub struct KvmStates<'a> {
cpu: &'a mut OwnedFd,
}

impl<'a> KvmStates<'a> {
pub fn from_cpu(cpu: &'a mut OwnedFd) -> Result<Self, StatesError> {
Ok(KvmStates { cpu })
}
}

impl<'a> CpuStates for KvmStates<'a> {
type Err = StatesError;

fn set_pstate(&mut self, v: Pstate) {
todo!()
}

fn set_sctlr(&mut self, v: Sctlr) {
todo!()
}

fn set_mair_el1(&mut self, attrs: u64) {
todo!()
}

fn set_tcr(&mut self, v: Tcr) {
todo!()
}

fn set_ttbr0_el1(&mut self, baddr: usize) {
todo!()
}

fn set_ttbr1_el1(&mut self, baddr: usize) {
todo!()
}

fn set_sp_el1(&mut self, v: usize) {
todo!()
}

fn set_pc(&mut self, v: usize) {
todo!()
}

fn set_x0(&mut self, v: usize) {
todo!()
}

fn set_x1(&mut self, v: usize) {
todo!()
}

fn commit(self) -> Result<(), Self::Err> {
todo!()
}
}

/// Implementation of [`CpuStates::Err`].
#[derive(Debug, Error)]
pub enum StatesError {}
24 changes: 23 additions & 1 deletion src/core/src/vmm/hv/linux/cpu.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use super::arch::{KvmStates, StatesError};
use super::ffi::{kvm_run, kvm_translate, KvmTranslation};
use super::ffi::kvm_run;
use super::run::KvmRun;
use crate::vmm::hv::{Cpu, CpuExit, CpuIo, IoBuf};
use libc::munmap;
Expand Down Expand Up @@ -101,6 +101,12 @@ impl<'a, 'b> CpuIo for KvmIo<'a, 'b> {
}
}

#[cfg(target_arch = "aarch64")]
fn translate(&self, vaddr: usize) -> Result<usize, Box<dyn Error>> {
todo!()
}

#[cfg(target_arch = "x86_64")]
fn translate(&self, vaddr: usize) -> Result<usize, Box<dyn Error>> {
let mut data = KvmTranslation {
linear_address: vaddr,
Expand All @@ -117,3 +123,19 @@ impl<'a, 'b> CpuIo for KvmIo<'a, 'b> {
}
}
}

#[cfg(target_arch = "x86_64")]
#[repr(C)]
struct KvmTranslation {
linear_address: usize,
physical_address: usize,
valid: u8,
writeable: u8,
usermode: u8,
pad: [u8; 5],
}

extern "C" {
#[cfg(target_arch = "x86_64")]
fn kvm_translate(vcpu: std::ffi::c_int, arg: *mut KvmTranslation) -> std::ffi::c_int;
}
12 changes: 1 addition & 11 deletions src/core/src/vmm/hv/linux/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::ffi::{c_int, c_void};

extern "C" {
pub fn kvm_check_version(kvm: c_int, compat: *mut bool) -> c_int;
pub fn kvm_check_extension(fd: c_int, id: c_int) -> bool;
pub fn kvm_max_vcpus(kvm: c_int, max: *mut usize) -> c_int;
pub fn kvm_create_vm(kvm: c_int, fd: *mut c_int) -> c_int;
pub fn kvm_get_vcpu_mmap_size(kvm: c_int) -> c_int;
Expand All @@ -16,15 +17,4 @@ extern "C" {
pub fn kvm_create_vcpu(vm: c_int, id: u32, fd: *mut c_int) -> c_int;

pub fn kvm_run(vcpu: c_int) -> c_int;
pub fn kvm_translate(vcpu: c_int, arg: *mut KvmTranslation) -> c_int;
}

#[repr(C)]
pub struct KvmTranslation {
pub linear_address: usize,
pub physical_address: usize,
pub valid: u8,
pub writeable: u8,
pub usermode: u8,
pub pad: [u8; 5],
}
60 changes: 57 additions & 3 deletions src/core/src/vmm/hv/linux/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
use self::cpu::KvmCpu;
use self::ffi::{
kvm_check_version, kvm_create_vcpu, kvm_create_vm, kvm_get_vcpu_mmap_size, kvm_max_vcpus,
kvm_set_user_memory_region,
kvm_check_extension, kvm_check_version, kvm_create_vcpu, kvm_create_vm, kvm_get_vcpu_mmap_size,
kvm_max_vcpus, kvm_set_user_memory_region,
};
use super::{CpuFeats, Hypervisor};
use crate::vmm::ram::Ram;
Expand All @@ -12,11 +12,11 @@ use std::os::fd::{AsRawFd, FromRawFd, OwnedFd};
use std::ptr::null_mut;
use thiserror::Error;

#[cfg_attr(target_arch = "aarch64", path = "aarch64.rs")]
#[cfg_attr(target_arch = "x86_64", path = "x86_64.rs")]
mod arch;
mod cpu;
mod ffi;
mod regs;
mod run;

pub fn new(cpu: usize, ram: Ram) -> Result<impl Hypervisor, VmmError> {
Expand Down Expand Up @@ -55,6 +55,12 @@ pub fn new(cpu: usize, ram: Ram) -> Result<impl Hypervisor, VmmError> {
return Err(VmmError::MaxCpuTooLow);
}

// Check KVM_CAP_ONE_REG. KVM_SET_ONE_REG and KVM_GET_ONE_REG are the only API that support all
// architectures.
if unsafe { !kvm_check_extension(kvm.as_raw_fd(), 70) } {
return Err(VmmError::NoKvmOneReg);
}

// Get size of CPU context.
let vcpu_mmap_size = match unsafe { kvm_get_vcpu_mmap_size(kvm.as_raw_fd()) } {
size @ 0.. => size as usize,
Expand Down Expand Up @@ -103,6 +109,54 @@ impl Hypervisor for Kvm {
type Cpu<'a> = KvmCpu<'a>;
type CpuErr = KvmCpuError;

#[cfg(target_arch = "aarch64")]
fn cpu_features(&mut self) -> Result<CpuFeats, Self::CpuErr> {
// See https://www.kernel.org/doc/html/latest/arch/arm64/cpu-feature-registers.html for the
// reason why we can access *_EL1 registers from a user space.
use crate::vmm::hv::{Mmfr0, Mmfr1, Mmfr2};
use std::arch::asm;

// ID_AA64MMFR0_EL1.
let mut mmfr0;

unsafe {
asm!(
"mrs {v}, ID_AA64MMFR0_EL1",
v = out(reg) mmfr0,
options(pure, nomem, preserves_flags, nostack)
)
};

// ID_AA64MMFR1_EL1.
let mut mmfr1;

unsafe {
asm!(
"mrs {v}, ID_AA64MMFR1_EL1",
v = out(reg) mmfr1,
options(pure, nomem, preserves_flags, nostack)
)
};

// ID_AA64MMFR2_EL1.
let mut mmfr2;

unsafe {
asm!(
"mrs {v}, ID_AA64MMFR2_EL1",
v = out(reg) mmfr2,
options(pure, nomem, preserves_flags, nostack)
)
};

Ok(CpuFeats {
mmfr0: Mmfr0::from_bits(mmfr0),
mmfr1: Mmfr1::from_bits(mmfr1),
mmfr2: Mmfr2::from_bits(mmfr2),
})
}

#[cfg(target_arch = "x86_64")]
fn cpu_features(&mut self) -> Result<CpuFeats, Self::CpuErr> {
Ok(CpuFeats {})
}
Expand Down
32 changes: 0 additions & 32 deletions src/core/src/vmm/hv/linux/regs.rs

This file was deleted.

4 changes: 4 additions & 0 deletions src/core/src/vmm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -698,6 +698,10 @@ enum VmmError {
#[error("unexpected KVM version")]
KvmVersionMismatched,

#[cfg(target_os = "linux")]
#[error("your OS does not support KVM_CAP_ONE_REG")]
NoKvmOneReg,

#[cfg(target_os = "linux")]
#[error("couldn't create a VM")]
CreateVmFailed(#[source] std::io::Error),
Expand Down
9 changes: 9 additions & 0 deletions src/kvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ extern "C" int kvm_check_version(int kvm, bool *compat)
return 0;
}

extern "C" bool kvm_check_extension(int fd, int id)
{
return ioctl(fd, KVM_CHECK_EXTENSION, id) > 0;
}

extern "C" int kvm_max_vcpus(int kvm, size_t *max)
{
auto num = ioctl(kvm, KVM_CHECK_EXTENSION, KVM_CAP_MAX_VCPUS);
Expand Down Expand Up @@ -91,6 +96,7 @@ extern "C" int kvm_run(int vcpu)
return ioctl(vcpu, KVM_RUN, 0);
}

#ifndef __aarch64__
extern "C" int kvm_get_regs(int vcpu, kvm_regs *regs)
{
return ioctl(vcpu, KVM_GET_REGS, regs);
Expand All @@ -100,7 +106,9 @@ extern "C" int kvm_set_regs(int vcpu, const kvm_regs *regs)
{
return ioctl(vcpu, KVM_SET_REGS, regs);
}
#endif

#ifdef __x86_64__
extern "C" int kvm_get_sregs(int vcpu, kvm_sregs *regs)
{
return ioctl(vcpu, KVM_GET_SREGS, regs);
Expand All @@ -114,3 +122,4 @@ extern "C" int kvm_set_sregs(int vcpu, const kvm_sregs *regs)
extern "C" int kvm_translate(int vcpu, kvm_translation *arg) {
return ioctl(vcpu, KVM_TRANSLATE, arg);
}
#endif

0 comments on commit 80c2b3a

Please sign in to comment.