Compare commits

..

219 Commits

Author SHA1 Message Date
Jan Höppner
c8d1aa55b4 New release s390-tools-2.24.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-09 17:11:48 +01:00
Matthew Rosato
25a70ac5a8 libap: use util_lockfile and remove liblockfile dependency
Now that we have a utility library for file locking, remove all
calls to liblockfile functions from libap and remove all links to
the library from the current users of the libap liblockfile
implementation (ap_tools/ap-check and zdev).

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/142
Suggested-by: Luca BRUNO <luca.bruno@coreos.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-09 16:09:19 +01:00
Matthew Rosato
6235a51d7c libutil: add example for util_lockfile
Adds util_lockfile_example.c, which can be used to sample
util_lockfile support.

To acquire a lock using a parent PID (e.g. your shell instance):
util_lockfile_exmample -f <path> -l <retries>

To release the lock using the parent PID:
util_lockfile_example -f <path> -r

To acquire the lock, sleep briefly, and then release the lock
using the PID of the util_lockfile_example process:
util_lockfile_example -f <path> -L <retries>

In each example, the <path> is the location of the desired lockfile
and <retries> is the number of times to retry acquiring the lock
if it fails.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/issues/142
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-09 16:09:19 +01:00
Matthew Rosato
e1aec24e84 libutil: introduce util_lockfile
Implement simple file-locking routines that use process PIDs for stale
lock detection.  The implementation is meant to be a simplified subset of
what liblockfile was previously being used for by libap, allowing the
external dependency to be removed.

This initial implementation provides a series of functions that allow for
creating/release file locks using either the current process PID or the
PID of the current process parent.  When creating a file lock, first a
temporary file is created and the appropriate PID (either this process
PID or the parent process PID) is placed in the file to specify the owner
of the lock.  Then an attempt is made to link that file to the desired
file location; if this succeeds, the lock is now held on behalf of the
specified PID.  If it fails, this implies the file already exists
(meaning the lock is already held).  In this case, stale lock detection
is performed by reading the PID from the file and ensuring that the
associated process still exists -- if it does not, then the lock is
presumed stale and destroyed.  If the process still exists, then either
the lock request fails or the caller will sleep and retry, depending on
an optional retry setting.

A lock remains valid until either 1) it is released via the corresponding
util_lockfile function, which will delete the corresponding file 2) the
associated PID no longer exists, which leaves the file in-place but will
cause it to be destroyed the next time a different process attempts to
lock that file or 3) the file is directly removed (e.g. rm).

A typical usecase for such support would be to provide a means for
multiple invocations of the same (or different) tools to ensure that they
do not access the same shared resource simultaneously.  For example,
ap-check, chzdev and lszdev all have a need to view and/or modify the AP
and vfio-ap configuration files; util_lockfile can be used to ensure that
only one instance of any of these utilities do that at a time by ensuring
they all use the same lockfile.
Additionally, providing the ability to specify the parent PID rather than
the current PID allows for a general purpose tool (like mdevctl) to
invoke a sub-program (ap-check) to acquire and release a lockfile as
necssary while allowing stale lock detection to be controlled by that
parent PID, allowing the lock to remain held over multiple sub-program
invocations.

Note that this implementation is sufficient for our current usage (e.g.
lockfiles placed in tmpfs) but does not take into consideration things
like NFS, which a more complete lockfile solution like liblockfile does.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/issues/142
Suggested-by: Luca BRUNO <luca.bruno@coreos.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-09 16:09:19 +01:00
Eduard Shishkin
d9a6fb3ccf zipl/src: fix secure boot status check
Set up the secure_boot_supported global variable at the
function bootmap_create() instead of bootmap_create_device()
to make sure that the secure boot status is checked for all
relevant jobs.

Fixes: 7b369318dd ("zipl: check for secure boot once")
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-09 16:09:19 +01:00
Steffen Eiden
a47dd4570a README: update zgetdump information
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:45:38 +01:00
Marc Hartmayer
8fa1b5a00b zdump: dfi: add support to read Protected Virtualization dumps
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 have
introduced Protected Virtualization (PV) dump support - also named
confidential dump support.

The confidential dump support works by integrating the firmware into the
dump process. New Ultravisor calls (UVC) 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 (CCK) for the
dumped guest. The output format is very similar the normal s390 vmcore
ELF format, it's only enriched by new sections where the returned data
from the UVC "Complete Configuration Dump" and the UVC "Dump
Configuration Storage State" is stored. The encrypted CPU data is stored
in a new note type `NT_S390_PV_CPU_DATA`. The old note types do still
exists but without any confidential data stored. The memory data is
stored in the LOAD segment as usual but for PV dumps it's fully AES-XTS
encrypted.

This commit adds support for reading/decrypting PV guest dumps to
zgetdump by introducing a new DFI input module (`dfi_pv_elf.c`). For
specifying the customer communication key a new command line option
`--key` is added.

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-11-03 17:45:38 +01:00
Marc Hartmayer
e537ab902e zdump: Makefile: add basic libpv support
The functionalities of libpv are used in the next patch. Libpv itself
requires glib2 and libcrypto.

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-11-03 17:45:38 +01:00
Marc Hartmayer
f0fb4a180a zdump: refactor usage print
The function will be reused in a later patch.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:45:38 +01:00
Marc Hartmayer
f957d895cd zdump: consolidate error reporting
Consolidate error reporting to make sure that error messages are used
consistently. In addition, don't call `zg_exit()` directly, but instead
return the value 1 in `main()`.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:45:38 +01:00
Marc Hartmayer
73c3a9e684 libpv: fix memory leak in pv_get_openssl_error
While at it, improve documentation and adapt libpv code.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:45:38 +01:00
Marc Hartmayer
2ee1387f34 libpv/genprotimg/pvattest: use glib/gi18n.h
Replace `<glib/gi18n-lib.h>` with `<glib/gi18n.h>` since `<glib/gi18n-lib.h>` should only be used
for libraries (see https://docs.gtk.org/glib/i18n.html).

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-11-03 17:45:38 +01:00
Eduard Shishkin
10cefb3337 zipl/src/zipl_helper.device-mapper: Fix bug in error path
Prevent double free/close that happens in get_multipath_status()
when the output of "dmsetup status XXX" is empty

Fixes: 599b141 ("zipl: Rewrite helper script in C")
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:45:09 +01:00
Dan Horák
7b369318dd zipl: check for secure boot once
Check for secure boot status only once when starting to create the
bootmap.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/133
Signed-off-by: Dan Horák <dan@danny.cz>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Dan Horák
cf2fb296f0 zipl: be verbose about secure boot support
Report the details about the state of secure boot on the system when running
zipl in verbose mode.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/133
Signed-off-by: Dan Horák <dan@danny.cz>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Marc Hartmayer
6cbd81f997 zdump: zg.h: consolidate PAGE_SIZE macros
Reuse `PAGE_SIZE` defined in `boot/s390.h`.

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-11-03 17:38:53 +01:00
Marc Hartmayer
2025cf751f zdump: man: fix long form of abbreviation
ELF stands for "Executable and Linkable Format" (see
https://refspecs.linuxfoundation.org/elf/TIS1.1.pdf).

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-11-03 17:38:53 +01:00
Marc Hartmayer
5a052103ae zdump: fix signatures of the wrappers zg_alloc, zg_realloc and zg_ioctl
Adapt the wrappers `zg_alloc`, `zg_realloc` and `zg_ioctl` to match the
signatures used by `calloc`, `realloc` and `ioctl`.

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-11-03 17:38:53 +01:00
Thomas Richter
2ced5853b4 cpumf/lshwc: fix incremented counter output
lshwc displays counter values extracted from the /dev/hwctr device.
The counter values are retrieved using a loop and incremented instead
of just displayed on output.
This leads to the situation where a counter is incremented in large
numbers while the counter triggering program is active. When this
program terminates, the counter should not increase but remain steady.

This is not the case as this example shows:

 # lshwc -i 2 -l90 -a :a | fgrep Total  | \
	awk -F ',' '{print $2 "," $152 "," $157}'
 Report time and values of DFLT_ACCESS and DFLT_CC counters
 sleep 10
 # DFLTCC=1 python3 -c "import zlib; zlib.compress(b'A'*6000000000);
 Increment counter DFLT_ACCESS and DFLT_CC, runs about 45 seconds

Output before:
15:24:20,0,0
15:24:22,0,0
15:24:24,0,0
15:24:26,0,0
15:24:28,0,0
15:24:30,0,0
15:24:32,2067027,592996481      <--- python3 program start
15:24:34,6953101,2039012580
15:24:36,14494585,4264340060
15:24:38,24759568,7346128396
....
15:24:56,232929262,70526362509
15:24:58,269037963,81464038124
15:25:00,307757248,93171809261
15:25:02,348900718,105620730492
15:25:04,392646075,118841031269  <--- python3 program stop
15:25:06,438956016,132853968029  <-- Value column two increased by 49148217
15:25:08,488104233,147709011658  <-- Similar high increase

The reason is that lshwc takes the last read counter value and keeps
adding it to the total count, even if there zero delta to the previous
read value. Fix this by clearing the total count value between ioctl()
read operations.

Output after:
15:39:26,0,0
15:39:28,0,0
15:39:30,0,0
15:39:32,0,0
15:39:34,0,0
15:39:36,1367250,380721127      <--- python3 program start
15:39:38,4104791,1108181711
15:39:40,6740994,1858843730
15:39:42,9277545,2646351211
15:39:44,11895180,3444375804
....
15:40:16,54060774,16315924126
15:40:18,57830349,17513712210
15:40:20,61628170,18690791102
15:40:22,65410470,19864086006
15:40:24,69070765,21028646754   <--- python3 program stop
15:40:26,70429758,21472772340   <-- No increase of value in column two
15:40:28,70429758,21472772340
15:40:30,70429758,21472772340
15:40:32,70429758,21472772340
15:40:34,70429758,21472772340
15:40:36,70429758,21472772340
15:40:38,70429758,21472772340

Fixes: 27a562da0a ("cpumf/lshwc: Program to extract complete counter sets")
Reported-by: Axel Busch <Axel.Busch@ibm.com>
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-11-03 17:38:53 +01:00
Thomas Richter
13edbb7d5e cpumf/pai: fix core dump when summary flag set
pai dumps core when invoked with summary flag -S and
certain painnpa.XXXXX data files:

   # ~/s390-tools/cpumf/pai -r -S
   Segmentation fault (core dumped)
   #

Fix this and check the existence of event raw data before
reading it. This avoid accessing NULL pointer trying to read raw
data when no counter values have been appended as raw data by the
kernel.

Fixes: dc73c77d73 ("cpumf/pai: Omit detailed event information when summary flag selected")
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
1643af4578 zdev: dracut: modifiy the module-setup.sh
Export and import the configurations with zdev:early on the
site-specific configurations as well. Filter the site-specific
configurations by attribute "zdev:early" and import the output
to the corresponding sites.

Note that --site parameter does not work with the device type.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
c7ac1e63bd zdev: add export/import support for site
Add export and import support for site-specific settings. For each
site-specific configuration, a new site-block will be generated as
below. The same format can be interpreted by the import function and use
the values on the device's site-specific configuration.

Typical example of a site-block in the export file:

[site3 dasd-fba 0.0.f001]
online=1
cmb_enable=0

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
fa3dd0ec20 zdev: add --deconfigure-all function for chzdev
Introduce --deconfigure-all feature, which will remove all available
settings from the mentioned device. A typical device can have 10
different site-specific settings, active settings, persistent
settings and sometimes auto-configured settings configured in it.
--deconfigure-all can be used to remove all of them with a single
command.

usage: 	chzdev -D <device-id>
	chzdev --deconfigure-all <device-id>

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
34146c3f92 zdev: modify man-pages to update the site information
Add the new site parameter help information in the man-pages of both
chzdev and lszdev.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
298ede17f5 zdev: provide site-specific information in lszdev
lszdev must be modified to share the site-specific configuration
information from the persistent settings. The persistent configuration
array will be read and tabularized based on the site-id input from the
user.

This patch also accommodates the site specific information in the
lszdev --info command. New information about the site-ids are integrated
with the command. For example,

DEVICE dasd-eckd 0.0.f001
  Names              : -
  Modules            : dasd_eckd_mod dasd_mod
  Online             : no
  Exists             : yes
  Persistent         : yes
  Sites              : 1,2

  ATTRIBUTE                     ACTIVE    PERSISTENT  SITE1  SITE2
  cmb_enable                    "0"       "0"         "1"    -
  eer_enabled                   "0"       -           -      -
  erplog                        "0"       -           -      -
  failfast                      "0"       -           -      -
  last_known_reservation_state  "none"    -           -      -
  online                        "0"       "1"         "1"    "1"
  raw_track_access              "0"       -           -      -
  readonly                      "0"       -           -      -
  reservation_policy            "ignore"  -           -      -
  use_diag                      "0"       -           -      -

Each available site specific configuration will be shown as column. The
"Sites" parameter in the above output indicates the available site
configurations and the SITE1 and SITE2 colums indicates the detailed
configuration for the respective sites.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
d66ace8121 zdev: add functionality to read site-specific settings
Modify the dev_get_setting_list function to get the site-specific
attributes of the device. The new site_id parameter for this function
must be less than SITE_FALLBACK to read the site-specific attributes.
As SITE_FALLBACK setting is same as persistent setting, we do not need
a separate read function for it.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
2e89722ef0 zdev: make site specific udev-rule for ccw
The udev-rules must be modified to make it site-specific. The site
specific part of the rule should be executed only on the sites where the
devices belong. Change the generic udev rule to support the site-specific
udev-rule.

During boot, the current site-id is read from the LOADPARM which is
located at /sys/firmware/ipl. The zdev_id command reads this LOADPARM
and prints the SITE_ID based on the value. This SITE_ID is the
current site where the udev-rule is executing. Based on this assumption,
the rule is divided in to multiple blocks where each site block is executed
only for the corresponding sites.

The rule executes based on the value read from the LOADPARM.
1. When the LOADPARM specifies a site-id and if the current device has
   an associated configuration settings, it will be used.
2. When the LOADPARM specifies a site, and the current device does not
   have any associated configuration set, the udev rule uses the
   fallback configuration settings.
3. If the device does not have a fallback-configuration settings or any
   site-specific settings, no configurations will be used.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
c8ad5f57d0 zdev: modify zdev_id to read the site_id from loadparm
The currently active site can be found from the loadparm attribute which
is located at /sys/firmware/ipl/loadparm. Read the value of loadparm and
extract the site_id.

The loadparm is an 8 byte alphanumerical IPL parameter. The content of
loadparm can be of different forms to indicate different boot menu
options, which are used by Linux for selecting the respective boot menu
entries. To indicate the site-id, loadparm adds a 'S' character. Where,
the following character after 'S' indicates either the site-id or
indivcation to derive the site-id from SSID.
For example,
If the loadparm value is Sn,'n' is the integer which could be one of the
valid site_ids from 0 to 9; i.e when booted on site-1, loadparm value will
be S1.
If loadparm value is "SS", zdev_id extracts the site_id from the SSID of
the current ipl device. For ccw and zfcp devices, the current ipl device-id
can be found at /sys/firmware/ipl/device.

In any case, if the loadparm contains invalid value, or empty, the
site_id will be default to the common-site.

After the first invocation of the zdev_id from udev-rule, the site-id
information is stored in /run/zdev_id.env file. This will reduce the
number of further invocation of zdev_id from within udev-rules.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
d2317943c0 zdev: add site specific states for devices
Currently zdev supports the configuration and maintenance of one single
persistent device state. With the introduction of sites, zdev should be
able to store, configure and maintaine NUM_SITES number of states in
the persistent configuration. This patch modifies the struct device and
adds a new site_specific device_state array, which stores the
persistent configuration for all the available sites.

Total number of available sites are configured with NUM_SITES. Where,
10 site-specific configurations and 1 common configuration.

1. during read, all site data is always read and update the
   site_specific[] array.
2. dev->persistent is a copy of dev->site_specific[global_site_id]
3. modifications are only done on dev->persistent, and during write
   dev->persistent overlays dev->site_specific[global_site_id]

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Vineeth Vijayan
198c9fc052 zdev: onboard --site option on zdev commands
In some high-availability setups, root and boot disks of a Linux
installation are copied to remote sites that can take over execution
of a Linux workload in case of an outage of the original site.
A site in this context is an execution environment such as an LPAR
or z/VM guest.

Each site may provide a different set of devices, or require different
parameters to be applied per device. chzdev supports site-specific
device configuration for up to 10 sites. Each site is identified by
a number in the range 0 to 9. You can provide a separate set of persistent
device configuration for each site. The IPL Load parameter value specified
during boot determines the currently active site. Only the device
configuration of the active site is applied during boot and when new
devices become available. A common configuration can be provided that is
applied when no site-specific configuration is available for a device in
the active site.

User can use the --site parameter to configure devices for a specific
site only. Configuration actions without a site parameter apply to the
common configuration.

During the boot, the active site configuration is chosed based on the
IPL LOADPARM variable. If the LOADPARM contains no valid site-id (0 to 9),
the fallback-site id will be used. The fallback-site-id can also be
configured with the zdev tools by not specifying the --site parameter.

Some of the new chzdev/lszdev commands with site-parameter can be as
follows

1. chzdev -ep f001 --site 3

This command is used to configure the device f001 for the site 3. During
boot, if the LOADPARM value is S3, this device configuration will be
used.

2. lszdev --site 3

This command lists all the devices which are configured for site 3.

3. chzdev -ep f001

Above command does not have a --site parameter. This device settings
will be used for the following conditions

1. When the loadparm specifies a site, (e.g S3), and the device does not
   have an associated config-set, zdev uses fallback config set.
2. When the loadparm does not specify any site information, then the
   fallback config set will be used.

When the loadparm specifies a site, and the device does not have an
associated config set, nor a fallback site, nothing is configured for this
device.

Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Marc Hartmayer
b3551f50a8 Provide codespell configuration
While at it, add a list with words to ignore. This suppresses the following codespell finding:

$ codespell libcpumf/libcpumf_cpuset.c
libcpumf/libcpumf_cpuset.c:15: parm ==> param, pram, parma
libcpumf/libcpumf_cpuset.c:17: parm ==> param, pram, parma

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Marc Hartmayer
4ff360e621 Provide CheckPatch configuration
Provie a CheckPatch configuration file and mention it in the coding style
guidelines (this feature was introduced with CheckPatch version 0.32 ~11 years
ago).

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Marc Hartmayer
87e8fa18cf CODINGSTYLE.md: mention EditorConfig configuration
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Marc Hartmayer
4bd135c3c7 Add project-wide .clang-format
Add a .clang-format configuration and mention it in the coding guidelines.

Usage example:

 $ clang-format -i **/*.[ch]

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-11-03 17:38:53 +01:00
Matthew Rosato
f69350e8bd ap_tools/ap-check: reject start for control domains without usage
When configuring a vfio-ap device, specifying only control domains
without any usage domains results in a useless configuration in that
both adapters and usage domains are required to make cryptographic
resources available to the guest.  Without that, the control domains
are useless.  While the kernel allows this, let's reject this
combination with a message.

Suggested-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Boris Fiuczynski <fiuczy@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:22 +02:00
Peter Oberparleiter
5768d55a08 zipl/boot: add secure boot trailer
This patch enhances the zipl stage3 loader image adding a trailer as
required for secure boot by future firmware versions.

Note: with the change in this patch the padding via objcopy command line
options is replaced by padding via linker script directives with the
same effect.

Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Holger Dengler
538264a8cd lszcrypt: fix parameter handling for device list
lszcrypt allows the explicit definition of a list of devices. Continue
the parameter processing if multiple devices are specified.

Signed-off-by: Holger Dengler <dengler@linux.ibm.com>
Reviewed-By: Harald Freudenberger <freude@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
7f09f0e4ad zdump: refactor pt_load_add
In an upcoming patch the refactored function `pt_load_add` is reused. While at
it, add a wrap-around check to `pt_load_add`, replace `g.opts.device` access
with `fh->path` (this makes this function easier testable) and improve the
documentation.

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-10-22 20:27:16 +02:00
Marc Hartmayer
e36084d7f2 libpv/pvattest: consolidate __PV_BIT and BIT macros
Consolidate `__PV_BIT` and `BIT` macros.

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-10-22 20:27:16 +02:00
Marc Hartmayer
bd18166a21 zdump: opts: declare print_usage_exit in header file
Remove `static` attribute from `print_usage_exit` and declare it in the header
file `opts.h`. The function will be reused in a later patch.

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-10-22 20:27:16 +02:00
Marc Hartmayer
a6f2c38891 zdump: constify dfi_vmcoreinfo_get
Caller of `dfi_vmcoreinfo_get` must not modify the returned value, therefore
return a `const char *` value for `dfi_vmcoreinfo_get`.

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-10-22 20:27:16 +02:00
Marc Hartmayer
029a3f8f52 zdump: add guarded storage support for ELF input and output format
Add guarded storage registers support for the ELF input and the ELF output
format. See `man 2 s390_guarded_storage` for details about guarded storage.

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-10-22 20:27:16 +02:00
Marc Hartmayer
dc87aef335 zdump: dfo_elf: replace HDR_PER_CPU_SIZE with get_max_note_size_per_cpu
The maximum size of all supported ELF note entries for a CPU can be 0x4a4 bytes
and not 0x4a0. Use a function for the calculation so it's easier to maintain.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
d712806b39 lib/zt_common.h: add macro for determining field size
The macro `sizeof_field` is used in the next patch.

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-10-22 20:27:16 +02:00
Marc Hartmayer
2734724432 zdump: df_elf: add multiple ELF section helper
Preparation for upcoming patches.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
6176509076 zdump: df_elf: refactor check_elf_hdr
The function will be reused by upcoming patches.

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-10-22 20:27:16 +02:00
Marc Hartmayer
1780efae07 zdump: df_elf: ehdr_is_elf_object: add ELF version check
Currently, only the ELF version `1` is defined by the ELF specification. See
`man 5 elf` for details. Therefore of course, we do only support this version.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
922e8cbb2f zdump: since we create ELF version 1 files use this value explicitly
The value of `EV_CURRENT` might change. The ELF specification says: "The value
of EV_CURRENT, though given as 1 above, will change as necessary to reflect the
current version number." [1]

[1] https://refspecs.linuxfoundation.org/elf/elf.pdf

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
eef0dd4fa4 zdump: df_elf: add missing endianness check
A s390x ELF file must use big-endian encoding.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
f93f437f8b zdump: df_elf: read_elf_hdr: return Elf64_Ehdr struct
This makes the API of `read_elf_hdr` consistent with `read_elf_phdrs`.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
4e6d43e2ac zdump: dfi_elf: refactor nt_* functions
The functions are refactored so the `struct zg_fh` value is now passed as
argument to the `nt_*` functions instead of accessing the global variable `g.fh`
from within of the functions. This makes the functions reusable and easier to
test. While at it, improve the documentation of `nt_read`.

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-10-22 20:27:16 +02:00
Marc Hartmayer
922d29ee49 zdump: dfi_elf_init: introduce temporary variable
Introduce variable `phdrs` and shrink the scope of `phdr`. This removes
duplicated code `&phdr[i]` and makes the code easier to read. While at it,
constify the parameter of `pt_notes_add`.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
25475bdf42 zdump: read_elf_phdrs: fix -Wconversion issue
`ehdr->e_phoff` has the type `Elf64_Off` and this maps to `uint64_t`, but `off_t` is signed. Let's
add a check for this.

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-10-22 20:27:16 +02:00
Marc Hartmayer
09c413b1be zdump: read_elf_phdrs: handle no program header case
Handle the case where no program headers are defined (see `man 5 elf`).

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
8944c2f60d zdump: dfi_elf: refactor read_elf_(ehdr|phdrs)
Make the function unit testable and easier to reuse - no functional change.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
ff3fe4bf43 zdump: constify struct zg_fh *fh parameter in the zg file APIs
Constify the `struct zg_fh *fh` parameter in the file APIS, e.g. `zg_path()`.

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-10-22 20:27:16 +02:00
Joern Siglen
5fe2e19277 dbginfo.sh: fix man page
add missing option in man page

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Joern Siglen
b8cf861aea dbginfo.sh: add kuberentes (OCP) data collection
generalize the collection step name from "docker" to "container host"

initial version of adding data collection for OCP.

all log file content might be too much for most installations

Reviewed-by: Alexander Klein <alkl@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Reviewed-by: Mike Storzer <mstorzer@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Joern Siglen
6ca3576dbf dbginfo.sh: fix typo
typo in KVM section

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
7ea425db5e pvattest/exchange_format.c: use proper endianess conversion macro for hdr->version
GUINT32_TO_BE and GUINT32_FROM_BE do exactly the same in case of glib2, just the
naming differs. However, at this point the conversion is from be to system
endianness therefore `GUINT32_FROM_BE` is the proper macro.

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-10-22 20:27:16 +02:00
Marc Hartmayer
330ddb7adb libpv: add copied parameter to pv_gbytes_memcpy and adapt pvattest
It's often useful to know how much data was actually copied, therefore let's
introduce an nullable parameter `@copied` to `pv_gbytes_memcpy`.

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-10-22 20:27:16 +02:00
Marc Hartmayer
d69b9fab4a pvattest: build_attestation_v1_ioctl: make the code more robust
...by adding a compile time assertion about the buffer size. While at it, report
the actual user data size in case of an error.

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-10-22 20:27:16 +02:00
Marc Hartmayer
4e02dc8751 pvattest: uvio.c: remove endianness handling
The endianness handling was only partially implemented for uvio.c. Let's remove
it since doesn't make much sense here, because the IOCTL must be build on the
same system where they're actually executed.

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-10-22 20:27:16 +02:00
Joern Siglen
0c8be405ce dbginfo.sh: fix vmcp buffer resizing
the buffer sizing did not work any longer
add explaining comments and rework the variable names for claritiy

refering commit f7cc14753cc9d930af804e2ac3ce108a12145db6

Reported-by: Mike Storzer <MSTORZER@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Steffen Eiden
24677dc561 libpv: remove wrong parameter attribute
`error` is actually used therefore let's remove the `G_GNUC_UNUSED` attribute.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Steffen Eiden
7e7c38755d libpv: improve error reporting
Use `PV_CERT_ERROR` error domain whenever useful. Currently, it's only used
internally in libpv and therefore there is no problem in changing it.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
229cd6d194 zdump: don't modify passed program header in pt_load_add()
There should be no problem with this change since the changed value was never
used. Therefore, let's remove the assignment and declare the parameter as const
to prevent such a behavior in the future.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
776e5d41d7 zdump: dfi_elf: factor out some ELF functionalities
This makes them reuseable and testable.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
8d7e8a87b5 zdump: df_elf: move function documentation to function declarations
It's more common to have the function documentation next to the function
declarations.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
e24d8c936c zdump: move NOTE_NAME_* definitions to df_elf.h
This allows the reuse in other source files.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
39b6c4a273 zdump: introduce ELF_NOTE_ROUNDUP macro
Introduce and use `ELF_NOTE_ROUNDUP` macro.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Marc Hartmayer
da9b96fb12 lib/zt_common.h: consolidate ROUNDUP macro
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:27:16 +02:00
Alexander Egorenkov
7d855acd07 util_arch: Fix max HSA size for Z16 machine
The machine types are not strictly increasing anymore since Z16, therefore,
we cannot use numerical comparison to find out the correct HSA size
of a machine.

Fixes: 2515832469 ("util_arch: Add IBM z16 as known machine")
Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:34 +02:00
Marc Hartmayer
f961a2bf90 common.mak: fix compiler command line for afl-clang
`afl-clang` requires a white space between a option name and the option value.
Therefore let's fix this for `-xc` by adding a white space.

How to reproduce:

$ make -C zdump CC=afl-clang-fast LINK=afl-clang-fast

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:34 +02:00
Joern Siglen
9f93af614f dbginfo.sh: ensure compatibility with /bin/dash
some versions of /bin/dash do interpreted our commands different, which
causes a variable failure and termination of the script.

e.g. a new line char "\n" will split the cmd_type to a multiple line variable
not working with the followup commands. adding the head command does avoid
multiline variables now.

Problem found in Ubuntu 20.4 and some older Ubuntu versions

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:34 +02:00
Joern Siglen
d529ba07d3 dbginfo.sh: update message on not beeing root
add a hint that dbginfo.sh -c can check some basic stuff even as non-root

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:34 +02:00
Joern Siglen
0fffb05d01 dbginfo.sh: add tool check for testing
move tool checking to the top of the script and add the output to
the check function (-c) for easy verifivation and testing

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:34 +02:00
Joern Siglen
92b8409207 dbginfo.sh: ensure type commands compatible with dash
All debian distors use the dash shell as default, where type is not supprting "-t" parameter

Remove of "-t" where not important and change type check not using -t

Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:34 +02:00
Steffen Maier
bc3134ba5a dbginfo.sh: collect config and logs of Dandified YUM (DNF)
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:31 +02:00
Steffen Maier
c7f55a182f dbginfo.sh: collect YaST log files of successful installation
Cf. /usr/sbin/save_y2logs of yast2-logs.rpm.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:28 +02:00
Steffen Maier
5078be45b8 dbginfo.sh: collect generated unattended installation kickstart files
anaconda-7.2.91-1
c4249bbe06 (diff-86b9da41b3aa75b36055aa04a2effff06c0decadc7b80f6efd8a513fe265746eR49)
("merge dispatch to HEAD")

anaconda-24.7-1
1c4af3b432
("Include original kickstart in /root/original-ks.cfg (#1227939)")
https://github.com/rhinstaller/anaconda/pull/447
https://bugzilla.redhat.com/show_bug.cgi?id=1227939

Cf. https://anaconda-installer.readthedocs.io/en/latest/boot-options.html#inst-nosave
from anaconda-25.2-1
b7d699a547
("Make it possible to skip saving of kickstarts and logs (#1285519)")

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:24 +02:00
Steffen Maier
2418ea93fc dbginfo.sh: collect anaconda log files of successful installation
Since anaconda-15.2-1
7e2754473e (diff-3b740ff14364c6d399b86ef7a6ca044e17b334ab351988600058d9af0e7fa0bc)

See also /usr/libexec/anaconda/log-capture of anaconda-core.rpm.

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:26:21 +02:00
Steffen Maier
13cac5de44 dbginfo.sh: also collect "local" multipath-tools config
Easier to read for a first glimpse than the (still required) full config.

$ man multipathd
       list|show config local
              Show the currently used configuration like show config, but lim‐
              iting  the  devices  section  to those devices that are actually
              present in the system.

Works as of multipath-tools 0.7.8 commit
c23924dc74ee ("multipathd: implement "show config local"")

Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:17:31 +02:00
Joern Siglen
b6687925cc dbginfo.sh: cleanup outdated comment and formating
remove spaces and outdated comment line

Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:17:31 +02:00
Marc Hartmayer
7ee51182bf zdump: fix memory leak of path
==660622== 385 bytes in 7 blocks are definitely lost in loss record 30 of 37
==660622==    at 0x484417C: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-s390x-linux.so)
==660622==    by 0x4E93BD7: strdup (strdup.c:42)
==660622==    by 0x11249F: zg_strdup (zg.c:115)
==660622==    by 0x11249F: zg_open (zg.c:164)
==660622==    by 0x114FBF: dfi_dump_open (dfi.c:750)
==660622==    by 0x114FBF: dfi_init (dfi.c:772)
==660622==    by 0x111465: do_copy (zgetdump.c:192)
==660622==    by 0x111465: main (zgetdump.c:216)

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:17:31 +02:00
Siglen
ec3e5b4a75 dbginfo.sh: save dbginfo.sh version to dbginfo.log
we do miss a simple way to see the dbginfo.sh version used by the
customer for the debug generation. saving the version now to dbginfo.log

Reported-by: Mike Storzer <MSTORZER@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-10-22 20:17:31 +02:00
Jan Höppner
0b5aac3d79 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-18 15:33:16 +02:00
Jan Höppner
bea3180836 New release s390-tools-2.23.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-18 15:33:16 +02:00
Steffen Eiden
1ffd767977 pvattest/tools: Add script to display config UID and additional data
Although the previous patch enables pvattest to display the
config UID this script enables the user to extract the config UID of
the SE-guest and the additional data if specified. This allows users of
pvattest v2.22.0 to view the config UID without examining binary blobs.

$ ./pvattest-info attresult.bin
Config UID:
1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a
Additional Data:
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b
1b1b

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
a4e396fdd7 pvattest: Add more information to verbose logging
In verbose mode (-v) `pvattest verify´ now also prints
"Attestation measurement verified", if the verification was successful and the
Config UID of the SE-guest and any additional data if available.

$ pvattest -V verify  [...]
Attestation measurement verified
Config UID:
1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a

Additional Data:
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b
1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b1b

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
972d4fe0a5 pvattest: Improve logging
Change the name of `hexdump´ to `pvattest_log_bytes´. Additionally, allow
that function to dump the bytes as a single hexadecimal number.

Change the name of `printf_hexdump´ to `pvattest_hexdump´.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
148460c235 pvattest: Improve error reporting
Map the Ultravisor return code 0x2 to "Invalid UV command" string. This
results in better error messages.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
8c2f6790fe genprotimg: sync man and help with pvattest
Syncronizes the description of shared options of genprotimg and pvattest

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
044272ea25 pvattest: Improve man pages and help
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Matthew Rosato
7d67dc8f1c zdev: add some --type ap examples to manpages
The ap type has some unique input parameters, provide some examples
on how to modify and set the apmask and aqmask via chzdev.  Also
include an example of using lszdev to view the apmask and aqmask.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/140
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Benjamin Block
71461d80bf Makefile: use common Make definition for DRACUTDIR
The dracut installation directory is referenced from `chreipl-fcp-mpath`,
`zdev`, and `zipl`; in each with its own individual definition and
variable name. This makes it unnecessarily hard to change it when
installing from the top level directory of s390-tools and passing
variable overwrites via the command line.

Fix this by defining a common `DRACUTDIR` variable in the shared
`common.mak` file, and referencing this in each tool as base directory.
With this a user can simply pass `DRACUTDIR=/foo/bar/baz` on the
commandline and change the installation for all three tools.

Further, also derive common `DRACUTCONFDIR` and `DRACUTMODDIR` variables
from `DRACUTDIR` in `common.mak`, so that `zdev` and `zipl` don't use
different variable names for the same directory anymore, and all these
are defined together in a common place.

Semantically nothing changes for a default build/installation.

Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Benjamin Block
9eac2788d7 Makefile: use common Make definition for UDEVDIR and UDEVRULESDIR
UDEVDIR is used in both `chreipl-fcp-mpath` and `zdev`, but with a
different meaning. In the former it points to the base udev directory,
not the rules directory; in the later it points to the rules directory.
If someone was to call `make` from the top level directory, and set
UDEVDIR for the whole build/installation, it would either break `zdev`
or `chreipl-fcp-mpath` (depending on what it was set to).

Fix this by pulling the definition of it in the shared `common.mak`
file, and giving it a common meaning. Point UDEVDIR to the base udev
directory, and UDEVRULESDIR to the rules directory below it.

Semantically nothing changes for a default build/installation.

Signed-off-by: Benjamin Block <bblock@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
6ff8202fa9 zipl: Add missing check for a nullpointer.
Fixes a bug that leads to a segmentation fault when no parmline is
provided.

Fixes: 11b401b5 ("zipl: move and make check for maximum command line length dynamic")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.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-08-16 18:28:21 +02:00
Steffen Eiden
acf30de415 pvattest: remove unnecessary variable
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
a766411306 pvattest: fix dependency checking
Fixes a bug that make still tried to build pvattest even when the
compilation of pvattest was turned off.
This lead to a build bug when one of the dependencies was not met.

Also fixes the check of the OpenSSL version at build time.

Fixes: 3ab06d77 ("pvattest: Create, perform, and verify attestation measurements")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Steffen Eiden
cbcab61c65 libpv: fix dependency checking
Fixes a bug that make still tried to build libpv even when the
compilation of libpv was turned off.
This lead to a build bug when one of the dependencies was not met.

Also fixes the check of the OpenSSL version at build time.i

Fixes: 38639269 ("libpv: New library for PV tools")
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-08-16 18:28:21 +02:00
Marc Hartmayer
c3d179f06e libpv: Fix condition in pv_BIO_reset()
pv_BIO_reset() wrongfully handled the BIO_reset() rc for non-file-backed BIOs.
This is currently not an issue as the only non-file BIO used cannot fail
at BIO_reset()

Fixes: 3ab06d77fb ("pvattest: Create, perform, and verify attestation measurements")
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-08-16 18:27:36 +02:00
Marc Hartmayer
f42250ca9b genprotimg: Fix BIO_reset() returncode handling
The returncode handling for BIO_reset() was wrong when handling with
file based BIOs.

This resulted in a bug that DER formated certificates cannot be read
by genprotimg which is now fixed.

Fixes: d90344a2 (genprotimg: check return value of BIO_reset)
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-08-16 18:23:13 +02:00
Dan Horák
7217903ce4 libvmdump: add default assignment operators
lkcd_dump.cpp: In constructor ‘LKCDDump32::LKCDDump32(Dump*, const RegisterContent32&)’:
lkcd_dump.cpp:191:27: warning: implicitly-declared ‘constexpr RegisterContent32& RegisterContent32::operator=(const RegisterContent32&)’ is deprecated [-Wdeprecated-copy]
  191 |         registerContent = r;
      |                           ^
In file included from lkcd_dump.h:18,
                 from lkcd_dump.cpp:17:
register_content.h:63:9: note: because ‘RegisterContent32’ has user-provided ‘RegisterContent32::RegisterContent32(const RegisterContent32&)’
   63 |         RegisterContent32(const RegisterContent32&);
      |         ^~~~~~~~~~~~~~~~~
lkcd_dump.cpp: In constructor ‘LKCDDump64::LKCDDump64(Dump*, const RegisterContent64&)’:
lkcd_dump.cpp:232:27: warning: implicitly-declared ‘constexpr RegisterContent64& RegisterContent64::operator=(const RegisterContent64&)’ is deprecated [-Wdeprecated-copy]
  232 |         registerContent = r;
      |                           ^
register_content.h:49:9: note: because ‘RegisterContent64’ has user-provided ‘RegisterContent64::RegisterContent64(const RegisterContent64&)’
   49 |         RegisterContent64(const RegisterContent64&);
      |         ^~~~~~~~~~~~~~~~~

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
708abbf380 dasdfmt: fix buffer overread warning
dasdfmt.c: In function ‘dasdfmt_write_labels’:
dasdfmt.c:1110:22: warning: ‘write’ reading 88 bytes from a region of size 4 [-Wstringop-overread]
 1110 |                 rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
      |                      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 1111 |                                                  - sizeof(vlabel->volkey)));
      |                                                  ~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from dasdfmt.c:23:
../include/lib/vtoc.h:84:14: note: source object ‘vollbl’ of size 4
   84 |         char vollbl[4];         /* volume label                              */
      |              ^~~~~~
In file included from ../include/lib/util_opt.h:16,
                 from dasdfmt.c:20:
/usr/include/unistd.h:378:16: note: in a call to function ‘write’ declared with attribute ‘access (read_only, 2, 3)’
  378 | extern ssize_t write (int __fd, const void *__buf, size_t __n) __wur
      |                ^~~~~

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
28dbec093b iucvterm: fix function declaration
GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
daf02f75b1 dasdview: fix string truncation warning
Replace strncpy() with util_strlcpy() which provides the required
semantic.

In function ‘dasdview_print_format1’,
    inlined from ‘dasdview_view_standard’ at dasdview.c:1952:4,
    inlined from ‘dasdview_view’ at dasdview.c:2165:3,
    inlined from ‘main’ at dasdview.c:2364:3:
dasdview.c:1791:25: warning: ‘strncpy’ output may be truncated copying 16 bytes from a string of length 1023 [-Wstringop-truncation]
 1791 |                         strncpy(asc, (char *)dumpstr + i, 16);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dasdview.c:1792:25: warning: ‘strncpy’ output may be truncated copying 16 bytes from a string of length 1023 [-Wstringop-truncation]
 1792 |                         strncpy(ebc, (char *)dumpstr + i, 16);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In function ‘dasdview_print_format2’,
    inlined from ‘dasdview_view_standard’ at dasdview.c:1935:4,
    inlined from ‘dasdview_view’ at dasdview.c:2165:3,
    inlined from ‘main’ at dasdview.c:2364:3:
dasdview.c:1825:25: warning: ‘strncpy’ output may be truncated copying 8 bytes from a string of length 1023 [-Wstringop-truncation]
 1825 |                         strncpy(asc, (char *)dumpstr + i, 8);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
dasdview.c:1826:25: warning: ‘strncpy’ output may be truncated copying 8 bytes from a string of length 1023 [-Wstringop-truncation]
 1826 |                         strncpy(ebc, (char *)dumpstr + i, 8);
      |                         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
[hoeppner@linux.ibm.com: sort include]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
71b0460d11 mon_tools: drop an always-true condition
The d_name member of struct dirent is a statically allocated string,
thus it's always non-NULL.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
ff62f4d425 mon_tools: fix user counting condition
The ut_user (aka ut_name) member of struct utmp is a statically
allocated string, thus always non-NULL.

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Acked-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
53c523ab19 ziomon: silence unaligned pointer value warnings
The build produces a number of warnings like the ones below. The
unaligned pointers are expected, thus silence the warnings by disabling
the compiler diagnostics.

ziomon_dacc.c: In function ‘read_message’:
ziomon_dacc.c:189:44: warning: taking address of packed member of ‘struct message’ may result in an unaligned pointer value [-Waddress-of-packed-member]
  189 |         if ( (rc = read_message_header(fp, &msg->length, &msg->type)) )
      |                                            ^~~~~~~~~~~~

or

In file included from ziomon_mgr.c:36:
blkiomon.h: In function ‘blkiomon_stat_init’:
blkiomon.h:70:21: warning: taking address of packed member of ‘struct blkiomon_stat’ may result in an unaligned pointer value [-Waddress-of-packed-member]
   70 |         minmax_init(&bstat->size_r);
      |                     ^~~~~~~~~~~~~~

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Dan Horák
2285b9527b lib: avoid redefinition of _AC() macro
The kernel already provides the same macro as does the zt_common.h file,
thus check for its availability first.

  CC      zconf/qeth/lsqeth.o
In file included from ../../include/lib/util_base.h:17,
                 from lsqeth.c:30:
../../include/lib/zt_common.h:27: warning: "_AC" redefined
   27 | #define _AC(X, TYPE)    X##TYPE
      |
In file included from /usr/include/linux/ethtool.h:17,
                 from lsqeth.c:12:
/usr/include/linux/const.h:21: note: this is the location of the previous definition
   21 | #define _AC(X,Y)        __AC(X,Y)
      |

GitHub-ID: https://github.com/ibm-s390-linux/s390-tools/pull/137
Signed-off-by: Dan Horák <dan@danny.cz>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Balint Reczey
b4648ec4bd dumpconf: Don't run the service in containers
It just fails to start in unprivileged containers

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/85
Signed-off-by: Balint Reczey <balint.reczey@canonical.com>
Acked-by: Alexander Egorenkov <egorenar@linux.ibm.com>
[hoeppner@linux.ibm.com: expanded from !lxc to !container]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Juergen Christ
c6207db8fc cpacfstats: Typos and Explanation
Correct wrong counter name.
Clarify counting of KMA.

Signed-off-by: Juergen Christ <jchrist@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Sven Schnelle
1bd73c68f9 zipl/boot: don't use lt to test value in tape0.S
This instruction is not present on older machines, therefore
use ltr.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Fixes: 1627c6a39f ("zipl: Support command lines longer than 896 bytes in bootloader")
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Joern Siglen
47016441f0 dbginfo.sh: get more details on lspci command
The new version of lspci does support an extended verbose mode "-vvv"

Using the the tripple v parameter does also work for the old version
having the same result as the double v called before.

Reported-by: Eberhard Pasch <epasch@de.ibm.com>
Reviewed-by: Mario Held <mario.held@de.ibm.com>
Signed-off-by: Joern Siglen <siglen@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Steffen Maier
eeed384a51 dbginfo.sh: fix accidental ftrace buffer shrinkage/free
https://www.kernel.org/doc/html/latest/trace/ftrace.html?highlight=free_buffer

  free_buffer:

        If a process is performing tracing, and the ring buffer should be
        shrunk "freed" when the process is finished, even if it were to be
        killed by a signal, this file can be used for that purpose. On close
        of this file, the ring buffer will be resized to its minimum size.
        Having a process that is tracing also open this file, when the process
        exits its file descriptor for this file will be closed, and in doing so,
        the ring buffer will be "freed".

        It may also stop tracing if disable_on_free option is set.

$ cat /sys/kernel/debug/tracing/buffer_size_kb
7 (expanded: 1408)
$ cat /sys/kernel/debug/tracing/free_buffer
cat: /sys/kernel/debug/tracing/free_buffer: Invalid argument
$ cat /sys/kernel/debug/tracing/buffer_size_kb
0

Reported-by: Thomas Lambart <Thomas.Lambart2@ibm.com>
Signed-off-by: Steffen Maier <maier@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Steffen Eiden
cd5d6a5004 libpv/cert.c: Improve error reporting
The current implementation drops the reason why a download of a CRL
failed. This is changed to the reporting of the error triggered by the
last CRL download attempt.

This mainly helps to check for the download error during CI testing
and prevent connectivity issues to be the reason of a test failure.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:57:17 +02:00
Thomas Richter
e4733002da cpumf/pai: Extract type number from PMU named pai_ext
Use PMU named pai_ext to extract the PMU type number required
for the installation of PAI NNPA counters using perf_event_open()
system call.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:56:44 +02:00
Thomas Richter
15158ee0ca libcpumf: Detect PMU named pai_ext
Add a check to detect Processor Activity Instrumentation (PAI)
Extension 1 facility unit.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:56:44 +02:00
Thomas Richter
dc73c77d73 cpumf/pai: Omit detailed event information when summary flag selected
When the summary flag is selected do not print detailed information
on every single event. Just print the summary information on each
non-zero counter value.

Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:56:44 +02:00
Thomas Richter
56529261db cpumf/pai: Omit file write progress information
During recording, progress information is displayed on the screen
on how many event have been processed and at which offset these
events have been extracted from the ring buffer.

This information is usually of no interest to the user. Omit this
data and only print them when requested via verbose flag.

Suggested-by: Christian Borntraeger <borntraeger@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-07-21 15:56:44 +02:00
Juergen Christ
fcb1f7efd1 cpacfstats: Add PAI and hotplug support
Add virtual counters pai_user and pai_kernel to detail all Processor Activity
 Instrumentation (PAI) counters in user resp. kernel space.  Once activated,
they will show all counters for the corresponding set.  Add option -n to limit
the display to only non-zero counter values.

Add support for cpu hotplug events based on libudev.  CPU hotplug events are
used to either detach from a vanishing CPU or (re-)attach to a (re-)appearing
CPU.  In that case, a "hotplug detected" virtual counter is set to a non-zero
value to indicate possible loss of counters which happens when CPACF is used
on the CPU before cpacfstatsd could attach to it.  The hotplug indication is
cleared once all counters are deactivated.

Add support for JSON output.  The JSON document is an array of JSON objects
representing the counters and their values.  Every object has a name (property
"counter") and a value (property "value").  For PAI counters, the counters
also have a space (property "space") determining the counter set pai_user or
pai_kernel, and a numeric id (property "counterid") that can be used to filter
the JSON document.

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-06-29 14:07:34 +02:00
Juergen Christ
72b5e8b313 cpacfstats: Handle CPU hotplug
cpacfstatsd now correctly handles offline cpus and dynamically attaches to
cpus once they get online.  If events are enabled when a hotplug event
occurs, cpacfstatsd uses a pseudo-counter to notify user applications about
the occurence of this event and a potential data inaccuracy.

cpacfstats shows if a hotplug event has been detected since at least one
counter was activated.  As soon as all counters are deactivated, the
hotplug detection state is reset.

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-06-29 14:07:31 +02:00
Juergen Christ
225964875c cpacfstats: Use timed operations in daemon.
The cpacfstats daemon is susceptible to dos attacks from malicious clients
that connect but either do not send a query or receive an answer fast
enough.  The latter currently is impossible but might occur once we
introduce further counters.

Solve both problems by exploiting a timed read/write operation in the
daemon and close the connection on timeout.

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-06-29 14:06:35 +02:00
Marc Hartmayer
e580190074 common.mak: remove -rdynamic since it's a linker flag
Remove `-rdynamic` since it's a linker flag. This should not cause any problems
because we differentiate between compilation and linking by default. While at
it, adapt the `print_backtrace` documentation accordingly.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-29 14:06:35 +02:00
Thomas Richter
8ef593904d cpumf/pai: Use util_file_read_va function
Use util_file_read_va() function to read out the event number
given the event file. Also use util_strdup() function to save
the event name. This function terminates on Out Of Memory condition.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-29 14:06:35 +02:00
Frank Heimes
51b9504720 zkey: use default benchmarked Argon2i with LUKS2.
cryptsetup 2.1.0 requires excessive amount of RAM (1GB) to luksOpen encrypted
drives (LP: #1820049).
LUKS2 introduced support for Argon2i and Argon2id as a Password-Based Key
Derivation Function (PBKDF).
Argon2 is the winner of Password Hashing Competition and is now officially
recommended by RFC 9106.
PBKDF2 is currently used in zkey to mitigate out-of-memory errors when
multiple LUKS2 volumes are opened automatically via /etc/crypttab.

This patch is to use Argon2i (the deflaut algorithm) as key derivation function
for LUKS2 volumes, but with options for low memory and time requirements.
Using the default Argon2i options might still cause out-of-memory errors.

Link: https://bugs.launchpad.net/ubuntu/+source/cryptsetup/+bug/1820049
Closes: https://github.com/ibm-s390-linux/s390-tools/pull/138
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Acked-by: Ingo Franzki ifranzki@linux.ibm.com
[hoeppner@linux.ibm.com: fix whitespace, line break, and commit message]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-29 14:06:34 +02:00
Thomas Richter
e9d0e267c5 cpumf/lscpumf: Replace /sys mount point by util_path_sysfs
Replace hard coded /sys directory by call to util_path_sysfs()
function.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-29 14:06:34 +02:00
Jan Höppner
b028d4c254 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 14:08:53 +02:00
Jan Höppner
a6f844d642 New release s390-tools-2.22.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 14:08:53 +02:00
Marc Hartmayer
7f059bef13 common.mak: fix -Wnewline-eof in check_header_prereq and check_dep
printf "#include <%s>\n int main(void) {return 0;}"  "glib.h" | ( clang -DS390_TOOLS_RELEASE=2.21.0-build-20220609 -DS390_TOOLS_LIBDIR=/lib/s390-tools -DS390_TOOLS_DATADIR=/usr/share/s390-tools -DS390_TOOLS_SYSCONFDIR=/etc -DS390_TOOLS_BINDIR=/sbin -g -fstack-protector-all -W -Wall -Wformat-security -O3 -std=gnu11 -DOPENSSL_API_COMPAT=0x10101000L -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -pthread -Wall -Wextra -Wshadow -Wcast-align -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes -Wpointer-arith -Wno-error=inline -Wpedantic -Werror -fPIC -I ../include -D_GNU_SOURCE  -o /dev/null -xc - )
<stdin>:2:28: error: no newline at end of file [-Werror,-Wnewline-eof]
 int main(void) {return 0;}
                           ^
1 error generated.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Steffen Eiden
4543d23dcf Makefile: remove trailing whitespace
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Ingo Franzki
12f7dbbb3d zkey: Fix EP11 host library version checking
Extract the minor version and modification level separately.
Previously only the modification level has been extracted, and was
reported as minor version.

Currently no one is checking the minor version or modification level,
so it does not hurt. But maybe in the future one will check, so report
it correctly.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Ingo Franzki
f7c048d0eb zkey_kmip: Setup ext-lib once the APQNs have been configured
During plugin initialization, the external libraries such as the
EP11 or CCA host libraries are set up, if the configuration is
appropriate.

A secure identity key may be generated once the APQNs are configured,
but before the server connection is configured. Trying to re-encipher
the plugin's secure keys to a new HSM master key at that stage fails
with 'ERROR: Invalid ext lib type: 0' because the external libraries
have not been setup yet.

Change the code to setup the libraries once the APQNs have been
configured, and not only after the server connection has been
configured.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Mete Durlu
80e54ac888 hyptop: increase initial update interval
Increase initial update interval from 200ms to 1 seconds to avoid
fluctuations on the initial data output.

Signed-off-by: Mete Durlu <meted@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Steffen Eiden
26148740df pvattest/tools: Add tool for attestation
Adds:
  * extract_hdr_from_image
    a bash script to extract the SE header from an SE image.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Steffen Eiden
3ab06d77fb pvattest: Create, perform, and verify attestation measurements
pvattest is a tool to attest an IBM Secure Execution guest.

In a trusted environment, one can create a request using
`pvattest create`. To get a measurement of an untrusted
IBM Secure Execution guest call 'pvattest perform'.
Again in a trusted environment, call 'pvattest verify'
to verify that the measurement is the expected one.

The tool runs on s390 and x86.
It has the same requirements like libpv and therefore
requires openssl v1.1.1+, glib2.56+, and libcurl.
Additionally, to measure, the linux kernel must provide
the Ultravisor userspace interface `uvdevice` at /dev/uv
and must be executed  on an IBM Secure Execution guest on
hardware with Ultravisor attestation support, like IBM z16 or later.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Steffen Eiden
386392690d libpv: New library for PV tools
libpv is a collection of definitions and functions related to
Protected Virtualization (PV).
The functions cover mainly encryption (e.g. AES-GCM)
and certificates (X509). There are also helping functions for glib2.

Most of the code is extracted+refactored from `genprotimg`, which
will use this library in future.

Requires openssl v1.1.1+, glib2.56+, and libcurl.

libpv is not designed or intended to be dynamically linked or used
outside of this project. Its purpose is to avoid code duplication
as PV tools do very similar things regarding cryptography.

Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Acked-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
72df42ea4e zdump: Adapt man page for NGDump dump tool
Document how to use zgetdump with NGDump and NVMe.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
6c0f429805 zdump: Implement DFI interface for NGDump
The NGDump DFI interface enables zgetdump to read and mount dumps created
with NGDump stand-alone dump.

Under the hood, the NGDump DFI delegates the task of reading and
parsing of ELF dump files to the ELF DFI interface dfi_elf.

Usage example 1:
----------------

$ zgetdump -i /dev/nvme0n1p1
General dump info:
  Dump format........: elf
  Version............: 1
  UTS node name......: t83lp49.lnxne.boe
  UTS kernel release.: 5.14.0-20210819.rc6.git0.efb8a921eec7.300.fc34.s390x
  UTS kernel version.: #1 SMP Thu Aug 19 00:22:04 CEST 2021
  System arch........: s390x (64 bit)
  CPU count (online).: 32
  Dump memory range..: 16384 MB

Memory map:
  0000000000000000 - 00000003ffffffff (16384 MB)

Usage example 2:
----------------

$ zgetdump /dev/nvme0n1p1 > dump.elf

Usage example 3:
----------------

$ zgetdump -m /dev/nvme0n1p1 /mnt
$ ls -l /mnt/dump.elf
$ zgetdump -u /mnt

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
0466760ec1 zdump: Implement DT interface for NGDump
The NGDump DT interface enables zgetdump to display various meta
information contained within a dump partition prepared for NGDump
stand-alone dump.

Usage example:
--------------

No dump yet made
----------------

$ zgetdump -d /dev/nvme0n1
Dump device info:
  Dump tool.........: Next Generation (NGDump) dump tool
  Version...........: 1
  Architecture......: s390x (64 bit)

Partition info:
  Partition number..: 1

Dump present
------------

$ zgetdump -d /dev/nvme0n1
Dump device info:
  Dump tool.........: Next Generation (NGDump) dump tool
  Version...........: 1
  Architecture......: s390x (64 bit)

Partition info:
  Partition number..: 1
Meta info:
  File..............: dump.elf

Alternative disk path
---------------------

$ zgetdump -d /dev/disk/by-id/nvme-eui.01000000010000005cd2e4c5bc845051
Dump device info:
  Dump tool.........: Next Generation (NGDump) dump tool
  Version...........: 1
  Architecture......: s390x (64 bit)

Partition info:
  Partition number..: 1
Meta info:
  File..............: dump.elf

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Tested-by:  Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
8ddc31ea77 zdump: Implement NGDump helpers
This commit introduces a new module containing various helpers for
NGDump stand-alone dump. The purpose of these helpers is to facilitate
the implementation of DT and DFI interfaces for NGDump, share code
between both, reduce duplication and enable unit testing later on.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
60f862b21c libutil/util_part: return partition containing given block range
Return the partition number which contains the given block range,
before it was tested for exact match between a partition block range
and the one provided by user. The old behavior with exact match
should still work, this change just relaxes the partition matching
algorithm and allows one to find a partition which contains the given
block range.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
a66f6bb075 zipl: Adapt man pages for NVMe stand-alone dump
From user perspective, there is no difference between SCSI stand-alone
dump and NVMe one.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
2b015183aa zipl: Implement NGDump
This commit finalizes the implementation of the new stand-alone dump -
Next Gen Dump (NGDump).

NGDump stand-alone dump is a universal stand-alone dump which works for both
SCSI and NVMe disks. But currently can be used only with NVMe disks
and SCSI stand-alone dump remains the default for SCSI disks.

Currently, this stand-alone dump can be used only on IBM z15 or newer
machine generations because it requires larger amount of HSA memory offered
by firmware only on IBM z15 machines. Whereas SCSI stand-alone dump is able
to work with HSA memory of 32M, the new stand-alone dump requires 512M HSA
memory at the moment.

NGDump stand-alone dump installation is initiated by passing a path to
a NVMe disk partition to zipl via the command-line -d, similar to SCSI
stand-alone dump. zipl will then:
- build a dumper initramfs with either dracut (Fedora/RHEL/SLES) or
  initramfs-tools (Ubuntu/Debian)
- format the given NVMe partition with ext4 file system
- create a bootmap file on the newly created file system using the built
  initramfs and the currently active kernel image
- install a boot loader on the disk the given dump partition belongs to

The operations described above are destructive for the given NVMe dump
partition and the boot record(s) of its disk.

After the installation step, users can configure the dumpconf to IPL
the dumper automatically on panic or trigger a dump manually via HMC
interface.

When activated, the dumper will create a dump ELF file named "dump.elf"
on the given NVMe dump partition by using the makedumpfile tool. The kdump
compressed file format is not supported yet due to zgetdump not being able
to read such a file format. Therefore, the dumper is restricted to write
the dump only in ELF format but only kernel pages which are in use.
This will usually make the dump smaller than the original size of
/proc/vmcore and the whole dump process faster as well.

Example configuration for dumpconf:

ON_PANIC=dump   # or dump_reipl
DUMP_TYPE=nvme
FID=0x00000001
NSID=0x00000001
BOOTPROG=0
BR_LBA=0

$ systemctl enable --now dumpconf

To install the dracut support on Fedora/RHEL/SUSE:

$ make -C zipl/dracut HAVE_DRACUT=1 install

To install the initramfs-tools support on Ubuntu/Debian:

$ make -C zipl/initramfs-tools HAVE_INITRAMFS=1 install

Example of NGDump console output on SLES during dump
----------------------------------------------------

         Starting NGDump...
[    8.932343] ngdump.sh[327]: NGDump started
[    8.934739] ngdump.sh[336]: Checking for memory holes                         : [  0.0 %] /
[    8.967536] ngdump.sh[336]: Checking for memory holes                         : [100.0 %] |
[    9.076976] ngdump.sh[336]: Excluding unnecessary pages                       : [100.0 %] \
[   11.721157] ngdump.sh[336]: Copying data                                      : [  0.0 %] -
[   12.317319] ngdump.sh[336]: Copying data                                      : [ 22.5 %] /           eta: 2s
[   13.273000] ngdump.sh[336]: Copying data                                      : [100.0 %] |           eta: 0s
[   13.273244] ngdump.sh[336]: The kernel version is not supported.
[   13.273263] ngdump.sh[336]: The makedumpfile operation may be incomplete.
[   13.273281] ngdump.sh[336]: The dumpfile is saved to /ngdump/dump.elf.
[   13.273299] ngdump.sh[336]: makedumpfile Completed.

Example of NGDump console output on Ubuntu during dump
-------------------------------------------------------

[    3.240078] zdump: The dump process started for a 64-bit operating system
Loading, please wait...
Starting version 245.4-4ubuntu3.17
Begin: Starting firmware auto-configuration ... done.
Begin: Loading essential drivers ... done.
Begin: Running /scripts/init-premount ...
Begin: NGDump ...
Checking for memory holes                         : [  0.0 %] /
Checking for memory holes                         : [100.0 %] |
Excluding unnecessary pages                       : [100.0 %] \
Copying data                                      : [  0.0 %] -
Copying data                                      : [ 40.7 %] /           eta: 1s
Copying data                                      : [100.0 %] |           eta: 0s
The kernel version is not supported.
The makedumpfile operation may be incomplete.
The dumpfile is saved to /ngdump/dump.elf.
makedumpfile Completed.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Tested-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
b4142a9966 zipl: Implement zipl helper script for NGDump
The purpose of the new zipl helper script is to build a dumper initramfs
for NGDump stand-alone dump. zipl executes the helper script when
preparing a NVMe dump partition for stand-alone dump.

The zipl helper script expects a single parameter - a path to the dump
partition to store a dump on. The helper script terminates with 0 on
success and a positive value otherwise.

The zipl helper script performs the following steps:
- It builds an initramfs image suitable for dumping. To perform this step,
  the script employs the dracut tool on Fedora/RHEL/SLES and
  the initramfs-tools on Ubuntu/Debian.
- It outputs the path to the newly built initramfs image and the currently
  active kernel bzImage on the standard output.
- It prints the kernel command-line to be used by the dumper on
  the standard output.

On success, zipl expects the helper script to return at least three lines
containing:
- initrd=<path to an initramfs image>
- kernel=<path to a kernel bzImage>
- cmdline=<kernel command-line parameters>

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
c1d08e1380 zipl: Add initramfs-tools module for NGDump
The NGDump initramfs-tools module is required to build an initramfs image
to be used with NGDump stand-alone dump. NGDump stand-alone dump does not
use a pre-built initramfs image in contrast to SCSI stand-alone dump.
Instead, an initramfs image is built with initramfs-tools if NGDump
stand-alone dump is installed on a NVMe partition.

The NGDump initramfs-tools module ensures that all necessary tools are
present within the built initramfs and a dump of /proc/vmcore is initiated
to the chosen NVMe partition when the installed dumper is IPLed.

The NGDump intramfs-tools module installs a configuration file and
a dump script into dumper initramfs. This dump script starts at boot
shortly after the initialization of the dump target device. It reads
the aforementioned configuration file that contains the name of a dump
partition to store a dump on. The dump script reads the configuration file,
mounts then the dump target device, creates a copy of /proc/vmcore with
the makedumpfile tool on it, and then shuts down the system.

Ubuntu and Debian are the main Linux distributions targeted by this
initramfs-tools module.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
85c9a49e63 zipl: Add dracut module for NGDump
The NGDump dracut module is required to build an initramfs image to be used
with NGDump stand-alone dump. NGDump stand-alone dump does not
use a pre-built initramfs image in contrast to SCSI stand-alone dump.
Instead, an initramfs image is built with dracut if NGDump stand-alone dump
is installed on a NVMe partition.

The NGDump dracut module ensures that all necessary tools are present
within the built initramfs and a dump of /proc/vmcore is initiated
to the chosen NVMe partition when the installed dumper is IPLed.

The NGDump dracut module installs a new systemd service and a dump script
into dumper initramfs. The systemd init process starts the NGDump service
at boot shortly after the initialization of the dump target device.
The NGDump systemd service, in its turn, starts the dump script provided
by the new dracut module. The dump script mounts then the dump target
device, creates a copy of /proc/vmcore with the makedumpfile tool on it,
and then shuts down the system.

The NGDump dracut module can be used on any Linux distribution which
supports dracut. But the primary targets are:
- Fedora
- RHEL
- SLES

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Tested-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
4939531fe5 zipl: Add bootmap directory parameter to bootmap_create_file()
This change adds a new parameter to the function bootmap_create_file()
that requires the caller to specify a path to the directory where
a bootmap file will be created. The primary motivation for this change is
to support NVMe stand-alone dump, in that case the job's bootmap directory
is not set.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
84abb27077 zipl: Extract SCSI dump partition check from bootmap_create_device()
The purpose of this change is to simplify the function
bootmap_create_device() and make it more readable. Furthermore,
the dump partition check can be reused for NVMe dump partitions later on.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
6826316350 zipl: Extract SCSI dump size estimation from bootmap_create_device()
The purpose of this change is to simplify the function
bootmap_create_device() and to make it more readable.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
b95a3c24b8 zipl: Extract SCSI superblock writing from bootmap_create_device()
The purpose of this change is to simplify the function
bootmap_create_device() and make it more readable.
Furthermore, make bootmap_create_device() more robust by checking the return
value of disk_write_block_aligned().

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
1f8496aa92 zipl: Extract SCSI dump partition handling from bootmap_create()
The purpose of this change is to simplify the function bootmap_create(),
make it more readable and prepare for new changes that will follow.
The original function bootmap_create() tried to handle two different cases
and, therefore, contained many conditional statements which had a negative
effect on readability.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
9aa59bfc4b zipl: Fix stage2 disk block memory leaks in bootmap_install_stages()
This commit fixes a bug that fails to release stage2 disk blocks in case
the installation of stage1b disk blocks has failed.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
fa111404cb zipl: Extract stage2 loader handling from bootmap_create()
The purpose of this change is to simplify the function bootmap_create(),
make it more readable and prepare for new changes that will follow.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
5094354c39 zipl: Implement helper function disk_is_nvme()
The new function disk_is_nvme() is a convenience function that indicates
whether the given path to a device file represents a NVMe disk.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Acked-by: Stefan Haberland <sth@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:05 +02:00
Alexander Egorenkov
844058bf4d zipl: Extend disk_get_info() to recognize NVMe disks
Until now, NVMe disks were handled by zipl as SCSI disks. To support
NVMe stand-alone dump, it became necessary to further differentiate between
both types of disks.

There are two cases that must be handled:
1. A non-device-mapper device is a NVMe disk if it is assigned to the blkext
   device driver.
2. A device-mapper disk is a NVMe disk if the ioctl NVME_IOCTL_ID succeeds.
   This case is necessary to properly recognize NVMe disks which are
   DM devices and, therefore, not directly handled by the blkext device
   driver.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Acked-by: Stefan Haberland <sth@linux.ibm.com>
Acked-by: Alexander Gordeev <agordeev@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
dc49b4fcf0 zdump/scsi: reuse zipl magic string definitions from boot_defs.h
To remove duplication of definitions.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
647e8b5c37 zipl/boot: move zipl magic string definitions to boot_defs.h for reuse
To reduce duplication of definitions and facilitate reuse between zipl
and zgetdump.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
1ae4fd18fe zfcpdump: reuse SCSI struct definitions from boot_defs.h
To remove duplication of definitions.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
561883b1d8 zdump/scsi: reuse SCSI MBR struct definitions from boot_defs.h
To remove duplication of definitions.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
953af2cc67 zipl/boot: move SCSI MBR struct definition to boot_defs.h for reuse
To reduce duplication of definitions and facilitate reuse between zipl
and zgetdump.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
8f37000137 zdump/scsi: reuse boot info struct definitions from boot_defs.h
To remove duplication of definitions.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
ba7bf2f6d3 zipl/boot: move boot info struct definitions to boot_defs.h for reuse
To reduce duplication of definitions and facilitate reuse between zipl
and zgetdump.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
4a8e52a019 zdump/scsi: reuse SCSI superblock struct definitions from boot_defs.h
To remove duplication of definitions.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
446ace09ad zipl/boot: move SCSI superblock struct definitions to boot_defs.h for reuse
To reduce duplication of definitions and facilitate reuse between zipl
and zgetdump.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
012b842652 zdump/scsi: reuse boot component struct definitions from boot_defs.h
To remove duplication of definitions.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Alexander Egorenkov
fed12a71cf zipl/boot: move boot component struct definitions to boot_defs.h for reuse
To reduce duplication of definitions and facilitate reuse between zipl
and zgetdump.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Thomas Richter
5cd9ad13e5 cpumf/lshwc: Use util_file_read_va function
Use util_file_read_va() function to read out the event number
given the event file. Also use util_strdup() function to save
the event name. This function terminates on Out Of Memory condition.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Frank Heimes
f2d5b649e1 README.md: Add 70-chreipl-fcp-mpath.rules to the list of udev rule descriptions
All udev rules that are part of the s390-tools package are listed in the main
README.md with a brief description.
This commit adds information about the newly added rule for chreipl-fcp-mpath,
called '70-chreipl-fcp-mpath.rules'.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/136
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Acked-by: Benjamin Block <bblock@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-20 13:14:04 +02:00
Jan Höppner
a957e3efd6 zcryptstats: Fix man page section in title line
The title line of the zcryptstats man page specifies section 1 (user
command) while the tool is a system command.
Change it to section 8 for system command.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/135
Reviewd-by Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Jan Höppner
463189bf60 cpumf: Move man pages to System commands section
lscpumf, lshwc, and pai are system commands but the corresponding man
pages are located in section 1 for user commands.

Move the man pages to section 8 for system commands.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/135
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Jan Höppner
aa2e8e1caa scripts: Move man pages to System commands section
dbginfo.sh, zfcpdbf, and zipl-switch-to-blscfg are system commands but
the corresponding man pages are located in section 1 for user commands.

Move the man pages to section 8 for system commands.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/135
Reviewed-by: Steffen Maier <maier@linux.ibm.com> [zfcpdbf]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Jan Höppner
7bc15537c8 genprotimg: Move man page to section 1 for user commands
genprotimg is a user command and as such installed into /usr/bin. Adapt
the man page accordingly and move it from section 8 (system commnds) to
section 1 (user commands).

Reported-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Frank Heimes
901f082f1a s390-tools: Fix typos that were detected by lintian as 'typo-in-manual-page'
The static analysis tool for Debian packages 'lintian', especially if called
like 'lintian -EvIL +pedantic', checks manual pages for correctness and typos.
This commit fixes typos that were identified by lintian and marked with
'typo-in-manual-page' while s390-tools version 2.20.0 was packaged.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/134
Signed-off-by: Frank Heimes <frank.heimes@canonical.com>
Acked-by: Steffen Maier maier@linux.ibm.com [ziomon]
Acked-by: Ingo Franzki ifranzki@linux.ibm.com [zkey]
[hoeppner@linux.ibm.com: fix commit message]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Ingo Franzki
cd2647ab78 libseckey: make secure key provider functions more type save
The provider functions are passed to OpenSSL in the dispatch array
casted to 'void (*)(void)', so they can not be type checked by the
compiler. Add function prototypes using the OpenSSL provided
function typedefs to allow the compiler to check the function
signatures.

No functional change.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Ingo Franzki
48bcfc3366 zkey-kmip: Fix possible use after free
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Ingo Franzki
57f3527799 libkmipclient: Fix -Wmaybe-uninitialized warning with gcc 12
Gcc 12 produces a -Wmaybe-uninitialized warning that the content
of the tmp buffer may be uninitialized. This is a false positive.
Silence the warning by using calloc instead of malloc to ensure
that the allocated buffer is initialized.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Eduard Shishkin
f51dc05f7f zipl/Makefile: create an empty environment file /etc/ziplenv
Create an empty environment file /etc/ziplenv at make install
time if that file doesn't exist

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Eduard Shishkin
3f9ead5731 ipl-tools/man: update a man page with LOADPARM specifications
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Eduard Shishkin
b4e4cd6cd5 zipl/man: update zipl-editenv man page
Add definitions of sites, namespaces and sections.
Document the new options --site (-S) and --effective-site (-E)

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Eduard Shishkin
e97c85bb80 zipl-editenv: added zIPL multienvironment support
. Support multiple namespaces in the installed environment block;
. Add option --site (-S) to specify a particular namespace
  when operating on the installed environment block;
. Add option --effective-site (-E) to specify a particular
  namespace. When using in a combination with the option -l
  (--list), it displays zIPL environment that would take place if
  the specified namespace was activated at boot time;
. Modify set/unset/reset/list operations over the installed
  environment block in the case when the option --site is specified

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Eduard Shishkin
c6443cf977 zipl/boot: added zIPL multienvironment support
. Parse LOADPARM specified by user to find out site-ID;
. Support multiple namespaces in the environment block. Use hash
  function on "extended" strings (i.e. strings with logical
  prefixes) for the key-value store implementation;
. Added logic to activate a particular namespace by site-ID passed
  by user via LOADPARM;
. Modify the logic of evaluation of zIPL environment variables in
  the kernel command line. Use the activated namespace for the
  evaluation

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Eduard Shishkin
6a439e6771 zipl/src: added zIPL multienvironment support
Support multiple namespaces in environment block. Use hash
function on "extended" strings for key-value store.
Support multiple sections in environment file.
Modify the import environment precedure to be "section-aware"

Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
2134aff491 zipl/boot: kdump: remove static struct
Makes the code easier to read since it can have less side effects.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
b41ac66f36 zipl: consolidate boot and dump type definitions
Consolidate type definitions in order to avoid duplicated code, getting
better compiler support, and to avoid confusing namings for the same
thing - e.g. `blk_end` vs. `blockcnt` field name used in the old `struct
fba_dump_param` definitions. It also allows us to get rid of two
`uint64_t` casts.

While at it, fix the documentation of `struct eckd_blockptr`.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
9aa368af54 zipl/boot: eckd2/fba: remove two superfluous casts
Remove two superfluous casts.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
2e6cf81c2a zipl/boot: stage3.lds.S: put notes section explicitly at the end
...otherwise `.note.gnu.build-id` will be put at 0x0 (location for s390x
lowcore) if the linker option `--build-id` is used (which is the default
if gcc is used for linking).

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
ae27066c15 zipl/boot: add struct tpi_info to the lowcore struct
Use the `tpi_info` struct definition, similar to the Linux kernel, in
the lowcore struct. This change allows us to use simple assignments
instead of using casts. Additionally, there is the advantage that the
lowcore definition from the s390-tools now looks more similar to the
lowcore definition used by the Linux kernel.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
47fcc71f96 include/s390.h: add STATIC_ASSERTION for size of lowcore
This helps to find possible bugs earlier, e.g. possible bugs in the
changes in the upcoming patches.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
5ac171d224 genprotimg/zipl: boot: Makefile: small refactoring
Move the common `-nostdlib` and `$(NO_PIE_LINKFLAGS) linker options to
the actual linker call. This makes the code easier to maintain.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Marc Hartmayer
67dbf094b2 genprotimg/zipl: boot: Makefile: do not link against shared libraries
It's pretty obvious that we don't want to link against shared libraries
therefore use `-static` for linking.

`ld` call before this change:

  /usr/bin/ld -v -plugin /usr/lib/gcc/s390x-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/s390x-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccLfGZu4.res --build-id --eh-frame-hdr -m elf64_s390 --hash-style=gnu --as-needed -dynamic-linker /lib/ld64.so.1 -z relro -o stage3.exec -L/usr/lib/gcc/s390x-linux-gnu/9 -L/usr/lib/gcc/s390x-linux-gnu/9/../../../../s390x-linux-gnu/lib/../lib -L/usr/lib/gcc/s390x-linux-gnu/9/../../../s390x-linux-gnu -L/usr/lib/gcc/s390x-linux-gnu/9/../../../../lib -L/lib/s390x-linux-gnu -L/lib/../lib -L/usr/lib/s390x-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/s390x-linux-gnu/9/../../../../s390x-linux-gnu/lib -L/usr/lib/gcc/s390x-linux-gnu/9/../../.. -T stage3.lds stage3.o head.o kdump3.o libc.o ebcdic.o ebcdic_conv.o sclp.o sclp_stage3.o kdump.o entry.o

`ld` call after this change:

  /usr/bin/ld -v -plugin /usr/lib/gcc/s390x-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/s390x-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/ccw0ELAp.res --build-id -m elf64_s390 --hash-style=gnu --as-needed -static -z relro -o stage3.exec -L/usr/lib/gcc/s390x-linux-gnu/9 -L/usr/lib/gcc/s390x-linux-gnu/9/../../../../s390x-linux-gnu/lib/../lib -L/usr/lib/gcc/s390x-linux-gnu/9/../../../s390x-linux-gnu -L/usr/lib/gcc/s390x-linux-gnu/9/../../../../lib -L/lib/s390x-linux-gnu -L/lib/../lib -L/usr/lib/s390x-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/s390x-linux-gnu/9/../../../../s390x-linux-gnu/lib -L/usr/lib/gcc/s390x-linux-gnu/9/../../.. -T stage3.lds stage3.o head.o kdump3.o libc.o ebcdic.o ebcdic_conv.o sclp.o sclp_stage3.o kdump.o entry.o

Fixes: b627b8d8e1 ("Initial s390-tools-2.0.0 import")
Fixes: 3356d6f4fa ("genprotimg: boot: initial bootloader support")
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Reviewed-by: Halil Pasic <pasic@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-06-03 18:40:36 +02:00
Dimitri John Ledkov
3669fd4d8a zkey: Add initramfs hook
Add hook script to allow zkey utilities to be used in initramfs.

Closes: https://github.com/ibm-s390-linux/s390-tools/pull/42
Signed-off-by: Dimitri John Ledkov <xnox@ubuntu.com>
Reviewd-by Ingo Franzki <ifranzki@linux.ibm.com>
[hoeppner@linux.ibm.com: removed / in Makefile and updated commit message]
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Jan Höppner
b01ef782f0 scripts/dumpconf: Bring installation rules in line with other scripts
Until recently dumpconf might have been installed in two different
locations, /etc/init.d/ and /lib/s390-tools/. As dumpconf is now part of
the helper scripts in the scripts directory, extend the installation
rule and add the %S390_TOOLS_VERSION% wildcard to the script along the
way for correct version output.

The installation rule in the systemd/Makefile is removed, bringing it in
line with cpictl.

Acked-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Jan Höppner
a177ae2439 scripts/dumpconf: Update header of the dumpconf script
Remove the leftovers of the SysV init configuration and replace it with
proper information about the tool. Also add the missing Copyright
statement and remove DUMPCONF_BIN as there is no user.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/132
Acked-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Jan Höppner
13fef6dbe0 dumpconf: Move dumpconf tool to scripts directory
Modern distributions use systemd and a corresponding systemd unit file
is provided that handles the dumpconf tool. The tool is also the last
script left in etc/init.d. Move it to scripts and get rid of the init.d
directory altogether.

Acked-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Jan Höppner
508253c666 etc/init.d: Remove SysV related daemon scripts
For cpacfstatsd, cpuplugd, and mon_statd there are still SysV daemon
scripts available. However, modern distributions use systemd and
corresponding systemd unit files are provided and in use for a long time
already.

Remove the daemon scripts for the obsolete SysV init system as they're
not used by modern systems anymore.

Acked-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Matthew Rosato
773d01e674 zdev: Introduce the ap device type
The AP device type initially allows only the setting of type
attributes 'apmask' and 'aqmask'.

Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Matthew Rosato
2da206f5a6 ap_tools: Introduce ap_tools and the ap-check tool
The ap_tools utilities are intended to be used in conjunction with
the mdevctl utility for safely managing and inspecting vfio-ap
mediated devices.  For now, this will consist of the ap-check tool
which will be driven via a call-out from mdevctl to validate a
proposed vfio-ap mediated device change.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Jason J. Herne <jjherne@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Matthew Rosato
bf71e3bb1f libap: Add library for ap / vfio-ap management tools
libap is intended to provide utility functions to be used by
tooling supporting the ap bus and vfio-ap mediated devices.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Matthew Rosato
6f7982dae5 libutil: Introduce util_udev
Move code to read udev files from zdev into a utility library for use by
other tools.

Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Matthew Rosato
f64b4087dd libutil: Move some zdev file reading functions into util
In preparation for sharing some zdev udev code with other libraries, move
some file operation code from zdev into util_file.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Matthew Rosato
a739584d6f libutil: add util_exit_code
zdev uses a particular set of exit codes -- In preparation for sharing
some zdev udev code with other libraries, let's also create a libutil
include to specify reusable exit codes.  For now, let's just initialize
it with the codes from zdev we care about.

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Reviewed-by: Jason J. Herne <jjherne@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Thomas Richter
cce5f510c3 cpumf/lscpumf: Add IBM z16 extended counter set definitions
Add IBM z16 extended counter set. For each counter in this set
add the counter number, the short and long description and the
counter number.

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-05-17 13:20:27 +02:00
Thomas Richter
2515832469 util_arch: Add IBM z16 as known machine
Add IBM z16 as known machine to the architecture definitions.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:27 +02:00
Ingo Franzki
6c5c5f7e55 libseckey: Adapt keymgmt_match() implementation to OpenSSL
OpenSSL commit ee22a3741e3fc27c981e7f7e9bcb8d3342b0c65a changed the
OpenSSL provider's keymgmt_match() function to be not so strict with
the selector bits in regards to matching different key parts.

Adapt the secure key provider's match function accordingly.
This means, that if the public key is selected to be matched, and
the public key matches (together with any also selected parameters),
then the private key is no longer checked, although it may also be
selected to be matched. This is according to how the OpenSSL function
EVP_PKEY_eq() is supposed to behave.

OpenSSL function SSL_CTX_use_PrivateKey() calls the providers match
function to check if the private key specified matches the public key
of the certificate using EVP_PKEY_eq(). EVP_PKEY_eq() includes the
private key into the selector bits here, although the certificate
only contains the public key part.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-17 13:20:26 +02:00
Thomas Richter
736c69379d cpumf/pai: Add support for PAI extension 1 NNPA counters
The Processor Activity Instrumentation facility (PAI) Extension 1
adds support for the counter set for Neural Network Processing Assist
(NNPA) counters.

NNPA counter values are appended as raw data to the data report.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-13 11:42:54 +02:00
Thomas Richter
130880159a libcpumf: Detect PMU pai_nnpa
Add a check to detect Processor Activity Instrumentation (PAI)
Extension 1 facility unit. This covers the counter set for
Neural Network Processing Assist (NNPA) counters.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-13 11:42:54 +02:00
Thomas Richter
d7b1cbad8b cpumf/pai: Add Processor Activity Instrumentation tool
The Processor Activity Instrumentation facility (PAI) uses the
perf_event_open system call to report data and the crypto counter
values. The data can be inspected with the perf tool in a very
generic way using raw data report and a hex dump utility.

The pai tool also uses the perf_event_open system call to record the
data, but uses specialized event attributes for recording detailed
information such as the recording of fork, exit, exec system call
events and context switch events.
Cryptography counter values are appended as raw data attachments.

The pai command can be used for recording and reporting.
Also a list of CPUs can be specified.
The recording ring buffers are created per CPU
and are named paicrypto.XXX where XXX stands for the CPU number.
The numbering scheme has leading zeros, such as 007 for CPU number 7.

For invocation and possible command line options see the man page.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-13 11:42:51 +02:00
Thomas Richter
a58460b5c7 libcpumf: Function to return PMU name
Return the PMU name as found in the sysfs tree given a PMU type number.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-13 11:41:56 +02:00
Thomas Richter
acdce2a7a9 libcpumf: Detect PMU pai_crypto
Add a check to detect Processor Activity Instrumentation (PAI)
facility unit.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-13 11:41:56 +02:00
Sven Schnelle
0981df62c0 cmsfs-fuse: fix enabling of hard_remove option
Since the switch to fuse3 setting the hard_remove option with the
FUSE_LIB_OPT() macro is no longer supported. See libfuse commit
8ee553dac029 ("fuse_new(): don't accept options that don't make sense
for end-users") for details. To fix this, add an appropriate init
function which sets this option.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/131
Fixes: e679a88d88 ("Switch from fuse2 to fuse3")
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Jan Höppner
4e28f6749b Add missing copyright header
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Thomas Richter
5f08033bb8 libcpumf: Fix doxygen comments
Fix the doxygen comments and add a description on the return values.

Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Marc Hartmayer
8231ec5f38 zipl/boot/Makefile: fix cleanup of linker script dependency files
By default, the Bash file globbing pattern '*' doesn't list files prefixed by a
dot (see https://linux.die.net/man/1/bash). Let's fix this by using the pattern
`.*` instead. While at it, add `--` option to remove possible problems with
leading dashes in filenames.

Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Marc Hartmayer
9e62005818 genprotimg/boot: disable -Warray-bounds for now
This work around fixes the gcc-12 false positive by disabling `Warray-bounds`:

  CC      genprotimg/boot/stage3a.o
  In file included from stage3a.c:14:
  In function ‘__test_facility’,
      inlined from ‘test_facility’ at ../../include/boot/s390.h:428:9,
      inlined from ‘start’ at stage3a.c:42:7:
  ../../include/boot/s390.h:418:17: error: array subscript 0 is outside array bounds of ‘void[0]’ [-Werror=array-bounds]
    418 |         return (*ptr & (0x80 >> (nr & 7))) != 0;
	|                 ^~~~

Unfortunately, there is currently no better fix available that doesn't result
in larger boot loader code sizes. Given the importancy of the boot loader file
sizes the other fixes aren't acceptable. The Linux kernel shares the
problem (but for performance reasons), take a look at the discussion
https://lore.kernel.org/lkml/yt9dzgkelelc.fsf@linux.ibm.com/ for details.

Fixes: https://github.com/ibm-s390-linux/s390-tools/issues/130
Signed-off-by: Marc Hartmayer <mhartmay@linux.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Eduard Shishkin
a0dba6bfdb zipl/src: Implement sorting bls entries by versions
This patch implements an additional method of sorting bls entries
by version field and uses it as default one. If sorting by version
fails, then it falls back to the most robust method of sorting by
file names

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Eduard Shishkin
ebc3384b9f zipl/src: make blsdir variable global instead of local
It is used by the next patch.
Specifically, ->filter() and ->sort() callbacks of the scandir(3)
accept only short names of directory entries to be filtered/sorted,
while we need to know absolute names to perform filtering/sorting.

Signed-off-by: Eduard Shishkin <edward6@linux.ibm.com>
Reviewed-by: Stefan Haberland <sth@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-05-10 13:33:24 +02:00
Jan Höppner
e9bf141264 Prepare for next release
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2022-04-20 13:29:04 +02:00
260 changed files with 24330 additions and 2792 deletions

12
.checkpatch.conf Normal file
View File

@@ -0,0 +1,12 @@
--max-line-length=100
--strict
# Not Linux therefore don't expect a Linux tree
--no-tree
# Ignore the following
--ignore PREFER_KERNEL_TYPES
--ignore EXECUTE_PERMISSIONS
--ignore FILE_PATH_CHANGES
--ignore NEW_TYPEDEFS
--ignore SPDX_LICENSE_TAG

134
.clang-format Normal file
View File

@@ -0,0 +1,134 @@
# Must be compatible with clang-format 14
---
AccessModifierOffset: "-4"
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments: false
AlignConsecutiveBitFields: AcrossComments
AlignConsecutiveMacros: AcrossComments
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: false
BitFieldColonSpacing: Both
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
BreakConstructorInitializers: BeforeComma
BreakConstructorInitializersBeforeComma: false
BreakStringLiterals: false
ColumnLimit: "100"
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: "8"
ContinuationIndentWidth: "8"
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
# git grep -h '^#define [^[:space:]]*\(for_each\|iterate\)[^[:space:]]*(' \
# | sed "s,^#define \([^[:space:]]*\(for_each\|iterate\)[^[:space:]]*\)(.*$, - '\1'," \
# | LC_ALL=C sort -u
ForEachMacros:
- "dfi_cpu_iterate"
- "dfi_mem_chunk_iterate"
- "dfo_chunk_iterate"
- "for_each_rb_entry"
- "ns_range_for_each"
- "sd_cpu_item_enable_iterate"
- "sd_cpu_item_iterate"
- "sd_cpu_iterate"
- "sd_cpu_type_iterate"
- "sd_sys_item_enable_iterate"
- "sd_sys_item_iterate"
- "sd_sys_iterate"
- "table_col_iterate"
- "table_iterate_mark_keys"
- "util_list_iterate"
- "util_list_iterate_safe"
- "util_opt_iterate"
- "util_rec_iterate"
IncludeBlocks: Preserve
# Leave imports as is
IncludeCategories:
- Regex: .*
Priority: 1
IndentCaseLabels: false
IndentGotoLabels: false
IndentPPDirectives: None
IndentWidth: "8"
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: "1"
NamespaceIndentation: Inner
PackConstructorInitializers: CurrentLine
PenaltyBreakAssignment: "10"
PenaltyBreakBeforeFirstCallParameter: "30"
PenaltyBreakComment: "10"
PenaltyBreakFirstLessLess: "0"
PenaltyBreakString: "10"
PenaltyExcessCharacter: "100"
PenaltyReturnTypeOnItsOwnLine: "60"
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatementsExceptForEachMacros
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: "1"
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
StatementMacros:
- "STATIC_ASSERT"
TabWidth: "8"
TypenameMacros:
- "STACK_OF"
UseTab: Always
WhitespaceSensitiveMacros:
- "STRINGIFY"

5
.codespellrc Normal file
View File

@@ -0,0 +1,5 @@
[codespell]
ignore-words-list = parm,parms
skip = ''
count = ''
quiet-level = 3

7
.gitignore vendored
View File

@@ -16,12 +16,14 @@ TAGS
#
# Ignore generated executables and other generated files
#
ap_tools/ap-check
cmsfs-fuse/cmsfs-fuse
cpacfstats/cpacfstats
cpacfstats/cpacfstatsd
cpumf/chcpumf
cpumf/lscpumf
cpumf/lshwc
cpumf/pai
cpuplugd/cpuplugd
dasdfmt/dasdfmt
dasdinfo/dasdinfo
@@ -45,6 +47,8 @@ iucvterm/src/iucvconn
iucvterm/src/iucvtty
iucvterm/src/ttyrun
iucvterm/test/test_afiucv
libap/check-dep-lock
libap/check-dep-json
libekmfweb/check-dep-libekmfweb
libekmfweb/detect-openssl-version.dep
libekmfweb/libekmfweb.so
@@ -64,6 +68,8 @@ lsstp/lsstp
mon_tools/mon_fsstatd
mon_tools/mon_procd
osasnmpd/osasnmpd
pvattest/src/pvattest
pvattest/tools/exchange_info
qetharp/qetharp
qethqoat/qethqoat
systemd/cpacfstatsd.service
@@ -117,3 +123,4 @@ zkey/kmip/zkey-kmip.so
zkey/zkey
zkey/zkey-cryptsetup
zpcictl/zpcictl
**/.detect-openssl.dep.c

View File

@@ -9,6 +9,7 @@ List of all individuals having contributed content to s390-tools
- Antoinette Kaschner
- Arnd Bergmann
- Axel Wirbser
- Balint Reczey
- Benjamin Block
- Brian C. Lane
- Carsten Otte
@@ -34,6 +35,7 @@ List of all individuals having contributed content to s390-tools
- Fedor Loshakov
- Felix Beck
- Frank Blaschka
- Frank Heimes
- Frank Munzert
- Frank Pavlic
- Fritz Elfert
@@ -79,6 +81,7 @@ List of all individuals having contributed content to s390-tools
- Matthew Rosato
- Maxim Shchetynin
- Melissa Howland
- Mete Durlu
- Michael Ernst
- Michael Holzheu
- Michael Mueller

View File

@@ -1,5 +1,84 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.24.0 (2022-11-09)__
For Linux kernel version: 6.0
Add new tools / libraries:
- Provide config files for checkpatch, codespell, and clang-format
Changes of existing tools:
- dbginfo.sh: Collect log from various distro tools (YaST, DNF, Anaconda)
- dbginfo.sh: add Kubernetes data collection
- libutil: Introduce util_lockfile
- zdev: Add site-aware device configuration
- zdump: Add support to read Protected Virtualization dumps
- zipl/boot: Add secure boot trailer
Bug Fixes:
- ap_tools/ap-check: Reject start for control domains without usage
- cpumf/lshwc: Fix incremented counter output
- cpumf/pai: Fix core dump when summary flag set
- dbginfo.sh: Ensure compatibility with /bin/dash shell
- dbginfo.sh: Save dbginfo.sh version to dbginfo.log
- zipl/src/zipl_helper.device-mapper: Fix bug in error path
* __v2.23.0 (2022-08-18)__
For Linux kernel version: 5.19
Changes of existing tools:
- Makefile: use common Make definition for DRACUTDIR
- Makefile: use common Make definition for UDEVDIR and UDEVRULESDIR
- cpacfstats: Add PAI and hotplug support
- cpumf/pai: Omit file write progress information
- dbginfo.sh: Get more details on lspci command
- dumpconf: Prevent running the service in containers
- libcpumf: Detect PMU named pai_ext
- pvattest: Improve error reporting and logging
- zdev: Add some --type ap examples to manpages
- zkey: Use default benchmarked Argon2i with LUKS2
Bug Fixes:
- dbginfo.sh: Fix accidental ftrace buffer shrinkage/free
- genprotimg: Fix BIO_reset() returncode handling
- libpv: Fix dependency checking
- pvattest: Fix dependency checking
- zipl: Fix segmentation fault when no parmline is provided
* __v2.22.0 (2022-06-20)__
For Linux kernel version: 5.18
Add new tools / libraries:
- ap_tools: Introduce ap_tools and the ap-check tool
- cpumf/pai: Add Processor Activity Instrumentation tool
- libpv: New library for PV tools
- pvattest: Add new tool to create, perform, and verify attestation measurements
- zipl/zdump: Add Next Gen Dump (NGDump) support
Changes of existing tools:
- Move man pages to System commands section (lscpumf, lshwc, pai, dbginfo.sh, zfcpdbf, zipl-switch-to-blscfg)
- README.md: Add 70-chreipl-fcp-mpath.rules to the list of udev rule descriptions
- Remove SysV related daemon scripts (cpacfstatsd, cpuplugd, mon_statd)
- genprotimg: Move man page to section 1 for user commands
- hyptop: increase initial update interval
- libseckey: Adapt keymgmt_match() implementation to OpenSSL
- libutil: Add util_exit_code
- libutil: Introduce util_udev
- zdev: Introduce the ap device type
- zipl-editenv: Add zIPL multienvironment support
- zipl: Implement sorting BLS entries by versions
- zkey: Add initramfs hook
Bug Fixes:
- cmsfs-fuse: Fix enabling of hard_remove option
- s390-tools: Fix typos that were detected by lintian as 'typo-in-manual-page'
- zkey-kmip: Fix possible use after free
- zkey: Fix EP11 host library version checking
- zkey_kmip: Setup ext-lib once the APQNs have been configured
* __v2.21.0 (2022-04-20)__
For Linux kernel version: 5.17

View File

@@ -4,8 +4,10 @@ Coding guidelines for s390-tools
For s390-tools the preferred language is C. We provide libraries, e.g.
[`libutil`](libutil) that should be used by all tools if possible.
The coding style is based on the Linux [kernel guidelines]. Therefore, use
the [checkpatch] tool for verification before you submit a patch.
The coding style is based on the Linux [kernel guidelines]. Therefore, use the
[checkpatch] tool for verification before you submit a patch. s390-tools
provides a CheckPatch configuration for this - see
[`.checkpatch.conf`](.checkpatch.conf).
[kernel guidelines]: https://www.kernel.org/doc/html/latest/process/coding-style.html
[checkpatch]: https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl
@@ -17,6 +19,39 @@ This package started in 2001 and has a long "tradition" - therefore, older tools
might not follow all recommendations. Note that when changing existing code,
consistency could have priority over applying rules.
Automatic Code Formatting
-------------------------
> **NOTE:** clang-format is a helpful tool but please don't use it blindly!
s390-tools provides a ClangFormat (https://clang.llvm.org/docs/ClangFormat.html)
configuration file - see [`.clang-format`](.clang-format). It can be used to
format your C/C++ code automatically.
Clang-format can format a single file or multiple files at once. For example, to
format `main.c` in place, run the following command in a terminal:
```bash
clang-format -i main.c
```
In order to format only your current staged changes use the clang-format git
plugin:
```bash
git clang-format --staged
```
See also `git clang-format -h`.
Automatic Editor Configuration
------------------------------
s390-tools provides a EditorConfig (https://editorconfig.org/) configuration
file - see [`.editorconfig`](.editorconfig). EditorConfig defines coding style
rules (such as indentation size, use of tabs, etc.) and is supported by most
common editors natively or via plugins.
Standard abbreviations
----------------------

View File

@@ -10,13 +10,13 @@ include common.mak
#
BASELIB_DIRS = libutil libseckey
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
libkmipclient libcpumf
libkmipclient libcpumf libap libpv
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 \
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools pvattest
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)
@@ -33,7 +33,7 @@ endif
#
# We have to build the base libraries before the other libraries are built,
# and then build the other libraries before the tools are built. Otherwise the
# and then build the other libraries before the tools are built. Otherwise the
# other libraries and tools would trigger parallel "make -C" builds for the
# base libraries and the other libraries in case of "make -j".
#

View File

@@ -33,6 +33,9 @@ Package contents
* genprotimg:
Create a protected virtualization image.
* pvattest:
Create, perform, and verify protected virtualization attestation measurements.
* udev rules:
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
- 57-osasnmpd.rules: udev rules for osasnmpd.
@@ -40,6 +43,9 @@ Package contents
- 40-z90crypt.rules: udev rules for z90crypt driver
- 90-cpi.rules: udev rule to update Control-Program-Information when KVM is
used.
- 70-chreipl-fcp-mpath.rules: udev rules to monitor multipath events for
re-IPL path failover and to adjust the re-IPL
device in case needed.
* systemd units:
- cpi.service: Unit to apply CPI settings
@@ -50,10 +56,11 @@ Package contents
- ttyrun-getty@.service: Instance unit to manage ttyrun
* zipl:
Make DASDs or tapes bootable for system IPL or system dump.
Make DASDs, SCSIs, NVMes or tapes bootable for system IPL or system dump.
* zgetdump:
Retrieve system dumps from either tapes or DASDs.
Retrieve system dumps from either tapes, DASDs, SCSIs or NVMes.
Decrypt Protected Virtualization (PV) dumps from IBM Secure Execution guests.
* qetharp:
Read and flush the ARP cache on OSA Express network cards.
@@ -274,6 +281,10 @@ Package contents
Use multipath information to change the configured FCP re-IPL path on
detecting issues with the current path.
* ap-check:
A utility called by mdevctl to assist in managing vfio_ap-passthrough
devices.
For more information refer to the following publications:
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
@@ -296,26 +307,28 @@ build options:
| | | hsavmcore |
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
| ncurses | `HAVE_NCURSES` | hyptop |
| pfm | `HAVE_PFM` | cpacfstats |
| net-snmp | `HAVE_SNMP` | osasnmpd |
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
| | | libkmipclient |
| | | libkmipclient, pvattest, zgetdump |
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
| | | libkmipclient |
| glib2 | `HAVE_GLIB2` | genprotimg |
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient |
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest, zgetdump |
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
| | | pvattest |
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
| systemd | `HAVE_SYSTEMD` | hsavmcore |
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
This table lists additional build or install options:
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:-----------------------:|
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath |
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|------------------|:----------------------------:|:------------------------:|
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath, |
| | | zipl |
| initramfs-tools | `HAVE_INITRAMFS` | zdev, zipl |
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
The s390-tools build process uses "pkg-config" if available and hard-coded
compiler and linker options otherwise.
@@ -337,6 +350,16 @@ the different tools are provided:
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
* pvattest:
For building pvattest you need OpenSSL version 1.1.1 or newer
installed (openssl-devel.rpm). Also required is glib2.56 or newer
(glib2-devel.rpm) and libcurl.
Tip: you may skip the pvattest build by adding
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_GLIB2=0`.
The runtime requirements are: openssl-libs (>= 1.1.1) and
glib2.56 or newer.
* osasnmpd:
You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)
installed, before building the osasnmpd subagent.
@@ -353,6 +376,13 @@ the different tools are provided:
- Packages: blktrace, multipath-tools, sg3-utils
- Tools: rsync, tar, lsscsi
* zgetdump
For building zgetdump you need OpenSSL version 1.1.0 or newer
installed (openssl-devel.rpm). Also required is glib2
(glib2-devel.rpm) and zlib (zlib-devel.rpm).
Tip: you may skip the zgetdump build by adding
`HAVE_OPENSSL=0`, `HAVE_GLIB2=0`, or `HAVE_ZLIB=0`.
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
@@ -380,14 +410,13 @@ the different tools are provided:
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
* cpacfstats:
For building the cpacfstats tools you need libpfm version 4 or
newer installed (libpfm-devel.rpm). Tip: you may skip the cpacfstats
build by adding `HAVE_PFN=0` to the make invocation. To run the
cpacfstats daemon the kernel needs to have performance
events enabled (check for `CONFIG_PERF_EVENTS=y`) and you need libpfm
version 4 or newer installed. A new group 'cpacfstats' needs to be
created and all users intending to use the tool should be added to
this group.
For building the cpacfstats tools you need libudev installed
(systemd-devel.rpm). Tip: you may skip the cpacfstats build by
adding `HAVE_LIBUDEV=0` to the make invocation. To run the
cpacfstats daemon the kernel needs to have performance events
enabled (check for `CONFIG_PERF_EVENTS=y`). A new group 'cpacfstats'
needs to be created and all users intending to use the tool should
be added to this group.
* zdev:
Depending on the boot loader and initial RAM-disk mechanism used by a
@@ -481,3 +510,9 @@ the different tools are provided:
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.
* ap-check:
For building the ap-check mdevctl callout utility you need json-c version
0.13 or newer (json-c-devel.rpm).
Tip: you may skip ap-check build by adding `HAVE_JSONC=0` to the make
invocation.

40
ap_tools/Makefile Normal file
View File

@@ -0,0 +1,40 @@
include ../common.mak
MDEVCTL_DIR = /etc/mdevctl.d/
MDEVCTL_SCRIPTS = /etc/mdevctl.d/scripts.d/
MDEVCTL_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
libs = $(rootdir)/libap/libap.a \
$(rootdir)/libutil/libutil.a
ifeq (${HAVE_JSONC},0)
all:
$(SKIP) HAVE_JSONC=0
install:
$(SKIP) HAVE_JSONC=0
else
LDLIBS += -ljson-c
all: ap-check
ap-check: ap-check.o $(libs)
install: all
@if [ ! -d $(DESTDIR)$(MDEVCTL_CALLOUTS) ]; then \
mkdir -p $(DESTDIR)$(MDEVCTL_CALLOUTS); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DIR); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_SCRIPTS); \
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_CALLOUTS); \
chmod 755 $(DESTDIR)$(MDEVCTL_DIR); \
chmod 755 $(DESTDIR)$(MDEVCTL_SCRIPTS); \
chmod 755 $(DESTDIR)$(MDEVCTL_CALLOUTS); \
fi; \
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check \
$(DESTDIR)$(MDEVCTL_CALLOUTS)
endif
clean:
rm -f *.o *~ ap-check core
.PHONY: all install clean

919
ap_tools/ap-check.c Normal file
View File

@@ -0,0 +1,919 @@
/*
* ap-check - Validate vfio-ap mediated device configuration changes
*
* This tool in intended to be driven via the callout API of the mdevctl
* utility (https://github.com/mdevctl/mdevctl/)
*
* 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 <dirent.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "lib/ap.h"
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_opt.h"
#include "lib/util_path.h"
#include "ap-check.h"
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
{MDEVCTL_ACTION_DEFINE, "define"},
{MDEVCTL_ACTION_LIST, "list"},
{MDEVCTL_ACTION_MODIFY, "modify"},
{MDEVCTL_ACTION_START, "start"},
{MDEVCTL_ACTION_STOP, "stop"},
{MDEVCTL_ACTION_TYPES, "types"},
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
};
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
{MDEVCTL_EVENT_PRE, "pre"},
{MDEVCTL_EVENT_POST, "post"},
{MDEVCTL_EVENT_GET, "get"}
};
/*
* Convert mdevctl action string to an enumerated value
*/
static enum mdevctl_action_id validate_action(char *action)
{
int i;
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++) {
if (strcmp(action, mdevctl_action_table[i].action) == 0)
return mdevctl_action_table[i].id;
}
return MDEVCTL_ACTION_UNKNOWN;
}
/*
* Convert mdevctl event string to an enumerated value
*/
static enum mdevctl_event_id validate_event(char *event)
{
int i;
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++) {
if (strcmp(event, mdevctl_event_table[i].event) == 0)
return mdevctl_event_table[i].id;
}
return MDEVCTL_EVENT_UNKNOWN;
}
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("DEVICE"),
{
.option = { "e", required_argument, NULL, 'e' },
.argument = "EVENT",
.desc = "The type of callout being issued",
},
{
.option = { "a", required_argument, NULL, 'a' },
.argument = "ACTION",
.desc = "The action being performed on the specified device",
},
{
.option = { "s", required_argument, NULL, 's' },
.argument = "STATE",
.desc = "The state of the associated mdevctl command",
},
{
.option = { "u", required_argument, NULL, 'u' },
.argument = "UUID",
.desc = "Universally Unique ID for the mediated device",
},
{
.option = { "p", required_argument, NULL, 'p' },
.argument = "PDEV",
.desc = "Parent device name, e.g. matrix",
},
{
.option = { "t", required_argument, NULL, 't' },
.argument = "TYPE",
.desc = "Mediated device type, e.g. vfio_ap-passthrough",
},
UTIL_OPT_END
};
/*
* Initialize the ap_check anchor struct.
*/
static void ap_check_init(struct ap_check_anchor *anc)
{
anc->uuid = anc->parent = anc->type = NULL;
anc->dev = vfio_ap_device_new();
anc->cleanup_lock = false;
}
/*
* Free memory of ap_check anchor struct.
*/
static void ap_check_cleanup(struct ap_check_anchor *anc)
{
if (anc->uuid)
free(anc->uuid);
if (anc->parent)
free(anc->parent);
if (anc->type)
free(anc->type);
if (anc->dev)
vfio_ap_device_free(anc->dev);
if (anc->cleanup_lock)
ap_release_lock_callout();
}
/*
* Exit ap_check
*/
static void __noreturn ap_check_exit(struct ap_check_anchor *anc, int rc)
{
ap_check_cleanup(anc);
exit(rc);
}
/*
* parses the command line
*/
static void ap_check_parse(struct ap_check_anchor *anc,
int argc, char *argv[])
{
bool action = false, event = false, state = false, bad_opts = false;
int opt;
util_opt_init(opt_vec, NULL);
while (1) {
opt = util_opt_getopt_long(argc, argv);
if (opt == -1)
break;
switch (opt) {
case 'e':
if (event) {
bad_opts = true;
} else {
anc->event = validate_event(optarg);
event = true;
}
break;
case 'a':
if (action) {
bad_opts = true;
} else {
anc->action = validate_action(optarg);
action = true;
}
break;
case 's':
if (state) {
bad_opts = true;
} else {
/* Ignore the state */
state = true;
}
break;
case 'u':
if (anc->uuid)
bad_opts = true;
else
anc->uuid = util_strdup(optarg);
break;
case 'p':
if (anc->parent)
bad_opts = true;
else
anc->parent = util_strdup(optarg);
break;
case 't':
if (anc->type)
bad_opts = true;
else
anc->type = util_strdup(optarg);
break;
default:
fprintf(stderr, "Unknown operand\n");
ap_check_exit(anc, EXIT_FAILURE);
}
}
/* Make sure we got all expected input values */
if (!(action && event && state && anc->uuid && anc->parent &&
anc->type) || bad_opts) {
fprintf(stderr, "Duplicate or missing operand\n");
ap_check_exit(anc, EXIT_FAILURE);
}
/* Check for invalid UUID */
if (!is_valid_uuid(anc->uuid)) {
fprintf(stderr, "Invalid UUID specified\n");
ap_check_exit(anc, EXIT_FAILURE);
}
anc->dev->uuid = util_strdup(anc->uuid);
/* Check for valid type */
if (strcmp(anc->type, VFIO_AP_TYPE) != 0)
ap_check_exit(anc, APC_EXIT_UNKNOWN_TYPE);
/* Check for invalid parent - currently only 'matrix' supported */
if (strcmp(anc->parent, "matrix") != 0) {
fprintf(stderr, "Invalid parent specified\n");
ap_check_exit(anc, EXIT_FAILURE);
}
}
/*
* Call a function for each entry in a directory:
* int callback(const char *abs_path, const char *rel_path, void *data)
* Continues for all entries in the directory regardless of callback return
* code. Will return 0 or, if one or more callbacks failed, the first nonzero
* rc received.
*/
static int path_for_each(const char *path,
int (*callback)(const char *, const char *, void *),
void *data)
{
struct dirent *de;
int rc = 0;
int r = 0;
DIR *dir;
char *p;
dir = opendir(path);
if (!dir)
return -1;
while ((de = readdir(dir))) {
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0)
continue;
util_asprintf(&p, "%s/%s", path, de->d_name);
r = callback(p, de->d_name, data);
/* Save first nonzero return code for caller */
if (rc == 0 && r != 0)
rc = r;
free(p);
}
closedir(dir);
return rc;
}
/*
* Report an error message when the specified configuration will conflict
* with an existing device
*/
static void conflict_error(const char *uuid, unsigned int a, unsigned int d,
bool persistent)
{
if (uuid) {
if (persistent) {
fprintf(stderr,
"APQN %u.%u is defined for autostart by %s\n",
a, d, uuid);
} else {
fprintf(stderr, "APQN %u.%u already in use by %s\n",
a, d, uuid);
}
} else {
if (persistent) {
fprintf(stderr, "AQPN %u.%u is not defined for "
"vfio_ap-passthrough use by the persistent "
"ap bus mask settings\n", a, d);
} else {
fprintf(stderr, "AQPN %u.%u is not allowed for "
"vfio_ap-passthrough use by the active ap "
"bus mask settings\n", a, d);
}
}
}
/*
* Compare the list of adapters and domains for two devices, reporting error
* messages for any conflicts that occur. A conflict occurs when both devices
* have the same adapter + domain pair.
* The function below takes advantage of the fact that the lists are known to
* be sorted in numeric order; therefore we can use this information to run
* the lists in parallel rather than always starting from the beginning.
*/
static int find_apqn_conflicts(const char *uuid,
struct util_list *adapters,
struct util_list *domains,
struct util_list *adapters2,
struct util_list *domains2,
bool persistent)
{
struct vfio_ap_node *a, *a2, *d, *d2;
int rc = 0;
/* Checks for conflicts with the device */
a = util_list_start(adapters);
a2 = util_list_start(adapters2);
while ((a != NULL) && (a2 != NULL)) {
if (a->id == a2->id) {
d = util_list_start(domains);
d2 = util_list_start(domains2);
while ((d != NULL) && (d2 != NULL)) {
if (d->id == d2->id) {
/* Report error, look for more */
conflict_error(uuid, a->id, d->id,
persistent);
rc = -1;
d = util_list_next(domains, d);
d2 = util_list_next(domains2, d2);
} else if (d->id > d2->id) {
d2 = util_list_next(domains2, d2);
} else {
d = util_list_next(domains, d);
}
}
a = util_list_next(adapters, a);
a2 = util_list_next(adapters2, a2);
} else if (a->id > a2->id) {
a2 = util_list_next(adapters2, a2);
} else {
a = util_list_next(adapters, a);
}
}
return rc;
}
/*
* If the provided path maps to a valid vfio-ap device configuration,
* determine if its current configuration will conflict with the proposed
* changes.
*/
static int check_other_mdev_cfg_cb(const char *path,
const char *filename,
void *data)
{
struct other_mdev_cb_data *cbdata = data;
struct vfio_ap_device *dev = cbdata->dev;
struct vfio_ap_device *dev2 = NULL;
int rc = 0;
/* Skip anything that isn't an mdev config */
if (!is_valid_uuid(filename))
goto out;
/* Skip if this is the input device */
if (strcasecmp(cbdata->uuid, filename) == 0)
goto out;
/* Read the device config */
dev2 = vfio_ap_device_new();
if (vfio_ap_read_device_config(path, dev2) != 0)
goto out;
/* If wrong device type, skip */
if (strcmp(dev2->type, VFIO_AP_TYPE) != 0)
goto out;
/* If not AUTO device, skip */
if (dev2->manual)
goto out;
/* Perform mdev-to-mdev apqn conflict analysis */
rc = find_apqn_conflicts(filename, dev->adapters, dev->domains,
dev2->adapters, dev2->domains, true);
out:
if (dev2 != NULL)
vfio_ap_device_free(dev2);
return rc;
}
/*
* Perform conflict analysis against all other vfio-ap persistent
* configurations.
*/
int check_other_mdevs_cfg(struct ap_check_anchor *anc)
{
struct other_mdev_cb_data cb_data;
if (!util_path_is_dir(VFIO_AP_CONFIG_PATH))
return 0;
cb_data.uuid = anc->uuid;
cb_data.dev = anc->dev;
return path_for_each(VFIO_AP_CONFIG_PATH, check_other_mdev_cfg_cb,
&cb_data);
}
/*
* If the provided path maps to a valid device, determine if its current
* configuration will conflict with the proposed changes.
*/
static int check_other_mdev_sysfs_cb(const char *path, const char *filename,
void *data)
{
struct other_mdev_cb_data *cbdata = data;
struct vfio_ap_device *dev = cbdata->dev;
struct vfio_ap_device *dev2;
char *matrix_path;
char buf[80];
int rc = 0;
FILE *f;
if (!is_valid_uuid(filename) || path == NULL ||
strcasecmp(filename, cbdata->uuid) == 0)
return 0;
dev2 = vfio_ap_device_new();
matrix_path = path_get_vfio_ap_attr(filename, "matrix");
f = fopen(matrix_path, "r");
while (fgets(buf, sizeof(buf), f))
vfio_ap_parse_matrix(dev2, buf);
vfio_ap_sort_matrix_results(dev2);
fclose(f);
free(matrix_path);
/* Look for conflicts between target device and this device */
rc = find_apqn_conflicts(filename, dev->adapters, dev->domains,
dev2->adapters, dev2->domains, false);
vfio_ap_device_free(dev2);
return rc;
}
/* Run conflict analysis against all other active vfio-ap devices */
static int check_other_mdevs_sysfs(struct ap_check_anchor *anc)
{
struct other_mdev_cb_data cb_data;
char *root;
int rc = 0;
cb_data.uuid = anc->uuid;
cb_data.dev = anc->dev;
root = path_get_vfio_ap_mdev("");
if (util_path_is_dir(root))
rc = path_for_each(root, check_other_mdev_sysfs_cb, &cb_data);
free(root);
return rc;
}
/*
* Determine if there are any conflicts between the specified device and
* the active apmask/aqmask settings. This is done by treating the masks
* as a temporary vfio_ap_device with all of the associated APQNs owned by
* the system.
*/
static int check_sysfs_mask_conflicts(struct ap_check_anchor *anc)
{
struct vfio_ap_device *sysdev = vfio_ap_device_new();
char *apmask = util_zalloc(AP_MASK_SIZE);
char *aqmask = util_zalloc(AP_MASK_SIZE);
int rc = 0;
if (ap_read_sysfs_masks(apmask, aqmask, AP_MASK_SIZE) != 0) {
fprintf(stderr, "Error reading system AP settings\n");
rc = -1;
goto out;
}
/* Convert the masks to a device with the associated APQNs */
ap_mask_to_list(apmask, sysdev->adapters);
ap_mask_to_list(aqmask, sysdev->domains);
/* Perform conflict analysis */
rc = find_apqn_conflicts(NULL, anc->dev->adapters,
anc->dev->domains, sysdev->adapters,
sysdev->domains, false);
out:
free(apmask);
free(aqmask);
vfio_ap_device_free(sysdev);
return rc;
}
/*
* Determine if there are any conflicts between the specified device and
* the apmask/aqmask settings stored in udev. This is done by treating
* the masks as a temporary vfio_ap_device with all of the associated
* AQPNs owned by the system.
*/
static int check_cfg_mask_conflicts(struct ap_check_anchor *anc)
{
struct vfio_ap_device *sysdev = vfio_ap_device_new();
char *apmask = util_zalloc(AP_MASK_SIZE);
char *aqmask = util_zalloc(AP_MASK_SIZE);
bool read_ap = false, read_aq = false;
char *path;
int rc = 0;
path = path_get_ap_udev();
if (!ap_read_udev_masks(path, apmask, aqmask, &read_ap, &read_aq)) {
fprintf(stderr, "Error reading system AP settings\n");
rc = -1;
goto out;
}
/* Convert the masks to a device with the associated APQNs */
ap_mask_to_list(apmask, sysdev->adapters);
ap_mask_to_list(aqmask, sysdev->domains);
/* Perform conflict analysis */
rc = find_apqn_conflicts(NULL, anc->dev->adapters,
anc->dev->domains, sysdev->adapters,
sysdev->domains, true);
out:
free(apmask);
free(aqmask);
free(path);
vfio_ap_device_free(sysdev);
return rc;
}
/* Subroutine to handle checking shared between DEFINE and MODIFY actions. */
static int ap_check_changes(struct ap_check_anchor *anc)
{
int rc = 0, rc2;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
rc = -1;
goto out;
}
anc->cleanup_lock = true;
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
fprintf(stderr, "Failed to read device config\n");
rc = -1;
goto out;
}
if (strcmp(anc->dev->type, anc->type) != 0) {
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
rc = -1;
goto out;
}
if (!anc->dev->manual) {
/* Check against all other AUTO config files */
rc = check_other_mdevs_cfg(anc);
/* Check against the system UDEV rule for apmask/aqmask */
rc2 = check_cfg_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
}
/* If successful, lock must remain held until post callout */
if (rc == 0)
anc->cleanup_lock = false;
out:
return rc;
}
/*
* Determine if defining the specified device is a valid operation.
* mdevctl can reach us for a DEFINE under the following circumstances:
* 1) the device does not exist
* 2) the device is active but does not have a config file, so this action
* would be to generate a config file based upon the active device.
* DEFINE has no effect on an active device (if one exists) it only creates
* the configuration file. The config file might be empty or may have various
* attributes if being fed by --jsonfile or an active device.
*/
static int ap_check_handle_define(struct ap_check_anchor *anc)
{
char *path = path_get_vfio_ap_mdev_config(anc->uuid);
if (util_path_is_readable(path)) {
fprintf(stderr, "Config already exists\n");
free(path);
return -1;
}
free(path);
return ap_check_changes(anc);
}
/*
* Determine if modifying the specified device is a valid operation.
* mdevctl can reach us for a MODIFY under the following circumstances:
* 1) Modifying a MANUAL device
* 2) Modifying an AUTO device
* In the case of MANUAL, we don't take any action because changes made via
* MODIFY don't take affect on the active mdev until a STOP/START cycle.
* In the case of AUTO, we must compare the contents of the proposed device
* with the contents of stashed AUTO mdev configurations + the system.
*/
static int ap_check_handle_modify(struct ap_check_anchor *anc)
{
char *path = path_get_vfio_ap_mdev_config(anc->uuid);
FILE *fd = fopen(path, "r");
/* Determine if a base config file already exists for UUID */
free(path);
if (fd == NULL) {
fprintf(stderr, "Config doesn't exist\n");
return -1;
}
fclose(fd);
return ap_check_changes(anc);
}
/*
* Determine if starting the specified device is a valid operation.
* mdevctl can reach us for a START under the following circumstances:
* 1) STARTing a MANUAL device
* 1a) Where the MANUAL device is defined (has a config file)
* 1b) Where the MANUAL device is NOT defined (no config file).
* For vfio-ap this case provides an mdev with no adapters/domains.
* 1c) Where the MANUAL device is NOT defined but a full configuration is
* provided via --jsonfile
* 2) STARTing an AUTO device
* 2a) Where the AUTO device is defined (has a config file)
* 2b) Where the AUTO device is NOT defined but a full configuration is
* provided via --jsonfile
* In each case, we must compare the proposed device with the contents of
* active mdevs + the system.
*/
static int ap_check_handle_start(struct ap_check_anchor *anc)
{
int rc = 0, rc2;
/* Can only start a device if vfio_ap is built-in or loaded */
if (!util_path_is_dir(VFIO_AP_PATH)) {
fprintf(stderr, "vfio_ap module is not loaded\n");
ap_check_exit(anc, EXIT_FAILURE);
}
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
rc = -1;
goto out;
}
anc->cleanup_lock = true;
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
fprintf(stderr, "Failed to read device config\n");
rc = -1;
goto out;
}
if (strcmp(anc->dev->type, anc->type) != 0) {
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
rc = -1;
goto out;
}
/* Ensure device with control domains also has usage domains */
if (util_list_is_empty(anc->dev->domains) &&
!util_list_is_empty(anc->dev->controls)) {
fprintf(stderr, "At least one usage domain must be specified\n");
rc = -1;
goto out;
}
/* Check against all other active vfio-ap devices */
rc = check_other_mdevs_sysfs(anc);
/* Check against the system sysfs values for apmask/aqmask */
rc2 = check_sysfs_mask_conflicts(anc);
/* If either hit an error, reflect this */
rc = rc != 0 ? rc : rc2;
/* If successful, lock must remain held until post callout */
if (rc == 0)
anc->cleanup_lock = false;
out:
return rc;
}
/*
* Acquire the appropriate serialization so that the specified device can be
* STOPped.
*/
static int ap_check_handle_stop(void)
{
int rc;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
return -1;
}
/* The lock must remain held until post callout */
return 0;
}
/*
* Determine if UNDEFINEing the specified device is a valid operation.
* mdevctl can reach us for an UNDEFINE under the following circumstances:
* 1) UNDEFINEing an active device
* 2) UNDEFINEing an inactive device
* UNDEFINE has no effect on the active device, it only removes the config
* file.
*/
static int ap_check_handle_undefine(struct ap_check_anchor *anc)
{
char *path = path_get_vfio_ap_mdev_config(anc->uuid);
int rc = 0;
rc = ap_get_lock_callout();
if (rc) {
fprintf(stderr, "Failed to acquire configuration lock %d\n",
rc);
rc = -1;
goto out;
}
anc->cleanup_lock = true;
if (vfio_ap_read_device_config(path, anc->dev) != 0) {
fprintf(stderr, "Failed to read device config\n");
rc = -1;
goto out;
}
if (strcmp(anc->dev->type, anc->type) != 0) {
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
rc = -1;
goto out;
}
/* Success: lock must remain held until post callout */
anc->cleanup_lock = false;
out:
free(path);
return rc;
}
/*
* For callouts where the "pre" callout would have acquired the lock, it is
* now safe to remove the lock as all changes have been committed.
*/
static int ap_check_handle_post(void)
{
return ap_release_lock_callout();
}
/* For the specified device, print the attributes to stdout in JSON format */
static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
{
struct vfio_ap_device *dev = anc->dev;
struct vfio_ap_node *node;
bool has_attr = false;
char buf[80];
char *path;
FILE *f;
path = path_get_vfio_ap_attr(anc->uuid, "matrix");
f = fopen(path, "r");
while (fgets(buf, sizeof(buf), f))
vfio_ap_parse_matrix(dev, buf);
vfio_ap_sort_matrix_results(dev);
fclose(f);
free(path);
path = path_get_vfio_ap_attr(anc->uuid, "control_domains");
f = fopen(path, "r");
while (fgets(buf, sizeof(buf), f))
vfio_ap_parse_control(dev, buf);
fclose(f);
free(path);
printf("[{");
if (!util_list_is_empty(dev->adapters)) {
util_list_iterate(dev->adapters, node) {
if (has_attr)
printf("},{");
printf("\"assign_adapter\": \"%u\"", node->id);
has_attr = true;
}
}
if (!util_list_is_empty(dev->domains)) {
util_list_iterate(dev->domains, node) {
if (has_attr)
printf("},{");
printf("\"assign_domain\": \"%u\"", node->id);
has_attr = true;
}
}
if (!util_list_is_empty(dev->controls)) {
util_list_iterate(dev->controls, node) {
if (has_attr)
printf("},{");
printf("\"assign_control_domain\": \"%u\"", node->id);
has_attr = true;
}
}
printf("}]\n");
return 0;
}
/*
* Determine which mdevctl action is being checked and handle accordingly.
*/
static int ap_check_handle_action(struct ap_check_anchor *anc)
{
int rc = 0;
switch (anc->event) {
case MDEVCTL_EVENT_PRE:
switch (anc->action) {
case MDEVCTL_ACTION_DEFINE:
rc = ap_check_handle_define(anc);
break;
case MDEVCTL_ACTION_MODIFY:
rc = ap_check_handle_modify(anc);
break;
case MDEVCTL_ACTION_START:
rc = ap_check_handle_start(anc);
break;
case MDEVCTL_ACTION_STOP:
rc = ap_check_handle_stop();
break;
case MDEVCTL_ACTION_UNDEFINE:
rc = ap_check_handle_undefine(anc);
break;
case MDEVCTL_ACTION_LIST:
case MDEVCTL_ACTION_TYPES:
default:
/* Ignore some actions including unknown ones */
break;
}
break;
case MDEVCTL_EVENT_POST:
switch (anc->action) {
case MDEVCTL_ACTION_DEFINE:
case MDEVCTL_ACTION_MODIFY:
case MDEVCTL_ACTION_START:
case MDEVCTL_ACTION_STOP:
case MDEVCTL_ACTION_UNDEFINE:
ap_check_handle_post();
break;
default:
/* Ignore other post events */
break;
}
break;
case MDEVCTL_EVENT_GET:
switch (anc->action) {
case MDEVCTL_ACTION_ATTRIBUTES:
rc = ap_check_handle_get_attributes(anc);
break;
default:
/* Ignore some actions including unknown ones */
break;
}
break;
default:
/* Ignore any unknown events */
break;
}
return rc;
}
/*
*
*/
int main(int argc, char *argv[])
{
struct ap_check_anchor anchor;
int rc;
ap_check_init(&anchor);
ap_check_parse(&anchor, argc, argv);
rc = ap_check_handle_action(&anchor);
ap_check_exit(&anchor, rc);
}

74
ap_tools/ap-check.h Normal file
View File

@@ -0,0 +1,74 @@
/*
* ap-check - Validate vfio-ap mediated device configuration changes
*
* 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 AP_CHECK_H
#define AP_CHECK_H
#include <stdbool.h>
/*
* List of all of the supported mdevctl actions
*/
enum mdevctl_action_id {
MDEVCTL_ACTION_DEFINE = 0,
MDEVCTL_ACTION_LIST,
MDEVCTL_ACTION_MODIFY,
MDEVCTL_ACTION_START,
MDEVCTL_ACTION_STOP,
MDEVCTL_ACTION_TYPES,
MDEVCTL_ACTION_UNDEFINE,
MDEVCTL_ACTION_ATTRIBUTES,
/* UNKNOWN must always be the last in the list */
MDEVCTL_ACTION_UNKNOWN,
};
#define NUM_MDEVCTL_ACTIONS MDEVCTL_ACTION_UNKNOWN
struct mdevctl_action {
enum mdevctl_action_id id;
const char action[32];
};
enum mdevctl_event_id {
MDEVCTL_EVENT_PRE = 0,
MDEVCTL_EVENT_POST,
MDEVCTL_EVENT_GET,
MDEVCTL_EVENT_UNKNOWN,
};
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN
struct mdevctl_event {
enum mdevctl_event_id id;
const char event[32];
};
/* ap-check special exit codes */
#define APC_EXIT_UNKNOWN_TYPE 2
struct ap_check_anchor {
enum mdevctl_event_id event;
enum mdevctl_action_id action;
char *uuid;
char *parent;
char *type;
struct vfio_ap_device *dev;
/* Active Masks */
char apmask[80];
char aqmask[80];
/* Persistent Masks */
char p_apmask[80];
char p_aqmask[80];
bool cleanup_lock;
};
struct other_mdev_cb_data {
const char *uuid;
struct vfio_ap_device *dev;
};
#endif /* AP_CHECK_H */

View File

@@ -27,11 +27,7 @@ ENABLE_DOC = 0
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
UDEVDIR = $(USRLIBDIR)/udev
UDEVRULESDIR = $(UDEVDIR)/rules.d
UDEVRUNDIR = /run/udev
DRACUTDIR = $(USRLIBDIR)/dracut
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
DEBUGOUTDIR = $(UDEVRUNDIR)
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps

View File

@@ -4492,6 +4492,15 @@ static void destroy_file_object(struct file *f)
free(f);
}
static void *cmsfs_oper_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
{
(void)conn;
/* force immediate file removal */
cfg->hard_remove = 1;
return NULL;
}
static struct file_operations fops_fixed = {
.cache_data = cache_file_fixed,
.write_data = extend_block_fixed,
@@ -4507,6 +4516,7 @@ static struct file_operations fops_variable = {
};
static struct fuse_operations cmsfs_oper = {
.init = cmsfs_oper_init,
.getattr = cmsfs_getattr,
.statfs = cmsfs_statfs,
.readdir = cmsfs_readdir,
@@ -4683,8 +4693,6 @@ int main(int argc, char *argv[])
fuse_opt_add_arg(&args, "-oro");
/* force single threaded mode which requires no locking */
fuse_opt_add_arg(&args, "-s");
/* force immediate file removal */
fuse_opt_add_arg(&args, "-ohard_remove");
if (cmsfs.mode == BINARY_MODE &&
(cmsfs.codepage_from != NULL || cmsfs.codepage_to != NULL))

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 = 21
RELEASE = 24
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -91,7 +91,7 @@ ifneq ("${V}","1")
else
echocmd=
endif
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
DEFAULT_CFLAGS = -g -fstack-protector-all -W -Wall -Wformat-security
ifeq ("${W}","1")
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
endif
@@ -118,9 +118,9 @@ endif
# Returns "yes" on success and nothing otherwise
#
define check_header_prereq
$(shell printf "#include <%s>\n int main(void) {return 0;}" $1 | \
$(shell printf "#include <%s>\n int main(void) {return 0;}\n" $1 | \
( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) \
$2 -o /dev/null -xc - ) >/dev/null 2>&1 && echo -n yes)
$2 -o /dev/null -x c - ) >/dev/null 2>&1 && echo -n yes)
endef
#
@@ -133,7 +133,7 @@ endef
# $5: Additional compiler & linker options (optional)
#
check_dep=\
printf "\#include <%s>\n int main(void) {return 0;}" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -xc - ) > /dev/null 2>&1; \
printf "\#include <%s>\n int main(void) {return 0;}\n" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -x c - ) > /dev/null 2>&1; \
if [ $$? != 0 ]; \
then \
printf " REQCHK %s (%s)\n" $1 $2; \
@@ -193,6 +193,11 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
SYSTEMDSYSTEMUNITDIR =
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
UDEVDIR = $(USRLIBDIR)/udev
UDEVRULESDIR = $(UDEVDIR)/rules.d
DRACUTDIR = $(USRLIBDIR)/dracut
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
DRACUTMODDIR = $(DRACUTDIR)/modules.d
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
SOINSTALLDIR = $(USRLIB64DIR)
@@ -383,6 +388,14 @@ $(rootdir)/libkmipclient/libkmipclient.so: $(rootdir)/libkmipclient
$(MAKE) -C $(rootdir)/libkmipclient/ libkmipclient.so
.PHONY: $(rootdir)/libkmipclient
$(rootdir)/libap/libap.a: $(rootdir)/libap
$(MAKE) -C $(rootdir)/libap/ libap.a
.PHONY: $(rootdir)/libap
$(rootdir)/libpv/libpv.a: $(rootdir)/libpv
$(MAKE) -C $(rootdir)/libpv libpv.a
.PHONY: $(rootdir)/libpv
$(rootdir)/zipl/boot/data.o:
$(MAKE) -C $(rootdir)/zipl/boot/ data.o

View File

@@ -1,11 +1,28 @@
include ../common.mak
ifeq (${HAVE_LIBUDEV},0)
all:
$(SKIP) HAVE_LIBUDEV=0
install:
$(SKIP) HAVE_LIBUDEV=0
else
check_dep:
$(call check_dep, \
"cpacfstatsd", \
"libudev.h", \
"systemd-devel", \
"HAVE_LIBUDEV=0")
ALL_CPPFLAGS += -DVERSION=$(VERSION)
all: cpacfstats cpacfstatsd
all: check_dep cpacfstats cpacfstatsd
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -ludev -lpthread -o $@
cpacfstats: cpacfstats.o stats_sock.o
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
@@ -16,6 +33,8 @@ install: all
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
endif
clean:
rm -f *.o *~ cpacfstatsd cpacfstats

View File

@@ -1,6 +1,6 @@
.\" cpacfstats.1
.\"
.\" Copyright IBM Corp. 2015, 2020
.\" Copyright IBM Corp. 2015, 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.
.\"
@@ -32,7 +32,9 @@ cpacfstats \- enable, disable and display CPACF statistical data
.RB ]
.RB [ \-p | \-\-print
.I counter
.RB [ \-n | \-\-nonzero]
.RB ]
.RB [ \-j | \-\-json ]
.
.SH DESCRIPTION
The cpacfstats client application interacts with the cpacfstatsd daemon and
@@ -44,12 +46,347 @@ All counters are initially disabled and must be switched on to measure
CPACF activities of the system. There is a slight performance penalty with
CPACF counters enabled.
Note: All cryptographic counters are bound to physical CPUs. If you use
dedicated CPUs for your LPAR, you obtain only your CPACF activities. If
your CPUs are shared with other LPARs, their cryptographic activities might
distort the results. CPACF performance counters are available on LPARs
only. For security reasons only members of the group \fIcpacfstats\fR are
allowed to run the cpacfstats client application.
CPACF activity counters come in two flavors: CPU-MF and PAI. CPU-MF
counters are only available on LPARs and have to be authorized. If
they are available, the counters
.B des,
.B aes,
.B sha,
.B rng,
and
.B ecc
are made available. These counters can individually be activated,
reset, printed, or deactivated. PAI counters are a lot more detailed.
The user interface only offers the counters
.B pai_user
and
.B pai_kernel
to count CPACF usage in user-space or kernel-space. When printing
these counters, detailed counters are shown. The detailed names are:
.RS
.IP \(bu
KM DES,
.IP \(bu
KM 2key TDES,
.IP \(bu
KM TDES,
.IP \(bu
KM DES protected key,
.IP \(bu
KM 2key TDES protected key,
.IP \(bu
KM TDES protected key,
.IP \(bu
KM AES 128bit,
.IP \(bu
KM AES 192bit,
.IP \(bu
KM AES 256bit,
.IP \(bu
KM AES 128bit protected key,
.IP \(bu
KM AES 192bit protected key,
.IP \(bu
KM AES 256bit protected key,
.IP \(bu
KM AES-XTS 128bit,
.IP \(bu
KM AES-XTS 256bit,
.IP \(bu
KM AES-XTS 128bit protected key,
.IP \(bu
KM AES-XTS 256bit protected key,
.IP \(bu
KMC DES,
.IP \(bu
KMC 2key TDES,
.IP \(bu
KMC TDES,
.IP \(bu
KMC DES protected key,
.IP \(bu
KMC 2key TDES protected key,
.IP \(bu
KMC TDES protected key,
.IP \(bu
KMC AES 128bit,
.IP \(bu
KMC AES 192bit,
.IP \(bu
KMC AES 256bit,
.IP \(bu
KMC AES 128bit protected key,
.IP \(bu
KMC AES 192bit protected key,
.IP \(bu
KMC AES 256bit protected key,
.IP \(bu
KMC PRNG,
.IP \(bu
KMA AES 128bit,
.IP \(bu
KMA AES 192bit,
.IP \(bu
KMA AES 256bit,
.IP \(bu
KMA AES 128bit protected key,
.IP \(bu
KMA AES 192bit protected key,
.IP \(bu
KMA AES 256bit protected key,
.IP \(bu
KMF DES,
.IP \(bu
KMF 2key TDES,
.IP \(bu
KMF TDES,
.IP \(bu
KMF DES protected key,
.IP \(bu
KMF 2key TDES protected key,
.IP \(bu
KMF TDES protected key,
.IP \(bu
KMF AES 128bit,
.IP \(bu
KMF AES 192bit,
.IP \(bu
KMF AES 256bit,
.IP \(bu
KMF AES 128bit protected key,
.IP \(bu
KMF AES 192bit protected key,
.IP \(bu
KMF AES 256bit protected key,
.IP \(bu
KMCTR DES,
.IP \(bu
KMCTR 2key TDES,
.IP \(bu
KMCTR TDES,
.IP \(bu
KMCTR DES protected key,
.IP \(bu
KMCTR 2key TDES protected key,
.IP \(bu
KMCTR TDES protected key,
.IP \(bu
KMCTR AES 128bit,
.IP \(bu
KMCTR AES 192bit,
.IP \(bu
KMCTR AES 256bit,
.IP \(bu
KMCTR AES 128bit protected key,
.IP \(bu
KMCTR AES 192bit protected key,
.IP \(bu
KMCTR AES 256bit protected key,
.IP \(bu
KMO DES,
.IP \(bu
KMO 2key TDES,
.IP \(bu
KMO TDES,
.IP \(bu
KMO DES protected key,
.IP \(bu
KMO 2key TDES protected key,
.IP \(bu
KMO TDES protected key,
.IP \(bu
KMO AES 128bit,
.IP \(bu
KMO AES 192bit,
.IP \(bu
KMO AES 256bit,
.IP \(bu
KMO AES 128bit protected key,
.IP \(bu
KMO AES 192bit protected key,
.IP \(bu
KMO AES 256bit protected key,
.IP \(bu
KIMD SHA1,
.IP \(bu
KIMD SHA256,
.IP \(bu
KIMD SHA512,
.IP \(bu
KIMD SHA3-224,
.IP \(bu
KIMD SHA3-256,
.IP \(bu
KIMD SHA3-384,
.IP \(bu
KIMD SHA3-512,
.IP \(bu
KIMD SHAKE 128,
.IP \(bu
KIMD SHAKE 256,
.IP \(bu
KIMD GHASH,
.IP \(bu
KLMD SHA1,
.IP \(bu
KLMD SHA256,
.IP \(bu
KLMD SHA512,
.IP \(bu
KLMD SHA3-224,
.IP \(bu
KLMD SHA3-256,
.IP \(bu
KLMD SHA3-384,
.IP \(bu
KLMD SHA3-512,
.IP \(bu
KLMD SHAKE 128,
.IP \(bu
KLMD SHAKE 256,
.IP \(bu
KMAC DES,
.IP \(bu
KMAC 2key TDES,
.IP \(bu
KMAC TDES,
.IP \(bu
KMAC DES protected key,
.IP \(bu
KMAC 2key TDES protected key,
.IP \(bu
KMAC TDES protected key,
.IP \(bu
KMAC AES 128bit,
.IP \(bu
KMAC AES 192bit,
.IP \(bu
KMAC AES 256bit,
.IP \(bu
KMAC AES 128bit protected key,
.IP \(bu
KMAC AES 192bit protected key,
.IP \(bu
KMAC AES 256bit protected key,
.IP \(bu
PCC Last Block CMAC DES,
.IP \(bu
PCC Last Block CMAC 2key TDES,
.IP \(bu
PCC Last Block CMAC TDES,
.IP \(bu
PCC Last Block CMAC DES protected key,
.IP \(bu
PCC Last Block CMAC 2key TDES protected key,
.IP \(bu
PCC Last Block CMAC TDES protected key,
.IP \(bu
PCC Last Block CMAC AES 128bit,
.IP \(bu
PCC Last Block CMAC AES 192bit,
.IP \(bu
PCC Last Block CMAC AES 256bit,
.IP \(bu
PCC Last Block CMAC AES 128bit protected key,
.IP \(bu
PCC Last Block CMAC AES 192bit protected key,
.IP \(bu
PCC Last Block CMAC AES 256bit protected key,
.IP \(bu
PCC XTS Parameter AES 128bit,
.IP \(bu
PCC XTS Parameter AES 256bit,
.IP \(bu
PCC XTS Parameter AES 128bit protected key,
.IP \(bu
PCC XTS Parameter AES 256bit protected key,
.IP \(bu
PCC Scalar Mult P256,
.IP \(bu
PCC Scalar Mult P384,
.IP \(bu
PCC Scalar Mult P521,
.IP \(bu
PCC Scalar Mult Ed25519,
.IP \(bu
PCC Scalar Mult Ed448,
.IP \(bu
PCC Scalar Mult X25519,
.IP \(bu
PCC Scalar Mult X448,
.IP \(bu
PRNO SHA512 DRNG,
.IP \(bu
PRNO TRNG Query Ratio,
.IP \(bu
PRNO TRNG,
.IP \(bu
KDSA ECDSA Verify P256,
.IP \(bu
KDSA ECDSA Verify P384,
.IP \(bu
KDSA ECDSA Verify P521,
.IP \(bu
KDSA ECDSA Sign P256,
.IP \(bu
KDSA ECDSA Sign P384,
.IP \(bu
KDSA ECDSA Sign P521,
.IP \(bu
KDSA ECDSA Sign P256 protected key,
.IP \(bu
KDSA ECDSA Sign P384 protected key,
.IP \(bu
KDSA ECDSA Sign P521 protected key,
.IP \(bu
KDSA EdDSA Verify Ed25519,
.IP \(bu
KDSA EdDSA Verify Ed448,
.IP \(bu
KDSA EdDSA Sign Ed25519,
.IP \(bu
KDSA EdDSA Sign Ed448,
.IP \(bu
KDSA EdDSA Sign Ed25519 protected key,
.IP \(bu
KDSA EdDSA Sign Ed448 protected key,
.IP \(bu
PCKMO DES,
.IP \(bu
PCKMO 2key TDES,
.IP \(bu
PCMKO TDES,
.IP \(bu
PCKMO AES 128bit,
.IP \(bu
PCKMO AES 192bit,
.IP \(bu
PCMKO AES 256bit,
.IP \(bu
PCKMO ECC P256,
.IP \(bu
PCKMO ECC P384,
.IP \(bu
PCKMO ECC P521,
.IP \(bu
PCKMO ECC Ed25519,
.IP \(bu
PCKMO ECC Ed448,
.IP \(bu
Reserved 1, and
.IP \(bu
Reserved 2.
.RE
Note that the counters starting with PCKMO and Reserved are only
available in the pai_kernel set. Also note that the counters are
designed to count successful operations. In the case of KMA this
means only complete GCM operations including final hashing are
counted.
Note: CPU-MF based CPACF performance counters are available on LPARs
only. PAI counters are available on all hypervisors. For security
reasons only members of the group \fIcpacfstats\fR are allowed to run
the cpacfstats client application.
Example usage scenario:
.P
@@ -101,12 +438,34 @@ argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
performance counters are reset to 0.
.TP
\fB\-p\fR or \fB\-\-print\fR [counter]
\fB\-p\fR or \fB\-\-print\fR [\fB\-n\fR or \fB\-\-nonzero\fR] [counter]
Display the value of one or all CPACF performance counters. The
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
\fBsha\fR, \fBprng\fR, \fBecc\fR, or \fBall\fR. If the counter
argument is omitted or if there is no argument, all performance
counters are displayed.
\fBsha\fR, \fBprng\fR, \fBecc\fR, \fBpai_user\fR, \fBpai_kernel\fR, or
\fBall\fR. If the counter argument is omitted or if there is no
argument, all performance counters are displayed. If the optional
\fB\-n\fR or \fB\-\-nonzero\fR argument is given, then only PAI
counters that have a non-zero value are printed.
.TP
\fB\-j\fR or \fB\-\-json\fR
Display all activated counters in JSON format. The JSON contains an
array of counter objects. Each object contains the property
.B counter
specifying either a CPU-MF counter of one of the detailed PAI counter.
Additional properties include
.B error
an error number if the counter could not be read,
.B value
the counter value if the counter could be read,
.B space
for PAI counters to specify
.B user
or
.B kernel
space counter set, and
.B counterid
for PAI counters to specify the PAI counter number as specified in the
Principles of Operation.
.TP
The default command is --print all.
.

View File

@@ -3,7 +3,7 @@
*
* cpacfstats client implementation
*
* Copyright IBM Corp. 2015, 2020
* Copyright IBM Corp. 2015, 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.
@@ -39,17 +39,187 @@ static const char *const usage =
"\t-d, --disable [counter] Disable one or all counters\n"
"\t-r, --reset [counter] Reset one or all counter values\n"
"\t-p, --print [counter] Print one or all counter values\n"
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc' or 'all'\n";
"\t-n, --nonzero Print all PAI counters\n"
"\t-j, --json Print all counter values in JSON format\n"
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc'\n"
"\t 'pai_user' 'pai_kernel' or 'all'\n";
static const char *const counter_str[] = {
[DES_FUNCTIONS] = "des",
[AES_FUNCTIONS] = "aes",
[SHA_FUNCTIONS] = "sha",
[PRNG_FUNCTIONS] = "rng",
[ECC_FUNCTIONS] = "ecc",
[ALL_COUNTER] = "all"
[ECC_FUNCTIONS] = "ecc",
[ALL_COUNTER] = "all",
[PAI_USER] = "pai_user",
[PAI_KERNEL] = "pai_kernel"
};
/* Strings for the pai counter details. Note that this is 0-based
* while PoP is 1-based.
*/
static const char *const pai_str[] = {
[ 0] = "KM DES",
[ 1] = "KM 2key TDES",
[ 2] = "KM TDES",
[ 3] = "KM DES protected key",
[ 4] = "KM 2key TDES protected key",
[ 5] = "KM TDES protected key",
[ 6] = "KM AES 128bit",
[ 7] = "KM AES 192bit",
[ 8] = "KM AES 256bit",
[ 9] = "KM AES 128bit protected key",
[ 10] = "KM AES 192bit protected key",
[ 11] = "KM AES 256bit protected key",
[ 12] = "KM AES-XTS 128bit",
[ 13] = "KM AES-XTS 256bit",
[ 14] = "KM AES-XTS 128bit protected key",
[ 15] = "KM AES-XTS 256bit protected key",
[ 16] = "KMC DES",
[ 17] = "KMC 2key TDES",
[ 18] = "KMC TDES",
[ 19] = "KMC DES protected key",
[ 20] = "KMC 2key TDES protected key",
[ 21] = "KMC TDES protected key",
[ 22] = "KMC AES 128bit",
[ 23] = "KMC AES 192bit",
[ 24] = "KMC AES 256bit",
[ 25] = "KMC AES 128bit protected key",
[ 26] = "KMC AES 192bit protected key",
[ 27] = "KMC AES 256bit protected key",
[ 28] = "KMC PRNG",
[ 29] = "KMA AES 128bit",
[ 30] = "KMA AES 192bit",
[ 31] = "KMA AES 256bit",
[ 32] = "KMA AES 128bit protected key",
[ 33] = "KMA AES 192bit protected key",
[ 34] = "KMA AES 256bit protected key",
[ 35] = "KMF DES",
[ 36] = "KMF 2key TDES",
[ 37] = "KMF TDES",
[ 38] = "KMF DES protected key",
[ 39] = "KMF 2key TDES protected key",
[ 40] = "KMF TDES protected key",
[ 41] = "KMF AES 128bit",
[ 42] = "KMF AES 192bit",
[ 43] = "KMF AES 256bit",
[ 44] = "KMF AES 128bit protected key",
[ 45] = "KMF AES 192bit protected key",
[ 46] = "KMF AES 256bit protected key",
[ 47] = "KMCTR DES",
[ 48] = "KMCTR 2key TDES",
[ 49] = "KMCTR TDES",
[ 50] = "KMCTR DES protected key",
[ 51] = "KMCTR 2key TDES protected key",
[ 52] = "KMCTR TDES protected key",
[ 53] = "KMCTR AES 128bit",
[ 54] = "KMCTR AES 192bit",
[ 55] = "KMCTR AES 256bit",
[ 56] = "KMCTR AES 128bit protected key",
[ 57] = "KMCTR AES 192bit protected key",
[ 58] = "KMCTR AES 256bit protected key",
[ 59] = "KMO DES",
[ 60] = "KMO 2key TDES",
[ 61] = "KMO TDES",
[ 62] = "KMO DES protected key",
[ 63] = "KMO 2key TDES protected key",
[ 64] = "KMO TDES protected key",
[ 65] = "KMO AES 128bit",
[ 66] = "KMO AES 192bit",
[ 67] = "KMO AES 256bit",
[ 68] = "KMO AES 128bit protected key",
[ 69] = "KMO AES 192bit protected key",
[ 70] = "KMO AES 256bit protected key",
[ 71] = "KIMD SHA1",
[ 72] = "KIMD SHA256",
[ 73] = "KIMD SHA512",
[ 74] = "KIMD SHA3-224",
[ 75] = "KIMD SHA3-256",
[ 76] = "KIMD SHA3-384",
[ 77] = "KIMD SHA3-512",
[ 78] = "KIMD SHAKE 128",
[ 79] = "KIMD SHAKE 256",
[ 80] = "KIMD GHASH",
[ 81] = "KLMD SHA1",
[ 82] = "KLMD SHA256",
[ 83] = "KLMD SHA512",
[ 84] = "KLMD SHA3-224",
[ 85] = "KLMD SHA3-256",
[ 86] = "KLMD SHA3-384",
[ 87] = "KLMD SHA3-512",
[ 88] = "KLMD SHAKE 128",
[ 89] = "KLMD SHAKE 256",
[ 90] = "KMAC DES",
[ 91] = "KMAC 2key TDES",
[ 92] = "KMAC TDES",
[ 93] = "KMAC DES protected key",
[ 94] = "KMAC 2key TDES protected key",
[ 95] = "KMAC TDES protected key",
[ 96] = "KMAC AES 128bit",
[ 97] = "KMAC AES 192bit",
[ 98] = "KMAC AES 256bit",
[ 99] = "KMAC AES 128bit protected key",
[100] = "KMAC AES 192bit protected key",
[101] = "KMAC AES 256bit protected key",
[102] = "PCC Last Block CMAC DES",
[103] = "PCC Last Block CMAC 2key TDES",
[104] = "PCC Last Block CMAC TDES",
[105] = "PCC Last Block CMAC DES protected key",
[106] = "PCC Last Block CMAC 2key TDES protected key",
[107] = "PCC Last Block CMAC TDES protected key",
[108] = "PCC Last Block CMAC AES 128bit",
[109] = "PCC Last Block CMAC AES 192bit",
[110] = "PCC Last Block CMAC AES 256bit",
[111] = "PCC Last Block CMAC AES 128bit protected key",
[112] = "PCC Last Block CMAC AES 192bit protected key",
[113] = "PCC Last Block CMAC AES 256bit protected key",
[114] = "PCC XTS Parameter AES 128bit",
[115] = "PCC XTS Parameter AES 256bit",
[116] = "PCC XTS Parameter AES 128bit protected key",
[117] = "PCC XTS Parameter AES 256bit protected key",
[118] = "PCC Scalar Mult P256",
[119] = "PCC Scalar Mult P384",
[120] = "PCC Scalar Mult P521",
[121] = "PCC Scalar Mult Ed25519",
[122] = "PCC Scalar Mult Ed448",
[123] = "PCC Scalar Mult X25519",
[124] = "PCC Scalar Mult X448",
[125] = "PRNO SHA512 DRNG",
[126] = "PRNO TRNG Query Ratio",
[127] = "PRNO TRNG",
[128] = "KDSA ECDSA Verify P256",
[129] = "KDSA ECDSA Verify P384",
[130] = "KDSA ECDSA Verify P521",
[131] = "KDSA ECDSA Sign P256",
[132] = "KDSA ECDSA Sign P384",
[133] = "KDSA ECDSA Sign P521",
[134] = "KDSA ECDSA Sign P256 protected key",
[135] = "KDSA ECDSA Sign P384 protected key",
[136] = "KDSA ECDSA Sign P521 protected key",
[137] = "KDSA EdDSA Verify Ed25519",
[138] = "KDSA EdDSA Verify Ed448",
[139] = "KDSA EdDSA Sign Ed25519",
[140] = "KDSA EdDSA Sign Ed448",
[141] = "KDSA EdDSA Sign Ed25519 protected key",
[142] = "KDSA EdDSA Sign Ed448 protected key",
[143] = "PCKMO DES",
[144] = "PCKMO 2key TDES",
[145] = "PCMKO TDES",
[146] = "PCKMO AES 128bit",
[147] = "PCKMO AES 192bit",
[148] = "PCMKO AES 256bit",
[149] = "PCKMO ECC P256",
[150] = "PCKMO ECC P384",
[151] = "PCKMO ECC P521",
[152] = "PCKMO ECC Ed25519",
[153] = "PCKMO ECC Ed448",
[154] = "Reserved 1",
[155] = "Reserved 2"
};
static int paiprintnonzero;
static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
{
@@ -62,7 +232,7 @@ static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
m.query.m_ctr = ctr;
m.query.m_cmd = cmd;
return send_msg(s, &m);
return send_msg(s, &m, 0);
}
@@ -71,7 +241,7 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
struct msg m;
int rc;
rc = recv_msg(s, &m);
rc = recv_msg(s, &m, 0);
if (rc == 0) {
if (m.head.m_ver != VERSION) {
eprint("Received msg with wrong version %d != %d\n",
@@ -92,9 +262,139 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
}
static void print_answer(int ctr, int state, uint64_t value)
static void printjsonsep(void)
{
if (state < 0)
static const char *jsonsep = "";
fputs(jsonsep, stdout);
jsonsep = ",";
}
static void json_print_virtual_counter_answer(int s, int ctr,
int state, uint64_t value)
{
int paictr = 0, paistate = 0, ec;
uint64_t i, paivalue = 0, maxnum;
const char *space;
switch (ctr) {
case HOTPLUG_DETECTED:
printjsonsep();
printf("{\"counter\":\"hotplug detected\",");
if (state < 0)
printf("\"error\":%d}", state);
else
printf("\"value\":%d}", !!value);
return;
case PAI_USER:
maxnum = NUM_PAI_USER;
space = "user";
break;
case PAI_KERNEL:
maxnum = NUM_PAI_KERNEL;
space = "kernel";
break;
default:
return;
}
/* Here, we have validated the PAI counter retrieved, but not
* yet printed. */
if (state != ENABLED)
return;
if (value > maxnum) {
eprint("Incompatible versions detected!\n");
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
maxnum, space, value);
exit(EXIT_FAILURE);
}
for (i = 0; i < value; ++i) {
ec = recv_answer(s, &paictr, &paistate, &paivalue);
if (ec < 0 || paistate < 0) {
eprint("Error on receiving answer message from daemon\n");
/* No more data for this virtual event after error. */
return;
}
if (paictr > NUM_PAI_KERNEL) {
eprint("Pai counter number too big: %d\n", paictr);
} else {
printjsonsep();
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
pai_str[paictr], space, paictr + 1);
if (paistate < 0) {
printf("\"error\":%d}", paistate);
/* Protocol does not send furter counters. */
return;
}
printf("\"value\":%"PRIu64"}", paivalue);
}
}
}
static void print_virtual_counter_answer(int s,
int ctr, int state, uint64_t value)
{
static const char *const states[] = {
[DISABLED] = "disabled",
[ENABLED] = "enabled",
[UNSUPPORTED] = "unsupported"
};
int paictr = 0, paistate = 0, ec;
uint64_t i, paivalue = 0, maxnum;
const char *ctrstr;
switch (ctr) {
case HOTPLUG_DETECTED:
if (state >= 0 && value > 0)
printf(" hotplug detected\n");
return;
case PAI_USER:
maxnum = NUM_PAI_USER;
ctrstr = "pai_user";
break;
case PAI_KERNEL:
maxnum = NUM_PAI_KERNEL;
ctrstr = "pai_kernel";
break;
default:
return;
}
/* Here, we have validated the PAI counter retrieved, but not
* yet printed. */
if (state < 0 || state > UNSUPPORTED) {
printf(" %11s: error state %d\n", ctrstr, state);
/* No details follow if counter in error state. */
return;
}
printf(" %-11s: %s\n", ctrstr, states[state]);
if (state != ENABLED)
return;
if (value > maxnum) {
eprint("Incompatible versions detected!\n");
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
maxnum, ctrstr, value);
exit(EXIT_FAILURE);
}
for (i = 0; i < value; ++i) {
ec = recv_answer(s, &paictr, &paistate, &paivalue);
if (ec < 0 || paistate < 0) {
eprint("Error on receiving answer message from daemon\n");
/* No more data for this virtual event after error. */
return;
}
if (paictr > NUM_PAI_KERNEL)
eprint("Pai counter number too big: %d\n", paictr);
else if (!paiprintnonzero || paivalue > 0)
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
}
}
static void print_answer(int s, int ctr, int state, uint64_t value)
{
if (ctr > ALL_COUNTER)
print_virtual_counter_answer(s, ctr, state, value);
else if (state < 0)
printf(" %s counter: error state %d\n",
counter_str[ctr], state);
else if (state == DISABLED)
@@ -106,6 +406,22 @@ static void print_answer(int ctr, int state, uint64_t value)
}
static void json_print_answer(int s, int ctr, int state, uint64_t value)
{
if (ctr > ALL_COUNTER) {
json_print_virtual_counter_answer(s, ctr, state, value);
} else if (state < 0) {
printjsonsep();
printf("{\"counter\":\"%s\",", counter_str[ctr]);
printf("\"error\":%d}\n", state);
} else if (state == ENABLED) {
printjsonsep();
printf("{\"counter\":\"%s\",", counter_str[ctr]);
printf("\"value\":%"PRIu64"}", value);
}
}
int eprint(const char *format, ...)
{
char buf[1024];
@@ -128,7 +444,7 @@ int main(int argc, char *argv[])
{
enum ctr_e ctr = ALL_COUNTER;
enum cmd_e cmd = PRINT;
int i, j, s, state;
int i, j, s, state, num, json = 0;
uint64_t value;
if (argc > 1) {
@@ -140,98 +456,108 @@ int main(int argc, char *argv[])
{ "disable", 0, NULL, 'd' },
{ "reset", 0, NULL, 'r' },
{ "print", 0, NULL, 'p' },
{ "nonzero", 0, NULL, 'n' },
{ "json", 0, NULL, 'j' },
{ NULL, 0, NULL, 0 } };
while (1) {
opt = getopt_long(argc, argv,
"hvedrp", long_opts, &idx);
"hvedrpnj", long_opts, &idx);
if (opt == -1)
break; /* no more arguments */
switch (opt) {
case 'h':
printf(usage, name);
exit(0);
break;
return 0;
case 'v':
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
"Version %s\n%s\n",
name, RELEASE_STRING, COPYRIGHT);
exit(0);
break;
return 0;
case 'e':
cmd = ENABLE;
json = 0;
break;
case 'd':
cmd = DISABLE;
json = 0;
break;
case 'r':
cmd = RESET;
break;
case 'p':
cmd = PRINT;
json = 0;
break;
case 'n':
paiprintnonzero = 1;
break;
case 'j':
cmd = PRINT;
json = 1;
break;
default:
eprint("Invalid argument, try -h or --help for more information\n");
exit(1);
break;
return EXIT_FAILURE;
}
}
/* there may be an optional counter argument */
if (optind > 0 && optind < argc) {
for (i = 0; i <= ALL_COUNTER; i++)
for (i = 0; i < NUM_COUNTER; i++)
if (strcmp(argv[optind], counter_str[i]) == 0)
break;
if (i > ALL_COUNTER) {
if (i >= NUM_COUNTER) {
eprint("Unknown counter '%s'\n", argv[optind]);
exit(1);
return EXIT_FAILURE;
}
ctr = (enum ctr_e) i;
}
}
if (json)
ctr = ALL_COUNTER;
/* try to open and connect socket to the cpacfstatsd daemon */
s = open_socket(CLIENT);
if (s < 0) {
eprint("Can't connect to daemon\n");
exit(1);
return EXIT_FAILURE;
}
/* send query */
if (send_query(s, cmd, ctr) != 0) {
eprint("Error on sending query message to daemon\n");
close(s);
exit(1);
return EXIT_FAILURE;
}
if (ctr == ALL_COUNTER) {
for (i = 0; i < ALL_COUNTER; i++) {
/* receive answer */
if (recv_answer(s, &j, &state, &value) != 0) {
eprint("Error on receiving answer message from daemon\n");
exit(1);
}
if (state < 0) {
eprint("Received bad status code %d from daemon\n",
state);
close(s);
exit(1);
}
print_answer(j, state, value);
}
/* The -1 is for ALL_COUNTER which is not sent, +1 for
* hotplug state. */
num = NUM_COUNTER - 1 + 1;
} else {
/* +1 for hotplug state */
num = 1 + 1;
}
if (json)
putchar('[');
for (i = 0; i < num; i++) {
/* receive answer */
if (recv_answer(s, &j, &state, &value) != 0) {
eprint("Error on receiving answer message from daemon\n");
close(s);
exit(1);
return EXIT_FAILURE;
}
if (state < 0) {
eprint("Received bad status code %d from daemon\n",
state);
state);
close(s);
exit(1);
return EXIT_FAILURE;
}
print_answer(j, state, value);
if (json)
json_print_answer(s, j, state, value);
else
print_answer(s, j, state, value);
}
if (json)
putchar(']');
/* close connection */
close(s);

View File

@@ -3,7 +3,7 @@
*
* common function prototypes and definitions
*
* Copyright IBM Corp. 2015, 2020
* Copyright IBM Corp. 2015, 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.
@@ -14,13 +14,27 @@
#include "lib/zt_common.h"
#define COPYRIGHT "Copyright IBM Corp. 2015, 2020"
#define COPYRIGHT "Copyright IBM Corp. 2015, 2022"
#define DEFAULT_SEND_TIMEOUT (30 * 1000)
#define DEFAULT_RECV_TIMEOUT (30 * 1000)
/*
* Number of PAI counters for user space. This excludes PCKMO since
* this instruction is privileged.
*/
#define NUM_PAI_USER 143
/* Number of PAI counters for kernel space. Contains all counters. */
#define NUM_PAI_KERNEL 156
int eprint(const char *format, ...);
/*
* Counter names
* ALL_COUNTER must always be the last member of the enum
* ALL_COUNTER specifies the number of physical counters. Virtual
* counters might be added afterwards. NUM_COUNTER is the last
* managed counter (i.e., a counter that can be activated, reset,
* deactivated).
*/
enum ctr_e {
DES_FUNCTIONS = 0,
@@ -28,7 +42,11 @@ enum ctr_e {
SHA_FUNCTIONS,
PRNG_FUNCTIONS,
ECC_FUNCTIONS,
ALL_COUNTER
ALL_COUNTER,
PAI_USER,
PAI_KERNEL,
NUM_COUNTER,
HOTPLUG_DETECTED = 0xffff
};
enum type_e {
@@ -50,7 +68,7 @@ enum state_e {
};
/*
* query send from clent to daemon
* query send from client to daemon
* Consist of:
* enum counter
* enum command
@@ -63,7 +81,7 @@ struct msg_query {
/*
* answer send from daemon to client
* Consist of:
* enum counter
* enum counter or PAI counter number if following PAI_USER or PAI_KERNEL
* status code: < 0 error, 0 disabled, > 0 enabled
* counter value
*/
@@ -99,17 +117,20 @@ struct msg {
} __packed;
int open_socket(int mode);
int send_msg(int sfd, struct msg *m);
int recv_msg(int sfd, struct msg *m);
int send_msg(int sfd, struct msg *m, int timeout);
int recv_msg(int sfd, struct msg *m, int timeout);
/* perf_crypto.c */
int perf_init(void);
void perf_stop(void);
void perf_close(void);
int perf_enable_ctr(enum ctr_e ctr);
int perf_disable_ctr(enum ctr_e ctr);
int perf_reset_ctr(enum ctr_e ctr);
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value);
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
int perf_ecc_supported(void);
int perf_ctr_state(enum ctr_e ctr);
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value);
#endif

View File

@@ -3,7 +3,7 @@
*
* cpacfstatsd daemon implementation
*
* Copyright IBM Corp. 2015, 2017
* Copyright IBM Corp. 2015, 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,6 +28,7 @@
#include "lib/zt_common.h"
#include "cpacfstats.h"
static volatile int stopsig;
static const char *const name = "cpacfstatsd";
@@ -43,15 +44,12 @@ static const char *const usage =
static int daemonized;
static int ctr_state[ALL_COUNTER];
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
{
struct msg m;
int rc;
rc = recv_msg(s, &m);
rc = recv_msg(s, &m, DEFAULT_RECV_TIMEOUT);
if (rc == 0) {
if (m.head.m_ver != VERSION) {
eprint("Received msg with wrong version %d != %d\n",
@@ -83,38 +81,82 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
m.answer.m_state = state;
m.answer.m_value = value;
return send_msg(s, &m);
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
}
/*
* Print according to protocol for PAI:
* - first the state and the number of PAI counters that follow
* - if state is ENABLED:
* - for each PAI counter the value with state ENABLED
* Note that the PAI counters are 0-based, not 1 based as in PoP!
* Sending ends with the first error.
*/
static int do_send_pai(int s, int user)
{
int ctr, state, i, maxctr, rc = 0;
uint64_t value;
if (user) {
ctr = PAI_USER;
maxctr = NUM_PAI_USER;
} else {
ctr = PAI_KERNEL;
maxctr = NUM_PAI_KERNEL;
}
state = perf_ctr_state(ctr);
if (state != ENABLED)
return rc;
for (i = 0; i < maxctr; ++i) {
rc = perf_read_pai_ctr(i, user, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
send_answer(s, i, state, value);
}
return rc;
}
static int do_enable(int s, enum ctr_e ctr)
{
uint64_t value;
uint64_t value = 0;
int i, rc = 0;
int state;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
if (ctr_state[i] == DISABLED) {
state = perf_ctr_state(i);
if (state == DISABLED) {
rc = perf_enable_ctr(i);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
ctr_state[i] = ENABLED;
state = ENABLED;
}
if (ctr_state[i] == UNSUPPORTED) {
send_answer(s, i, UNSUPPORTED, 0);
} else {
if (state != UNSUPPORTED) {
rc = perf_read_ctr(i, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
send_answer(s, i, ENABLED, value);
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
@@ -122,67 +164,90 @@ static int do_enable(int s, enum ctr_e ctr)
static int do_disable(int s, enum ctr_e ctr)
{
int i, rc = 0;
uint64_t value;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
if (ctr_state[i] == ENABLED) {
if (perf_ctr_state(i) == ENABLED) {
rc = perf_disable_ctr(i);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
ctr_state[i] = 0;
}
send_answer(s, i, ctr_state[i], 0);
send_answer(s, i, perf_ctr_state(i), 0);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
static int do_reset(int s, enum ctr_e ctr)
{
int i, rc = 0;
int i, rc = 0, state;
uint64_t value;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
if (ctr_state[i] == ENABLED) {
rc = perf_reset_ctr(i);
state = perf_ctr_state(i);
if (state == ENABLED) {
rc = perf_reset_ctr(i, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
send_answer(s, i, ENABLED, 0);
} else {
send_answer(s, i, ctr_state[i], 0);
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
static int do_print(int s, enum ctr_e ctr)
{
int i, rc = 0;
uint64_t value;
int i, rc = 0, state;
uint64_t value = 0;
for (i = 0; i < ALL_COUNTER; i++) {
for (i = 0; i < NUM_COUNTER; i++) {
if (i == ALL_COUNTER)
continue;
if (i == (int) ctr || ctr == ALL_COUNTER) {
if (ctr_state[i] == ENABLED) {
state = perf_ctr_state(i);
if (state == ENABLED) {
rc = perf_read_ctr(i, &value);
if (rc != 0) {
send_answer(s, i, rc, 0);
break;
}
send_answer(s, i, ENABLED, value);
} else {
send_answer(s, i, ctr_state[i], 0);
}
send_answer(s, i, state, value);
if (i == PAI_USER)
rc = do_send_pai(s, 1);
if (i == PAI_KERNEL)
rc = do_send_pai(s, 0);
}
}
if (rc == 0) {
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
send_answer(s, HOTPLUG_DETECTED, rc, value);
}
return rc;
}
@@ -324,18 +389,8 @@ static void remove_pidfile(void)
void signalhandler(int sig)
{
if (sig == SIGTERM)
eprint("Caught signal SIGTERM, terminating...\n");
else if (sig == SIGINT)
eprint("Caught signal SIGINT, terminating...\n");
else
eprint("Caught signal %d, terminating...\n", sig);
remove_sock();
perf_close();
remove_pidfile();
exit(0);
perf_stop();
stopsig = sig;
}
@@ -381,7 +436,7 @@ int main(int argc, char *argv[])
switch (opt) {
case 'h':
printf(usage, name);
exit(0);
return 0;
case 'f':
foreground = 1;
break;
@@ -389,40 +444,37 @@ int main(int argc, char *argv[])
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
"Version %s\n%s\n",
name, RELEASE_STRING, COPYRIGHT);
exit(0);
return 0;
default:
printf("%s: Invalid argument, try -h or --help for more information\n",
name);
exit(1);
return EXIT_FAILURE;
}
}
}
if (check_pidfile() != 0) {
eprint("Stalled pid file or daemon allready running, terminating\n");
exit(1);
return EXIT_FAILURE;
}
if (!foreground) {
if (become_daemon() != 0) {
eprint("Couldn't daemonize\n");
exit(1);
return EXIT_FAILURE;
}
}
if (perf_init() != 0) {
eprint("Couldn't initialize perf lib\n");
exit(1);
return EXIT_FAILURE;
}
atexit(perf_close);
if (!perf_ecc_supported())
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
sfd = open_socket(SERVER);
if (sfd < 0) {
eprint("Couldn't initialize server socket\n");
exit(1);
return EXIT_FAILURE;
}
atexit(remove_sock);
@@ -432,17 +484,19 @@ int main(int argc, char *argv[])
if (sigaction(SIGINT, &act, 0) != 0) {
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
errno, strerror(errno));
exit(1);
return EXIT_FAILURE;
}
if (sigaction(SIGTERM, &act, 0) != 0) {
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
errno, strerror(errno));
exit(1);
return EXIT_FAILURE;
}
/* Ignore SIGPIPE such that we see EPIPE as return from write. */
signal(SIGPIPE, SIG_IGN);
eprint("Running\n");
while (1) {
while (!stopsig) {
enum ctr_e ctr;
enum cmd_e cmd;
int s;
@@ -453,7 +507,7 @@ int main(int argc, char *argv[])
continue;
eprint("Accept() failure, errno=%d [%s]\n",
errno, strerror(errno));
exit(1);
return EXIT_FAILURE;
}
rc = recv_query(s, &ctr, &cmd);
@@ -480,5 +534,13 @@ cleanup:
close(s);
}
if (stopsig == SIGTERM)
eprint("Caught signal SIGTERM, terminating...\n");
else if (stopsig == SIGINT)
eprint("Caught signal SIGINT, terminating...\n");
else
eprint("Caught signal %d, terminating...\n", stopsig);
remove_pidfile();
return 0;
}

View File

@@ -3,7 +3,7 @@
*
* low level perf functions
*
* Copyright IBM Corp. 2015, 2020
* Copyright IBM Corp. 2015, 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.
@@ -16,14 +16,21 @@
#include <inttypes.h>
#include <limits.h>
#include <linux/perf_event.h>
#include <pthread.h>
#include <poll.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <unistd.h>
#include <libudev.h>
#include "cpacfstats.h"
#include "../include/lib/zt_common.h"
/* correlation between counter and perf counter string */
static const struct {
@@ -38,25 +45,83 @@ static const struct {
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
};
/*
* We need one filedescriptor per CPU per counter.
* So perf_init builds this:
*
* ctr_fds - is an array of pointers to file descriptor arrays.
* Each file descriptor array has space for number of logical CPUs + 1
* filedescriptors (int values). The last element of each file descriptor
* array is always 0, assuming there will never appear a filedescriptor
* with value 0:
*
* ctr_fds:
* ctr_fds[0] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
* ctr_fds[1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
* ...
* ctr_fds[ALL_COUNTER-1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
*/
static int *ctr_fds[ALL_COUNTER];
static struct pmf_data {
int pmutype;
int eventid;
} pmf_counter_data[ALL_COUNTER];
static int ecc_supported;
struct percpucounter {
int ctr_fds[ALL_COUNTER];
int pai_user[NUM_PAI_USER];
int pai_kernel[NUM_PAI_KERNEL];
unsigned int cpunum;
struct percpucounter *next;
};
static struct percpucounter *root;
pthread_mutex_t rootmux = PTHREAD_MUTEX_INITIALIZER;
static volatile int hotplugdetected;
static unsigned int enabledcounter;
pthread_t hotplugthread;
#define foreachcpu(PCPU) if (pthread_mutex_lock(&rootmux)) return -1; \
for ((PCPU) = root; (PCPU) != NULL; (PCPU) = (PCPU)->next)
#define endforeachcpu() pthread_mutex_unlock(&rootmux)
static int ctr_state[NUM_COUNTER];
static volatile int stoprequested;
static int paipmutype, paipmueventstart;
static struct percpucounter *allocpercpucounter(unsigned int cpunum)
{
struct percpucounter *ppc;
ppc = malloc(sizeof(struct percpucounter));
if (ppc) {
int i;
for (i = 0; i < ALL_COUNTER; ++i)
ppc->ctr_fds[i] = -1;
for (i = 0; i < NUM_PAI_USER; ++i)
ppc->pai_user[i] = -1;
for (i = 0; i < NUM_PAI_KERNEL; ++i)
ppc->pai_kernel[i] = -1;
ppc->cpunum = cpunum;
ppc->next = NULL;
}
return ppc;
}
static void freepercpucounter(struct percpucounter *pcpu)
{
int i;
for (i = 0; i < ALL_COUNTER; ++i)
(void)close(pcpu->ctr_fds[i]);
for (i = 0; i < NUM_PAI_USER; ++i)
(void)close(pcpu->pai_user[i]);
for (i = 0; i < NUM_PAI_KERNEL; ++i)
(void)close(pcpu->pai_kernel[i]);
free(pcpu);
}
static struct percpucounter *findcpu(unsigned int cpunum, int unlinkflag)
{
struct percpucounter **prev = &root, *walk = root;
while (walk) {
if (walk->cpunum == cpunum) {
if (unlinkflag)
*prev = walk->next;
return walk;
}
prev = &(walk->next);
walk = walk->next;
}
return NULL;
}
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
@@ -85,12 +150,43 @@ static int perf_counter_supported(const char *pmu, const char *counter)
return !access(buf, R_OK);
}
static int perf_event_encode(struct perf_event_attr *attr,
static int cpumf_authorized(void)
{
unsigned vermin, vermax, auth;
int res = 0, found = 0;
size_t linesize = 0;
char *line = NULL;
FILE *f;
f = fopen("/proc/service_levels", "r");
if (f == NULL) {
eprint("Failed to open /proc/service_levels (%d:%s)\n",
errno, strerror(errno));
return 0;
}
while (getline(&line, &linesize, f) >= 0) {
if (sscanf(line,
"CPU-MF: Counter facility: version=%d.%d authorization=%x",
&vermin, &vermax, &auth) == 3) {
if (auth & 0x8)
res = 1;
else
eprint("CPU-MF counters not authorized.\n");
found = 1;
break;
}
}
if (!found)
eprint("CPU-MF counters not available.\n");
free(line);
fclose(f);
return res;
}
static int perf_event_encode(int *pmutype, int *eventid,
const char *pmu, const char *event)
{
FILE *f;
int eventid;
int pmutype;
char buf[PATH_MAX];
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
@@ -104,7 +200,7 @@ static int perf_event_encode(struct perf_event_attr *attr,
errno, strerror(errno));
return -1;
}
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
if (fscanf(f, "event=0x%x\n", eventid) != 1) {
fclose(f);
eprint("Event file %s has invalid format\n", buf);
return -1;
@@ -121,21 +217,257 @@ static int perf_event_encode(struct perf_event_attr *attr,
errno, strerror(errno));
return -1;
}
if (fscanf(f, "%d\n", &pmutype) != 1) {
if (fscanf(f, "%d\n", pmutype) != 1) {
fclose(f);
eprint("Type file %s has invalid format\n", buf);
return -1;
}
attr->type = pmutype;
attr->config = eventid;
return 0;
}
static int activatecpu(unsigned int cpu)
{
struct perf_event_attr pfm_event;
struct percpucounter *ppc;
int fd, i, rc = 0;
ppc = allocpercpucounter(cpu);
if (ppc == NULL) {
eprint("Failed to allocate per cpu counter data");
return -1;
}
if (pthread_mutex_lock(&rootmux)) {
freepercpucounter(ppc);
return -1;
}
/* activate CPU-MF */
for (i = 0; i < ALL_COUNTER; ++i) {
if (ctr_state[i] == UNSUPPORTED)
continue;
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = pmf_counter_data[i].pmutype;
pfm_event.config = pmf_counter_data[i].eventid;
/* fetch file descriptor for this perf event
* the counter event should start disabled
*/
pfm_event.disabled = ctr_state[i] == DISABLED;
fd = perf_event_open(
&pfm_event,
-1, /* pid -1 means all processes */
cpu,
-1, /* group filedescriptor */
0); /* flags */
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[i] = UNSUPPORTED;
} else {
ppc->ctr_fds[i] = fd;
}
}
/* activate pai_user and pai_kernel */
/* invariant:
(ctr_state[PAI_USER] == UNSUPPORTED) ==
(ctr_state[PAI_KERNEL] == UNSUPPORTED) */
if (ctr_state[PAI_USER] != UNSUPPORTED) {
for (i = 1; i <= NUM_PAI_USER; ++i) {
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = paipmutype;
pfm_event.config = paipmueventstart + i;
pfm_event.exclude_kernel = 1;
pfm_event.exclude_user = 0;
pfm_event.disabled = ctr_state[PAI_USER] == DISABLED;
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
goto outevents;
} else {
ppc->pai_user[i - 1] = fd;
}
pfm_event.exclude_kernel = 0;
pfm_event.exclude_user = 1;
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
goto outevents;
} else {
ppc->pai_kernel[i - 1] = fd;
}
}
for (; i <= NUM_PAI_KERNEL; ++i) {
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
pfm_event.type = paipmutype;
pfm_event.config = paipmueventstart + i;
pfm_event.exclude_kernel = 0;
pfm_event.exclude_user = 1;
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
goto outevents;
} else {
ppc->pai_kernel[i - 1] = fd;
}
}
}
outevents:
ppc->next = root;
root = ppc;
if (enabledcounter)
hotplugdetected = 1;
pthread_mutex_unlock(&rootmux);
return rc;
}
static void deactivatecpu(unsigned int cpunum)
{
struct percpucounter *pcpu;
int i;
if (pthread_mutex_lock(&rootmux))
return;
pcpu = findcpu(cpunum, 1);
if (pcpu != NULL) {
for (i = 0; i < ALL_COUNTER; ++i)
(void)close(pcpu->ctr_fds[i]);
for (i = 0; i < NUM_PAI_USER; ++i)
(void)close(pcpu->pai_user[i]);
for (i = 0; i < NUM_PAI_KERNEL; ++i)
(void)close(pcpu->pai_kernel[i]);
free(pcpu);
if (enabledcounter)
hotplugdetected = 1;
}
pthread_mutex_unlock(&rootmux);
}
static int addallcpus(void)
{
unsigned int start, end;
int scanned, rc = 0;
FILE *fp;
/* comma separated list of intervals */
if ((fp = fopen("/sys/devices/system/cpu/online", "r")) == NULL) {
eprint("Failed to get online cpus (%d:%s)\n",
errno, strerror(errno));
return -1;
}
while (!feof(fp)) {
/* scan all intervals of online cpus */
scanned = fscanf(fp, "%u-%u", &start, &end);
/* take care of singleton intervals */
if (scanned == 1)
end = start;
for (; start <= end; ++start) {
if (activatecpu(start)) {
rc = -1;
goto out;
}
}
/* Skip comma separator */
(void)fgetc(fp);
}
out:
fclose(fp);
return rc;
}
static int perf_load_counter_data(void)
{
int i, res = 0;
for (i = 0; i < ALL_COUNTER; ++i) {
if (ctr_state[i] != UNSUPPORTED)
res |= perf_event_encode(&pmf_counter_data[i].pmutype,
&pmf_counter_data[i].eventid,
pmf_counter_name[i].pmu,
pmf_counter_name[i].pfm_name);
}
if (ctr_state[PAI_USER] != UNSUPPORTED)
res |= perf_event_encode(&paipmutype, &paipmueventstart,
"pai_crypto", "CRYPTO_ALL");
return res;
}
static void *hotplughandler(void *UNUSED(unused))
{
struct udev *hotplug;
struct udev_monitor *monitor;
struct pollfd item;
hotplug = udev_new();
if (!hotplug) {
eprint("Failed to create hotplug device\n");
return NULL;
}
monitor = udev_monitor_new_from_netlink(hotplug, "udev");
udev_monitor_filter_add_match_subsystem_devtype(monitor, "cpu", NULL);
udev_monitor_enable_receiving(monitor);
item.fd = udev_monitor_get_fd(monitor);
item.events = POLLIN;
item.revents = 0;
while (!stoprequested) {
struct udev_device *dev;
const char *path, *action;
unsigned int cpunum;
int rc, on, off;
errno = 0;
rc = poll(&item, 1, -1);
if (rc == -1) {
if (errno == EINTR)
continue;
break;
}
dev = udev_monitor_receive_device(monitor);
if (dev == NULL)
continue;
action = udev_device_get_action(dev);
if (action == NULL)
continue;
off = strcmp(action, "offline") == 0;
on = strcmp(action, "online") == 0;
if (!on && !off)
continue;
path = udev_device_get_devpath(dev);
if (sscanf(path, "/devices/system/cpu/cpu%u", &cpunum) != 1)
continue;
if (on && activatecpu(cpunum))
eprint("Failed to attach to hotplugged CPU %u\n", cpunum);
if (off)
deactivatecpu(cpunum);
}
udev_monitor_unref(monitor);
udev_unref(hotplug);
return NULL;
}
int perf_init(void)
{
int i, cpus, ctr, cpu, *fds;
memset(ctr_fds, 0, sizeof(ctr_fds));
int ecc_supported, i, num;
unsigned long maxfd;
struct rlimit rlim;
FILE *f;
/* initialize performance monitoring library */
if (!perf_supported()) {
@@ -143,99 +475,105 @@ int perf_init(void)
return -1;
}
/* We currently support all cpumf counters plus two virtual
* counters for PAI. */
num = ALL_COUNTER + 2;
/* Check if ECC is supported on current hardware */
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
/* get number of logical processors */
cpus = sysconf(_SC_NPROCESSORS_ONLN);
/* for each counter */
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
/* Skip ECC counters completely if unsupported */
if (ctr == ECC_FUNCTIONS && !ecc_supported)
continue;
/*
* allocate an array of ints to store for each CPU
* one filedescriptor + a terminating 0
*/
fds = (int *) calloc(sizeof(int), cpus+1);
if (!fds) {
eprint("Malloc() of %d byte failed, errno=%d [%s]\n",
(int)(sizeof(int) * (cpus+1)),
errno, strerror(errno));
return -1;
}
ctr_fds[ctr] = fds;
/* search for the counter's corresponding pfm name */
for (i = ALL_COUNTER-1; i >= 0; i--)
if ((int) pmf_counter_name[i].ctr == ctr)
break;
if (i < 0) {
eprint("Pfm ctr name not found for counter %d, please adjust pmf_counter_name[] in %s\n",
ctr, __FILE__);
return -1;
}
for (cpu = 0; cpu < cpus; cpu++) {
struct perf_event_attr pfm_event;
int fd;
memset(&pfm_event, 0, sizeof(pfm_event));
pfm_event.size = sizeof(pfm_event);
if (perf_event_encode(&pfm_event,
pmf_counter_name[i].pmu,
pmf_counter_name[i].pfm_name)) {
eprint("Failed to initialize counter %s for pmu %s\n",
pmf_counter_name[i].pfm_name,
pmf_counter_name[i].pmu);
return -1;
}
/* fetch file descriptor for this perf event
* the counter event should start disabled
*/
pfm_event.disabled = 1;
fd = perf_event_open(
&pfm_event,
-1, /* pid -1 means all processes */
cpu,
-1, /* group filedescriptor */
0); /* flags */
if (fd < 0) {
eprint("Perf_event_open() failed with errno=%d [%s]\n",
errno, strerror(errno));
return -1;
}
fds[cpu] = fd;
}
if (!cpumf_authorized()) {
for (i = 0; i < ALL_COUNTER; ++i)
ctr_state[i] = UNSUPPORTED;
num -= ALL_COUNTER;
} else if (!ecc_supported) {
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
--num;
}
return 0;
if (!perf_counter_supported("pai_crypto", "CRYPTO_ALL")) {
ctr_state[PAI_USER] = UNSUPPORTED;
ctr_state[PAI_KERNEL] = UNSUPPORTED;
num -= 2;
}
if (num == 0) {
eprint("No crypto counters supported!\n");
return -1;
}
if (perf_load_counter_data())
return -1;
/* We have to adjust the number of FDs possible since we might
* need more than 1024 (the typical soft limit) */
f = fopen("/proc/sys/fs/nr_open", "r");
if (f == NULL) {
eprint("fopen failed for /proc/sys/fs/nr_open with errno=%d [%s]\n",
errno, strerror(errno));
return -1;
}
if (fscanf(f, "%lu", &maxfd) != 1) {
fclose(f);
eprint("Failed to parse /proc/sys/fs/nr_open\n");
return -1;
}
fclose(f);
rlim.rlim_cur = maxfd;
rlim.rlim_max = maxfd;
if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
eprint("setrlimit failed with errno=%d [%s]\n",
errno, strerror(errno));
return -1;
}
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
eprint("Failed to start hotplug handler thread\n");
return -1;
}
return addallcpus();
}
void perf_stop(void)
{
stoprequested = 1;
}
void perf_close(void)
{
int ctr, *fds;
struct percpucounter *walk, *next;
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
close(*fds);
*fds = 0;
}
free(ctr_fds[ctr]);
ctr_fds[ctr] = NULL;
pthread_kill(hotplugthread, SIGINT);
pthread_join(hotplugthread, NULL);
walk = root;
while (walk) {
next = walk->next;
freepercpucounter(walk);
walk = next;
}
}
static int enable_array(int *arr, int size)
{
int i, ec, rc = 0;
for (i = 0; i < size; ++i) {
ec = ioctl(arr[i], PERF_EVENT_IOC_ENABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
return rc;
}
int perf_enable_ctr(enum ctr_e ctr)
{
int *fds, ec, rc = 0;
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
@@ -243,24 +581,64 @@ int perf_enable_ctr(enum ctr_e ctr)
if (rc != 0)
return rc;
}
} else {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = ioctl(*fds, PERF_EVENT_IOC_ENABLE, 0);
} else if (ctr < ALL_COUNTER) {
foreachcpu(pcpu) {
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_ENABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
ctr_state[ctr] = ENABLED;
++enabledcounter;
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = enable_array(pcpu->pai_user, NUM_PAI_USER);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = ENABLED;
++enabledcounter;
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = enable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = ENABLED;
++enabledcounter;
endforeachcpu();
} else {
rc = -1;
}
return rc;
}
static int disable_array(int *arr, int size)
{
int i, ec, rc = 0;
for (i = 0; i < size; ++i) {
ec = ioctl(arr[i], PERF_EVENT_IOC_DISABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
return rc;
}
int perf_disable_ctr(enum ctr_e ctr)
{
int *fds, ec, rc = 0;
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
@@ -268,70 +646,183 @@ int perf_disable_ctr(enum ctr_e ctr)
if (rc != 0)
return rc;
}
} else {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = ioctl(*fds, PERF_EVENT_IOC_DISABLE, 0);
} else if (ctr < ALL_COUNTER) {
foreachcpu(pcpu) {
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_DISABLE, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
ctr_state[ctr] = DISABLED;
--enabledcounter;
if (enabledcounter == 0)
hotplugdetected = 0;
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = disable_array(pcpu->pai_user, NUM_PAI_USER);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = DISABLED;
--enabledcounter;
if (enabledcounter == 0)
hotplugdetected = 0;
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = disable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
if (ec < 0)
rc = -1;
}
ctr_state[ctr] = DISABLED;
--enabledcounter;
if (enabledcounter == 0)
hotplugdetected = 0;
endforeachcpu();
} else {
rc = -1;
}
return rc;
}
int perf_reset_ctr(enum ctr_e ctr)
static int reset_array(int *arr, int size)
{
int *fds, ec, rc = 0;
int ec, rc = 0, i;
for (i = 0; i < size; ++i) {
ec = ioctl(arr[i], PERF_EVENT_IOC_RESET, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
return rc;
}
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
{
struct percpucounter *pcpu;
int ec, rc = 0;
if (ctr == ALL_COUNTER) {
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
rc = perf_reset_ctr(ctr);
rc = perf_reset_ctr(ctr, value);
if (rc != 0)
return rc;
}
} else {
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = ioctl(*fds, PERF_EVENT_IOC_RESET, 0);
} else if (ctr < ALL_COUNTER) {
foreachcpu(pcpu) {
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_RESET, 0);
if (ec < 0) {
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
}
}
endforeachcpu();
} else if (ctr == PAI_USER) {
foreachcpu(pcpu) {
ec = reset_array(pcpu->pai_user, NUM_PAI_USER);
if (ec < 0)
rc = -1;
}
endforeachcpu();
} else if (ctr == PAI_KERNEL) {
foreachcpu(pcpu) {
ec = reset_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
if (ec < 0)
rc = -1;
}
endforeachcpu();
} else {
rc = -1;
}
if (rc == 0)
rc = perf_read_ctr(ctr, value);
return rc;
}
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
{
int *fds, ec, rc = -1;
struct percpucounter *pcpu;
int ec, rc = 0;
uint64_t val;
if (!value)
return -1;
if (ctr == HOTPLUG_DETECTED) {
*value = hotplugdetected;
return 0;
}
if (ctr == PAI_USER) {
*value = NUM_PAI_USER;
return 0;
}
if (ctr == PAI_KERNEL) {
*value = NUM_PAI_KERNEL;
return 0;
}
if (ctr >= ALL_COUNTER)
return -1;
*value = 0;
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
ec = read(*fds, &val, sizeof(val));
foreachcpu(pcpu) {
ec = read(pcpu->ctr_fds[ctr], &val, sizeof(val));
if (ec != sizeof(val)) {
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
} else {
*value += val;
rc = 0;
}
}
endforeachcpu();
return rc;
}
int perf_ecc_supported(void)
{
return ecc_supported;
return ctr_state[ECC_FUNCTIONS] != UNSUPPORTED;
}
int perf_ctr_state(enum ctr_e ctr) {
if (ctr < NUM_COUNTER)
return ctr_state[ctr];
return UNSUPPORTED;
}
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value)
{
struct percpucounter *pcpu;
unsigned int maxctr;
int *arr, ec, rc = 0;
uint64_t val;
*value = 0;
maxctr = user ? NUM_PAI_USER : NUM_PAI_KERNEL;
if (ctrnum >= maxctr)
return -1;
foreachcpu(pcpu) {
arr = user ? pcpu->pai_user : pcpu->pai_kernel;
ec = read(arr[ctrnum], &val, sizeof(val));
if (ec != sizeof(val)) {
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
errno, strerror(errno));
rc = -1;
} else {
*value += val;
}
}
endforeachcpu();
return rc;
}

View File

@@ -3,7 +3,7 @@
*
* basic socket and receive/send functions
*
* Copyright IBM Corp. 2015, 2017
* Copyright IBM Corp. 2015, 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.
@@ -13,6 +13,7 @@
#include <endian.h>
#include <errno.h>
#include <grp.h>
#include <poll.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/socket.h>
@@ -148,7 +149,51 @@ static int __read(int fd, void *buf, int buflen)
}
int send_msg(int sfd, struct msg *m)
static int __timedwrite(int fd, const void *buf, int buflen, int timeout)
{
struct pollfd pfd = { .fd = fd, .events = POLLOUT };
int i = 0, n;
while (poll(&pfd, 1, timeout) == 1) {
n = write(fd, buf + i, buflen - i);
if (n < 0) {
if (errno == EINTR)
continue;
else
return n;
} else if (n == 0) {
return i;
}
i += n;
if (buflen == i)
return i;
}
return -1;
}
static int __timedread(int fd, void *buf, int buflen, int timeout)
{
struct pollfd pfd = { .fd = fd, .events = POLLIN };
int i = 0, n;
while (poll(&pfd, 1, timeout) == 1) {
n = read(fd, buf + i, buflen - i);
if (n < 0) {
if (errno == EINTR)
continue;
else
return n;
} else if (n == 0) {
return i;
}
i += n;
if (buflen == i)
return i;
}
return -1;
}
int send_msg(int sfd, struct msg *m, int timeout)
{
int n, len;
@@ -166,7 +211,7 @@ int send_msg(int sfd, struct msg *m)
return -1;
}
n = __write(sfd, m, len);
n = timeout ? __timedwrite(sfd, m, len, timeout) : __write(sfd, m, len);
if (n != len) {
eprint("Write() error: write()=%d expected %d, errno=%d [%s]\n",
n, len, errno, strerror(errno));
@@ -176,12 +221,12 @@ int send_msg(int sfd, struct msg *m)
return 0;
}
int recv_msg(int sfd, struct msg *m)
int recv_msg(int sfd, struct msg *m, int timeout)
{
int n, len;
len = sizeof(m->head);
n = __read(sfd, m, len);
n = timeout ? __timedread(sfd, m, len, timeout) : __read(sfd, m, len);
if (n != len) {
eprint("Recv() error: read()=%d expected %d, errno=%d [%s]\n",
n, len, errno, strerror(errno));
@@ -200,7 +245,8 @@ int recv_msg(int sfd, struct msg *m)
return -1;
}
n = __read(sfd, ((char *)m) + sizeof(m->head), len);
n = timeout ? __timedread(sfd, ((char *)m) + sizeof(m->head), len, timeout) :
__read(sfd, ((char *)m) + sizeof(m->head), len);
if (n != len) {
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
n, len, errno, strerror(errno));

View File

@@ -1,15 +1,16 @@
include ../common.mak
BIN_FILES = lscpumf chcpumf lshwc
MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
BIN_FILES = lscpumf chcpumf lshwc pai
MAN_FILES = lscpumf.8 chcpumf.8 lshwc.8 pai.8
all: $(BIN_FILES)
libs = $(rootdir)/libutil/libutil.a $(rootdir)/libcpumf/libcpumf.a
libs = $(rootdir)/libcpumf/libcpumf.a $(rootdir)/libutil/libutil.a
lscpumf: lscpumf.o $(libs)
chcpumf: chcpumf.o $(libs)
lshwc: lshwc.o $(libs)
pai: pai.o $(libs)
install: all install-man
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
@@ -22,8 +23,8 @@ clean:
install-man:
for man in $(MAN_FILES); do \
msection=`echo $$man |sed 's/.*\.\([1-9]\)$$/man\1/'` ; \
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 -D man/$$man $(DESTDIR)$(MANDIR)/$$msection/$$man ; \
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 man/$$man \
$(DESTDIR)$(MANDIR)/man8 ; \
done
.PHONY: all install clean

View File

@@ -26,6 +26,7 @@
#include "lib/util_arch.h"
#include "lib/util_base.h"
#include "lib/util_opt.h"
#include "lib/util_path.h"
#include "lib/util_prg.h"
#include "lib/libcpumf.h"
@@ -2555,6 +2556,586 @@ static struct counters cpumcf_z15_counters[] = {
},
};
static struct counters cpumcf_z16_counters[] = {
{
.ctrnum = 128,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "L1D_RO_EXCL_WRITES",
.desc = "A directory write to the Level-1 Data cache where"
"\n\t\tthe line was originally in a Read-Only state in the"
"\n\t\tcache but has been updated to be in the Exclusive"
"\n\t\tstate that allows stores to the cache line.",
},
{
.ctrnum = 129,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DTLB2_WRITES",
.desc = "A translation has been written into The Translation"
"\n\t\tLookaside Buffer 2 (TLB2) and the request was made"
"\n\t\tby the Level-1 Data cache. This is a replacement"
"\n\t\tfor what was provided for the DTLB on z13 and prior"
"\n\t\tmachines.",
},
{
.ctrnum = 130,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DTLB2_MISSES",
.desc = "A TLB2 miss is in progress for a request made by"
"\n\t\tthe Level-1 Data cache. Incremented by one for"
"\n\t\tevery TLB2 miss in progress for the Level-1 Data"
"\n\t\tcache on this cycle. This is a replacement for what"
"\n\t\twas provided for the DTLB on z13 and prior"
"\n\t\tmachines.",
},
{
.ctrnum = 131,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "CRSTE_1MB_WRITES",
.desc = "A translation entry was written into the Combined"
"\n\t\tRegion and Segment Table Entry array in the Level-2"
"\n\t\tTLB for a one-megabyte page.",
},
{
.ctrnum = 132,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DTLB2_GPAGE_WRITES",
.desc = "A translation entry for a two-gigabyte page was"
"\n\t\twritten into the Level-2 TLB.",
},
{
.ctrnum = 134,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ITLB2_WRITES",
.desc = "A translation entry has been written into the"
"\n\t\tTranslation Lookaside Buffer 2 (TLB2) and the"
"\n\t\trequest was made by the instruction cache. This is"
"\n\t\ta replacement for what was provided for the ITLB on"
"\n\t\tz13 and prior machines.",
},
{
.ctrnum = 135,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ITLB2_MISSES",
.desc = "A TLB2 miss is in progress for a request made by"
"\n\t\tthe Level-1 Instruction cache. Incremented by one"
"\n\t\tfor every TLB2 miss in progress for the Level-1"
"\n\t\tInstruction cache in a cycle. This is a replacement"
"\n\t\tfor what was provided for the ITLB on z13 and prior"
"\n\t\tmachines.",
},
{
.ctrnum = 137,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TLB2_PTE_WRITES",
.desc = "A translation entry was written into the Page Table"
"\n\t\tEntry array in the Level-2 TLB.",
},
{
.ctrnum = 138,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TLB2_CRSTE_WRITES",
.desc = "Translation entries were written into the Combined"
"\n\t\tRegion and Segment Table Entry array and the Page"
"\n\t\tTable Entry array in the Level-2 TLB.",
},
{
.ctrnum = 139,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TLB2_ENGINES_BUSY",
.desc = "The number of Level-2 TLB translation engines busy"
"\n\t\tin a cycle.",
},
{
.ctrnum = 140,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TX_C_TEND",
.desc = "A TEND instruction has completed in a constrained"
"\n\t\ttransactional-execution mode.",
},
{
.ctrnum = 141,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TX_NC_TEND",
.desc = "A TEND instruction has completed in a non-"
"\n\t\tconstrained transactional-execution mode.",
},
{
.ctrnum = 143,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "L1C_TLB2_MISSES",
.desc = "Increments by one for any cycle where a level-1"
"\n\t\tcache or level-2 TLB miss is in progress.",
},
{
.ctrnum = 145,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_REQ",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache.",
},
{
.ctrnum = 146,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_REQ_IV",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache with"
"\n\t\tintervention.",
},
{
.ctrnum = 147,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_REQ_CHIP_HIT",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache after using"
"\n\t\tchip level horizontal persistence, Chip-HP hit.",
},
{
.ctrnum = 148,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_REQ_DRAWER_HIT",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache after using"
"\n\t\tdrawer level horizontal persistence, Drawer-HP hit.",
},
{
.ctrnum = 149,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_CHIP",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip Level-2 cache.",
},
{
.ctrnum = 150,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_CHIP_IV",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip Level-2 cache with intervention.",
},
{
.ctrnum = 151,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_CHIP_CHIP_HIT",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip Level-2 cache after using chip"
"\n\t\tlevel horizontal persistence, Chip-HP hit.",
},
{
.ctrnum = 152,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_CHIP_DRAWER_HIT",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip Level-2 cache using drawer level"
"\n\t\thorizontal persistence, Drawer-HP hit.",
},
{
.ctrnum = 153,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_MODULE",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Module Level-2 cache.",
},
{
.ctrnum = 154,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_DRAWER",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Drawer Level-2 cache.",
},
{
.ctrnum = 155,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_OFF_DRAWER",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an Off-Drawer Level-2 cache.",
},
{
.ctrnum = 156,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_CHIP_MEMORY",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom On-Chip memory.",
},
{
.ctrnum = 157,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_MODULE_MEMORY",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom On-Module memory.",
},
{
.ctrnum = 158,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_ON_DRAWER_MEMORY",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom On-Drawer memory.",
},
{
.ctrnum = 159,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DCW_OFF_DRAWER_MEMORY",
.desc = "A directory write to the Level-1 Data cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom Off-Drawer memory.",
},
{
.ctrnum = 160,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_ON_MODULE_IV",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tInstruction cache directory where the returned"
"\n\t\tcache line was sourced from an On-Module Level-2"
"\n\t\tcache with intervention.",
},
{
.ctrnum = 161,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_ON_MODULE_CHIP_HIT",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tInstruction cache directory where the returned"
"\n\t\tcache line was sourced from an On-Module Level-2"
"\n\t\tcache using chip horizontal persistence, Chip-HP"
"\n\t\thit.",
},
{
.ctrnum = 162,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_ON_MODULE_DRAWER_HIT",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tInstruction cache directory where the returned"
"\n\t\tcache line was sourced from an On-Module Level-2"
"\n\t\tcache using drawer level horizontal persistence,"
"\n\t\tDrawer-HP hit.",
},
{
.ctrnum = 163,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_ON_DRAWER_IV",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tInstruction cache directory where the returned"
"\n\t\tcache line was sourced from an On-Drawer Level-2"
"\n\t\tcache with intervention.",
},
{
.ctrnum = 164,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_ON_DRAWER_CHIP_HIT",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tinstruction cache directory where the returned"
"\n\t\tcache line was sourced from an On-Drawer Level-2"
"\n\t\tcache using chip level horizontal persistence, Chip-"
"\n\t\tHP hit.",
},
{
.ctrnum = 165,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_ON_DRAWER_DRAWER_HIT",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tinstruction cache directory where the returned"
"\n\t\tcache line was sourced from an On-Drawer Level-2"
"\n\t\tcache using drawer level horizontal persistence,"
"\n\t\tDrawer-HP hit.",
},
{
.ctrnum = 166,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_OFF_DRAWER_IV",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tinstruction cache directory where the returned"
"\n\t\tcache line was sourced from an Off-Drawer Level-2"
"\n\t\tcache with intervention.",
},
{
.ctrnum = 167,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_OFF_DRAWER_CHIP_HIT",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tinstruction cache directory where the returned"
"\n\t\tcache line was sourced from an Off-Drawer Level-2"
"\n\t\tcache using chip level horizontal persistence, Chip-"
"\n\t\tHP hit.",
},
{
.ctrnum = 168,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "IDCW_OFF_DRAWER_DRAWER_HIT",
.desc = "A directory write to the Level-1 Data or Level-1"
"\n\t\tInstruction cache directory where the returned"
"\n\t\tcache line was sourced from an Off-Drawer Level-2"
"\n\t\tcache using drawer level horizontal persistence,"
"\n\t\tDrawer-HP hit.",
},
{
.ctrnum = 169,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_REQ",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tthe requestors Level-2 cache.",
},
{
.ctrnum = 170,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_REQ_IV",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache with"
"\n\t\tintervention.",
},
{
.ctrnum = 171,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_REQ_CHIP_HIT",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache using chip level"
"\n\t\thorizontal persistence, Chip-HP hit.",
},
{
.ctrnum = 172,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_REQ_DRAWER_HIT",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom the requestors Level-2 cache using drawer"
"\n\t\tlevel horizontal persistence, Drawer-HP hit.",
},
{
.ctrnum = 173,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_CHIP",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip Level-2 cache.",
},
{
.ctrnum = 174,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_CHIP_IV",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tan On-Chip Level-2 cache with intervention.",
},
{
.ctrnum = 175,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_CHIP_CHIP_HIT",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip Level-2 cache using chip level"
"\n\t\thorizontal persistence, Chip-HP hit.",
},
{
.ctrnum = 176,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_CHIP_DRAWER_HIT",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Chip level 2 cache using drawer level"
"\n\t\thorizontal persistence, Drawer-HP hit.",
},
{
.ctrnum = 177,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_MODULE",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom an On-Module Level-2 cache.",
},
{
.ctrnum = 178,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_DRAWER",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tan On-Drawer Level-2 cache.",
},
{
.ctrnum = 179,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_OFF_DRAWER",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tan Off-Drawer Level-2 cache.",
},
{
.ctrnum = 180,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_CHIP_MEMORY",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom On-Chip memory.",
},
{
.ctrnum = 181,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_MODULE_MEMORY",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom On-Module memory.",
},
{
.ctrnum = 182,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_ON_DRAWER_MEMORY",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom On-Drawer memory.",
},
{
.ctrnum = 183,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "ICW_OFF_DRAWER_MEMORY",
.desc = "A directory write to the Level-1 Instruction cache"
"\n\t\tdirectory where the returned cache line was sourced"
"\n\t\tfrom Off-Drawer memory.",
},
{
.ctrnum = 224,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "BCD_DFP_EXECUTION_SLOTS",
.desc = "Count of floating point execution slots used for"
"\n\t\tfinished Binary Coded Decimal to Decimal Floating"
"\n\t\tPoint conversions. Instructions: CDZT, CXZT, CZDT,"
"\n\t\tCZXT.",
},
{
.ctrnum = 225,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "VX_BCD_EXECUTION_SLOTS",
.desc = "Count of floating point execution slots used for"
"\n\t\tfinished vector arithmetic Binary Coded Decimal"
"\n\t\tinstructions. Instructions: VAP, VSP, VMP, VMSP,"
"\n\t\tVDP, VSDP, VRP, VLIP, VSRP, VPSOP, VCP, VTP, VPKZ,"
"\n\t\tVUPKZ, VCVB, VCVBG, VCVD, VCVDG.",
},
{
.ctrnum = 226,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DECIMAL_INSTRUCTIONS",
.desc = "Decimal instruction dispatched. Instructions: CVB,"
"\n\t\tCVD, AP, CP, DP, ED, EDMK, MP, SRP, SP, ZAP.",
},
{
.ctrnum = 232,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "LAST_HOST_TRANSLATIONS",
.desc = "Last Host Translation done",
},
{
.ctrnum = 244,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TX_NC_TABORT",
.desc = "A transaction abort has occurred in a non-"
"\n\t\tconstrained transactional-execution mode.",
},
{
.ctrnum = 245,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TX_C_TABORT_NO_SPECIAL",
.desc = "A transaction abort has occurred in a constrained"
"\n\t\ttransactional-execution mode and the CPU is not"
"\n\t\tusing any special logic to allow the transaction to"
"\n\t\tcomplete.",
},
{
.ctrnum = 246,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "TX_C_TABORT_SPECIAL",
.desc = "A transaction abort has occurred in a constrained"
"\n\t\ttransactional-execution mode and the CPU is using"
"\n\t\tspecial logic to allow the transaction to complete.",
},
{
.ctrnum = 248,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DFLT_ACCESS",
.desc = "Cycles CPU spent obtaining access to Deflate unit",
},
{
.ctrnum = 253,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DFLT_CYCLES",
.desc = "Cycles CPU is using Deflate unit",
},
{
.ctrnum = 256,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "SORTL",
.desc = "Increments by one for every SORT LISTS instruction"
"\n\t\texecuted.",
},
{
.ctrnum = 265,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DFLT_CC",
.desc = "Increments by one for every DEFLATE CONVERSION CALL"
"\n\t\tinstruction executed.",
},
{
.ctrnum = 266,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "DFLT_CCFINISH",
.desc = "Increments by one for every DEFLATE CONVERSION CALL"
"\n\t\tinstruction executed that ended in Condition Codes"
"\n\t\t0, 1 or 2.",
},
{
.ctrnum = 267,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "NNPA_INVOCATIONS",
.desc = "Increments by one for every Neural Network"
"\n\t\tProcessing Assist instruction executed.",
},
{
.ctrnum = 268,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "NNPA_COMPLETIONS",
.desc = "Increments by one for every Neural Network"
"\n\t\tProcessing Assist instruction executed that ended"
"\n\t\tin Condition Codes 0, 1 or 2.",
},
{
.ctrnum = 269,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "NNPA_WAIT_LOCK",
.desc = "Cycles CPU spent obtaining access to IBM Z"
"\n\t\tIntegrated Accelerator for AI.",
},
{
.ctrnum = 270,
.ctrset = CPUMF_CTRSET_EXTENDED,
.name = "NNPA_HOLD_LOCK",
.desc = "Cycles CPU is using IBM Z Integrated Accelerator"
"\n\t\tfor AI.",
},
{
.ctrnum = 448,
.ctrset = CPUMF_CTRSET_MT_DIAG,
.name = "MT_DIAG_CYCLES_ONE_THR_ACTIVE",
.desc = "Cycle count with one thread active",
},
{
.ctrnum = 449,
.ctrset = CPUMF_CTRSET_MT_DIAG,
.name = "MT_DIAG_CYCLES_TWO_THR_ACTIVE",
.desc = "Cycle count with two threads active",
},
};
/* Return the type number of the CPU Measurement facility from the sysfs file.
* If the type number is equal to PERF_TYPE_RAW, then the prefix is 'r' to
* specify the raw counter number by the perf tool.
@@ -2738,17 +3319,18 @@ static void show_info(struct cpumf_info *p, int details)
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
* Check for existence of file /sys/devices/cpum_cf/events/DLFT_CCERROR.
*/
#define CCERROR "/sys/devices/cpum_cf/events/DFLT_CCERROR"
static void read_ccerror(struct counters *cp, size_t cp_cnt)
{
char *ctrname, *path;
struct stat sbuf;
char *ctrname;
size_t i = 0;
if (!stat(CCERROR, &sbuf))
path = util_path_sysfs("devices/cpum_cf/events/DFLT_CCERROR");
if (!stat(path, &sbuf))
ctrname = "DFLT_CCERROR";
else
ctrname = "DFLT_CCFINISH";
free(path);
/* Find DFLT_CC{FINISH,ERROR} in table and set name */
for (struct counters *p = cp; i < cp_cnt; ++i, ++p)
if (p->ctrnum == 265) {
@@ -2890,6 +3472,9 @@ static struct counters *get_counter(int ctrset, size_t *len)
*len = ARRAY_SIZE(cpumcf_z15_counters);
read_ccerror(cp, *len);
break;
case UTIL_ARCH_MACHINE_TYPE_Z16:
cp = cpumcf_z16_counters;
*len = ARRAY_SIZE(cpumcf_z16_counters);
}
break;
}

View File

@@ -38,6 +38,7 @@
#include "lib/util_path.h"
#include "lib/util_scandir.h"
#include "lib/util_libc.h"
#include "lib/util_file.h"
#include "lib/libcpumf.h"
#include "lshwc.h"
@@ -62,25 +63,6 @@ static struct ctrname { /* List of defined counters */
unsigned long *ccv; /* Per CPU counter value */
} ctrname[MAXCTRS];
/* Open file and extract counter number */
static int read_counter(const char *p)
{
FILE *fp = fopen(p, "r");
int rc = 0, ctr;
if (fp) {
rc = fscanf(fp, "event=%x", &ctr);
fclose(fp);
}
return rc == 1 ? ctr : -EINVAL;
}
static int add_countername(char *name, int nr)
{
ctrname[nr].name = strdup(name);
return ctrname[nr].name ? 0 : -ENOMEM;
}
static bool read_counternames(void)
{
struct dirent **namelist = NULL;
@@ -96,13 +78,12 @@ static bool read_counternames(void)
}
for (i = 0; i < count && ctr >= 0; i++) {
util_asprintf(&ctrpath, "%s/%s", path, namelist[i]->d_name);
ctr = read_counter(ctrpath);
if (util_file_read_va(ctrpath, "event=%x", &ctr) == 1)
ctrname[ctr].name = util_strdup(namelist[i]->d_name);
else
warnx("Cannot parse %s", ctrpath);
free(ctrpath);
if (ctr >= 0)
ctr = add_countername(namelist[i]->d_name, ctr);
}
if (ctr < 0)
warnx("Cannot parse %s", path);
util_scandir_free(namelist, count);
free(path);
return ctr < 0 ? false : true;
@@ -375,6 +356,8 @@ static void line(char *header)
putchar(',');
printf("%ld", ctrname[i].total);
comma = true;
ctrname[i].total = 0;
ctrname[i].hitcnt = false;
}
putchar('\n');
}
@@ -465,7 +448,7 @@ static bool add_countervalue(size_t idx, unsigned int cpu, unsigned long value)
ctrname[idx].ccv = calloc(max_possible_cpus,
sizeof(unsigned long));
if (ctrname[idx].ccv)
ctrname[idx].ccv[cpu] += value;
ctrname[idx].ccv[cpu] = value;
ctrname[idx].total += value;
ctrname[idx].hitcnt = true;
return true;
@@ -477,10 +460,8 @@ static int test_read(struct s390_hwctr_read *read)
size_t offset = 0;
/* Clear previous hit counters */
for (unsigned int i = 0; i < max_possible_cpus; ++i) {
check[i].sets_hit = 0;
for (unsigned int i = 0; i < max_possible_cpus; ++i)
check[i].cpu_hit = false;
}
/* Iterate over all CPUs */
for (unsigned int i = 0; i < read->no_cpus; ++i) {

View File

@@ -1,11 +1,11 @@
\" lscpumf.1
\" lscpumf.8
.\"
.\"
.\" Copyright IBM Corp. 2014, 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.
.\" ----------------------------------------------------------------------
.TH lscpumf "1" "May 2020" "s390-tools" "CPU-MF management programs"
.TH lscpumf "8" "May 2022" "s390-tools" "CPU-MF management programs"
.
.ds c \fBlscpumf\fP
.

View File

@@ -1,4 +1,4 @@
.\" lshwc.1
.\" lshwc.8
.\"
.\"
.\" Copyright IBM Corp. 2021
@@ -7,7 +7,7 @@
.\" ----------------------------------------------------------------------
.ds c \fBlshwc\fP
.
.TH \*c "1" "February 2021" "s390-tools" "CPU-MF management programs"
.TH \*c "8" "May 2022" "s390-tools" "CPU-MF management programs"
.
.SH NAME
\*c \- extract CPU Measurement Facilities counter sets
@@ -130,5 +130,5 @@ Date,Time,CPU,PROBLEM_STATE_CPU_CYCLES(32),PROBLEM_STATE_INSTRUCTIONS(33)
.ft
.fi
.SH "SEE ALSO"
.BR lscpumf (1)
.BR lscpumf (8)
.BR chcpumf (8)

268
cpumf/man/pai.8 Normal file
View File

@@ -0,0 +1,268 @@
.\" pai.8
.\"
.\"
.\" 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.
.\" ----------------------------------------------------------------------
.ds c \fBpai\fP
.
.TH \*c "8" "May 2022" "s390-tools" "PAI Management Programs"
.
.SH NAME
\*c \- record and report Processor Activity Instrumentation (PAI) counters
.
.SH SYNOPSIS
\*c
.RB [ \-V ][ \-m | \-\-mapsize
.IR size ]
.RB [ \-i | \-\-interval
.IR ms ]
.BR \-c | \-\-crypto [ \fIcpulist ][: \fIdata\fR "] [" \fIloops\fP ]
.br
\*c
.RB [ \-V ][ \-m | \-\-mapsize
.IR size ]
.RB [ \-i | \-\-interval
.IR ms ]
.BR \-n | \-\-nnpa [ \fIcpulist ][: \fIdata\fR "] [" \fIloops\fP ]
.br
\*c
.RB [ \-V ][ \-H | \-\-humantime ][ \-S | \-\-summary "] " \-r | \-\-report " [" \fIfiles\fP ]
.br
\*c
.BR \-h | \-\-help
.br
\*c
.BR \-v | \-\-version
.
.
.SH DESCRIPTION
\*c
counters tally calls for specific CPU instructions.
The \*c command records PAI counters in a ring buffer.
\*c can record counter data for all CPUs or for selected CPUs.
The main command options are
.B \-c
for recording cryptographic CPU instructions,
.B \-n
for recording NNPA CPU instructions
and
.B \-r
for reporting.
If all three options are omitted, option
.B \-r
is assumed and a message is printed.
Recording stores data, by CPU, in files
.I paicrypto.<XXX>,
for option
.B \-c
or
.I painnpa.<XXX>,
for option
.B \-n
where <XXX> specifies the CPU number with leading
zeros.
The files are created in the working directory,
existing files are overwritten.
Reporting evaluates files that are created by recording.
.SH OPTIONS
.TP
.BR \-c ", " \-\-crypto "\fR[\fIcpulist\fR][:\fIdata\fR]"
Records data for all (default) or a specified list of CPUs.
The CPU list is a comma-separated list of CPU numbers and ranges.
In a range, a hyphen separates the first CPU number
from the last CPU number.
By default \*c lists all CPUs.
.RS
The optional data specification
follows the colon
and determines additional collection of data.
The specification consists of alphabetic
characters that can be upper or lower case:
.IP c|C
Include task rename system calls
.B exec
and
.BR prctl .
.IP f|F
Include task creation and deletion system calls
.B fork
and
.BR exit .
.IP s|S
Include context switch records created by the kernel scheduler.
.IP k|K
Include only PAI cryptographic counters changed during system call
execution.
.IP u|U
Include only PAI cryptographic counters changed during user space
execution.
.RE
.
.TP
.BR \-n ", " \-\-nnpa "\fR[\fIcpulist\fR][:\fIdata\fR]"
Records data for all (default) or a specified list of CPUs.
The CPU list is a comma-separated list of CPU numbers and ranges.
In a range, a hyphen separates the first CPU number
from the last CPU number.
By default \*c lists all CPUs.
.RS
The optional data specification
follows the colon
and determines additional collection of data.
The specification consists of alphabetic
characters that can be upper or lower case:
.IP c|C
Include task rename system calls
.B exec
and
.BR prctl .
.IP f|F
Include task creation and deletion system calls
.B fork
and
.BR exit .
.IP s|S
Include context switch records created by the kernel scheduler.
.RE
.
.TP
.BR \-r ", " \-\-report
Generates a report from the specified files.
Files is a list of blank-separated file names.
If no files are specified,
uses all files named
.I paicrypto.<X>,
in the working directory, where
.I <X>
is a CPU number that
identifies the CPU for which the data was recorded.
.
.TP
.BR \-h ", " \-\-help
Displays help information, then exits.
.
.TP
.BR \-v ", " \-\-version
Displays version information, then exits.
.
.TP
.BR \-V ", " \-\-verbose
Displays the following information during reporting:
the file name and the hexadecimal offset for each sample header.
Displays the following information during recording:
the read position in the ring buffer,
the file name, and the hexadecimal offset for each sample header.
.
.TP
.BR \-H ", " \-\-humantime
Changes the time stamp format for sample entries from a hexadecimal
number to a human readable <seconds>.<nanoseconds> format.
The time stamp specifies the elapsed time since Linux was booted.
.
.TP
.BR \-S ", " \-\-summary
Prints a summary of counter names and
counter numbers with non-zero values.
The summary is the last line in the command output.
It shows the sum of the counter values of all processed files.
.
.TP
.BR \-i ", " \-\-interval "\ ms"
Specifies the waiting time,
in milliseconds,
between ring buffer read operations during recording.
The default is 1000 milliseconds.
Argument
.B loops
is an integer that specifies the number of
read operations during recording. The default is 1.
.
.TP
.BR \-m ", " \-\-mapsize "\ size"
Specifies the size of the ring buffer
that holds the collected data.
The value specifies the number of 4 KB pages
to be allocated and must be a power of 2.
The default size is 512 pages.
The ring buffer is created with the
.IR mmap (2)
system call.
.
.SH ARGUMENT
The command line options determine how command line
arguments are interpreted.
For option
.B \-c
to start recording, the argument specifies
the number of read operations.
If omitted, the default is one.
For option
.B \-r
to start reporting, the argument specifies
the file names to be read.
If omitted all files in the current directory
with file name
.I paicryto.<X>
are read.
.SH "Concurrency with perf tool"
The following concurrency restrictions apply
for \*c and the
.B perf
tool.
Both tools use the
.IR perf_event_open ()
system call and use the same device driver.
The device driver supports limited concurrency:
.IP Counting:
Counting pai events can run in parallel.
.IP Sampling:
Only one sampling event pai_crypto/CRYPTO_ALL can be active at any one time.
If a sampling event is active, no pai counting event can be active.
Both tools stop with an error message if they detect a collision
reported by the device driver.
.SH "EXAMPLES"
This example collects cryptographic counter on CPU 0.
The program runs for 10 seconds
(10 intervals of 1000 milliseconds).
.sp 1
.nf
.ft CW
# \*c -c0 10
.ft R
.fi
.sp 1
This example displays the data
that is collected in the first example.
Each data line shows the time stamp in jiffies,
followed by the CPU number,
the event number,
process and thread identifier (pid/tid) separated by slash (/),
and a comma-separated list of counter number, colon (:),
and the counter value n hexadecimal notation.
.sp 1
.nf
.ft CW
# \*c -r
0x62a668f2fa 0 event 4096 sample pid 4956/4956 9:0xa7,73:0x8,74:0x18
0x6319c75653 0 event 4096 sample pid 4972/4972 32:0x1
0x6319e2ddee 0 event 4096 sample pid 4972/4972 32:0x1
0x631d3e44f5 0 event 4096 sample pid 4972/4972 32:0x2
0x631d4cfc2e 0 event 4096 sample pid 4972/4972 32:0x3
0x631d529fdd 0 event 4096 sample pid 4972/4972 32:0x2
0x631d84cfa0 0 event 4096 sample pid 4972/4972 73:0x1
0x636e9826bc 0 event 4096 sample pid 4984/4984 9:0xa7,73:0x8,74:0x18
0x636f81a137 0 event 4096 sample pid 4984/4984 9:0x2,74:0x7
0x6378026e54 0 event 4096 sample pid 4984/4984 73:0x2
0x637bcdc8da 0 event 4096 sample pid 4984/4984 73:0x2
0x637bd426cd 0 event 4096 sample pid 4984/4984 73:0x6
0x637c503384 0 event 4096 sample pid 4984/4984 73:0x2
0x64991d83ba 0 event 4096 sample pid 5026/5026 9:0xb0,73:0x8,74:0x18
#
.ft R
.fi
.sp 1
.SH "SEE ALSO"
perf(1)

1125
cpumf/pai.c Normal file

File diff suppressed because it is too large Load Diff

105
cpumf/pai.h Normal file
View File

@@ -0,0 +1,105 @@
/*
* pai - Extract CPU Processor Activity Instrumentation (PAI) facility data.
*
* 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 PAI_H
#define PAI_H
#define S390_EVT_PAI_CRYPTO 0x1000
enum { /* Event attribute specifications */
S390_EVTATTR_CTX_SWITCH = 1,
S390_EVTATTR_COMM = 2,
S390_EVTATTR_FORK = 4,
S390_EVTATTR_USERSPACE = 8,
S390_EVTATTR_KERNELSPACE = 16
};
struct pai_event {
struct util_list_node node; /* List node */
struct perf_event_attr attr; /* Perf_event_open(2) attr */
int fd; /* Perf event file descriptor */
void *map_addr; /* Sampling data mapping address */
size_t map_size; /* Sampling size mapping size */
char file_name[16]; /* File name of sampled data */
int file_fd; /* Map data output file descriptor */
int cpu; /* Perf_event_open(2) CPU */
unsigned long flags; /* Perf_event_open(2) flags */
};
struct pai_event_out { /* Output for CRYPTO_ALL event */
__u32 type; /* Header type, see PERF_RECORD_xxx */
__u16 misc; /* Header misc, value depends on type */
__u64 time; /* Time stamp valid for all entries */
__u32 cpu; /* CPU number valid for all entries */
union {
/* Fields from PERF_RECORD_FORK|EXIT */
struct {
__u32 pid, ppid;
__u32 tid, ptid;
__u64 time;
} s_fork;
/* Fields from PERF_RECORD_COMM */
struct {
__u32 pid, tid;
__u8 cmd[16];
} s_comm;
/* Fields from PERF_RECORD_SWITCH_CPU_WIDE */
struct {
__u32 next_prev_pid, next_prev_tid;
} s_cs;
/* Fields from PERF_RECORD_LOST_SAMPLES */
struct {
__u64 lost;
} s_lost;
/* Relevant fields from PERF_RECORD_SAMPLE, time and cpu
* are stored above
*/
struct {
__u64 ip;
__u64 period;
__u32 pid, tid;
} s_sample;
/* Fields from PERF_RECORD_[UN]THROTTLE */
struct {
__u64 time;
__u64 id;
__u64 stream_id;
} s_throttle;
} u;
/* Information on last context switch out */
struct cs_switch {
unsigned char valid;
__u32 topid, totid;
__u32 frompid, fromtid;
} cs_switch;
void *raw; /* Pointer to key/value array for crypto counters */
};
struct data_pos { /* Perf event mapped ring buffer */
__u64 data_head; /* Head in the data section */
__u64 data_tail; /* User-space written tail */
__u64 data_offset; /* Where the buffer starts */
__u64 data_size; /* Data buffer size */
};
struct event_name { /* Event list for number to name xlate */
char *name; /* Event name */
__u64 config; /* Event config value */
__u64 total; /* Total counter value */
};
struct pmu_events { /* Event list for PMU number to name xlate */
struct util_list_node node; /* List node */
char *name; /* PMU name */
int type; /* PMU type */
int lstlen; /* # of entries in lst */
unsigned long base; /* Base event number */
struct event_name *lst; /* List of event names */
};
#endif /* PAI_H */

View File

@@ -1107,8 +1107,8 @@ static void dasdfmt_write_labels(volume_label_t *vlabel,
} else {
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
- sizeof(vlabel->volkey)));
rc = write(fd, (void *)vlabel + sizeof(vlabel->volkey),
(sizeof(*vlabel) - sizeof(vlabel->volkey)));
}
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&

View File

@@ -47,7 +47,7 @@ Print DASD uid without z/VM minidisk token
z/VM may provide an additional token that can be used to distinguish
between different minidisks (see --extended-uid option). To remain
compatibile with systems that were installed on older Linux or z/VM
compatible with systems that were installed on older Linux or z/VM
levels, the -u option will print the uid excluding any z/VM-provided
minidisk token.

View File

@@ -29,6 +29,7 @@
#include "lib/dasd_sys.h"
#include "lib/libzds.h"
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_sys.h"
@@ -1788,10 +1789,8 @@ dasdview_print_format1(unsigned int size, unsigned char *dumpstr)
for (i = 0; i < size; i++) {
if ((i / 16) * 16 == i) {
printf("\n| ");
strncpy(asc, (char *)dumpstr + i, 16);
strncpy(ebc, (char *)dumpstr + i, 16);
asc[16] = '\0';
ebc[16] = '\0';
util_strlcpy(asc, (char *)dumpstr + i, 16);
util_strlcpy(ebc, (char *)dumpstr + i, 16);
}
printf("%02X", dumpstr[i]);
if (((i + 1) / 4) * 4 == i + 1)
@@ -1822,8 +1821,8 @@ dasdview_print_format2(unsigned int size, unsigned char *dumpstr,
begin + (unsigned long long)i,
begin + (unsigned long long)i);
strncpy(asc, (char *)dumpstr + i, 8);
strncpy(ebc, (char *)dumpstr + i, 8);
util_strlcpy(asc, (char *)dumpstr + i, 8);
util_strlcpy(ebc, (char *)dumpstr + i, 8);
}
printf("%02X", dumpstr[i]);
if (((i + 1) / 4) * 4 == i + 1)

View File

@@ -1,89 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: cpacfstatsd
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Should-Start:
# Should-Stop:
# Default-Start: 2 3 5
# Default-Stop: 0 1 6
# Short-Description: Start the cpacfstatsd daemon for Linux on System z
# Description: CPACF statistics collection daemon process for Linux on System z
### END INIT INFO
DAEMON=cpacfstatsd
DAEMON_PATH=/usr/sbin/cpacfstatsd
RUN_PID_FILE=/run/cpacfstatsd.pid
RETVAL=0
OPTIONS=""
# source function library
. /lib/lsb/init-functions
start()
{
if [ ! -f $RUN_PID_FILE ]; then
echo -n $"Starting $DAEMON:"
$DAEMON_PATH $OPTIONS
if [ $? == "0" ]; then
log_success_msg
else
log_failure_msg
fi
echo
else
echo "$DAEMON (pid $(cat $RUN_PID_FILE)) is already running..."
echo
fi
}
stop()
{
echo -n $"Stopping $DAEMON:"
if [ -f $RUN_PID_FILE ]; then
killproc $DAEMON_PATH -TERM
log_success_msg
rm -f $RUN_PID_FILE
else
log_failure_msg
fi
echo
}
restart() {
stop
sleep 1
start
}
status()
{
if [ ! -f $RUN_PID_FILE ]; then
echo "$DAEMON is not running."
echo
else
echo "$DAEMON (pid $(cat $RUN_PID_FILE)) is running."
echo
fi
}
# How are we called?
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
restart
;;
*)
echo "Usage: $DAEMON {start|stop|status|restart}"
RETVAL=1
esac
exit $RETVAL

View File

@@ -1,116 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: cpuplugd
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start:
# Should-Stop:
# Default-Start: 2 3 5
# Default-Stop: 0 1 6
# Short-Description: Start the cpu hotplug daemon for Linux on System z
# Description: Starts the cpuplugd. It uses the configuration
# file /etc/cpuplugd.conf
### END INIT INFO
# chkconfig: 235 01 99
DAEMON=cpuplugd
DAEMON_PATH=/usr/sbin/cpuplugd
CONFIG_FILE=/etc/cpuplugd.conf
RUN_PID_FILE=/run/cpuplugd.pid
RETVAL=0
OPTIONS="-c $CONFIG_FILE"
# source function library
. /lib/lsb/init-functions
start()
{
if [ ! -f $RUN_PID_FILE ]; then
echo -n $"Starting $DAEMON:"
$DAEMON_PATH $OPTIONS
if [ $? == "0" ]; then
log_success_msg
else
log_failure_msg
fi
echo
else
echo "$DAEMON (pid $(cat $RUN_PID_FILE)) is already running..."
echo
fi
}
stop()
{
echo -n $"Stopping $DAEMON:"
if [ -f $RUN_PID_FILE ]; then
killproc $DAEMON_PATH -TERM
log_success_msg
rm -f $RUN_PID_FILE
else
log_failure_msg
fi
echo
}
restart() {
stop
#
# We have to wait 2-3 seconds here. When the daemon is stopped it takes
# the time we sleep to reactivate cpus. If we restart to fast and
# cpuplugd wasn't able to restore some settings we may get a undesired
# online cpu count after cpuplugd shutdown
#
sleep 4
start
}
status()
{
if [ ! -f $RUN_PID_FILE ]; then
echo "$DAEMON is not running."
echo
else
echo "$DAEMON (pid $(cat $RUN_PID_FILE), options: $OPTIONS) is running."
echo
fi
}
reload()
{
echo -n $"Reloading $DAEMON: "
if [ -f $RUN_PID_FILE ]; then
killproc $DAEMON_PATH -HUP
log_success_msg
else
log_failure_msg
fi
RETVAL=$?
echo
}
# How are we called?
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart)
restart
;;
reload|force-reload)
reload
;;
*)
echo "Usage: $DAEMON {start|stop|status|restart|reload}"
RETVAL=1
esac
exit $RETVAL

View File

@@ -1,161 +0,0 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: mon_statd
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Should-Start:
# Should-Stop:
# Default-Start: 2 3 5
# Default-Stop: 0 1 6
# Short-Description: Configure the mon_fsstatd and mon_procd daemons.
# Description: Configures the mon_fsstatd and mon_procd daemons. It uses the
# configuration file /etc/sysconfig/mon_statd.
### END INIT INFO
# chkconfig: 235 01 99
DAEMON=mon_statd
FSSTATD=mon_fsstatd
PROCD=mon_procd
FSSTATD_PATH=/usr/sbin/$FSSTATD
PROCD_PATH=/usr/sbin/$PROCD
CONFIG_FILE=/etc/sysconfig/$DAEMON
FSSTATD_PID_FILE=/run/$FSSTATD.pid
PROCD_PID_FILE=/run/$PROCD.pid
# source function library
. /lib/lsb/init-functions
# Source config file
if [ -f $CONFIG_FILE ]; then
. $CONFIG_FILE
fi
UDEVSETTLE=/usr/bin/udevadm
if [ ! -e $UDEVSETTLE ]
then
UDEVSETTLE=/sbin/udevsettle
UDEVSETTLE_CALL="$UDEVSETTLE --timeout=10"
else
UDEVSETTLE_CALL="$UDEVSETTLE settle --timeout=10"
fi
load_kernel_module()
{
if [ ! -e /dev/monwriter ]; then
echo "Loading monwriter module..."
modprobe monwriter 2>&1
if [ $? -ne 0 ]; then
exit 1
fi
if [ -e $UDEVSETTLE ]
then
$UDEVSETTLE_CALL
fi
fi
}
start_daemon()
{
local daemon_name=$1
local daemon_interval=$2
local daemon_pid_file=$3
local daemon_path=$4
if [ ! -f $daemon_pid_file ]; then
load_kernel_module
echo -n "Starting $daemon_name:"
$daemon_path -i $daemon_interval
if [ $? -eq 0 ]; then
log_success_msg
else
log_failure_msg
fi
else
echo "$daemon_name (pid $(cat $daemon_pid_file)) is already running..."
fi
}
start()
{
if [ "$FSSTAT" = "yes" ]; then
start_daemon $FSSTATD $FSSTAT_INTERVAL $FSSTATD_PID_FILE \
$FSSTATD_PATH
fi
if [ "$PROC" = "yes" ]; then
start_daemon $PROCD $PROC_INTERVAL $PROCD_PID_FILE \
$PROCD_PATH
fi
}
stop_daemon()
{
local daemon_name=$1
local daemon_pid_file=$2
local daemon_path=$3
echo -n "Stopping $daemon_name:"
if [ -f $daemon_pid_file ]; then
killproc $daemon_path -TERM
log_success_msg
rm -f $daemon_pid_file
else
log_failure_msg
fi
}
stop()
{
if [ "$FSSTAT" = "yes" ]; then
stop_daemon $FSSTATD $FSSTATD_PID_FILE $FSSTATD_PATH
fi
if [ "$PROC" = "yes" ]; then
stop_daemon $PROCD $PROCD_PID_FILE $PROCD_PATH
fi
}
restart() {
stop
start
}
status_daemon()
{
local daemon_name=$1
local daemon_pid_file=$2
local daemon_interval=$3
if [ ! -f $daemon_pid_file ]; then
echo "$daemon_name is not running."
else
echo "$daemon_name (pid $(cat $daemon_pid_file), interval: $daemon_interval) is running."
fi
}
status()
{
status_daemon $FSSTATD $FSSTATD_PID_FILE $FSSTAT_INTERVAL
status_daemon $PROCD $PROCD_PID_FILE $PROC_INTERVAL
}
# How are we called?
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|reload|force-reload)
restart
;;
*)
echo "Usage: $DAEMON {start|stop|status|restart|reload}"
exit 1
esac
exit 0

View File

@@ -15,7 +15,8 @@ ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \
-fno-delete-null-pointer-checks -fno-stack-protector \
-fexec-charset=IBM1047 -m64 -mpacked-stack \
-mstack-size=4096 -mstack-guard=128 -msoft-float \
-Wall -Wformat-security -Wextra -Werror
-Wall -Wformat-security -Wextra -Werror \
-Wno-array-bounds
FILES := stage3a.bin stage3b.bin stage3b_reloc.bin
@@ -74,11 +75,11 @@ stage3b_reloc.elf:
%.elf: %.o
case $* in \
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";; \
stage3a) SFLAGS="-Wl,-T,stage3a.lds";; \
stage3b) SFLAGS="-Wl,-T,stage3b.lds";; \
stage3b_reloc) SFLAGS="-Wl,-estage3b_reloc_start,-Ttext,0";; \
esac; \
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
$(LINK) $$SFLAGS $(NO_PIE_LDFLAGS) -m64 -static -nostdlib $(filter %.o, $^) -o $@
@chmod a-x $@
%.bin: %.elf

View File

@@ -4,8 +4,8 @@ include ../../common.mak
all:
install:
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -m 644 -c genprotimg.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c genprotimg.1 $(DESTDIR)$(MANDIR)/man1
clean:

View File

@@ -2,7 +2,7 @@
.\" s390-tools is free software; you can redistribute it and/or modify
.\" it under the terms of the MIT license. See LICENSE for details.
.\"
.TH GENPROTIMG 8 "November 2020" "s390-tools"
.TH GENPROTIMG 1 "May 2022" "s390-tools"
.SH NAME
genprotimg \- Create a protected virtualization image
@@ -62,7 +62,8 @@ host.
Specifies the certificate that is used to establish a chain of trust
for the verification of the host-key documents. Specify this option
twice to specify the IBM Z signing key and the intermediate CA
certificate (signed by the root CA). Required.
certificate (signed by the root CA).
Required. Ignored if \fB--no-verify\fP is specified.
.TP
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
Specifies the output file. Required.
@@ -91,8 +92,9 @@ 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.
Does not require the host-key documents to be valid.
Do not use for a production image unless you verified
the host-key document before. Optional.
.TP
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
Specifies the encryption key you want to use for the PV guest dump. Use a

View File

@@ -1,9 +1,16 @@
/*
* Copyright IBM Corp. 2020, 2022
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef COMMON_H
#define COMMON_H
#define GETTEXT_PACKAGE "genprotimg"
#include <glib.h>
#include <glib/gi18n-lib.h>
#include <glib/gi18n.h>
#include "boot/linux_layout.h"
#include "boot/s390.h"

View File

@@ -280,7 +280,8 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
.arg_data = &args->host_keys,
.description =
_("FILE specifies a host-key document. At least\n" INDENT
"one is required."),
"one is required Specify this option multiple times\n" INDENT
"to enable the image to run on more than one host."),
.arg_description = _("FILE") },
{ .long_name = "cert",
.short_name = 'C',

View File

@@ -447,7 +447,7 @@ static X509_CRL *load_crl_from_bio(BIO *bio)
return g_steal_pointer(&crl);
ERR_clear_error();
rc = BIO_reset(bio);
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
if (rc != 1 && !(rc == 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
return NULL;
/* maybe the CRL is stored in DER format */
@@ -533,7 +533,7 @@ X509 *load_cert_from_file(const char *path, GError **err)
return g_steal_pointer(&cert);
ERR_clear_error();
rc = BIO_reset(bio);
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
if (rc != 1 && !(rc == 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_READ_CERTIFICATE,
_("unable to load certificate: '%s'"), path);
return NULL;

View File

@@ -17,7 +17,7 @@
#include "helper.h"
#include "table.h"
#define SD_DG_INIT_INTERVAL_MS 200
#define SD_DG_INIT_INTERVAL_SEC 1
#define SD_SYS_ID_SIZE 9
/*

View File

@@ -150,7 +150,7 @@ void sd_update(void)
*/
void sd_dg_register(struct sd_dg *dg, int has_core_data)
{
struct timespec ts = {0, SD_DG_INIT_INTERVAL_MS * 1000000};
struct timespec ts = {SD_DG_INIT_INTERVAL_SEC, 0};
struct sd_sys_item *sys_item;
struct sd_cpu_item *cpu_item;
unsigned int i;

185
include/boot/boot_defs.h Normal file
View File

@@ -0,0 +1,185 @@
/*
* Boot and dump related definitions
*
* 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 BOOT_DEFS_H
#define BOOT_DEFS_H
#include <stdint.h>
#include "lib/zt_common.h"
#define ZIPL_MAGIC "zIPL"
#define ZIPL_MAGIC_SIZE 4
/*
* ECKD dump parameter
*/
struct eckd_dump_param {
uint32_t blk_start;
uint32_t blk_end;
uint16_t blk_size;
uint8_t num_heads;
uint8_t bpt;
char reserved[4];
} __packed;
/*
* FBA dump parameter
*/
struct fba_dump_param {
uint32_t res1;
uint32_t blk_start;
uint32_t res2;
uint32_t blk_end;
} __packed;
/*
* SCSI dump parameter
*/
struct scsi_dump_param {
uint64_t block;
uint64_t reserved;
} __packed;
/*
* Layout of block pointer for linear devices
* e.g. SCSI
*/
struct linear_blockptr {
uint64_t blockno;
uint16_t size;
uint16_t blockct;
uint8_t reserved[4];
} __packed;
/*
* Layout of block pointer for cylinder/head/sector devices
* e.g. ECKD
*/
struct eckd_blockptr {
uint16_t cyl;
uint16_t head;
uint8_t sec;
uint16_t size;
uint8_t blockct;
uint8_t reserved[8];
} __packed;
typedef enum {
COMPONENT_EXECUTE = 0x01,
COMPONENT_LOAD = 0x02,
COMPONENT_SIGNATURE = 0x03
} component_type;
typedef enum {
COMPONENT_HEADER_IPL = 0x00,
COMPONENT_HEADER_DUMP = 0x01
} component_header_type;
struct component_header {
uint8_t magic[4];
uint8_t type;
uint8_t reserved[27];
} __packed;
struct signature_header {
uint8_t format;
uint8_t reserved[3];
uint32_t length;
} __packed;
typedef union {
uint64_t load_address;
uint64_t load_psw;
struct signature_header sig_head;
} component_data;
struct component_entry {
uint8_t data[23];
uint8_t type;
component_data compdat;
} __packed;
/* SCSI dump super block */
struct scsi_dump_sb {
uint64_t magic;
uint64_t version;
uint64_t part_start;
uint64_t part_size;
uint64_t dump_offset;
uint64_t dump_size;
uint64_t csum_offset;
uint64_t csum_size;
uint64_t csum;
} __packed;
#define SCSI_DUMP_SB_MAGIC 0x5a46435044554d50ULL /* ZFCPDUMP */
/* To avoid a csum entry of 0 a seed is used */
#define SCSI_DUMP_SB_SEED 0x12345678
#define SCSI_DUMP_SB_CSUM_SIZE 4096
/* Boot info */
#define BOOT_INFO_VERSION 1
#define BOOT_INFO_MAGIC "zIPL"
#define BOOT_INFO_DEV_TYPE_ECKD 0x00
#define BOOT_INFO_DEV_TYPE_FBA 0x01
#define BOOT_INFO_DEV_TYPE_SCSI 0x02
#define BOOT_INFO_BP_TYPE_IPL 0x00
#define BOOT_INFO_BP_TYPE_DUMP 0x01
#ifdef __s390x__
#define BOOT_INFO_FLAGS_ARCH 0x01
#else
#define BOOT_INFO_FLAGS_ARCH 0x00
#endif
struct boot_info_bp_dump {
union {
struct eckd_dump_param eckd;
struct fba_dump_param fba;
struct scsi_dump_param scsi;
} param;
uint8_t unused[16];
} __packed;
struct boot_info_bp_ipl {
union {
struct eckd_blockptr eckd;
struct linear_blockptr lin;
} bm_ptr;
uint8_t unused[16];
} __packed;
struct boot_info {
char magic[4];
uint8_t version;
uint8_t bp_type;
uint8_t dev_type;
uint8_t flags;
union {
struct boot_info_bp_dump dump;
struct boot_info_bp_ipl ipl;
} bp;
} __packed;
#define DISK_LAYOUT_ID 0x00000001
struct scsi_mbr {
uint8_t magic[4];
uint32_t version_id;
uint8_t reserved[8];
struct linear_blockptr program_table_pointer;
uint8_t reserved2[0x50];
struct boot_info boot_info;
} __packed;
#endif /* BOOT_DEFS_H */

View File

@@ -16,6 +16,8 @@
#define __LC_IPLDEV 0x0c6c
#define __LC_OS_INFO 0x0e18
#define LOWCORE_SIZE _AC(0x2000, UL)
#define PAGE_SIZE _AC(4096, UL)
/* Minimum size of a stack frame in bytes */
@@ -56,6 +58,26 @@ struct psw32_t {
void load_wait_psw(uint64_t, struct psw_t *);
struct subchannel_id {
uint32_t cssid:8;
uint32_t:4;
uint32_t m:1;
uint32_t ssid:2;
uint32_t one:1;
uint32_t sch_no:16;
} __packed __aligned(4);
struct tpi_info {
struct subchannel_id schid;
uint32_t intparm;
uint32_t adapter_IO:1;
uint32_t directed_irq:1;
uint32_t isc:3;
uint32_t:12;
uint32_t type:3;
uint32_t:12;
} __packed __aligned(4);
struct _lowcore {
uint8_t pad_0x0000[0x0014-0x0000]; /* 0x0000 */
uint32_t ipl_parmblock_ptr; /* 0x0014 */
@@ -78,10 +100,15 @@ struct _lowcore {
uint8_t pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */
uint64_t trans_exc_code; /* 0x00a8 */
uint64_t monitor_code; /* 0x00b0 */
uint16_t subchannel_id; /* 0x00b8 */
uint16_t subchannel_nr; /* 0x00ba */
uint32_t io_int_parm; /* 0x00bc */
uint32_t io_int_word; /* 0x00c0 */
union {
struct {
uint16_t subchannel_id; /* 0x00b8 */
uint16_t subchannel_nr; /* 0x00ba */
uint32_t io_int_parm; /* 0x00bc */
uint32_t io_int_word; /* 0x00c0 */
};
struct tpi_info tpi_info; /* 0x00b8 */
};
uint8_t pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */
uint32_t stfl_fac_list; /* 0x00c8 */
uint8_t pad_0x00cc[0x00e8-0x00cc]; /* 0x00cc */
@@ -210,6 +237,7 @@ struct _lowcore {
/* align to the top of the prefix area */
uint8_t pad_0x1900[0x2000-0x1900]; /* 0x1900 */
} __packed __aligned(8192);
STATIC_ASSERT(sizeof(struct _lowcore) == LOWCORE_SIZE)
#define S390_lowcore (*((struct _lowcore *) 0))

95
include/lib/ap.h Normal file
View File

@@ -0,0 +1,95 @@
/*
* libap - A collection of tools for ap/vfio-ap management
*
* 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 LIB_AP_H
#define LIB_AP_H
#include <stdbool.h>
#include "lib/util_list.h"
#define VFIO_AP_PATH "/sys/devices/vfio_ap"
#define VFIO_AP_PARENT_PATH "devices/vfio_ap/matrix"
#define VFIO_AP_CONFIG_PATH "/etc/mdevctl.d/matrix"
#define VFIO_AP_TYPE "vfio_ap-passthrough"
#define AP_UDEV_FILE "/etc/udev/rules.d/41-ap.rules"
#define AP_LOCKFILE "/run/lock/s390apconfig.lock"
#define AP_LOCK_RETRIES 15
/* apmask and aqmask are each represented as 67 character strings with:
* '0x' leading characters
* 64 hex digits (to represent 256 bits)
* terminating character
*/
#define AP_MASK_SIZE 67
#define AP_MAX_MASK_VALUE 255
/* List structure used for keeping track of lists of adapter/domain IDs */
struct vfio_ap_node {
struct util_list_node node; /* prev/next list info */
unsigned int id; /* list entry (adapter, domain, etc) */
};
/*
* Structure used to represent a vfio_ap-passthrough device configuration.
* The list of adapters and domains can be used to derive the APQNs for the
* device. The type value is used to verify that the device (when read from
* a mdevctl config file) is of type vfio_ap-passthrough. The manual value
* represents whether the device is started on-demand after boot (true) or
* automatically during boot (false).
*/
struct vfio_ap_device {
char *uuid; /* Unique ID for this mdev */
struct util_list *adapters; /* List of adapters for device */
struct util_list *domains; /* List of usage domains for device */
struct util_list *controls; /* List of control domains for device */
char *type; /* mdev type string */
bool manual; /* manual/auto start setting for mdev */
};
/* General Utility Functions */
void print_ap_device(struct vfio_ap_device *dev);
bool is_valid_uuid(const char *uuid);
int ap_test_bit(int n, const char *hexbytestr);
void ap_set_bit(int n, char *hexbytestr, bool val);
/* Path-related functions */
char *path_get_vfio_ap_mdev(const char *uuid);
char *path_get_vfio_ap_mdev_config(const char *uuid);
char *path_get_vfio_ap_attr(const char *uuid, const char *attr);
char *path_get_ap_udev(void);
/* Functions for manipulating sysfs to read active device info */
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
/* Functions for reading JSON device config */
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
/* Functions for managing vfio_ap device structures */
struct vfio_ap_device *vfio_ap_device_new(void);
void vfio_ap_device_clear(struct vfio_ap_device *dev);
void vfio_ap_device_free(struct vfio_ap_device *dev);
/* Functions for acquiring current vfio_ap device info */
int ap_read_sysfs_masks(char *ap, char *aq, int size);
bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
bool *read_aq);
void ap_mask_to_list(char *mask, struct util_list *list);
void ap_list_remove_all(struct util_list *list);
/* Lock Functions */
int ap_get_lock(void);
int ap_get_lock_callout(void);
int ap_release_lock(void);
int ap_release_lock_callout(void);
#endif /* LIB_AP_H */

View File

@@ -16,30 +16,48 @@
#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"
#define S390_SYSFS_PAI_CRYPTO "/sys/devices/pai_crypto/"
#define S390_SYSFS_PAI_EXT "/sys/devices/pai_ext/"
#define S390_SYSFS_PAI_NNPA S390_SYSFS_PAI_EXT "events/NNPA_ALL"
/**
* 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
* @retval >=0 Number of PMU assigned by the kernel
* @retval -1 PMU unknown to kernel
*/
int libcpumf_pmutype(const char *dirname);
/**
* Read out the PMU name from a given type.
*
* Return the PMU name this PMU was registered in kernel. If the PMU was
* registered without a name, it is not listed in the directory.
* The caller must free the memory returned by name.
*
* @param[in] wanted_type Type number of the PMU
* @param[out] name Name of the PMU (when retval is 0)
* @retval 0 PMU wanted_type detected and PMU name valid
* @retval -1 No PMU with wanted_type
*/
int libcpumf_pmuname(unsigned int wanted_type, char **name);
/**
* 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
* @retval 0 Successful conversion of cpulist
* @retval -1 Unsuccessful conversion of cpulist
*/
int libcpumf_cpuset(const char *buffer, cpu_set_t *mask);
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
@@ -55,11 +73,16 @@ int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
* @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
* @retval true Information returned in parameters is valid
* @retval false Information could not be retrieved
*/
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth);
/**
* Return true if CPU Measurement Counter Facility is available.
*
* @retval true CPU Measurement Counter Facility is available
* @retval false CPU Measurement Counter Facility is not available
*/
bool libcpumf_have_cpumcf(void);
@@ -77,18 +100,28 @@ bool libcpumf_have_cpumcf(void);
* microsecond
* @param[out] basic_sz Basic sample size in bytes
* @param[out] diag_sz Diagnostic sample size in bytes
* @retval true Information returned in parameters is valid
* @retval false Information could not be retrieved
*/
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.
*
* @retval true CPU Measurement Sampling Facility is available
* @retval false CPU Measurement Sampling Facility is not available
*/
bool libcpumf_have_cpumsf(void);
/**
* Return true if CPU Measurement Sampling Facility buffer sizes are
* available.
*
* @retval true CPU Measurement Sampling Facility buffer sizes are
* available
* @retval false CPU Measurement Sampling Facility buffer sizes are
* not available
*/
bool libcpumf_have_sfb(void);
@@ -101,6 +134,33 @@ bool libcpumf_have_sfb(void);
*
* @param[out] min Minimum supported sampling buffer size
* @param[out] max Maximum supported sampling buffer size
* @retval true Information returned in parameters is valid
* @retval false Information could not be retrieved
*/
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
/**
* Return true if PAI_CRYPTO counter Facility is supported.
*
* @retval true PAI_CRYPTO counter Facility is available
* @retval false PAI_CRYPTO counter Facility is not available
*/
bool libcpumf_have_pai_crypto(void);
/**
* Return true if PAI_EXTENSION Facility is supported.
*
* @retval true PAI_EXTENSION counter Facility is available
* @retval false PAI_EXTENSION counter Facility is not available
*/
bool libcpumf_have_pai_ext(void);
/**
* Return true if PAI_NNPA counter Facility is supported. This PMU facility
* supports the Neural Network Processing Assist (NNPA) counter set.
*
* @retval true PAI_NNPA counter Facility is available
* @retval false PAI_NNPA counter Facility is not available
*/
bool libcpumf_have_pai_nnpa(void);
#endif

View File

@@ -26,6 +26,7 @@ enum util_arch_machine_type {
UTIL_ARCH_MACHINE_TYPE_Z14_ZR1 = 3907,
UTIL_ARCH_MACHINE_TYPE_Z15 = 8561,
UTIL_ARCH_MACHINE_TYPE_Z15_T02 = 8562,
UTIL_ARCH_MACHINE_TYPE_Z16 = 3931,
};
int util_arch_machine_type(void);

View File

@@ -0,0 +1,21 @@
/**
* @defgroup util_exit_code_h util_exit_code: General purpose exit codes
* @{
* @brief General purpose exit codes
*
* 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 LIB_UTIL_EXIT_CODE_H
#define LIB_UTIL_EXIT_CODE_H
typedef enum {
UTIL_EXIT_OK = 0, /* Program finished successfully */
UTIL_EXIT_RUNTIME_ERROR = 15, /* A run-time error occurred */
UTIL_EXIT_OUT_OF_MEMORY = 22, /* Not enough available memory */
} util_exit_code_t;
#endif /** LIB_UTIL_EXIT_CODE_H @} */

View File

@@ -11,6 +11,8 @@
#ifndef LIB_UTIL_FILE_H
#define LIB_UTIL_FILE_H
#include "lib/util_exit_code.h"
int util_file_read_line(char *str, size_t size, const char *fmt, ...);
int util_file_read_i(int *val, int base, const char *fmt, ...);
int util_file_read_l(long *val, int base, const char *fmt, ...);
@@ -26,4 +28,10 @@ int util_file_write_ul(unsigned long val, int base, const char *fmt, ...);
int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...);
int util_file_read_va(const char *path, const char *fmt, ...);
util_exit_code_t util_file_read_fd_buf(FILE *fd, void **buffer_ptr,
size_t *size_ptr);
char *util_file_read_fd(FILE *fd, int chomp);
char *util_file_read_text_file(const char *path, int chomp);
#endif /** LIB_UTIL_FILE_H @} */

View File

@@ -0,0 +1,26 @@
/**
* @defgroup util_lockfile_h util_lockfile: File locking utility
* @{
* @brief Create file-based locks
*
* 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 LIB_UTIL_LOCKFILE_H
#define LIB_UTIL_LOCKFILE_H
#define UTIL_LOCKFILE_OK 0 /* Lock acquired/released successfully */
#define UTIL_LOCKFILE_LOCK_FAIL 1 /* Lock already held, ran out of retries */
#define UTIL_LOCKFILE_RELEASE_NONE 2 /* Lock not held */
#define UTIL_LOCKFILE_RELEASE_FAIL 3 /* Lock not held by specified pid */
#define UTIL_LOCKFILE_ERR 4 /* Other, unexpected error conditions */
int util_lockfile_lock(char *lockfile, int retries);
int util_lockfile_parent_lock(char *lockfile, int retries);
int util_lockfile_release(char *lockfile);
int util_lockfile_parent_release(char *lockfile);
#endif /** LIB_UTIL_LOCKFILE_H @} */

44
include/lib/util_udev.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* @defgroup util_udev_h util_udev: UDEV interface
* @{
* @brief Work with UDEV files
*
* 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 LIB_UTIL_UDEV_H
#define LIB_UTIL_UDEV_H
#include <stdbool.h>
#include "lib/util_exit_code.h"
#include "lib/util_list.h"
/* Single key-operator-value entry in a udev rule line.*/
struct util_udev_entry_node {
struct util_list_node node;
char *key;
char *op;
char *value;
};
/* Single udev line in a udev rule file. */
struct util_udev_line_node {
struct util_list_node node;
struct util_list entries;
char *line;
};
/* Udev rule file. */
struct util_udev_file {
struct util_list lines;
};
util_exit_code_t util_udev_read_file(const char *path,
struct util_udev_file **file_ptr);
void util_udev_free_file(struct util_udev_file *file);
void util_udev_file_print(struct util_udev_file *file);
#endif /** LIB_UTIL_UDEV_H @} */

View File

@@ -21,15 +21,21 @@
* Usage example:
* #define IMAGE_ENTRY _AC(0x10000, UL)
*/
#ifndef _AC
#ifdef __ASSEMBLER__
#define _AC(X, TYPE) X
#else
#define _AC(X, TYPE) X##TYPE
#endif
#endif
#ifndef __ASSEMBLER__
#ifndef sizeof_field
#define sizeof_field(type, field) (sizeof((type *)0)->field)
#endif
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
@@ -48,6 +54,10 @@
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
#ifndef ROUNDUP
# define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
#endif
#define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
@@ -60,6 +70,7 @@
#define __may_alias __attribute__((may_alias))
#define __section(x) __attribute__((__section__(#x)))
#define __noinline __attribute__((__noinline__))
#define __big_endian
/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
* __always_inline. Therefore undefine it first to allow the headers
* to be included first.

439
include/libpv/cert.h Normal file
View File

@@ -0,0 +1,439 @@
/*
* Certificate functions and definitions.
*
* 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 LIBPV_CERT_H
#define LIBPV_CERT_H
#include <openssl/x509v3.h>
#include <openssl/err.h>
#include "libpv/common.h"
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
#define PV_IBM_Z_SUBJECT_ORGANIZATIONAL_UNIT_NAME_SUFFIX "Key Signing Service"
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
#define PV_IBM_Z_SUBJECT_STATE "New York"
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
/* Minimum security level for the keys/certificates used to establish a chain of
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
* for details).
*/
#define PV_CERTS_SECURITY_LEVEL 2
/** pv_cert_init:
*
* Should not be called by user.
* Use pv_init() instead which
* calls this function during creation.
*
* Sets up data structures for caching CRLs.
*/
void pv_cert_init(void);
/** pv_cert_cleanup:
*
* Should not be called by user.
* Use pv_cleanup() instead which
* calls this function during creation.
*
* Cleans up data structures for caching CRLs.
*/
void pv_cert_cleanup(void);
#define PV_CERT_ERROR g_quark_from_static_string("pv-cert-error-quark")
typedef enum {
PV_CERT_ERROR_CERT_REVOKED,
PV_CERT_ERROR_CERT_SIGNATURE_INVALID,
PV_CERT_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
PV_CERT_ERROR_CRL_DOWNLOAD_FAILED,
PV_CERT_ERROR_CRL_SIGNATURE_INVALID,
PV_CERT_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
PV_CERT_ERROR_INTERNAL,
PV_CERT_ERROR_INVALID_PARM,
PV_CERT_ERROR_INVALID_SIGNATURE_ALGORITHM,
PV_CERT_ERROR_INVALID_VALIDITY_PERIOD,
PV_CERT_ERROR_LOAD_CRL,
PV_CERT_ERROR_LOAD_DEFAULT_CA,
PV_CERT_ERROR_LOAD_ROOT_CA,
PV_CERT_ERROR_MALFORMED_CERTIFICATE,
PV_CERT_ERROR_MALFORMED_ROOT_CA,
PV_CERT_ERROR_NO_CRL,
PV_CERT_ERROR_NO_CRLDP,
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
PV_CERT_ERROR_NO_PUBLIC_KEY,
PV_CERT_ERROR_READ_CERTIFICATE,
PV_CERT_ERROR_READ_CRL,
PV_CERT_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
PV_CERT_ERROR_SKID_AKID_MISMATCH,
PV_CERT_ERROR_VERIFICATION_FAILED,
PV_CERT_ERROR_WRONG_CA_USED,
} PvCertErrors;
/** PvX509WithPath - X509 certificate associated with a path
*/
typedef struct {
X509 *cert;
char *path;
} PvX509WithPath;
/** pv_x509_with_path_new:
*
* @cert: X509 certificate
* @path: Path of that X509 certificate
*
* Returns: (nullable) (transfer full): new X509 with path
*/
PvX509WithPath *pv_x509_with_path_new(X509 *cert, const char *path);
/** pv_x509_with_path_free:
*
* Frees the path and the PvX509WithPath; Decreases the refcount of the X509
*/
void pv_x509_with_path_free(PvX509WithPath *cert);
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
typedef STACK_OF(X509) STACK_OF_X509;
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
typedef GSList PvCertWithPathList;
typedef struct {
X509 *cert;
STACK_OF_X509_CRL *crls;
} PvX509Pair;
/** pv_x509_pair_new_take:
* @cert: ptr to X509
* @crls: ptr to CRLs
*
* Takes a X509 and the associated CRLs and builds a pair.
* Both, *cert and *crls will be NULL afterwards, and owned by the pair.
*
* Returns: (nullable) (transfer full): New PvX509Pair
*/
PvX509Pair *pv_x509_pair_new_take(X509 **cert, STACK_OF_X509_CRL **crls);
/** pv_x509_pair_free:
*
* Decreases the refcount of the X509 and crls.
* Frees the PvX509Pair.
*/
void pv_x509_pair_free(PvX509Pair *pair);
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
void STACK_OF_X509_free(STACK_OF_X509 *stack);
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
/** pv_x509_from_pem_der_data:
*
* @data: GBytes containing the cert in PEM format
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): X509 cert
*/
X509 *pv_x509_from_pem_der_data(GBytes *data, GError **error);
/** pv_x509_get_ec_pubkey:
*
* @cert: X509 to extract elliptic curve pubkey from
* @nid: numerical identifier of the expected curve
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): corresponding pupkey for the given certificate
*/
EVP_PKEY *pv_x509_get_ec_pubkey(X509 *cert, int nid, GError **error);
/** pv_get_ec_pubkeys:
*
* @certs_with_path: List of PvX509WithPath
* @nid: numerical identifier of the expected curve
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): List of corresponding public keys for the given certificate
*/
GSList *pv_get_ec_pubkeys(PvCertWithPathList *certs_with_path, int nid, GError **error);
/* pv_load_certificates:
*
* @cert_paths: list of cert paths.
* @error: return location for a #GError
*
* @cert_paths must contain at least one element, otherwise an error is
* reported.
*
* Returns: (nullable) (transfer full): List of PvX509WithPath corresponding to the given paths
*/
PvCertWithPathList *pv_load_certificates(char **cert_paths, GError **error);
/* pv_load_first_cert_from_file:
*
* @path: location of the x509
* @error: return location for a #GError
*
* This function reads in only the first certificate and ignores all other. This
* is only relevant for the PEM file format. For the host-key document and the
* root CA this behavior is expected.
*
* Returns: (nullable) (transfer full): PvX509WithPath corresponding to the given path
*/
X509 *pv_load_first_cert_from_file(const char *path, GError **error);
/* pv_load_first_crl_from_file:
*
* @path: location of the x509 CRL
* @error: return location for a #GError
*
* This function reads in only the first CRL and ignores all other. This
* is only relevant for the PEM file format.
*
* Returns: (nullable) (transfer full): X509_CRL corresponding to the given path
*/
X509_CRL *pv_load_first_crl_from_file(const char *path, GError **error);
/** pv_store_setup_crl_download:
*
* @st: X509_STORE
*/
void pv_store_setup_crl_download(X509_STORE *st);
/** pv_load_first_crl_by_cert:
* @cert: X509 to specify the download location.
* @error: return location for a #GError
*
* This function returns the first X509_CRL found from the CRL distribution
* points specified in @cert.
*
* Returns: (nullable) (transfer full): x509 CRL corresponding to the given X509
*/
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error);
/** pv_try_load_crls_by_certs:
*
* @certs_with_path: List of PvX509WithPath
*
* Returns: (nullable) (transfer full): Stack of CRLs corresponding to the given X509
*/
STACK_OF_X509_CRL *pv_try_load_crls_by_certs(PvCertWithPathList *certs_with_path);
/** pv_store_setup:
*
* @root_ca_path: Location of the rootCA or NULL if SystemRoot CA shall be used
* @crl_paths: List of CRL paths or NULL
* @cert_with_crl_paths: List of (untrusted) X509 paths
* @error: return location for a #GError
*
* The untrusted certs need to be verified before actually verifying a Host Key Document.
*
* Returns: (nullable) (transfer full): X509_store with given input data.
*
*/
X509_STORE *pv_store_setup(char *root_ca_path, char **crl_paths, char **cert_with_crl_paths,
GError **error);
/** pv_get_x509_stack:
*
* x509_with_path_list: list of PvX509WithPath
*
* Returns: (nullable) (transfer full): Stack of X509 corresponding to the given x509 with path
*/
STACK_OF_X509 *pv_get_x509_stack(const GSList *x509_with_path_list);
/** pv_init_store_ctx:
*
* @ctx: a uninitialized Store CTX
* @trusted: X509_STORE with a trusted rootCA
* @chain: untrusted X509s
* @error: return location for a #GError
*
* Can be called multiple times on the same context if X509_STORE_CTX_cleanup(ctx)
* was called before.
*
* Returns:
* 0 on success
* -1 in failure
*/
int pv_init_store_ctx(X509_STORE_CTX *ctx, X509_STORE *trusted, STACK_OF_X509 *chain,
GError **error) PV_NONNULL(1, 2, 3);
/** pv_init_store_ctx:
*
* @trusted: X509_STORE with a trusted rootCA
* @chain: untrusted X509s
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): X509_STORE_CTX setup with the input data
*/
X509_STORE_CTX *pv_create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain, GError **error)
PV_NONNULL(1, 2);
/** pv_remove_ibm_signing_certs:
*
* @certs: Stack of X509s
*
* Returns: (transfer full):
* List of all IBM Z signing key certificates in @certs and remove them
* from the chain.
* Empty stack if no IBM Z signing key is found.
*/
STACK_OF_X509 *pv_remove_ibm_signing_certs(STACK_OF_X509 *certs);
/** pv_c2b_name:
*
* Workaround to fix the mismatch between issuer name of the
* IBM Z signing CRLs and the IBM Z signing key subject name.
*
* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
* ordered. The problem is that our certificates are not consistent in the order
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
*
* This function tries to reorder the name attributes such that
* further OpenSSL calls can work with it. The caller is
* responsible to free the returned value.
*/
X509_NAME *pv_c2b_name(const X509_NAME *name);
/** pv_verify_host_key:
*
* @host_key: X509 to be verified
* @issuer_pairs: IBM signing key X509+CRLs Pairs used for verification
* @level: Security level. see PV_CERTS_SECURITY_LEVEL
* @error: return location for a #GError
*
* Returns:
* 0 if Host key could be verified with one of the IBM signing keys
* -1 if no IBM signing key could verify the authenticity of the given host key
*
*/
int pv_verify_host_key(X509 *host_key, GSList *issuer_pairs, int verify_flags, int level,
GError **error);
/** pv_verify_cert:
*
* @ctx: trusted store ctx used for verification
* @cert: X509 to be verified
* @error: return location for a #GError
*
* Cannot be used to verify host keys with IBM signing keys, as IBM signing
* keys are no intermediate CAs. Use pv_verify_host_key() instead.
*
* Returns:
* 0 if @cert could be verified
* -1 if @cert could not be verified
*/
int pv_verify_cert(X509_STORE_CTX *ctx, X509 *cert, GError **error) PV_NONNULL(1, 2);
/** pv_check_crl_valid_for_cert:
*
* @crl: CRL to be verified
* @cert: Cert that probably issued the given CRL
* @verify_flags: X509 Verification flags (X509_V_FLAG_<TYPE>)
* @error: return location for a #GError
*
* Verify whether a revocation list @crl is valid and is issued by @cert. For
* this multiple steps must be done:
*
* 1. verify issuer of the CRL matches with the suject name of @cert
* 2. verify the validity period of the CRL
* 3. verify the signature of the CRL
*
* Important: This function does not verify whether @cert is allowed to issue a
* CRL.
*
* Returns:
* 0 if @crl is valid and issued by @cert
* -1 otherwise
*/
int pv_verify_crl(X509_CRL *crl, X509 *cert, int verify_flags, GError **error);
/** pv_check_chain_parameters:
*
* @chain: chain of trust to be validated
* @error: return location for a #GError
*
* Verifies that chain has at least a RootCA ans intermediate CA
* and logs the used ROD CA subject
*
* Returns:
* 0 @chain is valid
* -1 otherwise
*/
int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error);
/** pv_store_set_verify_param:
*
* @store: X509_STORE to set parameters
* @error: return location for a #GError
*
* Returns:
* 0 on success
* -1 on failure
*/
int pv_store_set_verify_param(X509_STORE *store, GError **error);
/** pv_store_ctx_find_valid_crls:
*
* @ctx: STORE_CTX for searching CRLs
* @cert: X509 to match CRLs aggainst
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): STACK of CRLs related to given @crl fin @ctx
*/
STACK_OF_X509_CRL *pv_store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert, GError **error)
PV_NONNULL(1, 2);
/** pv_verify_host_key_doc:
*
* @host_key_certs_with_path: X509s to be verified
* @trusted. X509_STORE with a rusted RootCA
* @untrusted_certs: STACK OF untrusted X509s
* @online: true if CRLs shall be downloaded
* @error: return location for a #GError
*
* Returns:
* 0 if all given HKDs could be verified using the chain of trust.
* -1 otherwise
*/
int pv_verify_host_key_doc(PvCertWithPathList *host_key_certs_with_path, X509_STORE *trusted,
STACK_OF_X509 *untrusted_certs, gboolean online, GError **error)
PV_NONNULL(1, 2, 3);
/** pv_verify_host_key_docs_by_path:
*
* @host_key_paths: locations of X509 to be verified
* @optional_root_ca_path: rootCA location or NULL if Default shall be used
* @optional_crl_paths: locations of CRLs or NULL
* @untrusted_cert_paths: locations of IntermediateCAs including the IBM signing key
* @online: true if CRLs shall be downloaded
* @error: return location for a #GError
*
* Returns:
* 0 if all given HKDs could be verfied using the chain of trust.
* -1 otherwise
*/
int pv_verify_host_key_docs_by_path(char **host_key_paths, char *optional_root_ca_path,
char **optional_crl_paths, char **untrusted_cert_paths,
gboolean online, GError **error) PV_NONNULL(1, 4);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509WithPath, pv_x509_with_path_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509Pair, pv_x509_pair_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
#endif /* LIBPV_CERT_H */

35
include/libpv/common.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* Libpv common definitions.
*
* 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 LIBPV_COMMON_H
#define LIBPV_COMMON_H
/* must be included before any (other) glib header to verify that
* the glib version is supported
*/
#include "libpv/glib-helper.h"
#include <glib/gi18n.h>
#include "libpv/openssl-compat.h"
#include "libpv/macros.h"
/** pv_init:
*
* Must be called before any libpv call.
*/
int pv_init(void);
/** pv_cleanup:
*
* Must be called when done with using libpv.
*/
void pv_cleanup(void);
#endif /* LIBPV_COMMON_H */

202
include/libpv/crypto.h Normal file
View File

@@ -0,0 +1,202 @@
/*
* General cryptography helper functions and definitions
*
* 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 LIBPV_CRYPTO_H
#define LIBPV_CRYPTO_H
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include "libpv/common.h"
typedef struct pv_cipher_parms {
const EVP_CIPHER *cipher;
size_t tag_size;
GBytes *key;
union {
GBytes *iv;
GBytes *tweak;
};
} PvCipherParms;
typedef union {
struct {
uint8_t x[80];
uint8_t y[80];
};
uint8_t data[160];
} PvEcdhPubKey;
G_STATIC_ASSERT(sizeof(PvEcdhPubKey) == 160);
typedef GSList PvEvpKeyList;
enum PvCryptoMode {
PV_ENCRYPT,
PV_DECRYPT,
};
/** pv_get_openssl_errors:
*
* Returns the last OpenSSL error messages.
* Caller is responsible to free the returned value.
*
* Returns: String representing the error.
*/
char *pv_get_openssl_errors(void);
/**
* pv_BIO_reset:
* @b: BIO to reset
*
* Resets a BIO to its initial state.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_BIO_reset(BIO *b);
/**
* pv_generate_rand_data:
* @size: number of generated random bytes using a crypographically secure pseudo random generator
* @error: return location for a #GError
*
* Creates a new #GBytes with @size random bytes using a cryptographically
* secure pseudo random generator.
*
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
*/
GBytes *pv_generate_rand_data(size_t size, GError **error);
/**
* pv_generate_key:
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure key should be generated
* @error: return location for a #GError
*
* Creates a random key for @cipher using a cryptographically secure pseudo
* random generator.
*
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
*/
GBytes *pv_generate_key(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
/**
* pv_generate_iv:
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure IV should be generated
* @error: return location for a #GError
*
* Creates a random IV for @cipher using a cryptographically secure pseudo
* random generator.
*
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
*/
GBytes *pv_generate_iv(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
/* Symmetric en/decryption functions */
/**
* pv_gcm_encrypt:
* @plain: data to encrypt
* @aad: (optional): additional data that should be authenticated with the key
* @parms:
* @cipher: (out): location to store the ciphertext
* @tag: (out): location to store the generated GCM tag
* @error: return location for a #GError
*
* Encrypts the @plain data and authenticates @aad data.
*
* Returns: number of bytes, or -1 in case of an error
*/
int64_t pv_gcm_encrypt(GBytes *plain, GBytes *aad, const PvCipherParms *parms, GBytes **cipher,
GBytes **tag, GError **error) PV_NONNULL(1, 3, 4, 5);
/**
* pv_gcm_decrypt:
* @cipher: ciphertext to decrypt
* @aad: (optional): additional date to authenticate
* @tag: the GCM tag
* @parms:
* @plain: (out): location to store the decrypted data
* @error: return location for a #GError
*
* Decrypts the @cipher data and authenticates the @aad data.
*
* Returns: number of bytes, or -1 in case of an error
*/
int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherParms *parms,
GBytes **plain, GError **error) PV_NONNULL(1, 3, 4, 5);
/** pv_hkdf_extract_and_expand:
* @derived_key_len: size of the output key
* @key: input key
* @salt: salt for the extraction
* @info: infor for the expansion
* @md: EVP mode of operation
* @error: return location for a #GError
*
* Performs a RFC 5869 HKDF.
*
* Returns: (nullable) (transfer full): Result of RFC 5869 HKDF
*
*/
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
const EVP_MD *md, GError **error) PV_NONNULL(2, 3, 4, 5);
/** pv_generate_ec_key:
*
* @nid: Numerical identifier of the curve
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): new random key based on the given curve
*/
EVP_PKEY *pv_generate_ec_key(int nid, GError **error);
/** pv_evp_pkey_to_ecdh_pub_key:
*
* @key: input key in EVP_PKEY format
* @error: return location for a #GError
*
* Returns: the public part of the input @key in ECDH format.
*/
PvEcdhPubKey *pv_evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **error) PV_NONNULL(1);
/** pv_derive_exchange_key:
* @cust: Customer Key
* @host: Host key
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): Shared Secret of @cust and @host
*/
GBytes *pv_derive_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **error) PV_NONNULL(1, 2);
GQuark pv_crypto_error_quark(void);
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
typedef enum {
PV_CRYPTO_ERROR_DERIVE,
PV_CRYPTO_ERROR_HKDF_FAIL,
PV_CRYPTO_ERROR_INTERNAL,
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
PV_CRYPTO_ERROR_KEYGENERATION,
PV_CRYPTO_ERROR_RANDOMIZATION,
PV_CRYPTO_ERROR_READ_FILE,
PV_CRYPTO_ERROR_NO_MATCH_TAG,
} PvCryptoErrors;
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
#endif /* LIBPV_CRYPTO_H */

53
include/libpv/curl.h Normal file
View File

@@ -0,0 +1,53 @@
/*
* Libcurl utils
*
* 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 LIBPV_CURL_H
#define LIBPV_CURL_H
#include <curl/curl.h>
#include "libpv/common.h"
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
#define CRL_DOWNLOAD_MAX_SIZE 0x100000
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
/** curl_download:
* @url: URL to specify location of data
* @timeout_ms: time to wait until fail
* @max_size: Maximum size of the downloaded data
* @error: return location for a GError
*
* Returns: (nullable) (transfer full): Downloaded data as #GByteArray
*/
GByteArray *curl_download(const char *url, long timeout_ms, uint max_size, GError **err);
/** pv_curl_init:
*
* Should not be called by user.
* Use pv_init() instead which
* calls this function during creation.
*/
int pv_curl_init(void);
/** pv_curl_cleanup:
*
* Should not be called by user.
* Use pv_cleanup() instead which
* calls this function during creation.
*/
void pv_curl_cleanup(void);
#define PV_CURL_ERROR g_quark_from_static_string("pv-curl-error-quark")
typedef enum {
PV_CURL_ERROR_CURL_INIT_FAILED,
PV_CURL_ERROR_DOWNLOAD_FAILED,
} PvCurlErrors;
#endif /* LIBPV_CURL_H */

120
include/libpv/glib-helper.h Normal file
View File

@@ -0,0 +1,120 @@
/*
* Glib convenience functions
* Shall be used instead of manually including glib.
*
* 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 LIBPV_GLIB_HELPER_H
#define LIBPV_GLIB_HELPER_H
#if defined(GLIB_VERSION_MIN_REQUIRED)
#if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_56
#error "GLIB_VERSION must be at least 2.56"
#endif
#else
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_56
#endif
#include <glib.h>
#include <gmodule.h>
#include <stdio.h>
#include "libpv/macros.h"
#ifdef __clang__
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
DO_PRAGMA(clang diagnostic push) \
DO_PRAGMA(clang diagnostic ignored "-Wunused-function") \
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__) \
DO_PRAGMA(clang diagnostic pop)
#else
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
#endif
#define pv_wrapped_g_assert(__expr) g_assert(__expr)
/** pv_sec_gbytes_new_take:
*
* #g_bytes_new_take() with secure cleanup
*/
GBytes *pv_sec_gbytes_new_take(void *data, size_t size);
/** pv_sec_gbytes_new:
*
* #g_bytes_new() with secure cleanup
*/
GBytes *pv_sec_gbytes_new(const void *data, size_t size);
/** pv_file_get_content_as_secure_bytes:
*
* @filename: path to file for reading in
*
* read file and save as secure gbytes
*
* Return:
* Content of file as #GBytes with secure cleanup
*/
GBytes *pv_file_get_content_as_secure_bytes(const char *filename);
/** pv_file_get_content_as_g_bytes:
*
* @filename: path to file for reading in
*
* read file and save as gbytes
*
* Return:
* Content of file as #GBytes
*/
GBytes *pv_file_get_content_as_g_bytes(const char *filename, GError **error);
/** pv_file_seek:
*
* fseek with error reporting
*/
int pv_file_seek(FILE *file, long offset, int whence, GError **error);
/** pv_file_write:
*
* fwrite with error reporting
*/
size_t pv_file_write(FILE *file, const void *ptr, size_t size, GError **error);
/** pv_file_close:
*
* fclose with error reporting
*/
long pv_file_close(FILE *file, GError **error);
/** pv_file_tell:
*
* ftell with error reporting
*/
long pv_file_tell(FILE *file, GError **error);
/** pv_file_open:
*
* fopen with error reporting
*/
FILE *pv_file_open(const char *filename, const char *mode, GError **error);
/** pv_gbytes_memcpy:
*
* memcpy with size check. In case @dst_size is smaller than the size of @src
* the error value %NULL is returned and @copied and @dst are left unchanged.
*
* If @dst and @src data overlap, the behavior is undefined.
*/
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src, size_t *copied);
#define PV_GLIB_HELPER_ERROR g_quark_from_static_string("pv-glib-helper_error-quark")
typedef enum {
PV_GLIB_HELPER_FILE_ERROR,
} pv_glib_helper_error_e;
void pv_auto_close_file(FILE *file);
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(FILE, pv_auto_close_file)
#endif /* LIBPV_GLIB_HELPER_H */

119
include/libpv/hash.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* Hashing definitions.
*
* 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 LIBPV_HASH_H
#define LIBPV_HASH_H
#include <openssl/hmac.h>
#include "libpv/common.h"
/** pv_digest_ctx_new:
* @md: mode of digest, e.g. #EVP_sha256()
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): a new #EVP_MD_CTX, or %NULL in case of an error
*/
EVP_MD_CTX *pv_digest_ctx_new(const EVP_MD *md, GError **error);
/** pv_digest_ctx_update:
* @ctx: EVP_MD_CTX to add data
* @data: #GBytes to add to the context
* @error: return location for a #GError
*
* Adds @data to the digest context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_digest_ctx_update(EVP_MD_CTX *ctx, GBytes *data, GError **error);
/** pv_digest_ctx_update_raw:
* @ctx: #EVP_MD_CTX to add data
* @buf: data to add to the context
* @size: size of @buf
* @error: return location for a #GError
*
* Adds @buf to the digest context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_digest_ctx_update_raw(EVP_MD_CTX *ctx, const uint8_t *buf, size_t size, GError **error);
/** pv_digest_ctx_finalize:
* @ctx: #EVP_MD_CTX with data to digest
* @error: return location for a #GError
*
* Calculates the digest of all previously added data. Do not use @ctx afterwards.
*
* Returns: (nullable) (transfer full): Digest of all data added before as #GBytes, or NULL in case of error.
*/
GBytes *pv_digest_ctx_finalize(EVP_MD_CTX *ctx, GError **error);
/** pv_sha256_hash:
* @buf: data for which a sha256 hash sould be calculated
* @size: size of @buf
* @error: return location for a #GError
*
* Shorthand for initializing a sha256-digest ctx, updating, and finalizing.
*
* Returns: (nullable) (transfer full): SHA256 of @buf as #GBytes, or NULL in case of error.
*/
GBytes *pv_sha256_hash(uint8_t *buf, size_t size, GError **error);
/** pv_hmac_ctx_new:
* @key: key used for the HMAC
* @md: mode of digest, e.g. #EVP_sha512()
* @error: return location for a #GError
*
* Returns: (nullable) (transfer full): New #HMAC_CTX or NULL in case of error
*/
HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error);
/** pv_hmac_ctx_update_raw:
* @ctx: #HMAC_CTX to add data
* @buf: data to add to the context
* @size: size of @buf
* @error: return location for a #GError
*
* Adds @buf to the HMAC context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *data, size_t size, GError **error);
/** pv_hmac_ctx_update:
* @ctx: #HMAC_CTX to add data
* @data: #GBytes to add to the context
* @error: return location for a #GError
*
* Adds @data to the HMAC context. Can be called multiple times.
*
* Returns: 0 in case of success, -1 otherwise.
*/
int pv_hmac_ctx_update(HMAC_CTX *ctx, GBytes *data, GError **error);
/** pv_hmac_ctx_finalize:
* @ctx: #HMAC_CTX with data to digest
* @error: return location for a #GError
*
* Calculates the HMAC of all previously added data. Do not use @ctx afterwards.
*
* Returns: (nullable) (transfer full): HMAC of all data added before as #GBytes, or NULL in case of error.
*/
GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error);
#define PV_HASH_ERROR g_quark_from_static_string("pv-crypro-error-quark")
typedef enum {
PV_HASH_ERROR_INTERNAL,
} PvHashErrors;
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(HMAC_CTX, HMAC_CTX_free)
#endif /* LIBPV_HASH_H */

21
include/libpv/macros.h Normal file
View File

@@ -0,0 +1,21 @@
/*
* Libpv common macro definitions.
*
* 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 LIBPV_MACROS_H
#define LIBPV_MACROS_H
#include <stdint.h>
#define PV_NONNULL(...)
#define DO_PRAGMA(x) _Pragma(#x)
/* Most significant bit */
#define PV_MSB(idx) ((uint64_t)1 << (63 - (idx)))
#endif /* LIBPV_MACROS_H */

View File

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

96
include/libpv/se-hdr.h Normal file
View File

@@ -0,0 +1,96 @@
/*
* PV/SE header definitions
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#ifndef LIBPV_SE_HDR_H
#define LIBPV_SE_HDR_H
#include "libpv/common.h"
#include <openssl/sha.h>
#include "boot/s390.h"
#include "libpv/crypto.h"
#include "libpv/macros.h"
/* Magic number which is used to identify the file containing the PV
* header
*/
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
#define PV_VERSION_1 0x00000100U
/* Plaintext control flags */
/* dumping of the configuration is allowed */
#define PV_PCF_ALLOW_DUMPING PV_MSB(34)
/* prevent Ultravisor decryption during unpack operation */
#define PV_PCF_NO_DECRYPTION PV_MSB(35)
/* PCKMO encrypt-DEA/TDEA-key functions allowed */
#define PV_PCF_PCKMO_DEA_TDEA PV_MSB(56)
/* PCKMO encrypt-AES-key functions allowed */
#define PV_PCF_PCKMO_AES PV_MSB(57)
/* PCKMO encrypt-ECC-key functions allowed */
#define PV_PCF_PCKM_ECC PV_MSB(58)
/* maxima for the PV version 1 */
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
#define PV_V1_PV_HDR_MIN_SIZE \
(sizeof(struct pv_hdr_head) + sizeof(struct pv_hdr_encrypted) + \
sizeof(((struct pv_hdr *)0)->tag) + 1 * sizeof(struct pv_hdr_key_slot))
#define PV_V1_PV_HDR_MAX_SIZE (2 * PAGE_SIZE)
#define PV_IMAGE_ENCR_KEY_SIZE 64
typedef struct pv_hdr_key_slot {
uint8_t digest_key[SHA256_DIGEST_LENGTH];
uint8_t wrapped_key[32];
uint8_t tag[16];
} __packed PvHdrKeySlot;
typedef struct pv_hdr_opt_item {
uint32_t otype;
uint8_t ibk[32];
uint8_t data[];
} __packed PvHdrOptItem;
/* integrity protected data (by GCM tag), but non-encrypted */
struct pv_hdr_head {
uint64_t magic;
uint32_t version;
uint32_t phs;
uint8_t iv[12];
uint32_t res1;
uint64_t nks;
uint64_t sea;
uint64_t nep;
uint64_t pcf;
PvEcdhPubKey cust_pub_key;
uint8_t pld[SHA512_DIGEST_LENGTH];
uint8_t ald[SHA512_DIGEST_LENGTH];
uint8_t tld[SHA512_DIGEST_LENGTH];
} __packed;
/* Must not have any padding */
struct pv_hdr_encrypted {
uint8_t cust_comm_key[32];
uint8_t img_enc_key_1[PV_IMAGE_ENCR_KEY_SIZE / 2];
uint8_t img_enc_key_2[PV_IMAGE_ENCR_KEY_SIZE / 2];
struct psw_t psw;
uint64_t scf;
uint32_t noi;
uint32_t res2;
};
G_STATIC_ASSERT(sizeof(struct pv_hdr_encrypted) == 32 + 32 + 32 + sizeof(struct psw_t) + 8 + 4 + 4);
typedef struct pv_hdr {
struct pv_hdr_head head;
struct pv_hdr_key_slot *slots;
struct pv_hdr_encrypted *encrypted;
struct pv_hdr_opt_item **optional_items;
uint8_t tag[16];
} PvHdr;
#endif /* LIBPV_SE_HDR_H */

View File

@@ -139,8 +139,20 @@ the same as 0.0.5000).
.BR "\-L" " or " "\-\-loadparm"
Specifies an entry in the
.BR zipl (8)
boot menu. If this option is omitted, the default menu entry is used.
boot menu, and an active namespace in the installed zIPL environment block
for evaluation of zIPL environment variables in the kernel command line.
This option requires an argument, which has to be a string of the form
"nSX", where optional number 'n' indicates the boot menu entry, and optional
token 'SX' specifies the active namespace. This token consists of a mandatory
leading capital 'S' and of an optional trailing character 'X', which is
either any decimal digit, indicating ID of the active site, or a capital 'S'.
In the last case, ID of the active namespace is determined as the SSID
(Subchannel Set ID).
If the menu entry is omitted in the argument, then the default menu entry
is used. If the 'X' is omitted, or the whole token 'SX' is omitted, then the
common namespace of the installed zIPL environment block will be activated.
.TP
.BR "\-c" " or " "\-\-clear"
Specify whether memory should be cleared on re-IPL. Possible values are 0 to
@@ -158,9 +170,11 @@ loadparm:
\fB# chreipl ccw 0.0.7e78\fP
2. Next time reboot from the CCW device with the bus-ID 0.0.7e78
using the first entry of the zipl boot menu:
using the first entry of the zipl boot menu and the second site namespace
in the installed zIPL environment block for evaluation of zIPL environment
variables in the kernel command line:
\fB# chreipl ccw -d 0.0.7e78 -L 1\fP
\fB# chreipl ccw -d 0.0.7e78 -L 1S2\fP
.SH fcp
Use the fcp re-IPL target for SCSI disks that are accessed by the hardware
using Fibre Channel Protocol (FCP) channels.
@@ -306,4 +320,5 @@ that you would otherwise have to specify with the ccw or fcp target.
.BR lsreipl (8),
.BR zipl (8),
.BR zipl.conf (5),
.BR zipl-editenv (8)
.BR reboot (8)

View File

@@ -62,7 +62,7 @@ extern ssize_t __write(int, const void*, size_t);
extern int strmatch(const char *, const char *);
extern int is_regex_valid(const char *);
extern int is_client_allowed(const char *, const struct iucvterm_cfg *);
extern void userid_cpy(char [8], const char [8]);
extern void userid_cpy(char [9], const char [8]);
extern void iucv_msg_error(const char *, uint32_t);
extern void program_error(const char *, const char *);

26
libap/Makefile Normal file
View File

@@ -0,0 +1,26 @@
include ../common.mak
lib = libap.a
check-dep-json:
touch check-dep-json
ifneq (${HAVE_JSONC},0)
$(call check_dep, \
"libap", \
"json-c/json.h", \
"json-c-devel", \
"HAVE_JSONC=0")
ALL_CPPFLAGS += -DHAVE_JSONC
endif
all: $(lib)
objects = ap.o
$(lib): $(objects)
$(objects): check-dep-json
install: all
clean:
rm -f *.o check-dep-lock check-dep-json $(lib)

739
libap/ap.c Normal file
View File

@@ -0,0 +1,739 @@
/*
* libap - A collection of tools for ap/vfio-ap management
*
* 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 <ctype.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef HAVE_JSONC
#include <json-c/json.h>
#endif /* HAVE_JSONC */
#include "lib/ap.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_lockfile.h"
#include "lib/util_panic.h"
#include "lib/util_path.h"
#include "lib/util_udev.h"
/*
* Return sysfs path to a bus attribute
* Note: caller is responsible for freeing the returned string
*/
static char *path_get_bus_attr(const char *bus, const char *attr)
{
return util_path_sysfs("bus/%s/%s", bus, attr);
}
/*
* Compare two vfio_ap nodes based upon their id value. Return:
* -1: a < b
* 1: a > b
* 0: a == b
*/
static int vfio_ap_node_cmp(void *a, void *b, void *UNUSED(data))
{
struct vfio_ap_node *a_node = a, *b_node = b;
if (a_node->id < b_node->id)
return -1;
return (a_node->id > b_node->id);
}
static void vfio_ap_node_add_tail(struct util_list *list, unsigned int val)
{
struct vfio_ap_node *node = util_zalloc(sizeof(struct vfio_ap_node));
node->id = val;
util_list_add_tail(list, node);
}
/* Remove duplicate entries from a sorted vfio_ap_node list */
static void vfio_ap_node_remove_dupes(struct util_list *list)
{
struct vfio_ap_node *node, *check, *next;
util_list_iterate(list, node) {
/* Remove any subsequent duplicates */
check = util_list_next(list, node);
while (check) {
next = util_list_next(list, check);
if (node->id == check->id) {
util_list_remove(list, check);
free(check);
}
check = next;
}
}
}
static bool starts_with(const char *str, const char *s)
{
size_t len = strlen(s);
return (strncmp(str, s, len) == 0);
}
/*
* Pass a comma-delimited string of IDs (adapter, domains or control domains)
* and add these IDs to the input list. The resulting list will be sorted
* and duplicates removed before returning.
*/
static void modify_device_attr(struct util_list *list, char *value)
{
unsigned int val;
char *curr;
curr = strtok(value, ",");
if (curr == NULL)
return;
/* Create list from input setting */
while (curr != NULL) {
val = strtol(curr, NULL, 0);
vfio_ap_node_add_tail(list, val);
curr = strtok(NULL, ",");
}
/* Cleanup the list */
util_list_sort(list, vfio_ap_node_cmp, NULL);
vfio_ap_node_remove_dupes(list);
}
static void load_attr_to_device(struct vfio_ap_device *dev, char *attr,
const char *value)
{
char *v = util_strdup(value);
if (strcmp(attr, "assign_adapter") == 0)
modify_device_attr(dev->adapters, v);
else if (strcmp(attr, "assign_domain") == 0)
modify_device_attr(dev->domains, v);
else if (strcmp(attr, "assign_control_domain") == 0)
modify_device_attr(dev->controls, v);
free(v);
}
/**
* Print the contents of the vfio-ap device struct to stderr. Used for
* debugging.
*
* @param[in] dev vfio-ap device strcucture to print
*/
void print_ap_device(struct vfio_ap_device *dev)
{
struct vfio_ap_node *node;
warnx("Device %s:", dev->uuid);
warnx("Type: %s", dev->type);
if (dev->manual)
warnx("Start: MANUAL");
else
warnx("Start: AUTO");
if (util_list_is_empty(dev->adapters)) {
warnx("Adapters: (none)");
} else {
warnx("Adapters:");
util_list_iterate(dev->adapters, node) {
warnx(" %u", node->id);
}
}
if (util_list_is_empty(dev->domains)) {
warnx("Domains: (none)");
} else {
warnx("Domains:");
util_list_iterate(dev->domains, node) {
warnx(" %u", node->id);
}
}
if (util_list_is_empty(dev->controls)) {
warnx("Controls: (none)");
} else {
warnx("Controls:");
util_list_iterate(dev->controls, node) {
warnx(" %u", node->id);
}
}
}
/**
* Determine if the input string is a valid Universally Unique Identifier
*
* @param[in] uuid Character string to inspect
*
* @retval true Specified string is a valid UUID
* @retval false Specified string is not a valid UUID
*/
bool is_valid_uuid(const char *uuid)
{
uint32_t s1, s2, s3, s4;
uint64_t s5;
char d;
return (strlen(uuid) == 36 && sscanf(uuid, "%8x-%4x-%4x-%4x-%12x %c",
&s1, &s2, &s3, &s4,
(unsigned int *) &s5, &d) == 5);
}
/*
* For an input string of hex characters, find the nth character and return its
* numeric value to the caller.
*/
static int get_hexbyte_value(int n, const char *hexbytestr)
{
int i = 0, v = 0;
char c;
if (strncmp(hexbytestr, "0x", 2) == 0)
i = 2;
/*
* The specified mask is only valid if it includes at least 64 hex
* digits. The specified mask may optionally include a leading '0x'
*/
util_assert((strlen(hexbytestr) >= (size_t)(AP_MASK_SIZE - i - 1)),
"Invalid hex string provided for mask: %s", hexbytestr);
c = hexbytestr[i + n / 4];
if (c >= '0' && c <= '9')
v = c - '0';
else if (c >= 'a' && c <= 'f')
v = 10 + c - 'a';
else if (c >= 'A' && c <= 'F')
v = 10 + c - 'A';
else
util_assert(false, "Could not parse hex digit '%c'", c);
return v;
}
/**
* For an input hex string, determine if the specified nth bit is ON or OFF.
*
* @param[in] n Bit number to test
* @param[in, out] hexbytestr Character string of hex characters
*
* @retval 0 Specified bit is OFF
* @retval != 0 Specified bit is ON
*/
int ap_test_bit(int n, const char *hexbytestr)
{
int v;
v = get_hexbyte_value(n, hexbytestr);
return v & (1 << (3 - (n % 4)));
}
/**
* For an input hex string, set the nth bit true/false
*
* @param[in] n Bit number to set
* @param[in, out] hexbytestr Character string of hex characters
* @param[in] val Bit is to be set ON (true) or OFF (false)
*/
void ap_set_bit(int n, char *hexbytestr, bool val)
{
char c = 0;
int v, m, i = 0;
v = get_hexbyte_value(n, hexbytestr);
/* Calculate the bit mask */
m = (1 << (3 - (n % 4)));
/* Return if bit already at correct value */
if (((val) && ((v & m) != 0)) || (!val && ((v & m) == 0)))
return;
if (val)
v = v + m;
else
v = v - m;
if (v < 10)
c = '0' + v;
else if (v >= 10 && v <= 15)
c = 'a' + (v - 10);
else
util_assert(false, "Could not set bit value '%d'", v);
if (strncmp(hexbytestr, "0x", 2) == 0)
i = 2;
/* Set the new value */
hexbytestr[i + n / 4] = c;
}
/**
* Return sysfs path to vfio_ap mdev
* Note: caller is responsible for freeing the returned string
*
* @param[in] uuid Character string containing an mdev UUID
*
* @retval != 0 sysfs path for a vfio-ap device with this UUID
*/
char *path_get_vfio_ap_mdev(const char *uuid)
{
return util_path_sysfs("%s/%s", VFIO_AP_PARENT_PATH, uuid);
}
/**
* Return path to mdevctl config file for specified UUID
* Note: caller is responsible for freeing the returned string
*
* @param[in] uuid Character string containing an mdev UUID
*
* @retval != 0 config file path for vfio-ap device with this UUID
*/
char *path_get_vfio_ap_mdev_config(const char *uuid)
{
char *path;
util_asprintf(&path, "%s/%s", VFIO_AP_CONFIG_PATH, uuid);
return path;
}
/**
* Return sysfs path to vfio_ap mdev attribute (matrix, remove, ...)
* Note: caller is responsible for freeing the returned string
*
* @param[in] uuid Character string containing an mdev UUID
* @param[in] attr Character string containing device attribute name
*
* @retval != 0 sysfs path to specified attribute for this device
*/
char *path_get_vfio_ap_attr(const char *uuid, const char *attr)
{
return util_path_sysfs("%s/%s/%s", VFIO_AP_PARENT_PATH, uuid, attr);
}
/**
* Return path to ap udev config file
* Note: caller is responsible for freeing the returned string
*
* @retval != 0 path to the ap udev config file
*/
char *path_get_ap_udev(void)
{
char *path;
util_asprintf(&path, "%s", AP_UDEV_FILE);
return path;
}
/**
* Take one line from the active 'matrix' attribute and parse it
* into a list of adapters and domains. Each line of the 'matrix'
* attribute is presented as a "adapter.domain" (e.g. "03.0005") where the
* numeric values are always hexadecimal.
* In a case where no adapters are assigned, a valid string might be ".0005"
* In a case where no domains are assigned, a valid string might be "03."
*
* @param[in, out] dev Vfio-ap struct that will be updated
* @param[in] matrix Character string to parse
*/
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix)
{
char *curr;
int val;
if (!matrix)
return;
if (*matrix != '.') {
/* Handle a device with adapters */
curr = strtok(matrix, ".");
val = strtol(curr, NULL, 16);
vfio_ap_node_add_tail(dev->adapters, val);
curr = strtok(NULL, "\n");
} else {
/* Handle a device with no adapters */
curr = strtok(matrix + 1, "\n");
}
/* Leave now if the device has no domains */
if (!curr)
return;
/* Get the domain */
val = strtol(curr, NULL, 16);
vfio_ap_node_add_tail(dev->domains, val);
}
/**
* Function to sort the results of repeated vfio_ap_parse_matrix calls
*
* @param[in, out] dev Vfio-ap struct whose lists will be sorted
*/
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev)
{
/* Sort the lists for later use */
util_list_sort(dev->adapters, vfio_ap_node_cmp, NULL);
util_list_sort(dev->domains, vfio_ap_node_cmp, NULL);
/* Run the lists and delete duplicates */
vfio_ap_node_remove_dupes(dev->adapters);
vfio_ap_node_remove_dupes(dev->domains);
}
/**
* Take the string provided by the active 'control_domains' attribute and
* parse it into a list of control domains
*
* @param[in, out] dev Vfio-ap struct that will be updated
* @param[in] control Character string to parse
*/
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control)
{
char *curr;
int val;
curr = strtok(control, "\n");
while (curr != NULL) {
val = strtol(curr, NULL, 16);
vfio_ap_node_add_tail(dev->controls, val);
curr = strtok(NULL, "\n");
}
}
#ifdef HAVE_JSONC
/**
* For a given path, read in the contents. If no path is provided, get the
* input from stdin instead.
*
* @param[in] path Path to mdevctl config file
* @param[in, out] dev Vfio-ap struct that will be updated
*
* @retval 0 Config read successfully, dev updated
* @retval -1 Failed to read config, dev may have partial info
*/
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev)
{
json_object *root, *type, *start, *attrs, *attr;
int i, len, rc = 0;
const char *val;
if (path == NULL)
root = json_object_from_fd(STDIN_FILENO);
else
root = json_object_from_file(path);
if (root == NULL)
return -1;
if (json_object_object_get_ex(root, "mdev_type", &type)) {
val = json_object_get_string(type);
if (!val)
goto err;
dev->type = util_strdup(val);
if (strcmp(val, "vfio_ap-passthrough") != 0)
goto err;
}
if (json_object_object_get_ex(root, "start", &start)) {
val = json_object_get_string(start);
if (!val)
goto err;
if (strcmp(val, "auto") == 0)
dev->manual = false;
else if (strcmp(val, "manual") == 0)
dev->manual = true;
else
goto err;
}
if (json_object_object_get_ex(root, "attrs", &attrs)) {
len = json_object_array_length(attrs);
for (i = 0; i < len; i++) {
attr = json_object_array_get_idx(attrs, i);
json_object_object_foreach(attr, key, setting) {
val = json_object_get_string(setting);
load_attr_to_device(dev, key, val);
}
}
}
out:
json_object_put(root);
return rc;
err:
rc = -1;
goto out;
}
#else
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev)
{
return -1;
}
#endif /* HAVE_JSONC */
/**
* Allocate and initialize a vfio-ap device structure.
*
* @retval !=0 Address of the new vfio-ap device structure
*/
struct vfio_ap_device *vfio_ap_device_new(void)
{
struct vfio_ap_device *dev;
dev = util_zalloc(sizeof(struct vfio_ap_device));
dev->manual = false;
dev->type = NULL;
dev->uuid = NULL;
dev->adapters = util_list_new(struct vfio_ap_node, node);
dev->domains = util_list_new(struct vfio_ap_node, node);
dev->controls = util_list_new(struct vfio_ap_node, node);
return dev;
}
/**
* Re-initialize a vfio-ap device structure, leaving the structure allocated.
*
* @param[in, out] dev Vfio-ap struct that will be re-initialized
*/
void vfio_ap_device_clear(struct vfio_ap_device *dev)
{
if (dev == NULL)
return;
dev->manual = false;
if (dev->type) {
free(dev->type);
dev->type = NULL;
}
if (dev->uuid) {
free(dev->uuid);
dev->uuid = NULL;
}
ap_list_remove_all(dev->adapters);
ap_list_remove_all(dev->domains);
ap_list_remove_all(dev->controls);
}
/**
* Clear and release a vfio-ap device structure.
*
* @param[in, out] dev Vfio-ap struct that will be freed
*/
void vfio_ap_device_free(struct vfio_ap_device *dev)
{
if (dev == NULL)
return;
vfio_ap_device_clear(dev);
util_list_free(dev->adapters);
util_list_free(dev->domains);
util_list_free(dev->controls);
free(dev);
}
static int read_sysfs_mask(const char *path, char *mask, int size)
{
return util_file_read_line(mask, size, "%s", path);
}
/**
* Get the apmask and aqmask from sysfs
*
* @param[in, out] ap Buffer to hold apmask contents
* @param[in, out] aq Buffer to hold aqmask contents
* @param[in] size Size of the mask buffers
*
* @retval 0 Both mask values read successfully
* @retval != 0 Failed to read one or both mask values
*/
int ap_read_sysfs_masks(char *ap, char *aq, int size)
{
char *path;
int rc = 0;
path = path_get_bus_attr("ap", "apmask");
rc = read_sysfs_mask(path, ap, size);
free(path);
if (rc != 0)
goto out;
path = path_get_bus_attr("ap", "aqmask");
rc = read_sysfs_mask(path, aq, size);
free(path);
out:
return rc;
}
/**
* Get the apmask and aqmask from udev, falling back to sysfs if a udev rule
* is not available or does not provide values for both masks.
* The values in read_ap and read_aq tell the caller whether each mask was
* successfully loaded from udev or if the sysfs value was substituted
* Note: both ap and aq must point to a string that is at least AP_MASK_SIZE
* in length.
*
* @param[in] path Path to the ap udev file
* @param[in, out] ap Buffer to hold apmask contents
* @param[in, out] aq Buffer to hold aqmask contents
* @param[out] read_ap Specifies if an apmask value was read from udev
* @param[out] read_aq Specifies if an aqmask value was read from udev
*
* @retval true Udev file read successfully or did not exist
* @retval false Udev file exists but error was encountered
*/
bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
bool *read_aq)
{
struct util_udev_entry_node *entry;
struct util_udev_file *file = NULL;
struct util_udev_line_node *line;
char sysap[AP_MASK_SIZE];
char sysaq[AP_MASK_SIZE];
int rc;
/* Assume we fail to read both masks */
*read_ap = *read_aq = false;
/* If a udev file doesn't exist, quietly use the active masks */
if (!util_path_exists(path))
goto out;
rc = util_udev_read_file(path, &file);
/* If errors were encountered reading the udev file, exit now */
if (rc)
return false;
util_list_iterate(&file->lines, line) {
entry = util_list_start(&line->entries);
/* Skip comments and empty lines. */
if (!entry)
continue;
if (starts_with(entry->key, "ATTR{")) {
if (strstr(entry->key, "apmask")) {
util_strlcpy(ap, entry->value, AP_MASK_SIZE);
*read_ap = true;
} else if (strstr(entry->key, "aqmask")) {
util_strlcpy(aq, entry->value, AP_MASK_SIZE);
*read_aq = true;
}
}
}
util_udev_free_file(file);
out:
/* If we didn't read in masks, use current sysfs values */
if ((!*read_ap) || (!*read_aq)) {
rc = ap_read_sysfs_masks(sysap, sysaq, AP_MASK_SIZE);
if (rc != 0)
return false;
if (!*read_ap)
strcpy(ap, sysap);
if (!*read_aq)
strcpy(aq, sysaq);
}
return true;
}
/**
* For a given bitmask, create a list of vfio_ap_node entries corresponding
* to the ON bits in the mask.
*
* @param[in] mask Character string of hex characters
* @param[in, out] list List to be updated with entries for each ON bit
*/
void ap_mask_to_list(char *mask, struct util_list *list)
{
int i;
if (mask == NULL || list == NULL)
return;
for (i = 0; i <= AP_MAX_MASK_VALUE; i++) {
if (ap_test_bit(i, mask))
vfio_ap_node_add_tail(list, i);
}
/* Could have duplicates if the input list was not empty */
util_list_sort(list, vfio_ap_node_cmp, NULL);
vfio_ap_node_remove_dupes(list);
}
/**
* For the specified list, remove all elements and free each node
*
* @param[in, out] list List that will have all entries removed
*/
void ap_list_remove_all(struct util_list *list)
{
struct ap_node *node;
while (!util_list_is_empty(list)) {
node = util_list_start(list);
util_list_remove(list, node);
free(node);
}
}
/**
* Acquire the ap config lock using this Process ID
*
* @retval 0 Lock acquired on behalf of this process
*
* @retval != 0 Error, lock was not obtained
*/
int ap_get_lock(void)
{
return util_lockfile_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
}
/**
* Acquire the ap config lock using the Parent Process ID -- intended for use
* by the mdevctl callout ap-check utility
*
* @retval 0 Lock acquired on behalf of parent process
* @retval != 0 Error, lock was not obtained
*/
int ap_get_lock_callout(void)
{
return util_lockfile_parent_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
}
/**
* Release the ap config lock
*
* @retval 0 Lock successfully released or file didn't exist
* @retval != 0 Error removing the lockfile
*/
int ap_release_lock(void)
{
return util_lockfile_release(AP_LOCKFILE);
}
int ap_release_lock_callout(void)
{
return util_lockfile_parent_release(AP_LOCKFILE);
}

View File

@@ -13,7 +13,7 @@ $(lib): $(objects)
install: all
libcpumf_example: libcpumf_example.o $(lib)
libcpumf_example: libcpumf_example.o $(lib) $(rootdir)/libutil/libutil.a
clean:
rm -f *.o $(lib) $(examples)

View File

@@ -14,6 +14,7 @@ int main(void)
{
unsigned long min, max, speed, sfb_min, sfb_max;
int rc, pmu, cfvn, csvn, auth;
char *pmuname;
cpu_set_t set;
pmu = libcpumf_pmutype(S390_CPUMF_CF);
@@ -72,5 +73,18 @@ int main(void)
if (rc)
printf(" sfb_min %lu sfb_max %lu", sfb_min, sfb_max);
putchar('\n');
printf("PAI crypto support %d\n", libcpumf_have_pai_crypto());
rc = libcpumf_pmuname(10, &pmuname);
if (rc) {
printf("PMU type 10 PMU name lookup error %d\n", rc);
} else {
printf("PMU type 10 PMU name %s\n", pmuname);
free(pmuname);
}
printf("PAI NNPA support %d\n", libcpumf_have_pai_nnpa());
printf("PAI EXTENSION support %d\n", libcpumf_have_pai_ext());
return EXIT_SUCCESS;
}

View File

@@ -4,10 +4,16 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_path.h"
#include "lib/util_scandir.h"
#include "lib/libcpumf.h"
int libcpumf_pmutype(const char *dirname)
@@ -31,3 +37,36 @@ int libcpumf_pmutype(const char *dirname)
}
return ret;
}
int libcpumf_pmuname(unsigned int wanted_type, char **name)
{
struct dirent **de_vec;
unsigned int type;
char *dirname;
char *path;
int count;
int rc;
path = util_path_sysfs("devices");
count = util_scandir(&de_vec, alphasort, path, "(pai|cpum_).*");
free(path);
*name = NULL;
for (int i = 0; i < count; i++) {
if (de_vec[i]->d_type == DT_DIR) {
dirname = de_vec[i]->d_name;
path = util_path_sysfs("devices/%s/type", dirname);
rc = util_file_read_ui(&type, 10, path);
if (rc)
warn("Failed to open %s", path);
free(path);
if (!rc && type == wanted_type) {
*name = util_strdup(dirname);
goto out;
}
}
}
out:
util_scandir_free(de_vec, count);
return *name ? 0 : -1;
}

View File

@@ -139,3 +139,24 @@ bool libcpumf_sfb_info(unsigned long *min, unsigned long *max)
fclose(fp);
return rc;
}
bool libcpumf_have_pai_crypto(void)
{
struct stat statbuf;
return (stat(S390_SYSFS_PAI_CRYPTO, &statbuf) == -1) ? false : true;
}
bool libcpumf_have_pai_ext(void)
{
struct stat statbuf;
return (stat(S390_SYSFS_PAI_EXT, &statbuf) == -1) ? false : true;
}
bool libcpumf_have_pai_nnpa(void)
{
struct stat statbuf;
return (stat(S390_SYSFS_PAI_NNPA, &statbuf) == -1) ? false : true;
}

View File

@@ -259,7 +259,7 @@ int kmip_decode_bignum(const unsigned char *data, uint32_t length, BIGNUM **bn)
if (data[0] & 0x80) {
neg = 1;
tmp = malloc(length);
tmp = calloc(1, length);
if (tmp == NULL)
return -ENOMEM;

101
libpv/Makefile Normal file
View File

@@ -0,0 +1,101 @@
# Common definitions
include ../common.mak
.DEFAULT_GOAL := all
LIB := libpv.a
ifneq ($(shell sh -c 'command -v pkg-config'),)
GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto openssl)
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto openssl)
LIBCURL_CFLAGS := $(shell pkg-config --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell pkg-config --silence-errors --libs libcurl)
else
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
GLIB2_LIBS := -lglib-2.0
LIBCRYPTO_CFLAGS :=
LIBCRYPTO_LIBS := -lcrypto -lssl
LIBCURL_CFLAGS := -I/usr/include/s390x-linux-gnu
LIBCURL_LIBS := -lcurl
endif
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
-Wpointer-arith -Wno-error=inline \
-Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \
-Werror \
$(NULL)
ALL_CFLAGS += -std=gnu11 \
-DOPENSSL_API_COMPAT=0x10101000L \
$(GLIB2_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(LIBCURL_CFLAGS) \
$(WARNINGS) \
$(NULL)
BUILD_TARGETS := skip-$(LIB)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_GLIB2},0)
ifneq (${HAVE_LIBCURL},0)
BUILD_TARGETS := $(LIB)
endif
endif
endif
sources := $(wildcard *.c)
objects := $(patsubst %.c,%.o,$(sources))
all: $(BUILD_TARGETS)
$(LIB): $(objects)
$(LIB): ALL_CFLAGS += -fPIC
$(objects): .check-dep-$(LIB)
install: all
clean:
rm -f -- $(objects)
rm -f -- $(LIB)
rm -f -- .check-dep-$(LIB) .detect-openssl.dep.c
skip-$(LIB):
echo " SKIP $(LIB) due to unresolved dependencies"
.PHONY: all install clean skip-$(LIB) install-$(LIB)
.detect-openssl.dep.c:
echo "#include <openssl/evp.h>" > $@
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
echo " #error openssl version 1.1.1 is required" >> $@
echo "#endif" >> $@
echo "static void __attribute__((unused)) test(void) {" >> $@
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
echo " EVP_MD_CTX_free(ctx);" >> $@
echo "}" >> $@
.check-dep-$(LIB): .detect-openssl.dep.c
$(call check_dep, \
"$(LIB)", \
"glib.h", \
"glib2-devel / libglib2.0-dev", \
"HAVE_GLIB2=0")
$(call check_dep, \
"$(LIB)", \
$^, \
"openssl-devel / libssl-dev version >= 1.1.1", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(LIB)", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
touch $@

1654
libpv/cert.c Normal file

File diff suppressed because it is too large Load Diff

45
libpv/common.c Normal file
View File

@@ -0,0 +1,45 @@
/*
* Libpv common functions.
*
* 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.
*
*/
/* Must be included before any other header */
#include "config.h"
#include "libpv/common.h"
#include "libpv/cert.h"
#include "libpv/curl.h"
/* setup and tear down */
int pv_init(void)
{
static size_t openssl_initalized;
if (g_once_init_enter(&openssl_initalized)) {
if (OPENSSL_VERSION_NUMBER < 0x1000100fL)
g_assert_not_reached();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
SSL_library_init();
SSL_load_error_strings();
#else
OPENSSL_init_crypto(0, NULL);
#endif
if (pv_curl_init() != 0)
return -1;
pv_cert_init();
g_once_init_leave(&openssl_initalized, 1);
}
return 0;
}
void pv_cleanup(void)
{
pv_cert_cleanup();
pv_curl_cleanup();
}

15
libpv/config.h Normal file
View File

@@ -0,0 +1,15 @@
/*
* Config file.
* Must be include before any other header.
*
* 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 LIBPV_CONFIG_H
#define LIBPV_CONFIG_H
#define GETTEXT_PACKAGE "libpv"
#endif /* LIBPV_CONFIG_H */

528
libpv/crypto.c Normal file
View File

@@ -0,0 +1,528 @@
/*
* Cryptography functions
*
* 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.
*/
/* Must be included before any other header */
#include "config.h"
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/kdf.h>
#include "lib/zt_common.h"
#include "libpv/crypto.h"
#include "libpv/glib-helper.h"
#include "libpv/hash.h"
char *pv_get_openssl_errors(void)
{
char *ret;
char *buf;
BIO *bio;
long len;
bio = BIO_new(BIO_s_mem());
ERR_print_errors(bio);
len = BIO_get_mem_data(bio, &buf);
if (len <= 0 || !buf)
ret = g_strdup("Cannot receive OpenSSL error message.");
else
ret = g_strndup(buf, (size_t)len);
BIO_free(bio);
return ret;
}
int pv_BIO_reset(BIO *b)
{
int rc = BIO_reset(b);
if (rc != 1 && !(BIO_method_type(b) == BIO_TYPE_FILE && rc == 0))
return -1;
return 1;
}
GBytes *pv_generate_rand_data(size_t size, GError **error)
{
g_autofree uint8_t *data = NULL;
if (size > INT_MAX) {
g_set_error_literal(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_RANDOMIZATION,
"Too many random data requested. Split it up");
OPENSSL_clear_free(data, size);
return NULL;
}
data = g_malloc(size);
if (RAND_bytes(data, (int)size) != 1) {
g_set_error_literal(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_RANDOMIZATION,
"The required amount of random data is not available");
return NULL;
}
return pv_sec_gbytes_new_take(g_steal_pointer(&data), size);
}
GBytes *pv_generate_key(const EVP_CIPHER *cipher, GError **error)
{
int size;
pv_wrapped_g_assert(cipher);
size = EVP_CIPHER_key_length(cipher);
if (size <= 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
"Unknown cipher");
return NULL;
}
return pv_generate_rand_data((guint)size, error);
}
GBytes *pv_generate_iv(const EVP_CIPHER *cipher, GError **error)
{
int size;
pv_wrapped_g_assert(cipher);
size = EVP_CIPHER_iv_length(cipher);
if (size <= 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
"Unknown cipher");
return NULL;
}
return pv_generate_rand_data((guint)size, error);
}
static int64_t pv_gcm_encrypt_decrypt(GBytes *input, GBytes *aad, const PvCipherParms *parms,
GBytes **output, GBytes **tagp, enum PvCryptoMode mode,
GError **error)
{
const uint8_t *in_data, *aad_data = NULL, *iv_data, *key_data;
size_t in_size, aad_size = 0, iv_size, key_size, out_size;
const EVP_CIPHER *cipher = parms->cipher;
const size_t tag_size = parms->tag_size;
gboolean encrypt = mode == PV_ENCRYPT;
g_autoptr(EVP_CIPHER_CTX) ctx = NULL;
g_autofree uint8_t *out_data = NULL;
g_autofree uint8_t *tag_data = NULL;
const GBytes *key = parms->key;
const GBytes *iv = parms->iv;
int cipher_block_size;
int64_t ret = -1;
int len = -1;
GBytes *tag;
g_assert(tagp);
g_assert(cipher);
g_assert(key);
g_assert(iv);
tag = *tagp;
in_data = g_bytes_get_data((GBytes *)input, &in_size);
if (aad)
aad_data = g_bytes_get_data((GBytes *)aad, &aad_size);
iv_data = g_bytes_get_data((GBytes *)iv, &iv_size);
key_data = g_bytes_get_data((GBytes *)key, &key_size);
out_size = in_size;
cipher_block_size = EVP_CIPHER_block_size(cipher);
/* Checks for later casts */
g_assert(aad_size <= INT_MAX);
g_assert(in_size <= INT_MAX);
g_assert(iv_size <= INT_MAX);
g_assert(cipher_block_size > 0);
ctx = EVP_CIPHER_CTX_new();
if (!ctx)
g_abort();
if (tag_size == 0 || (tag_size % (size_t)cipher_block_size != 0)) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"Passed tag size is incorrect");
return -1;
}
/* Has the passed key the correct size? */
if (EVP_CIPHER_key_length(cipher) != (int)key_size) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"Passed key has incorrect size: %ld != %d", key_size,
EVP_CIPHER_key_length(cipher));
return -1;
}
/* First, set the cipher algorithm so we can verify our key/IV lengths
*/
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encrypt) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"EVP_CIPHER_CTX_new failed");
return -1;
}
/* Set IV length */
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)iv_size, NULL) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"EVP_CIPHER_CTX_ex failed");
return -1;
}
/* Initialise key and IV */
if (EVP_CipherInit_ex(ctx, NULL, NULL, key_data, iv_data, encrypt) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"EVP_CipherInit_ex failed");
return -1;
}
/* Allocate output data */
out_data = g_malloc0(out_size);
if (encrypt)
tag_data = g_malloc0(tag_size);
if (aad_size > 0) {
/* Provide any AAD data */
if (EVP_CipherUpdate(ctx, NULL, &len, aad_data, (int)aad_size) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"EVP_CipherUpdate failed");
return -1;
}
g_assert(len == (int)aad_size);
}
/* Provide data to be en/decrypted */
if (EVP_CipherUpdate(ctx, out_data, &len, in_data, (int)in_size) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"EVP_CipherUpdate failed");
return -1;
}
ret = len;
if (!encrypt) {
const uint8_t *tmp_tag_data = NULL;
size_t tmp_tag_size = 0;
if (tag)
tmp_tag_data = g_bytes_get_data(tag, &tmp_tag_size);
if (tag_size != tmp_tag_size) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"Getting the GCM tag failed");
return -1;
}
/* Set expected tag value */
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, (int)tmp_tag_size,
(uint8_t *)tmp_tag_data) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"Setting the GCM tag failed");
return -1;
}
}
/* Finalize the en/decryption */
if (EVP_CipherFinal_ex(ctx, (uint8_t *)out_data + len, &len) != 1) {
if (encrypt)
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"Encrypting failed (EVP_CipherFinal_ex)");
else
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_MATCH_TAG,
"Verifying the GCM tag failed");
return -1;
}
ret += len;
if (encrypt) {
/* Get the tag */
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, (int)tag_size, tag_data) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
"Getting the GCM tag failed");
return -1;
}
g_assert(!*tagp);
*tagp = g_bytes_new_take(g_steal_pointer(&tag_data), tag_size);
}
g_assert(ret == (int)out_size);
g_assert(out_size == in_size);
g_assert(!*output);
*output = pv_sec_gbytes_new_take(g_steal_pointer(&out_data), out_size);
return ret;
}
int64_t pv_gcm_encrypt(GBytes *plain, GBytes *aad, const PvCipherParms *parms, GBytes **cipher,
GBytes **tag, GError **error)
{
pv_wrapped_g_assert(plain);
pv_wrapped_g_assert(parms);
pv_wrapped_g_assert(cipher);
pv_wrapped_g_assert(tag);
return pv_gcm_encrypt_decrypt(plain, aad, parms, cipher, tag, PV_ENCRYPT, error);
}
int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherParms *parms,
GBytes **plain, GError **error)
{
pv_wrapped_g_assert(cipher);
pv_wrapped_g_assert(tag);
pv_wrapped_g_assert(parms);
pv_wrapped_g_assert(plain);
return pv_gcm_encrypt_decrypt(cipher, aad, parms, plain, &tag, PV_DECRYPT, error);
}
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
const EVP_MD *md, GError **error)
{
const unsigned char *salt_data, *key_data, *info_data;
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
size_t salt_len, key_len, info_len;
g_autofree unsigned char *derived_key = NULL;
g_assert(derived_key_len > 0);
pv_wrapped_g_assert(key);
pv_wrapped_g_assert(salt);
pv_wrapped_g_assert(info);
pv_wrapped_g_assert(md);
ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL);
if (!ctx)
g_abort();
if (EVP_PKEY_derive_init(ctx) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
if (EVP_PKEY_CTX_hkdf_mode(ctx, EVP_PKEY_HKDEF_MODE_EXTRACT_AND_EXPAND) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
if (EVP_PKEY_CTX_set_hkdf_md(ctx, md) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
salt_data = g_bytes_get_data(salt, &salt_len);
if (salt_len > INT_MAX) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
if (EVP_PKEY_CTX_set1_hkdf_salt(ctx, salt_data, (int)salt_len) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
key_data = g_bytes_get_data(key, &key_len);
if (key_len > INT_MAX) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
if (EVP_PKEY_CTX_set1_hkdf_key(ctx, key_data, (int)key_len) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
info_data = g_bytes_get_data(info, &info_len);
if (info_len > INT_MAX) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
if (EVP_PKEY_CTX_add1_hkdf_info(ctx, (unsigned char *)info_data, (int)info_len) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
derived_key = g_malloc0(derived_key_len);
if (EVP_PKEY_derive(ctx, derived_key, &derived_key_len) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
"FAILED to derive key via HKDF");
return NULL;
}
return pv_sec_gbytes_new_take(g_steal_pointer(&derived_key), derived_key_len);
}
EVP_PKEY *pv_generate_ec_key(int nid, GError **error)
{
g_autoptr(EVP_PKEY_CTX) ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
g_autoptr(EVP_PKEY) ret = NULL;
g_assert(ctx);
if (EVP_PKEY_keygen_init(ctx) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
_("EC key could not be auto-generated"));
return NULL;
}
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
_("EC key could not be auto-generated"));
return NULL;
}
if (EVP_PKEY_keygen(ctx, &ret) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
_("EC key could not be auto-generated"));
return NULL;
}
return g_steal_pointer(&ret);
}
/* Convert a EVP_PKEY to the key format used in the PV header */
PvEcdhPubKey *pv_evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **error)
{
g_autofree PvEcdhPubKey *ret = g_new0(PvEcdhPubKey, 1);
g_autoptr(BIGNUM) pub_x_big = NULL, pub_y_big = NULL;
g_autoptr(EC_KEY) ec_key = NULL;
const EC_POINT *pub_key;
const EC_GROUP *grp;
pv_wrapped_g_assert(key);
ec_key = EVP_PKEY_get1_EC_KEY(key);
if (!ec_key) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Key has the wrong type"));
return NULL;
}
pub_key = EC_KEY_get0_public_key(ec_key);
if (!pub_key) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Failed to get public key"));
return NULL;
}
grp = EC_KEY_get0_group(ec_key);
if (!grp) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Failed to get EC group"));
return NULL;
}
pub_x_big = BN_new();
if (!pub_x_big)
g_abort();
pub_y_big = BN_new();
if (!pub_y_big)
g_abort();
if (EC_POINT_get_affine_coordinates_GFp(grp, pub_key, pub_x_big, pub_y_big, NULL) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Cannot convert key to internal format"));
return NULL;
}
if (BN_bn2binpad(pub_x_big, ret->x, sizeof(ret->x)) < 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Cannot convert key to internal format"));
return NULL;
}
if (BN_bn2binpad(pub_y_big, ret->y, sizeof(ret->y)) < 0) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Cannot convert key to internal format"));
return NULL;
}
return g_steal_pointer(&ret);
}
static GBytes *derive_key(EVP_PKEY *key1, EVP_PKEY *key2, GError **error)
{
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
uint8_t *data = NULL;
size_t data_size, key_size;
ctx = EVP_PKEY_CTX_new(key1, NULL);
if (!ctx)
g_abort();
if (EVP_PKEY_derive_init(ctx) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Key derivation failed"));
return NULL;
}
if (EVP_PKEY_derive_set_peer(ctx, key2) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
_("Key derivation failed"));
return NULL;
}
/* Determine buffer length */
if (EVP_PKEY_derive(ctx, NULL, &key_size) != 1) {
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
_("Key derivation failed"));
return NULL;
}
data_size = key_size;
data = OPENSSL_malloc(data_size);
if (!data)
g_abort();
if (EVP_PKEY_derive(ctx, data, &data_size) != 1) {
OPENSSL_clear_free(data, data_size);
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
_("Key derivation failed"));
return NULL;
}
g_assert(data_size == key_size);
return pv_sec_gbytes_new_take(g_steal_pointer(&data), data_size);
}
GBytes *pv_derive_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **error)
{
const guint8 append[] = { 0x00, 0x00, 0x00, 0x01 };
g_autoptr(GBytes) derived_key = NULL, ret = NULL;
g_autoptr(GByteArray) der_key_ga = NULL;
g_autofree uint8_t *raw = NULL;
size_t raw_len;
pv_wrapped_g_assert(cust);
pv_wrapped_g_assert(host);
derived_key = derive_key(cust, host, error);
if (!derived_key)
return NULL;
der_key_ga = g_bytes_unref_to_array(g_steal_pointer(&derived_key));
/* ANSI X.9.63-2011: 66 bytes x with leading 7 bits and
* concatenate 32 bit int '1'
*/
der_key_ga = g_byte_array_append(der_key_ga, append, sizeof(append));
/* free GBytesArray and get underlying data */
raw_len = der_key_ga->len;
raw = g_byte_array_free(g_steal_pointer(&der_key_ga), FALSE);
ret = pv_sha256_hash(raw, raw_len, error);
OPENSSL_cleanse(raw, raw_len);
return g_steal_pointer(&ret);
}
GQuark pv_crypto_error_quark(void)
{
return g_quark_from_static_string("pv-crypto-error-quark");
}

116
libpv/curl.c Normal file
View File

@@ -0,0 +1,116 @@
/*
* Libcurl utils
*
* Copyright IBM Corp. 2020
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
/* Must be included before any other header */
#include "config.h"
#include <curl/curl.h>
#include <stdio.h>
#include "lib/zt_common.h"
#include "libpv/curl.h"
struct UserData {
GByteArray *buffer;
uint max_size;
};
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
g_assert(userdata);
struct UserData *data = (struct UserData *)userdata;
GByteArray *buffer = data->buffer;
uint64_t actual_size;
size_t err;
g_assert(buffer);
if (!g_uint64_checked_mul(&actual_size, size, nmemb))
g_abort();
/* Signal an error condition by returning a amount that differs
* from the amount passed to the callback. This results in a
* CURLE_WRITE_ERROR.
*/
err = actual_size + 1;
if (actual_size > G_MAXUINT)
return err;
data->buffer = g_byte_array_append(buffer, (uint8_t *)ptr, (uint)actual_size);
if (data->buffer->len > data->max_size)
return err;
return actual_size;
}
int pv_curl_init(void)
{
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
return -1;
return 0;
}
void pv_curl_cleanup(void)
{
curl_global_cleanup();
}
GByteArray *curl_download(const char *url, long timeout_ms, uint max_size, GError **err)
{
g_autoptr(GByteArray) ret = NULL;
g_autoptr(CURL) handle = NULL;
g_autofree char *agent = NULL;
struct UserData userdata;
CURLcode rc;
/* set up curl session */
handle = curl_easy_init();
if (!handle)
g_abort();
/* follow redirection */
rc = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
if (rc != CURLE_OK)
goto curl_err;
agent = g_strdup_printf("%s/%s", GETTEXT_PACKAGE, RELEASE_STRING);
rc = curl_easy_setopt(handle, CURLOPT_USERAGENT, agent);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
if (rc != CURLE_OK)
goto curl_err;
ret = g_byte_array_new();
userdata.buffer = ret;
userdata.max_size = max_size;
rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&userdata);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_setopt(handle, CURLOPT_URL, url);
if (rc != CURLE_OK)
goto curl_err;
rc = curl_easy_perform(handle);
if (rc != CURLE_OK) {
g_set_error(err, PV_CURL_ERROR, PV_CURL_ERROR_DOWNLOAD_FAILED,
_("download failed: %s"), curl_easy_strerror(rc));
return NULL;
}
return g_steal_pointer(&ret);
curl_err:
g_set_error(err, PV_CURL_ERROR, PV_CURL_ERROR_CURL_INIT_FAILED,
_("cURL initialization failed: %s"), curl_easy_strerror(rc));
return NULL;
}

181
libpv/glib-helper.c Normal file
View File

@@ -0,0 +1,181 @@
/*
* Glib convenience functions
*
* 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.
*/
/* Must be included before any other header */
#include "config.h"
#include <errno.h>
#include <openssl/crypto.h>
#include "libpv/glib-helper.h"
struct __data {
void *data;
size_t size;
GFreeFunc free_func;
};
static void __data_clear_and_free(void *p)
{
struct __data *ptr = p;
if (!ptr)
return;
if (ptr->data) {
OPENSSL_cleanse(ptr->data, ptr->size);
ptr->free_func(ptr->data);
}
g_free(ptr);
}
static GBytes *pv_sec_gbytes_new_take_func(void *data, size_t size, GFreeFunc free_func)
{
struct __data *tmp = g_new(struct __data, 1);
tmp->data = data;
tmp->size = size;
tmp->free_func = free_func;
return g_bytes_new_with_free_func(data, size, __data_clear_and_free, tmp);
}
GBytes *pv_sec_gbytes_new_take(void *data, size_t size)
{
return pv_sec_gbytes_new_take_func(data, size, g_free);
}
GBytes *pv_sec_gbytes_new(const void *data, size_t size)
{
g_autofree void *tmp_data = NULL;
g_return_val_if_fail(data || size != 0, NULL);
tmp_data = g_malloc(size);
memcpy(tmp_data, data, size);
return pv_sec_gbytes_new_take(g_steal_pointer(&tmp_data), size);
}
int pv_file_seek(FILE *file, long offset, int whence, GError **error)
{
int cached_errno;
int ret = fseek(file, offset, whence);
if (ret) {
cached_errno = errno;
g_set_error(error, PV_GLIB_HELPER_ERROR, PV_GLIB_HELPER_FILE_ERROR,
"Cannot seek: %s", g_strerror(cached_errno));
}
return ret;
}
size_t pv_file_write(FILE *file, const void *ptr, size_t size, GError **error)
{
int cached_errno;
size_t n = fwrite(ptr, 1, size, file);
if (n != size) {
cached_errno = errno;
g_set_error(error, PV_GLIB_HELPER_ERROR, PV_GLIB_HELPER_FILE_ERROR,
"Cannot write: %s", g_strerror(cached_errno));
}
return n;
}
long pv_file_close(FILE *file, GError **error)
{
int cached_errno;
int ret = fclose(file);
if (ret) {
cached_errno = errno;
g_set_error(error, PV_GLIB_HELPER_ERROR, PV_GLIB_HELPER_FILE_ERROR,
"Cannot close: %s", g_strerror(cached_errno));
}
return ret;
}
void pv_auto_close_file(FILE *file)
{
if (!file)
return;
(void)pv_file_close(file, NULL);
}
long pv_file_tell(FILE *file, GError **error)
{
int cached_errno;
long n = ftell(file);
if (n < 0) {
cached_errno = errno;
g_set_error(error, PV_GLIB_HELPER_ERROR, PV_GLIB_HELPER_FILE_ERROR,
"Cannot tell: %s", g_strerror(cached_errno));
}
return n;
}
FILE *pv_file_open(const char *filename, const char *mode, GError **error)
{
FILE *file = fopen(filename, mode);
int cached_errno;
if (!file) {
cached_errno = errno;
g_set_error(error, PV_GLIB_HELPER_ERROR, PV_GLIB_HELPER_FILE_ERROR,
"Cannot open '%s'. %s", filename, g_strerror(cached_errno));
return NULL;
}
return file;
}
GBytes *pv_file_get_content_as_g_bytes(const char *filename, GError **error)
{
g_autofree char *data = NULL;
size_t data_size;
if (!g_file_get_contents(filename, &data, &data_size, error))
return NULL;
return g_bytes_new_take(g_steal_pointer(&data), data_size);
}
GBytes *pv_file_get_content_as_secure_bytes(const char *filename)
{
g_autoptr(FILE) f = fopen(filename, "rb");
g_autofree char *data = NULL;
ssize_t file_size;
size_t data_size;
if (!f)
return NULL;
fseek(f, 0, SEEK_END);
file_size = ftell(f);
if (file_size < 0)
return NULL;
data_size = (size_t)file_size;
fseek(f, 0, SEEK_SET);
data = g_malloc0(data_size);
if (data_size != fread(data, 1, data_size, f))
return NULL;
return pv_sec_gbytes_new_take(g_steal_pointer(&data), data_size);
}
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src, size_t *copied)
{
size_t src_size;
const void *src_data = g_bytes_get_data(src, &src_size);
if (dst_size < src_size)
return NULL;
if (copied)
*copied = src_size;
return memcpy(dst, src_data, src_size);
}

153
libpv/hash.c Normal file
View File

@@ -0,0 +1,153 @@
/*
* Hashing functions.
* 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.
*/
/* Must be included before any other header */
#include "config.h"
#include "libpv/crypto.h"
#include "libpv/hash.h"
GBytes *pv_sha256_hash(uint8_t *buf, size_t size, GError **error)
{
g_autoptr(EVP_MD_CTX) ctx = NULL;
ctx = pv_digest_ctx_new(EVP_sha256(), error);
if (!ctx)
return NULL;
if (pv_digest_ctx_update_raw(ctx, buf, size, error) != 0)
return NULL;
return pv_digest_ctx_finalize(ctx, error);
}
EVP_MD_CTX *pv_digest_ctx_new(const EVP_MD *md, GError **error)
{
g_autoptr(EVP_MD_CTX) ctx = EVP_MD_CTX_new();
if (!ctx) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("Hash context generation failed"));
return NULL;
}
if (EVP_DigestInit_ex(ctx, md, NULL) != 1) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("EVP_DigestInit_ex failed"));
return NULL;
}
return g_steal_pointer(&ctx);
}
int pv_digest_ctx_update_raw(EVP_MD_CTX *ctx, const uint8_t *buf, size_t size, GError **error)
{
if (!buf || size == 0)
return 0;
if (EVP_DigestUpdate(ctx, buf, size) != 1) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("EVP_DigestUpdate failed"));
return -1;
}
return 0;
}
int pv_digest_ctx_update(EVP_MD_CTX *ctx, GBytes *data, GError **error)
{
const uint8_t *buf;
size_t buf_size;
if (!data)
return 0;
buf = g_bytes_get_data((GBytes *)data, &buf_size);
return pv_digest_ctx_update_raw(ctx, buf, buf_size, error);
}
GBytes *pv_digest_ctx_finalize(EVP_MD_CTX *ctx, GError **error)
{
int md_size = EVP_MD_size(EVP_MD_CTX_md(ctx));
g_autofree uint8_t *digest = NULL;
unsigned int digest_size;
g_assert(md_size > 0);
digest = g_malloc0((uint)md_size);
if (EVP_DigestFinal_ex(ctx, digest, &digest_size) != 1) {
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
_("EVP_DigestFinal_ex failed"));
return NULL;
}
g_assert(digest_size == (uint)md_size);
return g_bytes_new_take(g_steal_pointer(&digest), digest_size);
}
HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error)
{
g_autoptr(HMAC_CTX) ctx = HMAC_CTX_new();
const uint8_t *key_data;
size_t key_size;
key_data = g_bytes_get_data(key, &key_size);
if (HMAC_Init_ex(ctx, key_data, (int)key_size, md, NULL) != 1) {
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
"unable to create HMAC context: %s", openssl_err_msg);
return NULL;
}
return g_steal_pointer(&ctx);
}
int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *buf, size_t size, GError **error)
{
if (!buf || size == 0)
return 0;
if (HMAC_Update(ctx, buf, size) != 1) {
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
"unable to add data to HMAC context: %s", openssl_err_msg);
return -1;
}
return 0;
}
int pv_hmac_ctx_update(HMAC_CTX *ctx, GBytes *data, GError **error)
{
const uint8_t *buf;
size_t buf_size;
if (!data)
return 0;
buf = g_bytes_get_data((GBytes *)data, &buf_size);
return pv_hmac_ctx_update_raw(ctx, buf, buf_size, error);
}
GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error)
{
int md_size = EVP_MD_size(HMAC_CTX_get_md(ctx));
g_autofree uint8_t *hmac = NULL;
unsigned int hmac_size = 0;
g_assert(md_size > 0);
hmac = g_malloc0((unsigned int)md_size);
if (HMAC_Final(ctx, hmac, &hmac_size) != 1) {
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
"unable to calculate HMAC: %s", openssl_err_msg);
return NULL;
}
return g_bytes_new_take(g_steal_pointer(&hmac), hmac_size);
}

File diff suppressed because it is too large Load Diff

View File

@@ -93,6 +93,8 @@ const char *util_arch_machine_type_to_str(int type)
return "IBM z15";
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
return "IBM z15 Model T02";
case UTIL_ARCH_MACHINE_TYPE_Z16:
return "IBM z16";
default:
return "Unknown machine type";
}
@@ -105,13 +107,12 @@ const char *util_arch_machine_type_to_str(int type)
*/
unsigned long util_arch_hsa_maxsize(void)
{
unsigned long size = HSA_SIZE_32M;
int type;
type = util_arch_machine_type();
if (type != UTIL_ARCH_MACHINE_TYPE_UNKNOWN &&
type >= UTIL_ARCH_MACHINE_TYPE_Z15)
size = HSA_SIZE_512M;
return size;
switch (util_arch_machine_type()) {
case UTIL_ARCH_MACHINE_TYPE_Z15:
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
case UTIL_ARCH_MACHINE_TYPE_Z16:
return HSA_SIZE_512M;
default:
return HSA_SIZE_32M;
}
}

View File

@@ -9,6 +9,7 @@
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <linux/limits.h>
@@ -21,11 +22,16 @@
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_exit_code.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#include "lib/util_prg.h"
#define READ_CHUNK_SIZE 4096
extern const char *toolname;
/*
* Read the first line of a file into given buffer
*/
@@ -536,3 +542,129 @@ int util_file_read_va(const char *path, const char *fmt, ...)
return -1;
return ret;
}
/**
* Print an error message indicating an out-of-memory situation and exit.
*/
static void oom(void)
{
fprintf(stderr, "Out of memory\n");
/* We can't rely on our clean-up routines to work reliably during an
* OOM situation, so just exit here.
*/
exit(UTIL_EXIT_OUT_OF_MEMORY);
}
/**
* Read all data from @fd and return address of resulting buffer in
* @buffer_ptr. If @size_ptr is non-zero, use it to store the size of the
* resulting buffer. Return %UTIL_EXIT_OK on success.
*
* @param[in] fd File descriptor to read data from
* @param[in, out] buffer_ptr Buffer to read data into
* @param[in, out] size_ptr Buffer to save size of data read into buffer_ptr
*
* @retval 0 read was successful
* @retval UTIL_EXIT_RUNTIME_ERROR error while reading file
*/
util_exit_code_t util_file_read_fd_buf(FILE *fd, void **buffer_ptr,
size_t *size_ptr)
{
char *buffer = NULL;
size_t done = 0;
while (!feof(fd)) {
buffer = realloc(buffer, done + READ_CHUNK_SIZE);
if (!buffer)
oom();
done += fread(&buffer[done], 1, READ_CHUNK_SIZE, fd);
if (ferror(fd)) {
free(buffer);
return UTIL_EXIT_RUNTIME_ERROR;
}
}
buffer = realloc(buffer, done);
if (!buffer && done > 0)
oom();
*buffer_ptr = buffer;
if (size_ptr)
*size_ptr = done;
return UTIL_EXIT_OK;
}
/**
* Read text from @fd and return resulting NULL-terminated text buffer.
* If @chomp is non-zero, remove trailing newline character. Return %NULL
* on error or when unprintable characters are read.
*
* @param[in] fd File descriptor to read data from
* @param[in] chomp Flag to indicate trailing newlines should be removed
*
* @retval NULL Error reading from fd
* @retval != 0 Data read successfully, buffer returned
*/
char *util_file_read_fd(FILE *fd, int chomp)
{
char *buffer;
size_t done, i;
if (util_file_read_fd_buf(fd, (void **) &buffer, &done))
return NULL;
/* Check if this is a text file at all (required to filter out
* binary sysfs attributes).
*/
for (i = 0; i < done; i++) {
if (!isgraph(buffer[i]) && !isspace(buffer[i])) {
free(buffer);
return NULL;
}
}
/* Remove trailing new-line character if requested. */
if (chomp && done > 0 && buffer[done - 1] == '\n')
done--;
/* NULL-terminate. */
buffer = realloc(buffer, done + 1);
if (!buffer)
oom();
buffer[done] = 0;
return buffer;
}
/**
* Read file as text and return NULL-terminated contents. Remove trailing
* newline if CHOMP is specified.
*
* @param[in] path Path to the file that will be read from
* @param[in] chomp Flag to indicate trailing newlines should be removed
*
* @retval NULL Error reading from file
* @retval != 0 File read successfully, contents returned in buffer
*/
char *util_file_read_text_file(const char *path, int chomp)
{
char *buffer = NULL;
FILE *fd;
fd = fopen(path, "r");
if (!fd)
goto out;
buffer = util_file_read_fd(fd, chomp);
fclose(fd);
out:
if (!buffer) {
fprintf(stderr, "Could not read file %s: %s\n", path,
strerror(errno));
}
return buffer;
}

300
libutil/util_lockfile.c Normal file
View File

@@ -0,0 +1,300 @@
/*
* util - Utility function library
*
* Created file-based locks
*
* 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 <fcntl.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>
#include "lib/util_libc.h"
#include "lib/util_lockfile.h"
#include "lib/util_panic.h"
#define WAITPID 120 /* Time to wait for pid to be written */
#define WAITINC 5 /* Additional time to wait each retry */
#define MAXWAIT 60 /* Maximum wait between retries */
#define BUFSIZE 40 /* Buffer must be large enough to fit pid string */
/**
* Check if there is a process that exists with the specified identifier.
*
* @param[in] pid Process Identifier to check
*
* @retval true Process exists or we lack privelege to check
* @retval false Process does not exist
*/
static bool pid_exists(int pid)
{
int rc;
/* Use sig 0 to determine if the owner is still alive */
rc = kill(pid, 0);
if (rc != 0) {
switch (errno) {
case EPERM:
/* Privilege issue, just assume PID exists */
break;
case ESRCH:
/* PID does not exist, this lock is stale */
return false;
default:
util_assert(false, "Unexpected return from kill: %d\n", rc);
break;
}
}
return true;
}
/**
* Check for an existing lock that is deemed stale (either the associated PID
* is gone or no PID has been written to the file in a reasonable timeframe).
* In the case a stale lock is found, remove it.
*
* @param[in] lockfile Path to the lock file
*
* @retval 0 Either no lock or stale lock was found and removed
* @retval 1 Lock is held by another PID and is not stale
*/
static int handle_stale_lock(char *lockfile)
{
int fd, rc, pid, len;
struct stat info;
char buf[BUFSIZE];
time_t curr;
fd = open(lockfile, O_RDONLY);
if (fd >= 0) {
/* Lock exists, see who owns it */
len = read(fd, buf, sizeof(buf));
if (len > 0) {
buf[len] = 0; /* Ensure null terminated string */
pid = atoi(buf);
if (!pid_exists(pid)) {
/* Stale lock detected unlink and retry now */
close(fd);
unlink(lockfile);
return 0;
} else if (pid != 0) {
/* Lock is held by an active pid, delay */
close(fd);
return 1;
}
/*
* If we reach this point, the PID was 0 which is
* unexpected. Proceed under the assumption that the
* proper PID hasn't been written yet.
*/
}
/*
* PID hasn't been written yet? Either a bad lock or a very
* new one.
*/
time(&curr);
rc = fstat(fd, &info);
close(fd);
if (rc != 0) {
/* Can't read file anymore, retry now */
return 0;
}
if (curr > info.st_mtime + WAITPID) {
/*
* PID should be in the file within 2 minutes,
* something went wrong. Treat as stale.
*/
unlink(lockfile);
return 0;
}
/* Otherwise, assume file was newly created and delay */
return 1;
}
/* Couldn't open, try again immediately */
return 0;
}
/**
* Attempt to create a lockfile at the specified path.
*
* @param[in] lockfile Path to the lock file
* @param[in] retries Number of times to retry if lock fails initially
* @param[in] pid PID to use for lock ownership
*
* @retval 0 Lock created with PID as owner
* @retval !=0 Lock was not created
*/
static int do_lockfile_lock(char *lockfile, unsigned int retries, int pid)
{
int fd, plen, len, rc = 0, snooze = 0;
unsigned int tries = retries + 1;
char buf[BUFSIZE];
char *tpath;
if (!lockfile)
return UTIL_LOCKFILE_ERR;
plen = snprintf(buf, sizeof(buf), "%d\n", pid);
if (plen < 0 || (plen > ((int)sizeof(buf) - 1)))
return UTIL_LOCKFILE_ERR;
/* Allocate temporary lock file with a sufficiently unique path */
len = util_asprintf(&tpath, "%s%05d%02x", lockfile, getpid(),
(unsigned int)time(NULL) & 255);
if (len < 0)
return UTIL_LOCKFILE_ERR;
/* Open the temporary lockfile, write the specified pid */
fd = open(tpath, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
if (fd < 0) {
rc = UTIL_LOCKFILE_ERR;
goto out;
}
len = write(fd, buf, plen);
if (close(fd) != 0) {
rc = UTIL_LOCKFILE_ERR;
goto cleanup;
}
if (len != plen) {
/* Failed to write the temp lockfile, bail out */
rc = UTIL_LOCKFILE_ERR;
goto cleanup;
}
/* Link the temprorary file to the real path */
do {
rc = link(tpath, lockfile);
if (rc == 0) {
/* Lock successfully acquired */
rc = UTIL_LOCKFILE_OK;
goto cleanup;
}
/* Lock already held - check for stale lock */
rc = handle_stale_lock(lockfile);
/* Only wait if the lock was not stale */
if (rc != 0) {
tries--;
if (tries > 0) {
snooze += WAITINC;
snooze = (snooze > MAXWAIT) ? MAXWAIT : snooze;
sleep(snooze);
}
}
} while (tries > 0);
/* Exhausted specified number of retries, exit on failure */
rc = UTIL_LOCKFILE_LOCK_FAIL;
cleanup:
unlink(tpath);
free(tpath);
out:
return rc;
}
/**
* Attempt to release a lockfile at the specified path.
*
* @param[in] lockfile Path to the lock file
* @param[in] pid PID that should own the lock
*
* @retval 0 Lock released
* @retval !=0 Lock was not released or did not exist
*/
static int do_lockfile_release(char *lockfile, int pid)
{
int fd, len, lpid;
char buf[BUFSIZE];
if (!lockfile)
return UTIL_LOCKFILE_ERR;
/* Open lockfile, read the owning pid if it exists */
fd = open(lockfile, O_RDONLY);
if (fd < 0)
return UTIL_LOCKFILE_RELEASE_NONE;
len = read(fd, buf, sizeof(buf));
close(fd);
if (len <= 0)
return UTIL_LOCKFILE_RELEASE_FAIL;
buf[len] = 0;
lpid = atoi(buf);
/* Only release the lock if its held by the right pid */
if (pid != lpid)
return UTIL_LOCKFILE_RELEASE_FAIL;
unlink(lockfile);
return 0;
}
/**
* Attempt to create a lockfile owned by this process at the specified path.
*
* @param[in] lockfile Path to the lock file
* @param[in] retries Number of times to retry if lock fails initially
*
* @retval 0 Lock created
* @retval !=0 Lock was not created
*/
int util_lockfile_lock(char *lockfile, int retries)
{
return do_lockfile_lock(lockfile, retries, getpid());
}
/**
* Attempt to create a lockfile owned by the parent of this process at the
* specified path.
*
* @param[in] lockfile Path to the lock file
* @param[in] retries Number of times to retry if lock fails initially
*
* @retval 0 Lock created
* @retval !=0 Lock was not created
*/
int util_lockfile_parent_lock(char *lockfile, int retries)
{
return do_lockfile_lock(lockfile, retries, getppid());
}
/**
* Attempt to release a lockfile owned by this process at the specified path.
*
* @param[in] lockfile Path to the lock file
*
* @retval 0 Lock released
* @retval !=0 Lock was not released or did not exist
*/
int util_lockfile_release(char *lockfile)
{
return do_lockfile_release(lockfile, getpid());
}
/**
* Attempt to release a lockfile owned by the parent of this process at the
* specified path.
*
* @param[in] lockfile Path to the lock file
*
* @retval 0 Lock released
* @retval !=0 Lock was not released or did not exist
*/
int util_lockfile_parent_release(char *lockfile)
{
return do_lockfile_release(lockfile, getppid());
}

View File

@@ -0,0 +1,232 @@
/**
* util_lockfile_example - Example program for util_lockfile
*
* 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#include "lib/util_lockfile.h"
static const struct util_prg prg = {
.desc = "Example for util_lockfile.",
.copyright_vec = { {
.owner = "IBM Corp.",
.pub_first = 2022,
.pub_last = 2022,
},
UTIL_PRG_COPYRIGHT_END }
};
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTIONS"),
{
.option = { "file", required_argument, NULL, 'f' },
.argument = "PATH",
.desc = "Use the specified path for a lockfile.",
},
{
.option = { "lock", required_argument, NULL, 'l' },
.argument = "RETRIES",
.desc = "Acquire the specified file lock using the parent "
"process id of this process. If not immediately "
"successful, retry for the specified number of times",
},
{
.option = { "release", 0, NULL, 'r' },
.desc = "Release the specified lock file using the parent "
"process id",
},
{
.option = { "lock-and-release", required_argument, NULL, 'L' },
.argument = "RETRIES",
.desc = "Acquire the specified file lock using this process "
"id, then release it. If not immediately successful, "
"retry for the specified number of times.",
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
enum prg_action {
ACTION_NONE = 0,
ACTION_LOCK,
ACTION_RELEASE,
ACTION_LOCK_AND_RELEASE,
};
static void print_single_action_error(void)
{
warnx("Only a single action (--lock, --lock-parent, --release, "
"--release-parent) is allowed");
}
int main(int argc, char *argv[])
{
enum prg_action action_id = ACTION_NONE;
int opt, rc, retries = 0;
char *endp, *path = NULL;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
while (1) {
opt = util_opt_getopt_long(argc, argv);
if (opt == -1)
break;
switch (opt) {
case 'f':
path = optarg;
break;
case 'L':
if (action_id != ACTION_NONE) {
print_single_action_error();
return EXIT_FAILURE;
}
retries = strtol(optarg, &endp, 0);
if (*optarg == '\0' || *endp != '\0' || retries < 0) {
warnx("Invalid retry value for "
"--lock-and-release: '%s'",
optarg);
util_prg_print_parse_error();
return EXIT_FAILURE;
}
action_id = ACTION_LOCK_AND_RELEASE;
break;
case 'l':
if (action_id != ACTION_NONE) {
print_single_action_error();
return EXIT_FAILURE;
}
retries = strtol(optarg, &endp, 0);
if (*optarg == '\0' || *endp != '\0' || retries < 0) {
warnx("Invalid retry value for "
"--parent-lock: '%s'",
optarg);
util_prg_print_parse_error();
return EXIT_FAILURE;
}
action_id = ACTION_LOCK;
break;
case 'r':
if (action_id != ACTION_NONE) {
print_single_action_error();
return EXIT_FAILURE;
}
action_id = ACTION_RELEASE;
break;
case 'h':
util_prg_print_help();
util_opt_print_help();
exit(EXIT_SUCCESS);
case 'v':
util_prg_print_version();
exit(EXIT_SUCCESS);
default:
util_opt_print_parse_error(opt, argv);
return EXIT_FAILURE;
}
}
if (!path) {
warnx("--file is required, see --help for more information");
return EXIT_FAILURE;
}
if (action_id == ACTION_NONE) {
warnx("One of the following actions must be specified: "
"--lock, --release, --lock-and-release");
return EXIT_FAILURE;
}
/* Determine which util_lockfile function to call */
switch (action_id) {
case ACTION_LOCK:
rc = util_lockfile_parent_lock(path, retries);
switch (rc) {
case UTIL_LOCKFILE_OK:
printf("lock acquired successfully\n");
break;
case UTIL_LOCKFILE_LOCK_FAIL:
warnx("lock was not acquired; already held");
return EXIT_FAILURE;
case UTIL_LOCKFILE_ERR:
warnx("lock was not acquired; file error");
return EXIT_FAILURE;
default:
warnx("Unknown util_lockfile rc %d", rc);
return EXIT_FAILURE;
}
break;
case ACTION_RELEASE:
rc = util_lockfile_parent_release(path);
switch (rc) {
case UTIL_LOCKFILE_OK:
printf("lock released successfully\n");
break;
case UTIL_LOCKFILE_RELEASE_NONE:
warnx("lock file did not exist");
return EXIT_FAILURE;
case UTIL_LOCKFILE_RELEASE_FAIL:
warnx("lock was not held by the specified pid");
return EXIT_FAILURE;
case UTIL_LOCKFILE_ERR:
warnx("lock was not released; file error");
return EXIT_FAILURE;
default:
warnx("Unknown util_lockfile rc %d", rc);
return EXIT_FAILURE;
}
break;
case ACTION_LOCK_AND_RELEASE:
rc = util_lockfile_lock(path, retries);
switch (rc) {
case UTIL_LOCKFILE_OK:
printf("lock acquired successfully, holding for 2 seconds\n");
break;
case UTIL_LOCKFILE_LOCK_FAIL:
warnx("lock was not acquired; already held");
return EXIT_FAILURE;
case UTIL_LOCKFILE_ERR:
warnx("lock was not acquired; file error");
return EXIT_FAILURE;
default:
warnx("Unknown util_lockfile rc %d", rc);
return EXIT_FAILURE;
}
/* Briefly sleep while holding the lock */
sleep(2);
rc = util_lockfile_release(path);
switch (rc) {
case UTIL_LOCKFILE_OK:
printf("lock released successfully\n");
break;
case UTIL_LOCKFILE_RELEASE_NONE:
warnx("lock file did not exist");
return EXIT_FAILURE;
case UTIL_LOCKFILE_RELEASE_FAIL:
warnx("lock was not held by the specified pid");
return EXIT_FAILURE;
case UTIL_LOCKFILE_ERR:
warnx("lock was not released; file error");
return EXIT_FAILURE;
default:
warnx("Unknown util_lockfile rc %d", rc);
return EXIT_FAILURE;
}
break;
default:
warnx("Unknown util_lockfile action");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
//! [code]

View File

@@ -22,7 +22,7 @@
/*
* Obtain a backtrace and print it to stderr
*
* To get symbols, compile the code with "-rdynamic".
* To get symbols, link the code with "-rdynamic".
*/
static void print_backtrace(void)
{

View File

@@ -128,7 +128,7 @@ static int mbr_table_ext_search(int fh, size_t blk_start_mbr,
start = blk_start_mbr + le32toh(mbr.part_entry_vec[0].blk_start);
cnt = le32toh(mbr.part_entry_vec[0].blk_cnt);
if ((start == blk_start) && (cnt == blk_cnt))
if ((start <= blk_start) && (cnt >= (blk_start - start) + blk_cnt))
return part_num;
/* Second entry contains relative offset for next logical volume */
@@ -162,11 +162,11 @@ static int mbr_table_search(int fh, struct mbr *mbr, size_t blk_start,
* The kernel sets count for extended partitions explicitly.
* Therefore we do not check count here.
*/
if (mbr_part_is_ext(type) && (start == blk_start)) {
if (mbr_part_is_ext(type) && (start <= blk_start)) {
*part_ext = 1;
return part_num;
}
if ((start == blk_start) && (cnt == blk_cnt))
if ((start <= blk_start) && (cnt >= (blk_start - start) + blk_cnt))
return part_num;
if (!mbr_part_is_ext(type))
continue;
@@ -207,7 +207,7 @@ static int gpt_table_search(int fh, struct gpt *gpt, size_t blk_start,
end = le64toh(part_entry->blk_end);
if (start == 0) /* Empty slot */
continue;
if ((start == blk_start) && (end == blk_end))
if ((start <= blk_start) && (end >= blk_end))
return part_num;
}
return 0;

362
libutil/util_udev.c Normal file
View File

@@ -0,0 +1,362 @@
/*
* util - Utility function library
*
* UDEV helper functions
*
* 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 <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_exit_code.h"
#include "lib/util_file.h"
#include "lib/util_libc.h"
#include "lib/util_list.h"
#include "lib/util_path.h"
#include "lib/util_udev.h"
/* Create a newly allocated udev entry. */
static struct util_udev_entry_node *util_udev_entry_node_new(const char *key,
const char *op,
const char *value)
{
struct util_udev_entry_node *entry;
entry = util_zalloc(sizeof(struct util_udev_entry_node));
entry->key = util_strdup(key);
entry->op = util_strdup(op);
entry->value = util_strdup(value);
return entry;
}
/* Release resources associated with udev entry. */
static void util_udev_entry_node_free(struct util_udev_entry_node *entry)
{
if (!entry)
return;
free(entry->key);
free(entry->op);
free(entry->value);
free(entry);
}
/* Create a newly allocated udev line. */
static struct util_udev_line_node *util_udev_line_node_new(void)
{
struct util_udev_line_node *line;
line = util_zalloc(sizeof(struct util_udev_line_node));
util_list_init(&line->entries, struct util_udev_entry_node, node);
return line;
}
/* Release resources associated with udev line. */
static void util_udev_line_node_free(struct util_udev_line_node *line)
{
struct util_udev_entry_node *e, *n;
if (!line)
return;
util_list_iterate_safe(&line->entries, e, n) {
util_list_remove(&line->entries, e);
util_udev_entry_node_free(e);
}
free(line->line);
free(line);
}
/* Create a newly allocated udev file. */
static struct util_udev_file *util_udev_file_new(void)
{
struct util_udev_file *file;
file = util_zalloc(sizeof(struct util_udev_file));
util_list_init(&file->lines, struct util_udev_line_node, node);
return file;
}
/**
* Release resources associated with udev file.
*
* @param[in, out] file Udev file structure to be freed
*/
void util_udev_free_file(struct util_udev_file *file)
{
struct util_udev_line_node *l, *n;
if (!file)
return;
util_list_iterate_safe(&file->lines, l, n) {
util_list_remove(&file->lines, l);
util_udev_line_node_free(l);
}
free(file);
}
/**
* Print the contents of a udev file to stdout. Used for debugging.
*
* @param[in] file Udev file structure to print
*/
void util_udev_file_print(struct util_udev_file *file)
{
struct util_udev_line_node *l;
struct util_udev_entry_node *e;
printf("util_udev_file at %p\n", (void *) file);
if (!file)
return;
util_list_iterate(&file->lines, l) {
printf(" util_udev_line_node at %p\n", (void *) l);
printf(" line='%s'\n", l->line);
util_list_iterate(&l->entries, e) {
printf(" util_udev_entry at %p\n", (void *) e);
printf(" '%s' '%s' '%s'\n", e->key, e->op,
e->value);
}
}
}
static void skip_whitespace(const char **s_ptr)
{
const char *s = *s_ptr;
while (*s && isspace(*s))
s++;
*s_ptr = s;
}
static char *parse_key(const char **s_ptr)
{
const char *s, *e;
char *key;
s = *s_ptr;
/* Parse \w+(\{[^\}]*\})? */
e = s;
while (*e && (isalnum(*e) || *e == '_'))
e++;
if (*e == '{') {
while (*e && *e != '}')
e++;
if (*e == '}')
e++;
}
if (e == s)
return NULL;
/* s points to key start, e to character after key end. */
key = util_zalloc(e - s + 1);
memcpy(key, s, e - s);
*s_ptr = e;
return key;
}
static char *parse_op(const char **s_ptr)
{
const char *ops[] = { "==", "!=", "=", "+=", ":=", NULL };
const char *entry;
size_t len;
int i;
entry = *s_ptr;
for (i = 0; ops[i]; i++) {
len = strlen(ops[i]);
if (strncmp(entry, ops[i], len) == 0) {
*s_ptr += len;
return util_strdup(ops[i]);
}
}
return NULL;
}
static char *parse_value(const char **s_ptr)
{
const char *s, *e;
char *value;
/* Parse: ^\s*(.*)\s*$ */
s = *s_ptr;
skip_whitespace(&s);
e = s;
while (*e)
e++;
e--;
while (e > s && isspace(*e))
e--;
e++;
*s_ptr = e;
/* Remove quotes. */
if ((*s == '"' && *(e - 1) == '"') ||
(*s == '\'' && *(e - 1) == '\'')) {
s++;
e--;
}
/* s points to value start, e to character after value end. */
value = util_zalloc(e - s + 1);
memcpy(value, s, e - s);
return value;
}
static bool parse_util_udev_entry(struct util_udev_line_node *line,
const char *entry)
{
char *key = NULL, *op = NULL, *value = NULL;
struct util_udev_entry_node *e;
bool rc = false;
/* Parse: ^\s*(\w+)\s*(==|!=|=|\+=|:=)\s*"?([^"]*)"\s*$ */
/* Parse key. */
skip_whitespace(&entry);
key = parse_key(&entry);
if (!key)
goto out;
/* Parse operator. */
skip_whitespace(&entry);
op = parse_op(&entry);
if (!op)
goto out;
/* Parse value. */
skip_whitespace(&entry);
value = parse_value(&entry);
if (!value)
goto out;
skip_whitespace(&entry);
/* Check for unrecognized characters at end of entry. */
if (*entry != 0)
goto out;
/* Add entry to list. */
e = util_udev_entry_node_new(key, op, value);
util_list_add_tail(&line->entries, e);
rc = true;
out:
free(key);
free(op);
free(value);
return rc;
}
static void replace_unquoted(char *s, char from, char to)
{
char quoted = 0;
for (; *s; s++) {
if (quoted) {
/* Skip until quote end is found. */
if (*s == quoted)
quoted = 0;
continue;
}
if (*s == '"' || *s == '\'') {
quoted = *s;
continue;
}
if (*s == from)
*s = to;
}
}
static bool parse_util_udev_line(struct util_udev_file *file, const char *line)
{
char *copy, *curr, *next;
struct util_udev_line_node *l;
int i;
bool result = true;
l = util_udev_line_node_new();
l->line = util_strdup(line);
/* Check for empty lines and comment lines. */
for (i = 0; line[i] && isspace(line[i]); i++);
if (line[i] == 0 || line[i] == '#')
goto ok;
/* Parse each comma-separated entry. */
copy = util_strdup(line);
/* A hack to differentiate between quoted and unquoted commas. */
replace_unquoted(copy, ',', 1);
next = copy;
while ((curr = strsep(&next, "\1"))) {
if (!parse_util_udev_entry(l, curr)) {
result = false;
break;
}
}
free(copy);
ok:
if (result)
util_list_add_tail(&file->lines, l);
else
util_udev_line_node_free(l);
return result;
}
/**
* Create a new util_udev_file structure and read the contents of a specified
* udev file into that structure.
*
* @param[in] path Path to the udev file that will be read in
* @param[in, out] file_ptr A buffer to store resulting udev file structure
*
* @retval 0 Udev file read successfully
* @retval UTIL_EXIT_RUNTIME_ERROR Error reading the udev file
*/
util_exit_code_t util_udev_read_file(const char *path,
struct util_udev_file **file_ptr)
{
char *text, *curr, *next;
struct util_udev_file *file;
int once = 0;
text = util_file_read_text_file(path, 0);
if (!text)
return UTIL_EXIT_RUNTIME_ERROR;
file = util_udev_file_new();
/* Iterate over each line. */
next = text;
while ((curr = strsep(&next, "\n"))) {
if (parse_util_udev_line(file, curr))
continue;
if (!once) {
once = 1;
fprintf(stderr, "Unrecognized udev rule in %s:\n",
path);
}
fprintf(stderr, "%s\n", curr);
}
free(text);
*file_ptr = file;
return UTIL_EXIT_OK;
}

View File

@@ -50,6 +50,7 @@ public:
RegisterSet64 getRegisterSet(int cpu);
void addRegisterSet(const RegisterSet64&);
inline int getNumCpus(void) const { return nrCpus; }
RegisterContent64& operator=(const RegisterContent64&) = default;
RegisterSet64 regSets[MAX_CPUS];
private:
@@ -64,6 +65,7 @@ public:
RegisterSet32 getRegisterSet(int cpu);
void addRegisterSet(const RegisterSet32&);
inline int getNumCpus(void) const { return nrCpus; }
RegisterContent32& operator=(const RegisterContent32&) = default;
RegisterSet32 regSets[MAX_CPUS];
private:

View File

@@ -1,3 +1,12 @@
/*
* lsstp - Display STP system information
*
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

View File

@@ -248,7 +248,7 @@ static void count_users(void)
proc_sum.users = 0;
setutent();
while ((temp = getutent())) {
if ((temp->ut_type == USER_PROCESS) && (temp->ut_name))
if (temp->ut_type == USER_PROCESS)
proc_sum.users++;
}
endutent();
@@ -859,8 +859,6 @@ static void read_tasks(void)
}
while ((entry = readdir(proc_dir))) {
if (!entry->d_name)
break;
if (!isdigit(entry->d_name[0]) || !atoi(entry->d_name))
continue;
memset(&task, 0, sizeof(struct task_t));

22
pvattest/Makefile Normal file
View File

@@ -0,0 +1,22 @@
# Common definitions
include ../common.mak
.DEFAULT_GOAL := all
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/pvattest"
SUBDIRS := src man tools
RECURSIVE_TARGETS := all-recursive clean-recursive install-recursive
all: all-recursive
install: all install-recursive
clean: clean-recursive
$(RECURSIVE_TARGETS):
@target=`echo $@ |sed s/-recursive//`; \
for d in $(SUBDIRS); do \
$(MAKE) -C $$d $$target || exit 1; \
done
.PHONY: all install clean $(RECURSIVE_TARGETS)

100
pvattest/README.md Normal file
View File

@@ -0,0 +1,100 @@
# pvattest
Use `pvattest` to attest an IBM Secure Execution guest running on z16 and later.
With `pvattest` you can create attestation requests in a trusted environment and attest
an IBM Secure Execution for Linux guest to verify that a provider is running the correct image.
To achieve this, use the following commands:
* `create` On a trusted system, creates an attestation request.
* `perform` Performs an attestation measurement on the SE-guest to be attested. For this a
attestation request is sent to the Ultravisor (UV) and the answer received. The `perform`
command requires IBM z16 or later z/Architecture hardware.
* `verify` On a trusted system, compares the answer from the Ultravisor to the
expected answer. If they differ, the Secure Execution guest might be a different guest
than expected, or not secure at all.
For meaningful results, run `create` and `verify` only in a trusted environment,
like your workstation or a previously attested IBM Secure Execution guest.
Otherwise, the attestation can be compromised.
For all certificates, revocation lists, and host-key documents, both the PEM and DER input
formats are supported. If you run this program on a non S390 System, 'perform' is not be available.
## Getting started
If all dependencies are met (see the s390-tools README) issue `make` in the source tree to build `pvattest`.
## Details
### create
`pvattest create` needs the host-key-document, a location to store the
attestation request protection key, and a location to store the request data.
Unless the `--no-verify` flag is set it additionally requires the IBM signing key
and the intermediate CA. The output contains the request in binary form which serves as input
to `pvattest perform`. Must be run in a trusted environment. Especially, do not create the request
on a system you want to attest. The attestation request protection key is valid for this request only,
must be kept until the verification is completed and must be destroyed afterwards
Keep the key secret.
### perform
`pvattest perform` needs a request in binary form generated by `pvattest create`and
a location to store the output. It will send the request to the device at `/dev/uv`
which passes the request to the Ultravisor.
Kernel will then send the request to the Ultravisor which will calculate the answer.
The Answer is then passed back to userspace and handled by `pvattest`
The output includes the original request and the answer from the Ultravisor.
### verify
`pvattest verify` needs the SE-guest header, the attestation request protection key,
and the attestation request and the response to the `pvattest perform` command from the Ultravisor.
It calculates the measurement in the trusted environment and compares it to the response from
the Ultravisor in the previous step.
The following return codes are possible:
0. successful verification: The calculated measurement matches the response from the Ultravisor
1. failed verification: The command ended with an error, for example, because of incorrect input or an invalid SE header
2. failed verification: The calculated measurement does not match the response from the Ultravisor
Run `pvattest verify` in a trusted environment. Especially, do not verify on the system you want to attest.
## Measurement
The measurement is a cryptographic measurement of the following block.
Only HMAC-SHA512 is supported.
| Start | Size | Content |
|---------|------------|---------------------------------------------------------------|
| 0x0 | 0x40 | Page List Digest (from SE header) |
| 0x40 | 0x40 | Address List Digest (from SE header) |
| 0x80 | 0x40 | Tweak List Digest (from SE header) |
| 0xc0 | 0x10 | SE Header Tag (from SE header) |
| 0xd0 | 0x10 | Configuration UID (generated by UV, included in the answer) |
| 0xe0 | 0x02 | User Data Length (defined during measurement on the SE-guest) |
| 0xe2 | 0x02 | Zeros |
| 0xe4 | 0x04 | Additional Data Length (set by UV, included in the answer) |
| 0xe8 | 0 - 0x100 | User Data (generated during measurement on the SE-guest) |
| ... | 0 or 0x10 | Optional Nonce (generated during request creation) |
| ... | 0 - 0x8000 | Additional Data (generated by UV, included in the answer) |
### User Data
By default `pvattest` does not include any User Data, therefore the length is zero.
`User Data` is data generated by the SE guest and passed to UV during the measurement.
The `User Data` must be known to or be replicable by the verifier to verify the correctness of the User Data.
The addition of user data is currently an experimental setting.
### Additional Data
`Additional data` is data known to the Ultravisor. By default UV will not include any `Additional Data`.
Adding `Additional Data` is currently an experimental setting.
## Example
Create an attestation request in a trusted environment:
`pvattest create -k hkd.crt --arpk arp.key -o arcb.bin --cert IntermediateCA.crt --cert IbmSigningKey.crt`
Perform an attestation measurement on an IBM Secure Execution guest:
`pvattest perform --input arcb.bin --output measurement.bin`
Verify the response from the Ultravisor against the attestation request in a trusted environment:
`pvattest verify --input measurement.bin --arpk arp.key --hdr se_guest.hdr`

9
pvattest/man/Makefile Normal file
View File

@@ -0,0 +1,9 @@
include ../../common.mak
all:
install:
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c *.1 -t $(DESTDIR)$(MANDIR)/man1
.PHONY: all install clean

View File

@@ -0,0 +1,83 @@
.\" Copyright 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.
.\"
.TH pvattest-create 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] create [OPTIONS] \fP- create an attestation measurement request
\fB
.SH DESCRIPTION
Prepare attestation measurement requests for an IBM Secure Execution guest.
Only prepare attestation requests in a trusted environment, such as your workstation.
The 'pvattest create' command creates a randomly generated key to protect the attestation request.
This key is only valid for this specific request. In order to avoid compromising the attestation,
do not publish the protection key and delete it after verification.
Every 'create' command generates a new, random protection key.
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Prints usage information, then exits.
.TP
.B
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
Specify one or more host key documents. At least one is required.
Specify this option multiple times to enable the image to run on more than one host.
.TP
.B
\fB-C\fP, \fB--cert\fP=\fBFILE\fP
Specifies the certificate that is used to establish a chain of trust for the verification of the host-key documents. Specify this option twice to specify the IBM Z signing key and the intermediate CA certificate (signed by the root CA). Required. Ignored when \fB--no-verify\fP is specified.
.TP
.B
\fB--crl\fP=\fBFILE\fP
Specifies the revocation list that is used to check whether a certificate of the chain of trust is
revoked. Specify this option multiple times to use multiple CRLs (optional).
.TP
.B
\fB--root-ca\fP=\fBFILE\fP
Specifies the root CA certificate for the verification. If omitted,
the system wide root CAs installed on the system are used. Use
this only if you trust the specified certificate. Optional.
.TP
.B
\fB-o\fP, \fB--output\fP=\fBFILE\fP
\fBFILE\fP specifies the output for the attestation request control block.
.TP
.B
\fB-a\fP, \fB--arpk\fP=\fBFILE\fP
Save the protection key as GCM-AES256 key in \fBFILE\fP Do not publish this key, otherwise your attestation is compromised.
.TP
.B
\fB--no-verify\fP
Disable the host-key document verification. Does not require the host-key documents to be valid. Do
not use for a production request unless you verified the host-key document before (optional).
.TP
.B
\fB--offline\fP
Specifies offline mode, in which no attempt is made to download CRLs. (optional).
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional).
.SH EXAMPLE
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', and verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt'.
.PP
.nf
.fam C
pvattest create -k hkd.crt --arpk arp.key -o attreq.bin --cert DigiCertCA.crt --cert IbmSigningKey.crt
.fam T
.fi
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt', and instead of downloading the certificate revocation list use certificate revocation lists 'DigiCertCA.crl', 'IbmSigningKey.crl', and 'rootCA.crl'.
.PP
.nf
.fam C
pvattest create -k hkd.crt --arpk arp.key -o attreq.bin --cert DigiCertCA.crt --cert IbmSigningKey.crt --offline --crl DigiCertCA.crl --crl IbmSigningKey.crl --crl rootCA.crl
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP(1), \fBpvattest-verify\fP(1), \fBpvattest-perform\fP(1)

View File

@@ -0,0 +1,50 @@
.\" Copyright 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.
.\"
.TH pvattest-perform 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] perform [OPTIONS] \fP- execute an attestation measurement request
\fB
.SH DESCRIPTION
Run a measurement of this system using '/dev/uv'. Works only if this device is
available and the attestation Ultravisor facility is present.
The input must be an attestation request created with 'pvattest create'.
Output will contain the original request and the response from the Ultravisor.
.RE
.PP
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Show help options
.TP
.B
\fB-i\fP, \fB--input\fP=\fBFILE\fP
\fBFILE\fP specifies the attestation request as input.
.TP
.B
\fB-o\fP, \fB--output\fP=\fBFILE\fP
\fBFILE\fP specifies the output for the attestation result.
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional)
.RE
.PP
.SH EXAMPLE
Perform an attestation measurement with the attestation request 'arcb.bin' and write the output to 'measurement.bin'.
.PP
.nf
.fam C
pvattest perform --input attreq.bin --output attresp.bin
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP(1), \fBpvattest-create\fP(1), \fBpvattest-verify\fP(1)

View File

@@ -0,0 +1,60 @@
.\" Copyright 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.
.\"
.TH pvattest-verify 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] verify [OPTIONS] \fP- verify an attestation measurement
\fB
.SH DESCRIPTION
Verify that a previously generated attestation measurement of an IBM Secure Execution guest is as expected. Only verify attestation requests in a trusted environment, such as your workstation. Input must contain the response as produced by 'pvattest perform'. The protection key must be the one that was used to create the request by 'pvattest create'. Please delete it after verification. The header must be the IBM Secure Execution header of the image that was attested during 'pvattest perform'
.RE
.PP
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Show help options
.TP
.B
\fB-i\fP, \fB--input\fP=\fBFILE\fP
\fBFILE\fP specifies the attestation result as input.
.TP
.B
\fB--hdr\fP=\fBFILE\fP
Specify the header of the guest image. Exactly one is required.
.TP
.B
\fB-a\fP, \fB--arpk\fP=\fBFILE\fP
Use \fBFILE\fP to specify the GCM-AES256 key to decrypt the attestation request. Delete this key after verification.
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional)
.RE
.PP
.SH EXAMPLE
To verify a measurement in 'measurement.bin' with the protection key 'arp.kep' and SE-guest header 'se_guest.hdr'.
.PP
.nf
.fam C
pvattest verify --input attresp.bin --arpk arp.key --hdr se_guest.hdr
.fam T
.fi
If the verification was successful the program exists with zero.
If the verification failed it exists with 2 and prints the following to stderr:
.PP
.nf
.fam C
ERROR: Attestation measurement verification failed:
Calculated and received attestation measurement are not the same.
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP(1), \fBpvattest-create\fP(1), \fBpvattest-perform\fP(1)

104
pvattest/man/pvattest.1 Normal file
View File

@@ -0,0 +1,104 @@
.\" Copyright 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.
.\"
.TH pvattest 1 "07 June 2022" "s390-tools" "Attestation Manual"
.nh
.ad l
.SH NAME
\fBpvattest [OPTION?] COMMAND [OPTIONS] \fP- create, perform, and verify attestation measurements
\fB
.RE
\fB
.SH SYNOPSIS
.nf
.fam C
\fBpvattest\fP \fIcreate\fP [\fIOPTIONS\fP]
\fBpvattest\fP \fIperform\fP [\fIOPTIONS\fP]
\fBpvattest\fP \fIverify\fP [\fIOPTIONS\fP]
.fam T
.fi
.fam T
.fi
.SH DESCRIPTION
Use \fBpvattest\fP to attest that an IBM Secure Execution guest is the correct guest, and that it was started in a secure manner.
Run '\fBpvattest\fP \fIcreate\fP' and '\fBpvattest\fP \fIverify\fP' in a trusted environment only.
.PP
.nf
.fam C
create On a trusted system, creates an attestation request.
perform On the SE-guest to be attested, sends the attestation request to the Ultravisor and receives the answer.
verify On a trusted system, compares the answer from the Ultravisor to the one from your trusted environment. If they differ, the Secure Execution guest might be compromised.
.fam T
.fi
For meaningful results, run '\fIcreate\fP' and '\fIverify\fP' in a trusted environment, like your workstation or a previously attested IBM Secure Execution guest. Otherwise, the attestation might be tampered with. For all certificates, revocation lists, and host-key documents, both the PEM and DER input formats are supported. If you run \fBpvattest\fP on a machine architecture other than z/Architecture, 'measure' is not available.
.PP
Use '\fBpvattest\fP [COMMAND] \fB-h\fP' to get detailed help
.RE
.PP
.SH OPTIONS
.TP
.B
\fB-h\fP, \fB--help\fP
Show help options
.TP
.B
\fB-v\fP, \fB--version\fP
Print the version and exit.
.TP
.B
\fB-V\fP, \fB--verbose\fP
Provide more detailed output (optional)
.RE
.PP
.SH EXAMPLE
For details refer to the man page of the command.
.PP
Create the request on a trusted system.
.PP
.nf
.fam C
trusted:~$ pvattest create -k hkd.crt --cert CA.crt --cert ibmsk.crt --arpk arp.key -o attreq.bin
.fam T
.fi
On the SE-guest, \fIperform\fP the attestation.
.PP
.nf
.fam C
seguest:~$ pvattest perform -i attreq.bin -o attresp.bin
.fam T
.fi
On a trusted system, \fIverify\fP that the response is correct. Here, the protection key from the creation and the SE-guests header is used to \fIverify\fP the measurement.
.PP
.nf
.fam C
trusted:~$ pvattest verify -i attresp.bin --arpk arp.key --hdr se_guest.hdr
trusted:~$ echo $?
0
.fam T
.fi
If the measurements do not match \fBpvattest\fP exits with code 2 and emits an error message. The SE-guest attestation failed.
.PP
.nf
.fam C
trusted:~$ pvattest verify -i wrongresp.bin --arpk arp.key --hdr se_guest.hdr
ERROR: Attestation measurement verification failed:
Calculated and received attestation measurement are not the same.
trusted:~$ echo $?
2
.fam T
.fi
.SH SEE ALSO
\fBpvattest\fP-\fIcreate\fP(1), \fBpvattest-\fIverify\fP\fP(1), \fBpvattest\fP-\fIperform\fP(1)

2
pvattest/src/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.check-dep-pvattest
.detect-openssl.dep.c

123
pvattest/src/Makefile Normal file
View File

@@ -0,0 +1,123 @@
include ../../common.mak
BIN_PROGRAM = pvattest
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/$(BIN_PROGRAM)"
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
PVATTESTDIR := $(rootdir)/pvattest
INCLUDE_PATHS = "$(SRC_DIR)" "$(rootdir)/include"
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
LIBPV_DIR = $(rootdir)/libpv
LIBPV = $(LIBPV_DIR)/libpv.a
WARNINGS := -Wall -Wextra -Wshadow \
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
-Wpointer-arith -Wno-error=inline \
-Wno-unused-function -Wno-unused-parameter -Wno-unused-variable \
-Werror \
$(NULL)
PVATTEST_SRCS := $(wildcard *.c) \
$(NULL)
$(BIN_PROGRAM)_SRCS := \
$(PVATTEST_SRCS) \
$(NULL)
$(BIN_PROGRAM)_OBJS := $($(BIN_PROGRAM)_SRCS:.c=.o)
ifneq ($(shell sh -c 'command -v pkg-config'),)
GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto openssl)
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto openssl)
LIBCURL_CFLAGS := $(shell pkg-config --silence-errors --cflags libcurl)
LIBCURL_LIBS := $(shell pkg-config --silence-errors --libs libcurl)
else
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
GLIB2_LIBS := -lglib-2.0
LIBCRYPTO_CFLAGS :=
LIBCRYPTO_LIBS := -lcrypto -lssl
LIBCURL_CFLAGS := -I/usr/include/s390x-linux-gnu
LIBCURL_LIBS := -lcurl
endif
ALL_CFLAGS += -std=gnu11 \
-DPKGDATADIR=$(PKGDATADIR) \
-DOPENSSL_API_COMPAT=0x10101000L \
$(GLIB2_CFLAGS) \
$(LIBCRYPTO_CFLAGS) \
$(LIBCURL_CFLAGS) \
$(WARNINGS) \
$(NULL)
ifneq ($(call check_header_prereq,"asm/uvdevice.h"),yes)
ALL_CFLAGS += -DPVATTEST_NO_PERFORM
endif
ALL_CPPFLAGS += $(INCLUDE_PARMS)
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
BUILD_TARGETS := skip-$(BIN_PROGRAM)
INSTALL_TARGETS := skip-$(BIN_PROGRAM)
ifneq (${HAVE_OPENSSL},0)
ifneq (${HAVE_GLIB2},0)
ifneq (${HAVE_LIBCURL}, 0)
BUILD_TARGETS := $(BIN_PROGRAM)
INSTALL_TARGETS := install-$(BIN_PROGRAM)
endif
endif
endif
all: $(BUILD_TARGETS)
install: $(INSTALL_TARGETS)
$(BIN_PROGRAM): $($(BIN_PROGRAM)_OBJS) $(LIBPV)
skip-$(BIN_PROGRAM):
echo " SKIP $(BIN_PROGRAM) due to unresolved dependencies"
clean:
$(RM) -f -- $($(BIN_PROGRAM)_OBJS) $(BIN_PROGRAM) .check-dep-$(BIN_PROGRAM) .detect-openssl.dep.c
install-$(BIN_PROGRAM): $(BIN_PROGRAM)
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
$(INSTALL) -c $^ $(DESTDIR)$(USRBINDIR)
.PHONY: all install clean skip-$(BIN_PROGRAM) install-$(BIN_PROGRAM)
$($(BIN_PROGRAM)_OBJS): .check-dep-$(BIN_PROGRAM)
.detect-openssl.dep.c:
echo "#include <openssl/evp.h>" > $@
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
echo " #error openssl version 1.1.1 is required" >> $@
echo "#endif" >> $@
echo "static void __attribute__((unused)) test(void) {" >> $@
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
echo " EVP_MD_CTX_free(ctx);" >> $@
echo "}" >> $@
.check-dep-$(BIN_PROGRAM): .detect-openssl.dep.c
$(call check_dep, \
"$(BIN_PROGRAM)", \
"glib.h", \
"glib2-devel / libglib2.0-dev", \
"HAVE_GLIB2=0")
$(call check_dep, \
"$(BIN_PROGRAM)", \
$^, \
"openssl-devel / libssl-dev version >= 1.1.1", \
"HAVE_OPENSSL=0", \
"-I.")
$(call check_dep, \
"$(BIN_PROGRAM)", \
"curl/curl.h", \
"libcurl-devel", \
"HAVE_LIBCURL=0")
touch $@

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