12df8d2faSRuoqing He // Copyright © 2024 Institute of Software, CAS. All rights reserved.
22df8d2faSRuoqing He //
32df8d2faSRuoqing He // SPDX-License-Identifier: Apache-2.0
42df8d2faSRuoqing He
5*c5774685SRuoqing He pub mod aia;
6*c5774685SRuoqing He
72df8d2faSRuoqing He use kvm_bindings::{
82df8d2faSRuoqing He kvm_mp_state, kvm_one_reg, kvm_riscv_core, KVM_REG_RISCV_CORE, KVM_REG_RISCV_TYPE_MASK,
92df8d2faSRuoqing He KVM_REG_SIZE_MASK, KVM_REG_SIZE_U64,
102df8d2faSRuoqing He };
112df8d2faSRuoqing He pub use kvm_ioctls::{Cap, Kvm};
122df8d2faSRuoqing He use serde::{Deserialize, Serialize};
132df8d2faSRuoqing He
142df8d2faSRuoqing He use crate::kvm::{KvmError, KvmResult};
152df8d2faSRuoqing He
162df8d2faSRuoqing He // This macro gets the offset of a structure (i.e `str`) member (i.e `field`) without having
172df8d2faSRuoqing He // an instance of that structure.
182df8d2faSRuoqing He #[macro_export]
192df8d2faSRuoqing He macro_rules! _offset_of {
202df8d2faSRuoqing He ($str:ty, $field:ident) => {{
212df8d2faSRuoqing He let tmp: std::mem::MaybeUninit<$str> = std::mem::MaybeUninit::uninit();
222df8d2faSRuoqing He let base = tmp.as_ptr();
232df8d2faSRuoqing He
242df8d2faSRuoqing He // Avoid warnings when nesting `unsafe` blocks.
252df8d2faSRuoqing He #[allow(unused_unsafe)]
262df8d2faSRuoqing He // SAFETY: The pointer is valid and aligned, just not initialised. Using `addr_of` ensures
272df8d2faSRuoqing He // that we don't actually read from `base` (which would be UB) nor create an intermediate
282df8d2faSRuoqing He // reference.
292df8d2faSRuoqing He let member = unsafe { core::ptr::addr_of!((*base).$field) } as *const u8;
302df8d2faSRuoqing He
312df8d2faSRuoqing He // Avoid warnings when nesting `unsafe` blocks.
322df8d2faSRuoqing He #[allow(unused_unsafe)]
332df8d2faSRuoqing He // SAFETY: The two pointers are within the same allocated object `tmp`. All requirements
342df8d2faSRuoqing He // from offset_from are upheld.
352df8d2faSRuoqing He unsafe {
362df8d2faSRuoqing He member.offset_from(base as *const u8) as usize
372df8d2faSRuoqing He }
382df8d2faSRuoqing He }};
392df8d2faSRuoqing He }
402df8d2faSRuoqing He
412df8d2faSRuoqing He #[macro_export]
422df8d2faSRuoqing He macro_rules! offset_of {
432df8d2faSRuoqing He ($reg_struct:ty, $field:ident) => {
442df8d2faSRuoqing He $crate::_offset_of!($reg_struct, $field)
452df8d2faSRuoqing He };
462df8d2faSRuoqing He ($outer_reg_struct:ty, $outer_field:ident, $($inner_reg_struct:ty, $inner_field:ident), +) => {
472df8d2faSRuoqing He $crate::_offset_of!($outer_reg_struct, $outer_field) + offset_of!($($inner_reg_struct, $inner_field), +)
482df8d2faSRuoqing He };
492df8d2faSRuoqing He }
502df8d2faSRuoqing He
512df8d2faSRuoqing He // Following are macros that help with getting the ID of a riscv64 register, including config registers, core registers and timer registers.
522df8d2faSRuoqing He // The register of core registers are wrapped in the `user_regs_struct` structure. See:
532df8d2faSRuoqing He // https://elixir.bootlin.com/linux/v6.10/source/arch/riscv/include/uapi/asm/kvm.h#L62
542df8d2faSRuoqing He
552df8d2faSRuoqing He // Get the ID of a register
562df8d2faSRuoqing He #[macro_export]
572df8d2faSRuoqing He macro_rules! riscv64_reg_id {
582df8d2faSRuoqing He ($reg_type: tt, $offset: tt) => {
592df8d2faSRuoqing He // The core registers of an riscv64 machine are represented
602df8d2faSRuoqing He // in kernel by the `kvm_riscv_core` structure:
612df8d2faSRuoqing He //
622df8d2faSRuoqing He // struct kvm_riscv_core {
632df8d2faSRuoqing He // struct user_regs_struct regs;
642df8d2faSRuoqing He // unsigned long mode;
652df8d2faSRuoqing He // };
662df8d2faSRuoqing He //
672df8d2faSRuoqing He // struct user_regs_struct {
682df8d2faSRuoqing He // unsigned long pc;
692df8d2faSRuoqing He // unsigned long ra;
702df8d2faSRuoqing He // unsigned long sp;
712df8d2faSRuoqing He // unsigned long gp;
722df8d2faSRuoqing He // unsigned long tp;
732df8d2faSRuoqing He // unsigned long t0;
742df8d2faSRuoqing He // unsigned long t1;
752df8d2faSRuoqing He // unsigned long t2;
762df8d2faSRuoqing He // unsigned long s0;
772df8d2faSRuoqing He // unsigned long s1;
782df8d2faSRuoqing He // unsigned long a0;
792df8d2faSRuoqing He // unsigned long a1;
802df8d2faSRuoqing He // unsigned long a2;
812df8d2faSRuoqing He // unsigned long a3;
822df8d2faSRuoqing He // unsigned long a4;
832df8d2faSRuoqing He // unsigned long a5;
842df8d2faSRuoqing He // unsigned long a6;
852df8d2faSRuoqing He // unsigned long a7;
862df8d2faSRuoqing He // unsigned long s2;
872df8d2faSRuoqing He // unsigned long s3;
882df8d2faSRuoqing He // unsigned long s4;
892df8d2faSRuoqing He // unsigned long s5;
902df8d2faSRuoqing He // unsigned long s6;
912df8d2faSRuoqing He // unsigned long s7;
922df8d2faSRuoqing He // unsigned long s8;
932df8d2faSRuoqing He // unsigned long s9;
942df8d2faSRuoqing He // unsigned long s10;
952df8d2faSRuoqing He // unsigned long s11;
962df8d2faSRuoqing He // unsigned long t3;
972df8d2faSRuoqing He // unsigned long t4;
982df8d2faSRuoqing He // unsigned long t5;
992df8d2faSRuoqing He // unsigned long t6;
1002df8d2faSRuoqing He // };
1012df8d2faSRuoqing He // The id of a core register can be obtained like this: offset = id &
1022df8d2faSRuoqing He // ~(KVM_REG_ARCH_MASK | KVM_REG_SIZE_MASK | KVM_REG_RISCV_CORE). Thus,
1032df8d2faSRuoqing He // id = KVM_REG_RISCV | KVM_REG_SIZE_U64 | KVM_REG_RISCV_CORE | offset
1042df8d2faSRuoqing He //
1052df8d2faSRuoqing He // To generalize, the id of a register can be obtained by:
1062df8d2faSRuoqing He // id = KVM_REG_RISCV | KVM_REG_SIZE_U64 |
1072df8d2faSRuoqing He // KVM_REG_RISCV_CORE/KVM_REG_RISCV_CONFIG/KVM_REG_RISCV_TIMER |
1082df8d2faSRuoqing He // offset
1092df8d2faSRuoqing He kvm_bindings::KVM_REG_RISCV as u64
1102df8d2faSRuoqing He | u64::from($reg_type)
1112df8d2faSRuoqing He | u64::from(kvm_bindings::KVM_REG_SIZE_U64)
1122df8d2faSRuoqing He | (($offset / std::mem::size_of::<u64>()) as u64)
1132df8d2faSRuoqing He };
1142df8d2faSRuoqing He }
1152df8d2faSRuoqing He
1162df8d2faSRuoqing He /// Specifies whether a particular register is a core register or not.
1172df8d2faSRuoqing He ///
1182df8d2faSRuoqing He /// # Arguments
1192df8d2faSRuoqing He ///
1202df8d2faSRuoqing He /// * `regid` - The index of the register we are checking.
is_non_core_register(regid: u64) -> bool1212df8d2faSRuoqing He pub fn is_non_core_register(regid: u64) -> bool {
1222df8d2faSRuoqing He if (regid & KVM_REG_RISCV_TYPE_MASK as u64) == KVM_REG_RISCV_CORE as u64 {
1232df8d2faSRuoqing He return false;
1242df8d2faSRuoqing He }
1252df8d2faSRuoqing He
1262df8d2faSRuoqing He let size = regid & KVM_REG_SIZE_MASK;
1272df8d2faSRuoqing He
1282df8d2faSRuoqing He assert!(
1292df8d2faSRuoqing He size == KVM_REG_SIZE_U64,
1302df8d2faSRuoqing He "Unexpected register size for system register {size}"
1312df8d2faSRuoqing He );
1322df8d2faSRuoqing He
1332df8d2faSRuoqing He true
1342df8d2faSRuoqing He }
1352df8d2faSRuoqing He
check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()>1362df8d2faSRuoqing He pub fn check_required_kvm_extensions(kvm: &Kvm) -> KvmResult<()> {
1372df8d2faSRuoqing He macro_rules! check_extension {
1382df8d2faSRuoqing He ($cap:expr) => {
1392df8d2faSRuoqing He if !kvm.check_extension($cap) {
1402df8d2faSRuoqing He return Err(KvmError::CapabilityMissing($cap));
1412df8d2faSRuoqing He }
1422df8d2faSRuoqing He };
1432df8d2faSRuoqing He }
1442df8d2faSRuoqing He
1452df8d2faSRuoqing He // SetGuestDebug is required but some kernels have it implemented without the capability flag.
1462df8d2faSRuoqing He check_extension!(Cap::ImmediateExit);
1472df8d2faSRuoqing He check_extension!(Cap::Ioeventfd);
1482df8d2faSRuoqing He check_extension!(Cap::Irqchip);
1492df8d2faSRuoqing He check_extension!(Cap::Irqfd);
1502df8d2faSRuoqing He check_extension!(Cap::IrqRouting);
1512df8d2faSRuoqing He check_extension!(Cap::MpState);
1522df8d2faSRuoqing He check_extension!(Cap::OneReg);
1532df8d2faSRuoqing He check_extension!(Cap::UserMemory);
1542df8d2faSRuoqing He Ok(())
1552df8d2faSRuoqing He }
1562df8d2faSRuoqing He
1572df8d2faSRuoqing He #[derive(Clone, Default, Serialize, Deserialize)]
1582df8d2faSRuoqing He pub struct VcpuKvmState {
1592df8d2faSRuoqing He pub mp_state: kvm_mp_state,
1602df8d2faSRuoqing He pub core_regs: kvm_riscv_core,
1612df8d2faSRuoqing He pub non_core_regs: Vec<kvm_one_reg>,
1622df8d2faSRuoqing He }
163