Compare commits

...

58 Commits

Author SHA1 Message Date
Jan Höppner
d8b8114e6f New release s390-tools-2.21.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-20 13:29:04 +02:00
Mikhail Zaslonko
c4e4b926b4 zdump/dfi: Fix segfault due to double free
The problem can happen when dfi_s390mv_init_gen() returns with an error
code to dfi_init() in dfi.c.
Double free condition occurs on zg_close() call at the end of the
while loop in dfi_init() if zg_close() has already been called for the
same file handle at the end of open_dump() function in scope of
dfi_s390mv_init_gen() processing.
This global file handle is not closed during init() call for any
other dump formats. Since it is not reopened/reused after open_dump() call
during multi-volume dump initialization, we should not close it at all.

The problem can be reproduced in the following steps:

1) Install multi-volume dump tool

   # zipl -M mvdump.conf
   Dump target: 2 partitions with a total size of 4732 MB.
   Warning: All information on the following partitions will be lost!
      /dev/dasdb2
      /dev/dasdb3
   Do you want to continue creating multi-volume dump partitions (y/n)?y
   Done.

2) Run zgetdump -i using device (not partition) as a parameter without
   taking actual dump.

   # zgetdump -i /dev/dasdb
   free(): double free detected in tcache 2
   Aborted (core dumped)

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>
2022-04-19 18:37:17 +02:00
Niklas Schnelle
6324f62da7 zpcictl: Add option to trigger firmware reset
With "zpcictl --reset DDDD:BB:FF.F" now causing a fully Linux driven
reset where the Linux kernel does an explicit device driver unbind,
disable and re-enable, let's also expose a way to instead have firmware
perform a device reset by issuing an SCLP with SCLP_ERRNOTIFY_RESET.

When firmware is done resetting the device it will then issue an error
notification with PCI Error Code 0x3a indicating successful reset, which
will subsequently cause the new kernel based automatic recovery
mechanism to perform recovery in coordination with the device driver.
This allows resetting devices without unbinding them from their device
driver and thus without losing related block devices or network
interfaces. This may also be used to test the automatic recovery
mechanism.

Reviewed-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-12 17:18:26 +02:00
Niklas Schnelle
3ade063ea2 zpcictl: Fix race of SCLP reset and Linux recovery
Currently "zpcictl --reset DDDD:BB:FF.F" issues an SCLP call with
SCLP_ERRNOTIFY_AQ_RESET followed by a Linux driven device reset via the
recover sysfs attribute. The latter was introduced with commit
bc0d40c580 ("zpcictl: Initiate recover after reset") because the
firmware driven reset leaves the device in the error state. Now with the
addition of transparent PCI recovery however the situation has changed
as Linux will not leave the device in the error state after the reset
but will instead initiate its automatic recovery flow. With that however
the two mechanisms, automatic PCI recovery and the zpcictl triggered
recovery attribute handler will race against each other.

In practice this is harmless as the automatic recovery is serialized
with the recover attribute and whichever wins the race will do the reset.
The losing side will detect that the original device was removed and
will refrain from causing a double reset.

Letting both mechanisms race against each other is not predictable
behavior though so instead of SCLP_ERRNOTIFY_AQ_RESET issue
a SCLP_ERRNOTIFY_AQ_REPORT_ERROR that will report a device error to the
Support Element but not cause a reset and then predictably reset via the
recover sysfs attribute. If instead a firmware driven reset followed by
the automatic recovery flow is desired the new "--reset-fw" option may
be used.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Niklas Schnelle <schnelle@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-12 17:18:26 +02:00
Viktor Mihajlovski
92a3b30323 genprotimg/check_hostkeydoc: allow to disable default issuer check
The default issuer check may fail if the to-be-verified host key
document was issued and signed by an entity not known at the point
in time check_hostkeydoc was released.

In order to allow verification of the chain of trust for an unknown
but otherwise valid issuer, check_hostkeydoc can be called with
the -d command line option.

This commit also enhances the help text by briefly describing the
command line options and fixes a typo.

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Viktor Mihajlovski
673ff375d9 genprotimg/check_hostkeydoc: relax default issuer check
While the original default issuer's organizationalUnitName (OU)
was defined as "IBM Z Host Key Signing Service", any OU ending
with "Key Signing Service" is considered legal.

Let's relax the default issuer check by stripping off characters
preceding "Key Signing Service".

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Ingo Franzki
4e2ebe0370 libseckey: Fix re-enciphering of EP11 secure key
The re-enciphering of EP11 asymmetric secure keys does not work.
First, the result of the re-encipher operation of the private key
part must be copied back into the user supplied key token buffer.
Second, the public key part, i.e. the MACed SubjectPublicKeyInfo
(SPKI) structure must also be re-enciphered (i.e. re-MACed), since
the MAC is calculated with the EP11 master key.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Marc Hartmayer
78b053326c genprotimg: remove DigiCert root CA pinning
Remove the DigiCert root CA pinning. The root CA used for the chain of trust can
change in the future therefore let's remove this check. If someone wants to
enforce the usage of a specific root CA it can be selected by the genprotimg
command line option `--root-ca $CA`. Make it transparent to the user which root
CA is actually being used by printing the subject name of the root CA to stdout
in verbose mode.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Reviewed-and-tested-by: Nico Boehr <nrb@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Peter Oberparleiter
ab06a5d88a cpictl: Handle excessive kernel version numbers
Some development kernel versions provide an 8-digit date number like
"20220325" in place of the second kernel sublevel, while the data
format used to send this information to the HMC only supports 16 Bit
numbers. As a result, the HMC displays a seemingly random sublevel
number.

Fix this by replacing excessive sublevel numbers with 0 to ensure that
these numbers are handled consistently.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Viktor Mihajlovski
a0a71efde0 fdasd: Fix endless menu loop on EOF
Hitting CTRL-D anywhere will cause fdasd to go into an endless loop
displaying the main menu over and over again. Killing fdasd (e.g.
via CTR-C) is the only way out.
The issue is that read_line() is just ignoring the resulting EOF
condition on stdin. Subsequent invocations of read_line() will return
immediately and thus cause the loop. A simple fix is to reset stdin
after EOF. A caller of read_line() will see the same behavior as for
EOL with no input.

Signed-off-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Steffen Maier
b4b2202ff5 dbginfo.sh: collect all places where modprobe.d config files could exist
This can now include /lib/modprobe.d/10-unsupported-modules.conf

Strictly speaking, modprobe would only consider *.conf files inside
those directories, but for consistency with the already existing
collection of /etc/modprobe.d instead of /etc/modprobe.d/*.conf,
do the same for the added missing locations.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Steffen Maier
a26f61c4fe dbginfo.sh: collect config files of systemd-modules-load.service
Recent multipath-tools can depend on this.
a1eabea75e
("multipathd.service: drop ExecStartPre for loading dm-multipath")
92f0893ac1
("multipath-tools: install modules-load.d/multipath.conf")

This can now also include /usr/lib/modules-load.d/s390-pkey.conf
Complements v2.8.0 commit
dffd41943e ("pkey: Support autoloading kernel pkey module").

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-06 16:11:19 +02:00
Javier Martinez Canillas
a28b396d9e zipl: make IPL sections defined with BLS to inherit a target field
The target field is required for IPL sections, but the ones populated from
BLS snippets did not have this field. This was only working when using BLS
snippets because IPL sections inherit the target field with "defaultauto".

But that's not the case when using a menu, for example the following zipl
configuration will fail if it's used along with BLS defined IPL sections:
fail when running the zipl tool:

  [defaultboot]
  defaultmenu = menu1

  :menu1
  target = /boot
  1 = linux
  2 = test
  default = 1
  prompt = 1
  timeout = 0

Because "linux" and "test" will be defined using BLS snippets and these
don't have an option to define target fields. Let's make these to always
inherit a target field, either from the [defaultboot] section or a menu
section if there's a defaultmenu defined.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/111
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/113
[hoeppner@linux.ibm.com: Fixed a couple of style issues]
Reported-by: Renaud Métrich <rmetrich@redhat.com>
Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Tested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-18 14:41:43 +01:00
Juergen Christ
0012eaf68e zcryptctl: Fix some typos
Fix typos in usage and error messages.

Signed-off-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-18 14:41:21 +01:00
Juergen Christ
c22d282e67 zcryptctl: Add control domain handling
Support control domain handling for custom zcrypt device nodes.

Signed-off-by: Juergen Christ <jchrist@linux.ibm.com>
Reviewed-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-18 14:41:21 +01:00
Marc Hartmayer
071522f7d2 editorconfig: py/yaml: use spaces for indentation
Use spaces for the indentation of Python and YAML files.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-18 14:41:21 +01:00
Marc Hartmayer
ae7217806b common.mak: remove LINK and LINKXX
Now that we've concluded that the compiler is used for calling the actual
linker, it doesn't make much sense to select a different compiler for linking.
Even worse, it's prone to error. A naive user might try to compile s390-tools
using clang as follows:

  $ make -C genprotimg CC=clang
  ...
  CC      genprotimg/src/utils/curl.o
  LINK    genprotimg/src/genprotimg
  /usr/bin/ld: genprotimg.o: `stderr@@GLIBC_2.2' non-PLT reloc for symbol defined in shared library and accessed from executable (rebuild file with -fPIC ?)
  /usr/bin/ld: final link failed: bad value
  collect2: error: ld returned 1 exit status

Therefore it makes sense to use the same compiler for linking as well.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Marc Hartmayer
9f6150db34 common.mak: D=1: use -g3 and -ggdb3 compiler options
Level 3 includes extra information, such as macro definitions.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Marc Hartmayer
b39bdfbf6e common.mak: W=1: add multiple compiler warning options
Add multiple compiler warning options if `W=1` is set.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Jan Höppner
71fe58111c s390-tools: Clean up NO_PIE_* flags
Remove NO_PIE_LINKFLAGS and follow the naming convention by using
LDFLAGS for linker flags. Replace all occurrences accordingly.

Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Jan Höppner
5e46632767 zipl: Use the compiler for linking instead of ld
Instead of directly calling ld, it is recommended to call the compiler
to do the linking. Do that and adapt the linker flags accordingly.

This also fixes build issues with newer binutils as -no-pie has never
been a valid option for ld itself.

See:
https://sourceware.org/bugzilla/show_bug.cgi?id=27050
https://bugs.launchpad.net/ubuntu/+source/s390-tools/+bug/1907789

LD has no user anymore and is removed.

Closes: https://github.com/ibm-s390-tools/s390-tools/pull/106
Reported-by: Lukas Märdian <lukas.maerdian@canonical.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Steffen Maier
1bd64f5b0f dbginfo.sh: sort list of environment variables for readability
The "detour" with NUL terminated records ensures that sorting
works as expected for environment variables with values containing
one or more lines and thus '\n' as regular record separator.

Reviewed-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Steffen Maier
d311506dc4 dbginfo.sh: add hex FCP LUN to multipath FC addressing
Make use of multipath-tools 0.8.9 commit
("libmultipath: add %L path wildcard for 64-bit hex LUN")
260d7cb411 .
Multipath-tools versions that do not know the format wildcard simply
ignore it and expand to an empty string, so it's backwards compatible.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Steffen Maier
08e4520a4f dbginfo.sh: add multipath info to map paths to FC addressing and prio group
Eases mapping of multipath paths and FCP by-path information
without having to use different tool output and correlate,
such as "multipathd -k'show topo'" and "lszfcp -D".

Possibly the HBA is reported as "[undef]" for zfcp
[without multipath-tools 0.8.9 commit
 ("libmultipath: support host adapter name lookup for s390x ccw bus")
 852a1dfd94 ]
and the FCP LUN needs to be manually converted from the SCSI LUN in h:c:i:l.

While at it, append correlation information for block device name and
major:minor, as well as all information from a standard 'show paths',
which is the path state 3-tuple and next_check,
plus the number of path failures.

Example output:

$ multipathd -k'show paths format "%w|%a|%r|%p|%i|%d|%D|%t|%T|%o|%0|%C"'
uuid                             |host adapter|target WWPN       |pri|hcil     |dev|dev_t|dm_st |chk_st|dev_st |failures|next_check
3600507640081818ab00000000000025e|[undef]     |0x500507680b2581fa|10 |0:0:0:606|sdb|8:16 |active|ready |running|0       |XXXXXX.... 13/20
3600507640081818ab00000000000025e|[undef]     |0x500507680b2581fb|50 |0:0:1:606|sdc|8:32 |active|ready |running|0       |XX........ 4/20
3600507640081818ab00000000000025e|[undef]     |0x500507680b2681fa|10 |1:0:0:606|sdd|8:48 |active|ready |running|0       |XXXX...... 8/20
3600507640081818ab00000000000025e|[undef]     |0x500507680b2681fb|50 |1:0:1:606|sde|8:64 |active|ready |running|0       |XXXXXXX... 15/20

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Harald Freudenberger
46fd42af0c lszcrypt: new option to show the serial numbers of CCA and EP11 cards
The new option -s, long --serial shows the serial numbers of
CCA and EP11 cards.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Harald Freudenberger
a8b0d7ace8 lszcrypt: new options to filter cards/queues only
New options:
  --cardonly
  --queueonly
which filter the output to show only card or queue information.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Harald Freudenberger
a29b3c8997 lszcrypt: new options to show only accel, cca or ep11 cards/queues
New options:
  --accelonly
  --ccaonly
  --ep11only
which restrict the output to only cards/queues with the given mode.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Harald Freudenberger
27dce3317a lszcrypt: add support for checkstop state
Newer kernel show a sysfs attribute chkstop which displays
the checkstop state of a crypto card. This patch enables
support for lszcrypt to display the checkstop state.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:49 +01:00
Harald Freudenberger
4382901daa lszcrypt: show AP bus msg size limit capability
If there is a max_msg_size attribute for the card
the lszcrypt -c option will show this limit as
  AP bus max message size limit xx Kb

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:45 +01:00
Harald Freudenberger
bcbb6fcae6 zcryptstats: add CEX8 support
Add the CEX8 crypto card to the list of known crypto cards.

Signed-off-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>
2022-03-09 12:11:45 +01:00
Harald Freudenberger
b16a6d4fe1 lszcrypt: add CEX8S support
Recognize AP type 14 as CEX8S crypto express card.

Signed-off-by: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:11:42 +01:00
Benjamin Block
0d15a07c0a chreipl-fcp-mpath: bundle a pre-cooked version of the man page
On several distributions `pandoc` is not available via the default
repositories, and thus not available in the build environments for the
distribution packages. That means, the man page can't be bundled along
with the packages generated for those distributions.

But since this is a valuable asset for some users, instead of requiring
`pandoc` in order to have a man page be generated during the build, so it
can be installed, bundle a pre-cooked version that corresponds to the
current version of the `README.md` file. This way, the man page can always
be packaged, and is now always installed, even if `ENABLE_DOC` is set to
`0` (the default).

This also means, whenever the `README.md` file is changed, the bundled
man page needs to be regenerated, so it stays in sync. As a safeguard
we also add a checksum of the `README.md` file that is regenerated along
with the man page. This checksum is tested even when `pandoc` is not
available, and the user is notified whenever it runs out of sync (with a
hint as to how to remedy it).

Nothing changes for the compile/installation workflow, if `ENABLE_DOC` is
set to `1`.

Suggested-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-03-09 12:08:24 +01:00
Marc Hartmayer
5394cd363c genprotimg: add PV guest dump support
Sometimes dumping a virtual machine from the outside is the only way to
get the data that is needed. This can be the case if a dumping mechanism
like kdump hasn't been configured or data needs to be fetched at a
specific point. Dumping a protected guest from the outside without help
from FW/HW doesn't yield sufficient data to be useful. Hence we now
introduce Protected Virtualization (PV) dump support.

The PV dump support works by integrating the firmware into the dump
process. New Ultravisor calls are used to initiate the dump process,
dump cpu data, dump memory state and lastly complete the dump process.
The guest's data is fully encrypted and can only be decrypted by the
entity that owns the customer communication key for the dumped guest.
Also dumping needs to be allowed via a flag in the SE header.

This patch adds support for PV guest dumps to genprotimg. To prepare a
PV image in order that the PV guest can later be dumped from the
outside, the user has to provide a customer communication key used for
the dump process and he has to set the corresponding control flag. For
specifying the customer communication key a new command line option
`--comm-key` is added and for enabling/disabling the control flag the
command line options `--enable-dump` and `--disable-dump` are added.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Viktor Mihajlovski <mihajlov@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 17:06:33 +01:00
Marc Hartmayer
0906293cd8 genprotimg: --enable-pckmo and --disable-pckmo are mutually exclusive
Declare `--enable-pckmo` and `--disable-pckmo` as mutually exclusive.
Let's define a helper macro for this which allows an easier definition
of mutually exclusive command line flags.

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>
2022-02-21 17:06:33 +01:00
Marc Hartmayer
a9e13a2d69 genprotimg: introduce macro for the control flags and sort them
Introduce a private macro for the calculation of the control flags and
sort the flags by bit value.

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>
2022-02-21 17:06:33 +01:00
Philipp Kern
ee2c6d4160 zipl: Allow optional entries that are left out when files are missing.
Debian carried a patch forever that allowed zipl to run even if not all
menu items had files attached. If a required file is missing for an
entry (e.g. vmlinuz.old or initrd.img.old) and it is marked as
"optional" in the config, the section will be skipped. This allows
zipl to install after bootstrapping, as booting on s390 still relies
on the kernel/initrd symlinks in the root directory.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/2
Signed-off-by: Philipp Kern <pkern@debian.org>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
[sth@linux.ibm.com: adapted patches to latest changes, merged patches]
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Alexander Egorenkov
455ad953a9 zdump: Fix /dev/mem reading
This commit makes zgetdump work with /dev/mem again.
zg_seek() should not attempt to verify the given offset for devices before
issuing lseek() because special devices like /dev/mem report 0 in
stat.sb_size.

$ zgetdump -i /dev/mem
zgetdump: Trying to seek past file end "/dev/mem"

Fixes: 11e78cada5 ("zdump: catch attempts to seek past end of file in zg_seek()")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
02a0d12988 dbginfo.sh: (re)group commands by block/scsi
This change will group the commands executed for block and scsi devices
into a section with a comment.
By grouping, we intend to enhance the handling in our runtime.out file
and help to understand the purpose of command groups.

In addition we did get feedback for promoting some commands to the top.

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
be47b51890 dbginfo.sh: (re)group commands by z device
This change will group the commands executed for Z device subsystem
into a section with a comment.
By grouping, we try to enhance the handling in our runtime.out file and
help to understand the purpose of command groups.

In addition we did get feedback for promoting some commands to the top.
lspci -t was added on request of SMEs during the discussions

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Acked-by: Nicklas Schnelle <Niklas.Schnelle@ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
2677a4182d dbginfo.sh: (re)group commands by system state
This change will group the commands executed for overall state into a
first section with a comment.
By grouping, we intend to enhance the handling in our runtime.out file
and help to understand the purpose of command groups.

In addition we did get feedback for promoting some commands to the top.

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
812df795c3 dbginfo.sh: (re)group commands by topic
This change will group the commands executed for crypto, special SW or
specific for a distro into sections with a comment.
By grouping, we intend to enhance the handling in our runtime.out file
and help to understand the purpose of command groups.

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
a0d6edf03c dbginfo.sh: (re)group commands by long output
This change will group the commands with long output into two
sections with a comment.
By grouping, we intend to enhance the handling in our runtime.out file
and help to understand the purpose of command groups.

We did get feedback for moveing some independent long output files to
the end for speed up the scrolling in the upper parts.
Files which already have a separate output file are bundled in a
separate group at the end.

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
81920f7cfd dbginfo.sh: (re)group commands for network
This change will regroup & reorder the commands executed for network.
By grouping, we intend to enhance the handling in our runtime.out file
and help to understand the purpose of command groups.

In addition we did get feedback for promoting some commands to the top.
"ip -br a" was added on request of SMEs during the discussions

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Acked-by: Sandy Winter <WINTERA@de.ibm.com>
Acked-by: Stefan Raspl <stefan.raspl@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Thomas Richter
40dd63e2ac cpumf/lshwc: Fix missing CPU list invocation
When lshwc is invoked with
 # ./lshwc -a :P
 lshwc: ioctl S390_HWCTR_START: Invalid argument
 #
it returns an error instead of listing all problem state counters
of all online CPUs. The reason is an empty CPU list when it is
omitted and only a counter set is specified. Fix this.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
a8579a0727 dbginfo.sh: replace indents with 8char tab
cleanup of indents according to the guidlines
this patch has no logic changes

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
2ab27bdaf2 dbginfo.sh: update copyright date
adjust second year field on recent updates

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Thomas Richter
03fef264bd cpumf: Remove unneeded defines.h
With the introduction of libcpumf/libcpumf.a library there is no need
for this file anymore. Its defines have been moved to
include/lib/libcpumf.h are obsolete.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Thomas Richter
927a48e607 cpumf/lshwc: Use libcpumf.a library functions
Use new library functions defined in libcpumf/libcpumf.a

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Thomas Richter
fbcb3f384a cpumf/chcpumf-lscpumf: Use libcpumf.a library functions
Use new library functions defined in libcpumf/libcpumf.a

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Thomas Richter
c7fe21b019 libcpumf: Create library libcpumf for CPU Measurement functions
Add a function to detect the existence of the CPU Measurement Sampling
Facility on a system.
Add a function which extracts the CPU Measurement Sampling Facility
characteristics on a system, such as
 - minimum sample speed
 - maximum sample speed
 - current CPU speed
 - basic sample size in bytes
 - diagnostic sample size in bytes

Add a function to detect the existence of the CPU Measurement Sampling
Facility on a system and return the current sampling buffer management
characteristics, such as:
 - minimum supported sampling buffer size
 - maximum supported sampling buffer size

Add a function to detect the existence of the CPU Measurement Counting
Facility on a system.
Add a function which extracts the CPU Measurement Counting Facility
characteristics on a system, such as
 - counter first version number
 - counter second version number
 - counter set authorization level

Add a function the returm the PMU type number of a CPU Measurement
Facility device driver. These numbers may vary between boots.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Sumanth Korikkar <sumanthk@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
50a4740443 dbginfo.sh: replace "which" by builtin command "type" for cmd checks
'which' tool is packaged separately from other core tools and there will
likely be scenarios where this check will fail because 'which' is
unavailable.
The "type" is builtin itself and should solve this problem.
For a built in command, we will not suppress error out -> removing 2>&1.
On this replace - in call_run_command - get cmd_type as variable only once

Reported by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
164d4817ec dbginfo.sh: check existence of dump2tar before executing
a missing dump2tar command did show misleading error messages
now check it and give clear messages

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
abec41f514 dbginfo.sh: alphabetic order of log- and config files
as order itself does not matter for collection of log and config files,
we decided to use alphabetic order for better maintenance

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Reviewed-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
fcb503ea3c dbginfo.sh: sync excludes in sysfs data collection
critical paths in dump2tar data collection have been already excluded -
this update will sync the excludes in the fall back, running in case
dump2tar is missing or failing on a system
By this we also sync the filtering to match exact the same pattern.

Reported by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Sa Liu <saliu@de.ibm.com>

Fixes: 12c84469fd ("dbginfo.sh: exclude reading page_idle/bitmap sysfs
attribute")
Fixes: b627b8d8e1 ("Initial s390-tools-2.0.0 import")

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
2eea614bbf dbginfo.sh: unify indents - prettify code
adopt all indents to have the same setting overall - NO logic changes !
tooling: vim used with setting "shiftwidth=8",expandtab,autoindent
  commands "gg=G",":retab"
  some additional line brakes to stay below 100 chars
  and one line added manual before "collect_procfs"

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Joern Siglen
3a13cb43f2 dbginfo.sh: unify console output
use same look over all output

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Peter Oberparleiter
e8fca95592 zdev: Fix off-by one errors in cio_ignore handling
chzdev fails to generate correct cio_ignore udev-rules for a CCW device
with device number 0xffff. Also chzdev aborts due to a segmentation
fault when a CCW device with CSSID 0xff is configured. Both issues are
caused by off-by-one errors while interpreting CCW device ID limits
CSSID_MAX, SSID_MAX and DEVNO_MAX.

Fix these errors by correctly interpreting CCW device ID limits.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-21 12:54:34 +01:00
Jan Höppner
b5604850ab Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-02-04 12:34:47 +01:00
55 changed files with 2517 additions and 1223 deletions

View File

@@ -11,3 +11,11 @@ tab_width = 8
[*.sh]
shell_variant = bash # used by `shfmt`
[*.y{a,}ml]
indent_style = space
indent_size = 2
[*.py]
indent_style = space
indent_size = 4

View File

@@ -5,7 +5,7 @@ List of all individuals having contributed content to s390-tools
- Alexandra Winter
- Alexey Ishchuk
- Andreas Herrmann
- Andre Wild
- André Wild
- Antoinette Kaschner
- Arnd Bergmann
- Axel Wirbser
@@ -19,6 +19,7 @@ List of all individuals having contributed content to s390-tools
- Clemens von Mann
- Colin Walters
- Dan Horak
- Dan Horák
- Despina Papadopoulou
- Dimitri John Ledkov
- Eberhard Pasch
@@ -53,7 +54,7 @@ List of all individuals having contributed content to s390-tools
- Ingo Franzki
- Ingo Tuchscherer
- Jan Glauber
- Jan Hoeppner
- Jan Höppner
- Jan Willeke
- Jason J. Herne
- Javier Martinez Canillas

View File

@@ -1,6 +1,39 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.20.0 (2021-02-04)__
* __v2.21.0 (2022-04-20)__
For Linux kernel version: 5.17
Add new tools / libraries:
- libcpumf: Create library libcpumf for CPU Measurement functions
Changes of existing tools:
- chreipl-fcp-mpath: bundle a pre-cooked version of the manpage for build
environments without access to `pandoc`
- dbginfo.sh: Add multipath info to map paths to FC addressing and prio group
- dbginfo.sh: Collect config files of systemd-modules-load.service
- dbginfo.sh: Sort list of environment variables for readability
- dbginfo.sh: Replace "which" by builtin command "type"
- dbginfo.sh: Rework script formatting (indents, order)
- dbginfo.sh: Update sysfs collection (excludes, messages)
- genprotimg: Add Protected Virtualization (PV) dump support
- genprotimg: Remove DigiCert root CA pinning
- lszcrypt: Add CEX8S support
- zcryptctl: Add control domain handling
- zcryptstats: Add CEX8 support
- zipl: Allow optional entries that are left out when files are missing
- zipl: make IPL sections defined with BLS to inherit a target field
- zpcictl: Add option to trigger firmware reset
Bug Fixes:
- cpictl: Handle excessive kernel version numbers
- dbginfo.sh: Collect all places where modprobe.d config files could exist
- fdasd: Fix endless menu loop on EOF
- zdump/dfi: Fix segfault due to double free
- zdump: Fix /dev/mem reading
- zpcictl: Fix race of SCLP reset and Linux recovery
* __v2.20.0 (2022-02-04)__
For Linux kernel version: 5.16

View File

@@ -10,7 +10,7 @@ include common.mak
#
BASELIB_DIRS = libutil libseckey
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
libkmipclient
libkmipclient libcpumf
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \

View File

@@ -478,5 +478,6 @@ the different tools are provided:
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
make invocation to build a man page and render the README.md as HTML, make
further requires pandoc and GNU awk for the build process.
make invocation to build a fresh man page (instead of using the pre-cooked
version) and render the README.md as HTML, make further requires pandoc and
GNU awk for the build process.

View File

@@ -0,0 +1 @@
8e604dab39577678bc9f24bfe5e2ee35354b2f4b1759edd16093157b1ecce9d3 README.md

View File

@@ -9,4 +9,3 @@
/README.html
/README.pdf
/chreipl-fcp-mpath.md
/chreipl-fcp-mpath.7

View File

@@ -11,6 +11,8 @@
# - chreipl-fcp-mpath.mak
# bash:
# - bash
# GNU coreutils:
# - sha256sum
# If $(ENABLE_DOC) is `1`:
# GNU awk:
# - gawk
@@ -100,20 +102,41 @@ chreiplzfcpmp-doc-man-meta = \
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
chreipl-fcp-mpath.7: .chreipl-fcp-mpath.7.cksum
.INTERMEDIATE: chreipl-fcp-mpath.md
chreipl-fcp-mpath.md: README.md
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
.chreipl-fcp-mpath.7.cksum: README.md
sha256sum $(<) > $(@)
.PHONY: chreipl-fcp-mpath-doc-clean
chreipl-fcp-mpath-doc-clean:
rm -f README.html README.pdf chreipl-fcp-mpath.md chreipl-fcp-mpath.7
rm -f README.html README.pdf chreipl-fcp-mpath.md
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
else # $(ENABLE_DOC) != 1
# We bundle a pre-cooked man page with the source-code so that distributions
# don't need `pandoc` in order to be able to ship the man page. As of this
# writing multiple distributions don't have a packaged version of it.
#
# In order to remember to regenerate this pre-cooked version whenever the
# README.md is changed, we also generate a checksum of the README.md, bundle
# that as well, and compare that whenever `make` is called. This way, the
# freshness of the man page can be checked, even if `pandoc` is not available,
# or ENABLE_DOC disabled.
MANPAGE_FRESH := $(shell sha256sum --check .chreipl-fcp-mpath.7.cksum >/dev/null && echo 1 || echo 0)
ifeq ($(MANPAGE_FRESH),0)
$(warning chreipl-fcp-mpath.7 is outdated, please regenerate it by calling `make ENABLE_DOC=1`)
endif
endif # $(ENABLE_DOC) == 1
#
## Install
#
@@ -180,8 +203,6 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-dracut-config
endif
ifeq ($(ENABLE_DOC),1)
# chreipl-fcp-mpath: install man page
INSTDIRS += $(MANDIR)
$(DESTDIR)$(MANDIR)/man7: install_dirs
@@ -194,8 +215,6 @@ chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
endif
#
## Utility
#

View File

@@ -120,18 +120,20 @@ in place, but the toolset has some software dependencies besides the
requirements in section [Requirements](#requirements):
- GNU Bash;
- GNU Core Utilities (mktemp, readlink, sync, truncate);
- GNU Core Utilities (mktemp, readlink, sync, truncate, sha256sum);
- util-linux (flock, hexdump, logger);
- udev / systemd-udev;
- multipath-tools.
To make use of the optional dracut configuration you need: dracut.
To build and install the documentation (man page) you need:
To build a fresh version of the documentation (man page) you need:
- pandoc;
- GNU Core Utilities (date);
- GNU awk.
- GNU awk;
otherwise the pre-cooked version shipped with the source will be used.
INSTALLATION
============
@@ -160,7 +162,7 @@ steps and copies the resulting components to their final destination.
| Option | Values | Default | Effect
| :----- | :----: | :-----: | :-----
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
| ENABLE_DOC | 0, 1 | 0 | Build and install a man page for **chreipl-fcp-mpath**.
| ENABLE_DOC | 0, 1 | 0 | Build a fresh version of the man page for **chreipl-fcp-mpath**.
Specify any options as arguments for both the **make** and **make install**
command as shown in the following example:
@@ -195,8 +197,8 @@ the boot record to find the new initial ramdisk.
~ # zipl
With dracut and documentation enabled, **make install** deploys the following
files to these default locations:
With dracut enabled, **make install** deploys the following files to these
default locations:
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf

View File

@@ -0,0 +1,183 @@
.\" Automatically generated by Pandoc 2.16.1
.\"
.TH "CHREIPL-FCP-MPATH" "7" "2022-02-24" "s390-tools 2.20.0-build-20220224" "Administrator Manual"
.hy
.SH NAME
.PP
chreipl-fcp-mpath - use multipath information for re-IPL path failover
on a running Linux instance
.SH DESCRIPTION
.PP
The IPL process of Linux on Z or LinuxONE from an FCP-attached SCSI
volume uses exactly one path to the volume.
If this path is unavailable, the IPL fails.
.PP
The \f[B]chreipl-fcp-mpath\f[R] toolset monitors \f[B]udev\f[R] events
about paths to the re-IPL volume.
If the currently configured re-IPL path becomes unavailable, the toolset
checks for operational paths to the same volume.
If available, it reconfigures the re-IPL settings to use an operational
path.
.PP
Thus, re-IPL from an FCP-attached SCSI volume can be successful despite
path failures on a running Linux instance if at least one path to the
re-IPL volume remains operational.
.PP
\f[B]Chreipl-fcp-mpath\f[R] requires \f[B]udev\f[R],
\f[B]multipathd\f[R] and \f[B]dm-multipath\f[R].
Once installed, the toolset runs automatically and autonomously.
No user intervention is possible or required.
.PP
Other than installing the toolset, there is no user interface for
\f[B]chreipl-fcp-mpath\f[R].
.SS Requirements
.PP
The \f[B]chreipl-fcp-mpath\f[R] tool has the following requirements on
the Linux instance that is being monitored:
.IP \[bu] 2
The Linux instance must have started successfully, during IPL.
.IP \[bu] 2
The running Linux instance must use \f[B]dm-multipath\f[R] and
\f[B]multipathd\f[R] for the configured re-IPL volume - a volume that
contains a zipl boot record and has one of its paths used in the re-IPL
configuration.
.IP \[bu] 2
\f[B]udev\f[R] must run.
.IP \[bu] 2
The toolset must observe at least one event about the configured re-IPL
path.
Examples for such events are: the SCSI disk comes online, or a path of
the corresponding multipath device goes down or comes back online.
.RS 2
.IP \[bu] 2
The WWID of the re-IPL volume must not change while the Linux instance
is running.
.RE
.IP \[bu] 2
When the configured re-IPL path becomes unavailable while the Linux
instance is running, at least one operational path to the re-IPL volume
must be available, or must become available.
If no such path is available when the Linux instance is rebooted, the
re-IPL path is not changed.
.IP \[bu] 2
The tool assumes that any manually reconfigured re-IPL device is valid
and operational.
.RS 2
.PP
The tool treats a newly configured re-IPL device like the initially
configured re-IPL device.
In particular, if the newly configured re-IPL device fulfills the
requirements of the tool, re-IPL path failover takes place if the
configured re-IPL path becomes unavailable.
.RE
.SS Caution with Manual Changes to the Configured re-IPL Target
.PP
\f[B]chreipl-fcp-mpath\f[R] is designed to accept operator-inititated
changes of the re-IPL device.
However, concurrent changes by the operator and tool driven changes can
result in the operator change being overwritten.
.PP
To avoid this problem, change the re-IPL device only during steady-state
operations, when no path events happen.
Alternatively, make sure that no events are processed while you change
the device.
See EXAMPLES for one way to suspend event processing.
.SH MESSAGES
.PP
During monitoring and event processing, \f[B]chreipl-fcp-mpath\f[R]
writes messages to the syslog.
.PP
When the configured re-IPL path is changed to a different path to the
same volume (priority \f[I]daemon.notice\f[R]):
.RS
.PP
Changed re-IPL path to: <device-bus-id>:<wwpn>:<lun>.
.RE
.PP
When a path event indicates that the last available path has become
non-operational (priority \f[I]daemon.alert\f[R]):
.RS
.PP
The re-IPL device cannot be changed because no operational path to the
re-IPL volume remains.
The next re-IPL might fail unless you re-attach or enable at least one
valid path to the re-IPL volume.
.RE
.PP
When changing the configured re-IPL device failed because of an error
with the used Linux kernel interface (priority \f[I]daemon.crit\f[R]):
.RS
.PP
Changing the re-IPL device failed.
The current re-IPL settings might be inconsistent.
Check and correct the settings (see the README.md of chreipl-fcp-mpath)
to make sure that the current re-IPL device is valid.
.RE
.PP
A failure to change the re-IPL device can indicate an inconsistent
setting that cannot be corrected automatically by
\f[B]chreipl-fcp-mpath\f[R].
As a result, the next re-IPL might fail or might not use the intended
re-IPL device.
.PP
You can use the following tools to check and correct the current
settings:
.IP \[bu] 2
\f[B]lsreipl\f[R] to confirm that the intended re-IPL device is
configured;
.IP \[bu] 2
\f[B]chreipl\f[R] to change the re-IPL device;
.IP \[bu] 2
\f[B]lszfcp\f[R] to inspect the state of available paths to the re-IPL
device.
.SH EXAMPLES
.SS Manual Changes to the Configured re-IPL Device
.PP
As outlined in DESCRIPTION, be cautious when manually changing the
configured re-IPL device.
Assure that your reconfiguration actions do not collide with concurrent
automatic event processing by \f[B]chreipl-fcp-mpath\f[R].
You can avoid such collisions, by stopping event processing, making your
changes, and then re-enabling event processing.
You need \f[I]root\f[R] privileges for running the commands in the
following example:
.IP
.nf
\f[C]
\[ti] # udevadm settle
\[ti] # udevadm control --stop-exec-queue
\[ti] # chreipl ...
\[ti] # udevadm control --start-exec-queue
\f[R]
.fi
.SS Listing messages with journalctl
.PP
If your Linux instance includes \f[B]journalctl\f[R], use the following
command to list all messages that are issued by
\f[B]chreipl-fcp-mpath\f[R]:
.IP
.nf
\f[C]
\[ti] # journalctl -t chreipl-fcp-mpath
\f[R]
.fi
.PP
To list only messages that were issued since the last IPL, use this
command:
.IP
.nf
\f[C]
\[ti] # journalctl -t chreipl-fcp-mpath -b
\f[R]
.fi
.SH REPORTING BUGS
.PP
Use the \f[B]Issues\f[R] functionality on GitHub to report any bugs in
\f[B]chreipl-fcp-mpath\f[R]: s390-tools
Issues (https://github.com/ibm-s390-linux/s390-tools/issues).
.SH SEE ALSO
.PP
\f[B]chreipl\f[R](8), \f[B]dracut\f[R](8), \f[B]journalctl\f[R](1),
\f[B]lsreipl(8)\f[R], \f[B]lszfcp\f[R](8), \f[B]multipath\f[R](8),
\f[B]multipathd\f[R](8), \f[B]udev\f[R](7), \f[B]udevadm\f[R](8),
\f[B]zipl\f[R](8)

View File

@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
VERSION = 2
RELEASE = 20
RELEASE = 21
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -59,11 +59,8 @@ define cmd_define
endef
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
$(eval $(call cmd_define, LINK," LINK ",$(CROSS_COMPILE)gcc))
$(eval $(call cmd_define, LD," LD ",$(CROSS_COMPILE)ld))
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CROSS_COMPILE)g++))
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
@@ -84,6 +81,8 @@ CHECKTOOL = $(call echocmd," CHECK ",/$@)$(CHECK_SILENT)
SKIP = echo " SKIP $(call reldir) due to"
INSTALL = install
LINK = $(CC)
LINKXX = $(CXX)
CP = cp
ifneq ("${V}","1")
MAKEFLAGS += --quiet
@@ -92,13 +91,12 @@ ifneq ("${V}","1")
else
echocmd=
endif
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
ifeq ("${W}","1")
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security -Wextra
else
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
endif
ifeq ("${D}","1")
DEFAULT_CFLAGS += -Og
DEFAULT_CFLAGS += -Og -g3 -ggdb3
else
DEFAULT_CFLAGS += -O3
endif
@@ -252,11 +250,9 @@ export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
NO_PIE_CFLAGS := -fno-pie
NO_PIE_LINKFLAGS := -no-pie
NO_PIE_LDFLAGS := -no-pie
else
NO_PIE_CFLAGS :=
NO_PIE_LINKFLAGS :=
NO_PIE_LDFLAGS :=
endif
@@ -371,6 +367,10 @@ $(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
.PHONY: $(rootdir)/libvmcp
$(rootdir)/libcpumf/libcpumf.a: $(rootdir)/libcpumf
$(MAKE) -C $(rootdir)/libcpumf/ libcpumf.a
.PHONY: $(rootdir)/libcpumf
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
.PHONY: $(rootdir)/libekmfweb

View File

@@ -5,7 +5,7 @@ MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
all: $(BIN_FILES)
libs = $(rootdir)/libutil/libutil.a
libs = $(rootdir)/libutil/libutil.a $(rootdir)/libcpumf/libcpumf.a
lscpumf: lscpumf.o $(libs)
chcpumf: chcpumf.o $(libs)

View File

@@ -1,7 +1,7 @@
/*
* chcpumf - Change CPU Measurement Facility Characteristics
*
* Copyright IBM Corp. 2020
* 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.
@@ -20,9 +20,9 @@
#include "lib/util_prg.h"
#include "lib/util_base.h"
#include "defines.h"
#include "lib/libcpumf.h"
static int verbose;
static unsigned int verbose;
static unsigned long min_sdb, max_sdb;
static struct util_opt opt_vec[] = {
@@ -85,55 +85,30 @@ static long parse_buffersize(char *string)
return bytes;
}
static void read_sfb(unsigned long *min, unsigned long *max)
{
unsigned long cur_min_sdb, cur_max_sdb;
FILE *fp;
if (geteuid())
errx(EXIT_FAILURE, "Must run as root");
fp = fopen(PERF_SFB_SIZE, "r");
if (!fp)
err(EXIT_FAILURE, PERF_SFB_SIZE);
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
fclose(fp);
errx(EXIT_FAILURE, "Can not parse file " PERF_SFB_SIZE);
} else {
if (*min == 0)
*min = cur_min_sdb;
if (*max == 0)
*max = cur_max_sdb;
}
fclose(fp);
if (*min >= *max)
errx(EXIT_FAILURE,
"The specified maximum must be greater than the minimum");
}
static int write_sfb(unsigned long min, unsigned long max)
static int write_sfb(unsigned int min, unsigned int max)
{
int rc = EXIT_SUCCESS;
char text[64];
size_t len;
FILE *fp;
fp = fopen(PERF_SFB_SIZE, "w");
fp = fopen(S390_CPUMSF_BUFFERSZ, "w");
if (!fp)
err(EXIT_FAILURE, PERF_SFB_SIZE);
snprintf(text, sizeof text, "%ld,%ld", min, max);
err(EXIT_FAILURE, S390_CPUMSF_BUFFERSZ);
snprintf(text, sizeof(text), "%u,%u", min, max);
len = strlen(text) + 1;
if (fwrite(text, 1, len, fp) != len) {
warn(PERF_SFB_SIZE);
warn(S390_CPUMSF_BUFFERSZ);
rc = EXIT_FAILURE;
}
if (fclose(fp)) {
warn(PERF_SFB_SIZE);
warn(S390_CPUMSF_BUFFERSZ);
rc = EXIT_FAILURE;
}
if (verbose && rc != EXIT_FAILURE)
warnx("Sampling buffer sizes:\n"
" Minimum:%7ld sample-data-blocks\n"
" Maximum:%7ld sample-data-blocks\n",
" Minimum:%7d sample-data-blocks\n"
" Maximum:%7d sample-data-blocks\n",
min, max);
return rc;
}
@@ -183,15 +158,21 @@ static int parse_args(int argc, char **argv)
int main(int argc, char **argv)
{
struct stat sbuf;
unsigned long my_min, my_max;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
parse_args(argc, argv);
if (stat(PERF_PATH PERF_SF, &sbuf))
if (geteuid())
errx(EXIT_FAILURE, "Must run as root");
if (!libcpumf_have_sfb())
errx(EXIT_FAILURE,
"No CPU-measurement sampling facility detected");
read_sfb(&min_sdb, &max_sdb);
libcpumf_sfb_info(&my_min, &my_max);
if (!min_sdb)
min_sdb = my_min;
if (!max_sdb)
max_sdb = my_max;
return write_sfb(min_sdb, max_sdb);
}

View File

@@ -1,18 +0,0 @@
/*
* Defines for CPU Measurement Facility Characteristics
*
* 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 DEFINES_H
#define DEFINES_H
#define PERF_SFB_SIZE "/sys/module/kernel/parameters/cpum_sfb_size"
#define PERF_PATH "/sys/bus/event_source/devices/"
#define PERF_SF "cpum_sf"
#define PERF_CF "cpum_cf"
#endif

View File

@@ -1,7 +1,7 @@
/*
* lscpumf - Show CPU Measurement Facility Characteristics
*
* Copyright IBM Corp. 2020
* 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.
@@ -28,7 +28,7 @@
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "defines.h"
#include "lib/libcpumf.h"
#define ACTION_NONE 0
#define ACTION_INFO 1
@@ -45,9 +45,6 @@ static bool actions[ACTION_SAMPLE + 1]; /* Specified command line options */
#define PER_SDBT_SIZE 511
/* File names to read data from */
#define SERVICELEVEL "/proc/service_levels"
#define CPUMF_CF_TYPE "/sys/devices/cpum_cf/type"
#define CPUMF_SF_TYPE "/sys/devices/cpum_sf/type"
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTIONS"),
@@ -92,19 +89,18 @@ static char prefix[32]; /* Counter prefix */
static bool show_names;
static struct cpumf_info {
unsigned int first_vn; /* Counter facility first version nr */
unsigned int second_vn; /* Counter facility second version nr */
unsigned int authorization; /* Counter facility authorization */
float version;
int first_vn; /* Counter facility first version nr */
int second_vn; /* Counter facility second version nr */
int authorization; /* Counter facility authorization */
unsigned long min_rate; /* Minimum sampling rate */
unsigned long max_rate; /* Maximum sampling rate */
unsigned long cpu_speed; /* CPU Cycles per micro second */
unsigned int basic_sample_sz; /* # of Bytes per basic sample */
unsigned int diag_sample_sz; /* # of bytes per diagnostic sample */
unsigned char have_counter; /* CPUM counter facility detected */
unsigned char have_samples; /* CPUM sampling facility detected */
unsigned int min_sfb; /* Minimum sampling buffer size */
unsigned int max_sfb; /* Maximum sampling buffer size */
int basic_sample_sz; /* # of Bytes per basic sample */
int diag_sample_sz; /* # of bytes per diagnostic sample */
bool have_counter; /* CPUM counter facility detected */
bool have_samples; /* CPUM sampling facility detected */
unsigned long min_sfb; /* Minimum sampling buffer size */
unsigned long max_sfb; /* Maximum sampling buffer size */
unsigned short machine_type; /* Machine Type */
} cpumf;
@@ -2565,26 +2561,12 @@ static struct counters cpumcf_z15_counters[] = {
* If perf_pmu_register() kernel function assigned any other (higher) type
* number, set the prefix to <type-nr>:
*/
static int read_cpumf_type(const char *filename, const char *type)
static void set_prefix(int nr)
{
int nr, rc = EXIT_FAILURE;
FILE *fp = fopen(filename, "r");
if (fp == NULL) {
warnx("No CPU-measurement %s facility detected", type);
return rc;
}
if (fscanf(fp, "%d", &nr) != 1) {
warnx("Can not parse file %s", filename);
} else {
rc = EXIT_SUCCESS;
if (nr == PERF_TYPE_RAW)
strcat(prefix, "r");
else
snprintf(prefix, sizeof prefix, "%d:", nr);
}
fclose(fp);
return rc;
if (nr == PERF_TYPE_RAW)
strcat(prefix, "r");
else
snprintf(prefix, sizeof(prefix), "%d:", nr);
}
/* Parse tool parameters. In case of --help or --version, print
@@ -2661,8 +2643,6 @@ static unsigned long div_ceil(unsigned long a, unsigned long b)
static void show_info(struct cpumf_info *p, int details)
{
struct stat sbuf;
if (!p->have_counter && !p->have_samples) {
warnx("No CPU-measurement facilities detected");
return;
@@ -2672,7 +2652,7 @@ static void show_info(struct cpumf_info *p, int details)
if (details) {
printf("----------------------------------------------"
"----------------------------\n");
printf("Version: %3.1f\n\n", p->version);
printf("Version: %d.%d\n\n", p->first_vn, p->second_vn);
printf("Authorized counter sets:\n");
if (!p->authorization)
printf(" None\n");
@@ -2689,8 +2669,7 @@ static void show_info(struct cpumf_info *p, int details)
if (0x8000 & p->authorization)
printf(" Coprocessor Group counter Set\n");
printf("\nLinux perf event support: %s\n\n",
(stat(PERF_PATH PERF_CF, &sbuf)) ? "No" :
"Yes (PMU: " PERF_CF ")");
!p->have_counter ? "No" : "Yes (PMU: cpum_cf)");
}
} else
@@ -2718,19 +2697,18 @@ static void show_info(struct cpumf_info *p, int details)
p->diag_sample_sz);
printf("\nLinux perf event support: %s\n\n",
(stat(PERF_PATH PERF_SF, &sbuf)) ? "No" :
"Yes (PMU: " PERF_SF ")");
!p->have_samples ? "No" : "Yes (PMU: cpum_sf)");
printf("Current sampling buffer settings for %s:\n",
PERF_SF);
printf("Current sampling buffer settings for"
" cpum_sf:\n");
printf(" Basic-sampling mode\n");
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
human(text, sizeof text, PAGE_SIZE * total);
printf(" Minimum: %6d"
human(text, sizeof(text), PAGE_SIZE * total);
printf(" Minimum: %6ld"
" sample-data-blocks (%6s)\n", p->min_sfb, text);
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
human(text, sizeof text, PAGE_SIZE * total);
printf(" Maximum: %6d"
human(text, sizeof(text), PAGE_SIZE * total);
printf(" Maximum: %6ld"
" sample-data-blocks (%6s)\n\n", p->max_sfb,
text);
@@ -2739,13 +2717,13 @@ static void show_info(struct cpumf_info *p, int details)
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
total = fdiag * p->min_sfb
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
human(text, sizeof text, PAGE_SIZE * total);
human(text, sizeof(text), PAGE_SIZE * total);
printf(" Minimum: %6ld"
" sample-data-blocks (%6s)\n",
fdiag * p->min_sfb, text);
total = fdiag * p->max_sfb
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
human(text, sizeof text, PAGE_SIZE * total);
human(text, sizeof(text), PAGE_SIZE * total);
printf(" Maximum: %6ld"
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
text);
@@ -2755,27 +2733,6 @@ static void show_info(struct cpumf_info *p, int details)
warnx("No CPU-measurement sampling facility detected");
}
/* Read CPU Measurement sampling facility device driver minimum and maximum
* buffer size
*/
static int read_sfb(struct cpumf_info *p)
{
int rc = EXIT_SUCCESS;
FILE *fp;
fp = fopen(PERF_SFB_SIZE, "r");
if (!fp) {
warn(PERF_SFB_SIZE);
return EXIT_FAILURE;
}
if (fscanf(fp, "%d,%d", &p->min_sfb, &p->max_sfb) != 2) {
warnx("Can not parse %s", PERF_SFB_SIZE);
rc = EXIT_FAILURE;
}
fclose(fp);
return rc;
}
/* Set the counter name for z15 counter numbered 265. It is either named
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
@@ -2803,81 +2760,23 @@ static void read_ccerror(struct counters *cp, size_t cp_cnt)
/* Read allnecessary information from /sysfs file /proc/service_levels */
static int read_info(void)
{
char *linep = NULL;
size_t line_sz;
ssize_t nbytes;
FILE *slp;
int rc;
int rc = EXIT_FAILURE;
memset(&cpumf, 0, sizeof cpumf);
slp = fopen(SERVICELEVEL, "r");
if (!slp) {
warn(SERVICELEVEL);
return EXIT_FAILURE;
}
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
rc = sscanf(linep, "CPU-MF: Counter facility:"
" version=%f authorization=%x",
&cpumf.version, &cpumf.authorization);
if (rc != 2) {
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
cpumf.have_counter = 1;
cpumf.first_vn = (int)cpumf.version;
cpumf.second_vn = ((int)(10 * cpumf.version) % 10);
}
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
rc = sscanf(linep, "CPU-MF: Sampling facility:"
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
&cpumf.min_rate, &cpumf.max_rate,
&cpumf.cpu_speed);
if (rc != 3) {
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
cpumf.have_samples = 1;
}
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
rc = sscanf(linep, "CPU-MF: Sampling facility:"
" mode=basic sample_size=%u",
&cpumf.basic_sample_sz);
if (rc != 1) {
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
}
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
rc = sscanf(linep, "CPU-MF: Sampling facility:"
" mode=diagnostic sample_size=%u",
&cpumf.diag_sample_sz);
if (rc != 1) {
warnx("Can not parse line %s", linep);
rc = EXIT_FAILURE;
goto out;
}
}
}
if (cpumf.have_samples) {
rc = read_sfb(&cpumf);
if (rc == EXIT_FAILURE)
goto out;
}
cpumf.have_counter = libcpumf_cpumcf_info(&cpumf.first_vn,
&cpumf.second_vn,
&cpumf.authorization);
cpumf.have_samples = libcpumf_cpumsf_info(&cpumf.min_rate,
&cpumf.max_rate,
&cpumf.cpu_speed,
&cpumf.basic_sample_sz,
&cpumf.diag_sample_sz);
if (cpumf.have_samples)
libcpumf_sfb_info(&cpumf.min_sfb, &cpumf.max_sfb);
cpumf.machine_type = util_arch_machine_type();
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN) {
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN)
rc = EXIT_FAILURE;
goto out;
}
rc = EXIT_SUCCESS;
out:
fclose(slp);
free(linep);
else
rc = EXIT_SUCCESS;
return rc;
}
@@ -3051,14 +2950,18 @@ int main(int argc, char **argv)
case ACTION_CNT:
case ACTION_CNTALL:
all = ret == ACTION_CNTALL;
ret = read_cpumf_type(CPUMF_CF_TYPE, "counter");
if (ret == EXIT_SUCCESS)
ret = libcpumf_pmutype(S390_CPUMF_CF);
if (ret >= EXIT_SUCCESS) {
set_prefix(ret);
show_counter(all);
}
break;
case ACTION_SAMPLE:
ret = read_cpumf_type(CPUMF_SF_TYPE, "sampling");
if (ret == EXIT_SUCCESS)
ret = libcpumf_pmutype(S390_CPUMF_SF);
if (ret >= EXIT_SUCCESS) {
set_prefix(ret);
show_sample();
}
break;
case ACTION_NONE:
case ACTION_INFO:

View File

@@ -38,17 +38,18 @@
#include "lib/util_path.h"
#include "lib/util_scandir.h"
#include "lib/util_libc.h"
#include "lib/libcpumf.h"
#include "lshwc.h"
#define SERVICELEVEL "/proc/service_levels"
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
#define MAXCTRS 512
#define IOCTLSLEEP 60U
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
static unsigned int read_interval = IOCTLSLEEP;
static int cfvn, csvn, authorization;
static unsigned long loop_count = 1;
static unsigned char *ioctlbuffer;
static bool allcpu;
@@ -151,20 +152,6 @@ static unsigned long getnumber(char *word, char stopchar)
return no;
}
/* Remove all whitespace from string. */
static void kill_whitespace(char *s)
{
char *cp = s;
for (; *s != '\0'; ++s) {
if (isspace(*s))
continue;
if (isprint(*s))
*cp++ = *s;
}
*cp = '\0';
}
/* Read file to get all online CPUs */
static bool get_cpus(char *file, char *buf, size_t bufsz)
{
@@ -242,29 +229,34 @@ static char *show_ctrset(unsigned long set)
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
{
uint64_t *words = start->cpumask;
unsigned long i, no_a, no_b;
char *cp, *tokens[16]; /* Used to parse command line params */
char cpubuf[256];
unsigned int i, no_a, no_b;
cpu_set_t cpulist;
int rc;
CPU_ZERO(&cpulist);
start->data_bytes = 0;
if (parm)
kill_whitespace(parm);
if (!parm || *parm == ':') {
/* No CPU list or just counter sets */
if (!get_cpus(CPUS_ONLINE, cpubuf, sizeof(cpubuf)))
exit(EXIT_FAILURE);
if (parm)
strcat(cpubuf, parm);
parm = cpubuf;
start->counter_sets = S390_HWCTR_ALL; /* Default all counter sets */
if (parm) { /* CPU list with optional counter set */
char *cp = strchr(parm, ':');
if (cp) { /* Handle counter set */
*cp = '\0';
start->counter_sets = parse_ctrset(++cp);
}
if (strlen(parm) > 0) /* Handle CPU list */
rc = libcpumf_cpuset(parm, &cpulist);
else
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
if (rc)
errx(EXIT_FAILURE, "Cannot use CPU list %s", parm);
} else { /* No CPU list and no counter sets */
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
if (rc)
err(EXIT_FAILURE, "Cannot read file " S390_CPUS_ONLINE);
}
cp = strchr(parm, ':');
if (cp) { /* Handle counter set */
*cp = '\0';
start->counter_sets = parse_ctrset(++cp);
} else {
start->counter_sets = S390_HWCTR_ALL;
}
/* Check with authorized counter sets */
if ((start->counter_sets & authorization) != start->counter_sets) {
unsigned int noton = ~(start->counter_sets & authorization);
@@ -276,19 +268,10 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
show_ctrset(noton));
}
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
++i, parm = NULL) {
cp = strchr(tokens[i], '-'); /* Range character? */
if (cp) {
no_a = getnumber(tokens[i], *cp);
no_b = getnumber(++cp, '\0');
} else {
no_b = getnumber(tokens[i], '\0');
no_a = no_b;
}
if (!check_set(no_a, no_b, start->counter_sets))
errx(EXIT_FAILURE, "Invalid CPU list %s", tokens[i]);
}
for (rc = 0; rc < CPU_SETSIZE; ++rc)
if (CPU_ISSET(rc, &cpulist))
if (!check_set(rc, rc, start->counter_sets))
errx(EXIT_FAILURE, "Invalid CPU %d", rc);
/* Convert the CPU list to a bitmask for kernel cpumask_t */
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
@@ -632,37 +615,6 @@ static int do_it(char *s)
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
}
/* Read counter first and second version number */
static bool get_cvn(void)
{
char *linep = NULL;
bool good = false;
size_t line_sz;
ssize_t nbytes;
FILE *slp;
slp = fopen(SERVICELEVEL, "r");
if (!slp) {
warn(SERVICELEVEL);
return false;
}
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
int rc;
rc = sscanf(linep, "CPU-MF: Counter facility: version=%d.%d authorization=%x",
&cfvn, &csvn, &authorization);
good = rc == 3;
if (!good)
warnx("Cannot parse line %s", linep);
break;
}
}
fclose(slp);
free(linep);
return good;
}
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTIONS"),
{
@@ -746,7 +698,7 @@ int main(int argc, char **argv)
}
have_support();
if (!get_cvn())
if (!libcpumf_cpumcf_info(&cfvn, &csvn, &authorization))
return EXIT_FAILURE;
if (!check_setpossible())
return EXIT_FAILURE;

View File

@@ -408,8 +408,10 @@ static int read_line(void)
{
bzero(line_buffer, LINE_LENGTH);
line_ptr = line_buffer;
if (!fgets(line_buffer, LINE_LENGTH, stdin))
if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
clearerr(stdin);
return 0;
}
while (*line_ptr && !isgraph(*line_ptr))
line_ptr++;

View File

@@ -74,9 +74,9 @@ stage3b_reloc.elf:
%.elf: %.o
case $* in \
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
stage3a) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
stage3b) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
stage3b_reloc) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
esac; \
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
@chmod a-x $@

View File

@@ -87,13 +87,23 @@ CRLs. Optional.
.TP
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
Specifies the root CA certificate for the verification. If omitted,
the DigiCert root CA certificate installed on the system is used. Use
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
Do not require the host-key documents to be valid. For testing
purposes, do not use for a production image. Optional.
.TP
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
Specifies the encryption key you want to use for the PV guest dump. 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. Optional.
.TP
\fB\-\-enable\-pckmo\fR
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
functions. This is the default. Optional.
@@ -105,21 +115,25 @@ functions. Optional.
\fB\-v\fR, \fB\-\-version\fR
Prints version information, then exits.
.SH EXAMPLE
.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
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:
.PP
.Vb 1
.EX
\& 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 \-o \fI\,/boot/vmlinuz.pv\/\fR
.EE
.Ve
.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

View File

@@ -23,6 +23,7 @@ BODY_FILE=$(mktemp)
ISSUER_DN_FILE=$(mktemp)
SUBJECT_DN_FILE=$(mktemp)
DEF_ISSUER_DN_FILE=$(mktemp)
CANONICAL_ISSUER_DN_FILE=$(mktemp)
CRL_SERIAL_FILE=$(mktemp)
# Cleanup on exit
@@ -30,7 +31,7 @@ cleanup()
{
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
$CRL_SERIAL_FILE
$CANONICAL_ISSUER_DN_FILE $CRL_SERIAL_FILE
}
trap cleanup EXIT
@@ -47,13 +48,21 @@ set -e
usage()
{
cat <<-EOF
Usage: `basename $1` host-key-doc signing-key-cert [-c CA-cert] [-r CRL]
Usage: `basename $1` [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
Verify an IBM Secure Execution host key document against
a signing key.
Options:
-d disable default issuer check of host-key-doc
-c CA-cert trusted CA certificate
-r CRL list of revoked host-key-docs
Note that in order to have the full trust chain verified
it is necessary to provide the issueing CA's certificate.
it is necessary to provide the issuing CA's certificate.
The default issuer check may be disabled if a non-default
signing key certificate needs to be verified against the
CA certificate.
EOF
}
@@ -121,20 +130,34 @@ default_issuer()
commonName = International Business Machines Corporation
countryName = US
localityName = Poughkeepsie
organizationalUnitName = IBM Z Host Key Signing Service
organizationalUnitName = Key Signing Service
organizationName = International Business Machines Corporation
stateOrProvinceName = New York
EOF
}
verify_issuer_files()
# As organizationalUnitName can have an arbitrary prefix but must
# end with "Key Signing Service" let's normalize the OU name by
# stripping off the prefix
verify_default_issuer()
{
default_issuer > $DEF_ISSUER_DN_FILE
if ! diff $ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
$ISSUER_DN_FILE > $CANONICAL_ISSUER_DN_FILE
if ! diff $CANONICAL_ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
then
echo Incorrect default issuer >&2 && exit 1
fi
}
verify_issuer_files()
{
if [ $1 -eq 1 ]
then
verify_default_issuer
fi
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
then
@@ -196,14 +219,16 @@ check_file()
# check args
CRL_FILE=
CA_FILE=
CHECK_DEFAULT_ISSUER=1
args=$(getopt -qu "r:c:h" $*)
args=$(getopt -qu "dr:c:h" $*)
if [ $? = 0 ]
then
set -- $args
while [ $1 != "" ]
do
case $1 in
-d) CHECK_DEFAULT_ISSUER=0; shift;;
-r) CRL_FILE=$2; shift 2;;
-c) CA_FILE=$2; shift 2;;
-h) usage $0; exit 0;;
@@ -244,7 +269,7 @@ exit 1
# Verify the issuer
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
verify_issuer_files
verify_issuer_files $CHECK_DEFAULT_ISSUER
# Verify dates
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
@@ -261,7 +286,7 @@ then
echo -n "CRL "
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
verify_issuer_files
verify_issuer_files $CHECK_DEFAULT_ISSUER
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'

View File

@@ -29,9 +29,6 @@
*/
#define PV_CERTS_SECURITY_LEVEL 2
/* SKID for DigiCert Assured ID Root CA */
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
union ecdh_pub_key {
struct {
uint8_t x[80];

View File

@@ -24,11 +24,15 @@
#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_PCKM_ECC (1ULL << 5) /* PCKMO encrypt-ECC-key functions allowed */
#define PV_PCF_PCKMO_AES (1ULL << 6) /* PCKMO encrypt-AES-key functions allowed */
#define PV_PCF_PCKMO_DEA_TDEA (1ULL << 7) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
#define PV_PCF_NO_DECRYPTION (1ULL << 28) /* prevent Ultravisor decryption during unpack operation */
#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 */
/* maxima for the PV version 1 */
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE

View File

@@ -64,13 +64,17 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
{
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
if (args->pcf && args->allow_pckmo != PV_NOT_SET) {
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
_("The '--x-pcf' and '--(enable|disable)-pckmo' options are mutually"
" exclusive.\nUse 'genprotimg --help' for more information"));
/* Check for mutually exclusive arguments */
if (args->pcf && !(args->allow_pckmo == PV_NOT_SET &&
args->allow_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;
}
/* Check for unused arguments */
if (args->unused_values->len > 0) {
g_autofree gchar *unused = NULL;
@@ -88,6 +92,14 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
return -1;
}
/* Check for mandatory arguments */
if (args->allow_dump == PV_TRUE && !args->cust_comm_key_path) {
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
_("Option '--allow-dump' 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"));
@@ -111,7 +123,7 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
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 (DigiCert) intermediate CA certificate\n"
_("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;
@@ -155,14 +167,14 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
{
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-comm-key"))
args_option = &args->cust_comm_key_path;
if (g_str_equal(option, "--x-header-key"))
args_option = &args->cust_root_key_path;
if (g_str_equal(option, "--x-pcf"))
@@ -188,19 +200,6 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
return TRUE;
}
static gboolean cb_enable_disable_flag(const gchar *option, const gchar *value G_GNUC_UNUSED,
PvArgs *args, GError **err G_GNUC_UNUSED)
{
if (g_str_equal(option, "--enable-pckmo"))
args->allow_pckmo = PV_TRUE;
else if (g_str_equal(option, "--disable-pckmo"))
args->allow_pckmo = PV_FALSE;
else
g_assert_not_reached();
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)
@@ -217,8 +216,51 @@ static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
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->allow_##FLAG == PV_NOT_SET || \
args->allow_##FLAG == VALUE)) { \
g_set_error(err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \
"'--enable-" #FLAG "' and '--disable-" #FLAG \
"' are mutually exclusive"); \
return FALSE; \
} \
args->allow_##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(FLAG, ENABLE_DESC, DISABLE_DESC) \
{ \
.long_name = "enable-" #FLAG, \
.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-" #FLAG, \
.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)
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
GError **err)
{
@@ -282,21 +324,28 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
"(optional)."),
.arg_description = _("PARMFILE") },
{.long_name = "enable-pckmo",
.short_name = 0,
.flags = G_OPTION_FLAG_NO_ARG,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_enable_disable_flag,
.description = _("Enable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (default)\n" INDENT
"(optional).")},
{.long_name = "disable-pckmo",
.short_name = 0,
.flags = G_OPTION_FLAG_NO_ARG,
.arg = G_OPTION_ARG_CALLBACK,
.arg_data = cb_enable_disable_flag,
.description = _("Disable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (optional).")},
MUT_EXCL_BOOL_FLAG(
dump,
_("Enable PV guest dumps (optional). This option\n" INDENT
"requires the '--comm-key' option."),
_("Disable PV guest dumps (default) (optional).")),
MUT_EXCL_BOOL_FLAG(
pckmo,
_("Enable the support for the DEA, TDEA, AES, and\n" INDENT
"ECC PCKMO key encryption functions (default)\n" INDENT
"(optional)."),
_("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 key with which you encrypt\n" INDENT
"the PV guest dump (optional). Required by\n" INDENT
"the '--enable-dump' option."),
.arg_description = _("FILE") },
{ .long_name = "crl",
.short_name = 0,
.flags = G_OPTION_FLAG_NONE,
@@ -355,15 +404,6 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
};
GOptionEntry x_entries[] = {
{ .long_name = "x-comm-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 customer communication key.\n" INDENT
"Optional; default: auto-generated."),
.arg_description = _("FILE") },
{ .long_name = "x-comp-key",
.short_name = 0,
.flags = G_OPTION_FLAG_FILENAME,
@@ -446,6 +486,7 @@ 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->allow_dump = PV_NOT_SET;
args->allow_pckmo = PV_NOT_SET;
return g_steal_pointer(&args);
}

View File

@@ -34,6 +34,7 @@ typedef struct {
gboolean offline;
gchar *pcf;
gchar *scf;
PvTristate allow_dump;
PvTristate allow_pckmo;
gchar *psw_addr; /* PSW address which will be used for the start of
* the actual component (e.g. Linux kernel)

View File

@@ -229,7 +229,9 @@ static gint pv_img_set_psw_addr(PvImage *img, const gchar *psw_addr_s,
}
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
const gchar *scf_s, PvTristate allow_pckmo, GError **err)
const gchar *scf_s,
PvTristate allow_dump,
PvTristate allow_pckmo, GError **err)
{
uint64_t flags;
@@ -247,6 +249,11 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
img->scf = flags;
}
if (allow_dump == PV_TRUE)
img->pcf |= PV_PCF_ALLOW_DUMPING;
else if (allow_dump == PV_FALSE)
img->pcf &= ~PV_PCF_ALLOW_DUMPING;
if (allow_pckmo == PV_TRUE)
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
else if (allow_pckmo == PV_FALSE)
@@ -304,9 +311,10 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
}
/* Load all untrusted certificates (e.g. IBM Z signing key and
* DigiCert intermediate CA) that are required to establish a chain of
* trust starting from the host-key document up to the root CA (if not
* otherwise specified that's the DigiCert Assured ID Root CA).
* intermediate CA) that are required to establish a chain of trust
* starting from the host-key document up to the root CA (if not
* otherwise specified that can be one of the system wide installed
* root CAs, e.g. DigiCert).
*/
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
if (!untrusted_certs_with_path)
@@ -341,9 +349,8 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
* For this we must check:
*
* 1. Can a chain of trust be established ending in a root CA
* 2. Is the correct root CA ued? It has either to be the
* 'DigiCert Assured ID Root CA' or the root CA specified via
* command line.
* 2. Is the correct root CA used? It has either to be a system CA
* or the root CA specified via command line.
*/
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
@@ -364,17 +371,12 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
goto error;
/* Verify the build chain of trust chain. If the user passes a
* trusted root CA on the command line then the check for the
* Subject Key Identifier (SKID) is skipped, otherwise let's
* check if the SKID meets our expectation.
/* If there is a chain of trust using either the provided root
* CA on the command line or a system wide trusted root CA.
*/
if (!root_ca_path &&
check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
get_digicert_assured_id_root_ca_skid(),
err) < 0) {
if (check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
err) < 0)
goto error;
}
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
if (!ibm_signing_crls) {
@@ -588,7 +590,7 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
if (args->root_ca_path)
g_warning(_("A different root CA than the default DigiCert root CA is selected. Ensure that this root CA is trusted."));
g_warning(_("The root CA is selected through the command line. Ensure that this root CA is trusted."));
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
if (!ret->comps)
@@ -608,7 +610,9 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
return NULL;
/* set the control flags: PCF and SCF */
if (pv_img_set_control_flags(ret, args->pcf, args->scf, args->allow_pckmo, err) < 0)
if (pv_img_set_control_flags(ret, args->pcf, args->scf,
args->allow_dump, args->allow_pckmo,
err) < 0)
return NULL;
/* read in the keys */

View File

@@ -1079,8 +1079,8 @@ int store_set_verify_param(X509_STORE *store, GError **err)
g_abort();
/* The maximum depth level of the chain of trust for the verification of
* the IBM Z signing key is 2, i.e. IBM Z signing key -> (DigiCert)
* intermediate CA -> (DigiCert) root CA
* the IBM Z signing key is 2, i.e. IBM Z signing key -> intermediate CA
* -> root CA
*/
X509_VERIFY_PARAM_set_depth(param, 2);
@@ -1267,46 +1267,38 @@ static int security_level_to_bits(int level)
return security_bits[level];
}
static ASN1_OCTET_STRING *digicert_assured_id_root_ca;
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void)
{
pv_crypto_init();
return digicert_assured_id_root_ca;
}
/* Used for the caching of the downloaded CRLs */
static GHashTable *cached_crls;
void pv_crypto_init(void)
{
if (digicert_assured_id_root_ca)
if (cached_crls)
return;
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
(GDestroyNotify)X509_CRL_free);
digicert_assured_id_root_ca = s2i_ASN1_OCTET_STRING(
NULL, NULL, DIGICERT_ASSURED_ID_ROOT_CA_SKID);
}
void pv_crypto_cleanup(void)
{
if (!digicert_assured_id_root_ca)
if (!cached_crls)
return;
g_clear_pointer(&cached_crls, g_hash_table_destroy);
g_clear_pointer(&digicert_assured_id_root_ca, ASN1_OCTET_STRING_free);
}
gint check_chain_parameters(const STACK_OF_X509 *chain,
const ASN1_OCTET_STRING *skid, GError **err)
GError **err)
{
const ASN1_OCTET_STRING *ca_skid = NULL;
const X509_NAME *ca_x509_subject = NULL;
g_autofree gchar *ca_subject = NULL;
gint len = sk_X509_num(chain);
X509 *ca = NULL;
g_assert(skid);
/* at least one root and one leaf certificate must be defined */
g_assert(len >= 2);
if (len < 2) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("there must be at least on root and one leaf certificate in the chain of trust"));
return -1;
}
/* get the root certificate of the chain of trust */
ca = sk_X509_value(chain, len - 1);
@@ -1316,19 +1308,21 @@ gint check_chain_parameters(const STACK_OF_X509 *chain,
return -1;
}
ca_skid = X509_get0_subject_key_id(ca);
if (!ca_skid) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
_("malformed root certificate"));
ca_x509_subject = X509_get_subject_name(ca);
if (!ca_x509_subject) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("subject of the root CA cannot be retrieved"));
return -1;
}
if (ASN1_STRING_cmp(ca_skid, skid) != 0) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_WRONG_CA_USED,
_("expecting DigiCert root CA to be used"));
ca_subject = X509_NAME_oneline(ca_x509_subject, NULL, 0);
if (!ca_subject) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("subject name of the root CA cannot be retrieved"));
return -1;
}
g_info("Root CA used: '%s'", ca_subject);
return 0;
}

View File

@@ -125,7 +125,6 @@ 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);
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(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);
@@ -138,8 +137,7 @@ X509_STORE *store_setup(const gchar *root_ca_path,
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,
const ASN1_OCTET_STRING *skid, GError **err);
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);

106
include/lib/libcpumf.h Normal file
View File

@@ -0,0 +1,106 @@
/* Copyright IBM Corp. 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 LIBCPUMF_H
#define LIBCPUMF_H
#include <sched.h>
#include <stdbool.h>
#define S390_CPUMF_CF "/sys/devices/cpum_cf/"
#define S390_CPUMF_CFDIAG "/sys/devices/cpum_cf_diag/"
#define S390_CPUMF_SF "/sys/devices/cpum_sf/"
#define S390_CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
/**
* Read out the PMU type from a given file.
*
* Return the PMU type number assigned to this PMU by the kernel. This is
* a non zero number.
* If the PMU does not exist return -1 and set errno.
*
* @param[in] dirname Name of the event directory in sysfs
*/
int libcpumf_pmutype(const char *dirname);
/**
* Read out the CPU list from a given file name, for example from files
* /sys/devices/system/cpu/online or /sys/devices/system/cpu/possible.
*
* Return the cpu_set_t created from parsing the CPU list in the second
* parameter.
* Return code of zero indicates proper conversion and -1 indicates an
* error.
*
* @param[in] buffer Comma separated string of a CPU list
* @param[in] filename Name of a sysfs CPU list file name
* @param[out] mask Converted buffer into cpu_set_t mask structure
*/
int libcpumf_cpuset(const char *buffer, cpu_set_t *mask);
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
/**
* Read CPU Measurement Counting Facility hardware information
*
* Return true if CPU Measurement Counter facility information has been
* retrieved and is valid.
*
* Return false if the information could not be extracted from the file.
*
* @param[out] cfvn Contains CPUMF counter first version number
* @param[out] csvn Contains CPUMF counter second version number
* @param[out] auth Contains CPUMF counter set authorization level
*/
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth);
/**
* Return true if CPU Measurement Counter Facility is available.
*/
bool libcpumf_have_cpumcf(void);
/**
* Read CPU Measurement Sampling Facility hardware information
*
* Read all necessary information from /sysfs file /proc/service_levels
* to return CPU Measurement Counter Sampling facility information
* characteristics.
* Return true on success and false when the data can not be retrieved.
*
* @param[out] min Minimum supported sampling interval
* @param[out] max Maximum supported sampling interval
* @param[out] speed Current CPU speed, number of CPU cylces per
* microsecond
* @param[out] basic_sz Basic sample size in bytes
* @param[out] diag_sz Diagnostic sample size in bytes
*/
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
unsigned long *speed, int *basic_sz, int *diag_sz);
/**
* Return true if CPU Measurement Sampling Facility is available.
*/
bool libcpumf_have_cpumsf(void);
/**
* Return true if CPU Measurement Sampling Facility buffer sizes are
* available.
*/
bool libcpumf_have_sfb(void);
/**
* Read CPU Measurement Sampling Facility supported sampling buffer sizes.
*
* Return the minimum and maximum CPU Measurement sampling facitity buffer
* sizes supported.
* Return true on success and false otherwise.
*
* @param[out] min Minimum supported sampling buffer size
* @param[out] max Maximum supported sampling buffer size
*/
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
#endif

19
libcpumf/Makefile Normal file
View File

@@ -0,0 +1,19 @@
include ../common.mak
lib = libcpumf.a
examples = libcpumf_example
all: $(lib)
examples: $(lib) $(examples)
objects = libcpumf_pmutype.o libcpumf_cpuset.o libcpumf_support.o
$(lib): $(objects)
install: all
libcpumf_example: libcpumf_example.o $(lib)
clean:
rm -f *.o $(lib) $(examples)

View File

@@ -0,0 +1,75 @@
/* Copyright IBM Corp. 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.
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include "lib/libcpumf.h"
int libcpumf_cpuset(const char *parm, cpu_set_t *mask)
{
char *cp, *buffer = strdup(parm);
int to, from, rc;
if (!buffer) /* Errno set to ENOMEM */
return -1;
/* Check for invalid characters, such as 11.12 instead 11-12
* but allow blanks and newline. Newline is appended
* when the string is taken from sysfs files, for example
* /sys/devices/system/cpu/online
*/
if (strspn(buffer, "0123456789-,\n ") != strlen(buffer)) {
errno = EINVAL;
return -1;
}
CPU_ZERO(mask);
for (; (cp = strtok(buffer, ",")); buffer = NULL) {
char *dash = strchr(cp, '-'); /* Range character? */
bool is_ok;
if (dash) {
rc = sscanf(cp, "%d-%d", &from, &to);
is_ok = rc == 2;
} else {
rc = sscanf(cp, "%d", &to);
from = to;
is_ok = rc == 1;
}
if (!is_ok) {
errno = ERANGE;
rc = -1;
goto out;
}
for (; from <= to; ++from)
CPU_SET(from, mask);
}
rc = 0;
out:
free(buffer);
return rc;
}
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask)
{
char *txt = NULL;
ssize_t ret = -1;
size_t len = 0;
FILE *fp;
fp = fopen(filename, "r");
if (!fp)
return ret;
/* Read out file, one line expected */
ret = getline(&txt, &len, fp);
fclose(fp);
if (ret > 0)
ret = libcpumf_cpuset(txt, mask);
free(txt);
return ret;
}

View File

@@ -0,0 +1,76 @@
/* Copyright IBM Corp. 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.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "lib/libcpumf.h"
int main(void)
{
unsigned long min, max, speed, sfb_min, sfb_max;
int rc, pmu, cfvn, csvn, auth;
cpu_set_t set;
pmu = libcpumf_pmutype(S390_CPUMF_CF);
if (pmu >= 0)
printf("PMU %stype %d\n", S390_CPUMF_CF, pmu);
else
printf("PMU %stype error %d\n", S390_CPUMF_CF, errno);
pmu = libcpumf_pmutype(S390_CPUMF_SF);
if (pmu >= 0)
printf("PMU %stype %d\n", S390_CPUMF_SF, pmu);
else
printf("PMU %stype error %d\n", S390_CPUMF_SF, errno);
pmu = libcpumf_pmutype(S390_CPUMF_CFDIAG);
if (pmu >= 0)
printf("PMU %stype %d\n", S390_CPUMF_CFDIAG, pmu);
else
printf("PMU %stype error %d\n", S390_CPUMF_CFDIAG, errno);
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &set);
if (rc == 0) {
puts("Online CPUs:");
for (int i = 0; i < CPU_SETSIZE; ++i)
if (CPU_ISSET(i, &set))
printf("%d ", i);
putchar('\n');
}
rc = libcpumf_cpuset("0-7,9,11-12 ,15", &set);
if (rc == 0) {
puts("String CPUs:");
for (int i = 0; i < CPU_SETSIZE; ++i)
if (CPU_ISSET(i, &set))
printf("%d ", i);
putchar('\n');
} else {
printf("libcpumf_cpuset input invalid %d\n", errno);
}
printf("CPUMCF support %d\n", libcpumf_have_cpumcf());
rc = libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
printf("libcpumf_cpumcf_info %d", rc);
if (rc)
printf(" cfvn %d csvn %d authorization %#x", cfvn, csvn, auth);
putchar('\n');
printf("CPUMSF support %d\n", libcpumf_have_cpumsf());
rc = libcpumf_cpumsf_info(&min, &max, &speed, &cfvn, &csvn);
printf("libcpumf_cpumsf_info %d", rc);
if (rc)
printf(" min %ld max %ld speed %#lx basic %d diag %d", min,
max, speed, cfvn, csvn);
putchar('\n');
printf("CPUMSF have sfb %d\n", libcpumf_have_sfb());
rc = libcpumf_sfb_info(&sfb_min, &sfb_max);
printf("libcpumf_sfb_info %d", rc);
if (rc)
printf(" sfb_min %lu sfb_max %lu", sfb_min, sfb_max);
putchar('\n');
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,33 @@
/* Copyright IBM Corp. 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.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "lib/libcpumf.h"
int libcpumf_pmutype(const char *dirname)
{
FILE *file;
char *fn;
int ret;
ret = asprintf(&fn, "%s/type", dirname);
if (ret == -1) /* No memory, errno set */
return ret;
file = fopen(fn, "r");
free(fn);
ret = -1; /* Errno set on file open error */
if (file) {
/* Read out a single number from that file */
if (fscanf(file, "%u", &ret) != 1)
/* Unexpected format error, set errno */
errno = -ERANGE;
fclose(file);
}
return ret;
}

141
libcpumf/libcpumf_support.c Normal file
View File

@@ -0,0 +1,141 @@
/* Copyright IBM Corp. 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "lib/libcpumf.h"
#define SERVICELEVEL "/proc/service_levels"
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth)
{
char *linep = NULL;
bool rc = false;
size_t line_sz;
ssize_t nbytes;
FILE *fp;
fp = fopen(SERVICELEVEL, "r");
if (!fp)
err(EXIT_FAILURE, SERVICELEVEL);
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
int cnt = sscanf(linep, "CPU-MF: Counter facility:"
" version=%d.%d authorization=%x",
cfvn, csvn, auth);
if (cnt != 3) {
warnx("Can not parse line %s", linep);
goto out;
}
rc = true;
break;
}
}
out:
fclose(fp);
free(linep);
return rc;
}
bool libcpumf_have_cpumcf(void)
{
int cfvn, csvn, auth;
return libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
}
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
unsigned long *speed, int *basic_sz, int *diag_sz)
{
char *linep = NULL;
bool rc = true;
size_t line_sz;
ssize_t nbytes;
int hit = 0;
FILE *fp;
fp = fopen(SERVICELEVEL, "r");
if (!fp)
err(EXIT_FAILURE, SERVICELEVEL);
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
int ok;
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
ok = sscanf(linep, "CPU-MF: Sampling facility:"
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
min, max, speed);
if (ok != 3) {
warnx("Can not parse line %s", linep);
goto out;
}
hit += 1;
}
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
ok = sscanf(linep, "CPU-MF: Sampling facility:"
" mode=basic sample_size=%u", basic_sz);
if (ok != 1) {
warnx("Can not parse line %s", linep);
goto out;
}
hit += 1;
}
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
ok = sscanf(linep, "CPU-MF: Sampling facility:"
" mode=diagnostic sample_size=%u",
diag_sz);
if (ok != 1) {
warnx("Can not parse line %s", linep);
goto out;
}
hit += 1;
}
}
out:
fclose(fp);
free(linep);
if (hit != 3)
rc = false;
return rc;
}
bool libcpumf_have_cpumsf(void)
{
unsigned long a, b, c;
int basic_sz, diag_sz;
return libcpumf_cpumsf_info(&a, &b, &c, &basic_sz, &diag_sz);
}
bool libcpumf_have_sfb(void)
{
unsigned long a, b;
return libcpumf_sfb_info(&a, &b);
}
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max)
{
int rc = false;
FILE *fp;
fp = fopen(S390_CPUMSF_BUFFERSZ, "r");
if (!fp)
err(EXIT_FAILURE, "%s", S390_CPUMSF_BUFFERSZ);
if (fscanf(fp, "%lu,%lu", min, max) == 2)
rc = true;
fclose(fp);
return rc;
}

View File

@@ -1549,6 +1549,59 @@ int SK_EP11_reencipher_key(const struct sk_ext_ep11_lib *ep11_lib,
return -EIO;
}
memcpy(blob, lrb.payload, lrb.pllen);
/* re-encipher MACed SPKI */
rb.domain = domain;
lrb.domain = domain;
resp_len = sizeof(resp);
req_len = ep11.dll_xcpa_cmdblock(req, sizeof(req), XCP_ADM_REENCRYPT,
&rb, NULL, key_token + hdr->len,
key_token_length - hdr->len);
if (req_len < 0) {
sk_debug(debug, "Failed to build XCP command block");
return -EIO;
}
rv = ep11.dll_m_admin(resp, &resp_len, NULL, NULL, req, req_len, NULL,
0, ep11_lib->target);
if (rv != CKR_OK || resp_len == 0) {
sk_debug(debug, "Command XCP_ADM_REENCRYPT failed. "
"rc = 0x%lx, resp_len = %ld", rv, resp_len);
return -EIO;
}
rc = ep11.dll_xcpa_internal_rv(resp, resp_len, &lrb, &rv);
if (rc != 0) {
sk_debug(debug, "Failed to parse response. rc = %d", rc);
return -EIO;
}
if (rv != CKR_OK) {
sk_debug(debug, "Failed to re-encrypt the EP11 secure key. "
"rc = 0x%lx", rv);
switch (rv) {
case CKR_IBM_WKID_MISMATCH:
sk_debug(debug, "The EP11 secure key is currently "
"encrypted under a different master that does "
"not match the master key in the CURRENT "
"master key register of APQN %02X.%04X",
card, domain);
break;
}
return -EIO;
}
if (key_token_length - hdr->len != lrb.pllen) {
sk_debug(debug, "Re-encrypted EP11 secure key size has "
"changed: org-len: %lu, new-len: %lu",
hdr->len - sizeof(*hdr), lrb.pllen);
return -EIO;
}
memcpy(key_token + hdr->len, lrb.payload, lrb.pllen);
return 0;
}

View File

@@ -245,6 +245,11 @@ get_system_level()
read -r d_major d_minor d_minor2 <<< "$(split_version "$ver_str" "._-" 3)"
read -r k_ver k_patchlvl k_sublvl k_sublvl2 <<< "$(split_kver "$kver_str" 4)"
# Handle excessive sublevel numbers consistently
if [[ "$k_sublvl2" -gt 65535 ]] ; then
k_sublvl2=0
fi
# Apply distro-specific logic
case "$distro" in
"rhel")

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
.\" lszcrypt.8
.\"
.\" Copyright 2019 IBM Corp.
.\" Copyright IBM Corp. 2019, 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.
.\"
@@ -10,13 +10,14 @@
.\" nroff -man lszcrypt.8
.\" to process this source
.\"
.TH LSZCRYPT 8 "OCT 2020" "s390-tools"
.TH LSZCRYPT 8 "FEB 2022" "s390-tools"
.SH NAME
lszcrypt \- display zcrypt device and configuration information
.SH SYNOPSIS
.TP 9
.B lszcrypt
.RB "[ " -V " ] "
.RB "[" <filteroptions> "]"
.RB "[" -V "]"
[
.I <device-id>
[...]]
@@ -31,7 +32,12 @@ lszcrypt \- display zcrypt device and configuration information
.TP
.B lszcrypt -h
.TP
.B lszcrypt -s
.TP
.B lszcrypt -v
. TP
.B <filteroptions>
[--accelonly|--ccaonly|--ep11only] [--cardonly|--queueonly]
.SH DESCRIPTION
The
.B lszcrypt
@@ -109,8 +115,26 @@ B - indicate both (control and usage domain)
.B -h, --help
Displays help text and exits.
.TP 8
.B -s, --serial
Shows the serial numbers for CCA and EP11 crypto cards.
.TP 8
.B -v, --version
Displays version information and exits.
.TP 8
.B --accelonly
Show only information for cards/queues in Accelerator mode.
.TP 8
.B --ccaonly
Show only information for cards/queues in CCA-Coprocessor mode.
.TP 8
.B --ep11only
Show only information for cards/queues in EP11-Coprocessor mode.
.TP 8
.B --cardonly
Show only information for cards but no queue info.
.TP 8
.B --queueonly
Show only information for queues but no card info.
.SH LISTING DETAILS
Here is an explanation of the columns displayed. Please note that some
of the columns show up in verbose mode only.
@@ -123,7 +147,7 @@ dot for a queue line.
.B TYPE and HWTYPE
The HWTYPE is a numeric value showing which type of hardware the zcrypt
device driver presumes that this crypto card is. The currently known values
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6 and 13=CEX7.
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6, 13=CEX7 and 14=CEX8.
.br
The TYPE is a human readable value showing the hardware type and the basic
function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So
@@ -154,6 +178,9 @@ cryptographic operations. 'offline' is displayed when a card or queue
is switched to (software) offline. If a card is 'deconfigured' via
HMC, SE or chzcrypt the field shows 'deconfig'.
.br
A crypto card may also reach a 'checkstopped' state. lszcrypt shows
this as 'chkstop'.
.br
If a queue is not bound to a device driver there is no detailed
information available and thus the status shows only '-'.
.br
@@ -204,12 +231,17 @@ operations within the guests.
.B DRIVER
.br
Shows which card or queue device driver currently handles this crypto
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX7
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX8
hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware),
cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved
for use by kvm hypervisor for kvm guests and not accessible to host
applications). It is also valid to have no driver handling a queue which is
shown as a -no-driver- entry.
.SH NOTES
Use only one of the mode filtering options --accelonly, --ccaonly, --ep11only.
Same with card/queue filtering: Use only one of --cardonly, --queueonly.
However, one of the mode filtering options and one of the card/queue filtering
can be combined.
.SH EXAMPLES
.TP
.B lszcrypt

View File

@@ -1,7 +1,7 @@
/**
* lszcrypt - Display zcrypt devices and configuration settings
*
* Copyright IBM Corp. 2008, 2020
* Copyright IBM Corp. 2008, 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.
@@ -29,6 +29,11 @@
*/
static struct lszcrypt_l {
int verbose;
int showaccel;
int showcca;
int showep11;
int showcard;
int showqueue;
} l;
/*
@@ -39,6 +44,7 @@ static struct lszcrypt_l {
#define CAP_CCA "CCA Secure Key"
#define CAP_RNG "Long RNG"
#define CAP_EP11 "EP11 Secure Key"
#define CAP_APMMS "AP bus max message size limit %ld Kb"
/*
* Card types
@@ -95,6 +101,13 @@ static const struct util_prg prg = {
/*
* Configuration of command line options
*/
#define OPT_ACCELONLY 0x81
#define OPT_CCAONLY 0x82
#define OPT_EP11ONLY 0x83
#define OPT_CARDONLY 0x84
#define OPT_QUEUEONLY 0x85
static struct util_opt opt_vec[] = {
{
.option = {"bus", 0, NULL, 'b'},
@@ -113,6 +126,35 @@ static struct util_opt opt_vec[] = {
.option = {"verbose", 0, NULL, 'V'},
.desc = "Print verbose messages",
},
{
.option = {"accelonly", 0, NULL, OPT_ACCELONLY},
.flags = UTIL_OPT_FLAG_NOSHORT,
.desc = "Show only information from cards/queues in Accelerator mode",
},
{
.option = {"ccaonly", 0, NULL, OPT_CCAONLY},
.flags = UTIL_OPT_FLAG_NOSHORT,
.desc = "Show only information from cards/queues in CCA-Coprocessor mode",
},
{
.option = {"ep11only", 0, NULL, OPT_EP11ONLY},
.flags = UTIL_OPT_FLAG_NOSHORT,
.desc = "Show only information from cards/queues in EP11-Coprocessor mode",
},
{
.option = {"cardonly", 0, NULL, OPT_CARDONLY},
.flags = UTIL_OPT_FLAG_NOSHORT,
.desc = "Show only information from cards but no queue info",
},
{
.option = {"queueonly", 0, NULL, OPT_QUEUEONLY},
.flags = UTIL_OPT_FLAG_NOSHORT,
.desc = "Show only information from queues but no card info",
},
{
.option = {"serial", 0, NULL, 's'},
.desc = "Show the serial numbers for CCA and EP11 crypto cards",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
@@ -247,13 +289,94 @@ static void show_domains(void)
show_domains_util_rec(domain_array);
}
/*
* Show serialnumbers
*/
static void show_serialnumbers(void)
{
struct util_rec *rec = util_rec_new_wide("-");
struct dirent **dev_vec;
int i, count;
char *ap, *path, *device, *grp_dev, card[16], buf[256];
long config = -1, online = -1, chkstop = -1;
unsigned long facility;
/* check if ap driver is available */
ap = util_path_sysfs("bus/ap");
if (!util_path_is_dir(ap))
errx(EXIT_FAILURE, "Crypto device driver not available.");
/* define the record */
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 8, "CARD.DOM");
util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE");
util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE");
util_rec_def(rec, "status", UTIL_REC_ALIGN_LEFT, 10, "STATUS");
util_rec_def(rec, "serialnr", UTIL_REC_ALIGN_LEFT, 8, "SERIALNR");
/* scan the devices */
path = util_path_sysfs("devices/ap/");
count = util_scandir(&dev_vec, alphasort, path, "card[0-9a-fA-F]+");
if (count < 1)
errx(EXIT_FAILURE, "No crypto card devices found.");
util_rec_print_hdr(rec);
for (i = 0; i < count; i++) {
device = dev_vec[i]->d_name;
grp_dev = util_path_sysfs("devices/ap/%s", device);
if (!util_path_is_dir(grp_dev))
errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device);
if (!util_path_is_readable("%s/type", grp_dev) ||
!util_path_is_readable("%s/online", grp_dev))
goto next;
strcpy(card, device + 4);
util_rec_set(rec, "card", card);
util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev);
util_rec_set(rec, "type", buf);
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
if (facility & MASK_COPRO)
util_rec_set(rec, "mode", "CCA-Coproc");
else if (facility & MASK_EP11)
util_rec_set(rec, "mode", "EP11-Coproc");
else
goto next;
if (util_path_is_readable("%s/config", grp_dev))
util_file_read_l(&config, 10, "%s/config", grp_dev);
if (util_path_is_readable("%s/chkstop", grp_dev))
util_file_read_l(&chkstop, 10, "%s/chkstop", grp_dev);
if (util_path_is_readable("%s/online", grp_dev))
util_file_read_l(&online, 10, "%s/online", grp_dev);
if (config == 0) {
util_rec_set(rec, "status", "deconfig");
} else {
if (chkstop > 0)
util_rec_set(rec, "status", "chkstop");
else if (online > 0)
util_rec_set(rec, "status", "online");
else if (online == 0)
util_rec_set(rec, "status", "offline");
else
util_rec_set(rec, "status", "-");
}
if (util_file_read_line(buf, sizeof(buf), "%s/serialnr", grp_dev))
util_rec_set(rec, "serialnr", "-");
else {
buf[8] = '\0';
util_rec_set(rec, "serialnr", buf);
}
util_rec_print(rec);
next:
free(grp_dev);
}
free(path);
}
/*
* Show capability
*/
static void show_capability(const char *id_str)
{
unsigned long func_val;
long hwtype, id;
long hwtype, id, max_msg_size;
char *p, *ap, *dev, card[16], cbuf[256];
/* check if ap driver is available */
@@ -272,6 +395,9 @@ static void show_capability(const char *id_str)
/* If sysfs attribute is missing, set functions to 0 */
if (util_file_read_ul(&func_val, 16, "%s/ap_functions", dev))
func_val = 0x00000000;
/* try to read the ap bus max message size for this card */
if (util_file_read_l(&max_msg_size, 10, "%s/max_msg_size", dev))
max_msg_size = 0;
/* Skip devices, which are not supported by zcrypt layer */
if (!util_path_is_readable("%s/type", dev) ||
!util_path_is_readable("%s/online", dev)) {
@@ -289,9 +415,9 @@ static void show_capability(const char *id_str)
case 6:
case 8:
if (func_val & MASK_RSA4K)
printf("%s", CAP_RSA4K);
printf("%s\n", CAP_RSA4K);
else
printf("%s", CAP_RSA2K);
printf("%s\n", CAP_RSA2K);
break;
case 7:
case 9:
@@ -300,37 +426,39 @@ static void show_capability(const char *id_str)
printf("%s (%s)\n", CAP_CCA, cbuf);
else
printf("%s\n", CAP_CCA);
printf("%s", CAP_RNG);
printf("%s\n", CAP_RNG);
break;
case 10: /* CEX4S */
case 11: /* CEX5S */
case 12: /* CEX6S */
case 13: /* CEX7S */
case 14: /* CEX8S */
if (func_val & MASK_ACCEL) {
if (func_val & MASK_RSA4K)
printf("%s", CAP_RSA4K);
printf("%s\n", CAP_RSA4K);
else
printf("%s", CAP_RSA2K);
printf("%s\n", CAP_RSA2K);
} else if (func_val & MASK_COPRO) {
printf("%s\n", CAP_RSA4K);
if (cbuf[0])
printf("%s (%s)\n", CAP_CCA, cbuf);
else
printf("%s\n", CAP_CCA);
printf("%s", CAP_RNG);
printf("%s\n", CAP_RNG);
} else if (func_val & MASK_EP11) {
printf("%s", CAP_EP11);
printf("%s\n", CAP_EP11);
} else {
printf("Detailed capability information for %s (hardware type %ld) is not available.",
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
card, hwtype);
}
if (max_msg_size > 0)
printf(CAP_APMMS "\n", max_msg_size / 1024);
break;
default:
printf("Detailed capability information for %s (hardware type %ld) is not available.",
card, hwtype);
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
card, hwtype);
break;
}
printf("\n");
}
/*
@@ -375,7 +503,7 @@ static int read_driver(const char *dir, const char *subdir, char *buf, size_t bu
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
const char *sub_dev)
{
long config = -1, online = -1;
long config = -1, online = -1, chkstop = -1;
char buf[256];
unsigned long facility;
@@ -386,6 +514,8 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
if (util_path_is_readable("%s/%s/chkstop", grp_dev, sub_dev))
util_file_read_l(&chkstop, 10, "%s/%s/chkstop", grp_dev, sub_dev);
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
@@ -393,7 +523,9 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
if (config == 0) {
util_rec_set(rec, "status", "deconfig");
} else {
if (online > 0)
if (chkstop > 0)
util_rec_set(rec, "status", "chkstop");
else if (online > 0)
util_rec_set(rec, "status", "online");
else if (online == 0)
util_rec_set(rec, "status", "offline");
@@ -489,6 +621,9 @@ static void show_subdevice(struct util_rec *rec, const char *grp_dev,
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev)))
return;
if (!l.showqueue)
return;
util_rec_set(rec, "card", sub_dev);
read_subdev_rec_default(rec, grp_dev, sub_dev);
read_subdev_rec_verbose(rec, grp_dev, sub_dev);
@@ -516,7 +651,7 @@ static void show_subdevices(struct util_rec *rec, const char *grp_dev)
*/
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
{
long config = -1, online = -1;
long config = -1, online = -1, chkstop = -1;
char buf[256];
unsigned long facility;
@@ -537,12 +672,16 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
if (util_path_is_readable("%s/config", grp_dev))
util_file_read_l(&config, 10, "%s/config", grp_dev);
if (util_path_is_readable("%s/chkstop", grp_dev))
util_file_read_l(&chkstop, 10, "%s/chkstop", grp_dev);
if (util_path_is_readable("%s/online", grp_dev))
util_file_read_l(&online, 10, "%s/online", grp_dev);
if (config == 0) {
util_rec_set(rec, "status", "deconfig");
} else {
if (online > 0)
if (chkstop > 0)
util_rec_set(rec, "status", "chkstop");
else if (online > 0)
util_rec_set(rec, "status", "online");
else if (online == 0)
util_rec_set(rec, "status", "offline");
@@ -603,7 +742,7 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
*/
static void show_device(struct util_rec *rec, const char *device)
{
char *grp_dev, card[16];
char *grp_dev, card[16], type[16], t = '\0';
strcpy(card, &device[4]);
grp_dev = util_path_sysfs("devices/ap/%s", device);
@@ -621,11 +760,21 @@ static void show_device(struct util_rec *rec, const char *device)
}
util_rec_set(rec, "card", card);
if (util_file_read_line(type, sizeof(type), "%s/type", grp_dev) == 0)
t = type[strlen(type) - 1];
if ((t == 'A' && !l.showaccel) ||
(t == 'C' && !l.showcca) ||
(t == 'P' && !l.showep11))
goto out_free;
read_rec_default(rec, grp_dev);
read_rec_verbose(rec, grp_dev);
util_rec_print(rec);
show_subdevices(rec, grp_dev);
if (l.showcard)
util_rec_print(rec);
if (l.showqueue)
show_subdevices(rec, grp_dev);
out_free:
free(grp_dev);
}
@@ -799,9 +948,27 @@ int main(int argc, char **argv)
case 'd':
show_domains();
return EXIT_SUCCESS;
case 's':
show_serialnumbers();
return EXIT_SUCCESS;
case 'V':
l.verbose++;
break;
case OPT_ACCELONLY:
l.showaccel = 1;
break;
case OPT_CCAONLY:
l.showcca = 1;
break;
case OPT_EP11ONLY:
l.showep11 = 1;
break;
case OPT_CARDONLY:
l.showcard = 1;
break;
case OPT_QUEUEONLY:
l.showqueue = 1;
break;
case 'h':
util_prg_print_help();
util_opt_print_help();
@@ -815,6 +982,29 @@ int main(int argc, char **argv)
return EXIT_FAILURE;
}
}
switch (l.showaccel + l.showcca + l.showep11) {
case 0:
l.showaccel = l.showcca = l.showep11 = 1;
break;
case 1:
break;
default:
warnx("Only one of --accelonly or --ccaonly or --ep11only can be specified");
return EXIT_FAILURE;
}
switch (l.showcard + l.showqueue) {
case 0:
l.showcard = l.showqueue = 1;
break;
case 1:
break;
default:
warnx("Only one of --cardonly or --queueonly can be specified");
return EXIT_FAILURE;
}
if (optind == argc)
show_devices_all();
else

View File

@@ -1,6 +1,6 @@
.\" zcryptctl.8
.\"
.\" Copyright 2018 IBM Corp.
.\" Copyright 2018, 2022 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.
.\"
@@ -10,7 +10,7 @@
.\" nroff -man zcryptctl.8
.\" to process this source
.\"
.TH ZCRYPTCTL 8 "AUG 2018" "s390-tools"
.TH ZCRYPTCTL 8 "JAN 2022" "s390-tools"
.SH NAME
zcryptctl \- display information and administrate zcrypt multiple device nodes
.SH SYNOPSIS
@@ -35,6 +35,11 @@ zcryptctl \- display information and administrate zcrypt multiple device nodes
.B deldom
.I node-name domain-nr
.TP
.B zcryptctl addctrl
.R |
.B delctrl
.I node-name domain-nr
.TP
.B zcryptctl addioctl
.R |
.B delioctl
@@ -57,6 +62,7 @@ driver. Each zcrypt device node can be restricted in terms of crypto
cards, domains, and available ioctls. Such a device node can be used
as a base for container solutions like Docker to control and restrict
the access to crypto resources.
See the NOTES section below for information on control domains.
.SH COMMANDS
.TP 8
.B zcryptctl list
@@ -96,6 +102,14 @@ Update the filter for the specified zcrypt device node and add or
delete a domain to be accessible through this node. The symbol
\fBALL\fP can be used to enable or disable all domains.
.TP
.B zcryptctl addctrl
.R |
.B delctrl
.I node-name domain-nr
Update the filter for the specified zcrypt device node and add or
delete a control domain to be accessible through this node. The symbol
\fBALL\fP can be used to enable or disable all domains.
.TP
.B zcryptctl addioctl
.R |
.B delioctl
@@ -116,19 +130,20 @@ line and the settings are applied. Syntax is simple:
.IP "node=<node-name>"
.IP "aps=<list of ap numbers separated by space, tab or ','>"
.IP "doms=<list of domain numbers separated by space, tab or ','>"
.IP "ctrls=<list of control domain numbers separated by space, tab or ','>"
.IP "ioctls=<list of ioctl as numeric or symbolic number separated by space, tab or ','>"
.LP
Empty lines are ignored and the '#' marks the rest of the
line as comment.
.LP
The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP,
\fBdoms=\fP and \fBioctls=\fP lines customize the previously created
node. The symbol \fBALL\fP is also recognized for aps, doms, and
ioctls.
\fBdoms=\fP, \fBctrls=\fP and \fBioctls=\fP lines customize the
previously created node. The symbol \fBALL\fP is also recognized for
aps, doms, and ioctls.
.LP
Each action must fit into one line, spreading over multiple lines is
not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP
and \fBioctls=\fP lines to customize the very same node.
not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP,
\fBctrls=\fP and \fBioctls=\fP lines to customize the very same node.
.LP
Processing stops when a line cannot be parsed or the current action
fails. In this case the exit status is non zero but the successful
@@ -139,6 +154,17 @@ actions until the failure occurs are not rolled back.
List the current configuration in a form suitable for input to the
\fBzcryptctl config\fP command.
.LP
.SH NOTES
Control domain filtering is only supported for custom device
<nodename> if the \fBadmask\fP file in sysfs under
/sys/class/zcrypt/<nodename>/admask exists. If this file does not
exist, the kernel is too old and does not support control command
filtering. This is the same effect as setting the control domain mask
to ALL. Note that, even though you can allow more than available to
the system, you can only send control commands to control domains
available to the system.
.SH EXIT STATUS
On successful completion of the command the exit status is 0. A non
zero return code (and some kind of failure message) is emitted if the

View File

@@ -2,7 +2,7 @@
* zcryptctl - Maintain zcrypt multi device nodes.
*
* by Harald Freudenberger <freude@linux.ibm.com>
* Copyright IBM Corp. 2018
* Copyright IBM Corp. 2018, 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.
@@ -58,6 +58,8 @@
#define CMD_DEL_IOCTL 0x0009
#define CMD_CONFIG 0x000A
#define CMD_LISTCONFIG 0x000B
#define CMD_ADD_CTRL 0x000C
#define CMD_DEL_CTRL 0x000D
/*
* Program configuration
@@ -70,7 +72,7 @@ static const struct util_prg prg = {
{
.owner = "IBM Corp.",
.pub_first = 2018,
.pub_last = 2018,
.pub_last = 2022,
},
UTIL_PRG_COPYRIGHT_END
}
@@ -345,6 +347,18 @@ static int cmd_list(int cmd,
if (test_bit(i, buf))
printf("%c%d", n++ == 0 ? tab : ',', i);
putchar('\n');
if (cmd == CMD_LISTCONFIG)
printf(" ctrls =");
else
printf(" control domains:");
if (read_dn_attr(de->d_name, "admask", buf, sizeof(buf)) != 0)
errx(EXIT_FAILURE,
"Could not fetch admask attribute from sysfs for zcrypt node '%s'",
de->d_name);
for (i = n = 0; i < MAX_ZDEV_DOMAINS_EXT; i++)
if (test_bit(i, buf))
printf("%c%d", n++ == 0 ? tab : ',', i);
putchar('\n');
if (cmd == CMD_LISTCONFIG)
printf(" ioctls =");
else
@@ -526,6 +540,52 @@ static int cmd_add_del_dom(int cmd, const char *node, const char *arg)
return 0;
}
static void add_del_ctrl(int cmd, const char *node, int dom)
{
int rc;
char buf[PATH_MAX];
if (cmd == CMD_ADD_CTRL)
sprintf(buf, "+%d", dom);
else
sprintf(buf, "-%d", dom);
rc = write_dn_attr(node, "admask", buf);
if (rc != 0)
errx(EXIT_FAILURE,
"Could not write into sysfs entry to %s domain %d for zdev node '%s'",
cmd == CMD_ADD_CTRL ? "add" : "remove", dom, node);
}
static int cmd_add_del_ctrl(int cmd, const char *node, const char *arg)
{
int dom, all = 0;
if (strcasecmp(arg, "ALL") == 0) {
all = 1;
} else {
if (sscanf(arg, "%i", &dom) != 1)
errx(EXIT_FAILURE,
"Invalid domain argument '%s'", arg);
if (dom < 0 || dom >= MAX_ZDEV_DOMAINS_EXT)
errx(EXIT_FAILURE,
"Domain argument '%s' out of range [0..%d]",
arg, MAX_ZDEV_DOMAINS_EXT - 1);
}
if (!all) {
add_del_ctrl(cmd, node, dom);
printf("Control domain %d %s\n", dom,
(cmd == CMD_ADD_CTRL ? "added" : "removed"));
} else {
for (dom = 0; dom < MAX_ZDEV_DOMAINS_EXT; dom++)
add_del_ctrl(cmd, node, dom);
printf("All control domains %s\n",
(cmd == CMD_ADD_CTRL ? "added" : "removed"));
}
return 0;
}
static void add_del_ioctl(int cmd, const char *node, int ioctlnr)
{
int rc;
@@ -694,12 +754,34 @@ static int cmd_config(int cmd _UNUSED_,
break;
if (!_match_string(&p, buf))
errx(EXIT_FAILURE,
"Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'",
"Missing argument(s) for doms=... at '%-8.8s...' in line %d '%s'",
p, nr, line);
cmd_add_del_dom(CMD_ADD_DOM, node, buf);
while (isblank(*p) || *p == ',')
p++;
}
} else if (_match_keyword(&p, "ctrls")) {
if (!havenode)
errx(EXIT_FAILURE,
"Missing node=... before processing any ctrls=... statements in line %d '%s'",
nr, line);
if (!_match_character(&p, '='))
errx(EXIT_FAILURE,
"Missing '=' at '%-8.8s...' in line %d '%s'",
p, nr, line);
while (1) {
while (isspace(*p))
p++;
if (*p == '\0' || *p == '#')
break;
if (!_match_string(&p, buf))
errx(EXIT_FAILURE,
"Missing argument(s) for ctrls=... at '%-8.8s...' in line %d '%s'",
p, nr, line);
cmd_add_del_ctrl(CMD_ADD_CTRL, node, buf);
while (isblank(*p) || *p == ',')
p++;
}
} else if (_match_keyword(&p, "ioctls")) {
if (!havenode)
errx(EXIT_FAILURE,
@@ -810,13 +892,35 @@ static struct zcryptctl_cmds_s {
.cmd = CMD_DEL_DOM,
.command = "deldom",
.function = cmd_add_del_dom,
.usage = "zcryptctl deldom <adapter>",
.usage = "zcryptctl deldom <domain>",
.description =
"Update the filter for the specified zcrypt device node and\n"
"remove a crypto domain from the allowed domains list. The\n"
"domain argument may be a number in the range 0-255 or the\n"
"symbol ALL.",
},
{
.cmd = CMD_ADD_CTRL,
.command = "addctrl",
.function = cmd_add_del_ctrl,
.usage = "zcryptctl addctrl <domain>",
.description =
"Update the filter for the specified zcrypt device node and\n"
"add a crypto control domain to be accessible via this node.\n"
"The domain argument may be a number in the range 0-255 or\n"
"the symbol ALL.",
},
{
.cmd = CMD_DEL_CTRL,
.command = "delctrl",
.function = cmd_add_del_ctrl,
.usage = "zcryptctl delctrl <domain>",
.description =
"Update the filter for the specified zcrypt device node and\n"
"remove a crypto control domain from the allowed domains list.\n"
"The domain argument may be a number in the range 0-255 or\n"
"the symbol ALL.",
},
{
.cmd = CMD_ADD_IOCTL,
.command = "addioctl",
@@ -1003,6 +1107,19 @@ int main(int argc, char *argv[])
argv[optind + 1],
argv[optind + 2]);
break;
case CMD_ADD_CTRL:
case CMD_DEL_CTRL:
if (optind + 1 >= argc)
errx(EXIT_FAILURE, "Missing node name argument");
if (optind + 2 >= argc)
errx(EXIT_FAILURE, "Missing domain argument");
if (check_nodename(argv[optind + 1]) != 0)
errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'",
argv[optind + 1]);
rc = zcryptctl_cmds[cmdindex].function(c,
argv[optind + 1],
argv[optind + 2]);
break;
case CMD_ADD_IOCTL:
case CMD_DEL_IOCTL:
if (optind + 1 >= argc)

View File

@@ -1,7 +1,7 @@
/*
* zcryptstats - Show usage statistics of IBM Crypto Express adapters
*
* Copyright IBM Corp. 2019
* Copyright IBM Corp. 2019, 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.
@@ -148,8 +148,9 @@ struct chsc_cmb_area {
#define CRYPTO_TYPE_CEX5S 11
#define CRYPTO_TYPE_CEX6S 12
#define CRYPTO_TYPE_CEX7S 13
#define CRYPTO_TYPE_CEX8S 14
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX7S
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX8S
struct crypto_counter {
const char *name;
@@ -236,8 +237,8 @@ static const struct crypto_mode mode_pcica[1] = {
.counters = counter_pcica },
};
#define NUM_CEX4567_MODES 11
static const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
#define NUM_CEX45678_MODES 11
static const struct crypto_mode mode_cex45678[NUM_CEX45678_MODES] = {
{ 0 },
{ 0 },
{ 0 },
@@ -257,7 +258,7 @@ static const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
.counters = counter_ep11 },
};
#define NUM_CRYPTO_TYPES 14
#define NUM_CRYPTO_TYPES 15
static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
{ 0 },
{ 0 },
@@ -276,14 +277,16 @@ static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
.modes = mode_accel },
{ .name = "CEX3C", .num_modes = NUM_COPROC_MODES,
.modes = mode_coproc },
{ .name = "CEX4", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX5", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX6", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX7", .num_modes = NUM_CEX4567_MODES,
.modes = mode_cex4567 },
{ .name = "CEX4", .num_modes = NUM_CEX45678_MODES,
.modes = mode_cex45678 },
{ .name = "CEX5", .num_modes = NUM_CEX45678_MODES,
.modes = mode_cex45678 },
{ .name = "CEX6", .num_modes = NUM_CEX45678_MODES,
.modes = mode_cex45678 },
{ .name = "CEX7", .num_modes = NUM_CEX45678_MODES,
.modes = mode_cex45678 },
{ .name = "CEX8", .num_modes = NUM_CEX45678_MODES,
.modes = mode_cex45678 },
};
@@ -2424,4 +2427,3 @@ out:
return rc;
}

View File

@@ -804,17 +804,17 @@ void ccw_unblacklist_id_range(const char *range)
static char ***id_bitmap_new(void)
{
return misc_malloc(sizeof(char **) * CSSID_MAX);
return misc_malloc(sizeof(char **) * (CSSID_MAX + 1));
}
static void id_bitmap_free(char ***id_bitmap)
{
unsigned int cssid, ssid;
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
for (cssid = 0; cssid <= CSSID_MAX; cssid++) {
if (!id_bitmap[cssid])
continue;
for (ssid = 0; ssid < SSID_MAX; ssid++)
for (ssid = 0; ssid <= SSID_MAX; ssid++)
free(id_bitmap[cssid][ssid]);
free(id_bitmap[cssid]);
}
@@ -965,15 +965,15 @@ static struct util_list *cio_ignore_get_ranges(bool autoconf)
ranges = strlist_new();
id_bitmap = id_bitmap_collect(autoconf);
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
for (cssid = 0; cssid <= CSSID_MAX; cssid++) {
if (!id_bitmap[cssid])
continue;
for (ssid = 0; ssid < SSID_MAX; ssid++) {
for (ssid = 0; ssid <= SSID_MAX; ssid++) {
if (!id_bitmap[cssid][ssid])
continue;
first = NULL;
last = NULL;
for (devno = 0; devno < DEVNO_MAX; devno++) {
for (devno = 0; devno <= DEVNO_MAX; devno++) {
if (!id_bitmap_get(id_bitmap, cssid, ssid,
devno)) {
if (first) {

View File

@@ -556,7 +556,6 @@ static int open_dump(void)
}
if (mv_dumper_read() != 0)
return -ENODEV;
zg_close(g.fh);
return 0;
}

View File

@@ -280,7 +280,7 @@ off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
{
off_t rc;
if (off >= zg_fh->sb.st_size)
if (S_ISREG(zg_fh->sb.st_mode) && off >= zg_fh->sb.st_size)
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
rc = lseek(zg_fh->fh, off, SEEK_SET);

View File

@@ -68,11 +68,11 @@ stage3.exec: head.o stage3.o kdump3.o libc.o ebcdic.o ebcdic_conv.o sclp.o \
}' \
); \
case $$STAGE in \
0) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0";; \
1) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0x18";; \
1b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0xE000";; \
2) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage2.lds";; \
3) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3.lds";; \
0) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0";; \
1) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0x18";; \
1b) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0xE000";; \
2) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage2.lds";; \
3) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3.lds";; \
esac; \
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
@@ -110,7 +110,7 @@ stage3.bin: stage3.exec
$< $@
data.o: $(FILES)
$(LD) $(NO_PIE_LDFLAGS) -r -b binary -o data.o $(FILES)
$(LINK) $(NO_PIE_LDFLAGS) -static -nostdlib -Wl,--relocatable -Wl,--format,binary -o data.o $(FILES)
data.h: data.o
rm -f data.h

View File

@@ -13,6 +13,8 @@
#ifndef JOB_H
#define JOB_H
#include <stdbool.h>
#include "disk.h"
#include "zipl.h"
@@ -46,6 +48,8 @@ struct job_common_ipl_data {
address_t image_addr;
address_t parm_addr;
address_t ramdisk_addr;
bool optional;
bool ignore;
};
struct job_ipl_data {

View File

@@ -16,7 +16,7 @@
#define SCAN_SECTION_NUM 9
#define SCAN_KEYWORD_NUM 22
#define SCAN_KEYWORD_NUM 23
#define SCAN_KEYWORD_ONLY_NUM 1
#define SCAN_AUTOMENU_NAME "zipl-automatic-menu"
@@ -52,6 +52,7 @@ enum scan_keyword_id {
scan_keyword_defaultauto = 19,
scan_keyword_kdump = 20,
scan_keyword_secure = 21,
scan_keyword_optional = 22,
};
enum scan_section_type {

View File

@@ -447,6 +447,23 @@ This option cannot be used together with either
.BR 'segment' .
.PP
.B optional
=
.IR 0 / 1
(configuration only)
.IP
.B Configuration section:
.br
If this option is set to 1 the configuration section will only be included in
the boot menu if the referenced image file exists, and running
.B zipl
will not fail if the image file is missing.
The default value for
.B 'optional'
is 0.
.PP
.B parameters
=
.I kernel\-parameters

View File

@@ -394,6 +394,10 @@ store_stage2_menu(void* data, size_t size, struct job_data* job)
return 0;
/* Config texts */
for (i = 0; i < job->data.menu.num; i++) {
if (job->data.menu.entry[i].data.ipl.common.ignore) {
params->config[job->data.menu.entry[i].pos] = 0;
continue;
}
const char *kdump_str = "";
if (job->data.menu.entry[i].data.ipl.is_kdump)
kdump_str = " (kdump)";

View File

@@ -1089,6 +1089,12 @@ build_program_table(int fd, char *filename, struct job_data *job,
for (i=0; i < job->data.menu.num; i++) {
switch (job->data.menu.entry[i].id) {
case job_ipl:
if (job->data.menu.entry[i].data.ipl.common.ignore) {
printf("Skipping #%d: IPL section '%s' (missing files)\n",
job->data.menu.entry[i].pos,
job->data.menu.entry[i].name);
break;
}
printf("Adding #%d: IPL section '%s'%s",
job->data.menu.entry[i].pos,
job->data.menu.entry[i].name,

View File

@@ -758,7 +758,8 @@ static void error_text_section(const char *text, const char *section, const char
static int
check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
check_common_ipl_data(struct job_common_ipl_data *common, const char *section,
bool may_ignore)
{
uint64_t max_parm_size, len;
char *buffer = NULL;
@@ -768,10 +769,16 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
if (common->image != NULL) {
rc = misc_read_file(common->image, &buffer, &size, 0);
if (rc) {
error_text_section("Image file", section, common->image);
if (may_ignore && common->optional) {
printf("Optional section '%s': Missing image file '%s'\n",
section, common->image);
error_clear_reason();
common->ignore = true;
rc = 0;
goto skip_image;
}
return rc;
}
if (size < MAX_COMMAND_LINE_SIZE + sizeof(uint64_t)) {
error_text_section("Image file", section, common->image);
return -1;
@@ -789,12 +796,19 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
return -1;
}
}
skip_image:
if (common->ramdisk != NULL) {
rc = misc_check_readable_file(common->ramdisk);
if (rc) {
error_text_section("Ramdisk file", section, common->ramdisk);
return rc;
if (common->optional) {
printf("Optional section '%s': Missing ramdisk file '%s'\n",
section, common->ramdisk);
error_clear_reason();
common->ignore = true;
rc = 0;
} else {
return rc;
}
}
}
return 0;
@@ -802,13 +816,17 @@ check_common_ipl_data(struct job_common_ipl_data *common, const char *section)
static int
check_job_ipl_data(struct job_ipl_data *ipl, char *name,
struct job_envblk_data *envblk)
struct job_envblk_data *envblk, bool may_ignore)
{
int rc;
rc = check_common_ipl_data(&ipl->common, name);
rc = check_common_ipl_data(&ipl->common, name, may_ignore);
if (rc)
return rc;
if (ipl->common.ignore)
return 0;
return finalize_ipl_address_data(ipl, name, envblk);
}
@@ -887,9 +905,15 @@ check_job_menu_data(struct job_menu_data *menu, struct job_envblk_data *envblk)
case job_ipl:
rc = check_job_ipl_data(&menu->entry[i].data.ipl,
menu->entry[i].name,
envblk);
envblk, true);
if (rc)
return rc;
/* default_pos is 1-indexed */
if (menu->default_pos == i + 1 &&
menu->entry[i].data.ipl.common.ignore) {
error_text("Cannot ignore default entry");
return -1;
}
break;
case job_print_usage:
case job_print_version:
@@ -917,7 +941,7 @@ check_job_ipl_tape_data(struct job_ipl_tape_data *ipl, char* name)
return rc;
}
}
rc = check_common_ipl_data(&ipl->common, name);
rc = check_common_ipl_data(&ipl->common, name, false);
if (rc)
return rc;
return finalize_common_address_data(&ipl->common, name);
@@ -1016,7 +1040,7 @@ check_job_data(struct job_data* job)
break;
case job_ipl:
rc = check_job_ipl_data(&job->data.ipl, job->name,
&job->envblk);
&job->envblk, false);
break;
case job_menu:
rc = check_job_menu_data(&job->data.menu, &job->envblk);
@@ -1295,6 +1319,12 @@ get_job_from_section_data(char* data[], struct job_data* job, char* section)
if (rc)
return rc;
}
job->data.ipl.common.optional = false;
if (data[(int) scan_keyword_optional] != NULL) {
job->data.ipl.common.optional =
atoi(data[(int) scan_keyword_optional]) == 1;
}
job->data.ipl.common.ignore = false;
break;
case section_ipl_tape:
/* Tape IPL job */

View File

@@ -47,45 +47,45 @@ enum scan_key_state scan_key_table[SCAN_SECTION_NUM][SCAN_KEYWORD_NUM] = {
* ult to tofs e mete file isk ent et pt out ultm dump
* rs enu
*
* targ targ targ targ targ defa kdum secu
* etba etty etge etbl etof ulta p re
* targ targ targ targ targ defa kdum secu opti
* etba etty etge etbl etof ulta p re onal
* se pe omet ocks fset uto
* ry ize
*/
/* default auto */
{opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
opt, opt, opt, opt, opt, opt, inv, opt},
opt, opt, opt, opt, opt, opt, inv, opt, inv},
/* default menu */
{inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req, inv, inv,
inv, inv, inv, inv, inv, inv, inv, opt},
inv, inv, inv, inv, inv, inv, inv, opt, inv},
/* default section */
{req, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv,
inv, inv, inv, inv, inv, inv, inv, opt},
inv, inv, inv, inv, inv, inv, inv, opt, inv},
/* ipl */
{inv, inv, inv, req, opt, opt, opt, inv, req, inv, inv, inv, inv, inv,
opt, opt, opt, opt, opt, inv, opt, opt},
opt, opt, opt, opt, opt, inv, opt, opt, opt},
/* segment load */
{inv, inv, inv, inv, inv, inv, inv, req, req, inv, inv, inv, inv, inv,
inv, inv, inv, inv, inv, inv, inv, inv},
inv, inv, inv, inv, inv, inv, inv, inv, inv},
/* part dump */
{inv, req, inv, inv, inv, inv, inv, inv, opt, inv, inv, inv, inv, inv,
inv, inv, inv, inv, inv, inv, inv, inv},
inv, inv, inv, inv, inv, inv, inv, inv, inv},
/* fs dump */
{inv, inv, req, inv, opt, opt, inv, inv, req, inv, inv, inv, inv, inv,
inv, inv, inv, inv, inv, inv, inv, inv},
inv, inv, inv, inv, inv, inv, inv, inv, inv},
/* ipl tape */
{inv, inv, inv, req, opt, opt, opt, inv, inv, inv, inv, inv, req, inv,
inv, inv, inv, inv, inv, inv, inv, inv},
inv, inv, inv, inv, inv, inv, inv, inv, inv},
/* multi volume dump */
{inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, inv, req,
inv, inv, inv, inv, inv, inv, inv, inv}
inv, inv, inv, inv, inv, inv, inv, inv, inv}
};
/* Determines which keyword may be present in a menu section */
static enum scan_key_state scan_menu_key_table[SCAN_KEYWORD_NUM] = {
/* menu section */
opt, inv, inv, inv, inv, inv, inv, inv, req, opt, opt, inv, inv, inv,
opt, opt, opt, opt, opt, inv, inv, opt
opt, opt, opt, opt, opt, inv, inv, opt, inv
};
/* Mapping of keyword IDs to strings */
@@ -114,6 +114,7 @@ static const struct {
{ "tape", scan_keyword_tape},
{ "kdump", scan_keyword_kdump},
{ "secure", scan_keyword_secure},
{ "optional", scan_keyword_optional},
};
/* List of keywords that are used without an assignment */
@@ -794,102 +795,6 @@ static int sort_bls_fields(struct misc_file_buffer *file, char *filename)
return 0;
}
int
scan_bls(const char* blsdir, struct scan_token** token, int scan_size)
{
int count = 0;
int size, remaining = 0, n, current, rc = -1;
struct scan_token* buffer;
struct scan_token* array = *token;
struct dirent** bls_entries;
struct misc_file_buffer file;
struct stat sb;
char filename[PATH_MAX];
if (!(stat(blsdir, &sb) == 0 && S_ISDIR(sb.st_mode)))
return 0;
n = scandir(blsdir, &bls_entries, bls_filter, bls_sort);
if (n <= 0)
return n;
while (array[count].id != 0)
count++;
remaining = scan_size - count;
/* The array of scanned tokens is allocated when the zipl config file is
* parsed. Its size is a multiple of INITIAL_ARRAY_LENGTH so it may have
* enough space to scan all the tokens that are defined in the BLS files.
* Calculate if is enough assuming that a BLS fragment can contain up to
* 4 tokens: a section heading and 3 keywords (image, ramdisk, parameter).
*/
if (remaining < n * 4) {
size = scan_size - remaining + (n * 4);
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
if (!buffer)
goto err;
memset(buffer, 0, size * sizeof(struct scan_token));
memcpy(buffer, array, count * sizeof(struct scan_token));
} else {
buffer = array;
}
while (n--) {
sprintf(filename, "%s/%s", blsdir, bls_entries[n]->d_name);
printf("Using BLS config file '%s'\n", filename);
rc = misc_get_file_buffer(filename, &file);
if (rc)
goto err;
rc = sort_bls_fields(&file, filename);
if (rc)
goto err;
while ((size_t)file.pos < file.length) {
current = misc_get_char(&file, 0);
switch (current) {
case '#':
file.pos++;
skip_line(&file);
break;
case EOF:
break;
case '\t':
case '\n':
case '\0':
case ' ':
file.pos++;
break;
default:
rc = scan_bls_field(&file, buffer, &count);
if (rc) {
error_reason("Incorrect BLS field in "
"config file %s\n", filename);
goto err;
}
break;
}
}
misc_free_file_buffer(&file);
free(bls_entries[n]);
}
*token = buffer;
rc = 0;
err:
if (n > 0) {
do {
free(bls_entries[n]);
} while (n-- > 0);
}
free(bls_entries);
return rc;
}
/* Search scanned tokens SCAN for a section/menu heading (according to
* TYPE) of the given NAME, beginning at token OFFSET. Return the index of
@@ -1358,6 +1263,163 @@ scan_get_section_keywords(struct scan_token* scan, int* index, char* name,
}
/*
* Get the default target defined either in the defaultboot section or the
* menu section for the defaultmenu if there is a default menu defined.
*/
static char *scan_get_default_target(struct scan_token *scan)
{
int keyword_line[SCAN_KEYWORD_NUM];
char *keyword[SCAN_KEYWORD_NUM];
int num_line[BOOT_MENU_ENTRIES];
char *num[BOOT_MENU_ENTRIES];
int i, j, rc;
/* Find the defaultboot section */
i = scan_find_section(scan, DEFAULTBOOT_SECTION,
scan_id_section_heading, 0);
if (i < 0) {
error_reason("No '%s' section found and no section specified on command line",
DEFAULTBOOT_SECTION);
return NULL;
}
/* Get keyword and number data */
rc = scan_get_section_keywords(scan, &i, DEFAULTBOOT_SECTION, keyword,
keyword_line, NULL, NULL);
if (rc) {
error_reason("Could not get keywords for '%s' section",
DEFAULTBOOT_SECTION);
return NULL;
}
/* Check if a defaultmenu is set */
i = (int) scan_keyword_defaultmenu;
if (keyword[i]) {
j = scan_find_section(scan, keyword[i],
scan_id_menu_heading, 0);
if (j < 0) {
error_reason("No '%s' section found", keyword[i]);
return NULL;
}
/* Get keyword and number data */
rc = scan_get_section_keywords(scan, &j, keyword[i], keyword,
keyword_line, num, num_line);
if (rc) {
error_reason("Could not get keywords for '%s' section",
keyword[i]);
return NULL;
}
}
return keyword[(int) scan_keyword_target];
}
#define BLS_TOKEN_MAX 5 /* section heading, image, ramdisk, parameter, target */
int scan_bls(const char *blsdir, struct scan_token **token, int scan_size)
{
int size, remaining = 0, n, current, rc = -1, count = 0;
struct scan_token *array = *token;
struct misc_file_buffer file;
struct dirent **bls_entries;
struct scan_token *buffer;
char filename[PATH_MAX];
char *target = NULL;
struct stat sb;
if (!(stat(blsdir, &sb) == 0 && S_ISDIR(sb.st_mode)))
return 0;
n = scandir(blsdir, &bls_entries, bls_filter, bls_sort);
if (n <= 0)
return n;
while (array[count].id != 0)
count++;
remaining = scan_size - count;
/* The array of scanned tokens is allocated when the zipl config file is
* parsed. Its size is a multiple of INITIAL_ARRAY_LENGTH so it may have
* enough space to scan all the tokens that are defined in the BLS files.
* Calculate if is enough assuming that a BLS fragment can contain up to
* BLS_TOKEN_MAX.
*/
if (remaining < n * BLS_TOKEN_MAX) {
size = scan_size - remaining + (n * BLS_TOKEN_MAX);
buffer = (struct scan_token *)misc_malloc(size * sizeof(struct scan_token));
if (!buffer)
goto err;
memset(buffer, 0, size * sizeof(struct scan_token));
memcpy(buffer, array, count * sizeof(struct scan_token));
} else {
buffer = array;
}
target = scan_get_default_target(array);
while (n--) {
sprintf(filename, "%s/%s", blsdir, bls_entries[n]->d_name);
printf("Using BLS config file '%s'\n", filename);
rc = misc_get_file_buffer(filename, &file);
if (rc)
goto err;
rc = sort_bls_fields(&file, filename);
if (rc)
goto err;
while ((size_t)file.pos < file.length) {
current = misc_get_char(&file, 0);
switch (current) {
case '#':
file.pos++;
skip_line(&file);
break;
case EOF:
break;
case '\t':
case '\n':
case '\0':
case ' ':
file.pos++;
break;
default:
rc = scan_bls_field(&file, buffer, &count);
if (rc) {
error_reason("Incorrect BLS field in config file %s\n",
filename);
goto err;
}
break;
}
}
if (target != NULL)
scan_append_keyword_assignment(buffer, &count,
scan_keyword_target,
target);
misc_free_file_buffer(&file);
free(bls_entries[n]);
}
*token = buffer;
rc = 0;
err:
if (n > 0) {
do {
free(bls_entries[n]);
} while (n-- > 0);
}
free(bls_entries);
return rc;
}
/* Check section at INDEX for compliance with config file rules. Upon success,
* return zero and advance INDEX to point to the end of the section. Return
* non-zero otherwise. */

View File

@@ -1,4 +1,4 @@
.\" Copyright IBM Corp. 2018
.\" Copyright IBM Corp. 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.
.\"
@@ -17,7 +17,7 @@
. PD
..
.
.TH zpcictl 8 "Oct 2018" s390-tools zpcictl
.TH zpcictl 8 "Mar 2022" s390-tools zpcictl
.
.SH NAME
zpcictl - Manage PCI devices on IBM Z
@@ -52,7 +52,45 @@ device (e.g.
.SH OPTIONS
.SS Error Handling Options
.OD reset "" "DEVICE"
Reset and re-initialize the PCI device.
Reset and re-initialize the PCI device and report a device error to the Support
Element (SE). The reset consists of a controlled shutdown and a subsequent
re-enabling of the device from the shut off state. This process destroys and
then re-creates higher level interfaces such as network interfaces and block
devices. This reset is disruptive and often requires manual intervention on
multiple layers. In particular, network interfaces that are part of a bonded
interface must be re-added to the bond after the reset. Similarly, block
devices backed by an NVMe that are part of a software RAID must be re-synced by
re-adding to the RAID after resetting the NVMe.
Use this reset option only if the less disruptive automatic recovery mechanism
is not supported by your kernel or it failed to restore the device's
functionality. Unsuccessful automatic recovery can result in kernel messages
indicating required manual intervention. If the device is malfunctioning
without automatic recovery being triggered, consider using the \fB--reset-fw\fR
option to trigger a less disruptive automatic recovery through
a firmware-driven reset.
.PP
.
.OD reset-fw "" "DEVICE"
Reset the PCI device using a firmware-driven reset that also reports a device
error on the Support Element (SE). If supported by your kernel, automatic recovery
re-initializes the device after the firmware reports a successful device reset.
Use this option if the device is malfunctioning and automatic recovery is
supported by the kernel but was not triggered. This condition can occur if the
error is not detected by the low level PCI interfaces. A successful automatic
recovery after the firmware-driven reset, is less disruptive than the full
reset that is performed by the \fB--reset\fR option. Other than the full reset,
the automatic recovery does not completely shut down the device and re-create
it from the shut down state. Instead, it works with the device driver to
restore the device in place. Thus, higher level interfaces such as network
interfaces and block devices remain intact. In particular, with this type of
reset high availability mechanisms like a bonded network interface or
a software RAID can transparently re-integrate the recovered device. For
example, after a failure and recovery, a software RAID can resync a stroage
device or a network interface can be re-integrated in a bond. In contrast to
a complete shut down, the device driver remains active and informs higher
layers of both the occurence of an error state and the eventual recovery.
.PP
.
.OD deconfigure "" "DEVICE"

View File

@@ -46,12 +46,27 @@ static const struct util_prg prg = {
#define OPT_RESET 128
#define OPT_DECONF 129
#define OPT_REPORT_ERR 130
#define OPT_RESET_FW 131
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("ERROR HANDLING OPTIONS"),
{
.option = { "reset", no_argument, NULL, OPT_RESET },
.desc = "Reset the device",
.desc = "Reset the device and report an error to the Support Element (SE). "
"The reset consists of a controlled shutdown and a subsequent "
"re-enabling of the device. As a result, higher level interfaces such "
"as network interfaces and block devices are destroyed and re-created.\n"
"Manual configuration steps might be required to re-integrate the device, "
"for example, in bonded interfaces or software RAIDs.\n"
"Use this option only if the automatic recovery failed, or if it did "
"not succeed to restore regular operations of the device and manual "
"intervention is required.\n",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
.option = { "reset-fw", no_argument, NULL, OPT_RESET_FW },
.desc = "Reset the device through a firmware driven reset that triggers "
"automatic recovery and reports an error to the Support Element (SE).\n",
.flags = UTIL_OPT_FLAG_NOSHORT,
},
{
@@ -337,10 +352,19 @@ static void sclp_issue_action(struct zpci_device *pdev, int action)
*/
static void sclp_reset_device(struct zpci_device *pdev)
{
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET);
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_REPORT_ERR);
sysfs_write_value(pdev, "recover", 1);
}
/*
* Reset the PCI device via firmware and let auto recovery handle
* re-initialization
*/
static void sclp_reset_device_fw(struct zpci_device *pdev)
{
sclp_issue_action(pdev, SCLP_ERRNOTIFY_AQ_RESET);
}
/*
* De-Configure/repair PCI device. Moves the device from configured
* to reserved state.
@@ -372,6 +396,9 @@ static void parse_cmdline(int argc, char *argv[], struct options *opts)
case OPT_RESET:
opts->reset = 1;
break;
case OPT_RESET_FW:
opts->reset_fw = 1;
break;
case OPT_DECONF:
opts->deconfigure = 1;
break;
@@ -411,6 +438,8 @@ int main(int argc, char *argv[])
if (opts.reset)
sclp_reset_device(&pdev);
if (opts.reset_fw)
sclp_reset_device_fw(&pdev);
else if (opts.deconfigure)
sclp_deconfigure(&pdev);
else if (opts.report)

View File

@@ -23,6 +23,7 @@
struct options {
unsigned int reset;
unsigned int reset_fw;
unsigned int deconfigure;
unsigned int report;
};