Files
s390-tools/rust/pvimg
Marc Hartmayer 6689e25865 rust: Fix all cargo clippy findings
- Remove useless type conversion in uvdevice.rs
- Replace useless comparison in hostname.rs
- Replace unnecessary unwrap patterns in pvapconfig
- Use sort_by_key instead of sort_by in pvimg example

Command line used to get the findings:

  $ clippy --all-features -- --cap-lints=warn
  warning: useless conversion to the same type: `u64`
    --> pv_core/src/uvdevice.rs:56:28
     |
  56 |         rc = ioctl(raw_fd, cmd.try_into().unwrap(), cb.as_ptr_mut());
     |                            ^^^^^^^^^^^^^^
     |
     = help: consider removing `.try_into()`
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion
     = note: `#[warn(clippy::useless_conversion)]` on by default

  warning: this comparison involving the minimum or maximum element for this type contains a case that is always true or always false
    --> utils/src/hostname.rs:60:13
     |
  60 |     assert!(isize::try_from(buf_len).unwrap() <= isize::MAX);
     |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     |
     = help: because `isize::MAX` is the maximum value for this type, this comparison is always true
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#absurd_extreme_comparisons
     = note: `#[warn(clippy::absurd_extreme_comparisons)]` on by default

  warning: `utils` (lib) generated 1 warning
      Checking pvebc v0.12.0 (/home/mhartmay/git/s390-tools/rust/pvebc)
  warning: consider using `sort_unstable_by_key`
     --> pvapconfig/src/ap.rs:177:9
      |
  177 |         self.0.sort_unstable_by(|a, b| b.gen.cmp(&a.gen));
      |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_sort_by
      = note: `#[warn(clippy::unnecessary_sort_by)]` on by default
  help: try
      |
  177 -         self.0.sort_unstable_by(|a, b| b.gen.cmp(&a.gen));
  177 +         self.0.sort_unstable_by_key(|b| std::cmp::Reverse(b.gen));

  warning: called `unwrap_err` on `r` after checking its variant with `is_err`
    --> pvapconfig/src/main.rs:55:29
     |
  54 |         if $r.is_err() {
     |         -------------- help: try: `if let Err(<item>) = r`
  55 |             eprintln!("{}", $r.unwrap_err());
     |                             ^^^^^^^^^^^^^^^
  ...
  87 |     on_error_print_and_exit!(r);
     |     --------------------------- in this macro invocation
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_unwrap
     = note: this warning originates in the macro `on_error_print_and_exit` (in Nightly builds, run with -Z macro-backtrace for more info)

  warning: this `repeat().take()` can be written more concisely
    --> pvimg/src/se_img_comps/bootloader/ipl.rs:95:21
     |
  95 |           let comps = iter::repeat(ipl_pb0_pv_comp::default())
     |  _____________________^
  96 | |             .take(num_comp)
     | |___________________________^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(ipl_pb0_pv_comp::default(), num_comp)`
     |
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n
     = note: `#[warn(clippy::manual_repeat_n)]` on by default

  warning: this `repeat().take()` can be written more concisely
     --> pvimg/src/se_img_comps/bootloader/ipl.rs:113:21
      |
  113 |         let comps = iter::repeat(comp).take(num_comp).collect();
      |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `repeat_n()` instead: `std::iter::repeat_n(comp, num_comp)`
      |
      = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_repeat_n

Reviewed-by: Timo Keller <tkeller@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Marc Hartmayer <marc@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2026-06-25 14:14:43 +02:00
..
2025-11-07 14:31:47 +01:00
2026-06-25 14:14:43 +02:00
2024-12-05 15:09:03 +01:00
2026-06-22 16:43:02 +02:00

pvimg

pvimg create takes a kernel, key files, optionally an initrd image, optionally a file containing the kernel command line parameters, and generates a single, bootable image file. The generated image file consists of a concatenation of a plain text boot loader, the encrypted components for kernel, initrd, kernel command line, and the integrity-protected Secure Execution header, containing the metadata necessary for running the guest in protected mode. See Memory Layout for details about the internal structure of the created image.

It is possible to use the generated image as a kernel for zipl or for a direct kernel boot using QEMU.

Getting started

If all dependencies are met a simple make call in the source tree should be enough for building pvimg.

Details

The main idea of pvimg create is:

  1. Generate all keys, IVs, and other information needed for the encryption of the components and the generation of the PV header
  2. add stub stage3a (so we can calculate the memory addresses)
  3. add components: prepare the components (alignment and encryption) and add them to the memory layout
  4. build and add stage3b: generate the stage3b and add it to the memory layout
  5. generate the Secure Execution header: generate the hashes (pld, ald, and tld) of the components and create the header and IPIB
  6. parameterize the stub stage3a: uses the address of the IPIB and Secure Execution header
  7. write the final image to the specified output path and generate the boot image metadata at address 0xc000. The address 0xc000 is chosen as this is the BSS section of the stage3a loader and will therefore zeroed out as soon as the stage3a is executed and has therefore no leftovers in the memory.

Boot Loader

The boot loader consists of two parts:

  1. stage3a boot loader (cleartext), this loader is responsible for the transition into the protected mode by doing diag308 subcode 8 and 10 calls.
  2. stage3b boot loader (encrypted), this loader is very similar to the normal zipl stage3 boot loader. It will be loaded by the Ultravisor after the successful transition into protected mode. Like the zipl stage3 boot loader it moves the kernel and patches in the values for initrd and kernel command line.

The loaders have the following constraints:

  1. It must be possible to place stage3a and stage3b at a location greater than 0x10000 because the zipl stage3 loader zeroes out everything at addresses lower than 0x10000 of the image.
  2. As the stage3 loader of zipl assumes that the passed kernel image looks like a normal kernel image, the zipl stage3 loader modifies the content at the memory area 0x10400 - 0x10800, therefore we leave this area unused in our stage3a loader.
  3. The default entry address used by the zipl stage3 loader is 0x10000 so we add a simple branch to 0x11000 at 0x10000 so the zipl stage3 loader can modify the area 0x10400 - 0x10800 without affecting the stage3a loader.

Stage3b

The stage3b.bin is linked at address 0x9000, therefore it will not work at another address. The relocation support for the stage3b loader, so that it can be loaded at addresses != 0x9000, is added in the loader with the name stage3b_reloc.bin. By default, if we're talking about stage3b we refer to stage3b_reloc.bin.

Memory Layout

The memory layout of the bootable file looks like:

Start End Use
0 0x7 Short PSW, starting instruction at 0x11000
0x0c000 0x0cfff Image metadata, e.g. it includes the file offset of the SE-header
0x10000 0x10012 Branch to 0x11000
0x10013 0x10fff Left intentionally unused
0x11000 0x12fff Stage3a
0x14000 0x1[45]fff SE-header used for the diag308 call (size can be either 1 or 2 pages)
NEXT_PAGE_ALIGNED_ADDR Encrypted kernel
NEXT_PAGE_ALIGNED_ADDR Encrypted kernel parameters
NEXT_PAGE_ALIGNED_ADDR Encrypted initrd
NEXT_PAGE_ALIGNED_ADDR Encrypted stage3b_reloc
NEXT_PAGE_ALIGNED_ADDR IPIB used as argument for the diag308 call