1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
//! Cpuid vmexit controller.
//!
//! The cpuid instruction is a special instruction in x86 processors, used to obtain information about the processor and its features.
//! When executed, the instruction returns data in the processor's registers, including the vendor, model number, and feature flags.
//!
//! The cpuid instruction takes one input argument (leaf) in the EAX register, which determines the type of information to retrieve.
//! Different input values provide different information.
//! For example, setting EAX to 0 returns a 12-character ASCII string representing the CPU manufacturer ID in EBX, EDX, and ECX registers,
//! with "GenuineIntel" being the string for Intel processors.
//!
//! A guest operating system cannot execute the Cpuid instruction directly, instead causing a VM exit to the host, which must handle the instruction.
//! This part aims to emulate the cpuid instruction in the guest by executing the instruction on the host side.
//! However, not all the result could be forwarded. For example, when the host executes the Cpuid instruction with EAX = 1,
//! the result contains the executing core's CPU ID, not the VCPU ID. In this case, the result needs to modified to contain the VCPU ID.
//!
//! ## Tasks
//! Implement cpuid controller's handle method to emulate cpuid instruction.
//! If the input to the instruction is EAX = 1, you must carefully handle the cpuid. Because it holds the cpu id of the current logical processor not virtual cpu id.
//! It may be helpful to understand [how to obtain the CPU ID of the executing core.](/src/abyss/x86_64/intrinsics.rs.html)
//! In addition, you **MUST** forward the vCPU instruction pointer (rip) to prevent it from executing the same instructions indefinitely.
use core::arch::x86_64::{CpuidResult, __cpuid};
use kev::{
    vcpu::{GenericVCpuState, VmexitResult},
    vmcs::{BasicExitReason, ExitReason},
    Probe, VmError,
};

/// Cpuid vmexit controller.
pub struct Controller {}

impl Controller {
    /// Create a new cpuid controller.
    pub fn new() -> Self {
        Self {}
    }
}

impl kev::vmexits::VmexitController for Controller {
    fn handle<P: Probe>(
        &mut self,
        reason: ExitReason,
        _p: &mut P,
        generic_vcpu_state: &mut GenericVCpuState,
    ) -> Result<VmexitResult, VmError> {
        match reason.get_basic_reason() {
            BasicExitReason::Cpuid => {
                // HINT:
                //    - Use `core::arch::x86_64::__cpuid` to execute `cpuid`.
                //    - You should advance rip when an instruction is emulated.
                //    - You must carefully handle the cpuid leaf 1. Because it holds the cpu id, you must change the value to the virtual cpu id.
                todo!()
            }
            _ => Err(kev::VmError::HandleVmexitFailed(reason)),
        }
    }
}