Compare commits

..

68 Commits

Author SHA1 Message Date
Jan Höppner
d9ca409978 New release s390-tools-2.4.0
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 15:27:24 +02:00
Jan Höppner
13596f18da udev: Replace WAIT_FOR with TEST keyword
The udev rule for SCSI devices is still using the WAIT_FOR keyword,
which was used to make sure that a file does in fact exist before any
rule is applied. That keyword, however, was removed with systemd-220 and
is therefore no longer valid, which in turn leads to errors on newer
systems.

Use the TEST keyword instead to check the existence of a file before we
apply any rules.

Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 14:28:32 +02:00
Ingo Franzki
80b66da1d8 zkey: Update README to add info about packaging requirements
Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 14:28:32 +02:00
Hendrik Brueckner
3eb9af9c97 zkey: let packaging create the zkeyadm group and permission setup
Signed-off-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 14:28:32 +02:00
Ingo Franzki
f093d0bfd4 zkey: Man page updates
Add documentation for the new keystore related zkey commands.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
6a2f4fd376 zkey: Create key repository and group during make install
Create the default keystore directory '/etc/zkey/repository'
and the user group 'zkeyadm' during make install.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
e2f92e4079 zkey: Add keystore related commands
Add new commands to the zkey utility to store secure AES keys in
the secure key repository provided by the keystore implementation
introduced in the previous commit.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
c944f23d7e zkey: Add keystore implementation
Add a keystore implementation that stores secure AES keys in a
key repository, located in a directory, e.g. '/etc/zkey/repository'.
The keystore allows you to generate, validate, re-encipher, modify,
list, delete, etc secure keys.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
5872f8a21b zkey: Externalize secure key back-end functions
To reduce the size of the zkey.c source file, all routines that
deal with secure keys are moved to a new source file pkey.c.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
a090a1ffe8 zkey: Add helper functions for comma separated string handling
Comma separated strings are used in property values to store
multiple values in one property. These helper functions allow to
work with such comma separated strings.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
5e24f74fde zkey: Add build dependency to OpenSSL (libcrypto)
The integrity support for the properties file routines use
SHA-256 to build a hash of the keys and values of a property file.
The codes uses the EVP_DigestInit_ex, EVP_DigestUpdate, and
EVP_DigestFinal from the libcrypto library (OpenSSL).

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Ingo Franzki
340da73bb7 zkey: Add properties file handling routines
In preparation for a new feature, introduce property file
handling routines. A property file stores key value pairs
in a text file. Optionally a hash of all keys and values
contained in the properties file can be generated to
ensure integrity of the properties file and to detect
manual modifications.

Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
f642019bcc cpumf: Add IBM z14 ZR1 to the CPU Measurement Facility model list
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
7cc542352e zgetdump: Update the man page
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
cf99ea019e zgetdump: Add 'Dump file size' field for zgetdump -i output
Add 'Dump file size' field for zgetdump -i output to show the actual size
of dump file in s390 extended format on disk in megabytes.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
15c22ec742 zgetdump: Add verbose option
Add verbose option for zgetdump to display the detailed layout of memory
map when printing dump info for s390_ext or ELF dump format.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
45ac847dc9 zgetdump: Adjust zgetdump for ELF formatted dumps
Adjust ELF formatted dump processing by zgetdump tool in order to handle
so-called zero loads using zero memory chunks introduced with s390
extended dump format.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
4a223c70f2 zgetdump: Update zgetdump to process the new dump format
Update zgetdump tool to process dumps of the new s390 extended format.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
26d636f234 zgetdump: Update zgetdump to process the new dump tool
Update 'zgetdump -d' to process the new DASD dump tool installed (single
volume or multi-volume).

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
aade05b01d zgetdump: Update s390 dump common functions
Update df_s390_dumper structure and dumper reading functions to read
certain dumper fields instead of the entire dump tool.
Update other s390 dump common functions in preparation for the new dumper
and the new s390 extended dump format.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
c3821f0821 zipl: Update progress_print() function
Adjust progress_print() function to print dump progress message based on
the time interval thus printing the message with a regular rate.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
ac0ac48f6f zipl: Extend DASD stand-alone dumpers to drop zero pages
Update zipl DASD standalone dumpers for single-volume, multi-volume and FBA
to drop the sets of zero pages when dumping memory to disk. Thus, all
continuous sets of zero-megabytes in the memory are dropped during the dump
stage.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
54519b4465 zipl: Update page_is_valid() function to avoid tprot usage
Old implementation was using Test Protection (TPROT) instruction to
validate the memory page. Given that it is a rather slow instruction and
the fact that we only need to validate the read-access for a page, we can
use simple Load or Insert Character instruction to test that.
The new version of page_is_valid() without a TPROT is introduced.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.vnet.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
9f2e406525 zipl: Fixing program check handler function
The program check handler has a bug in calculating the address of the target
to jump to. Furthermore the use of relative addresses in the exception table
can lead to situations where the (calculated) fault is not unique. Storing
the absolute address of the fault and target in the exception table solves
both problems.
This patch is intended to:
  - Modify exception table to store the absolute address of 'fault' and
    'target' points
  - Adjust program check handler function pgm_check_handler_fn() accordingly

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.vnet.ibm.com>
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Vasily Gorbik
edaad2a927 chreipl: correct read-only attributes handling
chreipl could only be used as root (effective userid 0), which is
explicitly checked upon invocation.

"access" call is a wrong method to check super user read/write access
for sysfs files, because it is simply always returns 0 (success), despite
actual sysfs file permissions or underlying sysfs file callbacks setup.
The only guaranteed way of checking sysfs file super user access is an
actual open call with the corresponding access mode.

The problem is that chreipl always tries to update some sysfs attributes
even through they are not specified as command line arguments. Together
with a broken sysfs file access checks this leads to inability to use
the tool, when some sysfs attributes are read-only (which is the case
on older systems where diag308 set does not work).

$ chreipl ccw -d 0.0.ec5a
chreipl: Could not open "reipl/ccw/parm" (Permission denied)

The change fixes access checks, which are in place to handle "diag308
set does not work" case (presence of read-only sysfs attributes).

Also replaces R_OK with F_OK in "set_target_type_auto" to underline that
only file presence is checked, not an actual read access.

Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Vasily Gorbik
262a827ab4 chreipl: make write_str_errno return errno as the name suggests
Make write_str_errno return errno in all error cases, so that it would
be usable in scenarious where open call could fail and we just want to
get an errno, not to exit.

This function is currently only used by chshut in a context where
such a change wouldn't hurt debug ability.

159         if (write_str_errno(argv[2], path))
160                 ERR_EXIT_ERRNO("Could not set \"%s\"", path);

Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Vasily Gorbik
4b33d80595 chreipl: correct fcp reipl sysfs write sequence
kdump reipl implementation relies on os_info kernel structure
residing in old memory being dumped. os_info contains reipl block, which
is used (if valid) by the kdump kernel for reipl parameters.

The problem is that the reipl block and its checksum inside
os_info is updated only when /sys/firmware/reipl/reipl_type is
written. This sets an offset of a reipl block for "reipl_type" and
re-calculates reipl block checksum. Any further alteration of values
under /sys/firmware/reipl/{reipl_type}/ without subsequent write to
/sys/firmware/reipl/reipl_type lead to incorrect os_info reipl block
checksum. In such a case kdump kernel ignores it and reboots using
default logic.

This change makes sure that all fcp values are written before
reipl_type, to avoid potential problem with incorrect checksum.

Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Sa Liu
4c401162c0 dbginfo: Add VM commands to query protection settings.
Signed-off-by: Sa Liu <saliu@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
168acec5ea zgetdump: Avoid the Segfault on processing dumps with memory limit
When dump is not complete or dump memory limit is set, zgetdump might end up
with the Segfault on reading Vector Registers. That might take place when
the Vector Registers save area is beyond the dump memory limit.

Signed-off-by: Mikhail Zaslonko <zaslonko@linux.vnet.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
aab339d3e3 cpumf: Make short descriptions common for extended counter sets
The short descriptions for a counter in the extender counter
set should be identical for all models.
This patch fixes minor differences.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
1f459af568 cpumf: Add short description for crypto counter set
Add short description to the crypto counter set definition
file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
46f09a0adc cpumf: Add short description for diag counter set
Add a short description to the diagnosis counter set
definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
f65003a14e cpumf: Add short description for zEC12 extended counter set
Add a short description to the zEC12 extended counter set
definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
e092b4024a cpumf: Add short description for z196 extended counter set
Add a short description to the z196 extended counter set
definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
9d7bab18a4 cpumf: Add short description for z14 extended counter set
Add a short description to the z14 extended counter set
definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
8688d47e3d cpumf: Add short description for z13 extended counter set
Add a short description to the z13 extended counter set
definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
04bb72c0dc cpumf: Add short description for z10 extended counter set
Add a short description to the z10 extended counter set
definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
1c065082d2 cpumf: Add short description for basic counters level 3
Add a short description to the basic counter first
version number 3 definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
38642e6905 cpumf: Add short description for basic counters level 1
Add a short description to the basic counter first
version number 1 definition file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
ebdf888a2f cpumf: Fix typo in counter 135
Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Hendrik Brueckner
9745e4678a cpumf: correct counter name for z13 and z14
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Sebastian Ott
33a17df9fc lscss: fix scanning for defunct devices
util_scandir doesn't work with "/" at the end of the format string.

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Sebastian Ott
4ff7aeff39 lscss: fix double free in print_defunct_devices
double free or corruption (out)

Program received signal SIGABRT, Aborted.
0x000003fffdd40404 in raise () from /lib64/libc.so.6
(gdb) bt
#0  0x000003fffdd40404 in raise () from /lib64/libc.so.6
#1  0x000003fffdd41ec2 in abort () from /lib64/libc.so.6
#2  0x000003fffdd88d8e in __libc_message () from /lib64/libc.so.6
#3  0x000003fffdd905c8 in malloc_printerr () from /lib64/libc.so.6
#4  0x000003fffdd98dfa in free () from /lib64/libc.so.6
#5  0x0000000001005994 in util_ptr_vec_free (count=<optimized out>, ptr_vec=0x101de90) at ../include/lib/util_base.h:46
#6  util_scandir_free (de_vec=0x101de90, count=<optimized out>) at util_scandir.c:174
#7  0x00000000010043ce in print_defunct_devices (rec=rec@entry=0x10114f0,
    path=path@entry=0x101cc80 "/sys/devices/css0/defunct") at lscss.c:678
#8  0x0000000001004cfe in print_subchannels_of_type (type_requested=type_requested@entry=SUBCHANNEL_TYPE_IO,
    rec=rec@entry=0x10114f0) at lscss.c:726
#9  0x0000000001003888 in cmd_lscss () at lscss.c:761
#10 main (argc=<optimized out>, argv=<optimized out>) at lscss.c:932

Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
edb75870b5 cpumf_helper.in: Fix output of shortdesc
The cpumf_helper.in is called to parse counter definition
files stored in /usr/share/s390-tools/cpumf directory and
returns perl references to be examined by other perl tools
such as lsctrdef.

cpumf_helper.in expects several keywords in the counter
definition files, one is 'shortdesc' which contains
a short description of the purpose of the counter.

However this short description not is stored in the hash
field shortdesc keyed by counter number 'ctr' because the
wrong key is used.

Output before:
{
  '64' => {
            'desc' => 'Total number of the PRNG functions issued by the CPU',
            'name' => 'PRNG_FUNCTIONS',
            'set' => 8
          },
  '65' => {
            'desc' => 'Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU',
            'name' => 'PRNG_CYCLES',
            'set' => 8
          },
  ....
  'ctr' => {   <-------- WRONG
             'shortdesc' => 'AES Blocked Cycles'
           }
}

Output with this patch:
{
  '64' => {
            'desc' => 'Total number of the PRNG functions issued by the CPU',
            'name' => 'PRNG_FUNCTIONS',
            'set' => 8,
            'shortdesc' => 'PRNG Functions'
          },
  '65' => {
            'desc' => 'Total number of CPU cycles when the DEA/AES coprocessor is busy performing PRNG functions issued by the CPU',
            'name' => 'PRNG_CYCLES',
            'set' => 8,
            'shortdesc' => 'PRNG Cycles'
          },
  ...
}

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
a3c746846d cpumf: add missing Description: tag for z13/z14/ctr:128
Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
4044accf03 vmcp: Use libutil functions util_prg and util_opt
Use helper functions in libutil for command line parsing
and help text output.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
943e7e7198 vmcp: Use libvmcp and remove local vmcp code
Use the new libvmcp.a to send commands to z/VM CP.
The error messages remain unchanged.

Local header file vmcp.h now only contains variable definitions
and some defines used by vmcp.c. Move them to the source file
and remove the now empty header file.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
4f00cb6346 vmur: Use libvmcp and remove local vmcp code
Use the new libvmcp.a to send commands to z/VM CP.
The error messages remain unchanged.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
9d55086720 lsqeth: Use libvmcp and remove local vmcp code
Use the new libvmcp.a to send commands to z/VM CP.
The error messages remain unchanged.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
eaa2ef6ba4 libvmcp: Add common vmcp code to the lib
This patch prevents code duplication in vmcp related programs.
Some applications such as vmur, vmcp, and lsqeth
use z/VM CP commands to query information. Each program
uses its own defines and code.

Supply a library and common header file to use common code.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Reviewed-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
Reviewed-by: Jan Höppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Mikhail Zaslonko
37c3752b31 zgetdump: Remove unused function prototype
Signed-off-by: Mikhail Zaslonko <zaslonko@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Philipp Rudo
8585efadbe zipl: Remove unused inline assembly load
Signed-off-by: Philipp Rudo <prudo@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Harald Freudenberger
13648dd6f4 zcrypt: Corrections at the chzcrypt man page.
Fixed typo and added one sentence to explain more details
about online switching of queue devices.

Signed-off-by: Harald Freudenberger <freude@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
427dff3450 s390-tools: Move function util_strstrip
This patch
 - moves function util_strstrip to libutil/util_libc.c and deletes the
   extra files util_strstip.[ch]
 - adds doxygen comments for util_strstrip()
 - provides an example on how to use util_strstrip().

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Stefan Haberland
08bc0a947a zipl: fix some warnings in zipl_helper
Fix some warnings found by sparse.
Declare one function static and change static variables to defines.

Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Stefan Haberland
c3d583fe9c zipl: remove unused include
Remove unused include to fix an error reported by make C=1.

  CHECK   zipl/src/zipl_helper.device-mapper.o
../../include/lib/dasd_base.h:159:20: error: redefinition of struct hd_geometry
../../common.mak:234: recipe for target 'zipl_helper.device-mapper.o' failed
make: *** [zipl_helper.device-mapper.o] Error 1

The structure hd_geometry is defined in dasd_base.h.

Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Gerald Schaefer
983a72dab9 hmcdrvfs: fix parsing of link count >= 1000
hmcdrvfs will ignore files with a link count >= 1000, due to an inconsistency
in the input data. The parsing code relies on having spaces between the
different fields in its input data. When a file has a link count >= 1000,
there will be no space, and the "link count" field will be placed directly
after the previous "mode" field. This will confuse the parser, and all such
files will not be accesible.

The "mode" field will never contain digits, so in order to fix this issue,
the parser can recognize the "link count" field by the presence of a digit.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
811152c08a s390-tools: Use util_strstrip in vmur
Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Thomas Richter
6a1b9cf10a s390-tools: Add function util_strstrip
Function strstrip strips leading and trailung
spaces from a given string.
During review it was decided to move this function
to the libutil library to make it available for other tools.

Signed-off-by: Thomas Richter <tmricht@linux.vnet.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2018-05-07 13:42:03 +02:00
Rafael Fonseca
599b141b8a zipl: Rewrite helper script in C
To remove the perl dependency from zipl rewrite the helper script in C.

Closes: #18

Signed-off-by: Rafael Fonseca <r4f4rfs@gmail.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:39:10 +01:00
Sebastian Ott
b9e47e356b dbginfo: gather nvme related data
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:38:08 +01:00
Michael Holzheu
5e2a477bbf zfcpdump: Remove file system check from zfcpdump_initramfs.txt
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:37:05 +01:00
Michael Holzheu
bba34cb975 zfcpdump: Add /dev/sda to zfcpdump_initramfs.txt
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:36:43 +01:00
Michael Holzheu
a674011c0d zgetdump: Remove superfluous member 'size'
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:36:27 +01:00
Michael Holzheu
c78b5cd2ba zgetdump: Remove superfluous members from dfi_mem_chunk
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:36:08 +01:00
Michael Holzheu
f3e374ac77 zgetdump: Fix typo
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-02-16 10:35:22 +01:00
Michael Holzheu
1e6a9dbd56 AUTHORS: Cleanup
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2018-01-30 17:02:50 +01:00
Stefan Haberland
564a2601f6 Prepare for next release
Signed-off-by: Stefan Haberland <sth@linux.vnet.ibm.com>
2018-01-30 16:01:36 +01:00
87 changed files with 9780 additions and 2281 deletions

2
.gitignore vendored
View File

@@ -46,6 +46,7 @@ libutil/util_prg_example
libutil/util_rec_example
libutil/util_scandir_example
libzds/libzds.a
libvmcp/vmcp_example
mon_tools/mon_fsstatd
mon_tools/mon_procd
osasnmpd/osasnmpd
@@ -86,4 +87,5 @@ zipl/boot/*.exec
zipl/boot/data.h
zipl/src/chreipl_helper.device-mapper
zipl/src/zipl
zipl/src/zipl_helper.device-mapper
zkey/zkey

View File

@@ -14,7 +14,6 @@ List of all individuals having contributed content to s390-tools
- Christof Schmitt
- Claudio Imbrenda
- Clemens von Mann
- cvs2git
- Dan Horak
- Despina Papadopoulou
- Eberhard Pasch
@@ -22,7 +21,6 @@ List of all individuals having contributed content to s390-tools
- Erwin Vicari
- Eugene Crosser
- Eugene Dvurechenski
- Eugene (jno) Dvurechenski
- Farhan Ali
- Fedor Loshakov
- Felix Beck
@@ -62,7 +60,6 @@ List of all individuals having contributed content to s390-tools
- Martin Schwidefsky
- Maxim Shchetynin
- Melissa Howland
- Michael
- Michael Ernst
- Michael Holzheu
- Michael Mueller
@@ -77,11 +74,9 @@ List of all individuals having contributed content to s390-tools
- Ralph Wuerthner
- Rene Trumpp
- Rolf Schaefer
- root
- Sa Liu
- Sascha Silbe
- Sebastian Ott
- Seshagiri N Ippili
- Seshagiri N. Ippili
- Simon Sturm
- Stefan Bader
@@ -101,6 +96,7 @@ List of all individuals having contributed content to s390-tools
- Thomas Weber
- Ursula Braun
- Utz Bacher
- Vasily Gorbik
- Viktor Mihajlovski
- Volker Sameske
- Wolfgang Taphorn

View File

@@ -1,6 +1,29 @@
Release history for s390-tools (MIT version)
--------------------------------------------
* __v2.4.0 (2018-05-07)__
For Linux kernel version: 4.16
Changes of existing tools:
- dbginfo: Gather nvme related data
- zipl: Rewrite helper script in C
- libutil: Add function util_strstrip
- libvmcp: Introduce libvmcp
- zipl: Extend DASD stand-alone dumpers to drop zero pages
- zgetdump: Add verbose option
- zgetdump: Add 'Dump file size' field for zgetdump -i output
- cpumf: Add IBM z14 ZR1 to the CPU Measurement Facility model list
- zkey: Add build dependency to OpenSSL (libcrypto)
- zkey: Add keystore implementation
Bug Fixes:
- hmcdrvfs: fix parsing of link count >= 1000
- zgetdump: Avoid Segfault on processing dumps with memory limit
- chreipl: correct fcp reipl sysfs write sequence
- udev: Replace WAIT_FOR with TEST keyword
* __v2.3.0 (2018-01-30)__
For Linux kernel version: 4.15

View File

@@ -3,7 +3,7 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
# Include common definitions
include common.mak
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw libvmcp
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \

View File

@@ -264,6 +264,7 @@ build options:
| pfm | `HAVE_PFM` | cpacfstats |
| net-snmp | `HAVE_SNMP` | osasnmpd |
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
| openssl | `HAVE_OPENSSL` | zkey |
This table lists additional build or install options:
@@ -366,3 +367,12 @@ the different tools are provided:
For running znetconf these programs are required:
- modprobe (kmod)
- vmcp (s390-tools)
* zkey:
For building the zkey tools you need openssl version 0.9.7 or newer installed
(openssl-devel.rpm). Tip: you may skip the zkey build by adding
`HAVE_OPENSSL=0` to the make invocation.
A new group 'zkeyadm' needs to be created and all users intending to use the
tool must be added to this group. The owner of the default key repository
'/etc/zkey/repository' must be set to group 'zkeyadm' with write permission
for this group.

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 = 3
RELEASE = 4
PATCHLEVEL = 0
DISTRELEASE = build-$(shell date +%Y%m%d)
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
@@ -338,6 +338,10 @@ $(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
.PHONY: $(rootdir)/libvmdump
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
.PHONY: $(rootdir)/libvmcp
$(rootdir)/zipl/boot/data.o:
$(MAKE) -C $(rootdir)/zipl/boot/ data.o

3
cpumf/bin/cpumf_helper.in Normal file → Executable file
View File

@@ -172,7 +172,7 @@ sub cpumf_parse_ctrdef($;$)
# Parse short description (optional)
if ($line =~ m/^Short-Description:\s*(\S.*)?$/) {
$h->{ctr}->{shortdesc} = $1 || "";
$h->{$ctr}->{shortdesc} = $1 || "";
# Parse start of counter description
} elsif ($line =~ m/^Description:\s*(\S.*)?$/) {
@@ -211,6 +211,7 @@ my $system_z_hwtype_map = {
2964 => 'IBM z13',
2965 => 'IBM z13s',
3906 => 'IBM z14',
3907 => 'IBM z14 ZR1',
};
sub get_hardware_type()

View File

@@ -1,48 +1,60 @@
Counter: 0 Name:CPU_CYCLES
Short-Description:CPU Cycles
Description:
Cycle Count
.
Counter: 1 Name:INSTRUCTIONS
Short-Description:Instructions
Description:
Instruction Count
.
Counter: 2 Name:L1I_DIR_WRITES
Short-Description:L1I Directory Writes
Description:
Level-1 I-Cache Directory Write Count
.
Counter: 3 Name:L1I_PENALTY_CYCLES
Short-Description:L1I Penalty Cycles
Description:
Level-1 I-Cache Penalty Cycle Count
.
Counter: 4 Name:L1D_DIR_WRITES
Short-Description:L1D Directory Writes
Description:
Level-1 D-Cache Directory Write Count
.
Counter: 5 Name:L1D_PENALTY_CYCLES
Short-Description:L1D Penalty Cycles
Description:
Level-1 D-Cache Penalty Cycle Count
.
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
Short-Description:Problem-State CPU Cycles
Description:
Problem-State Cycle Count
.
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
Short-Description:Problem-State Instructions
Description:
Problem-State Instruction Count
.
Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES
Short-Description:Problem-State L1I Directory Writes
Description:
Problem-State Level-1 I-Cache Directory Write Count
.
Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES
Short-Description:Problem-State L1I Penalty Cycles
Description:
Problem-State Level-1 I-Cache Penalty Cycle Count
.
Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES
Short-Description:Problem-State L1D Directory Writes
Description:
Problem-State Level-1 D-Cache Directory Write Count
.
Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES
Short-Description:Problem-State L1D Penalty Cycles
Description:
Problem-State Level-1 D-Cache Penalty Cycle Count
.

View File

@@ -1,32 +1,40 @@
Counter: 0 Name:CPU_CYCLES
Short-Description:CPU Cycles
Description:
Cycle Count
.
Counter: 1 Name:INSTRUCTIONS
Short-Description:Instructions
Description:
Instruction Count
.
Counter: 2 Name:L1I_DIR_WRITES
Short-Description:L1I Directory Writes
Description:
Level-1 I-Cache Directory Write Count
.
Counter: 3 Name:L1I_PENALTY_CYCLES
Short-Description:L1I Penalty Cycles
Description:
Level-1 I-Cache Penalty Cycle Count
.
Counter: 4 Name:L1D_DIR_WRITES
Short-Description:L1D Directory Writes
Description:
Level-1 D-Cache Directory Write Count
.
Counter: 5 Name:L1D_PENALTY_CYCLES
Short-Description:L1D Penalty Cycles
Description:
Level-1 D-Cache Penalty Cycle Count
.
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
Short-Description:Problem-State CPU Cycles
Description:
Problem-State Cycle Count
.
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
Short-Description:Problem-State Instructions
Description:
Problem-State Instruction Count
.

View File

@@ -1,82 +1,98 @@
Counter: 64 Name:PRNG_FUNCTIONS
Short-Description:PRNG Functions
Description:
Total number of the PRNG functions issued by the CPU
.
Counter: 65 Name:PRNG_CYCLES
Short-Description:PRNG Cycles
Description:
Total number of CPU cycles when the DEA/AES coprocessor is busy
performing PRNG functions issued by the CPU
.
Counter: 66 Name:PRNG_BLOCKED_FUNCTIONS
Short-Description:PRNG Blocked Functions
Description:
Total number of the PRNG functions that are issued by the CPU and are
blocked because the DEA/AES coprocessor is busy performing a function
issued by another CPU
.
Counter: 67 Name:PRNG_BLOCKED_CYCLES
Short-Description:PRNG Blocked Cycles
Description:
Total number of CPU cycles blocked for the PRNG functions issued by
the CPU because the DEA/AES coprocessor is busy performing a function
issued by another CPU
.
Counter: 68 Name:SHA_FUNCTIONS
Short-Description:SHA Functions
Description:
Total number of SHA functions issued by the CPU
.
Counter: 69 Name:SHA_CYCLES
Short-Description:SHA Cycles
Description:
Total number of CPU cycles when the SHA coprocessor is busy performing
the SHA functions issued by the CPU
.
Counter: 70 Name:SHA_BLOCKED_FUNCTIONS
Short-Description:SHA Blocked Functions
Description:
Total number of the SHA functions that are issued by the CPU and are
blocked because the SHA coprocessor is busy performing a function issued
by another CPU
.
Counter: 71 Name:SHA_BLOCKED_CYCLES
Short-Description:SHA Bloced Cycles
Description:
Total number of CPU cycles blocked for the SHA functions issued by the
CPU because the SHA coprocessor is busy performing a function issued
by another CPU
.
Counter: 72 Name:DEA_FUNCTIONS
Short-Description:DEA Functions
Description:
Total number of the DEA functions issued by the CPU
.
Counter: 73 Name:DEA_CYCLES
Short-Description:DEA Cycles
Description:
Total number of CPU cycles when the DEA/AES coprocessor is busy
performing the DEA functions issued by the CPU
.
Counter: 74 Name:DEA_BLOCKED_FUNCTIONS
Short-Description:DEA Blocked Functions
Description:
Total number of the DEA functions that are issued by the CPU and are
blocked because the DEA/AES coprocessor is busy performing a function
issued by another CPU
.
Counter: 75 Name:DEA_BLOCKED_CYCLES
Short-Description:DEA Blocked Cycles
Description:
Total number of CPU cycles blocked for the DEA functions issued by the
CPU because the DEA/AES coprocessor is busy performing a function issued
by another CPU
.
Counter: 76 Name:AES_FUNCTIONS
Short-Description:AES Functions
Description:
Total number of AES functions issued by the CPU
.
Counter: 77 Name:AES_CYCLES
Short-Description:AES Cycles
Description:
Total number of CPU cycles when the DEA/AES coprocessor is busy
performing the AES functions issued by the CPU
.
Counter: 78 Name:AES_BLOCKED_FUNCTIONS
Short-Description:AES Blocked Functions
Description:
Total number of AES functions that are issued by the CPU and are blocked
because the DEA/AES coprocessor is busy performing a function issued
by another CPU
.
Counter: 79 Name:AES_BLOCKED_CYCLES
Short-Description:AES Blocked Cycles
Description:
Total number of CPU cycles blocked for the AES functions issued by the
CPU because the DEA/AES coprocessor is busy performing a function issued

View File

@@ -1,96 +1,114 @@
Counter: 128 Name:L1I_L2_SOURCED_WRITES
Short-Description:L1I L2 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from the Level-2 (L1.5) cache
.
Counter: 129 Name:L1D_L2_SOURCED_WRITES
Short-Description:L1D L2 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the installed
cache line was sourced from the Level-2 (L1.5) cache
.
Counter: 130 Name:L1I_L3_LOCAL_WRITES
Short-Description:L1I L3 Local Writes
Description:
A directory write to the Level-1 I-Cache directory where the installed
cache line was sourced from the Level-3 cache that is on the same book
as the Instruction cache (Local L2 cache)
.
Counter: 131 Name:L1D_L3_LOCAL_WRITES
Short-Description:L1D L3 Local Writes
Description:
A directory write to the Level-1 D-Cache directory where the installtion
cache line was source from the Level-3 cache that is on the same book
as the Data cache (Local L2 cache)
.
Counter: 132 Name:L1I_L3_REMOTE_WRITES
Short-Description:L1I L3 Remote Writes
Description:
A directory write to the Level-1 I-Cache directory where the installed
cache line was sourced from a Level-3 cache that is not on the same
book as the Instruction cache (Remote L2 cache)
.
Counter: 133 Name:L1D_L3_REMOTE_WRITES
Short-Description:L1D L3 Remote Writes
Description:
A directory write to the Level-1 D-Cache directory where the installed
cache line was sourced from a Level-3 cache that is not on the same
book as the Data cache (Remote L2 cache)
.
Counter: 134 Name:L1D_LMEM_SOURCED_WRITES
Short-Description:L1D Local Memory Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the installed
cache line was sourced from memory that is attached to the same book
as the Data cache (Local Memory)
.
Counter: 135 Name:L1I_LMEM_SOURCED_WRITES
Short-Description:L1I Local Memory Sourced Writes
Description:
A directory write to the Level-1 I-Cache where the installed cache
line was sourced from memory that is attached to the s ame book as the
Instruction cahe (local Memory)
Instruction cache (Local Memory)
.
Counter: 136 Name:L1D_RO_EXCL_WRITES
Short-Description:L1D Read-only Exclusive Writes
Description:
A directory write to the Level-1 D-Cache where the line was originally
in a Read-Only state in the cache but has been updated to be in the
Exclusive state that allows stores to the cache line
.
Counter: 137 Name:L1I_CACHELINE_INVALIDATES
Short-Description:L1I Cacheline Invalidates
Description:
A cache line in the Level-1 I-Cache has been invalidated by a store on
the same CPU as the Level-1 I-Cache
.
Counter: 138 Name:ITLB1_WRITES
Short-Description:ITLB1 Writes
Description:
A translation entry has been written into the Level-1 Instruction
Translation Lookaside Buffer
.
Counter: 139 Name:DTLB1_WRITES
Short-Description:DTLB1 Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer
.
Counter: 140 Name:TLB2_PTE_WRITES
Short-Description:TLB2 PTE Writes
Description:
A translation entry has been written to the Level-2 TLB Page Table
Entry arrays
.
Counter: 141 Name:TLB2_CRSTE_WRITES
Short-Description:TLB2 CRSTE Writes
Description:
A translation entry has been written to the Level-2 TLB Common Region
Segment Table Entry arrays
.
Counter: 142 Name:TLB2_CRSTE_HPAGE_WRITES
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-2 TLB Common Region
Segment Table Entry arrays for a one-megabyte large page translation
.
Counter: 145 Name:ITLB1_MISSES
Short-Description:ITLB1 Misses
Description:
Level-1 Instruction TLB miss in progress. Incremented by one for every
cycle an ITLB1 miss is in progress
.
Counter: 146 Name:DTLB1_MISSES
Short-Description:DTLB1 Misses
Description:
Level-1 Data TLB miss in progress. Incremented by one for every cycle
an DTLB1 miss is in progress
.
Counter: 147 Name:L2C_STORES_SENT
Short-Description:L2C Stores Sent
Description:
Incremented by one for every store sent to Level-2 (L1.5) cache
.

View File

@@ -16,288 +16,343 @@
#
# Extended Counter Set
# ---------------------------------------------------------------------
Counter:128 Name:L1D_WRITES_RO_EXCL
Counter:128 Name:L1D_RO_EXCL_WRITES
Short-Description:L1D Read-only Exclusive Writes
Description:
A directory write to the Level-1 Data cache where the line was
originally in a Read-Only state in the cache but has been updated
to be in the Exclusive state that allows stores to the cache line.
.
Counter:129 Name:DTLB1_WRITES
Short-Description:DTLB1 Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer
.
Counter:130 Name:DTLB1_MISSES
Short-Description:DTLB1 Misses
Description:
Level-1 Data TLB miss in progress. Incremented by one for every cycle
a DTLB1 miss is in progress.
.
Counter:131 Name:DTLB1_HPAGE_WRITES
Short-Description:DTLB1 One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer for a one-megabyte page
.
Counter:132 Name:DTLB1_GPAGE_WRITES
Short-Description:DTLB1 Two-Gigabyte Page Writes
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer for a two-gigabyte page.
.
Counter:133 Name:L1D_L2D_SOURCED_WRITES
Short-Description:L1D L2D Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from the Level-2 Data cache
.
Counter:134 Name:ITLB1_WRITES
Short-Description:ITLB1 Writes
Description:
A translation entry has been written to the Level-1 Instruction
Translation Lookaside Buffer
.
Counter:135 Name:ITLB1_MISSES
Short-Description:ITLB1 Misses
Description:
Level-1 Instruction TLB miss in progress. Incremented by one for every
cycle an ITLB1 miss is in progress
.
Counter:136 Name:L1I_L2I_SOURCED_WRITES
Short-Description:L1I L2I Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from the Level-2 Instruction cache
.
Counter:137 Name:TLB2_PTE_WRITES
Short-Description:TLB2 PTE Writes
Description:
A translation entry has been written to the Level-2 TLB Page Table
Entry arrays
.
Counter:138 Name:TLB2_CRSTE_HPAGE_WRITES
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-2 TLB Combined Region
Segment Table Entry arrays for a one-megabyte large page translation
.
Counter:139 Name:TLB2_CRSTE_WRITES
Short-Description:TLB2 CRSTE Writes
Description:
A translation entry has been written to the Level-2 TLB Combined Region
Segment Table Entry arrays
.
Counter:140 Name:TX_C_TEND
Short-Description:Completed TEND instructions in constrained TX mode
Description:
A TEND instruction has completed in a constrained transactional-execution
mode
.
Counter:141 Name:TX_NC_TEND
Short-Description:Completed TEND instructions in non-constrained TX mode
Description:
A TEND instruction has completed in a non-constrained
transactional-execution mode
.
Counter:143 Name:L1C_TLB1_MISSES
Short-Description:L1C TLB1 Misses
Description:
Increments by one for any cycle where a Level-1 cache or Level-1 TLB miss
is in progress.
.
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1D On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Chip Level-3 cache without intervention
.
Counter:145 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Chip Level-3 cache with intervention
.
Counter:146 Name:L1D_ONNODE_L4_SOURCED_WRITES
Short-Description:L1D On-Node L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Node Level-4 cache
.
Counter:147 Name:L1D_ONNODE_L3_SOURCED_WRITES_IV
Short-Description:L1D On-Node L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Node Level-3 cache with intervention
.
Counter:148 Name:L1D_ONNODE_L3_SOURCED_WRITES
Short-Description:L1D On-Node L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Node Level-3 cache without intervention
.
Counter:149 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
Short-Description:L1D On-Drawer L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Drawer Level-4 cache
.
Counter:150 Name:L1D_ONDRAWER_L3_SOURCED_WRITES_IV
Short-Description:L1D On-Drawer L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Drawer Level-3 cache with intervention
.
Counter:151 Name:L1D_ONDRAWER_L3_SOURCED_WRITES
Short-Description:L1D On-Drawer L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Drawer Level-3 cache without intervention
.
Counter:152 Name:L1D_OFFDRAWER_SCOL_L4_SOURCED_WRITES
Short-Description:L1D Off-Drawer Same-Column L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Same-Column Level-4 cache
.
Counter:153 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
Short-Description:L1D Off-Drawer Same-Column L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Same-Column Level-3 cache with
intervention
.
Counter:154 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES
Short-Description:L1D Off-Drawer Same-Column L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Same-Column Level-3 cache
without intervention
.
Counter:155 Name:L1D_OFFDRAWER_FCOL_L4_SOURCED_WRITES
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Far-Column Level-4 cache
.
Counter:156 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Far-Column Level-3 cache with
intervention
.
Counter:157 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Far-Column Level-3 cache
without intervention
.
Counter:158 Name:L1D_ONNODE_MEM_SOURCED_WRITES
Short-Description:L1D On-Node Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Node memory
.
Counter:159 Name:L1D_ONDRAWER_MEM_SOURCED_WRITES
Short-Description:L1D On-Drawer Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Drawer memory
.
Counter:160 Name:L1D_OFFDRAWER_MEM_SOURCED_WRITES
Short-Description:L1D Off-Drawer Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Drawer memory
.
Counter:161 Name:L1D_ONCHIP_MEM_SOURCED_WRITES
Short-Description:L1D On-Chip Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Chip memory
.
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1I On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On-Chip Level-3 cache without
intervention
.
Counter:163 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On Chip Level-3 cache with
intervention
.
Counter:164 Name:L1I_ONNODE_L4_SOURCED_WRITES
Short-Description:L1I On-Chip L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On-Node Level-4 cache
.
Counter:165 Name:L1I_ONNODE_L3_SOURCED_WRITES_IV
Short-Description:L1I On-Node L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an On-Node Level-3 cache
with intervention
.
Counter:166 Name:L1I_ONNODE_L3_SOURCED_WRITES
Short-Description:L1I On-Node L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an On-Node Level-3 cache
without intervention
.
Counter:167 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
Short-Description:L1I On-Drawer L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an On-Drawer Level-4 cache
.
Counter:168 Name:L1I_ONDRAWER_L3_SOURCED_WRITES_IV
Short-Description:L1I On-Drawer L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an On-Drawer Level-3 cache
with intervention
.
Counter:169 Name:L1I_ONDRAWER_L3_SOURCED_WRITES
Short-Description:L1I On-Drawer L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an On-Drawer Level-3 cache
without intervention
.
Counter:170 Name:L1I_OFFDRAWER_SCOL_L4_SOURCED_WRITES
Short-Description:L1I Off-Drawer Same-Column L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an Off-Drawer Same-Column
Level-4 cache
.
Counter:171 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
Short-Description:L1I Off-Drawer Same-Column L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an Off-Drawer Same-Column
Level-3 cache with intervention
.
Counter:172 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES
Short-Description:L1I Off-Drawer Same-Column L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an Off-Drawer Same-Column
Level-3 cache without intervention
.
Counter:173 Name:L1I_OFFDRAWER_FCOL_L4_SOURCED_WRITES
Short-Description:L1I Off-Drawer Far-Column L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an Off-Drawer Far-Column
Level-4 cache
.
Counter:174 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
Short-Description:L1I Off-Drawer Far-Column L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an Off-Drawer Far-Column
Level-3 cache with intervention
.
Counter:175 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES
Short-Description:L1I Off-Drawer Far-Column L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from an Off-Drawer Far-Column
Level-3 cache without intervention
.
Counter:176 Name:L1I_ONNODE_MEM_SOURCED_WRITES
Short-Description:L1I On-Node Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from On-Node memory
.
Counter:177 Name:L1I_ONDRAWER_MEM_SOURCED_WRITES
Short-Description:L1I On-Drawer Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from On-Drawer memory
.
Counter:178 Name:L1I_OFFDRAWER_MEM_SOURCED_WRITES
Short-Description:L1I Off-Drawer Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from On-Drawer memory
.
Counter:179 Name:L1I_ONCHIP_MEM_SOURCED_WRITES
Short-Description:L1I On-Chip Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where
the returned cache line was sourced from On-Chip memory
.
Counter:218 Name:TX_NC_TABORT
Short-Description:Aborted transactions in non-constrained TX mode
Description:
A transaction abort has occurred in a non-constrained
transactional-execution mode
.
Counter:219 Name:TX_C_TABORT_NO_SPECIAL
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
Description:
A transaction abort has occurred in a constrained transactional-execution
mode and the CPU is not using any special logic to allow the transaction
to complete
.
Counter:220 Name:TX_C_TABORT_SPECIAL
Short-Description:Aborted transactions in constrained TX mode using special completion logic
Description:
A transaction abort has occurred in a constrained transactional-execution
mode and the CPU is using special logic to allow the transaction to
@@ -307,10 +362,12 @@ complete
# MT-diagnostic counter set
# ---------------------------------------------------------------------
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
Short-Description:Cycle count with one thread active
Description:
Cycle count with one thread active
.
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
Short-Description:Cycle count with two threads active
Description:
Cycle count with two threads active
.

View File

@@ -19,272 +19,324 @@
#
# Extended Counter Set
# ---------------------------------------------------------------------
Counter:128 Name:L1D_WRITES_RO_EXCL
Counter:128 Name:L1D_RO_EXCL_WRITES
Short-Description:L1D Read-only Exclusive Writes
Description:
A directory write to the Level-1 Data cache where the line was
originally in a Read-Only state in the cache but has been updated
to be in the Exclusive state that allows stores to the cache line
.
Counter:129 Name:DTLB2_WRITES
Short-Description:DTLB2 Writes
Description:
A translation has been written into The Translation Lookaside
Buffer 2 (TLB2) and the request was made by the data cache
.
Counter:130 Name:DTLB2_MISSES
Short-Description:DTLB2 Misses
Description:
A TLB2 miss is in progress for a request made by the data cache.
Incremented by one for every TLB2 miss in progress for the Level-1
Data cache on this cycle
.
Counter:131 Name:DTLB2_HPAGE_WRITES
Short-Description:DTLB2 One-Megabyte Page Writes
Description:
A translation entry was written into the Combined Region and Segment
Table Entry array in the Level-2 TLB for a one-megabyte page or a
Last Host Translation was done
.
Counter:132 Name:DTLB2_GPAGE_WRITES
Short-Description:DTLB2 Two-Gigabyte Page Writes
Description:
A translation entry for a two-gigabyte page was written into the
Level-2 TLB
.
Counter:133 Name:L1D_L2D_SOURCED_WRITES
Short-Description:L1D L2D Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the
returned cache line was sourced from the Level-2 Data cache
.
Counter:134 Name:ITLB2_WRITES
Short-Description:ITLB2 Writes
Description:
A translation entry has been written into the Translation Lookaside
Buffer 2 (TLB2) and the request was made by the instruction cache
.
Counter:135 Name:ITLB2_MISSES
Short-Description:ITLB2 Misses
Description:
A TLB2 miss is in progress for a request made by the instruction cache.
Incremented by one for every TLB2 miss in progress for the Level-1
Instruction cache in a cycle
.
Counter:136 Name:L1I_L2I_SOURCED_WRITES
Short-Description:L1I L2I Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from the Level-2 Instruction cache
.
Counter:137 Name:TLB2_PTE_WRITES
Short-Description:TLB2 PTE Writes
Description:
A translation entry was written into the Page Table Entry array in the
Level-2 TLB
.
Counter:138 Name:TLB2_CRSTE_WRITES
Short-Description:TLB2 CRSTE Writes
Description:
Translation entries were written into the Combined Region and Segment
Table Entry array and the Page Table Entry array in the Level-2 TLB
.
Counter:139 Name:TLB2_ENGINES_BUSY
Short-Description:TLB2 Engines Busy
Description:
The number of Level-2 TLB translation engines busy in a cycle
.
Counter:140 Name:TX_C_TEND
Short-Description:Completed TEND instructions in constrained TX mode
Description:
A TEND instruction has completed in a constrained transactional-execution
mode
.
Counter:141 Name:TX_NC_TEND
Short-Description:Completed TEND instructions in non-constrained TX mode
Description:
A TEND instruction has completed in a non-constrained
transactional-execution mode
.
Counter:143 Name:L1C_TLB2_MISSES
Short-Description:L1C TLB2 Misses
Description:
Increments by one for any cycle where a level-1 cache or level-2 TLB miss
is in progress
.
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1D On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Chip Level-3 cache without intervention
.
Counter:145 Name:L1D_ONCHIP_MEMORY_SOURCED_WRITES
Short-Description:L1D On-Chip Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Chip memory
.
Counter:146 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Chip Level-3 cache with intervention
.
Counter:147 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES
Short-Description:L1D On-Cluster L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Cluster Level-3 cache withountervention
.
Counter:148 Name:L1D_ONCLUSTER_MEMORY_SOURCED_WRITES
Short-Description:L1D On-Cluster Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Cluster memory
.
Counter:149 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES_IV
Short-Description:L1D On-Cluster L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On-Cluster Level-3 cache with intervention
.
Counter:150 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES
Short-Description:L1D Off-Cluster L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Cluster Level-3 cache without
intervention
.
Counter:151 Name:L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES
Short-Description:L1D Off-Cluster Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from Off-Cluster memory
.
Counter:152 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV
Short-Description:L1D Off-Cluster L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Cluster Level-3 cache with intervention
.
Counter:153 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES
Short-Description:L1D Off-Drawer L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Level-3 cache without
intervention
.
Counter:154 Name:L1D_OFFDRAWER_MEMORY_SOURCED_WRITES
Short-Description:L1D Off-Drawer Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from Off-Drawer memory
.
Counter:155 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES_IV
Short-Description:L1D Off-Drawer L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off-Drawer Level-3 cache with intervention
.
Counter:156 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
Short-Description:L1D On-Drawer L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Drawer Level-4 cache
.
Counter:157 Name:L1D_OFFDRAWER_L4_SOURCED_WRITES
Short-Description:L1D Off-Drawer L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from Off-Drawer Level-4 cache
.
Counter:158 Name:L1D_ONCHIP_L3_SOURCED_WRITES_RO
Short-Description:L1D On-Chip L3 Sourced Writes read-only
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from On-Chip L3 but a read-only invalidate was
done to remove other copies of the cache line
.
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1I On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache ine was sourced from an On-Chip Level-3 cache without
intervention
.
Counter:163 Name:L1I_ONCHIP_MEMORY_SOURCED_WRITES
Short-Description:L1I On-Chip Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache ine was sourced from On-Chip memory
.
Counter:164 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache ine was sourced from an On-Chip Level-3 cache with
intervention
.
Counter:165 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES
Short-Description:L1I On-Cluster L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On-Cluster Level-3 cache without
intervention
.
Counter:166 Name:L1I_ONCLUSTER_MEMORY_SOURCED_WRITES
Short-Description:L1I On-Cluster Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On-Cluster memory
.
Counter:167 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES_IV
Short-Description:L1I On-Cluster L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from On-Cluster Level-3 cache with
intervention
.
Counter:168 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES
Short-Description:L1I Off-Cluster L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off-Cluster Level-3 cache without
intervention
.
Counter:169 Name:L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES
Short-Description:L1I Off-Cluster Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from Off-Cluster memory
.
Counter:170 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV
Short-Description:L1I Off-Cluster L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off-Cluster Level-3 cache with
intervention
.
Counter:171 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES
Short-Description:L1I Off-Drawer L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off-Drawer Level-3 cache without
intervention
.
Counter:172 Name:L1I_OFFDRAWER_MEMORY_SOURCED_WRITES
Short-Description:L1I Off-Drawer Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from Off-Drawer memory
.
Counter:173 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES_IV
Short-Description:L1I Off-Drawer L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off-Drawer Level-3 cache with
intervention
.
Counter:174 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
Short-Description:L1I On-Drawer L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from On-Drawer Level-4 cache
.
Counter:175 Name:L1I_OFFDRAWER_L4_SOURCED_WRITES
Short-Description:L1I Off-Drawer L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from Off-Drawer Level-4 cache
.
Counter:224 Name:BCD_DFP_EXECUTION_SLOTS
Short-Description:BCD DFP Execution Slots
Description:
Count of floating point execution slots used for finished Binary Coded
Decimal to Decimal Floating Point conversions. Instructions: CDZT,
CXZT, CZDT, CZXT
.
Counter:225 Name:VX_BCD_EXECUTION_SLOTS
Short-Description:VX BCD Execution Slots
Description:
Count of floating point execution slots used for finished vector arithmetic
Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP,
VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG
.
Counter:226 Name:DECIMAL_INSTRUCTIONS
Short-Description:Decimal Instructions
Description:
Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED,
EDMK, MP, SRP, SP, ZAP
.
Counter:232 Name:LAST_HOST_TRANSLATIONS
Short-Description:Last host translation done
Description:
Last Host Translation done
.
Counter:243 Name:TX_NC_TABORT
Short-Description:Aborted transactions in non-constrained TX mode
Description:
A transaction abort has occurred in a non-constrained
transactional-execution mode
.
Counter:244 Name:TX_C_TABORT_NO_SPECIAL
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
Description:
A transaction abort has occurred in a constrained transactional-execution
mode and the CPU is not using any special logic to allow the transaction
to complete
.
Counter:245 Name:TX_C_TABORT_SPECIAL
Short-Description:Aborted transactions in constrained TX mode using special completion logic
Description:
A transaction abort has occurred in a constrained transactional-execution
mode and the CPU is using special logic to allow the transaction to
@@ -294,10 +346,12 @@ complete
# MT-diagnostic counter set
# ---------------------------------------------------------------------
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
Short-Description:Cycle count with one thread active
Description:
Cycle count with one thread active
.
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
Short-Description:Cycle count with two threads active
Description:
Cycle count with two threads active
.

View File

@@ -1,121 +1,145 @@
Counter: 128 Name:L1D_L2_SOURCED_WRITES
Short-Description:L1D L2 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the returned
cache line was sourced from the Level-2 cache
.
Counter: 129 Name:L1I_L2_SOURCED_WRITES
Short-Description:L1I L2 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from the Level-2 cache
.
Counter: 130 Name:DTLB1_MISSES
Short-Description:DTLB1 Misses
Description:
Level-1 Data TLB miss in progress. Incremented by one for every cycle
a DTLB1 miss is in progress.
.
Counter: 131 Name:ITLB1_MISSES
Short-Description:ITLB1 Misses
Description:
Level-1 Instruction TLB miss in progress. Incremented by one for every
cycle a ITLB1 miss is in progress.
.
Counter: 133 Name:L2C_STORES_SENT
Short-Description:L2C Stores Sent
Description:
Incremented by one for every store sent to Level-2 cache
.
Counter: 134 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
Short-Description:L1D Off-Book L3 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the returned
cache line was sourced from an Off Book Level-3 cache
.
Counter: 135 Name:L1D_ONBOOK_L4_SOURCED_WRITES
Short-Description:L1D On-Book L4 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the returned
cache line was sourced from an On Book Level-4 cache
.
Counter: 136 Name:L1I_ONBOOK_L4_SOURCED_WRITES
Short-Description:L1I On-Book L4 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from an On Book Level-4 cache
.
Counter: 137 Name:L1D_RO_EXCL_WRITES
Short-Description:L1D Read-only Exclusive Writes
Description:
A directory write to the Level-1 D-Cache where the line was originally
in a Read-Only state in the cache but has been updated to be in the
Exclusive state that allows stores to the cache line
.
Counter: 138 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
Short-Description:L1D Off-Book L4 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the returned
cache line was sourced from an Off Book Level-4 cache
.
Counter: 139 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
Short-Description:L1I Off-Book L4 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from an Off Book Level-4 cache
.
Counter: 140 Name:DTLB1_HPAGE_WRITES
Short-Description:DTLB1 One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer for a one-megabyte page
.
Counter: 141 Name:L1D_LMEM_SOURCED_WRITES
Short-Description:L1D Local Memory Sourced Writes
Description:
A directory write to the Level-1 D-Cache where the installed cache line
was sourced from memory that is attached to the same book as the Data
cache (Local Memory)
.
Counter: 142 Name:L1I_LMEM_SOURCED_WRITES
Short-Description:L1I Local Memory Sourced Writes
Description:
A directory write to the Level-1 I-Cache where the installed cache
line was sourced from memory that is attached to the same book as the
Instruction cache (Local Memory)
.
Counter: 143 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
Short-Description:L1I Off-Book L3 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from an Off Book Level-3 cache
.
Counter: 144 Name:DTLB1_WRITES
Short-Description:DTLB1 Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer
.
Counter: 145 Name:ITLB1_WRITES
Short-Description:ITLB1 Writes
Description:
A translation entry has been written to the Level-1 Instruction
Translation Lookaside Buffer
.
Counter: 146 Name:TLB2_PTE_WRITES
Short-Description:TLB2 PTE Writes
Description:
A translation entry has been written to the Level-2 TLB Page Table
Entry arrays
.
Counter: 147 Name:TLB2_CRSTE_HPAGE_WRITES
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-2 TLB Common Region
Segment Table Entry arrays for a one-megabyte large page translation
.
Counter: 148 Name:TLB2_CRSTE_WRITES
Short-Description:TLB2 CRSTE Writes
Description:
A translation entry has been written to the Level-2 TLB Common Region
Segment Table Entry arrays
.
Counter: 150 Name:L1D_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1D On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the returned
cache line was sourced from an On Chip Level-3 cache
.
Counter: 152 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
Short-Description:L1D Off-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 D-Cache directory where the returned
cache line was sourced from an Off Chip/On Book Level-3 cache
.
Counter: 153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1I On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from an On Chip Level-3 cache
.
Counter: 155 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
Short-Description:L1I Off-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 I-Cache directory where the returned
cache line was sourced from an Off Chip/On Book Level-3 cache

View File

@@ -1,98 +1,117 @@
Counter: 128 Name:DTLB1_MISSES
Short-Description:DTLB1 Misses
Description:
Level-1 Data TLB miss in progress. Incremented by one for every cycle
a DTLB1 miss is in progress.
.
Counter:129 Name:ITLB1_MISSES
Short-Description:ITLB1 Misses
Description:
Level-1 Instruction TLB miss in progress. Incremented by one for every
cycle a ITLB1 miss is in progress.
.
Counter:130 Name:L1D_L2I_SOURCED_WRITES
Short-Description:L1D L2I Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from the Level-2 Instruction cache
.
Counter:131 Name:L1I_L2I_SOURCED_WRITES
Short-Description:L1I L2I Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from the Level-2 Instruction cache
.
Counter:132 Name:L1D_L2D_SOURCED_WRITES
Short-Description:L1D L2D Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from the Level-2 Data cache
.
Counter:133 Name:DTLB1_WRITES
Short-Description:DTLB1 Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer
.
Counter:135 Name:L1D_LMEM_SOURCED_WRITES
Short-Description:L1D Local Memory Sourced Writes
Description:
A directory write to the Level-1 Data cache where the installed cache line
was sourced from memory that is attached to the same book as the Data
cache (Local Memory)
.
Counter:137 Name:L1I_LMEM_SOURCED_WRITES
Short-Description:L1I Local Memory Sourced Writes
Description:
A directory write to the Level-1 Instruction cache where the installed cache
line was sourced from memory that is attached to the same book as the
Instruction cache (Local Memory)
.
Counter:138 Name:L1D_RO_EXCL_WRITES
Short-Description:L1D Read-only Exclusive Writes
Description:
A directory write to the Level-1 D-Cache where the line was originally
in a Read-Only state in the cache but has been updated to be in the
Exclusive state that allows stores to the cache line
.
Counter:139 Name:DTLB1_HPAGE_WRITES
Short-Description:DTLB1 One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-1 Data Translation
Lookaside Buffer for a one-megabyte page
.
Counter:140 Name:ITLB1_WRITES
Short-Description:ITLB1 Writes
Description:
A translation entry has been written to the Level-1 Instruction
Translation Lookaside Buffer
.
Counter:141 Name:TLB2_PTE_WRITES
Short-Description:TLB2 PTE Writes
Description:
A translation entry has been written to the Level-2 TLB Page Table
Entry arrays
.
Counter:142 Name:TLB2_CRSTE_HPAGE_WRITES
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
Description:
A translation entry has been written to the Level-2 TLB Common Region
Segment Table Entry arrays for a one-megabyte large page translation
.
Counter:143 Name:TLB2_CRSTE_WRITES
Short-Description:TLB2 CRSTE Writes
Description:
A translation entry has been written to the Level-2 TLB Common Region
Segment Table Entry arrays
.
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1D On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On Chip Level-3 cache without intervention
.
Counter:145 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
Short-Description:L1D Off-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off Chip/On Book Level-3 cache without
intervention
.
Counter:146 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
Short-Description:L1D Off-Book L3 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off Book Level-3 cache without intervention
.
Counter:147 Name:L1D_ONBOOK_L4_SOURCED_WRITES
Short-Description:L1D On-Book L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an On Book Level-4 cache
.
Counter:148 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
Short-Description:L1D Off-Book L4 Sourced Writes
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off Book Level-4 cache
@@ -104,16 +123,19 @@ cache line was sourced from an Off Book Level-4 cache
# C .. constrained
#
Counter:149 Name:TX_NC_TEND
Short-Description:Completed TEND instructions in non-constrained TX mode
Description:
A TEND instruction has completed in a nonconstrained
transactional-execution mode
.
Counter:150 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from a On Chip Level-3 cache with intervention
.
Counter:151 Name:L1D_OFFCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1D Off-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off Chip/On Book Level-3 cache with
@@ -121,73 +143,86 @@ intervention
.
# XXX Remove SOURCED from L1D_OFFBOOK_L3_SOURCED_WRITES...
Counter:152 Name:L1D_OFFBOOK_L3_SOURCED_WRITES_IV
Short-Description:L1D Off-Book L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Data cache directory where the returned
cache line was sourced from an Off Book Level-3 cache with intervention
.
Counter:153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
Short-Description:L1I On-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On Chip Level-3 cache without
intervention
.
Counter:154 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
Short-Description:L1I Off-Chip L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off Chip/On Book Level-3 cache
without intervention
.
Counter:155 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
Short-Description:L1I Off-Book L3 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off Book Level-3 cache without
intervention
.
Counter:156 Name:L1I_ONBOOK_L4_SOURCED_WRITES
Short-Description:L1I On-Book L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On Book Level-4 cache
.
Counter:157 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
Short-Description:L1I Off-Book L4 Sourced Writes
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off Book Level-4 cache
.
Counter:158 Name:TX_C_TEND
Short-Description:Completed TEND instructions in constrained TX mode
Description:
A TEND instruction has completed in a constrained transactional-execution
mode
.
Counter:159 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an On Chip Level-3 cache with
intervention
.
Counter:160 Name:L1I_OFFCHIP_L3_SOURCED_WRITES_IV
Short-Description:L1I Off-Chip L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off Chip/On Book Level-3 cache
with intervention
.
Counter:161 Name:L1I_OFFBOOK_L3_SOURCED_WRITES_IV
Short-Description:L1I Off-Book L3 Sourced Writes with Intervention
Description:
A directory write to the Level-1 Instruction cache directory where the
returned cache line was sourced from an Off Book Level-3 cache with
intervention
.
Counter:177 Name:TX_NC_TABORT
Short-Description:Aborted transactions in non-constrained TX mode
Description:
A transaction abort has occurred in a nonconstrained
transactional-execution mode
.
Counter:178 Name:TX_C_TABORT_NO_SPECIAL
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
Description:
A transaction abort has occurred in a constrained transactional-execution
mode and the CPU is not using any special logic to allow the transaction
to complete
.
Counter:179 Name:TX_C_TABORT_SPECIAL
Short-Description:Aborted transactions in constrained TX mode using special completion logic
Description:
A transaction abort has occurred in a constrained transactional-execution
mode and the CPU is using special logic to allow the transaction to

View File

@@ -26,4 +26,5 @@
2964 => 'cpum-cf-extended-z13.ctr',
2965 => 'cpum-cf-extended-z13.ctr',
3906 => 'cpum-cf-extended-z14.ctr',
3907 => 'cpum-cf-extended-z14.ctr',
};

View File

@@ -3,11 +3,13 @@
#
# Basic-sampling mode
Counter: 0xB0000 Name:SF_CYCLES_BASIC
Short-Description:Sample CPU Cycles Using Basic-sampling Mode
Description:
Sample CPU cycles using basic-sampling mode
.
# Diagnostic-sampling mode (includes basic-sampling)
Counter: 0xBD000 Name:SF_CYCLES_BASIC_DIAG
Short-Description:Sample CPU Cycle Using Diagnostic-sampling Mode (not for ordinary use)
Description:
Sample CPU cycle using diagnostic-sampling mode (not for ordinary use)
.

View File

@@ -7,7 +7,7 @@ SUBSYSTEM!="block", GOTO="ra_end"
ACTION!="add", GOTO="ra_change"
# on device add set initial readahead to 512 (instead of in kernel 128)
KERNEL=="sd*[!0-9]", WAIT_FOR="queue/read_ahead_kb", ATTR{queue/read_ahead_kb}="512"
KERNEL=="sd*[!0-9]", TEST=="queue/read_ahead_kb", ATTR{queue/read_ahead_kb}="512"
LABEL="ra_change"

View File

@@ -821,10 +821,13 @@ static char *hmcdrv_parse_line(char *line, char *namebuf,
if ((*line != '\0') && (*line != '\n')) {
field = hmcdrv_parse_ntoken(field, line, &attr);
while ((*line != '\0') &&
(*line != '\n') &&
!isspace(*line))
while ((*line != '\0') && (*line != '\n')) {
if (isspace(*line))
break;
if (field == 1 && isdigit(*line))
break;
++line; /* search end of field */
}
}
} /* while */

View File

@@ -14,6 +14,10 @@
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Allocate memory or panic in case of failure
*
@@ -125,4 +129,10 @@ int __util_vsprintf(const char *func, const char *file, int line,
char *util_strcat_realloc(char *str1, const char *str2);
void util_str_toupper(char *str);
char *util_strstrip(char *s);
#ifdef __cplusplus
}
#endif
#endif /** LIB_UTIL_LIBC_H @} */

52
include/lib/vmcp.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* vmcp - z/VM CP command library
*
* Copyright IBM Corp. 2005, 2018
*
* 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_VMCP_H
#define LIB_VMCP_H
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
#define VMCP_DEVICE_NODE "/dev/vmcp" /* VMCP device name */
#define VMCP_DEFAULT_BUFSZ 0x4000 /* VMCP default buffer size */
/*
* Error codes returned by vmcp() function. This enables the caller
* to emit a detailed error message on the type of failure.
*/
#define VMCP_SUCCESS 0 /* VMCP operation completed successfully */
#define VMCP_ERR_OPEN (-1) /* Error Open of VMCP device */
#define VMCP_ERR_SETBUF (-2) /* Error VMCP_SETBUF ioctl */
#define VMCP_ERR_READ (-3) /* Error VMCP read system call */
#define VMCP_ERR_GETCODE (-4) /* Error VMCP_GETCODE ioctl */
#define VMCP_ERR_GETSIZE (-5) /* Error VMCP_GETSIZE ioctl */
#define VMCP_ERR_TOOSMALL (-6) /* Error VMCP buffer too small for
* response
*/
#define VMCP_ERR_WRITE (-7) /* Error VMCP write system call */
struct vmcp_parm {
const char *cpcmd;
unsigned int buffer_size;
bool do_upper;
int cprc;
char *response;
unsigned int response_size;
};
int vmcp(struct vmcp_parm *cp);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -445,7 +445,7 @@ static void set_target_type_auto(const char *arg)
{
char busid[10];
if (access(arg, R_OK) == 0) {
if (access(arg, F_OK) == 0) {
set_target_type(TT_NODE, 1);
return;
}
@@ -539,12 +539,19 @@ static void parse_chreipl_options(int argc, char *argv[])
parse_pos_args(&argv[optind], argc - optind);
}
static void verify_write_access(const char *path, const char *attr)
static void check_exists(const char *path, const char *attr)
{
char fpath[PATH_MAX];
snprintf(fpath, sizeof(fpath), "/sys/firmware/%s", path);
if (access(fpath, W_OK) != 0)
if (access(fpath, F_OK) != 0)
ERR_EXIT("System does not allow to set %s", attr);
}
static void write_str_optional(char *string, char *file, int exit_on_fail,
const char *attr)
{
if (write_str_errno(string, file) && exit_on_fail)
ERR_EXIT("System does not allow to set %s", attr);
}
@@ -585,22 +592,18 @@ static void chreipl_ccw(void)
ERR_EXIT("Could not find DASD CCW device \"%s\"", l.busid);
}
if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_CCW_MAX) {
ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)",
strlen(l.bootparms), BOOTPARMS_CCW_MAX);
}
/*
* On old systems that use CCW reipl loadparm cannot be set
*/
if (l.loadparm_set)
verify_write_access("reipl/ccw/loadparm", "loadparm");
if (l.bootparms_set) {
verify_write_access("reipl/ccw/parm", "boot parameters");
if (strlen(l.bootparms) > BOOTPARMS_CCW_MAX)
ERR_EXIT("Maximum boot parameter length exceeded "
"(%zu/%u)", strlen(l.bootparms),
BOOTPARMS_CCW_MAX);
}
if (access("/sys/firmware/reipl/ccw/parm", W_OK) == 0)
write_str(l.bootparms, "reipl/ccw/parm");
if (access("/sys/firmware/reipl/ccw/loadparm", W_OK) == 0)
write_str(l.loadparm, "reipl/ccw/loadparm");
write_str_optional(l.loadparm, "reipl/ccw/loadparm", l.loadparm_set,
"loadparm");
write_str_optional(l.bootparms, "reipl/ccw/parm", l.bootparms_set,
"boot parameters");
write_str(l.busid, "reipl/ccw/device");
write_str("ccw", "reipl/reipl_type");
@@ -616,27 +619,21 @@ static void chreipl_fcp(void)
ERR_EXIT("Device is on cio_ignore list, try \"cio_ignore -r %s\"?", l.busid);
ERR_EXIT("Could not find FCP device \"%s\"", l.busid);
}
verify_write_access("reipl/fcp/device", "\"fcp\" re-IPL target");
check_exists("reipl/fcp/device", "\"fcp\" re-IPL target");
if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_FCP_MAX) {
ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)",
strlen(l.bootparms), BOOTPARMS_FCP_MAX);
}
/*
* On old systems the FCP reipl loadparm cannot be set
*/
if (l.loadparm_set)
verify_write_access("reipl/fcp/loadparm", "loadparm");
if (l.bootparms_set) {
verify_write_access("reipl/fcp/scp_data", "boot parameters");
if (strlen(l.bootparms) > BOOTPARMS_FCP_MAX)
ERR_EXIT("Maximum boot parameter length exceeded "
"(%zu/%u)", strlen(l.bootparms),
BOOTPARMS_FCP_MAX);
}
if (access("/sys/firmware/reipl/fcp/scp_data", W_OK) == 0)
write_str(l.bootparms, "reipl/fcp/scp_data");
if (access("/sys/firmware/reipl/fcp/loadparm", W_OK) == 0)
write_str(l.loadparm, "reipl/fcp/loadparm");
write_str_optional(l.loadparm, "reipl/fcp/loadparm", l.loadparm_set,
"loadparm");
write_str_optional(l.bootparms, "reipl/fcp/scp_data", l.bootparms_set,
"boot parameters");
write_str(l.busid, "reipl/fcp/device");
write_str(l.wwpn, "reipl/fcp/wwpn");
write_str(l.lun, "reipl/fcp/lun");
write_str("fcp", "reipl/reipl_type");
/*
* set the boot record logical block address. Master boot
* record. It is always 0 for Linux
@@ -645,6 +642,7 @@ static void chreipl_fcp(void)
if (!l.bootprog_set)
sprintf(l.bootprog, "0");
write_str(l.bootprog, "reipl/fcp/bootprog");
write_str("fcp", "reipl/reipl_type");
print_fcp(0, 0);
}
@@ -652,17 +650,14 @@ static void chreipl_fcp(void)
static void chreipl_nss(void)
{
check_nss_opts();
verify_write_access("reipl/nss/name", "\"nss\" re-IPL target");
if (l.bootparms_set) {
verify_write_access("reipl/nss/parm", "boot parameters");
if (strlen(l.bootparms) > BOOTPARMS_NSS_MAX)
ERR_EXIT("Maximum boot parameter length exceeded "
"(%zu/%u)", strlen(l.bootparms),
BOOTPARMS_NSS_MAX);
check_exists("reipl/nss/name", "\"nss\" re-IPL target");
if (l.bootparms_set && strlen(l.bootparms) > BOOTPARMS_NSS_MAX) {
ERR_EXIT("Maximum boot parameter length exceeded (%zu/%u)",
strlen(l.bootparms), BOOTPARMS_NSS_MAX);
}
write_str_optional(l.bootparms, "reipl/nss/parm", l.bootparms_set,
"boot parameters");
write_str(l.nss_name, "reipl/nss/name");
if (access("/sys/firmware/reipl/nss/parm", W_OK) == 0)
write_str(l.bootparms, "reipl/nss/parm");
write_str("nss", "reipl/reipl_type");
print_nss(0);
}

View File

@@ -129,7 +129,7 @@ int write_str_errno(char *string, char *file)
snprintf(path, sizeof(path), "/sys/firmware/%s", file);
fh = open(path, O_WRONLY);
if (fh < 0)
ERR_EXIT_ERRNO("Could not open \"%s\"", file);
return errno;
if (write(fh, value, strlen(value)) < 0)
return errno;
close(fh);

View File

@@ -198,3 +198,33 @@ int __util_vsprintf(const char *func, const char *file, int line,
rc != -1, "Could not format string\n");
return rc;
}
/**
* Strip leading and trailing spaces from string
*
* Remove string \a s leading and trailing spaces
*
* @param[in,out] s String to manipulate
*
* @returns Pointer to first non-space character in string \a s
*/
char *util_strstrip(char *s)
{
size_t size;
char *end;
size = strlen(s);
if (!size)
return s;
end = s + size - 1;
while (end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
while (*s && isspace(*s))
s++;
return s;
}

View File

@@ -10,10 +10,13 @@
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#define EXAMPLE_WORD " /sys/devices/system/cpu "
/*
* Demonstrate that out of memory is automatically handled via panic()
*/
@@ -22,6 +25,12 @@ int main(void)
unsigned long ulong_max = (unsigned long)-1;
void *ptr;
char *zeroes, *str;
char buffer[sizeof(EXAMPLE_WORD)];
strcat(buffer, EXAMPLE_WORD);
fprintf(stderr, "Try to remove leading and trailing spaces from "
"\"%s\"\nresult = \"%s\"\n", EXAMPLE_WORD,
util_strstrip(buffer));
/* Use util_strcat_realloc() for string concatenation */
fprintf(stderr, "Try to concatenate \"Hello\", \", \" and \"world!\": ");

18
libvmcp/Makefile Normal file
View File

@@ -0,0 +1,18 @@
include ../common.mak
lib = libvmcp.a
examples = vmcp_example
all: $(lib) $(examples)
objects = vmcp.o
$(lib): $(objects)
install: all
vmcp_example: vmcp_example.o $(lib) $(rootdir)/libutil/libutil.a
clean:
rm -f *.o $(lib) $(examples)

134
libvmcp/vmcp.c Normal file
View File

@@ -0,0 +1,134 @@
/*
* vmcp - z/VM CP function library
*
* Copyright IBM Corp. 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include "lib/util_libc.h"
#include "lib/vmcp.h"
#define VMCP_DEVICE_NODE "/dev/vmcp"
#define VMCP_GETSIZE _IOR(0x10, 3, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
#define VMCP_GETCODE _IOR(0x10, 1, int)
/*
* Read at most COUNT bytes from FD into memory at location BUF.
* Return number of bytes read on success, -1 on error.
*/
static ssize_t read_buffer(int fd, char *buf, ssize_t count)
{
ssize_t ret, done;
for (done = 0; done < (ssize_t)count; done += ret) {
ret = read(fd, &buf[done], count - done);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
return -1;
if (ret == 0)
break;
}
return done;
}
/**
* Submit a command to z/VM CP and return the response, the size in bytes
* of the response and CP command response code.
*
* The member response contains the response from CP. It is a pointer
* to a malloc'ed buffer which must be freed by the caller when the return
* code is zero or VMCP_ERR_TOOSMALL.
*
* @param[in,out] cmd Pointer to struct vmcp_parm.
* @param[in] cpcmd Pointer to CP command string.
* @param[in] do_upper If true convert cpcmd string to upper case.
* @param[out] cprc Return code of the CP command.
* @param[out] response Return buffer, has been allocated via malloc()
* must be freed by caller, see below.
* @param[out] response_size Size of the response in bytes, can be larger
* than buffer_size.
*
* @returns Zero on success or a negative error number on failure.
* @retval VMCP_SUCCESS Success valid members: cprc, response,
* response_size
* @retval VMCP_ERR_OPEN Error opening VMCP device, valid members: none
* @retval VMCP_ERR_SETBUF Error setting buffer, valid members: none
* @retval VMCP_ERR_GETCODE Error getting cp exit code, valid members: none
* @retval VMCP_ERR_WRITE Error write CP command, valid members: none
* @retval VMCP_ERR_GETSIZE Error reading response size,
* valid members: cprc
* @retval VMCP_ERR_READ Error reading resp
* @retval VMCP_ERR_TOOSMALL Error response buffer too small, response
* truncated, valid members: cprc, response,
* response_size
*/
int vmcp(struct vmcp_parm *cmd)
{
int rc = VMCP_SUCCESS, fd, len;
char *cpcmd;
cmd->response = NULL;
cmd->response_size = 0;
cmd->cprc = 0;
fd = open(VMCP_DEVICE_NODE, O_RDWR);
if (fd == -1)
return VMCP_ERR_OPEN;
cpcmd = util_strdup(cmd->cpcmd); /* Exits on failure */
if (cmd->do_upper)
util_str_toupper(cpcmd);
if (ioctl(fd, VMCP_SETBUF, &cmd->buffer_size) == -1) {
rc = VMCP_ERR_SETBUF;
goto fail;
}
if (write(fd, cpcmd, strlen(cpcmd)) == -1) {
rc = VMCP_ERR_WRITE;
goto fail;
}
if (ioctl(fd, VMCP_GETCODE, &cmd->cprc) == -1) {
rc = VMCP_ERR_GETCODE;
goto fail;
}
if (ioctl(fd, VMCP_GETSIZE, &cmd->response_size) == -1) {
rc = VMCP_ERR_GETSIZE;
goto fail;
}
if (cmd->response_size <= cmd->buffer_size) {
len = cmd->response_size;
} else {
len = cmd->buffer_size;
rc = VMCP_ERR_TOOSMALL;
}
/* Exits on failure */
cmd->response = (char *)util_zalloc(len + 1);
if (read_buffer(fd, cmd->response, len) == -1) {
rc = VMCP_ERR_READ;
free(cmd->response);
cmd->response = NULL;
}
fail:
close(fd);
free(cpcmd);
return rc;
}

65
libvmcp/vmcp_example.c Normal file
View File

@@ -0,0 +1,65 @@
/**
* vmcp_example - Example program for vmcp.c
*
* Copyright 2018 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.
*/
//! [code]
#include <stdio.h>
#include <stdlib.h>
#include <err.h>
#include "lib/vmcp.h"
/*
* Demonstrate vmcp() function usage
*/
int main(void)
{
struct vmcp_parm cp;
int rc;
cp.cpcmd = "q osa";
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
cp.do_upper = true;
rc = vmcp(&cp);
switch (rc) {
case VMCP_SUCCESS:
printf("%s\n", cp.response);
free(cp.response);
break;
case VMCP_ERR_OPEN:
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
break;
case VMCP_ERR_SETBUF:
errx(EXIT_FAILURE, "Could not set buffer size");
break;
case VMCP_ERR_GETCODE:
errx(EXIT_FAILURE, "Could not query return code");
break;
case VMCP_ERR_GETSIZE:
errx(EXIT_FAILURE, "Could not query response size");
break;
case VMCP_ERR_WRITE:
errx(EXIT_FAILURE, "Could not issue CP command");
break;
case VMCP_ERR_READ:
errx(EXIT_FAILURE, "Could not read CP response");
break;
case VMCP_ERR_TOOSMALL:
free(cp.response);
printf("Response truncated (requires %u bytes)\n",
cp.response_size);
errx(EXIT_FAILURE, "Response buffer (%u bytes) too small",
cp.buffer_size);
break;
}
return EXIT_SUCCESS;
}
//! [code]

View File

@@ -182,11 +182,14 @@ readonly OUTPUT_FILE_XML="${WORKPATH}domain_xml"
# File that includes the docker inspect output
readonly OUTPUT_FILE_DOCKER="${WORKPATH}docker_inspect.out"
# File that includes nvme related information
readonly OUTPUT_FILE_NVME="${WORKPATH}nvme.out"
# Mount point of the debug file system
readonly MOUNT_POINT_DEBUGFS="/sys/kernel/debug"
# The amount of steps running the whole collections
readonly COLLECTION_COUNT=11
readonly COLLECTION_COUNT=12
# The kernel version (e.g. '2' from 2.6.32 or '3' from 3.2.1)
readonly KERNEL_VERSION=$(uname -r 2>/dev/null | cut -d'.' -f1)
@@ -471,6 +474,8 @@ VM_CMDS="q userid\
:q privclass\
:q cplevel\
:q cpservice\
:q cpprot user\
:q specex\
:q ssi\
:q cpus\
:q srm\
@@ -826,6 +831,25 @@ collect_docker() {
pr_log_stdout " "
}
########################################
collect_nvme() {
local NVME
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Collecting nvme output"
call_run_command "nvme list" "${OUTPUT_FILE_NVME}"
for NVME in /dev/nvme[0-9]*; do
if [ -c $NVME ]; then
call_run_command "smartctl -x $NVME" "${OUTPUT_FILE_NVME}"
call_run_command "nvme fw-log $NVME" "${OUTPUT_FILE_NVME}"
call_run_command "nvme smart-log $NVME" "${OUTPUT_FILE_NVME}"
call_run_command "nvme error-log $NVME" "${OUTPUT_FILE_NVME}"
fi
done
pr_log_stdout " "
}
########################################
post_processing() {
local file_mtime
@@ -833,7 +857,7 @@ post_processing() {
local tmp_file
local file_name
pr_syslog_stdout "11 of ${COLLECTION_COUNT}: Postprocessing"
pr_syslog_stdout "${COLLECTION_COUNT} of ${COLLECTION_COUNT}: Postprocessing"
find "${WORKPATH}etc/libvirt/qemu/" -maxdepth 1 -name "*.xml" 2>/dev/null | while IFS= read -r file_name; do
file_mtime_epoche=$(stat --format=%Y "${file_name}")
@@ -1118,6 +1142,8 @@ collect_domain_xml
collect_docker
collect_nvme
post_processing
create_package

View File

@@ -2,7 +2,9 @@ include ../common.mak
all: vmcp
vmcp: vmcp.o
libs = $(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a
vmcp: vmcp.o $(libs)
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8

View File

@@ -4,7 +4,7 @@
* Tool for accessing the control program of z/VM using the
* kernel module vmcp
* return codes:
* 0: everything was fine (VMCP_OK)
* 0: everything was fine (EXIT_SUCCESS)
* 1: CP returned a nn zero response code (VMCP_CP)
* 2: the response buffer was not large enough (VMCP_BUF)
* 3: an internal Linux error occurred (VMCP_LIN)
@@ -28,33 +28,58 @@
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include "vmcp.h"
#include "lib/zt_common.h"
#include "lib/vmcp.h"
#include "lib/util_opt.h"
#include "lib/util_prg.h"
#define MAXBUFFER 1048576
#define MINBUFFER 4096
#define MAXCMDLEN 240
#define VMCP_OK 0
#define VMCP_CP 1
#define VMCP_BUF 2
#define VMCP_LIN 3
#define VMCP_OPT 4
static int keep_case = 0;
static int buffersize = 8192;
static int buffersize = VMCP_DEFAULT_BUFSZ;
static char command[MAXCMDLEN + 1];
static void print_help(const char *name)
{
printf("%s: z/VM CP command interface.\n%s", name, help_text);
}
static struct util_opt opt_vec[] = {
UTIL_OPT_SECTION("OPTIONS"),
{
.option = { "keepcase", no_argument, NULL, 'k' },
.desc = "Do not convert CP-command string to uppercase",
},
{
.option = { "buffer", required_argument, NULL, 'b' },
.argument = "SIZE",
.desc = "Specify buffer size in bytes, kilobytes (k) "
"or megabytes (M). SIZE range from 4096 to 1048576 "
"bytes"
},
UTIL_OPT_HELP,
UTIL_OPT_VERSION,
UTIL_OPT_END
};
static void print_version(const char *name)
{
printf("%s: z/VM CP command interface version %s\n"
"Copyright IBM Corp. 2005, 2017\n",
name, RELEASE_STRING);
}
static void uppercase(char *string)
{
while (*string != '\0') {
*string = toupper(*string);
string++;
static const struct util_prg prg = {
.desc = "z/VM CP command interface",
.args = "CP-command",
.copyright_vec = {
{
.owner = "IBM Corp.",
.pub_first = 2005,
.pub_last = 2018,
},
UTIL_PRG_COPYRIGHT_END
}
}
};
/* Parse STRING for buffer size in bytes, allowing size modifier suffix 'k' and
* 'm'. Return buffer size in bytes on success, -1 on error. */
@@ -95,17 +120,18 @@ static int parse_args(int argc, char **argv)
int index;
do {
opt = getopt_long(argc, argv, opt_string, options, NULL);
opt = util_opt_getopt_long(argc, argv);
switch (opt) {
case -1:
/* Reached end of parameter list. */
break;
case 'h':
print_help(argv[0]);
exit(VMCP_OK);
util_prg_print_help();
util_opt_print_help();
exit(EXIT_SUCCESS);
case 'v':
print_version(argv[0]);
exit(VMCP_OK);
util_prg_print_version();
exit(EXIT_SUCCESS);
case 'k':
keep_case = 1;
break;
@@ -137,7 +163,8 @@ static int parse_args(int argc, char **argv)
strcat(command, argv[index]);
}
if (strlen(command) == 0) {
print_help(argv[0]);
util_prg_print_help();
util_opt_print_help();
return VMCP_OPT;
}
return VMCP_OK;
@@ -148,25 +175,6 @@ static inline void linux_error(const char *message)
fprintf(stderr, "Error: %s: %s\n", message, strerror(errno));
}
/* Read at most COUNT bytes from FD into memory at location BUF. Return
* number of bytes read on success, -1 on error. */
static ssize_t read_buffer(int fd, char *buf, size_t count)
{
ssize_t ret;
ssize_t done;
for (done = 0; done < (ssize_t) count; done += ret) {
ret = read(fd, &buf[done], count - done);
if (ret == -1 && errno == EINTR)
continue;
if (ret == -1)
return -1;
if (ret == 0)
break;
}
return done;
}
/* Write COUNT bytes to FD from memory at location BUF. Return number of bytes
* written on success, -1 otherwise. */
static ssize_t write_buffer(int fd, const char *buf, size_t count)
@@ -188,77 +196,54 @@ static ssize_t write_buffer(int fd, const char *buf, size_t count)
int main(int argc, char **argv)
{
struct vmcp_parm cp;
int ret;
int fd;
int response_code;
int response_size;
char *buffer;
util_prg_init(&prg);
util_opt_init(opt_vec, NULL);
ret = parse_args(argc, argv);
if (ret != VMCP_OK)
return ret;
if (!keep_case)
uppercase(command);
cp.buffer_size = buffersize;
cp.cpcmd = command;
cp.do_upper = !keep_case;
buffer = malloc(buffersize);
if (!buffer) {
linux_error("Could not allocate return buffer");
ret = vmcp(&cp);
switch (ret) {
case VMCP_ERR_OPEN:
linux_error("Could not open device " VMCP_DEVICE_NODE);
return VMCP_LIN;
}
fd = open(DEVICE_NODE, O_RDWR);
if (fd == -1) {
linux_error("Could not open device " DEVICE_NODE);
free(buffer);
return VMCP_LIN;
}
if (ioctl(fd, VMCP_SETBUF, &buffersize) == -1) {
case VMCP_ERR_SETBUF:
linux_error("Could not set buffer size");
free(buffer);
close(fd);
return VMCP_LIN;
}
if (write(fd, command, strlen(command)) == -1) {
case VMCP_ERR_WRITE:
linux_error("Could not issue CP command");
free(buffer);
close(fd);
return VMCP_LIN;
}
if (ioctl(fd, VMCP_GETCODE, &response_code) == -1) {
case VMCP_ERR_GETCODE:
linux_error("Could not query return code");
free(buffer);
close(fd);
return VMCP_LIN;
}
if (ioctl(fd, VMCP_GETSIZE, &response_size) == -1) {
case VMCP_ERR_GETSIZE:
linux_error("Could not query response size");
free(buffer);
close(fd);
return VMCP_LIN;
}
ret = read_buffer(fd, buffer, buffersize);
if (ret == -1) {
case VMCP_ERR_READ:
linux_error("Could not read CP response");
free(buffer);
close(fd);
return VMCP_LIN;
}
write_buffer(STDOUT_FILENO, buffer, ret);
if (response_size > buffersize) {
write_buffer(STDOUT_FILENO, cp.response,
MIN(cp.response_size, cp.buffer_size));
free(cp.response);
if (ret == VMCP_ERR_TOOSMALL) {
fprintf(stderr, "Error: output (%d bytes) was truncated, try "
"--buffer to increase size\n", response_size);
free(buffer);
close(fd);
"--buffer to increase size\n", cp.response_size);
return VMCP_BUF;
}
if (response_code > 0) {
if (cp.cprc > 0) {
fprintf(stderr, "Error: non-zero CP response for command '%s': "
"#%d\n", command, response_code);
free(buffer);
close(fd);
"#%d\n", command, cp.cprc);
return VMCP_CP;
}
free(buffer);
close(fd);
return VMCP_OK;
return EXIT_SUCCESS;
}

View File

@@ -1,59 +0,0 @@
/*
* vmcp - Send commands to the z/VM control program
*
* Definitions used by vmcp
*
* Copyright IBM Corp. 2005, 2017
*
* 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 __vmcp_h__
#define __vmcp_h__
#include <getopt.h>
#include <sys/ioctl.h>
#include "lib/zt_common.h"
#define DEVICE_NODE "/dev/vmcp"
#define VMCP_GETCODE _IOR(0x10, 1, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
#define VMCP_GETSIZE _IOR(0x10, 3, int)
#define MAXBUFFER 1048576
#define MINBUFFER 4096
#define MAXCMDLEN 240
#define VMCP_OK 0
#define VMCP_CP 1
#define VMCP_BUF 2
#define VMCP_LIN 3
#define VMCP_OPT 4
static struct option options[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{"keepcase", no_argument, NULL, 'k'},
{"buffer", required_argument, NULL, 'b'},
{NULL, 0, NULL, 0}
};
static const char opt_string[] = "+hvkb:";
static const char help_text[] =
"Usage:\n"
"vmcp [-k] [-b <size>] command\n"
"vmcp [-h|-v]\n\n"
"Options:\n"
"-h or --help :Print usage information, then exit\n"
"-v or --version :Print version information, then exit\n"
"-k or --keepcase :Using this option, vmcp does not convert the command\n"
" to uppercase. The default is to translate the command\n"
" string.\n"
"-b <size> or :defines the buffer size for the response\n"
"--buffer=<size> valid values are from 4096 to 1048576 bytes\n"
" the k and M suffixes are also supported\n";
#endif

View File

@@ -5,7 +5,9 @@ LDLIBS += -lz
all: vmur
libs = $(rootdir)/libvmdump/libvmdump.a
libs = $(rootdir)/libvmdump/libvmdump.a \
$(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a
objects = vmur.o
vmur: $(objects) $(libs)

View File

@@ -31,9 +31,13 @@
#include "lib/vmdump.h"
#include "lib/zt_common.h"
#include "lib/util_libc.h"
#include "lib/vmcp.h"
#include "vmur.h"
#define CP_PREFIX_LEN 11
/* Program name */
static char *prog_name;
@@ -243,24 +247,6 @@ fail:
ERR_EXIT("Could not initialize signal handler (errno = %i)\n", errno);
}
/*
* Read at most COUNT bytes from FD into memory at location BUF.
* Return number of bytes read on success, -1 on error.
*/
static ssize_t read_buf(int fd, char *buf, ssize_t count)
{
ssize_t rc, len;
for (len = 0; len < count; len += rc) {
rc = read(fd, &buf[len], count - len);
if (rc == -1)
return -1;
if (rc == 0)
break;
}
return len;
}
/*
* Strip leading CP header from error message
*/
@@ -293,64 +279,63 @@ static void cperr_exit(char *cpcmd, int cprc, char *buf)
static void _cpcmd(char *cpcmd, char **resp, int *rc, int retry, int upper)
{
int fd, len, cprc, bufsize = VMCP_BUFSIZE;
char *buf;
struct vmcp_parm cp;
char cmd[MAXCMDLEN];
int ret;
strcpy(cmd, cpcmd);
if (upper)
to_upper(cmd);
cp.cpcmd = cmd;
cp.do_upper = upper;
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
fd = open(VMCP_DEVICE_NODE, O_RDWR);
if (fd == -1)
retry:
ret = vmcp(&cp);
switch (ret) {
case VMCP_ERR_OPEN:
ERR_EXIT("Could not issue CP command: \"%s\"\n"
"Ensure that vmcp kernel module is loaded!\n", cmd);
do {
if (ioctl(fd, VMCP_SETBUF, &bufsize) == -1)
goto fail;
if (write(fd, cmd, strlen(cmd)) == -1)
goto fail;
if (ioctl(fd, VMCP_GETCODE, &cprc) == -1)
goto fail;
if (ioctl(fd, VMCP_GETSIZE, &len) == -1)
goto fail;
if (len <= bufsize)
break;
else if (retry)
bufsize = len;
else
ERR_EXIT("Not enough buffer space (%i/%i) for CP "
"command '%s'.\nSorry, please issue command "
"on your 3270 console!\n", len, bufsize, cmd);
} while (1);
buf = (char *) malloc(len + 1);
if (!buf)
ERR_EXIT("Out of memory for CP command '%s'\n", cmd);
memset(buf, 0, len + 1);
if (read_buf(fd, buf, len) == -1)
case VMCP_ERR_SETBUF:
goto fail;
case VMCP_ERR_WRITE:
goto fail;
case VMCP_ERR_GETCODE:
goto fail;
case VMCP_ERR_GETSIZE:
goto fail;
case VMCP_ERR_READ:
goto fail;
case VMCP_ERR_TOOSMALL:
if (retry) {
cp.buffer_size = cp.response_size;
free(cp.response);
goto retry;
}
ERR_EXIT("Not enough buffer space (%u/%u) for CP "
"command '%s'.\nSorry, please issue command "
" on your 3270 console!\n", cp.response_size,
cp.buffer_size, cmd);
}
if (rc == NULL) {
if (cprc != 0) {
if (cp.cprc != 0) {
/* caller wants us to handle the error */
cperr_exit(cmd, cprc, buf);
cperr_exit(cmd, cp.cprc, cp.response);
}
} else {
*rc = cprc;
*rc = cp.cprc;
}
if (resp)
*resp = buf;
*resp = cp.response;
else
free(buf);
close(fd);
free(cp.response);
return;
fail:
@@ -1369,30 +1354,6 @@ static void close_reader(struct vmur *info, const char *hold)
cpcmd(cmd, NULL, NULL, 0);
}
/*
* strip leading and trailing blanks
*/
static char *strstrip(char *s)
{
size_t size;
char *end;
size = strlen(s);
if (!size)
return s;
end = s + size - 1;
while (end >= s && isspace(*end))
end--;
*(end + 1) = '\0';
while (*s && isspace(*s))
s++;
return s;
}
/*
* Check whether reader can handle class of reader spool file
*/
@@ -1431,9 +1392,9 @@ static int get_filename_from_reader(struct vmur *info)
sprintf(cmd, "QUERY RDR * %s ALL SHORTDATE", info->spoolid);
cpcmd(cmd, &buf, NULL, 0);
memcpy(name, &buf[130], 8);
strstrip(name);
util_strstrip(name);
memcpy(type, &buf[140], 8);
strstrip(type);
util_strstrip(type);
free(buf);
if (strlen(name) == 0) {
ERR("Please specify name to receive "

View File

@@ -31,14 +31,6 @@ do { \
ERR_EXIT(str " can only be specified once.\n"); \
} while (0)
#define VMCP_DEVICE_NODE "/dev/vmcp"
#define VMCP_BUFSIZE 0x4000
#define VMCP_GETSIZE _IOR(0x10, 3, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
#define VMCP_GETCODE _IOR(0x10, 1, int)
#define CP_PREFIX_LEN 11
#define VMRDR_DEVICE_NODE "/dev/vmrdr-0.0.000c"
#define VMPUN_DEVICE_NODE "/dev/vmpun-0.0.000d"
#define VMPRT_DEVICE_NODE "/dev/vmprt-0.0.000e"

View File

@@ -649,14 +649,12 @@ static void print_defunct_devices(struct util_rec *rec, char *path)
snprintf(buf, sizeof(buf), "%s", device);
}
if (cmd.opt_devrange && cmd.rng_count > 0 &&
!id_in_ranges_list(device)) {
util_scandir_free(de_vec, count);
!id_in_ranges_list(device))
continue;
}
if (fill_device_info(rec, path, device) != 0) {
util_scandir_free(de_vec, count);
if (fill_device_info(rec, path, device) != 0)
continue;
}
if (cmd.opt_uppercase)
util_str_toupper(buf);
util_rec_set(rec, "device", "%s", buf);
@@ -719,7 +717,7 @@ static void print_subchannels_of_type(enum sch_type type_requested,
if (!cmd.opt_devrange && cmd.rng_count > 0)
return;
path = util_path_sysfs("devices");
count = util_scandir(&de_vec, alphasort, path, "css.*/");
count = util_scandir(&de_vec, alphasort, path, "css.*");
free(path);
for (i = 0; i < count; i++) {
path = util_path_sysfs("devices/%s/defunct", de_vec[i]->d_name);

View File

@@ -2,7 +2,7 @@ include ../../common.mak
all: lsqeth
libs = $(rootdir)/libutil/libutil.a
libs = $(rootdir)/libvmcp/libvmcp.a $(rootdir)/libutil/libutil.a
lsqeth: lsqeth.o misc.o $(libs)

View File

@@ -37,6 +37,7 @@
#include "lib/util_rec.h"
#include "lib/util_scandir.h"
#include "lib/zt_common.h"
#include "lib/vmcp.h"
#include "misc.h"
@@ -44,15 +45,6 @@
#define MAX_ID_LENGTH 10
#define PAGE_SIZE 4096
/*
* Constants for CP call (taken from vmcp.h)
*/
#define VMCP_DEVICE_NODE "/dev/vmcp"
#define VMCP_GETCODE _IOR(0x10, 1, int)
#define VMCP_SETBUF _IOW(0x10, 2, int)
#define VMCP_GETSIZE _IOR(0x10, 3, int)
#define CP_BUF_SIZE 8192
/*
* Private data
*/
@@ -197,32 +189,38 @@ static void ethtool_checksumming(char *buf, const char *if_name)
*/
static void exec_cp(char **argz, size_t *argz_len, const char *fmt, ...)
{
int fd, response_code, response_size, rc;
static const int buf_size = CP_BUF_SIZE;
char *buf, *command;
struct vmcp_parm cp;
char *command;
va_list ap;
int rc;
fd = open(VMCP_DEVICE_NODE, O_RDWR);
if (fd == -1)
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
if (ioctl(fd, VMCP_SETBUF, &buf_size) == -1)
errx(EXIT_FAILURE, "Could not set buffer size");
UTIL_VASPRINTF(&command, fmt, ap);
if (write(fd, command, strlen(command)) == -1)
errx(EXIT_FAILURE, "Could not issue CP command");
cp.cpcmd = command;
cp.do_upper = false;
cp.buffer_size = VMCP_DEFAULT_BUFSZ;
rc = vmcp(&cp);
free(command);
if (ioctl(fd, VMCP_GETCODE, &response_code) == -1)
switch (rc) {
case VMCP_ERR_OPEN:
errx(EXIT_FAILURE, "Could not open device %s", VMCP_DEVICE_NODE);
case VMCP_ERR_SETBUF:
errx(EXIT_FAILURE, "Could not set buffer size");
case VMCP_ERR_GETCODE:
errx(EXIT_FAILURE, "Could not query return code");
if (ioctl(fd, VMCP_GETSIZE, &response_size) == -1)
case VMCP_ERR_GETSIZE:
errx(EXIT_FAILURE, "Could not query response size");
buf = util_malloc(buf_size);
rc = misc_read_buf(fd, buf, buf_size);
if (rc == -1)
case VMCP_ERR_WRITE:
errx(EXIT_FAILURE, "Could not issue CP command");
case VMCP_ERR_READ:
errx(EXIT_FAILURE, "Could not read CP response");
rc = argz_create_sep(buf, '\n', argz, argz_len);
case VMCP_ERR_TOOSMALL:
break; /* Truncated CP response treated as good */
}
rc = argz_create_sep(cp.response, '\n', argz, argz_len);
if (rc)
errx(EXIT_FAILURE, "Memory allocation error for CP response processing");
free(buf);
free(cp.response);
}
/*

View File

@@ -57,6 +57,7 @@ Set all available cryptographic device(s) online or offline.
.B <device id>
Specifies a cryptographic device which will be set either online or offline.
The device can either be a card device or a queue device.
A queue device can only get switched online when the providing card is online.
Please note that the card device and queue device representation are both
in hexadecimal notation.
@@ -95,7 +96,7 @@ Print version information and exit.
.B chzcrypt -e 0 1 12
Will set the cryptographic card devices 0, 1 and 12 online.
.TP
.B chzcrypt -e 01.0038
.B chzcrypt -e 10.0038
Will set the cryptographic device '10.0038' respectively card id 16
(0x10) with domain 56 (0x38) online.
.TP

View File

@@ -41,12 +41,16 @@ all: check_dep_fuse check_dep_zlib zgetdump
OBJECTS = zgetdump.o opts.o zg.o \
dfi.o dfi_vmcoreinfo.o \
dfi_lkcd.o dfi_elf.o dfi_s390.o dfi_s390mv.o dfi_s390tape.o \
dfi_kdump.o dfi_devmem.o \
dfo.o dfo_elf.o dfo_s390.o \
dfi_lkcd.o dfi_elf.o \
dfi_s390.o dfi_s390_ext.o\
dfi_s390mv.o dfi_s390mv_ext.o \
dfi_s390tape.o dfi_kdump.o \
dfi_devmem.o dfo.o \
dfo_elf.o dfo_s390.o \
df_s390.o \
dt.o dt_s390sv.o dt_s390mv.o dt_scsi.o \
stdout.o
dt.o dt_s390sv.o dt_s390sv_ext.o \
dt_s390mv.o dt_s390mv_ext.o \
dt_scsi.o stdout.o \
ifeq ("$(HAVE_FUSE)","0")
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64

View File

@@ -3,7 +3,7 @@
*
* S390 dump format common functions
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -41,7 +41,7 @@ void df_s390_cpu_info_add(struct df_s390_hdr *hdr, u64 addr_max)
{
unsigned int i;
if (hdr->version < 5) {
if (hdr->version < 5 && hdr->magic == DF_S390_MAGIC) {
/* No Prefix registers in header */
hdr->cpu_cnt = 0;
dfi_cpu_info_init(DFI_CPU_CONTENT_NONE);
@@ -85,11 +85,14 @@ void df_s390_hdr_add(struct df_s390_hdr *hdr)
dfi_arch_set(df_s390_to_dfi_arch(hdr->arch));
if (hdr->cpu_id)
dfi_attr_cpu_id_set(hdr->cpu_id);
if (hdr->version >= 3 && hdr->mem_size_real)
dfi_attr_mem_size_real_set(hdr->mem_size_real);
if (hdr->version >= 2 && hdr->build_arch)
if ((hdr->version >= 2 || hdr->magic == DF_S390_MAGIC_EXT) &&
hdr->build_arch)
dfi_attr_build_arch_set(df_s390_to_dfi_arch(hdr->build_arch));
if (hdr->version >= 5 && hdr->real_cpu_cnt)
if ((hdr->version >= 3 || hdr->magic == DF_S390_MAGIC_EXT) &&
hdr->mem_size_real)
dfi_attr_mem_size_real_set(hdr->mem_size_real);
if ((hdr->version >= 5 || hdr->magic == DF_S390_MAGIC_EXT) &&
hdr->real_cpu_cnt)
dfi_attr_real_cpu_cnt_set(hdr->real_cpu_cnt);
}
@@ -124,8 +127,38 @@ int df_s390_em_verify(struct df_s390_em *em, struct df_s390_hdr *hdr)
void df_s390_dumper_read(struct zg_fh *fh, int blk_size,
struct df_s390_dumper *dumper)
{
int offset = DF_S390_MAGIC_BLK_ECKD * blk_size;
int bytes_to_read, offset = DF_S390_MAGIC_BLK_ECKD * blk_size;
/*
* First read 3 fields at the start of the dumper. The magic number,
* version and one extra field for the old dumper case (no magic
* number, checking for specific assembler instructions).
*/
bytes_to_read = offsetof(struct df_s390_dumper, force);
zg_seek(fh, offset, ZG_CHECK);
zg_read(fh, dumper, sizeof(*dumper), ZG_CHECK);
zg_read(fh, dumper, bytes_to_read, ZG_CHECK);
if (memcmp(dumper->magic, OLD_DUMPER_HEX_INSTR1, 4) == 0 &&
memcmp(&dumper->size, OLD_DUMPER_HEX_INSTR2, 2) == 0)
/* We found basr r13,0 (old dumper) */
dumper->version = 0;
switch (dumper->version) {
case 1:
if (strncmp(dumper->magic, DF_S390_DUMPER_MAGIC_EXT, 7) == 0 ||
strncmp(dumper->magic, DF_S390_DUMPER_MAGIC_MV_EXT, 7) == 0)
dumper->size = DF_S390_DUMPER_SIZE_V3;
else
dumper->size = DF_S390_DUMPER_SIZE_V1;
break;
case 2:
dumper->size = DF_S390_DUMPER_SIZE_V2;
break;
case 3:
default:
dumper->size = DF_S390_DUMPER_SIZE_V3;
}
/* Read force and mem fields in the end of the dumper */
bytes_to_read = sizeof(dumper->force) + sizeof(dumper->mem);
offset += dumper->size - bytes_to_read;
zg_seek(fh, offset, ZG_CHECK);
zg_read(fh, &dumper->force, bytes_to_read, ZG_CHECK);
}

View File

@@ -3,7 +3,7 @@
*
* S390 dump format common functions
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* 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,6 +16,7 @@
#include "zg.h"
#define DF_S390_MAGIC 0xa8190173618f23fdULL
#define DF_S390_MAGIC_EXT 0xa8190173618f23feULL
#define DF_S390_HDR_SIZE 0x1000
#define DF_S390_EM_SIZE 16
#define DF_S390_EM_STR "DUMP_END"
@@ -68,6 +69,16 @@ struct df_s390_em {
u64 tod;
} __attribute__((packed));
/*
* Segment header for s390 extended dump format
*/
struct df_s390_dump_segm_hdr {
u64 start;
u64 len;
u64 stop_marker;
u8 reserved[0x1000 - 24];
} __attribute__((packed));
/*
* Convert DFI arch to s390 arch
*/
@@ -84,96 +95,31 @@ static inline enum dfi_arch df_s390_to_dfi_arch(enum df_s390_arch df_s390_arch)
return df_s390_arch == DF_S390_ARCH_64 ? DFI_ARCH_64 : DFI_ARCH_32;
}
/*
* Dump tool structure (version 1)
*/
struct df_s390_dumper_v1 {
char code[0xff7 - 0x8];
u8 force;
u64 mem;
} __attribute__ ((packed));
#define DF_S390_DUMPER_SIZE_V1 0x1000
/*
* Dump tool structure (version 2)
*/
struct df_s390_dumper_v2 {
char code[0x1ff7 - 0x8];
u8 force;
u64 mem;
} __attribute__ ((packed));
#define DF_S390_DUMPER_SIZE_V2 0x2000
/*
* Dump tool structure (version 3 and 4)
*/
struct df_s390_dumper_v3 {
char code[0x2ff7 - 0x8];
u8 force;
u64 mem;
} __attribute__ ((packed));
#define DF_S390_DUMPER_SIZE_V3 0x3000
#define DF_S390_DUMPER_SIZE_V1 0x1000
#define DF_S390_DUMPER_SIZE_V2 0x2000
#define DF_S390_DUMPER_SIZE_V3 0x3000
#define DF_S390_DUMPER_MAGIC32 "ZECKD31"
#define DF_S390_DUMPER_MAGIC64 "ZECKD64"
#define DF_S390_DUMPER_MAGIC_EXT "XECKD64"
#define DF_S390_DUMPER_MAGIC32_FBA "ZDFBA31"
#define DF_S390_DUMPER_MAGIC64_FBA "ZDFBA64"
#define DF_S390_DUMPER_MAGIC_FBA_EXT "XDFBA64"
#define DF_S390_DUMPER_MAGIC_MV "ZMULT64"
#define DF_S390_DUMPER_MAGIC_MV_EXT "XMULT64"
#define OLD_DUMPER_HEX_INSTR1 "\x0d\x10\x47\xf0" /* BASR + 1st halfword of BC */
#define OLD_DUMPER_HEX_INSTR2 "\x0d\xd0" /* BASR 13,0 */
/*
* Dump tool structure
*/
struct df_s390_dumper {
char magic[7];
u8 version;
union {
struct df_s390_dumper_v1 v1;
struct df_s390_dumper_v2 v2;
struct df_s390_dumper_v3 v3;
} d;
char magic[7];
u8 version;
u32 size;
u8 force;
u64 mem;
} __attribute__ ((packed));
/*
* Dumper member access helpers
*/
#define df_s390_dumper_magic(dumper) ((dumper).magic)
#define df_s390_dumper_version(dumper) ((dumper).version)
static inline u64 df_s390_dumper_mem(struct df_s390_dumper *dumper)
{
switch (dumper->version) {
case 1:
return dumper->d.v1.mem;
case 2:
return dumper->d.v2.mem;
case 3:
default:
return dumper->d.v3.mem;
}
}
static inline u8 df_s390_dumper_force(struct df_s390_dumper *dumper)
{
switch (dumper->version) {
case 1:
return dumper->d.v1.force;
case 2:
return dumper->d.v2.force;
case 3:
default:
return dumper->d.v3.force;
}
}
static inline unsigned long df_s390_dumper_size(struct df_s390_dumper *dumper)
{
switch (dumper->version) {
case 1:
return 0x1000;
case 2:
return 0x2000;
case 3:
default:
return 0x3000;
}
}
/*
* s390 dump helpers
*/
@@ -185,10 +131,14 @@ extern void df_s390_dumper_read(struct zg_fh *fh, int32_t blk_size,
struct df_s390_dumper *dumper);
/*
* DASD multi-volume dumper functions
* DASD dt and dfi functions
*/
extern int dt_s390mv_init(void);
extern void dt_s390mv_exit(void);
extern int dt_s390sv_init_gen(bool extended);
extern int dt_s390mv_init_gen(bool extended);
extern void dt_s390mv_info(void);
extern int dfi_s390_init_gen(bool extended);
extern int dfi_s390mv_init_gen(bool extended);
extern void dfi_s390mv_info(void);
#endif /* DF_S390_H */

View File

@@ -3,7 +3,7 @@
*
* Generic input dump format functions (DFI - Dump Format Input)
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -21,7 +21,9 @@
static struct dfi *dfi_vec[] = {
&dfi_s390tape,
&dfi_devmem,
&dfi_s390mv_ext,
&dfi_s390mv,
&dfi_s390_ext,
&dfi_s390,
&dfi_lkcd,
&dfi_elf,
@@ -70,6 +72,7 @@ struct attr {
u32 *real_cpu_cnt;
struct new_utsname *utsname;
char *dump_method;
u64 *file_size;
};
/*
@@ -149,12 +152,46 @@ static void mem_update(struct mem *mem)
static void mem_map_print(void)
{
struct dfi_mem_chunk *mem_chunk;
u64 print_start = 0, print_end = 0;
const char *zero_str;
u32 volnr = 0;
STDERR("\nMemory map:\n");
dfi_mem_chunk_iterate(mem_chunk) {
STDERR(" %016llx - %016llx (%llu MB)\n", mem_chunk->start,
mem_chunk->end, TO_MIB(mem_chunk->size));
/*
* Print each memory chunk if verbose specified
*/
if (g.opts.verbose_specified) {
dfi_mem_chunk_iterate(mem_chunk) {
zero_str = "";
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
zero_str = " zeroes";
STDERR(" %016llx - %016llx (%llu MB%s)\n",
mem_chunk->start, mem_chunk->end,
TO_MIB(mem_chunk->size), zero_str);
}
return;
}
/*
* Merge adjacent memory chunks from the same volume
*/
dfi_mem_chunk_iterate(mem_chunk) {
if (print_end == 0) {
print_start = mem_chunk->start;
print_end = mem_chunk->end;
volnr = mem_chunk->volnr;
continue;
}
if (mem_chunk->start != print_end + 1 ||
mem_chunk->volnr != volnr) {
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
print_end, TO_MIB(print_end - print_start + 1));
print_start = mem_chunk->start;
volnr = mem_chunk->volnr;
}
print_end = mem_chunk->end;
}
STDERR(" %016llx - %016llx (%llu MB)\n", print_start,
print_end, TO_MIB(print_end - print_start + 1));
}
/*
@@ -226,6 +263,9 @@ void dfi_info_print(void)
if (l.attr.mem_size_real)
STDERR(" Real memory range..: %lld MB\n",
TO_MIB(*l.attr.mem_size_real));
if (l.attr.file_size)
STDERR(" Dump file size.....: %lld MB\n",
TO_MIB(*l.attr.file_size));
if (dfi_mem_range())
mem_map_print();
if (l.dfi->info_dump) {
@@ -351,9 +391,27 @@ void dfi_mem_chunk_virt_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
if (size == 0)
return;
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
}
/*
* Add memory chunk with volume index
*/
void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn,
u32 volnr)
{
if (size == 0)
return;
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
l.mem_virt.chunk_cache->volnr = volnr;
}
/*
* Add memory chunk
*/
@@ -361,8 +419,16 @@ void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn)
{
mem_chunk_create(&l.mem_phys, start, size, data, read_fn, free_fn);
mem_chunk_create(&l.mem_virt, start, size, data, read_fn, free_fn);
dfi_mem_chunk_add_vol(start, size, data, read_fn, free_fn, 0);
}
/*
* Read zero pages
*/
void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
u64 UNUSED(off), void *buf, u64 cnt)
{
memset(buf, 0, cnt);
}
/*
@@ -401,6 +467,16 @@ struct dfi_mem_chunk *dfi_mem_chunk_first(void)
return util_list_start(&l.mem_virt.chunk_list);
}
/*
* Return last memory chunk
*/
struct dfi_mem_chunk *dfi_mem_chunk_last(void)
{
if (util_list_is_empty(&l.mem_virt.chunk_list))
return NULL;
return util_list_end(&l.mem_virt.chunk_list);
}
/*
* Return next memory chunk
*/
@@ -678,7 +754,7 @@ struct new_utsname *dfi_attr_utsname(void)
}
/*
* Attribute: dump method
* Attribute: Dump method
*/
void dfi_attr_dump_method_set(char *dump_method)
{
@@ -704,6 +780,21 @@ u64 *dfi_attr_mem_size_real(void)
return l.attr.mem_size_real;
}
/*
* Attribute: Dump file size
*/
void dfi_attr_file_size_set(u64 file_size)
{
l.attr.file_size = zg_alloc(sizeof(*l.attr.file_size));
*l.attr.file_size = file_size;
}
u64 *dfi_attr_file_size(void)
{
return l.attr.file_size;
}
/*
* Attribute: Build architecture
*/
@@ -795,7 +886,10 @@ static void lc2cpu_64(struct dfi_cpu *cpu, struct dfi_lowcore_64 *lc)
/* Add VX registers if available */
if (!dfi_cpu_lc_has_vx_sa(lc))
return;
dfi_mem_read(lc->vector_save_area_addr, &vx_sa, sizeof(vx_sa));
if (dfi_mem_read_rc(lc->vector_save_area_addr, &vx_sa, sizeof(vx_sa))) {
STDERR("zgetdump: Vector registers save area is beyond dump memory limit for CPU %d\n", cpu->cpu_id);
return;
}
memcpy(cpu->vxrs_high, &vx_sa[16 * 16], sizeof(cpu->vxrs_high));
for (i = 0; i < 16; i++)
memcpy(&cpu->vxrs_low[i], &vx_sa[16 * i + 8], sizeof(u64));
@@ -827,6 +921,7 @@ void dfi_cpu_add_from_lc(u32 lc_addr)
{
struct dfi_cpu *cpu = dfi_cpu_alloc();
cpu->cpu_id = l.cpus.cnt;
switch (l.cpus.content) {
case DFI_CPU_CONTENT_LC:
cpu->prefix = lc_addr;

View File

@@ -3,7 +3,7 @@
*
* Generic input dump format functions (DFI - Dump Format Input)
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -97,6 +97,7 @@ struct dfi_cpu {
u32 todpreg;
u64 vxrs_low[16];
struct dfi_vxrs vxrs_high[16];
u16 cpu_id;
};
struct dfi_cpu_32 {
@@ -125,7 +126,7 @@ enum dfi_cpu_content {
};
#define DFI_CPU_CONTENT_FAC_VX 0x00000001
extern int dfi_cpu_content_fac_check(int falgs);
extern int dfi_cpu_content_fac_check(int flags);
extern void dfi_cpu_content_fac_add(int flags);
#define dfi_cpu_iterate(cpu) \
@@ -158,13 +159,18 @@ struct dfi_mem_chunk {
u64 start; /* Start address in memory */
u64 end; /* End address in memory */
u64 size; /* Size of chunk in dump file */
u64 out_start; /* Start offset in dump file */
u64 out_end; /* End offset in dump file */
dfi_mem_chunk_read_fn read_fn; /* Chunk read callback */
dfi_mem_chunk_free_fn free_fn; /* Free data callback */
void *data; /* Data for callback */
u32 volnr; /* Volume id where chunk resides */
};
extern void dfi_mem_chunk_read_zero(struct dfi_mem_chunk *UNUSED(mem_chunk),
u64 UNUSED(off), void *buf, u64 cnt);
extern void dfi_mem_chunk_add_vol(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn,
u32 volnr);
extern void dfi_mem_chunk_add(u64 start, u64 size, void *data,
dfi_mem_chunk_read_fn read_fn,
dfi_mem_chunk_free_fn free_fn);
@@ -175,6 +181,7 @@ extern u64 dfi_mem_range(void);
extern int dfi_mem_range_valid(u64 addr, u64 len);
extern unsigned int dfi_mem_chunk_cnt(void);
extern struct dfi_mem_chunk *dfi_mem_chunk_first(void);
extern struct dfi_mem_chunk *dfi_mem_chunk_last(void);
extern struct dfi_mem_chunk *dfi_mem_chunk_next(struct dfi_mem_chunk *chunk);
extern struct dfi_mem_chunk *dfi_mem_chunk_prev(struct dfi_mem_chunk *chunk);
extern struct dfi_mem_chunk *dfi_mem_chunk_find(u64 addr);
@@ -202,7 +209,10 @@ extern void dfi_attr_dump_method_set(char *dump_method);
extern char *dfi_attr_dump_method(void);
extern void dfi_attr_mem_size_real_set(u64 mem_size_real);
extern u64 *dfi_attr_mem_size_real();
extern u64 *dfi_attr_mem_size_real(void);
extern void dfi_attr_file_size_set(u64 dump_size);
extern u64 *dfi_attr_file_size(void);
extern void dfi_attr_vol_nr_set(unsigned int vol_nr);
extern unsigned int *dfi_attr_vol_nr(void);

View File

@@ -3,7 +3,7 @@
*
* ELF core dump input format
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -42,12 +42,16 @@ static int pt_load_add(Elf64_Phdr *phdr)
STDERR("Dump file \"%s\" is a user space core dump\n",
g.opts.device);
}
if (phdr->p_filesz == 0) /* Skip null pt loads */
return 0;
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = phdr->p_offset;
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_filesz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
if (phdr->p_filesz == 0) {
/* Add zero memory chunk */
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, NULL,
dfi_mem_chunk_read_zero, NULL);
} else {
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = phdr->p_offset;
dfi_mem_chunk_add(phdr->p_paddr, phdr->p_memsz, off_ptr,
dfi_elf_mem_chunk_read_fn, zg_free);
}
if (phdr->p_offset + phdr->p_filesz > zg_size(g.fh))
return -EINVAL;
return 0;

View File

@@ -26,10 +26,11 @@
static struct {
struct df_s390_hdr hdr; /* s390 dump header */
struct df_s390_em em; /* s390 end marker */
bool extended; /* Extended input dump format */
} l;
/*
* S390 mem chunk read callback
* s390 mem chunk read callback
*/
static void dfi_s390_mem_chunk_read(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
@@ -40,16 +41,32 @@ static void dfi_s390_mem_chunk_read(struct dfi_mem_chunk *mem_chunk, u64 off,
zg_read(g.fh, buf, cnt, ZG_CHECK);
}
/*
* s390_ext mem chunk read callback
*/
static void dfi_s390_ext_mem_chunk_read(struct dfi_mem_chunk *mem_chunk,
u64 off, void *buf, u64 cnt)
{
u64 *mem_chunk_off = mem_chunk->data;
zg_seek(g.fh, *mem_chunk_off + off, ZG_CHECK);
zg_read(g.fh, buf, cnt, ZG_CHECK);
}
/*
* Read s390 dump header
*/
static int read_s390_hdr(void)
{
u64 magic_number;
magic_number = l.extended ? DF_S390_MAGIC_EXT : DF_S390_MAGIC;
if ((zg_type(g.fh) == ZG_TYPE_FILE) && (zg_size(g.fh) < sizeof(l.hdr)))
return -ENODEV;
if (zg_read(g.fh, &l.hdr, sizeof(l.hdr), ZG_CHECK_ERR) != sizeof(l.hdr))
return -ENODEV;
if (l.hdr.magic != DF_S390_MAGIC)
if (l.hdr.magic != magic_number)
return -ENODEV;
df_s390_hdr_add(&l.hdr);
return 0;
@@ -62,9 +79,6 @@ static int read_s390_em(void)
{
u64 rc;
rc = zg_seek(g.fh, l.hdr.mem_size + DF_S390_HDR_SIZE, ZG_CHECK_NONE);
if (rc != l.hdr.mem_size + DF_S390_HDR_SIZE)
return -EINVAL;
rc = zg_read(g.fh, &l.em, sizeof(l.em), ZG_CHECK_ERR);
if (rc != sizeof(l.em))
return -EINVAL;
@@ -75,23 +89,97 @@ static int read_s390_em(void)
}
/*
* Initialize s390 DFI
* Register memory chunks and verify the end marker
*/
static int dfi_s390_init(void)
static int mem_chunks_add(void)
{
u64 rc;
/* Single memory chunk for non-extended dump format */
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL,
dfi_s390_mem_chunk_read,
NULL);
rc = zg_seek(g.fh, DF_S390_HDR_SIZE + l.hdr.mem_size,
ZG_CHECK_NONE);
if (rc != DF_S390_HDR_SIZE + l.hdr.mem_size)
return -EINVAL;
/* Read and verify the end marker */
return read_s390_em();
}
/*
* Register memory chunks (extended dump format) and verify the end marker
*/
static int mem_chunks_add_ext(void)
{
struct df_s390_dump_segm_hdr dump_segm;
u64 rc, *off_ptr, old = 0, dump_size = 0;
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = zg_seek(g.fh, DF_S390_HDR_SIZE, ZG_CHECK_NONE);
if (*off_ptr != DF_S390_HDR_SIZE)
return -EINVAL;
while (*off_ptr < DF_S390_HDR_SIZE + l.hdr.mem_size - PAGE_SIZE) {
rc = zg_read(g.fh, &dump_segm, PAGE_SIZE, ZG_CHECK_ERR);
if (rc != PAGE_SIZE)
return -EINVAL;
*off_ptr += PAGE_SIZE;
/* Add zero memory chunk */
dfi_mem_chunk_add(old, dump_segm.start - old, NULL,
dfi_mem_chunk_read_zero, NULL);
/* Add memory chunk for a dump segment */
dfi_mem_chunk_add(dump_segm.start, dump_segm.len, off_ptr,
dfi_s390_ext_mem_chunk_read, zg_free);
old = dump_segm.start + dump_segm.len;
dump_size += dump_segm.len;
off_ptr = zg_alloc(sizeof(*off_ptr));
*off_ptr = zg_seek_cur(g.fh, dump_segm.len, ZG_CHECK_NONE);
if (dump_segm.stop_marker)
break;
}
/* Add zero memory chunk at the end */
dfi_mem_chunk_add(old, l.hdr.mem_size - old, NULL,
dfi_mem_chunk_read_zero, NULL);
/* Set the actual size of the dump file */
dfi_attr_file_size_set(dump_size);
/* Check if the last dump segment found */
if (!dump_segm.stop_marker)
return -EINVAL;
/* Read and verify the end marker */
return read_s390_em();
}
/*
* Initialize s390 single-volume DFI general function
*/
int dfi_s390_init_gen(bool extended)
{
int rc;
l.extended = extended;
if (read_s390_hdr() != 0)
return -ENODEV;
dfi_mem_chunk_add(0, l.hdr.mem_size, NULL, dfi_s390_mem_chunk_read,
NULL);
if (read_s390_em() != 0)
return -EINVAL;
if (!extended)
rc = mem_chunks_add();
else
rc = mem_chunks_add_ext();
if (rc)
return rc;
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_size);
zg_seek(g.fh, sizeof(l.hdr), ZG_CHECK);
return 0;
}
/*
* S390 DFI operations
* Initialize s390 single-volume DFI (non-extended)
*/
static int dfi_s390_init(void)
{
return dfi_s390_init_gen(DUMP_NON_EXTENDED);
}
/*
* s390 single-volume DFI (non-extended) operations
*/
struct dfi dfi_s390 = {
.name = "s390",

29
zdump/dfi_s390_ext.c Normal file
View File

@@ -0,0 +1,29 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 extended dump input format
*
* Copyright IBM Corp. 2001, 2018
*
* 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 "zgetdump.h"
/*
* Initialize s390 input dump format (extended)
*/
static int dfi_s390_ext_init(void)
{
return dfi_s390_init_gen(DUMP_EXTENDED);
}
/*
* s390 nput dump format (extedned) operations
*/
struct dfi dfi_s390_ext = {
.name = "s390_ext",
.init = dfi_s390_ext_init,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};

View File

@@ -3,7 +3,7 @@
*
* S390 multi-volume dump input format
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -21,52 +21,7 @@
#include <unistd.h>
#include "zgetdump.h"
#define SYSFS_BUSDIR "/sys/bus/ccw/devices"
#define MAX_VOLUMES 32
/*
* Parameter for DASD multi-volume dump
*/
struct vol_parm {
u16 devno;
u32 start_blk;
u32 end_blk;
u8 blk_size;
u8 end_sec;
u8 num_heads;
} __attribute__ ((packed));
struct vol_parm_table {
u64 timestamp;
u16 vol_cnt;
struct vol_parm vol_parm[MAX_VOLUMES];
u8 ssid[MAX_VOLUMES];
} __attribute__ ((packed));
/*
* Device signature
*/
enum dev_sign {
SIGN_INVALID = 0, /* No dumper installed */
SIGN_VALID = 1, /* dumper installed, but volume not used */
SIGN_ACTIVE = 2, /* dumper installed and volume userd */
};
static char *dev_sign_str[] = {"invalid", "valid", "active"};
#define dev_sign_str(x) (dev_sign_str[x])
/*
* Device status
*/
enum dev_status {
DEV_ONLINE = 0,
DEV_OFFLINE = 1,
DEV_UNDEFINED = 2,
};
static char *dev_status_str[] = {"online", "offline", "undefined"};
#define dev_status_str(x) (dev_status_str[x])
#include "dfi_s390mv.h"
/*
* Volume information
@@ -88,6 +43,14 @@ struct vol {
struct df_s390_hdr hdr;
};
/*
* Mem chunk helper structure for extended dump format
*/
struct vol_mem_chunk {
struct vol *vol;
u64 off; /* Offset to the memory chunk from the start of the volume */
};
/*
* File local static data
*/
@@ -99,6 +62,9 @@ static struct {
int blk_size;
struct df_s390_dumper dumper;
int dump_incomplete;
bool extended;
u64 magic_number; /* Reference value to compare with */
char dumper_magic[7]; /* Reference value to compare with */
} l;
/*
@@ -109,8 +75,7 @@ static void table_read(struct zg_fh *fh, u16 blk_size,
{
int off;
off = DF_S390_MAGIC_BLK_ECKD * blk_size +
df_s390_dumper_size(&l.dumper);
off = DF_S390_MAGIC_BLK_ECKD * blk_size + l.dumper.size;
zg_seek(fh, off, ZG_CHECK);
zg_read(fh, table, sizeof(*table), ZG_CHECK);
}
@@ -130,6 +95,7 @@ static void em_init(struct vol *vol)
l.dump_incomplete = 1;
}
/*
* Check sysfs, whether a device specified by its bus ID is defined and online.
* Find out the corresponding dev_t
@@ -221,9 +187,9 @@ static void vol_read(struct vol *vol)
}
/*
* Read memory
* Read memory chunk
*/
static void df_s390mv_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off,
static void dfi_s390mv_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
struct vol *vol = mem_chunk->data;
@@ -232,6 +198,19 @@ static void df_s390mv_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off,
zg_read(vol->fh, buf, cnt, ZG_CHECK);
}
/*
* Read memory chunk (extended)
*/
static void dfi_s390mv_ext_mem_read(struct dfi_mem_chunk *mem_chunk, u64 off,
void *buf, u64 cnt)
{
struct vol_mem_chunk *vol_mem_chunk = mem_chunk->data;
struct vol *vol = vol_mem_chunk->vol;
zg_seek(vol->fh, vol_mem_chunk->off + off, ZG_CHECK);
zg_read(vol->fh, buf, cnt, ZG_CHECK);
}
/*
* Initialize DASD volume
*/
@@ -258,12 +237,12 @@ static void vol_init(struct vol *vol, struct vol_parm *vol_parm, int ssid,
if ((vol->hdr.volnr == vol->nr) && (vol->hdr.mem_size != 0))
vol->sign = SIGN_ACTIVE;
if (vol->hdr.mvdump_sign != DF_S390_MAGIC) {
if (vol->hdr.mvdump_sign != l.magic_number) {
vol->sign = SIGN_INVALID;
l.dump_incomplete = 1;
}
if (strncmp(df_s390_dumper_magic(vol->dumper), "ZMULT64", 7) != 0) {
if (strncmp(vol->dumper.magic, l.dumper_magic, 7) != 0) {
vol->sign = SIGN_INVALID;
l.dump_incomplete = 1;
}
@@ -271,6 +250,9 @@ static void vol_init(struct vol *vol, struct vol_parm *vol_parm, int ssid,
if (vol->nr == 0)
l.hdr = vol->hdr;
if (l.extended)
return;
if (*mem_off == l.hdr.mem_size) {
/* Unused volume */
vol->mem_start = 0;
@@ -318,16 +300,86 @@ static void vol_print_all(void)
*/
static void mem_chunks_add(void)
{
struct vol *vol;
unsigned int i;
for (i = 0; i < l.table.vol_cnt; i++) {
vol = &l.vol_vec[i];
if (vol->sign != SIGN_ACTIVE)
continue;
dfi_mem_chunk_add_vol(vol->mem_start,
vol->mem_end - vol->mem_start + 1,
vol, dfi_s390mv_mem_read, NULL, vol->nr);
}
}
/*
* Add memory chunks (extended dump format) and verify the end marker
*/
static int mem_chunks_add_ext(void)
{
u64 off, rc, part_end, old = 0, dump_size = 0;
struct df_s390_dump_segm_hdr dump_segm;
struct vol_mem_chunk *vol_mem_chunk;
unsigned int i;
for (i = 0; i < l.table.vol_cnt; i++) {
struct vol *vol = &l.vol_vec[i];
if (vol->sign != SIGN_ACTIVE)
continue;
dfi_mem_chunk_add(vol->mem_start,
vol->mem_end - vol->mem_start + 1,
vol, df_s390mv_mem_read, NULL);
off = vol->part_off + DF_S390_HDR_SIZE;
part_end = vol->part_off + vol->part_size;
rc = zg_seek(vol->fh, off, ZG_CHECK_NONE);
if (rc != off)
return -EINVAL;
/*
* Reading dump segments from the start of partition (skipping
* the dump header) till the end of partition (considering that
* minimum dump segment size is one megabyte + one page and one
* more page is reserved for the end marker)
*/
while (off < part_end - MIB - PAGE_SIZE) {
rc = zg_read(vol->fh, &dump_segm, sizeof(dump_segm),
ZG_CHECK_ERR);
if (rc != PAGE_SIZE)
return -EINVAL;
off += PAGE_SIZE;
vol_mem_chunk = zg_alloc(sizeof(*vol_mem_chunk));
vol_mem_chunk->vol = vol;
vol_mem_chunk->off = off;
/* Add zero memory chunk */
dfi_mem_chunk_add_vol(old, dump_segm.start - old, NULL,
dfi_mem_chunk_read_zero, NULL,
vol->nr);
/* Add memory chunk for a dump segment */
dfi_mem_chunk_add_vol(dump_segm.start, dump_segm.len,
vol_mem_chunk,
dfi_s390mv_ext_mem_read, NULL,
vol->nr);
old = dump_segm.start + dump_segm.len;
dump_size += dump_segm.len;
off = zg_seek_cur(vol->fh, dump_segm.len,
ZG_CHECK_NONE);
if (dump_segm.stop_marker)
break;
}
if (dump_segm.stop_marker) {
/* Add zero memory chunk at the end*/
dfi_mem_chunk_add_vol(old, l.hdr.mem_size - old, NULL,
dfi_mem_chunk_read_zero, NULL,
vol->nr);
/* Set the actual size of the dump file */
dfi_attr_file_size_set(dump_size);
/* Read and verify the end marker */
rc = zg_read(vol->fh, &l.em, sizeof(l.em), ZG_CHECK);
if (rc != sizeof(l.em) ||
df_s390_em_verify(&l.em, &l.hdr) != 0)
return -EINVAL;
return 0;
}
}
/* No dump segment with the stop marker found */
return -EINVAL;
}
/*
@@ -405,9 +457,9 @@ static int mvdump_hdr_check(const char *file)
fh = zg_open(file, O_RDONLY, ZG_CHECK);
if (zg_read(fh, &hdr, sizeof(hdr), ZG_CHECK_ERR) != sizeof(hdr))
goto fail;
if (hdr.magic != DF_S390_MAGIC)
if (hdr.magic != l.magic_number)
goto fail;
if (hdr.mvdump_sign != DF_S390_MAGIC)
if (hdr.mvdump_sign != l.magic_number)
goto fail;
rc = 0;
fail:
@@ -428,14 +480,6 @@ static void check_sysfs(void)
closedir(fh_dir);
}
/*
* Print dump information (dfi operation)
*/
static void dfi_s390mvfo_dump(void)
{
vol_print_all();
}
/*
* Read dump tool from DASD and check if we have a multi-volume dump tool
*/
@@ -445,7 +489,7 @@ static int mv_dumper_read(void)
ZG_CHECK_NONE) == -1)
return -ENODEV;
df_s390_dumper_read(g.fh, l.blk_size, &l.dumper);
if (memcmp(df_s390_dumper_magic(l.dumper), "ZMULT64", 7) != 0)
if (strncmp(l.dumper.magic, l.dumper_magic, 7) != 0)
return -ENODEV;
table_read(g.fh, l.blk_size, &l.table);
return 0;
@@ -466,6 +510,8 @@ static void volumes_init(void)
vol_init(&l.vol_vec[i], &l.table.vol_parm[i], l.table.ssid[i],
&mem_off);
}
if (l.extended)
return;
if (mem_off != l.hdr.mem_size)
l.dump_incomplete = 1;
}
@@ -476,7 +522,7 @@ static void volumes_init(void)
static int open_dump(void)
{
const struct stat *stat = zg_stat(g.fh);
unsigned dev_minor;
unsigned int dev_minor;
enum zg_type type;
char *path;
@@ -500,10 +546,26 @@ static int open_dump(void)
}
/*
* Initialize s390 multi-volume input dump format
* Specify reference values for dumper magic and dump magic numbers
*/
static int dfi_s390mv_init(void)
static void set_magic_numbers(void)
{
if (l.extended) {
l.magic_number = DF_S390_MAGIC_EXT;
strncpy(l.dumper_magic, DF_S390_DUMPER_MAGIC_MV_EXT, 7);
} else {
l.magic_number = DF_S390_MAGIC;
strncpy(l.dumper_magic, DF_S390_DUMPER_MAGIC_MV, 7);
}
}
/*
* Initialize s390 multi-volume input dump format generic function
*/
int dfi_s390mv_init_gen(bool extended)
{
l.extended = extended;
set_magic_numbers();
if (open_dump() != 0)
return -ENODEV;
volumes_init();
@@ -512,7 +574,10 @@ static int dfi_s390mv_init(void)
if (l.hdr.mem_size == 0)
return -ENODEV;
df_s390_hdr_add(&l.hdr);
mem_chunks_add();
if (!extended)
mem_chunks_add();
else if (mem_chunks_add_ext() != 0)
return -EINVAL;
if (l.dump_incomplete)
return -EINVAL;
df_s390_cpu_info_add(&l.hdr, l.hdr.mem_end);
@@ -521,17 +586,35 @@ static int dfi_s390mv_init(void)
}
/*
* Initialize s390 multi-volume dump tool (for -d option)
* Initializt s390 multi-volume input dump
*/
int dt_s390mv_init(void)
static int dfi_s390mv_init(void)
{
return dfi_s390mv_init_gen(DUMP_NON_EXTENDED);
}
/*
* Print dump information (dfi operation)
*/
void dfi_s390mv_info(void)
{
vol_print_all();
}
/*
* Initialize s390 multi-volume dump tool generic function
*/
int dt_s390mv_init_gen(bool extended)
{
l.extended = extended;
set_magic_numbers();
if (open_dump() != 0)
return -ENODEV;
volumes_init();
dt_arch_set(DFI_ARCH_64);
dt_version_set(df_s390_dumper_version(l.dumper));
dt_attr_mem_limit_set(df_s390_dumper_mem(&l.dumper));
dt_attr_force_set(df_s390_dumper_force(&l.dumper));
dt_version_set(l.dumper.version);
dt_attr_mem_limit_set(l.dumper.mem);
dt_attr_force_set(l.dumper.force);
return 0;
}
@@ -549,6 +632,6 @@ void dt_s390mv_info(void)
struct dfi dfi_s390mv = {
.name = "s390mv",
.init = dfi_s390mv_init,
.info_dump = dfi_s390mvfo_dump,
.info_dump = dfi_s390mv_info,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};

62
zdump/dfi_s390mv.h Normal file
View File

@@ -0,0 +1,62 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 multi-volume dump input format common structures
*
* Copyright IBM Corp. 2001, 2018
*
* 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 DFI_S390MV_H
#define DFI_S390MV_H
#include "lib/zt_common.h"
#define SYSFS_BUSDIR "/sys/bus/ccw/devices"
#define MAX_VOLUMES 32
/*
* Parameter for DASD multi-volume dump
*/
struct vol_parm {
u16 devno;
u32 start_blk;
u32 end_blk;
u8 blk_size;
u8 end_sec;
u8 num_heads;
} __attribute__ ((packed));
struct vol_parm_table {
u64 timestamp;
u16 vol_cnt;
struct vol_parm vol_parm[MAX_VOLUMES];
u8 ssid[MAX_VOLUMES];
} __attribute__ ((packed));
/*
* Device signature
*/
enum dev_sign {
SIGN_INVALID = 0, /* No dumper installed */
SIGN_VALID = 1, /* dumper installed, but volume not used */
SIGN_ACTIVE = 2, /* dumper installed and volume userd */
};
static char *dev_sign_str[] = {"invalid", "valid", "active"};
#define dev_sign_str(x) (dev_sign_str[x])
/*
* Device status
*/
enum dev_status {
DEV_ONLINE = 0,
DEV_OFFLINE = 1,
DEV_UNDEFINED = 2,
};
static char *dev_status_str[] = {"online", "offline", "undefined"};
#define dev_status_str(x) (dev_status_str[x])
#endif /* DFI_S390MV_H */

30
zdump/dfi_s390mv_ext.c Normal file
View File

@@ -0,0 +1,30 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390x multi-volume dump input format
*
* Copyright IBM Corp. 2001, 2018
*
* 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 "zgetdump.h"
/*
* Initialize s390 multi-volume input dump format (extedend)
*/
static int dfi_s390mv_ext_init(void)
{
return dfi_s390mv_init_gen(DUMP_EXTENDED);
}
/*
* s390 multi-volume DFI (extedned) operations
*/
struct dfi dfi_s390mv_ext = {
.name = "s390mv_ext",
.init = dfi_s390mv_ext_init,
.info_dump = dfi_s390mv_info,
.feat_bits = DFI_FEAT_COPY | DFI_FEAT_SEEK,
};

View File

@@ -52,7 +52,6 @@ void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
dfo_chunk->start = start;
dfo_chunk->end = start + size - 1;
dfo_chunk->size = size;
dfo_chunk->data = data;
dfo_chunk->read_fn = read_fn;
util_list_add_head(&l.dump.chunk_list, dfo_chunk);

View File

@@ -24,7 +24,6 @@ struct dfo_chunk {
struct util_list_node list;
u64 start;
u64 end;
u64 size;
dfo_chunk_read_fn read_fn;
void *data;
};

View File

@@ -3,7 +3,7 @@
*
* ELF core dump output format
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -71,8 +71,12 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
phdr->p_offset = loads_offset;
phdr->p_vaddr = mem_chunk->start;
phdr->p_paddr = mem_chunk->start;
phdr->p_filesz = mem_chunk->end - mem_chunk->start + 1;
phdr->p_memsz = phdr->p_filesz;
phdr->p_memsz = mem_chunk->end - mem_chunk->start + 1;
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
/* Zero memory chunk */
phdr->p_filesz = 0;
else
phdr->p_filesz = phdr->p_memsz;
phdr->p_flags = PF_R | PF_W | PF_X;
phdr->p_align = PAGE_SIZE;
loads_offset += phdr->p_filesz;
@@ -277,6 +281,9 @@ static void dump_chunks_init(void)
dfo_chunk_add(0, l.hdr_size, l.hdr, dfo_chunk_buf_fn);
off = l.hdr_size;
dfi_mem_chunk_iterate(mem_chunk) {
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
/* Zero memory chunk */
continue;
dfo_chunk_add(off, mem_chunk->size, mem_chunk,
dfo_chunk_mem_fn);
off += mem_chunk->size;

View File

@@ -3,7 +3,7 @@
*
* Dump tool info generic functions
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -15,7 +15,9 @@
* Supported dump tools
*/
static struct dt *dt_vec[] = {
&dt_s390mv_ext,
&dt_s390mv,
&dt_s390sv_ext,
&dt_s390sv,
&dt_scsi,
NULL,

View File

@@ -13,6 +13,10 @@
#define DT_H
#include "dfi.h"
#include <stdbool.h>
#define DUMP_EXTENDED true
#define DUMP_NON_EXTENDED false
struct dt {
const char *desc;

View File

@@ -12,7 +12,15 @@
#include "zgetdump.h"
/*
* DT operations
* Initialize s390 multi-volume dump tool (for -d option)
*/
static int dt_s390mv_init(void)
{
return dt_s390mv_init_gen(DUMP_NON_EXTENDED);
}
/*
* Dump Tool operations
*/
struct dt dt_s390mv = {
.desc = "Multi-volume DASD dump tool",

29
zdump/dt_s390mv_ext.c Normal file
View File

@@ -0,0 +1,29 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390x multi-volume DASD dump tool
*
* Copyright IBM Corp. 2001, 2018
*
* 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 "zgetdump.h"
/*
* Initialize s390 multi-volume dump tool (extedend) for -d option
*/
static int dt_s390mv_ext_init(void)
{
return dt_s390mv_init_gen(DUMP_EXTENDED);
}
/*
* Dump Tool (extedned) operations
*/
struct dt dt_s390mv_ext = {
.desc = "Multi-volume DASD dump tool (extended)",
.init = dt_s390mv_ext_init,
.info = dt_s390mv_info,
};

View File

@@ -3,7 +3,7 @@
*
* S390 single-volume DASD dump tool
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -12,14 +12,13 @@
#include <linux/fs.h>
#include "zgetdump.h"
#define HEXINSTR "\x0d\x10\x47\xf0" /* BASR + 1st halfword of BC */
/*
* File local static data
*/
static struct {
struct df_s390_dumper dumper;
enum dfi_arch dumper_arch;
bool extended; /* Extended dump-tool */
} l;
/*
@@ -29,15 +28,19 @@ static int dumper_read_eckd(int blk_size)
{
df_s390_dumper_read(g.fh, blk_size, &l.dumper);
if (strncmp(l.dumper.magic, "ZECKD31", 7) == 0) {
l.dumper_arch = DFI_ARCH_32;
} else if (strncmp(l.dumper.magic, "ZECKD64", 7) == 0) {
if (l.extended) {
if (strncmp(l.dumper.magic, DF_S390_DUMPER_MAGIC_EXT, 7) != 0)
return -ENODEV;
l.dumper_arch = DFI_ARCH_64;
} else if ((memcmp(l.dumper.magic, HEXINSTR, 4) == 0) &&
(l.dumper.d.v1.code[0] == '\x0d') &&
(l.dumper.d.v1.code[1] == '\xd0')) {
/* We found basr r13,0 (old dumper) */
l.dumper.version = 0;
return 0;
}
if (strncmp(l.dumper.magic, DF_S390_DUMPER_MAGIC64, 7) == 0) {
l.dumper_arch = DFI_ARCH_64;
} else if (strncmp(l.dumper.magic, DF_S390_DUMPER_MAGIC32, 7) == 0) {
l.dumper_arch = DFI_ARCH_32;
} else if (memcmp(l.dumper.magic, OLD_DUMPER_HEX_INSTR1, 4) == 0 &&
l.dumper.version == 0) {
/* We found the old dumper */
l.dumper_arch = DFI_ARCH_UNKNOWN;
} else {
return -ENODEV;
@@ -46,28 +49,25 @@ static int dumper_read_eckd(int blk_size)
}
/*
* Read dump tool from FBA DASD device
* Check FBA dump tool magic number and set architecture attribute
*/
static void dumper_read_fba_gen(int size, void *buffer)
static int dumper_check_fba(struct df_s390_dumper *dumper)
{
zg_seek_end(g.fh, -size, ZG_CHECK);
zg_read(g.fh, buffer, size, ZG_CHECK);
}
/*
* Read dump tool on FBA disk and check its magic number
*/
static int dumper_check_fba(void)
{
if (strncmp(l.dumper.magic, "ZDFBA31", 7) == 0) {
l.dumper_arch = DFI_ARCH_32;
} else if (strncmp(l.dumper.magic, "ZDFBA64", 7) == 0) {
if (l.extended) {
if (strncmp(dumper->magic, DF_S390_DUMPER_MAGIC_FBA_EXT, 7)
!= 0)
return -ENODEV;
l.dumper_arch = DFI_ARCH_64;
} else if ((memcmp(l.dumper.magic, HEXINSTR, 4) == 0) &&
(l.dumper.d.v1.code[0] == '\x0d') &&
(l.dumper.d.v1.code[1] == '\xd0')) {
return 0;
}
if (strncmp(dumper->magic, DF_S390_DUMPER_MAGIC64_FBA, 7) == 0) {
l.dumper_arch = DFI_ARCH_64;
} else if (strncmp(dumper->magic, DF_S390_DUMPER_MAGIC32_FBA, 7) == 0) {
l.dumper_arch = DFI_ARCH_32;
} else if (memcmp(dumper->magic, OLD_DUMPER_HEX_INSTR1, 4) == 0 &&
memcmp(&dumper->size, OLD_DUMPER_HEX_INSTR2, 2) == 0) {
/* We found basr r13,0 (old dumper) */
l.dumper.version = 0;
dumper->version = 0;
l.dumper_arch = DFI_ARCH_UNKNOWN;
} else {
return -ENODEV;
@@ -75,19 +75,40 @@ static int dumper_check_fba(void)
return 0;
}
/*
* Read dump tool from FBA device
*/
static int dumper_read_validate_fba(int size, struct df_s390_dumper *dumper)
{
int bytes_to_read;
/*
* On FBA device the dumper is written at the end of the volume because
* there is not enough space to place it at the beginning due to the
* linux disk layout
*/
zg_seek_end(g.fh, -size, ZG_CHECK);
bytes_to_read = offsetof(struct df_s390_dumper, force);
zg_read(g.fh, dumper, bytes_to_read, ZG_CHECK);
if (dumper_check_fba(dumper) != 0)
return -ENODEV;
dumper->size = size;
bytes_to_read = sizeof(dumper->force) + sizeof(dumper->mem);
zg_seek_end(g.fh, -bytes_to_read, ZG_CHECK);
zg_read(g.fh, &dumper->force, bytes_to_read, ZG_CHECK);
return 0;
}
/*
* Read dump tool on FBA disk and check its magic number
*/
static int dumper_read_fba(void)
{
dumper_read_fba_gen(DF_S390_DUMPER_SIZE_V1, &l.dumper);
if (dumper_check_fba() == 0)
if (dumper_read_validate_fba(DF_S390_DUMPER_SIZE_V3, &l.dumper) == 0)
return 0;
dumper_read_fba_gen(DF_S390_DUMPER_SIZE_V2, &l.dumper);
if (dumper_check_fba() == 0)
if (dumper_read_validate_fba(DF_S390_DUMPER_SIZE_V2, &l.dumper) == 0)
return 0;
dumper_read_fba_gen(DF_S390_DUMPER_SIZE_V3, &l.dumper);
if (dumper_check_fba() == 0)
if (dumper_read_validate_fba(DF_S390_DUMPER_SIZE_V1, &l.dumper) == 0)
return 0;
return -ENODEV;
}
@@ -116,18 +137,23 @@ static int sv_dumper_read(void)
/*
* Initialize s390 single-volume dump tool (for -d option)
*/
static int dt_s390sv_init(void)
int dt_s390sv_init_gen(bool extended)
{
l.extended = extended;
if (sv_dumper_read() != 0)
return -ENODEV;
dt_arch_set(l.dumper_arch);
dt_version_set(df_s390_dumper_version(l.dumper));
dt_attr_mem_limit_set(df_s390_dumper_mem(&l.dumper));
dt_version_set(l.dumper.version);
dt_attr_mem_limit_set(l.dumper.mem);
return 0;
}
static int dt_s390sv_init(void)
{
return dt_s390sv_init_gen(DUMP_NON_EXTENDED);
}
/*
* s390 single-volume DT operations
* s390 single-volume DT (non-extended) operations
*/
struct dt dt_s390sv = {
.desc = "Single-volume DASD dump tool",

29
zdump/dt_s390sv_ext.c Normal file
View File

@@ -0,0 +1,29 @@
/*
* zgetdump - Tool for copying and converting System z dumps
*
* S390 single-volume DASD dump tool (extended)
*
* Copyright IBM Corp. 2001, 2018
*
* 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 <linux/fs.h>
#include "zgetdump.h"
/*
* Initialize s390 single-volume extended dump tool (for -d option)
*/
static int dt_s390sv_ext_init(void)
{
return dt_s390sv_init_gen(DUMP_EXTENDED);
}
/*
* s390 single-volume DT (extended) operations
*/
struct dt dt_s390sv_ext = {
.desc = "Single-volume DASD dump tool (extended)",
.init = dt_s390sv_ext_init,
};

View File

@@ -3,7 +3,7 @@
*
* Option parsing
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -46,9 +46,10 @@ static char help_text[] =
"-s, --select Select system data SYS (\"kdump\", \"prod\", or \"all\")\n"
"-d, --device Print DUMPDEV (dump device) information\n"
"-v, --version Print version information, then exit\n"
"-V, --verbose Show detailed layout of memory map on printing DUMP information\n"
"-h, --help Print this help, then exit\n";
static const char copyright_str[] = "Copyright IBM Corp. 2001, 2017";
static const char copyright_str[] = "Copyright IBM Corp. 2001, 2018";
/*
* Select option strings
@@ -251,9 +252,10 @@ void opts_parse(int argc, char *argv[])
{"fmt", required_argument, NULL, 'f'},
{"select", required_argument, NULL, 's'},
{"debug", no_argument, NULL, 'X'},
{"verbose", no_argument, NULL, 'V'},
{NULL, 0, NULL, 0 }
};
static const char optstr[] = "hvidmus:f:X";
static const char optstr[] = "hvVidmus:f:X";
init_defaults();
while ((opt = getopt_long(argc, argv, optstr, long_opts, &idx)) != -1) {
@@ -262,6 +264,9 @@ void opts_parse(int argc, char *argv[])
print_help_exit();
case 'v':
print_version_exit();
case 'V':
g.opts.verbose_specified = 1;
break;
case 'i':
action_set(ZG_ACTION_DUMP_INFO);
break;

View File

@@ -1,4 +1,4 @@
.\" Copyright 2017 IBM Corp.
.\" Copyright 2018 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.
.\"
@@ -59,6 +59,12 @@ more information.
Print the dump header information reading from the DUMP and check if
the dump is valid. See chapters DUMP and DUMP INFORMATION below for more
information.
.TP
.BR "\-V" " or " "\-\-verbose"
Show the detailed memory map layout when printing the dump header
information (relevant for s390_ext and ELF dump formats).
.TP
.BR "\-f <FMT>" " or " "\-\-fmt <FMT>"
Use the specified target dump format FMT when writing or mounting the dump.
@@ -170,6 +176,9 @@ This dump format is System z specific and is used for DASD and tape dumps.
.TP
The following dump formats are supported for the source dump only:
.TP
.BR "s390_ext"
This dump format is System z specific and is used for DASD dumps only.
.TP
.BR "lkcd"
This dump format is used by the Linux Kernel Crash Dumps (LKCD) project
and also on System z for the "vmconvert" dump tool.
@@ -245,6 +254,10 @@ The "real memory range" can differ from the "dump memory range" when
the SIZE parameter was used when preparing the dump device with the zipl
tool (see man zipl).
.TP
.BR "Dump file size"
Actual size of dump file on disk in megabytes. "Dump file size" may differ from
the "dump memory range" because of zero memory chunks.
.TP
.BR "Memory map"
Available memory chunks in the dump. Some dump tools create multiple memory
chunks when creating a dump on a system with memory gaps

View File

@@ -3,7 +3,7 @@
*
* Main include file - Should be included by all source files
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -35,6 +35,7 @@ struct options {
int argc_fuse;
const char *select;
int select_specified;
int verbose_specified;
};
extern const char *OPTS_SELECT_KDUMP;
@@ -75,7 +76,9 @@ void zfuse_umount(void);
*/
extern struct dfi dfi_s390tape;
extern struct dfi dfi_s390mv;
extern struct dfi dfi_s390mv_ext;
extern struct dfi dfi_s390;
extern struct dfi dfi_s390_ext;
extern struct dfi dfi_lkcd;
extern struct dfi dfi_elf;
extern struct dfi dfi_kdump;
@@ -92,7 +95,9 @@ extern struct dfo dfo_elf;
* Supported s390 dumpers
*/
extern struct dt dt_s390mv;
extern struct dt dt_s390mv_ext;
extern struct dt dt_s390sv;
extern struct dt dt_s390sv_ext;
extern struct dt dt_scsi;
#endif /* ZGETDUMP_H */

View File

@@ -6,6 +6,7 @@
dir /dev 755 0 0
nod /dev/console 644 0 0 c 5 1
nod /dev/null 644 0 0 c 1 3
nod /dev/sda 644 0 0 b 8 0
nod /dev/sda1 644 0 0 b 8 1
nod /dev/sda2 644 0 0 b 8 2
nod /dev/sda3 644 0 0 b 8 3
@@ -27,5 +28,4 @@ dir /mnt 755 0 0
dir /sbin 755 0 0
dir /etc 755 0 0
file /init arch/s390/boot/zfcpdump 755 0 0
file /sbin/e2fsck arch/s390/boot/e2fsck 755 0 0
slink /etc/mtab /proc/mounts 755 0 0

View File

@@ -74,6 +74,7 @@ stage3.exec: head.o stage3.o kdump3.o libc.o sclp.o sclp_stage3.o \
--only-section=.rodata \
--only-section=.stage2dump.tail \
--only-section=.eckd2dump_mv.tail \
--only-section=.fixup \
$< $@
data.o: $(FILES)

View File

@@ -3,7 +3,7 @@
*
* Common ECKD dump I/O functions
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -444,6 +444,34 @@ void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count)
io_block(cmd, blk, addr, blk_count, 0, 1);
}
/*
* Write dump segment with the header to DASD and return the next free
* block number
*/
unsigned long write_dump_segment(unsigned long blk,
struct df_s390_dump_segm_hdr *segm,
unsigned long zero_page)
{
unsigned long addr, start_blk, blk_count;
/* Write the dump segment header itself (1 page) */
writeblock(blk, (unsigned long)segm, m2b(PAGE_SIZE), zero_page);
blk += m2b(PAGE_SIZE);
/* Write the dump segment */
addr = segm->start;
start_blk = blk;
while (addr < segm->start + segm->len) {
/* Remaining blocks to write */
blk_count = m2b(segm->len) - (blk - start_blk);
blk_count = MIN(blk_count, eckd_blk_max);
writeblock(blk, addr, blk_count, zero_page);
progress_print(addr);
blk += blk_count;
addr += b2m(blk_count);
}
return blk;
}
/*
* Init ECKD common
*/

View File

@@ -3,7 +3,7 @@
*
* Common ECKD dump I/O functions
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -12,6 +12,7 @@
#define ECKD2DUMP_H
#include "cio.h"
#include "stage2dump.h"
struct eckd_device {
uint32_t blk_start;
@@ -46,5 +47,8 @@ void stage2dump_eckd_init();
void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
unsigned long zero_page);
void readblock(unsigned long blk, unsigned long addr, unsigned long blk_count);
unsigned long write_dump_segment(unsigned long blk,
struct df_s390_dump_segm_hdr *segm,
unsigned long zero_page);
#endif /* ECKD2DUMP_H */

View File

@@ -3,7 +3,7 @@
*
* Multi-volume ECKD DASD dump tool
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* 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,14 +13,14 @@
#include "error.h"
#include "stage2dump.h"
#define MVDUMP_SIZE 0x3000 /* Size of dump record */
#define MVDUMP_TOOL_SIZE 0x3000 /* Size of dump record */
#define MAX_DUMP_VOLUMES 32 /* Up to 32 dump volumes possible */
/*
* Magic number at start of dump record
*/
uint64_t magic __attribute__((section(".stage2.head")))
= 0x5a4d554c54363405ULL; /* ZMULT64, version 5 */
= 0x584d554c54363401ULL; /* XMULT64, version 1 */
/*
* Parameter format for ECKD MV dumper (13 bytes):
@@ -188,73 +188,117 @@ void dt_device_enable(void)
stage2dump_eckd_init();
}
/*
* Check for the volume timestamp and validate the dump signature
* before writing a dump.
*/
static void check_volume(unsigned long page)
{
struct mvdump_parm_table *mvdump_table_new;
struct df_s390_hdr *hdr_new;
/*
* Check whether parameter table on dump device has a valid
* time stamp. The parameter table is located right behind
* the dump tool, the corresponding block number is:
* MAGIC_BLK_ECKD + (MVDUMP_TOOL_SIZE / blocksize)
*/
mvdump_table_new = (void *) page;
readblock(DF_S390_MAGIC_BLK_ECKD + m2b(MVDUMP_TOOL_SIZE),
__pa(mvdump_table_new), 1);
/*
* Check if time stamps match
*/
if (mvdump_table.tod != mvdump_table_new->tod)
panic(ENOTIME, "Inconsistent time stamps");
/*
* Check if dump partition has a valid dump signature.
* Bypass signature check if "--force" had been specified during
* zipl -M.
*/
hdr_new = (void *) page;
if (!parm_tail.mvdump_force) {
readblock(device.blk_start, __pa(hdr_new), 1);
if (dump_hdr->magic != hdr_new->mvdump_sign)
panic(ENOSIGN, "Wrong signature");
}
}
/*
* Write the dump header and memory to the current volume and return the next
* address to write for the next volume or memory size if the dump ended
* on this volume
*/
static unsigned long write_volume(unsigned long addr, unsigned long page,
struct df_s390_dump_segm_hdr *dump_segm)
{
unsigned long free_space, blk;
/*
* Write dump header
*/
blk = device.blk_start;
writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
blk += m2b(DF_S390_HDR_SIZE);
/*
* The free space left on the volume minus 2 blocks (for the segment
* header and the end marker)
*/
free_space = b2m(device.blk_end - blk + 1) - b2m(2);
memset((void *) page, 0, PAGE_SIZE);
/*
* Write dump data
*/
while (addr < dump_hdr->mem_size) {
/*
* Find the next non-zero dump segment with the limit
* of segment length set to the amount of free space left
*/
addr = find_dump_segment(addr, dump_hdr->mem_size,
ROUND_DOWN(free_space, MIB),
dump_segm);
blk = write_dump_segment(blk, dump_segm, page);
/* Update free space left on vol */
free_space -= dump_segm->len;
/* Reserve one block for the next segment header */
if (free_space)
free_space -= b2m(1);
total_dump_size += dump_segm->len;
/* Check if no more dump segments follow */
if (dump_segm->stop_marker) {
/* Write end marker */
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
return dump_hdr->mem_size;
}
/*
* Go to the new volume if not enough space
*/
if (free_space < MIB)
break;
}
return addr;
}
/*
* Dump all memory to multiple DASD partitions
*/
void dt_dump_mem(void)
{
unsigned long blk, addr, addr_end, blk_num, dev_mem_size, page;
struct mvdump_parm_table *mvdump_table_new;
struct df_s390_hdr *hdr_new;
struct df_s390_dump_segm_hdr *dump_segm;
unsigned long addr, page;
dump_hdr->mvdump_sign = DF_S390_MAGIC;
dump_hdr->mvdump_sign = DF_S390_MAGIC_EXT;
dump_hdr->mvdump = 1;
addr = 0;
total_dump_size = 0;
page = get_zeroed_page();
do {
dump_segm = (void *)get_zeroed_page();
while (1) {
printf("Dumping to: 0.%x.%04x", device.sid.ssid, device.devno);
/*
* Check whether parameter table on dump device has a valid
* time stamp. The parameter table is located right behind
* the dump tool, the corresponding block number is:
* MAGIC_BLOCK_OFFSET + (MVDUMP_TOOL_SIZE / blocksize)
* So dump tool starts on track 0, block 3
*/
mvdump_table_new = (void *) page;
readblock(3 + MVDUMP_SIZE / 0x1000,
__pa(mvdump_table_new), m2b(0x1000));
/*
* Check if time stamps match
*/
if (mvdump_table.tod != mvdump_table_new->tod)
panic(ENOTIME, "Inconsistent time stamps");
/*
* Check if dump partition has a valid dump signature.
* Bypass signature check if "--force" had been specified during
* zipl -M.
*/
hdr_new = (void *) page;
if (!parm_tail.mvdump_force) {
readblock(device.blk_start, __pa(hdr_new), 1);
if (dump_hdr->magic != hdr_new->mvdump_sign)
panic(ENOSIGN, "Wrong signature");
}
/*
* Write dump header
*/
blk = device.blk_start;
writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
blk += m2b(DF_S390_HDR_SIZE);
dev_mem_size = b2m(device.blk_end - blk + 1);
addr_end = MIN(dump_hdr->mem_size, addr + dev_mem_size);
/*
* Write memory
*/
memset((void *) page, 0, PAGE_SIZE);
while (addr < addr_end) {
blk_num = MIN(eckd_blk_max, device.blk_end - blk + 1);
blk_num = MIN(m2b(addr_end - addr), blk_num);
writeblock(blk, addr, blk_num, page);
progress_print(addr);
blk += blk_num;
addr += b2m(blk_num);
}
check_volume(page);
addr = write_volume(addr, page, dump_segm);
if (addr == dump_hdr->mem_size)
break;
/*
@@ -267,12 +311,8 @@ void dt_dump_mem(void)
dt_device_parm_setup();
set_device(device.sid, DISABLED);
dt_device_enable();
} while (1);
}
progress_print(addr);
/*
* Write end marker
*/
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -3,7 +3,7 @@
*
* Single-volume ECKD DASD dump tool
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -17,7 +17,7 @@
* Magic number at start of dump record
*/
uint64_t magic __attribute__((section(".stage2.head"))) =
0x5a45434b44363404ULL; /* "ZECKD64", version 4 */
0x5845434b44363401ULL; /* "XECKD64", version 1 */
/*
* ECKD parameter block passed by zipl
@@ -61,20 +61,29 @@ void dt_device_enable(void)
*/
void dt_dump_mem(void)
{
unsigned long blk, addr, page;
unsigned long blk, addr, end, page;
struct df_s390_dump_segm_hdr *dump_segm;
blk = device.blk_start;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
/* Write dump header */
writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
blk += m2b(DF_S390_HDR_SIZE);
/* Write memory */
for (addr = 0; addr < dump_hdr->mem_size; addr += b2m(eckd_blk_max)) {
writeblock(blk, addr, eckd_blk_max, page);
progress_print(addr);
blk += eckd_blk_max;
addr = 0;
total_dump_size = 0;
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment(blk, dump_segm, page);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
progress_print(addr);
@@ -82,4 +91,5 @@ void dt_dump_mem(void)
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -3,7 +3,7 @@
*
* Single-volume FBA DASD dump tool
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* 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,14 +13,15 @@
#include "fba.h"
#include "stage2dump.h"
#define BLK_PWRT 64 /* Blocks per write */
#define BLK_SIZE 0x200 /* FBA block size */
#define BLK_PWRT 64 /* Blocks per write */
#define BLK_SIZE 0x200 /* FBA block size */
#define BLK_PER_PAGE (PAGE_SIZE / BLK_SIZE) /* FBA blocks per page */
/*
* Magic number at start of dump record
*/
uint64_t magic __attribute__((section(".stage2.head")))
= 0x5a44464241363404ULL; /* ZDFBA64, version 4 */
= 0x5844464241363401ULL; /* XDFBA64, version 1 */
/*
* FBA dump device partition specification
@@ -120,8 +121,8 @@ void dt_device_enable(void)
/*
* Write memory with number of blocks to start block
*/
static void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_count,
unsigned long zero_page)
static void writeblock_fba(unsigned long blk, unsigned long addr,
unsigned long blk_count, unsigned long zero_page)
{
unsigned long blk_end;
@@ -135,6 +136,35 @@ static void writeblock(unsigned long blk, unsigned long addr, unsigned long blk_
start_io(IPL_SC, &irb, &orb, 1);
}
/*
* Write dump segment with the header to FBA and return the next free
* block number
*/
unsigned long write_dump_segment_fba(unsigned long blk,
struct df_s390_dump_segm_hdr *dump_segm,
unsigned long zero_page)
{
unsigned long addr, start_blk, blk_count;
/* Write the dump segment header itself (1 page) */
writeblock_fba(blk, __pa(dump_segm), BLK_PER_PAGE, zero_page);
blk += BLK_PER_PAGE;
/* Write the dump segment */
addr = dump_segm->start;
start_blk = blk;
while (addr < dump_segm->start + dump_segm->len) {
/* Remaining blocks to write */
blk_count = m2b(dump_segm->len) - (blk - start_blk);
blk_count = MIN(blk_count, BLK_PWRT);
writeblock_fba(blk, addr, blk_count, zero_page);
progress_print(addr);
blk += blk_count;
addr += b2m(blk_count);
}
return blk;
}
/*
* Initialize the CCW program
*/
@@ -163,26 +193,36 @@ static void ccw_program_init(void)
*/
void dt_dump_mem(void)
{
unsigned long blk, addr, page;
struct df_s390_dump_segm_hdr *dump_segm;
unsigned long blk, addr, end, page;
ccw_program_init();
blk = device.blk_start;
page = get_zeroed_page();
dump_segm = (void *)get_zeroed_page();
/* Write dump header */
writeblock(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
blk += DF_S390_HDR_SIZE / BLK_SIZE;
writeblock_fba(blk, __pa(dump_hdr), m2b(DF_S390_HDR_SIZE), 0);
blk += m2b(DF_S390_HDR_SIZE);
/* Write memory */
for (addr = 0; addr < dump_hdr->mem_size; addr += b2m(BLK_PWRT)) {
writeblock(blk, addr, BLK_PWRT, page);
progress_print(addr);
blk += BLK_PWRT;
addr = 0;
total_dump_size = 0;
end = dump_hdr->mem_size;
while (addr < end) {
addr = find_dump_segment(addr, end, 0, dump_segm);
blk = write_dump_segment_fba(blk, dump_segm, page);
total_dump_size += dump_segm->len;
if (dump_segm->stop_marker) {
addr = end;
break;
}
}
progress_print(addr);
/* Write end marker */
df_s390_em_page_init(page);
writeblock(blk, page, 1, 0);
writeblock_fba(blk, page, 1, 0);
free_page(page);
free_page(__pa(dump_segm));
}

View File

@@ -23,8 +23,8 @@ extern char __ex_table_start[];
extern char __ex_table_stop[];
struct ex_table_entry {
int fault;
int target;
unsigned int fault;
unsigned int target;
};
#define MEM_ALLOC_START ((unsigned long) __heap_start)
@@ -310,16 +310,13 @@ void pgm_check_handler_fn(void)
struct ex_table_entry *ex_table = (void *) __ex_table_start;
struct psw_t *psw_old = &S390_lowcore.program_old_psw;
int i, ex_table_cnt;
unsigned long fault, target;
ex_table_cnt = (__ex_table_stop - __ex_table_start)
/ sizeof(struct ex_table_entry);
for (i = 0; i < ex_table_cnt; i++) {
fault = __pa(&ex_table[i]) + ex_table[i].fault;
if (fault == psw_old->addr) {
target = __pa(&ex_table[i]) + ex_table[i].target;
psw_old->addr = target;
if (ex_table[i].fault == psw_old->addr) {
psw_old->addr = ex_table[i].target;
return;
}
}

View File

@@ -18,6 +18,7 @@
#define __pa(x) ((unsigned long)(x))
#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define barrier() __asm__ __volatile__("": : :"memory")
#define inline inline __attribute__((always_inline))
/*
* Helper macro for exception table entries
@@ -25,8 +26,8 @@
#define EX_TABLE(_fault, _target) \
".section .ex_table,\"a\"\n" \
".align 4\n" \
".long (" #_fault ") - .\n" \
".long (" #_target ") - .\n" \
".long (" #_fault ")\n" \
".long (" #_target ")\n" \
".previous\n"
struct psw_t {
@@ -207,29 +208,24 @@ do { \
libc_stop(reason); \
} while (0)
#define CHUNK_READ_WRITE 0
#define CHUNK_READ_ONLY 1
static inline int tprot(unsigned long addr)
{
int rc = -EFAULT;
asm volatile(
" tprot 0(%1),0\n"
"0: ipm %0\n"
" srl %0,28\n"
"1:\n"
EX_TABLE(0b, 1b)
: "+d" (rc) : "a" (addr) : "cc");
return rc;
}
static inline int page_is_valid(unsigned long addr)
{
unsigned long tmp;
int rc;
rc = tprot(addr);
return (rc == CHUNK_READ_WRITE) || (rc == CHUNK_READ_ONLY);
asm volatile(
"0: ic %1,%2\n"
"1: lhi %0,1\n"
"2:\n"
".pushsection .fixup, \"ax\"\n"
"3: xr %0,%0\n"
" jg 2b\n"
".popsection\n"
EX_TABLE(0b, 3b) EX_TABLE(1b, 3b)
: "=d" (rc), "=d" (tmp)
: "Q" (*(unsigned long *) addr)
: "cc");
return rc;
}
static inline uint32_t csum_partial(const void *buf, int len, uint32_t sum)

View File

@@ -3,7 +3,7 @@
*
* Common functions for stand-alone dump tools
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -22,8 +22,6 @@
* Static globals
*/
static uint8_t machine_has_vx;
static unsigned long progress_next_addr;
static unsigned long progress_inc = 0x20000000; /* Issue message each 512M */
/*
* IPL info in lowcore
@@ -45,6 +43,7 @@ struct stage2dump_parm_tail parm_tail
* Globals
*/
struct df_s390_hdr *dump_hdr;
unsigned long total_dump_size;
/*
* Init dumper: Allocate standard pages, set timers
@@ -61,29 +60,132 @@ static void init_early(void)
machine_has_vx = 1;
}
/*
* Init dump progress messages to sclp console
*
* 8 messages if the memory is 4G or less, otherwise one message for each
* 512M chunk of dumped memory
*/
static void progress_init(void)
{
if (dump_hdr->mem_size <= (4 * 1024 * 1024 * 1024ULL))
progress_inc = dump_hdr->mem_size >> 3;
progress_next_addr = progress_inc;
}
/*
* Print progress message
*/
void progress_print(unsigned long addr)
{
if (addr < progress_next_addr && addr != dump_hdr->mem_size)
/* Print a message approximately every 5 sec */
static unsigned long delta = 5 * (1UL << 32);
static unsigned long next;
unsigned long time = get_tod_clock();
if (next == 0) {
next = time + delta;
return;
printf("%08lu / %08lu MB", addr >> 20, dump_hdr->mem_size >> 20);
progress_next_addr += progress_inc;
}
if (time < next && addr != dump_hdr->mem_size)
return;
printf("%08lu / %08lu MB (Dump file size %08lu MB)", addr >> 20,
dump_hdr->mem_size >> 20, total_dump_size >> 20);
next = time + delta;
}
/*
* Check if one MB memory after addr is zero
*/
static int __is_zero_mb(unsigned long addr)
{
register unsigned long _addr1 asm("2") = (unsigned long) addr;
register unsigned long _len1 asm("3") = (unsigned long) MIB;
register unsigned long _addr2 asm("4") = (unsigned long) addr;
register unsigned long _len2 asm("5") = (unsigned long) 0;
unsigned int ipm;
asm volatile(
"0: clcle %1,%3,0(0)\n"
" jo 0b\n"
" ipm %0\n"
" srl %0,28\n"
: "=d" (ipm), "+d" (_addr1), "+d" (_len1), "+d" (_addr2), "+d" (_len2)
:
: "cc");
return !ipm;
}
/*
* Check if the megabyte contains all zeroes.
*/
int is_zero_mb(unsigned long addr)
{
if (!page_is_valid(addr))
return 1;
if (__is_zero_mb(addr))
return 1;
return 0;
}
/*
* Find next non-zero megabyte in the address range
*/
static unsigned long find_next_non_zero(unsigned long start, unsigned long end)
{
while (start < end) {
if (!is_zero_mb(start))
break;
start += MIB;
}
if (start > end)
start = end;
return start;
}
/*
* Find next zero megabyte in the address range
*/
static unsigned long find_next_zero(unsigned long start, unsigned long end)
{
while (start < end) {
if (is_zero_mb(start))
break;
start += MIB;
}
if (start > end)
start = end;
return start;
}
/*
* Find first continuous set of non-zero megabytes in the specified
* address range and update *dump_segm structure accordingly. The segment's
* length is truncated to max_len if required. Afterwards, look for the next
* non-zero megabyte. Return the address of the next non-zero megabyte or zero
* if no more follow.
*/
unsigned long find_dump_segment(unsigned long start, unsigned long end,
unsigned long max_len,
struct df_s390_dump_segm_hdr *dump_segm)
{
unsigned long addr, limit;
memset(dump_segm, 0, sizeof(*dump_segm));
/* Check the input values for MB alingment */
if (!IS_ALIGNED(start, MIB) || !IS_ALIGNED(max_len, MIB))
panic(EINTERNAL, "start or max_len not MB aligned");
/* Search for dump segment start */
addr = find_next_non_zero(start, end);
if (addr == end)
goto out;
dump_segm->start = addr;
/* Search for dump segment end */
limit = end;
if (max_len)
limit = MIN(addr + max_len, end);
addr = find_next_zero(dump_segm->start, limit);
dump_segm->len = addr - dump_segm->start;
/* Search for next dump segment start */
addr = find_next_non_zero(addr, end);
/* Return the start address of the next segment */
if (addr < end)
return addr;
out:
/*
* Set the stop-marker indicating no more non-zero
* segments in the address range
*/
dump_segm->stop_marker = -1UL;
return 0;
}
/*
@@ -113,11 +215,11 @@ static void df_s390_dump_init(void)
{
struct df_s390_hdr *dh = dump_hdr;
dh->magic = DF_S390_MAGIC;
dh->magic = DF_S390_MAGIC_EXT;
dh->hdr_size = DF_S390_HDR_SIZE;
dh->page_size = PAGE_SIZE;
dh->dump_level = 4;
dh->version = 5;
dh->version = 1;
dh->mem_start = 0;
dh->arch = DF_S390_ARCH_64;
dh->build_arch = DF_S390_ARCH_64;
@@ -327,7 +429,6 @@ void start(void)
printf("Dumping 64 bit OS");
mem_and_cpu_init();
store_status();
progress_init();
dt_dump_mem();
printf("Dump successful");
dump_exit(0);

View File

@@ -3,7 +3,7 @@
*
* Common dump functions
*
* Copyright IBM Corp. 2013, 2017
* Copyright IBM Corp. 2013, 2018
*
* 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,6 +16,8 @@
#include "s390.h"
#define IPL_SC *((struct subchannel_id *) &S390_lowcore.subchannel_id)
#define ROUND_DOWN(x, a) ((x) & ~((typeof(x))(a) - 1))
#define IS_ALIGNED(x, a) ~((x) & ((typeof(x))(a) - 1))
/*
* zipl parameters passed at tail of dump tools
@@ -29,23 +31,11 @@ struct stage2dump_parm_tail {
extern struct stage2dump_parm_tail parm_tail
__attribute__ ((section(".stage2dump.tail")));
/*
* Load 4 bytes from addr
*/
static inline unsigned int load(unsigned long addr)
{
unsigned int val;
asm volatile(
" l %0,0(%1)\n"
: "=d" (val) : "d" (addr) : "cc");
return val;
}
/*
* S390 dump format defines
*/
#define DF_S390_MAGIC 0xa8190173618f23fdULL
#define DF_S390_MAGIC_EXT 0xa8190173618f23feULL
#define DF_S390_HDR_SIZE 0x1000
#define DF_S390_EM_SIZE 16
#define DF_S390_EM_MAGIC 0x44554d505f454e44ULL
@@ -98,6 +88,15 @@ struct df_s390_em {
uint64_t tod;
} __packed __aligned(16);
/*
* Dump segment header
*/
struct df_s390_dump_segm_hdr {
uint64_t start;
uint64_t len;
uint64_t stop_marker;
};
/*
* Linker script defined symbols
*/
@@ -108,6 +107,7 @@ extern char __stage2_desc[];
* Dump common globals
*/
extern struct df_s390_hdr *dump_hdr;
extern unsigned long total_dump_size;
/*
* Common functions
@@ -118,6 +118,10 @@ void init_progress_print(void);
void progress_print(unsigned long addr);
void df_s390_em_page_init(unsigned long page);
void pgm_check_handler(void);
int is_zero_mb(unsigned long addr);
unsigned long find_dump_segment(unsigned long start, unsigned long end,
unsigned long max_len,
struct df_s390_dump_segm_hdr *dump_segm);
/*
* Dump tool backend functions

View File

@@ -16,15 +16,19 @@ libs = $(rootdir)/libutil/libutil.a \
objects = misc.o error.o scan.o job.o boot.o bootmap.o disk.o \
install.o zipl.o $(rootdir)/zipl/boot/data.o
zipl_helpers = $(wildcard zipl_helper.*)
zipl_helpers = $(basename $(wildcard zipl_helper.*.c))
chreipl_helpers = $(subst zipl_,chreipl_, $(zipl_helpers))
all: zipl $(chreipl_helpers)
zipl: $(objects) $(libs)
zipl_helper.device-mapper: $(rootdir)/libdasd/libdasd.a \
$(rootdir)/libvtoc/libvtoc.a \
$(libs) zipl_helper.device-mapper.o
chreipl_helper.%: zipl_helper.%
ln -s $< $@
ln -f -s $< $@
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR)
@@ -34,7 +38,7 @@ install: all
$(CP) --no-dereference $(chreipl_helpers) $(DESTDIR)$(TOOLS_LIBDIR)
clean:
rm -f *.o $(chreipl_helpers) zipl
rm -f *.o $(zipl_helpers) $(chreipl_helpers) zipl
.PHONY: all install clean

View File

@@ -3,7 +3,7 @@
*
* Functions handling the installation of the boot loader code onto disk
*
* Copyright IBM Corp. 2001, 2017
* Copyright IBM Corp. 2001, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -636,7 +636,7 @@ overwrite_partition_start(int fd, struct disk_info* info, int mv_dump_magic)
unsigned int bytes = 65536;
char* buffer;
const char dump_magic[] = {0xa8, 0x19, 0x01, 0x73,
0x61, 0x8f, 0x23, 0xfd};
0x61, 0x8f, 0x23, 0xfe};
if (misc_seek(fd, info->geo.start * info->phy_block_size))
return -1;

View File

@@ -1,862 +0,0 @@
#!/usr/bin/perl -w
#
# zipl_helper.device-mapper: print zipl parameters for a device-mapper device
#
# Copyright IBM Corp. 2009, 2017
#
# s390-tools is free software; you can redistribute it and/or modify
# it under the terms of the MIT license. See LICENSE for details.
#
# Depending on the name by which the script is called, it serves one of two
# purposes:
#
# 1. Usage: zipl_helper.device-mapper <target directory> or
# <major:minor of target device>
#
# This tool attempts to obtain zipl parameters for a target directory or
# partition located on a device-mapper device. It assumes that the
# device-mapper table for this device conforms to the following rules:
# - directory is located on a device consisting of a single device-mapper
# target
# - only linear, mirror and multipath targets are supported
# - supported physical device types are DASD and SCSI devices
# - all of the device which contains the directory must be located on a single
# physical device (which may be mirrored or accessed through a multipath
# target)
# - any mirror in the device-mapper setup must include block 0 of the
# physical device
#
# 2. Usage: chreipl_helper.device-mapper <major:minor of target device>
#
# This tool identifies the physical device which contains the specified
# device-mapper target devices. If the physical device was found, its
# major:minor parameters are printed. Otherwise, the script exits with an
# error message and a non-zero return code.
#
use strict;
use File::Basename;
use POSIX qw/locale_h/;
# Required tools
our $dmsetup = "dmsetup";
our $mknod = "mknod";
our $dasdview = "dasdview";
our $blockdev = "blockdev";
# Constants
our $SECTOR_SIZE = 512;
our $DASD_PARTN_MASK = 0x03;
our $SCSI_PARTN_MASK = 0x0f;
# Internal constants
our $DEV_TYPE_CDL = 0;
our $DEV_TYPE_LDL = 1;
our $DEV_TYPE_FBA = 2;
our $DEV_TYPE_SCSI = 3;
our $TARGET_START = 0;
our $TARGET_LENGTH = 1;
our $TARGET_TYPE = 2;
our $TARGET_DATA = 3;
our $TARGET_TYPE_LINEAR = 0;
our $TARGET_TYPE_MIRROR = 1;
our $TARGET_TYPE_MULTIPATH = 2;
our $LINEAR_MAJOR = 0;
our $LINEAR_MINOR = 1;
our $LINEAR_START_SECTOR = 2;
our $MIRROR_MAJOR = 0;
our $MIRROR_MINOR = 1;
our $MIRROR_START_SECTOR = 2;
our $MULTIPATH_MAJOR = 0;
our $MULTIPATH_MINOR = 1;
sub get_physical_device_dir($);
sub get_physical_device($$);
sub get_major_minor($);
sub get_table($$);
sub get_linear_data($$);
sub get_mirror_data($$);
sub get_multipath_status($);
sub get_multipath_data($$);
sub filter_table($$$);
sub get_target_start($);
sub get_target_major_minor($);
sub create_temp_device_node($$$);
sub get_blocksize($);
sub get_dasd_info($);
sub get_partition_start($$);
sub is_dasd($);
sub get_partition_base($$$);
sub get_device_characteristics($$);
sub get_type_name($);
sub check_for_mirror($@);
sub get_target_base($$$$@);
sub get_device_name($$);
sub check_tools();
my $phy_geometry; # Disk geometry of physical device
my $phy_blocksize; # Blocksize of physical device
my $phy_offset; # Offset in 512-byte sectors between start of physical
# device and start of filesystem
my $phy_type; # Type of physical device
my $phy_bootsectors; # Size of boot record in 512-byte sectors
my $phy_partstart; # Partition offset of physical device
my $phy_major; # Major device number of physical device
my $phy_minor; # Minor device number of physical device
my @target_list; # List of dm-targets between filesystem and physical
# device.
my $base_major; # Major device number of base device.
my $base_minor; # Minor device number of base device
my $directory; # Command line parameter
my $toolname; # Name of tool
# Start
$toolname = basename($0);
# Setup and use a standard locale to
# avoid localized scripting output
$ENV{LC_ALL} = "C"; # for child processes
setlocale(LC_ALL, "C"); # for current process
# Use alternate code path if called as chreipl helper
if ($toolname eq "chreipl_helper.device-mapper") {
if (!defined($ARGV[0]) || !($ARGV[0] =~ /^\s*(\d+)\s*:\s*(\d+)\s*$/)) {
die("Usage: $toolname <major:minor of target devies>\n");
}
($phy_major, $phy_minor, $phy_offset, @target_list) =
get_physical_device($1, $2);
print("$phy_major:$phy_minor\n");
exit(0);
}
$directory = $ARGV[0];
if (!defined($directory)) {
die("Usage: $toolname <target directory> or <major:minor of target devies>\n");
}
# check if needed tools are available
check_tools();
if (($ARGV[0] =~ /^\s*(\d+)\s*:\s*(\d+)\s*$/)) {
# Determine physical (non-dm) device on which partition is located
($phy_major, $phy_minor, $phy_offset, @target_list) =
get_physical_device($1,$2);
}
else
{
# Determine physical (non-dm) device on which directory is located
($phy_major, $phy_minor, $phy_offset, @target_list) =
get_physical_device_dir($directory);
}
# Determine type and characteristics of physical device
($phy_type, $phy_blocksize, $phy_geometry, $phy_bootsectors, $phy_partstart) =
get_device_characteristics($phy_major, $phy_minor);
# Handle partitions
if ($phy_partstart > 0) {
# Only the partition of the physical device is mapped so only the
# physical device can provide access to the boot record.
($base_major, $base_minor) =
get_partition_base($phy_type, $phy_major, $phy_minor);
# Check for mirror
check_for_mirror(scalar(@target_list) - 1, @target_list);
# Adjust filesystem offset
$phy_offset += $phy_partstart * ($phy_blocksize / $SECTOR_SIZE);
$phy_partstart = 0;
# Update device geometry
(undef, undef, $phy_geometry, undef, undef) =
get_device_characteristics($base_major, $base_minor);
} else {
# All of the device is mapped, so the base device is the top most
# dm device which provides access to boot sectors
($base_major, $base_minor) =
get_target_base($phy_major, $phy_minor, 0, $phy_bootsectors,
@target_list);
}
# Check for valid offset of file system
if (($phy_offset % ($phy_blocksize / $SECTOR_SIZE)) != 0) {
die("Error: File system not aligned on physical block size\n");
}
# Print resulting information
print("targetbase=$base_major:$base_minor\n");
print("targettype=".get_type_name($phy_type)."\n");
if (defined($phy_geometry)) {
print("targetgeometry=$phy_geometry\n");
}
print("targetblocksize=$phy_blocksize\n");
print("targetoffset=".($phy_offset / ($phy_blocksize / $SECTOR_SIZE))."\n");
exit(0);
# get_physical_device_from_dir(dir)
# Returns (phy_major, phy_minor, phy_offset, @target_list).
# target_list: [target_data1, target_data2, ..., target_datan]
# target_data: [major, minor, target]
sub get_physical_device_dir($)
{
my ($directory) = @_;
my ($major, $minor) = get_major_minor($directory);
return get_physical_device($major, $minor);
}
# get_physical_device(major, minor)
# Returns (phy_major, phy_minor, phy_offset, @target_list).
# target_list: [target_data1, target_data2, ..., target_datan]
# target_data: [major, minor, target]
sub get_physical_device($$)
{
my ($major, $minor) = @_;
my $table;
my $target;
my $start;
my $length;
my @target_list;
$table = get_table($major, $minor);
if (scalar(@$table) == 0) {
die("Error: Could not retrieve device-mapper information for ".
"device '".get_device_name($major, $minor)."'\n");
}
# Filesystem must be on a single dm target
if (scalar(@$table) != 1) {
die("Error: Unsupported setup: Directory '$directory' is ".
"located on a multi-target device-mapper device\n");
}
$target = $table->[0];
push(@target_list, [$major, $minor, $target]);
$start = $target->[$TARGET_START];
$length = $target->[$TARGET_LENGTH];
while (1) {
# Convert fs_start to offset on parent dm device
$start += get_target_start($target);
($major, $minor) = get_target_major_minor($target);
$table = get_table($major, $minor);
if (scalar(@$table) == 0) {
# Found non-dm device
return ($major, $minor, $start, @target_list);
}
# Get target in parent table which contains filesystem
$table = filter_table($table, $start, $length);
if (scalar(@$table) != 1) {
die("Error: Unsupported setup: Could not map ".
"directory '$directory' to a single physical ".
"device\n");
}
$target = $table->[0];
push(@target_list, [$major, $minor, $target]);
# Convert fs_start to offset on parent target
$start -= $target->[$TARGET_START];
}
}
# get_major_minor(filename)
# Returns: (device major, device minor) of the device containing the
# specified file.
sub get_major_minor($)
{
my ($filename) = @_;
my @stat;
my $dev;
my $major;
my $minor;
@stat = stat($filename);
if (!@stat) {
die("Error: Could not stat '$filename'\n");
}
$dev = $stat[0];
$major = ($dev & 0xfff00) >> 8;
$minor = ($dev & 0xff) | (($dev >> 12) & 0xfff00);
return ($major, $minor);
}
# get_table(major, minor)
# Returns: [target1, target2, ..., targetn]
# target: [start, length, type, data]
# data: linear_data|mirror_data|multipath_data
sub get_table($$)
{
my ($major, $minor) = @_;
my @table;
my $dev_name = get_device_name($major, $minor);
local *HANDLE;
open(HANDLE, "$dmsetup table -j $major -m $minor 2>/dev/null|") or
return undef;
while (<HANDLE>) {
if (!(/^(\d+)\s+(\d+)\s+(\S+)\s+(\S.*)$/)) {
die("Error: Unrecognized device-mapper table format ".
"for device '$dev_name'\n");
}
my ($start, $length, $target_type, $args) = ($1, $2, $3, $4);
my $data;
my $type;
if ($target_type eq "linear") {
$type = $TARGET_TYPE_LINEAR;
$data = get_linear_data($dev_name, $args);
} elsif ($target_type eq "mirror") {
$type = $TARGET_TYPE_MIRROR;
$data = get_mirror_data($dev_name, $args);
} elsif ($target_type eq "multipath") {
$type = $TARGET_TYPE_MULTIPATH;
$data = get_multipath_data($dev_name, $args);
} else {
die("Error: Unsupported setup: Unsupported ".
"device-mapper target type '$target_type' for ".
"device '$dev_name'\n");
}
push(@table, [$start, $length, $type, $data]);
}
close(HANDLE);
return \@table;
}
# get_linear_data(dev_name, args)
# Returns: [major, minor, start_sector]
sub get_linear_data($$)
{
my ($dev_name, $args) = @_;
if (!($args =~ /^(\d+):(\d+)\s+(\d+)$/)) {
die("Error: Unrecognized device-mapper table format for ".
"device '$dev_name'\n");
}
return [$1, $2, $3];
}
# get_mirror_data(dev_name, args)
# Returns [[major1, minor1, start_sector1], [major2, minor2, start_sector2], ..]
sub get_mirror_data($$)
{
my ($dev_name, $args) = @_;
my @argv = split(/\s+/, $args);
my @data;
my $offset;
my $num;
# Remove log_type + #logargs + logargs
splice(@argv, 0, $argv[1] + 2);
if (!@argv) {
goto out_error;
}
$num = shift(@argv);
while ($num-- > 0) {
if (!($argv[0] =~ /^(\d+):(\d+)$/)) {
goto out_error;
}
push(@data, [$1, $2, $argv[1]]);
if (!defined($offset)) {
$offset = $argv[1];
} elsif ($argv[1] != $offset) {
die("Error: Unsupported setup: Mirror target on ".
"device '$dev_name' contains entries with varying ".
"sector offsets\n");
}
splice(@argv, 0, 2);
}
if (!scalar(@data)) {
goto out_error;
}
return \@data;
out_error:
die("Error: Unrecognized device-mapper table format for device ".
"'$dev_name'\n");
}
# get_multipath_status(device)
# Return map of nodes to F/A flags (i.e. $map{$node} is either "A" or "F").
# See linux/drivers/md/dm-mpath.c:multipath_status for details.
sub get_multipath_status($)
{
my $dev = shift();
my %map;
my $str;
my $failed = 0;
open(my $fh, "$dmsetup status /dev/$dev 2>/dev/null|") or return undef;
while ($str = <$fh>) {
# sample output (single line):
# 0 67108864 multipath \
# 2 0 0 \
# 0 \
# 2 2 \
# E 0 \
# 2 2 \
# 8:16 F 1 \
# 0 1 \
# 8:0 F 1 \
# 0 1 \
# A 0 \
# 2 2 \
# 8:32 A 0 \
# 0 1 \
# 8:48 A 0 \
# 0 1
my @line = split(/\s+/, $str);
next if !@line;
my ($start, $length, $type) = splice(@line, 0, 3);
next if $type ne "multipath";
my $cnt = shift(@line); # Remove #multipath_feature_args +
splice(@line, 0, $cnt) if $cnt > 0; # multipath_feature_args
$cnt = shift(@line); # Remove #handler_status_args +
splice(@line, 0, $cnt) if $cnt > 0; # handler_status_args
# num_groups init_group_number ...
my ($ngr, $ign) = splice(@line, 0, 2);
for (my $g = 0; $g < $ngr; $g++) {
# Remove group_state + #ps_status_args
# group_state: D(isabled), A(ctive), or E(nabled)
my ($state, $cnt) = splice(@line, 0, 2);
# Remove ps_status_args*
splice(@line, 0, $cnt) if $cnt > 0;
# Remove #paths + #selector_args
my ($paths, $nsa) = splice(@line, 0, 2);
for (my $p = 0; $p < $paths; $p++) {
# Fetch single path description
my ($node, $active, $fail_cnt)
= splice(@line, 0, 3);
# active: A(ctive) or F(ailed)
$map{$node} = $active;
$failed++ if $active ne "A";
# Remove selector_args*
splice(@line, 0, $nsa) if $nsa > 0;
}
}
}
close($fh);
die ("Error: No paths found for '$dev'\n") if scalar(keys %map) == 0;
if ($failed) {
die ("Error: All paths for '$dev' failed\n")
if $failed == scalar(keys %map);
print(STDERR "Warning: There are one or more failed paths for"
." device '$dev'\n");
}
return \%map;
}
# get_multipath_data(dev_name, args)
# Returns [[major1, minor1], [major2, minor2], ..]
sub get_multipath_data($$)
{
my ($dev_name, $args) = @_;
my $status = get_multipath_status($dev_name);
my @argv = split(/\s+/, $args);
my @data;
# Remove #features + features
splice(@argv, 0, $argv[0] + 1);
if (!@argv) {
goto out_error;
}
# Remove #handlerargs + handlerargs
splice(@argv, 0, $argv[0] + 1);
if (!@argv) {
goto out_error;
}
# Remove #pathgroups + pathgroup
splice(@argv, 0, 2);
while (@argv) {
# Remove pathselector + #selectorargs + selectorargs
splice(@argv, 0, 2 + $argv[1]);
if (!@argv) {
goto out_error;
}
my $num_paths = $argv[0];
my $num_path_args = $argv[1];
# Remove #paths + #pathargs
splice(@argv, 0, 2);
while ($num_paths-- > 0) {
if (!@argv) {
goto out_error;
}
if (!($argv[0] =~ /(\d+):(\d+)/)) {
goto out_error;
}
push(@data, [$1, $2]) if $status->{$argv[0]} eq "A";
# Remove device + deviceargs
splice(@argv, 0, 1 + $num_path_args);
}
}
if (!@data) {
goto out_error;
}
return \@data;
out_error:
die("Error: Unrecognized device-mapper table format for device ".
"'$dev_name'\n");
}
# filter_table(table, start, length)
# Returns table containing only targets between start and start + length - 1.
sub filter_table($$$)
{
my ($table, $start, $length) = @_;
my $end = $start + $length - 1;
my @result;
my $target;
foreach $target (@$table) {
my $target_start = $target->[$TARGET_START];
my $target_end = $target_start + $target->[$TARGET_LENGTH] - 1;
if (!(($target_end < $start) || ($target_start > $end))) {
push(@result, $target);
}
}
return \@result;
}
# get_target_start(target)
# Returns the start sector of target.
sub get_target_start($)
{
my ($target) = @_;
my $type = $target->[$TARGET_TYPE];
my $data = $target->[$TARGET_DATA];
if ($type == $TARGET_TYPE_LINEAR) {
return $data->[$LINEAR_START_SECTOR];
} elsif ($type == $TARGET_TYPE_MIRROR) {
my $mirror_data = $data->[0];
return $mirror_data->[$MIRROR_START_SECTOR];
} else {
return 0;
}
}
# get_target_major_minor(target)
# Returns (major, minor) of target of target.
sub get_target_major_minor($)
{
my ($target) = @_;
my $type = $target->[$TARGET_TYPE];
my $data = $target->[$TARGET_DATA];
my $major;
my $minor;
if ($type == $TARGET_TYPE_LINEAR) {
$major = $data->[$LINEAR_MAJOR];
$minor = $data->[$LINEAR_MINOR];
} elsif ($type == $TARGET_TYPE_MIRROR) {
# Use data of first device in list
my $mirror_data = $data->[0];
$major = $mirror_data->[$MIRROR_MAJOR];
$minor = $mirror_data->[$MIRROR_MINOR];
} elsif ($type == $TARGET_TYPE_MULTIPATH) {
# Use data of first device in list
my $multipath_data = $data->[0];
$major = $multipath_data->[$MULTIPATH_MAJOR];
$minor = $multipath_data->[$MULTIPATH_MINOR];
}
return ($major, $minor);
}
# create_temp_device_node(type, major, minor)
# Returns the name of a temporary device node.
sub create_temp_device_node($$$)
{
my ($type, $major, $minor) = @_;
my $path = "/dev";
my $name;
my $num;
for ($num = 0; $num < 100; $num++) {
$name = sprintf("$path/zipl-dm-temp-%02d", $num);
if (-e $name) {
next;
}
if (system("$mknod $name $type $major $minor --mode 0600 ".
"2>/dev/null")) {
next;
}
return $name;
}
die("Error: Could not create temporary device node in '$path'\n");
}
# get_blocksize(device)
# # Return blocksize in bytes for device.
sub get_blocksize($)
{
my ($dev) = @_;
my $blocksize;
local *HANDLE;
open(HANDLE, "$blockdev --getss $dev 2>/dev/null|") or
return undef;
$blocksize = <HANDLE>;
chomp($blocksize);
close(HANDLE);
return $blocksize;
}
# get_dasd_info(device)
# Returns (type, cylinders, heads, sectors)
sub get_dasd_info($)
{
my ($dev) = @_;
my $disk_type;
my $format;
my $cyl;
my $heads;
my $sectors;
my $type;
local *HANDLE;
open(HANDLE, "$dasdview -x $dev 2>/dev/null|") or
# dasdview returned with an error
return undef;
while (<HANDLE>) {
if (/^number of cylinders.*\s(\d+)\s*$/) {
$cyl = $1;
} elsif (/^tracks per cylinder.*\s(\d+)\s*$/) {
$heads = $1;
} elsif (/^blocks per track.*\s(\d+)\s*$/) {
$sectors = $1;
} elsif (/^type\s+:\s+(\S+)\s*$/) {
$disk_type = $1;
} elsif (/^format.*\s+dec\s(\d+)\s/) {
$format = $1;
}
}
close(HANDLE);
if (!defined($cyl) || !defined($heads) || !defined($sectors) ||
!defined($disk_type) || !defined($format)) {
# Unrecognized dadsview output format
return undef;
}
if ($disk_type eq "FBA") {
$type = $DEV_TYPE_FBA;
} elsif ($disk_type eq "ECKD") {
if ($format == 1) {
$type = $DEV_TYPE_LDL;
} elsif ($format == 2) {
$type = $DEV_TYPE_CDL;
}
}
return ($type, $cyl, $heads, $sectors);
}
# get_partition_start(major, minor)
# Return the partition offset of device.
sub get_partition_start($$)
{
my ($major, $minor) = @_;
my $dir = "/sys/dev/block/$major:$minor";
my $offset;
local *HANDLE;
return undef if (!-d $dir);
open(HANDLE, "<", "$dir/start") or return 0;
$offset = <HANDLE>;
close(HANDLE);
chomp($offset);
return $offset;
}
# is_dasd(type)
# Return whether disk with type is a DASD.
sub is_dasd($)
{
my ($type) = @_;
return ($type == $DEV_TYPE_CDL) || ($type == $DEV_TYPE_LDL) ||
($type == $DEV_TYPE_FBA);
}
# get_partition_base(type, major, minor)
# Return (major, minor) of the base device on which the partition is located.
sub get_partition_base($$$)
{
my ($type, $major, $minor) = @_;
if (is_dasd($type)) {
return ($major, $minor & ~$DASD_PARTN_MASK);
} else {
return ($major, $minor & ~$SCSI_PARTN_MASK);
}
}
# get_device_characteristics(major, minor)
# Returns (type, blocksize, geometry, bootsectors, partstart) for device.
sub get_device_characteristics($$)
{
my ($major, $minor) = @_;
my $dev;
my $blocksize;
my $type;
my $cyl;
my $heads;
my $sectors;
my $geometry;
my $bootsectors;
my $partstart;
$dev = create_temp_device_node("b", $major, $minor);
$blocksize = get_blocksize($dev);
if (!defined($blocksize)) {
unlink($dev);
die("Error: Could not get block size for ".
get_device_name($major, $minor)."\n");
}
($type, $cyl, $heads, $sectors) = get_dasd_info($dev);
if (defined($type)) {
$geometry = "$cyl,$heads,$sectors";
if ($type == $DEV_TYPE_CDL) {
# First track contains IPL records
$bootsectors = $blocksize * $sectors / $SECTOR_SIZE;
} elsif ($type == $DEV_TYPE_LDL) {
# First two blocks contain IPL records
$bootsectors = $blocksize * 2 / $SECTOR_SIZE;
} elsif ($type == $DEV_TYPE_FBA) {
# First block contains IPL records
$bootsectors = $blocksize / $SECTOR_SIZE;
}
} else {
# Assume SCSI if get_dasd_info failed
$type = $DEV_TYPE_SCSI;
# First block contains IPL records
$bootsectors = $blocksize / $SECTOR_SIZE;
}
$partstart = get_partition_start($major, $minor);
unlink($dev);
if (!defined($partstart)) {
die("Error: Could not determine partition start for ".
get_device_name($major, $minor)."\n");
}
# Convert partition start in sectors to blocks
$partstart = $partstart / ($blocksize / $SECTOR_SIZE);
return ($type, $blocksize, $geometry, $bootsectors, $partstart);
}
# get_type_name(type)
# Return textual representation of device type.
sub get_type_name($)
{
my ($type) = @_;
if ($type == $DEV_TYPE_CDL) {
return "CDL";
} elsif ($type == $DEV_TYPE_LDL) {
return "LDL";
} elsif ($type == $DEV_TYPE_FBA) {
return "FBA";
} elsif ($type == $DEV_TYPE_SCSI) {
return "SCSI";
}
return undef;
}
# check_for_mirror(index, target_list)
# Die if there is a mirror target between index and 0.
sub check_for_mirror($@)
{
my ($i, @target_list) = @_;
for (;$i >= 0; $i--) {
my $entry = $target_list[$i];
my ($major, $minor, $target) = @$entry;
if ($target->[$TARGET_TYPE] == $TARGET_TYPE_MIRROR) {
# IPL records are not mirrored.
die("Error: Unsupported setup: Block 0 is not ".
"mirrored in device '".
get_device_name($major, $minor)."'\n");
}
}
}
# get_target_base(bottom_major, bottom_minor, start, length, target_list)
# Return (major, minor) for the top most target in the target list that maps
# the region on (bottom_major, bottom_minor) defined by start and length at
# offset 0.
sub get_target_base($$$$@)
{
my ($bot_major, $bot_minor, $start, $length, @target_list) = @_;
my $entry;
my $top_major;
my $top_minor;
my $i;
# Pre-initialize with bottom major-minor
$top_major = $bot_major;
$top_minor = $bot_minor;
# Process all entries starting with the last one
for ($i = scalar(@target_list) - 1; $i >= 0; $i--) {
my $entry = $target_list[$i];
my ($major, $minor, $target) = @$entry;
if (($target->[$TARGET_START] != 0) ||
(get_target_start($target) != 0) ||
($target->[$TARGET_LENGTH] < $length)) {
last;
}
$top_major = $major;
$top_minor = $minor;
}
# Check for mirrorring between base device and fs device.
check_for_mirror($i, @target_list);
return ($top_major, $top_minor);
}
# get_device_name(major, minor)
# Return the name of the device specified by major and minor.
sub get_device_name($$)
{
my ($major, $minor) = @_;
my $name;
local *HANDLE;
$name = "$major:$minor";
open(HANDLE, "</proc/partitions") or goto out;
while (<HANDLE>) {
if (/^\s*(\d+)\s+(\d+)\s+\d+\s+(\S+)\s*$/) {
if (($major == $1) && ($minor == $2)) {
$name = $3;
last;
}
}
}
close(HANDLE);
out:
return $name;
}
sub check_tools()
{
system("$dmsetup --version &> /dev/null") >> 8 != 127
or die("Error: dmsetup not found\n");
system("$mknod --version &> /dev/null") >> 8 != 127
or die("Error: mknod not found\n");
system("$dasdview --version &> /dev/null") >> 8 != 127
or die("Error: dasdview not found\n");
system("$blockdev --version &> /dev/null") >> 8 != 127
or die("Error: blockdev not found\n");
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,45 @@
include ../common.mak
CPPFLAGS += -I../include
LDLIBS += -ldl
ifeq (${HAVE_OPENSSL},0)
all: zkey
all:
$(SKIP) HAVE_OPENSSL=0
install:
$(SKIP) HAVE_OPENSSL=0
else
check_dep:
$(call check_dep, \
"zkey", \
"openssl/evp.h", \
"openssl-devel", \
"HAVE_OPENSSL=0")
CPPFLAGS += -I../include
LDLIBS += -ldl -lcrypto
all: check_dep zkey
libs = $(rootdir)/libutil/libutil.a
zkey.o: zkey.c pkey.h misc.h
pkey.o: pkey.c pkey.h
properties.o: properties.c properties.h
keystore.o: keystore.c keystore.h properties.h
zkey: zkey.o $(libs)
zkey: zkey.o pkey.o properties.o keystore.o $(libs)
install: all
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 zkey $(DESTDIR)$(USRBINDIR)
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -m 644 -c zkey.1 $(DESTDIR)$(MANDIR)/man1
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey
$(INSTALL) -d -m 770 $(DESTDIR)$(SYSCONFDIR)/zkey/repository
endif
clean:
rm -f *.o zkey

3299
zkey/keystore.c Normal file

File diff suppressed because it is too large Load Diff

77
zkey/keystore.h Normal file
View File

@@ -0,0 +1,77 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* Keystore handling functions
*
* Copyright IBM Corp. 2018
*
* 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 KEYSTORE_H
#define KEYSTORE_H
#include <stdbool.h>
#include "pkey.h"
struct keystore {
bool verbose;
char *directory;
int lock_fd;
mode_t mode;
gid_t owner;
};
struct keystore *keystore_new(const char *directory, bool verbose);
int keystore_generate_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, size_t sector_size,
size_t keybits, bool xts, const char *clear_key_file,
int pkey_fd);
int keystore_import_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, size_t sector_size,
const char *import_file);
int keystore_change_key(struct keystore *keystore, const char *name,
const char *description, const char *volumes,
const char *apqns, long int sector_size);
int keystore_rename_key(struct keystore *keystore, const char *name,
const char *newname);
int keystore_validate_key(struct keystore *keystore, const char *name_filter,
const char *apqn_filter, int pkey_fd);
int keystore_reencipher_key(struct keystore *keystore, const char *name_filter,
const char *apqn_filter,
bool from_old, bool to_new, bool inplace,
bool staged, bool complete, int pkey_fd,
t_CSNBKTC dll_CSNBKTC);
int keystore_copy_key(struct keystore *keystore, const char *name,
const char *newname, const char *volumes);
int keystore_export_key(struct keystore *keystore, const char *name,
const char *export_file);
int keystore_remove_key(struct keystore *keystore, const char *name,
bool quiet);
int keystore_list_keys(struct keystore *keystore, const char *name_filter,
const char *volume_filter, const char *apqn_filter);
int keystore_cryptsetup(struct keystore *keystore, const char *volume_filter,
bool execute);
int keystore_crypttab(struct keystore *keystore, const char *volume_filter);
void keystore_free(struct keystore *keystore);
#endif

View File

@@ -3,7 +3,7 @@
*
* Local helper functions
*
* Copyright 2017 IBM Corp.
* Copyright IBM Corp. 2017, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -37,7 +37,7 @@ void misc_print_invalid_command(const char *command)
/**
* An required parameter has not been specified
*
* @param[in] option Parameter string
* @param[in] parm_name Parameter string
*/
void misc_print_required_parm(const char *parm_name)
{
@@ -45,4 +45,17 @@ void misc_print_required_parm(const char *parm_name)
util_prg_print_parse_error();
}
#endif
/**
* An required parameter has not been specified
*
* @param[in] parm_name1 Parameter string 1
* @param[in] parm_name2 Parameter string 2
*/
static void misc_print_required_parms(const char *parm_name1,
const char *parm_name2)
{
warnx("Parameter '%s' or '%s' is required", parm_name1, parm_name2);
util_prg_print_parse_error();
}
#endif

748
zkey/pkey.c Normal file
View File

@@ -0,0 +1,748 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* Copyright IBM Corp. 2018
*
* 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 <dlfcn.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include "lib/util_base.h"
#include "lib/util_libc.h"
#include "lib/util_panic.h"
#include "pkey.h"
#define pr_verbose(verbose, fmt...) do { \
if (verbose) \
warnx(fmt); \
} while (0)
#define DOUBLE_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? 2 * (keysize) : (keysize))
#define HALF_KEYSIZE_FOR_XTS(keysize, xts) ((xts) ? (keysize) / 2 : (keysize))
/*
* Definitions for the CCA library
*/
#define CCA_LIBRARY_NAME "libcsulcca.so"
#define DEFAULT_KEYBITS 256
/**
* Loads the CCA library and provides the entry point of the CSNBKTC function.
*
* @param[out] lib_csulcca on return this contains the address of the CCA
* library. dlclose() should be used to free this
* when no longer needed.
* @param[out] dll_CSNBKTC on return this contains the address of the
* CSNBKTC function.
* @param verbose if true, verbose messages are printed
*
* @returns 0 on success, -ELIBACC in case of library load errors
*/
int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose)
{
util_assert(lib_csulcca != NULL, "Internal error: lib_csulcca is NULL");
util_assert(dll_CSNBKTC != NULL, "Internal error: dll_CSNBKTC is NULL");
/* Load the CCA library */
*lib_csulcca = dlopen(CCA_LIBRARY_NAME, RTLD_GLOBAL | RTLD_NOW);
if (*lib_csulcca == NULL) {
warnx("%s\nEnsure that the IBM CCA Host Libraries and "
"Tools are installed properly", dlerror());
return -ELIBACC;
}
/* Get the Key Token Change function */
*dll_CSNBKTC = (t_CSNBKTC)dlsym(*lib_csulcca, "CSNBKTC");
if (*dll_CSNBKTC == NULL) {
warnx("%s\nEnsure that the IBM CCA Host Libraries and "
"Tools are installed properly", dlerror());
dlclose(*lib_csulcca);
*lib_csulcca = NULL;
return -ELIBACC;
}
pr_verbose(verbose, "CCA library '%s' has been loaded successfully",
CCA_LIBRARY_NAME);
return 0;
}
/**
* Opens the pkey device and returns its file descriptor.
*
* @param verbose if true, verbose messages are printed
*
* @returns the file descriptor or -1 to indicate an error
*/
int open_pkey_device(bool verbose)
{
int pkey_fd;
pkey_fd = open(PKEYDEVICE, O_RDWR);
if (pkey_fd < 0) {
warnx("File '%s:' %s\nEnsure that the 'pkey' kernel module "
"is loaded", PKEYDEVICE, strerror(errno));
return -1;
}
pr_verbose(verbose, "Device '%s' has been opened successfully",
PKEYDEVICE);
return pkey_fd;
}
/**
* Read a secure key file and return the allocated buffer and size.
*
* @param[in] keyfile the name of the file to read
* @param[out] secure_key_size on return, the size of the secure key read
* @param[in] verbose if true, verbose messages are printed
*
* @return a buffer containing the secure key, or NULL in case of an error.
* The returned buffer must be freed by the caller.
*/
u8 *read_secure_key(const char *keyfile, size_t *secure_key_size,
bool verbose)
{
size_t count, size;
struct stat sb;
char *msg;
FILE *fp;
u8 *buf;
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
util_assert(secure_key_size != NULL,
"Internal error: secure_key_size is NULL");
if (stat(keyfile, &sb)) {
warnx("File '%s': %s", keyfile, strerror(errno));
return NULL;
}
size = sb.st_size;
if (size != SECURE_KEY_SIZE && size != 2*SECURE_KEY_SIZE) {
warnx("File '%s' has an invalid size, %lu or %lu bytes "
"expected", keyfile, SECURE_KEY_SIZE,
2 * SECURE_KEY_SIZE);
return NULL;
}
fp = fopen(keyfile, "r");
if (fp == NULL) {
warnx("File '%s': %s", keyfile, strerror(errno));
return NULL;
}
buf = util_malloc(size);
count = fread(buf, 1, size, fp);
if (count <= 0) {
msg = feof(fp) ? "File is too small" : strerror(errno);
warnx("File '%s': %s", keyfile, msg);
free(buf);
buf = NULL;
goto out;
}
*secure_key_size = size;
if (verbose) {
pr_verbose(verbose, "%lu bytes read from file '%s'", size,
keyfile);
util_hexdump_grp(stderr, NULL, buf, 4, size, 0);
}
out:
fclose(fp);
return buf;
}
/**
* Write a secure key file
*
* @param[in] keyfile the name of the file to write
* @param[in] secure_key a buffer containing the secure key
* @param[in] secure_key_size the size of the secure key
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 in case of success, -EIO in case of an error
*/
int write_secure_key(const char *keyfile, const u8 *secure_key,
size_t secure_key_size, bool verbose)
{
size_t count;
FILE *fp;
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
util_assert(secure_key_size > 0,
"Internal error: secure_key_size is zero");
fp = fopen(keyfile, "w");
if (fp == NULL) {
warnx("File '%s': %s", keyfile, strerror(errno));
return -EIO;
}
count = fwrite(secure_key, 1, secure_key_size, fp);
if (count <= 0) {
warnx("File '%s': %s", keyfile, strerror(errno));
fclose(fp);
return -EIO;
}
if (verbose) {
pr_verbose(verbose, "%lu bytes written to file '%s'",
secure_key_size, keyfile);
util_hexdump_grp(stderr, NULL, secure_key, 4,
secure_key_size, 0);
}
fclose(fp);
return 0;
}
/**
* Read a clear key file and return the allocated buffer and size
*
* @param[in] keyfile the name of the file to read
* @param[in] keybits the clear key size in bits. When keybits is 0, then
* the file size determines the keybits.
* @param[in] xts if true an XTS key is to be read
* @param[out] clear_key_size on return, the size of the clear key read
* @param[in] verbose if true, verbose messages are printed
*
* @return a buffer containing the clear key, or NULL in case of an error.
* The returned buffer must be freed by the caller.
*/
static u8 *read_clear_key(const char *keyfile, size_t keybits, bool xts,
size_t *clear_key_size, bool verbose)
{
size_t count, size, expected_size;
struct stat sb;
char *msg;
FILE *fp;
u8 *buf;
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
util_assert(clear_key_size != NULL,
"Internal error: clear_key_size is NULL");
if (stat(keyfile, &sb)) {
warnx("File '%s': %s", keyfile, strerror(errno));
return NULL;
}
size = sb.st_size;
if (keybits != 0) {
expected_size = DOUBLE_KEYSIZE_FOR_XTS(keybits / 8, xts);
if (size != expected_size) {
warnx("File '%s' has an invalid size, "
"%lu bytes expected", keyfile, expected_size);
return NULL;
}
} else {
keybits = DOUBLE_KEYSIZE_FOR_XTS(size * 8, xts);
}
switch (keybits) {
case 128:
break;
case 192:
if (xts) {
warnx("File '%s' has an invalid size, "
"192 bit keys are not supported with XTS",
keyfile);
return NULL;
}
break;
case 256:
break;
default:
if (xts)
warnx("File '%s' has an invalid size, "
"32 or 64 bytes expected", keyfile);
else
warnx("File '%s' has an invalid size, 16, 24 "
"or 32 bytes expected", keyfile);
return NULL;
}
fp = fopen(keyfile, "r");
if (fp == NULL) {
warnx("File '%s': %s", keyfile, strerror(errno));
return NULL;
}
buf = util_malloc(size);
count = fread(buf, 1, size, fp);
if (count <= 0) {
msg = feof(fp) ? "File is too small" : strerror(errno);
warnx("File '%s': %s", keyfile, msg);
free(buf);
buf = NULL;
goto out;
}
*clear_key_size = size;
if (verbose) {
pr_verbose(verbose, "%lu bytes read from file '%s'", size,
keyfile);
util_hexdump_grp(stderr, NULL, buf, 4, size, 0);
}
out:
fclose(fp);
return buf;
}
/**
* Generate a secure key by random
*
* @param[in] pkey_fd the pkey file descriptor
* @param[in] keyfile the file name of the secure key to generate
* @param[in] keybits the cryptographic size of the key in bits
* @param[in] xts if true an XTS key is generated
* @param[in] card the card number to use (or AUTOSELECT)
* @param[in] domain the domain number to use (or AUTOSELECT)
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error
*/
int generate_secure_key_random(int pkey_fd, const char *keyfile,
size_t keybits, bool xts, u16 card, u16 domain,
bool verbose)
{
struct pkey_genseck gensec;
size_t secure_key_size;
u8 *secure_key;
int rc;
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
if (keybits == 0)
keybits = DEFAULT_KEYBITS;
secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
secure_key = util_malloc(secure_key_size);
pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
gensec.cardnr = card;
gensec.domain = domain;
switch (keybits) {
case 128:
gensec.keytype = PKEY_KEYTYPE_AES_128;
break;
case 192:
if (xts) {
warnx("Invalid value for '--keybits'|'-c' "
"for XTS: '%lu'", keybits);
rc = -EINVAL;
goto out;
}
gensec.keytype = PKEY_KEYTYPE_AES_192;
break;
case 256:
gensec.keytype = PKEY_KEYTYPE_AES_256;
break;
default:
warnx("Invalid value for '--keybits'/'-c': '%lu'", keybits);
rc = -EINVAL;
goto out;
}
rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
if (rc < 0) {
rc = -errno;
warnx("Failed to generate a secure key: %s", strerror(errno));
goto out;
}
memcpy(secure_key, &gensec.seckey, SECURE_KEY_SIZE);
if (xts) {
rc = ioctl(pkey_fd, PKEY_GENSECK, &gensec);
if (rc < 0) {
rc = -errno;
warnx("Failed to generate a secure key: %s",
strerror(errno));
goto out;
}
memcpy(secure_key + SECURE_KEY_SIZE, &gensec.seckey,
SECURE_KEY_SIZE);
}
pr_verbose(verbose, "Successfully generated a secure key");
rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose);
out:
free(secure_key);
return rc;
}
/*
* Generate a secure key from a clear key file
*
* @param[in] pkey_fd the pkey file descriptor
* @param[in] keyfile the file name of the secure key to generate
* @param[in] keybits the cryptographic size of the key in bits. When
* keybits is 0, then the clear key file size
* determines the keybits.
* @param[in] xts if true an XTS key is generated
* @param[in] clearkeyfile the file name of the clear key to read
* @param[in] card the card number to use (or AUTOSELECT)
* @param[in] domain the domain number to use (or AUTOSELECT)
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error
*/
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
size_t keybits, bool xts,
const char *clearkeyfile,
u16 card, u16 domain,
bool verbose)
{
struct pkey_clr2seck clr2sec;
size_t secure_key_size;
size_t clear_key_size;
u8 *secure_key;
u8 *clear_key;
int rc;
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
util_assert(keyfile != NULL, "Internal error: keyfile is NULL");
util_assert(clearkeyfile != NULL,
"Internal error: clearkeyfile is NULL");
secure_key_size = DOUBLE_KEYSIZE_FOR_XTS(SECURE_KEY_SIZE, xts);
secure_key = util_malloc(secure_key_size);
clear_key = read_clear_key(clearkeyfile, keybits, xts, &clear_key_size,
verbose);
if (clear_key == NULL)
return -EINVAL;
pr_verbose(verbose, "Generate key on card %02x.%04x", card, domain);
clr2sec.cardnr = card;
clr2sec.domain = domain;
switch (HALF_KEYSIZE_FOR_XTS(clear_key_size * 8, xts)) {
case 128:
clr2sec.keytype = PKEY_KEYTYPE_AES_128;
break;
case 192:
clr2sec.keytype = PKEY_KEYTYPE_AES_192;
break;
case 256:
clr2sec.keytype = PKEY_KEYTYPE_AES_256;
break;
default:
warnx("Invalid clear key size: '%lu' bytes", clear_key_size);
rc = -EINVAL;
goto out;
}
memcpy(&clr2sec.clrkey, clear_key,
HALF_KEYSIZE_FOR_XTS(clear_key_size, xts));
rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2sec);
if (rc < 0) {
rc = -errno;
warnx("Failed to generate a secure key from a "
"clear key: %s", strerror(errno));
goto out;
}
memcpy(secure_key, &clr2sec.seckey, SECURE_KEY_SIZE);
if (xts) {
memcpy(&clr2sec.clrkey, clear_key + clear_key_size / 2,
clear_key_size / 2);
rc = ioctl(pkey_fd, PKEY_CLR2SECK, &clr2sec);
if (rc < 0) {
rc = -errno;
warnx("Failed to generate a secure key from "
"a clear key: %s", strerror(errno));
goto out;
}
memcpy(secure_key+SECURE_KEY_SIZE, &clr2sec.seckey,
SECURE_KEY_SIZE);
}
pr_verbose(verbose,
"Successfully generated a secure key from a clear key");
rc = write_secure_key(keyfile, secure_key, secure_key_size, verbose);
out:
memset(&clr2sec, 0, sizeof(clr2sec));
memset(clear_key, 0, clear_key_size);
free(clear_key);
free(secure_key);
return rc;
}
/**
* Prints CCA return and reason code information for certain known CCA
* error situations.
*
* @param return_code the CCA return code
* @param reason_code the CCA reason code
*/
static void print_CCA_error(int return_code, int reason_code)
{
switch (return_code) {
case 8:
switch (reason_code) {
case 48:
warnx("The secure key has a CCA master key "
"verification pattern that is not valid");
break;
}
break;
case 12:
switch (reason_code) {
case 764:
warnx("The CCA master key is not loaded and "
"therefore a secure key cannot be enciphered");
break;
}
break;
}
}
/**
* Re-enciphers a secure key.
*
* @param[in] dll_CSNBKTC the address of the CCA CSNBKTC function
* @param[in] secure_key a buffer containing the secure key
* @param[in] secure_key_size the size of the secure key
* @param[in] method the re-enciphering method. METHOD_OLD_TO_CURRENT
* or METHOD_CURRENT_TO_NEW.
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, -EIO in case of an error
*/
int key_token_change(t_CSNBKTC dll_CSNBKTC,
u8 *secure_key, unsigned int secure_key_size,
char *method, bool verbose)
{
long exit_data_len = 0, rule_array_count;
unsigned char rule_array[2 * 80] = { 0, };
unsigned char exit_data[4] = { 0, };
long return_code, reason_code;
util_assert(dll_CSNBKTC != NULL, "Internal error: dll_CSNBKTC is NULL");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
util_assert(secure_key_size > 0,
"Internal error: secure_key_size is 0");
util_assert(method != NULL, "Internal error: method is NULL");
memcpy(rule_array, method, 8);
memcpy(rule_array + 8, "AES ", 8);
rule_array_count = 2;
dll_CSNBKTC(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
secure_key);
pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' returned: "
"return_code: %ld, reason_code: %ld", method, return_code,
reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
if (secure_key_size == 2 * SECURE_KEY_SIZE) {
dll_CSNBKTC(&return_code, &reason_code,
&exit_data_len, exit_data,
&rule_array_count, rule_array,
secure_key + SECURE_KEY_SIZE);
pr_verbose(verbose, "CSNBKTC (Key Token Change) with '%s' "
"returned: return_code: %ld, reason_code: %ld",
method, return_code, reason_code);
if (return_code != 0) {
print_CCA_error(return_code, reason_code);
return -EIO;
}
}
return 0;
}
/**
* Validates an XTS secure key (the second part)
*
* @param[in] pkey_fd the pkey file descriptor
* @param[in] secure_key a buffer containing the secure key
* @param[in] secure_key_size the secure key size
* @param[in] part1_keysize the key size of the first key part
* @param[in] part1_attributes the attributes of the first key part
* @param[out] clear_key_bitsize on return , the cryptographic size of the
* clear key
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error
*/
static int validate_secure_xts_key(int pkey_fd,
u8 *secure_key, size_t secure_key_size,
u16 part1_keysize, u32 part1_attributes,
size_t *clear_key_bitsize, bool verbose)
{
struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
struct pkey_verifykey verifykey;
struct secaeskeytoken *token2;
int rc;
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
/* XTS uses 2 secure key tokens concatenated to each other */
token2 = (struct secaeskeytoken *)(secure_key + SECURE_KEY_SIZE);
if (secure_key_size != 2 * SECURE_KEY_SIZE) {
pr_verbose(verbose, "Size of secure key is too small: "
"%lu expected %lu", secure_key_size,
2 * SECURE_KEY_SIZE);
return -EINVAL;
}
if (token->bitsize != token2->bitsize) {
pr_verbose(verbose, "XTS secure key contains 2 clear keys of "
"different sizes");
return -EINVAL;
}
if (token->keysize != token2->keysize) {
pr_verbose(verbose, "XTS secure key contains 2 keys of "
"different sizes");
return -EINVAL;
}
if (memcmp(&token->mkvp, &token2->mkvp, sizeof(token->mkvp)) != 0) {
pr_verbose(verbose, "XTS secure key contains 2 keys using "
"different CCA master keys");
return -EINVAL;
}
memcpy(&verifykey.seckey, token2, sizeof(verifykey.seckey));
rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
if (rc < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to validate a secure key: %s",
strerror(-rc));
return rc;
}
if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
pr_verbose(verbose, "Secure key is not an AES key");
return -EINVAL;
}
if (verifykey.keysize != part1_keysize) {
pr_verbose(verbose, "XTS secure key contains 2 keys using "
"different key sizes");
return -EINVAL;
}
if (verifykey.attributes != part1_attributes) {
pr_verbose(verbose, "XTS secure key contains 2 keys using "
"different attributes");
return -EINVAL;
}
if (clear_key_bitsize)
*clear_key_bitsize += verifykey.keysize;
return 0;
}
/**
* Validates a secure key
*
* @param[in] pkey_fd the pkey file descriptor
* @param[in] secure_key a buffer containing the secure key
* @param[in] secure_key_size the secure key size
* @param[out] clear_key_bitsize on return , the cryptographic size of the
* clear key
* @param[out] is_old_mk in return set to 1 to indicate if the secure key
* is currently enciphered by the OLD CCA master key
* @param[in] verbose if true, verbose messages are printed
*
* @returns 0 on success, a negative errno in case of an error
*/
int validate_secure_key(int pkey_fd,
u8 *secure_key, size_t secure_key_size,
size_t *clear_key_bitsize, int *is_old_mk,
bool verbose)
{
struct secaeskeytoken *token = (struct secaeskeytoken *)secure_key;
struct pkey_verifykey verifykey;
int rc;
util_assert(pkey_fd != -1, "Internal error: pkey_fd is -1");
util_assert(secure_key != NULL, "Internal error: secure_key is NULL");
if (secure_key_size < SECURE_KEY_SIZE) {
pr_verbose(verbose, "Size of secure key is too small: "
"%lu expected %lu", secure_key_size,
SECURE_KEY_SIZE);
return -EINVAL;
}
memcpy(&verifykey.seckey, token, sizeof(verifykey.seckey));
rc = ioctl(pkey_fd, PKEY_VERIFYKEY, &verifykey);
if (rc < 0) {
rc = -errno;
pr_verbose(verbose, "Failed to validate a secure key: %s",
strerror(-rc));
return rc;
}
if ((verifykey.attributes & PKEY_VERIFY_ATTR_AES) == 0) {
pr_verbose(verbose, "Secure key is not an AES key");
return -EINVAL;
}
if (clear_key_bitsize)
*clear_key_bitsize = verifykey.keysize;
/* XTS uses 2 secure key tokens concatenated to each other */
if (secure_key_size > SECURE_KEY_SIZE) {
rc = validate_secure_xts_key(pkey_fd,
secure_key, secure_key_size,
verifykey.keysize,
verifykey.attributes,
clear_key_bitsize,
verbose);
if (rc != 0)
return rc;
}
if (is_old_mk)
*is_old_mk = (verifykey.attributes &
PKEY_VERIFY_ATTR_OLD_MKVP) != 0;
pr_verbose(verbose, "Secure key validation completed successfully");
return 0;
}

View File

@@ -4,7 +4,7 @@
* This header file defines the interface to the pkey kernel module.
* It defines a set of IOCTL commands with its associated structures.
*
* Copyright 2017 IBM Corp.
* Copyright IBM Corp. 2017, 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
@@ -82,4 +82,44 @@ struct pkey_verifykey {
#define PKEY_VERIFYKEY _IOWR(PKEY_IOCTL_MAGIC, 0x07, struct pkey_verifykey)
#endif
#define METHOD_OLD_TO_CURRENT "RTCMK "
#define METHOD_CURRENT_TO_NEW "RTNMK "
typedef void (*t_CSNBKTC)(long *return_code,
long *reason_code,
long *exit_data_length,
unsigned char *exit_data,
long *rule_array_count,
unsigned char *rule_array,
unsigned char *key_identifier);
int load_cca_library(void **lib_csulcca, t_CSNBKTC *dll_CSNBKTC, bool verbose);
int open_pkey_device(bool verbose);
int generate_secure_key_random(int pkey_fd, const char *keyfile,
size_t keybits, bool xts, u16 card, u16 domain,
bool verbose);
int generate_secure_key_clear(int pkey_fd, const char *keyfile,
size_t keybits, bool xts,
const char *clearkeyfile,
u16 card, u16 domain,
bool verbose);
u8 *read_secure_key(const char *keyfile, size_t *secure_key_size,
bool verbose);
int write_secure_key(const char *keyfile, const u8 *secure_key,
size_t secure_key_size, bool verbose);
int validate_secure_key(int pkey_fd,
u8 *secure_key, size_t secure_key_size,
size_t *clear_key_bitsize, int *is_old_mk,
bool verbose);
int key_token_change(t_CSNBKTC dll_CSNBKTC,
u8 *secure_key, unsigned int secure_key_size,
char *method, bool verbose);
#endif

623
zkey/properties.c Normal file
View File

@@ -0,0 +1,623 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* Properties file handling functions
*
* Copyright IBM Corp. 2018
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/evp.h>
#include "lib/util_libc.h"
#include "lib/util_list.h"
#include "lib/util_panic.h"
#include "properties.h"
struct properties {
struct util_list list;
};
struct property {
struct util_list_node node;
char *name;
char *value;
};
#define SHA256_DIGEST_LEN 32
#define INTEGRITY_KEY_NAME "__hash__"
#define RESTRICTED_PROPERTY_NAME_CHARS "=\n"
#define RESTRICTED_PROPERTY_VALUE_CHARS "\n"
#define RESTRICTED_STR_LIST_CHARS ",\n"
static int openssl_initialized;
/**
* Allocate and initialize a SHA-256 context
*
* @returns a SHA context
*/
static EVP_MD_CTX *sha256_init(void)
{
EVP_MD_CTX *ctx;
int rc;
if (!openssl_initialized) {
OpenSSL_add_all_algorithms();
openssl_initialized = 1;
}
ctx = EVP_MD_CTX_create();
util_assert(ctx != NULL,
"Internal error: OpenSSL MD context allocation failed");
rc = EVP_DigestInit_ex(ctx, EVP_sha256(), NULL);
util_assert(rc == 1, "Internal error: SHA-256 digest init failed");
return ctx;
}
/**
* Add data to the SHA-256 context
*
* @parm[in] ctx the SHA context
* @parm[in] data the data to be hashed
* @parm[in] data_len the length of the data
*/
static void sha256_update(EVP_MD_CTX *ctx,
const char *data, unsigned int data_len)
{
int rc;
util_assert(ctx != NULL, "Internal error: OpenSSL MD context is NULL");
util_assert(data != NULL || data_len == 0,
"Internal error: data is NULL");
rc = EVP_DigestUpdate(ctx, data, data_len);
util_assert(rc == 1, "Internal error: SHA-256 digest udpdate failed");
}
/**
* Produce the digest for the SHA-256 context and free the context
*
* @parm[in] ctx the SHA context
* @parm[out] digest a buffer where the digest is stored
* @parm[in/out] digest_len on entry, *digest_len contains the size of the
* digest buffer, which must be large enough to hold
* a SHA-256 digest (32 bytes),
* on exit it contains the size of the digest
* returned in the buffer.
*/
static void sha256_final(EVP_MD_CTX *ctx,
unsigned char *digest, unsigned int *digest_len)
{
int rc;
util_assert(ctx != NULL, "Internal error: OpenSSL MD context is NULL");
if (digest != NULL && digest_len != NULL) {
util_assert(*digest_len >= (unsigned int)EVP_MD_CTX_size(ctx),
"Internal error: digest_len is too small");
rc = EVP_DigestFinal_ex(ctx, digest, digest_len);
util_assert(rc == 1,
"Internal error: SHA-256 digest final failed");
}
EVP_MD_CTX_destroy(ctx);
}
/**
* Allocates a new properties object
*
* @returns the properties object
*/
struct properties *properties_new(void)
{
struct properties *properties;
properties = util_zalloc(sizeof(struct properties));
util_list_init_offset(&properties->list,
offsetof(struct property, node));
return properties;
}
/**
* Frees a properties object with all its properties
*
* @param[in] properties the properties object
*/
void properties_free(struct properties *properties)
{
struct property *property;
util_assert(properties != NULL, "Internal error: properties is NULL");
while ((property = util_list_start(&properties->list)) != NULL) {
free(property->name);
free(property->value);
util_list_remove(&properties->list, property);
}
free(properties);
}
/**
* Find a property by its name in the list iof properties
*
* @param[in] properties the properties object
* @param[in] name the name of the property to find
*
* @returns a pointer to the proerty when it has been found, or NULL if not
*/
static struct property *properties_find(struct properties *properties,
const char *name)
{
struct property *property;
property = util_list_start(&properties->list);
while (property != NULL) {
if (strcmp(property->name, name) == 0)
return property;
property = util_list_next(&properties->list, property);
}
return NULL;
}
/**
* Adds or updates a property
*
* @param[in] properties the properties object
* @param[in] name the name of the property
* @param[in] value the value of the property
*
* @returns 0 on success,
* -EINVAL if the name or value contains invalid characters
*/
int properties_set(struct properties *properties,
const char *name, const char *value)
{
struct property *property;
util_assert(properties != NULL, "Internal error: properties is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
util_assert(value != NULL, "Internal error: value is NULL");
if (strpbrk(name, RESTRICTED_PROPERTY_NAME_CHARS) != NULL)
return -EINVAL;
if (strpbrk(value, RESTRICTED_PROPERTY_VALUE_CHARS) != NULL)
return -EINVAL;
property = properties_find(properties, name);
if (property != NULL) {
free(property->value);
property->value = util_strdup(value);
} else {
property = util_zalloc(sizeof(struct property));
property->name = util_strdup(name);
property->value = util_strdup(value);
util_list_add_tail(&properties->list, property);
}
return 0;
}
/**
* Gets a property
*
* @param[in] properties the properties object
* @param[in] name the name of the property
*
* @returns a string containing the property value, or NULL if the property
* was not found.
* Note: The returned string must be freed via free() by the caller.
*/
char *properties_get(struct properties *properties, const char *name)
{
struct property *property;
util_assert(properties != NULL, "Internal error: properties is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
property = properties_find(properties, name);
if (property == NULL)
return NULL;
return util_strdup(property->value);
}
/**
* Removes a property
*
* @param[in] properties the properties object
* @param[in] name the name of the property
*
* @returns 0 on success, -ENOENT if the property was not found.
*/
int properties_remove(struct properties *properties, const char *name)
{
struct property *property;
util_assert(properties != NULL, "Internal error: properties is NULL");
util_assert(name != NULL, "Internal error: name is NULL");
property = properties_find(properties, name);
if (property == NULL)
return -ENOENT;
free(property->name);
free(property->value);
util_list_remove(&properties->list, property);
return 0;
}
/**
* Saves the properties to a file
*
* @param[in] properties the properties object
* @param[in] filename the file name
* @param[in] check_integrity if TRUE, an hash of the key and values is
* stored as part of the file.
*
* @returns 0 on success, -EIO the file could not be created
*/
int properties_save(struct properties *properties, const char *filename,
bool check_integrity)
{
char digest_hex[SHA256_DIGEST_LEN * 2 + 1];
unsigned char digest[SHA256_DIGEST_LEN];
unsigned int digest_len = sizeof(digest);
struct property *property;
EVP_MD_CTX *ctx = NULL;
unsigned int i;
FILE *fp;
util_assert(properties != NULL, "Internal error: properties is NULL");
util_assert(filename != NULL, "Internal error: filename is NULL");
fp = fopen(filename, "w");
if (fp == NULL)
return -EIO;
if (check_integrity)
ctx = sha256_init();
property = util_list_start(&properties->list);
while (property != NULL) {
fprintf(fp, "%s=%s\n", property->name, property->value);
if (check_integrity) {
sha256_update(ctx, property->name,
strlen(property->name));
sha256_update(ctx, property->value,
strlen(property->value));
}
property = util_list_next(&properties->list, property);
}
if (check_integrity) {
sha256_final(ctx, digest, &digest_len);
util_assert(digest_len <= SHA256_DIGEST_LEN,
"Internal error: digest length too long");
for (i = 0; i < digest_len; i++)
sprintf(&digest_hex[i * 2], "%02x", digest[i]);
digest_hex[digest_len * 2] = '\0';
fprintf(fp, "%s=%s\n", INTEGRITY_KEY_NAME, digest_hex);
}
fclose(fp);
return 0;
}
/**
* Loads the properties from a file
*
* @param[in] properties the properties object
* @param[in] filename the file name
* @param[in] check_integrity if TRUE, an hash of the key and values is
* compared with the hash stored as part of the file.
*
* @returns 0 on success, -EIO the file could not be created,
* -EPERM in case of a syntax error or an integrity error
*/
int properties_load(struct properties *properties, const char *filename,
bool check_integrity)
{
char digest_hex[SHA256_DIGEST_LEN * 2 + 1];
unsigned char digest[SHA256_DIGEST_LEN];
unsigned int digest_len = sizeof(digest);
char *digest_read = NULL;
EVP_MD_CTX *ctx = NULL;
char line[4096];
unsigned int len, i;
int rc = 0;
char *ch;
FILE *fp;
util_assert(properties != NULL, "Internal error: properties is NULL");
util_assert(filename != NULL, "Internal error: filename is NULL");
fp = fopen(filename, "r");
if (fp == NULL)
return -EIO;
if (check_integrity)
ctx = sha256_init();
while (fgets(line, sizeof(line), fp) != NULL) {
len = strlen(line);
if (line[len-1] == '\n')
line[len-1] = '\0';
ch = strchr(line, '=');
if (ch == NULL) {
rc = -EPERM;
goto out;
}
*ch = '\0';
ch++;
if (check_integrity) {
if (strcmp(line, INTEGRITY_KEY_NAME) == 0) {
digest_read = util_strdup(ch);
continue;
}
sha256_update(ctx, line, strlen(line));
sha256_update(ctx, ch, strlen(ch));
}
properties_set(properties, line, ch);
}
if (check_integrity) {
sha256_final(ctx, digest, &digest_len);
ctx = NULL;
util_assert(digest_len <= SHA256_DIGEST_LEN,
"Internal error: digest length too long");
for (i = 0; i < digest_len; i++)
sprintf(&digest_hex[i * 2], "%02x", digest[i]);
digest_hex[digest_len * 2] = '\0';
if (digest_read == NULL ||
strcmp(digest_hex, digest_read) != 0) {
rc = -EPERM;
goto out;
}
}
out:
if (ctx != NULL)
sha256_final(ctx, NULL, NULL);
if (digest_read != NULL)
free(digest_read);
fclose(fp);
return rc;
}
/**
* Combines a list of strings into one comma separated string
*
* @param[in] strings zero terminated array of pointers to C-strings
*
* @returns a new string. This must be freed by the caller when no longer used.
* returns NULL if a string contains an invalid character.
*/
char *str_list_combine(const char **strings)
{
unsigned int i, size;
char *str;
util_assert(strings != NULL, "Internal error: strings is NULL");
for (i = 0, size = 0; strings[i] != NULL; i++) {
if (strpbrk(strings[i], RESTRICTED_STR_LIST_CHARS) != NULL)
return NULL;
if (i > 0)
size += 1;
size += strlen(strings[i]);
}
str = util_zalloc(size + 1);
for (i = 0, size = 0; strings[i] != NULL; i++) {
if (i > 0)
strcat(str, ",");
strcat(str, strings[i]);
}
return str;
}
/**
* Splits a comma separated string into its parts
*
* @param[in] str_list the comma separated string
*
* @returns a zero terminated array of pointers to C-strings. This array
* and all individual C-Strings need to be freed bay the caller when
* no longer used. This can be done using str_list_free_string_array().
*/
char **str_list_split(const char *str_list)
{
unsigned int i, count;
char **list;
char *copy;
char *tok;
util_assert(str_list != NULL, "Internal error: str_list is NULL");
count = str_list_count(str_list);
list = util_zalloc((count + 1) * sizeof(char *));
copy = util_strdup(str_list);
tok = strtok(copy, ",");
i = 0;
while (tok != NULL) {
list[i] = util_strdup(tok);
i++;
tok = strtok(NULL, ",");
}
free(copy);
return list;
}
/**
* Count the number of parts a comma separated string contains
*
* param[in] str_list the comma separated string
*
* @returns the number of parts
*/
unsigned int str_list_count(const char *str_list)
{
unsigned int i, count;
util_assert(str_list != NULL, "Internal error: str_list is NULL");
if (strlen(str_list) == 0)
return 0;
for (i = 0, count = 1; str_list[i] != '\0'; i++)
if (str_list[i] == ',')
count++;
return count;
}
/**
* Find a string in a comma separated string
*
* @param str_list the comma separated string.
* @param str the string to find
*
* @returns a pointer to the string within the comma separated string,
* or NULL if the string was not found
*
*/
static char *str_list_find(const char *str_list, const char *str)
{
char *before;
char *after;
char *ch;
ch = strstr(str_list, str);
if (ch == NULL)
return NULL;
if (ch != str_list) {
before = ch - 1;
if (*before != ',')
return NULL;
}
after = ch + strlen(str);
if (*after != ',' && *after != '\0')
return NULL;
return ch;
}
/**
* Appends a string to a comma separated string
*
* @param str_list the comma separated string.
* @param str the string to add
*
* @returns a new comma separated string. This must be freed by the caller when
* no longer used. If the string to add is already contained in the
* comma separated list, it is not added and NULL is returned.
* If the string to be added contains a comma, NULL is returned.
*/
char *str_list_add(const char *str_list, const char *str)
{
char *ret;
util_assert(str_list != NULL, "Internal error: str_list is NULL");
util_assert(str != NULL, "Internal error: str is NULL");
if (strpbrk(str, RESTRICTED_STR_LIST_CHARS) != NULL)
return NULL;
if (str_list_find(str_list, str))
return NULL;
ret = util_zalloc(strlen(str_list) + 1 + strlen(str) + 1);
strcpy(ret, str_list);
if (strlen(str_list) > 0)
strcat(ret, ",");
strcat(ret, str);
return ret;
}
/**
* Removes a string from a comma separated string
*
* @param str_list the comma separated string.
* @param str the string to remove
*
* @returns a new comma separated string. This must be freed by the caller when
* no longer used. If the string to remove is not found in the
* comma separated string, NULL is returned
*/
char *str_list_remove(const char *str_list, const char *str)
{
char *after;
char *ret;
char *ch;
util_assert(str_list != NULL, "Internal error: str_list is NULL");
util_assert(str != NULL, "Internal error: str is NULL");
ch = str_list_find(str_list, str);
if (ch == NULL)
return NULL;
after = ch + strlen(str);
if (*after == ',') {
/* there are more parts after the one to remove */
ret = util_zalloc(strlen(str_list) - strlen(str) - 1 + 1);
strncpy(ret, str_list, ch - str_list);
strcat(ret, after + 1);
} else if (ch == str_list) {
/* removing the one and only part -> empty string */
ret = util_zalloc(1);
} else {
/* there are no more parts after the one to remove */
ret = util_zalloc(strlen(str_list) - strlen(str) - 1 + 1);
strncpy(ret, str_list, ch - 1 - str_list);
}
return ret;
}
/**
* Frees a string array (as produced by str_list_split())
*
* @param strings a NULL terminated array of pointers to C-Strings.
*/
void str_list_free_string_array(char **strings)
{
util_assert(strings != NULL, "Internal error: strings is NULL");
while (*strings != NULL) {
free((void *)*strings);
strings++;
}
}

48
zkey/properties.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* zkey - Generate, re-encipher, and validate secure keys
*
* Properties file handling functions
*
* Copyright IBM Corp. 2018
*
* 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 PROPFILE_H
#define PROPFILE_H
#include <stdbool.h>
struct properties;
struct properties *properties_new(void);
void properties_free(struct properties *properties);
int properties_set(struct properties *properties,
const char *name, const char *value);
char *properties_get(struct properties *properties, const char *name);
int properties_remove(struct properties *properties, const char *name);
int properties_save(struct properties *properties, const char *filename,
bool check_integrity);
int properties_load(struct properties *properties, const char *filename,
bool check_integrity);
char *str_list_combine(const char **strings);
char **str_list_split(const char *str_list);
unsigned int str_list_count(const char *str_list);
char *str_list_add(const char *str_list, const char *str);
char *str_list_remove(const char *str_list, const char *str);
void str_list_free_string_array(char **strings);
#endif

View File

@@ -1,38 +1,17 @@
.\" Copyright 2017 IBM Corp.
.\" Copyright IBM Corp. 2017, 2018
.\" 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 ZKEY 1 "February 2017" "s390-tools"
.TH ZKEY 1 "May 2018" "s390-tools"
.SH NAME
zkey \- Generates, re-enciphers, and validates secure AES keys
zkey \- Manage secure AES keys
.
.
.SH SYNOPSIS
.B zkey
.BR generate | gen
.I secure\-key\-file
.RB [ \-\-keybits | \-k
.IB size ]
.RB [ \-\-xts | \-x ]
.RB [ \-\-clearkey | \-c
.IB clear\-key\-file ]
.RB [ \-\-verbose | \-V ]
.
.br
.B zkey
.BR validate | val
.I secure\-key\-file
.RB [ \-\-verbose | \-V ]
.
.br
.B zkey
.BR reencipher | re
.I secure\-key\-file
.RB [ \-\-to\-new | \-n ]
.RB [ \-\-from\-old | \-o ]
.RB [ \-\-output | \-f
.IB output\-file ]
.RB [ \-\-verbose | \-V ]
.I command
.RI [ secure\-key\-file ]
.RB [ OPTIONS ]
.
.PP
.B zkey
@@ -44,64 +23,194 @@ zkey \- Generates, re-enciphers, and validates secure AES keys
.
.
.SH DESCRIPTION
Use the \fBzkey\fP command to generate secure AES keys that are enciphered
with a master key of an IBM cryptographic adapter in CCA coprocessor mode.
You can also use the \fBzkey\fP command to validate and re-encipher secure
Use the \fBzkey\fP tool to generate and manage secure AES keys that are
enciphered with a master key of an IBM cryptographic adapter in CCA coprocessor
mode. You can also use the \fBzkey\fP tool to validate and re-encipher secure
AES keys.
.PP
The secure keys can either be stored in a file in the file system, or
in the secure key repository. The default location of the secure key repository
is \fB/etc/zkey/repository\fP. Set environment variable \fBZKEY_REPOSITORY\fP
to point to a different location to use a different secure key repository
location. Keys stored in a secure key repository inherit the permissions from
the repository directory (except write access for other users, which is always
denied). The default repository location \fB/etc/zkey/repository\fP is created
with group \fBzkeyadm\fP as owner and mode \fB770\fP. Thus all secure keys
created in that repository are owned by group \fBzkeyadm\fP. Anyone that
is supposed to access secure keys in the secure key repository must be part of
group \fBzkeyadm\fP.
.PP
When storing the secure key in a key repository, additional information, such as
a textual description of the key, can be associated with a secure key.
You can associate a secure key with one or multiple cryptographic adapters
(APQNs) that are set up with the same CCA master key.
You can also associate a secure key with one or multiple volumes
(block devices), which are encrypted using dm-crypt with the secure key. The
volume association also contains the device-mapper name, separated by a colon,
used with dm-crypt. A specific volume can only be associated with one secure
key.
.PP
The generated secure key is saved in a file with a size of 64 or 128 bytes.
The file contains an AES key of 128, 192, or 256 bits enciphered with the
master key of the CCA cryptographic adapter.
The file contains an AES key with a length of 128, 192, or 256 bits. The key is
enciphered with the master key of the CCA cryptographic adapter.
Secure keys that are used for the XTS cipher mode can be 128 or 256 bits
in size, because XTS requires two concatenated secure keys.
in size.
.
.
.
.SH USAGE
.SH COMMANDS
The \fBzkey\fP tool can operate in two modes. When argument
.I secure\-key\-file
is specified then it operates on the secure key contained in the specified file.
This applies to commands \fBgenerate\fP, \fBvalidate\fP, and \fBreencipher\fP.
When the
.B \-\-name
option is specified then it operates on a secure key contained in the secure
key repository.
.
.PP
.SS "Generating secure AES keys"
.
.B zkey
.BR generate | gen
.I secure\-key\-file
.RB [ \-\-keybits | \-k
.IB size ]
.RB [ \-\-xts | \-x ]
.RB [ \-\-clearkey | \-c
.IB clear\-key\-file ]
.RB [ \-\-verbose | \-V ]
.
.PP
.B zkey
.BR generate | gen
.B \-\-name | \-N
.IB key-name
.RB [ \-\-description | \-d
.IB description ]
.RB [ \-\-volumes | \-l
.IB volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-apqns | \-a
.IB card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-sector-size | \-S
.IB bytes ]
.RB [ \-\-keybits | \-k
.IB size ]
.RB [ \-\-xts | \-x ]
.RB [ \-\-clearkey | \-c
.IB clear\-key\-file ]
.RB [ \-\-verbose | \-V ]
.PP
Use the
.B generate
command to generate a new secure AES key either randomly within the CCA
cryptographic adapter, or from a clear AES key specified as input. When specifying
a clear key as input, the clear key should be kept at a secure place, or be
a clear key as input, the clear key should be kept in a secure place, or be
securely erased after creation of the secure key. The secure key itself does
not need to be kept secure, because it can only be used together with a
CCA cryptographic adapter that contains the master key with which the secure
key was generated.
.PP
The generated secure key can either be stored in a file in the file system,
or in the secure key repository. To store the generated secure key in a
file, specify the file name with option \fIsecure\-key\-file\fP. To store the
secure key in the secure key repository, specify the name of the key using the
.B --name
option. When storing the secure key in a key repository,
additional information can be associated with a secure key using the
.B --description
,
.B --volumes
,
.B --apqns
, or the
.B --sector-size
options.
.
.SS "Validating secure AES keys"
.
.B zkey
.BR validate | val
.I secure\-key\-file
.RB [ \-\-verbose | \-V ]
.
.PP
.B zkey
.BR validate | val
.RB [ \-\-name | \-N
.IB key-name ]
.RB [ \-\-verbose | \-V ]
.PP
Use the
.B validate
command to validate an existing secure key.
It checks if the specified file contains a valid secure key.
It checks if the specified file or repository entry contains a valid secure key.
It also displays the attributes of the secure key, such as key sizes, whether
it is a secure key that can be used for the XTS cipher mode, and the master key
register with which the secure key is enciphered.
it is a secure key that can be used for the XTS cipher mode, the master key
register (CURRENT or OLD) with which the secure key is enciphered, and other key
attributes. For further information about master key registers, see the
\fBreencipher\fP command.
.PP
The secure key can either be contained in a file in the file system, or in a
secure key repository. To validate a secure key contained in a file, specify
the file name with option \fIsecure\-key\-file\fP. To validate secure keys
contained in the secure key repository, specify the name of the key
or a pattern containing wildcards using the
.B --name
option. When wildcards are used you must quote the value.
If neither option \fIsecure\-key\-file\fP nor option
.B --name
are specified, then all secure keys contained in the key repository
are validated.
.
.SS "Re-encipher existing AES secure keys"
.
.B zkey
.BR reencipher | re
.I secure\-key\-file
.RB [ \-\-to\-new | \-n ]
.RB [ \-\-from\-old | \-o ]
.RB [ \-\-output | \-f
.IB output\-file ]
.RB [ \-\-verbose | \-V ]
.PP
.B zkey
.BR reencipher | re
.RB [ \-\-name | \-N
.IB key-name ]
.RB [ \-\-apqns | \-a
.IB card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-to\-new | \-n ]
.RB [ \-\-from\-old | \-o ]
.RB [ \-\-in-place | \-i ]
.RB [ \-\-staged | \-s ]
.RB [ \-\-complete | \-c ]
.RB [ \-\-verbose | \-V ]
.PP
Use the
.B reencipher
command to re-encipher an existing secure key with a new master key.
A secure key have to be re-enciphered, when the master key of the CCA
cryptographic adapter is being changed.
A secure key bust be re-enciphered when the master key of the CCA
cryptographic adapter changes.
.PP
The CCA cryptographic adapter has 3 different registers to store
The CCA cryptographic adapter has three different registers to store
master keys:
.RS 2
.IP "\(bu" 2
The \fPCURRENT\fP register contains the current master key.
The \fBCURRENT\fP register contains the current master key.
.
.IP "\(bu" 2
The \fBOLD\fP register contains the previously used master key.
Secure keys enciphered with the master key contained in the \fBOLD\fP
register canstill be used until the master key is changed again.
register can still be used until the master key is changed again.
.
.IP "\(bu" 2
The \fBNEW\fP register contains the new master key to be set.
The master key in the \fBNEW\fP register cannot be used until it is made
the current master key. Note that a secure key can be proactively
re-enciphered with the master key in the \fBNEW\fP register before
the new master key is made the current one.
the current master key. You can pro-actively re-encipher a secure key with the
\fBNEW\fP master key before this key is made the \fBCURRENT\fP key. Use the
.B \-\-to-new
option to do this.
.RE
.PP
Use the
@@ -110,13 +219,12 @@ option to re-encipher a secure key that is currently enciphered with
the master key in the \fBOLD\fP register with the master key in the
\fBCURRENT\fP register.
.PP
Use the
.B \-\-to\-new
option to proactively re-encipher a secure key that is currently
enciphered with the master key in the \fBCURRENT\fP register with
the master key in the \fBNEW\fP register.
.PP
If both options are specified, a secure key that is currently enciphered
If both the
.B \-\-from-old
and
.B \-\-to-new
options are specified, a secure key that is currently enciphered
with the master key in the \fBOLD\fP register is re-enciphered with the
master key in the \fBNEW\fP register.
.PP
@@ -127,11 +235,310 @@ If currently enciphered with the master key in the \fBOLD\fP register,
it is re-enciphered with the master key in the \fBCURRENT\fP register.
If it is currently enciphered with the master key in the \fBCURRENT\fP
register, it is re-enciphered with the master key in the \fBNEW\fP register.
If for this case the \fBNEW\fP register does not contain a valid master key,
then the re-encipher operation fails.
.PP
The secure key can either be contained in a file in the file system, or in a
secure key repository. To re-encipher a secure key contained in a file,
specify the file name with option \fIsecure\-key\-file\fP. To re-encipher
secure keys contained in the secure key repository, specify the name of the key
or a pattern containing wildcards using the
.B --name
option. When wildcards are used you must quote the value.
You can also specify the
.B --apqns
option to re-encipher those secure
keys which are associated with the specified cryptographic adapters (APQNs).
You can use wildcards for the APQN specification.
When wildcards are used you must quote the value.
If both option
.B --name
and option
.B --apqns
are specified then all secure keys
contained in the key repository that match both patterns are re-enciphered.
If all both options are omitted, then all secure keys contained in the key
repository are re-enciphered.
.PP
Re-enciphering a secure key contained in the secure key repository can be
performed \fBin-place\fP, or in \fBstaged\fP mode.
.PP
\fB"In-place"\fP immediately replaces the secure key in the repository with
the re-enciphered secure key. Re-enciphering from \fBOLD\fP to \fBCURRENT\fP is
performed in-place per default. You can use option \fB--in-place\fP to force an
in-place re-enciphering for the \fBCURRENT\fP to \fBNEW\fP case. Be aware that
a secure key that was re-enciphered in-place from \fBCURRENT\fP to \fBNEW\fP
is no longer valid, until the new CCA master key has been made the current one.
.PP
\fBStaged\fP mode means that the re-enciphered secure key is stored in a
separate file in the secure key repository. Thus the current secure key is still
valid at this point. Once the new CCA master key has been set (made active), you
must rerun the reencipher command with option \fB--complete\fP to complete the
staged re-enciphering. Re-enciphering from \fBCURRENT\fP to \fBNEW\fP is
performed in staged mode per default. You can use option \fB--staged\fP to force
a staged re-enciphering for the \fBOLD\fP to \fBCURRENT\fP case.
.PP
.B Note:
The \fBreencipher\fP command requires the IBM CCA Host Library (libcsulcca.so)
The \fBreencipher\fP command requires the CCA host library (libcsulcca.so)
to be installed.
.
.SS "Import existing AES secure keys into the secure key repository"
.
.B zkey
.BR import | im
.I secure\-key\-file
.B \-\-name | \-N
.IB key-name
.RB [ \-\-description | \-d
.IB description ]
.RB [ \-\-volumes | \-l
.IB volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-apqns | \-a
.IB card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-sector-size | \-S
.IB bytes ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B import
command to import an existing secure key contained in a file into the the
secure key repository. When importing a secure key in a key repository,
additional information can be associated with a secure key using the
.B --description
,
.B --volumes
,
.B --apqns
, or the
.B --sector-size
options.
.
.SS "Export AES secure keys from the secure key repository"
.
.B zkey
.BR export | ex
.I secure\-key\-file
.B \-\-name | \-N
.IB key-name
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B export
command to export an existing secure key contained in the secure key repository
to a file in the file system. Specify the name of the key that is to be exported
using the
.B --name
option. You cannot use wildcards.
When wildcards are used you must quote the value.
The exported secure key also remains in the secure key repository.
.
.SS "List AES secure keys contained in the secure key repository"
.
.B zkey
.BR list | li
.RB [ \-\-name | \-N
.IB key-name ]
.RB [ \-\-volumes | \-l
.IB volume1[:dmname1][,volume2[:dmname2][,...]] ]
.RB [ \-\-apqns | \-a
.IB card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B list
command to display a list of secure keys contained in the secure key repository.
You can filter the displayed list by key name, associated volumes, and
associated cryptographic adapters (APQNs). You can use wildcards for the key
name, associated APQNs, and associated volumes. The device-mapper name of an
associated volume can be omitted; if it is specified then only those keys are
listed that are associated with the specified volume and device-mapper name.
.PP
The
.B list
command displays the attributes of the secure keys, such as key sizes,
whether it is a secure key that can be used for the XTS cipher mode, the textual
description, associated cryptographic adapters (APQNs) and volumes, the
sector size, and timestamps for key creation, last modification and last
re-encipherment.
.
.SS "Remove existing AES secure keys from the secure key repository"
.
.B zkey
.BR remove | rem
.B \-\-name | \-N
.IB key-name
.RB [ \-\-force | \-F ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B remove
command to remove an existing secure key from the secure key repository.
Specify the name of the key that is to be removed using the
.B --name
option. You cannot use wildcards. The remove command prompts for
a confirmation, unless you specify the
.B --force
option.
.PP
.B Note:
When removing a secure key that is associated with one or multiple volumes,
a message informs you about the associated volumes. When the secure key is
removed, these volumes can no longer be used, unless you have a backup of the
secure key.
.
.SS "Change existing AES secure keys contained the secure key repository"
.
.B zkey
.BR change | ch
.B \-\-name | \-N
.IB key-name
.RB [ \-\-description | \-d
.IB description ]
.RB [ \-\-volumes | \-l
.IB [+|-]volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-apqns | \-a
.IB [+|-]card1.domain1[,card2.domain2[,...]] ]
.RB [ \-\-sector-size | \-S
.IB bytes ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B change
command to change the description, the associated volumes, the associated
cryptographic adapters (APQNs), and the sector size of a secure key contained
in the secure key repository. Specify the name of the key that is to be changed
using the
.B --name
option. You cannot use wildcards.
.PP
You can set (replace), add, or
remove volume and cryptographic adapters (APQN) associations. To set
(replace) an association, specify the association with the
.B --volumes
or the
.B --apqns
options. To add an association,
specify the new association prefixed with a \fI+\fP with the
.B --volumes
or the
.B --apqns
options. To remove an association,
specify the association to remove prefixed with a \fI-\fP with the
.B --volumes
or the
.B --apqns
options. You cannot mix \fI+\fP and
\fI-\fP in one specification. You can either add or remove (or set) the
associations with one command.
.PP
.B Note:
The secure key itself cannot be changed, only information about the secure
key is changed. To rename a secure key, use the \fBrename\fP command.
To re-encipher a secure key with a new CCA master key, use the \fBreencipher\fP
command.
.
.SS "Rename existing AES secure keys in the secure key repository"
.
.B zkey
.BR rename | ren
.B \-\-name | \-N
.IB key-name
.B \-\-new-name | \-w
.IB new-key-name
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B rename
command to rename an existing secure key in the secure key repository.
Specify the name of the key that is to be renamed using the
.B --name
option and the new name using the
.B --new-name
option. You cannot use wildcards.
.
.SS "Copy (duplicate) existing AES secure keys in the secure key repository"
.
.B zkey
.B copy | co
.RB \-\-name | \-N
.IB key-name
.B \-\-new-key-name | \-w
.IB new-name
.RB [ \-\-volumes | \-l
.IB volume1:dmname1[,volume2:dmname2[,...]] ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B copy
command to copy (duplicate) an existing secure key in the secure key repository.
Specify the name of the key that is to be copied using the
.B --name
option and the name of the copied key using the
.B --new-name
option. You cannot use wildcards.
.PP
.B Note:
When copying a secure key, the volume associations are not copied, because
a specific volume can only be associated with a single secure key. Specify the
.B --volumes
option to associate different
volumes with the copied secure key, or use the \fBchange\fP command to associate
volumes afterwards.
.
.SS "Generate crypttab entries for volumes associated with secure AES keys"
.
.B zkey
.BR crypttab | cryptt
.RB [ \-\-volumes | \-l
.IB volume1[:dmname1][,volume2[:dmname2][,...]] ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B crypttab
command to generate crypttab entries using the \fBplain\fP dm-crypt mode
for volumes that are associated with secure keys contained in the secure key
repository. Specify the
.B --volumes
option to limit the list
of volumes where crypttab entries are generated for. You can use wildcards.
When wildcards are used you must quote the value.
The device-mapper name of an associated volume can be omitted; if it is
specified then only those volumes with the specified volume and device-mapper
name are selected.
.
.SS "Generate cryptsetup commands for volumes associated with secure AES keys"
.
.B zkey
.BR cryptsetup | crypts
.RB [ \-\-volumes | \-l
.IB volume1[:dmname1][,volume2[:dmname2][,...]] ]
.RB [ \-\-run | \-r ]
.RB [ \-\-verbose | \-V ]
.
.PP
Use the
.B cryptsetup
command to generate \fBcryptsetup plainOpen\fP commands for volumes that are
associated with secure keys contained in the secure key repository. Specify the
.B --volumes
option to limit the list
of volumes where cryptsetup commands are generated for. You can use wildcards.
When wildcards are used you must quote the value.
The device-mapper name of an associated volume can be omitted; if it is
specified then only those volumes with the specified volume and device-mapper
name are selected. Specify the
.B --run
option to run the generated cryptsetup commands.
.
.
.
.
.SH OPTIONS
@@ -139,13 +546,13 @@ to be installed.
.TP
.BR \-k ", " \-\-keybits\~\fIsize\fP
Specifies the size of the AES key to be generated in bits.
Valid sizes are 128, 192, and 256 bits. Secure keys for use with the
Valid values are 128, 192, and 256. Secure keys for use with the
XTS cipher mode can only use keys of 128 or 256 bits.
The default is 256 bits.
.TP
.BR \-x ", " \-\-xts
Generates a secure AES key for the XTS cipher mode. A secure AES key for
the XTS cipher mode consist of two concatenated secure keys.
Generates a secure AES key for the XTS cipher mode that consist of two
concatenated secure keys.
.TP
.BR \-c ", " \-\-clearkey\~\fIclear\-key\-file\fP
Specifies a file path that contains the clear AES key in binary form.
@@ -154,6 +561,49 @@ determines the size of the AES key. If option \fB\-\-keybits\fP
is specified, the size of the specified file must match the specified
key size. Valid file sizes are of 16, 24, or 32 bytes, and of 32 or 64
bytes for keys to be used with the XTS cipher mode.
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-d ", " \-\-description\~\fIdescription\fP
Specifies a textual description for the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1[,volume2:dmname2[,...]]\fP
Specifies a comma-separated list of volumes (block devices) that are
associated with the secure AES key in the repository. These volumes are to be
encrypted using dm-crypt with the secure AES key. The volume association also
contains the device-mapper name, separated by a colon, used with dm-crypt.
A specific volume can only be associated with a single secure key.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQN) which are associated with the secure AES key in the
repository. Each APQN association specifies a card and domain number separated
by a period (like lszcrypt displays it). When at least one APQN is specified,
then the first one is used to generate the key. If no APQNs are specified,
then an APQN is selected automatically. All specified APQNs must be online.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
Specifies the sector size in bytes used with dm-crypt. It must be a power of two
and in the range 512 - 4096 bytes. If omitted, the system default sector size
is used.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the validate command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You can
use wildcards to select multiple secure keys in the secure key repository.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the reencipher command"
.TP
@@ -168,7 +618,256 @@ master key in the OLD register with the master key in the CURRENT register.
.BR \-f ", " \-\-output\~\fIoutput\-file\fP
Specifies the name of the output file to which the re-enciphered secure key
is written. If this option is omitted, the re-enciphered secure key
is replaced in the file that currently contains the secure key.
is replaced in the file that currently contains the secure key. This option is
only used for secure keys stored in a file in the file system. It is not valid
for keys contained in the secure key repository.
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You can
use wildcards to select multiple secure keys in the secure key repository.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQNs). You can use wildcards in the APQN specification.
All secure keys contained in the secure key repository
which are associated with the specified APQNs are re-enciphered.
Each APQN specifies a card and domain number separated by a period (like
lszcrypt displays it).
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-i ", " \-\-in-place
Forces an in-place re-enciphering of a secure AES key contained in the secure
key repository. "In-place" immediately replaces the secure key in the repository
with the re-enciphered secure key.
Re-enciphering from OLD to CURRENT is performed in-place per default.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-s ", " \-\-staged
Forces that the re-enciphering of a secure AES key contained in the secure key
repository is performed in staged mode. Staged mode means that the re-enciphered
secure key is stored in a separate file in the secure key repository. Thus the
current secure key is still valid at this point. Once the new CCA master key has
been set (made active), you must rerun the reencipher command with option
\fB--complete\fP to complete the staged re-enciphering.
Re-enciphering from CURRENT to NEW is performed in staged mode per default.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-p ", " \-\-complete
Completes a staged re-enciphering. Use this option after the new CCA master key
has been set (made active). This option replaces the secure key by its
re-enciphered version in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.
.SS "Options for the import command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-d ", " \-\-description\~\fIdescription\fP
Specifies a textual description for the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1[,volume2:dmname2[,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with the secure AES key in the repository. These volumes are to be
encrypted using dm-crypt with the secure AES key. The volume association also
contains the device-mapper name, separated by a colon, used with dm-crypt.
A specific volume can only be associated with a single secure key.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQN) which are associated with the secure AES key in the
repository. Each APQN association specifies a card and domain number separated
by a period (like lszcrypt displays it). All specified APQNs must be online.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
Specifies the sector size in bytes used with dm-crypt. It must be a power of two
and in the range 512 - 4096 bytes. If omitted, the system default sector size
is used.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the export command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You cannot
use wildcards.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the list command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You can
use wildcards to select multiple secure keys in the secure key repository.
When wildcards are used you must quote the value.
Only keys with names that match the pattern are listed.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with the secure AES key in the repository. Only those keys are
listed, which are associated with the specified volumes.
The volume association also contains the device-mapper name, separated by a
colon, used with dm-crypt. You can omit the device-mapper name; if it is
specified then only those keys are listed that are associated with the
specified volume and device-mapper name. You can use wildcards to specify
the volumes and device-mapper names.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fIcard1.domain1[,card2.domain2[,...]]\fP
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQN) which are associated with the secure AES key in the
repository. Only those keys are listed, which are associated with the specified
APQNs. Each APQN association specifies a card and domain number separated
by a period (like lszcrypt displays it). You can use wildcards in the APQN
specification.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the remove command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You cannot
use wildcards.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-F ", " \-\-force\fP
The user is prompted to confirm the removal of a secure key from the secure
key repository. Use this option to remove a secure key without prompting for
a confirmation.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the change command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You cannot
use wildcards.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-d ", " \-\-description\~\fIdescription\fP
Specifies a textual description for the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-l ", " \-\-volumes\~\fI[+|-]volume1:dmname1[,volume2:dmname2[,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with the secure AES key in the repository. These volumes are to be
encrypted using dm-crypt with the secure AES key. The volume association also
contains the device-mapper name, separated by a colon, used with dm-crypt.
To add a volume to the associated volumes, prefix the volume with a \fI+\fP.
To remove a volume from the associated volumes, prefix the volume with a \fI-\fP.
To set (replace) the volume association do not specify a prefix.
You cannot mix \fI+\fP and \fI-\fP in one specification. You can either add or
remove (or set) the associations with one command.
A specific volume can only be associated with a single secure key.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-a ", " \-\-apqns\~\fI[+|-]card1.domain1[,card2.domain2[,...]]\fP
Specifies a comma-separated list of cryptographic adapters in CCA
coprocessor mode (APQN) which are associated with the secure AES key in the
repository. Each APQN association specifies a card and domain number separated
by a period (like lszcrypt displays it).
To add an APQN to the associated APQNs, prefix the APQN with a \fI+\fP.
To remove an APQN from the associated APQNs, prefix the APQN with a \fI-\fP.
To set (replace) the APQN association do not specify a prefix.
You cannot mix \fI+\fP and \fI-\fP in one specification. You can either add or
remove (or set) the associations with one command.
All APQNs being added or set (replaced) must be online.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-S ", " \-\-sector-size\~\fIbytes\fP
Specifies the sector size in bytes used with dm-crypt. It must be a power of two
and in the range 512 - 4096 bytes. If omitted, the system default sector size
is used. Specify \fI0\fP to un-set the sector size so that the system default
is used.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the rename command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key in the secure key repository. You cannot
use wildcards.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-w ", " \-\-new-name\~\fInew-key-name\fP
Specifies the new name of the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the copy command"
.TP
.BR \-N ", " \-\-name\~\fIkey-name\fP
Specifies the name of the secure key to be copied in the secure key repository.
You cannot use wildcards.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-w ", " \-\-new-name\~\fInew-key-name\fP
Specifies the new name of the secure key in the secure key repository.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1:dmname1,volume2:dmname2[,...]]\fP
Volume associations are not copied, because a volume can only be associated
with a single secure key. To associate different volumes with the copied
secure AES key, specify a comma-separated list of volumes (block devices).
These volumes are to be encrypted using dm-crypt with the secure AES key. The
volume association also contains the device-mapper name, separated by a colon,
used with dm-crypt.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the crypttab command"
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with secure AES keys in the repository.
The volume association also contains the device-mapper name, separated by a
colon, used with dm-crypt. You can omit the device-mapper name; if it is
specified then only those keys are selected that are associated with the
specified volume and device-mapper name. You can use wildcards to specify
the volumes and device-mapper names.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "Options for the cryptsetup command"
.TP
.BR \-l ", " \-\-volumes\~\fIvolume1[:dmname1][,volume2[:dmname2][,...]]\fP
Specifies a comma-separated list of volumes (block devices) which are
associated with secure AES keys in the repository.
The volume association also contains the device-mapper name, separated by a
colon, used with dm-crypt. You can omit the device-mapper name; if it is
specified then only those keys are selected that are associated with the
specified volume and device-mapper name. You can use wildcards to specify
the volumes and device-mapper names.
When wildcards are used you must quote the value.
This option is only used for secure keys contained in the secure key repository.
.TP
.BR \-r ", " \-\-run\fP
Runs the generated cryptsetup commands. When an execution of a cryptsetup
command fails, no further cryptsetup commands are executed, and zkey ends
with an error.
This option is only used for secure keys contained in the secure key repository.
.
.
.
.SS "General options"
.TP
@@ -186,16 +885,25 @@ Displays version information and exits.
.SH EXAMPLES
.TP
.B zkey generate seckey.bin
Generates a 256-bit secure AES key and stores it in file 'seckey.bin'.
Generates a random 256-bit secure AES key and stores it in file 'seckey.bin'.
.TP
.B zkey generate seckey.bin \-\-keybits 128 \-\-xts
Generates a 128-bit secure AES key for the XTS cipher mode and stores it
Generates a random 128-bit secure AES key for the XTS cipher mode and stores it
in file 'seckey.bin'.
.TP
.B zkey generate seckey.bin \-\-clearkey clearkey.bin
Generates a secure AES key from the clear key in file 'clearkey.bin' and
stores it in file 'seckey.bin'.
.TP
.B zkey generate --name seckey
Generates a random 256-bit secure AES key and stores it in the secure key
repository under the name 'seckey'.
.TP
.B zkey generate --name seckey --volumes /dev/dasdc1:encvol --apqns 03.004c
Generates a random 256-bit secure AES key and stores it in the secure key
repository under the name 'seckey' and associates it with block
device '/dev/dasdc1' and device-mapper name 'encvol', and APQN '03.004c'.
.TP
.B zkey reencipher seckey.bin \-\-from\-old
Re-enciphers the secure key in file 'seckey.bin' which is currently enciphered
with the master key in the OLD register with the master key in the CURRENT
@@ -207,5 +915,49 @@ Re-enciphers the secure key in file 'seckey.bin' which is currently enciphered
with the master key in the CURRENT register with the master key in the NEW
register, and saves the re-enciphered secure key to file 'seckey2.bin'.
.TP
.B zkey reencipher --name seckey
Re-enciphers the secure key 'seckey' in the secure key repository.
.TP
.B zkey reencipher --apqns 03.004c
Re-enciphers all secure keys contained in the secure key repository that are
associated with APQN '03.004c'.
.TP
.B zkey validate seckey.bin
Validates the secure key in file 'seckey.bin' and displays its attributes.
.TP
.B zkey validate --name seckey
Validates the secure key 'seckey' in the secure key repository and displays its
attributes.
.TP
.B zkey list
Lists all secure keys in the secure key repository and displays its
attributes.
.TP
.B zkey list --name '*key'
Lists all secure keys in the secure key repository with names ending with 'key'
and displays its attributes.
.TP
.B zkey change --name seckey --volumes +/dev/dasdc2:encvol2
Changes the secure key 'seckey' in the secure key repository and adds
volume '/dev/dasdc2' with device-mapper name 'encvol2' to the list of associated
volumes of this secure key.
.TP
.B zkey change --name seckey --apqns -03.004c
Changes the secure key 'seckey' in the secure key repository and removes
APQN '03.004c' from the list of associated APQNs of this secure key.
.TP
.B zkey crypttab --volumes '/dev/dasdc*'
Generates crypttab entries for all volumes that match the pattern '/dev/dasdc*'.
.TP
.B zkey cryptsetup --volumes '*:enc_dasd'
Generates cryptsetup commands for the volumes that uses the device-mapper
name 'enc_dasd'.
.
.SH ENVIRONMENT
.TP
.BR ZKEY_REPOSITORY
If
.B $ZKEY_REPOSITORY
is set, it specifies the location of the secure key repository.
If it is not set, then the the default location of the secure key
repository is \fB/etc/zkey/repository\fP.

File diff suppressed because it is too large Load Diff