mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
368 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bb9a9ec5b | ||
|
|
4a3957fab5 | ||
|
|
e506c94839 | ||
|
|
dfd9f52873 | ||
|
|
14ca7c5080 | ||
|
|
4fc1a92a8d | ||
|
|
d73d7f91ac | ||
|
|
800df6bef8 | ||
|
|
3c661da4ee | ||
|
|
bf5ca4367d | ||
|
|
faf26220a7 | ||
|
|
522252d18a | ||
|
|
42889edc0c | ||
|
|
13016ebc5a | ||
|
|
c4546daf34 | ||
|
|
1e18429f69 | ||
|
|
11e78cada5 | ||
|
|
0a7df9e030 | ||
|
|
7dd03eaeec | ||
|
|
663262c962 | ||
|
|
bf9482709f | ||
|
|
cdf0b5d66f | ||
|
|
4aafd6962a | ||
|
|
863e1c3fa4 | ||
|
|
7c47ea8e09 | ||
|
|
c239d99379 | ||
|
|
6c6e3a2b0e | ||
|
|
2dca5d193f | ||
|
|
75675ec627 | ||
|
|
18bf2cce06 | ||
|
|
8781dd3e7b | ||
|
|
6380e77f28 | ||
|
|
733b86c02a | ||
|
|
7827a791c9 | ||
|
|
074de1e14e | ||
|
|
07d181e29b | ||
|
|
895a88b2f8 | ||
|
|
f01f8b240c | ||
|
|
be2bc610b7 | ||
|
|
c48d45ba92 | ||
|
|
886476a207 | ||
|
|
86685f001d | ||
|
|
d619b492e9 | ||
|
|
79e4798061 | ||
|
|
cf2311f1f1 | ||
|
|
7e832da790 | ||
|
|
3b402a0630 | ||
|
|
3437c9bb90 | ||
|
|
8898650266 | ||
|
|
3ae2100d5e | ||
|
|
93e4249fd3 | ||
|
|
8ec4705239 | ||
|
|
cad450fdf9 | ||
|
|
3a1cda59ce | ||
|
|
0566a492ae | ||
|
|
bc7359d2a3 | ||
|
|
db6f272607 | ||
|
|
6db7fbe018 | ||
|
|
2f154fa49d | ||
|
|
148d3f9b64 | ||
|
|
702dc96264 | ||
|
|
313092b202 | ||
|
|
b098990abe | ||
|
|
6802b86414 | ||
|
|
aa8c2945cc | ||
|
|
fa7a4dafa3 | ||
|
|
7eb04cdc54 | ||
|
|
d55b787d05 | ||
|
|
da4fdeeb82 | ||
|
|
9fe491df27 | ||
|
|
732b3dddab | ||
|
|
cb76e39cef | ||
|
|
09be935c54 | ||
|
|
65e18bff67 | ||
|
|
07ab32fa8b | ||
|
|
353403824b | ||
|
|
8a58389e2f | ||
|
|
f2cc871b02 | ||
|
|
4dbdc8dfab | ||
|
|
60900de5e9 | ||
|
|
2bba362e9a | ||
|
|
76044be98d | ||
|
|
885ff0a03f | ||
|
|
25968033bb | ||
|
|
1e746990c0 | ||
|
|
3002e7f754 | ||
|
|
ea10995f4d | ||
|
|
8b31319ddf | ||
|
|
1df4d66387 | ||
|
|
37348ef662 | ||
|
|
644432ba23 | ||
|
|
6eddae9a8a | ||
|
|
d19f0915c3 | ||
|
|
0ecf18b66d | ||
|
|
26c544998e | ||
|
|
edaa72d68a | ||
|
|
041e3ad996 | ||
|
|
301eece09b | ||
|
|
36bd05c4ba | ||
|
|
8aa3f064af | ||
|
|
48a7da096d | ||
|
|
094f52d604 | ||
|
|
0626dc7a72 | ||
|
|
0180054d07 | ||
|
|
800fe15d21 | ||
|
|
c570f51f5f | ||
|
|
57b70a0fe0 | ||
|
|
cc0d030ce9 | ||
|
|
9dce6793ab | ||
|
|
d8054d1a1a | ||
|
|
5a9c381225 | ||
|
|
3c6890317a | ||
|
|
1c42b9e3e4 | ||
|
|
beb6a1d6fd | ||
|
|
40e4b71159 | ||
|
|
8c0f2491a3 | ||
|
|
e44ae22989 | ||
|
|
3be8be4ac7 | ||
|
|
544c88ca39 | ||
|
|
c7afb5baec | ||
|
|
cc9b202a9b | ||
|
|
9f99706c26 | ||
|
|
8137128a96 | ||
|
|
1cdfb4946e | ||
|
|
5fb30f1e6f | ||
|
|
d8089e69fa | ||
|
|
cbf7f02d69 | ||
|
|
91b1692b16 | ||
|
|
cd8a733c82 | ||
|
|
bcce1e8d18 | ||
|
|
f832428109 | ||
|
|
1d7bb283fd | ||
|
|
a2f14fcfd7 | ||
|
|
bb6a47db55 | ||
|
|
35dd59d04c | ||
|
|
3fa511cfb9 | ||
|
|
c6c4df9697 | ||
|
|
1b0ab844b4 | ||
|
|
92fc94f152 | ||
|
|
f25aaf32b8 | ||
|
|
13f8709ec2 | ||
|
|
6a860a01c3 | ||
|
|
131a910ac5 | ||
|
|
7007937456 | ||
|
|
a528bb41e0 | ||
|
|
ed52031821 | ||
|
|
60f33fb2de | ||
|
|
5737a57920 | ||
|
|
b044aec4ff | ||
|
|
e584c88d8f | ||
|
|
fd817280d3 | ||
|
|
046d27a05b | ||
|
|
fd174cb952 | ||
|
|
70f1dcd770 | ||
|
|
fcd5d64a45 | ||
|
|
320e11dcf9 | ||
|
|
34cfca722c | ||
|
|
2215ba672e | ||
|
|
1003d81412 | ||
|
|
943c5dc51d | ||
|
|
c367a6bb65 | ||
|
|
0db89894b5 | ||
|
|
2f87cba1c7 | ||
|
|
c31eba5e00 | ||
|
|
04b0b43739 | ||
|
|
798967aba3 | ||
|
|
f2f4dc209c | ||
|
|
d7b816ff58 | ||
|
|
ae66f79512 | ||
|
|
3217e0438f | ||
|
|
41fae58ecd | ||
|
|
6dab7637fb | ||
|
|
53b949926f | ||
|
|
e08e07baa9 | ||
|
|
e679a4002e | ||
|
|
20b05e1f82 | ||
|
|
ce02dd7167 | ||
|
|
d2fc700b73 | ||
|
|
199b030580 | ||
|
|
71b36d17f0 | ||
|
|
ca8750e820 | ||
|
|
0472b5ea5c | ||
|
|
94a3272dac | ||
|
|
d72cf322c0 | ||
|
|
ab35d92028 | ||
|
|
39ceb02404 | ||
|
|
454f1427d3 | ||
|
|
1b65b23b43 | ||
|
|
0c583ec1a6 | ||
|
|
0ac7ce964e | ||
|
|
4eea67cd6f | ||
|
|
9a68a25ab6 | ||
|
|
1a150b2fe0 | ||
|
|
0843b7db36 | ||
|
|
cc069af26d | ||
|
|
d978fc6141 | ||
|
|
2fe5f27975 | ||
|
|
93a0cb254e | ||
|
|
eb4e806cdc | ||
|
|
19f747847f | ||
|
|
ce65c39e18 | ||
|
|
6c04f97773 | ||
|
|
cb11d6baec | ||
|
|
c673bacd7e | ||
|
|
6cf7f31746 | ||
|
|
c4a0933165 | ||
|
|
e67f630086 | ||
|
|
465348ced9 | ||
|
|
f148df4cc3 | ||
|
|
4d61a21811 | ||
|
|
e0ffb3c584 | ||
|
|
f4f2220693 | ||
|
|
fb62cc9e14 | ||
|
|
c91d8bd5f9 | ||
|
|
4753340e79 | ||
|
|
f742ed73e1 | ||
|
|
65b9fc442c | ||
|
|
2c106425e8 | ||
|
|
11bdab2629 | ||
|
|
b06af6026f | ||
|
|
1086548607 | ||
|
|
fbf8513d43 | ||
|
|
67496afe57 | ||
|
|
16b2799150 | ||
|
|
c063273b14 | ||
|
|
d2f8f972cf | ||
|
|
2d600570df | ||
|
|
3356d6f4fa | ||
|
|
67aef9bbf3 | ||
|
|
5d2871d626 | ||
|
|
6fcf64ebe0 | ||
|
|
e51663bbca | ||
|
|
f99560f734 | ||
|
|
303a3707e2 | ||
|
|
a37170b8be | ||
|
|
305235a7bc | ||
|
|
2568863f58 | ||
|
|
b0f82d22f9 | ||
|
|
b83c8944f1 | ||
|
|
f454c6825f | ||
|
|
c55ceabc67 | ||
|
|
2e28291c75 | ||
|
|
24fe8c1d1b | ||
|
|
67e76b8ebd | ||
|
|
97ab8fb4e9 | ||
|
|
c07104dbc7 | ||
|
|
c871050097 | ||
|
|
7e37a1d4e0 | ||
|
|
d884fb8db4 | ||
|
|
0e385a81ca | ||
|
|
675c854fa3 | ||
|
|
9d39a4bd47 | ||
|
|
400167f512 | ||
|
|
4fa9656613 | ||
|
|
87b54fc884 | ||
|
|
299fd2b772 | ||
|
|
36fed0e6c6 | ||
|
|
f7430027b4 | ||
|
|
8874b90825 | ||
|
|
6fe9e6c55c | ||
|
|
cc16e41595 | ||
|
|
bac3f93772 | ||
|
|
971970989b | ||
|
|
d415b8efed | ||
|
|
33031241c3 | ||
|
|
49cbaba302 | ||
|
|
304c3d8086 | ||
|
|
d77234ddb6 | ||
|
|
bc0d40c580 | ||
|
|
a1697a581d | ||
|
|
f75f4aff8f | ||
|
|
729a98fcb3 | ||
|
|
f52aeabca4 | ||
|
|
0be7efc956 | ||
|
|
88e6a18f96 | ||
|
|
a7e47685e0 | ||
|
|
b48aa5f435 | ||
|
|
d91e728e3c | ||
|
|
ce4704f365 | ||
|
|
2ca442feed | ||
|
|
82c86fa8bd | ||
|
|
e7f446432b | ||
|
|
1a87d3a3b4 | ||
|
|
0de533aef9 | ||
|
|
27a6409a4a | ||
|
|
6f9337d101 | ||
|
|
27f6c0a167 | ||
|
|
0652c687e3 | ||
|
|
16a62dff03 | ||
|
|
094905af87 | ||
|
|
dcce14923c | ||
|
|
1fd78d9f5e | ||
|
|
9d1baaa594 | ||
|
|
efcfbce386 | ||
|
|
3d74c534bf | ||
|
|
ca2ffe9e18 | ||
|
|
52192908eb | ||
|
|
d4cee7e65a | ||
|
|
bfbf456b83 | ||
|
|
235e997a77 | ||
|
|
c079e48d7d | ||
|
|
4762e65acb | ||
|
|
cb614ed1ee | ||
|
|
8face3e63e | ||
|
|
ea14f5471c | ||
|
|
b2ae5a91ac | ||
|
|
edfb6a03d8 | ||
|
|
5eace91ee7 | ||
|
|
86856f98db | ||
|
|
154734efc7 | ||
|
|
c7fcb457b0 | ||
|
|
244bf4e550 | ||
|
|
0f7ed7d4fc | ||
|
|
121d5d8013 | ||
|
|
abe0ba7412 | ||
|
|
2227bb8330 | ||
|
|
aa09b29248 | ||
|
|
2790d4faaa | ||
|
|
bbc46edaf5 | ||
|
|
e5c0fb249b | ||
|
|
b6d8e5833c | ||
|
|
d71628326d | ||
|
|
8bfe18e674 | ||
|
|
275105fe3d | ||
|
|
19259aeb65 | ||
|
|
125df52887 | ||
|
|
852fb9dfb8 | ||
|
|
b0fe75b92f | ||
|
|
bc987c8d18 | ||
|
|
a86e41a518 | ||
|
|
0d9e42264d | ||
|
|
7fede7021e | ||
|
|
e7d79d5c5c | ||
|
|
7d4b1e18b6 | ||
|
|
b0cc0e4737 | ||
|
|
b7bb90c552 | ||
|
|
560b672bfa | ||
|
|
0fab6bdf2a | ||
|
|
b56c74fe7b | ||
|
|
663d362ff3 | ||
|
|
d4027e6506 | ||
|
|
ddde3f354f | ||
|
|
298fab68fe | ||
|
|
b47007b8ac | ||
|
|
91c35543ca | ||
|
|
9de85f4295 | ||
|
|
e15e8a1bfa | ||
|
|
4fc0c3cfef | ||
|
|
a0ed6709cf | ||
|
|
552a915465 | ||
|
|
1091b0bf65 | ||
|
|
016a0a56fc | ||
|
|
0b4cbf0041 | ||
|
|
d854aed4b8 | ||
|
|
7f8e31e861 | ||
|
|
a5b58038a0 | ||
|
|
c2244a5795 | ||
|
|
ea7cc9ea60 | ||
|
|
b32c031474 | ||
|
|
bfc3dd018c | ||
|
|
625b81130a | ||
|
|
bf8872e94a | ||
|
|
a84d1c5d58 | ||
|
|
696e8458f0 | ||
|
|
95c7258ea7 | ||
|
|
21de913a5e | ||
|
|
7a2a96e8a3 | ||
|
|
7a569c7e33 |
25
.gitignore
vendored
25
.gitignore
vendored
@@ -11,9 +11,8 @@
|
||||
cmsfs-fuse/cmsfs-fuse
|
||||
cpacfstats/cpacfstats
|
||||
cpacfstats/cpacfstatsd
|
||||
cpumf/bin/chcpumf
|
||||
cpumf/bin/cpumf_helper
|
||||
cpumf/bin/lscpumf
|
||||
cpumf/chcpumf
|
||||
cpumf/lscpumf
|
||||
cpuplugd/cpuplugd
|
||||
dasdfmt/dasdfmt
|
||||
dasdinfo/dasdinfo
|
||||
@@ -35,6 +34,11 @@ iucvterm/src/iucvconn
|
||||
iucvterm/src/iucvtty
|
||||
iucvterm/src/ttyrun
|
||||
iucvterm/test/test_afiucv
|
||||
libekmfweb/check-dep-libekmfweb
|
||||
libekmfweb/detect-openssl-version.dep
|
||||
libekmfweb/libekmfweb.so
|
||||
libekmfweb/libekmfweb.so.1
|
||||
libekmfweb/libekmfweb.so.1.0
|
||||
libutil/util_base_example
|
||||
libutil/util_file_example
|
||||
libutil/util_libc_example
|
||||
@@ -45,8 +49,9 @@ libutil/util_path_example
|
||||
libutil/util_prg_example
|
||||
libutil/util_rec_example
|
||||
libutil/util_scandir_example
|
||||
libzds/libzds.a
|
||||
libvmcp/vmcp_example
|
||||
libzds/libzds.a
|
||||
lsstp/lsstp
|
||||
mon_tools/mon_fsstatd
|
||||
mon_tools/mon_procd
|
||||
osasnmpd/osasnmpd
|
||||
@@ -76,10 +81,10 @@ zdev/src/lszdev
|
||||
zdev/src/lszdev_usage.c
|
||||
zdsfs/zdsfs
|
||||
zdump/zgetdump
|
||||
zfcpdump/cpioinit
|
||||
zfcpdump/zfcpdump_part
|
||||
zfcpdump/zfcpdump-initrd
|
||||
zfcpdump/10-zfcpdump.install
|
||||
zfcpdump/cpioinit
|
||||
zfcpdump/zfcpdump-initrd
|
||||
zfcpdump/zfcpdump_part
|
||||
ziomon/ziomon_mgr
|
||||
ziomon/ziomon_util
|
||||
ziomon/ziomon_zfcpdd
|
||||
@@ -91,9 +96,11 @@ zipl/boot/data.h
|
||||
zipl/src/chreipl_helper.device-mapper
|
||||
zipl/src/zipl
|
||||
zipl/src/zipl_helper.device-mapper
|
||||
zkey/zkey
|
||||
zkey/zkey-cryptsetup
|
||||
zkey/check-dep-zkey
|
||||
zkey/check-dep-zkey-cryptsetup
|
||||
zkey/detect-libcryptsetup.dep
|
||||
zkey/ekmfweb/libekmfweb.dep
|
||||
zkey/ekmfweb/zkey-ekmfweb.so
|
||||
zkey/zkey
|
||||
zkey/zkey-cryptsetup
|
||||
zpcictl/zpcictl
|
||||
|
||||
16
AUTHORS.md
16
AUTHORS.md
@@ -1,6 +1,7 @@
|
||||
List of all individuals having contributed content to s390-tools
|
||||
----------------------------------------------------------------
|
||||
|
||||
- Alexander Egorenkov
|
||||
- Alexey Ishchuk
|
||||
- Andreas Herrmann
|
||||
- Andre Wild
|
||||
@@ -8,16 +9,19 @@ List of all individuals having contributed content to s390-tools
|
||||
- Arnd Bergmann
|
||||
- Axel Wirbser
|
||||
- Benjamin Block
|
||||
- Brian C. Lane
|
||||
- Carsten Otte
|
||||
- Christian Borntraeger
|
||||
- Christian Ehrhardt
|
||||
- Christof Schmitt
|
||||
- Claudio Imbrenda
|
||||
- Clemens von Mann
|
||||
- Colin Walters
|
||||
- Dan Horak
|
||||
- Despina Papadopoulou
|
||||
- Dimitri John Ledkov
|
||||
- Eberhard Pasch
|
||||
- Eduard Shishkin
|
||||
- Einar Lueck
|
||||
- Eric Sandeen
|
||||
- Erwin Vicari
|
||||
@@ -32,6 +36,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Fritz Elfert
|
||||
- Gerald Schaefer
|
||||
- Gerhard Tonn
|
||||
- Guevenc Guelce
|
||||
- Hannes Reinecke
|
||||
- Hans-Joachim Picht
|
||||
- Hans Wippel
|
||||
@@ -47,10 +52,12 @@ List of all individuals having contributed content to s390-tools
|
||||
- Jan Glauber
|
||||
- Jan Hoeppner
|
||||
- Jan Willeke
|
||||
- Jason J. Herne
|
||||
- Javier Martinez Canillas
|
||||
- Jean-Baptiste Joret
|
||||
- Jens Remus
|
||||
- Jochen Roehrig
|
||||
- Juergen Christ
|
||||
- Julian Wiedmann
|
||||
- Karsten Graul
|
||||
- Kittipon Meesompop
|
||||
@@ -58,6 +65,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Lakhvich Dmitriy
|
||||
- Marc Hartmayer
|
||||
- Mark Dettinger
|
||||
- Mark Post
|
||||
- Martin Kammerer
|
||||
- Martin Peschke
|
||||
- Martin Petermann
|
||||
@@ -69,10 +77,13 @@ List of all individuals having contributed content to s390-tools
|
||||
- Michael Mueller
|
||||
- Mijo Safradin
|
||||
- Mikhail Zaslonko
|
||||
- Nikita Dubrovskii
|
||||
- Niklas Schnelle
|
||||
- Peter Oberparleiter
|
||||
- Peter Tiedemann
|
||||
- Philipp Kern
|
||||
- Philipp Rudo
|
||||
- Prashanth Sundararaman
|
||||
- Rafael Fonseca
|
||||
- Raimund Schroeder
|
||||
- Ralph Wuerthner
|
||||
@@ -91,6 +102,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Steffen Maier
|
||||
- Steffen Thoss
|
||||
- Susanne Wintenberger
|
||||
- Sven Schnelle
|
||||
- Sven Schuetz
|
||||
- Swen Schillig
|
||||
- Taraka R. Bodireddy
|
||||
@@ -98,9 +110,13 @@ List of all individuals having contributed content to s390-tools
|
||||
- Thomas Richter
|
||||
- Thomas Spatzier
|
||||
- Thomas Weber
|
||||
- Tuan Hoang
|
||||
- Ursula Braun
|
||||
- Utz Bacher
|
||||
- Vance Morris
|
||||
- Vasily Gorbik
|
||||
- Viktor Mihajlovski
|
||||
- Vineeth Vijayan
|
||||
- Volker Sameske
|
||||
- Wenjia Zhang
|
||||
- Wolfgang Taphorn
|
||||
|
||||
167
CHANGELOG.md
167
CHANGELOG.md
@@ -1,6 +1,155 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
* __v2.11.0 (2019-09-06)__
|
||||
* __v2.16.0 (2021-02-19)__
|
||||
|
||||
For Linux kernel version: 5.10 / 5.11
|
||||
|
||||
Add new tool:
|
||||
- hsci: New tool to manage HSCI (HiperSockets Converged Interfaces)
|
||||
|
||||
Changes of existing tools:
|
||||
- genprotimg: Add host-key document verification support
|
||||
- genprotimg: boot: Make boot loader -march=z900 compatible
|
||||
- libekmfweb: Make install directory for shared libraries configurable
|
||||
- lsdasd: Add FC Endpoint Security information
|
||||
- make: Add address sanitizer support
|
||||
- netboot: Add version information to scripts
|
||||
- netboot: Bump busybox version in pxelinux.0 build
|
||||
- zdev: Add FC Endpoint Security information for DASD devices
|
||||
- zdev: Add build option to update initial RAM-disk by default
|
||||
- zkey-ekmfweb: Avoid sequence number clash when generating keys
|
||||
- zkey/zkey-ekmfweb: Install KMS plugins into configurable location
|
||||
- zkey: Add support to store LUKS2 dummy passphrase in key repository
|
||||
|
||||
Bug Fixes:
|
||||
- dasdfmt: Fix segfault when an incorrect option is specified
|
||||
- genprotimg: Fix several build issues
|
||||
- genprotimg: Require argument for 'ramdisk' and 'parmfile' options
|
||||
- zcryptstats: Fix handling of partial results with many domains
|
||||
- zfcpdbf: Deal with crash 7.2.9 change in caller name formatting
|
||||
- zipl/boot: Fix memory use after free in stage2
|
||||
- zipl/boot: Fix potential heap overflow in stage2
|
||||
- zipl: Fix reading 4k disk's geometry
|
||||
|
||||
* __v2.15.1 (2020-10-28)__
|
||||
|
||||
For Linux kernel version: 5.9
|
||||
|
||||
Changes of existing tools:
|
||||
- lsstp: Improve wording and fix typos in man page
|
||||
- zkey: Ensure zkey and friends are skipped with HAVE_OPENSSL=0
|
||||
- zkey: Add library versioning for libekmfweb and zkey-ekmfweb
|
||||
- libutil: Add function to determine base device of a partition block device
|
||||
|
||||
Bug Fixes:
|
||||
- dasdfmt: Fix bad file descriptor error when running on symlinks
|
||||
- libdasd: Fix dasd_get_host_access_count()
|
||||
- zipl: Fix multivolume dump
|
||||
- zgetdump: Fix device node determination via sysfs to work with multivolume again
|
||||
- genprotimg/boot: Fix build by disabling SSP
|
||||
- zipl/boot: Fix build by disabling SSP
|
||||
|
||||
* __v2.15.0 (2020-10-15)__
|
||||
|
||||
For Linux kernel version: 5.9
|
||||
|
||||
Add new tool:
|
||||
- lsstp: A small utility to display the Server Time Protocol (STP) information present in sysfs
|
||||
|
||||
Changes of existing tools:
|
||||
- dumpconf: support NVMe dump/reipl device
|
||||
- ipl_tools: support clear attribute for nvme re-IPL
|
||||
- zcrypt: Support new config state with lszcrypt and chzcrypt
|
||||
- zkey: Add support for key management system plugins
|
||||
including the KMS commands:
|
||||
bind, unbind, info, configure, rencipher, list, import, refresh
|
||||
- zkey: Add EKMFWeb support to remotely generate secure keys
|
||||
- libekmfweb: Add new EKMFWeb client library
|
||||
- libutil: Add util_file_read_va()
|
||||
- libutil: Add util_file_read_i()/util_file_read_ui()
|
||||
|
||||
Bug Fixes:
|
||||
- cpumf: Fix version and help printout when CPUMF is not installed
|
||||
- ziomon/ziorep_printers: fix virtual adapter CSV output
|
||||
- zipl: Fix Error when title is not the first field in BLS file
|
||||
|
||||
|
||||
* __v2.14.0 (2020-08-21)__
|
||||
|
||||
For Linux kernel version: 5.7 / 5.8
|
||||
|
||||
Changes of existing tools:
|
||||
- cpacfstats: Add ECC counters
|
||||
- dbginfo: Added collection of /proc/softirqs
|
||||
- ipl-tools: Add nvme device support to lsreipl/chreipl
|
||||
- zdsfs: Add coordinated read access
|
||||
- libzds: Add curl interface to access zosmf rest api
|
||||
- util_opt: Change util_opt_init() to honor current command, if set
|
||||
Bug Fixes:
|
||||
- lsluns: Try harder to find udevadm
|
||||
- mon_tools: Update udevadm location
|
||||
- zipl: Fix NVMe partition and base device detection
|
||||
- zipl/stage3: Correctly handle diag308 response code
|
||||
- znetconf: Introduce better ways to locate udevadm
|
||||
|
||||
* __v2.13.0 (2020-05-06)__
|
||||
|
||||
For Linux kernel version: 5.5 / 5.6
|
||||
|
||||
Add new tool:
|
||||
- genprotimg: Add genprotimg to create protected virtualization images
|
||||
- genprotimg: Add sample script to verify host keys
|
||||
|
||||
Changes of existing tools:
|
||||
- dbginfo: Gather bridge related data (using 'bridge')
|
||||
- dbginfo: Removed collection of /var/log/opencryptoki/
|
||||
- dbginfo: collect softnet_stat
|
||||
- dbginfo: gather ethtool output for per-queue coalescing
|
||||
- ipl_tools: Support clear attribute for FCP and CCW re-IPL
|
||||
- zdev: Report FC Endpoint Security of zfcp devices
|
||||
- zdev/dracut/95zdev/module-setup.sh: Add ctcm kernel module
|
||||
- cpumf/data: Add new deflate counters for IBM z15
|
||||
- zkey: Add support for EP11 secure keys
|
||||
- zpcictl: Initiate recover after reset
|
||||
- zipl: Add support for NVMe devices
|
||||
- zipl: A multitude of code and stability improvements
|
||||
|
||||
Bug Fixes:
|
||||
- zipl: Prevent endless loop during IPL
|
||||
- zipl/libc: Fix potential buffer overflow in printf
|
||||
- zkey: Fix listing of keys on file systems reporting DT_UNKNOWN
|
||||
- zkey: Fix display of clear key size for XTS, CCA-AESCIPHER, and EP11-AES XTS keys
|
||||
|
||||
|
||||
* __v2.12.0 (2019-12-17)__
|
||||
|
||||
For Linux kernel version: 5.4
|
||||
|
||||
Changes of existing tools:
|
||||
- dbginfo: Gather qdisc related data (using 'tc')
|
||||
- dbginfo: Gather extended network statistics (using 'ip link')
|
||||
- dbginfo: Collect all files under /usr/lib/systemd/system/
|
||||
- cpumf/cpumf_helper: Add IBM z15 machine name
|
||||
- zkey: Display MKVP when validating a secure key
|
||||
- zkey: Cross check APQNs when generating, validating, or importing secure keys,
|
||||
and when changing APQN associations
|
||||
- zkey: Check crypto card level during APQN cross checking
|
||||
- zkey: Add support for generating, validating, and re-enciphering AES CIPHER keys
|
||||
- zkey-cryptsetup: Add --to-new and --from-old options
|
||||
- zkey-cryptsetup: Allow setkey to set different key types
|
||||
- lszcrypt/chzcrypt: CEX7S exploitation support
|
||||
- zcryptstats: Add support for CEX7 crypto card
|
||||
- zipl: Ship a minimal zipl.conf
|
||||
- zipl: Add value of target= as search path for BLS case
|
||||
|
||||
Bug Fixes:
|
||||
- dasdview: Fix exit status in error cases
|
||||
- zipl: Fix various compile warnings
|
||||
- zipl: Fix dependency generation in zipl/boot
|
||||
- zipl: Fix entry point for stand-alone kdump
|
||||
- zipl: Add missing options to help output
|
||||
|
||||
* __v2.11.0 (2019-09-06)__
|
||||
|
||||
For Linux kernel version: 5.3
|
||||
|
||||
@@ -16,7 +165,7 @@ Release history for s390-tools (MIT version)
|
||||
- zipl: Fix freeing of uninitialized pointer
|
||||
- zipl: Set correct secure IPL default value
|
||||
|
||||
* __v2.10.0 (2019-07-31)__
|
||||
* __v2.10.0 (2019-07-31)__
|
||||
|
||||
For Linux kernel version: 5.2
|
||||
|
||||
@@ -34,7 +183,7 @@ Release history for s390-tools (MIT version)
|
||||
- zipl: Do not overwrite BOOT_IMAGE entry
|
||||
- zkey: Fix auto-detection of clear key bitsize for XTS keys
|
||||
|
||||
* __v2.9.0 (2019-05-21)__
|
||||
* __v2.9.0 (2019-05-21)__
|
||||
|
||||
For Linux kernel version: 5.0 / 5.1
|
||||
|
||||
@@ -67,7 +216,7 @@ Release history for s390-tools (MIT version)
|
||||
- zfcpdbf: Warn about ambiguous payload records with dup reqid & payarea
|
||||
- zpcictl: Check for regular directory to prevent possible buffer overflow
|
||||
|
||||
* __v2.8.0 (2019-02-15)__
|
||||
* __v2.8.0 (2019-02-15)__
|
||||
|
||||
For Linux kernel version: 4.20
|
||||
|
||||
@@ -81,7 +230,7 @@ Release history for s390-tools (MIT version)
|
||||
- zkey: Avoid EPERM on key change if user is not owner of key file
|
||||
- cpumf/cpumf_helper: Always return list reference for --sfb-size
|
||||
|
||||
* __v2.7.1 (2018-12-13)__
|
||||
* __v2.7.1 (2018-12-13)__
|
||||
|
||||
For Linux kernel version: 4.19
|
||||
|
||||
@@ -105,7 +254,7 @@ Release history for s390-tools (MIT version)
|
||||
ip_watcher, libvmdump, libvtoc, lsqeth, lszcrypt, qethqoat, zdev, zdsfs,
|
||||
zgetdump, zipl, zpcictl
|
||||
|
||||
* __v2.7.0 (2018-10-31)__
|
||||
* __v2.7.0 (2018-10-31)__
|
||||
|
||||
For Linux kernel version: 4.19
|
||||
|
||||
@@ -130,7 +279,7 @@ Release history for s390-tools (MIT version)
|
||||
- Direct --help and --version output to stdout for several tools
|
||||
- osasnmpd: Start without real OSA devices
|
||||
|
||||
* __v2.6.0 (2018-08-10)__
|
||||
* __v2.6.0 (2018-08-10)__
|
||||
|
||||
For Linux kernel version: 4.18
|
||||
|
||||
@@ -144,7 +293,7 @@ Release history for s390-tools (MIT version)
|
||||
- netboot: Include compressed kernel modules in initramfs
|
||||
- netboot: Send client architecture and handle path prefix
|
||||
|
||||
* __v2.5.0 (2018-06-08)__
|
||||
* __v2.5.0 (2018-06-08)__
|
||||
|
||||
For Linux kernel version: 4.17
|
||||
|
||||
@@ -156,7 +305,7 @@ Release history for s390-tools (MIT version)
|
||||
Bug Fixes:
|
||||
- lsluns: Print a message if no adapter or port exists
|
||||
|
||||
* __v2.4.0 (2018-05-07)__
|
||||
* __v2.4.0 (2018-05-07)__
|
||||
|
||||
For Linux kernel version: 4.16
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ In the examples below we use this fictive identity:
|
||||
### Setup GitHub and local git
|
||||
|
||||
1. Create a fork of this repository by clicking the `Fork` button on the top
|
||||
right of the [s390-tools](https://github.com/ibm-s390-tools/s390-tools)
|
||||
right of the [s390-tools](https://github.com/ibm-s390-linux/s390-tools)
|
||||
main page
|
||||
|
||||
2. Clone your forked repository to your local development system
|
||||
@@ -84,7 +84,7 @@ In the examples below we use this fictive identity:
|
||||
s390-tools repository on GitHub
|
||||
```
|
||||
$ cd s390-tools
|
||||
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-tools/s390-tools.git
|
||||
~/s390-tools $ git remote add upstream https://github.com/ibm-s390-linux/s390-tools.git
|
||||
```
|
||||
|
||||
4. Verify your remotes
|
||||
@@ -92,8 +92,8 @@ In the examples below we use this fictive identity:
|
||||
~/s390-tools $ git remote -v
|
||||
origin https://github.com/random-developer/s390-tools.git (fetch)
|
||||
origin https://github.com/random-developer/s390-tools.git (push)
|
||||
upstream https://github.com/ibm-s390-tools/s390-tools.git (fetch)
|
||||
upstream https://github.com/ibm-s390-tools/s390-tools.git (push)
|
||||
upstream https://github.com/ibm-s390-linux/s390-tools.git (fetch)
|
||||
upstream https://github.com/ibm-s390-linux/s390-tools.git (push)
|
||||
```
|
||||
You now have two remotes: The "origin" remote points to your fork
|
||||
and the "upstream" remote to the official s390-tools repository.
|
||||
|
||||
6
Makefile
6
Makefile
@@ -3,12 +3,14 @@ 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 libutil libzds libdasd libvmdump libccw libvmcp
|
||||
LIB_DIRS = libvtoc libutil libzds libdasd libvmdump libccw libvmcp libekmfweb
|
||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl
|
||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||
genprotimg lsstp hsci
|
||||
|
||||
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
|
||||
|
||||
all: $(TOOL_DIRS)
|
||||
|
||||
55
README.md
55
README.md
@@ -1,4 +1,3 @@
|
||||
|
||||
s390-tools
|
||||
==========
|
||||
|
||||
@@ -31,6 +30,9 @@ Package contents
|
||||
* dasdinfo:
|
||||
Display unique DASD ID, either UID or volser.
|
||||
|
||||
* genprotimg:
|
||||
Create a protected virtualization image.
|
||||
|
||||
* udev rules:
|
||||
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
|
||||
- 57-osasnmpd.rules: udev rules for osasnmpd.
|
||||
@@ -241,6 +243,15 @@ Package contents
|
||||
Provides simple tools to create a binary that can be used to implement
|
||||
simple network boot setups following the PXELINUX conventions.
|
||||
|
||||
* libekmfweb:
|
||||
A shared library that provides functions to communicate with an EKMF Web
|
||||
server via REST calls over HTTPS. EKMF Web stands for IBM Enterprise Key
|
||||
Management Foundation - Web Edition, and is used to manage keys in an
|
||||
enterprise.
|
||||
|
||||
* hsci:
|
||||
Manage HiperSockets Converged Interfaces (HSCI).
|
||||
|
||||
For more information refer to the following publications:
|
||||
|
||||
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
|
||||
@@ -265,16 +276,19 @@ build options:
|
||||
| pfm | `HAVE_PFM` | cpacfstats |
|
||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||
| openssl | `HAVE_OPENSSL` | zkey |
|
||||
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb |
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb |
|
||||
| glib2 | `HAVE_GLIB2` | genprotimg |
|
||||
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb |
|
||||
|
||||
This table lists additional build or install options:
|
||||
|
||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||
|----------------|:----------------:|:-------------------------------:|
|
||||
| dracut | `HAVE_DRACUT` | zdev |
|
||||
| initramfs-tools| `HAVE_INITRAMFS` | zdev |
|
||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||
|------------------|:----------------------------:|:--------------:|
|
||||
| dracut | `HAVE_DRACUT` | zdev |
|
||||
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
|
||||
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
|
||||
|
||||
The s390-tools build process uses "pkg-config" if available and hard-coded
|
||||
compiler and linker options otherwise.
|
||||
@@ -288,6 +302,14 @@ the different tools are provided:
|
||||
* dbginfo.sh:
|
||||
The tar package is required to archive collected data.
|
||||
|
||||
* genprotimg:
|
||||
For building genprotimg you need OpenSSL version 1.1.0 or newer
|
||||
installed (openssl-devel.rpm). Also required is glib2
|
||||
(glib2-devel.rpm). Tip: you may skip the genprotimg build by adding
|
||||
`HAVE_OPENSSL=0` or `HAVE_GLIB2=0`.
|
||||
|
||||
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
|
||||
|
||||
* osasnmpd:
|
||||
You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)
|
||||
installed, before building the osasnmpd subagent.
|
||||
@@ -357,6 +379,17 @@ the different tools are provided:
|
||||
Distributors with different boot or RAM-disk mechanisms should provide
|
||||
a custom zdev-root-update helper script.
|
||||
|
||||
- `ZDEV_ALWAYS_UPDATE_INITRD=1` upon modification of any persistent device
|
||||
configuration, chzdev updates the initial RAM-disk by default, without any
|
||||
additional user interaction.
|
||||
|
||||
For some distributions, all the configuration attributes must be copied to
|
||||
the initial RAM-disk. Because the device configuration directives applied
|
||||
in the initial RAM-disk takes precedence over those stored in the root file-
|
||||
system. This copying is done usually by explicitly invoking a command. This
|
||||
build option makes it user-friendly and does this copying without any manual
|
||||
intervention.
|
||||
|
||||
Some functions of zdev require that the following programs are available:
|
||||
|
||||
- modprobe (kmod)
|
||||
@@ -386,3 +419,11 @@ the different tools are provided:
|
||||
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.
|
||||
|
||||
* libekmfweb:
|
||||
For building the libekmfweb shared library you need openssl version 1.1.1 or
|
||||
newer installed (openssl-devel.rpm). Also required are json-c version 0.13 or
|
||||
newer (json-c-devel.rpm), and libcurl version 7.59 or newer
|
||||
(libcurl-devel.rpm).
|
||||
Tip: you may skip the libekmfweb build by adding `HAVE_OPENSSL=0`,
|
||||
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
||||
|
||||
@@ -299,7 +299,7 @@ static unsigned long dec_to_hex(unsigned long long num)
|
||||
{
|
||||
unsigned long res;
|
||||
|
||||
asm volatile("cvb %0,%1" : "=d" (res) : "m" (num));
|
||||
asm volatile("cvb %0,%1" : "=d" (res) : "Q" (num));
|
||||
return res & 0xffffffff;
|
||||
}
|
||||
|
||||
@@ -307,7 +307,7 @@ static unsigned int hex_to_dec(unsigned int num)
|
||||
{
|
||||
unsigned long long res;
|
||||
|
||||
asm volatile("cvd %1,%0" : "=m" (res) : "d" (num));
|
||||
asm volatile("cvd %1,%0" : "=Q" (res) : "d" (num));
|
||||
return res & 0xffffffff;
|
||||
}
|
||||
|
||||
@@ -2050,7 +2050,7 @@ static int update_dir_levels(int blocks)
|
||||
if (blocks < 2)
|
||||
return 0;
|
||||
|
||||
while (blocks / (PTRS_PER_BLOCK + 1)) {
|
||||
while (blocks / PTRS_PER_BLOCK) {
|
||||
levels++;
|
||||
blocks /= PTRS_PER_BLOCK;
|
||||
}
|
||||
@@ -3103,7 +3103,7 @@ static void update_levels(struct file *f)
|
||||
return;
|
||||
}
|
||||
|
||||
while (blocks / (per_block + 1)) {
|
||||
while (blocks / per_block) {
|
||||
levels++;
|
||||
blocks /= per_block;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "cmsfs-fuse.h"
|
||||
#include "edf.h"
|
||||
#include "helper.h"
|
||||
|
||||
@@ -49,6 +49,4 @@ extern FILE *logfile;
|
||||
fprintf(stderr, COMP "Warning, " __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#endif
|
||||
|
||||
31
common.mak
31
common.mak
@@ -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 = 11
|
||||
RELEASE = 16
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
@@ -106,6 +106,11 @@ endif
|
||||
DEFAULT_CPPFLAGS = -D_GNU_SOURCE
|
||||
DEFAULT_LDFLAGS = -rdynamic
|
||||
|
||||
ifeq ("${ASAN}","1")
|
||||
DEFAULT_CFLAGS += -fsanitize=address -fno-omit-frame-pointer
|
||||
DEFAULT_LDFLAGS += -fsanitize=address
|
||||
endif
|
||||
|
||||
#
|
||||
# Check for build dependency
|
||||
#
|
||||
@@ -163,6 +168,7 @@ USRSBINDIR = $(INSTALLDIR)/usr/sbin
|
||||
USRBINDIR = $(INSTALLDIR)/usr/bin
|
||||
BINDIR = $(INSTALLDIR)/sbin
|
||||
LIBDIR = $(INSTALLDIR)/lib
|
||||
USRLIB64DIR = $(INSTALLDIR)/usr/lib64
|
||||
SYSCONFDIR = $(INSTALLDIR)/etc
|
||||
MANDIR = $(INSTALLDIR)/usr/share/man
|
||||
VARDIR = $(INSTALLDIR)/var
|
||||
@@ -172,14 +178,24 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
|
||||
# Systemd support files are installed only if a directory is specified
|
||||
# for SYSTEMDSYSTEMUNITDIR (e.g. /lib/systemd/system)
|
||||
SYSTEMDSYSTEMUNITDIR =
|
||||
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
||||
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
|
||||
|
||||
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
|
||||
SOINSTALLDIR = $(USRLIB64DIR)
|
||||
else
|
||||
SOINSTALLDIR = $(LIBDIR)
|
||||
endif
|
||||
|
||||
INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
|
||||
$(SYSCONFDIR) $(SYSCONFDIR)/sysconfig \
|
||||
$(TOOLS_LIBDIR) $(TOOLS_DATADIR) \
|
||||
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR)
|
||||
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
|
||||
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
|
||||
$(SOINSTALLDIR)
|
||||
OWNER = $(shell id -un)
|
||||
GROUP = $(shell id -gn)
|
||||
export INSTALLDIR BINDIR LIBDIR MANDIR OWNER GROUP
|
||||
export INSTALLDIR BINDIR LIBDIR USRLIB64DIR MANDIR OWNER GROUP
|
||||
|
||||
# Special defines for zfcpdump
|
||||
ZFCPDUMP_IMAGE = zfcpdump-image
|
||||
@@ -261,6 +277,7 @@ help:
|
||||
@echo ' G=1 Build with gcov to collect code coverage data'
|
||||
@echo ' V=1 Generate verbose build output'
|
||||
@echo ' W=1 Build with higher warning level'
|
||||
@echo ' ASAN=1 Build with address sanitizer'
|
||||
@echo ''
|
||||
@echo 'EXAMPLES'
|
||||
@echo ' # make clean all D=1 W=1 -j'
|
||||
@@ -339,6 +356,10 @@ $(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
||||
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||
.PHONY: $(rootdir)/libvmcp
|
||||
|
||||
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
||||
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
||||
.PHONY: $(rootdir)/libekmfweb
|
||||
|
||||
$(rootdir)/zipl/boot/data.o:
|
||||
$(MAKE) -C $(rootdir)/zipl/boot/ data.o
|
||||
|
||||
@@ -359,9 +380,9 @@ install: install_echo install_dirs
|
||||
clean_echo:
|
||||
$(call echocmd," CLEAN ")
|
||||
clean_gcov:
|
||||
rm -f *.gcda *.gcno *.gcov
|
||||
rm -f -- *.gcda *.gcno *.gcov
|
||||
clean_dep:
|
||||
rm -f .*.o.d
|
||||
rm -f -- .*.o.d
|
||||
|
||||
clean: clean_echo clean_gcov clean_dep
|
||||
endif
|
||||
|
||||
@@ -2,28 +2,10 @@ include ../common.mak
|
||||
|
||||
ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
||||
|
||||
|
||||
ifeq (${HAVE_PFM},0)
|
||||
|
||||
all:
|
||||
$(SKIP) HAVE_PFM=0
|
||||
|
||||
install:
|
||||
$(SKIP) HAVE_PFM=0
|
||||
|
||||
else
|
||||
|
||||
check_dep:
|
||||
$(call check_dep, \
|
||||
"cpacfstats", \
|
||||
"perfmon/pfmlib.h", \
|
||||
"libpfm-devel or libpfm4-dev", \
|
||||
"HAVE_PFM=0")
|
||||
|
||||
all: check_dep cpacfstats cpacfstatsd
|
||||
all: cpacfstats cpacfstatsd
|
||||
|
||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -lpfm -o $@
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
cpacfstats: cpacfstats.o stats_sock.o
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
@@ -34,7 +16,6 @@ install: all
|
||||
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
endif
|
||||
clean:
|
||||
rm -f *.o *~ cpacfstatsd cpacfstats
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" cpacfstats.1
|
||||
.\"
|
||||
.\" Copyright IBM Corp. 2015, 2017
|
||||
.\" Copyright IBM Corp. 2015, 2020
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
@@ -80,31 +80,33 @@ Display help information for the command.
|
||||
Display version and copyright information for the command.
|
||||
.TP
|
||||
\fB\-e\fR or \fB\-\-enable\fR [counter]
|
||||
Enable one or all CPACF performance counters. The optional counter argument
|
||||
can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR or \fBall\fR. If
|
||||
the counter argument is omitted, all performance counters are
|
||||
enabled. Enabling a counter does not reset it. New events are added to the
|
||||
current counter value.
|
||||
Enable one or all CPACF performance counters. The optional counter
|
||||
argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
|
||||
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
||||
performance counters are enabled. Enabling a counter does not reset
|
||||
it. New events are added to the current counter value.
|
||||
.TP
|
||||
\fB\-d\fR or \fB\-\-disable\fR [counter]
|
||||
Disable one or all CPACF performance counters. The optional counter
|
||||
argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR or
|
||||
\fBall\fR. If the counter argument is omitted, all performance counters
|
||||
are disabled. Disabling a counter does not reset it. The counter value is
|
||||
preserved when a counter is disabled, and counting will resume using the
|
||||
preserved value when the counter is re-enabled.
|
||||
argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
|
||||
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
||||
performance counters are disabled. Disabling a counter does not reset
|
||||
it. The counter value is preserved when a counter is disabled, and
|
||||
counting will resume using the preserved value when the counter is
|
||||
re-enabled.
|
||||
.TP
|
||||
\fB\-r\fR or \fB\-\-reset\fR [counter]
|
||||
Reset one or all CPACF performance counters. The optional counter
|
||||
argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR or
|
||||
\fBall\fR. If the counter argument is omitted, all performance counters are
|
||||
reset to 0.
|
||||
argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
|
||||
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
||||
performance counters are reset to 0.
|
||||
.TP
|
||||
\fB\-p\fR or \fB\-\-print\fR [counter]
|
||||
Display the value of one or all CPACF performance counters. The optional
|
||||
counter argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR
|
||||
or \fBall\fR. If the counter argument is omitted or if there is no
|
||||
argument, all performance counters are displayed.
|
||||
Display the value of one or all CPACF performance counters. The
|
||||
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
|
||||
\fBsha\fR, \fBprng\fR, \fBecc\fR, or \fBall\fR. If the counter
|
||||
argument is omitted or if there is no argument, all performance
|
||||
counters are displayed.
|
||||
.TP
|
||||
The default command is --print all.
|
||||
.
|
||||
@@ -123,5 +125,10 @@ version mismatch between client and daemon, or the application is out of
|
||||
memory. The application prints a message with the details of the error and
|
||||
the errno value.
|
||||
.
|
||||
.SH NOTES
|
||||
ECC counters are only available since z15. cpacfstats will show the
|
||||
counters as \fIunsupported\fR if the hardware does not support ECC
|
||||
counters.
|
||||
.
|
||||
.SH SEE ALSO
|
||||
cpacfstatsd (8)
|
||||
.BR cpacfstatsd (8)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* cpacfstats client implementation
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2017
|
||||
* Copyright IBM Corp. 2015, 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
@@ -39,13 +39,14 @@ static const char *const usage =
|
||||
"\t-d, --disable [counter] Disable one or all counters\n"
|
||||
"\t-r, --reset [counter] Reset one or all counter values\n"
|
||||
"\t-p, --print [counter] Print one or all counter values\n"
|
||||
"\tcounter can be: 'aes' 'des' 'rng' 'sha' or 'all'\n";
|
||||
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc' or 'all'\n";
|
||||
|
||||
static const char *const counter_str[] = {
|
||||
[DES_FUNCTIONS] = "des",
|
||||
[AES_FUNCTIONS] = "aes",
|
||||
[SHA_FUNCTIONS] = "sha",
|
||||
[PRNG_FUNCTIONS] = "rng",
|
||||
[ECC_FUNCTIONS] = "ecc",
|
||||
[ALL_COUNTER] = "all"
|
||||
};
|
||||
|
||||
@@ -98,6 +99,8 @@ static void print_answer(int ctr, int state, uint64_t value)
|
||||
counter_str[ctr], state);
|
||||
else if (state == DISABLED)
|
||||
printf(" %s counter: disabled\n", counter_str[ctr]);
|
||||
else if (state == UNSUPPORTED)
|
||||
printf(" %s counter: unsupported\n", counter_str[ctr]);
|
||||
else
|
||||
printf(" %s counter: %"PRIu64"\n", counter_str[ctr], value);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* common function prototypes and definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2017
|
||||
* Copyright IBM Corp. 2015, 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define COPYRIGHT "Copyright IBM Corp. 2015, 2017"
|
||||
#define COPYRIGHT "Copyright IBM Corp. 2015, 2020"
|
||||
|
||||
int eprint(const char *format, ...);
|
||||
|
||||
@@ -27,6 +27,7 @@ enum ctr_e {
|
||||
AES_FUNCTIONS,
|
||||
SHA_FUNCTIONS,
|
||||
PRNG_FUNCTIONS,
|
||||
ECC_FUNCTIONS,
|
||||
ALL_COUNTER
|
||||
};
|
||||
|
||||
@@ -44,7 +45,8 @@ enum cmd_e {
|
||||
|
||||
enum state_e {
|
||||
DISABLED = 0,
|
||||
ENABLED
|
||||
ENABLED,
|
||||
UNSUPPORTED
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -108,5 +110,6 @@ int perf_enable_ctr(enum ctr_e ctr);
|
||||
int perf_disable_ctr(enum ctr_e ctr);
|
||||
int perf_reset_ctr(enum ctr_e ctr);
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
||||
int perf_ecc_supported(void);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" cpacfstatsd.8
|
||||
.\"
|
||||
.\" Copyright IBM Corp. 2015, 2017
|
||||
.\" Copyright IBM Corp. 2015, 2020
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
@@ -37,7 +37,10 @@ config option enabled.
|
||||
.P
|
||||
- Libpfm version 4 or higher is needed to successfully run the daemon.
|
||||
.P
|
||||
- Your LPAR must be configured to enable the "Counter Facility Security Options".
|
||||
- On the HMC or SE, authorize the LPAR for each counter set you want
|
||||
to use. Customize the LPAR activation profile and modify the Counter
|
||||
Facility Security Options. You need to activate the "Crypto activity
|
||||
counter set authorization control" checkbox.
|
||||
.P
|
||||
- The daemon requires root privileges to interact with the performance
|
||||
ioctls of the kernel.
|
||||
@@ -47,7 +50,7 @@ restart the daemon to ensure correct summing of the per-CPU performance
|
||||
counters.
|
||||
|
||||
The starting daemon first checks for any stale pid file
|
||||
/run/cpacfstatsd.pid. If this file exists, and the process ID in the
|
||||
\%/run/cpacfstatsd.pid. If this file exists, and the process ID in the
|
||||
file belongs to an active process, an error message is printed to the
|
||||
console and the program terminates.
|
||||
|
||||
@@ -94,4 +97,4 @@ done in the re-spawned process. Check the syslog for success or failure.
|
||||
The daemon could not be set to run in the background.
|
||||
|
||||
.SH SEE ALSO
|
||||
cpacfstats (1)
|
||||
.BR cpacfstats (1)
|
||||
|
||||
@@ -94,20 +94,24 @@ static int do_enable(int s, enum ctr_e ctr)
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (!ctr_state[i]) {
|
||||
if (ctr_state[i] == DISABLED) {
|
||||
rc = perf_enable_ctr(i);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
ctr_state[i] = 1;
|
||||
ctr_state[i] = ENABLED;
|
||||
}
|
||||
rc = perf_read_ctr(i, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
if (ctr_state[i] == UNSUPPORTED) {
|
||||
send_answer(s, i, UNSUPPORTED, 0);
|
||||
} else {
|
||||
rc = perf_read_ctr(i, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
send_answer(s, i, ENABLED, value);
|
||||
}
|
||||
send_answer(s, i, ENABLED, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +125,7 @@ static int do_disable(int s, enum ctr_e ctr)
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i]) {
|
||||
if (ctr_state[i] == ENABLED) {
|
||||
rc = perf_disable_ctr(i);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
@@ -129,7 +133,7 @@ static int do_disable(int s, enum ctr_e ctr)
|
||||
}
|
||||
ctr_state[i] = 0;
|
||||
}
|
||||
send_answer(s, i, DISABLED, 0);
|
||||
send_answer(s, i, ctr_state[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +147,7 @@ static int do_reset(int s, enum ctr_e ctr)
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i]) {
|
||||
if (ctr_state[i] == ENABLED) {
|
||||
rc = perf_reset_ctr(i);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
@@ -151,7 +155,7 @@ static int do_reset(int s, enum ctr_e ctr)
|
||||
}
|
||||
send_answer(s, i, ENABLED, 0);
|
||||
} else {
|
||||
send_answer(s, i, DISABLED, 0);
|
||||
send_answer(s, i, ctr_state[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +170,7 @@ static int do_print(int s, enum ctr_e ctr)
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i]) {
|
||||
if (ctr_state[i] == ENABLED) {
|
||||
rc = perf_read_ctr(i, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
@@ -174,7 +178,7 @@ static int do_print(int s, enum ctr_e ctr)
|
||||
}
|
||||
send_answer(s, i, ENABLED, value);
|
||||
} else {
|
||||
send_answer(s, i, DISABLED, 0);
|
||||
send_answer(s, i, ctr_state[i], 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -412,6 +416,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
atexit(perf_close);
|
||||
|
||||
if (!perf_ecc_supported())
|
||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||
|
||||
sfd = open_socket(SERVER);
|
||||
if (sfd < 0) {
|
||||
eprint("Couldn't initialize server socket\n");
|
||||
|
||||
@@ -3,36 +3,39 @@
|
||||
*
|
||||
* low level perf functions
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2017
|
||||
* Copyright IBM Corp. 2015, 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <asm/unistd.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#include <perfmon/perf_event.h>
|
||||
#include <perfmon/pfmlib.h>
|
||||
#include <perfmon/pfmlib_perf_event.h>
|
||||
#include <limits.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "cpacfstats.h"
|
||||
|
||||
/* correlation between counter and perf counter string */
|
||||
static const struct {
|
||||
char pfm_name[80];
|
||||
char pmu[20];
|
||||
char pfm_name[60];
|
||||
enum ctr_e ctr;
|
||||
} pmf_counter_name[ALL_COUNTER] = {
|
||||
{"cpum_cf::DEA_FUNCTIONS", DES_FUNCTIONS},
|
||||
{"cpum_cf::AES_FUNCTIONS", AES_FUNCTIONS},
|
||||
{"cpum_cf::SHA_FUNCTIONS", SHA_FUNCTIONS},
|
||||
{"cpum_cf::PRNG_FUNCTIONS", PRNG_FUNCTIONS}
|
||||
{"cpum_cf", "DEA_FUNCTIONS", DES_FUNCTIONS},
|
||||
{"cpum_cf", "AES_FUNCTIONS", AES_FUNCTIONS},
|
||||
{"cpum_cf", "SHA_FUNCTIONS", SHA_FUNCTIONS},
|
||||
{"cpum_cf", "PRNG_FUNCTIONS", PRNG_FUNCTIONS},
|
||||
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -53,27 +56,106 @@ static const struct {
|
||||
*/
|
||||
static int *ctr_fds[ALL_COUNTER];
|
||||
|
||||
static int ecc_supported;
|
||||
|
||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||
int cpu, int group_fd, unsigned long flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
|
||||
group_fd, flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int perf_supported(void)
|
||||
{
|
||||
return !access("/proc/sys/kernel/perf_event_paranoid", R_OK);
|
||||
}
|
||||
|
||||
static int perf_counter_supported(const char *pmu, const char *counter)
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
||||
pmu, counter) >= PATH_MAX) {
|
||||
eprint("overflow in path name");
|
||||
return 0;
|
||||
}
|
||||
return !access(buf, R_OK);
|
||||
}
|
||||
|
||||
static int perf_event_encode(struct perf_event_attr *attr,
|
||||
const char *pmu, const char *event)
|
||||
{
|
||||
FILE *f;
|
||||
int eventid;
|
||||
int pmutype;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
||||
pmu, event) >= PATH_MAX) {
|
||||
eprint("overflow in path name");
|
||||
return -1;
|
||||
}
|
||||
f = fopen(buf, "r");
|
||||
if (!f) {
|
||||
eprint("Event %s for pmu %s not found (%d:%s)\n", event, pmu,
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
|
||||
fclose(f);
|
||||
eprint("Event file %s has invalid format\n", buf);
|
||||
return -1;
|
||||
}
|
||||
fclose(f);
|
||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/type",
|
||||
pmu) >= PATH_MAX) {
|
||||
eprint("overflow in path name");
|
||||
return -1;
|
||||
}
|
||||
f = fopen(buf, "r");
|
||||
if (!f) {
|
||||
eprint("Event %s for pmu %s not found (%d:%s)\n", event, pmu,
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fscanf(f, "%d\n", &pmutype) != 1) {
|
||||
fclose(f);
|
||||
eprint("Type file %s has invalid format\n", buf);
|
||||
return -1;
|
||||
}
|
||||
attr->type = pmutype;
|
||||
attr->config = eventid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int perf_init(void)
|
||||
{
|
||||
int i, cpus, ctr, cpu, ec, *fds;
|
||||
int i, cpus, ctr, cpu, *fds;
|
||||
|
||||
memset(ctr_fds, 0, sizeof(ctr_fds));
|
||||
|
||||
/* initialize performance monitoring library */
|
||||
ec = pfm_initialize();
|
||||
if (ec != PFM_SUCCESS) {
|
||||
eprint("Pfm_initialize() returned with failure (%d:%s)\n",
|
||||
ec, pfm_strerror(ec));
|
||||
if (!perf_supported()) {
|
||||
eprint("Performance counter not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if ECC is supported on current hardware */
|
||||
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
||||
|
||||
/* get number of logical processors */
|
||||
cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
/* for each counter */
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
|
||||
/* Skip ECC counters completely if unsupported */
|
||||
if (ctr == ECC_FUNCTIONS && !ecc_supported)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* allocate an array of ints to store for each CPU
|
||||
* one filedescriptor + a terminating 0
|
||||
@@ -88,37 +170,28 @@ int perf_init(void)
|
||||
|
||||
ctr_fds[ctr] = fds;
|
||||
|
||||
/* search for the counter's corresponding pfm name */
|
||||
for (i = ALL_COUNTER-1; i >= 0; i--)
|
||||
if ((int) pmf_counter_name[i].ctr == ctr)
|
||||
break;
|
||||
if (i < 0) {
|
||||
eprint("Pfm ctr name not found for counter %d, please adjust pmf_counter_name[] in %s\n",
|
||||
ctr, __FILE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < cpus; cpu++) {
|
||||
pfm_perf_encode_arg_t pfm_arg;
|
||||
struct perf_event_attr pfm_event;
|
||||
int fd;
|
||||
|
||||
memset(&pfm_arg, 0, sizeof(pfm_arg));
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_arg.attr = &pfm_event;
|
||||
pfm_arg.size = sizeof(pfm_arg);
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
|
||||
/* search for the counter's corresponding pfm name */
|
||||
for (i = ALL_COUNTER-1; i >= 0; i--)
|
||||
if ((int) pmf_counter_name[i].ctr == ctr)
|
||||
break;
|
||||
if (i < 0) {
|
||||
eprint("Pfm ctr name not found for counter %d, please adjust pmf_counter_name[] in %s\n",
|
||||
ctr, __FILE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* encode the counters perf event into pfm_arg.attr */
|
||||
ec = pfm_get_os_event_encoding(
|
||||
pmf_counter_name[i].pfm_name,
|
||||
PFM_PLM0,
|
||||
PFM_OS_PERF_EVENT,
|
||||
&pfm_arg);
|
||||
if (ec != PFM_SUCCESS) {
|
||||
eprint("Pfm_initialize() for %s failed (%d:%s)\n",
|
||||
if (perf_event_encode(&pfm_event,
|
||||
pmf_counter_name[i].pmu,
|
||||
pmf_counter_name[i].pfm_name)) {
|
||||
eprint("Failed to initialize counter %s for pmu %s\n",
|
||||
pmf_counter_name[i].pfm_name,
|
||||
ec, pfm_strerror(ec));
|
||||
pmf_counter_name[i].pmu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -257,3 +330,8 @@ int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int perf_ecc_supported(void)
|
||||
{
|
||||
return ecc_supported;
|
||||
}
|
||||
|
||||
@@ -1,66 +1,28 @@
|
||||
#!/usr/bin/make -f
|
||||
|
||||
include ../common.mak
|
||||
|
||||
|
||||
CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf
|
||||
DATA_FILES = cpum-cf-hw-counter.map \
|
||||
cpum-cf-cfvn-1.ctr cpum-cf-cfvn-3.ctr \
|
||||
cpum-cf-csvn-12345.ctr cpum-cf-csvn-6.ctr \
|
||||
cpum-cf-extended-z10.ctr cpum-cf-extended-z196.ctr \
|
||||
cpum-cf-extended-zEC12.ctr cpum-sf-modes.ctr \
|
||||
cpum-cf-extended-z13.ctr cpum-cf-extended-z14.ctr
|
||||
LIB_FILES = bin/cpumf_helper
|
||||
USRBIN_SCRIPTS = bin/lscpumf
|
||||
USRSBIN_SCRIPTS = bin/chcpumf
|
||||
BIN_FILES = lscpumf chcpumf
|
||||
MAN_FILES = lscpumf.1 chcpumf.8
|
||||
|
||||
all:
|
||||
all: $(BIN_FILES)
|
||||
|
||||
scripts: $(USRBIN_SCRIPTS) $(USRSBIN_SCRIPTS) $(LIB_FILES)
|
||||
chmod +x $(USRBIN_SCRIPTS) $(USRSBIN_SCRIPTS) $(LIB_FILES)
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
|
||||
check:
|
||||
lscpumf: lscpumf.o $(libs)
|
||||
chcpumf: chcpumf.o $(libs)
|
||||
|
||||
install: scripts install-man
|
||||
for prg in $(USRBIN_SCRIPTS); do \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$prg $(DESTDIR)$(USRBINDIR) ; \
|
||||
done
|
||||
for prg in $(USRSBIN_SCRIPTS); do \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$prg $(DESTDIR)$(USRSBINDIR) ; \
|
||||
done
|
||||
test -d $(DESTDIR)$(CPUMF_DATADIR) || mkdir -p $(DESTDIR)$(CPUMF_DATADIR)
|
||||
for lib in $(LIB_FILES); do \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$lib $(DESTDIR)$(TOOLS_LIBDIR) ; \
|
||||
done
|
||||
for data in $(DATA_FILES); do \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 data/$$data $(DESTDIR)$(CPUMF_DATADIR) ; \
|
||||
install: all install-man
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||
for binf in $(BIN_FILES); do \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 $$binf $(DESTDIR)$(BINDIR); \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ $(BIN_FILES) core
|
||||
|
||||
install-man:
|
||||
for man in $(MAN_FILES); do \
|
||||
msection=`echo $$man |sed 's/.*\.\([1-9]\)$$/man\1/'` ; \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 -D man/$$man $(DESTDIR)$(MANDIR)/$$msection/$$man ; \
|
||||
done
|
||||
|
||||
man2pdf:
|
||||
for man in $(MAN_FILES); do \
|
||||
man -t man/$$man |ps2pdf -sPAPERSIZE=a4 - man/$${man}.pdf ; \
|
||||
done
|
||||
man2text:
|
||||
for man in $(MAN_FILES); do \
|
||||
MANWIDTH=80 LANG=C man man/$$man |col -b |expand > man/$${man}.txt ; \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm -f $(LIB_FILES) $(USRBIN_SCRIPTS) $(USRSBIN_SCRIPTS)
|
||||
|
||||
%: %.in
|
||||
real_libdir=$(TOOLS_LIBDIR); \
|
||||
real_cpumfdatadir=$(CPUMF_DATADIR); \
|
||||
$(SED) -e "s#@lib_path@#$$real_libdir#g" \
|
||||
-e "s#@cpumfdata_path@#$$real_cpumfdatadir#g" \
|
||||
-e 's#@S390_TOOLS_RELEASE@#$(S390_TOOLS_RELEASE)#g' \
|
||||
< $< > $@
|
||||
|
||||
.PHONY: all scripts install install-man man2pdf man2text clean
|
||||
.PHONY: all install clean
|
||||
|
||||
@@ -1,182 +0,0 @@
|
||||
#!/usr/bin/perl -W
|
||||
#
|
||||
# chcpumf - Control CPU-measurement facilities
|
||||
#
|
||||
# Copyright IBM Corp. 2014, 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.
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
use File::Basename qw/fileparse/;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long qw/:config no_ignore_case/;
|
||||
|
||||
# Global constants
|
||||
my $CPUMF_HELPER = '@lib_path@/cpumf_helper';
|
||||
my $CPUM_SFB_SIZE = '/sys/module/kernel/parameters/cpum_sfb_size';
|
||||
|
||||
# Prototypes
|
||||
sub main();
|
||||
sub show_help();
|
||||
sub show_version();
|
||||
sub do_set_sfb_size($);
|
||||
sub cpumf_set_sfb_size($);
|
||||
sub invoke_cpumf_helper($);
|
||||
|
||||
sub main()
|
||||
{
|
||||
my $config = {
|
||||
# Internal data
|
||||
cpumf => {}, # CPU-MF information hash
|
||||
};
|
||||
|
||||
unless (GetOptions(
|
||||
# General options for help, version, verbose,...
|
||||
"h|help" => \&show_help,
|
||||
"v|version" => \&show_version,
|
||||
"V|verbose+" => \$config->{verbose},
|
||||
# Change specific options
|
||||
"m|min=i" => \$config->{min},
|
||||
"x|max=i" => \$config->{max},
|
||||
)) {
|
||||
print STDERR "One or more options are not valid\n";
|
||||
print STDERR "Try '" . fileparse($0) .
|
||||
" --help' for more information\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Collect CPU-MF information
|
||||
$config->{cpumf} = invoke_cpumf_helper("-i");
|
||||
die "Failed to collect CPU-MF information: $!\n" unless $config->{cpumf};
|
||||
|
||||
# Process parameters
|
||||
my $exitval = 5;
|
||||
if (defined($config->{min}) || defined($config->{max})) {
|
||||
$exitval = do_set_sfb_size($config);
|
||||
} else {
|
||||
print STDERR "You must specify a valid option\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
exit($exitval);
|
||||
}
|
||||
|
||||
sub show_help()
|
||||
{
|
||||
my $prog = fileparse($0);
|
||||
|
||||
print <<"EoHelp";
|
||||
Usage: chcpumf -h|-v
|
||||
chcpumf -m <num_sdb>
|
||||
chcpumf -x <num_sdb>
|
||||
|
||||
Options:
|
||||
-m <num_sdb> Specifies the initial size of the sampling buffer.
|
||||
A sample-data-block (SDB) consumes about 4 kilobytes.
|
||||
-x <num_sdb> Specifies the maximum size of the sampling buffer.
|
||||
A sample-data-block (SDB) consumes about 4 kilobytes.
|
||||
-h Displays help information, then exits.
|
||||
-v Displays version information, then exits.
|
||||
|
||||
For more help information, issue 'man $prog'.
|
||||
EoHelp
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub show_version()
|
||||
{
|
||||
print <<'EoVersion';
|
||||
CPU-measurement facility utilities, version @S390_TOOLS_RELEASE@
|
||||
Copyright IBM Corp. 2014, 2017
|
||||
|
||||
EoVersion
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub cpumf_set_sfb_size($)
|
||||
{
|
||||
my @size = @{shift()};
|
||||
my $val = join ',', @size[0,1];
|
||||
my ($SFBSIZE, $rc);
|
||||
|
||||
return undef unless open($SFBSIZE, '>', $CPUM_SFB_SIZE);
|
||||
# Check the return code of print and close to detect error conditions
|
||||
# reported by the device driver. Because perl might buffer data, print
|
||||
# might be successful, but close might then report the error condition.
|
||||
# So check the return code of both functions and always close the file
|
||||
# handle.
|
||||
$rc = print { $SFBSIZE } "$val\n";
|
||||
unless ($rc) {
|
||||
close($SFBSIZE);
|
||||
return $rc;
|
||||
}
|
||||
return close($SFBSIZE);
|
||||
}
|
||||
|
||||
sub do_set_sfb_size($)
|
||||
{
|
||||
my $c = shift();
|
||||
my $size;
|
||||
|
||||
# Check if sampling facility is available
|
||||
unless (exists $c->{cpumf}->{sf}) {
|
||||
print STDERR "No CPU-measurement sampling facility detected\n";
|
||||
return 2;
|
||||
}
|
||||
# Check if perf support is available
|
||||
unless (exists $c->{cpumf}->{sf}->{perf}) {
|
||||
print STDERR "No perf support for the CPU-measurement" .
|
||||
" sampling facility availalble\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
# Optionally, change the sampling buffer sizes
|
||||
if (defined($c->{min}) || defined($c->{max})) {
|
||||
$size = invoke_cpumf_helper("--sfb-size");
|
||||
# Use current size value for zero min/max specifications
|
||||
$size->[0] = $c->{min} if defined($c->{min});
|
||||
$size->[1] = $c->{max} if defined($c->{max});
|
||||
# Validate new settings
|
||||
if ($size->[0] < 1 || $size->[1] < 1) {
|
||||
die "The specified number(s) are not valid\n";
|
||||
}
|
||||
if ($size->[0] >= $size->[1]) {
|
||||
die "The specified maximum must be greater " .
|
||||
"than the minimum\n";
|
||||
}
|
||||
# Set new sampling buffer sizes
|
||||
unless (cpumf_set_sfb_size($size)) {
|
||||
die "Failed to change sampling buffer size: $!\n";
|
||||
}
|
||||
}
|
||||
|
||||
# Finally, show sampling buffer sizes
|
||||
if ($c->{verbose}) {
|
||||
$size = invoke_cpumf_helper("--sfb-size");
|
||||
print "Sampling buffer sizes:\n";
|
||||
printf " Minimum: %6u sample-data-blocks\n", $size->[0];
|
||||
printf " Maximum: %6u sample-data-blocks\n", $size->[1];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub invoke_cpumf_helper($)
|
||||
{
|
||||
my $parms = shift();
|
||||
my $result;
|
||||
|
||||
# Call helper module
|
||||
my $output = qx"$CPUMF_HELPER $parms";
|
||||
die "Failed to run helper module for '$parms'\n" if $? >> 8;
|
||||
$result = eval "$output";
|
||||
die "Failed to parse helper module data\n" if $@;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
&main();
|
||||
__DATA__
|
||||
__END__
|
||||
@@ -1,525 +0,0 @@
|
||||
#!/usr/bin/perl -W
|
||||
#
|
||||
# cpumf_helper - Helper module for managing CPU-measurement facilities (CPU-MF)
|
||||
#
|
||||
# Copyright IBM Corp. 2014, 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.
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
use Carp qw/croak/;
|
||||
use Data::Dumper;
|
||||
use Getopt::Long qw/:config no_ignore_case/;
|
||||
use Pod::Usage;
|
||||
|
||||
|
||||
# Global constants
|
||||
my $SERVICE_LEVELS = '/proc/service_levels';
|
||||
my $CPUMF_DATA_DIR = '@cpumfdata_path@';
|
||||
my $CPUM_SFB_SIZE = '/sys/module/kernel/parameters/cpum_sfb_size';
|
||||
my $CPUM_SF_DBF='/sys/kernel/debug/s390dbf/cpum_sf';
|
||||
|
||||
# Counter set bits (according to QUERY COUNTER INFORMATION)
|
||||
my $BASIC_SET = 0x0002;
|
||||
my $PROBLEM_STATE_SET = 0x0004;
|
||||
my $CRYPTO_SET = 0x0008;
|
||||
my $EXTENTED_SET = 0x0001;
|
||||
my $MT_DIAG_SET = 0x0020;
|
||||
my $COPROC_GRP_SET = 0x8000;
|
||||
|
||||
|
||||
# Public prototypes
|
||||
sub cpumf_collect_data();
|
||||
sub cpumf_get_sfb_size();
|
||||
sub cpumf_set_sfb_size($);
|
||||
sub cpumf_parse_ctrdef($;$);
|
||||
sub cpumf_load_ctrdef($;$);
|
||||
sub cpumf_get_counter_set($);
|
||||
sub cpumf_counter_set_names();
|
||||
sub cpumf_counter_set_ids();
|
||||
sub cpumf_hardware_counter_map();
|
||||
|
||||
# Internal prototypes
|
||||
sub cpumf_parse_cf($$);
|
||||
sub cpumf_parse_sf($$);
|
||||
|
||||
|
||||
sub cpumf_get_sfb_size()
|
||||
{
|
||||
my $val = "0,0";
|
||||
my $SFBSIZE;
|
||||
|
||||
if (open($SFBSIZE, '<', $CPUM_SFB_SIZE)) {
|
||||
$val = <$SFBSIZE>;
|
||||
chomp($val);
|
||||
close($SFBSIZE);
|
||||
}
|
||||
|
||||
return [split /,/, $val];
|
||||
}
|
||||
|
||||
sub cpumf_set_sfb_size($)
|
||||
{
|
||||
my @size = @{shift()};
|
||||
my $val = join ',', @size[0,1];
|
||||
my ($SFBSIZE, $rc);
|
||||
|
||||
return undef unless open($SFBSIZE, '>', $CPUM_SFB_SIZE);
|
||||
# Check the return code of print and close to detect error conditions
|
||||
# reported by the device driver. Because perl might buffer data, print
|
||||
# might be successful, but close might then report the error condition.
|
||||
# So check the return code of both functions and always close the file
|
||||
# handle.
|
||||
$rc = print { $SFBSIZE } "$val\n";
|
||||
unless ($rc) {
|
||||
close($SFBSIZE);
|
||||
return $rc;
|
||||
}
|
||||
return close($SFBSIZE);
|
||||
}
|
||||
|
||||
|
||||
sub cpumf_parse_cf($$)
|
||||
{
|
||||
my ($ent, $data) = @_;
|
||||
|
||||
if ($ent =~ /version=([0-9.]+) authorization=([[:xdigit:]]+)/) {
|
||||
$data->{cf} = { version => $1, auth => hex($2) };
|
||||
}
|
||||
}
|
||||
|
||||
sub cpumf_parse_sf($$)
|
||||
{
|
||||
my ($ent, $data) = @_;
|
||||
|
||||
# Parse common sampling facility entry
|
||||
if ($ent =~ /min_rate=(\d+) max_rate=(\d+) cpu_speed=(\d+)/) {
|
||||
$data->{sf} = {
|
||||
min_sampl_interval => $1,
|
||||
max_sampl_interval => $2,
|
||||
cpu_speed => $3,
|
||||
# This contains a list of authorized sampling modes, for
|
||||
# example, basic
|
||||
modes => {},
|
||||
};
|
||||
}
|
||||
|
||||
# Parse sampling facility mode entries
|
||||
if ($ent =~ /mode=(\w+) sample_size=(\d+)/) {
|
||||
$data->{sf}->{modes}->{$1}->{sample_size} = $2;
|
||||
}
|
||||
}
|
||||
|
||||
sub cpumf_collect_data()
|
||||
{
|
||||
my $SL;
|
||||
|
||||
# Collect CPU-MF information from /proc/service_levels
|
||||
return undef unless open($SL, '<', $SERVICE_LEVELS);
|
||||
my @sl = <$SL>;
|
||||
chomp(@sl);
|
||||
close($SL);
|
||||
|
||||
# Process CPU-MF information and build data hash
|
||||
my $data = {};
|
||||
foreach my $ent (@sl) {
|
||||
$ent =~ s/^CPU-MF: // or next;
|
||||
cpumf_parse_cf($ent, $data) if $ent =~ s/Counter facility: //;
|
||||
cpumf_parse_sf($ent, $data) if $ent =~ s/Sampling facility: //;
|
||||
}
|
||||
|
||||
# Collect perf support for available facilities
|
||||
if (-e '/sys/bus/event_source/devices/cpum_cf') {
|
||||
$data->{cf}->{perf} = "cpum_cf" if exists $data->{cf};
|
||||
}
|
||||
if (-e '/sys/bus/event_source/devices/cpum_sf') {
|
||||
$data->{sf}->{perf} = "cpum_sf" if exists $data->{sf};
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
# Parse the specified counter definition file and returns a hash containing
|
||||
# the parsed counter definition. The optional argument specifies a hash
|
||||
# reference to which the new definitions are added. This reference is returned.
|
||||
sub cpumf_parse_ctrdef($;$)
|
||||
{
|
||||
my $ctrdef = shift();
|
||||
my $h = @_ ? shift() : {};
|
||||
my $CTRDEF;
|
||||
|
||||
return undef unless open($CTRDEF, '<', "$CPUMF_DATA_DIR/$ctrdef");
|
||||
my ($ctr, $name);
|
||||
while (my $line = <$CTRDEF>) {
|
||||
next if $line =~ /^#/;
|
||||
chomp($line);
|
||||
|
||||
# Parse start of counter definition entry
|
||||
if ($line =~ m/^Counter:\s*(0x[[:xdigit:]]+|\d+)
|
||||
\s+Name:\s*([[:alnum:]_]+)$/x) {
|
||||
($ctr, $name) = ($1, $2);
|
||||
$ctr = hex($ctr) if $ctr =~ /^0x/;
|
||||
unless (length($ctr)) {
|
||||
print STDERR "Found invalid entry in counter " .
|
||||
"definition: line $.\n";
|
||||
}
|
||||
$h->{$ctr} = { name => $name || "" };
|
||||
}
|
||||
|
||||
# At this point, a counter must be defined
|
||||
next unless defined($ctr);
|
||||
|
||||
# Parse short description (optional)
|
||||
if ($line =~ m/^Short-Description:\s*(\S.*)?$/) {
|
||||
$h->{$ctr}->{shortdesc} = $1 || "";
|
||||
|
||||
# Parse start of counter description
|
||||
} elsif ($line =~ m/^Description:\s*(\S.*)?$/) {
|
||||
$h->{$ctr}->{desc} = $1 || "";
|
||||
|
||||
# Parse end of counter description
|
||||
} elsif ($line =~ m/^\.$/) {
|
||||
# Complete the counter definition
|
||||
$h->{$ctr}->{set} = cpumf_get_counter_set($ctr);
|
||||
# Trim whitespaces
|
||||
$h->{$ctr}->{shortdesc} =~ s/^\s+|\s+$//g if $h->{$ctr}->{shortdesc};
|
||||
$h->{$ctr}->{desc} =~ s/^\s+|\s+$//g if $h->{$ctr}->{desc};
|
||||
# Finally, reset counter for next entry
|
||||
$ctr = undef;
|
||||
|
||||
# Line is part of counter description (if $ctr_num is set)
|
||||
} else {
|
||||
$h->{$ctr}->{desc} .= " $line";
|
||||
}
|
||||
}
|
||||
close($CTRDEF);
|
||||
|
||||
return $h;
|
||||
}
|
||||
|
||||
# IBM System z hardware with CPU-M counter facility support
|
||||
my $system_z_hwtype_map = {
|
||||
# Machine type Description
|
||||
'' => 'Unknown hardware model',
|
||||
2097 => 'IBM System z10 EC',
|
||||
2098 => 'IBM System z10 BC',
|
||||
2817 => 'IBM zEnterprise 196',
|
||||
2818 => 'IBM zEnterprise 114',
|
||||
2827 => 'IBM zEnterprise EC12',
|
||||
2828 => 'IBM zEnterprise BC12',
|
||||
2964 => 'IBM z13',
|
||||
2965 => 'IBM z13s',
|
||||
3906 => 'IBM z14',
|
||||
3907 => 'IBM z14 ZR1',
|
||||
};
|
||||
|
||||
sub get_hardware_type()
|
||||
{
|
||||
my $type = "";
|
||||
my $SYSINFO;
|
||||
|
||||
return undef unless open($SYSINFO, '<', '/proc/sysinfo');
|
||||
while (my $line = <$SYSINFO>) {
|
||||
if ($line =~ m/^Type:\s*(\d+)\s*$/) {
|
||||
$type = $1;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close($SYSINFO);
|
||||
return $type;
|
||||
}
|
||||
|
||||
sub get_cpum_cf_version()
|
||||
{
|
||||
my $SL;
|
||||
|
||||
my $v = {
|
||||
cfvn => 0,
|
||||
csvn => 0,
|
||||
};
|
||||
|
||||
return $v unless open($SL, '<', $SERVICE_LEVELS);
|
||||
while (my $line = <$SL>) {
|
||||
# CPU-MF: Counter facility: version=3.5
|
||||
if ($line =~ m/^CPU-MF: Counter facility: version=(\d+)\.(\d+)/) {
|
||||
$v->{cfvn} = $1; # Counter First Version Number
|
||||
$v->{csvn} = $2; # Counter Second Version Number
|
||||
last;
|
||||
}
|
||||
}
|
||||
close($SL);
|
||||
return $v
|
||||
}
|
||||
|
||||
sub cpumf_load_ctrdef($;$)
|
||||
{
|
||||
my $hw_type = shift();
|
||||
my $authorized = @_ ? shift() : 0xffff; # Counter Set authorization
|
||||
|
||||
my $ctrmap = cpumf_hardware_counter_map();
|
||||
return unless $ctrmap;
|
||||
|
||||
# Obtain CPU-MF counter facility versions
|
||||
my $version = get_cpum_cf_version();
|
||||
|
||||
# List of "generic" counter sets
|
||||
my @def = ();
|
||||
push @def, "cfvn-" . $version->{cfvn};
|
||||
if ($version->{csvn} >= 1 && $version->{csvn} <= 6) {
|
||||
push @def, "csvn-12345";
|
||||
}
|
||||
if ($version->{csvn} == 6) {
|
||||
push @def, "csvn-6";
|
||||
}
|
||||
|
||||
my $h = {};
|
||||
# Load counter set definition
|
||||
foreach my $ent (@def) {
|
||||
cpumf_parse_ctrdef($ctrmap->{$ent}, $h) or
|
||||
croak "Failed to read counter definition for $ent: $!\n";
|
||||
}
|
||||
# Load hardware model specific counter set(s)
|
||||
if ($hw_type && $ctrmap->{$hw_type}) {
|
||||
# Hardware-model specific counter sets are:
|
||||
# - Extended Counter Set
|
||||
# - MT-diagnostic Counter Set
|
||||
cpumf_parse_ctrdef($ctrmap->{$hw_type}, $h) or
|
||||
croak "Failed to read hardware-model counter definition: $!\n";
|
||||
}
|
||||
|
||||
# Remove counter sets that miss authorizations
|
||||
my @no_auth_list = ();
|
||||
foreach my $ctr (sort keys %$h) {
|
||||
push @no_auth_list, $ctr unless $h->{$ctr}->{set} & $authorized;
|
||||
}
|
||||
delete $h->{$_} foreach (@no_auth_list);
|
||||
|
||||
return $h;
|
||||
}
|
||||
|
||||
|
||||
sub cpumf_get_counter_set($)
|
||||
{
|
||||
my $ctr = shift();
|
||||
|
||||
return $BASIC_SET if $ctr < 32;
|
||||
return $PROBLEM_STATE_SET if $ctr < 64;
|
||||
return $CRYPTO_SET if $ctr < 128;
|
||||
#
|
||||
# The extended counter set ranges from
|
||||
# 128 to
|
||||
# 159 for csvn == 1
|
||||
# 175 for csvn == 2
|
||||
# 255 for csvn > 2
|
||||
# Tolerate any future counters up to
|
||||
# the MT-diagnostic counter set.
|
||||
return $EXTENTED_SET if $ctr < 448;
|
||||
#
|
||||
# The MT-diagnostic counter set ranges from
|
||||
# 448 to
|
||||
# 495 for cvsn > 3
|
||||
return $MT_DIAG_SET if $ctr <= 495;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub cpumf_counter_set_names()
|
||||
{
|
||||
return {
|
||||
# Identifier Name
|
||||
$BASIC_SET => 'Basic Counter Set',
|
||||
$PROBLEM_STATE_SET => 'Problem-State Counter Set',
|
||||
$CRYPTO_SET => 'Crypto-Activity Counter Set',
|
||||
$EXTENTED_SET => 'Extended Counter Set',
|
||||
$MT_DIAG_SET => 'MT-diagnostic Counter Set',
|
||||
$COPROC_GRP_SET => 'Coprocessor Group Counter Set',
|
||||
};
|
||||
}
|
||||
|
||||
sub cpumf_counter_set_ids()
|
||||
{
|
||||
return [$BASIC_SET, $PROBLEM_STATE_SET, $CRYPTO_SET, $EXTENTED_SET,
|
||||
$MT_DIAG_SET, $COPROC_GRP_SET];
|
||||
}
|
||||
|
||||
sub cpumf_hardware_counter_map()
|
||||
{
|
||||
my $map = do "$CPUMF_DATA_DIR/cpum-cf-hw-counter.map";
|
||||
croak "Failed to parse mapfile: $@" if $@;
|
||||
croak "Failed to read mapfile: $!" unless defined $map;
|
||||
return $map;
|
||||
}
|
||||
|
||||
|
||||
sub cpumf_helper_main()
|
||||
{
|
||||
# Configuration settings and options
|
||||
my $conf = {
|
||||
};
|
||||
|
||||
# Parse command line option
|
||||
GetOptions(
|
||||
"i|info" => \$conf->{opt_info},
|
||||
"c|counter=i" => \$conf->{opt_ctr},
|
||||
"ctr-def=s" => \$conf->{opt_ctrdef},
|
||||
"hardware-type" => \$conf->{opt_hwtype},
|
||||
"ctr-set-names" => \$conf->{opt_ctrset_names},
|
||||
"ctr-set-ids" => \$conf->{opt_ctrset_ids},
|
||||
"sfb-size" => \$conf->{opt_sfb_size},
|
||||
"ctr-sf" => \$conf->{opt_sf_ctr},
|
||||
) or pod2usage(-message =>"One or more options are not valid",
|
||||
-exitval => 1);
|
||||
|
||||
# Setting up Data::Dumper to create parseable Perl output
|
||||
local $Data::Dumper::Purity = 1;
|
||||
local $Data::Dumper::Sortkeys = 1;
|
||||
local $Data::Dumper::Terse = 1;
|
||||
|
||||
###print STDERR "CONF: " . Dumper($conf) . "\n";
|
||||
|
||||
# Process command line options
|
||||
my $exitval = 0;
|
||||
my $result;
|
||||
if (defined($conf->{opt_info})) {
|
||||
$result = cpumf_collect_data();
|
||||
|
||||
# Display System z hardware type
|
||||
} elsif (defined($conf->{opt_hwtype})) {
|
||||
my $type = get_hardware_type();
|
||||
$result = [$type, $system_z_hwtype_map->{$type} || ""];
|
||||
|
||||
# Display counters for current System z hardware
|
||||
} elsif (defined($conf->{opt_ctr})) {
|
||||
my $type = get_hardware_type();
|
||||
$type = 0 unless $type;
|
||||
$result = cpumf_load_ctrdef($type, $conf->{opt_ctr});
|
||||
|
||||
# Display counters for a particular System z hardware type
|
||||
} elsif (defined($conf->{opt_ctrdef})) {
|
||||
my $m = cpumf_hardware_counter_map();
|
||||
if (exists $m->{$conf->{opt_ctrdef}}) {
|
||||
$result = cpumf_parse_ctrdef($m->{$conf->{opt_ctrdef}});
|
||||
} else {
|
||||
printf STDERR "Invalid counter definition\n";
|
||||
$exitval = 2;
|
||||
}
|
||||
# Display the size of the sampling facility buffer (sfb)
|
||||
} elsif (defined($conf->{opt_sfb_size})) {
|
||||
$result = cpumf_get_sfb_size();
|
||||
|
||||
# Display counter definitions for the sampling facility support (perf)
|
||||
} elsif (defined($conf->{opt_sf_ctr})) {
|
||||
$result = cpumf_parse_ctrdef('cpum-sf-modes.ctr');
|
||||
|
||||
# Display mapping of counter set IDs to counter set names
|
||||
} elsif (defined($conf->{opt_ctrset_names})) {
|
||||
$result = cpumf_counter_set_names();
|
||||
|
||||
# Display counter set IDs
|
||||
} elsif (defined($conf->{opt_ctrset_ids})) {
|
||||
$result = cpumf_counter_set_ids();
|
||||
|
||||
} else {
|
||||
pod2usage(-message => "No option specified",
|
||||
-exitval => 1);
|
||||
}
|
||||
|
||||
# Display result
|
||||
print Dumper($result) if $result;
|
||||
exit $exitval;
|
||||
}
|
||||
|
||||
&cpumf_helper_main();
|
||||
__DATA__
|
||||
__END__
|
||||
=head1 NAME
|
||||
|
||||
B<cpumf_helper> - Helper module for managing CPU-Measurement Facilities (CPU-MF)
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The B<cpumf_helper> program is not intended for ordinary use.
|
||||
|
||||
=head1 OPTIONS
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<-i>, B<--info>
|
||||
|
||||
Displays detailed information about installed and available CPU-measurement
|
||||
facilities and the related Linux support.
|
||||
|
||||
=item B<-c>, B<--counter> I<authorization_value>
|
||||
|
||||
Displays counter information for the current System z hardware. The
|
||||
authorization value provides information about the authorized counter sets. The
|
||||
value must be specified in decimal format.
|
||||
|
||||
To display all supported counters, specify C<65535> (FFFF hex).
|
||||
|
||||
To display supported counters for a particular System z hardware, use the
|
||||
B<--ctr-def> option and specify the System z hardware type.
|
||||
|
||||
=item B<--hardware-type>
|
||||
|
||||
Displays the System z hardware type.
|
||||
|
||||
=item B<--ctr-def> I<ctr-definition>
|
||||
|
||||
Displays detailed information about the specified counter definition.
|
||||
Valid counter definitions start with C<cfvn-> or <csvn-> followed by
|
||||
the counter first/second version number of the CPU-Measurement Counter
|
||||
Facility. To display counter information of model-specific counter
|
||||
sets, specify the System z hardware type for I<ctr-definition>.
|
||||
|
||||
=item B<--ctr-set-names>
|
||||
|
||||
Displays the mapping of counter set IDs to counter set names. The counter set
|
||||
IDs are numbers that are used in counter definitions.
|
||||
|
||||
=item B<--ctr-set-ids>
|
||||
|
||||
Displays the counter set IDs. The counter set IDs are numbers that match the
|
||||
authorization bits (see QUERY COUNTER INFORMATION). The output format is a
|
||||
list. To get the ID for a particular counter set, use an index number as
|
||||
follows:
|
||||
|
||||
=over 16
|
||||
|
||||
=item 0: Basic Counter Set
|
||||
|
||||
=item 1: Problem-State Counter Set
|
||||
|
||||
=item 2: Crypto-Activity Counter Set
|
||||
|
||||
=item 3: Extended Counter Set
|
||||
|
||||
=item 4: MT-diagnostic Counter Set
|
||||
|
||||
=item 5: Coprocessor Group Counter Set
|
||||
|
||||
=back
|
||||
|
||||
=item B<--ctr-sf>
|
||||
|
||||
Displays the counter definitions for the sampling facility support. These
|
||||
counter definitions are specific to Linux perf infrastructure.
|
||||
|
||||
=item B<--sfb-size>
|
||||
|
||||
Displays the size of the sampling facility buffer (SFB). The minimum and
|
||||
maximum numbers are measured in units of sample-data-blocks. A
|
||||
sample-data-block uses about 4 kilobytes.
|
||||
|
||||
=back
|
||||
|
||||
=head1 FILES
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<lscpumf(1)>, L<chcpumf(1)>
|
||||
|
||||
=cut
|
||||
@@ -1,387 +0,0 @@
|
||||
#!/usr/bin/perl -W
|
||||
#
|
||||
# lscpumf - Display information about CPU-measurement facilities
|
||||
#
|
||||
# Copyright IBM Corp. 2014, 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.
|
||||
#
|
||||
use strict;
|
||||
use warnings;
|
||||
use Data::Dumper;
|
||||
use File::Basename qw/fileparse/;
|
||||
use Getopt::Long qw/:config no_ignore_case/;
|
||||
|
||||
# Global constants
|
||||
my $CPUMF_HELPER = '@lib_path@/cpumf_helper';
|
||||
|
||||
# Prototypes
|
||||
sub main();
|
||||
sub show_help();
|
||||
sub show_version();
|
||||
sub do_show_info($);
|
||||
sub do_show_cf($);
|
||||
sub do_show_sf($);
|
||||
sub do_show_ctr($;$);
|
||||
sub do_show_sf_events($);
|
||||
sub invoke_cpumf_helper($);
|
||||
|
||||
|
||||
sub main()
|
||||
{
|
||||
my $config = {
|
||||
# Internal data
|
||||
cpumf => {}, # CPU-MF information hash
|
||||
};
|
||||
|
||||
unless (GetOptions(
|
||||
# General options for help, version,...
|
||||
"h|help" => \&show_help,
|
||||
"v|version" => \&show_version,
|
||||
# Display options
|
||||
"i|info" => \$config->{opt_info},
|
||||
"c|list-counters" => \$config->{opt_ctr},
|
||||
"C|list-all-counters" => \$config->{opt_ctr_all},
|
||||
"s|list-sampling-events" => \$config->{opt_ctr_sf},
|
||||
)) {
|
||||
print STDERR "One or more options are not valid\n";
|
||||
print STDERR "Try '" . fileparse($0) .
|
||||
" --help' for more information\n";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Collect CPU-MF information
|
||||
$config->{cpumf} = invoke_cpumf_helper("-i");
|
||||
die "Failed to collect CPU-MF information: $!\n" unless $config->{cpumf};
|
||||
|
||||
# Process parameters
|
||||
my $exitval = 5;
|
||||
if (defined($config->{opt_info})) {
|
||||
do_show_cf($config);
|
||||
do_show_sf($config);
|
||||
$exitval = 0;
|
||||
|
||||
} elsif (defined($config->{opt_ctr})) {
|
||||
$exitval = do_show_ctr($config);
|
||||
} elsif (defined($config->{opt_ctr_all})) {
|
||||
$exitval = do_show_ctr($config, "all")
|
||||
} elsif (defined($config->{opt_ctr_sf})) {
|
||||
$exitval = do_show_sf_events($config);
|
||||
} else {
|
||||
$exitval = do_show_info($config);
|
||||
}
|
||||
|
||||
exit($exitval);
|
||||
}
|
||||
|
||||
sub show_help()
|
||||
{
|
||||
my $prog = fileparse($0);
|
||||
|
||||
print <<"EoHelp";
|
||||
Usage: lscpumf -h|-v
|
||||
lscpumf [-i]
|
||||
lscpumf -c|-C
|
||||
|
||||
Options:
|
||||
-i Displays detailed information.
|
||||
-c Lists counters for which the LPAR is authorized.
|
||||
-C Lists counters regardless of LPAR authorization.
|
||||
-s Lists perf raw events that activate the sampling facility.
|
||||
-h Displays help information, then exits.
|
||||
-v Displays version information, then exits.
|
||||
|
||||
For more help information, issue 'man $prog'.
|
||||
EoHelp
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub show_version()
|
||||
{
|
||||
print <<'EoVersion';
|
||||
CPU-measurement facility utilities, version @S390_TOOLS_RELEASE@
|
||||
Copyright IBM Corp. 2014, 2017
|
||||
|
||||
EoVersion
|
||||
exit 0;
|
||||
}
|
||||
|
||||
sub do_show_info($)
|
||||
{
|
||||
my $c = shift();
|
||||
my $cpumf = $c->{cpumf};
|
||||
my @f = ();
|
||||
|
||||
push @f, "CPU-measurement Counter Facility" if exists $cpumf->{cf};
|
||||
push @f, "CPU-measurement Sampling Facility" if exists $cpumf->{sf};
|
||||
|
||||
if (@f) {
|
||||
print((join "\n", @f) . "\n");
|
||||
} else {
|
||||
print STDERR "No CPU-measurement facilities detected\n";
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub do_show_cf($)
|
||||
{
|
||||
my $c = shift();
|
||||
|
||||
# Check if counter facility is available
|
||||
unless (exists $c->{cpumf}->{cf}) {
|
||||
print STDERR "No CPU-measurement counter facility detected\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
# Retrieve counter facility information
|
||||
my $cf = $c->{cpumf}->{cf};
|
||||
|
||||
# Create list of authorized counter sets
|
||||
my @sets = ();
|
||||
push @sets, "None" unless $cf->{auth};
|
||||
push @sets, "Crypto-Activity counter set" if $cf->{auth} & 0x8;
|
||||
push @sets, "Problem-State counter set" if $cf->{auth} & 0x4;
|
||||
push @sets, "Basic counter set" if $cf->{auth} & 0x2;
|
||||
push @sets, "Extented counter set" if $cf->{auth} & 0x1;
|
||||
push @sets, "MT-diagnostic counter set" if $cf->{auth} & 0x20;
|
||||
|
||||
print "CPU-measurement counter facility\n";
|
||||
print "-" x 74 . "\n";
|
||||
# TODO Display additional information about available conters depending
|
||||
# on the version information
|
||||
print "Version: " . $cf->{version} . "\n";
|
||||
print "\n";
|
||||
print "Authorized counter sets:\n";
|
||||
print " $_\n" foreach (sort @sets);
|
||||
printf "\nLinux perf event support: %s\n\n",
|
||||
exists $cf->{perf} ? "Yes (PMU: $cf->{perf})" : "No";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub div_ceil($$)
|
||||
{
|
||||
my ($a, $b) = @_;
|
||||
return int(($a + $b - 1) / $b);
|
||||
}
|
||||
|
||||
sub humanize_bytes($;$)
|
||||
{
|
||||
my $bytes = shift();
|
||||
my @units = split //, " KMGTPEZY";
|
||||
|
||||
my $u = @_ ? shift() : 0;
|
||||
while ($bytes >= 1024 && $u <= $#units) {
|
||||
$bytes /= 1024;
|
||||
$u++;
|
||||
}
|
||||
return sprintf "%.f%sB", $bytes, $units[$u];
|
||||
}
|
||||
|
||||
sub get_sfb_details($)
|
||||
{
|
||||
my $n_sdb = shift();
|
||||
|
||||
# Calculate sampling buffer structure
|
||||
my $n_sdbt = div_ceil($n_sdb, 511);
|
||||
my $n_pages = $n_sdb + $n_sdbt;
|
||||
return [
|
||||
$n_sdb, # number of sample-data-blocks
|
||||
$n_sdbt, # number of sample-data-block-tables
|
||||
$n_pages, # number of 4K pages
|
||||
$n_pages * 4096, # size in bytes
|
||||
];
|
||||
}
|
||||
|
||||
sub do_show_sf($)
|
||||
{
|
||||
my $c = shift();
|
||||
|
||||
# Check if sampling facility is available
|
||||
unless (exists $c->{cpumf}->{sf}) {
|
||||
print STDERR "No CPU-measurement sampling facility detected\n";
|
||||
return 2;
|
||||
}
|
||||
my $sf = $c->{cpumf}->{sf};
|
||||
my $size = invoke_cpumf_helper("--sfb-size");
|
||||
|
||||
# Sampling facility information
|
||||
print "CPU-measurement sampling facility\n";
|
||||
print "-" x 74 . "\n";
|
||||
print "Sampling Interval:\n";
|
||||
printf " Minimum: %10u cycles (approx. %8u Hz)\n",
|
||||
$sf->{min_sampl_interval},
|
||||
1000000 * $sf->{cpu_speed} / $sf->{min_sampl_interval};
|
||||
printf " Maximum: %10u cycles (approx. %8u Hz)\n",
|
||||
$sf->{max_sampl_interval},
|
||||
1000000 * $sf->{cpu_speed} / $sf->{max_sampl_interval};
|
||||
print "\n";
|
||||
print "Authorized sampling modes:\n";
|
||||
foreach my $m (sort keys %{$sf->{modes}}) {
|
||||
printf " %-10s (sample size: %3u bytes)\n", $m,
|
||||
$sf->{modes}->{$m}->{sample_size};
|
||||
}
|
||||
print "\n";
|
||||
printf "\nLinux perf event support: %s\n\n",
|
||||
exists $sf->{perf} ? "Yes (PMU: $sf->{perf})" : "No";
|
||||
|
||||
# Sampling buffer settings for cpum_sf
|
||||
goto out unless exists $sf->{perf};
|
||||
|
||||
print "Current sampling buffer settings for $sf->{perf}:\n";
|
||||
printf " Basic-sampling mode\n";
|
||||
my $s = get_sfb_details($size->[0]);
|
||||
printf " Minimum: %6u sample-data-blocks (%6s)\n",
|
||||
$s->[0], humanize_bytes($s->[3]);
|
||||
$s = get_sfb_details($size->[1]);
|
||||
printf " Maximum: %6u sample-data-blocks (%6s)\n",
|
||||
$s->[0], humanize_bytes($s->[3]);
|
||||
unless (exists $sf->{modes}->{diagnostic}) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
# Sampling buffer setting specific to diagnostic-sampling mode
|
||||
my $f_diag = div_ceil($sf->{modes}->{diagnostic}->{sample_size},
|
||||
$sf->{modes}->{basic}->{sample_size});
|
||||
print "\n";
|
||||
printf " Diagnostic-sampling mode (including basic-sampling)\n";
|
||||
$s = get_sfb_details($size->[0] * $f_diag);
|
||||
printf " Minimum: %6u sample-data-blocks (%6s)\n",
|
||||
$s->[0], humanize_bytes($s->[3]);
|
||||
$s = get_sfb_details($size->[1] * $f_diag);
|
||||
printf " Maximum: %6u sample-data-blocks (%6s)\n",
|
||||
$s->[0], humanize_bytes($s->[3]);
|
||||
printf " Size factor: %2u\n", $f_diag;
|
||||
out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub print_counters($$)
|
||||
{
|
||||
my ($ctrdef, $header) = @_;
|
||||
my $set_name_map = invoke_cpumf_helper('--ctr-set-names');
|
||||
my $out = [];
|
||||
|
||||
my ($ctr_perf, $ctr_num, $set, $name, $desc);
|
||||
format PERF_CTR_FORM =
|
||||
r@<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
$ctr_perf, $name
|
||||
|
||||
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
$desc
|
||||
^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ~~
|
||||
$desc
|
||||
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||
$set
|
||||
|
||||
.
|
||||
print $header;
|
||||
$~ = "PERF_CTR_FORM";
|
||||
foreach my $ctr (sort { $a <=> $b } keys %$ctrdef) {
|
||||
$ctr_perf = sprintf "%x", $ctr;
|
||||
$ctr_num = $ctr < (1 << 16) ? $ctr : "";
|
||||
$name = $ctrdef->{$ctr}->{name};
|
||||
$desc = $ctrdef->{$ctr}->{shortdesc} ?
|
||||
$ctrdef->{$ctr}->{shortdesc}
|
||||
: $ctrdef->{$ctr}->{desc};
|
||||
$desc .= ".";
|
||||
$set = $set_name_map->{$ctrdef->{$ctr}->{set}};
|
||||
if ($set) {
|
||||
$set = "Counter $ctr_num / $set.";
|
||||
} else {
|
||||
$set = "This event is not associated with a counter set.";
|
||||
}
|
||||
write;
|
||||
}
|
||||
}
|
||||
|
||||
sub do_show_ctr($;$)
|
||||
{
|
||||
my $c = shift();
|
||||
|
||||
# Check if counter facility is available
|
||||
unless (exists $c->{cpumf}->{cf}) {
|
||||
print STDERR "No CPU-measurement counter facility detected\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
# Retrieve counter authorization ("all" or authorized counters only)
|
||||
my $auth = @_ ? hex("0xFFFF") : $c->{cpumf}->{cf}->{auth};
|
||||
|
||||
# Retrieve counter information
|
||||
my $ctrs = invoke_cpumf_helper("-c $auth");
|
||||
unless ($ctrs) {
|
||||
print STDERR "No counters are available or authorized\n";
|
||||
return 3;
|
||||
}
|
||||
|
||||
# Retrieve hardware type
|
||||
my $hwtype = invoke_cpumf_helper("--hardware-type");
|
||||
my $model = length $hwtype->[1] ? "for $hwtype->[1]" : "";
|
||||
my $header = <<"EoHeader";
|
||||
Perf event counter list $model
|
||||
==============================================================================
|
||||
|
||||
Raw
|
||||
event Name Description
|
||||
------------------------------------------------------------------------------
|
||||
EoHeader
|
||||
print_counters($ctrs, $header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub do_show_sf_events($)
|
||||
{
|
||||
my $c = shift();
|
||||
|
||||
# Check if sampling facility is available
|
||||
unless (exists $c->{cpumf}->{sf}) {
|
||||
print STDERR "No CPU-measurement sampling facility detected\n";
|
||||
return 2;
|
||||
}
|
||||
my $sf = $c->{cpumf}->{sf};
|
||||
my $events = invoke_cpumf_helper("--ctr-sf");
|
||||
|
||||
# Remove events with missing authorization
|
||||
delete $events->{0xB0000} unless exists $sf->{modes}->{basic};
|
||||
delete $events->{0xBD000} unless exists $sf->{modes}->{diagnostic};
|
||||
|
||||
unless ($events) {
|
||||
print STDERR "Sampling facility is not authorized\n";
|
||||
return 3;
|
||||
}
|
||||
|
||||
# Display sampling facility events (aka. counters)
|
||||
my $header = <<"EoHeader";
|
||||
Perf events for activating the sampling facility
|
||||
==============================================================================
|
||||
|
||||
Raw
|
||||
event Name Description
|
||||
------------------------------------------------------------------------------
|
||||
EoHeader
|
||||
print_counters($events, $header);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub invoke_cpumf_helper($)
|
||||
{
|
||||
my $parms = shift();
|
||||
my $result;
|
||||
|
||||
# Call helper module
|
||||
my $output = qx"$CPUMF_HELPER $parms";
|
||||
die "Failed to run helper module for '$parms'\n" if $? >> 8;
|
||||
$result = eval "$output";
|
||||
die "Failed to parse helper module data\n" if $@;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
&main();
|
||||
__DATA__
|
||||
__END__
|
||||
220
cpumf/chcpumf.c
Normal file
220
cpumf/chcpumf.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* chcpumf - Change CPU Measurement Facility Characteristics
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
#include "lib/util_base.h"
|
||||
|
||||
#include "defines.h"
|
||||
|
||||
static int verbose;
|
||||
static unsigned long min_sdb, max_sdb;
|
||||
|
||||
static struct util_opt opt_vec[] = {
|
||||
UTIL_OPT_SECTION("OPTIONS"),
|
||||
{
|
||||
.option = { "min", required_argument, NULL, 'm' },
|
||||
.argument = "num_sdb",
|
||||
.desc = "Specifies the initial size of the sampling buffer.\n"
|
||||
"A sample-data-block (SDB) consumes about 4 kilobytes.",
|
||||
},
|
||||
{
|
||||
.option = { "max", required_argument, NULL, 'x' },
|
||||
.argument = "num_sdb",
|
||||
.desc = "Specifies the maximum size of the sampling buffer.\n"
|
||||
"A sample-data-block (SDB) consumes about 4 kilobytes.",
|
||||
},
|
||||
{
|
||||
.option = { "verbose", no_argument, NULL, 'V' },
|
||||
.desc = "Verbose, display new sample-data-block values.",
|
||||
},
|
||||
UTIL_OPT_HELP,
|
||||
UTIL_OPT_VERSION,
|
||||
UTIL_OPT_END
|
||||
};
|
||||
|
||||
static const struct util_prg prg = {
|
||||
.desc = "Change CPU Measurement facility charactertics",
|
||||
.copyright_vec = {
|
||||
{
|
||||
.owner = "IBM Corp.",
|
||||
.pub_first = 2020,
|
||||
.pub_last = 2020,
|
||||
},
|
||||
UTIL_PRG_COPYRIGHT_END
|
||||
}
|
||||
};
|
||||
|
||||
static long parse_buffersize(char *string)
|
||||
{
|
||||
char *suffix;
|
||||
long bytes;
|
||||
|
||||
bytes = strtol(string, &suffix, 10);
|
||||
if (strlen(suffix) > 1)
|
||||
return -1;
|
||||
switch (*suffix) {
|
||||
case 'k':
|
||||
case 'K':
|
||||
bytes *= 1024;
|
||||
break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
bytes *= 1048576;
|
||||
break;
|
||||
case '\0':
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
static int read_sfb(unsigned long *min, unsigned long *max)
|
||||
{
|
||||
unsigned long cur_min_sdb, cur_max_sdb;
|
||||
int rc = EXIT_SUCCESS;
|
||||
FILE *fp;
|
||||
|
||||
if (geteuid()) {
|
||||
fprintf(stderr, "Error: Must run as root\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fp = fopen(PERF_SFB_SIZE, "r");
|
||||
if (fp == NULL) {
|
||||
linux_error(PERF_SFB_SIZE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
|
||||
fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE
|
||||
"\n");
|
||||
rc = EXIT_FAILURE;
|
||||
} else {
|
||||
if (*min == 0)
|
||||
*min = cur_min_sdb;
|
||||
if (*max == 0)
|
||||
*max = cur_max_sdb;
|
||||
}
|
||||
fclose(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int write_sfb(unsigned long min, unsigned long max)
|
||||
{
|
||||
int rc = EXIT_SUCCESS;
|
||||
char text[64];
|
||||
size_t len;
|
||||
FILE *fp;
|
||||
|
||||
fp = fopen(PERF_SFB_SIZE, "w");
|
||||
if (fp == NULL) {
|
||||
linux_error(PERF_SFB_SIZE);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
snprintf(text, sizeof text, "%ld,%ld", min, max);
|
||||
len = strlen(text) + 1;
|
||||
if (fwrite(text, 1, len, fp) != len) {
|
||||
linux_error(PERF_SFB_SIZE);
|
||||
rc = EXIT_FAILURE;
|
||||
}
|
||||
if (fclose(fp)) {
|
||||
linux_error(PERF_SFB_SIZE);
|
||||
rc = EXIT_FAILURE;
|
||||
}
|
||||
if (verbose && rc != EXIT_FAILURE)
|
||||
fprintf(stderr, "Sampling buffer sizes:\n"
|
||||
" Minimum:%7ld sample-data-blocks\n"
|
||||
" Maximum:%7ld sample-data-blocks\n",
|
||||
min, max);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int parse_args(int argc, char **argv)
|
||||
{
|
||||
int opt, action = 0;
|
||||
long new;
|
||||
|
||||
while ((opt = util_opt_getopt_long(argc, argv)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
util_prg_print_help();
|
||||
util_opt_print_help();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'v':
|
||||
util_prg_print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'x':
|
||||
new = parse_buffersize(optarg);
|
||||
if (new < 1) {
|
||||
fprintf(stderr, "The specified number(s)"
|
||||
" are not valid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
max_sdb = new;
|
||||
action = 1;
|
||||
break;
|
||||
case 'm':
|
||||
new = parse_buffersize(optarg);
|
||||
if (new < 1) {
|
||||
fprintf(stderr, "The specified number(s)"
|
||||
" are not valid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
min_sdb = new;
|
||||
action = 1;
|
||||
break;
|
||||
case 'V':
|
||||
verbose = 1;
|
||||
break;
|
||||
case '?':
|
||||
fprintf(stderr, "One or more options are not valid\n");
|
||||
fprintf(stderr, "Try 'chcpumf --help' for more"
|
||||
" information\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (!action) {
|
||||
fprintf(stderr, "You must specify a valid option\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return action;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int ret = EXIT_FAILURE;
|
||||
struct stat sbuf;
|
||||
|
||||
util_prg_init(&prg);
|
||||
util_opt_init(opt_vec, NULL);
|
||||
|
||||
parse_args(argc, argv);
|
||||
if (stat(PERF_PATH PERF_SF, &sbuf) != 0) {
|
||||
fprintf(stderr,
|
||||
"No CPU-measurement sampling facility detected\n");
|
||||
return ret;
|
||||
}
|
||||
if (read_sfb(&min_sdb, &max_sdb))
|
||||
return ret;
|
||||
if (min_sdb >= max_sdb) {
|
||||
fprintf(stderr, "The specified maximum must be greater "
|
||||
"than the minimum\n");
|
||||
return ret;
|
||||
}
|
||||
return write_sfb(min_sdb, max_sdb);
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
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,40 +0,0 @@
|
||||
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,100 +0,0 @@
|
||||
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
|
||||
by another CPU
|
||||
.
|
||||
@@ -1,33 +0,0 @@
|
||||
Counter: 80 Name:ECC_FUNCTION_COUNT
|
||||
Short-Description:ECC Function Count
|
||||
Description:
|
||||
This counter counts the
|
||||
total number of the elliptic-curve cryptography (ECC)
|
||||
functions issued by the CPU.
|
||||
.
|
||||
Counter: 81 Name:ECC_CYCLES_COUNT
|
||||
Short-Description:ECC Cycles Count
|
||||
Description:
|
||||
This counter counts the total
|
||||
number of CPU cycles when the ECC coprocessor is
|
||||
busy performing the elliptic-curve cryptography
|
||||
(ECC) functions issued by the CPU.
|
||||
.
|
||||
Counter: 82 Name:ECC_BLOCKED_FUNCTION_COUNT
|
||||
Short-Description:Ecc Blocked Function Count
|
||||
Description:
|
||||
This counter
|
||||
counts the total number of the elliptic-curve
|
||||
cryptography (ECC) functions that are issued by the CPU
|
||||
and are blocked because the ECC coprocessor is
|
||||
busy performing a function issued by another CPU.
|
||||
.
|
||||
Counter: 83 Name:ECC_BLOCKED_CYCLES_COUNT
|
||||
Short-Description:ECC Blocked Cycles Count
|
||||
Description:
|
||||
This counter counts
|
||||
the total number of CPU cycles blocked for the elliptic-curve
|
||||
cryptography (ECC) functions issued by the
|
||||
CPU because the ECC coprocessor is busy perform-
|
||||
ing a function issued by another CPU.
|
||||
.
|
||||
@@ -1,114 +0,0 @@
|
||||
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 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
|
||||
.
|
||||
@@ -1,373 +0,0 @@
|
||||
# Counter decriptions for the
|
||||
# IBM z13 extended counter and MT-diagnostic counter set
|
||||
#
|
||||
# Notes for transactional-execution mode symbolic names:
|
||||
# TX .. transactional-execution mode
|
||||
# NC .. nonconstrained
|
||||
# C .. constrained
|
||||
#
|
||||
# Undefined counters in the extended counter set:
|
||||
# 142
|
||||
# 180-217
|
||||
# 221-225
|
||||
# Undefined counters in the MT-diagnostic counter set:
|
||||
# 450-495
|
||||
#
|
||||
#
|
||||
# Extended Counter Set
|
||||
# ---------------------------------------------------------------------
|
||||
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
|
||||
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,357 +0,0 @@
|
||||
# Counter decriptions for the
|
||||
# IBM z14 extended counter and MT-diagnostic counter set
|
||||
#
|
||||
# Notes for transactional-execution mode symbolic names:
|
||||
# TX .. transactional-execution mode
|
||||
# NC .. nonconstrained
|
||||
# C .. constrained
|
||||
#
|
||||
# Undefined counters in the extended counter set:
|
||||
# 142
|
||||
# 158-161
|
||||
# 176-223
|
||||
# 227-231
|
||||
# 233-242
|
||||
# 246-255
|
||||
# Undefined counters in the MT-diagnostic counter set:
|
||||
# 450-495
|
||||
#
|
||||
#
|
||||
# Extended Counter Set
|
||||
# ---------------------------------------------------------------------
|
||||
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
|
||||
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,146 +0,0 @@
|
||||
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,230 +0,0 @@
|
||||
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
|
||||
.
|
||||
#
|
||||
# Notes for the transactional-execution mode notations:
|
||||
# TX .. transactional-execution mode
|
||||
# NC .. nonconstrained
|
||||
# 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
|
||||
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
|
||||
complete
|
||||
.
|
||||
@@ -1,34 +0,0 @@
|
||||
# CPU-measurement facilities
|
||||
#
|
||||
# Mapping of:
|
||||
# 1. CPU-MF counter first/second version numbers to "generic" counter
|
||||
# definitions
|
||||
# 2. IBM z Systems hardware to respective extended counter set definitions
|
||||
#
|
||||
#
|
||||
{
|
||||
# Definition # File name
|
||||
|
||||
# CFVN
|
||||
'cfvn-1' => 'cpum-cf-cfvn-1.ctr',
|
||||
'cfvn-3' => 'cpum-cf-cfvn-3.ctr',
|
||||
|
||||
# CSVN
|
||||
'csvn-12345' => 'cpum-cf-csvn-12345.ctr',
|
||||
'csvn-6' => 'cpum-cf-csvn-6.ctr',
|
||||
|
||||
# Extended counters
|
||||
2097 => 'cpum-cf-extended-z10.ctr',
|
||||
2098 => 'cpum-cf-extended-z10.ctr',
|
||||
2817 => 'cpum-cf-extended-z196.ctr',
|
||||
2818 => 'cpum-cf-extended-z196.ctr',
|
||||
2827 => 'cpum-cf-extended-zEC12.ctr',
|
||||
2828 => 'cpum-cf-extended-zEC12.ctr',
|
||||
2964 => 'cpum-cf-extended-z13.ctr',
|
||||
2965 => 'cpum-cf-extended-z13.ctr',
|
||||
3906 => 'cpum-cf-extended-z14.ctr',
|
||||
3907 => 'cpum-cf-extended-z14.ctr',
|
||||
# Identical with z14
|
||||
8561 => 'cpum-cf-extended-z14.ctr',
|
||||
8562 => 'cpum-cf-extended-z14.ctr',
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
# Perf raw event counter definitions for the
|
||||
# CPU-measurment sampling facility
|
||||
#
|
||||
# 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)
|
||||
.
|
||||
23
cpumf/defines.h
Normal file
23
cpumf/defines.h
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Defines for CPU Measurement Facility Characteristics
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#define PERF_SFB_SIZE "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||
#define PERF_PATH "/sys/bus/event_source/devices/"
|
||||
#define PERF_SF "cpum_sf"
|
||||
#define PERF_CF "cpum_cf"
|
||||
|
||||
static inline void linux_error(const char *message)
|
||||
{
|
||||
fprintf(stderr, "Error: %s: %s\n", message, strerror(errno));
|
||||
}
|
||||
|
||||
#endif
|
||||
3122
cpumf/lscpumf.c
Normal file
3122
cpumf/lscpumf.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,6 +20,7 @@ chcpumf \- manage the CPU-measurement facilities support
|
||||
.IR num_sdb ]
|
||||
.RB [ \-x | \-\-max
|
||||
.IR num_sdb ]
|
||||
.RB [ \-V | \-\-verbose ]
|
||||
.br
|
||||
.B chcpumf
|
||||
.BR \-h | \-\-help
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
\" lscpumf.1
|
||||
.\"
|
||||
.\"
|
||||
.\" Copyright IBM Corp. 2014, 2017
|
||||
.\" Copyright IBM Corp. 2014, 2020
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\" ----------------------------------------------------------------------
|
||||
.TH lscpumf "1" "February 2014" "s390-tools" "CPU-MF management programs"
|
||||
.TH lscpumf "1" "May 2020" "s390-tools" "CPU-MF management programs"
|
||||
.
|
||||
.ds c \fBlscpumf\fP
|
||||
.
|
||||
@@ -19,9 +19,11 @@ lscpumf \- display information about CPU-measurement facilities
|
||||
.RB [ \-i | \-\-info ]
|
||||
.br
|
||||
.B lscpumf
|
||||
.RB [ \-c | \-\-list\-counters ]
|
||||
.RB [ \-C | \-\-list\-all\-counters ]
|
||||
.RB [ \-s | \-\-list\-sampling\-events ]
|
||||
.RB \-c | \-\-list\-counters | \-C | \-\-list\-all\-counters
|
||||
.RB [ \-n ]
|
||||
.br
|
||||
.B lscpumf
|
||||
.RB \-s | \-\-list\-sampling\-events
|
||||
.br
|
||||
.B lscpumf
|
||||
.BR \-h | \-\-help
|
||||
@@ -46,12 +48,25 @@ facilities.
|
||||
Lists counters that are provided by the CPU-measurement facility, omitting
|
||||
counters for which the LPAR is not authorized. For counter measurements with
|
||||
the perf program, the raw event identifier is displayed.
|
||||
For Linux version 5.5 and later, the raw event identifier is
|
||||
displayed as <type>:<number>, where type is an integer that the kernel
|
||||
assignes to the CPU Measurement counter facility device driver.
|
||||
For earlier Linux versions the raw event identifier is displayed as r<number>.
|
||||
.
|
||||
.TP
|
||||
.BR \-C ", " \-\-list\-all\-counters
|
||||
Lists all counters that are provided by the CPU-measurement counter facility,
|
||||
regardless of LPAR authorization. To list only those counters for which the
|
||||
LPAR is authorized, use the -c option.
|
||||
For linux version 5.5 and later the raw event identifier is
|
||||
displayed as <type>:<number>, where type is the number the CPU Measurement
|
||||
counter facility device driver was assigned to by the kernel.
|
||||
For earlier linux versions the raw event identifier is displayed as r<number>.
|
||||
.
|
||||
.TP
|
||||
.BR \-n ", " \-\-name
|
||||
.
|
||||
Display the counter name together with the raw event identifier.
|
||||
.
|
||||
.TP
|
||||
.BR \-s ", " \-\-list\-sampling\-events
|
||||
|
||||
@@ -152,7 +152,6 @@ struct symbol_names {
|
||||
};
|
||||
|
||||
extern int foreground;
|
||||
extern int debug;
|
||||
extern char *configfile;
|
||||
extern int debug; /* is verbose specified? */
|
||||
extern int memory;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,10 @@ static const char mode_str[3][10] = {
|
||||
"Full", "Quick", "Expand"
|
||||
};
|
||||
|
||||
/* Report error, free memory, and exit */
|
||||
static void error(const char *format, ...)
|
||||
__attribute__((__noreturn__, __format__(__printf__, 1, 2)));
|
||||
|
||||
#define DASD_PARTN_BITS 2
|
||||
#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
|
||||
|
||||
@@ -65,47 +69,24 @@ static const char mode_str[3][10] = {
|
||||
"is in invalid format\n",prog_name);}
|
||||
|
||||
typedef struct bootstrap1 {
|
||||
u_int32_t key;
|
||||
u_int32_t data[6];
|
||||
u_int32_t key;
|
||||
u_int32_t data[6];
|
||||
} __attribute__ ((packed)) bootstrap1_t;
|
||||
|
||||
typedef struct bootstrap2 {
|
||||
u_int32_t key;
|
||||
u_int32_t data[36];
|
||||
u_int32_t key;
|
||||
u_int32_t data[36];
|
||||
} __attribute__ ((packed)) bootstrap2_t;
|
||||
|
||||
typedef struct dasdfmt_info {
|
||||
dasd_information2_t dasd_info;
|
||||
int verbosity;
|
||||
int testmode;
|
||||
int withoutprompt;
|
||||
int print_progressbar;
|
||||
int print_hashmarks, hashstep;
|
||||
int print_percentage;
|
||||
int force;
|
||||
int writenolabel;
|
||||
int labelspec;
|
||||
int cdl_format;
|
||||
int blksize_specified;
|
||||
int reqsize_specified;
|
||||
int keep_volser;
|
||||
int force_host;
|
||||
int layout_specified;
|
||||
int check;
|
||||
int mode_specified;
|
||||
int ese;
|
||||
int no_discard;
|
||||
} dasdfmt_info_t;
|
||||
|
||||
|
||||
/*
|
||||
C9D7D3F1 000A0000 0000000F 03000000 00000001 00000000 00000000
|
||||
*/
|
||||
static bootstrap1_t ipl1 = {
|
||||
0xC9D7D3F1, {
|
||||
0x000A0000, 0x0000000F, 0x03000000,
|
||||
0x00000001, 0x00000000, 0x00000000
|
||||
}
|
||||
0xC9D7D3F1, {
|
||||
0x000A0000, 0x0000000F, 0x03000000,
|
||||
0x00000001, 0x00000000, 0x00000000
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -116,21 +97,20 @@ C9D7D3F2 07003AB8 40000006 31003ABE 40000005 08003AA0 00000000 06000000
|
||||
00000000 00000000 00000000 00000000 00000000
|
||||
*/
|
||||
static bootstrap2_t ipl2 = {
|
||||
0xC9D7D3F2, {
|
||||
0x07003AB8, 0x40000006, 0x31003ABE,
|
||||
0x40000005, 0x08003AA0, 0x00000000,
|
||||
0x06000000, 0x20000000, 0x00000000,
|
||||
0x00000000, 0x00000400, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000
|
||||
}
|
||||
0xC9D7D3F2, {
|
||||
0x07003AB8, 0x40000006, 0x31003ABE,
|
||||
0x40000005, 0x08003AA0, 0x00000000,
|
||||
0x06000000, 0x20000000, 0x00000000,
|
||||
0x00000000, 0x00000400, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000,
|
||||
0x00000000, 0x00000000, 0x00000000
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* DASDFMT_H */
|
||||
|
||||
|
||||
@@ -290,7 +290,7 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
||||
mode = S_IFBLK | S_IRWXU;
|
||||
|
||||
/* Try several locations for the temporary device node. */
|
||||
for (path = 0; path < UTIL_ARRAY_SIZE(pathname); path++) {
|
||||
for (path = 0; path < ARRAY_SIZE(pathname); path++) {
|
||||
if (pathname[path] == NULL)
|
||||
continue;
|
||||
for (retry = 0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
|
||||
|
||||
@@ -1,14 +1,39 @@
|
||||
include ../common.mak
|
||||
|
||||
ALL_CPPFLAGS += -DSYSFS
|
||||
|
||||
all: dasdview
|
||||
|
||||
libs = $(rootdir)/libdasd/libdasd.a \
|
||||
$(rootdir)/libzds/libzds.a \
|
||||
$(rootdir)/libvtoc/libvtoc.a \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
|
||||
ifneq (${HAVE_CURL},0)
|
||||
|
||||
check_dep:
|
||||
$(call check_dep, \
|
||||
"dasdview", \
|
||||
"curl/curl.h", \
|
||||
"curl-devel or libcurl-dev", \
|
||||
"HAVE_CURL=0")
|
||||
|
||||
BUILDTARGET = check_dep
|
||||
|
||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||
CURL_CFLAGS = $(shell pkg-config --silence-errors --cflags libcurl)
|
||||
CURL_LDLIBS = $(shell pkg-config --silence-errors --libs libcurl)
|
||||
else
|
||||
CURL_CFLAGS = -I/usr/include/s390x-linux-gnu/curl
|
||||
CURL_LDLIBS = -lcurl
|
||||
endif # shell
|
||||
|
||||
endif # HAVE_CURL
|
||||
|
||||
BUILDTARGET += dasdview
|
||||
|
||||
ALL_CPPFLAGS += -DSYSFS
|
||||
ALL_CFLAGS += $(CURL_CFLAGS)
|
||||
LDLIBS += $(CURL_LDLIBS)
|
||||
|
||||
all: $(BUILDTARGET)
|
||||
|
||||
dasdview: dasdview.o $(libs)
|
||||
|
||||
install: all
|
||||
|
||||
@@ -160,19 +160,19 @@ dasdview_get_info(dasdview_info_t *info)
|
||||
if (err != EBADF)
|
||||
zt_error_print("dasdview: "
|
||||
"Could not retrieve geo information!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (dasd_get_blocksize(info->device, &info->blksize) != 0) {
|
||||
zt_error_print("dasdview: "
|
||||
"Could not retrieve blocksize information!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (dasd_get_info(info->device, &info->dasd_info) != 0) {
|
||||
zt_error_print("dasdview: "
|
||||
"Could not retrieve disk information!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
characteristics = (struct dasd_eckd_characteristics *)
|
||||
@@ -261,7 +261,7 @@ dasdview_parse_input(unsigned long long *p, dasdview_info_t *info, char *s)
|
||||
error:
|
||||
zt_error_print("dasdview: usage error\n"
|
||||
"%s is not a valid begin/size value!", s);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -404,7 +404,7 @@ dasdview_print_extended_info(dasdview_info_t *info)
|
||||
if (dasd_info->features == DASD_FEATURE_DEFAULT) {
|
||||
printf("default\n");
|
||||
} else {
|
||||
for (i = 0; i < UTIL_ARRAY_SIZE(flist); i++)
|
||||
for (i = 0; i < ARRAY_SIZE(flist); i++)
|
||||
if (dasd_info->features & flist[i].mask)
|
||||
printf("%s ", flist[i].name);
|
||||
printf("\n");
|
||||
@@ -454,7 +454,7 @@ dasdview_print_vlabel(dasdview_info_t *info)
|
||||
if (rc) {
|
||||
zt_error_print("error when reading label from device:"
|
||||
" rc=%d\n", rc);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
lzds_dasd_get_vlabel(info->dasd, &tmpvlabel);
|
||||
memcpy(&vlabel, tmpvlabel, sizeof(vlabel));
|
||||
@@ -600,7 +600,7 @@ dasdview_print_volser(dasdview_info_t *info)
|
||||
if (rc) {
|
||||
zt_error_print("error when reading label from device:"
|
||||
" rc=%d\n", rc);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
lzds_dasd_get_vlabel(info->dasd, &tmpvlabel);
|
||||
memcpy(&vlabel, tmpvlabel, sizeof(vlabel));
|
||||
@@ -644,7 +644,7 @@ dasdview_read_vtoc(dasdview_info_t *info)
|
||||
zt_error_print("dasdview: disk layout error\n"
|
||||
"%s is not formatted with the z/OS "
|
||||
"compatible disk layout!\n", info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
vtocblk = (u_int64_t)vtoc_get_cyl_from_cchhb(&vlabel.vtoc) *
|
||||
@@ -664,7 +664,7 @@ dasdview_read_vtoc(dasdview_info_t *info)
|
||||
if ((vtocblk <= 0) || (vtocblk > maxblk)) {
|
||||
zt_error_print("dasdview: VTOC error\n"
|
||||
"Volume label VTOC pointer is not valid!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
vtoc_read_label(info->device, (vtocblk - 1) * info->blksize,
|
||||
@@ -676,7 +676,7 @@ dasdview_read_vtoc(dasdview_info_t *info)
|
||||
/* format4 DSCB is invalid */
|
||||
zt_error_print("dasdview: VTOC error\n"
|
||||
"Format 4 DSCB is invalid!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
info->f4c++;
|
||||
@@ -724,19 +724,19 @@ dasdview_read_vtoc(dasdview_info_t *info)
|
||||
if (info->f4c > 1) {
|
||||
zt_error_print("dasdview: VTOC error\n"
|
||||
"More than one FMT4 DSCB!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (info->f5c > 1) {
|
||||
zt_error_print("dasdview: VTOC error\n"
|
||||
"More than one FMT5 DSCB!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (info->f7c > 1) {
|
||||
zt_error_print("dasdview: VTOC error\n"
|
||||
"More than one FMT7 DSCB!\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -975,7 +975,7 @@ static void dasdview_print_format1_8_short_info_raw(format1_label_t *f1,
|
||||
}
|
||||
if (rc) {
|
||||
zt_error_print("dasdview: Broken format 3 DSCB chain \n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
f3 = (dscb && dscb->fmtid == 0xf3) ? (format3_label_t *)dscb : NULL;
|
||||
|
||||
@@ -990,7 +990,7 @@ static void dasdview_print_format1_8_short_info_raw(format1_label_t *f1,
|
||||
if (f3->DS3FMTID != 0xf3) {
|
||||
zt_error_print("dasdview: Broken format 3 DSCB"
|
||||
" chain \n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (j = 0; j < 4; ++j)
|
||||
dasdview_print_short_info_extent_raw(&f3->DS3EXTNT[j]);
|
||||
@@ -1002,7 +1002,7 @@ static void dasdview_print_format1_8_short_info_raw(format1_label_t *f1,
|
||||
if (rc) {
|
||||
zt_error_print("dasdview: Broken format 3 DSCB"
|
||||
" chain \n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
@@ -1025,7 +1025,7 @@ static void dasdview_print_vtoc_info_raw(dasdview_info_t *info)
|
||||
rc = lzds_raw_vtoc_alloc_dscbiterator(info->rawvtoc, &it);
|
||||
if (rc) {
|
||||
zt_error_print("dasdview: could not allocate DSCB iterator \n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (!lzds_dscbiterator_get_next_dscb(it, &dscb)) {
|
||||
if (dscb->fmtid == 0xf1)
|
||||
@@ -1058,7 +1058,7 @@ static void dasdview_print_vtoc_info_raw(dasdview_info_t *info)
|
||||
rc = lzds_raw_vtoc_alloc_dscbiterator(info->rawvtoc, &it);
|
||||
if (rc) {
|
||||
zt_error_print("dasdview: could not allocate DSCB iterator \n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (!lzds_dscbiterator_get_next_dscb(it, &dscb)) {
|
||||
if (dscb->fmtid == 0xf1 || dscb->fmtid == 0xf8)
|
||||
@@ -1739,23 +1739,23 @@ static void dasdview_print_vtoc_raw(dasdview_info_t *info)
|
||||
if (rc) {
|
||||
zt_error_print("error when reading label from device:"
|
||||
" rc=%d\n", rc);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc = lzds_dasd_alloc_rawvtoc(info->dasd);
|
||||
if (rc == EINVAL) {
|
||||
zt_error_print("dasdview: Cannot read VTOC because disk does"
|
||||
" not contain valid VOL1 label.\n",
|
||||
info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
} else if (rc) {
|
||||
zt_error_print("error when reading vtoc from device:"
|
||||
" rc=%d\n", rc);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc = lzds_dasd_get_rawvtoc(info->dasd, &info->rawvtoc);
|
||||
if (rc || !info->rawvtoc) {
|
||||
zt_error_print("dasdview: libvtoc could not read vtoc\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (info->vtoc_info || info->vtoc_all)
|
||||
@@ -1764,7 +1764,7 @@ static void dasdview_print_vtoc_raw(dasdview_info_t *info)
|
||||
rc = lzds_raw_vtoc_alloc_dscbiterator(info->rawvtoc, &it);
|
||||
if (rc) {
|
||||
zt_error_print("dasdview: could not allocate DSCB iterator\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (!lzds_dscbiterator_get_next_dscb(it, &record))
|
||||
dasdview_print_vtoc_dscb(info, record);
|
||||
@@ -1858,7 +1858,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
|
||||
zt_error_print("dasdview: open error\n"
|
||||
"Unable to open device %s in read-only mode!\n",
|
||||
info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
j = (info->begin / SEEK_STEP);
|
||||
@@ -1877,7 +1877,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
|
||||
zt_error_print("dasdview: seek error\n"
|
||||
"Unable to seek in device %s!\n",
|
||||
info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
b++;
|
||||
a += SEEK_STEP;
|
||||
@@ -1890,7 +1890,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
|
||||
zt_error_print("dasdview: seek error\n"
|
||||
"Unable to seek in device %s!\n",
|
||||
info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1926,7 +1926,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
|
||||
zt_error_print("dasdview: read error\n"
|
||||
"Unable to read from device %s!\n",
|
||||
info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (info->format1)
|
||||
@@ -1945,7 +1945,7 @@ static void dasdview_view_standard(dasdview_info_t *info)
|
||||
zt_error_print("dasdview: read error\n"
|
||||
"Unable to read from device %s!\n",
|
||||
info->device);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (info->format1)
|
||||
@@ -2112,18 +2112,18 @@ static void dasdview_view_raw(dasdview_info_t *info)
|
||||
trackdata = memalign(4096, trckbuffsize * RAWTRACKSIZE);
|
||||
if (!trackdata) {
|
||||
zt_error_print("failed to allocate memory\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc = lzds_dasd_alloc_dasdhandle(info->dasd, &dasdh);
|
||||
if (rc) {
|
||||
zt_error_print("failed to allocate memory\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc = lzds_dasdhandle_open(dasdh);
|
||||
if (rc) {
|
||||
lzds_dasdhandle_free(dasdh);
|
||||
zt_error_print("failed to open device\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* residual is the number of tracks we still have to read */
|
||||
residual = tracks_to_read;
|
||||
@@ -2135,7 +2135,7 @@ static void dasdview_view_raw(dasdview_info_t *info)
|
||||
trckend, trackdata);
|
||||
if (rc) {
|
||||
perror("Error on read");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
data = trackdata;
|
||||
for (i = 0; i < trckcount; ++i) {
|
||||
@@ -2153,7 +2153,7 @@ static void dasdview_view_raw(dasdview_info_t *info)
|
||||
lzds_dasdhandle_free(dasdh);
|
||||
if (rc < 0) {
|
||||
perror("Error on closing file");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2253,7 +2253,7 @@ int main(int argc, char *argv[])
|
||||
zt_error_print("dasdview: usage error\n"
|
||||
"%s is no valid argument for"
|
||||
" option -t/--vtoc\n", optarg);
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
info.vtoc = 1;
|
||||
info.action_specified = 1;
|
||||
@@ -2301,13 +2301,13 @@ int main(int argc, char *argv[])
|
||||
rc = lzds_zdsroot_alloc(&info.zdsroot);
|
||||
if (rc) {
|
||||
zt_error_print("Could not allocate index\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
rc = lzds_zdsroot_add_device(info.zdsroot, info.device,
|
||||
&info.dasd);
|
||||
if (rc) {
|
||||
zt_error_print("Could not add device to index\n");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2328,7 +2328,7 @@ int main(int argc, char *argv[])
|
||||
if (info.begin > max) {
|
||||
zt_error_print("dasdview: usage error\n"
|
||||
"'begin' value is not within disk range!");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (info.size_specified)
|
||||
@@ -2343,7 +2343,7 @@ int main(int argc, char *argv[])
|
||||
zt_error_print("dasdview: usage error\n"
|
||||
"'begin' + 'size' is not within "
|
||||
"disk range!");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if ((info.begin_specified || info.size_specified) &&
|
||||
@@ -2355,7 +2355,7 @@ int main(int argc, char *argv[])
|
||||
zt_error_print("dasdview: usage error\n"
|
||||
"Options -1 or -2 make only sense with "
|
||||
"options -b or -s!");
|
||||
exit(-1);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* do the output */
|
||||
|
||||
@@ -225,7 +225,7 @@ function CheckDeviceString() {
|
||||
fi
|
||||
}
|
||||
|
||||
setup_device()
|
||||
setup_ccw_device()
|
||||
{
|
||||
DEV="$(CheckDeviceString $DEVICE)"
|
||||
if [ "$DEV" != "" ]; then
|
||||
@@ -235,27 +235,37 @@ setup_device()
|
||||
pr_error "ERROR: Invalid DEVICE '$DEVICE'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
if [ $2 == "fcp" ]; then
|
||||
echo $WWPN > $1/fcp/wwpn 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid WWPN '$WWPN'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $LUN > $1/fcp/lun 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid LUN '$LUN'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $BOOTPROG > $1/fcp/bootprog 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid BOOTPROG '$BOOTPROG'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $BR_LBA > $1/fcp/br_lba 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
setup_fcp_device()
|
||||
{
|
||||
DEV="$(CheckDeviceString $DEVICE)"
|
||||
if [ "$DEV" != "" ]; then
|
||||
echo $DEV > $1/$2/device
|
||||
else
|
||||
RETVAL=1
|
||||
pr_error "ERROR: Invalid DEVICE '$DEVICE'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $WWPN > $1/fcp/wwpn 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid WWPN '$WWPN'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $LUN > $1/fcp/lun 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid LUN '$LUN'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $BOOTPROG > $1/fcp/bootprog 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid BOOTPROG '$BOOTPROG'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $BR_LBA > $1/fcp/br_lba 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -264,6 +274,30 @@ setup_nss_device()
|
||||
echo $NSS_NAME > $1/nss/name || RETVAL=1
|
||||
}
|
||||
|
||||
setup_nvme_device()
|
||||
{
|
||||
echo $FID > $1/nvme/fid 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid FID '$FID'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $NSID > $1/nvme/nsid 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid NSID '$NSID'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $BOOTPROG > $1/nvme/bootprog 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid BOOTPROG '$BOOTPROG'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
echo $BR_LBA > $1/nvme/br_lba 2>/dev/null || RETVAL=1
|
||||
if [ $RETVAL -eq 1 ]; then
|
||||
pr_error "ERROR: Invalid BR_LBA '$BR_LBA'." $ERRMSG
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
setup_reipl()
|
||||
{
|
||||
if [ "$REIPL_TYPE" == "" ]; then
|
||||
@@ -271,15 +305,25 @@ setup_reipl()
|
||||
return
|
||||
fi
|
||||
|
||||
if [ "$REIPL_TYPE" == "ccw" ] || [ "$REIPL_TYPE" == "fcp" ]; then
|
||||
setup_device $REIPL_CONFIG_DIR $REIPL_TYPE
|
||||
elif [ "$REIPL_TYPE" == "nss" ]; then
|
||||
setup_nss_device $REIPL_CONFIG_DIR
|
||||
else
|
||||
pr_error "ERROR: Unknown reipl type '$REIPL_TYPE'." $ERRMSG
|
||||
RETVAL=1
|
||||
return
|
||||
fi
|
||||
case "$REIPL_TYPE" in
|
||||
ccw)
|
||||
setup_ccw_device $REIPL_CONFIG_DIR $REIPL_TYPE
|
||||
;;
|
||||
fcp)
|
||||
setup_fcp_device $REIPL_CONFIG_DIR $REIPL_TYPE
|
||||
;;
|
||||
nvme)
|
||||
setup_nvme_device $REIPL_CONFIG_DIR
|
||||
;;
|
||||
nss)
|
||||
setup_nss_device $REIPL_CONFIG_DIR
|
||||
;;
|
||||
*)
|
||||
pr_error "ERROR: Unknown reipl type '$REIPL_TYPE'." $ERRMSG
|
||||
RETVAL=1
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
echo $REIPL_TYPE > $REIPL_CONFIG_DIR/reipl_type || RETVAL=1
|
||||
|
||||
@@ -292,13 +336,24 @@ setup_reipl()
|
||||
|
||||
setup_dump()
|
||||
{
|
||||
if [ "$DUMP_TYPE" == "ccw" ] || [ "$DUMP_TYPE" == "fcp" ]; then
|
||||
setup_device $DUMP_CONFIG_DIR $DUMP_TYPE
|
||||
elif [ "$DUMP_TYPE" != "none" ]; then
|
||||
pr_error "ERROR: Unknown dump type '$DUMP_TYPE'." $ERRMSG
|
||||
RETVAL=1
|
||||
return
|
||||
fi
|
||||
case "$DUMP_TYPE" in
|
||||
ccw)
|
||||
setup_ccw_device $DUMP_CONFIG_DIR $DUMP_TYPE
|
||||
;;
|
||||
fcp)
|
||||
setup_fcp_device $DUMP_CONFIG_DIR $DUMP_TYPE
|
||||
;;
|
||||
nvme)
|
||||
setup_nvme_device $DUMP_CONFIG_DIR
|
||||
;;
|
||||
none)
|
||||
;;
|
||||
*)
|
||||
pr_error "ERROR: Unknown dump type '$DUMP_TYPE'." $ERRMSG
|
||||
RETVAL=1
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
echo $DUMP_TYPE > $DUMP_CONFIG_DIR/dump_type || RETVAL=1
|
||||
|
||||
@@ -358,6 +413,18 @@ print_ccw_device()
|
||||
pr_info "device..: $DEVICE"
|
||||
}
|
||||
|
||||
print_nvme_device()
|
||||
{
|
||||
FID=$(cat $1/nvme/fid) || RETVAL=1
|
||||
pr_info "fid.....: $FID"
|
||||
NSID=$(cat $1/nvme/nsid) || RETVAL=1
|
||||
pr_info "nsid....: $NSID"
|
||||
BOOTPROG=$(cat $1/nvme/bootprog) || RETVAL=1
|
||||
pr_info "bootprog: $BOOTPROG"
|
||||
BR_LBA=$(cat $1/nvme/br_lba) || RETVAL=1
|
||||
pr_info "br_lba..: $BR_LBA"
|
||||
}
|
||||
|
||||
print_nss_name()
|
||||
{
|
||||
NAME=$(cat $1/nss/device) || RETVAL=1
|
||||
@@ -367,35 +434,52 @@ print_nss_name()
|
||||
status_dump()
|
||||
{
|
||||
CONF_DUMP_TYPE=$(cat $DUMP_CONFIG_DIR/dump_type) || RETVAL=1
|
||||
if [ "$CONF_DUMP_TYPE" == "none" ]; then
|
||||
pr_info "type....: no dump device configured"
|
||||
elif [ "$CONF_DUMP_TYPE" == "ccw" ]; then
|
||||
pr_info "type....: ccw"
|
||||
print_ccw_device $DUMP_CONFIG_DIR
|
||||
verify_ccw_dump_device $(cat $DUMP_CONFIG_DIR/ccw/device)
|
||||
elif [ "$CONF_DUMP_TYPE" == "fcp" ]; then
|
||||
pr_info "type....: fcp"
|
||||
print_fcp_device $DUMP_CONFIG_DIR
|
||||
else
|
||||
pr_error "ERROR: Unknown dump device type '$CONF_DUMP_TYPE'!"
|
||||
pr_error " Please check if you have the latest dumpconf package!"
|
||||
fi
|
||||
case "$CONF_DUMP_TYPE" in
|
||||
none)
|
||||
pr_info "type....: no dump device configured"
|
||||
;;
|
||||
ccw)
|
||||
pr_info "type....: ccw"
|
||||
print_ccw_device $DUMP_CONFIG_DIR
|
||||
verify_ccw_dump_device $(cat $DUMP_CONFIG_DIR/ccw/device)
|
||||
;;
|
||||
fcp)
|
||||
pr_info "type....: fcp"
|
||||
print_fcp_device $DUMP_CONFIG_DIR
|
||||
;;
|
||||
nvme)
|
||||
pr_info "type....: nvme"
|
||||
print_nvme_device $DUMP_CONFIG_DIR
|
||||
;;
|
||||
*)
|
||||
pr_error "ERROR: Unknown dump device type '$CONF_DUMP_TYPE'!"
|
||||
pr_error " Please check if you have the latest dumpconf package!"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
status_reipl()
|
||||
{
|
||||
REIPL_TYPE=$(cat $REIPL_CONFIG_DIR/reipl_type) || RETVAL=1
|
||||
pr_info "type....: $REIPL_TYPE"
|
||||
if [ "$REIPL_TYPE" == "ccw" ]; then
|
||||
print_ccw_device $REIPL_CONFIG_DIR
|
||||
elif [ "$REIPL_TYPE" == "fcp" ]; then
|
||||
print_fcp_device $REIPL_CONFIG_DIR
|
||||
elif [ "$REIPL_TYPE" == "nss" ]; then
|
||||
print_nss_name $REIPL_CONFIG_DIR
|
||||
else
|
||||
pr_error "ERROR: Unknown reipl device type '$REIPL_TYPE'!"
|
||||
pr_error " Please check if you have the latest dumpconf package!"
|
||||
fi
|
||||
case "$REIPL_TYPE" in
|
||||
ccw)
|
||||
print_ccw_device $REIPL_CONFIG_DIR
|
||||
;;
|
||||
fcp)
|
||||
print_fcp_device $REIPL_CONFIG_DIR
|
||||
;;
|
||||
nvme)
|
||||
print_nvme_device $REIPL_CONFIG_DIR
|
||||
;;
|
||||
nss)
|
||||
print_nss_name $REIPL_CONFIG_DIR
|
||||
;;
|
||||
*)
|
||||
pr_error "ERROR: Unknown reipl device type '$REIPL_TYPE'!"
|
||||
pr_error " Please check if you have the latest dumpconf package!"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
status_dump_reipl()
|
||||
|
||||
@@ -31,7 +31,7 @@ if [ -f $CONFIG_FILE ]; then
|
||||
. $CONFIG_FILE
|
||||
fi
|
||||
|
||||
UDEVSETTLE=/sbin/udevadm
|
||||
UDEVSETTLE=/usr/bin/udevadm
|
||||
if [ ! -e $UDEVSETTLE ]
|
||||
then
|
||||
UDEVSETTLE=/sbin/udevsettle
|
||||
|
||||
@@ -39,6 +39,16 @@
|
||||
# BOOTPROG=0
|
||||
# BR_LBA=0
|
||||
|
||||
#
|
||||
# Dump on nvme device (NVMe Disk)
|
||||
#
|
||||
# ON_PANIC=dump
|
||||
# DUMP_TYPE=nvme
|
||||
# FID=0x00000300
|
||||
# NSID=0x00000001
|
||||
# BOOTPROG=3
|
||||
# BR_LBA=0
|
||||
|
||||
#
|
||||
# Use VMDUMP
|
||||
#
|
||||
|
||||
@@ -75,7 +75,7 @@ static int get_part_name_by_dsname(char *dsname, char **name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < UTIL_ARRAY_SIZE(partition_types); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(partition_types); i++) {
|
||||
if (strstr(dsname, partition_types[i].dsname) != NULL) {
|
||||
*name = partition_types[i].name;
|
||||
return 0;
|
||||
@@ -97,7 +97,7 @@ static int get_part_type_by_dsname(char *dsname, int *type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < UTIL_ARRAY_SIZE(partition_types); i++) {
|
||||
for (i = 0; i < ARRAY_SIZE(partition_types); i++) {
|
||||
if (strstr(dsname, partition_types[i].dsname) != NULL) {
|
||||
*type = partition_types[i].type;
|
||||
return 0;
|
||||
@@ -112,7 +112,7 @@ static int get_part_type_by_dsname(char *dsname, int *type)
|
||||
*/
|
||||
static int get_part_dsname_by_type(unsigned int type, char **dsname)
|
||||
{
|
||||
if (type > UTIL_ARRAY_SIZE(partition_types))
|
||||
if (type > ARRAY_SIZE(partition_types))
|
||||
return 1;
|
||||
|
||||
if (type == 0)
|
||||
@@ -1205,7 +1205,7 @@ static void fdasd_list_known_partitions(void)
|
||||
unsigned int i;
|
||||
|
||||
for (i = VALID_PARTITION_OFFSET;
|
||||
i < UTIL_ARRAY_SIZE(partition_types); i++) {
|
||||
i < ARRAY_SIZE(partition_types); i++) {
|
||||
printf("%3d %s\n",
|
||||
partition_types[i].type, partition_types[i].name);
|
||||
}
|
||||
@@ -1232,7 +1232,7 @@ static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
|
||||
if (!anc->silent)
|
||||
printf("rereading partition table...\n");
|
||||
|
||||
if (dasd_reread_partition_table(options.device, 1) != 0) {
|
||||
if (dasd_reread_partition_table(options.device, 5) != 0) {
|
||||
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
|
||||
"partition table.\nPlease reboot!");
|
||||
}
|
||||
@@ -1622,7 +1622,7 @@ static void fdasd_change_part_type(fdasd_anchor_t *anc)
|
||||
|
||||
part_type = 0;
|
||||
while (part_type < 1 ||
|
||||
part_type > UTIL_ARRAY_SIZE(partition_types) - 1) {
|
||||
part_type > ARRAY_SIZE(partition_types) - 1) {
|
||||
do {
|
||||
part_type = read_char("new partition type: ");
|
||||
} while (!isdigit(part_type));
|
||||
|
||||
5
genprotimg/.gitignore
vendored
Normal file
5
genprotimg/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
tags
|
||||
compile_commands.json
|
||||
src/.check-dep-genprotimg
|
||||
src/.detect-openssl.dep.c
|
||||
src/genprotimg
|
||||
27
genprotimg/Makefile
Normal file
27
genprotimg/Makefile
Normal file
@@ -0,0 +1,27 @@
|
||||
# Common definitions
|
||||
include ../common.mak
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
|
||||
TESTS :=
|
||||
SUBDIRS := boot src man
|
||||
RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
|
||||
|
||||
all: all-recursive
|
||||
|
||||
install: all install-recursive
|
||||
$(INSTALL) -d -m 755 "$(PKGDATADIR)"
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 boot/stage3a.bin "$(PKGDATADIR)"
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 boot/stage3b_reloc.bin "$(PKGDATADIR)"
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(PKGDATADIR)"
|
||||
|
||||
clean: clean-recursive
|
||||
|
||||
$(RECURSIVE_TARGETS):
|
||||
@target=`echo $@ |sed s/-recursive//`; \
|
||||
for d in $(SUBDIRS); do \
|
||||
$(MAKE) -C $$d $$target || exit 1; \
|
||||
done
|
||||
|
||||
.PHONY: all install clean $(RECURSIVE_TARGETS)
|
||||
85
genprotimg/README.md
Normal file
85
genprotimg/README.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# genprotimg
|
||||
|
||||
`genprotimg` takes a kernel, key files, optionally an initrd image,
|
||||
optionally a file containing the kernel command line parameters, and
|
||||
generates a single, bootable image file. The generated image file
|
||||
consists of a concatenation of a plain text boot loader, the encrypted
|
||||
components for kernel, initrd, kernel command line, and the
|
||||
integrity-protected PV header, containing the metadata necessary for
|
||||
running the guest in protected mode. See [Memory Layout](#memory-layout)
|
||||
for details about the internal structure of the created image.
|
||||
|
||||
It is possible to use the generated image as a kernel for zipl or for
|
||||
a direct kernel boot using QEMU.
|
||||
|
||||
## Getting started
|
||||
|
||||
If all dependencies are met a simple `make` call in the source tree
|
||||
should be enough for building `genprotimg`.
|
||||
|
||||
## Details
|
||||
|
||||
The main idea of `genprotimg` is:
|
||||
|
||||
1. read in all keys, IVs, and other information needed for the
|
||||
encryption of the components and the generation of the PV header
|
||||
2. add stub stage3a (so we can calculate the memory addresses)
|
||||
3. add components: prepare the components (alignment and encryption)
|
||||
and add them to the memory layout
|
||||
4. build and add stage3b: generate the stage3b and add it to the memory layout
|
||||
5. generate the PV header: generate the hashes (pld, ald, and tld) of
|
||||
the components and create the PV header and IPIB
|
||||
6. parameterize the stub stage3a: uses the IPIB and PV header
|
||||
7. write the final image to the specified output path
|
||||
|
||||
### Boot Loader
|
||||
|
||||
The boot loader consists of two parts:
|
||||
|
||||
1. stage3a boot loader (cleartext), this loader is responsible for the
|
||||
transition into the protected mode by doing diag308 subcode 8 and
|
||||
10 calls.
|
||||
2. stage3b boot loader (encrypted), this loader is very similar to the
|
||||
normal zipl stage3 boot loader. It will be loaded by the Ultravisor
|
||||
after the successful transition into protected mode. Like the zipl
|
||||
stage3 boot loader it moves the kernel and patches in the values
|
||||
for initrd and parmline.
|
||||
|
||||
The loaders have the following constraints:
|
||||
|
||||
1. It must be possible to place stage3a and stage3b at a location
|
||||
greater than 0x10000 because the zipl stage3 loader zeroes out
|
||||
everything at addresses lower than 0x10000 of the image.
|
||||
2. As the stage3 loader of zipl assumes that the passed kernel image
|
||||
looks like a normal kernel image, the zipl stage3 loader modifies the
|
||||
content at the memory area 0x10400 - 0x10800, therefore we leave this
|
||||
area unused in our stage3a loader.
|
||||
3. The default entry address used by the zipl stage3 loader is 0x10000
|
||||
so we add a simple branch to 0x11000 at 0x10000 so the zipl stage3
|
||||
loader can modify the area 0x10400 - 0x10800 without affecting the
|
||||
stage3a loader.
|
||||
|
||||
#### Detail about stage3b
|
||||
|
||||
The stage3b.bin is linked at address 0x9000, therefore it will not
|
||||
work at another address. The relocation support for the stage3b
|
||||
loader, so that it can be placed at addresses != 0x9000, is added in
|
||||
the loader with the name stage3b_reloc.bin. By default, if we're
|
||||
talking about stage3b we refer to stage3b_reloc.bin.
|
||||
|
||||
### Memory Layout
|
||||
|
||||
The memory layout of the bootable file looks like:
|
||||
|
||||
| Start | End | Use |
|
||||
|------------------------|------------|-----------------------------------------------------------------------|
|
||||
| 0 | 0x7 | Short PSW, starting instruction at 0x11000 |
|
||||
| 0x10000 | 0x10012 | Branch to 0x11000 |
|
||||
| 0x10013 | 0x10fff | Left intentionally unused |
|
||||
| 0x11000 | 0x12fff | Stage3a |
|
||||
| 0x13000 | 0x13fff | IPIB used as argument for the diag308 call |
|
||||
| 0x14000 | 0x1[45]fff | UV header used for the diag308 call (size can be either 1 or 2 pages) |
|
||||
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted kernel |
|
||||
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted kernel parameters |
|
||||
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted initrd |
|
||||
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted stage3b_reloc |
|
||||
4
genprotimg/boot/.gitignore
vendored
Normal file
4
genprotimg/boot/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.elf
|
||||
*.lds
|
||||
*.bin
|
||||
*.d
|
||||
97
genprotimg/boot/Makefile
Normal file
97
genprotimg/boot/Makefile
Normal file
@@ -0,0 +1,97 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
ZIPL_DIR := $(rootdir)/zipl
|
||||
ZIPL_BOOT_DIR := $(ZIPL_DIR)/boot
|
||||
|
||||
INCLUDE_PATHS := $(ZIPL_BOOT_DIR) $(ZIPL_DIR)/include $(rootdir)/include
|
||||
INCLUDE_PARMS := $(addprefix -I,$(INCLUDE_PATHS))
|
||||
|
||||
ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \
|
||||
$(INCLUDE_PARMS) \
|
||||
-DENABLE_SCLP_ASCII=1 \
|
||||
-DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
|
||||
-fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
|
||||
-fno-delete-null-pointer-checks -fno-stack-protector \
|
||||
-fexec-charset=IBM1047 -m64 -mpacked-stack \
|
||||
-mstack-size=4096 -mstack-guard=128 -msoft-float \
|
||||
-Wall -Wformat-security -Wextra -Werror
|
||||
|
||||
FILES := stage3a.bin stage3b.bin stage3b_reloc.bin
|
||||
|
||||
ZIPL_SRCS_C := libc.c ebcdic.c ebcdic_conv.c sclp.c
|
||||
ZIPL_SRCS_ASM := entry.S
|
||||
|
||||
ZIPL_OBJS_C := $(ZIPL_SRCS_C:%.c=%.o)
|
||||
ZIPL_OBJS_ASM := $(ZIPL_SRCS_ASM:%.S=%.o)
|
||||
ZIPL_OBJS := $(ZIPL_OBJS_C) $(ZIPL_OBJS_ASM)
|
||||
|
||||
|
||||
all: $(FILES)
|
||||
|
||||
# Prevent make from using some default rules...
|
||||
%: %.S
|
||||
|
||||
%.o: %.S Makefile
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.c Makefile
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
|
||||
# Dependencies for the .lds generation
|
||||
sources_lds_S = $(wildcard *.lds.S)
|
||||
dependencies_lds_S = $(sources_lds_S:%.lds.S=.%.lds.d)
|
||||
# Include all ".lds.d" dependency files for all make targets except for "clean"
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(dependencies_lds_S)
|
||||
endif
|
||||
|
||||
%.lds: %.lds.S Makefile
|
||||
$(CPP) -Wp,-MD,.$@.d,-MT,$@ $(INCLUDE_PARMS) -P -C -o $@ $<
|
||||
|
||||
# Special rules for zipl object files
|
||||
$(ZIPL_OBJS_C): %.o : $(ZIPL_BOOT_DIR)/%.c
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
$(ZIPL_OBJS_ASM): %.o : $(ZIPL_BOOT_DIR)/%.S
|
||||
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||
|
||||
dependencies_zipl_c := $(ZIPL_SRCS_C:%.c=.%.o.d)
|
||||
|
||||
$(dependencies_zipl_c): .%.o.d : $(ZIPL_BOOT_DIR)/%.c
|
||||
$(CC_SILENT) -MM $(ALL_CPPFLAGS) $(ALL_CFLAGS) $< > $@
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(dependencies_zipl_c)
|
||||
endif
|
||||
|
||||
stage3b_reloc.o: stage3b.bin
|
||||
|
||||
stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS)
|
||||
stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS)
|
||||
stage3b_reloc.elf:
|
||||
|
||||
%.elf: %.o
|
||||
case $* in \
|
||||
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
||||
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
||||
stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
||||
esac; \
|
||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||
@chmod a-x $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -O binary \
|
||||
--only-section=.text* \
|
||||
--only-section=.ex_table* \
|
||||
--only-section=.fixup* \
|
||||
--only-section=.data* \
|
||||
--only-section=.rodata* \
|
||||
$< $@
|
||||
@chmod a-x $@
|
||||
|
||||
clean:
|
||||
rm -f *.o *.elf *.bin *.map .*.d *.lds
|
||||
|
||||
.PHONY: all clean
|
||||
25
genprotimg/boot/common_memory_layout.h
Normal file
25
genprotimg/boot/common_memory_layout.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Common memory layout for stage3a and stage3b bootloader.
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_MEMORY_LAYOUT_H
|
||||
#define COMMON_MEMORY_LAYOUT_H
|
||||
|
||||
#include "boot/loaders_layout.h"
|
||||
|
||||
#define STACK_ADDRESS STAGE3_STACK_ADDRESS
|
||||
#define STACK_SIZE STAGE3_STACK_SIZE
|
||||
|
||||
#define HEAP_ADDRESS STAGE3_HEAP_ADDRESS
|
||||
#define HEAP_SIZE STAGE3_HEAP_SIZE
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* COMMON_MEMORY_LAYOUT_H */
|
||||
31
genprotimg/boot/head.S
Normal file
31
genprotimg/boot/head.S
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Entry code for stage 3a and stage 3b boot loader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
|
||||
#include "common_memory_layout.h"
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "boot/sigp.h"
|
||||
|
||||
.section .text.start
|
||||
.globl _start
|
||||
_start:
|
||||
/* Might be called after a diag308 so better set
|
||||
* architecture and addressing mode
|
||||
*/
|
||||
lhi %r1, 1
|
||||
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
sam64
|
||||
|
||||
/* Initialize stack */
|
||||
basr %r13, 0
|
||||
.Lbase: llgf %r15, .Lstack - .Lbase(%r13)
|
||||
brasl %r14, initialize
|
||||
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||
.previous
|
||||
62
genprotimg/boot/stage3a.c
Normal file
62
genprotimg/boot/stage3a.c
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Main program for stage3a bootloader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "libc.h"
|
||||
#include "stage3a.h"
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "boot/s390.h"
|
||||
#include "boot/ipl.h"
|
||||
#include "sclp.h"
|
||||
#include "error.h"
|
||||
|
||||
|
||||
static volatile struct stage3a_args __section(".loader_parms") loader_parms;
|
||||
|
||||
void __noreturn start(void)
|
||||
{
|
||||
int rc;
|
||||
volatile struct stage3a_args *args = &loader_parms;
|
||||
/* calculate the IPIB memory address */
|
||||
struct ipl_parameter_block *ipib = (void *)((uint64_t)args + args->ipib_offs);
|
||||
|
||||
/* Calculate the PV header memory address and set it and its
|
||||
* size in the IPIB. This allows the PV header to be position
|
||||
* independent.
|
||||
*/
|
||||
ipib->pv.pv_hdr_addr = (uint64_t)args + args->hdr_offs;
|
||||
ipib->pv.pv_hdr_size = args->hdr_size;
|
||||
|
||||
/* set up ASCII and line-mode */
|
||||
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||
|
||||
/* test if Secure Execution Unpack facility is available */
|
||||
stfle(S390_lowcore.stfle_fac_list,
|
||||
ARRAY_SIZE(S390_lowcore.stfle_fac_list));
|
||||
rc = test_facility(UNPACK_FACILITY);
|
||||
if (rc == 0)
|
||||
panic(ENOPV, "Secure unpack facility is not available\n");
|
||||
|
||||
rc = diag308(DIAG308_SET_PV, ipib);
|
||||
if (rc != DIAG308_RC_OK)
|
||||
panic(EPV, "Protected boot setup has failed: 0x%x\n", rc);
|
||||
|
||||
rc = diag308(DIAG308_UNPACK_PV, 0x0);
|
||||
if (rc != DIAG308_RC_OK) {
|
||||
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||
panic(EPV, "Protected boot has failed: 0x%x\n", rc);
|
||||
}
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void panic_notify(unsigned long UNUSED(rc))
|
||||
{
|
||||
}
|
||||
34
genprotimg/boot/stage3a.h
Normal file
34
genprotimg/boot/stage3a.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Main program for stage3a bootloader.
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef STAGE3A_H
|
||||
#define STAGE3A_H
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "boot/loaders_layout.h"
|
||||
|
||||
#define STAGE3A_INIT_ENTRY IMAGE_ENTRY
|
||||
#define STAGE3A_ENTRY (STAGE3A_INIT_ENTRY + _AC(0x1000, UL))
|
||||
#define STAGE3A_LOAD_ADDRESS IMAGE_LOAD_ADDRESS
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* Must not have any padding */
|
||||
struct stage3a_args {
|
||||
uint64_t hdr_offs;
|
||||
uint64_t hdr_size;
|
||||
uint64_t ipib_offs;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct stage3a_args) == 3 * 8)
|
||||
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* STAGE3A_H */
|
||||
103
genprotimg/boot/stage3a.lds.S
Normal file
103
genprotimg/boot/stage3a.lds.S
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Memory layout for stage 3a
|
||||
* ==========================
|
||||
*
|
||||
* General memory layout
|
||||
* ---------------------
|
||||
*
|
||||
* 0x00000 - 0x01fff Lowcore
|
||||
* 0x02000 - 0x05fff Memory allocation (heap)
|
||||
* 0x0f000 - 0x0ffff Stack
|
||||
* 0x10000 - 0x10012 Jump to the "actual" stage3a code
|
||||
* 0x11000 - 0x12fff Stage3a code + arguments (offsets and lengths to the
|
||||
* actual data: IPIB and UV header)
|
||||
*/
|
||||
|
||||
#include "stage3a.h"
|
||||
#include "common_memory_layout.h"
|
||||
|
||||
OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
OUTPUT_ARCH(s390:64-bit)
|
||||
|
||||
ENTRY(_init)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x0;
|
||||
|
||||
. = HEAP_ADDRESS;
|
||||
__heap_start = .;
|
||||
.heap : {
|
||||
. = . + HEAP_SIZE;
|
||||
ASSERT(__heap_stop - __heap_start == HEAP_SIZE,
|
||||
"Heap section doesn't conform to the described memory layout");
|
||||
}
|
||||
__heap_stop = .;
|
||||
|
||||
. = STACK_ADDRESS;
|
||||
__stack_start = .;
|
||||
.stack : {
|
||||
. = . + STACK_SIZE;
|
||||
ASSERT(__stack_end - __stack_start == STACK_SIZE,
|
||||
"Stack section doesn't conform to the described memory layout");
|
||||
}
|
||||
__stack_end = .;
|
||||
|
||||
. = STAGE3A_INIT_ENTRY;
|
||||
__text_init_start = .;
|
||||
.text : {
|
||||
stage3a_init.o(.text.init)
|
||||
__text_init_stop = ABSOLUTE(.);
|
||||
/* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||
* otherwise the text data could be overwritten by the original zipl stage3
|
||||
* boot loader */
|
||||
ASSERT(__text_init_stop - __text_init_start < PARMAREA - IMAGE_ENTRY,
|
||||
"Text size must be smaller than 'PARMAREA - IMAGE_ENTRY'");
|
||||
. = 0x1000;
|
||||
ASSERT(ABSOLUTE(.) == STAGE3A_ENTRY,
|
||||
"Text section doesn't conform to the described memory layout");
|
||||
head.o(.text.start)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.ex_table ALIGN(16) : {
|
||||
__ex_table_start = .;
|
||||
*(.ex_table)
|
||||
__ex_table_stop = .;
|
||||
}
|
||||
|
||||
.bss ALIGN(16) : {
|
||||
__bss_start = .;
|
||||
*(.bss)
|
||||
__bss_stop = .;
|
||||
}
|
||||
|
||||
.rodata ALIGN(16) : {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
}
|
||||
|
||||
.data ALIGN(16) : {
|
||||
*(.data)
|
||||
. = ALIGN(16);
|
||||
/* The IPIB offset and the UV header offset and size will be
|
||||
* saved in 'loader_parms' */
|
||||
__loader_parms_start = .;
|
||||
KEEP(*(.loader_parms));
|
||||
__loader_parms_stop = .;
|
||||
ASSERT(__loader_parms_stop - __loader_parms_start == 3 * 8,
|
||||
"Data size must be equal to 'sizeof(struct stage3a_args)'");
|
||||
ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
||||
}
|
||||
|
||||
/* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
* put at 0x0 */
|
||||
.notes : {
|
||||
*(.note.*)
|
||||
}
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
}
|
||||
}
|
||||
28
genprotimg/boot/stage3a_init.S
Normal file
28
genprotimg/boot/stage3a_init.S
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Entry code for stage 3a boot loader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "stage3a.h"
|
||||
#include "boot/sigp.h"
|
||||
|
||||
.section .text.init
|
||||
.globl _init
|
||||
_init:
|
||||
/* set architecture and switch to 64bit */
|
||||
lhi %r1, 1
|
||||
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
sam64
|
||||
/* The original stage3 boot loader will try to store the
|
||||
* kernel command line and the address and size of the
|
||||
* ramdisk. Simply ignore this by starting at 0x11000.
|
||||
*/
|
||||
basr %r13, 0
|
||||
.Lbase: llgf %r1, .Lstage3a_entry - .Lbase(%r13)
|
||||
br %r1
|
||||
.Lstage3a_entry: .long STAGE3A_ENTRY
|
||||
.previous
|
||||
77
genprotimg/boot/stage3b.c
Normal file
77
genprotimg/boot/stage3b.c
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Main program for stage3b bootloader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "libc.h"
|
||||
#include "stage3b.h"
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "boot/s390.h"
|
||||
#include "boot/linux_layout.h"
|
||||
#include "boot/loaders_layout.h"
|
||||
#include "sclp.h"
|
||||
#include "error.h"
|
||||
|
||||
|
||||
static volatile struct stage3b_args __section(".loader_parms") loader_parms;
|
||||
|
||||
static inline void __noreturn load_psw(struct psw_t psw)
|
||||
{
|
||||
asm volatile("lpswe %0" : : "Q"(psw) : "cc");
|
||||
|
||||
while (1)
|
||||
;
|
||||
}
|
||||
|
||||
void __noreturn start(void)
|
||||
{
|
||||
volatile struct stage3b_args *args = &loader_parms;
|
||||
volatile struct memblob *kernel = &args->kernel;
|
||||
volatile struct memblob *cmdline = &args->cmdline;
|
||||
volatile struct memblob *initrd = &args->initrd;
|
||||
volatile struct psw_t psw = args->psw;
|
||||
|
||||
/* set up ASCII and line-mode */
|
||||
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||
|
||||
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
||||
panic(EINTERNAL, "Invalid kernel\n");
|
||||
|
||||
if (cmdline->size > COMMAND_LINE_SIZE)
|
||||
panic(EINTERNAL, "Command line is too large\n");
|
||||
|
||||
/* move the kernel and cut the kernel header */
|
||||
memmove((void *)IMAGE_LOAD_ADDRESS,
|
||||
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
||||
kernel->size - IMAGE_LOAD_ADDRESS);
|
||||
|
||||
/* move the kernel cmdline */
|
||||
memmove((void *)COMMAND_LINE,
|
||||
(void *)cmdline->src,
|
||||
cmdline->size);
|
||||
/* the initrd does not need to be moved */
|
||||
|
||||
if (initrd->size != 0) {
|
||||
/* copy initrd start address and size into new kernel space */
|
||||
*(unsigned long long *)INITRD_START = initrd->src;
|
||||
*(unsigned long long *)INITRD_SIZE = initrd->size;
|
||||
}
|
||||
|
||||
/* disable ASCII and line-mode */
|
||||
sclp_setup(SCLP_DISABLE);
|
||||
|
||||
/* use lpswe instead of diag308 as a I/O subsystem reset is not
|
||||
* needed as this was already done by the diag308 subcode 10 call
|
||||
* in stage3a
|
||||
*/
|
||||
load_psw(psw);
|
||||
}
|
||||
|
||||
void panic_notify(unsigned long UNUSED(rc))
|
||||
{
|
||||
}
|
||||
42
genprotimg/boot/stage3b.h
Normal file
42
genprotimg/boot/stage3b.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Main program for stage3b bootloader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef STAGE3B_H
|
||||
#define STAGE3B_H
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "boot/loaders_layout.h"
|
||||
|
||||
#define STAGE3B_ENTRY STAGE3_ENTRY
|
||||
#define STAGE3B_LOAD_ADDRESS STAGE3B_ENTRY
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
|
||||
/* Must not have any padding included */
|
||||
struct memblob {
|
||||
uint64_t src;
|
||||
uint64_t size;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct memblob) == 2 * 8)
|
||||
|
||||
/* Must not have any padding included */
|
||||
struct stage3b_args {
|
||||
struct memblob kernel;
|
||||
struct memblob cmdline;
|
||||
struct memblob initrd;
|
||||
struct psw_t psw;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct stage3b_args) == 3 * sizeof(struct memblob) + 16)
|
||||
#endif /* __ASSEMBLER__ */
|
||||
#endif /* STAGE3B_H */
|
||||
87
genprotimg/boot/stage3b.lds.S
Normal file
87
genprotimg/boot/stage3b.lds.S
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Memory layout for stage 3b
|
||||
* ==========================
|
||||
*
|
||||
* General memory layout
|
||||
* ---------------------
|
||||
*
|
||||
* 0x00000 - 0x01fff Lowcore
|
||||
* 0x02000 - 0x05fff Memory allocation (heap)
|
||||
* 0x0a000 - 0x0efff Stage3b code
|
||||
* 0x0f000 - 0x0ffff Stack
|
||||
*/
|
||||
|
||||
#include "stage3b.h"
|
||||
#include "common_memory_layout.h"
|
||||
|
||||
OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
OUTPUT_ARCH(s390:64-bit)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x0;
|
||||
|
||||
. = HEAP_ADDRESS;
|
||||
__heap_start = .;
|
||||
.heap : {
|
||||
. = . + HEAP_SIZE;
|
||||
ASSERT(__heap_stop - __heap_start == HEAP_SIZE,
|
||||
"Heap section doesn't conform to the described memory layout");
|
||||
}
|
||||
__heap_stop = .;
|
||||
|
||||
. = STAGE3B_ENTRY;
|
||||
.text : {
|
||||
head.o(.text.start)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
.ex_table ALIGN(16) : {
|
||||
__ex_table_start = .;
|
||||
*(.ex_table)
|
||||
__ex_table_stop = .;
|
||||
}
|
||||
|
||||
.bss ALIGN(16) : {
|
||||
__bss_start = .;
|
||||
*(.bss)
|
||||
__bss_stop = .;
|
||||
}
|
||||
|
||||
.rodata ALIGN(16) : {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
}
|
||||
|
||||
.data ALIGN(16) : {
|
||||
*(.data)
|
||||
. = ALIGN(16);
|
||||
__loader_parms_start = .;
|
||||
KEEP(*(.loader_parms));
|
||||
__loader_parms_end = .;
|
||||
ASSERT(__loader_parms_end - __loader_parms_start == 3 * 16 + 16,
|
||||
"Data size must be equal to 'sizeof(struct stage3b_args)'");
|
||||
}
|
||||
|
||||
. = STACK_ADDRESS;
|
||||
__stack_start = .;
|
||||
.stack : {
|
||||
. = . + STACK_SIZE;
|
||||
ASSERT(__stack_end - __stack_start == STACK_SIZE,
|
||||
"Stack section doesn't conform to the described memory layout");
|
||||
}
|
||||
__stack_end = .;
|
||||
|
||||
/* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
* put at 0x0 */
|
||||
.notes : {
|
||||
*(.note.*)
|
||||
}
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
}
|
||||
}
|
||||
55
genprotimg/boot/stage3b_reloc.S
Normal file
55
genprotimg/boot/stage3b_reloc.S
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Relocator code for stage 3b boot loader
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "stage3b.h"
|
||||
#include "boot/sigp.h"
|
||||
|
||||
.macro MEMCPY dst,src,len
|
||||
lgr %r0, \dst
|
||||
lgr %r1, \len
|
||||
lgr %r2, \src
|
||||
lgr %r3, \len
|
||||
|
||||
20: mvcle %r0, %r2, 0
|
||||
jo 20b
|
||||
.endm
|
||||
|
||||
.org 0x0
|
||||
.section .text.start
|
||||
.globl stage3b_reloc_start
|
||||
stage3b_reloc_start:
|
||||
/* Might be called after a diag308 so better set
|
||||
* architecture and addressing mode
|
||||
*/
|
||||
lhi %r1, 1
|
||||
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||
sam64
|
||||
|
||||
/* Location of stage3b in memory */
|
||||
larl %r8, stage3b_start
|
||||
|
||||
/* Destination for stage3b */
|
||||
basr %r13, 0
|
||||
.Lbase: llgf %r9, .Lstage3b_load_address - .Lbase(%r13)
|
||||
|
||||
/* Size of stage3b */
|
||||
lghi %r11, stage3b_end - stage3b_start
|
||||
|
||||
/* Copy the stage3b loader to address STAGE3B_LOAD_ADDRESS */
|
||||
MEMCPY %r9, %r8, %r11
|
||||
|
||||
/* Branch to STAGE3B_ENTRY */
|
||||
llgf %r9, .Lstage3b_entry - .Lbase(%r13)
|
||||
br %r9
|
||||
.Lstage3b_load_address: .long STAGE3B_LOAD_ADDRESS
|
||||
.Lstage3b_entry: .long STAGE3B_ENTRY
|
||||
stage3b_start:
|
||||
.incbin "stage3b.bin"
|
||||
stage3b_end:
|
||||
.previous
|
||||
12
genprotimg/man/Makefile
Normal file
12
genprotimg/man/Makefile
Normal file
@@ -0,0 +1,12 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
all:
|
||||
|
||||
install:
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 -c genprotimg.8 $(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
clean:
|
||||
|
||||
.PHONY: all install clean
|
||||
124
genprotimg/man/genprotimg.8
Normal file
124
genprotimg/man/genprotimg.8
Normal file
@@ -0,0 +1,124 @@
|
||||
.\" Copyright 2020 IBM Corp.
|
||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||
.\"
|
||||
.TH GENPROTIMG 8 "November 2020" "s390-tools"
|
||||
.SH NAME
|
||||
genprotimg \- Create a protected virtualization image
|
||||
|
||||
.SH SYNOPSIS
|
||||
.SY
|
||||
.B genprotimg
|
||||
\fB\-k\fR \fIHOST_KEY_DOCUMENT\fR...
|
||||
\fB\-C\fR \fICERTIFICATE\fR...
|
||||
\fB\-i\fR \fIVMLINUZ\fR
|
||||
[\fB\-r\fR \fIRAMDISK\fR]
|
||||
[\fB\-p\fR \fIPARMFILE\fR]
|
||||
\fB\-o\fR \fIOUTFILE\fR
|
||||
[\fIOPTION\fR]...
|
||||
.YS
|
||||
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Use \fBgenprotimg\fR to generate a single bootable image file with
|
||||
encrypted and integrity-protected parts. The command requires a kernel
|
||||
image, a host-key document, certificates for the host-key document
|
||||
verification, and an output file name. Optionally, specify an initial
|
||||
RAM filesystem, and a file containing the kernel parameters. If the
|
||||
command should be run offline, use the \fB\-\-offline\fR option and
|
||||
specify the certificate revocation lists (CRLs) by using the
|
||||
\fB\-\-crl\fR option. Should special circumstances require it, you can
|
||||
optionally specify your own keys for the encryption by using the
|
||||
experimental options. For all certificates, CRLs, and host-key
|
||||
documents, both the PEM and DER input formats are supported. In the
|
||||
resulting image file, a plain text boot loader, the encrypted
|
||||
components for kernel, initial RAM disk, kernel parameters, and the
|
||||
encrypted and integrity-protected header are concatenated. The header
|
||||
contains metadata necessary for running the guest in protected mode.
|
||||
.PP
|
||||
Use this image file as a kernel image for zipl or for a direct kernel
|
||||
boot using QEMU.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB\-h\fR, \fB\-\-help\fR
|
||||
Prints usage information, then exits.
|
||||
.TP
|
||||
\fB\-\-help-experimental\fR
|
||||
Prints experimental usage information, then exits.
|
||||
.TP
|
||||
\fB\-\-help-all\fR
|
||||
Prints all usage information, then exits.
|
||||
.TP
|
||||
\fB\-V\fR, \fB\-\-verbose\fR
|
||||
Provides more detailed output.
|
||||
.TP
|
||||
\fB\-k\fR, \fB\-\-host-key-document\fR=\fI\,HOST_KEY_DOCUMENT\/\fR
|
||||
Specifies a host-key document. At least one is required. Specify this
|
||||
option multiple times to enable the image to run on more than one
|
||||
host.
|
||||
.TP
|
||||
\fB\-C\fR, \fB\-\-cert\fR=\fI\,FILE\/\fR
|
||||
Specifies the certificate that is used to establish a chain of trust
|
||||
for the verification of the host-key documents. Specify this option
|
||||
twice to specify the IBM Z signing key and the intermediate CA
|
||||
certificate (signed by the root CA). Required.
|
||||
.TP
|
||||
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
||||
Specifies the output file. Required.
|
||||
.TP
|
||||
\fB\-i\fR, \fB\-\-image\fR=\fI\,VMLINUZ\/\fR
|
||||
Specifies the Linux kernel image file. Required.
|
||||
.TP
|
||||
\fB\-r\fR, \fB\-\-ramdisk\fR=\fI\,RAMDISK\/\fR
|
||||
Specifies the RAM disk image. Optional.
|
||||
.TP
|
||||
\fB\-p\fR, \fB\-\-parmfile\fR=\fI\,PARMFILE\/\fR
|
||||
Specifies the kernel command line stored in \fI\,PARMFILE\/\fR. Optional.
|
||||
.TP
|
||||
\fB\-\-crl\fR=\fI\,FILE\/\fR
|
||||
Specifies the revocation list that is used to check whether a
|
||||
certificate of the chain of trust is revoked. Specify this option
|
||||
multiple times to use multiple CRLs. Optional.
|
||||
.TP
|
||||
\fB\-\-offline\fR
|
||||
Specifies offline mode, in which no attempt is made to download
|
||||
CRLs. Optional.
|
||||
.TP
|
||||
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
||||
Specifies the root CA certificate for the verification. If omitted,
|
||||
the DigiCert root CA certificate installed on the system is used. Use
|
||||
this only if you trust the specified certificate. Optional.
|
||||
.TP
|
||||
\fB\-\-no-verify\fR
|
||||
Do not require the host-key documents to be valid. For testing
|
||||
purposes, do not use for a production image. Optional.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Prints version information, then exits.
|
||||
|
||||
.SH EXAMPLE
|
||||
.PP
|
||||
Generate a protected virtualization image in
|
||||
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
|
||||
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
||||
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR,
|
||||
the IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
||||
host-key document in \fI\,host_key.crt\/\fR:
|
||||
.PP
|
||||
.Vb 1
|
||||
.EX
|
||||
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||
.EE
|
||||
.Ve
|
||||
.PP
|
||||
|
||||
.SH NOTES
|
||||
.IP "1." 4
|
||||
An ELF file cannot be used as a Linux kernel image.
|
||||
.IP "2." 4
|
||||
Remember to re-run \fBzipl\fR after updating a protected
|
||||
virtualization image.
|
||||
|
||||
.SH SEE ALSO
|
||||
\&\fBzipl\fR\|(5), \fBqemu\fR\|(1)
|
||||
275
genprotimg/samples/check_hostkeydoc
Executable file
275
genprotimg/samples/check_hostkeydoc
Executable file
@@ -0,0 +1,275 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# check_hostkeydoc - Verify an IBM Secure Execution host key document
|
||||
#
|
||||
# Sample script to verify that a host key document is genuine by
|
||||
# verifying the issuer, the validity date and the signature.
|
||||
# Optionally verify the full trust chain using a CA certficate.
|
||||
#
|
||||
# Sample invocation:
|
||||
#
|
||||
# ./check_hostkeydoc HKD1234.crt ibm-z-host-key-signing.crt -c DigiCertCA.crt -r ibm-z-host-key.crl
|
||||
#
|
||||
# Copyright IBM Corp. 2020
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
|
||||
|
||||
# Allocate temporary files
|
||||
ISSUER_PUBKEY_FILE=$(mktemp)
|
||||
SIGNATURE_FILE=$(mktemp)
|
||||
BODY_FILE=$(mktemp)
|
||||
ISSUER_DN_FILE=$(mktemp)
|
||||
SUBJECT_DN_FILE=$(mktemp)
|
||||
DEF_ISSUER_DN_FILE=$(mktemp)
|
||||
CRL_SERIAL_FILE=$(mktemp)
|
||||
|
||||
# Cleanup on exit
|
||||
cleanup()
|
||||
{
|
||||
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
||||
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
||||
$CRL_SERIAL_FILE
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
# Enhanced error checking for bash
|
||||
if [ -n "${BASH}" ]
|
||||
then
|
||||
set -o posix
|
||||
set -o pipefail
|
||||
set -o nounset
|
||||
fi
|
||||
set -e
|
||||
|
||||
# Usage
|
||||
usage()
|
||||
{
|
||||
cat <<-EOF
|
||||
Usage: `basename $1` host-key-doc signing-key-cert [-c CA-cert] [-r CRL]
|
||||
|
||||
Verify an IBM Secure Execution host key document against
|
||||
a signing key.
|
||||
|
||||
Note that in order to have the full trust chain verified
|
||||
it is necessary to provide the issueing CA's certificate.
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
check_verify_chain()
|
||||
{
|
||||
# Verify certificate chain in case a CA certificate file/bundle
|
||||
# was specified on the command line.
|
||||
if [ $# = 1 ]
|
||||
then
|
||||
cat >&2 <<-EOF
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
No CA certificate specified! Skipping trust chain verification.
|
||||
Make sure that '$1' is a valid certificate.
|
||||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||
EOF
|
||||
else
|
||||
openssl verify -crl_download -crl_check $2 &&
|
||||
openssl verify -crl_download -crl_check -untrusted $2 $1 ||
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
extract_pubkey()
|
||||
{
|
||||
openssl x509 -in $1 -pubkey -noout > $2
|
||||
}
|
||||
|
||||
extract_signature()
|
||||
{
|
||||
# Assuming that the last field is the signature
|
||||
SIGOFFSET=$(openssl asn1parse -in $1 | tail -1 | cut -d : -f 1)
|
||||
|
||||
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
|
||||
}
|
||||
|
||||
extract_body()
|
||||
{
|
||||
# Assuming that the first field is the full cert body
|
||||
SIGOFFSET=$(openssl asn1parse -in $1 | head -2 | tail -1 | cut -d : -f 1)
|
||||
|
||||
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
|
||||
}
|
||||
|
||||
verify_signature()
|
||||
{
|
||||
# Assuming that the signature algorithm is SHA512 with RSA
|
||||
openssl sha512 -verify $1 -signature $2 $3
|
||||
}
|
||||
|
||||
canonical_dn()
|
||||
{
|
||||
OBJTYPE=$1
|
||||
OBJ=$2
|
||||
DNTYPE=$3
|
||||
OUTPUT=$4
|
||||
|
||||
openssl $OBJTYPE -in $OBJ -$DNTYPE -noout -nameopt multiline \
|
||||
| sort | grep -v $DNTYPE= > $OUTPUT
|
||||
}
|
||||
|
||||
default_issuer()
|
||||
{
|
||||
cat <<-EOF
|
||||
commonName = International Business Machines Corporation
|
||||
countryName = US
|
||||
localityName = Poughkeepsie
|
||||
organizationalUnitName = IBM Z Host Key Signing Service
|
||||
organizationName = International Business Machines Corporation
|
||||
stateOrProvinceName = New York
|
||||
EOF
|
||||
}
|
||||
|
||||
verify_issuer_files()
|
||||
{
|
||||
default_issuer > $DEF_ISSUER_DN_FILE
|
||||
|
||||
if ! diff $ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
||||
then
|
||||
echo Incorrect default issuer >&2 && exit 1
|
||||
fi
|
||||
|
||||
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
||||
then
|
||||
echo Issuer verification OK
|
||||
else
|
||||
echo Issuer verification failed >&2 && exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
cert_time()
|
||||
{
|
||||
DATE=$(openssl x509 -in $1 -$2 -noout | sed "s/^.*=//")
|
||||
|
||||
date -d "$DATE" +%s
|
||||
}
|
||||
|
||||
crl_time()
|
||||
{
|
||||
DATE=$(openssl crl -in $1 -$2 -noout | sed "s/^.*=//")
|
||||
|
||||
date -d "$DATE" +%s
|
||||
}
|
||||
|
||||
verify_dates()
|
||||
{
|
||||
START="$1"
|
||||
END="$2"
|
||||
MSG="${3:-Certificate}"
|
||||
NOW=$(date +%s)
|
||||
|
||||
if [ $START -le $NOW -a $NOW -le $END ]
|
||||
then
|
||||
echo "${MSG} dates are OK"
|
||||
else
|
||||
echo "${MSG} date verification failed" >&2 && exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
crl_serials()
|
||||
{
|
||||
openssl crl -in $1 -text -noout | \
|
||||
grep "Serial Number" > $CRL_SERIAL_FILE
|
||||
}
|
||||
|
||||
check_serial()
|
||||
{
|
||||
CERT_SERIAL=$(openssl x509 -in $1 -noout -serial | cut -d = -f 2)
|
||||
|
||||
grep -q $CERT_SERIAL $CRL_SERIAL_FILE
|
||||
}
|
||||
|
||||
check_file()
|
||||
{
|
||||
[ $# = 0 ] ||
|
||||
[ -e "$1" ] ||
|
||||
(echo "File '$1' not found" >&2 && exit 1)
|
||||
}
|
||||
|
||||
# check args
|
||||
CRL_FILE=
|
||||
CA_FILE=
|
||||
|
||||
args=$(getopt -qu "r:c:h" $*)
|
||||
if [ $? = 0 ]
|
||||
then
|
||||
set -- $args
|
||||
while [ $1 != "" ]
|
||||
do
|
||||
case $1 in
|
||||
-r) CRL_FILE=$2; shift 2;;
|
||||
-c) CA_FILE=$2; shift 2;;
|
||||
-h) usage $0; exit 0;;
|
||||
--) shift; break;;
|
||||
esac
|
||||
done
|
||||
else
|
||||
usage $0 >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -ne 2 ]
|
||||
then
|
||||
usage $0 >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
HKD_FILE=$1
|
||||
HKSK_FILE=$2
|
||||
|
||||
# Check whether all specified files exist
|
||||
check_file $HKD_FILE
|
||||
check_file $HKSK_FILE
|
||||
check_file $CA_FILE
|
||||
check_file $CRL_FILE
|
||||
|
||||
# Check trust chain
|
||||
check_verify_chain $HKSK_FILE $CA_FILE
|
||||
|
||||
# Verify host key document signature
|
||||
echo -n "Checking host key document signature: "
|
||||
extract_pubkey $HKSK_FILE $ISSUER_PUBKEY_FILE &&
|
||||
extract_signature $HKD_FILE $SIGNATURE_FILE &&
|
||||
extract_body $HKD_FILE $BODY_FILE &&
|
||||
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
|
||||
exit 1
|
||||
|
||||
# Verify the issuer
|
||||
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||
verify_issuer_files
|
||||
|
||||
# Verify dates
|
||||
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
||||
|
||||
# Check CRL if specified
|
||||
if [ -n "$CRL_FILE" ]
|
||||
then
|
||||
echo -n "Checking CRL signature: "
|
||||
extract_signature $CRL_FILE $SIGNATURE_FILE &&
|
||||
extract_body $CRL_FILE $BODY_FILE &&
|
||||
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
|
||||
exit 1
|
||||
|
||||
echo -n "CRL "
|
||||
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||
verify_issuer_files
|
||||
|
||||
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
||||
|
||||
crl_serials $CRL_FILE
|
||||
check_serial $HKD_FILE &&
|
||||
echo "Certificate is revoked, do not use it anymore!" >&2 &&
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# We made it
|
||||
echo All checks reqested for \'$HKD_FILE\' were successful
|
||||
112
genprotimg/src/Makefile
Normal file
112
genprotimg/src/Makefile
Normal file
@@ -0,0 +1,112 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
bin_PROGRAM = genprotimg
|
||||
|
||||
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
|
||||
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
TOP_SRCDIR := $(SRC_DIR)/../
|
||||
ROOT_DIR = $(TOP_SRC_DIR)/../../
|
||||
ZIPL_DIR = $(ROOT_DIR)/zipl
|
||||
LOADER_DIR = $(TOP_SRCDIR)/boot
|
||||
|
||||
INCLUDE_PATHS = "$(SRC_DIR)" "$(TOP_SRCDIR)" "$(ROOTDIR)/include"
|
||||
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
|
||||
|
||||
WARNINGS := -Wall -Wextra -Wshadow \
|
||||
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
|
||||
-Wmissing-declarations -Wredundant-decls -Wnested-externs \
|
||||
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
|
||||
-Wpointer-arith -Werror -Wno-error=inline \
|
||||
$(NULL)
|
||||
|
||||
$(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \
|
||||
pv/pv_comp.c pv/pv_hdr.c pv/pv_ipib.c utils/crypto.c utils/file_utils.c \
|
||||
pv/pv_args.c utils/buffer.c pv/pv_comps.c pv/pv_error.c \
|
||||
pv/pv_opt_item.c utils/curl.c \
|
||||
$(NULL)
|
||||
$(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
|
||||
|
||||
ALL_CFLAGS += -std=gnu11 -DPKGDATADIR=$(PKGDATADIR) \
|
||||
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
|
||||
$(WARNINGS) \
|
||||
$(NULL)
|
||||
ALL_CPPFLAGS += $(INCLUDE_PARMS)
|
||||
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
|
||||
|
||||
|
||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||
GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
|
||||
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
|
||||
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto)
|
||||
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto)
|
||||
LIBCURL_CFLAGS := $(shell pkg-config --silence-errors --cflags libcurl)
|
||||
LIBCURL_LIBS := $(shell pkg-config --silence-errors --libs libcurl)
|
||||
else
|
||||
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
|
||||
GLIB2_LIBS := -lglib-2.0
|
||||
LIBCRYPTO_CFLAGS :=
|
||||
LIBCRYPTO_LIBS := -lcrypto
|
||||
LIBCURL_CFLAGS :=
|
||||
LIBCURL_LIBS := -lcurl
|
||||
endif
|
||||
|
||||
BUILD_TARGETS := skip-$(bin_PROGRAM)
|
||||
INSTALL_TARGETS := skip-$(bin_PROGRAM)
|
||||
ifneq (${HAVE_OPENSSL},0)
|
||||
ifneq (${HAVE_GLIB2},0)
|
||||
ifneq (${HAVE_LIBCURL},0)
|
||||
BUILD_TARGETS := $(bin_PROGRAM)
|
||||
INSTALL_TARGETS := install-$(bin_PROGRAM)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
$(bin_PROGRAM): $($(bin_PROGRAM)_OBJS)
|
||||
|
||||
skip-$(bin_PROGRAM):
|
||||
echo " SKIP $(bin_PROGRAM) due to unresolved dependencies"
|
||||
|
||||
install-$(bin_PROGRAM): $(bin_PROGRAM)
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||
$(INSTALL) -c $^ $(DESTDIR)$(USRBINDIR)
|
||||
|
||||
clean:
|
||||
$(RM) -f $($(bin_PROGRAM)_OBJS) $(bin_PROGRAM) .check-dep-$(bin_PROGRAM) .detect-openssl.dep.c
|
||||
|
||||
.PHONY: all install clean skip-$(bin_PROGRAM) install-$(bin_PROGRAM)
|
||||
|
||||
$($(bin_PROGRAM)_OBJS): .check-dep-$(bin_PROGRAM)
|
||||
|
||||
.detect-openssl.dep.c:
|
||||
echo "#include <openssl/evp.h>" > $@
|
||||
echo "#if OPENSSL_VERSION_NUMBER < 0x10100000L" >> $@
|
||||
echo " #error openssl version 1.1.0 is required" >> $@
|
||||
echo "#endif" >> $@
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||
echo " EVP_MD_CTX_free(ctx);" >> $@
|
||||
echo "}" >> $@
|
||||
|
||||
.check-dep-$(bin_PROGRAM): .detect-openssl.dep.c
|
||||
$(call check_dep, \
|
||||
"$(bin_PROGRAM)", \
|
||||
"glib.h", \
|
||||
"glib2-devel / libglib2.0-dev", \
|
||||
"HAVE_GLIB2=0")
|
||||
$(call check_dep, \
|
||||
"$(bin_PROGRAM)", \
|
||||
$^, \
|
||||
"openssl-devel / libssl-dev version >= 1.1.0", \
|
||||
"HAVE_OPENSSL=0", \
|
||||
"-I.")
|
||||
$(call check_dep, \
|
||||
"$(bin_PROGRAM)", \
|
||||
"curl/curl.h", \
|
||||
"libcurl-devel", \
|
||||
"HAVE_LIBCURL=0")
|
||||
touch $@
|
||||
35
genprotimg/src/common.h
Normal file
35
genprotimg/src/common.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#define GETTEXT_PACKAGE "genprotimg"
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
|
||||
#include "boot/linux_layout.h"
|
||||
#include "boot/s390.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
static const gchar tool_name[] = "genprotimg";
|
||||
static const gchar copyright_notice[] = "Copyright IBM Corp. 2020";
|
||||
|
||||
/* default values */
|
||||
#define GENPROTIMG_STAGE3A_PATH (STRINGIFY(PKGDATADIR) "/stage3a.bin")
|
||||
#define GENPROTIMG_STAGE3B_PATH (STRINGIFY(PKGDATADIR) "/stage3b_reloc.bin")
|
||||
|
||||
#define DEFAULT_INITIAL_PSW_ADDR IMAGE_ENTRY
|
||||
#define DEFAULT_INITIAL_PSW_MASK (PSW_MASK_EA | PSW_MASK_BA)
|
||||
|
||||
#define DO_PRAGMA(x) _Pragma(#x)
|
||||
|
||||
# ifdef __clang__
|
||||
# define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
|
||||
DO_PRAGMA(clang diagnostic push) \
|
||||
DO_PRAGMA(clang diagnostic ignored "-Wunused-function") \
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__) \
|
||||
DO_PRAGMA(clang diagnostic pop)
|
||||
# else
|
||||
# define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
|
||||
# endif
|
||||
|
||||
#endif
|
||||
200
genprotimg/src/genprotimg.c
Normal file
200
genprotimg/src/genprotimg.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* genprotimg - build relocatable secure images
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <locale.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "pv/pv_args.h"
|
||||
#include "pv/pv_image.h"
|
||||
#include "utils/crypto.h"
|
||||
#include "utils/curl.h"
|
||||
|
||||
enum {
|
||||
LOG_LEVEL_CRITICAL = 0,
|
||||
LOG_LEVEL_INFO = 1,
|
||||
LOG_LEVEL_DEBUG = 2,
|
||||
};
|
||||
|
||||
static gint log_level = LOG_LEVEL_CRITICAL;
|
||||
static gchar *tmp_dir;
|
||||
|
||||
static void rmdir_recursive(gchar *dir_path, GError **err)
|
||||
{
|
||||
const gchar *file = NULL;
|
||||
g_autoptr(GDir) d = NULL;
|
||||
|
||||
if (!dir_path)
|
||||
return;
|
||||
|
||||
d = g_dir_open(dir_path, 0, err);
|
||||
if (!d) {
|
||||
g_set_error(err, G_FILE_ERROR,
|
||||
(gint)g_file_error_from_errno(errno),
|
||||
_("Failed to open directory '%s': %s"), dir_path,
|
||||
g_strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
while ((file = g_dir_read_name(d)) != NULL) {
|
||||
g_autofree gchar *file_path =
|
||||
g_build_filename(dir_path, file, NULL);
|
||||
/* ignore error */
|
||||
(void)g_unlink(file_path);
|
||||
}
|
||||
|
||||
if (g_rmdir(dir_path) != 0) {
|
||||
g_set_error(err, G_FILE_ERROR,
|
||||
(gint)g_file_error_from_errno(errno),
|
||||
_("Failed to remove directory '%s': %s"), dir_path,
|
||||
g_strerror(errno));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void sig_term_handler(int signal G_GNUC_UNUSED)
|
||||
{
|
||||
rmdir_recursive(tmp_dir, NULL);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static void log_handler_cb(const gchar *log_domain G_GNUC_UNUSED,
|
||||
GLogLevelFlags level, const gchar *message,
|
||||
gpointer user_data G_GNUC_UNUSED)
|
||||
{
|
||||
const gchar *prefix = "";
|
||||
|
||||
/* filter out messages depending on debugging level */
|
||||
if ((level & G_LOG_LEVEL_DEBUG) && log_level < LOG_LEVEL_DEBUG)
|
||||
return;
|
||||
|
||||
if ((level & G_LOG_LEVEL_INFO) && log_level < LOG_LEVEL_INFO)
|
||||
return;
|
||||
|
||||
if (level & G_LOG_LEVEL_WARNING)
|
||||
prefix = "WARNING: ";
|
||||
|
||||
if (level & G_LOG_LEVEL_ERROR)
|
||||
prefix = "ERROR: ";
|
||||
|
||||
if (level & (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR))
|
||||
g_printerr("%s%s\n", prefix, message);
|
||||
else
|
||||
g_print("%s%s\n", prefix, message);
|
||||
}
|
||||
|
||||
static void setup_prgname(const gchar *name)
|
||||
{
|
||||
g_set_prgname(name);
|
||||
g_set_application_name(_(name));
|
||||
}
|
||||
|
||||
static void setup_handler(const gint *signals, const gsize signals_n)
|
||||
{
|
||||
/* set up logging handler */
|
||||
g_log_set_handler(NULL,
|
||||
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
|
||||
G_LOG_FLAG_RECURSION,
|
||||
log_handler_cb, NULL);
|
||||
|
||||
/* set signal handler */
|
||||
for (gsize i = 0; i < signals_n; i++)
|
||||
signal(signals[i], sig_term_handler);
|
||||
}
|
||||
|
||||
static void remove_signal_handler(const gint *signals, const gsize signals_n)
|
||||
{
|
||||
for (gsize i = 0; i < signals_n; i++)
|
||||
signal(signals[i], SIG_DFL);
|
||||
}
|
||||
|
||||
static void __attribute__((constructor)) __init(void);
|
||||
static void __attribute__((destructor)) __cleanup(void);
|
||||
gint main(gint argc, gchar *argv[])
|
||||
{
|
||||
g_autoptr(PvArgs) args = pv_args_new();
|
||||
gint signals[] = { SIGINT, SIGTERM };
|
||||
g_autoptr(PvImage) img = NULL;
|
||||
gint ret = EXIT_FAILURE;
|
||||
GError *err = NULL;
|
||||
|
||||
setlocale(LC_CTYPE, "");
|
||||
setup_prgname(tool_name);
|
||||
setup_handler(signals, G_N_ELEMENTS(signals));
|
||||
|
||||
if (pv_args_parse_options(args, &argc, &argv, &err) < 0)
|
||||
goto error;
|
||||
|
||||
/* set new log level */
|
||||
log_level = args->log_level;
|
||||
|
||||
/* if the user has not specified a temporary directory let's
|
||||
* create one
|
||||
*/
|
||||
if (!args->tmp_dir) {
|
||||
tmp_dir = g_dir_make_tmp("genprotimg-XXXXXX", &err);
|
||||
if (!tmp_dir)
|
||||
goto error;
|
||||
args->tmp_dir = g_strdup(tmp_dir);
|
||||
}
|
||||
|
||||
/* allocate and initialize ``pv_img`` data structure */
|
||||
img = pv_img_new(args, GENPROTIMG_STAGE3A_PATH, &err);
|
||||
if (!img)
|
||||
goto error;
|
||||
|
||||
/* add user components: `args->comps` must be sorted by the
|
||||
* component type => by memory address
|
||||
*/
|
||||
for (GSList *iterator = args->comps; iterator; iterator = iterator->next) {
|
||||
const PvArg *arg = iterator->data;
|
||||
|
||||
if (pv_img_add_component(img, arg, &err) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (pv_img_finalize(img, GENPROTIMG_STAGE3B_PATH, &err) < 0)
|
||||
goto error;
|
||||
|
||||
if (pv_img_write(img, args->output_path, &err) < 0)
|
||||
goto error;
|
||||
|
||||
ret = EXIT_SUCCESS;
|
||||
|
||||
error:
|
||||
if (err) {
|
||||
fputs(err->message, stderr);
|
||||
fputc('\n', stderr);
|
||||
g_clear_error(&err);
|
||||
}
|
||||
rmdir_recursive(tmp_dir, NULL);
|
||||
remove_signal_handler(signals, G_N_ELEMENTS(signals));
|
||||
g_free(tmp_dir);
|
||||
g_clear_pointer(&img, pv_img_free);
|
||||
g_clear_pointer(&args, pv_args_free);
|
||||
exit(ret);
|
||||
}
|
||||
|
||||
static void __init(void)
|
||||
{
|
||||
pv_crypto_init();
|
||||
if (curl_init() != 0)
|
||||
g_abort();
|
||||
}
|
||||
|
||||
static void __cleanup(void)
|
||||
{
|
||||
curl_cleanup();
|
||||
pv_crypto_cleanup();
|
||||
}
|
||||
43
genprotimg/src/include/pv_crypto_def.h
Normal file
43
genprotimg/src/include/pv_crypto_def.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* PV cryptography related definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_CRYPTO_DEF_H
|
||||
#define PV_CRYPTO_DEF_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
/* IBM signing key subject */
|
||||
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
|
||||
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
|
||||
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
|
||||
#define PV_IBM_Z_SUBJECT_ORGANIZATIONONAL_UNIT_NAME_SUFFIX "Key Signing Service"
|
||||
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
|
||||
#define PV_IBM_Z_SUBJECT_STATE "New York"
|
||||
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
|
||||
|
||||
/* Minimum security level for the keys/certificates used to establish a chain of
|
||||
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
|
||||
* for details).
|
||||
*/
|
||||
#define PV_CERTS_SECURITY_LEVEL 2
|
||||
|
||||
/* SKID for DigiCert Assured ID Root CA */
|
||||
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
|
||||
|
||||
union ecdh_pub_key {
|
||||
struct {
|
||||
uint8_t x[80];
|
||||
uint8_t y[80];
|
||||
};
|
||||
uint8_t data[160];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
84
genprotimg/src/include/pv_hdr_def.h
Normal file
84
genprotimg/src/include/pv_hdr_def.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* PV header definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_HDR_DEF_H
|
||||
#define PV_HDR_DEF_H
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "lib/zt_common.h"
|
||||
#include "utils/crypto.h"
|
||||
|
||||
#include "pv_crypto_def.h"
|
||||
|
||||
/* Magic number which is used to identify the file containing the PV
|
||||
* header
|
||||
*/
|
||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||
#define PV_VERSION_1 0x00000100U
|
||||
|
||||
/* prevent Ultravisor decryption during unpack operation */
|
||||
#define PV_CFLAG_NO_DECRYPTION 0x10000000ULL
|
||||
|
||||
/* maxima for the PV version 1 */
|
||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||
#define PV_V1_PV_HDR_MAX_SIZE (2 * PAGE_SIZE)
|
||||
|
||||
typedef struct pv_hdr_key_slot {
|
||||
uint8_t digest_key[SHA256_DIGEST_LENGTH];
|
||||
uint8_t wrapped_key[32];
|
||||
uint8_t tag[AES_256_GCM_TAG_SIZE];
|
||||
} __packed PvHdrKeySlot;
|
||||
|
||||
typedef struct pv_hdr_opt_item {
|
||||
uint32_t otype;
|
||||
uint8_t ibk[32];
|
||||
uint8_t data[];
|
||||
} __packed PvHdrOptItem;
|
||||
|
||||
/* integrity protected data (by GCM tag), but non-encrypted */
|
||||
struct pv_hdr_head {
|
||||
uint64_t magic;
|
||||
uint32_t version;
|
||||
uint32_t phs;
|
||||
uint8_t iv[AES_256_GCM_IV_SIZE];
|
||||
uint32_t res1;
|
||||
uint64_t nks;
|
||||
uint64_t sea;
|
||||
uint64_t nep;
|
||||
uint64_t pcf;
|
||||
union ecdh_pub_key cust_pub_key;
|
||||
uint8_t pld[SHA512_DIGEST_LENGTH];
|
||||
uint8_t ald[SHA512_DIGEST_LENGTH];
|
||||
uint8_t tld[SHA512_DIGEST_LENGTH];
|
||||
} __packed;
|
||||
|
||||
/* Must not have any padding */
|
||||
struct pv_hdr_encrypted {
|
||||
uint8_t cust_comm_key[32];
|
||||
uint8_t img_enc_key_1[AES_256_XTS_KEY_SIZE / 2];
|
||||
uint8_t img_enc_key_2[AES_256_XTS_KEY_SIZE / 2];
|
||||
struct psw_t psw;
|
||||
uint64_t scf;
|
||||
uint32_t noi;
|
||||
uint32_t res2;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct pv_hdr_encrypted) ==
|
||||
32 + 32 + 32 + sizeof(struct psw_t) + 8 + 4 + 4)
|
||||
|
||||
typedef struct pv_hdr {
|
||||
struct pv_hdr_head head;
|
||||
struct pv_hdr_key_slot *slots;
|
||||
struct pv_hdr_encrypted *encrypted;
|
||||
struct pv_hdr_opt_item **optional_items;
|
||||
uint8_t tag[AES_256_GCM_TAG_SIZE];
|
||||
} PvHdr;
|
||||
|
||||
#endif
|
||||
454
genprotimg/src/pv/pv_args.c
Normal file
454
genprotimg/src/pv/pv_args.c
Normal file
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* PV arguments related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gprintf.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "pv_comp.h"
|
||||
#include "pv_error.h"
|
||||
#include "pv_args.h"
|
||||
|
||||
static gchar summary[] =
|
||||
"Use genprotimg to create a protected virtualization kernel image file,\n"
|
||||
"which can be loaded using zipl or QEMU. For all certificates, revocation\n"
|
||||
"lists, and host-key documents, both the PEM and DER input formats are\n"
|
||||
"supported.";
|
||||
|
||||
static gint pv_arg_compare(gconstpointer arg_1, gconstpointer arg_2)
|
||||
{
|
||||
g_assert(arg_1);
|
||||
g_assert(arg_2);
|
||||
|
||||
PvComponentType a = ((PvArg *)arg_1)->type;
|
||||
PvComponentType b = ((PvArg *)arg_2)->type;
|
||||
|
||||
if (a < b)
|
||||
return -1;
|
||||
if (a == b)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static gint pv_arg_has_type(gconstpointer arg, gconstpointer type)
|
||||
{
|
||||
const PvArg *c = arg;
|
||||
const PvComponentType *t = type;
|
||||
|
||||
g_assert(arg);
|
||||
|
||||
if (c->type == *t)
|
||||
return 0;
|
||||
if (c->type < *t)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static gint pv_args_set_defaults(PvArgs *args, GError **err G_GNUC_UNUSED)
|
||||
{
|
||||
if (!args->psw_addr)
|
||||
args->psw_addr =
|
||||
g_strdup_printf("0x%lx", DEFAULT_INITIAL_PSW_ADDR);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gint pv_args_validate_options(PvArgs *args, GError **err)
|
||||
{
|
||||
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
||||
|
||||
if (args->unused_values->len > 0) {
|
||||
g_autofree gchar *unused = NULL;
|
||||
|
||||
for (gsize i = args->unused_values->len; i > 0; i--) {
|
||||
g_autofree gchar *tmp = unused;
|
||||
|
||||
unused = g_strjoin(" ", g_ptr_array_index(args->unused_values, i - 1),
|
||||
tmp,
|
||||
NULL);
|
||||
}
|
||||
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_INVALID_ARGUMENT,
|
||||
_("Unrecognized arguments: '%s'.\nUse 'genprotimg --help' for more information"),
|
||||
unused);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!args->output_path) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!g_slist_find_custom(args->comps, &KERNEL, pv_arg_has_type)) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Option '--image' is required.\nUse 'genprotimg --help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!args->host_keys || g_strv_length(args->host_keys) == 0) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Option '--host-key-document' is required.\nUse 'genprotimg --help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!args->no_verify &&
|
||||
(!args->untrusted_cert_paths ||
|
||||
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
||||
g_set_error(
|
||||
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Either specify the IBM Z signing key and (DigiCert) intermediate CA certificate\n"
|
||||
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
||||
"host-key document verification completely (at your own risk)."));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean cb_add_component(const gchar *option, const gchar *value,
|
||||
PvArgs *args, GError **err)
|
||||
{
|
||||
PvArg *comp = NULL;
|
||||
gint type = -1;
|
||||
|
||||
if (g_str_equal(option, "-i") || g_str_equal(option, "--image"))
|
||||
type = PV_COMP_TYPE_KERNEL;
|
||||
if (g_str_equal(option, "-r") || g_str_equal(option, "--ramdisk"))
|
||||
type = PV_COMP_TYPE_INITRD;
|
||||
if (g_str_equal(option, "-p") || g_str_equal(option, "--parmfile"))
|
||||
type = PV_COMP_TYPE_CMDLINE;
|
||||
|
||||
if (type < 0) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||
_("Invalid option '%s': "), option);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (g_slist_find_custom(args->comps, &type, pv_arg_has_type)) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||
_("Multiple values for option '%s'"), option);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
comp = pv_arg_new((PvComponentType)type, value);
|
||||
args->comps = g_slist_insert_sorted(args->comps, comp, pv_arg_compare);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
||||
PvArgs *args, GError **err)
|
||||
{
|
||||
gchar **args_option = NULL;
|
||||
|
||||
if (g_str_equal(option, "--root-ca"))
|
||||
args_option = &args->root_ca_path;
|
||||
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||
args_option = &args->output_path;
|
||||
if (g_str_equal(option, "--x-comp-key"))
|
||||
args_option = &args->xts_key_path;
|
||||
if (g_str_equal(option, "--x-comm-key"))
|
||||
args_option = &args->cust_comm_key_path;
|
||||
if (g_str_equal(option, "--x-header-key"))
|
||||
args_option = &args->cust_root_key_path;
|
||||
if (g_str_equal(option, "--x-pcf"))
|
||||
args_option = &args->pcf;
|
||||
if (g_str_equal(option, "--x-psw"))
|
||||
args_option = &args->psw_addr;
|
||||
if (g_str_equal(option, "--x-scf"))
|
||||
args_option = &args->scf;
|
||||
|
||||
if (!args_option) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||
_("Invalid option '%s': "), option);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (*args_option) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||
_("Multiple values for option '%s'"), option);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*args_option = g_strdup(value);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
||||
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
||||
GError **err G_GNUC_UNUSED)
|
||||
{
|
||||
args->log_level++;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
|
||||
const gchar *value, PvArgs *args,
|
||||
GError **err G_GNUC_UNUSED)
|
||||
{
|
||||
g_ptr_array_add(args->unused_values, g_strdup(value));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#define INDENT " "
|
||||
|
||||
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||
GError **err)
|
||||
{
|
||||
g_autoptr(GOptionContext) context = NULL;
|
||||
gboolean print_version = FALSE;
|
||||
GOptionGroup *group, *x_group;
|
||||
|
||||
g_autofree gchar *psw_desc = g_strdup_printf(
|
||||
_("Load from the specified hexadecimal ADDRESS.\n" INDENT
|
||||
"Optional; default: '0x%lx'."),
|
||||
DEFAULT_INITIAL_PSW_ADDR);
|
||||
GOptionEntry entries[] = {
|
||||
{ .long_name = "host-key-document",
|
||||
.short_name = 'k',
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY,
|
||||
.arg_data = &args->host_keys,
|
||||
.description =
|
||||
_("FILE specifies a host-key document. At least\n" INDENT
|
||||
"one is required."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "cert",
|
||||
.short_name = 'C',
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY,
|
||||
.arg_data = &args->untrusted_cert_paths,
|
||||
.description = _(
|
||||
"FILE contains a certificate that is used to\n" INDENT
|
||||
"establish a chain of trust for the verification\n" INDENT
|
||||
"of the host-key documents. The IBM Z signing\n" INDENT
|
||||
"key and intermediate CA certificate (signed\n" INDENT
|
||||
"by the root CA) are required."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "output",
|
||||
.short_name = 'o',
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _("Set FILE as the output file."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "image",
|
||||
.short_name = 'i',
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_add_component,
|
||||
.description = _("Use IMAGE as the Linux kernel image."),
|
||||
.arg_description = _("IMAGE") },
|
||||
{ .long_name = "ramdisk",
|
||||
.short_name = 'r',
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_add_component,
|
||||
.description = _("Use RAMDISK as the initial RAM disk\n" INDENT
|
||||
"(optional)."),
|
||||
.arg_description = _("RAMDISK") },
|
||||
{ .long_name = "parmfile",
|
||||
.short_name = 'p',
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_add_component,
|
||||
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
||||
"(optional)."),
|
||||
.arg_description = _("PARMFILE") },
|
||||
{ .long_name = "crl",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY,
|
||||
.arg_data = &args->crl_paths,
|
||||
.description = _(
|
||||
"FILE contains a certificate revocation list\n" INDENT
|
||||
"(optional)."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "offline",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_NONE,
|
||||
.arg_data = &args->offline,
|
||||
.description = _("Don't download CRLs (optional)."),
|
||||
.arg_description = NULL },
|
||||
{ .long_name = "root-ca",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _(
|
||||
"Set FILE as the trusted root CA and don't use the\n" INDENT
|
||||
"root CAs that are installed on the system (optional)."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "no-verify",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_NONE,
|
||||
.arg_data = &args->no_verify,
|
||||
.description = _("Disable the host-key document verification\n" INDENT
|
||||
"(optional)."),
|
||||
.arg_description = NULL },
|
||||
{ .long_name = "verbose",
|
||||
.short_name = 'V',
|
||||
.flags = G_OPTION_FLAG_NO_ARG,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_log_level,
|
||||
.description = _("Provide more detailed output (optional)."),
|
||||
.arg_description = NULL },
|
||||
{ .long_name = "version",
|
||||
.short_name = 'v',
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_NONE,
|
||||
.arg_data = &print_version,
|
||||
.description = _("Print the version and exit."),
|
||||
.arg_description = NULL },
|
||||
{ .long_name = G_OPTION_REMAINING,
|
||||
.short_name = 0,
|
||||
.flags = 0,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_remaining_values,
|
||||
.description = NULL,
|
||||
.arg_description = NULL },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
GOptionEntry x_entries[] = {
|
||||
{ .long_name = "x-comm-key",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _(
|
||||
"Use FILE as the customer communication key.\n" INDENT
|
||||
"Optional; default: auto-generated."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "x-comp-key",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _(
|
||||
"Use FILE as the AES 256-bit XTS key\n" INDENT
|
||||
"that is used for the component encryption.\n" INDENT
|
||||
"Optional; default: auto-generated."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "x-header-key",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _(
|
||||
"Use FILE as the AES 256-bit GCM header key\n" INDENT
|
||||
"that protects the PV header.\n" INDENT
|
||||
"Optional; default: auto-generated."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "x-pcf",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description =
|
||||
_("Specify the plaintext control flags\n" INDENT
|
||||
"as a hexadecimal value.\n" INDENT
|
||||
"Optional; default: '0x0'."),
|
||||
.arg_description = _("VALUE") },
|
||||
{ .long_name = "x-psw",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = psw_desc,
|
||||
.arg_description = _("ADDRESS") },
|
||||
{ .long_name = "x-scf",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_NONE,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _("Specify the secret control flags\n" INDENT
|
||||
"as a hexadecimal value.\n" INDENT
|
||||
"Optional; default: '0x0'."),
|
||||
.arg_description = _("VALUE") },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
context = g_option_context_new(
|
||||
_("- Create a protected virtualization image"));
|
||||
g_option_context_set_summary(context, _(summary));
|
||||
group = g_option_group_new(GETTEXT_PACKAGE, _("Application Options:"),
|
||||
_("Show help options"), args, NULL);
|
||||
g_option_group_add_entries(group, entries);
|
||||
g_option_context_set_main_group(context, group);
|
||||
|
||||
x_group = g_option_group_new("experimental", _("Experimental Options:"),
|
||||
_("Show experimental options"), args, NULL);
|
||||
g_option_group_add_entries(x_group, x_entries);
|
||||
g_option_context_add_group(context, x_group);
|
||||
if (!g_option_context_parse(context, argc, argv, err))
|
||||
return -1;
|
||||
|
||||
if (print_version) {
|
||||
g_printf(_("%s version %s\n"), tool_name, RELEASE_STRING);
|
||||
g_printf("%s\n", copyright_notice);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (pv_args_set_defaults(args, err) < 0)
|
||||
return -1;
|
||||
|
||||
return pv_args_validate_options(args, err);
|
||||
}
|
||||
|
||||
PvArgs *pv_args_new(void)
|
||||
{
|
||||
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
||||
|
||||
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
||||
return g_steal_pointer(&args);
|
||||
}
|
||||
|
||||
void pv_args_free(PvArgs *args)
|
||||
{
|
||||
if (!args)
|
||||
return;
|
||||
|
||||
g_free(args->pcf);
|
||||
g_free(args->scf);
|
||||
g_free(args->psw_addr);
|
||||
g_free(args->cust_root_key_path);
|
||||
g_free(args->cust_comm_key_path);
|
||||
g_free(args->gcm_iv_path);
|
||||
g_free(args->root_ca_path);
|
||||
g_strfreev(args->crl_paths);
|
||||
g_strfreev(args->untrusted_cert_paths);
|
||||
g_strfreev(args->host_keys);
|
||||
g_free(args->xts_key_path);
|
||||
g_slist_free_full(args->comps, (GDestroyNotify)pv_arg_free);
|
||||
g_ptr_array_free(args->unused_values, TRUE);
|
||||
g_free(args->output_path);
|
||||
g_free(args->tmp_dir);
|
||||
g_free(args);
|
||||
}
|
||||
|
||||
void pv_arg_free(PvArg *arg)
|
||||
{
|
||||
if (!arg)
|
||||
return;
|
||||
|
||||
g_free(arg->path);
|
||||
g_free(arg);
|
||||
}
|
||||
PvArg *pv_arg_new(PvComponentType type, const gchar *path)
|
||||
{
|
||||
g_autoptr(PvArg) ret = g_new0(struct pv_arg, 1);
|
||||
|
||||
ret->type = type;
|
||||
ret->path = g_strdup(path);
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
59
genprotimg/src/pv/pv_args.h
Normal file
59
genprotimg/src/pv/pv_args.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* PV arguments related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_ARGS_H
|
||||
#define PV_ARGS_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "pv_comp.h"
|
||||
|
||||
typedef struct pv_arg {
|
||||
PvComponentType type;
|
||||
gchar *path;
|
||||
} PvArg;
|
||||
|
||||
PvArg *pv_arg_new(PvComponentType type, const gchar *path);
|
||||
void pv_arg_free(PvArg *arg);
|
||||
|
||||
typedef struct {
|
||||
gint log_level;
|
||||
gint no_verify;
|
||||
gboolean offline;
|
||||
gchar *pcf;
|
||||
gchar *scf;
|
||||
gchar *psw_addr; /* PSW address which will be used for the start of
|
||||
* the actual component (e.g. Linux kernel)
|
||||
*/
|
||||
gchar *cust_root_key_path;
|
||||
gchar *cust_comm_key_path;
|
||||
gchar *gcm_iv_path;
|
||||
gchar **host_keys;
|
||||
gchar *root_ca_path; /* Trusted root CA used for the verification of the
|
||||
* chain of trust (if specified).
|
||||
*/
|
||||
gchar **untrusted_cert_paths;
|
||||
gchar **crl_paths;
|
||||
gchar *xts_key_path;
|
||||
GSList *comps;
|
||||
gchar *output_path;
|
||||
gchar *tmp_dir;
|
||||
GPtrArray *unused_values;
|
||||
} PvArgs;
|
||||
|
||||
PvArgs *pv_args_new(void);
|
||||
void pv_args_free(PvArgs *args);
|
||||
|
||||
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||
GError **err);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvArg, pv_arg_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvArgs, pv_args_free)
|
||||
|
||||
#endif
|
||||
446
genprotimg/src/pv/pv_comp.c
Normal file
446
genprotimg/src/pv/pv_comp.c
Normal file
@@ -0,0 +1,446 @@
|
||||
/*
|
||||
* PV component related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "common.h"
|
||||
#include "utils/align.h"
|
||||
#include "utils/buffer.h"
|
||||
#include "utils/crypto.h"
|
||||
#include "utils/file_utils.h"
|
||||
|
||||
#include "pv_comp.h"
|
||||
#include "pv_error.h"
|
||||
|
||||
static void comp_file_free(CompFile *comp)
|
||||
{
|
||||
if (!comp)
|
||||
return;
|
||||
|
||||
g_free(comp->path);
|
||||
g_free(comp);
|
||||
}
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CompFile, comp_file_free)
|
||||
|
||||
static PvComponent *pv_component_new(PvComponentType type, gsize size,
|
||||
PvComponentDataType d_type, void **data,
|
||||
GError **err)
|
||||
{
|
||||
g_autoptr(PvComponent) ret = g_new0(PvComponent, 1);
|
||||
|
||||
g_assert(type >= 0 && type <= UINT16_MAX);
|
||||
|
||||
ret->type = (int)type;
|
||||
ret->d_type = (int)d_type;
|
||||
ret->data = g_steal_pointer(data);
|
||||
ret->orig_size = size;
|
||||
|
||||
if (generate_tweak(&ret->tweak, (uint16_t)type, err) < 0)
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
|
||||
GError **err)
|
||||
{
|
||||
g_autoptr(CompFile) file = g_new0(CompFile, 1);
|
||||
gsize size;
|
||||
gint rc;
|
||||
|
||||
g_assert(path != NULL);
|
||||
|
||||
rc = file_size(path, &size, err);
|
||||
if (rc < 0)
|
||||
return NULL;
|
||||
|
||||
file->path = g_strdup(path);
|
||||
file->size = size;
|
||||
return pv_component_new(type, size, DATA_FILE, (void **)&file, err);
|
||||
}
|
||||
|
||||
PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
|
||||
GError **err)
|
||||
{
|
||||
g_assert(buf);
|
||||
|
||||
g_autoptr(Buffer) dup_buf = buffer_dup(buf, FALSE);
|
||||
return pv_component_new(type, buf->size, DATA_BUFFER, (void **)&dup_buf,
|
||||
err);
|
||||
}
|
||||
|
||||
void pv_component_free(PvComponent *component)
|
||||
{
|
||||
if (!component)
|
||||
return;
|
||||
|
||||
switch ((PvComponentDataType)component->d_type) {
|
||||
case DATA_BUFFER:
|
||||
buffer_clear(&component->buf);
|
||||
break;
|
||||
case DATA_FILE:
|
||||
comp_file_free(component->file);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free(component);
|
||||
}
|
||||
|
||||
gint pv_component_type(const PvComponent *component)
|
||||
{
|
||||
return component->type;
|
||||
}
|
||||
|
||||
const gchar *pv_component_name(const PvComponent *component)
|
||||
{
|
||||
gint type = pv_component_type(component);
|
||||
|
||||
switch ((PvComponentType)type) {
|
||||
case PV_COMP_TYPE_KERNEL:
|
||||
return "kernel";
|
||||
case PV_COMP_TYPE_INITRD:
|
||||
return "ramdisk";
|
||||
case PV_COMP_TYPE_CMDLINE:
|
||||
return "parmline";
|
||||
case PV_COMP_TYPE_STAGE3B:
|
||||
return "stage3b";
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
uint64_t pv_component_size(const PvComponent *component)
|
||||
{
|
||||
switch ((PvComponentDataType)component->d_type) {
|
||||
case DATA_BUFFER:
|
||||
return component->buf->size;
|
||||
case DATA_FILE:
|
||||
return component->file->size;
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
uint64_t pv_component_get_src_addr(const PvComponent *component)
|
||||
{
|
||||
return component->src_addr;
|
||||
}
|
||||
|
||||
uint64_t pv_component_get_orig_size(const PvComponent *component)
|
||||
{
|
||||
return component->orig_size;
|
||||
}
|
||||
|
||||
uint64_t pv_component_get_tweak_prefix(const PvComponent *component)
|
||||
{
|
||||
return GUINT64_FROM_BE(component->tweak.cmp_idx.data);
|
||||
}
|
||||
|
||||
gboolean pv_component_is_stage3b(const PvComponent *component)
|
||||
{
|
||||
return pv_component_type(component) == PV_COMP_TYPE_STAGE3B;
|
||||
}
|
||||
|
||||
gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_path,
|
||||
void *opaque, GError **err)
|
||||
{
|
||||
struct cipher_parms *parms = opaque;
|
||||
|
||||
switch ((PvComponentDataType)component->d_type) {
|
||||
case DATA_BUFFER: {
|
||||
g_autoptr(Buffer) enc_buf = NULL;
|
||||
|
||||
if (!(IS_PAGE_ALIGNED(pv_component_size(component)))) {
|
||||
g_autoptr(Buffer) new = NULL;
|
||||
|
||||
/* create a page aligned copy */
|
||||
new = buffer_dup(component->buf, TRUE);
|
||||
buffer_clear(&component->buf);
|
||||
component->buf = g_steal_pointer(&new);
|
||||
}
|
||||
enc_buf = encrypt_buf(parms, component->buf, err);
|
||||
if (!enc_buf)
|
||||
return -1;
|
||||
|
||||
buffer_clear(&component->buf);
|
||||
component->buf = g_steal_pointer(&enc_buf);
|
||||
return 0;
|
||||
}
|
||||
case DATA_FILE: {
|
||||
const gchar *comp_name = pv_component_name(component);
|
||||
gchar *path_in = component->file->path;
|
||||
g_autofree gchar *path_out = NULL;
|
||||
gsize orig_size;
|
||||
gsize prep_size;
|
||||
|
||||
g_assert(path_in);
|
||||
|
||||
path_out = g_build_filename(tmp_path, comp_name, NULL);
|
||||
if (encrypt_file(parms, path_in, path_out, &orig_size,
|
||||
&prep_size, err) < 0)
|
||||
return -1;
|
||||
|
||||
if (component->orig_size != orig_size) {
|
||||
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||
_("File has changed during the preparation '%s'"),
|
||||
path_out);
|
||||
return -1;
|
||||
}
|
||||
|
||||
g_free(component->file->path);
|
||||
component->file->size = prep_size;
|
||||
component->file->path = g_steal_pointer(&path_out);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/* Page align the size of the component */
|
||||
gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
||||
void *opaque G_GNUC_UNUSED, GError **err)
|
||||
{
|
||||
if (IS_PAGE_ALIGNED(pv_component_size(component)))
|
||||
return 0;
|
||||
|
||||
switch (component->d_type) {
|
||||
case DATA_BUFFER: {
|
||||
g_autoptr(Buffer) buf = NULL;
|
||||
|
||||
buf = buffer_dup(component->buf, TRUE);
|
||||
buffer_clear(&component->buf);
|
||||
component->buf = g_steal_pointer(&buf);
|
||||
return 0;
|
||||
} break;
|
||||
case DATA_FILE: {
|
||||
const gchar *comp_name = pv_component_name(component);
|
||||
g_autofree gchar *path_out =
|
||||
g_build_filename(tmp_path, comp_name, NULL);
|
||||
gchar *path_in = component->file->path;
|
||||
gsize size_out;
|
||||
|
||||
if (pad_file_right(path_out, path_in, &size_out, PAGE_SIZE,
|
||||
err) < 0)
|
||||
return -1;
|
||||
|
||||
g_free(component->file->path);
|
||||
component->file->path = g_steal_pointer(&path_out);
|
||||
component->file->size = size_out;
|
||||
return 0;
|
||||
} break;
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
/* Convert uint64_t address to byte array */
|
||||
static void uint64_to_uint8_buf(uint8_t dst[8], uint64_t addr)
|
||||
{
|
||||
uint8_t *p = (uint8_t *)&addr;
|
||||
|
||||
g_assert(dst);
|
||||
|
||||
for (gint i = 0; i < 8; i++) {
|
||||
/* cppcheck-suppress objectIndex */
|
||||
dst[i] = p[i];
|
||||
}
|
||||
}
|
||||
|
||||
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||
GError **err)
|
||||
{
|
||||
uint64_t addr = pv_component_get_src_addr(comp);
|
||||
uint64_t size = pv_component_size(comp);
|
||||
uint64_t cur = addr;
|
||||
int64_t nep = 0;
|
||||
|
||||
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
|
||||
|
||||
do {
|
||||
uint64_t cur_be = GUINT64_TO_BE(cur);
|
||||
uint8_t addr_buf[8];
|
||||
|
||||
uint64_to_uint8_buf(addr_buf, cur_be);
|
||||
|
||||
if (EVP_DigestUpdate(ctx, addr_buf, sizeof(addr_buf)) != 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("EVP_DigestUpdate failed"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
cur += PAGE_SIZE;
|
||||
nep++;
|
||||
} while (cur < addr + size);
|
||||
|
||||
return nep;
|
||||
}
|
||||
|
||||
int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||
GError **err)
|
||||
{
|
||||
uint64_t size = pv_component_size(comp);
|
||||
int64_t nep = 0;
|
||||
|
||||
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
|
||||
|
||||
switch (comp->d_type) {
|
||||
case DATA_BUFFER: {
|
||||
const Buffer *buf = comp->buf;
|
||||
|
||||
g_assert(buf->size <= INT64_MAX);
|
||||
g_assert(buf->size == size);
|
||||
|
||||
if (EVP_DigestUpdate(ctx, buf->data, buf->size) != 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("EVP_DigestUpdate failed"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
nep = (int64_t)(buf->size / PAGE_SIZE);
|
||||
break;
|
||||
}
|
||||
case DATA_FILE: {
|
||||
const gchar *in_path = comp->file->path;
|
||||
guchar in_buf[PAGE_SIZE];
|
||||
gsize num_bytes_read_total = 0;
|
||||
gsize num_bytes_read = 0;
|
||||
FILE *f_in;
|
||||
|
||||
f_in = file_open(in_path, "rb", err);
|
||||
if (!f_in)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
/* Read data in blocks. Update the digest
|
||||
* context each read.
|
||||
*/
|
||||
if (file_read(f_in, in_buf, sizeof(*in_buf),
|
||||
sizeof(in_buf), &num_bytes_read,
|
||||
err) < 0) {
|
||||
fclose(f_in);
|
||||
return -1;
|
||||
}
|
||||
num_bytes_read_total += num_bytes_read;
|
||||
|
||||
if (EVP_DigestUpdate(ctx, in_buf, sizeof(in_buf)) != 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("EVP_DigestUpdate failed"));
|
||||
fclose(f_in);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nep++;
|
||||
} while (num_bytes_read_total < pv_component_size(comp) &&
|
||||
num_bytes_read != 0);
|
||||
|
||||
if (num_bytes_read_total != pv_component_size(comp)) {
|
||||
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||
_("'%s' has changed during the preparation"),
|
||||
in_path);
|
||||
fclose(f_in);
|
||||
return -1;
|
||||
}
|
||||
fclose(f_in);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return nep;
|
||||
}
|
||||
|
||||
int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||
GError **err)
|
||||
{
|
||||
uint64_t size = pv_component_size(comp);
|
||||
const union tweak *tweak = &comp->tweak;
|
||||
g_autoptr(BIGNUM) tweak_num = NULL;
|
||||
int64_t nep = 0;
|
||||
|
||||
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
|
||||
|
||||
tweak_num = BN_bin2bn(tweak->data, sizeof(tweak->data), NULL);
|
||||
if (!tweak_num) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("BN_bin2bn failed"));
|
||||
}
|
||||
|
||||
for (uint64_t cur = 0; cur < size; cur += PAGE_SIZE) {
|
||||
guchar tmp[sizeof(tweak->data)] = { 0 };
|
||||
|
||||
g_assert(BN_num_bytes(tweak_num) >= 0);
|
||||
g_assert(sizeof(tmp) - (guint)BN_num_bytes(tweak_num) > 0);
|
||||
|
||||
if (BN_bn2binpad(tweak_num, tmp, sizeof(tmp)) < 0) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("BN_bn2binpad failed"));
|
||||
}
|
||||
|
||||
if (EVP_DigestUpdate(ctx, tmp, sizeof(tmp)) != 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("EVP_DigestUpdate failed"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* calculate new tweak value */
|
||||
if (BN_add_word(tweak_num, PAGE_SIZE) != 1) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
_("BN_add_word failed"));
|
||||
}
|
||||
|
||||
nep++;
|
||||
}
|
||||
|
||||
return nep;
|
||||
}
|
||||
|
||||
gint pv_component_write(const PvComponent *component, FILE *f, GError **err)
|
||||
{
|
||||
uint64_t offset = pv_component_get_src_addr(component);
|
||||
|
||||
g_assert(f);
|
||||
|
||||
switch (component->d_type) {
|
||||
case DATA_BUFFER: {
|
||||
const Buffer *buf = component->buf;
|
||||
|
||||
if (seek_and_write_buffer(f, buf, offset, err) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
case DATA_FILE: {
|
||||
const CompFile *file = component->file;
|
||||
|
||||
if (seek_and_write_file(f, file, offset, err) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached();
|
||||
}
|
||||
78
genprotimg/src/pv/pv_comp.h
Normal file
78
genprotimg/src/pv/pv_comp.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* PV component related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_COMP_H
|
||||
#define PV_COMP_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "utils/crypto.h"
|
||||
|
||||
/* The order of this enum also implicitly defines the order of the
|
||||
* components within the PV image!
|
||||
*/
|
||||
typedef enum {
|
||||
PV_COMP_TYPE_KERNEL = 0,
|
||||
PV_COMP_TYPE_CMDLINE = 1,
|
||||
PV_COMP_TYPE_INITRD = 2,
|
||||
PV_COMP_TYPE_STAGE3B = 3,
|
||||
} PvComponentType;
|
||||
|
||||
typedef enum {
|
||||
DATA_FILE = 0,
|
||||
DATA_BUFFER,
|
||||
} PvComponentDataType;
|
||||
|
||||
typedef struct comp_file {
|
||||
gchar *path;
|
||||
gsize size;
|
||||
} CompFile;
|
||||
|
||||
typedef struct {
|
||||
gint type; /* PvComponentType */
|
||||
gint d_type; /* PvComponentDataType */
|
||||
union {
|
||||
struct comp_file *file;
|
||||
Buffer *buf;
|
||||
void *data;
|
||||
};
|
||||
uint64_t src_addr;
|
||||
uint64_t orig_size;
|
||||
union tweak tweak; /* used for the AES XTS encryption */
|
||||
} PvComponent;
|
||||
|
||||
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
|
||||
GError **err);
|
||||
PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
|
||||
GError **err);
|
||||
void pv_component_free(PvComponent *component);
|
||||
gint pv_component_type(const PvComponent *component);
|
||||
const gchar *pv_component_name(const PvComponent *component);
|
||||
uint64_t pv_component_size(const PvComponent *component);
|
||||
uint64_t pv_component_get_src_addr(const PvComponent *component);
|
||||
uint64_t pv_component_get_orig_size(const PvComponent *component);
|
||||
uint64_t pv_component_get_tweak_prefix(const PvComponent *component);
|
||||
gboolean pv_component_is_stage3b(const PvComponent *component);
|
||||
gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_path,
|
||||
void *opaque, GError **err);
|
||||
gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
||||
void *opaque G_GNUC_UNUSED, GError **err);
|
||||
int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||
GError **err);
|
||||
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||
GError **err);
|
||||
int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||
GError **err);
|
||||
gint pv_component_write(const PvComponent *component, FILE *f, GError **err);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvComponent, pv_component_free)
|
||||
|
||||
#endif
|
||||
252
genprotimg/src/pv/pv_comps.c
Normal file
252
genprotimg/src/pv/pv_comps.c
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* PV components related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "boot/stage3b.h"
|
||||
#include "common.h"
|
||||
#include "utils/align.h"
|
||||
#include "utils/crypto.h"
|
||||
|
||||
#include "pv_comp.h"
|
||||
#include "pv_comps.h"
|
||||
#include "pv_error.h"
|
||||
#include "pv_stage3.h"
|
||||
|
||||
struct _pv_img_comps {
|
||||
gboolean finalized;
|
||||
uint64_t next_src;
|
||||
uint64_t nep;
|
||||
EVP_MD_CTX *ald; /* context used for the hash of the addresses */
|
||||
EVP_MD_CTX *pld; /* context used for the hash of the pages content */
|
||||
EVP_MD_CTX *tld; /* context used for the hash of the tweaks */
|
||||
GSList *comps; /* elements sorted by component type */
|
||||
};
|
||||
|
||||
void pv_img_comps_free(PvImgComps *comps)
|
||||
{
|
||||
if (!comps)
|
||||
return;
|
||||
|
||||
EVP_MD_CTX_free(comps->ald);
|
||||
EVP_MD_CTX_free(comps->pld);
|
||||
EVP_MD_CTX_free(comps->tld);
|
||||
g_slist_free_full(comps->comps, (GDestroyNotify)pv_component_free);
|
||||
g_free(comps);
|
||||
}
|
||||
|
||||
PvImgComps *pv_img_comps_new(const EVP_MD *ald_md, const EVP_MD *pld_md,
|
||||
const EVP_MD *tld_md, GError **err)
|
||||
{
|
||||
g_autoptr(PvImgComps) ret = g_new0(PvImgComps, 1);
|
||||
|
||||
ret->ald = digest_ctx_new(ald_md, err);
|
||||
if (!ret->ald)
|
||||
return NULL;
|
||||
|
||||
ret->pld = digest_ctx_new(pld_md, err);
|
||||
if (!ret->pld)
|
||||
return NULL;
|
||||
|
||||
ret->tld = digest_ctx_new(tld_md, err);
|
||||
if (!ret->tld)
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
guint pv_img_comps_length(const PvImgComps *comps)
|
||||
{
|
||||
return g_slist_length(comps->comps);
|
||||
}
|
||||
|
||||
/* Update hashes and nep */
|
||||
/* Returns 0 in case of success and -1 in case of a failure */
|
||||
static gint pv_img_comps_hash_comp(PvImgComps *comps, const PvComponent *comp,
|
||||
GError **err)
|
||||
{
|
||||
int64_t nep_1 = 0;
|
||||
int64_t nep_2 = 0;
|
||||
int64_t nep_3 = 0;
|
||||
|
||||
/* update pld */
|
||||
nep_1 = pv_component_update_pld(comp, comps->pld, err);
|
||||
if (nep_1 < 0)
|
||||
return -1;
|
||||
|
||||
/* update ald */
|
||||
nep_2 = pv_component_update_ald(comp, comps->ald, err);
|
||||
if (nep_2 < 0)
|
||||
return -1;
|
||||
|
||||
/* update tld */
|
||||
nep_3 = pv_component_update_tld(comp, comps->tld, err);
|
||||
if (nep_3 < 0)
|
||||
return -1;
|
||||
|
||||
g_assert(nep_1 == nep_2);
|
||||
g_assert(nep_2 == nep_3);
|
||||
|
||||
/* update comps->nep */
|
||||
g_assert_true(g_uint64_checked_add(&comps->nep, comps->nep,
|
||||
(uint64_t)nep_1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
|
||||
GError **err)
|
||||
{
|
||||
g_assert(comp);
|
||||
g_assert(*comp);
|
||||
g_assert(comps);
|
||||
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||
|
||||
uint64_t src_addr = comps->next_src;
|
||||
uint64_t src_size = pv_component_size(*comp)
|
||||
? PAGE_ALIGN(pv_component_size(*comp))
|
||||
: PAGE_SIZE;
|
||||
|
||||
if (comps->finalized) {
|
||||
g_set_error(err, PV_COMPONENT_ERROR, PV_COMPONENT_ERROR_FINALIZED,
|
||||
_("Failed to add component, image is already finalized"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* set the address of the component in the memory layout */
|
||||
(*comp)->src_addr = src_addr;
|
||||
|
||||
g_info("%12s:\t0x%012lx (%12ld / %12ld Bytes)",
|
||||
pv_component_name(*comp), pv_component_get_src_addr(*comp),
|
||||
pv_component_size(*comp), pv_component_get_orig_size(*comp));
|
||||
|
||||
/* append the component and pass the responsibility of @comp
|
||||
* to @comps
|
||||
*/
|
||||
comps->comps = g_slist_append(comps->comps, g_steal_pointer(comp));
|
||||
comps->next_src += src_size;
|
||||
|
||||
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||
g_assert(!*comp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct stage3b_args *pv_img_comps_get_stage3b_args(const PvImgComps *comps,
|
||||
struct psw_t *psw)
|
||||
{
|
||||
g_autofree struct stage3b_args *ret = g_new0(struct stage3b_args, 1);
|
||||
|
||||
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
|
||||
const PvComponent *img_comp = iterator->data;
|
||||
uint64_t src_addr, dst_size;
|
||||
|
||||
g_assert(img_comp);
|
||||
|
||||
src_addr = pv_component_get_src_addr(img_comp);
|
||||
dst_size = pv_component_get_orig_size(img_comp);
|
||||
|
||||
g_assert(dst_size <= pv_component_size(img_comp));
|
||||
|
||||
switch ((PvComponentType)pv_component_type(img_comp)) {
|
||||
case PV_COMP_TYPE_KERNEL:
|
||||
memblob_init(&ret->kernel, src_addr, dst_size);
|
||||
break;
|
||||
case PV_COMP_TYPE_CMDLINE:
|
||||
memblob_init(&ret->cmdline, src_addr, dst_size);
|
||||
break;
|
||||
case PV_COMP_TYPE_INITRD:
|
||||
memblob_init(&ret->initrd, src_addr, dst_size);
|
||||
break;
|
||||
case PV_COMP_TYPE_STAGE3B:
|
||||
/* nothing needs to be done since it is the
|
||||
* stage3b itself
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* for `stage3b_args` big-endian format must be used */
|
||||
ret->psw.mask = GUINT64_TO_BE(psw->mask);
|
||||
ret->psw.addr = GUINT64_TO_BE(psw->addr);
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err)
|
||||
{
|
||||
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||
|
||||
if (!IS_PAGE_ALIGNED(offset)) {
|
||||
g_set_error(err, PV_IMAGE_ERROR, PV_IMAGE_ERROR_OFFSET,
|
||||
_("Offset must be page aligned"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pv_img_comps_length(comps) > 0) {
|
||||
g_set_error(err, PV_IMAGE_ERROR, PV_IMAGE_ERROR_OFFSET,
|
||||
_("Offset cannot be changed after a component was added"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
comps->next_src += offset;
|
||||
|
||||
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||
return 0;
|
||||
}
|
||||
|
||||
GSList *pv_img_comps_get_comps(const PvImgComps *comps)
|
||||
{
|
||||
return comps->comps;
|
||||
}
|
||||
|
||||
gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
|
||||
Buffer **ald_digest, Buffer **tld_digest,
|
||||
uint64_t *nep, GError **err)
|
||||
{
|
||||
g_autoptr(Buffer) tmp_pld_digest = NULL;
|
||||
g_autoptr(Buffer) tmp_ald_digest = NULL;
|
||||
g_autoptr(Buffer) tmp_tld_digest = NULL;
|
||||
|
||||
comps->finalized = TRUE;
|
||||
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
|
||||
const PvComponent *comp = iterator->data;
|
||||
|
||||
/* update hashes and nep */
|
||||
if (pv_img_comps_hash_comp(comps, comp, err) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
tmp_pld_digest = digest_ctx_finalize(comps->pld, err);
|
||||
if (!tmp_pld_digest)
|
||||
return -1;
|
||||
|
||||
tmp_ald_digest = digest_ctx_finalize(comps->ald, err);
|
||||
if (!tmp_ald_digest)
|
||||
return -1;
|
||||
|
||||
tmp_tld_digest = digest_ctx_finalize(comps->tld, err);
|
||||
if (!tmp_tld_digest)
|
||||
return -1;
|
||||
|
||||
*pld_digest = g_steal_pointer(&tmp_pld_digest);
|
||||
*ald_digest = g_steal_pointer(&tmp_ald_digest);
|
||||
*tld_digest = g_steal_pointer(&tmp_tld_digest);
|
||||
*nep = comps->nep;
|
||||
return 0;
|
||||
}
|
||||
|
||||
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n)
|
||||
{
|
||||
return g_slist_nth_data(comps->comps, n);
|
||||
}
|
||||
42
genprotimg/src/pv/pv_comps.h
Normal file
42
genprotimg/src/pv/pv_comps.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* PV components related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_COMPS_H
|
||||
#define PV_COMPS_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "boot/stage3b.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
#include "pv_comp.h"
|
||||
|
||||
typedef struct _pv_img_comps PvImgComps;
|
||||
|
||||
PvImgComps *pv_img_comps_new(const EVP_MD *ald_md, const EVP_MD *pld_md,
|
||||
const EVP_MD *tld_md, GError **err);
|
||||
guint pv_img_comps_length(const PvImgComps *comps);
|
||||
GSList *pv_img_comps_get_comps(const PvImgComps *comps);
|
||||
struct stage3b_args *pv_img_comps_get_stage3b_args(const PvImgComps *comps,
|
||||
struct psw_t *psw);
|
||||
gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
|
||||
GError **err);
|
||||
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n);
|
||||
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err);
|
||||
gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
|
||||
Buffer **ald_digest, Buffer **tld_digest,
|
||||
uint64_t *nep, GError **err);
|
||||
void pv_img_comps_free(PvImgComps *comps);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvImgComps, pv_img_comps_free)
|
||||
|
||||
#endif
|
||||
37
genprotimg/src/pv/pv_error.c
Normal file
37
genprotimg/src/pv/pv_error.c
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* PV error related functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "pv_error.h"
|
||||
|
||||
GQuark pv_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pv-error-quark");
|
||||
}
|
||||
|
||||
GQuark pv_crypto_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pv-crypto-error-quark");
|
||||
}
|
||||
|
||||
GQuark pv_component_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pv-component-error-quark");
|
||||
}
|
||||
|
||||
GQuark pv_image_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pv-image-error-quark");
|
||||
}
|
||||
|
||||
GQuark pv_parse_error_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pv-parse-error-quark");
|
||||
}
|
||||
89
genprotimg/src/pv/pv_error.h
Normal file
89
genprotimg/src/pv/pv_error.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* PV error related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_ERROR_H
|
||||
#define PV_ERROR_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
GQuark pv_error_quark(void);
|
||||
GQuark pv_parse_error_quark(void);
|
||||
GQuark pv_component_error_quark(void);
|
||||
GQuark pv_crypto_error_quark(void);
|
||||
GQuark pv_image_error_quark(void);
|
||||
|
||||
#define PV_ERROR pv_error_quark()
|
||||
#define PV_PARSE_ERROR pv_parse_error_quark()
|
||||
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
|
||||
#define PV_COMPONENT_ERROR pv_component_error_quark()
|
||||
#define PV_IMAGE_ERROR pv_image_error_quark()
|
||||
|
||||
typedef enum {
|
||||
PV_ERROR_IPIB_SIZE,
|
||||
PV_ERROR_PV_HDR_SIZE,
|
||||
PV_ERROR_INTERNAL,
|
||||
PV_ERROR_CURL_INIT_FAILED,
|
||||
PV_ERROR_DOWNLOAD_FAILED,
|
||||
} PvErrors;
|
||||
|
||||
typedef enum {
|
||||
PV_PARSE_ERROR_OK = 0,
|
||||
PV_PARSE_ERROR_SYNTAX,
|
||||
PR_PARSE_ERROR_INVALID_ARGUMENT,
|
||||
PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
} PvParseErrors;
|
||||
|
||||
typedef enum {
|
||||
PV_COMPONENT_ERROR_UNALIGNED,
|
||||
PV_COMPONENT_ERROR_FINALIZED,
|
||||
} PvComponentErrors;
|
||||
|
||||
typedef enum {
|
||||
PV_IMAGE_ERROR_OFFSET,
|
||||
PV_IMAGE_ERROR_FINALIZED,
|
||||
} PvImageErrors;
|
||||
|
||||
typedef enum {
|
||||
PV_CRYPTO_ERROR_VERIFICATION,
|
||||
PV_CRYPTO_ERROR_INIT,
|
||||
PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
PV_CRYPTO_ERROR_DERIVE,
|
||||
PV_CRYPTO_ERROR_KEYGENERATION,
|
||||
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||
PV_CRYPTO_ERROR_INVALID_PARM,
|
||||
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||
PV_CRYPTO_ERROR_INVALID_VALIDITY_PERIOD,
|
||||
PV_CRYPTO_ERROR_EXPIRED,
|
||||
PV_CRYPTO_ERROR_NOT_VALID_YET,
|
||||
PV_CRYPTO_ERROR_LOAD_CRL,
|
||||
PV_CRYPTO_ERROR_NO_PUBLIC_KEY,
|
||||
PV_CRYPTO_ERROR_INVALID_SIGNATURE_ALGORITHM,
|
||||
PV_CRYPTO_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
||||
PV_CRYPTO_ERROR_INVALID_URI,
|
||||
PV_CRYPTO_ERROR_CRL_DOWNLOAD_FAILED,
|
||||
PV_CRYPTO_ERROR_CERT_SIGNATURE_INVALID,
|
||||
PV_CRYPTO_ERROR_CRL_SIGNATURE_INVALID,
|
||||
PV_CRYPTO_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
|
||||
PV_CRYPTO_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
|
||||
PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
PV_CRYPTO_ERROR_MALFORMED_CERTIFICATE,
|
||||
PV_CRYPTO_ERROR_NO_CRL,
|
||||
PV_CRYPTO_ERROR_LOAD_ROOT_CA,
|
||||
PV_CRYPTO_ERROR_LOAD_DEFAULT_CA,
|
||||
PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
|
||||
PV_CRYPTO_ERROR_WRONG_CA_USED,
|
||||
PV_CRYPTO_ERROR_SKID_AKID_MISMATCH,
|
||||
PV_CRYPTO_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
||||
PV_CRYPTO_ERROR_FAILED_DOWNLOAD_CRL,
|
||||
PV_CRYPTO_ERROR_NO_CRLDP,
|
||||
PV_CRYPTO_ERROR_CERT_REVOKED,
|
||||
} PvCryptoErrors;
|
||||
|
||||
#endif
|
||||
293
genprotimg/src/pv/pv_hdr.c
Normal file
293
genprotimg/src/pv/pv_hdr.c
Normal file
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* PV header related functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <openssl/aes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "include/pv_crypto_def.h"
|
||||
#include "utils/buffer.h"
|
||||
#include "utils/crypto.h"
|
||||
|
||||
#include "pv_comp.h"
|
||||
#include "pv_hdr.h"
|
||||
#include "pv_image.h"
|
||||
|
||||
void pv_hdr_free(PvHdr *hdr)
|
||||
{
|
||||
if (!hdr)
|
||||
return;
|
||||
|
||||
g_free(hdr->optional_items);
|
||||
g_free(hdr->encrypted);
|
||||
g_free(hdr->slots);
|
||||
g_free(hdr);
|
||||
}
|
||||
|
||||
uint32_t pv_hdr_size(const PvHdr *hdr)
|
||||
{
|
||||
return GUINT32_FROM_BE(hdr->head.phs);
|
||||
}
|
||||
|
||||
gboolean pv_hdr_uses_encryption(const PvHdr *hdr)
|
||||
{
|
||||
return !(GUINT64_FROM_BE(hdr->head.pcf) & PV_CFLAG_NO_DECRYPTION);
|
||||
}
|
||||
|
||||
uint64_t pv_hdr_enc_size(const PvHdr *hdr)
|
||||
{
|
||||
return GUINT64_FROM_BE(hdr->head.sea);
|
||||
}
|
||||
|
||||
uint32_t pv_hdr_enc_size_casted(const PvHdr *hdr)
|
||||
{
|
||||
uint64_t size = pv_hdr_enc_size(hdr);
|
||||
|
||||
if (size > UINT32_MAX)
|
||||
g_abort();
|
||||
|
||||
return (uint32_t)size;
|
||||
}
|
||||
|
||||
static guint pv_hdr_tag_size(const PvHdr *hdr)
|
||||
{
|
||||
return sizeof(hdr->tag);
|
||||
}
|
||||
|
||||
uint32_t pv_hdr_aad_size(const PvHdr *hdr)
|
||||
{
|
||||
return pv_hdr_size(hdr) - pv_hdr_enc_size_casted(hdr) -
|
||||
pv_hdr_tag_size(hdr);
|
||||
}
|
||||
|
||||
uint64_t pv_hdr_get_nks(const PvHdr *hdr)
|
||||
{
|
||||
return GUINT64_FROM_BE(hdr->head.nks);
|
||||
}
|
||||
|
||||
/* In-place modification of ``buf`` */
|
||||
static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, Buffer *buf,
|
||||
GError **err)
|
||||
{
|
||||
uint32_t hdr_len = pv_hdr_size(hdr);
|
||||
uint32_t aad_len = pv_hdr_aad_size(hdr);
|
||||
guint tag_len = pv_hdr_tag_size(hdr);
|
||||
uint32_t enc_len = pv_hdr_enc_size_casted(hdr);
|
||||
const Buffer aad_part = { .data = buf->data, .size = aad_len };
|
||||
Buffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
|
||||
.size = enc_len };
|
||||
Buffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
|
||||
.size = tag_len };
|
||||
struct cipher_parms parms;
|
||||
int64_t c_len;
|
||||
|
||||
g_assert(aad_part.size + enc_part.size + tag_part.size == buf->size);
|
||||
g_assert(img->cust_root_key->size <= INT_MAX);
|
||||
g_assert(img->gcm_iv->size <= INT_MAX);
|
||||
g_assert(EVP_CIPHER_key_length(img->gcm_cipher) ==
|
||||
(int)img->cust_root_key->size);
|
||||
g_assert(EVP_CIPHER_iv_length(img->gcm_cipher) == (int)img->gcm_iv->size);
|
||||
|
||||
parms.key = img->cust_root_key;
|
||||
parms.iv_or_tweak = img->gcm_iv;
|
||||
parms.cipher = img->gcm_cipher;
|
||||
|
||||
/* in-place encryption */
|
||||
c_len = gcm_encrypt(&enc_part, &aad_part, &parms, &enc_part, &tag_part, err);
|
||||
if (c_len < 0)
|
||||
return -1;
|
||||
|
||||
g_assert(c_len == enc_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initializes the unencrypted, but integrity protected part of the PV
|
||||
* header
|
||||
*/
|
||||
static gint pv_hdr_aad_init(PvHdr *hdr, const PvImage *img, GError **err)
|
||||
{
|
||||
g_autofree union ecdh_pub_key *cust_pub_key = NULL;
|
||||
struct pv_hdr_key_slot *hdr_slot = hdr->slots;
|
||||
struct pv_hdr_head *head = &hdr->head;
|
||||
g_autoptr(Buffer) pld = NULL;
|
||||
g_autoptr(Buffer) ald = NULL;
|
||||
g_autoptr(Buffer) tld = NULL;
|
||||
uint64_t nep = 0;
|
||||
|
||||
g_assert(sizeof(head->iv) == img->gcm_iv->size);
|
||||
g_assert(sizeof(head->cust_pub_key) == sizeof(*cust_pub_key));
|
||||
|
||||
cust_pub_key = evp_pkey_to_ecdh_pub_key(img->cust_pub_priv_key, err);
|
||||
if (!cust_pub_key)
|
||||
return -1;
|
||||
|
||||
head->magic = GUINT64_TO_BE(PV_MAGIC_NUMBER);
|
||||
head->version = GUINT32_TO_BE(PV_VERSION_1);
|
||||
/* ``phs`` is already set so we can skip it here */
|
||||
memcpy(head->iv, img->gcm_iv->data, sizeof(head->iv));
|
||||
/* ``nks`` is already set so we can skip it here */
|
||||
/* ``sea`` is already set so we can skip it here */
|
||||
head->pcf = GUINT64_TO_BE(img->pcf);
|
||||
memcpy(head->cust_pub_key.data, cust_pub_key,
|
||||
sizeof(head->cust_pub_key));
|
||||
|
||||
if (pv_img_calc_pld_ald_tld_nep(img, &pld, &ald, &tld, &nep, err) < 0)
|
||||
return -1;
|
||||
|
||||
g_assert(sizeof(head->pld) == pld->size);
|
||||
g_assert(sizeof(head->ald) == ald->size);
|
||||
g_assert(sizeof(head->tld) == tld->size);
|
||||
|
||||
head->nep = GUINT64_TO_BE(nep);
|
||||
memcpy(head->pld, pld->data, sizeof(head->pld));
|
||||
memcpy(head->ald, ald->data, sizeof(head->ald));
|
||||
memcpy(head->tld, tld->data, sizeof(head->tld));
|
||||
|
||||
/* set the key slots */
|
||||
for (GSList *iterator = img->key_slots; iterator; iterator = iterator->next) {
|
||||
const PvHdrKeySlot *slot = iterator->data;
|
||||
|
||||
g_assert(slot);
|
||||
|
||||
/* the memory for the slots is pre-allocated so we
|
||||
* have not to allocate and since PvHdrKeySlot is
|
||||
* stored in the big-edian format we can simply use
|
||||
* memcpy.
|
||||
*/
|
||||
memcpy(hdr_slot++, slot, sizeof(*slot));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initializes the encrypted and also integrity protected part of the
|
||||
* PV header
|
||||
*/
|
||||
static gint pv_hdr_enc_init(PvHdr *hdr, const PvImage *img, GError **err)
|
||||
{
|
||||
struct pv_hdr_encrypted *enc = hdr->encrypted;
|
||||
const PvComponent *stage3b;
|
||||
struct psw_t psw;
|
||||
|
||||
g_assert(sizeof(enc->img_enc_key_1) + sizeof(enc->img_enc_key_2) ==
|
||||
EVP_CIPHER_key_length(img->xts_cipher));
|
||||
g_assert(sizeof(enc->cust_comm_key) == img->cust_comm_key->size);
|
||||
g_assert(img->xts_key->size ==
|
||||
(guint)EVP_CIPHER_key_length(img->xts_cipher));
|
||||
|
||||
stage3b = pv_img_get_stage3b_comp(img, err);
|
||||
if (!stage3b)
|
||||
return -1;
|
||||
|
||||
memcpy(enc->cust_comm_key, img->cust_comm_key->data,
|
||||
sizeof(enc->cust_comm_key));
|
||||
memcpy(enc->img_enc_key_1, img->xts_key->data,
|
||||
sizeof(enc->img_enc_key_1));
|
||||
memcpy(enc->img_enc_key_2,
|
||||
(uint8_t *)img->xts_key->data + sizeof(enc->img_enc_key_1),
|
||||
sizeof(enc->img_enc_key_2));
|
||||
|
||||
/* Setup program check handler */
|
||||
psw.mask = GUINT64_TO_BE(DEFAULT_INITIAL_PSW_MASK);
|
||||
psw.addr = GUINT64_TO_BE(pv_component_get_src_addr(stage3b));
|
||||
enc->psw = psw;
|
||||
enc->scf = GUINT64_TO_BE(img->scf);
|
||||
enc->noi = GUINT32_TO_BE(g_slist_length(img->optional_items));
|
||||
|
||||
/* set the optional items */
|
||||
for (GSList *iterator = img->optional_items; iterator;
|
||||
iterator = iterator->next) {
|
||||
const struct pv_hdr_opt_item *item = iterator->data;
|
||||
|
||||
g_assert(item);
|
||||
|
||||
/* not supported in the first version */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PvHdr *pv_hdr_new(const PvImage *img, GError **err)
|
||||
{
|
||||
uint32_t noi = g_slist_length(img->optional_items);
|
||||
uint32_t hdr_size = pv_img_get_pv_hdr_size(img);
|
||||
gsize nks = g_slist_length(img->key_slots);
|
||||
uint32_t sea = pv_img_get_enc_size(img);
|
||||
g_autoptr(PvHdr) ret = NULL;
|
||||
|
||||
g_assert(nks > 0);
|
||||
/* must be a multiple of AES block size */
|
||||
g_assert(sea % AES_BLOCK_SIZE == 0);
|
||||
g_assert(sea >= sizeof(struct pv_hdr_encrypted));
|
||||
|
||||
ret = g_new0(PvHdr, 1);
|
||||
ret->slots = g_new0(struct pv_hdr_key_slot, nks);
|
||||
ret->head.phs = GUINT32_TO_BE(hdr_size);
|
||||
ret->head.nks = GUINT64_TO_BE(nks);
|
||||
ret->head.sea = GUINT64_TO_BE(sea);
|
||||
|
||||
ret->encrypted = g_new0(struct pv_hdr_encrypted, 1);
|
||||
ret->optional_items = g_malloc0(sea - sizeof(struct pv_hdr_encrypted));
|
||||
ret->encrypted->noi = GUINT32_TO_BE(noi);
|
||||
|
||||
if (pv_hdr_aad_init(ret, img, err) < 0)
|
||||
return NULL;
|
||||
|
||||
if (pv_hdr_enc_init(ret, img, err) < 0)
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
static void pv_hdr_memcpy(const PvHdr *hdr, const Buffer *dst)
|
||||
{
|
||||
uint64_t nks = pv_hdr_get_nks(hdr);
|
||||
uint8_t *data;
|
||||
|
||||
g_assert(dst->size == pv_hdr_size(hdr));
|
||||
g_assert(pv_hdr_enc_size_casted(hdr) >= sizeof(*hdr->encrypted));
|
||||
|
||||
data = memcpy(dst->data, &hdr->head, sizeof(hdr->head));
|
||||
data = memcpy(data + sizeof(hdr->head), hdr->slots,
|
||||
sizeof(struct pv_hdr_key_slot) * nks);
|
||||
data = memcpy(data + sizeof(struct pv_hdr_key_slot) * nks,
|
||||
hdr->encrypted, sizeof(*hdr->encrypted));
|
||||
if (pv_hdr_enc_size_casted(hdr) - sizeof(*hdr->encrypted) > 0) {
|
||||
(void)memcpy(data + sizeof(*hdr->encrypted),
|
||||
hdr->optional_items,
|
||||
pv_hdr_enc_size_casted(hdr) - sizeof(*hdr->encrypted));
|
||||
}
|
||||
}
|
||||
|
||||
Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
|
||||
enum PvCryptoMode mode, GError **err)
|
||||
{
|
||||
uint32_t hdr_size = pv_hdr_size(hdr);
|
||||
g_autoptr(Buffer) ret = NULL;
|
||||
|
||||
ret = buffer_alloc(hdr_size);
|
||||
pv_hdr_memcpy(hdr, ret);
|
||||
|
||||
if (mode == PV_ENCRYPT) {
|
||||
/* The buffer @ret is modified in-place */
|
||||
if (pv_hdr_encrypt(hdr, img, ret, err) < 0)
|
||||
return NULL;
|
||||
} else {
|
||||
/* Simply copy the tag */
|
||||
memcpy((uint8_t *)ret->data + hdr_size - pv_hdr_tag_size(hdr),
|
||||
hdr->tag, pv_hdr_tag_size(hdr));
|
||||
}
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
36
genprotimg/src/pv/pv_hdr.h
Normal file
36
genprotimg/src/pv/pv_hdr.h
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* PV header related functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_HDR_H
|
||||
#define PV_HDR_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "include/pv_hdr_def.h"
|
||||
#include "utils/crypto.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
#include "pv_image.h"
|
||||
|
||||
PvHdr *pv_hdr_new(const PvImage *img, GError **err);
|
||||
void pv_hdr_free(PvHdr *hdr);
|
||||
G_GNUC_UNUSED gboolean pv_hdr_uses_encryption(const PvHdr *hdr);
|
||||
Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
|
||||
enum PvCryptoMode mode, GError **err);
|
||||
uint32_t pv_hdr_size(const PvHdr *hdr);
|
||||
uint32_t pv_hdr_aad_size(const PvHdr *hdr);
|
||||
uint64_t pv_hdr_enc_size(const PvHdr *hdr);
|
||||
uint32_t pv_hdr_enc_size_casted(const PvHdr *hdr);
|
||||
uint64_t pv_hdr_get_nks(const PvHdr *hdr);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvHdr, pv_hdr_free)
|
||||
|
||||
#endif
|
||||
1000
genprotimg/src/pv/pv_image.c
Normal file
1000
genprotimg/src/pv/pv_image.c
Normal file
File diff suppressed because it is too large
Load Diff
68
genprotimg/src/pv/pv_image.h
Normal file
68
genprotimg/src/pv/pv_image.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* PV image related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_IMAGE_H
|
||||
#define PV_IMAGE_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
#include "pv_args.h"
|
||||
#include "pv_comp.h"
|
||||
#include "pv_comps.h"
|
||||
#include "pv_stage3.h"
|
||||
|
||||
typedef struct {
|
||||
gchar *tmp_dir; /* directory used for temporary files */
|
||||
Buffer *stage3a; /* stage3a containing IPIB and PV header */
|
||||
gsize stage3a_bin_size; /* size of stage3a.bin */
|
||||
struct psw_t stage3a_psw; /* (short) PSW that is written to
|
||||
* location 0 of the created image
|
||||
*/
|
||||
struct psw_t initial_psw; /* PSW loaded by stage3b */
|
||||
EVP_PKEY *cust_pub_priv_key; /* customer private/public key */
|
||||
GSList *host_pub_keys; /* public host keys */
|
||||
gint nid; /* Elliptic Curve used for the key derivation */
|
||||
/* keys and cipher used for the AES-GCM encryption */
|
||||
Buffer *cust_root_key;
|
||||
Buffer *gcm_iv;
|
||||
const EVP_CIPHER *gcm_cipher;
|
||||
/* Information for the IPIB and PV header */
|
||||
uint64_t pcf;
|
||||
uint64_t scf;
|
||||
Buffer *cust_comm_key;
|
||||
const EVP_CIPHER *cust_comm_cipher;
|
||||
Buffer *xts_key;
|
||||
const EVP_CIPHER *xts_cipher;
|
||||
GSList *key_slots;
|
||||
GSList *optional_items;
|
||||
PvImgComps *comps;
|
||||
} PvImage;
|
||||
|
||||
PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err);
|
||||
void pv_img_free(PvImage *img);
|
||||
gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err);
|
||||
gint pv_img_finalize(PvImage *img, const gchar *stage3b_path, GError **err);
|
||||
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
|
||||
Buffer **tld, uint64_t *nep, GError **err);
|
||||
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err);
|
||||
const PvComponent *pv_img_get_stage3b_comp(const PvImage *img, GError **err);
|
||||
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err);
|
||||
uint32_t pv_img_get_enc_size(const PvImage *img);
|
||||
uint32_t pv_img_get_pv_hdr_size(const PvImage *img);
|
||||
gint pv_img_write(PvImage *img, const gchar *path, GError **err);
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvImage, pv_img_free)
|
||||
|
||||
#endif
|
||||
128
genprotimg/src/pv/pv_ipib.c
Normal file
128
genprotimg/src/pv/pv_ipib.c
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* PV IPIB related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "boot/ipl.h"
|
||||
#include "boot/s390.h"
|
||||
#include "common.h"
|
||||
#include "include/pv_hdr_def.h"
|
||||
#include "lib/zt_common.h"
|
||||
#include "utils/align.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
#include "pv_comp.h"
|
||||
#include "pv_error.h"
|
||||
#include "pv_ipib.h"
|
||||
|
||||
uint64_t pv_ipib_get_size(uint32_t num_comp)
|
||||
{
|
||||
gsize ipib_size = sizeof(struct ipl_pl_hdr) +
|
||||
sizeof(struct ipl_pb0_pv) +
|
||||
num_comp * sizeof(struct ipl_pb0_pv_comp);
|
||||
|
||||
/* the minimal size is one page */
|
||||
return MAX(ipib_size, PAGE_SIZE);
|
||||
}
|
||||
|
||||
static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
|
||||
const Buffer *hdr)
|
||||
{
|
||||
g_assert(sizeof(struct ipl_pl_hdr) <= UINT32_MAX);
|
||||
g_assert(sizeof(struct ipl_pb0_pv_comp) <= UINT32_MAX);
|
||||
g_assert(sizeof(struct ipl_pb0_pv) <= UINT32_MAX);
|
||||
g_assert(ipib);
|
||||
|
||||
guint comps_length = g_slist_length(comps);
|
||||
uint32_t ipl_pl_hdr_size = (uint32_t)sizeof(struct ipl_pl_hdr);
|
||||
struct ipl_pb0_pv *pv = &ipib->pv;
|
||||
uint32_t ipib_comps_size;
|
||||
uint32_t blk0_len;
|
||||
uint32_t ipib_size;
|
||||
gsize i;
|
||||
|
||||
g_assert_true(
|
||||
g_uint_checked_mul(&ipib_comps_size, comps_length,
|
||||
(uint32_t)sizeof(struct ipl_pb0_pv_comp)));
|
||||
g_assert_true(g_uint_checked_add(&blk0_len, (uint32_t)sizeof(*pv),
|
||||
ipib_comps_size));
|
||||
g_assert(ipl_pl_hdr_size + blk0_len <= PAGE_SIZE);
|
||||
|
||||
ipib_size = MAX(ipl_pl_hdr_size + blk0_len, (uint32_t)PAGE_SIZE);
|
||||
g_assert(pv_ipib_get_size(comps_length) == ipib_size);
|
||||
|
||||
pv->pbt = IPL_TYPE_PV;
|
||||
pv->len = GUINT32_TO_BE(blk0_len);
|
||||
pv->num_comp = GUINT32_TO_BE(comps_length);
|
||||
/* both values will be overwritten during the IPL process by
|
||||
* the stage3a loader
|
||||
*/
|
||||
pv->pv_hdr_addr = GUINT64_TO_BE(0x0);
|
||||
pv->pv_hdr_size = GUINT64_TO_BE(hdr->size);
|
||||
|
||||
ipib->hdr.len = GUINT32_TO_BE(ipib_size);
|
||||
ipib->hdr.version = IPL_PARM_BLOCK_VERSION;
|
||||
|
||||
i = 0;
|
||||
for (GSList *iterator = comps; iterator; iterator = iterator->next, i++) {
|
||||
const PvComponent *comp = iterator->data;
|
||||
uint64_t comp_addr, comp_size;
|
||||
|
||||
g_assert(comp);
|
||||
|
||||
comp_addr = pv_component_get_src_addr(comp);
|
||||
comp_size = pv_component_size(comp);
|
||||
|
||||
g_assert(IS_PAGE_ALIGNED(comp_size));
|
||||
|
||||
pv->components[i].addr = GUINT64_TO_BE(comp_addr);
|
||||
pv->components[i].len = GUINT64_TO_BE(comp_size);
|
||||
pv->components[i].tweak_pref =
|
||||
GUINT64_TO_BE(pv_component_get_tweak_prefix(comp));
|
||||
if (i > 0) {
|
||||
/* tweak prefixes of the components must grow
|
||||
* strictly monotonous
|
||||
*/
|
||||
g_assert(GUINT64_FROM_BE(pv->components[i].tweak_pref) >
|
||||
GUINT64_FROM_BE(pv->components[i - 1].tweak_pref));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err)
|
||||
{
|
||||
uint64_t ipib_size = pv_ipib_get_size(g_slist_length(comps));
|
||||
g_autoptr(IplParameterBlock) ret = NULL;
|
||||
|
||||
if (ipib_size > PV_V1_IPIB_MAX_SIZE) {
|
||||
g_set_error(err, PV_ERROR, PV_ERROR_IPIB_SIZE,
|
||||
_("IPIB size is too large: %lu < %lu"), ipib_size,
|
||||
PAGE_SIZE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = g_malloc0(ipib_size);
|
||||
if (pv_ipib_init(ret, comps, hdr) < 0)
|
||||
return NULL;
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
void pv_ipib_free(IplParameterBlock *ipib)
|
||||
{
|
||||
if (!ipib)
|
||||
return;
|
||||
|
||||
g_free(ipib);
|
||||
}
|
||||
27
genprotimg/src/pv/pv_ipib.h
Normal file
27
genprotimg/src/pv/pv_ipib.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* PV IPIB related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_IPIB_H
|
||||
#define PV_IPIB_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/ipl.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
typedef struct ipl_parameter_block IplParameterBlock;
|
||||
|
||||
uint64_t pv_ipib_get_size(uint32_t num_comp);
|
||||
IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err);
|
||||
void pv_ipib_free(IplParameterBlock *ipib);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(IplParameterBlock, pv_ipib_free)
|
||||
|
||||
#endif
|
||||
26
genprotimg/src/pv/pv_opt_item.c
Normal file
26
genprotimg/src/pv/pv_opt_item.c
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* PV optional item related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include "pv_opt_item.h"
|
||||
|
||||
uint32_t pv_opt_item_size(const struct pv_hdr_opt_item *item G_GNUC_UNUSED)
|
||||
{
|
||||
/* not implemented yet */
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
void pv_opt_item_free(struct pv_hdr_opt_item *item)
|
||||
{
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
g_free(item);
|
||||
}
|
||||
20
genprotimg/src/pv/pv_opt_item.h
Normal file
20
genprotimg/src/pv/pv_opt_item.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* PV optional item related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_OPT_ITEM_H
|
||||
#define PV_OPT_ITEM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "include/pv_hdr_def.h"
|
||||
|
||||
uint32_t pv_opt_item_size(const struct pv_hdr_opt_item *item);
|
||||
void pv_opt_item_free(struct pv_hdr_opt_item *item);
|
||||
|
||||
#endif
|
||||
164
genprotimg/src/pv/pv_stage3.c
Normal file
164
genprotimg/src/pv/pv_stage3.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* PV stage3 loader related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "boot/ipl.h"
|
||||
#include "boot/stage3a.h"
|
||||
#include "boot/stage3b.h"
|
||||
#include "common.h"
|
||||
#include "utils/align.h"
|
||||
|
||||
#include "pv_error.h"
|
||||
#include "pv_stage3.h"
|
||||
|
||||
#define STAGE3A_ARGS(data_ptr, loader_size) \
|
||||
((struct stage3a_args *)((uint64_t)data_ptr + loader_size - \
|
||||
sizeof(struct stage3a_args)))
|
||||
|
||||
static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
|
||||
gsize args_size, gsize data_size,
|
||||
gboolean data_aligned, GError **err)
|
||||
{
|
||||
g_autoptr(GMappedFile) mapped_file = NULL;
|
||||
g_autoptr(Buffer) ret = NULL;
|
||||
gsize size, tmp_loader_size;
|
||||
gchar *loader_data;
|
||||
|
||||
g_assert(loader_size);
|
||||
|
||||
mapped_file = g_mapped_file_new(filename, FALSE, err);
|
||||
if (!mapped_file)
|
||||
return NULL;
|
||||
|
||||
loader_data = g_mapped_file_get_contents(mapped_file);
|
||||
if (!loader_data) {
|
||||
g_set_error(err, G_FILE_ERROR, G_FILE_ERROR_BADF,
|
||||
_("File '%s' is empty"), filename);
|
||||
return NULL;
|
||||
}
|
||||
tmp_loader_size = g_mapped_file_get_length(mapped_file);
|
||||
|
||||
if (tmp_loader_size < args_size) {
|
||||
g_set_error(err, G_FILE_ERROR, G_FILE_ERROR_BADF,
|
||||
_("File size less than expected: %lu < %ln"),
|
||||
tmp_loader_size, loader_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* For example, the PV header and IPIB data must be page
|
||||
* aligned.
|
||||
*/
|
||||
size = (data_aligned ? PAGE_ALIGN(tmp_loader_size) : tmp_loader_size) +
|
||||
data_size;
|
||||
|
||||
ret = buffer_alloc(size);
|
||||
|
||||
/* copy the loader "template" */
|
||||
memcpy(ret->data, loader_data, tmp_loader_size);
|
||||
/* reset our dummy data (offsets and length) to zeros */
|
||||
memset((uint8_t *)ret->data + tmp_loader_size - args_size, 0,
|
||||
args_size);
|
||||
*loader_size = tmp_loader_size;
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
|
||||
gsize data_size, GError **err)
|
||||
{
|
||||
return loader_getblob(filename, loader_size,
|
||||
sizeof(struct stage3a_args), data_size, TRUE,
|
||||
err);
|
||||
}
|
||||
|
||||
/* For the memory layout see stage3a.lds */
|
||||
/* Set the right offsets and sizes in the stage3a template + add
|
||||
* the IPIB block with the PV header
|
||||
*/
|
||||
static gint stage3a_set_data(Buffer *loader, gsize loader_size,
|
||||
const Buffer *hdr, struct ipl_parameter_block *ipib,
|
||||
GError **err)
|
||||
{
|
||||
uint32_t ipib_size = GUINT32_FROM_BE(ipib->hdr.len);
|
||||
gsize args_size = sizeof(struct stage3a_args);
|
||||
uint32_t hdr_size = (uint32_t)hdr->size;
|
||||
uint64_t args_addr, next_data_addr;
|
||||
|
||||
if (hdr->size > UINT32_MAX) {
|
||||
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||
_("Invalid header size: %zu"), hdr->size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* we assume here that the loader ``stage3a`` is loaded page
|
||||
* aligned in the guest
|
||||
*/
|
||||
args_addr = (uint64_t)loader->data + loader_size - args_size;
|
||||
|
||||
/* therefore `next_data_addr` is also page aligned */
|
||||
next_data_addr = (uint64_t)loader->data + PAGE_ALIGN(loader_size);
|
||||
|
||||
/* copy IPIB data */
|
||||
memcpy((void *)next_data_addr, ipib, ipib_size);
|
||||
|
||||
/* set IPIB offset in relation to the stage3a arguments */
|
||||
STAGE3A_ARGS(loader->data, loader_size)->ipib_offs =
|
||||
GUINT64_TO_BE(next_data_addr - args_addr);
|
||||
|
||||
next_data_addr = next_data_addr + PAGE_ALIGN(ipib_size);
|
||||
/* copy PV header */
|
||||
memcpy((void *)next_data_addr, hdr->data, hdr_size);
|
||||
/* set PV header size and offset in relation to the stage3a
|
||||
* arguments
|
||||
*/
|
||||
STAGE3A_ARGS(loader->data, loader_size)->hdr_offs =
|
||||
GUINT64_TO_BE(next_data_addr - args_addr);
|
||||
STAGE3A_ARGS(loader->data, loader_size)->hdr_size = GUINT64_TO_BE(hdr_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint build_stage3a(Buffer *loader, gsize loader_size, const Buffer *hdr,
|
||||
struct ipl_parameter_block *ipib, GError **err)
|
||||
{
|
||||
return stage3a_set_data(loader, loader_size, hdr, ipib, err);
|
||||
}
|
||||
|
||||
Buffer *stage3b_getblob(const gchar *filename, GError **err)
|
||||
{
|
||||
g_autoptr(Buffer) ret = NULL;
|
||||
gsize rb_size;
|
||||
|
||||
ret = loader_getblob(filename, &rb_size, sizeof(struct stage3b_args), 0,
|
||||
FALSE, err);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
g_assert(ret->size == rb_size);
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
void build_stage3b(Buffer *stage3b, const struct stage3b_args *args)
|
||||
{
|
||||
g_assert(stage3b->size > sizeof(*args));
|
||||
|
||||
/* at the end of the stage3b there are the stage3b args
|
||||
* positioned
|
||||
*/
|
||||
memcpy((uint8_t *)stage3b->data + stage3b->size - sizeof(*args), args,
|
||||
sizeof(*args));
|
||||
}
|
||||
|
||||
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size)
|
||||
{
|
||||
arg->src = GUINT64_TO_BE(src);
|
||||
arg->size = GUINT64_TO_BE(size);
|
||||
}
|
||||
30
genprotimg/src/pv/pv_stage3.h
Normal file
30
genprotimg/src/pv/pv_stage3.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* PV stage3 loader related definitions and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_STAGE3_H
|
||||
#define PV_STAGE3_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "boot/ipl.h"
|
||||
#include "boot/s390.h"
|
||||
#include "boot/stage3b.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
|
||||
gsize data_size, GError **err);
|
||||
gint build_stage3a(Buffer *dc, gsize dc_size, const Buffer *hdr,
|
||||
struct ipl_parameter_block *ipib, GError **err);
|
||||
Buffer *stage3b_getblob(const gchar *filename, GError **err);
|
||||
void build_stage3b(Buffer *stage3b, const struct stage3b_args *args);
|
||||
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size);
|
||||
|
||||
#endif
|
||||
24
genprotimg/src/utils/align.h
Normal file
24
genprotimg/src/utils/align.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Alignment utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_UTILS_ALIGN_H
|
||||
#define PV_UTILS_ALIGN_H
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define IS_ALIGNED(addr, size) (!(addr & (size - 1)))
|
||||
|
||||
/* align addr to the next page boundary */
|
||||
#define PAGE_ALIGN(addr) ALIGN((unsigned long)addr, PAGE_SIZE)
|
||||
|
||||
/* test whether an address is aligned to PAGE_SIZE or not */
|
||||
#define IS_PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE)
|
||||
|
||||
#endif
|
||||
69
genprotimg/src/utils/buffer.c
Normal file
69
genprotimg/src/utils/buffer.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Buffer functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "align.h"
|
||||
#include "buffer.h"
|
||||
#include "common.h"
|
||||
#include "file_utils.h"
|
||||
|
||||
Buffer *buffer_alloc(gsize size)
|
||||
{
|
||||
Buffer *ret = g_new0(Buffer, 1);
|
||||
|
||||
ret->data = g_malloc0(size);
|
||||
ret->size = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned)
|
||||
{
|
||||
Buffer *ret;
|
||||
gsize size;
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
size = buf->size;
|
||||
if (page_aligned)
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
ret = buffer_alloc(size);
|
||||
|
||||
/* content will be 0-right-padded */
|
||||
memcpy(ret->data, buf->data, buf->size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gint buffer_write(const Buffer *buf, FILE *file, GError **err)
|
||||
{
|
||||
return file_write(file, buf->data, buf->size, 1, NULL, err);
|
||||
}
|
||||
|
||||
void buffer_free(Buffer *buf)
|
||||
{
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
g_free(buf->data);
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
void buffer_clear(Buffer **buf)
|
||||
{
|
||||
if (!buf || !*buf)
|
||||
return;
|
||||
|
||||
buffer_free(*buf);
|
||||
*buf = NULL;
|
||||
}
|
||||
31
genprotimg/src/utils/buffer.h
Normal file
31
genprotimg/src/utils/buffer.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Buffer definition and functions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_UTILS_BUFFER_H
|
||||
#define PV_UTILS_BUFFER_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
typedef struct Buffer {
|
||||
void *data;
|
||||
gsize size; /* in bytes */
|
||||
} Buffer;
|
||||
|
||||
Buffer *buffer_alloc(gsize size);
|
||||
void buffer_free(Buffer *buf);
|
||||
void buffer_clear(Buffer **buf);
|
||||
gint buffer_write(const Buffer *buf, FILE *file, GError **err);
|
||||
Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Buffer, buffer_free)
|
||||
|
||||
#endif
|
||||
2105
genprotimg/src/utils/crypto.c
Normal file
2105
genprotimg/src/utils/crypto.c
Normal file
File diff suppressed because it is too large
Load Diff
175
genprotimg/src/utils/crypto.h
Normal file
175
genprotimg/src/utils/crypto.h
Normal file
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* General cryptography helper functions and definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_UTILS_CRYPTO_H
|
||||
#define PV_UTILS_CRYPTO_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <openssl/asn1.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/ec.h>
|
||||
#include <openssl/ecdh.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/ossl_typ.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/sha.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "include/pv_crypto_def.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#define AES_256_GCM_IV_SIZE 12
|
||||
#define AES_256_GCM_TAG_SIZE 16
|
||||
|
||||
#define AES_256_XTS_TWEAK_SIZE 16
|
||||
#define AES_256_XTS_KEY_SIZE 64
|
||||
|
||||
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
|
||||
#define CRL_DOWNLOAD_MAX_SIZE (1024 * 1024) /* in bytes */
|
||||
|
||||
enum PvCryptoMode {
|
||||
PV_ENCRYPT,
|
||||
PV_DECRYPT,
|
||||
};
|
||||
|
||||
typedef GSList HostKeyList;
|
||||
|
||||
/* play nice with g_autoptr */
|
||||
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
|
||||
typedef STACK_OF(X509) STACK_OF_X509;
|
||||
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
|
||||
|
||||
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
|
||||
void STACK_OF_X509_free(STACK_OF_X509 *stack);
|
||||
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
|
||||
|
||||
typedef struct {
|
||||
X509 *cert;
|
||||
const gchar *path;
|
||||
} x509_with_path;
|
||||
|
||||
x509_with_path *x509_with_path_new(X509 *cert, const gchar *path);
|
||||
void x509_with_path_free(x509_with_path *cert);
|
||||
|
||||
typedef struct {
|
||||
X509 *cert;
|
||||
STACK_OF_X509_CRL *crls;
|
||||
} x509_pair;
|
||||
|
||||
x509_pair *x509_pair_new(X509 **cert, STACK_OF_X509_CRL **crls);
|
||||
void x509_pair_free(x509_pair *pair);
|
||||
|
||||
/* Register auto cleanup functions */
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free);
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free);
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free);
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_pair, x509_pair_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(x509_with_path, x509_with_path_free)
|
||||
|
||||
union cmp_index {
|
||||
struct {
|
||||
uint16_t idx;
|
||||
guchar rand[6];
|
||||
} __packed;
|
||||
uint64_t data;
|
||||
};
|
||||
|
||||
/* The tweak is always stored in big endian format */
|
||||
union tweak {
|
||||
struct {
|
||||
union cmp_index cmp_idx;
|
||||
uint64_t page_idx; /* page index */
|
||||
} __packed;
|
||||
uint8_t data[AES_256_XTS_TWEAK_SIZE];
|
||||
};
|
||||
|
||||
struct cipher_parms {
|
||||
const EVP_CIPHER *cipher;
|
||||
const Buffer *key;
|
||||
const Buffer *iv_or_tweak;
|
||||
};
|
||||
|
||||
int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
|
||||
gint verify_flags, GError **err);
|
||||
void pv_crypto_init(void);
|
||||
void pv_crypto_cleanup(void);
|
||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void);
|
||||
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
||||
gint verify_flags, int level, GError **err);
|
||||
X509 *load_cert_from_file(const char *path, GError **err);
|
||||
X509_CRL *load_crl_from_file(const gchar *path, GError **err);
|
||||
GSList *load_certificates(const gchar *const *cert_paths, GError **err);
|
||||
STACK_OF_X509 *get_x509_stack(const GSList *x509_with_path_list);
|
||||
X509_STORE *store_setup(const gchar *root_ca_path,
|
||||
const gchar * const *crl_paths,
|
||||
GError **err);
|
||||
int store_set_verify_param(X509_STORE *store, GError **err);
|
||||
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
|
||||
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
||||
const ASN1_OCTET_STRING *skid, GError **err);
|
||||
X509_NAME *c2b_name(const X509_NAME *name);
|
||||
|
||||
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||
STACK_OF_X509_CRL *store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert,
|
||||
GError **err);
|
||||
X509_STORE_CTX *create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain,
|
||||
GError **err);
|
||||
gint verify_cert(X509 *cert, X509_STORE_CTX *ctx, GError **err);
|
||||
X509_CRL *get_first_valid_crl(X509_STORE_CTX *ctx, X509 *cert, GError **err);
|
||||
void store_setup_crl_download(X509_STORE *st);
|
||||
EVP_PKEY *read_ec_pubkey_cert(X509 *cert, gint nid, GError **err);
|
||||
|
||||
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
|
||||
Buffer *generate_aes_key(guint size, GError **err);
|
||||
Buffer *generate_aes_iv(guint size, GError **err);
|
||||
EVP_PKEY *generate_ec_key(gint nid, GError **err);
|
||||
gint generate_tweak(union tweak *tweak, uint16_t i, GError **err);
|
||||
union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err);
|
||||
EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err);
|
||||
Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
|
||||
Buffer *sha256_buffer(const Buffer *buf, GError **err);
|
||||
int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
|
||||
const struct cipher_parms *parms, Buffer *out,
|
||||
Buffer *tag, GError **err);
|
||||
gint encrypt_file(const struct cipher_parms *parms, const gchar *in_path,
|
||||
const gchar *path_out, gsize *in_size, gsize *out_size,
|
||||
GError **err);
|
||||
Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
|
||||
GError **err);
|
||||
G_GNUC_UNUSED Buffer *decrypt_buf(const struct cipher_parms *parms,
|
||||
const Buffer *in, GError **err);
|
||||
|
||||
#endif
|
||||
121
genprotimg/src/utils/curl.c
Normal file
121
genprotimg/src/utils/curl.c
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Libcurl utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gtypes.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "pv/pv_error.h"
|
||||
|
||||
#include "curl.h"
|
||||
|
||||
struct UserData {
|
||||
GByteArray *buffer;
|
||||
guint max_size;
|
||||
};
|
||||
|
||||
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
g_assert(userdata);
|
||||
struct UserData *data = (struct UserData *)userdata;
|
||||
GByteArray *buffer = data->buffer;
|
||||
guint64 actual_size;
|
||||
size_t err;
|
||||
|
||||
g_assert(buffer);
|
||||
|
||||
if (!g_uint64_checked_mul(&actual_size, size, nmemb))
|
||||
g_abort();
|
||||
|
||||
/* Signal an error condition by returning a amount that differs
|
||||
* from the amount passed to the callback. This results in a
|
||||
* CURLE_WRITE_ERROR.
|
||||
*/
|
||||
err = actual_size + 1;
|
||||
|
||||
if (actual_size > G_MAXUINT)
|
||||
return err;
|
||||
|
||||
data->buffer = g_byte_array_append(buffer, (guchar *)ptr, (guint)actual_size);
|
||||
if (data->buffer->len > data->max_size)
|
||||
return err;
|
||||
|
||||
return actual_size;
|
||||
}
|
||||
|
||||
gint curl_init(void)
|
||||
{
|
||||
if (curl_global_init(CURL_GLOBAL_ALL) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void curl_cleanup(void)
|
||||
{
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
|
||||
GError **err)
|
||||
{
|
||||
g_autoptr(GByteArray) ret = NULL;
|
||||
g_autoptr(CURL) handle = NULL;
|
||||
g_autofree gchar *agent = NULL;
|
||||
struct UserData userdata;
|
||||
CURLcode rc;
|
||||
|
||||
/* set up curl session */
|
||||
handle = curl_easy_init();
|
||||
if (!handle)
|
||||
g_abort();
|
||||
|
||||
/* follow redirection */
|
||||
rc = curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1l);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, timeout_ms);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1l);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
agent = g_strdup_printf("%s/%s", tool_name, RELEASE_STRING);
|
||||
rc = curl_easy_setopt(handle, CURLOPT_USERAGENT, agent);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_callback);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
ret = g_byte_array_new();
|
||||
userdata.buffer = ret;
|
||||
userdata.max_size = max_size;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_WRITEDATA, (void *)&userdata);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
rc = curl_easy_setopt(handle, CURLOPT_URL, url);
|
||||
if (rc != CURLE_OK)
|
||||
goto curl_err;
|
||||
|
||||
rc = curl_easy_perform(handle);
|
||||
if (rc != CURLE_OK) {
|
||||
g_set_error(err, PV_ERROR, PV_ERROR_DOWNLOAD_FAILED,
|
||||
_("download failed: %s"), curl_easy_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return g_steal_pointer(&ret);
|
||||
curl_err:
|
||||
g_set_error(err, PV_ERROR,
|
||||
PV_ERROR_CURL_INIT_FAILED,
|
||||
_("cURL initialization failed: %s"),
|
||||
curl_easy_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
25
genprotimg/src/utils/curl.h
Normal file
25
genprotimg/src/utils/curl.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Libcurl utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_UTILS_LIBCURL_H
|
||||
#define PV_UTILS_LIBCURL_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
|
||||
|
||||
GByteArray *curl_download(const gchar *url, long timeout_ms, guint max_size,
|
||||
GError **err);
|
||||
gint curl_init(void);
|
||||
void curl_cleanup(void);
|
||||
|
||||
#endif /* PV_UTILS_LIBCURL_H */
|
||||
234
genprotimg/src/utils/file_utils.c
Normal file
234
genprotimg/src/utils/file_utils.c
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* General file utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <limits.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "pv/pv_error.h"
|
||||
|
||||
#include "align.h"
|
||||
#include "buffer.h"
|
||||
#include "common.h"
|
||||
#include "file_utils.h"
|
||||
|
||||
FILE *file_open(const gchar *filename, const gchar *mode, GError **err)
|
||||
{
|
||||
FILE *f = fopen(filename, mode);
|
||||
|
||||
if (!f) {
|
||||
g_set_error(err, G_FILE_ERROR,
|
||||
(gint)g_file_error_from_errno(errno),
|
||||
_("Failed to open file '%s': %s"), filename,
|
||||
g_strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
gint file_size(const gchar *filename, gsize *size, GError **err)
|
||||
{
|
||||
GStatBuf st_buf;
|
||||
|
||||
g_assert(size);
|
||||
|
||||
if (g_stat(filename, &st_buf) != 0) {
|
||||
g_set_error(err, G_FILE_ERROR,
|
||||
(gint)g_file_error_from_errno(errno),
|
||||
_("Failed to get file status '%s': %s"), filename,
|
||||
g_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!S_ISREG(st_buf.st_mode)) {
|
||||
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||
_("File '%s' is not a regular file"), filename);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (st_buf.st_size < 0) {
|
||||
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||
_("Invalid file size for '%s': %zu"), filename,
|
||||
st_buf.st_size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*size = (gsize)st_buf.st_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Returns 0 on success, otherwise -1. Stores the total number of
|
||||
* elements successfully read in @count_read
|
||||
*/
|
||||
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
|
||||
gsize *count_read, GError **err)
|
||||
{
|
||||
gsize tmp_count_read;
|
||||
|
||||
tmp_count_read = fread(ptr, size, count, in);
|
||||
if (count_read)
|
||||
*count_read = tmp_count_read;
|
||||
|
||||
if (ferror(in)) {
|
||||
g_set_error(err, G_FILE_ERROR, 0, _("Failed to read file"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
|
||||
gsize *count_written, GError **err)
|
||||
{
|
||||
gsize tmp_count_written;
|
||||
|
||||
tmp_count_written = fwrite(ptr, size, count, out);
|
||||
if (count_written)
|
||||
*count_written = tmp_count_written;
|
||||
|
||||
if (tmp_count_written != count || ferror(out)) {
|
||||
g_set_error(err, G_FILE_ERROR, 0, _("Failed to write file"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gint file_seek(FILE *f, uint64_t offset, GError **err)
|
||||
{
|
||||
gint rc;
|
||||
|
||||
if (offset > LONG_MAX) {
|
||||
g_set_error(err, PV_ERROR, 0, _("Offset is too large"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = fseek(f, (long)offset, SEEK_SET);
|
||||
if (rc != 0) {
|
||||
g_set_error(err, G_FILE_ERROR,
|
||||
(gint)g_file_error_from_errno(errno),
|
||||
_("Failed to seek: '%s'"), g_strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
|
||||
GError **err)
|
||||
{
|
||||
gsize bytes_read, bytes_written;
|
||||
gsize total_bytes_read = 0;
|
||||
FILE *i = NULL;
|
||||
gchar buf[4096];
|
||||
gint ret = -1;
|
||||
|
||||
if (file_seek(o, offset, err) < 0)
|
||||
return -1;
|
||||
|
||||
i = file_open(ifile->path, "rb", err);
|
||||
if (!i)
|
||||
return -1;
|
||||
|
||||
do {
|
||||
if (file_read(i, buf, 1, sizeof(buf), &bytes_read, err) < 0) {
|
||||
g_prefix_error(err, _("Failed to read file '%s': "),
|
||||
ifile->path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (bytes_read == 0)
|
||||
break;
|
||||
|
||||
total_bytes_read += bytes_read;
|
||||
|
||||
if (file_write(o, buf, bytes_read, 1, &bytes_written, err) < 0)
|
||||
goto err;
|
||||
} while (bytes_written != 0);
|
||||
|
||||
if (ifile->size != total_bytes_read) {
|
||||
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||
_("'%s' has changed during the preparation"),
|
||||
ifile->path);
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
fclose(i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gint seek_and_write_buffer(FILE *o, const Buffer *buf, uint64_t offset,
|
||||
GError **err)
|
||||
{
|
||||
if (file_seek(o, offset, err) < 0)
|
||||
return -1;
|
||||
|
||||
if (buffer_write(buf, o, err) < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint pad_file_right(const gchar *path_out, const gchar *path_in, gsize *size_out,
|
||||
guint padding, GError **err)
|
||||
{
|
||||
FILE *f_in, *f_out = NULL;
|
||||
guchar buf[padding];
|
||||
gsize num_bytes_written;
|
||||
gsize num_bytes_read;
|
||||
uint64_t size_in = 0;
|
||||
gint ret = -1;
|
||||
|
||||
*size_out = 0;
|
||||
f_in = file_open(path_in, "rb", err);
|
||||
if (!f_in)
|
||||
goto err;
|
||||
|
||||
f_out = file_open(path_out, "wb", err);
|
||||
if (!f_out)
|
||||
goto err;
|
||||
|
||||
do {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (file_read(f_in, buf, 1, sizeof(buf), &num_bytes_read, err) < 0) {
|
||||
g_prefix_error(err, _("Failed to read file '%s': "),
|
||||
path_in);
|
||||
goto err;
|
||||
}
|
||||
|
||||
size_in += num_bytes_read;
|
||||
|
||||
if (file_write(f_out, buf, 1, sizeof(buf), &num_bytes_written, err)) {
|
||||
g_prefix_error(err, _("Failed to write file '%s': "),
|
||||
path_out);
|
||||
goto err;
|
||||
}
|
||||
|
||||
*size_out += num_bytes_written;
|
||||
} while (num_bytes_read == padding);
|
||||
|
||||
g_assert(num_bytes_written == ALIGN(num_bytes_read, padding));
|
||||
|
||||
ret = 0;
|
||||
err:
|
||||
if (f_out)
|
||||
fclose(f_out);
|
||||
if (f_in)
|
||||
fclose(f_in);
|
||||
return ret;
|
||||
}
|
||||
34
genprotimg/src/utils/file_utils.h
Normal file
34
genprotimg/src/utils/file_utils.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* General file utils
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_FILE_UTILS_H
|
||||
#define PV_FILE_UTILS_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "pv/pv_comp.h"
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
FILE *file_open(const gchar *filename, const gchar *mode, GError **err);
|
||||
gint file_size(const gchar *filename, gsize *size, GError **err);
|
||||
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
|
||||
gsize *count_read, GError **err);
|
||||
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
|
||||
gsize *count_written, GError **err);
|
||||
gint pad_file_right(const gchar *path_out, const gchar *path_in,
|
||||
gsize *size_out, guint padding, GError **err);
|
||||
gint seek_and_write_buffer(FILE *out, const Buffer *buf, uint64_t offset,
|
||||
GError **err);
|
||||
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
|
||||
GError **err);
|
||||
|
||||
#endif
|
||||
16
hsci/Makefile
Normal file
16
hsci/Makefile
Normal file
@@ -0,0 +1,16 @@
|
||||
include ../common.mak
|
||||
|
||||
all:
|
||||
|
||||
install: hsci
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< hsci >$(DESTDIR)$(BINDIR)/hsci; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/hsci; \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 hsci.8 \
|
||||
$(DESTDIR)$(MANDIR)/man8
|
||||
|
||||
clean:
|
||||
|
||||
.PHONY: all install clean
|
||||
436
hsci/hsci
Executable file
436
hsci/hsci
Executable file
@@ -0,0 +1,436 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# hsci - Tool to manage HiperSockets Converged Interfaces (HSCI)
|
||||
#
|
||||
# Copyright IBM Corp. 2020
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
hsdev=""
|
||||
ndev=""
|
||||
hsci=""
|
||||
hsdev_mac=""
|
||||
hsif_pnetid=""
|
||||
netif_pnetid=""
|
||||
hsci_pnetid=""
|
||||
|
||||
function usage {
|
||||
cat <<-EOD
|
||||
Usage: hsci COMMAND [OPTION]
|
||||
|
||||
This tool is designed to control and show HSCI (HiperSockets Converged
|
||||
Interfaces) settings. A HiperSockets interface and an external network
|
||||
interface are converged into an HSCI interface.
|
||||
|
||||
COMMANDS
|
||||
add HIPERSOCKETS_DEV NET_DEV Adds an HSCI interface
|
||||
del HSCI_NAME Deletes an HSCI interface
|
||||
show Lists the configured HSCI interfaces
|
||||
|
||||
OPTIONS:
|
||||
-v, --version Prints the version number of the hsci tool and exits
|
||||
-h, --help Displays the help information for the command
|
||||
EOD
|
||||
}
|
||||
|
||||
function prereqs_check {
|
||||
if ! [ -x "$(command -v ip)" ]; then
|
||||
echo "Error: No iproute2 installed on this system" >&2
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
function check_pnetids {
|
||||
# get PNETID of the HS
|
||||
local hsif_pnetids=""
|
||||
local netif_pnetids=""
|
||||
|
||||
if [ -e /sys/class/net/$hsdev/device/util_string ]; then
|
||||
hsif_pnetids="$(cat /sys/class/net/$hsdev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
else
|
||||
if [ -e /sys/class/net/$hsdev/device/chpid ]; then
|
||||
chpid="$(cat /sys/class/net/$hsdev/device/chpid | tr [:upper:] [:lower:])"
|
||||
hsif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
fi
|
||||
fi
|
||||
if [ "$hsif_pnetids" != "" ]; then
|
||||
port_hsif="$(cat /sys/class/net/$hsdev/dev_port)"
|
||||
(( idx=16*$port_hsif+1 ))
|
||||
(( end=$idx+15 ))
|
||||
hsif_pnetid="$(echo "$hsif_pnetids" | cut -c $idx-$end | tr -d ' ')"
|
||||
fi
|
||||
|
||||
# get PNETID of the NET_DEV
|
||||
if [ -e /sys/class/net/$ndev/device/util_string ]; then
|
||||
netif_pnetids="$(cat /sys/class/net/$ndev/device/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
else
|
||||
if [ -e /sys/class/net/$ndev/device/chpid ]; then
|
||||
chpid="$(cat /sys/class/net/$ndev/device/chpid | tr [:upper:] [:lower:])"
|
||||
netif_pnetids="$(cat /sys/devices/css0/chp0.$chpid/util_string | tr -d '\000' | iconv -f IBM-1047 -t ASCII)"
|
||||
fi
|
||||
fi
|
||||
if [ "$netif_pnetids" != "" ]; then
|
||||
port_netif="$(cat /sys/class/net/$ndev/dev_port)"
|
||||
(( idx=16*$port_netif+1 ))
|
||||
(( end=$idx+15 ))
|
||||
netif_pnetid="$(echo "$netif_pnetids" | cut -c $idx-$end | tr -d ' ')"
|
||||
fi
|
||||
|
||||
#Check PNETIDs
|
||||
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" != "$hsif_pnetid" ]; then
|
||||
echo "Error: $hsdev and $ndev have different PNETIDs! They are $hsif_pnetid and $netif_pnetid respectively" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [ "$hsif_pnetid" != "" ] && [ "$netif_pnetid" != "" ] && [ "$netif_pnetid" == "$hsif_pnetid" ]; then
|
||||
hsci_pnetid=$hsif_pnetid
|
||||
fi
|
||||
}
|
||||
|
||||
function verify_precon {
|
||||
echo "Verifying net dev $ndev and HiperSockets dev $hsdev"
|
||||
|
||||
if [ ! -e /sys/class/net/$hsdev ]; then
|
||||
echo "Error: $hsdev does not exist" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$hsdev/device/card_type)" != "HiperSockets" ]; then
|
||||
echo "Error: $hsdev is not a HiperSockets device" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$hsdev/device/layer2)" != "1" ]; then
|
||||
echo "Error: $hsdev is not in layer 2 mode" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ ! -e /sys/class/net/$hsdev/device/vnicc/bridge_invisible ]; then
|
||||
echo "Error: Missing vnic-characteristics support" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$hsdev/device/vnicc/bridge_invisible)" == "n/a" ]; then
|
||||
echo "Error: $hsdev does not support vnicc" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $hsdev | grep UP | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsdev is not in state UP" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(bridge -d link show dev $hsdev self | grep learning_sync | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsdev does not support attribute learning_sync" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $hsdev | grep master | wc -l) -ne 0 ]; then
|
||||
echo "Error: $hsdev is already a bridge port" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#Pre-verify net_dev
|
||||
if [ ! -e /sys/class/net/$ndev ]; then
|
||||
echo "Error: $ndev does not exist" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ "$(cat /sys/class/net/$ndev/device/card_type)" == "HiperSockets" ]; then
|
||||
echo "Error: $ndev is also a HiperSockets device" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $ndev | grep UP | wc -l) -eq 0 ]; then
|
||||
echo "Error: $ndev is not in state UP" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show $ndev | grep master | wc -l) -ne 0 ]; then
|
||||
echo "Error: $ndev is already a bridge port" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#Check PNETIDs
|
||||
check_pnetids
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function clean_up {
|
||||
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
|
||||
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible >/dev/null 2>&1
|
||||
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
|
||||
ip link del $hsci >/dev/null 2>&1
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
## add a new HSCI interface
|
||||
##############################################################################
|
||||
function add_hsci {
|
||||
|
||||
if [ $# != 2 ]; then
|
||||
echo "hsci: Invalid parameters" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
return 1
|
||||
fi
|
||||
hsdev=$1
|
||||
ndev=$2
|
||||
|
||||
#### Verify preconditions
|
||||
verify_precon
|
||||
if [ $? -ne 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
hsci_postfix="$(readlink /sys/class/net/$hsdev/device/cdev0 | tail -c5)"
|
||||
hsci=hsci$hsci_postfix
|
||||
|
||||
echo "Adding $hsci with a HiperSockets dev $hsdev and an external dev $ndev"
|
||||
|
||||
#### Create bridge
|
||||
ip link add name $hsci type bridge stp_state 0 >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not create a bridge" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
#### Prepare hsdev
|
||||
# Set VNICC of hsdev to invisible
|
||||
#(mandatory for co-existence with HS-OSA bridges!)
|
||||
echo 1 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
||||
|
||||
#### Create bridge ports
|
||||
ip link set dev $ndev master $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not set master for $ndev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
ip link set dev $hsdev master $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Could not set master for $hsdev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# no forwarding between ndev and hsdev -> isolated on
|
||||
# ndev is default for outgoing unknown targets -> flood on
|
||||
# no need to learn external LAN targets into fdb -> learning off
|
||||
bridge link set dev $ndev isolated on learning off flood on mcast_flood on >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set bridge attributes on $ndev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# no forwarding between ndev and hsdev -> isolated on
|
||||
# fdb will be populated by dev-to-bridge-notification, no need to learn
|
||||
# -> learning off
|
||||
# only send to hsdev, if listed in fdb -> flood off
|
||||
# don't send MC/BC on hsdev -> mcast_flood off
|
||||
bridge link set dev $hsdev isolated on learning off flood off mcast_flood off >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set bridge attributes on $hsdev" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# NOTE: Although not required, BCs will be sent out on hsdev.
|
||||
# NOTE: We need to receive BCs on hsdev, as z/OS HSCI does ARP requests on HS.
|
||||
|
||||
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
|
||||
echo "Set $hsdev MAC $hsdev_mac on $ndev and $hsci"
|
||||
|
||||
# set HS MAC on OSA as secondary MAC
|
||||
bridge fdb add $hsdev_mac dev $ndev >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set HS MAC on OSA as secondary MAC" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# set HS MAC (common MAC) on HSCI as primary MAC
|
||||
ip link set address $hsdev_mac dev $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set HiperSockets MAC (common MAC) on HSCI as primary MAC" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
ip link set dev $hsci up >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to set $hsci up" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Turn on device for bridge notification
|
||||
bridge link set dev $hsdev learning_sync on self >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to turn on device for bridge notification" >&2
|
||||
clean_up
|
||||
return 1
|
||||
fi
|
||||
echo "Successfully added HSCI interface $hsci"
|
||||
return 0
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
## Delete HSCI
|
||||
##############################################################################
|
||||
|
||||
function del_hsci {
|
||||
if [ $# != 1 ]; then
|
||||
echo "hsci: invalid parameters" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
return 1
|
||||
fi
|
||||
hsci=$1
|
||||
if [ $(ip link show dev $hsci | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsci does not exit" >&2
|
||||
return 1
|
||||
fi
|
||||
if [ $(ip link show | grep "master $hsci" | wc -l) -eq 0 ]; then
|
||||
echo "Error: $hsci is not an active HSCI interface" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
bports="$(ip link show | grep "master $hsci" | awk '{print $2}')"
|
||||
for bport in $bports; do
|
||||
bport=${bport%:}
|
||||
if [[ $bport == *@* ]]; then
|
||||
bport=${bport%@*}
|
||||
fi
|
||||
if [ $(bridge -d link show dev $bport | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
||||
hsdev=$bport
|
||||
else
|
||||
ndev=$bport
|
||||
fi
|
||||
done
|
||||
if [ "$hsdev" == "" ]; then
|
||||
echo "Error: $hsci has no active HiperSockets port" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "Deleting HSCI interface $hsci with the HiperSockets $hsdev and the external $ndev"
|
||||
|
||||
bridge link set dev $hsdev learning_sync off self >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to turn off learning_sync on $hsdev" >&2
|
||||
return 1
|
||||
fi
|
||||
echo 0 > /sys/class/net/$hsdev/device/vnicc/bridge_invisible
|
||||
|
||||
hsdev_mac="$(cat /sys/class/net/$hsdev/address)"
|
||||
echo "Deleting $hsev MAC $hsdev_mac on $ndev"
|
||||
bridge fdb del $hsdev_mac dev $ndev >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to delete $hsev MAC $hsdev_mac on $ndev" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
ip link del $hsci >/dev/null 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Error: Failed to delete $hsci" >&2
|
||||
return 1
|
||||
fi
|
||||
echo "Successfully deleted device $hsci"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
## Show HSCI
|
||||
##############################################################################
|
||||
|
||||
function list_active {
|
||||
hsdev=$1
|
||||
local ext=""
|
||||
|
||||
hsci="$(ip link show dev $hsdev | awk '{for(x=1;x<NF;x++) if($x~/master/) print $(x+1)}')"
|
||||
ext="$(ip link show | grep "master $hsci" | grep --invert-match $hsdev | awk '{print $2}')"
|
||||
# remove trailing ':'
|
||||
ndev="${ext%:}"
|
||||
|
||||
check_pnetids
|
||||
|
||||
printf '%-8s %-16s %-15s %-15s\n' "$hsci" "$hsci_pnetid" "$hsdev" "$ndev"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function print_header {
|
||||
if [ $header -eq 0 ]; then
|
||||
echo "HSCI PNET_ID HiperSockets External "
|
||||
echo "------------------------------------------------------------"
|
||||
fi
|
||||
}
|
||||
|
||||
function list_one {
|
||||
local hsnetdev=$1
|
||||
|
||||
if [ $(bridge -d link show dev $hsnetdev | grep "learning_sync on" | wc -l) -ne 0 ]; then
|
||||
print_header
|
||||
list_active $hsnetdev
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
function show_hsci {
|
||||
if [ $# != 0 ]; then
|
||||
echo "hsci: invalid parameters" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
return 1
|
||||
fi
|
||||
header=0
|
||||
|
||||
for hs_net_dev in $(ls -1 /sys/class/net/); do
|
||||
list_one $hs_net_dev
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
#==============================================================================
|
||||
|
||||
function print_version()
|
||||
{
|
||||
echo "hsci utility: version %S390_TOOLS_VERSION%"
|
||||
echo "Copyright IBM Corp. 2020"
|
||||
}
|
||||
|
||||
##############################################################################
|
||||
##### Main
|
||||
##############################################################################
|
||||
prereqs_check
|
||||
|
||||
args="$(getopt -u -o hv -l help,version -- $*)"
|
||||
[ $? -ne 0 ] && exit 2
|
||||
set -- $args
|
||||
while true; do
|
||||
case $1 in
|
||||
-v | --version)
|
||||
print_version
|
||||
exit 0
|
||||
;;
|
||||
-h | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--)
|
||||
;;
|
||||
add) shift
|
||||
add_hsci "$@"
|
||||
exit $?
|
||||
;;
|
||||
del) shift
|
||||
del_hsci "$@"
|
||||
exit $?
|
||||
;;
|
||||
show) shift
|
||||
show_hsci "$@"
|
||||
exit $?
|
||||
;;
|
||||
*) echo "hsci: Please specify a valid command or option" >&2
|
||||
echo "Use 'hsci --help' for more information" >&2
|
||||
exit 1
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
100
hsci/hsci.8
Normal file
100
hsci/hsci.8
Normal file
@@ -0,0 +1,100 @@
|
||||
.\" Copyright IBM Corp. 2020
|
||||
|
||||
.TH HSCI 8 "November 2020" "s390-tools" "Linux Programmer's Manual"
|
||||
|
||||
|
||||
.SH NAME
|
||||
.B hsci
|
||||
\- control and show HSCI settings.
|
||||
|
||||
|
||||
.SH SYNOPSIS
|
||||
.B hsci add
|
||||
.I HSDEV
|
||||
.I NETDEV
|
||||
.br
|
||||
.B hsci del
|
||||
.I HSCINAME
|
||||
.br
|
||||
.B hsci show
|
||||
.br
|
||||
.B hsci [\-hv]
|
||||
|
||||
.SH DESCRIPTION
|
||||
.BI hsci
|
||||
is used to control and show HSCI (HiperSockets Converged Interfaces) settings. A HiperSockets interface and an external network interface are converged into an HSCI interface.
|
||||
|
||||
.SH COMMANDS
|
||||
.TP
|
||||
.B add \fIHSDEV\fR \fINETDEV\fR
|
||||
.RS .4i
|
||||
.PP
|
||||
Adds an HSCI interface
|
||||
.PP
|
||||
.I HSDEV
|
||||
is the interface name of the HiperSockets device to be converged into the HSCI interface.
|
||||
.PP
|
||||
.I NETDEV
|
||||
is the interface name of the external network device to be converged into the HSCI interface.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B del \fIHSCINAME\fR
|
||||
.RS .4i
|
||||
.PP
|
||||
Deletes an HSCI interface
|
||||
.PP
|
||||
.I HSCINAME
|
||||
is the name of the HSCI interface for the HiperSockets device and the external network device.
|
||||
.RE
|
||||
|
||||
.TP
|
||||
.B show
|
||||
.RS .4i
|
||||
.PP
|
||||
Lists the configured HSCI interfaces.
|
||||
.RE
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.BR \-v ", " \-\-version
|
||||
Prints the version number of hsci and exits.
|
||||
.TP
|
||||
.BR \-h ", " \-\-help
|
||||
Displays the help information for the command.
|
||||
|
||||
.SH EXIT CODES
|
||||
.TP
|
||||
.BR "0"
|
||||
The hsci command ran successfully.
|
||||
|
||||
.TP
|
||||
.BR "1"
|
||||
An error occurred.
|
||||
|
||||
.SH EXAMPLE
|
||||
.BR "hsci show"
|
||||
.TP
|
||||
.RB
|
||||
Lists the configured HSCI interfaces:
|
||||
.RS 1.2i
|
||||
|
||||
HSCI PNET_ID HiperSockets External
|
||||
.br
|
||||
-----------------------------------------
|
||||
.br
|
||||
hsci8410 NET1 enc8410 encb040
|
||||
|
||||
.RE
|
||||
|
||||
.SH SEE ALSO
|
||||
.nf
|
||||
ip(8), bridge(8)
|
||||
.fi
|
||||
|
||||
.SH AUTHOR
|
||||
.nf
|
||||
Written by Alexandra Winter <wintera@linux.ibm.com>
|
||||
Wenjia Zhang <wenjia@linux.ibm.com>
|
||||
.fi
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user