Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ resolver = "2"
members = [
"xen",
"xen-bindings",
"xen-hvm",
"xen-ioctls",
"xen-store",
"xen-sys",
Expand Down
4 changes: 4 additions & 0 deletions xen-hvm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
name = "xen-hvm"
edition = "2021"
license = "Apache-2.0 OR MIT"
87 changes: 87 additions & 0 deletions xen-hvm/src/elfnote.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
//! Xen ELF notes.
//!
//! This module helps with adding Xen ELF notes to guests kernels.
//!
//! For details, see [xen/include/public/elfnote.h].
//!
//! [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

use core::mem;

use crate::start_info::StartInfo;

/// Creates a `XEN_ELFNOTE_PHYS32_ENTRY`.
///
/// <div class="warning">The entry itself has to be 32-bit code!</div>
///
/// # Safety
///
/// The provided `phys32_entry` needs to conform to the HVM booting
/// requirements.
///
/// # Example
///
/// ```
/// use xen_hvm::start_info::StartInfo;
///
/// unsafe extern "C" fn phys32_entry(start_info: &'static StartInfo) -> ! {
/// loop {}
/// }
///
/// xen_hvm::phys32_entry!(phys32_entry);
/// ```
#[macro_export]
macro_rules! phys32_entry {
($phys32_entry:expr) => {
#[used]
#[unsafe(link_section = ".note.Xen")]
static XEN_ELFNOTE: $crate::elfnote::ElfnotePhys32Entry =
$crate::elfnote::ElfnotePhys32Entry::phys32_entry($phys32_entry);
};
}

#[repr(C, packed(4))]
pub struct Elfnote<N, D> {
header: Nhdr32,
name: N,
desc: D,
}

impl<N, D> Elfnote<N, D> {
pub const fn new(n_type: u32, name: N, desc: D) -> Self {
Self {
header: Nhdr32 {
n_namesz: mem::size_of::<N>() as u32,
n_descsz: mem::size_of::<D>() as u32,
n_type,
},
name,
desc,
}
}
}

pub type Phys32Entry = unsafe extern "C" fn(start_info: &'static StartInfo) -> !;
pub type ElfnotePhys32Entry = Elfnote<[u8; 4], Phys32Entry>;

impl ElfnotePhys32Entry {
/// Physical entry point into the kernel.
///
/// 32bit entry point into the kernel. When requested to launch the
/// guest kernel in a HVM container, Xen will use this entry point to
/// launch the guest in 32bit protected mode with paging disabled.
/// Ignored otherwise.
#[doc(alias = "XEN_ELFNOTE_PHYS32_ENTRY")]
const PHYS32_ENTRY: u32 = 18;

pub const fn phys32_entry(phys32_entry: Phys32Entry) -> Self {
Self::new(Self::PHYS32_ENTRY, *b"Xen\0", phys32_entry)
}
}

#[repr(C, packed(4))]
struct Nhdr32 {
n_namesz: u32,
n_descsz: u32,
n_type: u32,
}
12 changes: 12 additions & 0 deletions xen-hvm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! Xen x86/HVM definitions.
//!
//! This crate allows guest kernels to be started via HVM.
//! [`phys32_entry!`] allows creating a `XEN_ELFNOTE_PHYS32_ENTRY`.
//! [`start_info`] provides the definitions for the start info that is passed by
//! the hypervisor.

#![no_std]

#[doc(hidden)]
pub mod elfnote;
pub mod start_info;
191 changes: 191 additions & 0 deletions xen-hvm/src/start_info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
//! HVM start info.
//!
//! For details, see [xen/include/public/arch-x86/hvm/start_info.h].
//!
//! [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

/// Start of day structure passed to PVH guests and to HVM guests in %ebx.
///
/// NOTE: nothing will be loaded at physical address 0, so a 0 value in any
/// of the address fields should be treated as not present.
///
/// 0 +----------------+
/// | magic | Contains the magic value XEN_HVM_START_MAGIC_VALUE
/// | | ("xEn3" with the 0x80 bit of the "E" set).
/// 4 +----------------+
/// | version | Version of this structure. Current version is 1. New
/// | | versions are guaranteed to be backwards-compatible.
/// 8 +----------------+
/// | flags | SIF_xxx flags.
/// 12 +----------------+
/// | nr_modules | Number of modules passed to the kernel.
/// 16 +----------------+
/// | modlist_paddr | Physical address of an array of modules
/// | | (layout of the structure below).
/// 24 +----------------+
/// | cmdline_paddr | Physical address of the command line,
/// | | a zero-terminated ASCII string.
/// 32 +----------------+
/// | rsdp_paddr | Physical address of the RSDP ACPI data structure.
/// 40 +----------------+
/// | memmap_paddr | Physical address of the (optional) memory map. Only
/// | | present in version 1 and newer of the structure.
/// 48 +----------------+
/// | memmap_entries | Number of entries in the memory map table. Zero
/// | | if there is no memory map being provided. Only
/// | | present in version 1 and newer of the structure.
/// 52 +----------------+
/// | reserved | Version 1 and newer only.
/// 56 +----------------+
///
/// The layout of each entry in the module structure is the following:
///
/// 0 +----------------+
/// | paddr | Physical address of the module.
/// 8 +----------------+
/// | size | Size of the module in bytes.
/// 16 +----------------+
/// | cmdline_paddr | Physical address of the command line,
/// | | a zero-terminated ASCII string.
/// 24 +----------------+
/// | reserved |
/// 32 +----------------+
///
/// The layout of each entry in the memory map table is as follows:
///
/// 0 +----------------+
/// | addr | Base address
/// 8 +----------------+
/// | size | Size of mapping in bytes
/// 16 +----------------+
/// | type | Type of mapping as defined between the hypervisor
/// | | and guest. See XEN_HVM_MEMMAP_TYPE_* values below.
/// 20 +----------------|
/// | reserved |
/// 24 +----------------+
///
/// The address and sizes are always a 64bit little endian unsigned integer.
///
/// NB: Xen on x86 will always try to place all the data below the 4GiB
/// boundary.
///
/// Version numbers of the hvm_start_info structure have evolved like this:
///
/// Version 0: Initial implementation.
///
/// Version 1: Added the memmap_paddr/memmap_entries fields (plus 4 bytes of
/// padding) to the end of the hvm_start_info struct. These new
/// fields can be used to pass a memory map to the guest. The
/// memory map is optional and so guests that understand version 1
/// of the structure must check that memmap_entries is non-zero
/// before trying to read the memory map.
#[doc(alias = "XEN_HVM_START_MAGIC_VALUE")]
pub const START_MAGIC_VALUE: u32 = 0x336ec578;

/// The values used in the type field of the memory map table entries are
/// defined below and match the Address Range Types as defined in the "System
/// Address Map Interfaces" section of the ACPI Specification. Please refer to
/// section 15 in version 6.2 of the ACPI spec: http://uefi.org/specifications
#[doc(alias = "XEN_HVM_MEMMAP_TYPE")]
#[derive(Debug)]
#[repr(u32)]
pub enum MemmapType {
#[doc(alias = "XEN_HVM_MEMMAP_TYPE_RAM")]
Ram = 1,

#[doc(alias = "XEN_HVM_MEMMAP_TYPE_RESERVED")]
Reserved = 2,

#[doc(alias = "XEN_HVM_MEMMAP_TYPE_ACPI")]
Acpi = 3,

#[doc(alias = "XEN_HVM_MEMMAP_TYPE_NVS")]
Nvs = 4,

#[doc(alias = "XEN_HVM_MEMMAP_TYPE_UNUSABLE")]
Unusable = 5,

#[doc(alias = "XEN_HVM_MEMMAP_TYPE_DISABLED")]
Disabled = 6,

#[doc(alias = "XEN_HVM_MEMMAP_TYPE_PMEM")]
Pmem = 7,
}

/// C representation of the x86/HVM start info layout.
///
/// The canonical definition of this layout is above, this is just a way to
/// represent the layout described there using C types.
#[doc(alias = "hvm_start_info")]
#[derive(Debug)]
#[repr(C)]
pub struct StartInfo {
/// Contains the magic value 0x336ec578 "xEn3" with the 0x80 bit of the "E"
/// set).
///
/// See [`START_MAGIC_VALUE`] for a definition of the magic value.
magic: u32,

/// Version of this structure.
version: u32,

/// SIF_xxx flags.
flags: u32,

/// Number of modules passed to the kernel.
nr_modules: u32,

/// Physical address of an array of hvm_modlist_entry.
modlist_paddr: u64,

/// Physical address of the command line.
cmdline_paddr: u64,

/// Physical address of the RSDP ACPI data structure.
rsdp_paddr: u64,

// All following fields only present in version 1 and newer
/// Physical address of an array of hvm_memmap_table_entry.
memmap_paddr: u64,

/// Number of entries in the memmap table.
///
/// Value will be zero if there is no memory map being provided.
memmap_entries: u32,

/// Must be zero.
reserved: u32,
}

#[doc(alias = "hvm_modlist_entry")]
#[derive(Debug)]
#[repr(C)]
pub struct ModlistEntry {
/// Physical address of the module.
paddr: u64,

/// Size of the module in bytes.
size: u64,

/// Physical address of the command line.
cmdline_paddr: u64,
reserved: u64,
}

#[doc(alias = "hvm_memmap_table_entry")]
#[derive(Debug)]
#[repr(C)]
pub struct MemmapTableEntry {
/// Base address of the memory region
addr: u64,

/// Size of the memory region in bytes
size: u64,

/// Mapping type
#[doc(alias = "type")]
ty: u32,

/// Must be zero for Version 1.
reserved: u32,
}