vcpu_x86_64.rs0.00%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
mod tdx;16
17
use std::arch::x86_64::CpuidResult;18
use std::collections::HashMap;19
use std::iter::zip;20
use std::os::fd::{FromRawFd, OwnedFd};21
22
use snafu::ResultExt;23
24
use crate::arch::cpuid::CpuidIn;25
use crate::arch::reg::{DtReg, DtRegVal, Reg, SReg, SegAccess, SegReg, SegRegVal};26
use crate::hv::kvm::kvm_error;27
use crate::hv::kvm::vcpu::KvmVcpu;28
use crate::hv::kvm::vm::KvmVm;29
use crate::hv::{Error, Result, error};30
use crate::sys::kvm::{31
KVM_MAX_CPUID_ENTRIES, KvmCpuid2, KvmCpuid2Flag, KvmCpuidEntry2, KvmMsrEntry, KvmMsrs, KvmRegs,32
MAX_IO_MSRS, kvm_create_vcpu, kvm_get_regs, kvm_get_sregs, kvm_get_sregs2, kvm_kvmclock_ctrl,33
kvm_set_cpuid2, kvm_set_msrs, kvm_set_regs, kvm_set_sregs, kvm_set_sregs2,34
};35
36
#[derive(Debug)]37
pub struct VcpuArch {38
pub io_index: usize,39
}40
41
impl VcpuArch {42
pub fn new(_id: u64) -> Self {43
Self { io_index: 0 }44
}45
}46
47
macro_rules! set_kvm_sreg {48
($kvm_sregs:ident, $sreg:ident, $val:expr) => {49
match $sreg {50
SReg::Cr0 => $kvm_sregs.cr0 = $val,51
SReg::Cr2 => $kvm_sregs.cr2 = $val,52
SReg::Cr3 => $kvm_sregs.cr3 = $val,53
SReg::Cr4 => $kvm_sregs.cr4 = $val,54
SReg::Cr8 => $kvm_sregs.cr8 = $val,55
SReg::Efer => $kvm_sregs.efer = $val,56
SReg::ApicBase => $kvm_sregs.apic_base = $val,57
}58
};59
}60
61
macro_rules! set_kvm_dt_reg {62
($kvm_sregs:ident, $dt_reg:ident, $val:expr) => {63
let target = match $dt_reg {64
DtReg::Idtr => &mut $kvm_sregs.idt,65
DtReg::Gdtr => &mut $kvm_sregs.gdt,66
};67
target.limit = $val.limit;68
target.base = $val.base;69
};70
}71
72
macro_rules! set_kvm_seg_reg {73
($kvm_sregs:ident, $seg_reg:ident, $val:expr) => {74
let target = match $seg_reg {75
SegReg::Cs => &mut $kvm_sregs.cs,76
SegReg::Ds => &mut $kvm_sregs.ds,77
SegReg::Es => &mut $kvm_sregs.es,78
SegReg::Fs => &mut $kvm_sregs.fs,79
SegReg::Gs => &mut $kvm_sregs.gs,80
SegReg::Ss => &mut $kvm_sregs.ss,81
SegReg::Tr => &mut $kvm_sregs.tr,82
SegReg::Ldtr => &mut $kvm_sregs.ldt,83
};84
target.selector = $val.selector;85
target.base = $val.base;86
target.limit = $val.limit;87
target.type_ = $val.access.seg_type() as u8;88
target.s = $val.access.s_code_data() as u8;89
target.dpl = $val.access.priv_level() as u8;90
target.present = $val.access.present() as u8;91
target.avl = $val.access.available() as u8;92
target.db = $val.access.db_size_32() as u8;93
target.g = $val.access.granularity() as u8;94
target.l = $val.access.l_64bit() as u8;95
target.unusable = $val.access.unusable() as u8;96
};97
}98
99
macro_rules! get_kvm_sreg {100
($kvm_sregs:ident, $sreg:ident) => {101
match $sreg {102
SReg::Cr0 => $kvm_sregs.cr0,103
SReg::Cr2 => $kvm_sregs.cr2,104
SReg::Cr3 => $kvm_sregs.cr3,105
SReg::Cr4 => $kvm_sregs.cr4,106
SReg::Cr8 => $kvm_sregs.cr8,107
SReg::Efer => $kvm_sregs.efer,108
SReg::ApicBase => $kvm_sregs.apic_base,109
}110
};111
}112
113
macro_rules! get_kvm_dt_reg {114
($kvm_sregs:ident, $dt_reg:ident) => {{115
let target = match $dt_reg {116
DtReg::Idtr => $kvm_sregs.idt,117
DtReg::Gdtr => $kvm_sregs.gdt,118
};119
DtRegVal {120
limit: target.limit,121
base: target.base,122
}123
}};124
}125
126
macro_rules! get_kvm_seg_reg {127
($kvm_sregs:ident, $seg_reg:ident) => {{128
let kvm_segment = match $seg_reg {129
SegReg::Cs => $kvm_sregs.cs,130
SegReg::Ds => $kvm_sregs.ds,131
SegReg::Es => $kvm_sregs.es,132
SegReg::Fs => $kvm_sregs.fs,133
SegReg::Gs => $kvm_sregs.gs,134
SegReg::Ss => $kvm_sregs.ss,135
SegReg::Tr => $kvm_sregs.tr,136
SegReg::Ldtr => $kvm_sregs.ldt,137
};138
let access = (kvm_segment.unusable as u32) << 16139
| (kvm_segment.g as u32) << 15140
| (kvm_segment.db as u32) << 14141
| (kvm_segment.l as u32) << 13142
| (kvm_segment.avl as u32) << 12143
| (kvm_segment.present as u32) << 7144
| (kvm_segment.dpl as u32) << 5145
| (kvm_segment.s as u32) << 4146
| (kvm_segment.type_ as u32);147
SegRegVal {148
selector: kvm_segment.selector,149
base: kvm_segment.base,150
limit: kvm_segment.limit,151
access: SegAccess(access),152
}153
}};154
}155
156
impl KvmVcpu {157
pub fn create_vcpu(vm: &KvmVm, _: u16, identity: u64) -> Result<OwnedFd> {158
let apic_id = identity as u32;159
let fd = unsafe { kvm_create_vcpu(&vm.vm.fd, apic_id) }.context(error::CreateVcpu)?;160
Ok(unsafe { OwnedFd::from_raw_fd(fd) })161
}162
163
pub fn kvmclock_ctrl(&mut self) -> Result<()> {164
unsafe { kvm_kvmclock_ctrl(&self.fd) }.context(kvm_error::KvmClockCtrl)?;165
Ok(())166
}167
168
fn get_kvm_regs(&self) -> Result<KvmRegs> {169
let kvm_regs = unsafe { kvm_get_regs(&self.fd) }.context(error::VcpuReg)?;170
Ok(kvm_regs)171
}172
173
fn set_kvm_regs(&self, kvm_regs: &KvmRegs) -> Result<()> {174
unsafe { kvm_set_regs(&self.fd, kvm_regs) }.context(error::VcpuReg)?;175
Ok(())176
}177
178
pub fn kvm_set_regs(&self, vals: &[(Reg, u64)]) -> Result<()> {179
let mut kvm_regs = self.get_kvm_regs()?;180
for (reg, val) in vals {181
match reg {182
Reg::Rax => kvm_regs.rax = *val,183
Reg::Rbx => kvm_regs.rbx = *val,184
Reg::Rcx => kvm_regs.rcx = *val,185
Reg::Rdx => kvm_regs.rdx = *val,186
Reg::Rsi => kvm_regs.rsi = *val,187
Reg::Rdi => kvm_regs.rdi = *val,188
Reg::Rsp => kvm_regs.rsp = *val,189
Reg::Rbp => kvm_regs.rbp = *val,190
Reg::R8 => kvm_regs.r8 = *val,191
Reg::R9 => kvm_regs.r9 = *val,192
Reg::R10 => kvm_regs.r10 = *val,193
Reg::R11 => kvm_regs.r11 = *val,194
Reg::R12 => kvm_regs.r12 = *val,195
Reg::R13 => kvm_regs.r13 = *val,196
Reg::R14 => kvm_regs.r14 = *val,197
Reg::R15 => kvm_regs.r15 = *val,198
Reg::Rip => kvm_regs.rip = *val,199
Reg::Rflags => kvm_regs.rflags = *val,200
}201
}202
self.set_kvm_regs(&kvm_regs)203
}204
205
pub fn kvm_get_reg(&self, reg: Reg) -> Result<u64> {206
let kvm_regs = self.get_kvm_regs()?;207
let val = match reg {208
Reg::Rax => kvm_regs.rax,209
Reg::Rbx => kvm_regs.rbx,210
Reg::Rcx => kvm_regs.rcx,211
Reg::Rdx => kvm_regs.rdx,212
Reg::Rsi => kvm_regs.rsi,213
Reg::Rdi => kvm_regs.rdi,214
Reg::Rsp => kvm_regs.rsp,215
Reg::Rbp => kvm_regs.rbp,216
Reg::R8 => kvm_regs.r8,217
Reg::R9 => kvm_regs.r9,218
Reg::R10 => kvm_regs.r10,219
Reg::R11 => kvm_regs.r11,220
Reg::R12 => kvm_regs.r12,221
Reg::R13 => kvm_regs.r13,222
Reg::R14 => kvm_regs.r14,223
Reg::R15 => kvm_regs.r15,224
Reg::Rip => kvm_regs.rip,225
Reg::Rflags => kvm_regs.rflags,226
};227
Ok(val)228
}229
230
pub fn kvm_set_sregs2(231
&mut self,232
sregs: &[(SReg, u64)],233
seg_regs: &[(SegReg, SegRegVal)],234
dt_regs: &[(DtReg, DtRegVal)],235
) -> Result<(), Error> {236
let mut kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;237
for (reg, val) in sregs {238
set_kvm_sreg!(kvm_sregs2, reg, *val)239
}240
for (reg, val) in dt_regs {241
set_kvm_dt_reg!(kvm_sregs2, reg, val);242
}243
for (reg, val) in seg_regs {244
set_kvm_seg_reg!(kvm_sregs2, reg, val);245
}246
unsafe { kvm_set_sregs2(&self.fd, &kvm_sregs2) }.context(error::VcpuReg)?;247
Ok(())248
}249
250
pub fn kvm_get_dt_reg2(&self, reg: DtReg) -> Result<DtRegVal> {251
let kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;252
let val = get_kvm_dt_reg!(kvm_sregs2, reg);253
Ok(val)254
}255
256
pub fn kvm_get_seg_reg2(&self, reg: SegReg) -> Result<SegRegVal> {257
let kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;258
let val = get_kvm_seg_reg!(kvm_sregs2, reg);259
Ok(val)260
}261
262
pub fn kvm_get_sreg2(&self, reg: SReg) -> Result<u64> {263
let kvm_sregs2 = unsafe { kvm_get_sregs2(&self.fd) }.context(error::VcpuReg)?;264
let val = get_kvm_sreg!(kvm_sregs2, reg);265
Ok(val)266
}267
268
pub fn kvm_set_sregs(269
&mut self,270
sregs: &[(SReg, u64)],271
seg_regs: &[(SegReg, SegRegVal)],272
dt_regs: &[(DtReg, DtRegVal)],273
) -> Result<(), Error> {274
let mut kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;275
for (reg, val) in sregs {276
set_kvm_sreg!(kvm_sregs, reg, *val)277
}278
for (reg, val) in dt_regs {279
set_kvm_dt_reg!(kvm_sregs, reg, val);280
}281
for (reg, val) in seg_regs {282
set_kvm_seg_reg!(kvm_sregs, reg, val);283
}284
unsafe { kvm_set_sregs(&self.fd, &kvm_sregs) }.context(error::VcpuReg)?;285
Ok(())286
}287
288
pub fn kvm_get_dt_reg(&self, reg: DtReg) -> Result<DtRegVal> {289
let kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;290
let val = get_kvm_dt_reg!(kvm_sregs, reg);291
Ok(val)292
}293
294
pub fn kvm_get_seg_reg(&self, reg: SegReg) -> Result<SegRegVal> {295
let kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;296
let val = get_kvm_seg_reg!(kvm_sregs, reg);297
Ok(val)298
}299
300
pub fn kvm_get_sreg(&self, reg: SReg) -> Result<u64> {301
let kvm_sregs = unsafe { kvm_get_sregs(&self.fd) }.context(error::VcpuReg)?;302
let val = get_kvm_sreg!(kvm_sregs, reg);303
Ok(val)304
}305
306
pub fn kvm_set_cpuids(&mut self, cpuids: &HashMap<CpuidIn, CpuidResult>) -> Result<(), Error> {307
if cpuids.len() > KVM_MAX_CPUID_ENTRIES {308
return kvm_error::CpuidTableTooLong.fail()?;309
}310
let mut kvm_cpuid2 = KvmCpuid2 {311
nent: cpuids.len() as u32,312
padding: 0,313
entries: [KvmCpuidEntry2::default(); KVM_MAX_CPUID_ENTRIES],314
};315
for ((in_, out), entry) in zip(cpuids, &mut kvm_cpuid2.entries) {316
entry.eax = out.eax;317
entry.ebx = out.ebx;318
entry.ecx = out.ecx;319
entry.edx = out.edx;320
entry.function = in_.func;321
if let Some(index) = in_.index {322
entry.index = index;323
entry.flags = KvmCpuid2Flag::SIGNIFCANT_INDEX;324
} else {325
entry.flags = KvmCpuid2Flag::empty();326
}327
}328
unsafe { kvm_set_cpuid2(&self.fd, &kvm_cpuid2) }.context(error::GuestCpuid)?;329
Ok(())330
}331
332
pub fn kvm_set_msrs(&mut self, msrs: &[(u32, u64)]) -> Result<()> {333
let mut kvm_msrs = KvmMsrs {334
nmsrs: msrs.len() as u32,335
_pad: 0,336
entries: [KvmMsrEntry::default(); MAX_IO_MSRS],337
};338
for (i, (index, data)) in msrs.iter().enumerate() {339
kvm_msrs.entries[i].index = *index;340
kvm_msrs.entries[i].data = *data;341
}342
unsafe { kvm_set_msrs(&self.fd, &kvm_msrs) }.context(error::GuestMsr)?;343
Ok(())344
}345
}346
347
#[cfg(test)]348
#[path = "vcpu_x86_64_test.rs"]349
mod tests;350