Skip to content

Commit c5e8eb9

Browse files
cpercivaaljimenezb
andcommitted
pvh/arch-x86_64: Initialize vCPU regs for PVH
Set the initial values of the KVM vCPU registers as specified in the PVH boot ABI: https://xenbits.xen.org/docs/unstable/misc/pvh.html Signed-off-by: Colin Percival <cperciva@freebsd.org> Co-authored-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
1 parent b389e5f commit c5e8eb9

14 files changed

+2679
-65
lines changed
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
From e0b0f71e3f3b6fcd53c49875b18d0d5dbdd53e88 Mon Sep 17 00:00:00 2001
2+
From: Colin Percival <cperciva@freebsd.org>
3+
Date: Sun, 2 Oct 2022 10:42:24 -0700
4+
Subject: [PATCH 1/3] pvh/arch: Introduce EntryPoint struct
5+
6+
In order to properly configure the initial vCPU register state
7+
and boot parameters in guest memory, we must specify which
8+
boot protocol to use with the kernel entry point address.
9+
10+
Create an EntryPoint struct that contains the required
11+
information. This structure will later be used in the vCPU
12+
configuration methods to set the appropriate initial
13+
conditions for the guest.
14+
15+
Signed-off-by: Colin Percival <cperciva@freebsd.org>
16+
Co-authored-by: Alejandro Jimenez <alejandro.j.jimenez@oracle.com>
17+
---
18+
src/arch/src/lib.rs | 29 +++++++++++++++++++++++++++++
19+
src/vmm/src/builder.rs | 25 ++++++++++++++++++++-----
20+
2 files changed, 49 insertions(+), 5 deletions(-)
21+
22+
diff --git a/src/arch/src/lib.rs b/src/arch/src/lib.rs
23+
index 7d025f39..950676cf 100644
24+
--- a/src/arch/src/lib.rs
25+
+++ b/src/arch/src/lib.rs
26+
@@ -65,3 +65,32 @@ impl fmt::Display for DeviceType {
27+
write!(f, "{:?}", self)
28+
}
29+
}
30+
+
31+
+/// Suported boot protocols for
32+
+#[derive(Debug, Copy, Clone)]
33+
+pub enum BootProtocol {
34+
+ /// Linux 64-bit boot protocol
35+
+ LinuxBoot,
36+
+ /// PVH boot protocol (x86/HVM direct boot ABI)
37+
+ PvhBoot,
38+
+}
39+
+
40+
+impl fmt::Display for BootProtocol {
41+
+ fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
42+
+ match self {
43+
+ BootProtocol::LinuxBoot => write!(f, "Linux 64-bit boot protocol"),
44+
+ BootProtocol::PvhBoot => write!(f, "PVH boot protocol"),
45+
+ }
46+
+ }
47+
+}
48+
+
49+
+#[derive(Debug, Copy, Clone)]
50+
+/// Specifies the entry point address where the guest must start
51+
+/// executing code, as well as which boot protocol is to be used
52+
+/// to configure the guest initial state.
53+
+pub struct EntryPoint {
54+
+ /// Address in guest memory where the guest must start execution
55+
+ pub entry_addr: vm_memory::GuestAddress,
56+
+ /// Specifies which boot protocol to use
57+
+ pub protocol: BootProtocol,
58+
+}
59+
diff --git a/src/vmm/src/builder.rs b/src/vmm/src/builder.rs
60+
index 09506087..5c2828bc 100644
61+
--- a/src/vmm/src/builder.rs
62+
+++ b/src/vmm/src/builder.rs
63+
@@ -9,7 +9,7 @@ use std::io::{self, Read, Seek, SeekFrom};
64+
use std::os::unix::io::{AsRawFd, RawFd};
65+
use std::sync::{Arc, Mutex};
66+
67+
-use arch::InitrdConfig;
68+
+use arch::{BootProtocol, EntryPoint, InitrdConfig};
69+
#[cfg(target_arch = "x86_64")]
70+
use cpuid::common::is_same_model;
71+
use devices::legacy::serial::ReadableFd;
72+
@@ -22,6 +22,7 @@ use libc::EFD_NONBLOCK;
73+
use linux_loader::cmdline::Cmdline as LoaderKernelCmdline;
74+
#[cfg(target_arch = "x86_64")]
75+
use linux_loader::loader::elf::Elf as Loader;
76+
+use linux_loader::loader::elf::PvhBootCapability;
77+
#[cfg(target_arch = "aarch64")]
78+
use linux_loader::loader::pe::PE as Loader;
79+
use linux_loader::loader::KernelLoader;
80+
@@ -334,7 +335,7 @@ pub fn build_microvm_for_boot(
81+
let guest_memory =
82+
create_guest_memory(vm_resources.vm_config().mem_size_mib, track_dirty_pages)?;
83+
let vcpu_config = vm_resources.vcpu_config();
84+
- let entry_addr = load_kernel(boot_config, &guest_memory)?;
85+
+ let entry_point = load_kernel(boot_config, &guest_memory)?;
86+
let initrd = load_initrd_from_config(boot_config, &guest_memory)?;
87+
// Clone the command-line so that a failed boot doesn't pollute the original.
88+
#[allow(unused_mut)]
89+
@@ -407,7 +408,7 @@ pub fn build_microvm_for_boot(
90+
&vmm,
91+
vcpus.as_mut(),
92+
vcpu_config,
93+
- entry_addr,
94+
+ entry_point.entry_addr,
95+
&initrd,
96+
boot_cmdline,
97+
)?;
98+
@@ -636,7 +637,7 @@ pub fn create_guest_memory(
99+
fn load_kernel(
100+
boot_config: &BootConfig,
101+
guest_memory: &GuestMemoryMmap,
102+
-) -> std::result::Result<GuestAddress, StartMicrovmError> {
103+
+) -> std::result::Result<EntryPoint, StartMicrovmError> {
104+
let mut kernel_file = boot_config
105+
.kernel_file
106+
.try_clone()
107+
@@ -660,7 +661,21 @@ fn load_kernel(
108+
)
109+
.map_err(StartMicrovmError::KernelLoader)?;
110+
111+
- Ok(entry_addr.kernel_load)
112+
+ let mut entry_point_addr: GuestAddress = entry_addr.kernel_load;
113+
+ let mut boot_prot: BootProtocol = BootProtocol::LinuxBoot;
114+
+
115+
+ if cfg!(target_arch = "x86_64") {
116+
+ if let PvhBootCapability::PvhEntryPresent(pvh_entry_addr) = entry_addr.pvh_boot_cap {
117+
+ // Use the PVH kernel entry point to boot the guest
118+
+ entry_point_addr = pvh_entry_addr;
119+
+ boot_prot = BootProtocol::PvhBoot;
120+
+ }
121+
+ }
122+
+
123+
+ Ok(EntryPoint {
124+
+ entry_addr: entry_point_addr,
125+
+ protocol: boot_prot,
126+
+ })
127+
}
128+
129+
fn load_initrd_from_config(
130+
--
131+
2.38.1
132+

0 commit comments

Comments
 (0)