Skip to content

Commit 821741c

Browse files
committed
feat: add xen-hvm crate for guest kernel definitions
Signed-off-by: Martin Kröning <martin.kroening@eonerc.rwth-aachen.de>
1 parent 46cbbcd commit 821741c

File tree

5 files changed

+295
-0
lines changed

5 files changed

+295
-0
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ resolver = "2"
33
members = [
44
"xen",
55
"xen-bindings",
6+
"xen-hvm",
67
"xen-ioctls",
78
"xen-store",
89
"xen-sys",

xen-hvm/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[package]
2+
name = "xen-hvm"
3+
edition = "2021"
4+
license = "Apache-2.0 OR MIT"

xen-hvm/src/elfnote.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! Xen ELF notes.
2+
//!
3+
//! This module helps with adding Xen ELF notes to guests kernels.
4+
//!
5+
//! For details, see [xen/include/public/elfnote.h].
6+
//!
7+
//! [xen/include/public/elfnote.h]: https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=xen/include/public/elfnote.h;h=2fd8f1b770fd34214313a4b811e910958116f0c7;hb=06af9ef22996cecc2024a2e6523cec77a655581e
8+
9+
use core::mem;
10+
11+
use crate::start_info::StartInfo;
12+
13+
/// Creates a `XEN_ELFNOTE_PHYS32_ENTRY`.
14+
///
15+
/// <div class="warning">The entry itself has to be 32-bit code!</div>
16+
///
17+
/// # Safety
18+
///
19+
/// The provided `phys32_entry` needs to conform to the HVM booting
20+
/// requirements.
21+
///
22+
/// # Example
23+
///
24+
/// ```
25+
/// use xen_hvm::start_info::StartInfo;
26+
///
27+
/// unsafe extern "C" fn phys32_entry(start_info: &'static StartInfo) -> ! {
28+
/// loop {}
29+
/// }
30+
///
31+
/// xen_hvm::phys32_entry!(phys32_entry);
32+
/// ```
33+
#[macro_export]
34+
macro_rules! phys32_entry {
35+
($phys32_entry:expr) => {
36+
#[used]
37+
#[unsafe(link_section = ".note.Xen")]
38+
static XEN_ELFNOTE: $crate::elfnote::ElfnotePhys32Entry =
39+
$crate::elfnote::ElfnotePhys32Entry::phys32_entry($phys32_entry);
40+
};
41+
}
42+
43+
#[repr(C, packed(4))]
44+
pub struct Elfnote<N, D> {
45+
header: Nhdr32,
46+
name: N,
47+
desc: D,
48+
}
49+
50+
impl<N, D> Elfnote<N, D> {
51+
pub const fn new(n_type: u32, name: N, desc: D) -> Self {
52+
Self {
53+
header: Nhdr32 {
54+
n_namesz: mem::size_of::<N>() as u32,
55+
n_descsz: mem::size_of::<D>() as u32,
56+
n_type,
57+
},
58+
name,
59+
desc,
60+
}
61+
}
62+
}
63+
64+
pub type Phys32Entry = unsafe extern "C" fn(start_info: &'static StartInfo) -> !;
65+
pub type ElfnotePhys32Entry = Elfnote<[u8; 4], Phys32Entry>;
66+
67+
impl ElfnotePhys32Entry {
68+
/// Physical entry point into the kernel.
69+
///
70+
/// 32bit entry point into the kernel. When requested to launch the
71+
/// guest kernel in a HVM container, Xen will use this entry point to
72+
/// launch the guest in 32bit protected mode with paging disabled.
73+
/// Ignored otherwise.
74+
#[doc(alias = "XEN_ELFNOTE_PHYS32_ENTRY")]
75+
const PHYS32_ENTRY: u32 = 18;
76+
77+
pub const fn phys32_entry(phys32_entry: Phys32Entry) -> Self {
78+
Self::new(Self::PHYS32_ENTRY, *b"Xen\0", phys32_entry)
79+
}
80+
}
81+
82+
#[repr(C, packed(4))]
83+
struct Nhdr32 {
84+
n_namesz: u32,
85+
n_descsz: u32,
86+
n_type: u32,
87+
}

xen-hvm/src/lib.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//! Xen x86/HVM definitions.
2+
//!
3+
//! This crate allows guest kernels to be started via HVM.
4+
//! [`phys32_entry!`] allows creating a `XEN_ELFNOTE_PHYS32_ENTRY`.
5+
//! [`start_info`] provides the definitions for the start info that is passed by
6+
//! the hypervisor.
7+
8+
#![no_std]
9+
10+
#[doc(hidden)]
11+
pub mod elfnote;
12+
pub mod start_info;

xen-hvm/src/start_info.rs

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
//! HVM start info.
2+
//!
3+
//! For details, see [xen/include/public/arch-x86/hvm/start_info.h].
4+
//!
5+
//! [xen/include/public/arch-x86/hvm/start_info.h]: https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=xen/include/public/arch-x86/hvm/start_info.h;h=e33557c0b4e98c6db3d3521710daa3838586733c;hb=06af9ef22996cecc2024a2e6523cec77a655581e
6+
7+
/// Start of day structure passed to PVH guests and to HVM guests in %ebx.
8+
///
9+
/// NOTE: nothing will be loaded at physical address 0, so a 0 value in any
10+
/// of the address fields should be treated as not present.
11+
///
12+
/// 0 +----------------+
13+
/// | magic | Contains the magic value XEN_HVM_START_MAGIC_VALUE
14+
/// | | ("xEn3" with the 0x80 bit of the "E" set).
15+
/// 4 +----------------+
16+
/// | version | Version of this structure. Current version is 1. New
17+
/// | | versions are guaranteed to be backwards-compatible.
18+
/// 8 +----------------+
19+
/// | flags | SIF_xxx flags.
20+
/// 12 +----------------+
21+
/// | nr_modules | Number of modules passed to the kernel.
22+
/// 16 +----------------+
23+
/// | modlist_paddr | Physical address of an array of modules
24+
/// | | (layout of the structure below).
25+
/// 24 +----------------+
26+
/// | cmdline_paddr | Physical address of the command line,
27+
/// | | a zero-terminated ASCII string.
28+
/// 32 +----------------+
29+
/// | rsdp_paddr | Physical address of the RSDP ACPI data structure.
30+
/// 40 +----------------+
31+
/// | memmap_paddr | Physical address of the (optional) memory map. Only
32+
/// | | present in version 1 and newer of the structure.
33+
/// 48 +----------------+
34+
/// | memmap_entries | Number of entries in the memory map table. Zero
35+
/// | | if there is no memory map being provided. Only
36+
/// | | present in version 1 and newer of the structure.
37+
/// 52 +----------------+
38+
/// | reserved | Version 1 and newer only.
39+
/// 56 +----------------+
40+
///
41+
/// The layout of each entry in the module structure is the following:
42+
///
43+
/// 0 +----------------+
44+
/// | paddr | Physical address of the module.
45+
/// 8 +----------------+
46+
/// | size | Size of the module in bytes.
47+
/// 16 +----------------+
48+
/// | cmdline_paddr | Physical address of the command line,
49+
/// | | a zero-terminated ASCII string.
50+
/// 24 +----------------+
51+
/// | reserved |
52+
/// 32 +----------------+
53+
///
54+
/// The layout of each entry in the memory map table is as follows:
55+
///
56+
/// 0 +----------------+
57+
/// | addr | Base address
58+
/// 8 +----------------+
59+
/// | size | Size of mapping in bytes
60+
/// 16 +----------------+
61+
/// | type | Type of mapping as defined between the hypervisor
62+
/// | | and guest. See XEN_HVM_MEMMAP_TYPE_* values below.
63+
/// 20 +----------------|
64+
/// | reserved |
65+
/// 24 +----------------+
66+
///
67+
/// The address and sizes are always a 64bit little endian unsigned integer.
68+
///
69+
/// NB: Xen on x86 will always try to place all the data below the 4GiB
70+
/// boundary.
71+
///
72+
/// Version numbers of the hvm_start_info structure have evolved like this:
73+
///
74+
/// Version 0: Initial implementation.
75+
///
76+
/// Version 1: Added the memmap_paddr/memmap_entries fields (plus 4 bytes of
77+
/// padding) to the end of the hvm_start_info struct. These new
78+
/// fields can be used to pass a memory map to the guest. The
79+
/// memory map is optional and so guests that understand version 1
80+
/// of the structure must check that memmap_entries is non-zero
81+
/// before trying to read the memory map.
82+
#[doc(alias = "XEN_HVM_START_MAGIC_VALUE")]
83+
pub const START_MAGIC_VALUE: u32 = 0x336ec578;
84+
85+
/// The values used in the type field of the memory map table entries are
86+
/// defined below and match the Address Range Types as defined in the "System
87+
/// Address Map Interfaces" section of the ACPI Specification. Please refer to
88+
/// section 15 in version 6.2 of the ACPI spec: http://uefi.org/specifications
89+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE")]
90+
#[derive(Debug)]
91+
#[repr(u32)]
92+
pub enum MemmapType {
93+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_RAM")]
94+
Ram = 1,
95+
96+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_RESERVED")]
97+
Reserved = 2,
98+
99+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_ACPI")]
100+
Acpi = 3,
101+
102+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_NVS")]
103+
Nvs = 4,
104+
105+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_UNUSABLE")]
106+
Unusable = 5,
107+
108+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_DISABLED")]
109+
Disabled = 6,
110+
111+
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_PMEM")]
112+
Pmem = 7,
113+
}
114+
115+
/// C representation of the x86/HVM start info layout.
116+
///
117+
/// The canonical definition of this layout is above, this is just a way to
118+
/// represent the layout described there using C types.
119+
#[doc(alias = "hvm_start_info")]
120+
#[derive(Debug)]
121+
#[repr(C)]
122+
pub struct StartInfo {
123+
/// Contains the magic value 0x336ec578 "xEn3" with the 0x80 bit of the "E"
124+
/// set).
125+
///
126+
/// See [`START_MAGIC_VALUE`] for a definition of the magic value.
127+
magic: u32,
128+
129+
/// Version of this structure.
130+
version: u32,
131+
132+
/// SIF_xxx flags.
133+
flags: u32,
134+
135+
/// Number of modules passed to the kernel.
136+
nr_modules: u32,
137+
138+
/// Physical address of an array of hvm_modlist_entry.
139+
modlist_paddr: u64,
140+
141+
/// Physical address of the command line.
142+
cmdline_paddr: u64,
143+
144+
/// Physical address of the RSDP ACPI data structure.
145+
rsdp_paddr: u64,
146+
147+
// All following fields only present in version 1 and newer
148+
/// Physical address of an array of hvm_memmap_table_entry.
149+
memmap_paddr: u64,
150+
151+
/// Number of entries in the memmap table.
152+
///
153+
/// Value will be zero if there is no memory map being provided.
154+
memmap_entries: u32,
155+
156+
/// Must be zero.
157+
reserved: u32,
158+
}
159+
160+
#[doc(alias = "hvm_modlist_entry")]
161+
#[derive(Debug)]
162+
#[repr(C)]
163+
pub struct ModlistEntry {
164+
/// Physical address of the module.
165+
paddr: u64,
166+
167+
/// Size of the module in bytes.
168+
size: u64,
169+
170+
/// Physical address of the command line.
171+
cmdline_paddr: u64,
172+
reserved: u64,
173+
}
174+
175+
#[doc(alias = "hvm_memmap_table_entry")]
176+
#[derive(Debug)]
177+
#[repr(C)]
178+
pub struct MemmapTableEntry {
179+
/// Base address of the memory region
180+
addr: u64,
181+
182+
/// Size of the memory region in bytes
183+
size: u64,
184+
185+
/// Mapping type
186+
#[doc(alias = "type")]
187+
ty: u32,
188+
189+
/// Must be zero for Version 1.
190+
reserved: u32,
191+
}

0 commit comments

Comments
 (0)