linux_loader/configurator/x86_64/
pvh.rs1#![cfg(any(feature = "elf", feature = "bzimage"))]
16
17use vm_memory::{ByteValued, Bytes, GuestMemoryBackend};
18
19use crate::configurator::{BootConfigurator, BootParams, Error as BootConfiguratorError, Result};
20use crate::loader_gen::start_info::{hvm_memmap_table_entry, hvm_modlist_entry, hvm_start_info};
21
22use std::fmt;
23
24pub struct PvhBootConfigurator {}
26
27#[derive(Debug, PartialEq, Eq)]
29pub enum Error {
30 MemmapTableAddressMissing,
32 MemmapTableMissing,
34 MemmapTablePastRamEnd,
36 MemmapTableSetup,
38 StartInfoPastRamEnd,
40 StartInfoSetup,
42 ModulesAddressMissing,
44 ModulesSetup,
46}
47
48impl fmt::Display for Error {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 use Error::*;
51 let desc = match self {
52 MemmapTableAddressMissing => {
53 "the starting address for the memory map wasn't passed to the boot configurator."
54 }
55 MemmapTableMissing => "no memory map was passed to the boot configurator.",
56 MemmapTablePastRamEnd => "the memory map table extends past the end of guest memory.",
57 MemmapTableSetup => "error writing memory map table to guest memory.",
58 StartInfoPastRamEnd => {
59 "the hvm_start_info structure extends past the end of guest memory."
60 }
61 StartInfoSetup => "error writing hvm_start_info to guest memory.",
62 ModulesAddressMissing => "the starting address for the modules descriptions wasn't passed to the boot configurator.",
63 ModulesSetup => "error writing module descriptions to guest memory.",
64 };
65
66 write!(f, "PVH Boot Configurator: {}", desc)
67 }
68}
69
70impl std::error::Error for Error {}
71
72impl From<Error> for BootConfiguratorError {
73 fn from(err: Error) -> Self {
74 BootConfiguratorError::Pvh(err)
75 }
76}
77
78unsafe impl ByteValued for hvm_start_info {}
81
82unsafe impl ByteValued for hvm_memmap_table_entry {}
85
86unsafe impl ByteValued for hvm_modlist_entry {}
89
90impl BootConfigurator for PvhBootConfigurator {
91 fn write_bootparams<M>(params: &BootParams, guest_memory: &M) -> Result<()>
147 where
148 M: GuestMemoryBackend,
149 {
150 let memmap = params.sections.as_ref().ok_or(Error::MemmapTableMissing)?;
155 let memmap_addr = params
156 .sections_start
157 .ok_or(Error::MemmapTableAddressMissing)?;
158
159 guest_memory
160 .checked_offset(memmap_addr, memmap.len())
161 .ok_or(Error::MemmapTablePastRamEnd)?;
162 guest_memory
163 .write_slice(memmap.as_slice(), memmap_addr)
164 .map_err(|_| Error::MemmapTableSetup)?;
165
166 guest_memory
167 .checked_offset(params.header_start, params.header.len())
168 .ok_or(Error::StartInfoPastRamEnd)?;
169 guest_memory
170 .write_slice(params.header.as_slice(), params.header_start)
171 .map_err(|_| Error::StartInfoSetup)?;
172
173 if let Some(modules) = params.modules.as_ref() {
174 let modules_addr = params.modules_start.ok_or(Error::ModulesAddressMissing)?;
175 guest_memory
176 .write_slice(modules.as_slice(), modules_addr)
177 .map_err(|_| Error::ModulesSetup)?;
178 }
179
180 Ok(())
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use std::mem;
188 use vm_memory::{Address, GuestAddress, GuestMemoryMmap};
189
190 const XEN_HVM_START_MAGIC_VALUE: u32 = 0x336ec578;
191 const MEM_SIZE: u64 = 0x100_0000;
192 const E820_RAM: u32 = 1;
193
194 fn create_guest_mem() -> GuestMemoryMmap {
195 GuestMemoryMmap::from_ranges(&[(GuestAddress(0x0), (MEM_SIZE as usize))]).unwrap()
196 }
197
198 fn build_bootparams_common() -> (
199 hvm_start_info,
200 Vec<hvm_memmap_table_entry>,
201 Vec<hvm_modlist_entry>,
202 ) {
203 let mut start_info = hvm_start_info::default();
204 let memmap_entry = hvm_memmap_table_entry {
205 addr: 0x7000,
206 size: 0,
207 type_: E820_RAM,
208 reserved: 0,
209 };
210
211 let modlist_entry = hvm_modlist_entry {
212 paddr: 0x10000,
213 size: 0x100,
214 cmdline_paddr: 0,
215 reserved: 0,
216 };
217
218 start_info.magic = XEN_HVM_START_MAGIC_VALUE;
219 start_info.version = 1;
220 start_info.nr_modules = 0;
221 start_info.memmap_entries = 0;
222
223 (start_info, vec![memmap_entry], vec![modlist_entry])
224 }
225
226 #[test]
227 fn test_configure_pvh_boot() {
228 let (mut start_info, memmap_entries, modlist_entries) = build_bootparams_common();
229 let guest_memory = create_guest_mem();
230
231 let start_info_addr = GuestAddress(0x6000);
232 let memmap_addr = GuestAddress(0x7000);
233 let modlist_addr = GuestAddress(0x6040);
234 start_info.memmap_paddr = memmap_addr.raw_value();
235
236 let mut boot_params = BootParams::new::<hvm_start_info>(&start_info, start_info_addr);
237
238 assert_eq!(
240 PvhBootConfigurator::write_bootparams::<GuestMemoryMmap>(&boot_params, &guest_memory,)
241 .err(),
242 Some(Error::MemmapTableMissing.into())
243 );
244
245 let bad_start_info_addr = GuestAddress(
247 guest_memory.last_addr().raw_value() - mem::size_of::<hvm_start_info>() as u64 + 1,
248 );
249 boot_params.set_sections::<hvm_memmap_table_entry>(&memmap_entries, memmap_addr);
250 boot_params.header_start = bad_start_info_addr;
251 assert_eq!(
252 PvhBootConfigurator::write_bootparams::<GuestMemoryMmap>(&boot_params, &guest_memory,)
253 .err(),
254 Some(Error::StartInfoPastRamEnd.into())
255 );
256
257 let himem_start = GuestAddress(0x100000);
259 boot_params.header_start = himem_start;
260 let bad_memmap_addr = GuestAddress(
261 guest_memory.last_addr().raw_value() - mem::size_of::<hvm_memmap_table_entry>() as u64
262 + 1,
263 );
264 boot_params.set_sections::<hvm_memmap_table_entry>(&memmap_entries, bad_memmap_addr);
265
266 assert_eq!(
267 PvhBootConfigurator::write_bootparams::<GuestMemoryMmap>(&boot_params, &guest_memory,)
268 .err(),
269 Some(Error::MemmapTablePastRamEnd.into())
270 );
271
272 boot_params.set_sections::<hvm_memmap_table_entry>(&memmap_entries, memmap_addr);
273 boot_params.set_modules::<hvm_modlist_entry>(&modlist_entries, modlist_addr);
274 assert!(PvhBootConfigurator::write_bootparams::<GuestMemoryMmap>(
275 &boot_params,
276 &guest_memory,
277 )
278 .is_ok());
279 }
280
281 #[test]
282 fn test_error_messages() {
283 assert_eq!(
284 format!("{}", Error::MemmapTableMissing),
285 "PVH Boot Configurator: no memory map was passed to the boot configurator."
286 );
287 assert_eq!(
288 format!("{}", Error::MemmapTablePastRamEnd),
289 "PVH Boot Configurator: the memory map table extends past the end of guest memory."
290 );
291 assert_eq!(
292 format!("{}", Error::MemmapTableSetup),
293 "PVH Boot Configurator: error writing memory map table to guest memory."
294 );
295 assert_eq!(format!("{}", Error::StartInfoPastRamEnd), "PVH Boot Configurator: the hvm_start_info structure extends past the end of guest memory.");
296 assert_eq!(
297 format!("{}", Error::StartInfoSetup),
298 "PVH Boot Configurator: error writing hvm_start_info to guest memory."
299 );
300 }
301}