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