mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
68 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d9ca409978 | ||
|
|
13596f18da | ||
|
|
80b66da1d8 | ||
|
|
3eb9af9c97 | ||
|
|
f093d0bfd4 | ||
|
|
6a2f4fd376 | ||
|
|
e2f92e4079 | ||
|
|
c944f23d7e | ||
|
|
5872f8a21b | ||
|
|
a090a1ffe8 | ||
|
|
5e24f74fde | ||
|
|
340da73bb7 | ||
|
|
f642019bcc | ||
|
|
7cc542352e | ||
|
|
cf99ea019e | ||
|
|
15c22ec742 | ||
|
|
45ac847dc9 | ||
|
|
4a223c70f2 | ||
|
|
26d636f234 | ||
|
|
aade05b01d | ||
|
|
c3821f0821 | ||
|
|
ac0ac48f6f | ||
|
|
54519b4465 | ||
|
|
9f2e406525 | ||
|
|
edaad2a927 | ||
|
|
262a827ab4 | ||
|
|
4b33d80595 | ||
|
|
4c401162c0 | ||
|
|
168acec5ea | ||
|
|
aab339d3e3 | ||
|
|
1f459af568 | ||
|
|
46f09a0adc | ||
|
|
f65003a14e | ||
|
|
e092b4024a | ||
|
|
9d7bab18a4 | ||
|
|
8688d47e3d | ||
|
|
04bb72c0dc | ||
|
|
1c065082d2 | ||
|
|
38642e6905 | ||
|
|
ebdf888a2f | ||
|
|
9745e4678a | ||
|
|
33a17df9fc | ||
|
|
4ff7aeff39 | ||
|
|
edb75870b5 | ||
|
|
a3c746846d | ||
|
|
4044accf03 | ||
|
|
943e7e7198 | ||
|
|
4f00cb6346 | ||
|
|
9d55086720 | ||
|
|
eaa2ef6ba4 | ||
|
|
37c3752b31 | ||
|
|
8585efadbe | ||
|
|
13648dd6f4 | ||
|
|
427dff3450 | ||
|
|
08bc0a947a | ||
|
|
c3d583fe9c | ||
|
|
983a72dab9 | ||
|
|
811152c08a | ||
|
|
6a1b9cf10a | ||
|
|
599b141b8a | ||
|
|
b9e47e356b | ||
|
|
5e2a477bbf | ||
|
|
bba34cb975 | ||
|
|
a674011c0d | ||
|
|
c78b5cd2ba | ||
|
|
f3e374ac77 | ||
|
|
1e6a9dbd56 | ||
|
|
564a2601f6 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
23
CHANGELOG.md
23
CHANGELOG.md
@@ -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
|
||||
|
||||
2
Makefile
2
Makefile
@@ -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 \
|
||||
|
||||
10
README.md
10
README.md
@@ -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.
|
||||
|
||||
@@ -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
3
cpumf/bin/cpumf_helper.in
Normal file → Executable 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()
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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
|
||||
.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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',
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
.
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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
52
include/lib/vmcp.h
Normal 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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
18
libvmcp/Makefile
Normal 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
134
libvmcp/vmcp.c
Normal 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
65
libvmcp/vmcp_example.c
Normal 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]
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
171
vmcp/vmcp.c
171
vmcp/vmcp.c
@@ -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;
|
||||
}
|
||||
|
||||
59
vmcp/vmcp.h
59
vmcp/vmcp.h
@@ -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
|
||||
@@ -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)
|
||||
|
||||
131
vmur/vmur.cpp
131
vmur/vmur.cpp
@@ -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 "
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
124
zdump/df_s390.h
124
zdump/df_s390.h
@@ -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 */
|
||||
|
||||
111
zdump/dfi.c
111
zdump/dfi.c
@@ -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;
|
||||
|
||||
20
zdump/dfi.h
20
zdump/dfi.h
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
112
zdump/dfi_s390.c
112
zdump/dfi_s390.c
@@ -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
29
zdump/dfi_s390_ext.c
Normal 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,
|
||||
};
|
||||
@@ -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
62
zdump/dfi_s390mv.h
Normal 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
30
zdump/dfi_s390mv_ext.c
Normal 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,
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
29
zdump/dt_s390mv_ext.c
Normal 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,
|
||||
};
|
||||
@@ -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
29
zdump/dt_s390sv_ext.c
Normal 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,
|
||||
};
|
||||
11
zdump/opts.c
11
zdump/opts.c
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
1070
zipl/src/zipl_helper.device-mapper.c
Normal file
1070
zipl/src/zipl_helper.device-mapper.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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
3299
zkey/keystore.c
Normal file
File diff suppressed because it is too large
Load Diff
77
zkey/keystore.h
Normal file
77
zkey/keystore.h
Normal 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
|
||||
19
zkey/misc.h
19
zkey/misc.h
@@ -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
748
zkey/pkey.c
Normal 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;
|
||||
}
|
||||
44
zkey/pkey.h
44
zkey/pkey.h
@@ -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
623
zkey/properties.c
Normal 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
48
zkey/properties.h
Normal 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
|
||||
870
zkey/zkey.1
870
zkey/zkey.1
@@ -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.
|
||||
1625
zkey/zkey.c
1625
zkey/zkey.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user