Compare commits

..

196 Commits

Author SHA1 Message Date
Jan Höppner
0cd063e40d New release s390-tools-2.36.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 12:24:57 +01:00
Jan Höppner
4d97e15eb0 s390-tools: Update README.md and rust/README.md
Add missing build requirements and dependency information to README.md
and rust/README.md.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 11:33:48 +01:00
Jan Höppner
a32fe8641a gitignore: Update gitignore
Add opticsmon and remove old pvattest.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 11:33:48 +01:00
Niklas Schnelle
c34adb9cab opticsmon: Introduce opticsmon tool
The optics monitoring tool opticsmon implements the user-space portion
of reporting optics data to the SE. Its basic functionality is to
collect optical module information equivalent to "ethtool --module-info"
for PCI Physical Functions and forwards this data to the SE using the
new SCLP Write Event Data Action Qualifier 3.

For the part of finding all PFs we need to look at all PCI
functions and determine which ones are PFs and what netdevs they
correspond to. This is a generally useful functionality so this part as
well as the SCLP issuing code go into a new libzpci library which also
includes a standalone example for listing PCI functions and their s390x
specific attributes. Medium term we plan to add this functionality to
lszdev.

For the opticsmon tool itself there are 2 basic operating modes:

* One-shot Mode: Without parameters opticsmon collects optical module
  data and prints a summary of the netdevice in JSON format. With
  --module-data it also includes a base64 encoded raw dump equivalent to
  ethtool --module-info <netdev> raw on.
* Monitor Mode: With the --monitor flag opticsmon runs continuously
  usually started via a systemd unit and collects new optical module
  data on a time interval (default 24h) or when the operational state
  ("/sys/class/net/<netdev/operstate") changes. The tool listens for
  changes via netlink so no polling on sysfs is necessary

Note: Both modes will *NOT* issues SCLPs without adding the
--send-report flag but will output a JSON summary for each data
collection so can be tested without firmware impact.

Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Niklas Schnelle
86b5df0d2d libzpci: Add helper to check if a PCI function is a VF
Add zpci_is_vf() helper based on the /sys/bus/pci/devices/<dev>/vfn
attribute which is non-zero for VFs unlike the common code VF number
which starts at 0.

Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Niklas Schnelle
e0caed5534 libzpci: Add operational state for netdevs
The operational state is read from sysfs but can later also be updated
via AF_NETLINK.

Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Niklas Schnelle
8704c9c80e zpcictl: Pull SCLP handling out and into libzpci
The upcoming optics monitoring tool will have to issue SCLP Write Event
data just like zpcictl so pull that functionality out and into libzpci.
While at it decouple getting SMART data from the actual SCLP handling.
No change in behavior intended.

Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Niklas Schnelle
4ec33d0b76 zpcictl: Use actual instead of max length in SCLP report
The SCLP report currently always uses the maximum length even if no
extra data is proved at all. Instead use the actual length of either
just the timestamp and err_log_id or additionally the length of sdata.

Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Niklas Schnelle
3a4c20b443 libzpci: Introduce libzpci
This introduces libzpci which is a library intended to handle s390x
specific PCI attributes and peculiarities. As a first step it introduces
code to list PCI devices on s390x including an initial set of s390x
specific attributes like FID, PFT, UID etc. It also collects information
on network device associated with a particular PCI function. The
included example serves as a demonstration of using libzpci to list PCI
devices.

Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Niklas Schnelle
c54a915a90 libutil: Add stdio.h include in util_file.h
Without including stdio.h before util_file.h tye FILE type will not be
known leading to a build failure. Fix this by including stdio.h.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-06 10:57:34 +01:00
Steffen Eiden
bc269ddb38 rust: Update rust crates version to 0.11.0
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 17:03:25 +01:00
Marc Hartmayer
8c21f09570 rust/genprotimg: Add '--help-all' and '--help-experimental' for backward compatibility
The '--help-all' and '--help-experimental' flags are now considered
deprecated, but should still be available for backward compatibility.

Fixes: f4cf4ae6eb ("rust: Add a new tool called 'pvimg'")
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 16:56:55 +01:00
Steffen Eiden
4df0781989 rust/pvattest: Improve check and verifiy documentation
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:44:17 +01:00
Marc Hartmayer
195579cf0b Remove genprotimg-C and switch to genprotimg-Rust implementation
Removes the C implementation of genprotimg and use the Rust
implementation instead.

Adapt the README.md accordingly.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:44:09 +01:00
Marc Hartmayer
849819cb77 rust/pvimg: Add manpages for 'pvimg' and 'genprotimg'
Add manpages for 'pvimg' and 'genprotimg'.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
72aa64495c rust/genprotimg: Add support for '--(enable|disable)-(pckmo-hmac|backup-keys)'
Add support for enabling/disabling the backup keys and HMAC-PCKMO key
encryption function plaintext control flags in the Secure Execution
header.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
d2de7f2808 rust/(pv|pvimg): Add Secure Execution boot image metadata
Add metadata about the image to the Secure Execution image. This helps
to identify where the Secure Execution header is located in the image
and therefore it's less prone to errors to locate the header.

This patch adds the support for it to 'pvimg' as well as to the
'pvsecret' and 'pvattest' tools.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
f4cf4ae6eb rust: Add a new tool called 'pvimg'
Add a new tool called 'pvimg' that can be used to create and inspect
Secure Execution images. It has several subcommands:

 + create: create an IBM Secure Execution image (genprotimg compatible
	  sytnax) and C-'genprotimg' is going to be replaced by a
	  symlink to this subcommand.
 + test: test various aspects of an existing Secure Execution image
 + info: print information about an existing Secure Execution
	 image (experimental API!)
 + version: print version and exit

As mentioned above, the 'genprotimg' tool is now a symbolic link to the
'pvimg create' subcommand and the CLI is backward compatible with the
original genprotimg CLI, with the following exceptions:

  - '-v' increases the verbosity instead of showing the version
  - '-V' is now deprecated in favor of '-v'
  - an existing output file is no longer silently overwritten, but there
    is a new flag '--overwrite' to get the original behavior
  - experimental options are no longer described in the help
  - the commands '--cert ...' and '--root-ca' are now mutually exclusive
  - to '--no-verify'
  - there is now a component check, e.g. it checks if the specified
    Linux kernel looks like a raw binary s390x kernel. These checks can be
    disabled by using the new command line flag '--no-component-check'

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
f524b0b8dc rust/pvimg: Add 'tools/check_hostkeydoc' script
This is done in preparation for the Rust port of genprotimg.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
f99719a695 rust/pvimg/boot: Hard code location and size of the stage3a BSS section
Hardcode the location and size of the BSS section of stage3a to 0xc000
and 0x1000. This change is made in preparation for storing the Secure
Execution image metadata at the address of the BSS section of stage3a.
The idea behind this is that since there is no ELF loader involved, the
stage3a loader will memset it's BSS section and therefore the Secure
Execution image metadata to 0. This way, it's avoided having any
leftover metadata after running the stage3a loader.

In addition, add .bss.* as input sections for the .bss section.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
7d81c1bbd4 rust/pvimg: Copy genprotimg/boot to rust/pvimg/boot
This change is done in preparation for the Rust port of genprotimg.

While at it, format the code using `clang-format`.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
2ed2c608ab rust/pvimg: Add a Secure Execution header library and an example how to use
The new Rust port of genprotimg will have the name 'pvimg' as it has
more functionalities than the original genprotimg tool. As preparation
add a Secure Execution header library and an example how to use it. The
example can be used by the KVM-Unit-Tests for creating the Secure
Execution headers needed by the tests [1].

[1] See dc4f7106f3
more information how to use.

Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
d73f4dc22a rust/utils: Add 'ExitCodeTrait' and an macro that implements the trait
A manpage auto-generation tool can use this trait to get the exit codes
and their documentation of a program.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
ea297ecf84 rust: Add missing license headers
Command used:

 $ rg --files-without-match --type rust '^// SPDX-Licen' --null | xargs -0 -I {} sed -i '1 i\// SPDX-License-Identifier: MIT\n//\n// Copyright IBM Corp. 2024\n' {}

Reviewed-by: Julian Ruess <julianr@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
7d41430e68 rust/pv: Refactor seek_se_hdr_start and export the function
Refactor `seek_se_hdr_start` so it can be reused. While at it, improve
the documentation of it and format the code.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
f095a892b9 rust/utils: Improve documentation wording
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
646a389b53 rust/utils: VerbosityOptions: Make sure the options are listed last
See
https://docs.rs/clap/latest/clap/struct.Arg.html#method.display_order
for details.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
66ef6b5945 rust/pvapconfig: Fix 'doc list item without indentation'
Command used:

$  cargo +nightly clippy
...
warning: doc list item without indentation
  --> pvapconfig/src/ap.rs:71:5
   |
71 | /// This may take some time and even loop forever if there

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
6c75a06b12 pvattest: Use map_or and map_or_else
Replace 'match .. { Some(v) => y, None/_ => x }' statements with
'Option::map_or_else' and 'Option::map_or'. See
https://rust-lang.github.io/rust-clippy/master/index.html#option_if_let_else.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
b1ca60f5ba rust: Automatically generated Clippy fixes for the tools only
Clippy settings:

[workspace.lints.clippy]
cognitive_complexity = "warn"
dbg_macro = "warn"
debug_assert_with_mut_call = "warn"
doc_link_with_quotes = "warn"
doc_markdown = "warn"
empty_line_after_outer_attr = "warn"
empty_structs_with_brackets = "warn"
float_cmp = "warn"
float_cmp_const = "warn"
float_equality_without_abs = "warn"
missing_const_for_fn = "warn"
missing_errors_doc = "warn"
mod_module_files = "warn"
option_if_let_else = "warn"
similar_names = "warn"
suspicious_operation_groupings = "warn"
unused_self = "warn"
use_debug = "warn"
used_underscore_binding = "warn"
useless_let_if_seq = "warn"
wildcard_dependencies = "warn"
wildcard_imports = "warn"

Command used:

  $ cargo +nightly clippy --fix

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
3d83100fa3 rust/utils/(tmp)file: Add missing license headers
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
8c23e09a60 rust/pv_core: Fix the argument order in 'LengthMismatch'
Fix the ordering of the parameters in 'TryFrom<Confidential<Vec<u8> for
Confidential<[u8; N>'. While at it, convert 'LengthMismatch' error to a
named struct.

Fixes: 7608cf2de4 ("rust/confidential: Add `From` and `Into` for confidential byes arrays/vectors")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-12-05 15:09:03 +01:00
Marc Hartmayer
24e285ce02 common.mak: Use '?=' assignment operator for 'CROSS_COMPILE'
This fixes the following error:

$ make CROSS_COMPILE=s390x-linux-gnu- HOST_ARCH=s390x
../../../common.mak:117: *** Please specify CROSS_COMPILE=... and try it again!.  Stop.

$ make --version
GNU Make 4.4.1

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Marc Hartmayer
ad709c1eaf README.md: Update dependencies for pvattest
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Marc Hartmayer
b61596327b rust: Upgrade openssl to 0.10.66
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Peter Oberparleiter
de18a72249 chpstat: Add data bandwidth utilization column
Add column 'UTIL DATA' that indicates the percentage of channel-path
data bandwidth currently in use. Since channel-paths are bidirectional,
this column represents the maximum of read or write bandwidth
utilization.

Also use this new column in place of 'UTIL BUS' for CMG 4 and 5 default
views since the bus utilization no longer provides a relevant value for
DPU-based channel-path types.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Peter Oberparleiter
482bd93e2e chpstat: Add support for new CMG types
New machine models introduce CHPIDs with two new CMG types 4 and 5.
Add support for decoding the associated channel-measurement data.

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Peter Oberparleiter
026ecbafea chpstat: Add support for full CMCB
Newer kernels provide the full, unfiltered Channel-Measurements
Characteristics Block (CMCB) via a new sysfs attribute named
"measurement_chars_full".

Add support for reading the full CMCB data if available in preparation
of new tool functions that will make use of this data.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
40846bce49 hyptop: Update man page for structured output
Add information about the new command line flag for formatted output and
output formats.

Reviewed-by: Maria Eisenhändler <maria1@de.ibm.com>
Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
b9879cbfc7 hyptop: Don't show visualization in structured output
The utilization visualization column does not provide meaningful data
when using structured output. Omit it when an output format has been
specified on the command line.

Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
e61ed4f433 hyptop: Support for structured output
Introduce a new command line flag ("--format") to specify the output
format in batch mode. Valid options are "pairs" for shell-compatible key
value pairs, "csv" for CSV, "json" for a formatted JSON document, and
"json-seq" for a stream of JSON text sequences as per RFC7464[1].

[1]: https://datatracker.ietf.org/doc/html/rfc7464

Note: Specifying the --format flag implies the --batch_mode flag.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
589090f79a hyptop: Move separator line to table update
The separator line is written as part of the input processing step and
is better be moved to the place where the table is actually written.
Same goes for the terminating '\n' which is performed as the final step
while updating the terminal in batch mode.

While at it, use the designated print functions over raw printf().

Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
57eef7c412 hyptop: Keep track of string-typed columns
For structured output (i.e. JSON), some type information of the columns
is required, at least the ability to distinguish values that are strings
and possibly need to be quoted. Unfortunately at the time column values
are formatted this information is lost.

The column types are specified implicitly during the unit conversion of
the raw value. For example, online time is stored as a u64 value but is
converted into a "d:h:m" string.

Introduce a private flag per column that signifies if that column is to
be formatted as a string. This flag will be set in the appropriate unit
conversion function.

Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
d864c55336 libutil: Introduce util_str_tolower()
Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Bjoern Walk
1b18ba3a03 hyptop: Switch to util_str_toupper()
Instead of implementing our own version, use the available library
function util_str_toupper() from libutil.

Reviewed-by: Mete Durlu <meted@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Bjoern Walk <bwalk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-11-29 15:52:24 +01:00
Marc Hartmayer
938fe2a744 rust/utils: Add AtomicFile
This type helps to perform atomic operations by writing to a temporary
file and renaming it to the actual filename when the
`AtomicFile::finish` function is called. If the `AtomicFile::finish`
function is never called, the temporary file is automatically removed
when it goes out of scope. It utilizes the `renameat2` [1] libc function
and its semantics.

[1] https://man7.org/linux/man-pages/man2/renameat.2.html
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:02 +01:00
Marc Hartmayer
171432852b rust/crypto: Add try_from_data for SymKey
This function makes it easy to convert (confidential) data into a
SymKey.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:02 +01:00
Marc Hartmayer
7608cf2de4 rust/confidential: Add From and Into for confidential byes arrays/vectors
Implement `TryFrom<Confidential<Vec<u8>> for Confidential<[u8; N]>` and
`From<Confidential<[u8; N]> for Confidential<Vec<u8>>`.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:02 +01:00
Marc Hartmayer
e480c4738d rust/pv: Format lib.rs and req.rs
Command line used:

  rustfmt --config group_imports=StdExternalCrate,imports_granularity=Crate
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:02 +01:00
Marc Hartmayer
4cd7e8fd9a rust/crypto: Improve AEAD en-/decryption functions
Rename "Authenticated Encryption with Associated Data" (AEAD)
encryption/decryption functions and change the result type. This makes
the functions easier extendable. In addition, it's now possible to use
the functions as following:

`encrypt(decrypt(data)) == decrypt(encrypt(data) == data`

Add more AES and SHA related constants and use them whenever possible.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:02 +01:00
Marc Hartmayer
f1b94abefa rust/pv_core: Implement Zeroize trait for u* and i* primtives
Use a macro for the trait implementations.
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Marc Hartmayer
5a54722848 rust/crypto: Implement Display for SymKeyType
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Marc Hartmayer
cb0e119bed rust/pv_core: Add From<Msb0Flags64> and From<Lsb0Flags64 for u64
That way it's possible to convert a u64 to (Msb|Lsb)0Flags64 and vice
versa.
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Marc Hartmayer
081a055115 rust/pv: Export Encrypt trait
Export `Encrypt` trait so it can be used outside of the `pv` crate.
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Marc Hartmayer
6e27c2f2e9 rust: Rename Aes256* to Aes256Gcm* and export it
Rename `Aes256*` to `Aes256Gcm*` and add a deprecated constant with the
old name for backward compatibility. Adapt existing code to use the new
enum variant.
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Marc Hartmayer
d1d0bd39ba rust/pv_core: Document possible errors of open_file and create_file
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Marc Hartmayer
8d0c620257 rust/pv: Add get_test_key_and_cert
Useful for tests that also check the host-key document.
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Mikhail Zaslonko
d1884db236 zipl/boot: Add assertion of the dumper size to the linker script
Update eckd2dump linker script with assertions of single-volume and
multi-volume DASD dumper size.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Mikhail Zaslonko
73f211ecb1 zipl/boot: Combine linker scripts for CCW DASD dumpers
Combine linker scripts for single volume and multi-volume ECKD dumpers
to avoid duplicating. Use C preprocessor to define conditional symbols.
Cleanup the generic stage2 linker script(stage2.lds). Since it is still
used for FBA and TAPE dumpers (fba2dump and tape2dump) the .stage2dump.tail
section should be preserved.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Mikhail Zaslonko
8d2290977b zipl/boot: Move MVDUMP_TOOL_SIZE to loaders_layout.h
Move MVDUMP_TOOL_SIZE contsant to loaders_layout.h and rename it
to STAGE2_DUMPER_SIZE_MV.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
25aac53d52 rust/pvsecret: Fix secret info file location
Write the secret metadata into the same directory as the generated
secret request. Before, the metadata was accidentally written into the
working directory.

Fixes: dd82c26f87 ("rust: Add tool to manage UV-secrets")
Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
6b75568750 rust/pvattest: Update manuals and README
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
7cc131880c rust/pvattest: Firmware version check
Check if the SE-guests machine firmware is in an IBM approved state.
The machine firmware version can be obtained via setting a flag in the
attestation request.

The opaque 320 byte value from firmware is forwarded to an IBM server
that verifies the firmware value and confirms if the machine is in an
IBM approved firmware state.
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
26465e37d7 rust/pvattest: Secret-store hash check
Add a check to verify the hash over the Secret Store in the guest UV
storage. During 'create' the user can request that hash via a flag. During
'check' the user specifies the Add Secret requests and check whether the store is
locked. If the calculated hash over this state matches the one reported
by attestation, this check is successful.
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
697dcc0f6b rust/pvattest: Add check command
Add a new command: check. This allows users to perform policy checks on
the Attestation result.
The host-key hashes, and the user-data can be tested for certain values.

While at it fix some typos and enable CSV parsing for the Additional-data flags.

Example:
```
pvattest check attestresp checkresult -k hkd0.crt,hkd1.crt
--host-key-check AttKeyCheck
```
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
ac7f866237 rust/pvsecret: Cleanup CLI
Fix some typos/wordings and enable CSV parsing for the Additional-data flags.
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
339ad5c2ed rust/pv: Add new attestation additional-data flags
Add additional data for the Attestation request. The secret store hash
measures all added secrets and the state of the store (locked or not)
with a single hash. The hash is computed by concatenating all add-secret
request tags (16 bytes each) and a byte stating the locked state (1 for
locked, 0 for not locked). The firmware state is an opaque state
description of the systems firmware status to be interpreted by an IBM
service. Add request flags and fields in the additional data structure.
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:01 +01:00
Steffen Eiden
48f1e0da0a rust/pv: Add unrecognized field to additional-data handling
Add an unrecognized field to the AdditionalData struct that contains any
data that is not known by the library. Generalize the intention of the
additional data read function and make extensions to Additional data
easier. Add tests for serialization.
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Steffen Eiden
413adbe7bb rust/pv: Rename additional-data size constant
Rename 'ATT_ADD_HASH_SIZE' to 'PHKH_SIZE'. The new name describes the
value better. It is the size of the Public Host-Key Hash and not the
size of a generic additional-data item.
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Marc Hartmayer
667a8d714b rust: Fix cargo clippy and cargo doc findings
Fix the new `cargo clippy` and `cargo doc` findings that were triggered
with the recent policy addition.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Marc Hartmayer
2155b83c1f rust: Add more useful linting rules
See

https://doc.rust-lang.org/rustc/lints/groups.html
https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents

For `missing_docs` there must a priority specified to fix the following
error:

  warning: lint group `unused` has the same priority (0) as a lint
    --> Cargo.toml:25:1
     |
  19 | missing_docs = "deny"
     | ------------ has the same priority as this lint
  ...
  25 | unused = "warn"
     | ^^^^^^   ------ has an implicit priority of 0
     |
     = note: the order of the lints in the table is ignored by Cargo
     = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#lint_groups_priority
     = note: `#[warn(clippy::lint_groups_priority)]` on by default
  help: to have lints override the group set `unused` to a lower priority
     |
  25 | unused = { level = "warn", priority = -1 }
     |          ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Marc Hartmayer
e6c17461a3 rust: Provide and use a workspace.lints table
Provide and use a `workspace.lints` table. This makes it easier to
maintain and to enforce one coding style. Let's explicitly disable the
`missing_docs` linting rule for tests.

MSRV for the lints table is 1.74 [1]

[1] https://doc.rust-lang.org/cargo/reference/workspaces.html#the-lints-table

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Finn Callies <fcallies@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Ingo Franzki
f68d3932c7 zkey: Update list of kernel modules for initrd
With the recent changes in the pkey kernel module to split it up into
sub-modules, as well as the addition to support Secure Execution
retrievable secrets, an update to the list of modules to copy to
initrd is required.

Besides the pkey module itself, all its sub-modules must be copied.
Furthermore, sub-module pkey_uv requires the uvdevice modules, so copy
this, too.

While at it, remove the old drivers zcrypt_cex2a and zcrypt_pcixcc,
those are not provided anymore since at least 2 years.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Eduard Shishkin
81f3845f34 zipl/src: Use definitions for the fixed string values
Use definitions for the fixed string values provided by util_proc

Suggested-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:20:00 +01:00
Steffen Eiden
75820cf62d Makefile: Do not quote install targets
Sync all install targets implementations. Some did quote the target
directories some don't. Remove all quotations. This fixes wrong install
locations of install paths that have a '~'. With quotes '~' is
interpreted literally instead of using the home dir.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:19:57 +01:00
Steffen Eiden
3f0dc6b3af rust/pv: Get request-tag for add-secret requests
Enables API users to get the request tag of an Add-Secret request.
This enables them to check for attestation policies.
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Eiden
db6c500e6d rust/pv: Get authenticated data from a binary attestation request
Allows API users to inspect the value of additional data to use it as
part of a policy check.
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Eiden
578b77072a pv/utils: Improve HexSlice implementation
Add more unit-tests and useful derives.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
f94e9e9352 rust/pv: Explicitly reduce BinReqValues visibility
This struct is not exported. Prevent any accidental exports by reducing
the visibility to pub(crate).

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
079ae1e24d rust/utils: Improve TemporaryDirectory APIs
Rename the previous "default" `new` constructor [1] to `with_prefix` and
add a new default `new` constructor that takes no argument is therefore
easier to use.

In addition, improve the overall documentation, add more tests, and
examples to the code.

[1] https://doc.rust-lang.org/nomicon/constructors.html
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
2f3c189fda rust/crypto: Export gen_ec_key and open-code the SECP521R1 NID
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
dec796d52f rust/crypto: Export random_array
The function is useful, therefore export it.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
385ba6b51f rust/crypto: Replace From<Aes256Key> for SymKey with enum_dispatch macro
Use the `enum_dispatch` macro for providing the `From` and `TryInto`
functionalities. In addition, it makes dynamic dispatching using enums
much easier.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
050441922b rust/crypto: Add key_type method to SymKey impl
This function is easier to be used than a match! statement.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
567cbce8a8 rust/crypto: Implement From<SymKeyType> for Nid
Implement `From<SymKeyType> for Nid`. This makes it easier to implement
generalized functions.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
eee29e0399 rust/crypto: Rename derive_key to derive_aes256_gcm_key and export it
This is currently the only key type supported, therefore rename the
function to make this clear. In addition, improve the documentation of
the function as function is now exported.
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
a0a8aa47a8 rust/crypto: Add Aes256Xts to SymKey
This type can be used for AES 256 XTS encryption.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
fe2946f76c rust/pv: Fix some comments
The library is used by multiple PV related tools, not only for managing
the guest secret store.
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Eiden
17aba9322e rust/pv: Export EcPubKeyCoord
Make EcPubKeyCoord available, after renaming it from EcdhPubkeyCoord.
This enables API users to calculate the hash of a public host-key and
compare it to a hash from attestation.
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Eiden
53d803abf3 rust: Streamline and cleanup verbosity handling
Create one implementation for the verbose option to be used by all
tools. While at it, add a quiet option to decrease the verbosity.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Alexander Egorenkov
576a230341 util_arch: Use dump area size provided by kernel through sysfs attribute
Newer s390 kernels provide the new sysfs /sys/firmware/dump/dump_area_size
attribute which specifies the exact size of machine's dump area size.
Use this value if it is present but fall back to the previous and
slightly improved way of computation of dump area size to support
also older s390 kernels w/o the new sysfs attribute. This has
the advantage that util_arch_hsa_maxsize() has no longer to be adapted
with every introduction of yet another machine type in the future.

Suggested-by: Heiko Carstens <hca@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
bdaef6e76d lszfcp: associative array speeds up extended SCSI device list a lot
The linear search in the nested loop over SCSI devices and over the indexed
array is still time consuming. So replace the indexed array with an
associative array. Build the array once outside of the nested loop by using
pathname expansion and extracting key and value from each item. Within
the SCSI device loop, an array entry is removed by means of the key without
linear search.

This commit is separate from the previous one so it is possible to revert
this one in case associative arrays would not be available and still get
the speed improvement from the indexed array in the previous commit.

Before:

$ time ~/git/s390-tools/zconf/lszfcp -De | wc -l
1036

real	0m17.605s
user	0m17.159s
sys	0m0.308s

After:

$ time ~/git/s390-tools/zconf/lszfcp -De | wc -l
1036

real	0m0.207s
user	0m0.175s
sys	0m0.032s

Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
e6c73c9974 lszfcp: indexed array speeds up extended SCSI device list
Apparently the repeated string concatenation and word splitting was
much slower.

While at it, also remember in $ZFCP_UNIT_PATH whether the loop over
ZFCP_UNIT_ARRAY already found a zfcp_unit and re-use the path string to
replace the previous file glob construct generating the zfcp_unit path by
means of pathname expansion. This only works for the extended output case.

Before:

$ time lszfcp -De | wc -l
1036

real	2m15.387s
user	2m9.323s
sys	0m5.130s

After:

$ time ~/git/s390-tools/zconf/lszfcp -De | wc -l
1036

real	0m17.605s
user	0m17.159s
sys	0m0.308s

Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
d4316c155c lszfcp: save a stat syscall on the SCSI device loop hot path
Just go ahead and read the sysfs attribute directly as the syscalls are
needed anyway.
If necessary stderr could be redirected to /dev/null in the future,
but there was no case so far where the attribute did not exist.

This does not make a runtime difference when running on sysfs. Change it
anyway to avoid somebody searching for speed improvement options stumbling
over it again.

Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
a4f4337060 lszfcp: more specific file glob patterns are better for SCSI device list
It's not on the hot path as the glob match is done only once.
But there is no point in matching anything but SCSI devices
such as "fc_transport" and "subsystem"
just to have an additional child process filter it once more.

Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
32dbfc4712 lszfcp: eliminate costly child process for each SCSI device
A simple built-in parameter expansion removing the matching prefix
pattern (everything up to and including the last slash) is sufficient to
strip the path from the basename.

Speeds up "lszfcp -D" significantly.

Before:

$ time ~/git/s390-tools/zconf/lszfcp -D | wc -l
1028

real	0m5.322s
user	0m0.300s
sys	0m4.907s

After:

$ time ~/git/s390-tools/zconf/lszfcp -D | wc -l
1028

real	0m0.602s
user	0m0.100s
sys	0m0.492s

Above measurements are from the fast in-memory sysfs. The improvements are
likely amplified when running "lszfcp --sysfs ..." on collected debug data
in a regular file system.

Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
63142e3051 lszfcp: show device names line for zfcp_units without SCSI device
The verbose output for SCSI devices consists of 3 lines:
1. <path to zfcp_unit>
2. <path to SCSI device>
3. <path to block device> <path to SCSI generic sysfs>

The last line was missing for (failed) zfcp_units without SCSI device.

Before:

$ lszfcp -DeV
/sys/devices/css0/0.0.001b/0.0.1880/0x500507630908d430/0x401540fb00000000
/sys/bus/ccw/drivers/zfcp/0.0.1880/host0/rport-0:0-1/target0:0:1/0:0:1:1090207765
/sys/block/sda /sys/class/scsi_generic/sg0
/sys/devices/css0/0.0.001b/0.0.1880/0x500507630908d430/0xdead000000000000 failed
-

After:
$ lszfcp -DeV
/sys/devices/css0/0.0.001b/0.0.1880/0x500507630908d430/0x401540fb00000000
/sys/bus/ccw/drivers/zfcp/0.0.1880/host0/rport-0:0-1/target0:0:1/0:0:1:1090207765
/sys/block/sda /sys/class/scsi_generic/sg0
/sys/devices/css0/0.0.001b/0.0.1880/0x500507630908d430/0xdead000000000000 failed
-
- -

Fixes: f67758160e ("lszfcp: allow to show zfcp_units without associated SCSI device")
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Steffen Maier
464d4d2842 lszfcp: add missing fallback marker for non-good fc_host port_state
An online CCW device, which is available and not defunct and not failed,
can have an undesired fc_host port_state, which is not Online and does not
have the special case Linkdown. Indicate such unexpected state.

Complements
v2.9.0 commit 4036e80b26 ("lszfcp: add new output marker for non-good FCP
devices (hosts)")
v2.9.0 commit be7b854969 ("lszfcp: also mark FCP devices (hosts) that are
not available")
v2.18.0 commit 45e3f016f4 ("lszfcp: add linkdown case to host marker of
extended output")

Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:18:37 +01:00
Marc Hartmayer
b378ff788e rust/pv_core: Add Error section for decode_hex documentation
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:17:19 +01:00
Marc Hartmayer
20f1c0e2ea rust/pv: Replace PKey with Self
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Peter Oberparleiter
54e175a783 chpstat: Improve --cmg value parsing
Switch from atoi() to existing parse_int() helper function for parsing
the integer --cmg argument to better handle invalid values such as
numbers followed by an unsupported suffix (e.g. 1x).

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Mikhail Zaslonko
30dc1a5ddd zdump/dfi_vmdump: Consider vmdump requested memory ranges
At the moment the memory range of processed vmdump always corresponds to
the highest defined byte (q v storage) obtained from Address Space
Information Block ignoring memory ranges specified in CP vmdump command.
This might lead to the invalid dump size calculation upon conversion to
s390 format.
Use Requested Range Table from ASIZBK to identify actual memory ranges
being dumped. Consider the end of the highest memory range as a vmdump
upper limit (dump memory size). In case no range table entries present
fall back to the original method using 'storage_size_def_store' value.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Eduard Shishkin
47460e6e33 zipl/src: Support md-partitions as zipl targets
This patch adds support for zipl targets over partitions of md-devices.
With this patch it is possible to specify a zipl target over any
partition of an md-device, so that all the physical disks participating
in the mirrored setup will be prepared for IPL.

Unlike a whole md-device which has major number 9, its partitions
have major numbers 259 and the driver name is identified as 'blkext'
in '/proc/devices'. Handle this case in set_driver_name(): call ioctl()
to make sure that device is an md-partition.

Drop re-definition of some macros.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Joern Siglen
6fc13a0ff4 dbginfo.sh: add overview and crypto update
Add "zhypinfo" as an overview on Hypervisor structure in runtime.out
Get an overview of all block devices in front of the detailed outputs
using "lsblk" into runtime.out
Starting OpenSSL3.0 "openssl engine" is deprecated and needs replacement by:
"openssl list --providers" (keep "engine" for older versions)

Suggested-by: Christian Rund <Christian.Rund@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Steffen Eiden
5751c08627 s390-tools/rust: Define MSRV as 1.75.0
Define and set the minimal supported Rust version (MSRV) to 1.75.0. This
is the (current) minimal supported version over all supported distros
that use rust in s390-tools.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Steffen Eiden
5e97205530 rust/pv_core: Implement Zeroroize for String
String is more or less a Vec<u8> with some extra invariants (i.e. only
UFF-8 chars). Zeroroize is implemented by calling the Vec<u8>
implementation. The zero byte is a valid UTF-8 symbol. The String
invariant is uphold by the clearing code.

Also, implement a into_inner function for clone-able inner types.
This allows converting confidential types into no-confidential types.
As Drop is implemented this requires a clone (see E0509).

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Steffen Eiden
0495947604 rust/pv_core: Generalize Confidential
Generalize the `Confidential` impl over Vec<T> and [COUNT; T] instead of
specializing T to u8.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Steffen Eiden
516bd8c2cf rust/pv: Move confidential.rs to pv_core
Migrate Confidential to pv_core crate. This has no impact on the public
API of pv as the migrated symbols are reexported.
This enables pv_core to manage confidential data as well.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:59 +01:00
Marc Hartmayer
d1b5f80fe5 rust/utils: Use PathBuf for CertificateOptions
It's more common to use a `PathBuf` for paths than a `String`.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:58 +01:00
Mikhail Zaslonko
e2ee24b3ac zdump/df_vmdump: Rename vmd_asibk_64_new structure to vmd_asizbk
Rename vmd_asibk_64_new structure to vmd_asizbk to be in sync with CP
notations:
https://www.vm.ibm.com/pubs/cp730/ASIBK.HTML
Add ASIZBK magic number constant and magic number verification step.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:58 +01:00
Mikhail Zaslonko
f23c207622 zdump/df_vmdump: Fix the layout of vmd_asibk_64_new structure
The struct vmd_asibk_64_new representing Address Space Information Block
(ASZIBK) does not match the control block format form CP reference:
https://www.vm.ibm.com/pubs/cp730/ASIBK.HTML
Adjust the layout of vmd_asibk_64_new structure to be in sync with CP
control block format.
Introduce vmd_otble structure used for range table entries, reflecting
the related CP control block:
https://www.vm.ibm.com/pubs/cp730/OLTBLE.HTML

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:58 +01:00
Mikhail Zaslonko
649f1bc084 zdump/df_vmdump: Adjust comment lines for magic constants
Remove duplicate hex notation in comments.
Append EBCDIC string notation comment to the constant define line.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:58 +01:00
Steffen Eiden
17e575e350 rust/pv: Fix EC signature test
The size of an EC-secp521r1 signature can be up to 139 bytes (if ASN1
encoded). There is no lower bound, although sizes lower than 137 are
very unlikely but possible.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:58 +01:00
Finn Callies
57a32d98ef rust/cpacfinfo: New CLI tool to provide CPACF information
The new cpacfinfo command provides information about CPACF, such as which CPACF functions are installed, and make use of the new MSA 13 Query Authentication Information function.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-11-22 17:15:58 +01:00
Mikhail Zaslonko
03340afe88 zdump/dfi_vmdump: Add extra trace logs for vmdump processing
Add extra trace logs for vmdump processing.
Log number of Index Pages, Bit-Key Pages and actual stored pages in the
vmdump.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Finn Callies
e7cef378e0 rust/utils: Add space mode for HexSlice display
Add a new format option to HexSlice to print every byte with a separated
space in between. Additionally the old format option 'alternate'
together with the new one results in another new format which prints
every byte separated by a space AND every byte has a leading '0x'.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Co-developed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Marc Hartmayer
8da2f44ae2 rust/pv_core: Add decode_hex
It's uncommon and prone to error to silently stop decoding/parsing a
hex-string if there is an invalid character. Therefore, add a new
function `decode_hex` which fixes this behavior and use it in the code.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Marc Hartmayer
a4a29d1e05 rust/pv: Implement EcdhPubkeyCord from and to PKey conversions
Make it possible to convert internal key format to OpenSSL public key
format and vice versa. E.g. this can be useful when reading UV data
structures.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Marc Hartmayer
89f475cee1 pv/req: Move constant out of function definition
This makes it possible to reuse the constant. In addition, change the
type from i32 to usize since the value describes a size.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Marc Hartmayer
96dbabae8d pv/crypto: Improve comment about the AES 256 GCM key
The size of an AES key depends on the mode of operation, so add this
information at least in the comments, as the API cannot be changed as it
is already published.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Steffen Eiden
d30d272523 rust: Use Self wherever possible
Use Self instead of the struct name whenever possible.
Automagically replace struct name with Self:
`cargo clippy --fix -- -W clippy::use_self`

This streamlines the code.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Harald Freudenberger
300f8d23b5 lszcrypt: Fix wrong state showing up for removed AP queue within SE guest
When a queue is removed from a SE guest which was in a state other
than "usable" (for example "unbound") the state displayed by lszcrypt
switches to "usable" until the queue device is finally removed by the
AP bus scan running every 30s.

This intermediate state is caused by reading 0x00000000 on the
underlying /sys/devices/cardxx/xx.yyyy/ap_functions. lszcrypt only
extracts the BS bits from this value and maps these both bits to
string output
  0: "usable"
  1: "bound"
  2: "unbound"
  3: "illicit"
totally ignoring the fact that there is no AP function at all.

Now the code checks for a valid ap_functions value first, before
actually extracting and displaying the SE state. In case the
ap_functions reads as 0x00000000 lszcrypt now displays the string
"invalid".

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Holger Dengler <dengler@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:44 +02:00
Mikhail Zaslonko
b7ac46b98b zdump/dfi_vmdump: Fix Index Page processing for vmdump DFI
According to vmdump format, each bit of the Index page represents a Bit-Key
page and indicates if that Bit-Key page exists.
Due to the bug in vmdump64big_init() only 4096 bits of the Index Page were
processed instead of 32768. Thus for vmdumps of guests with defined storage
above 64G we could have invalid memory_start_record calculated. This ruins
the VMDUMP mem chunk read callback function.
One of the problem symptoms reported was missing UTS data in
'zgetdump -i' output caused by inability to locate OS_INFO in the dump.

Fixes: 067dd5c7ef ("zdump: Add vmdump dfi for vmdump format to elf format")
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-25 11:57:18 +02:00
Jan Höppner
e91ad1b70e Prepare for next release
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 13:23:01 +02:00
Jan Höppner
c2db7ce05f New release s390-tools-2.35.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 13:23:01 +02:00
Steffen Eiden
0031c762cf rust/pv_core: Fix rusttest owned file descriptor already closed
Newer rust std libary code checks if a fd is already closes and panics.
Test code created a file with fd=17 and relied that test code never
touched the file. This cannot be done anymore. Just use the working dir
as backing file.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Steffen Eiden
7031429d1e rust/pv: Fix new warnings for rustc 1.80
`sizeof` was added into the prelude in rustc 1.80.
This triggers a lint-warning for `unused_qualifications` if rustc 1.80+
is used. Fix this warning by using a use statement to stay compatible
for <1.80.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Steffen Eiden
73d8597db1 rust/pv_core: Clarify error reason for 003* return codes
The RCs 30, 31, 32 may be caused by a malicious host or host bug.
Make this clear and advise to stop the SE-guest.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Marc Hartmayer
77d0d1d1a1 rust/Makefile: Consider HAVE_CARGO in the clean target
This fixes `make clean` errors when cargo is not available:

  $ make clean
  ...
  | make[1]: Entering directory '/home/mhartmay/storage/git/poky/build/workspace/sources/s390-tools/rust'
  | cargo clean  --release
  | /bin/bash: cargo: command not found
  | make[1]: *** [Makefile:72: clean] Error 127

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Finn Callies
77a7e11a51 rust/Makefile: Build pvapconfig only on s390x
Configuring the AP bus only makes sense on s390x.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Suggested-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
279070fa43 zdump/ngdump: Fix seek error on 'zgetdump -d'
When checking CDL formatted DASD for installed dump-tool (zgetdump -d),
we might stumble upon an 'empty' boot record pointer in the volume label
filled with bytes of 0x40 (EBCDIC spaces). This leads to the following
seek error reported:

  # zgetdump -d /dev/dasdb
  zgetdump: Could not seek "/dev/dasdb" (Invalid argument)

Check for empty boot record and return proper error code by
ngdump_get_eckd_part_num() in order to end up with a regular
"No dump tool found" message.

Fixes: f3bcd94524 ("zdump: Add zgetdump -d support for ECKD ldipl-dump")
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
3989e1b741 zipl/src: fix segfault on '--dry-run' for device-based dumps
This fixes a segfault when the option '--dry-run' is specified for
device-based dumps (for which the bootmap file is created on a RAW
device, not formatted with a file system).

The actual status is that the option '--dry-run' for device-based
dumps is not implemented. The implementation is evaluated as not
trivial: In contrast with filesystem-based dumps, it is not possible
to simply make do with rename/unlink of temporary created bootmap.

The fixup returns error on any not file system based dumps being
created with the option '--dry-run'.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
c230b5385a zipl/src: move common checks to disk_is_appropriate()
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
68ecf79b01 zipl/src: cleanups in add_dump_progrem()
Drop a pair of duplicated assignmets
Replace the parameter 'struct job_data' with 'struct job_dump_data'

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
f2960eb0df zipl/src: drop check_dump_device_late()
Move all checks from check_dump_device_late() to disk_is_approproate()
and drop check_dump_device_late() entirely

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Eduard Shishkin
4d004cf8b1 zipl/src: drop never happening case in check_dump_device_late()
In the function check_dump_device_late() drop the case of
(info->device != target_info->device) which never happens. Indeed,
the @info created in check_dump_device_late() coincides with the
@target_info previously created by
prepare_build_program_table_{file, device}.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
d8f504f271 zdump/dfi: Fix vm_info_get() check for non-VR kernel
Since the following kernel commit:
"32db401965f1 s390/mm: Pin identity mapping base to zero"
we can have zero identity_base value in os_info. This makes zgetdump
check for non-VR kernel in vm_info_get() incorrect what leads to missing
data (e.g. UTS kernel version) in 'zgetdump -i' output.
Check for zero kaslr_offset value instead (like crash and makedumpfile
do) in order to identify non-VR kernel.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Jan Höppner
7fb3ee4478 gitignore: Add zipl md files
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-10-01 12:16:19 +02:00
Mikhail Zaslonko
a95bad6c87 zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
Since memory chunks can overlap for vr-kernel dumps stored in elf
format (ngdump, zfcpdump), we need to consider this when converting to
s390 dump output format. For that sort DFI memory chunks by start
address and adjust dfo_s390 logic for identifying memory gaps.
Otherwise we might end up with bogus DFO memory chunks being created.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Mete Durlu
147ff1bf49 cpuplugd: Halt cpu hotplugging on vertical polarization
On vertical polarization, kernel can be adjusting CPU capacities
dynamically, and cpuplugd can interfere this with hotplug operations
causing performance degradation. To prevent this, check if system has
switched its polarization state, and act accordingly.
If system is on vertical polarization when daemon starts, no CPU hotplug
action is triggered. If system changes to vertical polarization during
daemon runtime, revert cpuhotplug adjustments and stop further CPU
hotplug actions. If system switches back to horizontal polarization
during runtime of the daemon, start evaluating CPU hotplug rules and
trigger adjustments.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Mete Durlu
c91d172c99 cpuplugd/cpu: Rework CPU management functions
Simplify the cpu management parts of cpuplugd code by introducing
functions from libutil and rework some logic to drop some assumptions
about how kernel assigns cpuids.
Right now cpuplugd assumes that the cpuids are always sequential and
there are no gaps in between, however kernel does not guarantee that.
Make cpuplugd compliant by traversing cpu sysfs entries instead.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
0e4992da3a zipl/src: prevent NULL pointer deref when preparing qcow2 images for IPL
This fixes c0f02d2f6 which results in problems when preparing qcow2
images for IPL:

zipl -V --blsdir /tmp/tmp.kdPooQjoBh/boot//loader/entries/ --config /
Program terminated with signal SIGFPE, Arithmetic exception.

Don't use pointer to not initialized struct disk_info after failed
auto-detection of disk parameters. Make the check that the file
locates on the disk in the form of a separate procedure.

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
41da0f0809 zipl/src: make disk type detecton fail
When detecting disk type, the function disk_get_info() is called.
It can fail for various reasons (e.g. when the logial target is not
eligible for boot record installation).

Once disk_get_info() fails, don't proceed with type detection.
Return error instead. When applicable, mark the dump job with
"is_ngdump" flag to avoid extra type detection calls.

Acked-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
f43789e16a zipl/src: fix bugs in SCSI dump installation
This fixes d6b702d57 which introduces a problem: SCSI dump
installation fails:

zipl -V -d /dev/mapper/mpathd1
Error: Invalid dump device: Could not read partition table

The reasons:
1) Wrong (logical) device is passed as a target base;
2) In case of 'source_script' the check to make sure that specified
   target is over a partition isn't applicable any more after zipl
   support of complex logical targets (e.g. mirrors).

The fixup passes the physical device as a target base (instead of
the logical one). Also the fixup removes invalid check from
check_dump_device_late() and instead adds a more generic check to
the helper script that data starts beyong the boot area.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Marc Hartmayer
136e5eed8c rustfmt: List experimental group_imports option
This option is experimental, but can still be useful.

While at it, sort the options alphabetically.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Eduard Shishkin
e09753f2a3 chreipl_helper.device-mapper: complete device resolution process
This fixes 670bf3e8 which actually isn't an equivalent refactoring.
The generic dm-device resolution procedure was modified to not resolve
the topmost dm-device in the path. So that any calles who don't expect
it, should complete the resolutioin process by themselves. In case of
chreipl_helper such completion was missed. chreipl(8) utility doesn't
expect dm-devices at the output of chreipl_helper.device-mapper

Example:

NAME                     MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda                        8:0    0   20G  0 disk
|-sda1                     8:1    0   20G  0 part
`-mpathb                 253:0    0   20G  0 mpath
  `-mpathb1              253:2    0   20G  0 part  /
sdb                        8:16   0   20G  0 disk
|-sdb1                     8:17   0   20G  0 part
`-mpathb                 253:0    0   20G  0 mpath
  `-mpathb1              253:2    0   20G  0 part  /

Expected result:
8:16

Actual result:
253:0

As a result, the chreipl(8) "node" option stopped working.
The fixup adds the completion.

Reported-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Tested-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Sertonix
fe2d240656 netboot/mk-s390image: Fix size when argument is a symlink
`du -b` by default returns the size of a symlink when it is passed a
symlink. Adding the `-L` option allows passing symlinks to mk-s390image
without resulting in unbootable image.

Signed-off-by: Sertonix <sertonix@posteo.net>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/176
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:15:01 +02:00
Frank Heimes
6fc450f696 (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
The .note.package [1] section is not used by the zipl/genprotimg bootloaders,
therefore discard them via linker script.

This fix solves the error:
 /usr/bin/ld: Heap section doesn't conform to the described memory layout
 collect2: error: ld returned 1 exit status
 make[4]: *** [Makefile:77: stage3a.elf] Error 1
 make[4]: Leaving directory '/<>/genprotimg/boot'
 make[3]: *** [Makefile:20: all-recursive] Error 1
 make[3]: Leaving directory '/<>/genprotimg'
 make[2]: *** [Makefile:56: genprotimg] Error 2

[1] https://systemd.io/ELF_PACKAGE_METADATA/

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/174
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/176
[seiden@linux.ibm.com: Add/edit fixes tags]
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-09-13 19:14:16 +02:00
Steffen Eiden
6a55d0c2e5 rust/pv: Lower most lints to warn
Lower the lint level to warn for the styling lints.
This avoids compile issues during packaging for newer tooling with
potential more lint findings.
Still deny compiling if a public symbol has no documentation.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/173
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
0e69dc1262 zipl_helper.device-mapper: add support for 'raid' device-mapper target
Introduce target operations (struct target_ops);
For each supported device-mapper target implement
. check_target_status()
. get_target_data()

Add support for new 'raid' device-mapper target, which is now default
in LVM.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
3296d85e35 zipl/src: add support of md-mirrors
Add a script to process mirrored zipl targets managed by Linux "md"
driver (AKA "software mirrors")

. In the file zipl_helper.device-mapper.c implement two handlers
  identified by pairs (ZIPL_UTIL_ID, MD_DRIVER_ID) and
  (CHREIPL_UTIL_ID, MD_DRIVER_ID) for the helpers zipl_helper.md
  and chreipl_helper.md respectively

  . zipl_helper.md: prints sets of target parameters (one such set
    per mirror) for a specified logical zipl target managed by linux
    "md" driver.

  . chreipl_helper.md: for a specified logical zipl target managed
    by linux "md" driver prints a random disk from the set of disks
    participating in the mirrored setup.

. Add zipl_helper.md and chreipl_helper.md as symbolic links to
  zipl_helper.device-mapper

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
0eeab96f0d zipl_helper.device-mapper: check status of "mirror" dm targets
For "mirror" device-mapper targets:

. Check status of all the mirrors;
. Return error if some mirror contain failures;
. Align the sample output properly

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
283a61dc2f zipl_helper.device-mapper: support multiple base disks
For "mirror" device-mapper targets:

. Don't assign a logical mirrored device as a zipl target base.
  Instead, add one more branch in complete_physical_device() and
  proceed (in that new branch) to the physical disk participating
  in the mirrored target. This approach allowes to handle
  heterogeneous mirrors properly;
. Provide a set of target parameters for each found physical disk
  by calling dm_dev_to_zipl_params() recursively;
. Don't allow "nested mirrors" by checking/updating the
  fail_on_mirror global;
. Remove the requirements on including block #0 to the mirrored
  device-mapper setup (no more actual);
. Update comments.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
670bf3e870 zipl: refactor zipl_helper.device-mapper
This is used by the next patches in the series to support mirror
setups not including boot sectors (e.g. mirrors over partitions).

. Rework the core procedure of device resolution (by walking along
  the device-mapper tree during logical device resolution) to be an
  explicit sequence of pairs (level-lookup, goto-parent-level);
. Add an "extended" device to keep a track of file system offset
  while ascending the device tree;
. Identify all possible results of a single level lookup;
. Rename target_entry to dmpath_entry;
. Make the main() function to look like a call of a handler
  identified by a pair (driver-id, util-id) and found by the name
  of the executable.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
9cfaac58ea zipl_helper.device-mapper: fix bug in get_physical_device()
Fix mistake in @fs_offset calculation.

Since any logical dm-device can be built of partitions, @fs_offset
must not decrease while ascending the "device tree" during the
procedure of dm-device resolution (which always starts at the
formatted logical device, for which @fs_offset is 0).

This bug was not reproducible earlier because of restricted
functionality in a combination with side-effects. The fixup is
required however by the next patches in the series implementing
support of mirrored targets by zipl tool

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Eduard Shishkin
d6b702d579 zipl/src: add basic support for multiple target base disks
. Modify disk_get_info() to process multiple sets of target parameters
  provided by the helper script and store it in the array of "targets"
  of the structure job_target_data;
. Besides the logical device, maintain an array of physical base disks
  in the disk_info structure;
. Use the logical target device only to create bootmap (it is
  automatically mirrored by the respective linux driver (dm, or md)
  managing the mirrored target). In contrast, install bootstrap blocks
  to each physical base disk individually, bypassing that driver;
. Report in verbose mode on which base disks the bootstrap
  installation was performed;
. Use the following logic of setting @info->device (which is printed
  as "Device...:" in verbose mode):
  . source_auto   - the target base disk is set;
  . source_script - the target (logical) device is set;
  . source_user   - the device specified by user (via --targetbase
                    option), or config file is set.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-08-26 10:40:21 +02:00
Peter Oberparleiter
d9a9bd8dcf zdev: Add option to select IPL device
Add new command-line option --ipldev. When specified and IPL was done
from a supported device type, the IPL device is selected for the
requested tool operation.

Example to list IPL device information:

$ lszdev --ipldev

Example to create a persistent configuration for the IPL device:

$ chzdev --enable --persistent --ipldev

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Peter Oberparleiter
cad4e9e15b zdev: Add function for reading text files
Reduce code complexity by adding a utility function for reading text
files based on a variable path.

Note: chzdev/lszdev tools apply special path-handling via command line
option --base to allow redirecting hard-coded paths therefore libutil's
util_file functions cannot easily be used.

Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Eduard Shishkin
c0f02d2f68 zipl/src: Fix problems when target parameters are specified by user
Steps to reproduce: Prepare some disk for IPL, specifying its
parameters via zipl "target options", and an image IMAGE_NAME
located on another disk. Don't specify "-a" option.

Actual result: Installation succeeded (resulting in unbootable setup)
Expected result: "Error: Could not add image file 'IMAGE_NAME': File
is not on target device"

The problem is in incorrect evaluation of device number (dev_t)
of the base disk where the image is located by the function
add_component_file_range() in case when target parameters are
specified by user.

Fixup: Retrieve info of the underlying disk without any user hints,
passing zeroed structure job_target_data

This is an improved version of fb0b6263d that was reverted by
63ff07ba3 afterwards. The shortcoming of the original ( fb0b6263d )
fix: it fails to prepare for IPL mounted qcow2 images.
The difference from the original fix: when making sure that boot
files are located on the target disk: in case of failed auto-detection
of disk parameters skip the check with warnings instead of aborting
the whole installation session.

Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Finn Callies
5218c243f4 cpacfstats: add MSA 10 and MSA 11 counters
MSA 10 and MSA 11 introduce new function codes containing Full XTS
functions for KM instruction and HMAC functions for KMAC instruction.
Additional Full XTS and HMAC for PCKMO instruction is introduced.

Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Finn Callies
c364692e7a cpacfstats: white space fix in cpacfstats/cpacfstatsd.c
Signed-off-by: Finn Callies <fcallies@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Reviewed-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Nihar Panda
41eb7d076f ziomon/ziorep_config: fix warning when multipath device is not there
Perl logs warning message if a variable is not initialized.
get_device_data() set mp_dev with multipath device for a scsi disk device.
mp_dev remain uninitialized if there is no multipath device.
This can happen if a scsi device is not managed by dm multipath driver.

Warning message:
"Use of uninitialized value in subroutine entry at /usr/sbin/ziorep_config line 136"

Fix it by skipping the code dealing with mp_dev and continue with next
scsi device in the loop.

To reproduce, remove a scsi device from dm multipath.
$multipathd -k'del path sdh'
Then run `ziorep_config -D`.

Signed-off-by: Nihar Panda <niharp@linux.ibm.com>
Reviewed-by: Fedor Loshakov <loshakov@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:32:36 +02:00
Joern Siglen
1062a7cde6 dbginfo.sh: add network sockstat info
Add procfs files to collect network socket data.

Suggested-by: Eberhard Pasch <epasch@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-22 10:31:33 +02:00
Jan Höppner
54e5e99657 Prepare for next release
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 15:17:58 +02:00
Jan Höppner
4c922b105b New release s390-tools-2.34.0
Signed-off by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 15:17:42 +02:00
Mikhail Zaslonko
4b19b9d950 zdump/dfi_s390: Get rid of device type check for s390_ext dump
Simplify ioctl error processing logic for "BLKSSZGET" operation.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Ingo Franzki
cee4bb4995 libkmipclient: Fix typo in debug message
Fix copy & paste error in debug message

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Ingo Franzki
c98d8e7629 libkmipclient: Remove superfluous break
A double break in a switch does not make any sense, remove it.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Joern Siglen
96084339f5 dbginfo.sh: update/add additional DASD collection
We changed lscss for more detailed output.
Adding use of dasdview for a detailed view on DASD storage.
This data will be collected in a separate file, as many DASDs might flood
the runtime.out
Also updated man pages as a new step is added

Reviewed-by: Stefan Hberland <sth@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Harald Freudenberger
f8d5b4b341 rust/pvapconfig: add dead_code pragmas to suppress warnings
The ap.rs code is already prepared for possible support
for CCA mode APQNs for the Secure Execution environment.
However, this patch marks these fields and structs with
pragma allow(dead_code) to prevent warnings during cargo
build of pvapconfig.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Matthew Rosato
5806c4e1f4 ap_tools/ap-check: implement get capabilities callout
Add a new action type 'capabilities' for the 'get' event.  This
will return a JSON list of events and actions that the callout
script recognizes and actually does something with.  It omits
events like 'notify' and actions like 'list' that ap-check
currently ignores.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:06 +02:00
Matthew Rosato
9d199e06cb ap_tools/ap-check: implement dynamic config during live modify
mdevctl introduces a new event type 'live' with action 'modify',
indicating that the specified configuration changes should be
made dynamically if possible.  Use this as a trigger to perform
dynamic configuration changes to the specified vfio-ap device
if it is active.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
f7425a08d1 ap_tools/ap-check: refactor active config checking
Create a single routine to perform conflict analysis for a
given device against the active configuration.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
f6a97902c3 libap: handle reading ap_config attribute
While unlikely, it is possible for a vfio-ap configuration JSON
to include the 'ap_config' attribute.  In this case, process it
by overwriting the current list of adapters, domains and control
domains for the associated vfio-ap device struct.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
962af1a90e libap: add routines to generate masks for vfio_ap_device
Add routines to generate mask values for the adapters, domains and
control domains for a specified vfio_ap_device struct.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
46dadc8cc4 libap: add routine to check for dynamic config support
For a given vfio-ap mdev, determine whether or not the device will
need dynamic config operations.  This boils down to whether or not
the device is currently active + whether or not the kernel is
detected to support dynamic config operations (via the
'ap_config' sysfs attribute).

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Matthew Rosato
9c8d117cc2 zdev: remove duplicate ap_node structure
There is already an identical vfio_ap_node defined in libap, use
that instead.  Also remove one awkard usage of struct ap_node in
libap.

Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Anthony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-08-01 14:26:05 +02:00
Vineeth Vijayan
d7b3196286 zdev: fix warning about failed ATTR writes by udev
The qeth-udev-rule execution logs a warning as below in the journalfs.

Failed to write ATTR{/sys/bus/ccwgroup/drivers/qeth/group}, \
ignoring: Invalid argument

This occurs because the udev rule for qeth devices is triggered by
multiple ccw devices and can be invoked in parallel. This can lead to a
situation where each of the three parallel-running udev rules tries to
group the devices simultaneously. As a result, only the first rule
succeeds, while the others fail with an -EINVAL error because the CCW
devices have already been grouped.

To prevent this, schedule a new change uevent for the base device, which
will verify the sysfs before attempting the grouping. The change event is
triggered by all three devices, ensuring that the actual write to the
attribute occurs only once and only when the sysfs attribute is ready.

Hence the add events on different devices are serialized to change event
on the base device, which then prevent duplicate concurrent grouping
attempts.

Suggested-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-07-08 09:25:12 +02:00
Alexander Egorenkov
b6c30404bc zfcpdump: drop use of mmap() for /proc/vmcore
The function copy_table_entry_write() maps/unmaps /proc/vmcore for each
64kB of the file in order to write its content to a dump partition.
This requires a page allocation of order 2 in kernel (crst_table_alloc)
each time a mmap() syscall is performed and which cannot always be
fulfilled due to external memory fragmentation. And this in turn
results in a OOM kernel panic while writing /proc/vmcore content to
a dump partition. To make zfcpdump more robust in the face of such
problems with page allocations of order > 0, we use a simple file
read/write loop to transfer the content of /proc/vmcore to a dump
partition. This solution is less efficient (by not much) than the old
one with mmap() because it requires additional user space copy but
we trade off here efficiency for robustness which is more important
for zfcpdump.

We use a statically allocated buffer to read data into from /proc/vmcore
and write to a dump partition to avoid repeated use of the memory
mapping kernel path which would be required for a buffer allocated
dynamically at each entry of copy_table_entry_write().

Another possible and very convenient solution would be to use sendfile()
which would avoid any user space copies but, unfortunately, sendfile()
doesn't work with large /proc files.

Example of failed mmap() call for /proc/vmcore
==============================================

  [   26.568654] init invoked oom-killer: gfp_mask=0x40cc0(GFP_KERNEL|__GFP_COMP), order=2, oom_score_adj=0
  [   26.568665] CPU: 0 PID: 1 Comm: init Not tainted 6.9.0-20240504.rc6.git0.9986ea583f39.300.fc39.s390x+zfcpdump #1
  [   26.568668] Hardware name: IBM 3931 A01 704 (LPAR)
  [   26.568669] Call Trace:
  [   26.568671]  [<000003ffe03277c6>] dump_stack_lvl+0x76/0x98
  [   26.568676]  [<000003ffe00f15c8>] dump_header+0x58/0x2d0
  [   26.568680]  [<000003ffe00f219a>] out_of_memory+0x252/0x348
  [   26.568683]  [<000003ffe0132f3e>] __alloc_pages_slowpath.constprop.0+0x65e/0x7c0
  [   26.568686]  [<000003ffe01331a4>] __alloc_pages+0x104/0x128
  [   26.568688]  [<000003ffe001ab46>] crst_table_alloc+0x2e/0xa0
  [   26.568693]  [<000003ffe01164c4>] __pmd_alloc+0x24/0x160
  [   26.568696]  [<000003ffe0116650>] pmd_alloc+0x50/0x68
  [   26.568698]  [<000003ffe0117be4>] remap_pfn_range_notrack+0x194/0x310
  [   26.568701]  [<000003ffe0117d7c>] remap_pfn_range+0x1c/0x28
  [   26.568703]  [<000003ffe0015442>] remap_oldmem_pfn_range+0xb2/0x108
  [   26.568705]  [<000003ffe01a0544>] mmap_vmcore+0x414/0x448
  [   26.568707]  [<000003ffe01937c4>] proc_reg_mmap+0x84/0xa0
  [   26.568709]  [<000003ffe011f264>] mmap_region+0x22c/0x6f8
  [   26.568711]  [<000003ffe011fae8>] do_mmap+0x3b8/0x410
  [   26.568713]  [<000003ffe01015cc>] vm_mmap_pgoff+0x9c/0xe8
  [   26.568715]  [<000003ffe011d006>] ksys_mmap_pgoff+0x8e/0xb8
  [   26.568716]  [<000003ffe011d0f4>] __s390x_sys_old_mmap+0x74/0x90
  [   26.568718]  [<000003ffe0341a2a>] __do_syscall+0x1aa/0x220
  [   26.568720]  [<000003ffe03478b0>] system_call+0x70/0x98
  [   26.568724] Mem-Info:
  [   26.568725] active_anon:1 inactive_anon:12 isolated_anon:0
                  active_file:83590 inactive_file:93939 isolated_file:0
                  unevictable:201 dirty:17845 writeback:4
                  slab_reclaimable:4259 slab_unreclaimable:1482
                  mapped:174 shmem:0 pagetables:810
                  sec_pagetables:0 bounce:0
                  kernel_misc_reclaimable:0
                  free:2694 free_pcp:105 free_cma:0
  [   26.568729] Node 0 active_anon:4kB inactive_anon:48kB active_file:334360kB inactive_file:375756kB unevictable:804kB isolated(anon):0kB isolated(file):0kB mapped:696kB dirty:71380kB writeback:16kB shmem:0kB writeback_tmp:0kB kernel_stack:544kB pagetables:3240kB sec_pagetables:0kB all_unreclaimable? no
  [   26.568732] DMA free:10776kB boost:0kB min:3496kB low:4368kB high:5240kB reserved_highatomic:0KB active_anon:4kB inactive_anon:48kB active_file:334360kB inactive_file:375756kB unevictable:804kB writepending:71360kB present:786428kB managed:764664kB mlocked:0kB bounce:0kB free_pcp:420kB local_pcp:420kB free_cma:0kB
  [   26.568735] lowmem_reserve[]: 0 0 0
  [   26.568738] DMA: 1069*4kB (UH) 757*8kB (UH) 11*16kB (H) 6*32kB (H) 1*64kB (H) 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 10764kB
  [   26.568747] 177773 total pagecache pages
  [   26.568748] 196607 pages RAM
  [   26.568748] 0 pages HighMem/MovableOnly
  [   26.568749] 5441 pages reserved
  [   26.568749] Tasks state (memory values in pages):
  [   26.568750] [  pid  ]   uid  tgid total_vm      rss rss_anon rss_file rss_shmem pgtables_bytes swapents oom_score_adj name
  [   26.568751] Out of memory and no killable processes...
  [   26.568752] Kernel panic - not syncing: System is deadlocked on memory
  [   26.568755] CPU: 0 PID: 1 Comm: init Not tainted 6.9.0-20240504.rc6.git0.9986ea583f39.300.fc39.s390x+zfcpdump #1
  [   26.568758] Hardware name: IBM 3931 A01 704 (LPAR)
  [   26.568759] Call Trace:
  [   26.568760]  [<000003ffe03277c6>] dump_stack_lvl+0x76/0x98
  [   26.568763]  [<000003ffe001f14e>] panic+0x10e/0x2e8
  [   26.568765]  [<000003ffe00f21c8>] out_of_memory+0x280/0x348
  [   26.568768]  [<000003ffe0132f3e>] __alloc_pages_slowpath.constprop.0+0x65e/0x7c0
  [   26.568771]  [<000003ffe01331a4>] __alloc_pages+0x104/0x128
  [   26.568773]  [<000003ffe001ab46>] crst_table_alloc+0x2e/0xa0
  [   26.568776]  [<000003ffe01164c4>] __pmd_alloc+0x24/0x160
  [   26.568779]  [<000003ffe0116650>] pmd_alloc+0x50/0x68
  [   26.568781]  [<000003ffe0117be4>] remap_pfn_range_notrack+0x194/0x310
  [   26.568784]  [<000003ffe0117d7c>] remap_pfn_range+0x1c/0x28
  [   26.568787]  [<000003ffe0015442>] remap_oldmem_pfn_range+0xb2/0x108
  [   26.568789]  [<000003ffe01a0544>] mmap_vmcore+0x414/0x448
  [   26.568791]  [<000003ffe01937c4>] proc_reg_mmap+0x84/0xa0
  [   26.568793]  [<000003ffe011f264>] mmap_region+0x22c/0x6f8
  [   26.568795]  [<000003ffe011fae8>] do_mmap+0x3b8/0x410
  [   26.568797]  [<000003ffe01015cc>] vm_mmap_pgoff+0x9c/0xe8
  [   26.568799]  [<000003ffe011d006>] ksys_mmap_pgoff+0x8e/0xb8
  [   26.568801]  [<000003ffe011d0f4>] __s390x_sys_old_mmap+0x74/0x90
  [   26.568803]  [<000003ffe0341a2a>] __do_syscall+0x1aa/0x220
  [   26.568805]  [<000003ffe03478b0>] system_call+0x70/0x98

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
6d15850480 zdump: Use os_info data to convert dump vaddr to paddr
For vr-kernel dumps use the offsets stored in os_info entries for
virt to phys address conversion when dump virtual address is to be
read, (e.g. vmcoreinfo symbols) using similar method as implemented
in crash-utility.
It is mainly required for reading "init_uts_ns" symbol and, in case
of crashed kdump, "lowcore_ptr" symbol along with a pointers to the
lowcore of every CPU.

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
858da9af57 zdump: Use os_info.h from include/boot
Get rid of duplicate os_info definitions in dfi_vmcoreinfo.c

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
a7373674bf include/boot/os_info: Add static assert for os_info size
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
613353cd33 zdump/dfi_elf: Support core dumps of vr-kernels
Support vmcore based dumps (ngdump, zfcpdump) with uncoupled physical and
virtual addresses. For that we just remove p_paddr != p_vaddr sanity check
for elf load headers.

Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Peter Oberparleiter
f6e932e0fd libutil: Make formatted meta-data configurable
Output generated using libutil's util_fmt_*() functions contains
meta-data such as hostname and time of invocation. When writing test
cases that compare expected and actual tool output, this run-time
variable information needs to be filtered out, resulting in increased
complexity.

To address this, add a global option to suppress meta-data output via
environment variable FMT_NOMETA. If set to '1', no meta-data will be
generated.

Example:

$ FMT_NOMETA=1 chpstat --format json

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Steffen Eiden
7e31c425c9 rust/pv: Try again if first CRL-URI is invalid
The previous implementation did stop after the first download was
successful, even if it did not contain a CRL. This behavior renders a
second, third, ... link as backup location useless as the code ignores
them if the URI e.g. contains a error message. That results in not
having a CRL and probably a failed certificate verification.

Fix this by trying again if the download was successful but did not
contain a CRL

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
6c4171b775 zdump/dfi_s390: Adjust device type check for s390_ext dump
In order to allow loop devices usage for DASD dump emulation in fvt-tests,
do not bail out on ZG_TYPE_DASD device type returned by zg_type() for
s390_ext dump.

Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Jan Höppner
0b0960254e s390-tools: Replace 'which' with built-in 'command -v'
There are still a few scripts using the 'which' command to determine
either the full path or the mere existence of an executable.
Some of these scripts might run in minimal environments where 'which' is
not available due to dependency restriction. 'which' is also considered
unreliable for historical implementation details.

Use the POSIX defined [1] built-in 'command -v' instead to reduce
package dependencies and improve reliability.

[1] https://pubs.opengroup.org/onlinepubs/9699919799/
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
4d2c9267c2 dumpconf: add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
The new parameter 'SCP_DATA' can be used to pass additional kernel cmdline
parameters to a stand-alone SCSI/NVMe/ECKD dumper for debugging purposes.

Configuration example
=====================

ON_PANIC=dump_reipl
DUMP_TYPE=fcp
DEVICE=0.0.4711
WWPN=0x5005076303004711
LUN=0x4711000000000000
BOOTPROG=0
BR_LBA=0
SCP_DATA="dump_debug=6 ignore_loglevel earlyprintk=sclp panic_print=3"

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
7ea0dfdc17 dumpconf: fix whitespace in sysconfig example for ECKD dump device
Make it conform with every other example.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Alexander Egorenkov
2d3aac1241 dumpconf: fix coding style of CheckDeviceString()
Make it conform with the naming style used for every other function in
this script.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Mikhail Zaslonko
c7fd515790 zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
When dump is copied to the filesystem in s390 format, follow on
'zgetdump -i' can fail with ioctl error:

  # zgetdump /dev/dasdb1 -f s390 dump.s390
  Format Info:
      Source: s390_ext
      Target: s390

  Copying dump:
      00000001 / 00008192 MB
      00003688 / 00008192 MB
      00006646 / 00008192 MB
      00008192 / 00008192 MB
  Success: Dump has been copied

  # zgetdump -iVVVV dump.s390

  zgetdump: Operation "BLKSSZGET" failed on "dump.s390" (Inappropriate ioctl for device)

Call ioctl(BLKSSZGET) only for s390_ext dump format (dump can be
stored on DASD partition only, not on the filesystem). For s390 format
a blocksize is not required for dump processing since s390 dump data is
not compressed.

Fixes: 271b809495 ("zdump/dfi_s390: Support reading compressed s390_ext dumps")
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Steffen Eiden
7a4ec55d77 rust/pvattest: Add short option for --arpk
pvattest-C had a -a option for --arpk which the Rust implementation
missed.
Add this short option.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Marc Hartmayer
63ff07ba38 Revert "zipl/src: Fix problems when target parameters are specified by user"
The commit fb0b6263d1 ("zipl/src: Fix problems when target parameters
are specified by user") breaks the case where the user has to provide
all target attributes via the zipl command line, because the target
device cannot be used to retrieve those attributes.

$ zipl -V --blsdir /tmp/tmp.xHmFUdgBCi/boot//loader/entries/ --config /tmp/tmp.dSv9MJ3svs
Looking for components in '/lib/s390-tools'
Using config file '/tmp/tmp.dSv9MJ3svs' (from command line)
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//50_normal.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//45_normal_swiotlb.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//40_pv.conf'
Using BLS config file '/tmp/tmp.xHmFUdgBCi/boot//loader/entries//30_pv_reboot.conf'
Secure boot support: yes
Target device information
  Device..........................: 2b:00
  Device name.....................: nbd0 *)
  Device driver name..............: nbd
  Type............................: disk device
  Disk layout.....................: SCSI disk layout *)
  Geometry - start................: 2048 *)
  File system block size..........: 4096
  Physical block size.............: 512 *)
  Device size in physical blocks..: 2095071
  *) Data provided by user.
Building bootmap in '/tmp/tmp.xHmFUdgBCi/boot/'
Building menu 'zipl-automatic-menu'
Adding #1: IPL section 'Normal Guest' (default)
  initial ramdisk...: /tmp/tmp.xHmFUdgBCi/boot//ramdisk-s390x
  kernel image......: /tmp/tmp.xHmFUdgBCi/boot//vmlinux-s390x
zIPL environment block content:
Error: Could not add image file '/tmp/tmp.xHmFUdgBCi/boot//vmlinux-s390x': Could not get disk geometry

This reverts commit fb0b6263d1.

Acked-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:24 +02:00
Frank Heimes
26d7eed0aa zfcpdump: Do not save timestamps when compressing
Having timestamps in gzip leads to lintian warning
'package-contains-timestamped-gzip' and will harm reproducible builds.
Gzip option '-n' avoids saving original file name and especially timestamps
by default.

Fixes: https://github.com/ibm-s390-linux/s390-tools/pull/169
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
[seiden@linux.ibm.com: Fix commit message]
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:13 +02:00
Frank Heimes
e0034eddbf s390-tools: Fix typos in code and man page files
Fix typos reported by (Debian) lintian.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/168
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
2024-06-24 16:23:09 +02:00
Jan Höppner
0e3034c0f6 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2024-05-28 08:26:36 +02:00
337 changed files with 20881 additions and 9380 deletions

5
.gitignore vendored
View File

@@ -77,9 +77,8 @@ libzds/libzds.a
lsstp/lsstp
mon_tools/mon_fsstatd
mon_tools/mon_procd
opticsmon/opticsmon
osasnmpd/osasnmpd
pvattest/src/pvattest
pvattest/tools/exchange_info
qetharp/qetharp
qethqoat/qethqoat
systemd/cpacfstatsd.service
@@ -124,9 +123,11 @@ zipl/boot/*.exec
zipl/boot/.loaders
zipl/boot/data.h
zipl/src/chreipl_helper.device-mapper
zipl/src/chreipl_helper.md
zipl/src/zipl
zipl/src/zipl-editenv
zipl/src/zipl_helper.device-mapper
zipl/src/zipl_helper.md
zkey/check-dep-zkey
zkey/check-dep-zkey-cryptsetup
zkey/detect-libcryptsetup.dep

View File

@@ -5,8 +5,9 @@ newline_style = "Unix"
# when they become stable.
#
# They are kept here since they are useful to run from time to time.
#format_code_in_doc_comments = true
#reorder_impl_items = true
#comment_width = 100
#wrap_comments = true
#format_code_in_doc_comments = true
#group_imports = "StdExternalCrate"
#normalize_comments = true
#reorder_impl_items = true
#wrap_comments = true

View File

@@ -11,6 +11,7 @@ List of all individuals having contributed content to s390-tools
- Axel Wirbser
- Balint Reczey
- Benjamin Block
- Bjoern Walk
- Brian C. Lane
- Carsten Otte
- Christian Borntraeger
@@ -91,6 +92,7 @@ List of all individuals having contributed content to s390-tools
- Michael Mueller
- Mijo Safradin
- Mikhail Zaslonko
- Nihar Panda
- Nikita Dubrovskii
- Niklas Schnelle
- Nikolay Gueorguiev
@@ -107,6 +109,7 @@ List of all individuals having contributed content to s390-tools
- Sa Liu
- Sascha Silbe
- Sebastian Ott
- Sertonix
- Seshagiri N. Ippili
- Simon Sturm
- Stefan Bader
@@ -133,6 +136,7 @@ List of all individuals having contributed content to s390-tools
- Ursula Braun
- Utz Bacher
- Vance Morris
- VasiliyS
- Vasily Gorbik
- Viktor Mihajlovski
- Vineeth Vijayan

View File

@@ -1,6 +1,72 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.36.0 (2024-12-06)__
For Linux kernel version: 6.12
s390-tools: Define Rust MSRV as 1.75.0
Add new tools / libraries:
- cpacfinfo: Tool to provide CPACF information
- opticsmon: Tools to monitor optical modules for directly attached PCI based NICs
- pvimg: Rust rewrite of genprotimg
Changes of existing tools:
- chpstat: Add data bandwidth utilization column
- chpstat: Add support for full CMCB
- chpstat: Add support for new CMG types
- dbginfo.sh: add overview commands and crypto update
- hyptop: Support for structured output (json, json-seq, csv)
- lszfcp: Add missing fallback marker for non-good fc_host port_state
- lszfcp: Improve speed with many SCSI devices
- pvattest: Add attestation policy check command
- zipl: Add support of partitions of mirror md-devices
Bug Fixes:
- lszcrypt: Fix wrong state showing up for removed AP queue within SE guest
- lszfcp: Show device names line for zfcp_units without SCSI device
* __v2.35.0 (2024-10-01)__
For Linux kernel version: 6.11
Add new tools / libraries:
Changes of existing tools:
- cpacfstats: Add support for FULL XTS (MSA 10) and HMAC (MSA 11) PAI counter
- cpuplugd: Make cpuplugd compatible with hiperdispatch
- dbginfo.sh: Add network sockstat info
- pvapconfig: s390x exclusive build
- zdev: Add option to select IPL device
- zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
- zipl: Add support of mirror devices
Bug Fixes:
- (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
- netboot/mk-s390image: Fix size when argument is a symlink
- ziorep_config: Fix warning message when multipath device is not there.
- zipl: Fix problems when target parameters are specified by user
- zipl: Fix segfault when creating device-based dumps with '--dry-run'
* __v2.34.0 (2024-08-01)__
For Linux kernel version: 6.10
Changes of existing tools:
- ap_tools/ap-check: Add support for vfio-ap dynamic configuration
- dbginfo.sh: Update/Add additional DASD data collection
- dumpconf: Add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
- libutil: Make formatted meta-data configurable
- s390-tools: Replace 'which' with built-in 'command -v'
- zdump/dfi_elf: Support core dumps of vr-kernels
Bug Fixes:
- chzdev: Fix warning about failed ATTR writes by udev
- rust/pv: Try again if first CRL-URI is invalid
- rust/pvattest: Add short option for --arpk
- zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
* __v2.33.1 (2024-05-28)__
For Linux kernel version: 6.9

View File

@@ -9,18 +9,18 @@ include common.mak
ifeq ($(HOST_ARCH),s390x)
BASELIB_DIRS = libutil libseckey
LIB_DIRS = libvtoc libzds libdasd libccw libvmcp libekmfweb \
libkmipclient libcpumf libap libpv
libkmipclient libcpumf libap libpv libzpci
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools rust
lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools rust opticsmon
else
BASELIB_DIRS =
LIB_DIRS = libpv
TOOL_DIRS = genprotimg rust
TOOL_DIRS = rust
endif
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)

View File

@@ -19,12 +19,17 @@ Package contents
all s390-tools that are written in rust and require external crates.
Disable the compilation of all tools in `rust/` using HAVE_CARGO=0
See the `rust/README.md` for Details
- cpacfinfo:
Command line interface to get information about CP Assist for
Cryptographic Functions (CPACF)
- pvattest:
Create, perform, and verify IBM Secure Execution attestation measurements.
- pvapconfig:
Automatic configure APQNs within an SE KVM guest
- pvsecret:
Manage secrets for IBM Secure Execution guests
- pvimg:
Create and inspect IBM Secure Execution images
* dasdfmt:
Low-level format ECKD DASDs with the classical Linux disk layout or the new
@@ -42,7 +47,8 @@ Package contents
Display unique DASD ID, either UID or volser.
* genprotimg:
Create a protected virtualization image.
Create an IBM Secure Execution (protected virtualization) image. The
genprotimg command is a symbolic link to the `pvimg create` command.
* udev rules:
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
@@ -304,26 +310,27 @@ HAVE_FUSE=0`".
The following table provides an overview of the used libraries and
build options:
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|----------------|:------------------:|:-------------------------------------:|
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
| | | hsavmcore |
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
| ncurses | `HAVE_NCURSES` | hyptop |
| net-snmp | `HAVE_SNMP` | osasnmpd |
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
| | | libkmipclient, pvattest, zgetdump, |
| | | rust/pvsecret, |
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
| | | libkmipclient |
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest, zgetdump |
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
| | | pvattest, rust/pvsecret, |
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
| systemd | `HAVE_SYSTEMD` | hsavmcore |
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|--------------|:------------------:|:--------------------------------------:|
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump, |
| | | hsavmcore |
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
| ncurses | `HAVE_NCURSES` | hyptop |
| net-snmp | `HAVE_SNMP` | osasnmpd |
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
| openssl | `HAVE_OPENSSL` | zkey, libekmfweb, libkmipclient, |
| | | zgetdump, rust/pvattest, rust/pvimg, |
| | | zgetdump/pvsecret, opticsmon |
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
| | | libkmipclient |
| glib2 | `HAVE_GLIB2` | zgetdump |
| libcurl | `HAVE_LIBCURL` | libekmfweb, libkmipclient, rust/pvimg, |
| | | rust/pvattest, rust/pvsecret, |
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
| systemd | `HAVE_SYSTEMD` | hsavmcore |
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
| libnl3 | `HAVE_LIBNL3` | opticsmon |
This table lists additional build or install options:
@@ -355,13 +362,13 @@ the different tools are provided:
* dbginfo.sh:
The tar package is required to archive collected data.
* genprotimg:
For building genprotimg you need OpenSSL version 1.1.0 or newer
installed (openssl-devel.rpm). Also required is glib2
(glib2-devel.rpm). Tip: you may skip the genprotimg build by adding
`HAVE_OPENSSL=0` or `HAVE_GLIB2=0`.
* rust/pvimg:
For building pvimg you need OpenSSL version 1.1.1 or newer
installed (openssl-devel.rpm). Also required is cargo and libcurl.
Tip: you may skip the pvimg build by adding
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_CARGO=0`.
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
The runtime requirements are: openssl-libs (>= 1.1.1) and libcurl.
* rust/pvattest:
For building pvattest you need OpenSSL version 1.1.1 or newer
@@ -369,8 +376,13 @@ the different tools are provided:
Tip: you may skip the pvattest build by adding
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_CARGO=0`.
The runtime requirements are: openssl-libs (>= 1.1.1) and
glib2.56 or newer.
The runtime requirements are: openssl-libs (>= 1.1.1) and libcurl.
* opticsmon:
For building opticsmon OpenSSL and the Netlink Library Suite (libnl3) are
required.
Tip: you may skip the opticsmon build by adding
`HAVE_OPENSSL=0` or `HAVE_LIBNL3=0`
* osasnmpd:
You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)

View File

@@ -15,6 +15,7 @@
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <json-c/json.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -27,21 +28,33 @@
#include "ap-check.h"
/* The supported mdevctl callout version */
#define MDEVCTL_CAP_VERSION 2
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
{MDEVCTL_ACTION_DEFINE, "define"},
{MDEVCTL_ACTION_LIST, "list"},
{MDEVCTL_ACTION_MODIFY, "modify"},
{MDEVCTL_ACTION_START, "start"},
{MDEVCTL_ACTION_STOP, "stop"},
{MDEVCTL_ACTION_TYPES, "types"},
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"},
{MDEVCTL_ACTION_CAPABILITIES, "capabilities"}
/*
* Note: the following actions are known to exist but currently ignored:
* {MDEVCTL_ACTION_LIST, "list"},
* {MDEVCTL_ACTION_TYPES, "types"}
*/
};
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
{MDEVCTL_EVENT_PRE, "pre"},
{MDEVCTL_EVENT_POST, "post"},
{MDEVCTL_EVENT_GET, "get"}
{MDEVCTL_EVENT_GET, "get"},
{MDEVCTL_EVENT_LIVE, "live"}
/*
* Note: the following events are known to exist but currently ignored:
* {MDEVCTL_EVENT_NOTIFY, "notify"},
*/
};
/*
@@ -596,6 +609,94 @@ out:
return rc;
}
static int ap_check_active(struct ap_check_anchor *anc)
{
int rc, rc2;
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
return -1;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
return rc;
}
static int ap_do_dynamic_config(struct ap_check_anchor *anc)
{
char *adapters, *domains, *controls, *path, *attr;
int asize, dsize, csize, size;
int rc = 0;
FILE *f;
adapters = vfio_ap_device_get_adapter_mask(anc->dev, &asize);
domains = vfio_ap_device_get_domain_mask(anc->dev, &dsize);
controls = vfio_ap_device_get_control_mask(anc->dev, &csize);
if (!adapters || !domains || !controls) {
fprintf(stderr, "Failed to read device config\n");
rc = -1;
goto out;
}
/*
* The 'ap_config' command takes a comma-delimited list of the 3 masks
* combined. Each mask size includes a terminating character, two of
* which will be replaced by commas and the final replaced by a
* newline, which ap_config seems to require at the end of the input.
* Add one to ensure room for a null termination.
*/
size = asize + dsize + csize + 1;
attr = util_zalloc(size);
/* Use the 3 masks to generate a 'ap_config' command */
rc = snprintf(attr, size, "%s,%s,%s\n", adapters, domains, controls);
if (rc < size - 1) {
fprintf(stderr, "Error creating ap_config command\n");
rc = -1;
goto out;
}
/* Apply the new configuration to the active device */
path = path_get_vfio_ap_attr(anc->uuid, "ap_config");
f = fopen(path, "w");
if (!f) {
fprintf(stderr, "Error opening ap_config\n");
rc = -1;
goto out;
}
rc = fputs(attr, f);
fclose(f);
if (rc == EOF)
fprintf(stderr, "Error writing to ap_config\n");
else
rc = 0;
out:
if (!adapters)
free(adapters);
if (!domains)
free(domains);
if (!controls)
free(controls);
if (!path)
free(path);
if (!attr)
free(attr);
return rc;
}
/*
* Determine if defining the specified device is a valid operation.
* mdevctl can reach us for a DEFINE under the following circumstances:
@@ -647,6 +748,50 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
return ap_check_changes(anc);
}
/*
* Determine if modifying the active device is a valid operation.
* This is similar to STARTing a device, in that the requested modifications
* cannot conflict with the active configuration. LIVE MODIFY can only be
* handled if the ap_config attribute is available in the vfio-ap driver.
*/
static int ap_check_handle_live_modify(struct ap_check_anchor *anc)
{
int rc;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
return -1;
}
anc->cleanup_lock = true;
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
fprintf(stderr, "Failed to read device config\n");
return -1;
}
if (strcmp(anc->dev->type, anc->type) != 0) {
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
return -1;
}
if (!vfio_ap_need_dynamic_config(anc->dev)) {
fprintf(stderr, "vfio-ap module does not support ap_config for live modification");
return -1;
}
/* Check if the new configuration would cause conflicts */
rc = ap_check_active(anc);
if (rc)
return rc;
/* Attempt to perform the dynamic configuration */
rc = ap_do_dynamic_config(anc);
return rc;
}
/*
* Determine if starting the specified device is a valid operation.
* mdevctl can reach us for a START under the following circumstances:
@@ -665,7 +810,7 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
*/
static int ap_check_handle_start(struct ap_check_anchor *anc)
{
int rc = 0, rc2;
int rc = 0;
/* Can only start a device if vfio_ap is built-in or loaded */
if (!util_path_is_dir(VFIO_AP_PATH)) {
@@ -694,20 +839,7 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
goto out;
}
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
rc = -1;
goto out;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
rc = ap_check_active(anc);
/* If successful, lock must remain held until post callout */
if (rc == 0)
@@ -886,6 +1018,122 @@ static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
return 0;
}
/*
* If the target 'attr' is in the 's' array, add it to the 't' array.
*/
static void json_add_attr(json_object *t, json_object *s, const char *attr)
{
size_t vlen, alen = strlen(attr);
const char *val;
json_object *o;
int i, num;
num = json_object_array_length(s);
for (i = 0; i < num; i++) {
o = json_object_array_get_idx(s, i);
val = json_object_get_string(o);
vlen = strlen(val);
if (alen == vlen && strncasecmp(attr, val, alen) == 0) {
json_object_array_add(t, json_object_new_string(val));
return;
}
}
}
/*
* Generate a JSON-formatted list of capability information that this script
* supports and return it to the caller via stdout. An example of what the
* output should look like (without the newlines):
* {
* "supports": {
* "version": 2,
* "actions": ["define",
* "modify",
* "start",
* "stop",
* "undefine",
* "attributes",
* "capabilities"],
* "events": ["pre",
* "post",
* "get",
* "live"]
* }
* }
*/
static int ap_check_handle_get_capabilities(void)
{
json_object *root, *csup, *cver, *cact, *cev, *cap, *caps, *o;
int i, rc = 0;
root = json_object_from_fd(STDIN_FILENO);
if (!root) {
fprintf(stderr, "No capabilities provided\n");
return -1;
}
if (!json_object_object_get_ex(root, "provides", &csup)) {
fprintf(stderr, "No supported capabilities provided\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "version", &cver)) {
fprintf(stderr, "No version provided in capabilities\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "actions", &cact)) {
fprintf(stderr, "No actions provided in capabilities\n");
rc = -1;
goto out;
}
if (!json_object_object_get_ex(csup, "events", &cev)) {
fprintf(stderr, "No events provided in capabilities\n");
rc = -1;
goto out;
}
/*
* Advertise the subset of supported capabilities from the list
* provided on stdin.
*/
cap = json_object_new_object();
caps = json_object_new_object();
json_object_object_add(cap, "supports", caps);
/*
* Currently we always advertise a fixed version, but we may need to
* revisit this if we increase MDEVCTL_CAP_VERSION in the future (e.g.
* how to handle ap-check having a greater supported version than
* what mdevctl reports)
*/
o = json_object_new_int(MDEVCTL_CAP_VERSION);
json_object_object_add(caps, "version", o);
o = json_object_new_array();
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++)
json_add_attr(o, cact, mdevctl_action_table[i].action);
json_object_object_add(caps, "actions", o);
o = json_object_new_array();
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++)
json_add_attr(o, cev, mdevctl_event_table[i].event);
json_object_object_add(caps, "events", o);
/* Return supported capabilities JSON on stdout */
printf("%s\n", json_object_to_json_string(cap));
json_object_put(cap);
out:
json_object_put(root);
return rc;
}
/*
* Determine which mdevctl action is being checked and handle accordingly.
*/
@@ -911,8 +1159,6 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
case MDEVCTL_ACTION_UNDEFINE:
rc = ap_check_handle_undefine(anc);
break;
case MDEVCTL_ACTION_LIST:
case MDEVCTL_ACTION_TYPES:
default:
/* Ignore some actions including unknown ones */
break;
@@ -937,6 +1183,19 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
case MDEVCTL_ACTION_ATTRIBUTES:
rc = ap_check_handle_get_attributes(anc);
break;
case MDEVCTL_ACTION_CAPABILITIES:
rc = ap_check_handle_get_capabilities();
break;
default:
/* Ignore some actions including unknown ones */
break;
}
break;
case MDEVCTL_EVENT_LIVE:
switch (anc->action) {
case MDEVCTL_ACTION_MODIFY:
rc = ap_check_handle_live_modify(anc);
break;
default:
/* Ignore some actions including unknown ones */
break;

View File

@@ -24,6 +24,7 @@ enum mdevctl_action_id {
MDEVCTL_ACTION_TYPES,
MDEVCTL_ACTION_UNDEFINE,
MDEVCTL_ACTION_ATTRIBUTES,
MDEVCTL_ACTION_CAPABILITIES,
/* UNKNOWN must always be the last in the list */
MDEVCTL_ACTION_UNKNOWN,
};
@@ -38,6 +39,7 @@ enum mdevctl_event_id {
MDEVCTL_EVENT_PRE = 0,
MDEVCTL_EVENT_POST,
MDEVCTL_EVENT_GET,
MDEVCTL_EVENT_LIVE,
MDEVCTL_EVENT_UNKNOWN,
};
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN

View File

@@ -951,7 +951,7 @@ static void set_record_extension(struct file *f, int *record, off_t addr,
if (f->record_scan_state != RSS_DATA_BLOCK_STARTED &&
f->record_scan_state != RSS_DATA_BLOCK_EXT)
DIE("%s: interal error\n", __func__);
DIE("%s: internal error\n", __func__);
BUG(*record >= f->fst->nr_records);

View File

@@ -32,8 +32,8 @@ endif
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION := 2
RELEASE := 33
PATCHLEVEL := 1
RELEASE := 36
PATCHLEVEL := 0
DISTRELEASE := build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
export S390_TOOLS_RELEASE
@@ -48,7 +48,7 @@ export S390_TEST_LIB_PATH=$(rootdir)/s390-tools-testsuite/lib
# $ make HOST_ARCH=s390x CROSS_COMPILE="s390x-linux-gnu-"
#
CROSS_COMPILE =
CROSS_COMPILE ?=
#
# Commands can be overwritten on the command line with "make <VAR>=<VALUE>":
@@ -504,6 +504,10 @@ $(rootdir)/libpv/libpv.a: $(rootdir)/libpv
$(MAKE) -C $(rootdir)/libpv libpv.a
.PHONY: $(rootdir)/libpv
$(rootdir)/libzpci/libzpci.a: $(rootdir)/libzpci
$(MAKE) -C $(rootdir)/libzpci libzpci.a
.PHONY: $(rootdir)/libzpci
$(rootdir)/zipl/boot/.loaders:
$(MAKE) -C $(rootdir)/zipl/boot/ .loaders

View File

@@ -23,7 +23,7 @@
* Number of PAI counters. Contains all counters regardless of kernel or user
* space
*/
#define MAX_NUM_PAI 156
#define MAX_NUM_PAI 172
/*
* This is the sysfs directory from which cpacfstatsd daemon application loads

View File

@@ -192,7 +192,27 @@ const struct pai_counter pai[] = {
[152] = {"PCKMO ECC Ed25519", KERNEL_ONLY_COUNTER},
[153] = {"PCKMO ECC Ed448", KERNEL_ONLY_COUNTER},
[154] = {"Reserved 1", KERNEL_ONLY_COUNTER},
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER}
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER},
[156] = {"KM AES-XTS (full) 128bit", KERNEL_AND_USER_COUNTER},
[157] = {"KM AES-XTS (full) 256bit", KERNEL_AND_USER_COUNTER},
[158] = {"KM AES-XTS (full) 128bit protected key",
KERNEL_AND_USER_COUNTER},
[159] = {"KM AES-XTS (full) 256bit protected key",
KERNEL_AND_USER_COUNTER},
[160] = {"KMAC HMAC SHA 224", KERNEL_AND_USER_COUNTER},
[161] = {"KMAC HMAC SHA 256", KERNEL_AND_USER_COUNTER},
[162] = {"KMAC HMAC SHA 384", KERNEL_AND_USER_COUNTER},
[163] = {"KMAC HMAC SHA 512", KERNEL_AND_USER_COUNTER},
[164] = {"KMAC HMAC SHA 224 protected key", KERNEL_AND_USER_COUNTER},
[165] = {"KMAC HMAC SHA 256 protected key", KERNEL_AND_USER_COUNTER},
[166] = {"KMAC HMAC SHA 384 protected key", KERNEL_AND_USER_COUNTER},
[167] = {"KMAC HMAC SHA 512 protected key", KERNEL_AND_USER_COUNTER},
[168] = {"PCKMO HMAC 512 protected key", KERNEL_ONLY_COUNTER},
[169] = {"PCKMO HMAC 1024 protected key", KERNEL_ONLY_COUNTER},
[170] = {"PCKMO AES-XTS 128bit double key protected key",
KERNEL_ONLY_COUNTER},
[171] = {"PCKMO AES-XTS 256bit double key protected key",
KERNEL_ONLY_COUNTER}
};
/*

View File

@@ -39,7 +39,8 @@ static volatile int stopsig;
*/
static const unsigned int pai_idx[] = {
// KM
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 156, 157, 158,
159,
// KMC
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
// KMA
@@ -55,7 +56,8 @@ static const unsigned int pai_idx[] = {
// KLMD
81, 82, 83, 84, 85, 86, 87, 88, 89,
// KMAC
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 160, 161, 162, 163,
164, 165, 166, 167,
// PCC
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
@@ -65,7 +67,7 @@ static const unsigned int pai_idx[] = {
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
140, 141, 142,
// PCKMO
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153,
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 168, 169, 170, 171,
// Reserved
154, 155
};
@@ -108,7 +110,6 @@ static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
return rc;
}
static int send_answer(int s, int ctr, int state, uint64_t value)
{
struct msg m;
@@ -124,7 +125,6 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
}
/*
* Print according to protocol for PAI:
* - first the state and the number of PAI counters that follow
@@ -160,7 +160,6 @@ static int do_send_pai(int s, int user, unsigned int *counter)
return rc;
}
static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
uint64_t value = 0;
@@ -201,7 +200,6 @@ static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0;
@@ -228,7 +226,6 @@ static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0, state;
@@ -260,7 +257,6 @@ static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
{
int i, rc = 0, state;
@@ -292,7 +288,6 @@ static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
return rc;
}
static int become_daemon(int *startup_pipe)
{
int child_initialized = 0, fd;
@@ -385,7 +380,6 @@ static int become_daemon(int *startup_pipe)
return 0;
}
static void remove_sock(void)
{
remove(SOCKET_FILE);
@@ -447,14 +441,12 @@ static void remove_pidfile(void)
remove(PID_FILE);
}
void signalhandler(int sig)
{
perf_stop();
stopsig = sig;
}
int eprint(const char *format, ...)
{
char buf[512];
@@ -476,7 +468,6 @@ int eprint(const char *format, ...)
return n;
}
/*
* returns -1 on error
* returns X where X is the found counters in dir

View File

@@ -4,9 +4,11 @@ all: cpuplugd
LDLIBS += -lm
libs = $(rootdir)/libutil/libutil.a
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
cpuplugd: $(OBJECTS)
cpuplugd: $(OBJECTS) $(libs)
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
clean:

View File

@@ -204,6 +204,45 @@ void parse_configfile(char *file)
fclose(filp);
}
void apply_cpu_config(void)
{
/*
* Check that the initial number of cpus is not below the
* minimum
*/
if (num_cpu_start < cfg.cpu_min &&
get_numcpus() >= cfg.cpu_min) {
cpuplugd_debug("The number of online cpus is below ");
cpuplugd_debug("the minimum and will be increased.\n");
while (get_num_online_cpus() < cfg.cpu_min) {
if (hotplug_one_cpu())
break;
}
}
if (get_num_online_cpus() > cfg.cpu_max) {
cpuplugd_debug("The number of online cpus is above the maximum");
cpuplugd_debug(" and will be decreased.\n");
while (get_num_online_cpus() > cfg.cpu_max) {
if (hotunplug_one_cpu())
break;
}
}
if (cfg.cpu_min > get_numcpus()) {
/*
* This check only works if nobody used the
* additional_cpus in the boot parameter section
*/
cpuplugd_debug("The minimum amount of cpus is above the ");
cpuplugd_debug("number of available cpus.\n");
cpuplugd_exit("Detected %d available cpus\n", get_numcpus());
}
if (get_num_online_cpus() < cfg.cpu_min) {
cpuplugd_debug("Failed to set the number of online cpus to ");
cpuplugd_debug("the minimum. ");
cpuplugd_exit("Aborting.\n");
}
}
/*
* Check if the required settings are found in the configuration file.
* "Autodetect" if cpu and/or memory hotplug configuration entries
@@ -211,7 +250,6 @@ void parse_configfile(char *file)
*/
void check_config()
{
int cpuid;
int lpar_status;
lpar_status = check_lpar();
@@ -262,60 +300,23 @@ void check_config()
/*
* Save the number of online cpus and the cmm_pagesize at startup,
* so that we can enable exactly the same amount when the daemon ends
*
* Don't adjust cpus if system is on vertical polarization
*/
if (cpu) {
num_cpu_start = get_num_online_cpus();
cpuplugd_debug("Daemon started with %d active cpus.\n",
num_cpu_start);
/*
* Check that the initial number of cpus is not below the
* minimum
*/
if (num_cpu_start < cfg.cpu_min &&
get_numcpus() >= cfg.cpu_min) {
cpuplugd_debug("The number of online cpus is below "
"the minimum and will be increased.\n");
cpuid = 0;
while (get_num_online_cpus() < cfg.cpu_min &&
cpuid < get_numcpus()) {
if (is_online(cpuid) == 1) {
cpuid++;
continue;
}
cpuplugd_debug("cpu with id %d is currently offline "
"and will be enabled\n", cpuid);
hotplug(cpuid);
cpuid++;
}
}
if (get_num_online_cpus() > cfg.cpu_max) {
cpuplugd_debug("The number of online cpus is above the maximum"
" and will be decreased.\n");
cpuid = 0;
while (get_num_online_cpus() > cfg.cpu_max &&
cpuid < get_numcpus()) {
if (is_online(cpuid) != 1) {
cpuid++;
continue;
}
cpuplugd_debug("cpu with id %d is currently online "
"and will be disabled\n", cpuid);
hotunplug(cpuid);
cpuid++;
}
}
if (cfg.cpu_min > get_numcpus())
/*
* This check only works if nobody used the
* additional_cpus in the boot parameter section
*/
cpuplugd_exit("The minimum amount of cpus is above "
"the number of available cpus.\n"
"Detected %d available cpus\n",
get_numcpus());
if (get_num_online_cpus() < cfg.cpu_min)
cpuplugd_exit("Failed to set the number of online "
"cpus to the minimum. Aborting.\n");
saved_polarization = get_polarization();
num_cpu_start = get_num_online_cpus();
cpuplugd_debug("Daemon started with %d active cpus.\n",
num_cpu_start);
if (saved_polarization < 0) {
cpuplugd_debug("Daemon couldn't determine system polarization\n");
cpuplugd_debug("Starting without evaluating cpu rules\n");
} else if (saved_polarization == PLR_VERTICAL) {
cpuplugd_debug("Daemon started with vertical polarization.\n");
cpuplugd_debug("Cpu adjustments won't be made until system ");
cpuplugd_debug("is in horizontal polarization\n");
} else if (saved_polarization == PLR_HORIZONTAL &&
cpu == 1) {
apply_cpu_config();
}
if (memory == 1) {
/*

View File

@@ -12,217 +12,241 @@
#include <limits.h>
#include "cpuplugd.h"
#define NUM_BASE (10)
#define CPU_OFFLINE (0)
#define CPU_ONLINE (1)
#define CPU_DECONFIGURED (0)
#define CPU_CONFIGURED (1)
#define CPU_LIST_LEN (4096)
/*
* Return overall number of available cpus. This does not necessarily
* mean that those are currently online
*/
int get_numcpus()
static int get_sysfs_attribute_cpu_count(char *path)
{
int i;
char path[PATH_MAX];
int number = 0;
char cpu_list[CPU_LIST_LEN];
int number, start, end;
char *sub_list;
for (i = 0; ; i++) {
/* check whether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d", i);
if (access(path, R_OK) == 0)
if (util_file_read_line(cpu_list, sizeof(cpu_list), path))
cpuplugd_exit("Cannot open %s file: %s\n", path, strerror(errno));
number = 0;
sub_list = strtok(cpu_list, ",");
while (sub_list) {
if (strchr(sub_list, '-')) {
if (sscanf(sub_list, "%d-%d", &start, &end) != 2)
cpuplugd_exit("Malformed content of %s: %s\n", path, sub_list);
number += (end - start) + 1;
} else {
number++;
else
break;
}
sub_list = strtok(NULL, ",");
}
return number;
}
/*
* Return number of online cpus
* get_numcpus() - return number of present cpus by sysfs'
* cpu/present attribute.
* This number represents the total number of usable cpus,
* this includes offline or deconfigured cpus as well.
*/
int get_num_online_cpus()
int get_numcpus(void)
{
FILE *filp;
int i;
char path[PATH_MAX];
int status = 0;
int value_of_onlinefile, rc;
int number;
char *path;
for (i = 0; i < get_numcpus(); i++) {
/* check wether file exists and is readable */
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
if (access(path, R_OK) != 0) {
status++;
continue;
}
filp = fopen(path, "r");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: "
"%s\n", strerror(errno));
else {
rc = fscanf(filp, "%d", &value_of_onlinefile);
if (rc != 1)
cpuplugd_exit("Cannot read cpu online file: "
"%s\n", strerror(errno));
if (value_of_onlinefile == 1)
status++;
}
fclose(filp);
path = util_path_sysfs("devices/system/cpu/present");
number = get_sysfs_attribute_cpu_count(path);
free(path);
if (number <= 0)
cpuplugd_exit("number of present cpus (%d) <= 0\n", number);
return number;
}
/*
* get_num_online_cpus() - return number of online cpus
* by parsing sysfs cpu/online attribute
*/
int get_num_online_cpus(void)
{
int number;
char *path;
path = util_path_sysfs("devices/system/cpu/online");
number = get_sysfs_attribute_cpu_count(path);
free(path);
if (number <= 0)
cpuplugd_exit("number of online cpus (%d) <= 0\n", number);
return number;
}
/*
* get_polarization() - return system polarization
*/
int get_polarization(void)
{
int polarization;
char *path;
path = util_path_sysfs("devices/system/cpu/dispatching");
if (util_file_read_i(&polarization, NUM_BASE, path) < 0) {
polarization = -1;
cpuplugd_debug("failed to read system polarization\n");
}
free(path);
return polarization;
}
/*
* is_cpu_hotpluggable() - check if cpuhotplug operations are supported
* for the given cpu.
*/
static int is_cpu_hotpluggable(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_path_exists(path);
free(path);
return rc;
}
/*
* hotplug() - perform cpu hotplug on given cpuid
*/
static int hotplug(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_file_write_l(CPU_ONLINE, NUM_BASE, path);
if (rc < 0)
cpuplugd_debug("failed to enable cpu with id %d\n", cpuid);
free(path);
return rc;
}
/*
* hotunplug() - perform cpu hotunplug on given cpuid
*/
static int hotunplug(int cpuid)
{
char *path;
int rc;
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
rc = util_file_write_l(CPU_OFFLINE, NUM_BASE, path);
if (rc < 0)
cpuplugd_debug("failed to disable cpu with id %d\n", cpuid);
free(path);
return rc;
}
/*
* get_cpu_attribute() - get a certain cpu's selected attribute
*/
static int get_cpu_attribute(int cpuid, char *attribute)
{
int status;
char *path;
path = util_path_sysfs("devices/system/cpu/cpu%d/%s", cpuid, attribute);
if (util_file_read_i(&status, NUM_BASE, path) < 0) {
status = -1;
cpuplugd_debug("failed to read %s status of cpu with id %d\n", attribute, cpuid);
}
free(path);
return status;
}
/*
* Enable a certain cpu
* hotplug_one_cpu() - perform hotplugging on the first available cpu
*/
int hotplug(int cpuid)
int hotplug_one_cpu(void)
{
FILE *filp;
char path[PATH_MAX];
int status, rc;
struct dirent **cpu_dir;
int cpuid, count, i, rc;
char *path;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, W_OK) == 0) {
filp = fopen(path, "w");
if (!filp)
cpuplugd_exit("Cannot open cpu online file: %s\n",
strerror(errno));
fprintf(filp, "1");
fclose(filp);
/*
* check if the attempt to enable the cpus really worked
*/
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &status);
if (rc != 1)
cpuplugd_exit("Cannot open cpu online file: %s\n",
strerror(errno));
fclose(filp);
if (status == 1) {
cpuplugd_debug("cpu with id %d enabled\n", cpuid);
return 1;
} else {
cpuplugd_debug("failed to enable cpu with id %d\n",
cpuid);
return -1;
rc = -1;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (rc != 0); i++) {
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (!is_cpu_hotpluggable(cpuid))
continue;
if (get_cpu_attribute(cpuid, "configure") == CPU_CONFIGURED &&
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) {
cpuplugd_debug("cpu%d will be enabled", cpuid);
rc = hotplug(cpuid);
}
}
cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid);
return -1;
util_scandir_free(cpu_dir, count);
free(path);
return rc;
}
/*
* Disable a certain cpu
* hotunplug_one_cpu() - perform hotunplugging on the first available cpu
*/
int hotunplug(int cpuid)
int hotunplug_one_cpu(void)
{
FILE *filp;
int state, rc;
int retval = -1;
char path[PATH_MAX];
struct dirent **cpu_dir;
int cpuid, count, i, rc;
char *path;
state = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, W_OK) == 0) {
filp = fopen(path, "w");
fprintf(filp, "0");
fclose(filp);
/*
* Check if the attempt to enable the cpus really worked
*/
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc != 1)
cpuplugd_error("Failed to disable cpu with id %d\n",
cpuid);
fclose(filp);
if (state == 0)
return 1;
}
cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid);
return retval;
}
/*
* Check if a certain cpu is currently online
*/
int is_online(int cpuid)
{
FILE *filp;
int state;
int retval, rc;
char path[PATH_MAX];
retval = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
if (access(path, R_OK) == 0) {
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc == 1) {
if (state == 1)
retval = 1;
if (state == 0)
retval = 0;
rc = -1;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (rc != 0); i++) {
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (!is_cpu_hotpluggable(cpuid))
continue;
if (get_cpu_attribute(cpuid, "online") == CPU_ONLINE) {
cpuplugd_debug("cpu%d will be disabled\n", cpuid);
rc = hotunplug(cpuid);
}
fclose(filp);
} else {
retval = 1;
}
return retval;
util_scandir_free(cpu_dir, count);
free(path);
return rc;
}
/*
* Cleanup method. If the daemon is stopped, we (re)activate all cpus
*/
void reactivate_cpus()
void reactivate_cpus(void)
{
/*
* Only enable the number of cpus which where
* available at daemon startup time
*/
int cpuid, nc;
struct dirent **cpu_dir;
int cpuid, nc, count, i;
char *path;
cpuid = 0;
/* suppress verbose messages on exit */
debug = 0;
/*
* We check for num_cpu_start != 0 because we might want to
* clean up, before we queried for the number on cpus at
* startup
*/
/*
* Only enable the number of cpus which where available at
* daemon startup time by checking num_cpu_start.
* We check for num_cpu_start != 0 because we might want to
* clean up, before we queried for the number on cpus at
* startup
*/
if (num_cpu_start == 0)
return;
while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) {
nc = 0;
path = util_path_sysfs("devices/system/cpu/");
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
for (i = 0; (i < count) && (nc != num_cpu_start); i++) {
nc = get_num_online_cpus();
if (nc == num_cpu_start)
return;
if (nc > num_cpu_start && is_online(cpuid) == 1)
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
if (nc > num_cpu_start &&
get_cpu_attribute(cpuid, "online") == CPU_ONLINE)
hotunplug(cpuid);
if (nc < num_cpu_start && is_online(cpuid) == 0)
if (nc < num_cpu_start &&
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE)
hotplug(cpuid);
cpuid++;
}
util_scandir_free(cpu_dir, count);
free(path);
}
/*
* In kernels > 2.6.24 cpus can be deconfigured. The following functions is used
* to check if a certain cpus is in a deconfigured state.
*/
int cpu_is_configured(int cpuid)
{
FILE *filp;
int retval, state, rc;
char path[4096];
retval = -1;
sprintf(path, "/sys/devices/system/cpu/cpu%d/configure", cpuid);
if (access(path, R_OK) == 0) {
filp = fopen(path, "r");
rc = fscanf(filp, "%d", &state);
if (rc == 1) {
if (state == 1)
retval = 1;
if (state == 0)
retval = 0;
}
fclose(filp);
}
return retval;
}

View File

@@ -23,6 +23,9 @@
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_path.h"
#include "lib/util_file.h"
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
#define NAME "cpuplugd"
@@ -35,6 +38,8 @@
#define MAX_VARNAME 128
#define MAX_LINESIZE 2048
#define CPUSTATS 10
#define PLR_HORIZONTAL 0
#define PLR_VERTICAL 1
/*
* Precedence of C operators
@@ -173,9 +178,11 @@ extern unsigned int history_max;
extern unsigned int history_current;
extern struct symbol_names sym_names[];
extern unsigned int sym_names_count;
extern int saved_polarization;
int get_numcpus();
int get_num_online_cpus();
int get_polarization(void);
void get_loadavg_runnable(double *loadavg, double *runnable);
void clean_up();
void reactivate_cpus();
@@ -190,9 +197,8 @@ void proc_cpu_read(char *procinfo);
unsigned long proc_read_size(char *path);
char *get_var_rvalue(char *var_name);
void cleanup_cmm(void);
int hotplug(int cpuid);
int hotunplug(int cpuid);
int is_online(int cpuid);
int hotplug_one_cpu(void);
int hotunplug_one_cpu(void);
long get_cmmpages_size();
void parse_options(int argc, char **argv);
void check_if_started_twice();
@@ -202,9 +208,9 @@ void reload_daemon(void);
int daemonize(void);
int check_cmmfiles(void);
void check_config();
void apply_cpu_config(void);
void set_cmm_pages(long size);
int check_lpar();
int cpu_is_configured(int cpuid);
void setup_history(void);

View File

@@ -149,6 +149,8 @@ void clean_up()
cpuplugd_info("terminated\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();
@@ -163,6 +165,8 @@ void kill_daemon(int UNUSED(a))
cpuplugd_info("shutting down\n");
remove(pid_file);
remove(LOCKFILE);
/* suppress verbose messages on exit */
debug = 0;
reactivate_cpus();
if (memory)
cleanup_cmm();

View File

@@ -54,12 +54,12 @@ struct config cfg = {
.hotunplug = NULL,
};
int num_cpu_start, memory, cpu, reload_pending;
long cmm_pagesize_start;
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
char *meminfo, *vmstat, *cpustat, *varinfo;
double *timestamps;
unsigned int history_max, history_current, history_prev, sym_names_count;
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
int num_cpu_start, memory, cpu, reload_pending, saved_polarization;
char *meminfo, *vmstat, *cpustat, *varinfo;
long cmm_pagesize_start;
double *timestamps;
static struct symbols symbols;
static jmp_buf jmpenv;
@@ -77,8 +77,29 @@ static void eval_cpu_rules(void)
{
double diffs[CPUSTATS], diffs_total, percent_factor;
char *procinfo_current, *procinfo_prev;
int cpu, nr_cpus, on_off;
int nr_cpus, on_off, polarization;
polarization = get_polarization();
if (polarization < 0) {
cpuplugd_debug("couldn't determine system polarization\n");
cpuplugd_debug("skipping cpu rule evaluation\n");
return;
}
if (saved_polarization != polarization) {
saved_polarization = polarization;
if (polarization == PLR_VERTICAL) {
/* revert cpu hotplug adjustments after switching from horizontal */
reactivate_cpus();
} else if (polarization == PLR_HORIZONTAL) {
/* reapply cpu config after switching from vertical */
apply_cpu_config();
}
}
if (polarization == PLR_VERTICAL) {
cpuplugd_debug("system is running vertical polarization\n");
cpuplugd_debug("cpuplugd won't make cpu adjustments\n");
return;
}
nr_cpus = get_numcpus();
procinfo_current = cpustat + history_current * cpustat_size;
procinfo_prev = cpustat + history_prev * cpustat_size;
@@ -157,7 +178,6 @@ static void eval_cpu_rules(void)
printf("\n");
printf("---------------------------------------------\n");
}
on_off = 0;
/* Evaluate the hotplug rule */
if (eval_term(cfg.hotplug, &symbols))
@@ -172,40 +192,16 @@ static void eval_cpu_rules(void)
cpuplugd_debug("maximum cpu limit is reached\n");
return;
}
/* try to find a offline cpu */
for (cpu = 0; cpu < nr_cpus; cpu++)
if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0)
break;
if (cpu < nr_cpus) {
cpuplugd_debug("cpu with id %d is currently offline "
"and will be enabled\n", cpu);
if (hotplug(cpu) == -1)
cpuplugd_debug("unable to find a cpu which "
"can be enabled\n");
} else {
/*
* In case we tried to enable a cpu but this failed.
* This is the case if a cpu is deconfigured
*/
cpuplugd_debug("unable to find a cpu which can "
"be enabled\n");
}
if (hotplug_one_cpu())
cpuplugd_debug("unable to find a cpu which can be enabled\n");
} else if (on_off < 0) {
/* check cpu nr limit */
if (symbols.onumcpus <= cfg.cpu_min) {
cpuplugd_debug("minimum cpu limit is reached\n");
return;
}
/* try to find a online cpu */
for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) {
if (is_online(cpu) != 0)
break;
}
if (cpu > 0) {
cpuplugd_debug("cpu with id %d is currently online "
"and will be disabled\n", cpu);
hotunplug(cpu);
}
if (hotunplug_one_cpu())
cpuplugd_debug("unable to find a cpu which can be disabled\n");
}
}

View File

@@ -22,6 +22,9 @@ of active CPUs are reset to the values they had before the cpuplugd was started.
This program can be used to control the number of CPUs for Linux on z/VM
and for Linux in LPAR mode. The memory hotplug feature (CMM page pool) applies
to Linux on z/VM only.
The cpuplugd daemon stops any CPU hot-plug operations when the system switches
to vertical polarization, thus avoiding possible performance penalties.
.
.SH OPTIONS
.TP

View File

@@ -31,11 +31,11 @@
#
# Dump on ECKD device (DASD)
#
#ON_PANIC=dump
#DUMP_TYPE=eckd
#DEVICE=0.0.1004
#BOOTPROG=0
#BR_CHR=auto
# ON_PANIC=dump
# DUMP_TYPE=eckd
# DEVICE=0.0.1004
# BOOTPROG=0
# BR_CHR=auto
#
# Dump on fcp device (SCSI Disk)

View File

@@ -1,5 +0,0 @@
tags
compile_commands.json
src/.check-dep-genprotimg
src/.detect-openssl.dep.c
src/genprotimg

View File

@@ -1,25 +0,0 @@
# Common definitions
include ../common.mak
.DEFAULT_GOAL := all
PKGDATADIR := "$(TOOLS_DATADIR)/genprotimg"
TESTS :=
SUBDIRS := boot src man
RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
all: all-recursive
install: install-recursive
$(INSTALL) -d -m 755 "$(DESTDIR)$(PKGDATADIR)"
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(DESTDIR)$(PKGDATADIR)"
clean: clean-recursive
$(RECURSIVE_TARGETS):
@target=`echo $@ |sed s/-recursive//`; \
for d in $(SUBDIRS); do \
$(MAKE) -C $$d $$target || exit 1; \
done
.PHONY: all install clean $(RECURSIVE_TARGETS)

View File

@@ -1,85 +0,0 @@
# genprotimg
`genprotimg` 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 PV header, containing the metadata necessary for
running the guest in protected mode. See [Memory Layout](#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 `genprotimg`.
## Details
The main idea of `genprotimg` is:
1. read in 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 PV header: generate the hashes (pld, ald, and tld) of
the components and create the PV header and IPIB
6. parameterize the stub stage3a: uses the IPIB and PV header
7. write the final image to the specified output path
### 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 parmline.
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.
#### Detail about 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 placed 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 |
| 0x10000 | 0x10012 | Branch to 0x11000 |
| 0x10013 | 0x10fff | Left intentionally unused |
| 0x11000 | 0x12fff | Stage3a |
| 0x13000 | 0x13fff | IPIB used as argument for the diag308 call |
| 0x14000 | 0x1[45]fff | UV 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 |

View File

@@ -1,12 +0,0 @@
# Common definitions
include ../../common.mak
all:
install:
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c genprotimg.1 $(DESTDIR)$(MANDIR)/man1
clean:
.PHONY: all install clean

View File

@@ -1,159 +0,0 @@
.\" Copyright 2020 IBM Corp.
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH GENPROTIMG 1 "May 2022" "s390-tools"
.SH NAME
genprotimg \- Create a protected virtualization image
.SH SYNOPSIS
.SY
.B genprotimg
\fB\-k\fR \fIHOST_KEY_DOCUMENT\fR...
\fB\-C\fR \fICERTIFICATE\fR...
\fB\-i\fR \fIVMLINUZ\fR
[\fB\-r\fR \fIRAMDISK\fR]
[\fB\-p\fR \fIPARMFILE\fR]
\fB\-o\fR \fIOUTFILE\fR
[\fIOPTION\fR]...
.YS
.SH DESCRIPTION
.PP
Use \fBgenprotimg\fR to generate a single bootable image file with
encrypted and integrity-protected parts. The command requires a kernel
image, a host-key document, certificates for the host-key document
verification, and an output file name. Optionally, specify an initial
RAM filesystem, and a file containing the kernel parameters. If the
command should be run offline, use the \fB\-\-offline\fR option and
specify the certificate revocation lists (CRLs) by using the
\fB\-\-crl\fR option. Should special circumstances require it, you can
optionally specify your own keys for the encryption by using the
experimental options. For all certificates, CRLs, and host-key
documents, both the PEM and DER input formats are supported. In the
resulting image file, a plain text boot loader, the encrypted
components for kernel, initial RAM disk, kernel parameters, and the
encrypted and integrity-protected header are concatenated. The header
contains metadata necessary for running the guest in protected mode.
.PP
Use this image file as a kernel image for zipl or for a direct kernel
boot using QEMU.
.SH OPTIONS
.TP
\fB\-h\fR, \fB\-\-help\fR
Prints usage information, then exits.
.TP
\fB\-\-help-experimental\fR
Prints experimental usage information, then exits.
.TP
\fB\-\-help-all\fR
Prints all usage information, then exits.
.TP
\fB\-V\fR, \fB\-\-verbose\fR
Provides more detailed output.
.TP
\fB\-k\fR, \fB\-\-host-key-document\fR=\fI\,HOST_KEY_DOCUMENT\/\fR
Specifies a host-key document. At least one is required. Specify this
option multiple times to enable the image to run on more than one
host.
.TP
\fB\-C\fR, \fB\-\-cert\fR=\fI\,FILE\/\fR
Specifies the certificate that is used to establish a chain of trust
for the verification of the host-key documents. Specify this option
twice to specify the IBM Z signing key and the intermediate CA
certificate (signed by the root CA).
Required. Ignored if \fB--no-verify\fP is specified.
.TP
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
Specifies the output file. Required.
.TP
\fB\-i\fR, \fB\-\-image\fR=\fI\,VMLINUZ\/\fR
Specifies the Linux kernel image file. Required.
.TP
\fB\-r\fR, \fB\-\-ramdisk\fR=\fI\,RAMDISK\/\fR
Specifies the RAM disk image. Optional.
.TP
\fB\-p\fR, \fB\-\-parmfile\fR=\fI\,PARMFILE\/\fR
Specifies the kernel command line stored in \fI\,PARMFILE\/\fR. Optional.
.TP
\fB\-\-crl\fR=\fI\,FILE\/\fR
Specifies the revocation list that is used to check whether a
certificate of the chain of trust is revoked. Specify this option
multiple times to use multiple CRLs. Optional.
.TP
\fB\-\-offline\fR
Specifies offline mode, in which no attempt is made to download
CRLs. Optional.
.TP
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
Specifies the root CA certificate for the verification. If omitted,
the system wide root CAs installed on the system is used. Use
this only if you trust the specified certificate. Optional.
.TP
\fB\-\-no-verify\fR
Does not require the host-key documents to be valid.
Do not use for a production image unless you verified
the host-key document before. Optional.
.TP
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
Specifies the customer communication key (CCK). This key is used for the
PV guest dump encryption and to derive the CCK-derived extension secret
used for add-secret requests. Use a secure, random, plaintext AES-256
GCM key. Optional.
.TP
\fB\-\-enable\-dump\fR
Enable PV guest dumps. Requires the \fB\-\-comm\-key\fR option. Optional.
.TP
\fB\-\-disable\-dump\fR
Disable PV guest dumps. This is the default.
.TP
\fB\-\-enable\-cck\-extension\-secret\fR
Add-secret requests must provide an extension secret that matches the
CCK-derived extension secret. Requires the \fB\-\-comm\-key\fR option.
Optional.
.TP
\fB\-\-disable\-cck\-extension\-secret\fR
Add-secret requests don't have to provide an extension secret. This is
the default.
.TP
\fB\-\-enable\-pckmo\fR
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
functions. This is the default.
.TP
\fB\-\-disable\-pckmo\fR
Disable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
functions. Optional.
.TP
\fB\-v\fR, \fB\-\-version\fR
Prints version information, then exits.
.SH EXAMPLES
These are examples to generate a protected virtualization image in
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR, the
initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR, the
IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
host-key document in \fI\,host_key.crt\/\fR. An AES-256 GCM key is stored in
\fI\,comm-key\/\fR, which is used for the PV guest dump support in the second
example.
Generate a protected virtualization image:
.PP
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR
Generate a protected virtualization image with PV guest dump support:
.PP
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR \-\-enable\-dump \-\-comm\-key \fI\,comm-key\fR
.SH NOTES
.IP "1." 4
An ELF file cannot be used as a Linux kernel image.
.IP "2." 4
Remember to re-run \fBzipl\fR after updating a protected
virtualization image.
.SH SEE ALSO
\&\fBzipl\fR\|(5), \fBqemu\fR\|(1)

View File

@@ -1,104 +0,0 @@
# Common definitions
include ../../common.mak
bin_PROGRAM = genprotimg
PKGDATADIR ?= "$(TOOLS_DATADIR)/genprotimg"
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
TOP_SRCDIR := $(SRC_DIR)/../
ROOT_DIR = $(TOP_SRC_DIR)/../../
ZIPL_DIR = $(ROOT_DIR)/zipl
LOADER_DIR = $(TOP_SRCDIR)/boot
INCLUDE_PATHS = "$(SRC_DIR)" "$(TOP_SRCDIR)" "$(ROOTDIR)/include"
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
-Wpointer-arith -Wno-error=inline \
$(NULL)
$(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \
pv/pv_comp.c pv/pv_hdr.c pv/pv_ipib.c utils/crypto.c utils/file_utils.c \
pv/pv_args.c utils/buffer.c pv/pv_comps.c pv/pv_error.c \
pv/pv_opt_item.c utils/curl.c \
$(NULL)
$(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
ALL_CFLAGS += -DPKGDATADIR=$(PKGDATADIR) \
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
-DOPENSSL_API_COMPAT=0x10100000L \
$(WARNINGS) \
$(NULL)
ALL_CPPFLAGS += $(INCLUDE_PARMS)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
GLIB2_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags glib-2.0)
GLIB2_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs glib-2.0)
LIBCRYPTO_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcrypto)
LIBCRYPTO_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcrypto)
LIBCURL_CFLAGS := $(shell $(PKG_CONFIG) --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell $(PKG_CONFIG) --silence-errors --libs libcurl)
BUILD_TARGETS := skip-$(bin_PROGRAM)
INSTALL_TARGETS := skip-$(bin_PROGRAM)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_GLIB2},0)
ifneq (${HAVE_LIBCURL},0)
BUILD_TARGETS := $(bin_PROGRAM)
INSTALL_TARGETS := install-$(bin_PROGRAM)
endif
endif
endif
all: $(BUILD_TARGETS)
install: $(INSTALL_TARGETS)
$(bin_PROGRAM): $($(bin_PROGRAM)_OBJS)
skip-$(bin_PROGRAM):
echo " SKIP $(bin_PROGRAM) due to unresolved dependencies"
install-$(bin_PROGRAM): $(bin_PROGRAM)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
$(INSTALL) -c $^ $(DESTDIR)$(USRBINDIR)
clean:
$(RM) -f $($(bin_PROGRAM)_OBJS) $(bin_PROGRAM) .check-dep-$(bin_PROGRAM) .detect-openssl.dep.c
.PHONY: all install clean skip-$(bin_PROGRAM) install-$(bin_PROGRAM)
$($(bin_PROGRAM)_OBJS): .check-dep-$(bin_PROGRAM)
.detect-openssl.dep.c:
echo "#include <openssl/evp.h>" > $@
echo "#if OPENSSL_VERSION_NUMBER < 0x10100000L" >> $@
echo " #error openssl version 1.1.0 is required" >> $@
echo "#endif" >> $@
echo "static void __attribute__((unused)) test(void) {" >> $@
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
echo " EVP_MD_CTX_free(ctx);" >> $@
echo "}" >> $@
.check-dep-$(bin_PROGRAM): .detect-openssl.dep.c
$(call check_dep, \
"$(bin_PROGRAM)", \
"glib.h", \
"glib2-devel / libglib2.0-dev", \
"HAVE_GLIB2=0")
$(call check_dep, \
"$(bin_PROGRAM)", \
$^, \
"openssl-devel / libssl-dev version >= 1.1.0", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(bin_PROGRAM)", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
touch $@

View File

@@ -1,41 +0,0 @@
/*
* Copyright IBM Corp. 2020, 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef COMMON_H
#define COMMON_H
#define GETTEXT_PACKAGE "genprotimg"
#include <glib.h>
#include <glib/gi18n.h>
#include "boot/linux_layout.h"
#include "lib/zt_common.h"
static const gchar tool_name[] = "genprotimg";
static const gchar copyright_notice[] = "Copyright IBM Corp. 2020";
/* default values */
#define GENPROTIMG_STAGE3A_PATH (STRINGIFY(PKGDATADIR) "/stage3a.bin")
#define GENPROTIMG_STAGE3B_PATH (STRINGIFY(PKGDATADIR) "/stage3b_reloc.bin")
#define DEFAULT_INITIAL_PSW_ADDR IMAGE_ENTRY
#define DEFAULT_INITIAL_PSW_MASK (PSW_MASK_EA | PSW_MASK_BA)
#define DO_PRAGMA(x) _Pragma(#x)
# ifdef __clang__
# define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
DO_PRAGMA(clang diagnostic push) \
DO_PRAGMA(clang diagnostic ignored "-Wunused-function") \
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__) \
DO_PRAGMA(clang diagnostic pop)
# else
# define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
# endif
#endif

View File

@@ -1,200 +0,0 @@
/*
* genprotimg - build relocatable secure images
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <glib/gtypes.h>
#include <locale.h>
#include <signal.h>
#include <stdio.h>
#include "common.h"
#include "pv/pv_args.h"
#include "pv/pv_image.h"
#include "utils/crypto.h"
#include "utils/curl.h"
enum {
LOG_LEVEL_CRITICAL = 0,
LOG_LEVEL_INFO = 1,
LOG_LEVEL_DEBUG = 2,
};
static gint log_level = LOG_LEVEL_CRITICAL;
static gchar *tmp_dir;
static void rmdir_recursive(gchar *dir_path, GError **err)
{
const gchar *file = NULL;
g_autoptr(GDir) d = NULL;
if (!dir_path)
return;
d = g_dir_open(dir_path, 0, err);
if (!d) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to open directory '%s': %s"), dir_path,
g_strerror(errno));
return;
}
while ((file = g_dir_read_name(d)) != NULL) {
g_autofree gchar *file_path =
g_build_filename(dir_path, file, NULL);
/* ignore error */
(void)g_unlink(file_path);
}
if (g_rmdir(dir_path) != 0) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to remove directory '%s': %s"), dir_path,
g_strerror(errno));
return;
}
}
static void sig_term_handler(int signal G_GNUC_UNUSED)
{
rmdir_recursive(tmp_dir, NULL);
exit(EXIT_FAILURE);
}
static void log_handler_cb(const gchar *log_domain G_GNUC_UNUSED,
GLogLevelFlags level, const gchar *message,
gpointer user_data G_GNUC_UNUSED)
{
const gchar *prefix = "";
/* filter out messages depending on debugging level */
if ((level & G_LOG_LEVEL_DEBUG) && log_level < LOG_LEVEL_DEBUG)
return;
if ((level & G_LOG_LEVEL_INFO) && log_level < LOG_LEVEL_INFO)
return;
if (level & G_LOG_LEVEL_WARNING)
prefix = "WARNING: ";
if (level & G_LOG_LEVEL_ERROR)
prefix = "ERROR: ";
if (level & (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR))
g_printerr("%s%s\n", prefix, message);
else
g_print("%s%s\n", prefix, message);
}
static void setup_prgname(const gchar *name)
{
g_set_prgname(name);
g_set_application_name(_(name));
}
static void setup_handler(const gint *signals, const gsize signals_n)
{
/* set up logging handler */
g_log_set_handler(NULL,
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
G_LOG_FLAG_RECURSION,
log_handler_cb, NULL);
/* set signal handler */
for (gsize i = 0; i < signals_n; i++)
signal(signals[i], sig_term_handler);
}
static void remove_signal_handler(const gint *signals, const gsize signals_n)
{
for (gsize i = 0; i < signals_n; i++)
signal(signals[i], SIG_DFL);
}
static void __attribute__((constructor)) __init(void);
static void __attribute__((destructor)) __cleanup(void);
gint main(gint argc, gchar *argv[])
{
g_autoptr(PvArgs) args = pv_args_new();
gint signals[] = { SIGINT, SIGTERM };
g_autoptr(PvImage) img = NULL;
gint ret = EXIT_FAILURE;
GError *err = NULL;
setlocale(LC_CTYPE, "");
setup_prgname(tool_name);
setup_handler(signals, G_N_ELEMENTS(signals));
if (pv_args_parse_options(args, &argc, &argv, &err) < 0)
goto error;
/* set new log level */
log_level = args->log_level;
/* if the user has not specified a temporary directory let's
* create one
*/
if (!args->tmp_dir) {
tmp_dir = g_dir_make_tmp("genprotimg-XXXXXX", &err);
if (!tmp_dir)
goto error;
args->tmp_dir = g_strdup(tmp_dir);
}
/* allocate and initialize ``pv_img`` data structure */
img = pv_img_new(args, GENPROTIMG_STAGE3A_PATH, &err);
if (!img)
goto error;
/* add user components: `args->comps` must be sorted by the
* component type => by memory address
*/
for (GSList *iterator = args->comps; iterator; iterator = iterator->next) {
const PvArg *arg = iterator->data;
if (pv_img_add_component(img, arg, &err) < 0)
goto error;
}
if (pv_img_finalize(img, GENPROTIMG_STAGE3B_PATH, &err) < 0)
goto error;
if (pv_img_write(img, args->output_path, &err) < 0)
goto error;
ret = EXIT_SUCCESS;
error:
if (err) {
fputs(err->message, stderr);
fputc('\n', stderr);
g_clear_error(&err);
}
rmdir_recursive(tmp_dir, NULL);
remove_signal_handler(signals, G_N_ELEMENTS(signals));
g_free(tmp_dir);
g_clear_pointer(&img, pv_img_free);
g_clear_pointer(&args, pv_args_free);
exit(ret);
}
static void __init(void)
{
pv_crypto_init();
if (curl_init() != 0)
g_abort();
}
static void __cleanup(void)
{
curl_cleanup();
pv_crypto_cleanup();
}

View File

@@ -1,41 +0,0 @@
/*
* PV cryptography related definitions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_CRYPTO_DEF_H
#define PV_CRYPTO_DEF_H
#include <stdint.h>
#include "lib/zt_common.h"
/* IBM signing key subject */
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
/* Minimum security level for the keys/certificates used to establish a chain of
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
* for details).
*/
#define PV_CERTS_SECURITY_LEVEL 2
union ecdh_pub_key {
struct {
uint8_t x[80];
uint8_t y[80];
};
uint8_t data[160];
} __packed;
#endif

View File

@@ -1,95 +0,0 @@
/*
* PV header definitions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_HDR_DEF_H
#define PV_HDR_DEF_H
#include <openssl/sha.h>
#include "boot/psw.h"
#include "lib/zt_common.h"
#include "utils/crypto.h"
#include "pv_crypto_def.h"
/* Magic number which is used to identify the file containing the PV
* header
*/
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
#define PV_VERSION_1 0x00000100U
/* Internal helper macro */
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
/* Plaintext control flags */
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34) /* dumping of the configuration is allowed */
#define PV_PCF_NO_DECRYPTION __PV_BIT(35) /* prevent Ultravisor decryption during unpack operation */
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
#define PV_PCF_PCKMO_AES __PV_BIT(57) /* PCKMO encrypt-AES-key functions allowed */
#define PV_PCF_PCKM_ECC __PV_BIT(58) /* PCKMO encrypt-ECC-key functions allowed */
/* Secret control flags */
#define PV_SCF_CCK_EXTENSION_SECRET_ENFORCMENT \
__PV_BIT(1) /* All add-secret requests must provide an extension secret */
/* maxima for the PV version 1 */
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
#define PV_V1_PV_HDR_MAX_SIZE (2 * PAGE_SIZE)
typedef struct pv_hdr_key_slot {
uint8_t digest_key[SHA256_DIGEST_LENGTH];
uint8_t wrapped_key[32];
uint8_t tag[AES_256_GCM_TAG_SIZE];
} __packed PvHdrKeySlot;
typedef struct pv_hdr_opt_item {
uint32_t otype;
uint8_t ibk[32];
uint8_t data[];
} __packed PvHdrOptItem;
/* integrity protected data (by GCM tag), but non-encrypted */
struct pv_hdr_head {
uint64_t magic;
uint32_t version;
uint32_t phs;
uint8_t iv[AES_256_GCM_IV_SIZE];
uint32_t res1;
uint64_t nks;
uint64_t sea;
uint64_t nep;
uint64_t pcf;
union ecdh_pub_key cust_pub_key;
uint8_t pld[SHA512_DIGEST_LENGTH];
uint8_t ald[SHA512_DIGEST_LENGTH];
uint8_t tld[SHA512_DIGEST_LENGTH];
} __packed;
/* Must not have any padding */
struct pv_hdr_encrypted {
uint8_t cust_comm_key[32];
uint8_t img_enc_key_1[AES_256_XTS_KEY_SIZE / 2];
uint8_t img_enc_key_2[AES_256_XTS_KEY_SIZE / 2];
struct psw_t psw;
uint64_t scf;
uint32_t noi;
uint32_t res2;
};
STATIC_ASSERT(sizeof(struct pv_hdr_encrypted) ==
32 + 32 + 32 + sizeof(struct psw_t) + 8 + 4 + 4)
typedef struct pv_hdr {
struct pv_hdr_head head;
struct pv_hdr_key_slot *slots;
struct pv_hdr_encrypted *encrypted;
struct pv_hdr_opt_item **optional_items;
uint8_t tag[AES_256_GCM_TAG_SIZE];
} PvHdr;
#endif

View File

@@ -1,556 +0,0 @@
/*
* PV arguments related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include <glib/gprintf.h>
#include "common.h"
#include "pv_comp.h"
#include "pv_error.h"
#include "pv_args.h"
static gchar summary[] =
"Use genprotimg to create a protected virtualization kernel image file,\n"
"which can be loaded using zipl or QEMU. For all certificates, revocation\n"
"lists, and host-key documents, both the PEM and DER input formats are\n"
"supported.";
static gint pv_arg_compare(gconstpointer arg_1, gconstpointer arg_2)
{
g_assert(arg_1);
g_assert(arg_2);
PvComponentType a = ((PvArg *)arg_1)->type;
PvComponentType b = ((PvArg *)arg_2)->type;
if (a < b)
return -1;
if (a == b)
return 0;
return 1;
}
static gint pv_arg_has_type(gconstpointer arg, gconstpointer type)
{
const PvArg *c = arg;
const PvComponentType *t = type;
g_assert(arg);
if (c->type == *t)
return 0;
if (c->type < *t)
return -1;
return 1;
}
static gint pv_args_set_defaults(PvArgs *args, GError **err G_GNUC_UNUSED)
{
if (!args->psw_addr)
args->psw_addr =
g_strdup_printf("0x%lx", DEFAULT_INITIAL_PSW_ADDR);
return 0;
}
static gint pv_args_validate_options(PvArgs *args, GError **err)
{
const PvControlFlagsArgs *cf_args = &args->cf_args;
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
/* Check for mutually exclusive arguments */
if (cf_args->pcf &&
!(cf_args->enable_pckmo == PV_NOT_SET && cf_args->enable_dump == PV_NOT_SET)) {
g_set_error(
err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("The '--x-pcf' option cannot be used with the '--(enable|disable)-pckmo' or"
" '--(enable|disable)-dump' flags.\nUse 'genprotimg --help' for more information"));
return -1;
}
if (cf_args->scf && !(cf_args->enable_cck_extension_secret_enforcement == PV_NOT_SET)) {
g_set_error(
err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("The '--x-scf' option cannot be used with the '--(enable|disable)-extension-secret-required' flags.\nUse 'genprotimg --help' for more information"));
return -1;
}
/* Check for unused arguments */
if (args->unused_values->len > 0) {
g_autofree gchar *unused = NULL;
for (gsize i = args->unused_values->len; i > 0; i--) {
g_autofree gchar *tmp = unused;
unused = g_strjoin(" ", g_ptr_array_index(args->unused_values, i - 1),
tmp,
NULL);
}
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_INVALID_ARGUMENT,
_("Unrecognized arguments: '%s'.\nUse 'genprotimg --help' for more information"),
unused);
return -1;
}
/* Check for mandatory arguments */
if (cf_args->enable_dump == PV_TRUE && !args->cust_comm_key_path) {
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Option '--enable-dump' requires the '--comm-key' option.\nUse 'genprotimg "
"--help' for more information"));
return -1;
}
if (cf_args->enable_cck_extension_secret_enforcement == PV_TRUE &&
!args->cust_comm_key_path) {
g_set_error(
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Option '--enable-cck-extension-secret' requires the '--comm-key' option.\nUse 'genprotimg "
"--help' for more information"));
return -1;
}
if (!args->output_path) {
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
return -1;
}
if (!g_slist_find_custom(args->comps, &KERNEL, pv_arg_has_type)) {
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Option '--image' is required.\nUse 'genprotimg --help' for more information"));
return -1;
}
if (!args->host_keys || g_strv_length(args->host_keys) == 0) {
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Option '--host-key-document' is required.\nUse 'genprotimg --help' for more information"));
return -1;
}
if (!args->no_verify &&
(!args->untrusted_cert_paths ||
g_strv_length(args->untrusted_cert_paths) == 0)) {
g_set_error(
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Either specify the IBM Z signing key and intermediate CA certificate\n"
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
"host-key document verification completely (at your own risk)."));
return -1;
}
return 0;
}
static gboolean cb_add_component(const gchar *option, const gchar *value,
PvArgs *args, GError **err)
{
PvArg *comp = NULL;
gint type = -1;
if (g_str_equal(option, "-i") || g_str_equal(option, "--image"))
type = PV_COMP_TYPE_KERNEL;
if (g_str_equal(option, "-r") || g_str_equal(option, "--ramdisk"))
type = PV_COMP_TYPE_INITRD;
if (g_str_equal(option, "-p") || g_str_equal(option, "--parmfile"))
type = PV_COMP_TYPE_CMDLINE;
if (type < 0) {
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("Invalid option '%s': "), option);
return FALSE;
}
if (g_slist_find_custom(args->comps, &type, pv_arg_has_type)) {
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("Multiple values for option '%s'"), option);
return FALSE;
}
comp = pv_arg_new((PvComponentType)type, value);
args->comps = g_slist_insert_sorted(args->comps, comp, pv_arg_compare);
return TRUE;
}
static gboolean cb_set_string_option(const gchar *option, const gchar *value,
PvArgs *args, GError **err)
{
gchar **args_option = NULL;
if (g_str_equal(option, "--comm-key"))
args_option = &args->cust_comm_key_path;
if (g_str_equal(option, "--root-ca"))
args_option = &args->root_ca_path;
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
args_option = &args->output_path;
if (g_str_equal(option, "--x-comp-key"))
args_option = &args->xts_key_path;
if (g_str_equal(option, "--x-header-key"))
args_option = &args->cust_root_key_path;
if (g_str_equal(option, "--x-pcf"))
args_option = &args->cf_args.pcf;
if (g_str_equal(option, "--x-psw"))
args_option = &args->psw_addr;
if (g_str_equal(option, "--x-scf"))
args_option = &args->cf_args.scf;
if (!args_option) {
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("Invalid option '%s': "), option);
return FALSE;
}
if (*args_option) {
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("Multiple values for option '%s'"), option);
return FALSE;
}
*args_option = g_strdup(value);
return TRUE;
}
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
const gchar *value G_GNUC_UNUSED, PvArgs *args,
GError **err G_GNUC_UNUSED)
{
args->log_level++;
return TRUE;
}
static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
const gchar *value, PvArgs *args,
GError **err G_GNUC_UNUSED)
{
g_ptr_array_add(args->unused_values, g_strdup(value));
return TRUE;
}
#define MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE) (cb_##FLAG##_##VALUE)
#define DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, VALUE) \
static gboolean MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE)(const gchar *option G_GNUC_UNUSED, \
const gchar *value G_GNUC_UNUSED, \
PvArgs *args, GError **err) \
{ \
if (!(args->cf_args.enable_##FLAG == PV_NOT_SET || \
args->cf_args.enable_##FLAG == VALUE)) { \
g_set_error(err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \
"'--enable-" #FLAG "' and '--disable-" #FLAG \
"' are mutually exclusive"); \
return FALSE; \
} \
args->cf_args.enable_##FLAG = VALUE; \
return TRUE; \
}
#define DEFINE_MUT_EXCL_BOOL_FLAG_CBS(FLAG) \
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_TRUE) \
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_FALSE)
#define MUT_EXCL_BOOL_FLAG(NAME, FLAG, ENABLE_DESC, DISABLE_DESC) \
{ \
.long_name = "enable-" #NAME, \
.short_name = 0, \
.flags = G_OPTION_FLAG_NO_ARG, \
.arg = G_OPTION_ARG_CALLBACK, \
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_TRUE), \
.description = ENABLE_DESC, \
}, \
{ \
.long_name = "disable-" #NAME, .short_name = 0, .flags = G_OPTION_FLAG_NO_ARG, \
.arg = G_OPTION_ARG_CALLBACK, \
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_FALSE), \
.description = DISABLE_DESC, \
}
#define INDENT " "
/* Define the callbacks for mutually exclusive command line flags */
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(dump);
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(pckmo);
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(cck_extension_secret_enforcement);
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
GError **err)
{
g_autoptr(GOptionContext) context = NULL;
gboolean print_version = FALSE;
GOptionGroup *group, *x_group;
g_autofree gchar *psw_desc = g_strdup_printf(
_("Load from the specified hexadecimal ADDRESS.\n" INDENT
"Optional; default: '0x%lx'."),
DEFAULT_INITIAL_PSW_ADDR);
GOptionEntry entries[] = {
{ .long_name = "host-key-document",
.short_name = 'k',
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_FILENAME_ARRAY,
.arg_data = &args->host_keys,
.description =
_("FILE specifies a host-key document. At least\n" INDENT
"one is required. Specify this option multiple times\n" INDENT
"to enable the image to run on more than one host."),
.arg_description = _("FILE") },
{ .long_name = "cert",
.short_name = 'C',
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_FILENAME_ARRAY,
.arg_data = &args->untrusted_cert_paths,
.description = _(
"FILE contains a certificate that is used to\n" INDENT
"establish a chain of trust for the verification\n" INDENT
"of the host-key documents. The IBM Z signing\n" INDENT
"key and intermediate CA certificate (signed\n" INDENT
"by the root CA) are required."),
.arg_description = _("FILE") },
{ .long_name = "output",
.short_name = 'o',
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _("Set FILE as the output file."),
.arg_description = _("FILE") },
{ .long_name = "image",
.short_name = 'i',
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_add_component,
.description = _("Use IMAGE as the Linux kernel image."),
.arg_description = _("IMAGE") },
{ .long_name = "ramdisk",
.short_name = 'r',
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_add_component,
.description = _("Use RAMDISK as the initial RAM disk\n" INDENT
"(optional)."),
.arg_description = _("RAMDISK") },
{ .long_name = "parmfile",
.short_name = 'p',
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_add_component,
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
"(optional)."),
.arg_description = _("PARMFILE") },
MUT_EXCL_BOOL_FLAG(dump, dump,
_("Enable PV guest dumps (optional). This option\n" INDENT
"requires the '--comm-key' option."),
_("Disable PV guest dumps (default).")),
MUT_EXCL_BOOL_FLAG(
cck-extension-secret, cck_extension_secret_enforcement,
_("Add-secret requests must provide an extension\n" INDENT
"secret that matches the CCK-derived extension\n" INDENT
"secret (optional). This option requires the\n" INDENT
"'--comm-key' option."),
_("Add-secret requests don't have to provide\n" INDENT
"the CCK-derived extension secret (default).")),
MUT_EXCL_BOOL_FLAG(pckmo, pckmo,
_("Enable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (default)."),
_("Disable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (optional).")),
{ .long_name = "comm-key",
.short_name = 0,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _(
"FILE contains the customer communication key\n" INDENT
"(CCK) (optional)."),
.arg_description = _("FILE") },
{ .long_name = "crl",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_FILENAME_ARRAY,
.arg_data = &args->crl_paths,
.description = _(
"FILE contains a certificate revocation list\n" INDENT
"(optional)."),
.arg_description = _("FILE") },
{ .long_name = "offline",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_NONE,
.arg_data = &args->offline,
.description = _("Don't download CRLs (optional)."),
.arg_description = NULL },
{ .long_name = "root-ca",
.short_name = 0,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _(
"Set FILE as the trusted root CA and don't use the\n" INDENT
"root CAs that are installed on the system (optional)."),
.arg_description = _("FILE") },
{ .long_name = "no-verify",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_NONE,
.arg_data = &args->no_verify,
.description = _("Disable the host-key document verification\n" INDENT
"(optional)."),
.arg_description = NULL },
{ .long_name = "verbose",
.short_name = 'V',
.flags = G_OPTION_FLAG_NO_ARG,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_log_level,
.description = _("Provide more detailed output (optional)."),
.arg_description = NULL },
{ .long_name = "version",
.short_name = 'v',
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_NONE,
.arg_data = &print_version,
.description = _("Print the version and exit."),
.arg_description = NULL },
{ .long_name = G_OPTION_REMAINING,
.short_name = 0,
.flags = 0,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_remaining_values,
.description = NULL,
.arg_description = NULL },
{ 0 },
};
GOptionEntry x_entries[] = {
{ .long_name = "x-comp-key",
.short_name = 0,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _(
"Use FILE as the AES 256-bit XTS key\n" INDENT
"that is used for the component encryption.\n" INDENT
"Optional; default: auto-generated."),
.arg_description = _("FILE") },
{ .long_name = "x-header-key",
.short_name = 0,
.flags = G_OPTION_FLAG_FILENAME,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _(
"Use FILE as the AES 256-bit GCM header key\n" INDENT
"that protects the PV header.\n" INDENT
"Optional; default: auto-generated."),
.arg_description = _("FILE") },
{ .long_name = "x-pcf",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description =
_("Specify the plaintext control flags\n" INDENT
"as a hexadecimal value.\n" INDENT
"Optional; mutually exclusive with\n" INDENT
"'--(enable|disable)-pckmo'; default: '0xe0'."),
.arg_description = _("VALUE") },
{ .long_name = "x-psw",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = psw_desc,
.arg_description = _("ADDRESS") },
{ .long_name = "x-scf",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_set_string_option,
.description = _("Specify the secret control flags\n" INDENT
"as a hexadecimal value.\n" INDENT
"Optional; mutually exclusive with\n" INDENT
"'--(enable|disable)-cck-extension-secret';\n" INDENT
"Optional; default: '0x0'."),
.arg_description = _("VALUE") },
{ 0 },
};
context = g_option_context_new(
_("- Create a protected virtualization image"));
g_option_context_set_summary(context, _(summary));
group = g_option_group_new(GETTEXT_PACKAGE, _("Application Options:"),
_("Show help options"), args, NULL);
g_option_group_add_entries(group, entries);
g_option_context_set_main_group(context, group);
x_group = g_option_group_new("experimental", _("Experimental Options:"),
_("Show experimental options"), args, NULL);
g_option_group_add_entries(x_group, x_entries);
g_option_context_add_group(context, x_group);
if (!g_option_context_parse(context, argc, argv, err))
return -1;
if (print_version) {
g_printf(_("%s version %s\n"), tool_name, RELEASE_STRING);
g_printf("%s\n", copyright_notice);
exit(EXIT_SUCCESS);
}
if (pv_args_set_defaults(args, err) < 0)
return -1;
return pv_args_validate_options(args, err);
}
PvArgs *pv_args_new(void)
{
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
args->unused_values = g_ptr_array_new_with_free_func(g_free);
/* `args->cf_args` is implicitly initialized with zeros since
* `g_new0` is used. So there is no reason to explicitly
* initialize the values as PV_NOT_SET == 0.
*/
return g_steal_pointer(&args);
}
void pv_args_free(PvArgs *args)
{
if (!args)
return;
g_free(args->cf_args.pcf);
g_free(args->cf_args.scf);
g_free(args->psw_addr);
g_free(args->cust_root_key_path);
g_free(args->cust_comm_key_path);
g_free(args->gcm_iv_path);
g_free(args->root_ca_path);
g_strfreev(args->crl_paths);
g_strfreev(args->untrusted_cert_paths);
g_strfreev(args->host_keys);
g_free(args->xts_key_path);
g_slist_free_full(args->comps, (GDestroyNotify)pv_arg_free);
g_ptr_array_free(args->unused_values, TRUE);
g_free(args->output_path);
g_free(args->tmp_dir);
g_free(args);
}
void pv_arg_free(PvArg *arg)
{
if (!arg)
return;
g_free(arg->path);
g_free(arg);
}
PvArg *pv_arg_new(PvComponentType type, const gchar *path)
{
g_autoptr(PvArg) ret = g_new0(struct pv_arg, 1);
ret->type = type;
ret->path = g_strdup(path);
return g_steal_pointer(&ret);
}

View File

@@ -1,75 +0,0 @@
/*
* PV arguments related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_ARGS_H
#define PV_ARGS_H
#include <glib.h>
#include "pv_comp.h"
typedef struct pv_arg {
PvComponentType type;
gchar *path;
} PvArg;
PvArg *pv_arg_new(PvComponentType type, const gchar *path);
void pv_arg_free(PvArg *arg);
typedef enum pv_tristate {
PV_NOT_SET = 0,
PV_TRUE,
PV_FALSE,
} PvTristate;
/* The value of PV_NOT_SET is not allowed to be changed */
STATIC_ASSERT(PV_NOT_SET == 0)
typedef struct {
gchar *pcf;
gchar *scf;
/* Add-secret requests do require CCK-extension secrets */
PvTristate enable_cck_extension_secret_enforcement;
PvTristate enable_dump;
PvTristate enable_pckmo;
} PvControlFlagsArgs;
typedef struct {
gint log_level;
gint no_verify;
gboolean offline;
PvControlFlagsArgs cf_args;
gchar *psw_addr; /* PSW address which will be used for the start of
* the actual component (e.g. Linux kernel)
*/
gchar *cust_root_key_path;
gchar *cust_comm_key_path;
gchar *gcm_iv_path;
gchar **host_keys;
gchar *root_ca_path; /* Trusted root CA used for the verification of the
* chain of trust (if specified).
*/
gchar **untrusted_cert_paths;
gchar **crl_paths;
gchar *xts_key_path;
GSList *comps;
gchar *output_path;
gchar *tmp_dir;
GPtrArray *unused_values;
} PvArgs;
PvArgs *pv_args_new(void);
void pv_args_free(PvArgs *args);
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
GError **err);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvArg, pv_arg_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvArgs, pv_args_free)
#endif

View File

@@ -1,432 +0,0 @@
/*
* PV component related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include <glib/gtypes.h>
#include <openssl/bn.h>
#include <openssl/evp.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "common.h"
#include "utils/align.h"
#include "utils/buffer.h"
#include "utils/crypto.h"
#include "utils/file_utils.h"
#include "pv_comp.h"
#include "pv_error.h"
static void comp_file_free(CompFile *comp)
{
if (!comp)
return;
g_free(comp->path);
g_free(comp);
}
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CompFile, comp_file_free)
static PvComponent *pv_component_new(PvComponentType type, gsize size,
PvComponentDataType d_type, void **data,
GError **err)
{
g_autoptr(PvComponent) ret = g_new0(PvComponent, 1);
g_assert(type >= 0 && type <= UINT16_MAX);
ret->type = (int)type;
ret->d_type = (int)d_type;
ret->data = g_steal_pointer(data);
ret->orig_size = size;
if (generate_tweak(&ret->tweak, (uint16_t)type, err) < 0)
return NULL;
return g_steal_pointer(&ret);
}
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
GError **err)
{
g_autoptr(CompFile) file = g_new0(CompFile, 1);
gsize size;
gint rc;
g_assert(path != NULL);
rc = file_size(path, &size, err);
if (rc < 0)
return NULL;
file->path = g_strdup(path);
file->size = size;
return pv_component_new(type, size, DATA_FILE, (void **)&file, err);
}
PvComponent *pv_component_new_buf(PvComponentType type, const PvBuffer *buf,
GError **err)
{
g_assert(buf);
g_autoptr(PvBuffer) dup_buf = pv_buffer_dup(buf, FALSE);
return pv_component_new(type, buf->size, DATA_BUFFER, (void **)&dup_buf,
err);
}
void pv_component_free(PvComponent *component)
{
if (!component)
return;
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER:
pv_buffer_clear(&component->buf);
break;
case DATA_FILE:
comp_file_free(component->file);
break;
}
g_free(component);
}
gint pv_component_type(const PvComponent *component)
{
return component->type;
}
const gchar *pv_component_name(const PvComponent *component)
{
gint type = pv_component_type(component);
switch ((PvComponentType)type) {
case PV_COMP_TYPE_KERNEL:
return "kernel";
case PV_COMP_TYPE_INITRD:
return "ramdisk";
case PV_COMP_TYPE_CMDLINE:
return "parmline";
case PV_COMP_TYPE_STAGE3B:
return "stage3b";
}
g_assert_not_reached();
}
uint64_t pv_component_size(const PvComponent *component)
{
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER:
return component->buf->size;
case DATA_FILE:
return component->file->size;
}
g_assert_not_reached();
}
uint64_t pv_component_get_src_addr(const PvComponent *component)
{
return component->src_addr;
}
uint64_t pv_component_get_orig_size(const PvComponent *component)
{
return component->orig_size;
}
uint64_t pv_component_get_tweak_prefix(const PvComponent *component)
{
return GUINT64_FROM_BE(component->tweak.cmp_idx.data);
}
gboolean pv_component_is_stage3b(const PvComponent *component)
{
return pv_component_type(component) == PV_COMP_TYPE_STAGE3B;
}
gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_path,
void *opaque, GError **err)
{
struct cipher_parms *parms = opaque;
switch ((PvComponentDataType)component->d_type) {
case DATA_BUFFER: {
g_autoptr(PvBuffer) enc_buf = NULL;
if (!(IS_PAGE_ALIGNED(pv_component_size(component)))) {
g_autoptr(PvBuffer) new = NULL;
/* create a page aligned copy */
new = pv_buffer_dup(component->buf, TRUE);
pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&new);
}
enc_buf = encrypt_buf(parms, component->buf, err);
if (!enc_buf)
return -1;
pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&enc_buf);
return 0;
}
case DATA_FILE: {
const gchar *comp_name = pv_component_name(component);
gchar *path_in = component->file->path;
g_autofree gchar *path_out = NULL;
gsize orig_size;
gsize prep_size;
g_assert(path_in);
path_out = g_build_filename(tmp_path, comp_name, NULL);
if (encrypt_file(parms, path_in, path_out, &orig_size,
&prep_size, err) < 0)
return -1;
if (component->orig_size != orig_size) {
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
_("File has changed during the preparation '%s'"),
path_out);
return -1;
}
g_free(component->file->path);
component->file->size = prep_size;
component->file->path = g_steal_pointer(&path_out);
return 0;
}
}
g_assert_not_reached();
}
/* Page align the size of the component */
gint pv_component_align(PvComponent *component, const gchar *tmp_path,
void *opaque G_GNUC_UNUSED, GError **err)
{
if (IS_PAGE_ALIGNED(pv_component_size(component)))
return 0;
switch (component->d_type) {
case DATA_BUFFER: {
g_autoptr(PvBuffer) buf = NULL;
buf = pv_buffer_dup(component->buf, TRUE);
pv_buffer_clear(&component->buf);
component->buf = g_steal_pointer(&buf);
return 0;
} break;
case DATA_FILE: {
const gchar *comp_name = pv_component_name(component);
g_autofree gchar *path_out =
g_build_filename(tmp_path, comp_name, NULL);
gchar *path_in = component->file->path;
gsize size_out;
if (pad_file_right(path_out, path_in, &size_out, PAGE_SIZE,
err) < 0)
return -1;
g_free(component->file->path);
component->file->path = g_steal_pointer(&path_out);
component->file->size = size_out;
return 0;
} break;
}
g_assert_not_reached();
}
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err)
{
uint64_t addr = pv_component_get_src_addr(comp);
uint64_t size = pv_component_size(comp);
uint64_t cur = addr;
int64_t nep = 0;
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
do {
uint64_t cur_be = GUINT64_TO_BE(cur);
if (EVP_DigestUpdate(ctx, &cur_be, sizeof(cur_be)) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));
return -1;
}
cur += PAGE_SIZE;
nep++;
} while (cur < addr + size);
return nep;
}
int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err)
{
uint64_t size = pv_component_size(comp);
int64_t nep = 0;
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
switch (comp->d_type) {
case DATA_BUFFER: {
const PvBuffer *buf = comp->buf;
g_assert(buf->size <= INT64_MAX);
g_assert(buf->size == size);
if (EVP_DigestUpdate(ctx, buf->data, buf->size) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));
return -1;
}
nep = (int64_t)(buf->size / PAGE_SIZE);
break;
}
case DATA_FILE: {
const gchar *in_path = comp->file->path;
guchar in_buf[PAGE_SIZE];
gsize num_bytes_read_total = 0;
gsize num_bytes_read = 0;
FILE *f_in;
f_in = file_open(in_path, "rb", err);
if (!f_in)
return -1;
do {
/* Read data in blocks. Update the digest
* context each read.
*/
if (file_read(f_in, in_buf, sizeof(*in_buf),
sizeof(in_buf), &num_bytes_read,
err) < 0) {
fclose(f_in);
return -1;
}
num_bytes_read_total += num_bytes_read;
if (EVP_DigestUpdate(ctx, in_buf, sizeof(in_buf)) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));
fclose(f_in);
return -1;
}
nep++;
} while (num_bytes_read_total < pv_component_size(comp) &&
num_bytes_read != 0);
if (num_bytes_read_total != pv_component_size(comp)) {
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
_("'%s' has changed during the preparation"),
in_path);
fclose(f_in);
return -1;
}
fclose(f_in);
break;
}
default:
g_assert_not_reached();
}
return nep;
}
int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err)
{
uint64_t size = pv_component_size(comp);
const union tweak *tweak = &comp->tweak;
g_autoptr(BIGNUM) tweak_num = NULL;
int64_t nep = 0;
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
tweak_num = BN_bin2bn(tweak->data, sizeof(tweak->data), NULL);
if (!tweak_num) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_bin2bn failed"));
return -1;
}
for (uint64_t cur = 0; cur < size; cur += PAGE_SIZE) {
guchar tmp[sizeof(tweak->data)] = { 0 };
g_assert(BN_num_bytes(tweak_num) >= 0);
g_assert(sizeof(tmp) - (guint)BN_num_bytes(tweak_num) > 0);
if (BN_bn2binpad(tweak_num, tmp, sizeof(tmp)) < 0) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_bn2binpad failed"));
return -1;
}
if (EVP_DigestUpdate(ctx, tmp, sizeof(tmp)) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));
return -1;
}
/* calculate new tweak value */
if (BN_add_word(tweak_num, PAGE_SIZE) != 1) {
g_set_error(err, PV_CRYPTO_ERROR,
PV_CRYPTO_ERROR_INTERNAL,
_("BN_add_word failed"));
return -1;
}
nep++;
}
return nep;
}
gint pv_component_write(const PvComponent *component, FILE *f, GError **err)
{
uint64_t offset = pv_component_get_src_addr(component);
g_assert(f);
switch (component->d_type) {
case DATA_BUFFER: {
const PvBuffer *buf = component->buf;
if (seek_and_write_buffer(f, buf, offset, err) < 0)
return -1;
return 0;
}
case DATA_FILE: {
const CompFile *file = component->file;
if (seek_and_write_file(f, file, offset, err) < 0)
return -1;
return 0;
}
}
g_assert_not_reached();
}

View File

@@ -1,78 +0,0 @@
/*
* PV component related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_COMP_H
#define PV_COMP_H
#include <glib.h>
#include <openssl/evp.h>
#include <stdint.h>
#include "utils/crypto.h"
/* The order of this enum also implicitly defines the order of the
* components within the PV image!
*/
typedef enum {
PV_COMP_TYPE_KERNEL = 0,
PV_COMP_TYPE_CMDLINE = 1,
PV_COMP_TYPE_INITRD = 2,
PV_COMP_TYPE_STAGE3B = 3,
} PvComponentType;
typedef enum {
DATA_FILE = 0,
DATA_BUFFER,
} PvComponentDataType;
typedef struct comp_file {
gchar *path;
gsize size;
} CompFile;
typedef struct {
gint type; /* PvComponentType */
gint d_type; /* PvComponentDataType */
union {
struct comp_file *file;
PvBuffer *buf;
void *data;
};
uint64_t src_addr;
uint64_t orig_size;
union tweak tweak; /* used for the AES XTS encryption */
} PvComponent;
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
GError **err);
PvComponent *pv_component_new_buf(PvComponentType type, const PvBuffer *buf,
GError **err);
void pv_component_free(PvComponent *component);
gint pv_component_type(const PvComponent *component);
const gchar *pv_component_name(const PvComponent *component);
uint64_t pv_component_size(const PvComponent *component);
uint64_t pv_component_get_src_addr(const PvComponent *component);
uint64_t pv_component_get_orig_size(const PvComponent *component);
uint64_t pv_component_get_tweak_prefix(const PvComponent *component);
gboolean pv_component_is_stage3b(const PvComponent *component);
gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_path,
void *opaque, GError **err);
gint pv_component_align(PvComponent *component, const gchar *tmp_path,
void *opaque G_GNUC_UNUSED, GError **err);
int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err);
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err);
int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
GError **err);
gint pv_component_write(const PvComponent *component, FILE *f, GError **err);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvComponent, pv_component_free)
#endif

View File

@@ -1,252 +0,0 @@
/*
* PV components related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include <glib/gtypes.h>
#include <openssl/evp.h>
#include <stdint.h>
#include "boot/psw.h"
#include "boot/stage3b.h"
#include "common.h"
#include "utils/align.h"
#include "utils/crypto.h"
#include "pv_comp.h"
#include "pv_comps.h"
#include "pv_error.h"
#include "pv_stage3.h"
struct _pv_img_comps {
gboolean finalized;
uint64_t next_src;
uint64_t nep;
EVP_MD_CTX *ald; /* context used for the hash of the addresses */
EVP_MD_CTX *pld; /* context used for the hash of the pages content */
EVP_MD_CTX *tld; /* context used for the hash of the tweaks */
GSList *comps; /* elements sorted by component type */
};
void pv_img_comps_free(PvImgComps *comps)
{
if (!comps)
return;
EVP_MD_CTX_free(comps->ald);
EVP_MD_CTX_free(comps->pld);
EVP_MD_CTX_free(comps->tld);
g_slist_free_full(comps->comps, (GDestroyNotify)pv_component_free);
g_free(comps);
}
PvImgComps *pv_img_comps_new(const EVP_MD *ald_md, const EVP_MD *pld_md,
const EVP_MD *tld_md, GError **err)
{
g_autoptr(PvImgComps) ret = g_new0(PvImgComps, 1);
ret->ald = digest_ctx_new(ald_md, err);
if (!ret->ald)
return NULL;
ret->pld = digest_ctx_new(pld_md, err);
if (!ret->pld)
return NULL;
ret->tld = digest_ctx_new(tld_md, err);
if (!ret->tld)
return NULL;
return g_steal_pointer(&ret);
}
guint pv_img_comps_length(const PvImgComps *comps)
{
return g_slist_length(comps->comps);
}
/* Update hashes and nep */
/* Returns 0 in case of success and -1 in case of a failure */
static gint pv_img_comps_hash_comp(PvImgComps *comps, const PvComponent *comp,
GError **err)
{
int64_t nep_1 = 0;
int64_t nep_2 = 0;
int64_t nep_3 = 0;
/* update pld */
nep_1 = pv_component_update_pld(comp, comps->pld, err);
if (nep_1 < 0)
return -1;
/* update ald */
nep_2 = pv_component_update_ald(comp, comps->ald, err);
if (nep_2 < 0)
return -1;
/* update tld */
nep_3 = pv_component_update_tld(comp, comps->tld, err);
if (nep_3 < 0)
return -1;
g_assert(nep_1 == nep_2);
g_assert(nep_2 == nep_3);
/* update comps->nep */
g_assert_true(g_uint64_checked_add(&comps->nep, comps->nep,
(uint64_t)nep_1));
return 0;
}
gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
GError **err)
{
g_assert(comp);
g_assert(*comp);
g_assert(comps);
g_assert(IS_PAGE_ALIGNED(comps->next_src));
uint64_t src_addr = comps->next_src;
uint64_t src_size = pv_component_size(*comp)
? PAGE_ALIGN(pv_component_size(*comp))
: PAGE_SIZE;
if (comps->finalized) {
g_set_error(err, PV_COMPONENT_ERROR, PV_COMPONENT_ERROR_FINALIZED,
_("Failed to add component, image is already finalized"));
return -1;
}
/* set the address of the component in the memory layout */
(*comp)->src_addr = src_addr;
g_info("%12s:\t0x%012lx (%12ld / %12ld Bytes)",
pv_component_name(*comp), pv_component_get_src_addr(*comp),
pv_component_size(*comp), pv_component_get_orig_size(*comp));
/* append the component and pass the responsibility of @comp
* to @comps
*/
comps->comps = g_slist_append(comps->comps, g_steal_pointer(comp));
comps->next_src += src_size;
g_assert(IS_PAGE_ALIGNED(comps->next_src));
g_assert(!*comp);
return 0;
}
struct stage3b_args *pv_img_comps_get_stage3b_args(const PvImgComps *comps,
struct psw_t *psw)
{
g_autofree struct stage3b_args *ret = g_new0(struct stage3b_args, 1);
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
const PvComponent *img_comp = iterator->data;
uint64_t src_addr, dst_size;
g_assert(img_comp);
src_addr = pv_component_get_src_addr(img_comp);
dst_size = pv_component_get_orig_size(img_comp);
g_assert(dst_size <= pv_component_size(img_comp));
switch ((PvComponentType)pv_component_type(img_comp)) {
case PV_COMP_TYPE_KERNEL:
memblob_init(&ret->kernel, src_addr, dst_size);
break;
case PV_COMP_TYPE_CMDLINE:
memblob_init(&ret->cmdline, src_addr, dst_size);
break;
case PV_COMP_TYPE_INITRD:
memblob_init(&ret->initrd, src_addr, dst_size);
break;
case PV_COMP_TYPE_STAGE3B:
/* nothing needs to be done since it is the
* stage3b itself
*/
break;
default:
g_assert_not_reached();
break;
}
}
/* for `stage3b_args` big-endian format must be used */
ret->psw.mask = GUINT64_TO_BE(psw->mask);
ret->psw.addr = GUINT64_TO_BE(psw->addr);
return g_steal_pointer(&ret);
}
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err)
{
g_assert(IS_PAGE_ALIGNED(comps->next_src));
if (!IS_PAGE_ALIGNED(offset)) {
g_set_error(err, PV_IMAGE_ERROR, PV_IMAGE_ERROR_OFFSET,
_("Offset must be page aligned"));
return -1;
}
if (pv_img_comps_length(comps) > 0) {
g_set_error(err, PV_IMAGE_ERROR, PV_IMAGE_ERROR_OFFSET,
_("Offset cannot be changed after a component was added"));
return -1;
}
comps->next_src += offset;
g_assert(IS_PAGE_ALIGNED(comps->next_src));
return 0;
}
GSList *pv_img_comps_get_comps(const PvImgComps *comps)
{
return comps->comps;
}
gint pv_img_comps_finalize(PvImgComps *comps, PvBuffer **pld_digest,
PvBuffer **ald_digest, PvBuffer **tld_digest,
uint64_t *nep, GError **err)
{
g_autoptr(PvBuffer) tmp_pld_digest = NULL;
g_autoptr(PvBuffer) tmp_ald_digest = NULL;
g_autoptr(PvBuffer) tmp_tld_digest = NULL;
comps->finalized = TRUE;
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
const PvComponent *comp = iterator->data;
/* update hashes and nep */
if (pv_img_comps_hash_comp(comps, comp, err) < 0)
return -1;
}
tmp_pld_digest = digest_ctx_finalize(comps->pld, err);
if (!tmp_pld_digest)
return -1;
tmp_ald_digest = digest_ctx_finalize(comps->ald, err);
if (!tmp_ald_digest)
return -1;
tmp_tld_digest = digest_ctx_finalize(comps->tld, err);
if (!tmp_tld_digest)
return -1;
*pld_digest = g_steal_pointer(&tmp_pld_digest);
*ald_digest = g_steal_pointer(&tmp_ald_digest);
*tld_digest = g_steal_pointer(&tmp_tld_digest);
*nep = comps->nep;
return 0;
}
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n)
{
return g_slist_nth_data(comps->comps, n);
}

View File

@@ -1,42 +0,0 @@
/*
* PV components related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_COMPS_H
#define PV_COMPS_H
#include <glib.h>
#include <openssl/evp.h>
#include <stdint.h>
#include "boot/psw.h"
#include "boot/stage3b.h"
#include "utils/buffer.h"
#include "pv_comp.h"
typedef struct _pv_img_comps PvImgComps;
PvImgComps *pv_img_comps_new(const EVP_MD *ald_md, const EVP_MD *pld_md,
const EVP_MD *tld_md, GError **err);
guint pv_img_comps_length(const PvImgComps *comps);
GSList *pv_img_comps_get_comps(const PvImgComps *comps);
struct stage3b_args *pv_img_comps_get_stage3b_args(const PvImgComps *comps,
struct psw_t *psw);
gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
GError **err);
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n);
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err);
gint pv_img_comps_finalize(PvImgComps *comps, PvBuffer **pld_digest,
PvBuffer **ald_digest, PvBuffer **tld_digest,
uint64_t *nep, GError **err);
void pv_img_comps_free(PvImgComps *comps);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvImgComps, pv_img_comps_free)
#endif

View File

@@ -1,37 +0,0 @@
/*
* PV error related functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include "pv_error.h"
GQuark pv_error_quark(void)
{
return g_quark_from_static_string("pv-error-quark");
}
GQuark pv_crypto_error_quark(void)
{
return g_quark_from_static_string("pv-crypto-error-quark");
}
GQuark pv_component_error_quark(void)
{
return g_quark_from_static_string("pv-component-error-quark");
}
GQuark pv_image_error_quark(void)
{
return g_quark_from_static_string("pv-image-error-quark");
}
GQuark pv_parse_error_quark(void)
{
return g_quark_from_static_string("pv-parse-error-quark");
}

View File

@@ -1,89 +0,0 @@
/*
* PV error related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_ERROR_H
#define PV_ERROR_H
#include <glib.h>
GQuark pv_error_quark(void);
GQuark pv_parse_error_quark(void);
GQuark pv_component_error_quark(void);
GQuark pv_crypto_error_quark(void);
GQuark pv_image_error_quark(void);
#define PV_ERROR pv_error_quark()
#define PV_PARSE_ERROR pv_parse_error_quark()
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
#define PV_COMPONENT_ERROR pv_component_error_quark()
#define PV_IMAGE_ERROR pv_image_error_quark()
typedef enum {
PV_ERROR_IPIB_SIZE,
PV_ERROR_PV_HDR_SIZE,
PV_ERROR_INTERNAL,
PV_ERROR_CURL_INIT_FAILED,
PV_ERROR_DOWNLOAD_FAILED,
} PvErrors;
typedef enum {
PV_PARSE_ERROR_OK = 0,
PV_PARSE_ERROR_SYNTAX,
PR_PARSE_ERROR_INVALID_ARGUMENT,
PR_PARSE_ERROR_MISSING_ARGUMENT,
} PvParseErrors;
typedef enum {
PV_COMPONENT_ERROR_UNALIGNED,
PV_COMPONENT_ERROR_FINALIZED,
} PvComponentErrors;
typedef enum {
PV_IMAGE_ERROR_OFFSET,
PV_IMAGE_ERROR_FINALIZED,
} PvImageErrors;
typedef enum {
PV_CRYPTO_ERROR_VERIFICATION,
PV_CRYPTO_ERROR_INIT,
PV_CRYPTO_ERROR_READ_CERTIFICATE,
PV_CRYPTO_ERROR_INTERNAL,
PV_CRYPTO_ERROR_DERIVE,
PV_CRYPTO_ERROR_KEYGENERATION,
PV_CRYPTO_ERROR_RANDOMIZATION,
PV_CRYPTO_ERROR_INVALID_PARM,
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
PV_CRYPTO_ERROR_INVALID_VALIDITY_PERIOD,
PV_CRYPTO_ERROR_EXPIRED,
PV_CRYPTO_ERROR_NOT_VALID_YET,
PV_CRYPTO_ERROR_LOAD_CRL,
PV_CRYPTO_ERROR_NO_PUBLIC_KEY,
PV_CRYPTO_ERROR_INVALID_SIGNATURE_ALGORITHM,
PV_CRYPTO_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
PV_CRYPTO_ERROR_INVALID_URI,
PV_CRYPTO_ERROR_CRL_DOWNLOAD_FAILED,
PV_CRYPTO_ERROR_CERT_SIGNATURE_INVALID,
PV_CRYPTO_ERROR_CRL_SIGNATURE_INVALID,
PV_CRYPTO_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
PV_CRYPTO_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
PV_CRYPTO_ERROR_MALFORMED_CERTIFICATE,
PV_CRYPTO_ERROR_NO_CRL,
PV_CRYPTO_ERROR_LOAD_ROOT_CA,
PV_CRYPTO_ERROR_LOAD_DEFAULT_CA,
PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
PV_CRYPTO_ERROR_WRONG_CA_USED,
PV_CRYPTO_ERROR_SKID_AKID_MISMATCH,
PV_CRYPTO_ERROR_NO_ISSUER_IBM_Z_FOUND,
PV_CRYPTO_ERROR_FAILED_DOWNLOAD_CRL,
PV_CRYPTO_ERROR_NO_CRLDP,
PV_CRYPTO_ERROR_CERT_REVOKED,
} PvCryptoErrors;
#endif

View File

@@ -1,293 +0,0 @@
/*
* PV header related functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include <glib/gtypes.h>
#include <openssl/aes.h>
#include <openssl/evp.h>
#include <stdint.h>
#include <string.h>
#include "boot/psw.h"
#include "include/pv_crypto_def.h"
#include "utils/buffer.h"
#include "utils/crypto.h"
#include "pv_comp.h"
#include "pv_hdr.h"
#include "pv_image.h"
void pv_hdr_free(PvHdr *hdr)
{
if (!hdr)
return;
g_free(hdr->optional_items);
g_free(hdr->encrypted);
g_free(hdr->slots);
g_free(hdr);
}
uint32_t pv_hdr_size(const PvHdr *hdr)
{
return GUINT32_FROM_BE(hdr->head.phs);
}
gboolean pv_hdr_uses_encryption(const PvHdr *hdr)
{
return !(GUINT64_FROM_BE(hdr->head.pcf) & PV_PCF_NO_DECRYPTION);
}
uint64_t pv_hdr_enc_size(const PvHdr *hdr)
{
return GUINT64_FROM_BE(hdr->head.sea);
}
uint32_t pv_hdr_enc_size_casted(const PvHdr *hdr)
{
uint64_t size = pv_hdr_enc_size(hdr);
if (size > UINT32_MAX)
g_abort();
return (uint32_t)size;
}
static guint pv_hdr_tag_size(const PvHdr *hdr)
{
return sizeof(hdr->tag);
}
uint32_t pv_hdr_aad_size(const PvHdr *hdr)
{
return pv_hdr_size(hdr) - pv_hdr_enc_size_casted(hdr) -
pv_hdr_tag_size(hdr);
}
uint64_t pv_hdr_get_nks(const PvHdr *hdr)
{
return GUINT64_FROM_BE(hdr->head.nks);
}
/* In-place modification of ``buf`` */
static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, PvBuffer *buf,
GError **err)
{
uint32_t hdr_len = pv_hdr_size(hdr);
uint32_t aad_len = pv_hdr_aad_size(hdr);
guint tag_len = pv_hdr_tag_size(hdr);
uint32_t enc_len = pv_hdr_enc_size_casted(hdr);
const PvBuffer aad_part = { .data = buf->data, .size = aad_len };
PvBuffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
.size = enc_len };
PvBuffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
.size = tag_len };
struct cipher_parms parms;
int64_t c_len;
g_assert(aad_part.size + enc_part.size + tag_part.size == buf->size);
g_assert(img->cust_root_key->size <= INT_MAX);
g_assert(img->gcm_iv->size <= INT_MAX);
g_assert(EVP_CIPHER_key_length(img->gcm_cipher) ==
(int)img->cust_root_key->size);
g_assert(EVP_CIPHER_iv_length(img->gcm_cipher) == (int)img->gcm_iv->size);
parms.key = img->cust_root_key;
parms.iv_or_tweak = img->gcm_iv;
parms.cipher = img->gcm_cipher;
/* in-place encryption */
c_len = gcm_encrypt(&enc_part, &aad_part, &parms, &enc_part, &tag_part, err);
if (c_len < 0)
return -1;
g_assert(c_len == enc_len);
return 0;
}
/* Initializes the unencrypted, but integrity protected part of the PV
* header
*/
static gint pv_hdr_aad_init(PvHdr *hdr, const PvImage *img, GError **err)
{
g_autofree union ecdh_pub_key *cust_pub_key = NULL;
struct pv_hdr_key_slot *hdr_slot = hdr->slots;
struct pv_hdr_head *head = &hdr->head;
g_autoptr(PvBuffer) pld = NULL;
g_autoptr(PvBuffer) ald = NULL;
g_autoptr(PvBuffer) tld = NULL;
uint64_t nep = 0;
g_assert(sizeof(head->iv) == img->gcm_iv->size);
g_assert(sizeof(head->cust_pub_key) == sizeof(*cust_pub_key));
cust_pub_key = evp_pkey_to_ecdh_pub_key(img->cust_pub_priv_key, err);
if (!cust_pub_key)
return -1;
head->magic = GUINT64_TO_BE(PV_MAGIC_NUMBER);
head->version = GUINT32_TO_BE(PV_VERSION_1);
/* ``phs`` is already set so we can skip it here */
memcpy(head->iv, img->gcm_iv->data, sizeof(head->iv));
/* ``nks`` is already set so we can skip it here */
/* ``sea`` is already set so we can skip it here */
head->pcf = GUINT64_TO_BE(img->pcf);
memcpy(head->cust_pub_key.data, cust_pub_key,
sizeof(head->cust_pub_key));
if (pv_img_calc_pld_ald_tld_nep(img, &pld, &ald, &tld, &nep, err) < 0)
return -1;
g_assert(sizeof(head->pld) == pld->size);
g_assert(sizeof(head->ald) == ald->size);
g_assert(sizeof(head->tld) == tld->size);
head->nep = GUINT64_TO_BE(nep);
memcpy(head->pld, pld->data, sizeof(head->pld));
memcpy(head->ald, ald->data, sizeof(head->ald));
memcpy(head->tld, tld->data, sizeof(head->tld));
/* set the key slots */
for (GSList *iterator = img->key_slots; iterator; iterator = iterator->next) {
const PvHdrKeySlot *slot = iterator->data;
g_assert(slot);
/* the memory for the slots is pre-allocated so we
* have not to allocate and since PvHdrKeySlot is
* stored in the big-edian format we can simply use
* memcpy.
*/
memcpy(hdr_slot++, slot, sizeof(*slot));
}
return 0;
}
/* Initializes the encrypted and also integrity protected part of the
* PV header
*/
static gint pv_hdr_enc_init(PvHdr *hdr, const PvImage *img, GError **err)
{
struct pv_hdr_encrypted *enc = hdr->encrypted;
const PvComponent *stage3b;
struct psw_t psw;
g_assert(sizeof(enc->img_enc_key_1) + sizeof(enc->img_enc_key_2) ==
EVP_CIPHER_key_length(img->xts_cipher));
g_assert(sizeof(enc->cust_comm_key) == img->cust_comm_key->size);
g_assert(img->xts_key->size ==
(guint)EVP_CIPHER_key_length(img->xts_cipher));
stage3b = pv_img_get_stage3b_comp(img, err);
if (!stage3b)
return -1;
memcpy(enc->cust_comm_key, img->cust_comm_key->data,
sizeof(enc->cust_comm_key));
memcpy(enc->img_enc_key_1, img->xts_key->data,
sizeof(enc->img_enc_key_1));
memcpy(enc->img_enc_key_2,
(uint8_t *)img->xts_key->data + sizeof(enc->img_enc_key_1),
sizeof(enc->img_enc_key_2));
/* Setup program check handler */
psw.mask = GUINT64_TO_BE(DEFAULT_INITIAL_PSW_MASK);
psw.addr = GUINT64_TO_BE(pv_component_get_src_addr(stage3b));
enc->psw = psw;
enc->scf = GUINT64_TO_BE(img->scf);
enc->noi = GUINT32_TO_BE(g_slist_length(img->optional_items));
/* set the optional items */
for (GSList *iterator = img->optional_items; iterator;
iterator = iterator->next) {
const struct pv_hdr_opt_item *item = iterator->data;
g_assert(item);
/* not supported in the first version */
g_assert_not_reached();
}
return 0;
}
PvHdr *pv_hdr_new(const PvImage *img, GError **err)
{
uint32_t noi = g_slist_length(img->optional_items);
uint32_t hdr_size = pv_img_get_pv_hdr_size(img);
gsize nks = g_slist_length(img->key_slots);
uint32_t sea = pv_img_get_enc_size(img);
g_autoptr(PvHdr) ret = NULL;
g_assert(nks > 0);
/* must be a multiple of AES block size */
g_assert(sea % AES_BLOCK_SIZE == 0);
g_assert(sea >= sizeof(struct pv_hdr_encrypted));
ret = g_new0(PvHdr, 1);
ret->slots = g_new0(struct pv_hdr_key_slot, nks);
ret->head.phs = GUINT32_TO_BE(hdr_size);
ret->head.nks = GUINT64_TO_BE(nks);
ret->head.sea = GUINT64_TO_BE(sea);
ret->encrypted = g_new0(struct pv_hdr_encrypted, 1);
ret->optional_items = g_malloc0(sea - sizeof(struct pv_hdr_encrypted));
ret->encrypted->noi = GUINT32_TO_BE(noi);
if (pv_hdr_aad_init(ret, img, err) < 0)
return NULL;
if (pv_hdr_enc_init(ret, img, err) < 0)
return NULL;
return g_steal_pointer(&ret);
}
static void pv_hdr_memcpy(const PvHdr *hdr, const PvBuffer *dst)
{
uint64_t nks = pv_hdr_get_nks(hdr);
uint8_t *data;
g_assert(dst->size == pv_hdr_size(hdr));
g_assert(pv_hdr_enc_size_casted(hdr) >= sizeof(*hdr->encrypted));
data = memcpy(dst->data, &hdr->head, sizeof(hdr->head));
data = memcpy(data + sizeof(hdr->head), hdr->slots,
sizeof(struct pv_hdr_key_slot) * nks);
data = memcpy(data + sizeof(struct pv_hdr_key_slot) * nks,
hdr->encrypted, sizeof(*hdr->encrypted));
if (pv_hdr_enc_size_casted(hdr) - sizeof(*hdr->encrypted) > 0) {
(void)memcpy(data + sizeof(*hdr->encrypted),
hdr->optional_items,
pv_hdr_enc_size_casted(hdr) - sizeof(*hdr->encrypted));
}
}
PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
enum PvCryptoMode mode, GError **err)
{
uint32_t hdr_size = pv_hdr_size(hdr);
g_autoptr(PvBuffer) ret = NULL;
ret = pv_buffer_alloc(hdr_size);
pv_hdr_memcpy(hdr, ret);
if (mode == PV_ENCRYPT) {
/* The buffer @ret is modified in-place */
if (pv_hdr_encrypt(hdr, img, ret, err) < 0)
return NULL;
} else {
/* Simply copy the tag */
memcpy((uint8_t *)ret->data + hdr_size - pv_hdr_tag_size(hdr),
hdr->tag, pv_hdr_tag_size(hdr));
}
return g_steal_pointer(&ret);
}

View File

@@ -1,35 +0,0 @@
/*
* PV header related functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_HDR_H
#define PV_HDR_H
#include <glib.h>
#include <stdint.h>
#include "include/pv_hdr_def.h"
#include "utils/crypto.h"
#include "utils/buffer.h"
#include "pv_image.h"
PvHdr *pv_hdr_new(const PvImage *img, GError **err);
void pv_hdr_free(PvHdr *hdr);
G_GNUC_UNUSED gboolean pv_hdr_uses_encryption(const PvHdr *hdr);
PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
enum PvCryptoMode mode, GError **err);
uint32_t pv_hdr_size(const PvHdr *hdr);
uint32_t pv_hdr_aad_size(const PvHdr *hdr);
uint64_t pv_hdr_enc_size(const PvHdr *hdr);
uint32_t pv_hdr_enc_size_casted(const PvHdr *hdr);
uint64_t pv_hdr_get_nks(const PvHdr *hdr);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvHdr, pv_hdr_free)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,68 +0,0 @@
/*
* PV image related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_IMAGE_H
#define PV_IMAGE_H
#include <glib.h>
#include <glib/gtypes.h>
#include <openssl/evp.h>
#include <stdint.h>
#include "boot/psw.h"
#include "utils/buffer.h"
#include "pv_args.h"
#include "pv_comp.h"
#include "pv_comps.h"
#include "pv_stage3.h"
typedef struct {
gchar *tmp_dir; /* directory used for temporary files */
PvBuffer *stage3a; /* stage3a containing IPIB and PV header */
gsize stage3a_bin_size; /* size of stage3a.bin */
struct psw_t stage3a_psw; /* (short) PSW that is written to
* location 0 of the created image
*/
struct psw_t initial_psw; /* PSW loaded by stage3b */
EVP_PKEY *cust_pub_priv_key; /* customer private/public key */
GSList *host_pub_keys; /* public host keys */
gint nid; /* Elliptic Curve used for the key derivation */
/* keys and cipher used for the AES-GCM encryption */
PvBuffer *cust_root_key;
PvBuffer *gcm_iv;
const EVP_CIPHER *gcm_cipher;
/* Information for the IPIB and PV header */
uint64_t pcf;
uint64_t scf;
PvBuffer *cust_comm_key;
const EVP_CIPHER *cust_comm_cipher;
PvBuffer *xts_key;
const EVP_CIPHER *xts_cipher;
GSList *key_slots;
GSList *optional_items;
PvImgComps *comps;
} PvImage;
PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err);
void pv_img_free(PvImage *img);
gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err);
gint pv_img_finalize(PvImage *img, const gchar *stage3b_path, GError **err);
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, PvBuffer **pld, PvBuffer **ald,
PvBuffer **tld, uint64_t *nep, GError **err);
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err);
const PvComponent *pv_img_get_stage3b_comp(const PvImage *img, GError **err);
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err);
uint32_t pv_img_get_enc_size(const PvImage *img);
uint32_t pv_img_get_pv_hdr_size(const PvImage *img);
gint pv_img_write(PvImage *img, const gchar *path, GError **err);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvImage, pv_img_free)
#endif

View File

@@ -1,127 +0,0 @@
/*
* PV IPIB related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include <glib/gtypes.h>
#include <stdint.h>
#include <stdio.h>
#include "boot/ipl.h"
#include "common.h"
#include "include/pv_hdr_def.h"
#include "lib/zt_common.h"
#include "utils/align.h"
#include "utils/buffer.h"
#include "pv_comp.h"
#include "pv_error.h"
#include "pv_ipib.h"
uint64_t pv_ipib_get_size(uint32_t num_comp)
{
gsize ipib_size = sizeof(struct ipl_pl_hdr) +
sizeof(struct ipl_pb0_pv) +
num_comp * sizeof(struct ipl_pb0_pv_comp);
/* the minimal size is one page */
return MAX(ipib_size, PAGE_SIZE);
}
static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
const PvBuffer *hdr)
{
g_assert(sizeof(struct ipl_pl_hdr) <= UINT32_MAX);
g_assert(sizeof(struct ipl_pb0_pv_comp) <= UINT32_MAX);
g_assert(sizeof(struct ipl_pb0_pv) <= UINT32_MAX);
g_assert(ipib);
guint comps_length = g_slist_length(comps);
uint32_t ipl_pl_hdr_size = (uint32_t)sizeof(struct ipl_pl_hdr);
struct ipl_pb0_pv *pv = &ipib->pv;
uint32_t ipib_comps_size;
uint32_t blk0_len;
uint32_t ipib_size;
gsize i;
g_assert_true(
g_uint_checked_mul(&ipib_comps_size, comps_length,
(uint32_t)sizeof(struct ipl_pb0_pv_comp)));
g_assert_true(g_uint_checked_add(&blk0_len, (uint32_t)sizeof(*pv),
ipib_comps_size));
g_assert(ipl_pl_hdr_size + blk0_len <= PAGE_SIZE);
ipib_size = MAX(ipl_pl_hdr_size + blk0_len, (uint32_t)PAGE_SIZE);
g_assert(pv_ipib_get_size(comps_length) == ipib_size);
pv->pbt = IPL_PBT_PV;
pv->len = GUINT32_TO_BE(blk0_len);
pv->num_comp = GUINT32_TO_BE(comps_length);
/* both values will be overwritten during the IPL process by
* the stage3a loader
*/
pv->pv_hdr_addr = GUINT64_TO_BE(0x0);
pv->pv_hdr_size = GUINT64_TO_BE(hdr->size);
ipib->hdr.len = GUINT32_TO_BE(ipib_size);
ipib->hdr.version = IPL_PARM_BLOCK_VERSION;
i = 0;
for (GSList *iterator = comps; iterator; iterator = iterator->next, i++) {
const PvComponent *comp = iterator->data;
uint64_t comp_addr, comp_size;
g_assert(comp);
comp_addr = pv_component_get_src_addr(comp);
comp_size = pv_component_size(comp);
g_assert(IS_PAGE_ALIGNED(comp_size));
pv->components[i].addr = GUINT64_TO_BE(comp_addr);
pv->components[i].len = GUINT64_TO_BE(comp_size);
pv->components[i].tweak_pref =
GUINT64_TO_BE(pv_component_get_tweak_prefix(comp));
if (i > 0) {
/* tweak prefixes of the components must grow
* strictly monotonous
*/
g_assert(GUINT64_FROM_BE(pv->components[i].tweak_pref) >
GUINT64_FROM_BE(pv->components[i - 1].tweak_pref));
}
}
return 0;
}
IplParameterBlock *pv_ipib_new(GSList *comps, const PvBuffer *hdr, GError **err)
{
uint64_t ipib_size = pv_ipib_get_size(g_slist_length(comps));
g_autoptr(IplParameterBlock) ret = NULL;
if (ipib_size > PV_V1_IPIB_MAX_SIZE) {
g_set_error(err, PV_ERROR, PV_ERROR_IPIB_SIZE,
_("IPIB size is too large: %lu < %lu"), ipib_size,
PAGE_SIZE);
return NULL;
}
ret = g_malloc0(ipib_size);
if (pv_ipib_init(ret, comps, hdr) < 0)
return NULL;
return g_steal_pointer(&ret);
}
void pv_ipib_free(IplParameterBlock *ipib)
{
if (!ipib)
return;
g_free(ipib);
}

View File

@@ -1,27 +0,0 @@
/*
* PV IPIB related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_IPIB_H
#define PV_IPIB_H
#include <glib.h>
#include <stdint.h>
#include "boot/ipl.h"
#include "utils/buffer.h"
typedef struct ipl_parameter_block IplParameterBlock;
uint64_t pv_ipib_get_size(uint32_t num_comp);
IplParameterBlock *pv_ipib_new(GSList *comps, const PvBuffer *hdr, GError **err);
void pv_ipib_free(IplParameterBlock *ipib);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(IplParameterBlock, pv_ipib_free)
#endif

View File

@@ -1,26 +0,0 @@
/*
* PV optional item related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include "pv_opt_item.h"
uint32_t pv_opt_item_size(const struct pv_hdr_opt_item *item G_GNUC_UNUSED)
{
/* not implemented yet */
g_assert_not_reached();
}
void pv_opt_item_free(struct pv_hdr_opt_item *item)
{
if (!item)
return;
g_free(item);
}

View File

@@ -1,20 +0,0 @@
/*
* PV optional item related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_OPT_ITEM_H
#define PV_OPT_ITEM_H
#include <stdint.h>
#include "include/pv_hdr_def.h"
uint32_t pv_opt_item_size(const struct pv_hdr_opt_item *item);
void pv_opt_item_free(struct pv_hdr_opt_item *item);
#endif

View File

@@ -1,164 +0,0 @@
/*
* PV stage3 loader related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <glib.h>
#include <stdint.h>
#include <string.h>
#include "boot/ipl.h"
#include "boot/stage3a.h"
#include "boot/stage3b.h"
#include "common.h"
#include "utils/align.h"
#include "pv_error.h"
#include "pv_stage3.h"
#define STAGE3A_ARGS(data_ptr, loader_size) \
((struct stage3a_args *)((uint64_t)data_ptr + loader_size - \
sizeof(struct stage3a_args)))
static PvBuffer *loader_getblob(const gchar *filename, gsize *loader_size,
gsize args_size, gsize data_size,
gboolean data_aligned, GError **err)
{
g_autoptr(GMappedFile) mapped_file = NULL;
g_autoptr(PvBuffer) ret = NULL;
gsize size, tmp_loader_size;
gchar *loader_data;
g_assert(loader_size);
mapped_file = g_mapped_file_new(filename, FALSE, err);
if (!mapped_file)
return NULL;
loader_data = g_mapped_file_get_contents(mapped_file);
if (!loader_data) {
g_set_error(err, G_FILE_ERROR, G_FILE_ERROR_BADF,
_("File '%s' is empty"), filename);
return NULL;
}
tmp_loader_size = g_mapped_file_get_length(mapped_file);
if (tmp_loader_size < args_size) {
g_set_error(err, G_FILE_ERROR, G_FILE_ERROR_BADF,
_("File size less than expected: %lu < %ln"),
tmp_loader_size, loader_size);
return NULL;
}
/* For example, the PV header and IPIB data must be page
* aligned.
*/
size = (data_aligned ? PAGE_ALIGN(tmp_loader_size) : tmp_loader_size) +
data_size;
ret = pv_buffer_alloc(size);
/* copy the loader "template" */
memcpy(ret->data, loader_data, tmp_loader_size);
/* reset our dummy data (offsets and length) to zeros */
memset((uint8_t *)ret->data + tmp_loader_size - args_size, 0,
args_size);
*loader_size = tmp_loader_size;
return g_steal_pointer(&ret);
}
PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
gsize data_size, GError **err)
{
return loader_getblob(filename, loader_size,
sizeof(struct stage3a_args), data_size, TRUE,
err);
}
/* For the memory layout see stage3a.lds */
/* Set the right offsets and sizes in the stage3a template + add
* the IPIB block with the PV header
*/
static gint stage3a_set_data(PvBuffer *loader, gsize loader_size,
const PvBuffer *hdr, struct ipl_parameter_block *ipib,
GError **err)
{
uint32_t ipib_size = GUINT32_FROM_BE(ipib->hdr.len);
gsize args_size = sizeof(struct stage3a_args);
uint32_t hdr_size = (uint32_t)hdr->size;
uint64_t args_addr, next_data_addr;
if (hdr->size > UINT32_MAX) {
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
_("Invalid header size: %zu"), hdr->size);
return -1;
}
/* we assume here that the loader ``stage3a`` is loaded page
* aligned in the guest
*/
args_addr = (uint64_t)loader->data + loader_size - args_size;
/* therefore `next_data_addr` is also page aligned */
next_data_addr = (uint64_t)loader->data + PAGE_ALIGN(loader_size);
/* copy IPIB data */
memcpy((void *)next_data_addr, ipib, ipib_size);
/* set IPIB offset in relation to the stage3a arguments */
STAGE3A_ARGS(loader->data, loader_size)->ipib_offs =
GUINT64_TO_BE(next_data_addr - args_addr);
next_data_addr = next_data_addr + PAGE_ALIGN(ipib_size);
/* copy PV header */
memcpy((void *)next_data_addr, hdr->data, hdr_size);
/* set PV header size and offset in relation to the stage3a
* arguments
*/
STAGE3A_ARGS(loader->data, loader_size)->hdr_offs =
GUINT64_TO_BE(next_data_addr - args_addr);
STAGE3A_ARGS(loader->data, loader_size)->hdr_size = GUINT64_TO_BE(hdr_size);
return 0;
}
gint build_stage3a(PvBuffer *loader, gsize loader_size, const PvBuffer *hdr,
struct ipl_parameter_block *ipib, GError **err)
{
return stage3a_set_data(loader, loader_size, hdr, ipib, err);
}
PvBuffer *stage3b_getblob(const gchar *filename, GError **err)
{
g_autoptr(PvBuffer) ret = NULL;
gsize rb_size;
ret = loader_getblob(filename, &rb_size, sizeof(struct stage3b_args), 0,
FALSE, err);
if (!ret)
return NULL;
g_assert(ret->size == rb_size);
return g_steal_pointer(&ret);
}
void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args)
{
g_assert(stage3b->size > sizeof(*args));
/* at the end of the stage3b there are the stage3b args
* positioned
*/
memcpy((uint8_t *)stage3b->data + stage3b->size - sizeof(*args), args,
sizeof(*args));
}
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size)
{
arg->src = GUINT64_TO_BE(src);
arg->size = GUINT64_TO_BE(size);
}

View File

@@ -1,29 +0,0 @@
/*
* PV stage3 loader related definitions and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_STAGE3_H
#define PV_STAGE3_H
#include <glib.h>
#include <glib/gtypes.h>
#include <stdint.h>
#include "boot/ipl.h"
#include "boot/stage3b.h"
#include "utils/buffer.h"
PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
gsize data_size, GError **err);
gint build_stage3a(PvBuffer *dc, gsize dc_size, const PvBuffer *hdr,
struct ipl_parameter_block *ipib, GError **err);
PvBuffer *stage3b_getblob(const gchar *filename, GError **err);
void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args);
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size);
#endif

View File

@@ -1,24 +0,0 @@
/*
* Alignment utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_ALIGN_H
#define PV_UTILS_ALIGN_H
#include "lib/zt_common.h"
#include "boot/page.h"
#define IS_ALIGNED(addr, size) (!(addr & (size - 1)))
/* align addr to the next page boundary */
#define PAGE_ALIGN(addr) ALIGN((unsigned long)addr, PAGE_SIZE)
/* test whether an address is aligned to PAGE_SIZE or not */
#define IS_PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE)
#endif

View File

@@ -1,78 +0,0 @@
/*
* Buffer functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <glib.h>
#include <stdio.h>
#include <string.h>
#include "align.h"
#include "buffer.h"
#include "common.h"
#include "file_utils.h"
PvBuffer *pv_buffer_alloc(gsize size)
{
PvBuffer *ret = g_new0(PvBuffer, 1);
ret->data = g_malloc0(size);
ret->size = size;
return ret;
}
PvBuffer *pv_buffer_take(char *data, gsize size)
{
PvBuffer *ret = g_new0(PvBuffer, 1);
ret->data = data;
ret->size = size;
return ret;
}
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned)
{
PvBuffer *ret;
gsize size;
if (!buf)
return NULL;
size = buf->size;
if (page_aligned)
size = PAGE_ALIGN(size);
ret = pv_buffer_alloc(size);
/* content will be 0-right-padded */
memcpy(ret->data, buf->data, buf->size);
return ret;
}
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err)
{
return file_write(file, buf->data, buf->size, 1, NULL, err);
}
void pv_buffer_free(PvBuffer *buf)
{
if (!buf)
return;
g_free(buf->data);
g_free(buf);
}
void pv_buffer_clear(PvBuffer **buf)
{
if (!buf || !*buf)
return;
pv_buffer_free(*buf);
*buf = NULL;
}

View File

@@ -1,35 +0,0 @@
/*
* Buffer definition and functions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_BUFFER_H
#define PV_UTILS_BUFFER_H
#include <glib.h>
#include <stdio.h>
#include "common.h"
typedef struct PvBuffer {
void *data;
gsize size; /* in bytes */
} PvBuffer;
PvBuffer *pv_buffer_alloc(gsize size);
/* After this call @data belongs to the PvBuffer and must no longer be modified
* by the caller.
*/
PvBuffer *pv_buffer_take(char *data, gsize size);
void pv_buffer_free(PvBuffer *buf);
void pv_buffer_clear(PvBuffer **buf);
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err);
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvBuffer, pv_buffer_free)
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,174 +0,0 @@
/*
* General cryptography helper functions and definitions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_CRYPTO_H
#define PV_UTILS_CRYPTO_H
#include <glib.h>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/ecdh.h>
#include <openssl/evp.h>
#include <openssl/ossl_typ.h>
#include <openssl/rand.h>
#include <openssl/safestack.h>
#include <openssl/sha.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <stdint.h>
#include "common.h"
#include "include/pv_crypto_def.h"
#include "lib/zt_common.h"
#include "buffer.h"
#define AES_256_GCM_IV_SIZE 12
#define AES_256_GCM_TAG_SIZE 16
#define AES_256_XTS_TWEAK_SIZE 16
#define AES_256_XTS_KEY_SIZE 64
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
#define CRL_DOWNLOAD_MAX_SIZE (1024 * 1024) /* in bytes */
enum PvCryptoMode {
PV_ENCRYPT,
PV_DECRYPT,
};
typedef GSList HostKeyList;
/* play nice with g_autoptr */
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
typedef STACK_OF(X509) STACK_OF_X509;
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
void STACK_OF_X509_free(STACK_OF_X509 *stack);
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
typedef struct {
X509 *cert;
const gchar *path;
} x509_with_path;
x509_with_path *x509_with_path_new(X509 *cert, const gchar *path);
void x509_with_path_free(x509_with_path *cert);
typedef struct {
X509 *cert;
STACK_OF_X509_CRL *crls;
} x509_pair;
x509_pair *x509_pair_new(X509 **cert, STACK_OF_X509_CRL **crls);
void x509_pair_free(x509_pair *pair);
/* Register auto cleanup functions */
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_pair, x509_pair_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_with_path, x509_with_path_free)
union cmp_index {
struct {
uint16_t idx;
guchar rand[6];
} __packed;
uint64_t data;
};
/* The tweak is always stored in big endian format */
union tweak {
struct {
union cmp_index cmp_idx;
uint64_t page_idx; /* page index */
} __packed;
uint8_t data[AES_256_XTS_TWEAK_SIZE];
};
struct cipher_parms {
const EVP_CIPHER *cipher;
const PvBuffer *key;
const PvBuffer *iv_or_tweak;
};
int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
gint verify_flags, GError **err);
void pv_crypto_init(void);
void pv_crypto_cleanup(void);
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
gint verify_flags, int level, GError **err);
X509 *load_cert_from_file(const char *path, GError **err);
X509_CRL *load_crl_from_file(const gchar *path, GError **err);
GSList *load_certificates(const gchar *const *cert_paths, GError **err);
STACK_OF_X509 *get_x509_stack(const GSList *x509_with_path_list);
X509_STORE *store_setup(const gchar *root_ca_path,
const gchar * const *crl_paths,
GError **err);
int store_set_verify_param(X509_STORE *store, GError **err);
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
gint check_chain_parameters(const STACK_OF_X509 *chain, GError **err);
X509_NAME *c2b_name(const X509_NAME *name);
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
STACK_OF_X509_CRL *store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
GError **err);
X509_STORE_CTX *create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain,
GError **err);
gint verify_cert(X509 *cert, X509_STORE_CTX *ctx, GError **err);
X509_CRL *get_first_valid_crl(X509_STORE_CTX *ctx, X509 *cert, GError **err);
void store_setup_crl_download(X509_STORE *st);
EVP_PKEY *read_ec_pubkey_cert(X509 *cert, gint nid, GError **err);
PvBuffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
PvBuffer *generate_aes_key(guint size, GError **err);
PvBuffer *generate_aes_iv(guint size, GError **err);
EVP_PKEY *generate_ec_key(gint nid, GError **err);
gint generate_tweak(union tweak *tweak, uint16_t i, GError **err);
union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err);
EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err);
PvBuffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
PvBuffer *sha256_buffer(const PvBuffer *buf, GError **err);
int64_t gcm_encrypt(const PvBuffer *in, const PvBuffer *aad,
const struct cipher_parms *parms, PvBuffer *out,
PvBuffer *tag, GError **err);
gint encrypt_file(const struct cipher_parms *parms, const gchar *in_path,
const gchar *path_out, gsize *in_size, gsize *out_size,
GError **err);
PvBuffer *encrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
GError **err);
G_GNUC_UNUSED PvBuffer *decrypt_buf(const struct cipher_parms *parms,
const PvBuffer *in, GError **err);
#endif

View File

@@ -1,121 +0,0 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <glib.h>
#include <glib/gtypes.h>
#include <curl/curl.h>
#include "lib/zt_common.h"
#include "pv/pv_error.h"
#include "curl.h"
struct UserData {
GByteArray *buffer;
guint max_size;
};
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
g_assert(userdata);
struct UserData *data = (struct UserData *)userdata;
GByteArray *buffer = data->buffer;
guint64 actual_size;
size_t err;
g_assert(buffer);
if (!g_uint64_checked_mul(&actual_size, size, nmemb))
g_abort();
/* Signal an error condition by returning a amount that differs
* from the amount passed to the callback. This results in a
* CURLE_WRITE_ERROR.
*/
err = actual_size + 1;
if (actual_size > G_MAXUINT)
return err;
data->buffer = g_byte_array_append(buffer, (guchar *)ptr, (guint)actual_size);
if (data->buffer->len > data->max_size)
return err;
return actual_size;
}
gint curl_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
return -1;
return 0;
}
void curl_cleanup(void)
{
curl_global_cleanup();
}
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
GError **err)
{
g_autoptr(GByteArray) ret = NULL;
g_autoptr(CURL) handle = NULL;
g_autofree gchar *agent = NULL;
struct UserData userdata;
CURLcode rc;
/* set up curl session */
handle = curl_easy_init();
if (!handle)
g_abort();
/* follow redirection */
rc = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1l);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1l);
if (rc != CURLE_OK)
goto curl_err;
agent = g_strdup_printf("%s/%s", tool_name, RELEASE_STRING);
rc = curl_easy_setopt(handle, CURLOPT_USERAGENT, agent);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
if (rc != CURLE_OK)
goto curl_err;
ret = g_byte_array_new();
userdata.buffer = ret;
userdata.max_size = max_size;
rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&userdata);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_URL, url);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_perform(handle);
if (rc != CURLE_OK) {
g_set_error(err, PV_ERROR, PV_ERROR_DOWNLOAD_FAILED,
_("download failed: %s"), curl_easy_strerror(rc));
return NULL;
}
return g_steal_pointer(&ret);
curl_err:
g_set_error(err, PV_ERROR,
PV_ERROR_CURL_INIT_FAILED,
_("cURL initialization failed: %s"),
curl_easy_strerror(rc));
return NULL;
}

View File

@@ -1,25 +0,0 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_LIBCURL_H
#define PV_UTILS_LIBCURL_H
#include <glib.h>
#include <curl/curl.h>
#include "common.h"
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
GError **err);
gint curl_init(void);
void curl_cleanup(void);
#endif /* PV_UTILS_LIBCURL_H */

View File

@@ -1,234 +0,0 @@
/*
* General file utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <fcntl.h>
#include <glib.h>
#include <glib/gstdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "pv/pv_error.h"
#include "align.h"
#include "buffer.h"
#include "common.h"
#include "file_utils.h"
FILE *file_open(const gchar *filename, const gchar *mode, GError **err)
{
FILE *f = fopen(filename, mode);
if (!f) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to open file '%s': %s"), filename,
g_strerror(errno));
return NULL;
}
return f;
}
gint file_size(const gchar *filename, gsize *size, GError **err)
{
GStatBuf st_buf;
g_assert(size);
if (g_stat(filename, &st_buf) != 0) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to get file status '%s': %s"), filename,
g_strerror(errno));
return -1;
}
if (!S_ISREG(st_buf.st_mode)) {
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
_("File '%s' is not a regular file"), filename);
return -1;
}
if (st_buf.st_size < 0) {
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
_("Invalid file size for '%s': %zu"), filename,
st_buf.st_size);
return -1;
}
*size = (gsize)st_buf.st_size;
return 0;
}
/* Returns 0 on success, otherwise -1. Stores the total number of
* elements successfully read in @count_read
*/
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
gsize *count_read, GError **err)
{
gsize tmp_count_read;
tmp_count_read = fread(ptr, size, count, in);
if (count_read)
*count_read = tmp_count_read;
if (ferror(in)) {
g_set_error(err, G_FILE_ERROR, 0, _("Failed to read file"));
return -1;
}
return 0;
}
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
gsize *count_written, GError **err)
{
gsize tmp_count_written;
tmp_count_written = fwrite(ptr, size, count, out);
if (count_written)
*count_written = tmp_count_written;
if (tmp_count_written != count || ferror(out)) {
g_set_error(err, G_FILE_ERROR, 0, _("Failed to write file"));
return -1;
}
return 0;
}
static gint file_seek(FILE *f, uint64_t offset, GError **err)
{
gint rc;
if (offset > LONG_MAX) {
g_set_error(err, PV_ERROR, 0, _("Offset is too large"));
return -1;
}
rc = fseek(f, (long)offset, SEEK_SET);
if (rc != 0) {
g_set_error(err, G_FILE_ERROR,
(gint)g_file_error_from_errno(errno),
_("Failed to seek: '%s'"), g_strerror(errno));
return -1;
}
return 0;
}
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
GError **err)
{
gsize bytes_read, bytes_written;
gsize total_bytes_read = 0;
FILE *i = NULL;
gchar buf[4096];
gint ret = -1;
if (file_seek(o, offset, err) < 0)
return -1;
i = file_open(ifile->path, "rb", err);
if (!i)
return -1;
do {
if (file_read(i, buf, 1, sizeof(buf), &bytes_read, err) < 0) {
g_prefix_error(err, _("Failed to read file '%s': "),
ifile->path);
goto err;
}
if (bytes_read == 0)
break;
total_bytes_read += bytes_read;
if (file_write(o, buf, bytes_read, 1, &bytes_written, err) < 0)
goto err;
} while (bytes_written != 0);
if (ifile->size != total_bytes_read) {
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
_("'%s' has changed during the preparation"),
ifile->path);
goto err;
}
ret = 0;
err:
fclose(i);
return ret;
}
gint seek_and_write_buffer(FILE *o, const PvBuffer *buf, uint64_t offset,
GError **err)
{
if (file_seek(o, offset, err) < 0)
return -1;
if (pv_buffer_write(buf, o, err) < 0)
return -1;
return 0;
}
gint pad_file_right(const gchar *path_out, const gchar *path_in, gsize *size_out,
guint padding, GError **err)
{
FILE *f_in, *f_out = NULL;
guchar buf[padding];
gsize num_bytes_written;
gsize num_bytes_read;
uint64_t size_in = 0;
gint ret = -1;
*size_out = 0;
f_in = file_open(path_in, "rb", err);
if (!f_in)
goto err;
f_out = file_open(path_out, "wb", err);
if (!f_out)
goto err;
do {
memset(buf, 0, sizeof(buf));
if (file_read(f_in, buf, 1, sizeof(buf), &num_bytes_read, err) < 0) {
g_prefix_error(err, _("Failed to read file '%s': "),
path_in);
goto err;
}
size_in += num_bytes_read;
if (file_write(f_out, buf, 1, sizeof(buf), &num_bytes_written, err)) {
g_prefix_error(err, _("Failed to write file '%s': "),
path_out);
goto err;
}
*size_out += num_bytes_written;
} while (num_bytes_read == padding);
g_assert(num_bytes_written == ALIGN(num_bytes_read, padding));
ret = 0;
err:
if (f_out)
fclose(f_out);
if (f_in)
fclose(f_in);
return ret;
}

View File

@@ -1,34 +0,0 @@
/*
* General file utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_FILE_UTILS_H
#define PV_FILE_UTILS_H
#include <glib.h>
#include <stdint.h>
#include <stdio.h>
#include "pv/pv_comp.h"
#include "buffer.h"
FILE *file_open(const gchar *filename, const gchar *mode, GError **err);
gint file_size(const gchar *filename, gsize *size, GError **err);
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
gsize *count_read, GError **err);
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
gsize *count_written, GError **err);
gint pad_file_right(const gchar *path_out, const gchar *path_in,
gsize *size_out, guint padding, GError **err);
gint seek_and_write_buffer(FILE *out, const PvBuffer *buf, uint64_t offset,
GError **err);
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
GError **err);
#endif

View File

@@ -1,33 +0,0 @@
/*
* OpenSSL compatibility utils
*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef PV_UTILS_OPENSSL_COMPAT_H
#define PV_UTILS_OPENSSL_COMPAT_H
#include <openssl/opensslv.h>
#include <openssl/x509.h>
#include <openssl/x509_vfy.h>
#if OPENSSL_VERSION_NUMBER < 0x30000000L
#define Pv_X509_STORE_CTX_get_current_cert(ctx) \
X509_STORE_CTX_get_current_cert((X509_STORE_CTX *)(ctx))
#define Pv_X509_STORE_CTX_get1_crls(ctx, nm) \
X509_STORE_CTX_get1_crls((X509_STORE_CTX *)(ctx), (X509_NAME *)(nm))
#define Pv_X509_STORE_set_lookup_crls(st, cb) \
X509_STORE_set_lookup_crls(st, (X509_STORE_CTX_lookup_crls_fn)(cb))
#else
#define Pv_X509_STORE_CTX_get_current_cert(ctx) \
X509_STORE_CTX_get_current_cert(ctx)
#define Pv_X509_STORE_CTX_get1_crls(ctx, nm) \
X509_STORE_CTX_get1_crls(ctx, nm)
#define Pv_X509_STORE_set_lookup_crls(st, cb) \
X509_STORE_set_lookup_crls(st, cb)
#endif
#endif

View File

@@ -25,6 +25,9 @@
#include <time.h>
#include <unistd.h>
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "helper.h"
#include "hyptop.h"
#include "sd.h"
@@ -354,17 +357,6 @@ out:
ht_reverse_off();
}
/*
* Convert string to uppercase
*/
void ht_str_to_upper(char *str)
{
while (*str) {
*str = toupper(*str);
str++;
}
}
/*
* Convert ext TOD to microseconds
*/
@@ -412,3 +404,40 @@ s64 ht_calculate_smt_util(u64 core_us, u64 thr_us, u64 mgm_us, int thread_per_co
return smt_us;
}
/*
* Add two new key value pairs containing the current time as UNIX epoch and formatted string to a
* structured output object.
*/
void ht_fmt_time(void)
{
struct timeval tv;
struct tm *tm;
char str[30];
gettimeofday(&tv, NULL);
tm = localtime(&tv.tv_sec);
if (!tm)
return;
util_fmt_pair(FMT_PERSIST, "time_epoch", "%lld", mktime(tm));
strftime(str, sizeof(str), "%F %T%z", tm);
util_fmt_pair(FMT_PERSIST | FMT_QUOTE, "time", "%s", str);
}
/*
* Add a new object for available CPU types to a structured output object.
*/
void ht_fmt_cpu_types(void)
{
struct sd_cpu_type *cpu_type;
int i;
util_fmt_obj_start(FMT_DEFAULT, "cputypes");
sd_cpu_type_iterate(cpu_type, i) {
char *cpu_type_str = sd_cpu_type_id(cpu_type);
util_str_tolower(cpu_type_str);
util_fmt_pair(FMT_PERSIST, cpu_type_str, "%i",
sd_cpu_type_cpu_cnt(cpu_type));
}
util_fmt_obj_end(); /* cpus{} */
}

View File

@@ -66,6 +66,12 @@ void ht_print_scroll_bar(int row_cnt, int row_start, int row_bar_start,
int row_bar_bottom, int can_scroll_up,
int can_scroll_down, int with_boder);
/*
* util_fmt helper functions
*/
void ht_fmt_time(void);
void ht_fmt_cpu_types(void);
/*
* Error Macros
*/

View File

@@ -71,6 +71,51 @@ Use batch mode (no curses). This can be useful for sending output from hyptop
to another program, a file, or a line mode terminal.
In this mode no user input is accepted.
.TP
.BR "\-\-format=<FORMAT>"
.RS
Use this option to show output in a machine-readable format. FORMAT can be
one of:
.IP \(bu 3
.B json:
Single JavaScript Object Notation (JSON) data structure
Data for all iterations is formatted as one JSON data structure in multiple
lines to make them more readable by humans.
.BR
See section "OUTPUT FORMAT" for more details.
.BR
.PP
.IP \(bu 3
.B json\-seq:
Sequence of JSON data structures
Data for each iteration is formatted as a separate JSON data structure prefixed
with an ASCII Record Separator character (0x1e) and suffixed with an ASCII Line
Feed character (0x0a) in accordance with RFC7464.
.BR
See section "OUTPUT FORMAT" for more details.
.BR
.PP
.IP \(bu 3
.B pairs:
Textual key=value pairs
.PP
.IP \(bu 3
.B csv:
Comma-separated-value (CSV) list
.BR
All values are enclosed in double quotation marks and separated by commas. The
first line of output contains a list of headings. Subsequent lines each
represent data for one system in one iteration.
.PP
This option implies the "\-\-batch_mode" option.
.RE
.TP
.BR "\-d <SECONDS>" " or " "\-\-delay=<SECONDS>"
Specifies the delay between screen updates.
.TP
@@ -216,6 +261,196 @@ For the online time field, the value is the time during which at least
one CPU has been operational.
Operating CPUs are shown with CPU identifier "0" and stopped CPUs with "1".
.SH OUTPUT FORMATS
This section contains additional information for some of the supported
output formats.
.SS json
JSON output consists of a top-level object with the following properties
(key-value pairs):
.IP \(bu 3
.BR meta :
Tool meta-data including API level, version, host name, and time of invocation
.PP
.IP \(bu 3
.BR hyptop :
Hypervisor performance data
.PP
Performance data is stored as an array of iteration objects under the "hyptop"
property in the top-level object. Iteration objects contain the following properties:
.IP \(bu 3
.BR iteration :
sequential count of the current iteration
.PP
.IP \(bu 3
.BR "time" " and " "time_epoch" :
time when the iteration was recorded, in human-readable format and as Unix
epoch.
.PP
.IP \(bu 3
.BR cputypes :
contains the number of CPUs hyptop detected, per CPU type. Possible properties
are
.BR "cp" ", " "ifl" " and " "un".
.PP
.IP \(bu 3
.BR systems :
when the "sys_list" window is selected, contains an array of system objects
that contain the performance data per system. Each system object contains a
"system" property and properties for its performance data (see below).
.PP
.IP \(bu 3
.BR cpus :
when the "sys" window is selected, contains an array of CPU objects
that contain the performance data per CPU of the selected system. Each CPU
object contains a "coreid" property and properties for its performance data
(see below).
.PP
.IP \(bu 3
.BR summary :
contains aggregated performance data over all systems in the "systems" or
"cpus" array.
.PP
All performance data available for the platform (LPAR, z/VM) hyptop is executed
on is shown. Selecting specific fields with \-\-fields is not supported but it
is possible to change the units of fields. Properties for performance data are
labeled after their respective columns.
Example JSON output for a single iteration:
.br
.RS
{
.br
"meta": {
.br
"api_level": 1,
.br
"version": "2.35.0",
.br
"host": "mylpar.local",
.br
"time_epoch": 1730787834,
.br
"time": "2024-11-05 07:23:54+0100"
.br
},
.br
"hyptop": [
.br
{
.br
"iteration": 0,
.br
"time_epoch": 1730787834,
.br
"time": "2024-11-05 07:23:54+0100",
.br
"cputypes": {
.br
"ifl": 124,
.br
"cp": 1,
.br
"un": 0
.br
},
.br
"systems": [
.br
{
.br
"system": "MYLPAR",
.br
"#core": 30,
.br
"#the": 60,
.br
"core": 379.57,
.br
"the": 382.43,
.br
"smt": 294.73,
.br
"mgm": 2.09,
.br
"core+": "1503:13",
.br
"the+": "2060:45",
.br
"mgm+": "22:19",
.br
"online": "18:18:09"
.br
}
.br
],
.br
"summary": {
.br
"#core": 30,
.br
"#the": 60,
.br
"core": 379.57,
.br
"the": 382.43,
.br
"smt": 294.73,
.br
"mgm": 2.09,
.br
"core+": "1503:13",
.br
"the+": "2060:45",
.br
"mgm+": "22:19",
.br
"online": "18:18:09"
.br
}
.br
}
.br
]
.br
}
.br
.RE
.SS json\-seq
The json\-seq output format is a variation of the JSON output format described
above with the following differences:
.IP \(bu 3
Output consists of a sequence of top-level JSON objects, each contained in
single line with no indentation
.br
.IP \(bu 3
Each top-level object is prefixed by an ASCII Record Separator character (0x1e)
and suffixed with an ASCII Line Feed character (0x0a) in accordance with
RFC7464
.br
.PP
.IP \(bu 3
The first object contains tool meta-data properties defined in the previous
section
.br
.PP
.IP \(bu 3
Subsequent objects each represent performance data for one iteration
.br
.PP
.SH EXAMPLES
To start hyptop with the "sys_list" window in interactive mode, enter:
.br
@@ -258,6 +493,14 @@ for CPU time calculation, enter:
# hyptop -t ifl,cp
.br
To show a single iteration of performance data as a formatted JSON object for
system "MYLPAR" and with fields CPU time, thread time, management time and
online time in microseconds, enter:
.br
# hyptop -f C:us,E:us,M:us,o:us --format json -n 1 -s MYLPAR
.SH ENVIRONMENT
.TP
.B TERM

View File

@@ -18,6 +18,8 @@
#include <sys/types.h>
#include <time.h>
#include "lib/util_fmt.h"
#include "dg_debugfs.h"
#include "helper.h"
#include "hyptop.h"
@@ -218,6 +220,22 @@ static void l_term_check(void)
" try \"--batch_mode\"\n");
}
/*
* Init util_fmt if --format is specified on the command line.
*/
static void l_fmt_init(void)
{
unsigned int flags = FMT_WARN;
if (!g.o.format_specified)
return;
if (g.o.format == FMT_CSV)
flags |= FMT_QUOTEALL;
if (g.o.format == FMT_JSON || g.o.format == FMT_JSONSEQ)
flags |= FMT_HANDLEINT;
util_fmt_init(stdout, g.o.format, flags, 1);
}
/*
* Init curses
*/
@@ -296,7 +314,6 @@ static void l_update_term_curses(void)
static void l_update_term_batch(void)
{
g.w.cur->update_term(g.w.cur);
printf("\n");
}
/*
@@ -360,6 +377,7 @@ void __noreturn hyptop_exit(int rc)
int main(int argc, char *argv[])
{
opts_parse(argc, argv);
l_fmt_init();
hyptop_helper_init();
sd_init();
l_dg_init();

View File

@@ -17,6 +17,8 @@
#include <stdlib.h>
#include <termios.h>
#include "lib/util_fmt.h"
#include "helper.h"
#include "nav_desc.h"
#include "table.h"
@@ -52,6 +54,8 @@ struct hyptop_win_opts {
struct hyptop_opts {
unsigned int win_specified;
unsigned int batch_mode_specified;
unsigned int format_specified;
enum util_fmt_t format;
unsigned int iterations_specified;
unsigned int iterations;
unsigned int iterations_act;

View File

@@ -12,6 +12,8 @@
#include <ctype.h>
#include <stdio.h>
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "lib/zt_common.h"
#include "getopt.h"
@@ -19,6 +21,7 @@
#include "hyptop.h"
#include "opts.h"
#include "sd.h"
#include "table.h"
static const char l_copyright_str[] = "Copyright IBM Corp. 2010, 2017";
@@ -38,10 +41,16 @@ static char HELP_TEXT[] =
"-S, --sort LETTER Sort field for current window\n"
"-t, --cpu_types TYPE[,..] CPU types used for time calculations\n"
"-b, --batch_mode Use batch mode (no curses)\n"
" --format FORMAT Output format (" FMT_TYPE_NAMES "), implies -b\n"
"-d, --delay SECONDS Delay time between screen updates\n"
"-m, --smt_factor FACTOR Machine generation dependent SMT speedup factor.\n"
"-n, --iterations NUMBER Number of iterations before ending\n";
/*
* Options with long-name only
*/
#define OPT_FORMAT 256 /* --format */
/*
* Initialize default settings
*/
@@ -287,6 +296,23 @@ static void l_batch_mode_set(void)
g.o.batch_mode_specified = 1;
}
/*
* Set the "--format" option
*/
static void l_format_set(const char *str)
{
enum util_fmt_t fmt;
if (!util_fmt_name_to_type(str, &fmt)) {
ERR_EXIT("Unknown format '%s', supported formats: "
FMT_TYPE_NAMES "\n", str);
}
l_batch_mode_set();
g.o.format_specified = 1;
g.o.format = fmt;
}
/*
* Make option consisteny checks at end of command line parsing
*/
@@ -322,6 +348,7 @@ void opts_parse(int argc, char *argv[])
{ "fields", required_argument, NULL, 'f'},
{ "sort_field", required_argument, NULL, 'S'},
{ "cpu_types", required_argument, NULL, 't'},
{ "format", required_argument, NULL, OPT_FORMAT },
{ NULL, 0, NULL, 0 }
};
static const char option_string[] = "vhbd:m:w:s:n:f:t:S:";
@@ -366,6 +393,9 @@ void opts_parse(int argc, char *argv[])
case 'S':
l_sort_field_set(optarg);
break;
case OPT_FORMAT:
l_format_set(optarg);
break;
default:
l_std_usage_exit();
}
@@ -404,7 +434,7 @@ static void l_verify_systems(struct hyptop_win *win)
if (sd_sys_get(sd_sys_root_get(), win->opts.sys.vec[i]))
continue;
sys_name = ht_strdup(win->opts.sys.vec[i]);
ht_str_to_upper(win->opts.sys.vec[i]);
util_str_toupper(win->opts.sys.vec[i]);
if (sd_sys_get(sd_sys_root_get(), win->opts.sys.vec[i])) {
ht_free(sys_name);
continue;
@@ -431,11 +461,11 @@ void opts_iterations_next(void)
{
if (g.o.iterations_specified) {
g.o.iterations_act++;
if (g.o.iterations_act >= g.o.iterations)
if (g.o.iterations_act >= g.o.iterations) {
if (g.o.format_specified)
table_fmt_end();
hyptop_exit(0);
}
}
if (g.o.batch_mode_specified)
printf("---------------------------------------------------"
"----------------------------\n");
}

View File

@@ -16,6 +16,9 @@
#include <stdlib.h>
#include <string.h>
#include "lib/util_fmt.h"
#include "lib/util_libc.h"
#include "helper.h"
#include "hyptop.h"
#include "table.h"
@@ -196,8 +199,8 @@ static void l_col_headline_init(struct table *t, struct table_col *col)
col->p->head_char[0] = col->hotkey;
strcpy(col->p->head_last, ++ptr);
if (!t->attr_sorted_table) {
ht_str_to_upper(col->p->head_first);
ht_str_to_upper(col->p->head_last);
util_str_toupper(col->p->head_first);
util_str_toupper(col->p->head_last);
col->p->head_char[0] = toupper(col->p->head_char[0]);
}
}
@@ -948,6 +951,76 @@ static void l_table_print_all(struct table *t)
hyptop_print_nl();
}
l_row_print(t, t->row_last);
hyptop_print_nl();
hyptop_printf("------------------------------------------------------"
"-------------------------\n");
}
/*
* Print one table row as structured output
*
* Note: column filtering and sorting is explicitly ignored because the
* assumption is that these operations can be trivially performed by the
* consumer.
*/
static void l_row_print_formatted(struct table *t, struct table_row *row)
{
struct table_col *col;
int col_nr;
table_col_iterate(t, col, col_nr) {
unsigned int flags = 0;
struct table_entry *e = &row->entries[col_nr];
if (row == t->row_last && col_nr == 0)
continue;
if (table_col_needs_quotes(col))
flags = FMT_QUOTE;
util_fmt_pair(flags, col->head, "%s", e->str);
}
}
/*
* Print table as structured output
*/
static void l_table_print_all_formatted(struct table *t)
{
struct table_row *row;
util_fmt_obj_start(FMT_ROW, "iteration");
util_fmt_pair(FMT_PERSIST, "iteration", "%u", g.o.iterations_act);
ht_fmt_time();
ht_fmt_cpu_types();
if (strcmp(g.o.cur_win->id, "sys_list") == 0)
util_fmt_obj_start(FMT_LIST, "systems");
else
util_fmt_obj_start(FMT_LIST, "cpus");
util_list_iterate(&t->row_list, row) {
util_fmt_obj_start(FMT_ROW, "entry");
l_row_print_formatted(t, row);
util_fmt_obj_end(); /* entry */
}
util_fmt_obj_end(); /* systems[] */
util_fmt_obj_start(FMT_DEFAULT, "summary");
l_row_print_formatted(t, t->row_last);
util_fmt_obj_end(); /* summary{} */
util_fmt_obj_end(); /* iteration */
}
void table_fmt_start(void)
{
if (!g.o.format_specified)
return;
if (g.o.format != FMT_JSONSEQ)
util_fmt_obj_start(FMT_LIST, "hyptop");
}
void table_fmt_end(void)
{
if (!g.o.format_specified)
return;
if (g.o.format != FMT_JSONSEQ)
util_fmt_obj_end(); /* hyptop[] */
}
/*
@@ -955,10 +1028,14 @@ static void l_table_print_all(struct table *t)
*/
void table_print(struct table *t)
{
if (g.o.batch_mode_specified)
l_table_print_all(t);
else
if (g.o.batch_mode_specified) {
if (!g.o.format_specified)
l_table_print_all(t);
else
l_table_print_all_formatted(t);
} else {
l_table_print_curses(t);
}
}
/*

View File

@@ -106,6 +106,7 @@ struct table_col_priv {
char head_char[2];
char head_last[TABLE_HEADING_SIZE];
int rsort;
int needs_quotes;
};
/*
@@ -135,6 +136,11 @@ static inline int table_col_enabled(struct table_col *col)
return col->p->enabled;
}
static inline int table_col_needs_quotes(struct table_col *col)
{
return col->p->needs_quotes;
}
/*
* Table Column Constructor Macros
*/
@@ -384,6 +390,9 @@ extern struct table_row *table_row_alloc(struct table *t);
extern void table_scroll_down(struct table *t, enum table_scroll_unit unit);
extern void table_scroll_up(struct table *t, enum table_scroll_unit unit);
extern void table_fmt_start(void);
extern void table_fmt_end(void);
/*
* Entry add functions
*/

View File

@@ -63,7 +63,7 @@ static int l_unit_raw(struct table_col *col, struct table_entry *e)
*/
static int l_str(struct table_col *col, struct table_entry *e)
{
(void) col;
col->p->needs_quotes = 1;
return strlen(e->str);
}
@@ -226,6 +226,8 @@ static int l_unit_hm_u64(char *str, u64 v1, int negative)
static int l_unit_hm(struct table_col *col, struct table_entry *e)
{
col->p->needs_quotes = 1;
if (!e->set)
return snprintf(e->str, sizeof(e->str), L_COL_NOT_SET_STR);
@@ -272,6 +274,8 @@ static int l_unit_dhm_u64(char *str, u64 v1, int negative)
static int l_unit_dhm(struct table_col *col, struct table_entry *e)
{
col->p->needs_quotes = 1;
if (!e->set)
return snprintf(e->str, sizeof(e->str), L_COL_NOT_SET_STR);

View File

@@ -162,7 +162,8 @@ static void l_cpu_add(struct sd_cpu *cpu)
continue;
l_cpu_item_add(table_row, cpu, item);
}
l_cpu_add_visual(table_row, cpu);
if (!g.o.format_specified)
l_cpu_add_visual(table_row, cpu);
table_row_add(l_t, table_row);
}
@@ -194,7 +195,8 @@ static void l_table_update_term(struct hyptop_win *win)
{
(void) win;
ht_print_head(l_sys_id);
if (!g.o.format_specified)
ht_print_head(l_sys_id);
table_print(l_t);
}
@@ -300,6 +302,7 @@ static void l_run(struct hyptop_win *win)
/* Reformat table when entering window */
table_rebuild(l_t);
table_fmt_start();
while (1) {
if (l_table_create()) {
if (g.o.batch_mode_specified)
@@ -363,9 +366,11 @@ void win_sys_init(void)
col_vec[i] = col;
col_desc_vec[i] = item->desc;
}
col_vec[i] = &l_vis_col;
col_desc_vec[i] = vis_str;
table_col_add(l_t, &l_vis_col);
if (!g.o.format_specified) {
col_vec[i] = &l_vis_col;
col_desc_vec[i] = vis_str;
table_col_add(l_t, &l_vis_col);
}
/* Enable fields */
if (win_sys.opts.fields.specified)

View File

@@ -206,7 +206,8 @@ static void l_table_update_term(struct hyptop_win *win)
{
(void) win;
ht_print_head(NULL);
if (!g.o.format_specified)
ht_print_head(NULL);
table_print(l_t);
}
@@ -310,6 +311,7 @@ static void l_run(struct hyptop_win *win)
/* Reformat table when entering window */
table_rebuild(l_t);
table_fmt_start();
while (1) {
l_table_create();
hyptop_update_term();

View File

@@ -21,18 +21,20 @@
#define STAGE2_DESC _AC(0x78, UL)
#define STAGE2_ENTRY _AC(0x2018, UL)
#define ECKD2DUMP_MV_TAIL_ADDRESS _AC(0x5000, UL)
#define STAGE2_HEAP_ADDRESS _AC(0x6000, UL)
#define ECKD2DUMP_SV_HEAP_ADDRESS _AC(0xb000, UL)
#define ECKD2DUMP_HEAP_ADDRESS _AC(0xb000, UL)
#define STAGE2_HEAP_SIZE _AC(0x3000, UL)
#define STAGE2_STACK_ADDRESS _AC(0xe400, UL)
#define STAGE2_STACK_SIZE _AC(0x1c00, UL)
#define ECKD2DUMP_SV_STACK_ADDRESS _AC(0xe000, UL)
#define ECKD2DUMP_SV_STACK_SIZE _AC(0x2000, UL)
#define ECKD2DUMP_STACK_ADDRESS _AC(0xe000, UL)
#define ECKD2DUMP_STACK_SIZE _AC(0x2000, UL)
#define STAGE2_MAX_SIZE _AC(0x3000, UL)
#define STAGE2_DUMPER_SIZE_V1 _AC(0x1000, UL)
#define STAGE2_DUMPER_SIZE_V2 _AC(0x2000, UL)
#define STAGE2_DUMPER_SIZE_V3 _AC(0x3000, UL)
#define STAGE2_DUMPER_SIZE_MV _AC(0x3000, UL)
#define STAGE2_DUMPER_SIZE_ZLIB _AC(0x8000, UL)
#define STAGE3_ENTRY _AC(0xa000, UL)

View File

@@ -58,6 +58,8 @@ struct os_info {
uint8_t reserved[3804];
} __packed;
STATIC_ASSERT(sizeof(struct os_info) == 4096)
/*
* Return 0 in case of valid os_info
* Return -EOS_INFO_MISSING if os_info address is not page aligned or page is

View File

@@ -72,6 +72,7 @@ char *path_get_ap_udev(void);
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev);
/* Functions for reading JSON device config */
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
@@ -87,6 +88,9 @@ bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
bool *read_aq);
void ap_mask_to_list(char *mask, struct util_list *list);
void ap_list_remove_all(struct util_list *list);
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size);
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size);
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size);
/* Lock Functions */
int ap_get_lock(void);

96
include/lib/pci_list.h Normal file
View File

@@ -0,0 +1,96 @@
/**
* @defgroup pci_list_h libzpci: zPCI device handling
* @{
* @brief Work with zPCI devices
*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIB_ZPCI_PCI_LIST_H
#define LIB_ZPCI_PCI_LIST_H
#include <stdint.h>
#include <stdbool.h>
#include "util_list.h"
enum zpci_pft {
ZPCI_PFT_UNCLASSIFIED = 0x00,
ZPCI_PFT_ROCE_EXPRESS = 0x02,
ZPCI_PFT_ROCE_EXPRESS2 = 0x0a,
ZPCI_PFT_CNW = 0x0d,
ZPCI_PFT_NETH = 0x0c,
ZPCI_PFT_NETD = 0x0f,
ZPCI_PFT_NVME = 0x0b,
ZPCI_PFT_ISM = 0x05
};
/*
* Follows RFC 2863 operational states with the
* numeric values from IF_OPER_* in linux/if.h:
*/
typedef uint8_t operstate_t;
struct zpci_netdev {
char *name;
operstate_t operstate;
};
struct zpci_dev {
struct util_list_node entry;
/* PCI Domain */
uint32_t domain_nr;
/* PCI Bus (8 bits), Device (5 bits), Function (3 bits) */
union {
uint16_t val;
struct {
uint16_t bus : 8;
uint16_t dev : 5;
uint16_t fn : 3;
};
} bdf;
/* Function attributes (see linux/Documentation/arch/s390/pci.rst) */
uint32_t fid;
uint32_t uid;
uint16_t pchid;
uint16_t vfn;
uint8_t port;
enum zpci_pft pft;
bool uid_is_unique;
/* Configuration state 0 - Standby, 1 Configured */
bool conf;
/* Associated netdevs if any */
int num_netdevs;
struct zpci_netdev *netdevs;
};
/**
* Get if a PCI device is a PCI Virtual Function
*
* @param[in] zdev The device in question
*
* @return true if the device is a VF false otherwise
*/
static inline bool zpci_is_vf(struct zpci_dev *zdev)
{
return !!zdev->vfn;
}
struct util_list *zpci_dev_list(void);
void zpci_free_dev_list(struct util_list *zpci_list);
void zpci_free_dev(struct zpci_dev *zdev);
char *zpci_pci_addr(struct zpci_dev *zdev);
const char *zpci_pft_str(struct zpci_dev *zdev);
const char *zpci_operstate_str(operstate_t state);
operstate_t zpci_operstate_from_str(const char *oper_str);
#endif /* LIB_ZPCI_PCI_LIST_H */

56
include/lib/pci_sclp.h Normal file
View File

@@ -0,0 +1,56 @@
/**
* @defgroup pci_sclp_h libzpci: zPCI device handling
* @{
* @brief Issue SCLPs for zPCI devices
*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIB_ZPCI_PCI_SCLP_H
#define LIB_ZPCI_PCI_SCLP_H
#include <linux/types.h>
#include <stddef.h>
#include "lib/zt_common.h"
#define SCLP_ERRNOTIFY_AQ_RESET 0
#define SCLP_ERRNOTIFY_AQ_DECONF 1
#define SCLP_ERRNOTIFY_AQ_REPORT_ERR 2
#define SCLP_ERRNOTIFY_AQ_OPTICS_DATA 3
#define SCLP_ERRNOTIFY_ID_ZPCICTL 0x4713
#define SCLP_ERRNOTIFY_ID_OPTICSMON 0x4714
#define SCLP_ERRNOTIFY_DATA_SIZE 4054
struct zpci_report_error_header {
__u8 version; /* Interface version byte */
__u8 action; /* Action qualifier byte
* 0: Adapter Reset Request
* 1: Deconfigure and repair action requested
* 2: Informational Report
* 3: Optics Data
*/
__u16 length; /* Length of Subsequent Data (up to 4K SCLP header) */
} __packed;
struct zpci_report_error_data {
__u64 timestamp;
__u64 err_log_id;
/* We cannot exceed a total of 4074 bytes (header + data) */
char log_data[SCLP_ERRNOTIFY_DATA_SIZE];
} __packed;
struct zpci_report_error {
struct zpci_report_error_header header;
struct zpci_report_error_data data;
} __packed;
int zpci_sclp_issue_action(char *pci_addr, int action,
char *data, size_t length, u64 err_log_id);
#endif /* LIB_ZPCI_PCI_SCLP_H */

View File

@@ -11,6 +11,8 @@
#ifndef LIB_UTIL_FILE_H
#define LIB_UTIL_FILE_H
#include <stdio.h>
#include "lib/util_exit_code.h"
int util_file_read_line(char *str, size_t size, const char *fmt, ...);

View File

@@ -129,6 +129,7 @@ int __util_vsprintf(const char *func, const char *file, int line,
char *util_strcat_realloc(char *str1, const char *str2);
void util_concatf(char **str1, const char *fmt, ...);
void util_str_toupper(char *str);
void util_str_tolower(char *str);
char *util_strstrip(char *s);
size_t util_strlcpy(char *dest, const char *src, size_t size);

View File

@@ -14,7 +14,6 @@
#include <ctype.h>
#include <sys/types.h>
struct util_proc_part_entry {
dev_t device;
size_t blockcount;
@@ -27,6 +26,12 @@ struct util_proc_dev_entry {
char *name;
};
#define UTIL_PROC_DEV_ENTRY_DASD "dasd"
#define UTIL_PROC_DEV_ENTRY_VIRTBLK "virtblk"
#define UTIL_PROC_DEV_ENTRY_SD "sd"
#define UTIL_PROC_DEV_ENTRY_BLKEXT "blkext"
#define UTIL_PROC_DEV_ENTRY_MD "md"
int util_proc_part_get_entry(dev_t device, struct util_proc_part_entry *entry);
void util_proc_part_free_entry(struct util_proc_part_entry *entry);
int util_proc_dev_get_entry(dev_t dev, int blockdev,

View File

@@ -723,14 +723,14 @@ static void check_exists(const char *path, const char *attr)
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
if (access(fpath, F_OK) != 0)
ERR_EXIT("System does not allow to set %s", attr);
ERR_EXIT("System does not allow one to set %s", attr);
}
static void write_str_optional(char *string, char *file, int exit_on_fail,
const char *attr)
{
if (write_str_errno(string, file) && exit_on_fail)
ERR_EXIT("System does not allow to set %s", attr);
ERR_EXIT("System does not allow one to set %s", attr);
}
/*

View File

@@ -15,7 +15,7 @@
prog_name=`basename $0`
guest_name=${USER:-`whoami 2>/dev/null`}
terminal=lnxhvc0
iucvconn=`which iucvconn 2>/dev/null`
iucvconn=`command -v iucvconn 2>/dev/null`
__error() {
printf "$prog_name: $@\n" >&2

View File

@@ -33,6 +33,9 @@
#include "lib/util_path.h"
#include "lib/util_udev.h"
static const char default_mask[AP_MASK_SIZE] =
"0x0000000000000000000000000000000000000000000000000000000000000000";
/*
* Return sysfs path to a bus attribute
* Note: caller is responsible for freeing the returned string
@@ -118,6 +121,37 @@ static void modify_device_attr(struct util_list *list, char *value)
vfio_ap_node_remove_dupes(list);
}
/*
* Pass a comma-delimited string of masks (adapters,domains,controls) and
* for each ON bit in these masks add the associated ID to the device
* lists.
*/
static void modify_device_ap_config(struct vfio_ap_device *dev,
char *value)
{
char *mask, *adapters, *domains, *controls;
mask = util_strdup(value);
adapters = strtok(mask, ",");
domains = strtok(NULL, ",");
controls = strtok(NULL, ",");
util_assert((!strtok(NULL, ",")) && adapters && domains && controls,
"Invalid ap_config attribute encountered %s", value);
/*
* ap_config overwrites the current list of adapters, domains and
* control domains. Clear the current lists before generating new ones
* based upon the input mask values.
*/
ap_list_remove_all(dev->adapters);
ap_list_remove_all(dev->domains);
ap_list_remove_all(dev->controls);
ap_mask_to_list(adapters, dev->adapters);
ap_mask_to_list(domains, dev->domains);
ap_mask_to_list(controls, dev->controls);
}
static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
const char *value)
{
@@ -129,6 +163,8 @@ static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
modify_device_attr(dev->domains, v);
else if (strcmp(attr, "assign_control_domain") == 0)
modify_device_attr(dev->controls, v);
else if (strcmp(attr, "ap_config") == 0)
modify_device_ap_config(dev, v);
free(v);
}
@@ -416,6 +452,28 @@ void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control)
}
}
/**
* Determine if the specified device is currently active. If so, see if
* it is enabled for dynamic configuration support.
*
* @param[in] dev Vfio-ap struct
*
* @retval True Device is active and enabled for dynamic config
* @retval False Device is not active OR no dynamic config support
*/
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev)
{
char *attr = path_get_vfio_ap_attr(dev->uuid, "ap_config");
if (!attr)
return false;
if (!util_path_is_readable(attr))
return false;
return true;
}
#ifdef HAVE_JSONC
/**
@@ -692,7 +750,7 @@ void ap_mask_to_list(char *mask, struct util_list *list)
*/
void ap_list_remove_all(struct util_list *list)
{
struct ap_node *node;
struct vfio_ap_node *node;
while (!util_list_is_empty(list)) {
node = util_list_start(list);
@@ -715,6 +773,90 @@ static unsigned int random_delay(void)
return AP_LOCK_DELAY_US + (rand() % AP_LOCK_VARIANCE_US);
}
/**
* Return a mask of assigned adapters for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get adapter mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Adapter mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->adapters, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Return a mask of assigned domains for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get domain mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Domain mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->domains, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Return a mask of assigned control domains for the specified vfio_ap device.
* Note: caller is responsible for freeing the returned string
*
* @param[in] dev Vfio-ap struct to get control domain mask from
* @param[in, out] size Size of mask buffer returned
*
* @retval != 0 Control domain mask (hex string)
* @retval 0 Failed to generate a mask
*/
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size)
{
struct vfio_ap_node *node;
char *mask;
if (!dev || !size)
return NULL;
mask = util_strdup(default_mask);
*size = AP_MASK_SIZE;
util_list_iterate(dev->controls, node) {
ap_set_bit(node->id, mask, true);
}
return mask;
}
/**
* Acquire the ap config lock using this Process ID
*

View File

@@ -1084,8 +1084,6 @@ int kmip_connection_new(const struct kmip_conn_config *config,
return -EINVAL;
}
break;
break;
default:
kmip_debug(debug, "Invalid encoding: %d", config->encoding);
return -EINVAL;

View File

@@ -89,7 +89,7 @@ int kmip_decode_xml(const xmlNode *xml, struct kmip_node *parent,
} else {
n->type = kmip_type_by_name_or_hex(type_attr);
if (n->type == 0) {
kmip_debug(debug, "Unknown 'type' in JSON object: '%s'",
kmip_debug(debug, "Unknown 'type' in XML object: '%s'",
type_attr);
rc = -EBADMSG;
goto out;
@@ -361,7 +361,7 @@ int kmip_encode_xml(const struct kmip_node *node, xmlNode **xml, bool debug)
while (element != NULL) {
rc = kmip_encode_xml(element, &elem_xml, debug);
if (rc != 0) {
kmip_debug(debug, "kmip_encode_json failed");
kmip_debug(debug, "kmip_encode_xml failed");
goto out;
}
if (xmlAddChild(ret_xml, elem_xml) == NULL) {

View File

@@ -13,6 +13,8 @@
#include <stdlib.h>
#include <string.h>
#include "lib/util_path.h"
#include "lib/util_file.h"
#include "lib/util_arch.h"
#define PROC_SYSINFO "/proc/sysinfo"
@@ -107,13 +109,44 @@ const char *util_arch_machine_type_to_str(int type)
*/
unsigned long util_arch_hsa_maxsize(void)
{
switch (util_arch_machine_type()) {
case UTIL_ARCH_MACHINE_TYPE_Z15:
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
case UTIL_ARCH_MACHINE_TYPE_Z16:
case UTIL_ARCH_MACHINE_TYPE_Z16_A02:
return HSA_SIZE_512M;
default:
return HSA_SIZE_32M;
unsigned long hsa_size = 0;
char *path;
int rc;
path = util_path_sysfs("firmware/dump/dump_area_size");
if (util_path_exists(path)) {
rc = util_file_read_ul(&hsa_size, 10, path);
if (rc)
hsa_size = 0;
}
free(path);
/*
* Fall back in case of failed attempt to obtain dump area size
* from sysfs for some reason (e.g. no kernel support of
* the sysfs attribute /sys/firmware/dump/dump_area_size).
* For all machine types starting with z15 we can safely assume
* at least 512M of dump area size, otherwise, only 32M can be
* safely assumed.
*/
if (!hsa_size) {
switch (util_arch_machine_type()) {
case UTIL_ARCH_MACHINE_TYPE_Z10_EC:
case UTIL_ARCH_MACHINE_TYPE_Z10_BC:
case UTIL_ARCH_MACHINE_TYPE_ZE_196:
case UTIL_ARCH_MACHINE_TYPE_ZE_114:
case UTIL_ARCH_MACHINE_TYPE_ZE_EC12:
case UTIL_ARCH_MACHINE_TYPE_ZE_BC12:
case UTIL_ARCH_MACHINE_TYPE_Z13:
case UTIL_ARCH_MACHINE_TYPE_Z13_S:
case UTIL_ARCH_MACHINE_TYPE_Z14:
case UTIL_ARCH_MACHINE_TYPE_Z14_ZR1:
hsa_size = HSA_SIZE_32M;
break;
default:
hsa_size = HSA_SIZE_512M;
}
}
return hsa_size;
}

View File

@@ -710,6 +710,14 @@ static void csv_map(struct obj_t *UNUSED(obj), unsigned int mflags,
free(qval);
}
static bool hide_meta_env(void)
{
char *v;
v = secure_getenv("FMT_NOMETA");
return (v && strcmp(v, "1") == 0);
}
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
int api_level)
{
@@ -719,7 +727,7 @@ void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
f.fileno = fileno(fd);
f.hide_prefix = (flags & FMT_NOPREFIX);
f.hide_inval = !(flags & FMT_KEEPINVAL);
f.hide_meta = (flags & FMT_NOMETA);
f.hide_meta = (flags & FMT_NOMETA) || hide_meta_env();
f.quote_all = (flags & FMT_QUOTEALL);
f.do_filter = (flags & FMT_FILTER);
f.do_warn = (flags & FMT_WARN);

View File

@@ -174,6 +174,21 @@ void util_str_toupper(char *str)
str[i] = toupper(str[i]);
}
/**
* Convert string to lowercase
*
* String \a str is converted to lowercase
*
* @param[in,out] str String to convert
*/
void util_str_tolower(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
str[i] = tolower(str[i]);
}
/*
* Print to newly allocated string or exit in case of failure
*/

20
libzpci/Makefile Normal file
View File

@@ -0,0 +1,20 @@
include ../common.mak
lib = libzpci.a
all: $(lib)
objects = pci_list.o pci_sclp.o
examples := $(patsubst %.c,%,$(wildcard *_example.c))
examples: $(examples)
$(examples): %: %.o $(lib) $(rootdir)/libutil/libutil.a
$(lib): ALL_CFLAGS += -fPIC -std=c11
$(lib): $(objects)
install: all
clean:
rm -f *.o $(lib) $(examples)

48
libzpci/libzpci_example.c Normal file
View File

@@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <err.h>
#include "lib/util_list.h"
#include "lib/pci_list.h"
static void zpci_print(struct zpci_dev *zdev)
{
char *pci_addr = zpci_pci_addr(zdev);
int i;
if (!zdev->conf) {
printf("fid: %8x address: %s\n", zdev->fid, pci_addr);
} else {
printf("fid: %8x address: %s uid: %4x%s pchid: %4x vfn: %4d port: %1d pft: %s ",
zdev->fid, pci_addr, zdev->uid, (zdev->uid_is_unique) ? " (unique)" : "",
zdev->pchid, zdev->vfn, zdev->port, zpci_pft_str(zdev));
if (zdev->num_netdevs) {
printf("netdevs: ");
for (i = 0; i < zdev->num_netdevs; i++) {
printf("%s (%s)", zdev->netdevs[i].name,
zpci_operstate_str(zdev->netdevs[i].operstate));
if (i + 1 < zdev->num_netdevs)
printf(", ");
}
}
printf("\n");
}
free(pci_addr);
}
int main(void)
{
struct util_list *zpci_list;
struct zpci_dev *zdev;
zpci_list = zpci_dev_list();
if (!zpci_list)
errx(EXIT_FAILURE, "Error getting list of zPCI devices");
util_list_iterate(zpci_list, zdev)
zpci_print(zdev);
zpci_free_dev_list(zpci_list);
return EXIT_SUCCESS;
}

358
libzpci/pci_list.c Normal file
View File

@@ -0,0 +1,358 @@
/**
* libzpci - Functions to handle zPCI devices and their properties
*
* Copyright IBM Corp. 2023
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <err.h>
#include <errno.h>
#include <linux/if.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "lib/pci_list.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_list.h"
#include "lib/util_path.h"
#include "lib/util_scandir.h"
/**
* Get the function type name for the given device
*
* The device type name is suitable for presentation to a user.
*
* @param[in] zdev The device in question
*
* @return a string representing the PCI device type
*/
const char *zpci_pft_str(struct zpci_dev *zdev)
{
switch (zdev->pft) {
case ZPCI_PFT_UNCLASSIFIED:
return "unclassified";
case ZPCI_PFT_ROCE_EXPRESS:
return "RoCE Express";
case ZPCI_PFT_ROCE_EXPRESS2:
return "RoCE Express-2";
case ZPCI_PFT_CNW:
return "Cloud Network Adapter";
case ZPCI_PFT_NETH:
return "Network Express Hybrid";
case ZPCI_PFT_NETD:
return "Network Express Dedicated";
case ZPCI_PFT_NVME:
return "NVMe";
case ZPCI_PFT_ISM:
return "ISM";
default:
return "unknown";
}
}
/**
* Get a textual representation of the device's PCI address
*
* The representation has extended "DDDD:bb:dd.f" format used
* by Linux tooling such as lspci.
*
* @param[in] zdev The device in question
*
* @return the string representing the PCI address
*/
char *zpci_pci_addr(struct zpci_dev *zdev)
{
uint8_t bus = zdev->bdf.bus;
uint8_t dev = zdev->bdf.dev;
uint8_t fn = zdev->bdf.fn;
char *pci_addr;
util_asprintf(&pci_addr, "%04x:%02x:%02x.%x", zdev->domain_nr, bus, dev, fn);
return pci_addr;
}
/**
* Get an operationanl state value from its state name
*
* The state names follow RFC 2863 and the values match
* IF_OPER_* in linux/if.h.
*
* @param[in] oper_str The name of the operational state
*
* @return the operational state value
*/
operstate_t zpci_operstate_from_str(const char *oper_str)
{
if (!strcmp(oper_str, "notpresent"))
return IF_OPER_NOTPRESENT;
else if (!strcmp(oper_str, "down"))
return IF_OPER_DOWN;
else if (!strcmp(oper_str, "lowerlayerdown"))
return IF_OPER_LOWERLAYERDOWN;
else if (!strcmp(oper_str, "testing"))
return IF_OPER_TESTING;
else if (!strcmp(oper_str, "dormant"))
return IF_OPER_DORMANT;
else if (!strcmp(oper_str, "up"))
return IF_OPER_UP;
else
return IF_OPER_UNKNOWN;
}
/**
* Get an operationanl state name from its value
*
* The state names follow RFC 2863 and the values match
* IF_OPER_* in linux/if.h.
*
* @param[in] state The value of the operational state
*
* @return the operational state name string representation
*/
const char *zpci_operstate_str(operstate_t state)
{
switch (state) {
case IF_OPER_NOTPRESENT:
return "notpresent";
case IF_OPER_DOWN:
return "down";
case IF_OPER_LOWERLAYERDOWN:
return "lowerlayerdown";
case IF_OPER_TESTING:
return "testing";
case IF_OPER_DORMANT:
return "dormant";
case IF_OPER_UP:
return "up";
case IF_OPER_UNKNOWN:
default:
return "unknown";
};
}
static int zpci_populate_from_slot_dir(struct zpci_dev *zdev, const char *slot_dir,
const char *slot_name)
{
char buf_addr[11]; /* "dddd:bb:dd\0" */
uint8_t bus, df;
uint32_t domain;
int val, rc;
rc = sscanf(slot_name, "%x", &zdev->fid);
if (rc != 1)
return -EINVAL;
rc = util_file_read_line(buf_addr, sizeof(buf_addr), "%s/%s/address", slot_dir, slot_name);
if (rc) {
warn("Reading address from slot %s/%s", slot_dir, slot_name);
return rc;
}
rc = sscanf(buf_addr, "%04x:%02hhx:%02hhx", &domain, &bus, &df);
if (rc != 3)
return -EINVAL;
zdev->domain_nr = domain;
zdev->bdf.val = (((uint16_t)bus) << 8) | df;
rc = util_file_read_i(&val, 10, "%s/%s/power", slot_dir, slot_name);
if (rc) {
warn("Reading power from slot %s/%s", slot_dir, slot_name);
return rc;
}
zdev->conf = val > 0;
return 0;
}
static int zpci_populate_netdevices(struct zpci_dev *zdev, const char *dev_dir)
{
const char *netdev_patt = "en.*";
struct dirent **de_vec;
int count, i, rc = 0;
char *net_dir;
char buf[16]; /* "lowerlayerdown" */
util_asprintf(&net_dir, "%s/net", dev_dir);
count = util_scandir(&de_vec, alphasort, net_dir, netdev_patt);
if (count == -1) {
warn("Reading netdevice information for %s/net failed", dev_dir);
rc = -EINVAL;
goto out_net_dir;
}
/* A directory per netdev */
for (i = 0; i < count; i++) {
if (de_vec[i]->d_type != DT_DIR) {
rc = -EINVAL;
goto out_scan_dir;
}
}
zdev->num_netdevs = count;
if (!count)
goto out_scan_dir;
zdev->netdevs = util_zalloc(sizeof(struct zpci_netdev) * zdev->num_netdevs);
for (i = 0; i < count; i++) {
zdev->netdevs[i].name = util_strdup(de_vec[i]->d_name);
rc = util_file_read_line(buf, sizeof(buf), "%s/%s/operstate", net_dir,
zdev->netdevs[i].name);
if (rc) {
/* If operstate is not readable just set to unknown */
zdev->netdevs[i].operstate = IF_OPER_UNKNOWN;
rc = 0;
continue;
}
zdev->netdevs[i].operstate = zpci_operstate_from_str(buf);
}
out_scan_dir:
util_scandir_free(de_vec, count);
out_net_dir:
free(net_dir);
return rc;
}
static int zpci_populate_from_dev_dir(struct zpci_dev *zdev)
{
char *pci_addr = zpci_pci_addr(zdev);
int rc, val;
char *path;
path = util_path_sysfs("bus/pci/devices/%s", pci_addr);
if (!path) {
rc = -EINVAL;
goto out_pci_addr;
}
if (!util_path_exists(path)) {
rc = -ENODEV;
goto out_path;
}
rc = util_file_read_i(&val, 16, "%s/uid", path);
if (rc)
goto out_path;
zdev->uid = val;
/* In old Linux versions uid_is_unique doesn't exist
* so don't treat this as an error.
*/
rc = util_file_read_i(&val, 10, "%s/uid_is_unique", path);
if (!rc)
zdev->uid_is_unique = !!val;
rc = util_file_read_i(&val, 16, "%s/pchid", path);
if (rc)
goto out_path;
zdev->pchid = val;
rc = util_file_read_i(&val, 16, "%s/vfn", path);
if (rc)
goto out_path;
zdev->vfn = val;
rc = util_file_read_i(&val, 10, "%s/port", path);
if (rc)
goto out_path;
zdev->port = val;
rc = util_file_read_i(&val, 16, "%s/pft", path);
if (rc)
goto out_path;
zdev->pft = val;
if (util_path_is_readable("%s/net", path)) {
rc = zpci_populate_netdevices(zdev, path);
if (rc)
goto out_path;
}
out_path:
free(path);
out_pci_addr:
free(pci_addr);
return rc;
}
/**
* Get a list of all configured and standby PCI devices
*
* @return a list of struct zpci_dev in case of success,
* NULL in case of failure
*/
struct util_list *zpci_dev_list(void)
{
char *path = util_path_sysfs("bus/pci/slots/");
const char *zpci_slot_patt = "[0-9a-f]{8}";
struct util_list *zpci_list = NULL;
struct dirent **de_vec;
struct zpci_dev *zdev;
int count, i, rc;
count = util_scandir(&de_vec, alphasort, path, zpci_slot_patt);
if (count == -1) {
warn("util_scandir failed");
goto error_path;
}
zpci_list = util_list_new(struct zpci_dev, entry);
for (i = 0; i < count; i++) {
if (de_vec[i]->d_type != DT_DIR)
continue;
zdev = util_zalloc(sizeof(*zdev));
rc = zpci_populate_from_slot_dir(zdev, path, de_vec[i]->d_name);
if (rc) {
free(zdev);
continue;
}
if (zdev->conf) {
rc = zpci_populate_from_dev_dir(zdev);
if (rc) {
free(zdev);
continue;
}
}
util_list_add_tail(zpci_list, zdev);
}
util_scandir_free(de_vec, count);
error_path:
free(path);
return zpci_list;
}
/**
* Free a PCI device struct
*
* This frees both the struct zpci_dev and its associated netdevs array
*
* @param[in] zdev The device struct to free
*/
void zpci_free_dev(struct zpci_dev *zdev)
{
int i;
if (zdev->num_netdevs) {
for (i = 0; i < zdev->num_netdevs; i++)
free(zdev->netdevs[i].name);
free(zdev->netdevs);
}
free(zdev);
}
/**
* Free a PCI device list
*
* This frees all elements in the list
*
* @param[in] zpci_list The device list to free
*/
void zpci_free_dev_list(struct util_list *zpci_list)
{
struct zpci_dev *zdev, *tmp;
util_list_iterate_safe(zpci_list, zdev, tmp) {
util_list_remove(zpci_list, zdev);
zpci_free_dev(zdev);
}
util_list_free(zpci_list);
}

61
libzpci/pci_sclp.c Normal file
View File

@@ -0,0 +1,61 @@
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <time.h>
#include "lib/pci_sclp.h"
#include "lib/util_path.h"
static int zpci_sclp_report(char *pci_addr, struct zpci_report_error *report)
{
size_t r_size = sizeof(*report);
char *path;
FILE *fp;
path = util_path_sysfs("bus/pci/devices/%s/report_error", pci_addr);
fp = fopen(path, "w");
free(path);
if (!fp)
return -ENODEV;
if (fwrite(report, 1, r_size, fp) != r_size)
return -EIO;
if (fclose(fp))
return -EIO;
return 0;
}
/**
* Issue an SCLP Adapter Error Notification event with a specific action
* qualifier and optional log data.
*
* The logged data is truncated if needed.
*
* @return the number of bytes of the data which were actually logged
* or a negative value on error.
*/
int zpci_sclp_issue_action(char *pci_addr, int action,
char *data, size_t length, u64 err_log_id)
{
struct zpci_report_error report = {0};
size_t copy_length = 0;
int ret;
/* Data is truncated to fit in the report */
if (data)
copy_length = MIN(length, sizeof(report.data.log_data));
report.header.version = 1;
report.header.action = action;
report.header.length = offsetof(struct zpci_report_error_data, log_data) + copy_length;
report.data.timestamp = (__u64)time(NULL);
report.data.err_log_id = err_log_id;
if (data)
memcpy(report.data.log_data, data, copy_length);
ret = zpci_sclp_report(pci_addr, &report);
if (ret)
return ret;
return copy_length;
}

View File

@@ -80,6 +80,10 @@ Cylinder, Head and Record) or "auto".
\fB - BR_LBA:\fR
Boot record logical block address.
.TP
\fB - SCP_DATA:\fR
SCP data for SCSI, NVMe and ECKD dump devices.
.TP
\fB - VMCMD_1, VMCMD_2 ... VMCMD_8:\fR
Up to eight CP commands, which are executed in case of a kernel panic

View File

@@ -127,7 +127,7 @@ echo "$cmd: Copying kexec"
# Install both binary and required shared libraries
OLDPATH=$PATH
PATH=$OLDPATH:/sbin:/usr/sbin
kexec_bin=$(which kexec)
kexec_bin=$(command -v kexec)
kexec_sos=$(sharedobjs $kexec_bin)
PATH=$OLDPATH

View File

@@ -119,9 +119,9 @@ dobuild()
# append ramdisk if specified
if [ "$ramdisk" != "" ]
then
ramdisk_size=$(du -b $ramdisk | cut -f1)
kernel_size=$(du -b $kernel | cut -f1)
ramdisk_offset=$(du -b $image | cut -f1)
ramdisk_size=$(du -b -L $ramdisk | cut -f1)
kernel_size=$(du -b -L $kernel | cut -f1)
ramdisk_offset=$(du -b -L $image | cut -f1)
cat $ramdisk >> $image
binval=$(mktemp)
dec2be64 $ramdisk_offset > $binval
@@ -135,7 +135,7 @@ dobuild()
# set cmdline
if [ "$parmfile" != "" ]
then
parmfile_size=$(du -b $parmfile | cut -f1)
parmfile_size=$(du -b -L $parmfile | cut -f1)
if [ $parmfile_size -le $MAX_PARMFILE_SIZE ]
then
# Clear any previous parameters

83
opticsmon/Makefile Normal file
View File

@@ -0,0 +1,83 @@
include ../common.mak
TESTS := tests/
libs =$(rootdir)/libzpci/libzpci.a $(rootdir)/libutil/libutil.a
ifneq (${HAVE_OPENSSL},0)
check_dep_openssl:
$(call check_dep, \
"opticsmon", \
"openssl/evp.h", \
"openssl-devel", \
"HAVE_OPENSSL=0")
BUILDTARGET += check_dep_openssl
endif # HAVE_OPENSSL
ifneq (${HAVE_LIBNL3},0)
check_dep_libnl3:
$(call check_dep, \
"opticsmon", \
"netlink/socket.h", \
"libnl3-devel", \
"HAVE_LIBNL3=0")
BUILDTARGET += check_dep_libnl3
endif # HAVE_LIBNL3
ifeq (${HAVE_OPENSSL},0)
all:
$(SKIP) HAVE_OPENSSL=0
install:
$(SKIP) HAVE_OPENSSL=0
else ifeq (${HAVE_LIBNL3},0)
all:
$(SKIP) HAVE_LIBNL3=0
install:
$(SKIP) HAVE_LIBNL3=0
else
ifneq ($(shell sh -c 'command -v pkg-config'),)
LIB_CFLAGS += $(shell pkg-config --silence-errors --cflags libnl-3.0)
LIB_CFLAGS += $(shell pkg-config --silence-errors --cflags libnl-genl-3.0)
LIB_CFLAGS += $(shell pkg-config --silence-errors --cflags libnl-route-3.0)
LIB_CFLAGS += $(shell pkg-config --silence-errors --cflags libcrypto)
LIB_LFLAGS += $(shell pkg-config --silence-errors --libs libnl-3.0)
LIB_LFLAGS += $(shell pkg-config --silence-errors --libs libnl-genl-3.0)
LIB_LFLAGS += $(shell pkg-config --silence-errors --libs libnl-route-3.0)
LIB_LFLAGS += $(shell pkg-config --silence-errors --libs libcrypto)
else
LIB_CFLAGS += -I /usr/include/libnl3/
LIB_LFLAGS += -lnl-route-3 -lnl-genl-3 -lnl-3
LIB_CFLAGS += -I /usr/include/openssl/
LIB_LFLAGS += -lcrypto
endif
ALL_CPPFLAGS += $(LIB_CFLAGS)
LDLIBS += $(LIB_LFLAGS)
BUILDTARGET += opticsmon
all: ${BUILDTARGET}
opticsmon: opticsmon.o optics_info.o optics_sclp.o ethtool.o link_mon.o $(libs)
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 opticsmon $(DESTDIR)$(BINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 opticsmon.8 \
$(DESTDIR)$(MANDIR)/man8
endif # HAVE_OPENSSL3=0 or HAVE_LIBNL3=0
clean:
rm -f *.o *~ opticsmon core
.PHONY: all install clean

279
opticsmon/ethtool.c Normal file
View File

@@ -0,0 +1,279 @@
#include <execinfo.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <linux/netlink.h>
#include <linux/ethtool_netlink.h>
#include <netlink/socket.h>
#include <netlink/msg.h>
#include <netlink/genl/ctrl.h>
#include <netlink/genl/genl.h>
#include <netlink/handlers.h>
#include <netlink/attr.h>
#include "lib/util_libc.h"
#include "ethtool.h"
static int ethtool_nl_cb(struct nl_msg *msg, void *arg)
{
struct nlattr *attrs[ETHTOOL_A_MODULE_EEPROM_DATA + 1] = {};
struct nlmsghdr *hdr = nlmsg_hdr(msg);
struct optics **oi = arg;
int rc = 0;
size_t len;
rc = genlmsg_parse(hdr, 0, attrs, ETHTOOL_A_MODULE_EEPROM_DATA, NULL);
if (rc) {
nl_perror(rc, "genlmsg parse");
return NL_STOP;
}
len = nla_len(attrs[ETHTOOL_A_MODULE_EEPROM_DATA]);
/* Extend optics info*/
if (!(*oi)->raw)
(*oi)->raw = util_malloc(len);
else
(*oi)->raw = util_realloc((*oi)->raw, (*oi)->size + len);
memcpy((*oi)->raw + (*oi)->size, nla_data(attrs[ETHTOOL_A_MODULE_EEPROM_DATA]), len);
(*oi)->size += len;
return NL_OK;
}
int ethtool_nl_connect(struct ethtool_nl_ctx *ctx)
{
struct nl_sock *sk;
int ethtool_id;
int rc = 0;
sk = nl_socket_alloc();
if (!sk) {
nl_perror(NLE_NOMEM, "alloc");
return EXIT_FAILURE;
}
rc = genl_connect(sk);
if (rc) {
nl_perror(rc, "connect");
rc = EXIT_FAILURE;
goto err_free;
}
ethtool_id = genl_ctrl_resolve(sk, ETHTOOL_GENL_NAME);
if (ethtool_id < 0) {
if (ethtool_id == -NLE_OBJ_NOTFOUND)
fprintf(stderr, "Ethtool netlink family not found\n");
else
nl_perror(ethtool_id, "ctrl resolve");
rc = EXIT_FAILURE;
goto err_close;
}
ctx->sk = sk;
ctx->ethtool_id = ethtool_id;
return rc;
err_close:
nl_close(sk);
err_free:
nl_socket_free(sk);
return rc;
}
void ethtool_nl_close(struct ethtool_nl_ctx *ctx)
{
nl_close(ctx->sk);
nl_socket_free(ctx->sk);
}
static int ethtool_nl_put_req_hdr(struct ethtool_nl_ctx *ctx, struct nl_msg *msg, uint8_t cmd,
const char *netdev)
{
struct nlattr *opts;
void *user_hdr;
int rc = 0;
user_hdr = genlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, ctx->ethtool_id, 0,
NLM_F_REQUEST | NLM_F_ACK, cmd, ETHTOOL_GENL_VERSION);
if (!user_hdr) {
fprintf(stderr, "genlmsg put failed\n");
return EXIT_FAILURE;
}
opts = nla_nest_start(msg, ETHTOOL_A_MODULE_EEPROM_HEADER);
if (!opts) {
fprintf(stderr, "nla nest for start failed\n");
return EXIT_FAILURE;
}
NLA_PUT_STRING(msg, ETHTOOL_A_HEADER_DEV_NAME, netdev);
nla_nest_end(msg, opts);
return rc;
nla_put_failure:
nla_nest_cancel(msg, opts);
return EXIT_FAILURE;
}
static int ethtool_nl_put_eeprom_get_attrs(struct nl_msg *msg, uint8_t addr, uint8_t page,
uint32_t offset)
{
NLA_PUT_U32(msg, ETHTOOL_A_MODULE_EEPROM_LENGTH, SFF8636_PAGE_SIZE);
NLA_PUT_U8(msg, ETHTOOL_A_MODULE_EEPROM_PAGE, page);
NLA_PUT_U32(msg, ETHTOOL_A_MODULE_EEPROM_OFFSET, offset);
NLA_PUT_U8(msg, ETHTOOL_A_MODULE_EEPROM_BANK, 0);
NLA_PUT_U8(msg, ETHTOOL_A_MODULE_EEPROM_I2C_ADDRESS, addr);
return 0;
nla_put_failure:
return EXIT_FAILURE;
}
static int ethtool_nl_get_page(struct ethtool_nl_ctx *ctx, const char *netdev, uint8_t addr,
uint8_t page, uint32_t offset)
{
struct nl_msg *msg;
int rc = 0;
msg = nlmsg_alloc();
if (!msg) {
nl_perror(NLE_NOMEM, "nlmsg alloc");
return -ENOMEM;
}
ethtool_nl_put_req_hdr(ctx, msg, ETHTOOL_MSG_MODULE_EEPROM_GET, netdev);
ethtool_nl_put_eeprom_get_attrs(msg, addr, page, offset);
rc = nl_send_auto(ctx->sk, msg);
if (rc < 0) {
nl_perror(rc, "Failed to send netlink message");
rc = -EIO;
goto free_msg;
}
rc = nl_recvmsgs_default(ctx->sk);
if (rc < 0) {
if (rc == -NLE_NODEV) {
rc = -ENODEV;
} else {
nl_perror(rc, "Failed to receive netlink message");
rc = -EIO;
}
goto free_msg;
}
/* Ethtool netlink sends ACKs need to pick them up */
rc = nl_wait_for_ack(ctx->sk);
if (rc < 0) {
nl_perror(rc, "Failed to wait for netlink ack");
rc = -EIO;
goto free_msg;
}
free_msg:
nlmsg_free(msg);
return rc;
}
static int ethtool_nl_get_sfp(struct ethtool_nl_ctx *ctx, const char *netdev, struct optics *oi)
{
int rc = 0;
/* Page A0h upper */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_LOW, 0x0, SFF8636_PAGE_SIZE);
if (rc < 0)
return rc;
/* If page A2h is not present we're done */
if (!(oi->raw[SFF8472_DIAGNOSTICS_TYPE_OFFSET] & SFF8472_DIAGNOSTICS_TYPE_MASK))
return 0;
/* Page A2h lower */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_HIGH, 0x0, 0);
if (rc < 0)
return rc;
/* Page A2h upper */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_HIGH, 0x0, SFF8636_PAGE_SIZE);
if (rc < 0)
return rc;
return 0;
}
static int ethtool_nl_get_qsfp(struct ethtool_nl_ctx *ctx, const char *netdev, struct optics *oi)
{
int rc = 0;
/* Page 00h upper */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_LOW, 0x0, SFF8636_PAGE_SIZE);
if (rc)
return rc;
/* Page 01h */
if (oi->raw[SFF8636_PAGE_OFFSET] & SFF8636_P01H) {
/* Page 01h upper only */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_LOW, 0x1,
SFF8636_PAGE_SIZE);
if (rc < 0)
return rc;
}
/* Page 02h */
if (oi->raw[SFF8636_PAGE_OFFSET] & SFF8636_P02H) {
/* Page 02h upper only */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_LOW, 0x2,
SFF8636_PAGE_SIZE);
if (rc < 0)
return rc;
}
/* Page 03h is present if flatmem is not set */
if (!(oi->raw[SFF8636_STATUS_2_OFFSET] & SFF8636_STATUS_FLAT_MEM)) {
/* Page 03h upper only */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_LOW, 0x3,
SFF8636_PAGE_SIZE);
if (rc < 0)
return rc;
}
return 0;
}
int ethtool_nl_get_optics(struct ethtool_nl_ctx *ctx, const char *netdev, struct optics **oi)
{
int rc = 0;
int type;
*oi = util_zalloc(sizeof(**oi));
nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, ethtool_nl_cb, oi);
/* Page 00h lower */
rc = ethtool_nl_get_page(ctx, netdev, SFF8079_I2C_ADDRESS_LOW, 0x0, 0);
if (rc < 0)
goto out_err_free_oi;
type = optics_type(*oi);
switch (type) {
case OPTICS_TYPE_SFP:
rc = ethtool_nl_get_sfp(ctx, netdev, *oi);
break;
case OPTICS_TYPE_QSFP28:
rc = ethtool_nl_get_qsfp(ctx, netdev, *oi);
break;
};
if (rc < 0)
goto out_err_free_oi;
return rc;
out_err_free_oi:
free(*oi);
*oi = NULL;
return rc;
}

11
opticsmon/ethtool.h Normal file
View File

@@ -0,0 +1,11 @@
#pragma once
#include "optics_info.h"
struct ethtool_nl_ctx {
struct nl_sock *sk;
int ethtool_id;
};
int ethtool_nl_connect(struct ethtool_nl_ctx *ctx);
void ethtool_nl_close(struct ethtool_nl_ctx *ctx);
int ethtool_nl_get_optics(struct ethtool_nl_ctx *ctx, const char *netdev, struct optics **oi);

96
opticsmon/link_mon.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <sys/epoll.h>
#include <sys/signalfd.h>
#include <signal.h>
#include <linux/if.h>
#include <netlink/route/link.h>
#include <netlink/netlink.h>
#include "link_mon.h"
#define MAX_EVENTS 32
static void nl_obj_parsed_cb(struct nl_object *obj, void *arg)
{
struct link_mon_nl_ctx *ctx = arg;
struct rtnl_link *link;
struct zpci_netdev netdev;
if (strcmp(nl_object_get_type(obj), "route/link") != 0)
return;
link = (struct rtnl_link *)obj;
netdev.name = rtnl_link_get_name(link);
netdev.operstate = rtnl_link_get_operstate(link);
ctx->cb(&netdev, ctx->arg);
}
static int nl_rtnl_lnkgrp_cb(struct nl_msg *msg, void *arg)
{
if (nl_msg_parse(msg, &nl_obj_parsed_cb, arg) < 0)
fprintf(stderr, "<<EVENT>> Unknown message type\n");
return NL_STOP;
}
void link_mon_nl_waitfd_read(struct link_mon_nl_ctx *ctx)
{
nl_recvmsgs_default(ctx->sk);
}
int link_mon_nl_waitfd_getfd(struct link_mon_nl_ctx *ctx)
{
return nl_socket_get_fd(ctx->sk);
}
int link_mon_nl_waitfd_create(struct link_mon_nl_ctx *ctx, link_mon_nl_cb cb, void *arg)
{
int ret = 0, rc = 0;
ctx->sk = nl_socket_alloc();
if (!ctx->sk)
return -ENOMEM;
ctx->cb = cb;
ctx->arg = arg;
nl_socket_disable_seq_check(ctx->sk);
nl_socket_modify_cb(ctx->sk, NL_CB_VALID, NL_CB_CUSTOM, nl_rtnl_lnkgrp_cb, ctx);
rc = nl_connect(ctx->sk, NETLINK_ROUTE);
if (rc < 0) {
ret = rc;
goto err_free;
}
rc = nl_socket_add_membership(ctx->sk, RTNLGRP_LINK);
if (rc < 0) {
ret = rc;
goto err_close;
}
rc = rtnl_link_alloc_cache(ctx->sk, AF_UNSPEC, &ctx->cache);
if (rc < 0) {
ret = rc;
goto err_close;
}
nl_cache_mngt_provide(ctx->cache);
return 0;
err_close:
nl_close(ctx->sk);
err_free:
nl_socket_free(ctx->sk);
return ret;
}
void link_mon_nl_waitfd_destroy(struct link_mon_nl_ctx *ctx)
{
nl_cache_free(ctx->cache);
nl_close(ctx->sk);
nl_socket_free(ctx->sk);
}

27
opticsmon/link_mon.h Normal file
View File

@@ -0,0 +1,27 @@
/*
* Copyright IBM Corp. 2024
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#pragma once
#include <stdint.h>
#include <linux/if.h>
#include "lib/pci_list.h"
typedef void (*link_mon_nl_cb)(struct zpci_netdev *, void *arg);
struct link_mon_nl_ctx {
/* private fields */
struct nl_sock *sk;
struct nl_cache *cache;
link_mon_nl_cb cb;
void *arg;
};
int link_mon_nl_waitfd_create(struct link_mon_nl_ctx *ctx, link_mon_nl_cb cb, void *arg);
void link_mon_nl_waitfd_read(struct link_mon_nl_ctx *ctx);
void link_mon_nl_waitfd_destroy(struct link_mon_nl_ctx *ctx);
int link_mon_nl_waitfd_getfd(struct link_mon_nl_ctx *ctx);

171
opticsmon/optics_info.c Normal file
View File

@@ -0,0 +1,171 @@
#include <stdlib.h>
#include "optics_info.h"
#define OPTICS_TYPE_OFFSET 0x0
#define OPTICS_SFP_LOS_IMPLEMENTED_OFFSET 0x41
#define OPTICS_SFP_LOS_IMPLEMENTED_MASK 0x2
#define OPTICS_SFP_A2H_OFFSET 0x100
#define OPTICS_SFP_LOS_OFFSET (OPTICS_SFP_A2H_OFFSET + 0x6e)
#define OPTICS_SFP_DATA_NOT_READY_MASK 0x1
#define OPTICS_SFP_TX_FAULT_MASK 0x4
#define OPTICS_SFP_RX_LOS_MASK 0x2
#define OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET 0xC3
#define OPTICS_QSFP28_TX_LOS_IMPLEMENTED_MASK 0x2
#define OPTICS_QSFP28_TX_FAULT_IMPLEMENTED_MASK 0x8
#define OPTICS_QSFP28_LOS_OFFSET 0x3
#define OPTICS_QSFP28_LOS_MASK 0xf
#define OPTICS_QSFP28_TX_LOS_MASK 0xf0
#define OPTICS_QSFP28_TX_LOS_SHIFT 0x4
#define OPTICS_QSFP28_TX_FAULT_OFFSET 0x4
#define OPTICS_QSFP28_TX_FAULT_MASK 0xf
const char *optics_type_str(enum optics_type type)
{
switch (type) {
case OPTICS_TYPE_UNKNOWN:
return "unknown";
case OPTICS_TYPE_SFP:
return "SFP/SFP+/SFP28";
case OPTICS_TYPE_QSFP28:
return "QSFP28";
};
return "n.a.";
}
enum optics_type optics_type(struct optics *oi)
{
if (!oi || !oi->raw || oi->size < OPTICS_TYPE_OFFSET + 1)
return OPTICS_TYPE_UNKNOWN;
switch (oi->raw[OPTICS_TYPE_OFFSET]) {
case (uint8_t)OPTICS_TYPE_SFP:
return OPTICS_TYPE_SFP;
case (uint8_t)OPTICS_TYPE_QSFP28:
return OPTICS_TYPE_QSFP28;
default:
return OPTICS_TYPE_UNKNOWN;
};
}
bool optics_los_implemented(struct optics *oi)
{
enum optics_type type = optics_type(oi);
uint8_t implemented;
if (type == OPTICS_TYPE_SFP) {
if (oi->size < OPTICS_SFP_LOS_IMPLEMENTED_OFFSET + 1)
return false;
implemented = oi->raw[OPTICS_SFP_LOS_IMPLEMENTED_OFFSET];
return !!(implemented & OPTICS_SFP_LOS_IMPLEMENTED_MASK);
} else if (type == OPTICS_TYPE_QSFP28) {
if (oi->size < OPTICS_QSFP28_LOS_OFFSET + 1)
return false;
if (oi->size < OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET)
return false;
implemented = oi->raw[OPTICS_QSFP28_LOS_IMPLEMENTED_OFFSET];
/*
* No RX LoS implemented flag take TX LOS implemented like
* ethtool
*/
return !!(implemented & OPTICS_QSFP28_TX_LOS_IMPLEMENTED_MASK);
}
return false;
}
enum optics_los optics_rx_los(struct optics *oi)
{
enum optics_los los = OPTICS_UNKNOWN_LOS;
enum optics_type type = optics_type(oi);
if (!optics_los_implemented(oi))
return los;
if (type == OPTICS_TYPE_SFP) {
los = oi->raw[OPTICS_SFP_LOS_OFFSET];
if (los & OPTICS_SFP_DATA_NOT_READY_MASK)
return OPTICS_UNKNOWN_LOS;
if (los & OPTICS_SFP_RX_LOS_MASK)
return OPTICS_LOS;
else
return OPTICS_NO_LOS;
} else if (type == OPTICS_TYPE_QSFP28) {
los = oi->raw[OPTICS_QSFP28_LOS_OFFSET];
if (los & OPTICS_QSFP28_LOS_MASK)
los = OPTICS_LOS;
else
los = OPTICS_NO_LOS;
}
return los;
}
const char *optics_los_str(enum optics_los los)
{
switch (los) {
case OPTICS_LOS:
return "yes";
case OPTICS_NO_LOS:
return "no";
case OPTICS_UNAVAILABLE_LOS:
return "unavailable";
default:
return "unknown";
}
}
enum optics_los optics_tx_fault(struct optics *oi)
{
enum optics_los los = OPTICS_UNKNOWN_LOS;
enum optics_type type = optics_type(oi);
if (!optics_los_implemented(oi))
return los;
if (type == OPTICS_TYPE_SFP) {
los = oi->raw[OPTICS_SFP_LOS_OFFSET];
if (los & OPTICS_SFP_DATA_NOT_READY_MASK)
return OPTICS_UNKNOWN_LOS;
if (los & OPTICS_SFP_TX_FAULT_MASK)
return OPTICS_LOS;
else
return OPTICS_NO_LOS;
} else if (type == OPTICS_TYPE_QSFP28) {
los = oi->raw[OPTICS_QSFP28_TX_FAULT_OFFSET];
if (los & OPTICS_QSFP28_TX_FAULT_MASK)
los = OPTICS_LOS;
else
los = OPTICS_NO_LOS;
}
return los;
}
enum optics_los optics_tx_los(struct optics *oi)
{
enum optics_los los = OPTICS_UNKNOWN_LOS;
enum optics_type type = optics_type(oi);
if (!optics_los_implemented(oi))
return los;
if (type == OPTICS_TYPE_SFP) {
return OPTICS_UNAVAILABLE_LOS;
} else if (type == OPTICS_TYPE_QSFP28) {
los = oi->raw[OPTICS_QSFP28_LOS_OFFSET];
if (los & OPTICS_QSFP28_TX_LOS_MASK)
los = OPTICS_LOS;
else
los = OPTICS_NO_LOS;
}
return los;
}
void optics_free(struct optics *oi)
{
free(oi->raw);
free(oi);
}

49
opticsmon/optics_info.h Normal file
View File

@@ -0,0 +1,49 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#define SFF8079_I2C_ADDRESS_LOW 0x50
#define SFF8079_I2C_ADDRESS_HIGH 0x51
#define SFF8472_DIAGNOSTICS_TYPE_OFFSET 0x5C
#define SFF8472_DIAGNOSTICS_TYPE_MASK (1 << 6)
#define SFF8636_PAGE_SIZE 0x80
#define SFF8636_QSFP28_LENGTH 0x100
#define SFF8636_STATUS_2_OFFSET 0x02
#define SFF8636_STATUS_FLAT_MEM (1 << 2)
#define SFF8636_PAGE_OFFSET 0xC3
#define SFF8636_P01H (1 << 6)
#define SFF8636_P02H (1 << 7)
enum optics_type {
OPTICS_TYPE_UNKNOWN = 0x0, /* Unknown or unsupported */
OPTICS_TYPE_SFP = 0x3, /* SFP/SFP+/SFP28 and later with SFF-8472 management interface */
OPTICS_TYPE_QSFP28 = 0x11 /* QSFP28 (SFF-8665 et al.)*/
};
enum optics_los {
OPTICS_NO_LOS = 0x0,
OPTICS_LOS = 0x1,
OPTICS_UNKNOWN_LOS = 0x2,
OPTICS_UNAVAILABLE_LOS = 0x3,
};
struct optics {
size_t size;
uint8_t *raw;
};
enum optics_type optics_type(struct optics *oi);
const char *optics_type_str(enum optics_type type);
const char *optics_los_str(enum optics_los los);
enum optics_los optics_rx_los(struct optics *oi);
enum optics_los optics_tx_los(struct optics *oi);
enum optics_los optics_tx_fault(struct optics *oi);
void optics_free(struct optics *oi);

Some files were not shown because too many files have changed in this diff Show More