mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
282 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cd063e40d | ||
|
|
4d97e15eb0 | ||
|
|
a32fe8641a | ||
|
|
c34adb9cab | ||
|
|
86b5df0d2d | ||
|
|
e0caed5534 | ||
|
|
8704c9c80e | ||
|
|
4ec33d0b76 | ||
|
|
3a4c20b443 | ||
|
|
c54a915a90 | ||
|
|
bc269ddb38 | ||
|
|
8c21f09570 | ||
|
|
4df0781989 | ||
|
|
195579cf0b | ||
|
|
849819cb77 | ||
|
|
72aa64495c | ||
|
|
d2de7f2808 | ||
|
|
f4cf4ae6eb | ||
|
|
f524b0b8dc | ||
|
|
f99719a695 | ||
|
|
7d81c1bbd4 | ||
|
|
2ed2c608ab | ||
|
|
d73f4dc22a | ||
|
|
ea297ecf84 | ||
|
|
7d41430e68 | ||
|
|
f095a892b9 | ||
|
|
646a389b53 | ||
|
|
66ef6b5945 | ||
|
|
6c75a06b12 | ||
|
|
b1ca60f5ba | ||
|
|
3d83100fa3 | ||
|
|
8c23e09a60 | ||
|
|
24e285ce02 | ||
|
|
ad709c1eaf | ||
|
|
b61596327b | ||
|
|
de18a72249 | ||
|
|
482bd93e2e | ||
|
|
026ecbafea | ||
|
|
40846bce49 | ||
|
|
b9879cbfc7 | ||
|
|
e61ed4f433 | ||
|
|
589090f79a | ||
|
|
57eef7c412 | ||
|
|
d864c55336 | ||
|
|
1b18ba3a03 | ||
|
|
938fe2a744 | ||
|
|
171432852b | ||
|
|
7608cf2de4 | ||
|
|
e480c4738d | ||
|
|
4cd7e8fd9a | ||
|
|
f1b94abefa | ||
|
|
5a54722848 | ||
|
|
cb0e119bed | ||
|
|
081a055115 | ||
|
|
6e27c2f2e9 | ||
|
|
d1d0bd39ba | ||
|
|
8d0c620257 | ||
|
|
d1884db236 | ||
|
|
73f211ecb1 | ||
|
|
8d2290977b | ||
|
|
25aac53d52 | ||
|
|
6b75568750 | ||
|
|
7cc131880c | ||
|
|
26465e37d7 | ||
|
|
697dcc0f6b | ||
|
|
ac7f866237 | ||
|
|
339ad5c2ed | ||
|
|
48f1e0da0a | ||
|
|
413adbe7bb | ||
|
|
667a8d714b | ||
|
|
2155b83c1f | ||
|
|
e6c17461a3 | ||
|
|
f68d3932c7 | ||
|
|
81f3845f34 | ||
|
|
75820cf62d | ||
|
|
3f0dc6b3af | ||
|
|
db6c500e6d | ||
|
|
578b77072a | ||
|
|
f94e9e9352 | ||
|
|
079ae1e24d | ||
|
|
2f3c189fda | ||
|
|
dec796d52f | ||
|
|
385ba6b51f | ||
|
|
050441922b | ||
|
|
567cbce8a8 | ||
|
|
eee29e0399 | ||
|
|
a0a8aa47a8 | ||
|
|
fe2946f76c | ||
|
|
17aba9322e | ||
|
|
53d803abf3 | ||
|
|
576a230341 | ||
|
|
bdaef6e76d | ||
|
|
e6c73c9974 | ||
|
|
d4316c155c | ||
|
|
a4f4337060 | ||
|
|
32dbfc4712 | ||
|
|
63142e3051 | ||
|
|
464d4d2842 | ||
|
|
b378ff788e | ||
|
|
20f1c0e2ea | ||
|
|
54e175a783 | ||
|
|
30dc1a5ddd | ||
|
|
47460e6e33 | ||
|
|
6fc13a0ff4 | ||
|
|
5751c08627 | ||
|
|
5e97205530 | ||
|
|
0495947604 | ||
|
|
516bd8c2cf | ||
|
|
d1b5f80fe5 | ||
|
|
e2ee24b3ac | ||
|
|
f23c207622 | ||
|
|
649f1bc084 | ||
|
|
17e575e350 | ||
|
|
57a32d98ef | ||
|
|
03340afe88 | ||
|
|
e7cef378e0 | ||
|
|
8da2f44ae2 | ||
|
|
a4a29d1e05 | ||
|
|
89f475cee1 | ||
|
|
96dbabae8d | ||
|
|
d30d272523 | ||
|
|
300f8d23b5 | ||
|
|
b7ac46b98b | ||
|
|
e91ad1b70e | ||
|
|
c2db7ce05f | ||
|
|
0031c762cf | ||
|
|
7031429d1e | ||
|
|
73d8597db1 | ||
|
|
77d0d1d1a1 | ||
|
|
77a7e11a51 | ||
|
|
279070fa43 | ||
|
|
3989e1b741 | ||
|
|
c230b5385a | ||
|
|
68ecf79b01 | ||
|
|
f2960eb0df | ||
|
|
4d004cf8b1 | ||
|
|
d8f504f271 | ||
|
|
7fb3ee4478 | ||
|
|
a95bad6c87 | ||
|
|
147ff1bf49 | ||
|
|
c91d172c99 | ||
|
|
0e4992da3a | ||
|
|
41da0f0809 | ||
|
|
f43789e16a | ||
|
|
136e5eed8c | ||
|
|
e09753f2a3 | ||
|
|
fe2d240656 | ||
|
|
6fc450f696 | ||
|
|
6a55d0c2e5 | ||
|
|
0e69dc1262 | ||
|
|
3296d85e35 | ||
|
|
0eeab96f0d | ||
|
|
283a61dc2f | ||
|
|
670bf3e870 | ||
|
|
9cfaac58ea | ||
|
|
d6b702d579 | ||
|
|
d9a9bd8dcf | ||
|
|
cad4e9e15b | ||
|
|
c0f02d2f68 | ||
|
|
5218c243f4 | ||
|
|
c364692e7a | ||
|
|
41eb7d076f | ||
|
|
1062a7cde6 | ||
|
|
54e5e99657 | ||
|
|
4c922b105b | ||
|
|
4b19b9d950 | ||
|
|
cee4bb4995 | ||
|
|
c98d8e7629 | ||
|
|
96084339f5 | ||
|
|
f8d5b4b341 | ||
|
|
5806c4e1f4 | ||
|
|
9d199e06cb | ||
|
|
f7425a08d1 | ||
|
|
f6a97902c3 | ||
|
|
962af1a90e | ||
|
|
46dadc8cc4 | ||
|
|
9c8d117cc2 | ||
|
|
d7b3196286 | ||
|
|
b6c30404bc | ||
|
|
6d15850480 | ||
|
|
858da9af57 | ||
|
|
a7373674bf | ||
|
|
613353cd33 | ||
|
|
f6e932e0fd | ||
|
|
7e31c425c9 | ||
|
|
6c4171b775 | ||
|
|
0b0960254e | ||
|
|
4d2c9267c2 | ||
|
|
7ea0dfdc17 | ||
|
|
2d3aac1241 | ||
|
|
c7fd515790 | ||
|
|
7a4ec55d77 | ||
|
|
63ff07ba38 | ||
|
|
26d7eed0aa | ||
|
|
e0034eddbf | ||
|
|
0e3034c0f6 | ||
|
|
686262fdcd | ||
|
|
2379fd8a58 | ||
|
|
3552a27ae6 | ||
|
|
39106ba760 | ||
|
|
f270ac99f0 | ||
|
|
f83af8e076 | ||
|
|
4d2c92f6d5 | ||
|
|
503e241db1 | ||
|
|
dea5f80215 | ||
|
|
c261db259b | ||
|
|
c382e7ef44 | ||
|
|
16610a211f | ||
|
|
4d57ff046d | ||
|
|
4a76efe6d5 | ||
|
|
87d43c7a32 | ||
|
|
f383278a5a | ||
|
|
a9d4b1e1b9 | ||
|
|
61c5d7d431 | ||
|
|
b7765993e2 | ||
|
|
e152b554f5 | ||
|
|
c46a066827 | ||
|
|
cf003379ac | ||
|
|
7b94783cb7 | ||
|
|
38600bb4e2 | ||
|
|
16875f7c6d | ||
|
|
381fecfc44 | ||
|
|
5648b924d6 | ||
|
|
636d2d571b | ||
|
|
d016ec129d | ||
|
|
cb77faeae7 | ||
|
|
38ea8fc3ee | ||
|
|
d8e5bc07aa | ||
|
|
3b26f79143 | ||
|
|
c366429e57 | ||
|
|
8ed478ce46 | ||
|
|
a97a8f1cba | ||
|
|
fb0b6263d1 | ||
|
|
76aaf3d4a8 | ||
|
|
08232d29b9 | ||
|
|
cfaccc5fad | ||
|
|
7da5a6b9ed | ||
|
|
7ed87bed8c | ||
|
|
46ec94d0ce | ||
|
|
6bc0b023aa | ||
|
|
13d673e0f7 | ||
|
|
c40c159173 | ||
|
|
202ded5d11 | ||
|
|
e3a698c382 | ||
|
|
3a60b4caa8 | ||
|
|
f57858b3a8 | ||
|
|
9e430b9010 | ||
|
|
ad2a42ce9e | ||
|
|
1c32635b3a | ||
|
|
558594fddf | ||
|
|
c8879322b0 | ||
|
|
d716c553c4 | ||
|
|
ab35922161 | ||
|
|
474c6adf8f | ||
|
|
f5f806af06 | ||
|
|
0a01719477 | ||
|
|
07cd9143da | ||
|
|
d064cb522f | ||
|
|
802c7db50e | ||
|
|
0f87acc2b3 | ||
|
|
998b61e5f3 | ||
|
|
c47071815b | ||
|
|
0ed6c1ccde | ||
|
|
d888a27f07 | ||
|
|
7c2ae3d2e8 | ||
|
|
c88a8b6130 | ||
|
|
32a0434bc3 | ||
|
|
a2e556858a | ||
|
|
9eab43994b | ||
|
|
c53dfa9754 | ||
|
|
81a1e13f3b | ||
|
|
8f89234f1a | ||
|
|
d757dbfbff | ||
|
|
0d9a6e45fb | ||
|
|
4d4666cff7 | ||
|
|
46092add29 | ||
|
|
1655c39ded | ||
|
|
a95dc09c6e | ||
|
|
f1f80a8a20 | ||
|
|
4c2bfb1d47 | ||
|
|
c0fc21efb3 | ||
|
|
93d3c44a1a |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -77,9 +77,8 @@ libzds/libzds.a
|
||||
lsstp/lsstp
|
||||
mon_tools/mon_fsstatd
|
||||
mon_tools/mon_procd
|
||||
opticsmon/opticsmon
|
||||
osasnmpd/osasnmpd
|
||||
pvattest/src/pvattest
|
||||
pvattest/tools/exchange_info
|
||||
qetharp/qetharp
|
||||
qethqoat/qethqoat
|
||||
systemd/cpacfstatsd.service
|
||||
@@ -92,6 +91,7 @@ vmcp/vmcp
|
||||
vmur/vmur
|
||||
zconf/chp/chchp
|
||||
zconf/chp/lschp
|
||||
zconf/chp/chpstat/chpstat
|
||||
zconf/css/lscss
|
||||
zconf/qeth/lsqeth
|
||||
zconf/scm/lsscm
|
||||
@@ -123,9 +123,11 @@ zipl/boot/*.exec
|
||||
zipl/boot/.loaders
|
||||
zipl/boot/data.h
|
||||
zipl/src/chreipl_helper.device-mapper
|
||||
zipl/src/chreipl_helper.md
|
||||
zipl/src/zipl
|
||||
zipl/src/zipl-editenv
|
||||
zipl/src/zipl_helper.device-mapper
|
||||
zipl/src/zipl_helper.md
|
||||
zkey/check-dep-zkey
|
||||
zkey/check-dep-zkey-cryptsetup
|
||||
zkey/detect-libcryptsetup.dep
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
exclude: \.(crt|crl)$
|
||||
exclude: \.(bin|crl|crt|key)$
|
||||
repos:
|
||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||
rev: v4.1.0
|
||||
|
||||
@@ -5,8 +5,9 @@ newline_style = "Unix"
|
||||
# when they become stable.
|
||||
#
|
||||
# They are kept here since they are useful to run from time to time.
|
||||
#format_code_in_doc_comments = true
|
||||
#reorder_impl_items = true
|
||||
#comment_width = 100
|
||||
#wrap_comments = true
|
||||
#format_code_in_doc_comments = true
|
||||
#group_imports = "StdExternalCrate"
|
||||
#normalize_comments = true
|
||||
#reorder_impl_items = true
|
||||
#wrap_comments = true
|
||||
|
||||
@@ -11,6 +11,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Axel Wirbser
|
||||
- Balint Reczey
|
||||
- Benjamin Block
|
||||
- Bjoern Walk
|
||||
- Brian C. Lane
|
||||
- Carsten Otte
|
||||
- Christian Borntraeger
|
||||
@@ -91,6 +92,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Michael Mueller
|
||||
- Mijo Safradin
|
||||
- Mikhail Zaslonko
|
||||
- Nihar Panda
|
||||
- Nikita Dubrovskii
|
||||
- Niklas Schnelle
|
||||
- Nikolay Gueorguiev
|
||||
@@ -107,6 +109,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Sa Liu
|
||||
- Sascha Silbe
|
||||
- Sebastian Ott
|
||||
- Sertonix
|
||||
- Seshagiri N. Ippili
|
||||
- Simon Sturm
|
||||
- Stefan Bader
|
||||
@@ -133,6 +136,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Ursula Braun
|
||||
- Utz Bacher
|
||||
- Vance Morris
|
||||
- VasiliyS
|
||||
- Vasily Gorbik
|
||||
- Viktor Mihajlovski
|
||||
- Vineeth Vijayan
|
||||
|
||||
96
CHANGELOG.md
96
CHANGELOG.md
@@ -1,6 +1,102 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
|
||||
* __v2.36.0 (2024-12-06)__
|
||||
|
||||
For Linux kernel version: 6.12
|
||||
|
||||
s390-tools: Define Rust MSRV as 1.75.0
|
||||
|
||||
Add new tools / libraries:
|
||||
- cpacfinfo: Tool to provide CPACF information
|
||||
- opticsmon: Tools to monitor optical modules for directly attached PCI based NICs
|
||||
- pvimg: Rust rewrite of genprotimg
|
||||
|
||||
Changes of existing tools:
|
||||
- chpstat: Add data bandwidth utilization column
|
||||
- chpstat: Add support for full CMCB
|
||||
- chpstat: Add support for new CMG types
|
||||
- dbginfo.sh: add overview commands and crypto update
|
||||
- hyptop: Support for structured output (json, json-seq, csv)
|
||||
- lszfcp: Add missing fallback marker for non-good fc_host port_state
|
||||
- lszfcp: Improve speed with many SCSI devices
|
||||
- pvattest: Add attestation policy check command
|
||||
- zipl: Add support of partitions of mirror md-devices
|
||||
|
||||
Bug Fixes:
|
||||
- lszcrypt: Fix wrong state showing up for removed AP queue within SE guest
|
||||
- lszfcp: Show device names line for zfcp_units without SCSI device
|
||||
|
||||
* __v2.35.0 (2024-10-01)__
|
||||
|
||||
For Linux kernel version: 6.11
|
||||
|
||||
Add new tools / libraries:
|
||||
|
||||
Changes of existing tools:
|
||||
- cpacfstats: Add support for FULL XTS (MSA 10) and HMAC (MSA 11) PAI counter
|
||||
- cpuplugd: Make cpuplugd compatible with hiperdispatch
|
||||
- dbginfo.sh: Add network sockstat info
|
||||
- pvapconfig: s390x exclusive build
|
||||
- zdev: Add option to select IPL device
|
||||
- zdump/dfo_s390: Support s390 DFO for vr-kernel dumps
|
||||
- zipl: Add support of mirror devices
|
||||
|
||||
Bug Fixes:
|
||||
- (genprotimg|zipl)/boot: discard .note.package ELF section to save memory
|
||||
- netboot/mk-s390image: Fix size when argument is a symlink
|
||||
- ziorep_config: Fix warning message when multipath device is not there.
|
||||
- zipl: Fix problems when target parameters are specified by user
|
||||
- zipl: Fix segfault when creating device-based dumps with '--dry-run'
|
||||
|
||||
* __v2.34.0 (2024-08-01)__
|
||||
|
||||
For Linux kernel version: 6.10
|
||||
|
||||
Changes of existing tools:
|
||||
- ap_tools/ap-check: Add support for vfio-ap dynamic configuration
|
||||
- dbginfo.sh: Update/Add additional DASD data collection
|
||||
- dumpconf: Add new parameter 'SCP_DATA' for SCSI/NVMe/ECKD dump devices
|
||||
- libutil: Make formatted meta-data configurable
|
||||
- s390-tools: Replace 'which' with built-in 'command -v'
|
||||
- zdump/dfi_elf: Support core dumps of vr-kernels
|
||||
|
||||
Bug Fixes:
|
||||
- chzdev: Fix warning about failed ATTR writes by udev
|
||||
- rust/pv: Try again if first CRL-URI is invalid
|
||||
- rust/pvattest: Add short option for --arpk
|
||||
- zdump: Fix 'zgetdump -i' ioctl error on s390 formatted dump file
|
||||
|
||||
* __v2.33.1 (2024-05-28)__
|
||||
|
||||
For Linux kernel version: 6.9
|
||||
|
||||
Bug Fixes:
|
||||
- s390-tools: Fix formatting and typos in README.md
|
||||
- s390-tools: Fix release string
|
||||
|
||||
* __v2.33.0 (2024-05-27)__
|
||||
|
||||
For Linux kernel version: 6.9
|
||||
|
||||
Add new tools / libraries:
|
||||
- chpstat: New tool for displaying channel path statistics
|
||||
- libutil: Add output format helpers(util_fmt: JSON, JSON-SEQ, CSV, text pairs)
|
||||
|
||||
Changes of existing tools / libraries:
|
||||
- chzdev: Add --is-owner to identify files created by zdev
|
||||
- dasdfmt: Change default mode to always use full-format (Note: affects ESE DASD)
|
||||
- libap: Significantly reduce delay time between file lock retries
|
||||
- pvattest: Rewrite from C to Rust
|
||||
- pvattest: Support additional data & user-data
|
||||
- rust/pv: Support for Attestation
|
||||
|
||||
Bug Fixes:
|
||||
- chreipl: Improve disk type detection when running under QEMU
|
||||
- dbginfo.sh: Use POSIX option with uname
|
||||
- s390-tools: Fix missing hyphen escapes in the man page for many tools
|
||||
- zipl/src: Fix bugs in disk_get_info() reproducible in corner cases
|
||||
|
||||
* __v2.32.0 (2024-04-03)__
|
||||
|
||||
For Linux kernel version: 6.8
|
||||
|
||||
8
Makefile
8
Makefile
@@ -9,18 +9,18 @@ include common.mak
|
||||
ifeq ($(HOST_ARCH),s390x)
|
||||
BASELIB_DIRS = libutil libseckey
|
||||
LIB_DIRS = libvtoc libzds libdasd libccw libvmcp libekmfweb \
|
||||
libkmipclient libcpumf libap libpv
|
||||
libkmipclient libcpumf libap libpv libzpci
|
||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools pvattest \
|
||||
rust
|
||||
lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools rust opticsmon
|
||||
|
||||
else
|
||||
BASELIB_DIRS =
|
||||
LIB_DIRS = libpv
|
||||
TOOL_DIRS = genprotimg pvattest rust
|
||||
TOOL_DIRS = rust
|
||||
endif
|
||||
|
||||
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)
|
||||
|
||||
86
README.md
86
README.md
@@ -19,6 +19,17 @@ Package contents
|
||||
all s390-tools that are written in rust and require external crates.
|
||||
Disable the compilation of all tools in `rust/` using HAVE_CARGO=0
|
||||
See the `rust/README.md` for Details
|
||||
- cpacfinfo:
|
||||
Command line interface to get information about CP Assist for
|
||||
Cryptographic Functions (CPACF)
|
||||
- pvattest:
|
||||
Create, perform, and verify IBM Secure Execution attestation measurements.
|
||||
- pvapconfig:
|
||||
Automatic configure APQNs within an SE KVM guest
|
||||
- pvsecret:
|
||||
Manage secrets for IBM Secure Execution guests
|
||||
- pvimg:
|
||||
Create and inspect IBM Secure Execution images
|
||||
|
||||
* dasdfmt:
|
||||
Low-level format ECKD DASDs with the classical Linux disk layout or the new
|
||||
@@ -36,10 +47,8 @@ Package contents
|
||||
Display unique DASD ID, either UID or volser.
|
||||
|
||||
* genprotimg:
|
||||
Create a protected virtualization image.
|
||||
|
||||
* pvattest:
|
||||
Create, perform, and verify protected virtualization attestation measurements.
|
||||
Create an IBM Secure Execution (protected virtualization) image. The
|
||||
genprotimg command is a symbolic link to the `pvimg create` command.
|
||||
|
||||
* udev rules:
|
||||
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
|
||||
@@ -301,26 +310,27 @@ HAVE_FUSE=0`".
|
||||
The following table provides an overview of the used libraries and
|
||||
build options:
|
||||
|
||||
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
||||
|----------------|:------------------:|:-------------------------------------:|
|
||||
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
||||
| | | hsavmcore |
|
||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
||||
| | | libkmipclient, pvattest, zgetdump, |
|
||||
| | | rust/pvsecret, |
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
||||
| | | libkmipclient |
|
||||
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest, zgetdump |
|
||||
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
|
||||
| | | pvattest, rust/pvsecret, |
|
||||
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
||||
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
||||
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
|
||||
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
||||
|--------------|:------------------:|:--------------------------------------:|
|
||||
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump, |
|
||||
| | | hsavmcore |
|
||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||
| openssl | `HAVE_OPENSSL` | zkey, libekmfweb, libkmipclient, |
|
||||
| | | zgetdump, rust/pvattest, rust/pvimg, |
|
||||
| | | zgetdump/pvsecret, opticsmon |
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
||||
| | | libkmipclient |
|
||||
| glib2 | `HAVE_GLIB2` | zgetdump |
|
||||
| libcurl | `HAVE_LIBCURL` | libekmfweb, libkmipclient, rust/pvimg, |
|
||||
| | | rust/pvattest, rust/pvsecret, |
|
||||
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
||||
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
||||
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
|
||||
| libnl3 | `HAVE_LIBNL3` | opticsmon |
|
||||
|
||||
This table lists additional build or install options:
|
||||
|
||||
@@ -352,23 +362,27 @@ 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`.
|
||||
* rust/pvimg:
|
||||
For building pvimg you need OpenSSL version 1.1.1 or newer
|
||||
installed (openssl-devel.rpm). Also required is cargo and libcurl.
|
||||
Tip: you may skip the pvimg build by adding
|
||||
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_CARGO=0`.
|
||||
|
||||
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
|
||||
The runtime requirements are: openssl-libs (>= 1.1.1) and libcurl.
|
||||
|
||||
* pvattest:
|
||||
* rust/pvattest:
|
||||
For building pvattest you need OpenSSL version 1.1.1 or newer
|
||||
installed (openssl-devel.rpm). Also required is glib2.56 or newer
|
||||
(glib2-devel.rpm) and libcurl.
|
||||
installed (openssl-devel.rpm). Also required is cargo and libcurl.
|
||||
Tip: you may skip the pvattest build by adding
|
||||
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_GLIB2=0`.
|
||||
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_CARGO=0`.
|
||||
|
||||
The runtime requirements are: openssl-libs (>= 1.1.1) and
|
||||
glib2.56 or newer.
|
||||
The runtime requirements are: openssl-libs (>= 1.1.1) and libcurl.
|
||||
|
||||
* opticsmon:
|
||||
For building opticsmon OpenSSL and the Netlink Library Suite (libnl3) are
|
||||
required.
|
||||
Tip: you may skip the opticsmon build by adding
|
||||
`HAVE_OPENSSL=0` or `HAVE_LIBNL3=0`
|
||||
|
||||
* osasnmpd:
|
||||
You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <json-c/json.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
@@ -27,21 +28,33 @@
|
||||
|
||||
#include "ap-check.h"
|
||||
|
||||
/* The supported mdevctl callout version */
|
||||
#define MDEVCTL_CAP_VERSION 2
|
||||
|
||||
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
|
||||
{MDEVCTL_ACTION_DEFINE, "define"},
|
||||
{MDEVCTL_ACTION_LIST, "list"},
|
||||
{MDEVCTL_ACTION_MODIFY, "modify"},
|
||||
{MDEVCTL_ACTION_START, "start"},
|
||||
{MDEVCTL_ACTION_STOP, "stop"},
|
||||
{MDEVCTL_ACTION_TYPES, "types"},
|
||||
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
|
||||
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
|
||||
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"},
|
||||
{MDEVCTL_ACTION_CAPABILITIES, "capabilities"}
|
||||
/*
|
||||
* Note: the following actions are known to exist but currently ignored:
|
||||
* {MDEVCTL_ACTION_LIST, "list"},
|
||||
* {MDEVCTL_ACTION_TYPES, "types"}
|
||||
*/
|
||||
};
|
||||
|
||||
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
|
||||
{MDEVCTL_EVENT_PRE, "pre"},
|
||||
{MDEVCTL_EVENT_POST, "post"},
|
||||
{MDEVCTL_EVENT_GET, "get"}
|
||||
{MDEVCTL_EVENT_GET, "get"},
|
||||
{MDEVCTL_EVENT_LIVE, "live"}
|
||||
/*
|
||||
* Note: the following events are known to exist but currently ignored:
|
||||
* {MDEVCTL_EVENT_NOTIFY, "notify"},
|
||||
*/
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -596,6 +609,94 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ap_check_active(struct ap_check_anchor *anc)
|
||||
{
|
||||
int rc, rc2;
|
||||
|
||||
/* Ensure device with control domains also has usage domains */
|
||||
if (util_list_is_empty(anc->dev->domains) &&
|
||||
!util_list_is_empty(anc->dev->controls)) {
|
||||
fprintf(stderr, "At least one usage domain must be specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check against all other active vfio-ap devices */
|
||||
rc = check_other_mdevs_sysfs(anc);
|
||||
/* Check against the system sysfs values for apmask/aqmask */
|
||||
rc2 = check_sysfs_mask_conflicts(anc);
|
||||
/* If either hit an error, reflect this */
|
||||
rc = rc != 0 ? rc : rc2;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ap_do_dynamic_config(struct ap_check_anchor *anc)
|
||||
{
|
||||
char *adapters, *domains, *controls, *path, *attr;
|
||||
int asize, dsize, csize, size;
|
||||
int rc = 0;
|
||||
FILE *f;
|
||||
|
||||
adapters = vfio_ap_device_get_adapter_mask(anc->dev, &asize);
|
||||
domains = vfio_ap_device_get_domain_mask(anc->dev, &dsize);
|
||||
controls = vfio_ap_device_get_control_mask(anc->dev, &csize);
|
||||
|
||||
if (!adapters || !domains || !controls) {
|
||||
fprintf(stderr, "Failed to read device config\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The 'ap_config' command takes a comma-delimited list of the 3 masks
|
||||
* combined. Each mask size includes a terminating character, two of
|
||||
* which will be replaced by commas and the final replaced by a
|
||||
* newline, which ap_config seems to require at the end of the input.
|
||||
* Add one to ensure room for a null termination.
|
||||
*/
|
||||
size = asize + dsize + csize + 1;
|
||||
attr = util_zalloc(size);
|
||||
|
||||
/* Use the 3 masks to generate a 'ap_config' command */
|
||||
rc = snprintf(attr, size, "%s,%s,%s\n", adapters, domains, controls);
|
||||
|
||||
if (rc < size - 1) {
|
||||
fprintf(stderr, "Error creating ap_config command\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Apply the new configuration to the active device */
|
||||
path = path_get_vfio_ap_attr(anc->uuid, "ap_config");
|
||||
f = fopen(path, "w");
|
||||
if (!f) {
|
||||
fprintf(stderr, "Error opening ap_config\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
rc = fputs(attr, f);
|
||||
fclose(f);
|
||||
|
||||
if (rc == EOF)
|
||||
fprintf(stderr, "Error writing to ap_config\n");
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
if (!adapters)
|
||||
free(adapters);
|
||||
if (!domains)
|
||||
free(domains);
|
||||
if (!controls)
|
||||
free(controls);
|
||||
if (!path)
|
||||
free(path);
|
||||
if (!attr)
|
||||
free(attr);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if defining the specified device is a valid operation.
|
||||
* mdevctl can reach us for a DEFINE under the following circumstances:
|
||||
@@ -647,6 +748,50 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
|
||||
return ap_check_changes(anc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if modifying the active device is a valid operation.
|
||||
* This is similar to STARTing a device, in that the requested modifications
|
||||
* cannot conflict with the active configuration. LIVE MODIFY can only be
|
||||
* handled if the ap_config attribute is available in the vfio-ap driver.
|
||||
*/
|
||||
static int ap_check_handle_live_modify(struct ap_check_anchor *anc)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ap_get_lock_callout();
|
||||
if (rc) {
|
||||
fprintf(stderr, "Failed to acquire configuration lock %d\n",
|
||||
rc);
|
||||
return -1;
|
||||
}
|
||||
anc->cleanup_lock = true;
|
||||
|
||||
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
|
||||
fprintf(stderr, "Failed to read device config\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (strcmp(anc->dev->type, anc->type) != 0) {
|
||||
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!vfio_ap_need_dynamic_config(anc->dev)) {
|
||||
fprintf(stderr, "vfio-ap module does not support ap_config for live modification");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if the new configuration would cause conflicts */
|
||||
rc = ap_check_active(anc);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* Attempt to perform the dynamic configuration */
|
||||
rc = ap_do_dynamic_config(anc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine if starting the specified device is a valid operation.
|
||||
* mdevctl can reach us for a START under the following circumstances:
|
||||
@@ -665,7 +810,7 @@ static int ap_check_handle_modify(struct ap_check_anchor *anc)
|
||||
*/
|
||||
static int ap_check_handle_start(struct ap_check_anchor *anc)
|
||||
{
|
||||
int rc = 0, rc2;
|
||||
int rc = 0;
|
||||
|
||||
/* Can only start a device if vfio_ap is built-in or loaded */
|
||||
if (!util_path_is_dir(VFIO_AP_PATH)) {
|
||||
@@ -694,20 +839,7 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ensure device with control domains also has usage domains */
|
||||
if (util_list_is_empty(anc->dev->domains) &&
|
||||
!util_list_is_empty(anc->dev->controls)) {
|
||||
fprintf(stderr, "At least one usage domain must be specified\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check against all other active vfio-ap devices */
|
||||
rc = check_other_mdevs_sysfs(anc);
|
||||
/* Check against the system sysfs values for apmask/aqmask */
|
||||
rc2 = check_sysfs_mask_conflicts(anc);
|
||||
/* If either hit an error, reflect this */
|
||||
rc = rc != 0 ? rc : rc2;
|
||||
rc = ap_check_active(anc);
|
||||
|
||||
/* If successful, lock must remain held until post callout */
|
||||
if (rc == 0)
|
||||
@@ -886,6 +1018,122 @@ static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target 'attr' is in the 's' array, add it to the 't' array.
|
||||
*/
|
||||
static void json_add_attr(json_object *t, json_object *s, const char *attr)
|
||||
{
|
||||
size_t vlen, alen = strlen(attr);
|
||||
const char *val;
|
||||
json_object *o;
|
||||
int i, num;
|
||||
|
||||
num = json_object_array_length(s);
|
||||
for (i = 0; i < num; i++) {
|
||||
o = json_object_array_get_idx(s, i);
|
||||
val = json_object_get_string(o);
|
||||
vlen = strlen(val);
|
||||
if (alen == vlen && strncasecmp(attr, val, alen) == 0) {
|
||||
json_object_array_add(t, json_object_new_string(val));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a JSON-formatted list of capability information that this script
|
||||
* supports and return it to the caller via stdout. An example of what the
|
||||
* output should look like (without the newlines):
|
||||
* {
|
||||
* "supports": {
|
||||
* "version": 2,
|
||||
* "actions": ["define",
|
||||
* "modify",
|
||||
* "start",
|
||||
* "stop",
|
||||
* "undefine",
|
||||
* "attributes",
|
||||
* "capabilities"],
|
||||
* "events": ["pre",
|
||||
* "post",
|
||||
* "get",
|
||||
* "live"]
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
static int ap_check_handle_get_capabilities(void)
|
||||
{
|
||||
json_object *root, *csup, *cver, *cact, *cev, *cap, *caps, *o;
|
||||
int i, rc = 0;
|
||||
|
||||
root = json_object_from_fd(STDIN_FILENO);
|
||||
|
||||
if (!root) {
|
||||
fprintf(stderr, "No capabilities provided\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(root, "provides", &csup)) {
|
||||
fprintf(stderr, "No supported capabilities provided\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(csup, "version", &cver)) {
|
||||
fprintf(stderr, "No version provided in capabilities\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(csup, "actions", &cact)) {
|
||||
fprintf(stderr, "No actions provided in capabilities\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!json_object_object_get_ex(csup, "events", &cev)) {
|
||||
fprintf(stderr, "No events provided in capabilities\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Advertise the subset of supported capabilities from the list
|
||||
* provided on stdin.
|
||||
*/
|
||||
|
||||
cap = json_object_new_object();
|
||||
caps = json_object_new_object();
|
||||
json_object_object_add(cap, "supports", caps);
|
||||
/*
|
||||
* Currently we always advertise a fixed version, but we may need to
|
||||
* revisit this if we increase MDEVCTL_CAP_VERSION in the future (e.g.
|
||||
* how to handle ap-check having a greater supported version than
|
||||
* what mdevctl reports)
|
||||
*/
|
||||
o = json_object_new_int(MDEVCTL_CAP_VERSION);
|
||||
json_object_object_add(caps, "version", o);
|
||||
|
||||
o = json_object_new_array();
|
||||
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++)
|
||||
json_add_attr(o, cact, mdevctl_action_table[i].action);
|
||||
json_object_object_add(caps, "actions", o);
|
||||
|
||||
o = json_object_new_array();
|
||||
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++)
|
||||
json_add_attr(o, cev, mdevctl_event_table[i].event);
|
||||
json_object_object_add(caps, "events", o);
|
||||
|
||||
/* Return supported capabilities JSON on stdout */
|
||||
printf("%s\n", json_object_to_json_string(cap));
|
||||
|
||||
json_object_put(cap);
|
||||
|
||||
out:
|
||||
json_object_put(root);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine which mdevctl action is being checked and handle accordingly.
|
||||
*/
|
||||
@@ -911,8 +1159,6 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
|
||||
case MDEVCTL_ACTION_UNDEFINE:
|
||||
rc = ap_check_handle_undefine(anc);
|
||||
break;
|
||||
case MDEVCTL_ACTION_LIST:
|
||||
case MDEVCTL_ACTION_TYPES:
|
||||
default:
|
||||
/* Ignore some actions including unknown ones */
|
||||
break;
|
||||
@@ -937,6 +1183,19 @@ static int ap_check_handle_action(struct ap_check_anchor *anc)
|
||||
case MDEVCTL_ACTION_ATTRIBUTES:
|
||||
rc = ap_check_handle_get_attributes(anc);
|
||||
break;
|
||||
case MDEVCTL_ACTION_CAPABILITIES:
|
||||
rc = ap_check_handle_get_capabilities();
|
||||
break;
|
||||
default:
|
||||
/* Ignore some actions including unknown ones */
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MDEVCTL_EVENT_LIVE:
|
||||
switch (anc->action) {
|
||||
case MDEVCTL_ACTION_MODIFY:
|
||||
rc = ap_check_handle_live_modify(anc);
|
||||
break;
|
||||
default:
|
||||
/* Ignore some actions including unknown ones */
|
||||
break;
|
||||
|
||||
@@ -24,6 +24,7 @@ enum mdevctl_action_id {
|
||||
MDEVCTL_ACTION_TYPES,
|
||||
MDEVCTL_ACTION_UNDEFINE,
|
||||
MDEVCTL_ACTION_ATTRIBUTES,
|
||||
MDEVCTL_ACTION_CAPABILITIES,
|
||||
/* UNKNOWN must always be the last in the list */
|
||||
MDEVCTL_ACTION_UNKNOWN,
|
||||
};
|
||||
@@ -38,6 +39,7 @@ enum mdevctl_event_id {
|
||||
MDEVCTL_EVENT_PRE = 0,
|
||||
MDEVCTL_EVENT_POST,
|
||||
MDEVCTL_EVENT_GET,
|
||||
MDEVCTL_EVENT_LIVE,
|
||||
MDEVCTL_EVENT_UNKNOWN,
|
||||
};
|
||||
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN
|
||||
|
||||
@@ -951,7 +951,7 @@ static void set_record_extension(struct file *f, int *record, off_t addr,
|
||||
|
||||
if (f->record_scan_state != RSS_DATA_BLOCK_STARTED &&
|
||||
f->record_scan_state != RSS_DATA_BLOCK_EXT)
|
||||
DIE("%s: interal error\n", __func__);
|
||||
DIE("%s: internal error\n", __func__);
|
||||
|
||||
BUG(*record >= f->fst->nr_records);
|
||||
|
||||
|
||||
20
common.mak
20
common.mak
@@ -31,11 +31,11 @@ endif
|
||||
# Global definitions
|
||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||
VERSION = 2
|
||||
RELEASE = 32
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
VERSION := 2
|
||||
RELEASE := 36
|
||||
PATCHLEVEL := 0
|
||||
DISTRELEASE := build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE := $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
export S390_TOOLS_RELEASE
|
||||
|
||||
reldir = $(subst $(realpath $(dir $(filter %common.mak,$(MAKEFILE_LIST))))/,,$(CURDIR))
|
||||
@@ -48,7 +48,7 @@ export S390_TEST_LIB_PATH=$(rootdir)/s390-tools-testsuite/lib
|
||||
# $ make HOST_ARCH=s390x CROSS_COMPILE="s390x-linux-gnu-"
|
||||
#
|
||||
|
||||
CROSS_COMPILE =
|
||||
CROSS_COMPILE ?=
|
||||
|
||||
#
|
||||
# Commands can be overwritten on the command line with "make <VAR>=<VALUE>":
|
||||
@@ -293,8 +293,8 @@ INSTDIRS = $(USRSBINDIR) $(USRBINDIR) $(BINDIR) $(LIBDIR) $(MANDIR) \
|
||||
$(ZFCPDUMP_DIR) $(SYSTEMDSYSTEMUNITDIR) \
|
||||
$(USRLIB64DIR) $(USRINCLUDEDIR) $(ZKEYKMSPLUGINDIR) \
|
||||
$(SOINSTALLDIR) $(USRLIBDIR)
|
||||
OWNER = $(shell id -un)
|
||||
GROUP = $(shell id -gn)
|
||||
OWNER := $(shell id -un)
|
||||
GROUP := $(shell id -gn)
|
||||
export INSTALLDIR BINDIR LIBDIR USRLIBDIR USRLIB64DIR MANDIR OWNER GROUP
|
||||
|
||||
# Special defines for zfcpdump
|
||||
@@ -504,6 +504,10 @@ $(rootdir)/libpv/libpv.a: $(rootdir)/libpv
|
||||
$(MAKE) -C $(rootdir)/libpv libpv.a
|
||||
.PHONY: $(rootdir)/libpv
|
||||
|
||||
$(rootdir)/libzpci/libzpci.a: $(rootdir)/libzpci
|
||||
$(MAKE) -C $(rootdir)/libzpci libzpci.a
|
||||
.PHONY: $(rootdir)/libzpci
|
||||
|
||||
$(rootdir)/zipl/boot/.loaders:
|
||||
$(MAKE) -C $(rootdir)/zipl/boot/ .loaders
|
||||
|
||||
|
||||
@@ -21,10 +21,11 @@ ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
||||
|
||||
all: check_dep cpacfstats cpacfstatsd
|
||||
|
||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o cpacfstats_common.o \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -ludev -lpthread -o $@
|
||||
|
||||
cpacfstats: cpacfstats.o stats_sock.o
|
||||
cpacfstats: cpacfstats.o stats_sock.o cpacfstats_common.o
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
install: all
|
||||
|
||||
@@ -55,168 +55,6 @@ static const char *const counter_str[] = {
|
||||
[PAI_KERNEL] = "pai_kernel"
|
||||
};
|
||||
|
||||
/* Strings for the pai counter details. Note that this is 0-based
|
||||
* while PoP is 1-based.
|
||||
*/
|
||||
static const char *const pai_str[] = {
|
||||
[ 0] = "KM DES",
|
||||
[ 1] = "KM 2key TDES",
|
||||
[ 2] = "KM TDES",
|
||||
[ 3] = "KM DES protected key",
|
||||
[ 4] = "KM 2key TDES protected key",
|
||||
[ 5] = "KM TDES protected key",
|
||||
[ 6] = "KM AES 128bit",
|
||||
[ 7] = "KM AES 192bit",
|
||||
[ 8] = "KM AES 256bit",
|
||||
[ 9] = "KM AES 128bit protected key",
|
||||
[ 10] = "KM AES 192bit protected key",
|
||||
[ 11] = "KM AES 256bit protected key",
|
||||
[ 12] = "KM AES-XTS 128bit",
|
||||
[ 13] = "KM AES-XTS 256bit",
|
||||
[ 14] = "KM AES-XTS 128bit protected key",
|
||||
[ 15] = "KM AES-XTS 256bit protected key",
|
||||
[ 16] = "KMC DES",
|
||||
[ 17] = "KMC 2key TDES",
|
||||
[ 18] = "KMC TDES",
|
||||
[ 19] = "KMC DES protected key",
|
||||
[ 20] = "KMC 2key TDES protected key",
|
||||
[ 21] = "KMC TDES protected key",
|
||||
[ 22] = "KMC AES 128bit",
|
||||
[ 23] = "KMC AES 192bit",
|
||||
[ 24] = "KMC AES 256bit",
|
||||
[ 25] = "KMC AES 128bit protected key",
|
||||
[ 26] = "KMC AES 192bit protected key",
|
||||
[ 27] = "KMC AES 256bit protected key",
|
||||
[ 28] = "KMC PRNG",
|
||||
[ 29] = "KMA AES 128bit",
|
||||
[ 30] = "KMA AES 192bit",
|
||||
[ 31] = "KMA AES 256bit",
|
||||
[ 32] = "KMA AES 128bit protected key",
|
||||
[ 33] = "KMA AES 192bit protected key",
|
||||
[ 34] = "KMA AES 256bit protected key",
|
||||
[ 35] = "KMF DES",
|
||||
[ 36] = "KMF 2key TDES",
|
||||
[ 37] = "KMF TDES",
|
||||
[ 38] = "KMF DES protected key",
|
||||
[ 39] = "KMF 2key TDES protected key",
|
||||
[ 40] = "KMF TDES protected key",
|
||||
[ 41] = "KMF AES 128bit",
|
||||
[ 42] = "KMF AES 192bit",
|
||||
[ 43] = "KMF AES 256bit",
|
||||
[ 44] = "KMF AES 128bit protected key",
|
||||
[ 45] = "KMF AES 192bit protected key",
|
||||
[ 46] = "KMF AES 256bit protected key",
|
||||
[ 47] = "KMCTR DES",
|
||||
[ 48] = "KMCTR 2key TDES",
|
||||
[ 49] = "KMCTR TDES",
|
||||
[ 50] = "KMCTR DES protected key",
|
||||
[ 51] = "KMCTR 2key TDES protected key",
|
||||
[ 52] = "KMCTR TDES protected key",
|
||||
[ 53] = "KMCTR AES 128bit",
|
||||
[ 54] = "KMCTR AES 192bit",
|
||||
[ 55] = "KMCTR AES 256bit",
|
||||
[ 56] = "KMCTR AES 128bit protected key",
|
||||
[ 57] = "KMCTR AES 192bit protected key",
|
||||
[ 58] = "KMCTR AES 256bit protected key",
|
||||
[ 59] = "KMO DES",
|
||||
[ 60] = "KMO 2key TDES",
|
||||
[ 61] = "KMO TDES",
|
||||
[ 62] = "KMO DES protected key",
|
||||
[ 63] = "KMO 2key TDES protected key",
|
||||
[ 64] = "KMO TDES protected key",
|
||||
[ 65] = "KMO AES 128bit",
|
||||
[ 66] = "KMO AES 192bit",
|
||||
[ 67] = "KMO AES 256bit",
|
||||
[ 68] = "KMO AES 128bit protected key",
|
||||
[ 69] = "KMO AES 192bit protected key",
|
||||
[ 70] = "KMO AES 256bit protected key",
|
||||
[ 71] = "KIMD SHA1",
|
||||
[ 72] = "KIMD SHA256",
|
||||
[ 73] = "KIMD SHA512",
|
||||
[ 74] = "KIMD SHA3-224",
|
||||
[ 75] = "KIMD SHA3-256",
|
||||
[ 76] = "KIMD SHA3-384",
|
||||
[ 77] = "KIMD SHA3-512",
|
||||
[ 78] = "KIMD SHAKE 128",
|
||||
[ 79] = "KIMD SHAKE 256",
|
||||
[ 80] = "KIMD GHASH",
|
||||
[ 81] = "KLMD SHA1",
|
||||
[ 82] = "KLMD SHA256",
|
||||
[ 83] = "KLMD SHA512",
|
||||
[ 84] = "KLMD SHA3-224",
|
||||
[ 85] = "KLMD SHA3-256",
|
||||
[ 86] = "KLMD SHA3-384",
|
||||
[ 87] = "KLMD SHA3-512",
|
||||
[ 88] = "KLMD SHAKE 128",
|
||||
[ 89] = "KLMD SHAKE 256",
|
||||
[ 90] = "KMAC DES",
|
||||
[ 91] = "KMAC 2key TDES",
|
||||
[ 92] = "KMAC TDES",
|
||||
[ 93] = "KMAC DES protected key",
|
||||
[ 94] = "KMAC 2key TDES protected key",
|
||||
[ 95] = "KMAC TDES protected key",
|
||||
[ 96] = "KMAC AES 128bit",
|
||||
[ 97] = "KMAC AES 192bit",
|
||||
[ 98] = "KMAC AES 256bit",
|
||||
[ 99] = "KMAC AES 128bit protected key",
|
||||
[100] = "KMAC AES 192bit protected key",
|
||||
[101] = "KMAC AES 256bit protected key",
|
||||
[102] = "PCC Last Block CMAC DES",
|
||||
[103] = "PCC Last Block CMAC 2key TDES",
|
||||
[104] = "PCC Last Block CMAC TDES",
|
||||
[105] = "PCC Last Block CMAC DES protected key",
|
||||
[106] = "PCC Last Block CMAC 2key TDES protected key",
|
||||
[107] = "PCC Last Block CMAC TDES protected key",
|
||||
[108] = "PCC Last Block CMAC AES 128bit",
|
||||
[109] = "PCC Last Block CMAC AES 192bit",
|
||||
[110] = "PCC Last Block CMAC AES 256bit",
|
||||
[111] = "PCC Last Block CMAC AES 128bit protected key",
|
||||
[112] = "PCC Last Block CMAC AES 192bit protected key",
|
||||
[113] = "PCC Last Block CMAC AES 256bit protected key",
|
||||
[114] = "PCC XTS Parameter AES 128bit",
|
||||
[115] = "PCC XTS Parameter AES 256bit",
|
||||
[116] = "PCC XTS Parameter AES 128bit protected key",
|
||||
[117] = "PCC XTS Parameter AES 256bit protected key",
|
||||
[118] = "PCC Scalar Mult P256",
|
||||
[119] = "PCC Scalar Mult P384",
|
||||
[120] = "PCC Scalar Mult P521",
|
||||
[121] = "PCC Scalar Mult Ed25519",
|
||||
[122] = "PCC Scalar Mult Ed448",
|
||||
[123] = "PCC Scalar Mult X25519",
|
||||
[124] = "PCC Scalar Mult X448",
|
||||
[125] = "PRNO SHA512 DRNG",
|
||||
[126] = "PRNO TRNG Query Ratio",
|
||||
[127] = "PRNO TRNG",
|
||||
[128] = "KDSA ECDSA Verify P256",
|
||||
[129] = "KDSA ECDSA Verify P384",
|
||||
[130] = "KDSA ECDSA Verify P521",
|
||||
[131] = "KDSA ECDSA Sign P256",
|
||||
[132] = "KDSA ECDSA Sign P384",
|
||||
[133] = "KDSA ECDSA Sign P521",
|
||||
[134] = "KDSA ECDSA Sign P256 protected key",
|
||||
[135] = "KDSA ECDSA Sign P384 protected key",
|
||||
[136] = "KDSA ECDSA Sign P521 protected key",
|
||||
[137] = "KDSA EdDSA Verify Ed25519",
|
||||
[138] = "KDSA EdDSA Verify Ed448",
|
||||
[139] = "KDSA EdDSA Sign Ed25519",
|
||||
[140] = "KDSA EdDSA Sign Ed448",
|
||||
[141] = "KDSA EdDSA Sign Ed25519 protected key",
|
||||
[142] = "KDSA EdDSA Sign Ed448 protected key",
|
||||
[143] = "PCKMO DES",
|
||||
[144] = "PCKMO 2key TDES",
|
||||
[145] = "PCKMO TDES",
|
||||
[146] = "PCKMO AES 128bit",
|
||||
[147] = "PCKMO AES 192bit",
|
||||
[148] = "PCKMO AES 256bit",
|
||||
[149] = "PCKMO ECC P256",
|
||||
[150] = "PCKMO ECC P384",
|
||||
[151] = "PCKMO ECC P521",
|
||||
[152] = "PCKMO ECC Ed25519",
|
||||
[153] = "PCKMO ECC Ed448",
|
||||
[154] = "Reserved 1",
|
||||
[155] = "Reserved 2"
|
||||
};
|
||||
|
||||
|
||||
static int paiprintnonzero;
|
||||
|
||||
@@ -275,7 +113,8 @@ static void json_print_virtual_counter_answer(int s, int ctr,
|
||||
int state, uint64_t value)
|
||||
{
|
||||
int paictr = 0, paistate = 0, ec;
|
||||
uint64_t i, paivalue = 0, maxnum;
|
||||
uint64_t i, paivalue = 0;
|
||||
unsigned int maxnum;
|
||||
const char *space;
|
||||
|
||||
switch (ctr) {
|
||||
@@ -288,11 +127,11 @@ static void json_print_virtual_counter_answer(int s, int ctr,
|
||||
printf("\"value\":%d}", !!value);
|
||||
return;
|
||||
case PAI_USER:
|
||||
maxnum = NUM_PAI_USER;
|
||||
maxnum = get_num_user_space_ctrs();
|
||||
space = "user";
|
||||
break;
|
||||
case PAI_KERNEL:
|
||||
maxnum = NUM_PAI_KERNEL;
|
||||
maxnum = MAX_NUM_PAI;
|
||||
space = "kernel";
|
||||
break;
|
||||
default:
|
||||
@@ -304,7 +143,7 @@ static void json_print_virtual_counter_answer(int s, int ctr,
|
||||
return;
|
||||
if (value > maxnum) {
|
||||
eprint("Incompatible versions detected!\n");
|
||||
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
|
||||
eprint("Expected %lu counter space for %s, but got %lu\n",
|
||||
maxnum, space, value);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -315,18 +154,18 @@ static void json_print_virtual_counter_answer(int s, int ctr,
|
||||
/* No more data for this virtual event after error. */
|
||||
return;
|
||||
}
|
||||
if (paictr > NUM_PAI_KERNEL) {
|
||||
if (paictr > MAX_NUM_PAI) {
|
||||
eprint("Pai counter number too big: %d\n", paictr);
|
||||
} else {
|
||||
printjsonsep();
|
||||
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
|
||||
pai_str[paictr], space, paictr + 1);
|
||||
get_ctr_name(paictr), space, paictr + 1);
|
||||
if (paistate < 0) {
|
||||
printf("\"error\":%d}", paistate);
|
||||
/* Protocol does not send further counters. */
|
||||
return;
|
||||
}
|
||||
printf("\"value\":%"PRIu64"}", paivalue);
|
||||
printf("\"value\":%lu}", paivalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -341,7 +180,8 @@ static void print_virtual_counter_answer(int s,
|
||||
[UNSUPPORTED] = "unsupported"
|
||||
};
|
||||
int paictr = 0, paistate = 0, ec;
|
||||
uint64_t i, paivalue = 0, maxnum;
|
||||
uint64_t i, paivalue = 0;
|
||||
unsigned int maxnum;
|
||||
const char *ctrstr;
|
||||
|
||||
switch (ctr) {
|
||||
@@ -350,11 +190,11 @@ static void print_virtual_counter_answer(int s,
|
||||
printf(" hotplug detected\n");
|
||||
return;
|
||||
case PAI_USER:
|
||||
maxnum = NUM_PAI_USER;
|
||||
maxnum = get_num_user_space_ctrs();
|
||||
ctrstr = "pai_user";
|
||||
break;
|
||||
case PAI_KERNEL:
|
||||
maxnum = NUM_PAI_KERNEL;
|
||||
maxnum = MAX_NUM_PAI;
|
||||
ctrstr = "pai_kernel";
|
||||
break;
|
||||
default:
|
||||
@@ -372,7 +212,7 @@ static void print_virtual_counter_answer(int s,
|
||||
return;
|
||||
if (value > maxnum) {
|
||||
eprint("Incompatible versions detected!\n");
|
||||
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
|
||||
eprint("Expected %lu counters for %s, but got %lu\n",
|
||||
maxnum, ctrstr, value);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -383,10 +223,11 @@ static void print_virtual_counter_answer(int s,
|
||||
/* No more data for this virtual event after error. */
|
||||
return;
|
||||
}
|
||||
if (paictr > NUM_PAI_KERNEL)
|
||||
if (paictr > MAX_NUM_PAI)
|
||||
eprint("Pai counter number too big: %d\n", paictr);
|
||||
else if (!paiprintnonzero || paivalue > 0)
|
||||
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
|
||||
printf(" (%3d) %-45s: %lu\n", paictr + 1,
|
||||
get_ctr_name(paictr), paivalue);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -402,7 +243,7 @@ static void print_answer(int s, int ctr, int state, uint64_t value)
|
||||
else if (state == UNSUPPORTED)
|
||||
printf(" %s counter: unsupported\n", counter_str[ctr]);
|
||||
else
|
||||
printf(" %s counter: %"PRIu64"\n", counter_str[ctr], value);
|
||||
printf(" %s counter: %lu\n", counter_str[ctr], value);
|
||||
}
|
||||
|
||||
|
||||
@@ -417,7 +258,7 @@ static void json_print_answer(int s, int ctr, int state, uint64_t value)
|
||||
} else if (state == ENABLED) {
|
||||
printjsonsep();
|
||||
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
||||
printf("\"value\":%"PRIu64"}", value);
|
||||
printf("\"value\":%lu}", value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,22 @@
|
||||
#define DEFAULT_RECV_TIMEOUT (30 * 1000)
|
||||
|
||||
/*
|
||||
* Number of PAI counters for user space. This excludes PCKMO since
|
||||
* this instruction is privileged.
|
||||
* Number of PAI counters. Contains all counters regardless of kernel or user
|
||||
* space
|
||||
*/
|
||||
#define NUM_PAI_USER 143
|
||||
/* Number of PAI counters for kernel space. Contains all counters. */
|
||||
#define NUM_PAI_KERNEL 156
|
||||
#define MAX_NUM_PAI 172
|
||||
|
||||
/*
|
||||
* This is the sysfs directory from which cpacfstatsd daemon application loads
|
||||
* the available PAI counters
|
||||
*/
|
||||
#define SYSFS_PAI_COUNTER "/sys/bus/event_source/devices/pai_crypto/events/"
|
||||
|
||||
/*
|
||||
* Note that this is the first kernel only counter in the 1-based list of the
|
||||
* architecture and NOT from the 0-based list in the cpacfstats code!
|
||||
*/
|
||||
#define FIRST_KERNEL_ONLY_COUNTER 144
|
||||
|
||||
int eprint(const char *format, ...);
|
||||
|
||||
@@ -67,6 +77,12 @@ enum state_e {
|
||||
UNSUPPORTED
|
||||
};
|
||||
|
||||
enum counter_type {
|
||||
SUPPRESS_COUNTER = 0,
|
||||
KERNEL_AND_USER_COUNTER,
|
||||
KERNEL_ONLY_COUNTER,
|
||||
};
|
||||
|
||||
/*
|
||||
* query send from client to daemon
|
||||
* Consist of:
|
||||
@@ -122,15 +138,23 @@ int recv_msg(int sfd, struct msg *m, int timeout);
|
||||
|
||||
/* perf_crypto.c */
|
||||
|
||||
int perf_init(void);
|
||||
int perf_init(unsigned int *supported_counters);
|
||||
void perf_stop(void);
|
||||
void perf_close(void);
|
||||
int perf_enable_ctr(enum ctr_e ctr);
|
||||
int perf_disable_ctr(enum ctr_e ctr);
|
||||
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value);
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
||||
int perf_enable_ctr(enum ctr_e ctr, unsigned int *supported_counters);
|
||||
int perf_disable_ctr(enum ctr_e ctr, unsigned int *supported_counters);
|
||||
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
|
||||
*supported_counters);
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
|
||||
*supported_counters);
|
||||
int perf_ecc_supported(void);
|
||||
int perf_ctr_state(enum ctr_e ctr);
|
||||
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value);
|
||||
|
||||
/* cpacfstats_common.c */
|
||||
|
||||
enum counter_type is_user_space(unsigned int ctr);
|
||||
const char *get_ctr_name(unsigned int ctr);
|
||||
unsigned int get_num_user_space_ctrs(void);
|
||||
|
||||
#endif
|
||||
|
||||
253
cpacfstats/cpacfstats_common.c
Normal file
253
cpacfstats/cpacfstats_common.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* cpacfstats_common.c - shared code by daemon and client
|
||||
*
|
||||
* Copyright IBM Corp. 2024
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include "cpacfstats.h"
|
||||
|
||||
struct pai_counter {
|
||||
const char *str;
|
||||
const unsigned int counter_type;
|
||||
};
|
||||
|
||||
/*
|
||||
* Strings for the pai counter details.
|
||||
* Integer indicating if kernel space is needed (0 for user, KERNEL_ONLY_COUNTER for kernel)
|
||||
* Note that this is 0-based while PoP is 1-based.
|
||||
*
|
||||
* When adding new items to this list add the counter number in the pai_idx
|
||||
* list in cpacfstatsd.c and increase the number of total counters in
|
||||
* cpacfstats.h.
|
||||
*/
|
||||
const struct pai_counter pai[] = {
|
||||
[ 0] = {"KM DES", KERNEL_AND_USER_COUNTER},
|
||||
[ 1] = {"KM 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 2] = {"KM TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 3] = {"KM DES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 4] = {"KM 2key TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 5] = {"KM TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 6] = {"KM AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 7] = {"KM AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 8] = {"KM AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 9] = {"KM AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 10] = {"KM AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 11] = {"KM AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 12] = {"KM AES-XTS 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 13] = {"KM AES-XTS 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 14] = {"KM AES-XTS 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 15] = {"KM AES-XTS 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 16] = {"KMC DES", KERNEL_AND_USER_COUNTER},
|
||||
[ 17] = {"KMC 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 18] = {"KMC TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 19] = {"KMC DES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 20] = {"KMC 2key TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 21] = {"KMC TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 22] = {"KMC AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 23] = {"KMC AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 24] = {"KMC AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 25] = {"KMC AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 26] = {"KMC AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 27] = {"KMC AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 28] = {"KMC PRNG", KERNEL_AND_USER_COUNTER},
|
||||
[ 29] = {"KMA AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 30] = {"KMA AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 31] = {"KMA AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 32] = {"KMA AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 33] = {"KMA AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 34] = {"KMA AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 35] = {"KMF DES", KERNEL_AND_USER_COUNTER},
|
||||
[ 36] = {"KMF 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 37] = {"KMF TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 38] = {"KMF DES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 39] = {"KMF 2key TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 40] = {"KMF TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 41] = {"KMF AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 42] = {"KMF AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 43] = {"KMF AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 44] = {"KMF AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 45] = {"KMF AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 46] = {"KMF AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 47] = {"KMCTR DES", KERNEL_AND_USER_COUNTER},
|
||||
[ 48] = {"KMCTR 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 49] = {"KMCTR TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 50] = {"KMCTR DES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 51] = {"KMCTR 2key TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 52] = {"KMCTR TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 53] = {"KMCTR AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 54] = {"KMCTR AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 55] = {"KMCTR AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 56] = {"KMCTR AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 57] = {"KMCTR AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 58] = {"KMCTR AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 59] = {"KMO DES", KERNEL_AND_USER_COUNTER},
|
||||
[ 60] = {"KMO 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 61] = {"KMO TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 62] = {"KMO DES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 63] = {"KMO 2key TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 64] = {"KMO TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 65] = {"KMO AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 66] = {"KMO AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 67] = {"KMO AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 68] = {"KMO AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 69] = {"KMO AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 70] = {"KMO AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 71] = {"KIMD SHA1", KERNEL_AND_USER_COUNTER},
|
||||
[ 72] = {"KIMD SHA256", KERNEL_AND_USER_COUNTER},
|
||||
[ 73] = {"KIMD SHA512", KERNEL_AND_USER_COUNTER},
|
||||
[ 74] = {"KIMD SHA3-224", KERNEL_AND_USER_COUNTER},
|
||||
[ 75] = {"KIMD SHA3-256", KERNEL_AND_USER_COUNTER},
|
||||
[ 76] = {"KIMD SHA3-384", KERNEL_AND_USER_COUNTER},
|
||||
[ 77] = {"KIMD SHA3-512", KERNEL_AND_USER_COUNTER},
|
||||
[ 78] = {"KIMD SHAKE 128", KERNEL_AND_USER_COUNTER},
|
||||
[ 79] = {"KIMD SHAKE 256", KERNEL_AND_USER_COUNTER},
|
||||
[ 80] = {"KIMD GHASH", KERNEL_AND_USER_COUNTER},
|
||||
[ 81] = {"KLMD SHA1", KERNEL_AND_USER_COUNTER},
|
||||
[ 82] = {"KLMD SHA256", KERNEL_AND_USER_COUNTER},
|
||||
[ 83] = {"KLMD SHA512", KERNEL_AND_USER_COUNTER},
|
||||
[ 84] = {"KLMD SHA3-224", KERNEL_AND_USER_COUNTER},
|
||||
[ 85] = {"KLMD SHA3-256", KERNEL_AND_USER_COUNTER},
|
||||
[ 86] = {"KLMD SHA3-384", KERNEL_AND_USER_COUNTER},
|
||||
[ 87] = {"KLMD SHA3-512", KERNEL_AND_USER_COUNTER},
|
||||
[ 88] = {"KLMD SHAKE 128", KERNEL_AND_USER_COUNTER},
|
||||
[ 89] = {"KLMD SHAKE 256", KERNEL_AND_USER_COUNTER},
|
||||
[ 90] = {"KMAC DES", KERNEL_AND_USER_COUNTER},
|
||||
[ 91] = {"KMAC 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 92] = {"KMAC TDES", KERNEL_AND_USER_COUNTER},
|
||||
[ 93] = {"KMAC DES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 94] = {"KMAC 2key TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 95] = {"KMAC TDES protected key", KERNEL_AND_USER_COUNTER},
|
||||
[ 96] = {"KMAC AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 97] = {"KMAC AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 98] = {"KMAC AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[ 99] = {"KMAC AES 128bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[100] = {"KMAC AES 192bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[101] = {"KMAC AES 256bit protected key", KERNEL_AND_USER_COUNTER},
|
||||
[102] = {"PCC Last Block CMAC DES", KERNEL_AND_USER_COUNTER},
|
||||
[103] = {"PCC Last Block CMAC 2key TDES", KERNEL_AND_USER_COUNTER},
|
||||
[104] = {"PCC Last Block CMAC TDES", KERNEL_AND_USER_COUNTER},
|
||||
[105] = {"PCC Last Block CMAC DES protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[106] = {"PCC Last Block CMAC 2key TDES protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[107] = {"PCC Last Block CMAC TDES protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[108] = {"PCC Last Block CMAC AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[109] = {"PCC Last Block CMAC AES 192bit", KERNEL_AND_USER_COUNTER},
|
||||
[110] = {"PCC Last Block CMAC AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[111] = {"PCC Last Block CMAC AES 128bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[112] = {"PCC Last Block CMAC AES 192bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[113] = {"PCC Last Block CMAC AES 256bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[114] = {"PCC XTS Parameter AES 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[115] = {"PCC XTS Parameter AES 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[116] = {"PCC XTS Parameter AES 128bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[117] = {"PCC XTS Parameter AES 256bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[118] = {"PCC Scalar Mult P256", KERNEL_AND_USER_COUNTER},
|
||||
[119] = {"PCC Scalar Mult P384", KERNEL_AND_USER_COUNTER},
|
||||
[120] = {"PCC Scalar Mult P521", KERNEL_AND_USER_COUNTER},
|
||||
[121] = {"PCC Scalar Mult Ed25519", KERNEL_AND_USER_COUNTER},
|
||||
[122] = {"PCC Scalar Mult Ed448", KERNEL_AND_USER_COUNTER},
|
||||
[123] = {"PCC Scalar Mult X25519", KERNEL_AND_USER_COUNTER},
|
||||
[124] = {"PCC Scalar Mult X448", KERNEL_AND_USER_COUNTER},
|
||||
[125] = {"PRNO SHA512 DRNG", KERNEL_AND_USER_COUNTER},
|
||||
[126] = {"PRNO TRNG Query Ratio", KERNEL_AND_USER_COUNTER},
|
||||
[127] = {"PRNO TRNG", KERNEL_AND_USER_COUNTER},
|
||||
[128] = {"KDSA ECDSA Verify P256", KERNEL_AND_USER_COUNTER},
|
||||
[129] = {"KDSA ECDSA Verify P384", KERNEL_AND_USER_COUNTER},
|
||||
[130] = {"KDSA ECDSA Verify P521", KERNEL_AND_USER_COUNTER},
|
||||
[131] = {"KDSA ECDSA Sign P256", KERNEL_AND_USER_COUNTER},
|
||||
[132] = {"KDSA ECDSA Sign P384", KERNEL_AND_USER_COUNTER},
|
||||
[133] = {"KDSA ECDSA Sign P521", KERNEL_AND_USER_COUNTER},
|
||||
[134] = {"KDSA ECDSA Sign P256 protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[135] = {"KDSA ECDSA Sign P384 protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[136] = {"KDSA ECDSA Sign P521 protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[137] = {"KDSA EdDSA Verify Ed25519", KERNEL_AND_USER_COUNTER},
|
||||
[138] = {"KDSA EdDSA Verify Ed448", KERNEL_AND_USER_COUNTER},
|
||||
[139] = {"KDSA EdDSA Sign Ed25519", KERNEL_AND_USER_COUNTER},
|
||||
[140] = {"KDSA EdDSA Sign Ed448", KERNEL_AND_USER_COUNTER},
|
||||
[141] = {"KDSA EdDSA Sign Ed25519 protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[142] = {"KDSA EdDSA Sign Ed448 protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[143] = {"PCKMO DES", KERNEL_ONLY_COUNTER},
|
||||
[144] = {"PCKMO 2key TDES", KERNEL_ONLY_COUNTER},
|
||||
[145] = {"PCKMO TDES", KERNEL_ONLY_COUNTER},
|
||||
[146] = {"PCKMO AES 128bit", KERNEL_ONLY_COUNTER},
|
||||
[147] = {"PCKMO AES 192bit", KERNEL_ONLY_COUNTER},
|
||||
[148] = {"PCKMO AES 256bit", KERNEL_ONLY_COUNTER},
|
||||
[149] = {"PCKMO ECC P256", KERNEL_ONLY_COUNTER},
|
||||
[150] = {"PCKMO ECC P384", KERNEL_ONLY_COUNTER},
|
||||
[151] = {"PCKMO ECC P521", KERNEL_ONLY_COUNTER},
|
||||
[152] = {"PCKMO ECC Ed25519", KERNEL_ONLY_COUNTER},
|
||||
[153] = {"PCKMO ECC Ed448", KERNEL_ONLY_COUNTER},
|
||||
[154] = {"Reserved 1", KERNEL_ONLY_COUNTER},
|
||||
[155] = {"Reserved 2", KERNEL_ONLY_COUNTER},
|
||||
[156] = {"KM AES-XTS (full) 128bit", KERNEL_AND_USER_COUNTER},
|
||||
[157] = {"KM AES-XTS (full) 256bit", KERNEL_AND_USER_COUNTER},
|
||||
[158] = {"KM AES-XTS (full) 128bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[159] = {"KM AES-XTS (full) 256bit protected key",
|
||||
KERNEL_AND_USER_COUNTER},
|
||||
[160] = {"KMAC HMAC SHA 224", KERNEL_AND_USER_COUNTER},
|
||||
[161] = {"KMAC HMAC SHA 256", KERNEL_AND_USER_COUNTER},
|
||||
[162] = {"KMAC HMAC SHA 384", KERNEL_AND_USER_COUNTER},
|
||||
[163] = {"KMAC HMAC SHA 512", KERNEL_AND_USER_COUNTER},
|
||||
[164] = {"KMAC HMAC SHA 224 protected key", KERNEL_AND_USER_COUNTER},
|
||||
[165] = {"KMAC HMAC SHA 256 protected key", KERNEL_AND_USER_COUNTER},
|
||||
[166] = {"KMAC HMAC SHA 384 protected key", KERNEL_AND_USER_COUNTER},
|
||||
[167] = {"KMAC HMAC SHA 512 protected key", KERNEL_AND_USER_COUNTER},
|
||||
[168] = {"PCKMO HMAC 512 protected key", KERNEL_ONLY_COUNTER},
|
||||
[169] = {"PCKMO HMAC 1024 protected key", KERNEL_ONLY_COUNTER},
|
||||
[170] = {"PCKMO AES-XTS 128bit double key protected key",
|
||||
KERNEL_ONLY_COUNTER},
|
||||
[171] = {"PCKMO AES-XTS 256bit double key protected key",
|
||||
KERNEL_ONLY_COUNTER}
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns counter_type of pai_counter struct
|
||||
*
|
||||
* SUPPRESS_COUNTER
|
||||
* KERNEL_AND_USER_COUNTER
|
||||
* KERNEL_ONLY_COUNTER
|
||||
*/
|
||||
enum counter_type is_user_space(unsigned int ctr)
|
||||
{
|
||||
if (ctr >= MAX_NUM_PAI)
|
||||
return SUPPRESS_COUNTER;
|
||||
return pai[ctr].counter_type;
|
||||
}
|
||||
|
||||
const char *get_ctr_name(unsigned int ctr)
|
||||
{
|
||||
if (ctr >= MAX_NUM_PAI)
|
||||
return NULL;
|
||||
return pai[ctr].str;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns number of PAI counters for which no kernel space is needed
|
||||
*/
|
||||
unsigned int get_num_user_space_ctrs(void)
|
||||
{
|
||||
unsigned int counter = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < MAX_NUM_PAI; i++) {
|
||||
if (is_user_space(i) == KERNEL_AND_USER_COUNTER)
|
||||
counter++;
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
@@ -24,12 +24,54 @@
|
||||
#include <sys/stat.h>
|
||||
#include <syslog.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "cpacfstats.h"
|
||||
|
||||
static volatile int stopsig;
|
||||
|
||||
/*
|
||||
* This list contains the counter numbers sorted by instruction
|
||||
*/
|
||||
static const unsigned int pai_idx[] = {
|
||||
// KM
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 156, 157, 158,
|
||||
159,
|
||||
// KMC
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
|
||||
// KMA
|
||||
29, 30, 31, 32, 33, 34,
|
||||
// KMF
|
||||
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
|
||||
// KMCTR
|
||||
47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58,
|
||||
// KMO
|
||||
59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
|
||||
// KIMD
|
||||
71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
|
||||
// KLMD
|
||||
81, 82, 83, 84, 85, 86, 87, 88, 89,
|
||||
// KMAC
|
||||
90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 160, 161, 162, 163,
|
||||
164, 165, 166, 167,
|
||||
// PCC
|
||||
102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
|
||||
114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
|
||||
// PRNO
|
||||
125, 126, 127,
|
||||
// KDSA
|
||||
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
|
||||
140, 141, 142,
|
||||
// PCKMO
|
||||
143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 168, 169, 170, 171,
|
||||
// Reserved
|
||||
154, 155
|
||||
};
|
||||
|
||||
static const char *const name = "cpacfstatsd";
|
||||
|
||||
static const char *const usage =
|
||||
@@ -68,7 +110,6 @@ static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int send_answer(int s, int ctr, int state, uint64_t value)
|
||||
{
|
||||
struct msg m;
|
||||
@@ -84,7 +125,6 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
|
||||
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print according to protocol for PAI:
|
||||
* - first the state and the number of PAI counters that follow
|
||||
@@ -93,34 +133,34 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
|
||||
* Note that the PAI counters are 0-based, not 1 based as in PoP!
|
||||
* Sending ends with the first error.
|
||||
*/
|
||||
static int do_send_pai(int s, int user)
|
||||
static int do_send_pai(int s, int user, unsigned int *counter)
|
||||
{
|
||||
int ctr, state, i, maxctr, rc = 0;
|
||||
int ctr, state, i, rc = 0;
|
||||
unsigned int current_ctr;
|
||||
uint64_t value;
|
||||
|
||||
if (user) {
|
||||
ctr = PAI_USER;
|
||||
maxctr = NUM_PAI_USER;
|
||||
} else {
|
||||
ctr = PAI_KERNEL;
|
||||
maxctr = NUM_PAI_KERNEL;
|
||||
}
|
||||
ctr = user ? PAI_USER : PAI_KERNEL;
|
||||
|
||||
state = perf_ctr_state(ctr);
|
||||
if (state != ENABLED)
|
||||
return rc;
|
||||
for (i = 0; i < maxctr; ++i) {
|
||||
rc = perf_read_pai_ctr(i, user, &value);
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
current_ctr = pai_idx[i];
|
||||
if ((user && is_user_space(current_ctr) != KERNEL_AND_USER_COUNTER) ||
|
||||
(!user && is_user_space(current_ctr) == SUPPRESS_COUNTER) ||
|
||||
counter[current_ctr] != 1)
|
||||
continue;
|
||||
rc = perf_read_pai_ctr(current_ctr, user, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
send_answer(s, current_ctr, rc, 0);
|
||||
break;
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
send_answer(s, current_ctr, state, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_enable(int s, enum ctr_e ctr)
|
||||
static int do_enable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||
{
|
||||
uint64_t value = 0;
|
||||
int i, rc = 0;
|
||||
@@ -132,7 +172,7 @@ static int do_enable(int s, enum ctr_e ctr)
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
state = perf_ctr_state(i);
|
||||
if (state == DISABLED) {
|
||||
rc = perf_enable_ctr(i);
|
||||
rc = perf_enable_ctr(i, supported_counters);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
@@ -140,7 +180,7 @@ static int do_enable(int s, enum ctr_e ctr)
|
||||
state = ENABLED;
|
||||
}
|
||||
if (state != UNSUPPORTED) {
|
||||
rc = perf_read_ctr(i, &value);
|
||||
rc = perf_read_ctr(i, &value, supported_counters);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
@@ -148,20 +188,19 @@ static int do_enable(int s, enum ctr_e ctr)
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
if (i == PAI_USER)
|
||||
rc = do_send_pai(s, 1);
|
||||
rc = do_send_pai(s, 1, supported_counters);
|
||||
if (i == PAI_KERNEL)
|
||||
rc = do_send_pai(s, 0);
|
||||
rc = do_send_pai(s, 0, supported_counters);
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_disable(int s, enum ctr_e ctr)
|
||||
static int do_disable(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||
{
|
||||
int i, rc = 0;
|
||||
uint64_t value;
|
||||
@@ -171,7 +210,7 @@ static int do_disable(int s, enum ctr_e ctr)
|
||||
continue;
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (perf_ctr_state(i) == ENABLED) {
|
||||
rc = perf_disable_ctr(i);
|
||||
rc = perf_disable_ctr(i, supported_counters);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
@@ -181,14 +220,13 @@ static int do_disable(int s, enum ctr_e ctr)
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_reset(int s, enum ctr_e ctr)
|
||||
static int do_reset(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||
{
|
||||
int i, rc = 0, state;
|
||||
uint64_t value;
|
||||
@@ -199,7 +237,7 @@ static int do_reset(int s, enum ctr_e ctr)
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
state = perf_ctr_state(i);
|
||||
if (state == ENABLED) {
|
||||
rc = perf_reset_ctr(i, &value);
|
||||
rc = perf_reset_ctr(i, &value, supported_counters);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
@@ -207,20 +245,19 @@ static int do_reset(int s, enum ctr_e ctr)
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
if (i == PAI_USER)
|
||||
rc = do_send_pai(s, 1);
|
||||
rc = do_send_pai(s, 1, supported_counters);
|
||||
if (i == PAI_KERNEL)
|
||||
rc = do_send_pai(s, 0);
|
||||
rc = do_send_pai(s, 0, supported_counters);
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_print(int s, enum ctr_e ctr)
|
||||
static int do_print(int s, enum ctr_e ctr, unsigned int *supported_counters)
|
||||
{
|
||||
int i, rc = 0, state;
|
||||
uint64_t value = 0;
|
||||
@@ -231,7 +268,7 @@ static int do_print(int s, enum ctr_e ctr)
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
state = perf_ctr_state(i);
|
||||
if (state == ENABLED) {
|
||||
rc = perf_read_ctr(i, &value);
|
||||
rc = perf_read_ctr(i, &value, supported_counters);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
@@ -239,19 +276,18 @@ static int do_print(int s, enum ctr_e ctr)
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
if (i == PAI_USER)
|
||||
rc = do_send_pai(s, 1);
|
||||
rc = do_send_pai(s, 1, supported_counters);
|
||||
if (i == PAI_KERNEL)
|
||||
rc = do_send_pai(s, 0);
|
||||
rc = do_send_pai(s, 0, supported_counters);
|
||||
}
|
||||
}
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value, NULL);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int become_daemon(int *startup_pipe)
|
||||
{
|
||||
int child_initialized = 0, fd;
|
||||
@@ -344,7 +380,6 @@ static int become_daemon(int *startup_pipe)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void remove_sock(void)
|
||||
{
|
||||
remove(SOCKET_FILE);
|
||||
@@ -406,14 +441,12 @@ static void remove_pidfile(void)
|
||||
remove(PID_FILE);
|
||||
}
|
||||
|
||||
|
||||
void signalhandler(int sig)
|
||||
{
|
||||
perf_stop();
|
||||
stopsig = sig;
|
||||
}
|
||||
|
||||
|
||||
int eprint(const char *format, ...)
|
||||
{
|
||||
char buf[512];
|
||||
@@ -435,10 +468,44 @@ int eprint(const char *format, ...)
|
||||
return n;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns -1 on error
|
||||
* returns X where X is the found counters in dir
|
||||
*
|
||||
* the supplied array supported_counters[] is filled in this function with the
|
||||
* available PAI counters found in SYSFS_PAI_COUNTER
|
||||
*/
|
||||
static void supported_functions(unsigned int supported_counters[])
|
||||
{
|
||||
const char *dir = SYSFS_PAI_COUNTER;
|
||||
struct dirent *dp = NULL;
|
||||
char filepath[PATH_MAX];
|
||||
unsigned int num;
|
||||
DIR *dfd = NULL;
|
||||
|
||||
dfd = opendir(dir);
|
||||
if (dfd == NULL)
|
||||
return;
|
||||
|
||||
while ((dp = readdir(dfd)) != NULL) {
|
||||
if ((strcmp(dp->d_name, ".") != 0) &&
|
||||
(strcmp(dp->d_name, "..") != 0)) {
|
||||
snprintf(filepath, sizeof(filepath), "%s%s", dir, dp->d_name);
|
||||
if (util_file_read_va(filepath, "event=0x10%x", &num) != 1)
|
||||
continue;
|
||||
if (num > 0 && num <= MAX_NUM_PAI)
|
||||
supported_counters[num - 1] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dfd);
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int rc, sfd, foreground = 0, startup_pipe = -1, initialized = 0;
|
||||
unsigned int supported_counters[MAX_NUM_PAI] = { 0 };
|
||||
struct sigaction act;
|
||||
|
||||
if (argc > 1) {
|
||||
@@ -485,7 +552,9 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (perf_init() != 0) {
|
||||
supported_functions(supported_counters);
|
||||
|
||||
if (perf_init(supported_counters) != 0) {
|
||||
eprint("Couldn't initialize perf lib\n");
|
||||
goto error;
|
||||
}
|
||||
@@ -548,13 +617,13 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (cmd == ENABLE)
|
||||
rc = do_enable(s, ctr);
|
||||
rc = do_enable(s, ctr, supported_counters);
|
||||
else if (cmd == DISABLE)
|
||||
rc = do_disable(s, ctr);
|
||||
rc = do_disable(s, ctr, supported_counters);
|
||||
else if (cmd == RESET)
|
||||
rc = do_reset(s, ctr);
|
||||
rc = do_reset(s, ctr, supported_counters);
|
||||
else if (cmd == PRINT)
|
||||
rc = do_print(s, ctr);
|
||||
rc = do_print(s, ctr, supported_counters);
|
||||
else {
|
||||
eprint("Received unknown command %d, ignoring\n",
|
||||
(int) cmd);
|
||||
|
||||
@@ -52,8 +52,8 @@ static struct pmf_data {
|
||||
|
||||
struct percpucounter {
|
||||
int ctr_fds[ALL_COUNTER];
|
||||
int pai_user[NUM_PAI_USER];
|
||||
int pai_kernel[NUM_PAI_KERNEL];
|
||||
int pai_user[MAX_NUM_PAI];
|
||||
int pai_kernel[MAX_NUM_PAI];
|
||||
unsigned int cpunum;
|
||||
struct percpucounter *next;
|
||||
};
|
||||
@@ -84,10 +84,10 @@ static struct percpucounter *allocpercpucounter(unsigned int cpunum)
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
ppc->ctr_fds[i] = -1;
|
||||
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
ppc->pai_user[i] = -1;
|
||||
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||
ppc->pai_kernel[i] = -1;
|
||||
}
|
||||
ppc->cpunum = cpunum;
|
||||
ppc->next = NULL;
|
||||
}
|
||||
@@ -100,10 +100,10 @@ static void freepercpucounter(struct percpucounter *pcpu)
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
(void)close(pcpu->ctr_fds[i]);
|
||||
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
(void)close(pcpu->pai_user[i]);
|
||||
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||
(void)close(pcpu->pai_kernel[i]);
|
||||
}
|
||||
free(pcpu);
|
||||
}
|
||||
|
||||
@@ -225,7 +225,7 @@ static int perf_event_encode(int *pmutype, int *eventid,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int activatecpu(unsigned int cpu)
|
||||
static int activatecpu(unsigned int cpu, unsigned int *supported_counters)
|
||||
{
|
||||
struct perf_event_attr pfm_event;
|
||||
struct percpucounter *ppc;
|
||||
@@ -273,7 +273,10 @@ static int activatecpu(unsigned int cpu)
|
||||
(ctr_state[PAI_USER] == UNSUPPORTED) ==
|
||||
(ctr_state[PAI_KERNEL] == UNSUPPORTED) */
|
||||
if (ctr_state[PAI_USER] != UNSUPPORTED) {
|
||||
for (i = 1; i <= NUM_PAI_USER; ++i) {
|
||||
for (i = 1; i <= MAX_NUM_PAI; ++i) {
|
||||
if (is_user_space(i - 1) != KERNEL_AND_USER_COUNTER ||
|
||||
supported_counters[i - 1] != 1)
|
||||
continue;
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
pfm_event.type = paipmutype;
|
||||
@@ -307,7 +310,14 @@ static int activatecpu(unsigned int cpu)
|
||||
ppc->pai_kernel[i - 1] = fd;
|
||||
}
|
||||
}
|
||||
for (; i <= NUM_PAI_KERNEL; ++i) {
|
||||
/*
|
||||
* i can start at the index of the first PAI counter
|
||||
* for which kernel space is needed
|
||||
*/
|
||||
for (i = FIRST_KERNEL_ONLY_COUNTER; i <= MAX_NUM_PAI; ++i) {
|
||||
if (is_user_space(i - 1) == SUPPRESS_COUNTER ||
|
||||
supported_counters[i - 1] != 1)
|
||||
continue;
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
pfm_event.type = paipmutype;
|
||||
@@ -348,10 +358,10 @@ static void deactivatecpu(unsigned int cpunum)
|
||||
if (pcpu != NULL) {
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
(void)close(pcpu->ctr_fds[i]);
|
||||
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
(void)close(pcpu->pai_user[i]);
|
||||
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||
(void)close(pcpu->pai_kernel[i]);
|
||||
}
|
||||
free(pcpu);
|
||||
if (enabledcounter)
|
||||
hotplugdetected = 1;
|
||||
@@ -359,7 +369,7 @@ static void deactivatecpu(unsigned int cpunum)
|
||||
pthread_mutex_unlock(&rootmux);
|
||||
}
|
||||
|
||||
static int addallcpus(void)
|
||||
static int addallcpus(unsigned int *supported_counters)
|
||||
{
|
||||
unsigned int start, end;
|
||||
int scanned, rc = 0;
|
||||
@@ -379,7 +389,7 @@ static int addallcpus(void)
|
||||
if (scanned == 1)
|
||||
end = start;
|
||||
for (; start <= end; ++start) {
|
||||
if (activatecpu(start)) {
|
||||
if (activatecpu(start, supported_counters)) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
@@ -409,7 +419,7 @@ static int perf_load_counter_data(void)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *hotplughandler(void *UNUSED(unused))
|
||||
static void *hotplughandler(void *supported_counters)
|
||||
{
|
||||
struct udev *hotplug;
|
||||
struct udev_monitor *monitor;
|
||||
@@ -452,7 +462,7 @@ static void *hotplughandler(void *UNUSED(unused))
|
||||
path = udev_device_get_devpath(dev);
|
||||
if (sscanf(path, "/devices/system/cpu/cpu%u", &cpunum) != 1)
|
||||
continue;
|
||||
if (on && activatecpu(cpunum))
|
||||
if (on && activatecpu(cpunum, (unsigned int *) supported_counters))
|
||||
eprint("Failed to attach to hotplugged CPU %u\n", cpunum);
|
||||
if (off)
|
||||
deactivatecpu(cpunum);
|
||||
@@ -462,11 +472,18 @@ static void *hotplughandler(void *UNUSED(unused))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int perf_init(void)
|
||||
int perf_init(unsigned int *supported_counters)
|
||||
{
|
||||
int ecc_supported, i, num;
|
||||
static const char *cpum_cf[] = {
|
||||
"DEA_FUNCTIONS",
|
||||
"AES_FUNCTIONS",
|
||||
"SHA_FUNCTIONS",
|
||||
"PRNG_FUNCTIONS",
|
||||
"ECC_FUNCTION_COUNT"
|
||||
};
|
||||
unsigned long maxfd;
|
||||
struct rlimit rlim;
|
||||
int i, num;
|
||||
FILE *f;
|
||||
|
||||
/* initialize performance monitoring library */
|
||||
@@ -478,16 +495,18 @@ int perf_init(void)
|
||||
/* We currently support all cpumf counters plus two virtual
|
||||
* counters for PAI. */
|
||||
num = ALL_COUNTER + 2;
|
||||
/* Check if ECC is supported on current hardware */
|
||||
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
||||
|
||||
if (!cpumf_authorized()) {
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
ctr_state[i] = UNSUPPORTED;
|
||||
num -= ALL_COUNTER;
|
||||
} else if (!ecc_supported) {
|
||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||
--num;
|
||||
} else {
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
if (!perf_counter_supported("cpum_cf", cpum_cf[i])) {
|
||||
ctr_state[i] = UNSUPPORTED;
|
||||
num--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!perf_counter_supported("pai_crypto", "CRYPTO_ALL")) {
|
||||
@@ -523,11 +542,12 @@ int perf_init(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
|
||||
if (pthread_create(&hotplugthread, NULL, hotplughandler,
|
||||
supported_counters)) {
|
||||
eprint("Failed to start hotplug handler thread\n");
|
||||
return -1;
|
||||
}
|
||||
return addallcpus();
|
||||
return addallcpus(supported_counters);
|
||||
}
|
||||
|
||||
|
||||
@@ -552,11 +572,14 @@ void perf_close(void)
|
||||
}
|
||||
|
||||
|
||||
static int enable_array(int *arr, int size)
|
||||
static int enable_array(int *arr, int user, unsigned int *supported_counters)
|
||||
{
|
||||
int i, ec, rc = 0;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
if ((user && is_user_space(i) != KERNEL_AND_USER_COUNTER) ||
|
||||
supported_counters[i] != 1 || is_user_space(i) == SUPPRESS_COUNTER)
|
||||
continue;
|
||||
ec = ioctl(arr[i], PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||
@@ -568,14 +591,14 @@ static int enable_array(int *arr, int size)
|
||||
}
|
||||
|
||||
|
||||
int perf_enable_ctr(enum ctr_e ctr)
|
||||
int perf_enable_ctr(enum ctr_e ctr, unsigned int *supported_counters)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
rc = perf_enable_ctr(ctr);
|
||||
rc = perf_enable_ctr(ctr, supported_counters);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
@@ -593,7 +616,7 @@ int perf_enable_ctr(enum ctr_e ctr)
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_USER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = enable_array(pcpu->pai_user, NUM_PAI_USER);
|
||||
ec = enable_array(pcpu->pai_user, 1, supported_counters);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
@@ -602,7 +625,7 @@ int perf_enable_ctr(enum ctr_e ctr)
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_KERNEL) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = enable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||
ec = enable_array(pcpu->pai_kernel, 0, supported_counters);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
@@ -617,11 +640,14 @@ int perf_enable_ctr(enum ctr_e ctr)
|
||||
}
|
||||
|
||||
|
||||
static int disable_array(int *arr, int size)
|
||||
static int disable_array(int *arr, int user, unsigned int *supported_counters)
|
||||
{
|
||||
int i, ec, rc = 0;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
if ((user && is_user_space(i) != KERNEL_AND_USER_COUNTER) ||
|
||||
supported_counters[i] != 1 || is_user_space(i) == SUPPRESS_COUNTER)
|
||||
continue;
|
||||
ec = ioctl(arr[i], PERF_EVENT_IOC_DISABLE, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||
@@ -633,14 +659,14 @@ static int disable_array(int *arr, int size)
|
||||
}
|
||||
|
||||
|
||||
int perf_disable_ctr(enum ctr_e ctr)
|
||||
int perf_disable_ctr(enum ctr_e ctr, unsigned int *supported_counters)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
rc = perf_disable_ctr(ctr);
|
||||
rc = perf_disable_ctr(ctr, supported_counters);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
@@ -660,7 +686,7 @@ int perf_disable_ctr(enum ctr_e ctr)
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_USER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = disable_array(pcpu->pai_user, NUM_PAI_USER);
|
||||
ec = disable_array(pcpu->pai_user, 1, supported_counters);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
@@ -671,7 +697,7 @@ int perf_disable_ctr(enum ctr_e ctr)
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_KERNEL) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = disable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||
ec = disable_array(pcpu->pai_kernel, 0, supported_counters);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
@@ -688,11 +714,14 @@ int perf_disable_ctr(enum ctr_e ctr)
|
||||
}
|
||||
|
||||
|
||||
static int reset_array(int *arr, int size)
|
||||
static int reset_array(int *arr, int user, unsigned int *supported_counters)
|
||||
{
|
||||
int ec, rc = 0, i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
for (i = 0; i < MAX_NUM_PAI; ++i) {
|
||||
if ((user && is_user_space(i) != KERNEL_AND_USER_COUNTER) ||
|
||||
supported_counters[i] != 1 || is_user_space(i) == SUPPRESS_COUNTER)
|
||||
continue;
|
||||
ec = ioctl(arr[i], PERF_EVENT_IOC_RESET, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||
@@ -704,14 +733,15 @@ static int reset_array(int *arr, int size)
|
||||
}
|
||||
|
||||
|
||||
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
|
||||
*supported_counters)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
rc = perf_reset_ctr(ctr, value);
|
||||
rc = perf_reset_ctr(ctr, value, supported_counters);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
@@ -727,14 +757,14 @@ int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_USER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = reset_array(pcpu->pai_user, NUM_PAI_USER);
|
||||
ec = reset_array(pcpu->pai_user, 1, supported_counters);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_KERNEL) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = reset_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||
ec = reset_array(pcpu->pai_kernel, 0, supported_counters);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
@@ -743,12 +773,13 @@ int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
rc = -1;
|
||||
}
|
||||
if (rc == 0)
|
||||
rc = perf_read_ctr(ctr, value);
|
||||
rc = perf_read_ctr(ctr, value, supported_counters);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value, unsigned int
|
||||
*supported_counters)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
@@ -761,11 +792,26 @@ int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
return 0;
|
||||
}
|
||||
if (ctr == PAI_USER) {
|
||||
*value = NUM_PAI_USER;
|
||||
int c = 0;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_PAI; i++) {
|
||||
if (is_user_space(i) == KERNEL_AND_USER_COUNTER &&
|
||||
supported_counters[i] == 1)
|
||||
c++;
|
||||
}
|
||||
|
||||
*value = c;
|
||||
return 0;
|
||||
}
|
||||
if (ctr == PAI_KERNEL) {
|
||||
*value = NUM_PAI_KERNEL;
|
||||
int c = 0;
|
||||
|
||||
for (int i = 0; i < MAX_NUM_PAI; i++) {
|
||||
if (supported_counters[i] == 1)
|
||||
c++;
|
||||
}
|
||||
|
||||
*value = c;
|
||||
return 0;
|
||||
}
|
||||
if (ctr >= ALL_COUNTER)
|
||||
@@ -802,14 +848,15 @@ int perf_ctr_state(enum ctr_e ctr) {
|
||||
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
unsigned int maxctr;
|
||||
int *arr, ec, rc = 0;
|
||||
uint64_t val;
|
||||
|
||||
*value = 0;
|
||||
maxctr = user ? NUM_PAI_USER : NUM_PAI_KERNEL;
|
||||
if (ctrnum >= maxctr)
|
||||
|
||||
if (is_user_space(ctrnum) == SUPPRESS_COUNTER ||
|
||||
(user && is_user_space(ctrnum) == KERNEL_ONLY_COUNTER))
|
||||
return -1;
|
||||
|
||||
foreachcpu(pcpu) {
|
||||
arr = user ? pcpu->pai_user : pcpu->pai_kernel;
|
||||
ec = read(arr[ctrnum], &val, sizeof(val));
|
||||
|
||||
@@ -4,9 +4,11 @@ all: cpuplugd
|
||||
|
||||
LDLIBS += -lm
|
||||
|
||||
libs = $(rootdir)/libutil/libutil.a
|
||||
|
||||
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
|
||||
|
||||
cpuplugd: $(OBJECTS)
|
||||
cpuplugd: $(OBJECTS) $(libs)
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
|
||||
clean:
|
||||
|
||||
@@ -204,6 +204,45 @@ void parse_configfile(char *file)
|
||||
fclose(filp);
|
||||
}
|
||||
|
||||
void apply_cpu_config(void)
|
||||
{
|
||||
/*
|
||||
* Check that the initial number of cpus is not below the
|
||||
* minimum
|
||||
*/
|
||||
if (num_cpu_start < cfg.cpu_min &&
|
||||
get_numcpus() >= cfg.cpu_min) {
|
||||
cpuplugd_debug("The number of online cpus is below ");
|
||||
cpuplugd_debug("the minimum and will be increased.\n");
|
||||
while (get_num_online_cpus() < cfg.cpu_min) {
|
||||
if (hotplug_one_cpu())
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (get_num_online_cpus() > cfg.cpu_max) {
|
||||
cpuplugd_debug("The number of online cpus is above the maximum");
|
||||
cpuplugd_debug(" and will be decreased.\n");
|
||||
while (get_num_online_cpus() > cfg.cpu_max) {
|
||||
if (hotunplug_one_cpu())
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cfg.cpu_min > get_numcpus()) {
|
||||
/*
|
||||
* This check only works if nobody used the
|
||||
* additional_cpus in the boot parameter section
|
||||
*/
|
||||
cpuplugd_debug("The minimum amount of cpus is above the ");
|
||||
cpuplugd_debug("number of available cpus.\n");
|
||||
cpuplugd_exit("Detected %d available cpus\n", get_numcpus());
|
||||
}
|
||||
if (get_num_online_cpus() < cfg.cpu_min) {
|
||||
cpuplugd_debug("Failed to set the number of online cpus to ");
|
||||
cpuplugd_debug("the minimum. ");
|
||||
cpuplugd_exit("Aborting.\n");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the required settings are found in the configuration file.
|
||||
* "Autodetect" if cpu and/or memory hotplug configuration entries
|
||||
@@ -211,7 +250,6 @@ void parse_configfile(char *file)
|
||||
*/
|
||||
void check_config()
|
||||
{
|
||||
int cpuid;
|
||||
int lpar_status;
|
||||
|
||||
lpar_status = check_lpar();
|
||||
@@ -262,60 +300,23 @@ void check_config()
|
||||
/*
|
||||
* Save the number of online cpus and the cmm_pagesize at startup,
|
||||
* so that we can enable exactly the same amount when the daemon ends
|
||||
*
|
||||
* Don't adjust cpus if system is on vertical polarization
|
||||
*/
|
||||
if (cpu) {
|
||||
num_cpu_start = get_num_online_cpus();
|
||||
cpuplugd_debug("Daemon started with %d active cpus.\n",
|
||||
num_cpu_start);
|
||||
/*
|
||||
* Check that the initial number of cpus is not below the
|
||||
* minimum
|
||||
*/
|
||||
if (num_cpu_start < cfg.cpu_min &&
|
||||
get_numcpus() >= cfg.cpu_min) {
|
||||
cpuplugd_debug("The number of online cpus is below "
|
||||
"the minimum and will be increased.\n");
|
||||
cpuid = 0;
|
||||
while (get_num_online_cpus() < cfg.cpu_min &&
|
||||
cpuid < get_numcpus()) {
|
||||
if (is_online(cpuid) == 1) {
|
||||
cpuid++;
|
||||
continue;
|
||||
}
|
||||
cpuplugd_debug("cpu with id %d is currently offline "
|
||||
"and will be enabled\n", cpuid);
|
||||
hotplug(cpuid);
|
||||
cpuid++;
|
||||
}
|
||||
}
|
||||
if (get_num_online_cpus() > cfg.cpu_max) {
|
||||
cpuplugd_debug("The number of online cpus is above the maximum"
|
||||
" and will be decreased.\n");
|
||||
cpuid = 0;
|
||||
while (get_num_online_cpus() > cfg.cpu_max &&
|
||||
cpuid < get_numcpus()) {
|
||||
if (is_online(cpuid) != 1) {
|
||||
cpuid++;
|
||||
continue;
|
||||
}
|
||||
cpuplugd_debug("cpu with id %d is currently online "
|
||||
"and will be disabled\n", cpuid);
|
||||
hotunplug(cpuid);
|
||||
cpuid++;
|
||||
}
|
||||
}
|
||||
if (cfg.cpu_min > get_numcpus())
|
||||
/*
|
||||
* This check only works if nobody used the
|
||||
* additional_cpus in the boot parameter section
|
||||
*/
|
||||
cpuplugd_exit("The minimum amount of cpus is above "
|
||||
"the number of available cpus.\n"
|
||||
"Detected %d available cpus\n",
|
||||
get_numcpus());
|
||||
if (get_num_online_cpus() < cfg.cpu_min)
|
||||
cpuplugd_exit("Failed to set the number of online "
|
||||
"cpus to the minimum. Aborting.\n");
|
||||
saved_polarization = get_polarization();
|
||||
num_cpu_start = get_num_online_cpus();
|
||||
cpuplugd_debug("Daemon started with %d active cpus.\n",
|
||||
num_cpu_start);
|
||||
if (saved_polarization < 0) {
|
||||
cpuplugd_debug("Daemon couldn't determine system polarization\n");
|
||||
cpuplugd_debug("Starting without evaluating cpu rules\n");
|
||||
} else if (saved_polarization == PLR_VERTICAL) {
|
||||
cpuplugd_debug("Daemon started with vertical polarization.\n");
|
||||
cpuplugd_debug("Cpu adjustments won't be made until system ");
|
||||
cpuplugd_debug("is in horizontal polarization\n");
|
||||
} else if (saved_polarization == PLR_HORIZONTAL &&
|
||||
cpu == 1) {
|
||||
apply_cpu_config();
|
||||
}
|
||||
if (memory == 1) {
|
||||
/*
|
||||
|
||||
362
cpuplugd/cpu.c
362
cpuplugd/cpu.c
@@ -12,217 +12,241 @@
|
||||
#include <limits.h>
|
||||
#include "cpuplugd.h"
|
||||
|
||||
#define NUM_BASE (10)
|
||||
#define CPU_OFFLINE (0)
|
||||
#define CPU_ONLINE (1)
|
||||
#define CPU_DECONFIGURED (0)
|
||||
#define CPU_CONFIGURED (1)
|
||||
#define CPU_LIST_LEN (4096)
|
||||
|
||||
/*
|
||||
* Return overall number of available cpus. This does not necessarily
|
||||
* mean that those are currently online
|
||||
*/
|
||||
int get_numcpus()
|
||||
static int get_sysfs_attribute_cpu_count(char *path)
|
||||
{
|
||||
int i;
|
||||
char path[PATH_MAX];
|
||||
int number = 0;
|
||||
char cpu_list[CPU_LIST_LEN];
|
||||
int number, start, end;
|
||||
char *sub_list;
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
/* check whether file exists and is readable */
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d", i);
|
||||
if (access(path, R_OK) == 0)
|
||||
if (util_file_read_line(cpu_list, sizeof(cpu_list), path))
|
||||
cpuplugd_exit("Cannot open %s file: %s\n", path, strerror(errno));
|
||||
number = 0;
|
||||
sub_list = strtok(cpu_list, ",");
|
||||
while (sub_list) {
|
||||
if (strchr(sub_list, '-')) {
|
||||
if (sscanf(sub_list, "%d-%d", &start, &end) != 2)
|
||||
cpuplugd_exit("Malformed content of %s: %s\n", path, sub_list);
|
||||
number += (end - start) + 1;
|
||||
} else {
|
||||
number++;
|
||||
else
|
||||
break;
|
||||
}
|
||||
sub_list = strtok(NULL, ",");
|
||||
}
|
||||
return number;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return number of online cpus
|
||||
* get_numcpus() - return number of present cpus by sysfs'
|
||||
* cpu/present attribute.
|
||||
* This number represents the total number of usable cpus,
|
||||
* this includes offline or deconfigured cpus as well.
|
||||
*/
|
||||
int get_num_online_cpus()
|
||||
int get_numcpus(void)
|
||||
{
|
||||
FILE *filp;
|
||||
int i;
|
||||
char path[PATH_MAX];
|
||||
int status = 0;
|
||||
int value_of_onlinefile, rc;
|
||||
int number;
|
||||
char *path;
|
||||
|
||||
for (i = 0; i < get_numcpus(); i++) {
|
||||
/* check wether file exists and is readable */
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i);
|
||||
if (access(path, R_OK) != 0) {
|
||||
status++;
|
||||
continue;
|
||||
}
|
||||
filp = fopen(path, "r");
|
||||
if (!filp)
|
||||
cpuplugd_exit("Cannot open cpu online file: "
|
||||
"%s\n", strerror(errno));
|
||||
else {
|
||||
rc = fscanf(filp, "%d", &value_of_onlinefile);
|
||||
if (rc != 1)
|
||||
cpuplugd_exit("Cannot read cpu online file: "
|
||||
"%s\n", strerror(errno));
|
||||
if (value_of_onlinefile == 1)
|
||||
status++;
|
||||
}
|
||||
fclose(filp);
|
||||
path = util_path_sysfs("devices/system/cpu/present");
|
||||
number = get_sysfs_attribute_cpu_count(path);
|
||||
free(path);
|
||||
if (number <= 0)
|
||||
cpuplugd_exit("number of present cpus (%d) <= 0\n", number);
|
||||
return number;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_num_online_cpus() - return number of online cpus
|
||||
* by parsing sysfs cpu/online attribute
|
||||
*/
|
||||
int get_num_online_cpus(void)
|
||||
{
|
||||
int number;
|
||||
char *path;
|
||||
|
||||
path = util_path_sysfs("devices/system/cpu/online");
|
||||
number = get_sysfs_attribute_cpu_count(path);
|
||||
free(path);
|
||||
if (number <= 0)
|
||||
cpuplugd_exit("number of online cpus (%d) <= 0\n", number);
|
||||
return number;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_polarization() - return system polarization
|
||||
*/
|
||||
int get_polarization(void)
|
||||
{
|
||||
int polarization;
|
||||
char *path;
|
||||
|
||||
path = util_path_sysfs("devices/system/cpu/dispatching");
|
||||
if (util_file_read_i(&polarization, NUM_BASE, path) < 0) {
|
||||
polarization = -1;
|
||||
cpuplugd_debug("failed to read system polarization\n");
|
||||
}
|
||||
free(path);
|
||||
return polarization;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_cpu_hotpluggable() - check if cpuhotplug operations are supported
|
||||
* for the given cpu.
|
||||
*/
|
||||
static int is_cpu_hotpluggable(int cpuid)
|
||||
{
|
||||
char *path;
|
||||
int rc;
|
||||
|
||||
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
|
||||
rc = util_path_exists(path);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* hotplug() - perform cpu hotplug on given cpuid
|
||||
*/
|
||||
static int hotplug(int cpuid)
|
||||
{
|
||||
char *path;
|
||||
int rc;
|
||||
|
||||
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
|
||||
rc = util_file_write_l(CPU_ONLINE, NUM_BASE, path);
|
||||
if (rc < 0)
|
||||
cpuplugd_debug("failed to enable cpu with id %d\n", cpuid);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* hotunplug() - perform cpu hotunplug on given cpuid
|
||||
*/
|
||||
static int hotunplug(int cpuid)
|
||||
{
|
||||
char *path;
|
||||
int rc;
|
||||
|
||||
path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid);
|
||||
rc = util_file_write_l(CPU_OFFLINE, NUM_BASE, path);
|
||||
if (rc < 0)
|
||||
cpuplugd_debug("failed to disable cpu with id %d\n", cpuid);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_cpu_attribute() - get a certain cpu's selected attribute
|
||||
*/
|
||||
static int get_cpu_attribute(int cpuid, char *attribute)
|
||||
{
|
||||
int status;
|
||||
char *path;
|
||||
|
||||
path = util_path_sysfs("devices/system/cpu/cpu%d/%s", cpuid, attribute);
|
||||
if (util_file_read_i(&status, NUM_BASE, path) < 0) {
|
||||
status = -1;
|
||||
cpuplugd_debug("failed to read %s status of cpu with id %d\n", attribute, cpuid);
|
||||
}
|
||||
free(path);
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable a certain cpu
|
||||
* hotplug_one_cpu() - perform hotplugging on the first available cpu
|
||||
*/
|
||||
int hotplug(int cpuid)
|
||||
int hotplug_one_cpu(void)
|
||||
{
|
||||
FILE *filp;
|
||||
char path[PATH_MAX];
|
||||
int status, rc;
|
||||
struct dirent **cpu_dir;
|
||||
int cpuid, count, i, rc;
|
||||
char *path;
|
||||
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
|
||||
if (access(path, W_OK) == 0) {
|
||||
filp = fopen(path, "w");
|
||||
if (!filp)
|
||||
cpuplugd_exit("Cannot open cpu online file: %s\n",
|
||||
strerror(errno));
|
||||
fprintf(filp, "1");
|
||||
fclose(filp);
|
||||
/*
|
||||
* check if the attempt to enable the cpus really worked
|
||||
*/
|
||||
filp = fopen(path, "r");
|
||||
rc = fscanf(filp, "%d", &status);
|
||||
if (rc != 1)
|
||||
cpuplugd_exit("Cannot open cpu online file: %s\n",
|
||||
strerror(errno));
|
||||
fclose(filp);
|
||||
if (status == 1) {
|
||||
cpuplugd_debug("cpu with id %d enabled\n", cpuid);
|
||||
return 1;
|
||||
} else {
|
||||
cpuplugd_debug("failed to enable cpu with id %d\n",
|
||||
cpuid);
|
||||
return -1;
|
||||
rc = -1;
|
||||
path = util_path_sysfs("devices/system/cpu/");
|
||||
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
|
||||
for (i = 0; (i < count) && (rc != 0); i++) {
|
||||
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
|
||||
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
|
||||
if (!is_cpu_hotpluggable(cpuid))
|
||||
continue;
|
||||
if (get_cpu_attribute(cpuid, "configure") == CPU_CONFIGURED &&
|
||||
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) {
|
||||
cpuplugd_debug("cpu%d will be enabled", cpuid);
|
||||
rc = hotplug(cpuid);
|
||||
}
|
||||
}
|
||||
cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid);
|
||||
return -1;
|
||||
util_scandir_free(cpu_dir, count);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable a certain cpu
|
||||
* hotunplug_one_cpu() - perform hotunplugging on the first available cpu
|
||||
*/
|
||||
int hotunplug(int cpuid)
|
||||
int hotunplug_one_cpu(void)
|
||||
{
|
||||
FILE *filp;
|
||||
int state, rc;
|
||||
int retval = -1;
|
||||
char path[PATH_MAX];
|
||||
struct dirent **cpu_dir;
|
||||
int cpuid, count, i, rc;
|
||||
char *path;
|
||||
|
||||
state = -1;
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
|
||||
if (access(path, W_OK) == 0) {
|
||||
filp = fopen(path, "w");
|
||||
fprintf(filp, "0");
|
||||
fclose(filp);
|
||||
/*
|
||||
* Check if the attempt to enable the cpus really worked
|
||||
*/
|
||||
filp = fopen(path, "r");
|
||||
rc = fscanf(filp, "%d", &state);
|
||||
if (rc != 1)
|
||||
cpuplugd_error("Failed to disable cpu with id %d\n",
|
||||
cpuid);
|
||||
fclose(filp);
|
||||
if (state == 0)
|
||||
return 1;
|
||||
}
|
||||
cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a certain cpu is currently online
|
||||
*/
|
||||
int is_online(int cpuid)
|
||||
{
|
||||
FILE *filp;
|
||||
int state;
|
||||
int retval, rc;
|
||||
char path[PATH_MAX];
|
||||
|
||||
retval = -1;
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid);
|
||||
if (access(path, R_OK) == 0) {
|
||||
filp = fopen(path, "r");
|
||||
rc = fscanf(filp, "%d", &state);
|
||||
if (rc == 1) {
|
||||
if (state == 1)
|
||||
retval = 1;
|
||||
if (state == 0)
|
||||
retval = 0;
|
||||
rc = -1;
|
||||
path = util_path_sysfs("devices/system/cpu/");
|
||||
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
|
||||
for (i = 0; (i < count) && (rc != 0); i++) {
|
||||
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
|
||||
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
|
||||
if (!is_cpu_hotpluggable(cpuid))
|
||||
continue;
|
||||
if (get_cpu_attribute(cpuid, "online") == CPU_ONLINE) {
|
||||
cpuplugd_debug("cpu%d will be disabled\n", cpuid);
|
||||
rc = hotunplug(cpuid);
|
||||
}
|
||||
fclose(filp);
|
||||
} else {
|
||||
retval = 1;
|
||||
}
|
||||
return retval;
|
||||
util_scandir_free(cpu_dir, count);
|
||||
free(path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup method. If the daemon is stopped, we (re)activate all cpus
|
||||
*/
|
||||
void reactivate_cpus()
|
||||
void reactivate_cpus(void)
|
||||
{
|
||||
/*
|
||||
* Only enable the number of cpus which where
|
||||
* available at daemon startup time
|
||||
*/
|
||||
int cpuid, nc;
|
||||
struct dirent **cpu_dir;
|
||||
int cpuid, nc, count, i;
|
||||
char *path;
|
||||
|
||||
cpuid = 0;
|
||||
/* suppress verbose messages on exit */
|
||||
debug = 0;
|
||||
/*
|
||||
* We check for num_cpu_start != 0 because we might want to
|
||||
* clean up, before we queried for the number on cpus at
|
||||
* startup
|
||||
*/
|
||||
/*
|
||||
* Only enable the number of cpus which where available at
|
||||
* daemon startup time by checking num_cpu_start.
|
||||
* We check for num_cpu_start != 0 because we might want to
|
||||
* clean up, before we queried for the number on cpus at
|
||||
* startup
|
||||
*/
|
||||
if (num_cpu_start == 0)
|
||||
return;
|
||||
while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) {
|
||||
nc = 0;
|
||||
path = util_path_sysfs("devices/system/cpu/");
|
||||
count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*");
|
||||
for (i = 0; (i < count) && (nc != num_cpu_start); i++) {
|
||||
nc = get_num_online_cpus();
|
||||
if (nc == num_cpu_start)
|
||||
return;
|
||||
if (nc > num_cpu_start && is_online(cpuid) == 1)
|
||||
if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1)
|
||||
cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name);
|
||||
if (nc > num_cpu_start &&
|
||||
get_cpu_attribute(cpuid, "online") == CPU_ONLINE)
|
||||
hotunplug(cpuid);
|
||||
if (nc < num_cpu_start && is_online(cpuid) == 0)
|
||||
if (nc < num_cpu_start &&
|
||||
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE)
|
||||
hotplug(cpuid);
|
||||
cpuid++;
|
||||
}
|
||||
util_scandir_free(cpu_dir, count);
|
||||
free(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* In kernels > 2.6.24 cpus can be deconfigured. The following functions is used
|
||||
* to check if a certain cpus is in a deconfigured state.
|
||||
*/
|
||||
int cpu_is_configured(int cpuid)
|
||||
{
|
||||
FILE *filp;
|
||||
int retval, state, rc;
|
||||
char path[4096];
|
||||
|
||||
retval = -1;
|
||||
sprintf(path, "/sys/devices/system/cpu/cpu%d/configure", cpuid);
|
||||
if (access(path, R_OK) == 0) {
|
||||
filp = fopen(path, "r");
|
||||
rc = fscanf(filp, "%d", &state);
|
||||
if (rc == 1) {
|
||||
if (state == 1)
|
||||
retval = 1;
|
||||
if (state == 0)
|
||||
retval = 0;
|
||||
}
|
||||
fclose(filp);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_path.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util_scandir.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define NAME "cpuplugd"
|
||||
@@ -35,6 +38,8 @@
|
||||
#define MAX_VARNAME 128
|
||||
#define MAX_LINESIZE 2048
|
||||
#define CPUSTATS 10
|
||||
#define PLR_HORIZONTAL 0
|
||||
#define PLR_VERTICAL 1
|
||||
|
||||
/*
|
||||
* Precedence of C operators
|
||||
@@ -173,9 +178,11 @@ extern unsigned int history_max;
|
||||
extern unsigned int history_current;
|
||||
extern struct symbol_names sym_names[];
|
||||
extern unsigned int sym_names_count;
|
||||
extern int saved_polarization;
|
||||
|
||||
int get_numcpus();
|
||||
int get_num_online_cpus();
|
||||
int get_polarization(void);
|
||||
void get_loadavg_runnable(double *loadavg, double *runnable);
|
||||
void clean_up();
|
||||
void reactivate_cpus();
|
||||
@@ -190,9 +197,8 @@ void proc_cpu_read(char *procinfo);
|
||||
unsigned long proc_read_size(char *path);
|
||||
char *get_var_rvalue(char *var_name);
|
||||
void cleanup_cmm(void);
|
||||
int hotplug(int cpuid);
|
||||
int hotunplug(int cpuid);
|
||||
int is_online(int cpuid);
|
||||
int hotplug_one_cpu(void);
|
||||
int hotunplug_one_cpu(void);
|
||||
long get_cmmpages_size();
|
||||
void parse_options(int argc, char **argv);
|
||||
void check_if_started_twice();
|
||||
@@ -202,9 +208,9 @@ void reload_daemon(void);
|
||||
int daemonize(void);
|
||||
int check_cmmfiles(void);
|
||||
void check_config();
|
||||
void apply_cpu_config(void);
|
||||
void set_cmm_pages(long size);
|
||||
int check_lpar();
|
||||
int cpu_is_configured(int cpuid);
|
||||
void setup_history(void);
|
||||
|
||||
|
||||
|
||||
@@ -149,6 +149,8 @@ void clean_up()
|
||||
cpuplugd_info("terminated\n");
|
||||
remove(pid_file);
|
||||
remove(LOCKFILE);
|
||||
/* suppress verbose messages on exit */
|
||||
debug = 0;
|
||||
reactivate_cpus();
|
||||
if (memory)
|
||||
cleanup_cmm();
|
||||
@@ -163,6 +165,8 @@ void kill_daemon(int UNUSED(a))
|
||||
cpuplugd_info("shutting down\n");
|
||||
remove(pid_file);
|
||||
remove(LOCKFILE);
|
||||
/* suppress verbose messages on exit */
|
||||
debug = 0;
|
||||
reactivate_cpus();
|
||||
if (memory)
|
||||
cleanup_cmm();
|
||||
|
||||
@@ -54,12 +54,12 @@ struct config cfg = {
|
||||
.hotunplug = NULL,
|
||||
};
|
||||
|
||||
int num_cpu_start, memory, cpu, reload_pending;
|
||||
long cmm_pagesize_start;
|
||||
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
|
||||
char *meminfo, *vmstat, *cpustat, *varinfo;
|
||||
double *timestamps;
|
||||
unsigned int history_max, history_current, history_prev, sym_names_count;
|
||||
unsigned long meminfo_size, vmstat_size, cpustat_size, varinfo_size;
|
||||
int num_cpu_start, memory, cpu, reload_pending, saved_polarization;
|
||||
char *meminfo, *vmstat, *cpustat, *varinfo;
|
||||
long cmm_pagesize_start;
|
||||
double *timestamps;
|
||||
|
||||
static struct symbols symbols;
|
||||
static jmp_buf jmpenv;
|
||||
@@ -77,8 +77,29 @@ static void eval_cpu_rules(void)
|
||||
{
|
||||
double diffs[CPUSTATS], diffs_total, percent_factor;
|
||||
char *procinfo_current, *procinfo_prev;
|
||||
int cpu, nr_cpus, on_off;
|
||||
int nr_cpus, on_off, polarization;
|
||||
|
||||
polarization = get_polarization();
|
||||
if (polarization < 0) {
|
||||
cpuplugd_debug("couldn't determine system polarization\n");
|
||||
cpuplugd_debug("skipping cpu rule evaluation\n");
|
||||
return;
|
||||
}
|
||||
if (saved_polarization != polarization) {
|
||||
saved_polarization = polarization;
|
||||
if (polarization == PLR_VERTICAL) {
|
||||
/* revert cpu hotplug adjustments after switching from horizontal */
|
||||
reactivate_cpus();
|
||||
} else if (polarization == PLR_HORIZONTAL) {
|
||||
/* reapply cpu config after switching from vertical */
|
||||
apply_cpu_config();
|
||||
}
|
||||
}
|
||||
if (polarization == PLR_VERTICAL) {
|
||||
cpuplugd_debug("system is running vertical polarization\n");
|
||||
cpuplugd_debug("cpuplugd won't make cpu adjustments\n");
|
||||
return;
|
||||
}
|
||||
nr_cpus = get_numcpus();
|
||||
procinfo_current = cpustat + history_current * cpustat_size;
|
||||
procinfo_prev = cpustat + history_prev * cpustat_size;
|
||||
@@ -157,7 +178,6 @@ static void eval_cpu_rules(void)
|
||||
printf("\n");
|
||||
printf("---------------------------------------------\n");
|
||||
}
|
||||
|
||||
on_off = 0;
|
||||
/* Evaluate the hotplug rule */
|
||||
if (eval_term(cfg.hotplug, &symbols))
|
||||
@@ -172,40 +192,16 @@ static void eval_cpu_rules(void)
|
||||
cpuplugd_debug("maximum cpu limit is reached\n");
|
||||
return;
|
||||
}
|
||||
/* try to find a offline cpu */
|
||||
for (cpu = 0; cpu < nr_cpus; cpu++)
|
||||
if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0)
|
||||
break;
|
||||
if (cpu < nr_cpus) {
|
||||
cpuplugd_debug("cpu with id %d is currently offline "
|
||||
"and will be enabled\n", cpu);
|
||||
if (hotplug(cpu) == -1)
|
||||
cpuplugd_debug("unable to find a cpu which "
|
||||
"can be enabled\n");
|
||||
} else {
|
||||
/*
|
||||
* In case we tried to enable a cpu but this failed.
|
||||
* This is the case if a cpu is deconfigured
|
||||
*/
|
||||
cpuplugd_debug("unable to find a cpu which can "
|
||||
"be enabled\n");
|
||||
}
|
||||
if (hotplug_one_cpu())
|
||||
cpuplugd_debug("unable to find a cpu which can be enabled\n");
|
||||
} else if (on_off < 0) {
|
||||
/* check cpu nr limit */
|
||||
if (symbols.onumcpus <= cfg.cpu_min) {
|
||||
cpuplugd_debug("minimum cpu limit is reached\n");
|
||||
return;
|
||||
}
|
||||
/* try to find a online cpu */
|
||||
for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) {
|
||||
if (is_online(cpu) != 0)
|
||||
break;
|
||||
}
|
||||
if (cpu > 0) {
|
||||
cpuplugd_debug("cpu with id %d is currently online "
|
||||
"and will be disabled\n", cpu);
|
||||
hotunplug(cpu);
|
||||
}
|
||||
if (hotunplug_one_cpu())
|
||||
cpuplugd_debug("unable to find a cpu which can be disabled\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ of active CPUs are reset to the values they had before the cpuplugd was started.
|
||||
This program can be used to control the number of CPUs for Linux on z/VM
|
||||
and for Linux in LPAR mode. The memory hotplug feature (CMM page pool) applies
|
||||
to Linux on z/VM only.
|
||||
|
||||
The cpuplugd daemon stops any CPU hot-plug operations when the system switches
|
||||
to vertical polarization, thus avoiding possible performance penalties.
|
||||
.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
dasdfmt \- formatting of DASD (ECKD) disk drives.
|
||||
|
||||
.SH SYNOPSIS
|
||||
\fBdasdfmt\fR [-h] [-t] [-v] [-y] [-p] [-P] [-m \fIstep\fR]
|
||||
\fBdasdfmt\fR [\-h] [\-t] [\-v] [\-y] [\-p] [\-P] [\-m \fIstep\fR]
|
||||
.br
|
||||
[-r \fIcylinder\fR] [-b \fIblksize\fR] [-l \fIvolser\fR] [-d \fIlayout\fR]
|
||||
[\-r \fIcylinder\fR] [\-b \fIblksize\fR] [\-l \fIvolser\fR] [\-d \fIlayout\fR]
|
||||
.br
|
||||
[-L] [-V] [-F] [-k] [-C] [-M \fImode\fR] \fIdevice\fR
|
||||
[\-L] [\-V] [\-F] [\-k] [\-C] [\-M \fImode\fR] \fIdevice\fR
|
||||
|
||||
.SH DESCRIPTION
|
||||
\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
|
||||
@@ -26,26 +26,26 @@ Any device node created by udev for kernel 2.6 can be used
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-h\fR or \fB--help\fR
|
||||
\fB\-h\fR or \fB\-\-help\fR
|
||||
Print usage and exit.
|
||||
|
||||
.TP
|
||||
\fB-t\fR or \fB--test\fR
|
||||
\fB\-t\fR or \fB\-\-test\fR
|
||||
Disables any modification of the disk drive.
|
||||
.br
|
||||
\fBdasdfmt\fR just prints
|
||||
out, what it \fBwould\fR do.
|
||||
|
||||
.TP
|
||||
\fB-v\fR
|
||||
\fB\-v\fR
|
||||
Increases verbosity.
|
||||
|
||||
.TP
|
||||
\fB-y\fR
|
||||
\fB\-y\fR
|
||||
Start formatting without further user-confirmation.
|
||||
|
||||
.TP
|
||||
\fB--norecordzero\fR
|
||||
\fB\-\-norecordzero\fR
|
||||
Remove permission for subsystem to format write record zero.
|
||||
.br
|
||||
This is an expert option: Per default in recent dasd drivers, subsystems are
|
||||
@@ -54,32 +54,32 @@ to remove this permission.
|
||||
.br
|
||||
|
||||
.TP
|
||||
\fB-L\fR or \fB--no_label\fR
|
||||
\fB\-L\fR or \fB\-\-no_label\fR
|
||||
Omit the writing of a disk label after formatting.
|
||||
.br
|
||||
This makes only sense for the 'ldl' disk layout.
|
||||
.br
|
||||
The '-L' option has to be specified after the '-d ldl' option.
|
||||
The '\-L' option has to be specified after the '\-d ldl' option.
|
||||
.br
|
||||
|
||||
e.g. dasdfmt -d ldl -L /dev/...
|
||||
e.g. dasdfmt \-d ldl \-L /dev/...
|
||||
|
||||
|
||||
.TP
|
||||
\fB-V\fR or \fB--version\fR
|
||||
\fB\-V\fR or \fB\-\-version\fR
|
||||
Print version number and exit.
|
||||
|
||||
.TP
|
||||
\fB-F\fR or \fB--force\fR
|
||||
\fB\-F\fR or \fB\-\-force\fR
|
||||
Formats the device without performing sanity checking.
|
||||
|
||||
.TP
|
||||
\fB-C\fR or \fB--check_host_count\fR
|
||||
\fB\-C\fR or \fB\-\-check_host_count\fR
|
||||
Force dasdfmt to check the host access open count to ensure the device
|
||||
is not online on another operating system instance
|
||||
|
||||
.TP
|
||||
\fB-d\fR \fIlayout\fR or \fB--disk_layout\fR=\fIlayout\fR
|
||||
\fB\-d\fR \fIlayout\fR or \fB\-\-disk_layout\fR=\fIlayout\fR
|
||||
Formats the device with compatible disk layout or linux disk layout.
|
||||
\fIlayout\fR is either \fIcdl\fR for the compatible disk layout
|
||||
(default) or \fIldl\fR for the linux disk layout.
|
||||
@@ -95,39 +95,39 @@ Do not use this option if you are using a 3270 console,
|
||||
running in background or redirecting the output to a file.
|
||||
|
||||
.TP
|
||||
\fB-P\fR or \fB--percentage\fR
|
||||
\fB\-P\fR or \fB\-\-percentage\fR
|
||||
Print one line for each formatted cylinder showing the number of the
|
||||
cylinder and percentage of formatting process.
|
||||
Intended to be used by higher level interfaces.
|
||||
|
||||
.TP
|
||||
\fB-m\fR \fIstep\fR or \fB--hashmarks\fR=\fIstep\fR
|
||||
\fB\-m\fR \fIstep\fR or \fB\-\-hashmarks\fR=\fIstep\fR
|
||||
Print a hashmark every \fIstep\fR cylinders. The value \fIstep\fR has to be within range [1,1000], otherwise it will be set to the default, which is 10.
|
||||
.br
|
||||
You can use this option to see the progress of formatting in case you
|
||||
are not able to use the progress bar option -p, e.g. with a 3270
|
||||
are not able to use the progress bar option \-p, e.g. with a 3270
|
||||
terminal.
|
||||
.br
|
||||
The value will be at least as big as the -r or --requestsize value.
|
||||
The value will be at least as big as the \-r or \-\-requestsize value.
|
||||
.br
|
||||
|
||||
.TP
|
||||
\fB-M\fR \fImode\fR or \fB--mode\fR=\fImode\fR
|
||||
\fB\-M\fR \fImode\fR or \fB\-\-mode\fR=\fImode\fR
|
||||
Specify the \fImode\fR to be used to format the device. Valid modes are:
|
||||
.RS
|
||||
.IP full
|
||||
Format the entire disk with the specified blocksize. (default)
|
||||
.IP quick
|
||||
Format the first two tracks and write label and partition information. Use this
|
||||
option only if you are sure that the target DASD already contains a regular
|
||||
format with the specified blocksize. A blocksize can optionally be specified
|
||||
using \fB-b\fR (\fB--blocksize\fR).
|
||||
Format the first two tracks and write label and partition information.
|
||||
.br
|
||||
For thin-provisioned DASD ESE volumes, quick is the default mode. A full space
|
||||
release then precedes the formatting step. If this space release fails, dasdfmt
|
||||
falls back to a full-format mode. Formatting stops if the space release fails
|
||||
and quick mode was specified explicitly using \fB-M\fR. Specify the
|
||||
\fB--no-discard\fR option to omit the space release.
|
||||
Use this option for DASD ESE volumes to take the benefits of thin provisioning.
|
||||
In this case, a full space release precedes the formatting step. If this space
|
||||
release fails, then the formatting also fails. Specify the \fB\-\-no\-discard\fR
|
||||
option to omit the space release.
|
||||
.br
|
||||
For non-ESE volumes use this option only if you are sure that the target DASD
|
||||
already contains a regular format with the specified blocksize. A blocksize can
|
||||
optionally be specified using \fB\-b\fR (\fB\-\-blocksize\fR).
|
||||
|
||||
.IP expand
|
||||
Format all unformatted tracks at the end of the target DASD. This mode assumes
|
||||
@@ -135,20 +135,20 @@ that tracks at the beginning of the DASD volume have already been correctly
|
||||
formatted, while a consecutive set of tracks at the end are unformatted. You can
|
||||
use this mode to make added space available for Linux use after dynamically
|
||||
increasing the size of a DASD volume. A blocksize can optionally be specified
|
||||
using \fB-b\fR (\fB--blocksize\fR).
|
||||
using \fB\-b\fR (\fB\-\-blocksize\fR).
|
||||
.RE
|
||||
|
||||
.TP
|
||||
\fB--check\fR
|
||||
\fB\-\-check\fR
|
||||
Perform a complete format check on a DASD volume. A blocksize can be specified
|
||||
with \fB-b\fR (\fB--blocksize\fR).
|
||||
with \fB\-b\fR (\fB\-\-blocksize\fR).
|
||||
|
||||
.TP
|
||||
\fB--no-discard\fR
|
||||
\fB\-\-no\-discard\fR
|
||||
Omit a full space release when formatting a thin-provisioned DASD ESE volume.
|
||||
|
||||
.TP
|
||||
\fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR
|
||||
\fB\-r\fR \fIcylindercount\fR or \fB\-\-requestsize\fR=\fIcylindercount\fR
|
||||
Number of cylinders to be processed in one formatting step.
|
||||
The value must be an integer in the range 1 - 255.
|
||||
.br
|
||||
@@ -158,19 +158,19 @@ devices, counting the base device and all alias devices.
|
||||
.br
|
||||
|
||||
.TP
|
||||
\fB-b\fR \fIblksize\fR or \fB--blocksize\fR=\fIblksize\fR
|
||||
\fB\-b\fR \fIblksize\fR or \fB\-\-blocksize\fR=\fIblksize\fR
|
||||
Specify blocksize to be used. \fIblksize\fR must be a positive integer
|
||||
and always be a power of two. The recommended blocksize is 4096 bytes.
|
||||
|
||||
.TP
|
||||
\fB-l\fR \fIvolser\fR or \fB--label\fR=\fIvolser\fR
|
||||
\fB\-l\fR \fIvolser\fR or \fB\-\-label\fR=\fIvolser\fR
|
||||
Specify the volume serial number or volume identifier to be written
|
||||
to disk after formatting. If no label is specified, a sensible default
|
||||
is used. \fIvolser\fR is interpreted as ASCII string and is automatically
|
||||
converted to uppercase and then to EBCDIC.
|
||||
.br
|
||||
|
||||
e.g. -l LNX001 or --label=DASD01
|
||||
e.g. \-l LNX001 or \-\-label=DASD01
|
||||
.br
|
||||
|
||||
The \fIvolser\fR identifies by serial number the volume. A volume serial
|
||||
@@ -192,11 +192,11 @@ NOTE: Try to avoid using special characters in the volume serial. This may cause
|
||||
In case you really have to use special characters, make sure you are using quotes. In addition there is a special handling for the '$' sign. Please specify it using '\\$' if necessary.
|
||||
.br
|
||||
|
||||
e.g. -l 'a@b\\$c#' to get A@B$C#
|
||||
e.g. \-l 'a@b\\$c#' to get A@B$C#
|
||||
.br
|
||||
|
||||
.TP
|
||||
\fB-k\fR or \fB--keep_volser\fR
|
||||
\fB\-k\fR or \fB\-\-keep_volser\fR
|
||||
Keeps the Volume Serial Number when writing the Volume Label. This is useful if
|
||||
the volume already has a Serial Number that should not be overwritten.
|
||||
.br
|
||||
|
||||
@@ -1230,7 +1230,7 @@ static void dasdfmt_find_start(unsigned int cylinders, unsigned int heads,
|
||||
format_params->start_unit = first;
|
||||
}
|
||||
|
||||
static int dasdfmt_release_space(void)
|
||||
static void dasdfmt_release_space(void)
|
||||
{
|
||||
format_data_t r = {
|
||||
.start_unit = 0,
|
||||
@@ -1240,21 +1240,12 @@ static int dasdfmt_release_space(void)
|
||||
int err = 0;
|
||||
|
||||
if (!g.ese || g.no_discard)
|
||||
return 0;
|
||||
return;
|
||||
|
||||
printf("Releasing space for the entire device...\n");
|
||||
err = dasd_release_space(g.dev_node, &r);
|
||||
/*
|
||||
* Warn or Error on failing RAS depending on QUICK mode set explicitly or automatically
|
||||
*/
|
||||
if (err && !g.mode_specified) {
|
||||
warnx("Could not release space. Falling back to full format.");
|
||||
return 1;
|
||||
} else if (err && g.mode_specified) {
|
||||
if (err)
|
||||
error("Could not release space: %s", strerror(err));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dasdfmt_prepare_and_format(unsigned int cylinders, unsigned int heads,
|
||||
@@ -1454,12 +1445,8 @@ static void do_format_dasd(volume_label_t *vlabel, format_data_t *p,
|
||||
dasdfmt_prepare_and_format(cylinders, heads, p);
|
||||
break;
|
||||
case QUICK:
|
||||
if (dasdfmt_release_space()) {
|
||||
p->stop_unit = (cylinders * heads) - 1;
|
||||
dasdfmt_prepare_and_format(cylinders, heads, p);
|
||||
} else {
|
||||
dasdfmt_quick_format(cylinders, heads, p);
|
||||
}
|
||||
dasdfmt_release_space();
|
||||
dasdfmt_quick_format(cylinders, heads, p);
|
||||
break;
|
||||
case EXPAND:
|
||||
dasdfmt_expand_format(cylinders, heads, p);
|
||||
@@ -1491,7 +1478,7 @@ static void eval_format_mode(void)
|
||||
}
|
||||
|
||||
if (!g.mode_specified)
|
||||
mode = g.ese ? QUICK : FULL;
|
||||
mode = FULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -7,28 +7,28 @@
|
||||
.B "dasdinfo "
|
||||
\- tool to read unique id from s390 DASD device
|
||||
.SH SYNOPSIS
|
||||
.BI "dasdinfo [-a] [-l] [-u] [-x] [-e] {-i " <busid>
|
||||
.BI "| -b " <blockdev>
|
||||
.BI " | -d " <devnode>
|
||||
.BI "dasdinfo [\-a] [\-l] [\-u] [\-x] [\-e] {\-i " <busid>
|
||||
.BI "| \-b " <blockdev>
|
||||
.BI " | \-d " <devnode>
|
||||
.BI "}"
|
||||
.sp
|
||||
.BI "dasdinfo [-h] [-v]"
|
||||
.BI "dasdinfo [\-h] [\-v]"
|
||||
|
||||
.SH DESCRIPTION
|
||||
.B dasdinfo
|
||||
.B dasdinfo
|
||||
displays specific information about a specified DASD device.
|
||||
It is normally called from a udev rule, to provide udev with a unique id string and
|
||||
additional information (type, serial) for an S390 DASD drive. Udev can use this
|
||||
information to create symlinks in /dev/disk/by-id and /dev/disk/by-label
|
||||
information to create symlinks in /dev/disk/by\-id and /dev/disk/by\-label
|
||||
to the real device node.
|
||||
|
||||
.SH OPTIONS
|
||||
|
||||
.TP
|
||||
.BI "-a|--all"
|
||||
.BI "\-a|\-\-all"
|
||||
Same as -u -x -l
|
||||
.TP
|
||||
.BI "-x|--extended-uid"
|
||||
.BI "\-x|\-\-extended\-uid"
|
||||
Print DASD uid
|
||||
|
||||
This option prints the full uid of the DASD. When z/VM provides two
|
||||
@@ -42,13 +42,13 @@ For z/VM: VM support for the hypervisor injected Special Node Element
|
||||
Qualifier (SNEQ) (or hypervisor injected self-description data) is
|
||||
available by applying the PTFs for VM APAR VM64273 on z/VM 5.2.0 and higher.
|
||||
.TP
|
||||
.BI "-u|--uid"
|
||||
.BI "\-u|\-\-uid"
|
||||
Print DASD uid without z/VM minidisk token
|
||||
|
||||
z/VM may provide an additional token that can be used to distinguish
|
||||
between different minidisks (see --extended-uid option). To remain
|
||||
between different minidisks (see \-\-extended\-uid option). To remain
|
||||
compatible with systems that were installed on older Linux or z/VM
|
||||
levels, the -u option will print the uid excluding any z/VM-provided
|
||||
levels, the \-u option will print the uid excluding any z/VM-provided
|
||||
minidisk token.
|
||||
|
||||
For example, if the extended uid is
|
||||
@@ -57,35 +57,35 @@ uid is IBM.75000000092461.e900.10. If the extended uid contains no
|
||||
minidisk token, e.g. in an LPAR environment, then both uids are the
|
||||
same.
|
||||
.TP
|
||||
.BI "-l|--label"
|
||||
.BI "\-l|\-\-label"
|
||||
Print DASD volume label (volser).
|
||||
.TP
|
||||
.BI "-i|--busid " <busid>
|
||||
.BI "\-i|\-\-busid " <busid>
|
||||
Use the bus ID as input parameter, e.g. 0.0.e910.
|
||||
.TP
|
||||
.BI "-b|--block " <blockdev>
|
||||
.BI "\-b|\-\-block " <blockdev>
|
||||
Use the block device name as input parameter, e.g. dasdb.
|
||||
.TP
|
||||
.BI "-d|--devnode " <devnode>
|
||||
.BI "\-d|\-\-devnode " <devnode>
|
||||
Use a device node as input parameter, e.g. /dev/dasdb.
|
||||
.TP
|
||||
.BI "-e|--export"
|
||||
.BI "\-e|\-\-export"
|
||||
Print all values (ID_BUS, ID_TYPE, ID_SERIAL).
|
||||
.TP
|
||||
.BI "-h|--help"
|
||||
.BI "\-h|\-\-help"
|
||||
Print usage text.
|
||||
.TP
|
||||
.BI "-v|--version"
|
||||
.BI "\-v|\-\-version"
|
||||
Print version number.
|
||||
|
||||
.SH EXAMPLES
|
||||
dasdinfo -u -i 0.0.e910
|
||||
dasdinfo \-u \-i 0.0.e910
|
||||
|
||||
dasdinfo -u -b dasdb
|
||||
dasdinfo \-u \-b dasdb
|
||||
|
||||
dasdinfo -u -d /dev/dasdb
|
||||
dasdinfo \-u \-d /dev/dasdb
|
||||
|
||||
All three examples should return the same unique ID for
|
||||
All three examples should return the same unique ID for
|
||||
the same DASD device, e.g. IBM.75000000092461.e900.10.
|
||||
|
||||
In case this uid is not available, dasdinfo will return
|
||||
|
||||
@@ -7,21 +7,21 @@
|
||||
dasdview \- Display DASD and VTOC information and dump the content of a DASD
|
||||
to the console.
|
||||
.SH SYNOPSIS
|
||||
\fBdasdview\fR [-h] [-v]
|
||||
\fBdasdview\fR [\-h] [\-v]
|
||||
.br
|
||||
[-b \fIbegin\fR] [-s \fIsize\fR] [-1|-2]
|
||||
[\-b \fIbegin\fR] [\-s \fIsize\fR] [\-1|\-2]
|
||||
.br
|
||||
[-i] [-x] [-j] [-c]
|
||||
[\-i] [\-x] [\-j] [\-c]
|
||||
.br
|
||||
[-l] [-t {\fIinfo\fR|\fIf1\fR|\fIf3\fR|\fIf4\fR|\fIf5\fR|\fIf7\fR|\fIf8\fR|\fIf9\fR}]
|
||||
[\-l] [\-t {\fIinfo\fR|\fIf1\fR|\fIf3\fR|\fIf4\fR|\fIf5\fR|\fIf7\fR|\fIf8\fR|\fIf9\fR}]
|
||||
.br
|
||||
\fIdevice\fR
|
||||
.SH DESCRIPTION
|
||||
\fBdasdview\fR prints you some useful information of your disks to the console.
|
||||
You can display a disk dump by specifying start point and offset and you can
|
||||
You can display a disk dump by specifying start point and offset and you can
|
||||
print the volume label and VTOC entries.
|
||||
The \fIdevice\fR is the node of the device (e.g. '/dev/dasda').
|
||||
Any device node created by udev for kernel 2.6 can be used
|
||||
Any device node created by udev for kernel 2.6 can be used
|
||||
(e.g. '/dev/dasd/0.0.b100/disc').
|
||||
|
||||
DASD devices in raw_track_access mode are supported and detected
|
||||
@@ -29,30 +29,30 @@ automatically. When in raw_track_access mode, the same basic
|
||||
functions are available as in the regular mode, but the output may
|
||||
have a slightly different layout:
|
||||
.IP \(bu 2
|
||||
The disk dump functions (\fB-b\fR and \fB-s\fR) print the count,
|
||||
The disk dump functions (\fB\-b\fR and \fB\-s\fR) print the count,
|
||||
key and data information for the whole track, and not just the
|
||||
contents of the data areas.
|
||||
.IP \(bu 2
|
||||
The VTOC listing (\fB-t\fR) print all specified DSCBs in the same
|
||||
The VTOC listing (\fB\-t\fR) print all specified DSCBs in the same
|
||||
format as in the regular mode, but in the sequence as they appear in
|
||||
the VTOC. The \fB-t info\fR overview contains more details for each
|
||||
the VTOC. The \fB\-t info\fR overview contains more details for each
|
||||
data set than in the regular mode, to support the larger variety of
|
||||
data set layouts.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-h\fR or \fB--help\fR
|
||||
\fB\-h\fR or \fB\-\-help\fR
|
||||
Print usage and exit.
|
||||
|
||||
.TP
|
||||
\fB-v\fR or \fB--version\fR
|
||||
\fB\-v\fR or \fB\-\-version\fR
|
||||
Print version number and exit.
|
||||
|
||||
.TP
|
||||
\fB-b\fR \fIbegin\fR or \fB--begin=\fR\fIbegin\fR
|
||||
Print a disk dump to the console, starting with \fIbegin\fR. The content of
|
||||
the disk will be displayed in hexadecimal numbers, ASCII text and EBCDIC text.
|
||||
If no size is specified dasdview will take the default size. The variable
|
||||
\fB\-b\fR \fIbegin\fR or \fB\-\-begin=\fR\fIbegin\fR
|
||||
Print a disk dump to the console, starting with \fIbegin\fR. The content of
|
||||
the disk will be displayed in hexadecimal numbers, ASCII text and EBCDIC text.
|
||||
If no size is specified dasdview will take the default size. The variable
|
||||
\fIbegin\fR can be specified in one of the following ways:
|
||||
.br
|
||||
|
||||
@@ -63,10 +63,10 @@ The default for \fIbegin\fR is \fI0\fR.
|
||||
.br
|
||||
|
||||
\fBNote 1:\fR dasdview will show you the content of your disk using the DASD
|
||||
driver. If this driver decides to hide or add some parts of the disk, you have
|
||||
to live with it. This happens for example with the first two tracks of a
|
||||
cdl-formatted disk. In this case the DASD driver fills up shorter blocks with
|
||||
zeros to have a constant blocksize. And all applications, including dasdview,
|
||||
driver. If this driver decides to hide or add some parts of the disk, you have
|
||||
to live with it. This happens for example with the first two tracks of a
|
||||
cdl-formatted disk. In this case the DASD driver fills up shorter blocks with
|
||||
zeros to have a constant blocksize. And all applications, including dasdview,
|
||||
believe it.
|
||||
.br
|
||||
\fBNote 2:\fR In raw_track_access mode \fIbegin\fR must be aligned to
|
||||
@@ -76,24 +76,24 @@ cylinder as starting point.
|
||||
|
||||
examples:
|
||||
.br
|
||||
-b 32 --> start printing at Byte 32
|
||||
\-b 32 --> start printing at Byte 32
|
||||
.br
|
||||
-b 32k --> start printing at kByte 32
|
||||
\-b 32k --> start printing at kByte 32
|
||||
.br
|
||||
-b 32m --> start printing at MByte 32
|
||||
\-b 32m --> start printing at MByte 32
|
||||
.br
|
||||
-b 32b --> start printing at block 32
|
||||
\-b 32b --> start printing at block 32
|
||||
.br
|
||||
-b 32t --> start printing at track 32
|
||||
\-b 32t --> start printing at track 32
|
||||
.br
|
||||
-b 32c --> start printing at cylinder 32
|
||||
\-b 32c --> start printing at cylinder 32
|
||||
|
||||
.TP
|
||||
\fB-s\fR \fIsize\fR or \fB--size=\fR\fIsize\fR
|
||||
Print a disk dump to the console, starting with \fIbegin\fR, specified with
|
||||
the \fB-b\fR option and size \fIsize\fR. The content of the disk will be
|
||||
displayed in hexadecimal numbers, ASCII text and EBCDIC text. If no start
|
||||
value is specified dasdview will take the default start value. The variable
|
||||
\fB\-s\fR \fIsize\fR or \fB\-\-size=\fR\fIsize\fR
|
||||
Print a disk dump to the console, starting with \fIbegin\fR, specified with
|
||||
the \fB\-b\fR option and size \fIsize\fR. The content of the disk will be
|
||||
displayed in hexadecimal numbers, ASCII text and EBCDIC text. If no start
|
||||
value is specified dasdview will take the default start value. The variable
|
||||
\fIsize\fR can be specified in one of the following ways:
|
||||
.br
|
||||
|
||||
@@ -111,76 +111,76 @@ in raw_track_access mode.
|
||||
|
||||
examples:
|
||||
.br
|
||||
-s 16 --> use a 16 Byte size
|
||||
\-s 16 --> use a 16 Byte size
|
||||
.br
|
||||
-s 16k --> use a 16 kByte size
|
||||
\-s 16k --> use a 16 kByte size
|
||||
.br
|
||||
-s 16m --> use a 16 MByte size
|
||||
\-s 16m --> use a 16 MByte size
|
||||
.br
|
||||
-s 16b --> use a 16 block size
|
||||
\-s 16b --> use a 16 block size
|
||||
.br
|
||||
-s 16t --> use a 16 track size
|
||||
\-s 16t --> use a 16 track size
|
||||
.br
|
||||
-s 16c --> use a 16 cylinder size
|
||||
\-s 16c --> use a 16 cylinder size
|
||||
|
||||
.TP
|
||||
\fB-1\fR
|
||||
This option tells dasdview to print the disk dump using format 1. This means
|
||||
you will get 16 Bytes per line in hex, ascii and ebcdic. There is no line
|
||||
\fB\-1\fR
|
||||
This option tells dasdview to print the disk dump using format 1. This means
|
||||
you will get 16 Bytes per line in hex, ascii and ebcdic. There is no line
|
||||
number.
|
||||
.br
|
||||
The \fB-1\fR option makes only sense with the \fB-b\fR and/or the \fB-s\fR
|
||||
options.
|
||||
The \fB\-1\fR option makes only sense with the \fB\-b\fR and/or the \fB\-s\fR
|
||||
options.
|
||||
.br
|
||||
This is the default.
|
||||
|
||||
.TP
|
||||
\fB-2\fR
|
||||
This option tells dasdview to print the disk dump using format 2. This means
|
||||
you will get 8 Bytes per line in hex, ascii and ebcdic. And in addition a line
|
||||
\fB\-2\fR
|
||||
This option tells dasdview to print the disk dump using format 2. This means
|
||||
you will get 8 Bytes per line in hex, ascii and ebcdic. And in addition a line
|
||||
number and a decimal and hexadecimal byte count will be printed.
|
||||
.br
|
||||
The \fB-2\fR option makes only sense with the \fB-b\fR and/or the \fB-s\fR
|
||||
The \fB\-2\fR option makes only sense with the \fB\-b\fR and/or the \fB\-s\fR
|
||||
options. In raw_track_access mode this format is not supported and the
|
||||
option will be ignored.
|
||||
|
||||
.TP
|
||||
\fB-i\fR or \fB--info\fR
|
||||
\fB\-i\fR or \fB\-\-info\fR
|
||||
Print some useful information (e.g. device node/number/type or geometry data).
|
||||
When running dasdview on a kernel 2.6 based distribution the busid
|
||||
When running dasdview on a kernel 2.6 based distribution the busid
|
||||
is printed instead of the device number.
|
||||
|
||||
.TP
|
||||
\fB-x\fR or \fB--extended\fR
|
||||
\fB\-x\fR or \fB\-\-extended\fR
|
||||
Print some more DASD information (e.g. open count, subchannel identifier).
|
||||
|
||||
.TP
|
||||
\fB-j\fR or \fB--volser\fR
|
||||
\fB\-j\fR or \fB\-\-volser\fR
|
||||
Print volume serial number (volume identifier).
|
||||
|
||||
.TP
|
||||
\fB-l\fR or \fB--label\fR
|
||||
\fB\-l\fR or \fB\-\-label\fR
|
||||
Print the volume label.
|
||||
|
||||
.TP
|
||||
\fB-c\fR or \fB--characteristic\fR
|
||||
\fB\-c\fR or \fB\-\-characteristic\fR
|
||||
Print some information about the device e.g. if it is encrypted.
|
||||
|
||||
.TP
|
||||
\fB-t\fR \fIspec\fR or \fB--vtoc=\fR\fIspec\fR
|
||||
\fB\-t\fR \fIspec\fR or \fB\-\-vtoc=\fR\fIspec\fR
|
||||
Print the VTOC (table of content) or single VTOC entries to the console.
|
||||
\fIspec\fR can be one of the following strings:
|
||||
.br
|
||||
|
||||
\fIinfo\fR:
|
||||
\fIinfo\fR:
|
||||
.br
|
||||
Gives you a VTOC overview. You will see what other S/390 or zSeries operating
|
||||
Gives you a VTOC overview. You will see what other S/390 or zSeries operating
|
||||
systems would see (e.g. data set names and sizes).
|
||||
.br
|
||||
|
||||
\fIf1\fR:
|
||||
.br
|
||||
Print the content of all format 1 DSCBs.
|
||||
Print the content of all format 1 DSCBs.
|
||||
.br
|
||||
|
||||
\fIf3\fR:
|
||||
@@ -188,17 +188,17 @@ Print the content of all format 1 DSCBs.
|
||||
Print the content of all format 3 DSCBs.
|
||||
.br
|
||||
|
||||
\fIf4\fR:
|
||||
\fIf4\fR:
|
||||
.br
|
||||
Print the content of the format 4 DSCB.
|
||||
.br
|
||||
|
||||
\fIf5\fR:
|
||||
\fIf5\fR:
|
||||
.br
|
||||
Print the content of the format 5 DSCB.
|
||||
.br
|
||||
|
||||
\fIf7\fR:
|
||||
\fIf7\fR:
|
||||
.br
|
||||
Print the content of the format 7 DSCB.
|
||||
.br
|
||||
@@ -213,6 +213,6 @@ Print the content of all format 8 DSCBs.
|
||||
Print the content of all format 9 DSCBs.
|
||||
.br
|
||||
|
||||
\fIall\fR:
|
||||
\fIall\fR:
|
||||
.br
|
||||
Print the content of all DSCBs.
|
||||
Print the content of all DSCBs.
|
||||
|
||||
@@ -31,11 +31,11 @@
|
||||
#
|
||||
# Dump on ECKD device (DASD)
|
||||
#
|
||||
#ON_PANIC=dump
|
||||
#DUMP_TYPE=eckd
|
||||
#DEVICE=0.0.1004
|
||||
#BOOTPROG=0
|
||||
#BR_CHR=auto
|
||||
# ON_PANIC=dump
|
||||
# DUMP_TYPE=eckd
|
||||
# DEVICE=0.0.1004
|
||||
# BOOTPROG=0
|
||||
# BR_CHR=auto
|
||||
|
||||
#
|
||||
# Dump on fcp device (SCSI Disk)
|
||||
|
||||
@@ -8,16 +8,16 @@ fdasd \- partitioning tool.
|
||||
.SH SYNOPSIS
|
||||
interactive mode:
|
||||
.br
|
||||
\fBfdasd\fR [-s] [-r] [-C] \fIdevice\fR
|
||||
\fBfdasd\fR [\-s] [\-r] [\-C] \fIdevice\fR
|
||||
.br
|
||||
command line mode:
|
||||
.br
|
||||
\fBfdasd\fR [-s] [-r] [-C] {-a[-k|-l \fIvolser\fR]|-i|-p|-c \fIconf_file\fR}
|
||||
\fBfdasd\fR [\-s] [\-r] [\-C] {\-a[\-k|\-l \fIvolser\fR]|\-i|\-p|\-c \fIconf_file\fR}
|
||||
[-f \fI[type,blocksize]\fR] \fIdevice\fR
|
||||
.br
|
||||
help:
|
||||
.br
|
||||
\fBfdasd\fR {-h|-v}
|
||||
\fBfdasd\fR {\-h|\-v}
|
||||
.SH DESCRIPTION
|
||||
\fBfdasd\fR writes a partition table to a cdl (compatible disk layout)
|
||||
formatted DASD, in the form of
|
||||
@@ -30,35 +30,35 @@ will use it, otherwise it asks to write a new one.
|
||||
\fBfdasd\fR can result in loss of data.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
\fB-h\fR or \fB--help\fR
|
||||
\fB\-h\fR or \fB\-\-help\fR
|
||||
Print usage information, then exit.
|
||||
|
||||
.TP
|
||||
\fB-v\fR or \fB--version\fR
|
||||
\fB\-v\fR or \fB\-\-version\fR
|
||||
Print version information, then exit.
|
||||
|
||||
.TP
|
||||
\fB-s\fR or \fB--silent\fR
|
||||
\fB\-s\fR or \fB\-\-silent\fR
|
||||
Suppress messages in non-interactive mode.
|
||||
|
||||
.TP
|
||||
\fB-r\fR or \fB--verbose\fR
|
||||
\fB\-r\fR or \fB\-\-verbose\fR
|
||||
Provide more verbose output.
|
||||
|
||||
.TP
|
||||
\fB-a\fR or \fB--auto\fR
|
||||
\fB\-a\fR or \fB\-\-auto\fR
|
||||
Automatically create a partition using the entire disk in non-interactive
|
||||
mode.
|
||||
|
||||
.TP
|
||||
\fB-k\fR or \fB--keep_volser\fR
|
||||
\fB\-k\fR or \fB\-\-keep_volser\fR
|
||||
Keeps the Volume Serial Number when writing the Volume Label.
|
||||
.br
|
||||
This is useful if the volume already has a Serial Number that should not be
|
||||
overwritten. This option is only applicable in non-interactive mode.
|
||||
|
||||
.TP
|
||||
\fB-l\fR \fIvolser\fR or \fB--label\fR \fIvolser\fR
|
||||
\fB\-l\fR \fIvolser\fR or \fB\-\-label\fR \fIvolser\fR
|
||||
Specify the volume serial.
|
||||
.br
|
||||
\fIvolser\fR is interpreted as ASCII string and is automatically converted to
|
||||
@@ -82,14 +82,14 @@ quotes. In addition there is a special handling for the '$' sign.
|
||||
Please specify it using '\\$' if necessary.
|
||||
.br
|
||||
|
||||
e.g. -l 'a@b\\$c#' to get A@B$C#
|
||||
e.g. \-l 'a@b\\$c#' to get A@B$C#
|
||||
.br
|
||||
|
||||
Omitting this parameter causes fdasd to ask for it in case it is needed.
|
||||
.br
|
||||
|
||||
.TP
|
||||
\fB-c\fR \fIconf_file\fR or \fB--config\fR \fIconf_file\fR
|
||||
\fB\-c\fR \fIconf_file\fR or \fB\-\-config\fR \fIconf_file\fR
|
||||
Use this option to create multiple partitions according to
|
||||
specifications in a configuration file, \fIconf_file\fR.
|
||||
.br
|
||||
@@ -124,37 +124,37 @@ partitions that use the entire disk:
|
||||
.br
|
||||
|
||||
.TP
|
||||
\fB-i\fR or \fB--volser\fR
|
||||
\fB\-i\fR or \fB\-\-volser\fR
|
||||
Print the volume serial, then exit.
|
||||
|
||||
.TP
|
||||
\fB-p\fR or \fB--table\fR
|
||||
\fB\-p\fR or \fB\-\-table\fR
|
||||
Print partition table, then exit.
|
||||
.br
|
||||
In combination with the -s option fdasd will display a short version of the
|
||||
In combination with the \-s option fdasd will display a short version of the
|
||||
partition table.
|
||||
|
||||
.TP
|
||||
\fB-C\fR or \fB--check_host_count\fR
|
||||
\fB\-C\fR or \fB\-\-check_host_count\fR
|
||||
Force fdasd to check the host access open count to ensure the device
|
||||
is not online on another operating system instance
|
||||
|
||||
.TP
|
||||
\fB-f\fR \fI[type,blocksize]\fR or \fB--force\fR \fI[type,blocksize]\fR
|
||||
\fB\-f\fR \fI[type,blocksize]\fR or \fB\-\-force\fR \fI[type,blocksize]\fR
|
||||
Force fdasd to work on non DASD devices.
|
||||
.br
|
||||
If fdasd is to be used on a block device that is neither a native DASD
|
||||
nor exposes the proper disk geometry of a DASD of type 3390,
|
||||
then the --force option can be used to assume the geometry of a
|
||||
then the \-\-force option can be used to assume the geometry of a
|
||||
given device type. The default device type is 3390 and the default
|
||||
block size is 4096. An optional argument of <device type>,<blocksize>
|
||||
can be used to specify type and blocksize explicitly. For example:
|
||||
|
||||
-f
|
||||
\-f
|
||||
|
||||
has the same effect as
|
||||
|
||||
-f3390,4096 or --force=3390,4096
|
||||
\-f3390,4096 or \-\-force=3390,4096
|
||||
|
||||
Valid device types are: 3390, 3380, 9345
|
||||
.br
|
||||
|
||||
5
genprotimg/.gitignore
vendored
5
genprotimg/.gitignore
vendored
@@ -1,5 +0,0 @@
|
||||
tags
|
||||
compile_commands.json
|
||||
src/.check-dep-genprotimg
|
||||
src/.detect-openssl.dep.c
|
||||
src/genprotimg
|
||||
@@ -1,25 +0,0 @@
|
||||
# Common definitions
|
||||
include ../common.mak
|
||||
|
||||
.DEFAULT_GOAL := all
|
||||
|
||||
PKGDATADIR := "$(TOOLS_DATADIR)/genprotimg"
|
||||
TESTS :=
|
||||
SUBDIRS := boot src man
|
||||
RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
|
||||
|
||||
all: all-recursive
|
||||
|
||||
install: install-recursive
|
||||
$(INSTALL) -d -m 755 "$(DESTDIR)$(PKGDATADIR)"
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(DESTDIR)$(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)
|
||||
@@ -1,85 +0,0 @@
|
||||
# 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 |
|
||||
@@ -1,12 +0,0 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
all:
|
||||
|
||||
install:
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
|
||||
$(INSTALL) -m 644 -c genprotimg.1 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
clean:
|
||||
|
||||
.PHONY: all install clean
|
||||
@@ -1,159 +0,0 @@
|
||||
.\" 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 1 "May 2022" "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. Ignored if \fB--no-verify\fP is specified.
|
||||
.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 system wide root CAs installed on the system is used. Use
|
||||
this only if you trust the specified certificate. Optional.
|
||||
.TP
|
||||
\fB\-\-no-verify\fR
|
||||
Does not require the host-key documents to be valid.
|
||||
Do not use for a production image unless you verified
|
||||
the host-key document before. Optional.
|
||||
.TP
|
||||
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
|
||||
Specifies the customer communication key (CCK). This key is used for the
|
||||
PV guest dump encryption and to derive the CCK-derived extension secret
|
||||
used for add-secret requests. Use a secure, random, plaintext AES-256
|
||||
GCM key. Optional.
|
||||
.TP
|
||||
\fB\-\-enable\-dump\fR
|
||||
Enable PV guest dumps. Requires the \fB\-\-comm\-key\fR option. Optional.
|
||||
.TP
|
||||
\fB\-\-disable\-dump\fR
|
||||
Disable PV guest dumps. This is the default.
|
||||
.TP
|
||||
\fB\-\-enable\-cck\-extension\-secret\fR
|
||||
Add-secret requests must provide an extension secret that matches the
|
||||
CCK-derived extension secret. Requires the \fB\-\-comm\-key\fR option.
|
||||
Optional.
|
||||
.TP
|
||||
\fB\-\-disable\-cck\-extension\-secret\fR
|
||||
Add-secret requests don't have to provide an extension secret. This is
|
||||
the default.
|
||||
.TP
|
||||
\fB\-\-enable\-pckmo\fR
|
||||
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
||||
functions. This is the default.
|
||||
.TP
|
||||
\fB\-\-disable\-pckmo\fR
|
||||
Disable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
||||
functions. Optional.
|
||||
.TP
|
||||
\fB\-v\fR, \fB\-\-version\fR
|
||||
Prints version information, then exits.
|
||||
|
||||
.SH EXAMPLES
|
||||
|
||||
These are examples to generate a protected virtualization image in
|
||||
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR, the
|
||||
initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
||||
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR, the
|
||||
IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
||||
host-key document in \fI\,host_key.crt\/\fR. An AES-256 GCM key is stored in
|
||||
\fI\,comm-key\/\fR, which is used for the PV guest dump support in the second
|
||||
example.
|
||||
|
||||
Generate a protected virtualization image:
|
||||
|
||||
.PP
|
||||
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||
|
||||
Generate a protected virtualization image with PV guest dump support:
|
||||
.PP
|
||||
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR \-\-enable\-dump \-\-comm\-key \fI\,comm-key\fR
|
||||
|
||||
.SH NOTES
|
||||
.IP "1." 4
|
||||
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)
|
||||
@@ -1,104 +0,0 @@
|
||||
# Common definitions
|
||||
include ../../common.mak
|
||||
|
||||
bin_PROGRAM = genprotimg
|
||||
|
||||
PKGDATADIR ?= "$(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 -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 += -DPKGDATADIR=$(PKGDATADIR) \
|
||||
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBCURL_CFLAGS) \
|
||||
-DOPENSSL_API_COMPAT=0x10100000L \
|
||||
$(WARNINGS) \
|
||||
$(NULL)
|
||||
ALL_CPPFLAGS += $(INCLUDE_PARMS)
|
||||
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS) $(LIBCURL_LIBS)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
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 $@
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright IBM Corp. 2020, 2022
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef COMMON_H
|
||||
#define COMMON_H
|
||||
|
||||
#define GETTEXT_PACKAGE "genprotimg"
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "boot/linux_layout.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
|
||||
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* 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();
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* 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 "Poughkeepsie"
|
||||
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
|
||||
#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
|
||||
|
||||
union ecdh_pub_key {
|
||||
struct {
|
||||
uint8_t x[80];
|
||||
uint8_t y[80];
|
||||
};
|
||||
uint8_t data[160];
|
||||
} __packed;
|
||||
|
||||
#endif
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* 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/psw.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
|
||||
|
||||
/* Internal helper macro */
|
||||
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
|
||||
|
||||
/* Plaintext control flags */
|
||||
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34) /* dumping of the configuration is allowed */
|
||||
#define PV_PCF_NO_DECRYPTION __PV_BIT(35) /* prevent Ultravisor decryption during unpack operation */
|
||||
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||
#define PV_PCF_PCKMO_AES __PV_BIT(57) /* PCKMO encrypt-AES-key functions allowed */
|
||||
#define PV_PCF_PCKM_ECC __PV_BIT(58) /* PCKMO encrypt-ECC-key functions allowed */
|
||||
|
||||
/* Secret control flags */
|
||||
#define PV_SCF_CCK_EXTENSION_SECRET_ENFORCMENT \
|
||||
__PV_BIT(1) /* All add-secret requests must provide an extension secret */
|
||||
|
||||
/* 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
|
||||
@@ -1,556 +0,0 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
const PvControlFlagsArgs *cf_args = &args->cf_args;
|
||||
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
||||
|
||||
/* Check for mutually exclusive arguments */
|
||||
if (cf_args->pcf &&
|
||||
!(cf_args->enable_pckmo == PV_NOT_SET && cf_args->enable_dump == PV_NOT_SET)) {
|
||||
g_set_error(
|
||||
err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||
_("The '--x-pcf' option cannot be used with the '--(enable|disable)-pckmo' or"
|
||||
" '--(enable|disable)-dump' flags.\nUse 'genprotimg --help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cf_args->scf && !(cf_args->enable_cck_extension_secret_enforcement == PV_NOT_SET)) {
|
||||
g_set_error(
|
||||
err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||
_("The '--x-scf' option cannot be used with the '--(enable|disable)-extension-secret-required' flags.\nUse 'genprotimg --help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check for unused arguments */
|
||||
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;
|
||||
}
|
||||
|
||||
/* Check for mandatory arguments */
|
||||
if (cf_args->enable_dump == PV_TRUE && !args->cust_comm_key_path) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Option '--enable-dump' requires the '--comm-key' option.\nUse 'genprotimg "
|
||||
"--help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
if (cf_args->enable_cck_extension_secret_enforcement == PV_TRUE &&
|
||||
!args->cust_comm_key_path) {
|
||||
g_set_error(
|
||||
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Option '--enable-cck-extension-secret' requires the '--comm-key' option.\nUse 'genprotimg "
|
||||
"--help' for more information"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!args->output_path) {
|
||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
||||
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 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, "--comm-key"))
|
||||
args_option = &args->cust_comm_key_path;
|
||||
if (g_str_equal(option, "--root-ca"))
|
||||
args_option = &args->root_ca_path;
|
||||
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||
args_option = &args->output_path;
|
||||
if (g_str_equal(option, "--x-comp-key"))
|
||||
args_option = &args->xts_key_path;
|
||||
if (g_str_equal(option, "--x-header-key"))
|
||||
args_option = &args->cust_root_key_path;
|
||||
if (g_str_equal(option, "--x-pcf"))
|
||||
args_option = &args->cf_args.pcf;
|
||||
if (g_str_equal(option, "--x-psw"))
|
||||
args_option = &args->psw_addr;
|
||||
if (g_str_equal(option, "--x-scf"))
|
||||
args_option = &args->cf_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 MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE) (cb_##FLAG##_##VALUE)
|
||||
#define DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, VALUE) \
|
||||
static gboolean MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE)(const gchar *option G_GNUC_UNUSED, \
|
||||
const gchar *value G_GNUC_UNUSED, \
|
||||
PvArgs *args, GError **err) \
|
||||
{ \
|
||||
if (!(args->cf_args.enable_##FLAG == PV_NOT_SET || \
|
||||
args->cf_args.enable_##FLAG == VALUE)) { \
|
||||
g_set_error(err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \
|
||||
"'--enable-" #FLAG "' and '--disable-" #FLAG \
|
||||
"' are mutually exclusive"); \
|
||||
return FALSE; \
|
||||
} \
|
||||
args->cf_args.enable_##FLAG = VALUE; \
|
||||
return TRUE; \
|
||||
}
|
||||
|
||||
#define DEFINE_MUT_EXCL_BOOL_FLAG_CBS(FLAG) \
|
||||
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_TRUE) \
|
||||
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_FALSE)
|
||||
|
||||
#define MUT_EXCL_BOOL_FLAG(NAME, FLAG, ENABLE_DESC, DISABLE_DESC) \
|
||||
{ \
|
||||
.long_name = "enable-" #NAME, \
|
||||
.short_name = 0, \
|
||||
.flags = G_OPTION_FLAG_NO_ARG, \
|
||||
.arg = G_OPTION_ARG_CALLBACK, \
|
||||
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_TRUE), \
|
||||
.description = ENABLE_DESC, \
|
||||
}, \
|
||||
{ \
|
||||
.long_name = "disable-" #NAME, .short_name = 0, .flags = G_OPTION_FLAG_NO_ARG, \
|
||||
.arg = G_OPTION_ARG_CALLBACK, \
|
||||
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_FALSE), \
|
||||
.description = DISABLE_DESC, \
|
||||
}
|
||||
|
||||
#define INDENT " "
|
||||
|
||||
/* Define the callbacks for mutually exclusive command line flags */
|
||||
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(dump);
|
||||
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(pckmo);
|
||||
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(cck_extension_secret_enforcement);
|
||||
|
||||
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. Specify this option multiple times\n" INDENT
|
||||
"to enable the image to run on more than one host."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "cert",
|
||||
.short_name = 'C',
|
||||
.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") },
|
||||
MUT_EXCL_BOOL_FLAG(dump, dump,
|
||||
_("Enable PV guest dumps (optional). This option\n" INDENT
|
||||
"requires the '--comm-key' option."),
|
||||
_("Disable PV guest dumps (default).")),
|
||||
MUT_EXCL_BOOL_FLAG(
|
||||
cck-extension-secret, cck_extension_secret_enforcement,
|
||||
_("Add-secret requests must provide an extension\n" INDENT
|
||||
"secret that matches the CCK-derived extension\n" INDENT
|
||||
"secret (optional). This option requires the\n" INDENT
|
||||
"'--comm-key' option."),
|
||||
_("Add-secret requests don't have to provide\n" INDENT
|
||||
"the CCK-derived extension secret (default).")),
|
||||
MUT_EXCL_BOOL_FLAG(pckmo, pckmo,
|
||||
_("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||
"ECC PCKMO key encryption functions (default)."),
|
||||
_("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||
"ECC PCKMO key encryption functions (optional).")),
|
||||
{ .long_name = "comm-key",
|
||||
.short_name = 0,
|
||||
.flags = G_OPTION_FLAG_FILENAME,
|
||||
.arg = G_OPTION_ARG_CALLBACK,
|
||||
.arg_data = cb_set_string_option,
|
||||
.description = _(
|
||||
"FILE contains the customer communication key\n" INDENT
|
||||
"(CCK) (optional)."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .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-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; mutually exclusive with\n" INDENT
|
||||
"'--(enable|disable)-pckmo'; default: '0xe0'."),
|
||||
.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; mutually exclusive with\n" INDENT
|
||||
"'--(enable|disable)-cck-extension-secret';\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);
|
||||
/* `args->cf_args` is implicitly initialized with zeros since
|
||||
* `g_new0` is used. So there is no reason to explicitly
|
||||
* initialize the values as PV_NOT_SET == 0.
|
||||
*/
|
||||
return g_steal_pointer(&args);
|
||||
}
|
||||
|
||||
void pv_args_free(PvArgs *args)
|
||||
{
|
||||
if (!args)
|
||||
return;
|
||||
|
||||
g_free(args->cf_args.pcf);
|
||||
g_free(args->cf_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);
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/*
|
||||
* 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 enum pv_tristate {
|
||||
PV_NOT_SET = 0,
|
||||
PV_TRUE,
|
||||
PV_FALSE,
|
||||
} PvTristate;
|
||||
/* The value of PV_NOT_SET is not allowed to be changed */
|
||||
STATIC_ASSERT(PV_NOT_SET == 0)
|
||||
|
||||
typedef struct {
|
||||
gchar *pcf;
|
||||
gchar *scf;
|
||||
/* Add-secret requests do require CCK-extension secrets */
|
||||
PvTristate enable_cck_extension_secret_enforcement;
|
||||
PvTristate enable_dump;
|
||||
PvTristate enable_pckmo;
|
||||
} PvControlFlagsArgs;
|
||||
|
||||
typedef struct {
|
||||
gint log_level;
|
||||
gint no_verify;
|
||||
gboolean offline;
|
||||
PvControlFlagsArgs cf_args;
|
||||
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
|
||||
@@ -1,432 +0,0 @@
|
||||
/*
|
||||
* 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 "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 PvBuffer *buf,
|
||||
GError **err)
|
||||
{
|
||||
g_assert(buf);
|
||||
|
||||
g_autoptr(PvBuffer) dup_buf = pv_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:
|
||||
pv_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(PvBuffer) enc_buf = NULL;
|
||||
|
||||
if (!(IS_PAGE_ALIGNED(pv_component_size(component)))) {
|
||||
g_autoptr(PvBuffer) new = NULL;
|
||||
|
||||
/* create a page aligned copy */
|
||||
new = pv_buffer_dup(component->buf, TRUE);
|
||||
pv_buffer_clear(&component->buf);
|
||||
component->buf = g_steal_pointer(&new);
|
||||
}
|
||||
enc_buf = encrypt_buf(parms, component->buf, err);
|
||||
if (!enc_buf)
|
||||
return -1;
|
||||
|
||||
pv_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(PvBuffer) buf = NULL;
|
||||
|
||||
buf = pv_buffer_dup(component->buf, TRUE);
|
||||
pv_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();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (EVP_DigestUpdate(ctx, &cur_be, sizeof(cur_be)) != 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 PvBuffer *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"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
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"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
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"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
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 PvBuffer *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();
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
PvBuffer *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 PvBuffer *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
|
||||
@@ -1,252 +0,0 @@
|
||||
/*
|
||||
* 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/psw.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, PvBuffer **pld_digest,
|
||||
PvBuffer **ald_digest, PvBuffer **tld_digest,
|
||||
uint64_t *nep, GError **err)
|
||||
{
|
||||
g_autoptr(PvBuffer) tmp_pld_digest = NULL;
|
||||
g_autoptr(PvBuffer) tmp_ald_digest = NULL;
|
||||
g_autoptr(PvBuffer) 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);
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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/psw.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, PvBuffer **pld_digest,
|
||||
PvBuffer **ald_digest, PvBuffer **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
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* 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/psw.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_PCF_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, PvBuffer *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 PvBuffer aad_part = { .data = buf->data, .size = aad_len };
|
||||
PvBuffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
|
||||
.size = enc_len };
|
||||
PvBuffer 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(PvBuffer) pld = NULL;
|
||||
g_autoptr(PvBuffer) ald = NULL;
|
||||
g_autoptr(PvBuffer) 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 PvBuffer *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));
|
||||
}
|
||||
}
|
||||
|
||||
PvBuffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
|
||||
enum PvCryptoMode mode, GError **err)
|
||||
{
|
||||
uint32_t hdr_size = pv_hdr_size(hdr);
|
||||
g_autoptr(PvBuffer) ret = NULL;
|
||||
|
||||
ret = pv_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);
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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 "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);
|
||||
PvBuffer *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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* 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/psw.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 */
|
||||
PvBuffer *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 */
|
||||
PvBuffer *cust_root_key;
|
||||
PvBuffer *gcm_iv;
|
||||
const EVP_CIPHER *gcm_cipher;
|
||||
/* Information for the IPIB and PV header */
|
||||
uint64_t pcf;
|
||||
uint64_t scf;
|
||||
PvBuffer *cust_comm_key;
|
||||
const EVP_CIPHER *cust_comm_cipher;
|
||||
PvBuffer *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, PvBuffer **pld, PvBuffer **ald,
|
||||
PvBuffer **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
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
* 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 "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 PvBuffer *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_PBT_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 PvBuffer *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);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
* 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 PvBuffer *hdr, GError **err);
|
||||
void pv_ipib_free(IplParameterBlock *ipib);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(IplParameterBlock, pv_ipib_free)
|
||||
|
||||
#endif
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
/*
|
||||
* 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
|
||||
@@ -1,164 +0,0 @@
|
||||
/*
|
||||
* 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 PvBuffer *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(PvBuffer) 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 = pv_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);
|
||||
}
|
||||
|
||||
PvBuffer *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(PvBuffer *loader, gsize loader_size,
|
||||
const PvBuffer *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(PvBuffer *loader, gsize loader_size, const PvBuffer *hdr,
|
||||
struct ipl_parameter_block *ipib, GError **err)
|
||||
{
|
||||
return stage3a_set_data(loader, loader_size, hdr, ipib, err);
|
||||
}
|
||||
|
||||
PvBuffer *stage3b_getblob(const gchar *filename, GError **err)
|
||||
{
|
||||
g_autoptr(PvBuffer) 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(PvBuffer *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);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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/stage3b.h"
|
||||
#include "utils/buffer.h"
|
||||
|
||||
PvBuffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
|
||||
gsize data_size, GError **err);
|
||||
gint build_stage3a(PvBuffer *dc, gsize dc_size, const PvBuffer *hdr,
|
||||
struct ipl_parameter_block *ipib, GError **err);
|
||||
PvBuffer *stage3b_getblob(const gchar *filename, GError **err);
|
||||
void build_stage3b(PvBuffer *stage3b, const struct stage3b_args *args);
|
||||
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size);
|
||||
|
||||
#endif
|
||||
@@ -1,24 +0,0 @@
|
||||
/*
|
||||
* 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 "lib/zt_common.h"
|
||||
#include "boot/page.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
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
PvBuffer *pv_buffer_alloc(gsize size)
|
||||
{
|
||||
PvBuffer *ret = g_new0(PvBuffer, 1);
|
||||
|
||||
ret->data = g_malloc0(size);
|
||||
ret->size = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
PvBuffer *pv_buffer_take(char *data, gsize size)
|
||||
{
|
||||
PvBuffer *ret = g_new0(PvBuffer, 1);
|
||||
|
||||
ret->data = data;
|
||||
ret->size = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned)
|
||||
{
|
||||
PvBuffer *ret;
|
||||
gsize size;
|
||||
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
size = buf->size;
|
||||
if (page_aligned)
|
||||
size = PAGE_ALIGN(size);
|
||||
|
||||
ret = pv_buffer_alloc(size);
|
||||
|
||||
/* content will be 0-right-padded */
|
||||
memcpy(ret->data, buf->data, buf->size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err)
|
||||
{
|
||||
return file_write(file, buf->data, buf->size, 1, NULL, err);
|
||||
}
|
||||
|
||||
void pv_buffer_free(PvBuffer *buf)
|
||||
{
|
||||
if (!buf)
|
||||
return;
|
||||
|
||||
g_free(buf->data);
|
||||
g_free(buf);
|
||||
}
|
||||
|
||||
void pv_buffer_clear(PvBuffer **buf)
|
||||
{
|
||||
if (!buf || !*buf)
|
||||
return;
|
||||
|
||||
pv_buffer_free(*buf);
|
||||
*buf = NULL;
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
/*
|
||||
* 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 PvBuffer {
|
||||
void *data;
|
||||
gsize size; /* in bytes */
|
||||
} PvBuffer;
|
||||
|
||||
PvBuffer *pv_buffer_alloc(gsize size);
|
||||
/* After this call @data belongs to the PvBuffer and must no longer be modified
|
||||
* by the caller.
|
||||
*/
|
||||
PvBuffer *pv_buffer_take(char *data, gsize size);
|
||||
void pv_buffer_free(PvBuffer *buf);
|
||||
void pv_buffer_clear(PvBuffer **buf);
|
||||
gint pv_buffer_write(const PvBuffer *buf, FILE *file, GError **err);
|
||||
PvBuffer *pv_buffer_dup(const PvBuffer *buf, gboolean page_aligned);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvBuffer, pv_buffer_free)
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,174 +0,0 @@
|
||||
/*
|
||||
* 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(AUTHORITY_KEYID, AUTHORITY_KEYID_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 PvBuffer *key;
|
||||
const PvBuffer *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);
|
||||
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, 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);
|
||||
|
||||
PvBuffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
|
||||
PvBuffer *generate_aes_key(guint size, GError **err);
|
||||
PvBuffer *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);
|
||||
PvBuffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
|
||||
PvBuffer *sha256_buffer(const PvBuffer *buf, GError **err);
|
||||
int64_t gcm_encrypt(const PvBuffer *in, const PvBuffer *aad,
|
||||
const struct cipher_parms *parms, PvBuffer *out,
|
||||
PvBuffer *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);
|
||||
PvBuffer *encrypt_buf(const struct cipher_parms *parms, const PvBuffer *in,
|
||||
GError **err);
|
||||
G_GNUC_UNUSED PvBuffer *decrypt_buf(const struct cipher_parms *parms,
|
||||
const PvBuffer *in, GError **err);
|
||||
|
||||
#endif
|
||||
@@ -1,121 +0,0 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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 */
|
||||
@@ -1,234 +0,0 @@
|
||||
/*
|
||||
* 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 PvBuffer *buf, uint64_t offset,
|
||||
GError **err)
|
||||
{
|
||||
if (file_seek(o, offset, err) < 0)
|
||||
return -1;
|
||||
|
||||
if (pv_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;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* 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 PvBuffer *buf, uint64_t offset,
|
||||
GError **err);
|
||||
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
|
||||
GError **err);
|
||||
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
/*
|
||||
* OpenSSL compatibility utils
|
||||
*
|
||||
* Copyright IBM Corp. 2021
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef PV_UTILS_OPENSSL_COMPAT_H
|
||||
#define PV_UTILS_OPENSSL_COMPAT_H
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER < 0x30000000L
|
||||
#define Pv_X509_STORE_CTX_get_current_cert(ctx) \
|
||||
X509_STORE_CTX_get_current_cert((X509_STORE_CTX *)(ctx))
|
||||
#define Pv_X509_STORE_CTX_get1_crls(ctx, nm) \
|
||||
X509_STORE_CTX_get1_crls((X509_STORE_CTX *)(ctx), (X509_NAME *)(nm))
|
||||
#define Pv_X509_STORE_set_lookup_crls(st, cb) \
|
||||
X509_STORE_set_lookup_crls(st, (X509_STORE_CTX_lookup_crls_fn)(cb))
|
||||
#else
|
||||
#define Pv_X509_STORE_CTX_get_current_cert(ctx) \
|
||||
X509_STORE_CTX_get_current_cert(ctx)
|
||||
#define Pv_X509_STORE_CTX_get1_crls(ctx, nm) \
|
||||
X509_STORE_CTX_get1_crls(ctx, nm)
|
||||
#define Pv_X509_STORE_set_lookup_crls(st, cb) \
|
||||
X509_STORE_set_lookup_crls(st, cb)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -25,6 +25,9 @@
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_fmt.h"
|
||||
#include "lib/util_libc.h"
|
||||
|
||||
#include "helper.h"
|
||||
#include "hyptop.h"
|
||||
#include "sd.h"
|
||||
@@ -354,17 +357,6 @@ out:
|
||||
ht_reverse_off();
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to uppercase
|
||||
*/
|
||||
void ht_str_to_upper(char *str)
|
||||
{
|
||||
while (*str) {
|
||||
*str = toupper(*str);
|
||||
str++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert ext TOD to microseconds
|
||||
*/
|
||||
@@ -412,3 +404,40 @@ s64 ht_calculate_smt_util(u64 core_us, u64 thr_us, u64 mgm_us, int thread_per_co
|
||||
|
||||
return smt_us;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add two new key value pairs containing the current time as UNIX epoch and formatted string to a
|
||||
* structured output object.
|
||||
*/
|
||||
void ht_fmt_time(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct tm *tm;
|
||||
char str[30];
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
tm = localtime(&tv.tv_sec);
|
||||
if (!tm)
|
||||
return;
|
||||
util_fmt_pair(FMT_PERSIST, "time_epoch", "%lld", mktime(tm));
|
||||
strftime(str, sizeof(str), "%F %T%z", tm);
|
||||
util_fmt_pair(FMT_PERSIST | FMT_QUOTE, "time", "%s", str);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a new object for available CPU types to a structured output object.
|
||||
*/
|
||||
void ht_fmt_cpu_types(void)
|
||||
{
|
||||
struct sd_cpu_type *cpu_type;
|
||||
int i;
|
||||
|
||||
util_fmt_obj_start(FMT_DEFAULT, "cputypes");
|
||||
sd_cpu_type_iterate(cpu_type, i) {
|
||||
char *cpu_type_str = sd_cpu_type_id(cpu_type);
|
||||
util_str_tolower(cpu_type_str);
|
||||
util_fmt_pair(FMT_PERSIST, cpu_type_str, "%i",
|
||||
sd_cpu_type_cpu_cnt(cpu_type));
|
||||
}
|
||||
util_fmt_obj_end(); /* cpus{} */
|
||||
}
|
||||
|
||||
@@ -66,6 +66,12 @@ void ht_print_scroll_bar(int row_cnt, int row_start, int row_bar_start,
|
||||
int row_bar_bottom, int can_scroll_up,
|
||||
int can_scroll_down, int with_boder);
|
||||
|
||||
/*
|
||||
* util_fmt helper functions
|
||||
*/
|
||||
void ht_fmt_time(void);
|
||||
void ht_fmt_cpu_types(void);
|
||||
|
||||
/*
|
||||
* Error Macros
|
||||
*/
|
||||
|
||||
243
hyptop/hyptop.8
243
hyptop/hyptop.8
@@ -71,6 +71,51 @@ Use batch mode (no curses). This can be useful for sending output from hyptop
|
||||
to another program, a file, or a line mode terminal.
|
||||
In this mode no user input is accepted.
|
||||
.TP
|
||||
.BR "\-\-format=<FORMAT>"
|
||||
.RS
|
||||
Use this option to show output in a machine-readable format. FORMAT can be
|
||||
one of:
|
||||
|
||||
.IP \(bu 3
|
||||
.B json:
|
||||
Single JavaScript Object Notation (JSON) data structure
|
||||
|
||||
Data for all iterations is formatted as one JSON data structure in multiple
|
||||
lines to make them more readable by humans.
|
||||
.BR
|
||||
|
||||
See section "OUTPUT FORMAT" for more details.
|
||||
.BR
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.B json\-seq:
|
||||
Sequence of JSON data structures
|
||||
|
||||
Data for each iteration is formatted as a separate JSON data structure prefixed
|
||||
with an ASCII Record Separator character (0x1e) and suffixed with an ASCII Line
|
||||
Feed character (0x0a) in accordance with RFC7464.
|
||||
.BR
|
||||
|
||||
See section "OUTPUT FORMAT" for more details.
|
||||
.BR
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.B pairs:
|
||||
Textual key=value pairs
|
||||
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.B csv:
|
||||
Comma-separated-value (CSV) list
|
||||
.BR
|
||||
|
||||
All values are enclosed in double quotation marks and separated by commas. The
|
||||
first line of output contains a list of headings. Subsequent lines each
|
||||
represent data for one system in one iteration.
|
||||
.PP
|
||||
This option implies the "\-\-batch_mode" option.
|
||||
.RE
|
||||
.TP
|
||||
.BR "\-d <SECONDS>" " or " "\-\-delay=<SECONDS>"
|
||||
Specifies the delay between screen updates.
|
||||
.TP
|
||||
@@ -216,6 +261,196 @@ For the online time field, the value is the time during which at least
|
||||
one CPU has been operational.
|
||||
Operating CPUs are shown with CPU identifier "0" and stopped CPUs with "1".
|
||||
|
||||
.SH OUTPUT FORMATS
|
||||
This section contains additional information for some of the supported
|
||||
output formats.
|
||||
|
||||
.SS json
|
||||
|
||||
JSON output consists of a top-level object with the following properties
|
||||
(key-value pairs):
|
||||
|
||||
.IP \(bu 3
|
||||
.BR meta :
|
||||
Tool meta-data including API level, version, host name, and time of invocation
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR hyptop :
|
||||
Hypervisor performance data
|
||||
.PP
|
||||
|
||||
Performance data is stored as an array of iteration objects under the "hyptop"
|
||||
property in the top-level object. Iteration objects contain the following properties:
|
||||
|
||||
.IP \(bu 3
|
||||
.BR iteration :
|
||||
sequential count of the current iteration
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR "time" " and " "time_epoch" :
|
||||
time when the iteration was recorded, in human-readable format and as Unix
|
||||
epoch.
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR cputypes :
|
||||
contains the number of CPUs hyptop detected, per CPU type. Possible properties
|
||||
are
|
||||
.BR "cp" ", " "ifl" " and " "un".
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR systems :
|
||||
when the "sys_list" window is selected, contains an array of system objects
|
||||
that contain the performance data per system. Each system object contains a
|
||||
"system" property and properties for its performance data (see below).
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR cpus :
|
||||
when the "sys" window is selected, contains an array of CPU objects
|
||||
that contain the performance data per CPU of the selected system. Each CPU
|
||||
object contains a "coreid" property and properties for its performance data
|
||||
(see below).
|
||||
.PP
|
||||
.IP \(bu 3
|
||||
.BR summary :
|
||||
contains aggregated performance data over all systems in the "systems" or
|
||||
"cpus" array.
|
||||
.PP
|
||||
|
||||
All performance data available for the platform (LPAR, z/VM) hyptop is executed
|
||||
on is shown. Selecting specific fields with \-\-fields is not supported but it
|
||||
is possible to change the units of fields. Properties for performance data are
|
||||
labeled after their respective columns.
|
||||
|
||||
Example JSON output for a single iteration:
|
||||
.br
|
||||
|
||||
.RS
|
||||
{
|
||||
.br
|
||||
"meta": {
|
||||
.br
|
||||
"api_level": 1,
|
||||
.br
|
||||
"version": "2.35.0",
|
||||
.br
|
||||
"host": "mylpar.local",
|
||||
.br
|
||||
"time_epoch": 1730787834,
|
||||
.br
|
||||
"time": "2024-11-05 07:23:54+0100"
|
||||
.br
|
||||
},
|
||||
.br
|
||||
"hyptop": [
|
||||
.br
|
||||
{
|
||||
.br
|
||||
"iteration": 0,
|
||||
.br
|
||||
"time_epoch": 1730787834,
|
||||
.br
|
||||
"time": "2024-11-05 07:23:54+0100",
|
||||
.br
|
||||
"cputypes": {
|
||||
.br
|
||||
"ifl": 124,
|
||||
.br
|
||||
"cp": 1,
|
||||
.br
|
||||
"un": 0
|
||||
.br
|
||||
},
|
||||
.br
|
||||
"systems": [
|
||||
.br
|
||||
{
|
||||
.br
|
||||
"system": "MYLPAR",
|
||||
.br
|
||||
"#core": 30,
|
||||
.br
|
||||
"#the": 60,
|
||||
.br
|
||||
"core": 379.57,
|
||||
.br
|
||||
"the": 382.43,
|
||||
.br
|
||||
"smt": 294.73,
|
||||
.br
|
||||
"mgm": 2.09,
|
||||
.br
|
||||
"core+": "1503:13",
|
||||
.br
|
||||
"the+": "2060:45",
|
||||
.br
|
||||
"mgm+": "22:19",
|
||||
.br
|
||||
"online": "18:18:09"
|
||||
.br
|
||||
}
|
||||
.br
|
||||
],
|
||||
.br
|
||||
"summary": {
|
||||
.br
|
||||
"#core": 30,
|
||||
.br
|
||||
"#the": 60,
|
||||
.br
|
||||
"core": 379.57,
|
||||
.br
|
||||
"the": 382.43,
|
||||
.br
|
||||
"smt": 294.73,
|
||||
.br
|
||||
"mgm": 2.09,
|
||||
.br
|
||||
"core+": "1503:13",
|
||||
.br
|
||||
"the+": "2060:45",
|
||||
.br
|
||||
"mgm+": "22:19",
|
||||
.br
|
||||
"online": "18:18:09"
|
||||
.br
|
||||
}
|
||||
.br
|
||||
}
|
||||
.br
|
||||
]
|
||||
.br
|
||||
}
|
||||
.br
|
||||
.RE
|
||||
|
||||
.SS json\-seq
|
||||
|
||||
The json\-seq output format is a variation of the JSON output format described
|
||||
above with the following differences:
|
||||
|
||||
.IP \(bu 3
|
||||
Output consists of a sequence of top-level JSON objects, each contained in
|
||||
single line with no indentation
|
||||
.br
|
||||
|
||||
.IP \(bu 3
|
||||
Each top-level object is prefixed by an ASCII Record Separator character (0x1e)
|
||||
and suffixed with an ASCII Line Feed character (0x0a) in accordance with
|
||||
RFC7464
|
||||
.br
|
||||
.PP
|
||||
|
||||
.IP \(bu 3
|
||||
The first object contains tool meta-data properties defined in the previous
|
||||
section
|
||||
.br
|
||||
.PP
|
||||
|
||||
.IP \(bu 3
|
||||
Subsequent objects each represent performance data for one iteration
|
||||
.br
|
||||
.PP
|
||||
|
||||
.SH EXAMPLES
|
||||
To start hyptop with the "sys_list" window in interactive mode, enter:
|
||||
.br
|
||||
@@ -258,6 +493,14 @@ for CPU time calculation, enter:
|
||||
|
||||
# hyptop -t ifl,cp
|
||||
|
||||
.br
|
||||
To show a single iteration of performance data as a formatted JSON object for
|
||||
system "MYLPAR" and with fields CPU time, thread time, management time and
|
||||
online time in microseconds, enter:
|
||||
.br
|
||||
|
||||
# hyptop -f C:us,E:us,M:us,o:us --format json -n 1 -s MYLPAR
|
||||
|
||||
.SH ENVIRONMENT
|
||||
.TP
|
||||
.B TERM
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "lib/util_fmt.h"
|
||||
|
||||
#include "dg_debugfs.h"
|
||||
#include "helper.h"
|
||||
#include "hyptop.h"
|
||||
@@ -218,6 +220,22 @@ static void l_term_check(void)
|
||||
" try \"--batch_mode\"\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Init util_fmt if --format is specified on the command line.
|
||||
*/
|
||||
static void l_fmt_init(void)
|
||||
{
|
||||
unsigned int flags = FMT_WARN;
|
||||
|
||||
if (!g.o.format_specified)
|
||||
return;
|
||||
if (g.o.format == FMT_CSV)
|
||||
flags |= FMT_QUOTEALL;
|
||||
if (g.o.format == FMT_JSON || g.o.format == FMT_JSONSEQ)
|
||||
flags |= FMT_HANDLEINT;
|
||||
util_fmt_init(stdout, g.o.format, flags, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Init curses
|
||||
*/
|
||||
@@ -296,7 +314,6 @@ static void l_update_term_curses(void)
|
||||
static void l_update_term_batch(void)
|
||||
{
|
||||
g.w.cur->update_term(g.w.cur);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -360,6 +377,7 @@ void __noreturn hyptop_exit(int rc)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
opts_parse(argc, argv);
|
||||
l_fmt_init();
|
||||
hyptop_helper_init();
|
||||
sd_init();
|
||||
l_dg_init();
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "lib/util_fmt.h"
|
||||
|
||||
#include "helper.h"
|
||||
#include "nav_desc.h"
|
||||
#include "table.h"
|
||||
@@ -52,6 +54,8 @@ struct hyptop_win_opts {
|
||||
struct hyptop_opts {
|
||||
unsigned int win_specified;
|
||||
unsigned int batch_mode_specified;
|
||||
unsigned int format_specified;
|
||||
enum util_fmt_t format;
|
||||
unsigned int iterations_specified;
|
||||
unsigned int iterations;
|
||||
unsigned int iterations_act;
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lib/util_fmt.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#include "getopt.h"
|
||||
@@ -19,6 +21,7 @@
|
||||
#include "hyptop.h"
|
||||
#include "opts.h"
|
||||
#include "sd.h"
|
||||
#include "table.h"
|
||||
|
||||
static const char l_copyright_str[] = "Copyright IBM Corp. 2010, 2017";
|
||||
|
||||
@@ -38,10 +41,16 @@ static char HELP_TEXT[] =
|
||||
"-S, --sort LETTER Sort field for current window\n"
|
||||
"-t, --cpu_types TYPE[,..] CPU types used for time calculations\n"
|
||||
"-b, --batch_mode Use batch mode (no curses)\n"
|
||||
" --format FORMAT Output format (" FMT_TYPE_NAMES "), implies -b\n"
|
||||
"-d, --delay SECONDS Delay time between screen updates\n"
|
||||
"-m, --smt_factor FACTOR Machine generation dependent SMT speedup factor.\n"
|
||||
"-n, --iterations NUMBER Number of iterations before ending\n";
|
||||
|
||||
/*
|
||||
* Options with long-name only
|
||||
*/
|
||||
#define OPT_FORMAT 256 /* --format */
|
||||
|
||||
/*
|
||||
* Initialize default settings
|
||||
*/
|
||||
@@ -287,6 +296,23 @@ static void l_batch_mode_set(void)
|
||||
g.o.batch_mode_specified = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the "--format" option
|
||||
*/
|
||||
static void l_format_set(const char *str)
|
||||
{
|
||||
enum util_fmt_t fmt;
|
||||
|
||||
if (!util_fmt_name_to_type(str, &fmt)) {
|
||||
ERR_EXIT("Unknown format '%s', supported formats: "
|
||||
FMT_TYPE_NAMES "\n", str);
|
||||
}
|
||||
|
||||
l_batch_mode_set();
|
||||
g.o.format_specified = 1;
|
||||
g.o.format = fmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make option consisteny checks at end of command line parsing
|
||||
*/
|
||||
@@ -322,6 +348,7 @@ void opts_parse(int argc, char *argv[])
|
||||
{ "fields", required_argument, NULL, 'f'},
|
||||
{ "sort_field", required_argument, NULL, 'S'},
|
||||
{ "cpu_types", required_argument, NULL, 't'},
|
||||
{ "format", required_argument, NULL, OPT_FORMAT },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
static const char option_string[] = "vhbd:m:w:s:n:f:t:S:";
|
||||
@@ -366,6 +393,9 @@ void opts_parse(int argc, char *argv[])
|
||||
case 'S':
|
||||
l_sort_field_set(optarg);
|
||||
break;
|
||||
case OPT_FORMAT:
|
||||
l_format_set(optarg);
|
||||
break;
|
||||
default:
|
||||
l_std_usage_exit();
|
||||
}
|
||||
@@ -404,7 +434,7 @@ static void l_verify_systems(struct hyptop_win *win)
|
||||
if (sd_sys_get(sd_sys_root_get(), win->opts.sys.vec[i]))
|
||||
continue;
|
||||
sys_name = ht_strdup(win->opts.sys.vec[i]);
|
||||
ht_str_to_upper(win->opts.sys.vec[i]);
|
||||
util_str_toupper(win->opts.sys.vec[i]);
|
||||
if (sd_sys_get(sd_sys_root_get(), win->opts.sys.vec[i])) {
|
||||
ht_free(sys_name);
|
||||
continue;
|
||||
@@ -431,11 +461,11 @@ void opts_iterations_next(void)
|
||||
{
|
||||
if (g.o.iterations_specified) {
|
||||
g.o.iterations_act++;
|
||||
if (g.o.iterations_act >= g.o.iterations)
|
||||
if (g.o.iterations_act >= g.o.iterations) {
|
||||
if (g.o.format_specified)
|
||||
table_fmt_end();
|
||||
hyptop_exit(0);
|
||||
}
|
||||
}
|
||||
if (g.o.batch_mode_specified)
|
||||
printf("---------------------------------------------------"
|
||||
"----------------------------\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/util_fmt.h"
|
||||
#include "lib/util_libc.h"
|
||||
|
||||
#include "helper.h"
|
||||
#include "hyptop.h"
|
||||
#include "table.h"
|
||||
@@ -196,8 +199,8 @@ static void l_col_headline_init(struct table *t, struct table_col *col)
|
||||
col->p->head_char[0] = col->hotkey;
|
||||
strcpy(col->p->head_last, ++ptr);
|
||||
if (!t->attr_sorted_table) {
|
||||
ht_str_to_upper(col->p->head_first);
|
||||
ht_str_to_upper(col->p->head_last);
|
||||
util_str_toupper(col->p->head_first);
|
||||
util_str_toupper(col->p->head_last);
|
||||
col->p->head_char[0] = toupper(col->p->head_char[0]);
|
||||
}
|
||||
}
|
||||
@@ -948,6 +951,76 @@ static void l_table_print_all(struct table *t)
|
||||
hyptop_print_nl();
|
||||
}
|
||||
l_row_print(t, t->row_last);
|
||||
hyptop_print_nl();
|
||||
hyptop_printf("------------------------------------------------------"
|
||||
"-------------------------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Print one table row as structured output
|
||||
*
|
||||
* Note: column filtering and sorting is explicitly ignored because the
|
||||
* assumption is that these operations can be trivially performed by the
|
||||
* consumer.
|
||||
*/
|
||||
static void l_row_print_formatted(struct table *t, struct table_row *row)
|
||||
{
|
||||
struct table_col *col;
|
||||
int col_nr;
|
||||
|
||||
table_col_iterate(t, col, col_nr) {
|
||||
unsigned int flags = 0;
|
||||
struct table_entry *e = &row->entries[col_nr];
|
||||
|
||||
if (row == t->row_last && col_nr == 0)
|
||||
continue;
|
||||
if (table_col_needs_quotes(col))
|
||||
flags = FMT_QUOTE;
|
||||
util_fmt_pair(flags, col->head, "%s", e->str);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print table as structured output
|
||||
*/
|
||||
static void l_table_print_all_formatted(struct table *t)
|
||||
{
|
||||
struct table_row *row;
|
||||
|
||||
util_fmt_obj_start(FMT_ROW, "iteration");
|
||||
util_fmt_pair(FMT_PERSIST, "iteration", "%u", g.o.iterations_act);
|
||||
ht_fmt_time();
|
||||
ht_fmt_cpu_types();
|
||||
if (strcmp(g.o.cur_win->id, "sys_list") == 0)
|
||||
util_fmt_obj_start(FMT_LIST, "systems");
|
||||
else
|
||||
util_fmt_obj_start(FMT_LIST, "cpus");
|
||||
util_list_iterate(&t->row_list, row) {
|
||||
util_fmt_obj_start(FMT_ROW, "entry");
|
||||
l_row_print_formatted(t, row);
|
||||
util_fmt_obj_end(); /* entry */
|
||||
}
|
||||
util_fmt_obj_end(); /* systems[] */
|
||||
util_fmt_obj_start(FMT_DEFAULT, "summary");
|
||||
l_row_print_formatted(t, t->row_last);
|
||||
util_fmt_obj_end(); /* summary{} */
|
||||
util_fmt_obj_end(); /* iteration */
|
||||
}
|
||||
|
||||
void table_fmt_start(void)
|
||||
{
|
||||
if (!g.o.format_specified)
|
||||
return;
|
||||
if (g.o.format != FMT_JSONSEQ)
|
||||
util_fmt_obj_start(FMT_LIST, "hyptop");
|
||||
}
|
||||
|
||||
void table_fmt_end(void)
|
||||
{
|
||||
if (!g.o.format_specified)
|
||||
return;
|
||||
if (g.o.format != FMT_JSONSEQ)
|
||||
util_fmt_obj_end(); /* hyptop[] */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -955,10 +1028,14 @@ static void l_table_print_all(struct table *t)
|
||||
*/
|
||||
void table_print(struct table *t)
|
||||
{
|
||||
if (g.o.batch_mode_specified)
|
||||
l_table_print_all(t);
|
||||
else
|
||||
if (g.o.batch_mode_specified) {
|
||||
if (!g.o.format_specified)
|
||||
l_table_print_all(t);
|
||||
else
|
||||
l_table_print_all_formatted(t);
|
||||
} else {
|
||||
l_table_print_curses(t);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -106,6 +106,7 @@ struct table_col_priv {
|
||||
char head_char[2];
|
||||
char head_last[TABLE_HEADING_SIZE];
|
||||
int rsort;
|
||||
int needs_quotes;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -135,6 +136,11 @@ static inline int table_col_enabled(struct table_col *col)
|
||||
return col->p->enabled;
|
||||
}
|
||||
|
||||
static inline int table_col_needs_quotes(struct table_col *col)
|
||||
{
|
||||
return col->p->needs_quotes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Table Column Constructor Macros
|
||||
*/
|
||||
@@ -384,6 +390,9 @@ extern struct table_row *table_row_alloc(struct table *t);
|
||||
extern void table_scroll_down(struct table *t, enum table_scroll_unit unit);
|
||||
extern void table_scroll_up(struct table *t, enum table_scroll_unit unit);
|
||||
|
||||
extern void table_fmt_start(void);
|
||||
extern void table_fmt_end(void);
|
||||
|
||||
/*
|
||||
* Entry add functions
|
||||
*/
|
||||
|
||||
@@ -63,7 +63,7 @@ static int l_unit_raw(struct table_col *col, struct table_entry *e)
|
||||
*/
|
||||
static int l_str(struct table_col *col, struct table_entry *e)
|
||||
{
|
||||
(void) col;
|
||||
col->p->needs_quotes = 1;
|
||||
return strlen(e->str);
|
||||
}
|
||||
|
||||
@@ -226,6 +226,8 @@ static int l_unit_hm_u64(char *str, u64 v1, int negative)
|
||||
|
||||
static int l_unit_hm(struct table_col *col, struct table_entry *e)
|
||||
{
|
||||
col->p->needs_quotes = 1;
|
||||
|
||||
if (!e->set)
|
||||
return snprintf(e->str, sizeof(e->str), L_COL_NOT_SET_STR);
|
||||
|
||||
@@ -272,6 +274,8 @@ static int l_unit_dhm_u64(char *str, u64 v1, int negative)
|
||||
|
||||
static int l_unit_dhm(struct table_col *col, struct table_entry *e)
|
||||
{
|
||||
col->p->needs_quotes = 1;
|
||||
|
||||
if (!e->set)
|
||||
return snprintf(e->str, sizeof(e->str), L_COL_NOT_SET_STR);
|
||||
|
||||
|
||||
@@ -162,7 +162,8 @@ static void l_cpu_add(struct sd_cpu *cpu)
|
||||
continue;
|
||||
l_cpu_item_add(table_row, cpu, item);
|
||||
}
|
||||
l_cpu_add_visual(table_row, cpu);
|
||||
if (!g.o.format_specified)
|
||||
l_cpu_add_visual(table_row, cpu);
|
||||
table_row_add(l_t, table_row);
|
||||
}
|
||||
|
||||
@@ -194,7 +195,8 @@ static void l_table_update_term(struct hyptop_win *win)
|
||||
{
|
||||
(void) win;
|
||||
|
||||
ht_print_head(l_sys_id);
|
||||
if (!g.o.format_specified)
|
||||
ht_print_head(l_sys_id);
|
||||
table_print(l_t);
|
||||
}
|
||||
|
||||
@@ -300,6 +302,7 @@ static void l_run(struct hyptop_win *win)
|
||||
|
||||
/* Reformat table when entering window */
|
||||
table_rebuild(l_t);
|
||||
table_fmt_start();
|
||||
while (1) {
|
||||
if (l_table_create()) {
|
||||
if (g.o.batch_mode_specified)
|
||||
@@ -363,9 +366,11 @@ void win_sys_init(void)
|
||||
col_vec[i] = col;
|
||||
col_desc_vec[i] = item->desc;
|
||||
}
|
||||
col_vec[i] = &l_vis_col;
|
||||
col_desc_vec[i] = vis_str;
|
||||
table_col_add(l_t, &l_vis_col);
|
||||
if (!g.o.format_specified) {
|
||||
col_vec[i] = &l_vis_col;
|
||||
col_desc_vec[i] = vis_str;
|
||||
table_col_add(l_t, &l_vis_col);
|
||||
}
|
||||
|
||||
/* Enable fields */
|
||||
if (win_sys.opts.fields.specified)
|
||||
|
||||
@@ -206,7 +206,8 @@ static void l_table_update_term(struct hyptop_win *win)
|
||||
{
|
||||
(void) win;
|
||||
|
||||
ht_print_head(NULL);
|
||||
if (!g.o.format_specified)
|
||||
ht_print_head(NULL);
|
||||
table_print(l_t);
|
||||
}
|
||||
|
||||
@@ -310,6 +311,7 @@ static void l_run(struct hyptop_win *win)
|
||||
|
||||
/* Reformat table when entering window */
|
||||
table_rebuild(l_t);
|
||||
table_fmt_start();
|
||||
while (1) {
|
||||
l_table_create();
|
||||
hyptop_update_term();
|
||||
|
||||
@@ -21,18 +21,20 @@
|
||||
|
||||
#define STAGE2_DESC _AC(0x78, UL)
|
||||
#define STAGE2_ENTRY _AC(0x2018, UL)
|
||||
#define ECKD2DUMP_MV_TAIL_ADDRESS _AC(0x5000, UL)
|
||||
#define STAGE2_HEAP_ADDRESS _AC(0x6000, UL)
|
||||
#define ECKD2DUMP_SV_HEAP_ADDRESS _AC(0xb000, UL)
|
||||
#define ECKD2DUMP_HEAP_ADDRESS _AC(0xb000, UL)
|
||||
#define STAGE2_HEAP_SIZE _AC(0x3000, UL)
|
||||
#define STAGE2_STACK_ADDRESS _AC(0xe400, UL)
|
||||
#define STAGE2_STACK_SIZE _AC(0x1c00, UL)
|
||||
#define ECKD2DUMP_SV_STACK_ADDRESS _AC(0xe000, UL)
|
||||
#define ECKD2DUMP_SV_STACK_SIZE _AC(0x2000, UL)
|
||||
#define ECKD2DUMP_STACK_ADDRESS _AC(0xe000, UL)
|
||||
#define ECKD2DUMP_STACK_SIZE _AC(0x2000, UL)
|
||||
#define STAGE2_MAX_SIZE _AC(0x3000, UL)
|
||||
|
||||
#define STAGE2_DUMPER_SIZE_V1 _AC(0x1000, UL)
|
||||
#define STAGE2_DUMPER_SIZE_V2 _AC(0x2000, UL)
|
||||
#define STAGE2_DUMPER_SIZE_V3 _AC(0x3000, UL)
|
||||
#define STAGE2_DUMPER_SIZE_MV _AC(0x3000, UL)
|
||||
#define STAGE2_DUMPER_SIZE_ZLIB _AC(0x8000, UL)
|
||||
|
||||
#define STAGE3_ENTRY _AC(0xa000, UL)
|
||||
|
||||
@@ -24,11 +24,25 @@
|
||||
#define OS_INFO_VMCOREINFO 0
|
||||
#define OS_INFO_REIPL_BLOCK 1
|
||||
#define OS_INFO_FLAGS_ENTRY 2
|
||||
#define OS_INFO_RESERVED 3
|
||||
#define OS_INFO_IDENTITY_BASE 4
|
||||
#define OS_INFO_KASLR_OFFSET 5
|
||||
#define OS_INFO_KASLR_OFF_PHYS 6
|
||||
#define OS_INFO_VMEMMAP 7
|
||||
#define OS_INFO_AMODE31_START 8
|
||||
#define OS_INFO_AMODE31_END 9
|
||||
#define OS_INFO_IMAGE_START 10
|
||||
#define OS_INFO_IMAGE_END 11
|
||||
#define OS_INFO_IMAGE_PHYS 12
|
||||
#define OS_INFO_MAX 13
|
||||
|
||||
#define OS_INFO_FLAG_REIPL_CLEAR (1UL << 0)
|
||||
|
||||
struct os_info_entry {
|
||||
uint64_t addr;
|
||||
union {
|
||||
uint64_t addr;
|
||||
uint64_t val;
|
||||
};
|
||||
uint64_t size;
|
||||
uint32_t csum;
|
||||
} __packed;
|
||||
@@ -40,10 +54,12 @@ struct os_info {
|
||||
uint16_t version_minor;
|
||||
uint64_t crashkernel_addr;
|
||||
uint64_t crashkernel_size;
|
||||
struct os_info_entry entry[3];
|
||||
uint8_t reserved[4004];
|
||||
struct os_info_entry entry[OS_INFO_MAX];
|
||||
uint8_t reserved[3804];
|
||||
} __packed;
|
||||
|
||||
STATIC_ASSERT(sizeof(struct os_info) == 4096)
|
||||
|
||||
/*
|
||||
* Return 0 in case of valid os_info
|
||||
* Return -EOS_INFO_MISSING if os_info address is not page aligned or page is
|
||||
|
||||
@@ -21,7 +21,9 @@
|
||||
#define AP_UDEV_FILE "/etc/udev/rules.d/41-ap.rules"
|
||||
#define AP_LOCKFILE "/run/lock/s390apconfig.lock"
|
||||
|
||||
#define AP_LOCK_RETRIES 15
|
||||
#define AP_LOCK_RETRIES 3000
|
||||
#define AP_LOCK_DELAY_US 30000 /* wait at least 30ms between lock retries */
|
||||
#define AP_LOCK_VARIANCE_US 3000 /* or as much as 33ms */
|
||||
|
||||
/* apmask and aqmask are each represented as 67 character strings with:
|
||||
* '0x' leading characters
|
||||
@@ -70,6 +72,7 @@ char *path_get_ap_udev(void);
|
||||
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
|
||||
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
|
||||
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
|
||||
bool vfio_ap_need_dynamic_config(struct vfio_ap_device *dev);
|
||||
|
||||
/* Functions for reading JSON device config */
|
||||
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
|
||||
@@ -85,6 +88,9 @@ bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
|
||||
bool *read_aq);
|
||||
void ap_mask_to_list(char *mask, struct util_list *list);
|
||||
void ap_list_remove_all(struct util_list *list);
|
||||
char *vfio_ap_device_get_adapter_mask(struct vfio_ap_device *dev, int *size);
|
||||
char *vfio_ap_device_get_domain_mask(struct vfio_ap_device *dev, int *size);
|
||||
char *vfio_ap_device_get_control_mask(struct vfio_ap_device *dev, int *size);
|
||||
|
||||
/* Lock Functions */
|
||||
int ap_get_lock(void);
|
||||
|
||||
96
include/lib/pci_list.h
Normal file
96
include/lib/pci_list.h
Normal file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @defgroup pci_list_h libzpci: zPCI device handling
|
||||
* @{
|
||||
* @brief Work with zPCI devices
|
||||
*
|
||||
* Copyright IBM Corp. 2024
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef LIB_ZPCI_PCI_LIST_H
|
||||
#define LIB_ZPCI_PCI_LIST_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "util_list.h"
|
||||
|
||||
enum zpci_pft {
|
||||
ZPCI_PFT_UNCLASSIFIED = 0x00,
|
||||
|
||||
ZPCI_PFT_ROCE_EXPRESS = 0x02,
|
||||
ZPCI_PFT_ROCE_EXPRESS2 = 0x0a,
|
||||
ZPCI_PFT_CNW = 0x0d,
|
||||
ZPCI_PFT_NETH = 0x0c,
|
||||
ZPCI_PFT_NETD = 0x0f,
|
||||
|
||||
ZPCI_PFT_NVME = 0x0b,
|
||||
ZPCI_PFT_ISM = 0x05
|
||||
};
|
||||
|
||||
/*
|
||||
* Follows RFC 2863 operational states with the
|
||||
* numeric values from IF_OPER_* in linux/if.h:
|
||||
*/
|
||||
typedef uint8_t operstate_t;
|
||||
|
||||
struct zpci_netdev {
|
||||
char *name;
|
||||
operstate_t operstate;
|
||||
};
|
||||
|
||||
struct zpci_dev {
|
||||
struct util_list_node entry;
|
||||
/* PCI Domain */
|
||||
uint32_t domain_nr;
|
||||
/* PCI Bus (8 bits), Device (5 bits), Function (3 bits) */
|
||||
union {
|
||||
uint16_t val;
|
||||
struct {
|
||||
uint16_t bus : 8;
|
||||
uint16_t dev : 5;
|
||||
uint16_t fn : 3;
|
||||
};
|
||||
} bdf;
|
||||
|
||||
/* Function attributes (see linux/Documentation/arch/s390/pci.rst) */
|
||||
uint32_t fid;
|
||||
uint32_t uid;
|
||||
uint16_t pchid;
|
||||
uint16_t vfn;
|
||||
uint8_t port;
|
||||
enum zpci_pft pft;
|
||||
bool uid_is_unique;
|
||||
/* Configuration state 0 - Standby, 1 Configured */
|
||||
bool conf;
|
||||
|
||||
/* Associated netdevs if any */
|
||||
int num_netdevs;
|
||||
struct zpci_netdev *netdevs;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get if a PCI device is a PCI Virtual Function
|
||||
*
|
||||
* @param[in] zdev The device in question
|
||||
*
|
||||
* @return true if the device is a VF false otherwise
|
||||
*/
|
||||
static inline bool zpci_is_vf(struct zpci_dev *zdev)
|
||||
{
|
||||
return !!zdev->vfn;
|
||||
}
|
||||
|
||||
struct util_list *zpci_dev_list(void);
|
||||
void zpci_free_dev_list(struct util_list *zpci_list);
|
||||
void zpci_free_dev(struct zpci_dev *zdev);
|
||||
|
||||
char *zpci_pci_addr(struct zpci_dev *zdev);
|
||||
const char *zpci_pft_str(struct zpci_dev *zdev);
|
||||
|
||||
const char *zpci_operstate_str(operstate_t state);
|
||||
operstate_t zpci_operstate_from_str(const char *oper_str);
|
||||
|
||||
#endif /* LIB_ZPCI_PCI_LIST_H */
|
||||
56
include/lib/pci_sclp.h
Normal file
56
include/lib/pci_sclp.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @defgroup pci_sclp_h libzpci: zPCI device handling
|
||||
* @{
|
||||
* @brief Issue SCLPs for zPCI devices
|
||||
*
|
||||
* Copyright IBM Corp. 2024
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef LIB_ZPCI_PCI_SCLP_H
|
||||
#define LIB_ZPCI_PCI_SCLP_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define SCLP_ERRNOTIFY_AQ_RESET 0
|
||||
#define SCLP_ERRNOTIFY_AQ_DECONF 1
|
||||
#define SCLP_ERRNOTIFY_AQ_REPORT_ERR 2
|
||||
#define SCLP_ERRNOTIFY_AQ_OPTICS_DATA 3
|
||||
|
||||
#define SCLP_ERRNOTIFY_ID_ZPCICTL 0x4713
|
||||
#define SCLP_ERRNOTIFY_ID_OPTICSMON 0x4714
|
||||
|
||||
#define SCLP_ERRNOTIFY_DATA_SIZE 4054
|
||||
|
||||
struct zpci_report_error_header {
|
||||
__u8 version; /* Interface version byte */
|
||||
__u8 action; /* Action qualifier byte
|
||||
* 0: Adapter Reset Request
|
||||
* 1: Deconfigure and repair action requested
|
||||
* 2: Informational Report
|
||||
* 3: Optics Data
|
||||
*/
|
||||
__u16 length; /* Length of Subsequent Data (up to 4K – SCLP header) */
|
||||
} __packed;
|
||||
|
||||
struct zpci_report_error_data {
|
||||
__u64 timestamp;
|
||||
__u64 err_log_id;
|
||||
/* We cannot exceed a total of 4074 bytes (header + data) */
|
||||
char log_data[SCLP_ERRNOTIFY_DATA_SIZE];
|
||||
} __packed;
|
||||
|
||||
struct zpci_report_error {
|
||||
struct zpci_report_error_header header;
|
||||
struct zpci_report_error_data data;
|
||||
} __packed;
|
||||
|
||||
int zpci_sclp_issue_action(char *pci_addr, int action,
|
||||
char *data, size_t length, u64 err_log_id);
|
||||
|
||||
#endif /* LIB_ZPCI_PCI_SCLP_H */
|
||||
@@ -14,7 +14,10 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "zt_common.h"
|
||||
#include "lib/util_libc.h"
|
||||
|
||||
void util_hexdump(FILE *fh, const char *tag, const void *data, int cnt);
|
||||
void util_hexdump_grp(FILE *fh, const char *tag, const void *data, int group,
|
||||
@@ -37,4 +40,30 @@ static inline void util_ptr_vec_free(void **ptr_vec, int count)
|
||||
free(ptr_vec);
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand size of dynamic array (element_t *) by one element
|
||||
*
|
||||
* @param[in,out] array Pointer to array (element_t **)
|
||||
* @param[in,out] num Pointer to integer containing number of elements
|
||||
*/
|
||||
#define util_expand_array(array, num) \
|
||||
do { \
|
||||
unsigned int __size = sizeof(*(*(array))); \
|
||||
*(array) = util_realloc(*(array), ++(*(num)) * __size); \
|
||||
memset(&((*(array))[*(num) - 1]), 0, __size); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Append one element to dynamic array (element_t *)
|
||||
*
|
||||
* @param[in,out] array Pointer to array (element_t **)
|
||||
* @param[in,out] num Pointer to integer containing number of elements
|
||||
* @param[in] element Element to add (element_t)
|
||||
*/
|
||||
#define util_add_array(array, num, element) \
|
||||
do { \
|
||||
util_expand_array(array, num); \
|
||||
(*(array))[*(num) - 1] = (element) ; \
|
||||
} while (0)
|
||||
|
||||
#endif /* LIB_UTIL_BASE_H */
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef LIB_UTIL_FILE_H
|
||||
#define LIB_UTIL_FILE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "lib/util_exit_code.h"
|
||||
|
||||
int util_file_read_line(char *str, size_t size, const char *fmt, ...);
|
||||
|
||||
235
include/lib/util_fmt.h
Normal file
235
include/lib/util_fmt.h
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* util_fmt - Format structured key-value data as JSON, text pairs, or CSV
|
||||
*
|
||||
* Copyright IBM Corp. 2024
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*
|
||||
* This module provides helper functions for converting structured key-value
|
||||
* data into different output formats.
|
||||
*
|
||||
* Benefits:
|
||||
* - Output format can be dynamically configured at run-time
|
||||
* - Callers do not need to add extra code for each output format
|
||||
* - Some format-specific requirements such as quoting, indentation, and
|
||||
* comma-placement are automated
|
||||
*
|
||||
* Basic API calling sequence:
|
||||
*
|
||||
* util_fmt_init() => Select output format
|
||||
* util_fmt_obj_start() => Start a new object or list
|
||||
* util_fmt_pair() => Emit a key-value pair
|
||||
* util_fmt_obj_end() => End the latest object or list
|
||||
* util_fmt_exit() => Cleanup
|
||||
*
|
||||
* Note:
|
||||
* - Supported data elements are objects, lists and key-value pairs (mappings)
|
||||
* - Scalars are only supported as part of a mapping
|
||||
* - For CSV output and key filtering, mapping keys must be unique - this can
|
||||
* be achieved either by choosing unique key names or by including object
|
||||
* names via the FMT_PREFIX flag
|
||||
* - For CSV output, at least one object or list with the FMT_ROW flag must be
|
||||
* emitted
|
||||
* - Common tool-specific meta-information such as API-level, tool version,
|
||||
* etc. is automatically added to the output
|
||||
*/
|
||||
|
||||
#ifndef LIB_UTIL_FMT_H
|
||||
#define LIB_UTIL_FMT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Flag value for default behavior (all flag types). */
|
||||
#define FMT_DEFAULT 0
|
||||
|
||||
/* Names of supported output format types. */
|
||||
#define FMT_TYPE_NAMES "json json-seq pairs csv"
|
||||
|
||||
/**
|
||||
* enum util_fmt_t - Output format types.
|
||||
* @FMT_JSON: JavaScript Object Notation output data structure
|
||||
* @FMT_JSONSEQ: Sequence of JSON data structures according to RFC7464
|
||||
* @FMT_PAIRS: Textual key=value pairs
|
||||
* @FMT_CSV: Comma-separated-values output
|
||||
*
|
||||
* Use these types with util_fmt_init() to control the output format.
|
||||
*/
|
||||
enum util_fmt_t {
|
||||
FMT_JSON,
|
||||
FMT_JSONSEQ,
|
||||
FMT_PAIRS,
|
||||
FMT_CSV,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum util_fmt_flags_t - Format control flags.
|
||||
* @FMT_NOPREFIX: (pairs) Remove object hierarchy prefix from keys
|
||||
* @FMT_KEEPINVAL: (all) Print mappings even if value is marked as invalid
|
||||
* Values will be replaced with null (JSON) or an empty
|
||||
* string
|
||||
* @FMT_QUOTEALL: (all) Add quotes to all mapping values
|
||||
* @FMT_FILTER: (all) Ignore keys not announced via util_fmt_add_key()
|
||||
* @FMT_HANDLEINT: (json) Ensure correct JSON closure when interrupted
|
||||
* @FMT_NOMETA: (all) Do not emit tool meta-data
|
||||
* @FMT_WARN: (all) Warn about incorrect API usage
|
||||
*
|
||||
* Use these flags with util_fmt_init() to control generic aspects.
|
||||
*/
|
||||
enum util_fmt_flags_t {
|
||||
FMT_NOPREFIX = (1 << 0),
|
||||
FMT_KEEPINVAL = (1 << 1),
|
||||
FMT_QUOTEALL = (1 << 2),
|
||||
FMT_FILTER = (1 << 3),
|
||||
FMT_HANDLEINT = (1 << 4),
|
||||
FMT_NOMETA = (1 << 5),
|
||||
FMT_WARN = (1 << 6),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum util_fmt_oflags_t - Object flags.
|
||||
* @FMT_LIST: (all) Object is a list
|
||||
* @FMT_ROW: (csv) Start a new CSV row with this object
|
||||
* @FMT_PREFIX: (all) Include object name in key prefix for CSV headings
|
||||
* and filter keys
|
||||
*
|
||||
* Use these flags with util_fmt_obj_start() to control object related
|
||||
* aspects.
|
||||
*/
|
||||
enum util_fmt_oflags_t {
|
||||
FMT_LIST = (1 << 0),
|
||||
FMT_ROW = (1 << 1),
|
||||
FMT_PREFIX = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* enum util_fmt_mflags_t - Mapping flags.
|
||||
* @FMT_QUOTE: (all) Quote value
|
||||
* @FMT_INVAL: (all) Mark value as invalid
|
||||
* @FMT_PERSIST: (csv) Keep value across CSV rows until overwritten
|
||||
*
|
||||
* Use these flags with util_fmt_pair() to control mapping related aspects.
|
||||
*/
|
||||
enum util_fmt_mflags_t {
|
||||
FMT_QUOTE = (1 << 0),
|
||||
FMT_INVAL = (1 << 1),
|
||||
FMT_PERSIST = (1 << 2),
|
||||
};
|
||||
|
||||
/**
|
||||
* util_fmt_init() - Initialize output formatter.
|
||||
* @fd : Output file descriptor
|
||||
* @type : Output format type
|
||||
* @flags: Formatting parameters
|
||||
* @api_level: Output format level indicator
|
||||
*
|
||||
* Prepare for writing formatted output with the given @type to @fd. Additional
|
||||
* @flags can be specified to control certain output aspects (see &enum
|
||||
* util_fmt_flags_t).
|
||||
*
|
||||
* @api_level represents an application-specific output format version number:
|
||||
* this number starts at 1 and must be increased whenever an incompatible format
|
||||
* change is introduced, e.g. when a non-optional object or mapping is removed
|
||||
* or used for different data.
|
||||
*/
|
||||
void util_fmt_init(FILE *fd, enum util_fmt_t type, unsigned int flags,
|
||||
int api_level);
|
||||
|
||||
/**
|
||||
* util_fmt_exit() - Release resources used by output formatter.
|
||||
*
|
||||
* Release all resources currently in use by the output formatter.
|
||||
*/
|
||||
void util_fmt_exit(void);
|
||||
|
||||
/**
|
||||
* util_fmt_name_to_type() - Convert format name to type identifier.
|
||||
* @name: Format name
|
||||
* @type: Pointer to resulting format type identifier
|
||||
*
|
||||
* Search supported output format types for a type with associated @name. If
|
||||
* found, store resulting type identifier in @type.
|
||||
*
|
||||
* Return: %true if type is found, %false otherwise.
|
||||
*/
|
||||
bool util_fmt_name_to_type(const char *name, enum util_fmt_t *type);
|
||||
|
||||
/**
|
||||
* util_fmt_set_indent() - Set indentation parameters.
|
||||
* @base : Base indentation level to apply to all output lines (default 0)
|
||||
* @width : Number of indentation characters per intendation level (default 2)
|
||||
* @ind_char: Indentation characters to use (default space).
|
||||
*/
|
||||
void util_fmt_set_indent(unsigned int base, unsigned int width, char ind_char);
|
||||
|
||||
/**
|
||||
* util_fmt_add_key() - Register expected mapping keys.
|
||||
* @fmt: Format string to generate key
|
||||
*
|
||||
* Register a mapping key before the associated key-value pair is emitted.
|
||||
*
|
||||
* Use this function together with format control flag @FMT_FILTER to ignore all
|
||||
* key-value pairs for which the key has not been registered. This can be
|
||||
* useful to allow for dynamically configured filtering of output based on
|
||||
* a static list of emitted mappings.
|
||||
*
|
||||
* When creating CSV output, use this function to register all column keys
|
||||
* in advance to enable a stable column list in case of rows that do not
|
||||
* provide data for all columns.
|
||||
*/
|
||||
void util_fmt_add_key(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* util_fmt_obj_start() - Start a new data object.
|
||||
* @oflags: Flags controlling aspects of this object.
|
||||
* @fmt : Format string for generating an object name or %NULL.
|
||||
*
|
||||
* Use this function to start a new object in output data. Depending on
|
||||
* @oflags, the new object represents either a normal object or a list. @oflags
|
||||
* can also be used to indicated that an object corresponds to a new row of
|
||||
* CSV data. If @fmt is non-%NULL, the resulting name is used in a format
|
||||
* type specified way:
|
||||
*
|
||||
* Pairs:
|
||||
* - Object names are reflected as dot-separated component in the mapping
|
||||
* prefix, e.g. 'a.b.key=value'
|
||||
* - An index is generated for mappings and objects that are part of list,
|
||||
* e.g. 'a.b[1].key=value'
|
||||
* JSON:
|
||||
* - Object names are reflected as key-object mappings, e.g.
|
||||
* <name>: { }
|
||||
* - Required commas between objects and mappings are automatically generated
|
||||
* CSV:
|
||||
* - Object names and the list type flag have no effect
|
||||
* - When flag @FMT_ROW is specified, a CSV row will be emitted when
|
||||
* util_fmt_obj_end() is called for the associated object
|
||||
*/
|
||||
void util_fmt_obj_start(unsigned int oflags, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* util_fmt_obj_end() - Announce the end of the latest data object started.
|
||||
*
|
||||
* Each object started with util_fmt_obj_start() must be ended with an
|
||||
* associated util_fmt_obj_end() call.
|
||||
*/
|
||||
void util_fmt_obj_end(void);
|
||||
|
||||
/**
|
||||
* util_fmt_pair() - Emit a key-value pair.
|
||||
* @mflags: Flags controlling this pair.
|
||||
* @key : Key for this pair, excluding prefix.
|
||||
* @fmt : Format string used to generated the pair value.
|
||||
*
|
||||
* Emit a key-value pair with the specified @key and the value that results
|
||||
* from format string @fmt.
|
||||
*
|
||||
* Notes:
|
||||
* - For JSON, a mapping can only occur after util_fmt_obj_start()
|
||||
* - For CSV, each @key must be unique, either by choosing unique key names
|
||||
* or by including object names as prefix via the use of FMT_PREFIX in
|
||||
* parent objects
|
||||
*/
|
||||
void util_fmt_pair(unsigned int mflags, const char *key, const char *fmt, ...);
|
||||
|
||||
#endif /* LIB_UTIL_FMT_H */
|
||||
@@ -127,7 +127,9 @@ do { \
|
||||
int __util_vsprintf(const char *func, const char *file, int line,
|
||||
char *str, const char *fmt, va_list ap);
|
||||
char *util_strcat_realloc(char *str1, const char *str2);
|
||||
void util_concatf(char **str1, const char *fmt, ...);
|
||||
void util_str_toupper(char *str);
|
||||
void util_str_tolower(char *str);
|
||||
|
||||
char *util_strstrip(char *s);
|
||||
size_t util_strlcpy(char *dest, const char *src, size_t size);
|
||||
|
||||
@@ -18,7 +18,11 @@
|
||||
#define UTIL_LOCKFILE_ERR 4 /* Other, unexpected error conditions */
|
||||
|
||||
int util_lockfile_lock(char *lockfile, int retries);
|
||||
int util_lockfile_lock_cw(char *lockfile, int retries, unsigned int waitinc,
|
||||
unsigned int maxwait);
|
||||
int util_lockfile_parent_lock(char *lockfile, int retries);
|
||||
int util_lockfile_parent_lock_cw(char *lockfile, int retries,
|
||||
unsigned int waitinc, unsigned int maxwait);
|
||||
|
||||
int util_lockfile_release(char *lockfile);
|
||||
int util_lockfile_parent_release(char *lockfile);
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
||||
struct util_proc_part_entry {
|
||||
dev_t device;
|
||||
size_t blockcount;
|
||||
@@ -27,6 +26,12 @@ struct util_proc_dev_entry {
|
||||
char *name;
|
||||
};
|
||||
|
||||
#define UTIL_PROC_DEV_ENTRY_DASD "dasd"
|
||||
#define UTIL_PROC_DEV_ENTRY_VIRTBLK "virtblk"
|
||||
#define UTIL_PROC_DEV_ENTRY_SD "sd"
|
||||
#define UTIL_PROC_DEV_ENTRY_BLKEXT "blkext"
|
||||
#define UTIL_PROC_DEV_ENTRY_MD "md"
|
||||
|
||||
int util_proc_part_get_entry(dev_t device, struct util_proc_part_entry *entry);
|
||||
void util_proc_part_free_entry(struct util_proc_part_entry *entry);
|
||||
int util_proc_dev_get_entry(dev_t dev, int blockdev,
|
||||
|
||||
@@ -1,440 +0,0 @@
|
||||
/*
|
||||
* Certificate functions and definitions.
|
||||
*
|
||||
* Copyright IBM Corp. 2022
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
#ifndef LIBPV_CERT_H
|
||||
#define LIBPV_CERT_H
|
||||
|
||||
#include <openssl/x509v3.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
#include "libpv/common.h"
|
||||
|
||||
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
|
||||
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
|
||||
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_POUGHKEEPSIE "Poughkeepsie"
|
||||
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME_ARMONK "Armonk"
|
||||
#define PV_IBM_Z_SUBJECT_ORGANIZATIONAL_UNIT_NAME_SUFFIX "Key Signing Service"
|
||||
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
|
||||
#define PV_IBM_Z_SUBJECT_STATE "New York"
|
||||
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
|
||||
|
||||
/* Minimum security level for the keys/certificates used to establish a chain of
|
||||
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
|
||||
* for details).
|
||||
*/
|
||||
#define PV_CERTS_SECURITY_LEVEL 2
|
||||
|
||||
/** pv_cert_init:
|
||||
*
|
||||
* Should not be called by user.
|
||||
* Use pv_init() instead which
|
||||
* calls this function during creation.
|
||||
*
|
||||
* Sets up data structures for caching CRLs.
|
||||
*/
|
||||
void pv_cert_init(void);
|
||||
|
||||
/** pv_cert_cleanup:
|
||||
*
|
||||
* Should not be called by user.
|
||||
* Use pv_cleanup() instead which
|
||||
* calls this function during creation.
|
||||
*
|
||||
* Cleans up data structures for caching CRLs.
|
||||
*/
|
||||
void pv_cert_cleanup(void);
|
||||
|
||||
#define PV_CERT_ERROR g_quark_from_static_string("pv-cert-error-quark")
|
||||
typedef enum {
|
||||
PV_CERT_ERROR_CERT_REVOKED,
|
||||
PV_CERT_ERROR_CERT_SIGNATURE_INVALID,
|
||||
PV_CERT_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
|
||||
PV_CERT_ERROR_CRL_DOWNLOAD_FAILED,
|
||||
PV_CERT_ERROR_CRL_SIGNATURE_INVALID,
|
||||
PV_CERT_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
|
||||
PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||
PV_CERT_ERROR_INTERNAL,
|
||||
PV_CERT_ERROR_INVALID_PARM,
|
||||
PV_CERT_ERROR_INVALID_SIGNATURE_ALGORITHM,
|
||||
PV_CERT_ERROR_INVALID_VALIDITY_PERIOD,
|
||||
PV_CERT_ERROR_LOAD_CRL,
|
||||
PV_CERT_ERROR_LOAD_DEFAULT_CA,
|
||||
PV_CERT_ERROR_LOAD_ROOT_CA,
|
||||
PV_CERT_ERROR_MALFORMED_CERTIFICATE,
|
||||
PV_CERT_ERROR_MALFORMED_ROOT_CA,
|
||||
PV_CERT_ERROR_NO_CRL,
|
||||
PV_CERT_ERROR_NO_CRLDP,
|
||||
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
||||
PV_CERT_ERROR_NO_PUBLIC_KEY,
|
||||
PV_CERT_ERROR_READ_CERTIFICATE,
|
||||
PV_CERT_ERROR_READ_CRL,
|
||||
PV_CERT_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
||||
PV_CERT_ERROR_SKID_AKID_MISMATCH,
|
||||
PV_CERT_ERROR_VERIFICATION_FAILED,
|
||||
PV_CERT_ERROR_WRONG_CA_USED,
|
||||
} PvCertErrors;
|
||||
|
||||
/** PvX509WithPath - X509 certificate associated with a path
|
||||
*/
|
||||
typedef struct {
|
||||
X509 *cert;
|
||||
char *path;
|
||||
} PvX509WithPath;
|
||||
|
||||
/** pv_x509_with_path_new:
|
||||
*
|
||||
* @cert: X509 certificate
|
||||
* @path: Path of that X509 certificate
|
||||
*
|
||||
* Returns: (nullable) (transfer full): new X509 with path
|
||||
*/
|
||||
PvX509WithPath *pv_x509_with_path_new(X509 *cert, const char *path);
|
||||
|
||||
/** pv_x509_with_path_free:
|
||||
*
|
||||
* Frees the path and the PvX509WithPath; Decreases the refcount of the X509
|
||||
*/
|
||||
void pv_x509_with_path_free(PvX509WithPath *cert);
|
||||
|
||||
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
|
||||
typedef STACK_OF(X509) STACK_OF_X509;
|
||||
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
|
||||
typedef GSList PvCertWithPathList;
|
||||
|
||||
typedef struct {
|
||||
X509 *cert;
|
||||
STACK_OF_X509_CRL *crls;
|
||||
} PvX509Pair;
|
||||
|
||||
/** pv_x509_pair_new_take:
|
||||
* @cert: ptr to X509
|
||||
* @crls: ptr to CRLs
|
||||
*
|
||||
* Takes a X509 and the associated CRLs and builds a pair.
|
||||
* Both, *cert and *crls will be NULL afterwards, and owned by the pair.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): New PvX509Pair
|
||||
*/
|
||||
PvX509Pair *pv_x509_pair_new_take(X509 **cert, STACK_OF_X509_CRL **crls);
|
||||
|
||||
/** pv_x509_pair_free:
|
||||
*
|
||||
* Decreases the refcount of the X509 and crls.
|
||||
* Frees the PvX509Pair.
|
||||
*/
|
||||
void pv_x509_pair_free(PvX509Pair *pair);
|
||||
|
||||
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
|
||||
void STACK_OF_X509_free(STACK_OF_X509 *stack);
|
||||
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
|
||||
|
||||
/** pv_x509_from_pem_der_data:
|
||||
*
|
||||
* @data: GBytes containing the cert in PEM format
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): X509 cert
|
||||
*/
|
||||
X509 *pv_x509_from_pem_der_data(GBytes *data, GError **error);
|
||||
|
||||
/** pv_x509_get_ec_pubkey:
|
||||
*
|
||||
* @cert: X509 to extract elliptic curve pubkey from
|
||||
* @nid: numerical identifier of the expected curve
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): corresponding pupkey for the given certificate
|
||||
*/
|
||||
EVP_PKEY *pv_x509_get_ec_pubkey(X509 *cert, int nid, GError **error);
|
||||
|
||||
/** pv_get_ec_pubkeys:
|
||||
*
|
||||
* @certs_with_path: List of PvX509WithPath
|
||||
* @nid: numerical identifier of the expected curve
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): List of corresponding public keys for the given certificate
|
||||
*/
|
||||
GSList *pv_get_ec_pubkeys(PvCertWithPathList *certs_with_path, int nid, GError **error);
|
||||
|
||||
/* pv_load_certificates:
|
||||
*
|
||||
* @cert_paths: list of cert paths.
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* @cert_paths must contain at least one element, otherwise an error is
|
||||
* reported.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): List of PvX509WithPath corresponding to the given paths
|
||||
*/
|
||||
PvCertWithPathList *pv_load_certificates(char **cert_paths, GError **error);
|
||||
|
||||
/* pv_load_first_cert_from_file:
|
||||
*
|
||||
* @path: location of the x509
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* This function reads in only the first certificate and ignores all other. This
|
||||
* is only relevant for the PEM file format. For the host-key document and the
|
||||
* root CA this behavior is expected.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): PvX509WithPath corresponding to the given path
|
||||
*/
|
||||
X509 *pv_load_first_cert_from_file(const char *path, GError **error);
|
||||
|
||||
/* pv_load_first_crl_from_file:
|
||||
*
|
||||
* @path: location of the x509 CRL
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* This function reads in only the first CRL and ignores all other. This
|
||||
* is only relevant for the PEM file format.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): X509_CRL corresponding to the given path
|
||||
*/
|
||||
X509_CRL *pv_load_first_crl_from_file(const char *path, GError **error);
|
||||
|
||||
/** pv_store_setup_crl_download:
|
||||
*
|
||||
* @st: X509_STORE
|
||||
*/
|
||||
void pv_store_setup_crl_download(X509_STORE *st);
|
||||
|
||||
/** pv_load_first_crl_by_cert:
|
||||
* @cert: X509 to specify the download location.
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* This function returns the first X509_CRL found from the CRL distribution
|
||||
* points specified in @cert.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): x509 CRL corresponding to the given X509
|
||||
*/
|
||||
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error);
|
||||
|
||||
/** pv_try_load_crls_by_certs:
|
||||
*
|
||||
* @certs_with_path: List of PvX509WithPath
|
||||
*
|
||||
* Returns: (nullable) (transfer full): Stack of CRLs corresponding to the given X509
|
||||
*/
|
||||
STACK_OF_X509_CRL *pv_try_load_crls_by_certs(PvCertWithPathList *certs_with_path);
|
||||
|
||||
/** pv_store_setup:
|
||||
*
|
||||
* @root_ca_path: Location of the rootCA or NULL if SystemRoot CA shall be used
|
||||
* @crl_paths: List of CRL paths or NULL
|
||||
* @cert_with_crl_paths: List of (untrusted) X509 paths
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* The untrusted certs need to be verified before actually verifying a Host Key Document.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): X509_store with given input data.
|
||||
*
|
||||
*/
|
||||
X509_STORE *pv_store_setup(char *root_ca_path, char **crl_paths, char **cert_with_crl_paths,
|
||||
GError **error);
|
||||
|
||||
/** pv_get_x509_stack:
|
||||
*
|
||||
* x509_with_path_list: list of PvX509WithPath
|
||||
*
|
||||
* Returns: (nullable) (transfer full): Stack of X509 corresponding to the given x509 with path
|
||||
*/
|
||||
STACK_OF_X509 *pv_get_x509_stack(const GSList *x509_with_path_list);
|
||||
|
||||
/** pv_init_store_ctx:
|
||||
*
|
||||
* @ctx: a uninitialized Store CTX
|
||||
* @trusted: X509_STORE with a trusted rootCA
|
||||
* @chain: untrusted X509s
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Can be called multiple times on the same context if X509_STORE_CTX_cleanup(ctx)
|
||||
* was called before.
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* -1 in failure
|
||||
*/
|
||||
int pv_init_store_ctx(X509_STORE_CTX *ctx, X509_STORE *trusted, STACK_OF_X509 *chain,
|
||||
GError **error) PV_NONNULL(1, 2, 3);
|
||||
|
||||
/** pv_init_store_ctx:
|
||||
*
|
||||
* @trusted: X509_STORE with a trusted rootCA
|
||||
* @chain: untrusted X509s
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): X509_STORE_CTX setup with the input data
|
||||
*/
|
||||
X509_STORE_CTX *pv_create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain, GError **error)
|
||||
PV_NONNULL(1, 2);
|
||||
/** pv_remove_ibm_signing_certs:
|
||||
*
|
||||
* @certs: Stack of X509s
|
||||
*
|
||||
* Returns: (transfer full):
|
||||
* List of all IBM Z signing key certificates in @certs and remove them
|
||||
* from the chain.
|
||||
* Empty stack if no IBM Z signing key is found.
|
||||
*/
|
||||
STACK_OF_X509 *pv_remove_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||
|
||||
/** pv_c2b_name:
|
||||
*
|
||||
* Workaround to fix the mismatch between issuer name of the
|
||||
* IBM Z signing CRLs and the IBM Z signing key subject name.
|
||||
*
|
||||
* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
|
||||
* ordered. The problem is that our certificates are not consistent in the order
|
||||
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
|
||||
*
|
||||
* This function tries to reorder the name attributes such that
|
||||
* further OpenSSL calls can work with it. The caller is
|
||||
* responsible to free the returned value.
|
||||
*/
|
||||
X509_NAME *pv_c2b_name(const X509_NAME *name);
|
||||
|
||||
/** pv_verify_host_key:
|
||||
*
|
||||
* @host_key: X509 to be verified
|
||||
* @issuer_pairs: IBM signing key X509+CRLs Pairs used for verification
|
||||
* @level: Security level. see PV_CERTS_SECURITY_LEVEL
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns:
|
||||
* 0 if Host key could be verified with one of the IBM signing keys
|
||||
* -1 if no IBM signing key could verify the authenticity of the given host key
|
||||
*
|
||||
*/
|
||||
int pv_verify_host_key(X509 *host_key, GSList *issuer_pairs, int verify_flags, int level,
|
||||
GError **error);
|
||||
|
||||
/** pv_verify_cert:
|
||||
*
|
||||
* @ctx: trusted store ctx used for verification
|
||||
* @cert: X509 to be verified
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Cannot be used to verify host keys with IBM signing keys, as IBM signing
|
||||
* keys are no intermediate CAs. Use pv_verify_host_key() instead.
|
||||
*
|
||||
* Returns:
|
||||
* 0 if @cert could be verified
|
||||
* -1 if @cert could not be verified
|
||||
*/
|
||||
int pv_verify_cert(X509_STORE_CTX *ctx, X509 *cert, GError **error) PV_NONNULL(1, 2);
|
||||
|
||||
/** pv_check_crl_valid_for_cert:
|
||||
*
|
||||
* @crl: CRL to be verified
|
||||
* @cert: Cert that probably issued the given CRL
|
||||
* @verify_flags: X509 Verification flags (X509_V_FLAG_<TYPE>)
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Verify whether a revocation list @crl is valid and is issued by @cert. For
|
||||
* this multiple steps must be done:
|
||||
*
|
||||
* 1. verify issuer of the CRL matches with the suject name of @cert
|
||||
* 2. verify the validity period of the CRL
|
||||
* 3. verify the signature of the CRL
|
||||
*
|
||||
* Important: This function does not verify whether @cert is allowed to issue a
|
||||
* CRL.
|
||||
*
|
||||
* Returns:
|
||||
* 0 if @crl is valid and issued by @cert
|
||||
* -1 otherwise
|
||||
*/
|
||||
int pv_verify_crl(X509_CRL *crl, X509 *cert, int verify_flags, GError **error);
|
||||
|
||||
/** pv_check_chain_parameters:
|
||||
*
|
||||
* @chain: chain of trust to be validated
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Verifies that chain has at least a RootCA ans intermediate CA
|
||||
* and logs the used ROD CA subject
|
||||
*
|
||||
* Returns:
|
||||
* 0 @chain is valid
|
||||
* -1 otherwise
|
||||
*/
|
||||
int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error);
|
||||
|
||||
/** pv_store_set_verify_param:
|
||||
*
|
||||
* @store: X509_STORE to set parameters
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* -1 on failure
|
||||
*/
|
||||
int pv_store_set_verify_param(X509_STORE *store, GError **error);
|
||||
|
||||
/** pv_store_ctx_find_valid_crls:
|
||||
*
|
||||
* @ctx: STORE_CTX for searching CRLs
|
||||
* @cert: X509 to match CRLs aggainst
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): STACK of CRLs related to given @crl fin @ctx
|
||||
*/
|
||||
STACK_OF_X509_CRL *pv_store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert, GError **error)
|
||||
PV_NONNULL(1, 2);
|
||||
|
||||
/** pv_verify_host_key_doc:
|
||||
*
|
||||
* @host_key_certs_with_path: X509s to be verified
|
||||
* @trusted. X509_STORE with a rusted RootCA
|
||||
* @untrusted_certs: STACK OF untrusted X509s
|
||||
* @online: true if CRLs shall be downloaded
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns:
|
||||
* 0 if all given HKDs could be verified using the chain of trust.
|
||||
* -1 otherwise
|
||||
*/
|
||||
int pv_verify_host_key_doc(PvCertWithPathList *host_key_certs_with_path, X509_STORE *trusted,
|
||||
STACK_OF_X509 *untrusted_certs, gboolean online, GError **error)
|
||||
PV_NONNULL(1, 2, 3);
|
||||
|
||||
/** pv_verify_host_key_docs_by_path:
|
||||
*
|
||||
* @host_key_paths: locations of X509 to be verified
|
||||
* @optional_root_ca_path: rootCA location or NULL if Default shall be used
|
||||
* @optional_crl_paths: locations of CRLs or NULL
|
||||
* @untrusted_cert_paths: locations of IntermediateCAs including the IBM signing key
|
||||
* @online: true if CRLs shall be downloaded
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns:
|
||||
* 0 if all given HKDs could be verfied using the chain of trust.
|
||||
* -1 otherwise
|
||||
*/
|
||||
int pv_verify_host_key_docs_by_path(char **host_key_paths, char *optional_root_ca_path,
|
||||
char **optional_crl_paths, char **untrusted_cert_paths,
|
||||
gboolean online, GError **error) PV_NONNULL(1, 4);
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509WithPath, pv_x509_with_path_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509Pair, pv_x509_pair_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
|
||||
|
||||
#endif /* LIBPV_CERT_H */
|
||||
@@ -14,22 +14,6 @@
|
||||
* the glib version is supported
|
||||
*/
|
||||
#include "libpv/glib-helper.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libpv/openssl-compat.h"
|
||||
#include "libpv/macros.h"
|
||||
|
||||
/** pv_init:
|
||||
*
|
||||
* Must be called before any libpv call.
|
||||
*/
|
||||
int pv_init(void);
|
||||
|
||||
/** pv_cleanup:
|
||||
*
|
||||
* Must be called when done with using libpv.
|
||||
*/
|
||||
void pv_cleanup(void);
|
||||
|
||||
#endif /* LIBPV_COMMON_H */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#include "libpv/common.h"
|
||||
#define PV_NONNULL(...)
|
||||
|
||||
typedef struct pv_cipher_parms {
|
||||
const EVP_CIPHER *cipher;
|
||||
@@ -26,17 +27,6 @@ typedef struct pv_cipher_parms {
|
||||
};
|
||||
} PvCipherParms;
|
||||
|
||||
typedef union {
|
||||
struct {
|
||||
uint8_t x[80];
|
||||
uint8_t y[80];
|
||||
};
|
||||
uint8_t data[160];
|
||||
} PvEcdhPubKey;
|
||||
G_STATIC_ASSERT(sizeof(PvEcdhPubKey) == 160);
|
||||
|
||||
typedef GSList PvEvpKeyList;
|
||||
|
||||
enum PvCryptoMode {
|
||||
PV_ENCRYPT,
|
||||
PV_DECRYPT,
|
||||
@@ -61,42 +51,6 @@ char *pv_get_openssl_errors(void);
|
||||
*/
|
||||
int pv_BIO_reset(BIO *b);
|
||||
|
||||
/**
|
||||
* pv_generate_rand_data:
|
||||
* @size: number of generated random bytes using a crypographically secure pseudo random generator
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Creates a new #GBytes with @size random bytes using a cryptographically
|
||||
* secure pseudo random generator.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
|
||||
*/
|
||||
GBytes *pv_generate_rand_data(size_t size, GError **error);
|
||||
|
||||
/**
|
||||
* pv_generate_key:
|
||||
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure key should be generated
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Creates a random key for @cipher using a cryptographically secure pseudo
|
||||
* random generator.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
|
||||
*/
|
||||
GBytes *pv_generate_key(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
|
||||
|
||||
/**
|
||||
* pv_generate_iv:
|
||||
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure IV should be generated
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Creates a random IV for @cipher using a cryptographically secure pseudo
|
||||
* random generator.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
|
||||
*/
|
||||
GBytes *pv_generate_iv(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
|
||||
|
||||
/* Symmetric en/decryption functions */
|
||||
|
||||
/**
|
||||
@@ -135,7 +89,7 @@ int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherP
|
||||
* @derived_key_len: size of the output key
|
||||
* @key: input key
|
||||
* @salt: salt for the extraction
|
||||
* @info: infor for the expansion
|
||||
* @info: info for the expansion
|
||||
* @md: EVP mode of operation
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
@@ -147,54 +101,15 @@ int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherP
|
||||
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
|
||||
const EVP_MD *md, GError **error) PV_NONNULL(2, 3, 4, 5);
|
||||
|
||||
/** pv_generate_ec_key:
|
||||
*
|
||||
* @nid: Numerical identifier of the curve
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): new random key based on the given curve
|
||||
*/
|
||||
EVP_PKEY *pv_generate_ec_key(int nid, GError **error);
|
||||
|
||||
/** pv_evp_pkey_to_ecdh_pub_key:
|
||||
*
|
||||
* @key: input key in EVP_PKEY format
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: the public part of the input @key in ECDH format.
|
||||
*/
|
||||
PvEcdhPubKey *pv_evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **error) PV_NONNULL(1);
|
||||
|
||||
/** pv_derive_exchange_key:
|
||||
* @cust: Customer Key
|
||||
* @host: Host key
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): Shared Secret of @cust and @host
|
||||
*/
|
||||
GBytes *pv_derive_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **error) PV_NONNULL(1, 2);
|
||||
|
||||
GQuark pv_crypto_error_quark(void);
|
||||
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
|
||||
typedef enum {
|
||||
PV_CRYPTO_ERROR_DERIVE,
|
||||
PV_CRYPTO_ERROR_HKDF_FAIL,
|
||||
PV_CRYPTO_ERROR_INTERNAL,
|
||||
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||
PV_CRYPTO_ERROR_KEYGENERATION,
|
||||
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||
PV_CRYPTO_ERROR_READ_FILE,
|
||||
PV_CRYPTO_ERROR_NO_MATCH_TAG,
|
||||
} PvCryptoErrors;
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
* Libcurl utils
|
||||
*
|
||||
* Copyright IBM Corp. 2022
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
#ifndef LIBPV_CURL_H
|
||||
#define LIBPV_CURL_H
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "libpv/common.h"
|
||||
|
||||
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
|
||||
#define CRL_DOWNLOAD_MAX_SIZE 0x100000
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
|
||||
|
||||
/** curl_download:
|
||||
* @url: URL to specify location of data
|
||||
* @timeout_ms: time to wait until fail
|
||||
* @max_size: Maximum size of the downloaded data
|
||||
* @error: return location for a GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): Downloaded data as #GByteArray
|
||||
*/
|
||||
GByteArray *curl_download(const char *url, long timeout_ms, uint max_size, GError **err);
|
||||
|
||||
/** pv_curl_init:
|
||||
*
|
||||
* Should not be called by user.
|
||||
* Use pv_init() instead which
|
||||
* calls this function during creation.
|
||||
*/
|
||||
int pv_curl_init(void);
|
||||
|
||||
/** pv_curl_cleanup:
|
||||
*
|
||||
* Should not be called by user.
|
||||
* Use pv_cleanup() instead which
|
||||
* calls this function during creation.
|
||||
*/
|
||||
void pv_curl_cleanup(void);
|
||||
|
||||
#define PV_CURL_ERROR g_quark_from_static_string("pv-curl-error-quark")
|
||||
typedef enum {
|
||||
PV_CURL_ERROR_CURL_INIT_FAILED,
|
||||
PV_CURL_ERROR_DOWNLOAD_FAILED,
|
||||
} PvCurlErrors;
|
||||
|
||||
#endif /* LIBPV_CURL_H */
|
||||
@@ -28,8 +28,6 @@
|
||||
#include <gmodule.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libpv/macros.h"
|
||||
|
||||
#ifdef __clang__
|
||||
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
|
||||
DO_PRAGMA(clang diagnostic push) \
|
||||
@@ -40,6 +38,8 @@
|
||||
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define DO_PRAGMA(x) _Pragma(#x)
|
||||
|
||||
#define pv_wrapped_g_assert(__expr) g_assert(__expr)
|
||||
|
||||
/** pv_sec_gbytes_new_take:
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Hashing definitions.
|
||||
*
|
||||
* Copyright IBM Corp. 2022
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
#ifndef LIBPV_HASH_H
|
||||
#define LIBPV_HASH_H
|
||||
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
#include "libpv/common.h"
|
||||
|
||||
/** pv_digest_ctx_new:
|
||||
* @md: mode of digest, e.g. #EVP_sha256()
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): a new #EVP_MD_CTX, or %NULL in case of an error
|
||||
*/
|
||||
EVP_MD_CTX *pv_digest_ctx_new(const EVP_MD *md, GError **error);
|
||||
|
||||
/** pv_digest_ctx_update:
|
||||
* @ctx: EVP_MD_CTX to add data
|
||||
* @data: #GBytes to add to the context
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Adds @data to the digest context. Can be called multiple times.
|
||||
*
|
||||
* Returns: 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int pv_digest_ctx_update(EVP_MD_CTX *ctx, GBytes *data, GError **error);
|
||||
|
||||
/** pv_digest_ctx_update_raw:
|
||||
* @ctx: #EVP_MD_CTX to add data
|
||||
* @buf: data to add to the context
|
||||
* @size: size of @buf
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Adds @buf to the digest context. Can be called multiple times.
|
||||
*
|
||||
* Returns: 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int pv_digest_ctx_update_raw(EVP_MD_CTX *ctx, const uint8_t *buf, size_t size, GError **error);
|
||||
|
||||
/** pv_digest_ctx_finalize:
|
||||
* @ctx: #EVP_MD_CTX with data to digest
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Calculates the digest of all previously added data. Do not use @ctx afterwards.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): Digest of all data added before as #GBytes, or NULL in case of error.
|
||||
*/
|
||||
GBytes *pv_digest_ctx_finalize(EVP_MD_CTX *ctx, GError **error);
|
||||
|
||||
/** pv_sha256_hash:
|
||||
* @buf: data for which a sha256 hash sould be calculated
|
||||
* @size: size of @buf
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Shorthand for initializing a sha256-digest ctx, updating, and finalizing.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): SHA256 of @buf as #GBytes, or NULL in case of error.
|
||||
*/
|
||||
GBytes *pv_sha256_hash(uint8_t *buf, size_t size, GError **error);
|
||||
|
||||
/** pv_hmac_ctx_new:
|
||||
* @key: key used for the HMAC
|
||||
* @md: mode of digest, e.g. #EVP_sha512()
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Returns: (nullable) (transfer full): New #HMAC_CTX or NULL in case of error
|
||||
*/
|
||||
HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error);
|
||||
|
||||
/** pv_hmac_ctx_update_raw:
|
||||
* @ctx: #HMAC_CTX to add data
|
||||
* @buf: data to add to the context
|
||||
* @size: size of @buf
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Adds @buf to the HMAC context. Can be called multiple times.
|
||||
*
|
||||
* Returns: 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *data, size_t size, GError **error);
|
||||
|
||||
/** pv_hmac_ctx_update:
|
||||
* @ctx: #HMAC_CTX to add data
|
||||
* @data: #GBytes to add to the context
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Adds @data to the HMAC context. Can be called multiple times.
|
||||
*
|
||||
* Returns: 0 in case of success, -1 otherwise.
|
||||
*/
|
||||
|
||||
int pv_hmac_ctx_update(HMAC_CTX *ctx, GBytes *data, GError **error);
|
||||
|
||||
/** pv_hmac_ctx_finalize:
|
||||
* @ctx: #HMAC_CTX with data to digest
|
||||
* @error: return location for a #GError
|
||||
*
|
||||
* Calculates the HMAC of all previously added data. Do not use @ctx afterwards.
|
||||
*
|
||||
* Returns: (nullable) (transfer full): HMAC of all data added before as #GBytes, or NULL in case of error.
|
||||
*/
|
||||
GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error);
|
||||
|
||||
#define PV_HASH_ERROR g_quark_from_static_string("pv-crypro-error-quark")
|
||||
typedef enum {
|
||||
PV_HASH_ERROR_INTERNAL,
|
||||
} PvHashErrors;
|
||||
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
|
||||
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(HMAC_CTX, HMAC_CTX_free)
|
||||
|
||||
#endif /* LIBPV_HASH_H */
|
||||
@@ -1,21 +0,0 @@
|
||||
/*
|
||||
* Libpv common macro definitions.
|
||||
*
|
||||
* Copyright IBM Corp. 2022
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*
|
||||
*/
|
||||
#ifndef LIBPV_MACROS_H
|
||||
#define LIBPV_MACROS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PV_NONNULL(...)
|
||||
#define DO_PRAGMA(x) _Pragma(#x)
|
||||
|
||||
/* Most significant bit */
|
||||
#define PV_MSB(idx) ((uint64_t)1 << (63 - (idx)))
|
||||
|
||||
#endif /* LIBPV_MACROS_H */
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* OpenSSL compatibility utils
|
||||
*
|
||||
* Copyright IBM Corp. 2021
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
#ifndef LIBPV_OPENSSL_COMPAT_H
|
||||
#define LIBPV_OPENSSL_COMPAT_H
|
||||
|
||||
#include <openssl/opensslv.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509_vfy.h>
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x30000000L
|
||||
#define pv_X509_STORE_CTX_get_current_cert(ctx) X509_STORE_CTX_get_current_cert(ctx)
|
||||
#define pv_X509_STORE_CTX_get1_crls(ctx, nm) X509_STORE_CTX_get1_crls((ctx), (nm))
|
||||
#define pv_X509_STORE_set_lookup_crls(st, cb) X509_STORE_set_lookup_crls(st, cb)
|
||||
#elif OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
#define pv_X509_STORE_CTX_get_current_cert(ctx) \
|
||||
X509_STORE_CTX_get_current_cert((X509_STORE_CTX *)(ctx))
|
||||
#define pv_X509_STORE_CTX_get1_crls(ctx, nm) \
|
||||
X509_STORE_CTX_get1_crls((X509_STORE_CTX *)(ctx), (X509_NAME *)(nm))
|
||||
#define pv_X509_STORE_set_lookup_crls(st, cb) \
|
||||
X509_STORE_set_lookup_crls(st, (X509_STORE_CTX_lookup_crls_fn)(cb))
|
||||
#endif
|
||||
|
||||
#endif /* LIBPV_OPENSSL_COMPAT_H */
|
||||
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* PV/SE header definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2020
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
#ifndef LIBPV_SE_HDR_H
|
||||
#define LIBPV_SE_HDR_H
|
||||
|
||||
#include "libpv/common.h"
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include "boot/psw.h"
|
||||
#include "libpv/crypto.h"
|
||||
#include "libpv/macros.h"
|
||||
|
||||
/* Magic number which is used to identify the file containing the PV
|
||||
* header
|
||||
*/
|
||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||
#define PV_VERSION_1 0x00000100U
|
||||
|
||||
/* Plaintext control flags */
|
||||
/* dumping of the configuration is allowed */
|
||||
#define PV_PCF_ALLOW_DUMPING PV_MSB(34)
|
||||
/* prevent Ultravisor decryption during unpack operation */
|
||||
#define PV_PCF_NO_DECRYPTION PV_MSB(35)
|
||||
/* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||
#define PV_PCF_PCKMO_DEA_TDEA PV_MSB(56)
|
||||
/* PCKMO encrypt-AES-key functions allowed */
|
||||
#define PV_PCF_PCKMO_AES PV_MSB(57)
|
||||
/* PCKMO encrypt-ECC-key functions allowed */
|
||||
#define PV_PCF_PCKM_ECC PV_MSB(58)
|
||||
|
||||
/* maxima for the PV version 1 */
|
||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||
#define PV_V1_PV_HDR_MIN_SIZE \
|
||||
(sizeof(struct pv_hdr_head) + sizeof(struct pv_hdr_encrypted) + \
|
||||
sizeof(((struct pv_hdr *)0)->tag) + 1 * sizeof(struct pv_hdr_key_slot))
|
||||
#define PV_V1_PV_HDR_MAX_SIZE (2 * PAGE_SIZE)
|
||||
|
||||
#define PV_IMAGE_ENCR_KEY_SIZE 64
|
||||
|
||||
typedef struct pv_hdr_key_slot {
|
||||
uint8_t digest_key[SHA256_DIGEST_LENGTH];
|
||||
uint8_t wrapped_key[32];
|
||||
uint8_t tag[16];
|
||||
} __packed PvHdrKeySlot;
|
||||
|
||||
typedef struct pv_hdr_opt_item {
|
||||
uint32_t otype;
|
||||
uint8_t ibk[32];
|
||||
uint8_t data[];
|
||||
} __packed PvHdrOptItem;
|
||||
|
||||
/* integrity protected data (by GCM tag), but non-encrypted */
|
||||
struct pv_hdr_head {
|
||||
uint64_t magic;
|
||||
uint32_t version;
|
||||
uint32_t phs;
|
||||
uint8_t iv[12];
|
||||
uint32_t res1;
|
||||
uint64_t nks;
|
||||
uint64_t sea;
|
||||
uint64_t nep;
|
||||
uint64_t pcf;
|
||||
PvEcdhPubKey cust_pub_key;
|
||||
uint8_t pld[SHA512_DIGEST_LENGTH];
|
||||
uint8_t ald[SHA512_DIGEST_LENGTH];
|
||||
uint8_t tld[SHA512_DIGEST_LENGTH];
|
||||
} __packed;
|
||||
|
||||
/* Must not have any padding */
|
||||
struct pv_hdr_encrypted {
|
||||
uint8_t cust_comm_key[32];
|
||||
uint8_t img_enc_key_1[PV_IMAGE_ENCR_KEY_SIZE / 2];
|
||||
uint8_t img_enc_key_2[PV_IMAGE_ENCR_KEY_SIZE / 2];
|
||||
struct psw_t psw;
|
||||
uint64_t scf;
|
||||
uint32_t noi;
|
||||
uint32_t res2;
|
||||
};
|
||||
G_STATIC_ASSERT(sizeof(struct pv_hdr_encrypted) == 32 + 32 + 32 + sizeof(struct psw_t) + 8 + 4 + 4);
|
||||
|
||||
typedef struct pv_hdr {
|
||||
struct pv_hdr_head head;
|
||||
struct pv_hdr_key_slot *slots;
|
||||
struct pv_hdr_encrypted *encrypted;
|
||||
struct pv_hdr_opt_item **optional_items;
|
||||
uint8_t tag[16];
|
||||
} PvHdr;
|
||||
|
||||
#endif /* LIBPV_SE_HDR_H */
|
||||
@@ -15,8 +15,31 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_path.h"
|
||||
#include "lib/util_panic.h"
|
||||
#include "ipl_tools.h"
|
||||
|
||||
/*
|
||||
* Look up for the device in /sys/devices/ hierarchy.
|
||||
*
|
||||
* path must be PATH_MAX large and the value will be replaced in place
|
||||
*/
|
||||
static int device_sysfs_path(const char *device, char *path, const size_t path_size)
|
||||
{
|
||||
util_assert(device != NULL, "Internal error: device is NULL");
|
||||
util_assert(path != NULL, "Internal error: path is NULL");
|
||||
util_assert(path_size == PATH_MAX, "Internal error: path_size is '%zu', but must be '%zu'",
|
||||
path_size, PATH_MAX);
|
||||
char *buf = util_path_sysfs("block/%s/device", device);
|
||||
|
||||
if (!realpath(buf, path)) {
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
free(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the specified device number is a valid device number
|
||||
* which can be found in the /sys/bus/ccw/drivers/dasd-eckd/
|
||||
@@ -42,6 +65,26 @@ int ccw_is_device(const char *busid)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the specified device is a valid virtio subchannel device
|
||||
*/
|
||||
int ccw_is_virtio_device(const char *device)
|
||||
{
|
||||
char path[PATH_MAX] = { '\0' };
|
||||
unsigned virtio = 0;
|
||||
|
||||
if (device_sysfs_path(device, path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* The output has the following format:
|
||||
* /sys/devices/css0/0.0.0000/0.0.0000/virtio0/block/vda
|
||||
*/
|
||||
if (sscanf(path, "/sys/devices/css0/%*[0-9a-f.]/%*[0-9a-f.]/virtio%u", &virtio) != 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return CCW Bus ID (old sysfs)
|
||||
*/
|
||||
@@ -77,11 +120,9 @@ out_fclose:
|
||||
*/
|
||||
static int ccw_busid_get_sysfs_new(const char *device, char *busid)
|
||||
{
|
||||
char path[PATH_MAX], buf[4096];
|
||||
char path[PATH_MAX] = { '\0' };
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
snprintf(path, sizeof(path), "/sys/block/%s/device", device);
|
||||
if (realpath(path, buf) == NULL)
|
||||
if (device_sysfs_path(device, path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
@@ -89,7 +130,7 @@ static int ccw_busid_get_sysfs_new(const char *device, char *busid)
|
||||
* /sys/devices/css0/0.0.0119/0.0.3f19/block/dasda
|
||||
* /sys/devices/css0/0.0.0000/0.0.0000/virtio0/block/vda
|
||||
*/
|
||||
if (sscanf(buf, "/sys/devices/css0/%*[0-9a-f.]/%[0-9a-f.]", busid) != 1)
|
||||
if (sscanf(path, "/sys/devices/css0/%*[0-9a-f.]/%[0-9a-f.]", busid) != 1)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user