@@ -85,6 +85,39 @@ impl error::Error for Error {
85
85
}
86
86
}
87
87
88
+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
89
+ /// Availability of PVH entry point in the kernel, which allows the VMM
90
+ /// to use the PVH boot protocol to start guests.
91
+ pub enum PvhBootCapability {
92
+ /// PVH entry point is present
93
+ PvhEntryPresent ( GuestAddress ) ,
94
+ /// PVH entry point is not present
95
+ PvhEntryNotPresent ,
96
+ /// PVH entry point is ignored, even if available
97
+ PvhEntryIgnored ,
98
+ }
99
+
100
+ impl Default for PvhBootCapability {
101
+ fn default ( ) -> Self {
102
+ PvhBootCapability :: PvhEntryIgnored
103
+ }
104
+ }
105
+
106
+ impl Display for PvhBootCapability {
107
+ fn fmt ( & self , f : & mut :: std:: fmt:: Formatter ) -> fmt:: Result {
108
+ use self :: PvhBootCapability :: * ;
109
+ match self {
110
+ PvhEntryPresent ( pvh_entry_addr) => write ! (
111
+ f,
112
+ "PVH entry point present at guest address: {:#x}" ,
113
+ pvh_entry_addr. raw_value( )
114
+ ) ,
115
+ PvhEntryNotPresent => write ! ( f, "PVH entry point not present" ) ,
116
+ PvhEntryIgnored => write ! ( f, "PVH entry point ignored" ) ,
117
+ }
118
+ }
119
+ }
120
+
88
121
impl Display for Error {
89
122
fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
90
123
write ! ( f, "Kernel Loader Error: {}" , self . description( ) )
@@ -121,7 +154,9 @@ impl Elf {
121
154
impl KernelLoader for Elf {
122
155
/// Loads a kernel from a vmlinux elf image into guest memory.
123
156
///
124
- /// The kernel is loaded into guest memory at offset `phdr.p_paddr` specified by the elf image.
157
+ /// By default, the kernel is loaded into guest memory at offset `phdr.p_paddr` specified by the elf image.
158
+ /// When used, `kernel_offset` specifies a fixed offset from `phdr.p_paddr` at which to load the kernel. If
159
+ /// `kernel_offset` is requested, the `pvh_entry_addr` field of the result will not be populated.
125
160
///
126
161
/// # Arguments
127
162
///
@@ -204,8 +239,17 @@ impl KernelLoader for Elf {
204
239
for phdr in phdrs {
205
240
if phdr. p_type != elf:: PT_LOAD || phdr. p_filesz == 0 {
206
241
if phdr. p_type == elf:: PT_NOTE {
207
- // This segment describes a Note, check if PVH entry point is encoded.
208
- loader_result. pvh_entry_addr = parse_elf_note ( & phdr, kernel_image) ?;
242
+ // The PVH boot protocol currently requires that the kernel is loaded at
243
+ // the default kernel load address in guest memory (specified at kernel
244
+ // build time by the value of CONFIG_PHYSICAL_START). Therefore, only
245
+ // attempt to use PVH if an offset from the default load address has not
246
+ // been requested using the kernel_offset parameter.
247
+ if let Some ( _offset) = kernel_offset {
248
+ loader_result. pvh_boot_cap = PvhBootCapability :: PvhEntryIgnored ;
249
+ } else {
250
+ // If kernel_offset is not requested, check if PVH a entry point is present
251
+ loader_result. pvh_boot_cap = parse_elf_note ( & phdr, kernel_image) ?;
252
+ }
209
253
}
210
254
continue ;
211
255
}
@@ -250,7 +294,7 @@ const PVH_NOTE_STR_SZ: usize = 4;
250
294
/// with paging disabled, as described by the PVH boot protocol.
251
295
/// Returns the encoded entry point address, or `None` if no `XEN_ELFNOTE_PHYS32_ENTRY` entries are
252
296
/// found in the note header.
253
- fn parse_elf_note < F > ( phdr : & elf:: Elf64_Phdr , kernel_image : & mut F ) -> Result < Option < GuestAddress > >
297
+ fn parse_elf_note < F > ( phdr : & elf:: Elf64_Phdr , kernel_image : & mut F ) -> Result < PvhBootCapability >
254
298
where
255
299
F : Read + Seek ,
256
300
{
@@ -299,7 +343,7 @@ where
299
343
300
344
if read_size >= phdr. p_filesz as usize {
301
345
// PVH ELF note not found, nothing else to do.
302
- return Ok ( None ) ;
346
+ return Ok ( PvhBootCapability :: PvhEntryNotPresent ) ;
303
347
}
304
348
305
349
// Otherwise the correct note type was found.
@@ -324,7 +368,7 @@ where
324
368
. read_exact ( & mut pvh_addr_bytes)
325
369
. map_err ( |_| Error :: ReadNoteHeader ) ?;
326
370
327
- Ok ( Some ( GuestAddress (
371
+ Ok ( PvhBootCapability :: PvhEntryPresent ( GuestAddress (
328
372
u32:: from_le_bytes ( pvh_addr_bytes) . into ( ) ,
329
373
) ) )
330
374
}
@@ -457,15 +501,34 @@ mod tests {
457
501
let gm = create_guest_mem ( ) ;
458
502
let pvhnote_image = make_elfnote ( ) ;
459
503
let loader_result = Elf :: load ( & gm, None , & mut Cursor :: new ( & pvhnote_image) , None ) . unwrap ( ) ;
460
- assert_eq ! ( loader_result. pvh_entry_addr. unwrap( ) . raw_value( ) , 0x1e1fe1f ) ;
504
+ assert_eq ! (
505
+ loader_result. pvh_boot_cap,
506
+ PvhBootCapability :: PvhEntryPresent ( GuestAddress ( 0x1e1fe1f ) )
507
+ ) ;
508
+
509
+ // Verify that PVH is ignored when kernel_start is requested
510
+ let loader_result = Elf :: load (
511
+ & gm,
512
+ Some ( GuestAddress ( 0x0020_0000 ) ) ,
513
+ & mut Cursor :: new ( & pvhnote_image) ,
514
+ None ,
515
+ )
516
+ . unwrap ( ) ;
517
+ assert_eq ! (
518
+ loader_result. pvh_boot_cap,
519
+ PvhBootCapability :: PvhEntryIgnored
520
+ ) ;
461
521
}
462
522
463
523
#[ test]
464
524
fn test_dummy_elfnote ( ) {
465
525
let gm = create_guest_mem ( ) ;
466
526
let dummynote_image = make_dummy_elfnote ( ) ;
467
527
let loader_result = Elf :: load ( & gm, None , & mut Cursor :: new ( & dummynote_image) , None ) . unwrap ( ) ;
468
- assert ! ( loader_result. pvh_entry_addr. is_none( ) ) ;
528
+ assert_eq ! (
529
+ loader_result. pvh_boot_cap,
530
+ PvhBootCapability :: PvhEntryNotPresent
531
+ ) ;
469
532
}
470
533
471
534
#[ test]
0 commit comments