mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
119 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d8b8114e6f | |||
| c4e4b926b4 | |||
| 6324f62da7 | |||
| 3ade063ea2 | |||
| 92a3b30323 | |||
| 673ff375d9 | |||
| 4e2ebe0370 | |||
| 78b053326c | |||
| ab06a5d88a | |||
| a0a71efde0 | |||
| b4b2202ff5 | |||
| a26f61c4fe | |||
| a28b396d9e | |||
| 0012eaf68e | |||
| c22d282e67 | |||
| 071522f7d2 | |||
| ae7217806b | |||
| 9f6150db34 | |||
| b39bdfbf6e | |||
| 71fe58111c | |||
| 5e46632767 | |||
| 1bd64f5b0f | |||
| d311506dc4 | |||
| 08e4520a4f | |||
| 46fd42af0c | |||
| a8b0d7ace8 | |||
| a29b3c8997 | |||
| 27dce3317a | |||
| 4382901daa | |||
| bcbb6fcae6 | |||
| b16a6d4fe1 | |||
| 0d15a07c0a | |||
| 5394cd363c | |||
| 0906293cd8 | |||
| a9e13a2d69 | |||
| ee2c6d4160 | |||
| 455ad953a9 | |||
| 02a0d12988 | |||
| be47b51890 | |||
| 2677a4182d | |||
| 812df795c3 | |||
| a0d6edf03c | |||
| 81920f7cfd | |||
| 40dd63e2ac | |||
| a8579a0727 | |||
| 2ab27bdaf2 | |||
| 03fef264bd | |||
| 927a48e607 | |||
| fbcb3f384a | |||
| c7fe21b019 | |||
| 50a4740443 | |||
| 164d4817ec | |||
| abec41f514 | |||
| fcb503ea3c | |||
| 2eea614bbf | |||
| 3a13cb43f2 | |||
| e8fca95592 | |||
| b5604850ab | |||
| 18efac6306 | |||
| 18f8db2225 | |||
| f1a13749df | |||
| b5da337d1e | |||
| a67888f36a | |||
| e1f174ae22 | |||
| 7503d88b3b | |||
| 43039943cd | |||
| b2e02d202a | |||
| 1faa5d2957 | |||
| d62e075450 | |||
| 983233730c | |||
| ad024c06e1 | |||
| e2843232d5 | |||
| b79d17d233 | |||
| 11b401b599 | |||
| 69c5ee2e52 | |||
| 3ee625d74f | |||
| 832268ecb0 | |||
| 5fb6434548 | |||
| 5894e3f700 | |||
| e384f06014 | |||
| 1627c6a39f | |||
| bb8f17a7da | |||
| 8b3d3dd4bd | |||
| a5c04e5746 | |||
| c5ae1a41da | |||
| 970c697983 | |||
| cff4b0384f | |||
| 724f800dc5 | |||
| 4cdfe91ca9 | |||
| a44db0f367 | |||
| 03ddcd6267 | |||
| 5c468a220e | |||
| 4ba65eaa74 | |||
| 58cae4fecd | |||
| 9b84de4b0a | |||
| e679a88d88 | |||
| 6acf6ed76d | |||
| e7abf256f6 | |||
| 0d407904dd | |||
| 2238eb820f | |||
| 81013f0c70 | |||
| 697c5dc405 | |||
| e9deec4c62 | |||
| d60b7770fd | |||
| 70925f9aff | |||
| ef88fac874 | |||
| 4bd16ba8ea | |||
| f6a7da141c | |||
| 1bbd34e500 | |||
| c2f8988444 | |||
| d2990db15f | |||
| fd3d79335a | |||
| 07b3837e68 | |||
| 13a1227a02 | |||
| 52118a8d02 | |||
| ee89b850fe | |||
| 5160f41079 | |||
| 5b0115fdb4 | |||
| ae305b5158 |
@@ -0,0 +1,21 @@
|
|||||||
|
# Check https://editorconfig.org for details
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
tab_width = 8
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
shell_variant = bash # used by `shfmt`
|
||||||
|
|
||||||
|
[*.y{a,}ml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
+6
-2
@@ -5,7 +5,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Alexandra Winter
|
- Alexandra Winter
|
||||||
- Alexey Ishchuk
|
- Alexey Ishchuk
|
||||||
- Andreas Herrmann
|
- Andreas Herrmann
|
||||||
- Andre Wild
|
- André Wild
|
||||||
- Antoinette Kaschner
|
- Antoinette Kaschner
|
||||||
- Arnd Bergmann
|
- Arnd Bergmann
|
||||||
- Axel Wirbser
|
- Axel Wirbser
|
||||||
@@ -19,6 +19,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Clemens von Mann
|
- Clemens von Mann
|
||||||
- Colin Walters
|
- Colin Walters
|
||||||
- Dan Horak
|
- Dan Horak
|
||||||
|
- Dan Horák
|
||||||
- Despina Papadopoulou
|
- Despina Papadopoulou
|
||||||
- Dimitri John Ledkov
|
- Dimitri John Ledkov
|
||||||
- Eberhard Pasch
|
- Eberhard Pasch
|
||||||
@@ -38,6 +39,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Fritz Elfert
|
- Fritz Elfert
|
||||||
- Gerald Schaefer
|
- Gerald Schaefer
|
||||||
- Gerhard Tonn
|
- Gerhard Tonn
|
||||||
|
- Graham Inggs
|
||||||
- Guevenc Guelce
|
- Guevenc Guelce
|
||||||
- Hannes Reinecke
|
- Hannes Reinecke
|
||||||
- Hans-Joachim Picht
|
- Hans-Joachim Picht
|
||||||
@@ -52,7 +54,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Ingo Franzki
|
- Ingo Franzki
|
||||||
- Ingo Tuchscherer
|
- Ingo Tuchscherer
|
||||||
- Jan Glauber
|
- Jan Glauber
|
||||||
- Jan Hoeppner
|
- Jan Höppner
|
||||||
- Jan Willeke
|
- Jan Willeke
|
||||||
- Jason J. Herne
|
- Jason J. Herne
|
||||||
- Javier Martinez Canillas
|
- Javier Martinez Canillas
|
||||||
@@ -74,6 +76,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Martin Peschke
|
- Martin Peschke
|
||||||
- Martin Petermann
|
- Martin Petermann
|
||||||
- Martin Schwidefsky
|
- Martin Schwidefsky
|
||||||
|
- Matthew Rosato
|
||||||
- Maxim Shchetynin
|
- Maxim Shchetynin
|
||||||
- Melissa Howland
|
- Melissa Howland
|
||||||
- Michael Ernst
|
- Michael Ernst
|
||||||
@@ -103,6 +106,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Stefan Raspl
|
- Stefan Raspl
|
||||||
- Stefan Reimbold
|
- Stefan Reimbold
|
||||||
- Stefan Weinhuber
|
- Stefan Weinhuber
|
||||||
|
- Steffen Eiden
|
||||||
- Steffen Maier
|
- Steffen Maier
|
||||||
- Steffen Thoss
|
- Steffen Thoss
|
||||||
- Susanne Wintenberger
|
- Susanne Wintenberger
|
||||||
|
|||||||
@@ -1,5 +1,61 @@
|
|||||||
Release history for s390-tools (MIT version)
|
Release history for s390-tools (MIT version)
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
* __v2.21.0 (2022-04-20)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.17
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- libcpumf: Create library libcpumf for CPU Measurement functions
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- chreipl-fcp-mpath: bundle a pre-cooked version of the manpage for build
|
||||||
|
environments without access to `pandoc`
|
||||||
|
- dbginfo.sh: Add multipath info to map paths to FC addressing and prio group
|
||||||
|
- dbginfo.sh: Collect config files of systemd-modules-load.service
|
||||||
|
- dbginfo.sh: Sort list of environment variables for readability
|
||||||
|
- dbginfo.sh: Replace "which" by builtin command "type"
|
||||||
|
- dbginfo.sh: Rework script formatting (indents, order)
|
||||||
|
- dbginfo.sh: Update sysfs collection (excludes, messages)
|
||||||
|
- genprotimg: Add Protected Virtualization (PV) dump support
|
||||||
|
- genprotimg: Remove DigiCert root CA pinning
|
||||||
|
- lszcrypt: Add CEX8S support
|
||||||
|
- zcryptctl: Add control domain handling
|
||||||
|
- zcryptstats: Add CEX8 support
|
||||||
|
- zipl: Allow optional entries that are left out when files are missing
|
||||||
|
- zipl: make IPL sections defined with BLS to inherit a target field
|
||||||
|
- zpcictl: Add option to trigger firmware reset
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cpictl: Handle excessive kernel version numbers
|
||||||
|
- dbginfo.sh: Collect all places where modprobe.d config files could exist
|
||||||
|
- fdasd: Fix endless menu loop on EOF
|
||||||
|
- zdump/dfi: Fix segfault due to double free
|
||||||
|
- zdump: Fix /dev/mem reading
|
||||||
|
- zpcictl: Fix race of SCLP reset and Linux recovery
|
||||||
|
|
||||||
|
* __v2.20.0 (2022-02-04)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.16
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- Add EditorConfig configuration
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- s390-tools switches to Fuse 3 as Fuse 2 is deprecated.
|
||||||
|
Affected tools: cmsfs, hmcdrvfs, hsavmcore, zdsfs, zdump
|
||||||
|
- chreipl-fcp-mpath: don't compress the manpage before installing it
|
||||||
|
- cpictl: Report extended version information
|
||||||
|
- genprotimg: Add extended kernel command line support
|
||||||
|
- zdev: modify the lsblk output parser in lszdev
|
||||||
|
- zipl: Add support for longer kernel command lines (now supports up to 64k length)
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cpictl: Suppress messages for unwritable sysfs files
|
||||||
|
- dbginfo.sh: Fix missing syslog for step create_package
|
||||||
|
- lshwc: Fix CPU list parameter setup for device driver
|
||||||
|
- zdev: Check for errors when removing a devtype setting
|
||||||
|
- zdev: Fix path resolution for multi-mount point file systems
|
||||||
|
|
||||||
* __v2.19.0 (2021-11-10)__
|
* __v2.19.0 (2021-11-10)__
|
||||||
|
|
||||||
For Linux kernel version: 5.15
|
For Linux kernel version: 5.15
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ include common.mak
|
|||||||
#
|
#
|
||||||
BASELIB_DIRS = libutil libseckey
|
BASELIB_DIRS = libutil libseckey
|
||||||
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
||||||
libkmipclient
|
libkmipclient libcpumf
|
||||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||||
|
|||||||
@@ -292,7 +292,7 @@ build options:
|
|||||||
|
|
||||||
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
||||||
|----------------|:------------------:|:-------------------------------------:|
|
|----------------|:------------------:|:-------------------------------------:|
|
||||||
| fuse | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
||||||
| | | hsavmcore |
|
| | | hsavmcore |
|
||||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||||
@@ -355,12 +355,12 @@ the different tools are provided:
|
|||||||
|
|
||||||
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
||||||
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
||||||
FUSE is provided by installing the fuse and libfuse packages and by a
|
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
|
||||||
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
|
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
|
||||||
the fuse-devel package is required.
|
the fuse3-devel package is required.
|
||||||
The cmsfs-fuse tool requires FUSE version 2.8.1 or newer for full
|
The cmsfs-fuse tool requires FUSE version 3.0 or newer for full
|
||||||
functionality.
|
functionality.
|
||||||
For further information about FUSE see: http://fuse.sourceforge.net
|
For further information about FUSE see: https://github.com/libfuse/libfuse
|
||||||
|
|
||||||
* hyptop:
|
* hyptop:
|
||||||
The ncurses-devel package is required to build hyptop.
|
The ncurses-devel package is required to build hyptop.
|
||||||
@@ -456,7 +456,7 @@ the different tools are provided:
|
|||||||
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
||||||
|
|
||||||
* hsavmcore:
|
* hsavmcore:
|
||||||
For building the hsavmcore tool you need fuse version 2.6 and optionally
|
For building the hsavmcore tool you need fuse version 3.0 and optionally
|
||||||
systemd which is enabled by default, to disable systemd support,
|
systemd which is enabled by default, to disable systemd support,
|
||||||
add `HAVE_SYSTEMD=0` to the make invocation.
|
add `HAVE_SYSTEMD=0` to the make invocation.
|
||||||
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
|
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
|
||||||
@@ -478,5 +478,6 @@ the different tools are provided:
|
|||||||
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
||||||
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
||||||
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
||||||
make invocation to build a man page and render the README.md as HTML, make
|
make invocation to build a fresh man page (instead of using the pre-cooked
|
||||||
further requires pandoc, GNU awk, and GNU Gzip for the build process.
|
version) and render the README.md as HTML, make further requires pandoc and
|
||||||
|
GNU awk for the build process.
|
||||||
|
|||||||
+2
-2
@@ -32,7 +32,7 @@ Usage: $cmd [-t LAST_GIT_TAG]
|
|||||||
Add all new authors since last release to the $authors_file file. Without
|
Add all new authors since last release to the $authors_file file. Without
|
||||||
the -t option the tool uses the last available git tag as last release.
|
the -t option the tool uses the last available git tag as last release.
|
||||||
|
|
||||||
The tool should be called form the s390-tools master branch.
|
The tool runs on the s390-tools master branch.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
|
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
|
||||||
@@ -116,7 +116,7 @@ echo "$cmd: Adding new authors since tag: $release_tag_last"
|
|||||||
# Print authors list without header
|
# Print authors list without header
|
||||||
tail -n +4 $authors_file_path
|
tail -n +4 $authors_file_path
|
||||||
# Add the new authors
|
# Add the new authors
|
||||||
git log --format="- %an" $release_tag_last..
|
git log --format="- %an" $release_tag_last..master
|
||||||
# Then sort everything and remove duplicates
|
# Then sort everything and remove duplicates
|
||||||
} | sort | uniq > $authors_file_tmp
|
} | sort | uniq > $authors_file_tmp
|
||||||
# Create new AUTHORS file with header ...
|
# Create new AUTHORS file with header ...
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
8e604dab39577678bc9f24bfe5e2ee35354b2f4b1759edd16093157b1ecce9d3 README.md
|
||||||
@@ -9,5 +9,3 @@
|
|||||||
/README.html
|
/README.html
|
||||||
/README.pdf
|
/README.pdf
|
||||||
/chreipl-fcp-mpath.md
|
/chreipl-fcp-mpath.md
|
||||||
/chreipl-fcp-mpath.7
|
|
||||||
/chreipl-fcp-mpath.7.gz
|
|
||||||
|
|||||||
+30
-15
@@ -11,9 +11,9 @@
|
|||||||
# - chreipl-fcp-mpath.mak
|
# - chreipl-fcp-mpath.mak
|
||||||
# bash:
|
# bash:
|
||||||
# - bash
|
# - bash
|
||||||
|
# GNU coreutils:
|
||||||
|
# - sha256sum
|
||||||
# If $(ENABLE_DOC) is `1`:
|
# If $(ENABLE_DOC) is `1`:
|
||||||
# GNU Gzip:
|
|
||||||
# - gzip
|
|
||||||
# GNU awk:
|
# GNU awk:
|
||||||
# - gawk
|
# - gawk
|
||||||
|
|
||||||
@@ -102,20 +102,41 @@ chreiplzfcpmp-doc-man-meta = \
|
|||||||
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
||||||
|
|
||||||
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
||||||
|
chreipl-fcp-mpath.7: .chreipl-fcp-mpath.7.cksum
|
||||||
|
|
||||||
.INTERMEDIATE: chreipl-fcp-mpath.md
|
.INTERMEDIATE: chreipl-fcp-mpath.md
|
||||||
chreipl-fcp-mpath.md: README.md
|
chreipl-fcp-mpath.md: README.md
|
||||||
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
||||||
|
|
||||||
|
.chreipl-fcp-mpath.7.cksum: README.md
|
||||||
|
sha256sum $(<) > $(@)
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-doc-clean
|
.PHONY: chreipl-fcp-mpath-doc-clean
|
||||||
chreipl-fcp-mpath-doc-clean:
|
chreipl-fcp-mpath-doc-clean:
|
||||||
rm -f README.html README.pdf chreipl-fcp-mpath.md chreipl-fcp-mpath.7
|
rm -f README.html README.pdf chreipl-fcp-mpath.md
|
||||||
|
|
||||||
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
||||||
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
||||||
|
|
||||||
|
else # $(ENABLE_DOC) != 1
|
||||||
|
|
||||||
|
# We bundle a pre-cooked man page with the source-code so that distributions
|
||||||
|
# don't need `pandoc` in order to be able to ship the man page. As of this
|
||||||
|
# writing multiple distributions don't have a packaged version of it.
|
||||||
|
#
|
||||||
|
# In order to remember to regenerate this pre-cooked version whenever the
|
||||||
|
# README.md is changed, we also generate a checksum of the README.md, bundle
|
||||||
|
# that as well, and compare that whenever `make` is called. This way, the
|
||||||
|
# freshness of the man page can be checked, even if `pandoc` is not available,
|
||||||
|
# or ENABLE_DOC disabled.
|
||||||
|
|
||||||
|
MANPAGE_FRESH := $(shell sha256sum --check .chreipl-fcp-mpath.7.cksum >/dev/null && echo 1 || echo 0)
|
||||||
|
ifeq ($(MANPAGE_FRESH),0)
|
||||||
|
$(warning chreipl-fcp-mpath.7 is outdated, please regenerate it by calling `make ENABLE_DOC=1`)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
endif # $(ENABLE_DOC) == 1
|
||||||
|
|
||||||
#
|
#
|
||||||
## Install
|
## Install
|
||||||
#
|
#
|
||||||
@@ -133,6 +154,7 @@ install: chreipl-fcp-mpath-install
|
|||||||
|
|
||||||
# install udev rules
|
# install udev rules
|
||||||
INSTDIRS += $(UDEVRULESDIR)
|
INSTDIRS += $(UDEVRULESDIR)
|
||||||
|
$(DESTDIR)$(UDEVRULESDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-udev-rules
|
.PHONY: chreipl-fcp-mpath-install-udev-rules
|
||||||
chreipl-fcp-mpath-install-udev-rules: | $(DESTDIR)$(UDEVRULESDIR)
|
chreipl-fcp-mpath-install-udev-rules: | $(DESTDIR)$(UDEVRULESDIR)
|
||||||
@@ -144,6 +166,7 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-rules
|
|||||||
|
|
||||||
# install udev helper programs
|
# install udev helper programs
|
||||||
INSTDIRS += $(UDEVDIR)
|
INSTDIRS += $(UDEVDIR)
|
||||||
|
$(DESTDIR)$(UDEVDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-udev-helper
|
.PHONY: chreipl-fcp-mpath-install-udev-helper
|
||||||
chreipl-fcp-mpath-install-udev-helper: | $(DESTDIR)$(UDEVDIR)
|
chreipl-fcp-mpath-install-udev-helper: | $(DESTDIR)$(UDEVDIR)
|
||||||
@@ -154,6 +177,7 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-helper
|
|||||||
|
|
||||||
# install common library files
|
# install common library files
|
||||||
INSTDIRS += $(CHREIPLZFCPMPDIR)
|
INSTDIRS += $(CHREIPLZFCPMPDIR)
|
||||||
|
$(DESTDIR)$(CHREIPLZFCPMPDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-libfiles
|
.PHONY: chreipl-fcp-mpath-install-libfiles
|
||||||
chreipl-fcp-mpath-install-libfiles: | $(DESTDIR)$(CHREIPLZFCPMPDIR)
|
chreipl-fcp-mpath-install-libfiles: | $(DESTDIR)$(CHREIPLZFCPMPDIR)
|
||||||
@@ -167,6 +191,7 @@ ifeq ($(HAVE_DRACUT),1)
|
|||||||
|
|
||||||
# install dracut config files
|
# install dracut config files
|
||||||
INSTDIRS += $(DRACUTCONFDIR)
|
INSTDIRS += $(DRACUTCONFDIR)
|
||||||
|
$(DESTDIR)$(DRACUTCONFDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-dracut-config
|
.PHONY: chreipl-fcp-mpath-install-dracut-config
|
||||||
chreipl-fcp-mpath-install-dracut-config: | $(DESTDIR)$(DRACUTCONFDIR)
|
chreipl-fcp-mpath-install-dracut-config: | $(DESTDIR)$(DRACUTCONFDIR)
|
||||||
@@ -178,28 +203,18 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-dracut-config
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_DOC),1)
|
|
||||||
|
|
||||||
# chreipl-fcp-mpath: install man page
|
# chreipl-fcp-mpath: install man page
|
||||||
INSTDIRS += $(MANDIR)
|
INSTDIRS += $(MANDIR)
|
||||||
|
$(DESTDIR)$(MANDIR)/man7: install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-man-page
|
.PHONY: chreipl-fcp-mpath-install-man-page
|
||||||
chreipl-fcp-mpath-install-man-page: | $(DESTDIR)$(MANDIR)/man7
|
chreipl-fcp-mpath-install-man-page: | $(DESTDIR)$(MANDIR)/man7
|
||||||
chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
|
chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
|
||||||
$(GZIP) -fk --best chreipl-fcp-mpath.7
|
|
||||||
$(INSTALL_DATA) -t $(DESTDIR)$(MANDIR)/man7 \
|
$(INSTALL_DATA) -t $(DESTDIR)$(MANDIR)/man7 \
|
||||||
chreipl-fcp-mpath.7.gz
|
chreipl-fcp-mpath.7
|
||||||
|
|
||||||
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-man-page-clean
|
|
||||||
chreipl-fcp-mpath-install-man-page-clean:
|
|
||||||
rm -f chreipl-fcp-mpath.7.gz
|
|
||||||
|
|
||||||
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-install-man-page-clean
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
#
|
||||||
## Utility
|
## Utility
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -120,19 +120,20 @@ in place, but the toolset has some software dependencies besides the
|
|||||||
requirements in section [Requirements](#requirements):
|
requirements in section [Requirements](#requirements):
|
||||||
|
|
||||||
- GNU Bash;
|
- GNU Bash;
|
||||||
- GNU Core Utilities (mktemp, readlink, sync, truncate);
|
- GNU Core Utilities (mktemp, readlink, sync, truncate, sha256sum);
|
||||||
- util-linux (flock, hexdump, logger);
|
- util-linux (flock, hexdump, logger);
|
||||||
- udev / systemd-udev;
|
- udev / systemd-udev;
|
||||||
- multipath-tools.
|
- multipath-tools.
|
||||||
|
|
||||||
To make use of the optional dracut configuration you need: dracut.
|
To make use of the optional dracut configuration you need: dracut.
|
||||||
|
|
||||||
To build and install the documentation (man page) you need:
|
To build a fresh version of the documentation (man page) you need:
|
||||||
|
|
||||||
- pandoc;
|
- pandoc;
|
||||||
- GNU Core Utilities (date);
|
- GNU Core Utilities (date);
|
||||||
- GNU awk;
|
- GNU awk;
|
||||||
- GNU Gzip.
|
|
||||||
|
otherwise the pre-cooked version shipped with the source will be used.
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
============
|
============
|
||||||
@@ -161,7 +162,7 @@ steps and copies the resulting components to their final destination.
|
|||||||
| Option | Values | Default | Effect
|
| Option | Values | Default | Effect
|
||||||
| :----- | :----: | :-----: | :-----
|
| :----- | :----: | :-----: | :-----
|
||||||
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
||||||
| ENABLE_DOC | 0, 1 | 0 | Build and install a man page for **chreipl-fcp-mpath**.
|
| ENABLE_DOC | 0, 1 | 0 | Build a fresh version of the man page for **chreipl-fcp-mpath**.
|
||||||
|
|
||||||
Specify any options as arguments for both the **make** and **make install**
|
Specify any options as arguments for both the **make** and **make install**
|
||||||
command as shown in the following example:
|
command as shown in the following example:
|
||||||
@@ -196,8 +197,8 @@ the boot record to find the new initial ramdisk.
|
|||||||
|
|
||||||
~ # zipl
|
~ # zipl
|
||||||
|
|
||||||
With dracut and documentation enabled, **make install** deploys the following
|
With dracut enabled, **make install** deploys the following files to these
|
||||||
files to these default locations:
|
default locations:
|
||||||
|
|
||||||
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
||||||
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
@@ -207,7 +208,7 @@ files to these default locations:
|
|||||||
/usr/lib/udev/chreipl-fcp-mpath-record-volume-identifier
|
/usr/lib/udev/chreipl-fcp-mpath-record-volume-identifier
|
||||||
/usr/lib/udev/chreipl-fcp-mpath-try-change-ipl-path
|
/usr/lib/udev/chreipl-fcp-mpath-try-change-ipl-path
|
||||||
/usr/lib/udev/rules.d/70-chreipl-fcp-mpath.rules
|
/usr/lib/udev/rules.d/70-chreipl-fcp-mpath.rules
|
||||||
/usr/share/man/man7/chreipl-fcp-mpath.7.gz
|
/usr/share/man/man7/chreipl-fcp-mpath.7
|
||||||
|
|
||||||
UNINSTALL
|
UNINSTALL
|
||||||
=========
|
=========
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#!/bin/bash
|
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
#
|
#
|
||||||
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
|
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
.\" Automatically generated by Pandoc 2.16.1
|
||||||
|
.\"
|
||||||
|
.TH "CHREIPL-FCP-MPATH" "7" "2022-02-24" "s390-tools 2.20.0-build-20220224" "Administrator Manual"
|
||||||
|
.hy
|
||||||
|
.SH NAME
|
||||||
|
.PP
|
||||||
|
chreipl-fcp-mpath - use multipath information for re-IPL path failover
|
||||||
|
on a running Linux instance
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
The IPL process of Linux on Z or LinuxONE from an FCP-attached SCSI
|
||||||
|
volume uses exactly one path to the volume.
|
||||||
|
If this path is unavailable, the IPL fails.
|
||||||
|
.PP
|
||||||
|
The \f[B]chreipl-fcp-mpath\f[R] toolset monitors \f[B]udev\f[R] events
|
||||||
|
about paths to the re-IPL volume.
|
||||||
|
If the currently configured re-IPL path becomes unavailable, the toolset
|
||||||
|
checks for operational paths to the same volume.
|
||||||
|
If available, it reconfigures the re-IPL settings to use an operational
|
||||||
|
path.
|
||||||
|
.PP
|
||||||
|
Thus, re-IPL from an FCP-attached SCSI volume can be successful despite
|
||||||
|
path failures on a running Linux instance if at least one path to the
|
||||||
|
re-IPL volume remains operational.
|
||||||
|
.PP
|
||||||
|
\f[B]Chreipl-fcp-mpath\f[R] requires \f[B]udev\f[R],
|
||||||
|
\f[B]multipathd\f[R] and \f[B]dm-multipath\f[R].
|
||||||
|
Once installed, the toolset runs automatically and autonomously.
|
||||||
|
No user intervention is possible or required.
|
||||||
|
.PP
|
||||||
|
Other than installing the toolset, there is no user interface for
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
.SS Requirements
|
||||||
|
.PP
|
||||||
|
The \f[B]chreipl-fcp-mpath\f[R] tool has the following requirements on
|
||||||
|
the Linux instance that is being monitored:
|
||||||
|
.IP \[bu] 2
|
||||||
|
The Linux instance must have started successfully, during IPL.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The running Linux instance must use \f[B]dm-multipath\f[R] and
|
||||||
|
\f[B]multipathd\f[R] for the configured re-IPL volume - a volume that
|
||||||
|
contains a zipl boot record and has one of its paths used in the re-IPL
|
||||||
|
configuration.
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]udev\f[R] must run.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The toolset must observe at least one event about the configured re-IPL
|
||||||
|
path.
|
||||||
|
Examples for such events are: the SCSI disk comes online, or a path of
|
||||||
|
the corresponding multipath device goes down or comes back online.
|
||||||
|
.RS 2
|
||||||
|
.IP \[bu] 2
|
||||||
|
The WWID of the re-IPL volume must not change while the Linux instance
|
||||||
|
is running.
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
When the configured re-IPL path becomes unavailable while the Linux
|
||||||
|
instance is running, at least one operational path to the re-IPL volume
|
||||||
|
must be available, or must become available.
|
||||||
|
If no such path is available when the Linux instance is rebooted, the
|
||||||
|
re-IPL path is not changed.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The tool assumes that any manually reconfigured re-IPL device is valid
|
||||||
|
and operational.
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
The tool treats a newly configured re-IPL device like the initially
|
||||||
|
configured re-IPL device.
|
||||||
|
In particular, if the newly configured re-IPL device fulfills the
|
||||||
|
requirements of the tool, re-IPL path failover takes place if the
|
||||||
|
configured re-IPL path becomes unavailable.
|
||||||
|
.RE
|
||||||
|
.SS Caution with Manual Changes to the Configured re-IPL Target
|
||||||
|
.PP
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R] is designed to accept operator-inititated
|
||||||
|
changes of the re-IPL device.
|
||||||
|
However, concurrent changes by the operator and tool driven changes can
|
||||||
|
result in the operator change being overwritten.
|
||||||
|
.PP
|
||||||
|
To avoid this problem, change the re-IPL device only during steady-state
|
||||||
|
operations, when no path events happen.
|
||||||
|
Alternatively, make sure that no events are processed while you change
|
||||||
|
the device.
|
||||||
|
See EXAMPLES for one way to suspend event processing.
|
||||||
|
.SH MESSAGES
|
||||||
|
.PP
|
||||||
|
During monitoring and event processing, \f[B]chreipl-fcp-mpath\f[R]
|
||||||
|
writes messages to the syslog.
|
||||||
|
.PP
|
||||||
|
When the configured re-IPL path is changed to a different path to the
|
||||||
|
same volume (priority \f[I]daemon.notice\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
Changed re-IPL path to: <device-bus-id>:<wwpn>:<lun>.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
When a path event indicates that the last available path has become
|
||||||
|
non-operational (priority \f[I]daemon.alert\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
The re-IPL device cannot be changed because no operational path to the
|
||||||
|
re-IPL volume remains.
|
||||||
|
The next re-IPL might fail unless you re-attach or enable at least one
|
||||||
|
valid path to the re-IPL volume.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
When changing the configured re-IPL device failed because of an error
|
||||||
|
with the used Linux kernel interface (priority \f[I]daemon.crit\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
Changing the re-IPL device failed.
|
||||||
|
The current re-IPL settings might be inconsistent.
|
||||||
|
Check and correct the settings (see the README.md of chreipl-fcp-mpath)
|
||||||
|
to make sure that the current re-IPL device is valid.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
A failure to change the re-IPL device can indicate an inconsistent
|
||||||
|
setting that cannot be corrected automatically by
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
As a result, the next re-IPL might fail or might not use the intended
|
||||||
|
re-IPL device.
|
||||||
|
.PP
|
||||||
|
You can use the following tools to check and correct the current
|
||||||
|
settings:
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]lsreipl\f[R] to confirm that the intended re-IPL device is
|
||||||
|
configured;
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]chreipl\f[R] to change the re-IPL device;
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]lszfcp\f[R] to inspect the state of available paths to the re-IPL
|
||||||
|
device.
|
||||||
|
.SH EXAMPLES
|
||||||
|
.SS Manual Changes to the Configured re-IPL Device
|
||||||
|
.PP
|
||||||
|
As outlined in DESCRIPTION, be cautious when manually changing the
|
||||||
|
configured re-IPL device.
|
||||||
|
Assure that your reconfiguration actions do not collide with concurrent
|
||||||
|
automatic event processing by \f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
You can avoid such collisions, by stopping event processing, making your
|
||||||
|
changes, and then re-enabling event processing.
|
||||||
|
You need \f[I]root\f[R] privileges for running the commands in the
|
||||||
|
following example:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # udevadm settle
|
||||||
|
\[ti] # udevadm control --stop-exec-queue
|
||||||
|
\[ti] # chreipl ...
|
||||||
|
\[ti] # udevadm control --start-exec-queue
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SS Listing messages with journalctl
|
||||||
|
.PP
|
||||||
|
If your Linux instance includes \f[B]journalctl\f[R], use the following
|
||||||
|
command to list all messages that are issued by
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R]:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # journalctl -t chreipl-fcp-mpath
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
To list only messages that were issued since the last IPL, use this
|
||||||
|
command:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # journalctl -t chreipl-fcp-mpath -b
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SH REPORTING BUGS
|
||||||
|
.PP
|
||||||
|
Use the \f[B]Issues\f[R] functionality on GitHub to report any bugs in
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R]: s390-tools
|
||||||
|
Issues (https://github.com/ibm-s390-linux/s390-tools/issues).
|
||||||
|
.SH SEE ALSO
|
||||||
|
.PP
|
||||||
|
\f[B]chreipl\f[R](8), \f[B]dracut\f[R](8), \f[B]journalctl\f[R](1),
|
||||||
|
\f[B]lsreipl(8)\f[R], \f[B]lszfcp\f[R](8), \f[B]multipath\f[R](8),
|
||||||
|
\f[B]multipathd\f[R](8), \f[B]udev\f[R](7), \f[B]udevadm\f[R](8),
|
||||||
|
\f[B]zipl\f[R](8)
|
||||||
+7
-6
@@ -16,17 +16,18 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"cmsfs-fuse", \
|
"cmsfs-fuse", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
|
|
||||||
all: check_dep cmsfs-fuse
|
all: check_dep cmsfs-fuse
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
|
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
|
||||||
LDLIBS += $(FUSE_LDLIBS) -lm
|
LDLIBS += $(FUSE_LDLIBS) -lm
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ Allow access by other users
|
|||||||
\fB\-o\fR allow_root
|
\fB\-o\fR allow_root
|
||||||
Allow access by root
|
Allow access by root
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR nonempty
|
|
||||||
Allow mounts over non\-empty file/dir
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR default_permissions
|
\fB\-o\fR default_permissions
|
||||||
Enable permission checking by kernel
|
Enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+23
-9
@@ -9,7 +9,7 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -1516,7 +1516,7 @@ static void walk_dir_block(struct fst_entry *fst, struct walk_file *walk,
|
|||||||
decode_edf_name(file, fst->name, fst->type);
|
decode_edf_name(file, fst->name, fst->type);
|
||||||
if (!file_unlinked(file)) {
|
if (!file_unlinked(file)) {
|
||||||
cache_fst_addr(walk->addr, file);
|
cache_fst_addr(walk->addr, file);
|
||||||
walk->filler(walk->buf, file, NULL, 0);
|
walk->filler(walk->buf, file, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1728,8 +1728,11 @@ static off_t get_file_size_logical(struct fst_entry *fst)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_getattr(const char *path, struct stat *stbuf)
|
static int cmsfs_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
int mask = (cmsfs.allow_other) ? 0444 : 0440;
|
int mask = (cmsfs.allow_other) ? 0444 : 0440;
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
|
|
||||||
@@ -1783,13 +1786,15 @@ static int cmsfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
off_t offset, struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
struct walk_file walk;
|
struct walk_file walk;
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
|
|
||||||
(void) offset;
|
(void) offset;
|
||||||
(void) fi;
|
(void) fi;
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Offset is ignored and 0 passed to the filler fn so the whole
|
* Offset is ignored and 0 passed to the filler fn so the whole
|
||||||
@@ -1800,8 +1805,8 @@ static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
if (strcmp(path, "/") != 0)
|
if (strcmp(path, "/") != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
memset(&walk, 0, sizeof(walk));
|
memset(&walk, 0, sizeof(walk));
|
||||||
/* readdir is possible without open so fi->fh is not set */
|
/* readdir is possible without open so fi->fh is not set */
|
||||||
@@ -2683,13 +2688,16 @@ static int cmsfs_statfs(const char *path, struct statvfs *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_utimens(const char *path, const struct timespec ts[2])
|
static int cmsfs_utimens(const char *path, const struct timespec ts[2],
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
off_t fst_addr;
|
off_t fst_addr;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@@ -2825,7 +2833,8 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_rename(const char *path, const char *new_path)
|
static int cmsfs_rename(const char *path, const char *new_path,
|
||||||
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct fst_entry fst, fst_new;
|
struct fst_entry fst, fst_new;
|
||||||
off_t fst_addr, fst_addr_new;
|
off_t fst_addr, fst_addr_new;
|
||||||
@@ -2835,6 +2844,8 @@ static int cmsfs_rename(const char *path, const char *new_path)
|
|||||||
struct file *f;
|
struct file *f;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@@ -3232,13 +3243,16 @@ static void update_fst(struct file *f, off_t addr)
|
|||||||
unhide_null_blocks(f);
|
unhide_null_blocks(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_truncate(const char *path, off_t size)
|
static int cmsfs_truncate(const char *path, off_t size,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
off_t fst_addr, len;
|
off_t fst_addr, len;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
|
||||||
|
|||||||
+10
-10
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
|||||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
RELEASE = 19
|
RELEASE = 21
|
||||||
PATCHLEVEL = 0
|
PATCHLEVEL = 0
|
||||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||||
@@ -59,11 +59,8 @@ define cmd_define
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
||||||
$(eval $(call cmd_define, LINK," LINK ",$(CROSS_COMPILE)gcc))
|
|
||||||
$(eval $(call cmd_define, LD," LD ",$(CROSS_COMPILE)ld))
|
|
||||||
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
||||||
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
||||||
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CROSS_COMPILE)g++))
|
|
||||||
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
||||||
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
||||||
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
||||||
@@ -84,6 +81,8 @@ CHECKTOOL = $(call echocmd," CHECK ",/$@)$(CHECK_SILENT)
|
|||||||
SKIP = echo " SKIP $(call reldir) due to"
|
SKIP = echo " SKIP $(call reldir) due to"
|
||||||
|
|
||||||
INSTALL = install
|
INSTALL = install
|
||||||
|
LINK = $(CC)
|
||||||
|
LINKXX = $(CXX)
|
||||||
CP = cp
|
CP = cp
|
||||||
ifneq ("${V}","1")
|
ifneq ("${V}","1")
|
||||||
MAKEFLAGS += --quiet
|
MAKEFLAGS += --quiet
|
||||||
@@ -92,13 +91,12 @@ ifneq ("${V}","1")
|
|||||||
else
|
else
|
||||||
echocmd=
|
echocmd=
|
||||||
endif
|
endif
|
||||||
|
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
||||||
ifeq ("${W}","1")
|
ifeq ("${W}","1")
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security -Wextra
|
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
|
||||||
else
|
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
|
||||||
endif
|
endif
|
||||||
ifeq ("${D}","1")
|
ifeq ("${D}","1")
|
||||||
DEFAULT_CFLAGS += -Og
|
DEFAULT_CFLAGS += -Og -g3 -ggdb3
|
||||||
else
|
else
|
||||||
DEFAULT_CFLAGS += -O3
|
DEFAULT_CFLAGS += -O3
|
||||||
endif
|
endif
|
||||||
@@ -252,11 +250,9 @@ export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
|
|||||||
|
|
||||||
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
||||||
NO_PIE_CFLAGS := -fno-pie
|
NO_PIE_CFLAGS := -fno-pie
|
||||||
NO_PIE_LINKFLAGS := -no-pie
|
|
||||||
NO_PIE_LDFLAGS := -no-pie
|
NO_PIE_LDFLAGS := -no-pie
|
||||||
else
|
else
|
||||||
NO_PIE_CFLAGS :=
|
NO_PIE_CFLAGS :=
|
||||||
NO_PIE_LINKFLAGS :=
|
|
||||||
NO_PIE_LDFLAGS :=
|
NO_PIE_LDFLAGS :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@@ -371,6 +367,10 @@ $(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
|||||||
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||||
.PHONY: $(rootdir)/libvmcp
|
.PHONY: $(rootdir)/libvmcp
|
||||||
|
|
||||||
|
$(rootdir)/libcpumf/libcpumf.a: $(rootdir)/libcpumf
|
||||||
|
$(MAKE) -C $(rootdir)/libcpumf/ libcpumf.a
|
||||||
|
.PHONY: $(rootdir)/libcpumf
|
||||||
|
|
||||||
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
||||||
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
||||||
.PHONY: $(rootdir)/libekmfweb
|
.PHONY: $(rootdir)/libekmfweb
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@ MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
|
|||||||
|
|
||||||
all: $(BIN_FILES)
|
all: $(BIN_FILES)
|
||||||
|
|
||||||
libs = $(rootdir)/libutil/libutil.a
|
libs = $(rootdir)/libutil/libutil.a $(rootdir)/libcpumf/libcpumf.a
|
||||||
|
|
||||||
lscpumf: lscpumf.o $(libs)
|
lscpumf: lscpumf.o $(libs)
|
||||||
chcpumf: chcpumf.o $(libs)
|
chcpumf: chcpumf.o $(libs)
|
||||||
|
|||||||
+20
-39
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* chcpumf - Change CPU Measurement Facility Characteristics
|
* chcpumf - Change CPU Measurement Facility Characteristics
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2020
|
* Copyright IBM Corp. 2020, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
|
||||||
#include "defines.h"
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
static int verbose;
|
static unsigned int verbose;
|
||||||
static unsigned long min_sdb, max_sdb;
|
static unsigned long min_sdb, max_sdb;
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
@@ -85,55 +85,30 @@ static long parse_buffersize(char *string)
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_sfb(unsigned long *min, unsigned long *max)
|
static int write_sfb(unsigned int min, unsigned int max)
|
||||||
{
|
|
||||||
unsigned long cur_min_sdb, cur_max_sdb;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if (geteuid())
|
|
||||||
errx(EXIT_FAILURE, "Must run as root");
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "r");
|
|
||||||
if (!fp)
|
|
||||||
err(EXIT_FAILURE, PERF_SFB_SIZE);
|
|
||||||
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
|
|
||||||
fclose(fp);
|
|
||||||
errx(EXIT_FAILURE, "Can not parse file " PERF_SFB_SIZE);
|
|
||||||
} else {
|
|
||||||
if (*min == 0)
|
|
||||||
*min = cur_min_sdb;
|
|
||||||
if (*max == 0)
|
|
||||||
*max = cur_max_sdb;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
if (*min >= *max)
|
|
||||||
errx(EXIT_FAILURE,
|
|
||||||
"The specified maximum must be greater than the minimum");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_sfb(unsigned long min, unsigned long max)
|
|
||||||
{
|
{
|
||||||
int rc = EXIT_SUCCESS;
|
int rc = EXIT_SUCCESS;
|
||||||
char text[64];
|
char text[64];
|
||||||
size_t len;
|
size_t len;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "w");
|
fp = fopen(S390_CPUMSF_BUFFERSZ, "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
err(EXIT_FAILURE, PERF_SFB_SIZE);
|
err(EXIT_FAILURE, S390_CPUMSF_BUFFERSZ);
|
||||||
snprintf(text, sizeof text, "%ld,%ld", min, max);
|
snprintf(text, sizeof(text), "%u,%u", min, max);
|
||||||
len = strlen(text) + 1;
|
len = strlen(text) + 1;
|
||||||
if (fwrite(text, 1, len, fp) != len) {
|
if (fwrite(text, 1, len, fp) != len) {
|
||||||
warn(PERF_SFB_SIZE);
|
warn(S390_CPUMSF_BUFFERSZ);
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (fclose(fp)) {
|
if (fclose(fp)) {
|
||||||
warn(PERF_SFB_SIZE);
|
warn(S390_CPUMSF_BUFFERSZ);
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (verbose && rc != EXIT_FAILURE)
|
if (verbose && rc != EXIT_FAILURE)
|
||||||
warnx("Sampling buffer sizes:\n"
|
warnx("Sampling buffer sizes:\n"
|
||||||
" Minimum:%7ld sample-data-blocks\n"
|
" Minimum:%7d sample-data-blocks\n"
|
||||||
" Maximum:%7ld sample-data-blocks\n",
|
" Maximum:%7d sample-data-blocks\n",
|
||||||
min, max);
|
min, max);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -183,15 +158,21 @@ static int parse_args(int argc, char **argv)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct stat sbuf;
|
unsigned long my_min, my_max;
|
||||||
|
|
||||||
util_prg_init(&prg);
|
util_prg_init(&prg);
|
||||||
util_opt_init(opt_vec, NULL);
|
util_opt_init(opt_vec, NULL);
|
||||||
|
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
if (stat(PERF_PATH PERF_SF, &sbuf))
|
if (geteuid())
|
||||||
|
errx(EXIT_FAILURE, "Must run as root");
|
||||||
|
if (!libcpumf_have_sfb())
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
"No CPU-measurement sampling facility detected");
|
"No CPU-measurement sampling facility detected");
|
||||||
read_sfb(&min_sdb, &max_sdb);
|
libcpumf_sfb_info(&my_min, &my_max);
|
||||||
|
if (!min_sdb)
|
||||||
|
min_sdb = my_min;
|
||||||
|
if (!max_sdb)
|
||||||
|
max_sdb = my_max;
|
||||||
return write_sfb(min_sdb, max_sdb);
|
return write_sfb(min_sdb, max_sdb);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Defines for CPU Measurement Facility Characteristics
|
|
||||||
*
|
|
||||||
* Copyright IBM Corp. 2020
|
|
||||||
*
|
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DEFINES_H
|
|
||||||
#define DEFINES_H
|
|
||||||
|
|
||||||
#define PERF_SFB_SIZE "/sys/module/kernel/parameters/cpum_sfb_size"
|
|
||||||
#define PERF_PATH "/sys/bus/event_source/devices/"
|
|
||||||
#define PERF_SF "cpum_sf"
|
|
||||||
#define PERF_CF "cpum_cf"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
+49
-146
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* lscpumf - Show CPU Measurement Facility Characteristics
|
* lscpumf - Show CPU Measurement Facility Characteristics
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2020
|
* Copyright IBM Corp. 2020, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
|
|
||||||
#include "defines.h"
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
#define ACTION_NONE 0
|
#define ACTION_NONE 0
|
||||||
#define ACTION_INFO 1
|
#define ACTION_INFO 1
|
||||||
@@ -45,9 +45,6 @@ static bool actions[ACTION_SAMPLE + 1]; /* Specified command line options */
|
|||||||
#define PER_SDBT_SIZE 511
|
#define PER_SDBT_SIZE 511
|
||||||
|
|
||||||
/* File names to read data from */
|
/* File names to read data from */
|
||||||
#define SERVICELEVEL "/proc/service_levels"
|
|
||||||
#define CPUMF_CF_TYPE "/sys/devices/cpum_cf/type"
|
|
||||||
#define CPUMF_SF_TYPE "/sys/devices/cpum_sf/type"
|
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("OPTIONS"),
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
@@ -92,19 +89,18 @@ static char prefix[32]; /* Counter prefix */
|
|||||||
static bool show_names;
|
static bool show_names;
|
||||||
|
|
||||||
static struct cpumf_info {
|
static struct cpumf_info {
|
||||||
unsigned int first_vn; /* Counter facility first version nr */
|
int first_vn; /* Counter facility first version nr */
|
||||||
unsigned int second_vn; /* Counter facility second version nr */
|
int second_vn; /* Counter facility second version nr */
|
||||||
unsigned int authorization; /* Counter facility authorization */
|
int authorization; /* Counter facility authorization */
|
||||||
float version;
|
|
||||||
unsigned long min_rate; /* Minimum sampling rate */
|
unsigned long min_rate; /* Minimum sampling rate */
|
||||||
unsigned long max_rate; /* Maximum sampling rate */
|
unsigned long max_rate; /* Maximum sampling rate */
|
||||||
unsigned long cpu_speed; /* CPU Cycles per micro second */
|
unsigned long cpu_speed; /* CPU Cycles per micro second */
|
||||||
unsigned int basic_sample_sz; /* # of Bytes per basic sample */
|
int basic_sample_sz; /* # of Bytes per basic sample */
|
||||||
unsigned int diag_sample_sz; /* # of bytes per diagnostic sample */
|
int diag_sample_sz; /* # of bytes per diagnostic sample */
|
||||||
unsigned char have_counter; /* CPUM counter facility detected */
|
bool have_counter; /* CPUM counter facility detected */
|
||||||
unsigned char have_samples; /* CPUM sampling facility detected */
|
bool have_samples; /* CPUM sampling facility detected */
|
||||||
unsigned int min_sfb; /* Minimum sampling buffer size */
|
unsigned long min_sfb; /* Minimum sampling buffer size */
|
||||||
unsigned int max_sfb; /* Maximum sampling buffer size */
|
unsigned long max_sfb; /* Maximum sampling buffer size */
|
||||||
unsigned short machine_type; /* Machine Type */
|
unsigned short machine_type; /* Machine Type */
|
||||||
} cpumf;
|
} cpumf;
|
||||||
|
|
||||||
@@ -2565,26 +2561,12 @@ static struct counters cpumcf_z15_counters[] = {
|
|||||||
* If perf_pmu_register() kernel function assigned any other (higher) type
|
* If perf_pmu_register() kernel function assigned any other (higher) type
|
||||||
* number, set the prefix to <type-nr>:
|
* number, set the prefix to <type-nr>:
|
||||||
*/
|
*/
|
||||||
static int read_cpumf_type(const char *filename, const char *type)
|
static void set_prefix(int nr)
|
||||||
{
|
{
|
||||||
int nr, rc = EXIT_FAILURE;
|
if (nr == PERF_TYPE_RAW)
|
||||||
FILE *fp = fopen(filename, "r");
|
strcat(prefix, "r");
|
||||||
|
else
|
||||||
if (fp == NULL) {
|
snprintf(prefix, sizeof(prefix), "%d:", nr);
|
||||||
warnx("No CPU-measurement %s facility detected", type);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (fscanf(fp, "%d", &nr) != 1) {
|
|
||||||
warnx("Can not parse file %s", filename);
|
|
||||||
} else {
|
|
||||||
rc = EXIT_SUCCESS;
|
|
||||||
if (nr == PERF_TYPE_RAW)
|
|
||||||
strcat(prefix, "r");
|
|
||||||
else
|
|
||||||
snprintf(prefix, sizeof prefix, "%d:", nr);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse tool parameters. In case of --help or --version, print
|
/* Parse tool parameters. In case of --help or --version, print
|
||||||
@@ -2661,8 +2643,6 @@ static unsigned long div_ceil(unsigned long a, unsigned long b)
|
|||||||
|
|
||||||
static void show_info(struct cpumf_info *p, int details)
|
static void show_info(struct cpumf_info *p, int details)
|
||||||
{
|
{
|
||||||
struct stat sbuf;
|
|
||||||
|
|
||||||
if (!p->have_counter && !p->have_samples) {
|
if (!p->have_counter && !p->have_samples) {
|
||||||
warnx("No CPU-measurement facilities detected");
|
warnx("No CPU-measurement facilities detected");
|
||||||
return;
|
return;
|
||||||
@@ -2672,7 +2652,7 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
if (details) {
|
if (details) {
|
||||||
printf("----------------------------------------------"
|
printf("----------------------------------------------"
|
||||||
"----------------------------\n");
|
"----------------------------\n");
|
||||||
printf("Version: %3.1f\n\n", p->version);
|
printf("Version: %d.%d\n\n", p->first_vn, p->second_vn);
|
||||||
printf("Authorized counter sets:\n");
|
printf("Authorized counter sets:\n");
|
||||||
if (!p->authorization)
|
if (!p->authorization)
|
||||||
printf(" None\n");
|
printf(" None\n");
|
||||||
@@ -2689,8 +2669,7 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
if (0x8000 & p->authorization)
|
if (0x8000 & p->authorization)
|
||||||
printf(" Coprocessor Group counter Set\n");
|
printf(" Coprocessor Group counter Set\n");
|
||||||
printf("\nLinux perf event support: %s\n\n",
|
printf("\nLinux perf event support: %s\n\n",
|
||||||
(stat(PERF_PATH PERF_CF, &sbuf)) ? "No" :
|
!p->have_counter ? "No" : "Yes (PMU: cpum_cf)");
|
||||||
"Yes (PMU: " PERF_CF ")");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -2718,19 +2697,18 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
p->diag_sample_sz);
|
p->diag_sample_sz);
|
||||||
|
|
||||||
printf("\nLinux perf event support: %s\n\n",
|
printf("\nLinux perf event support: %s\n\n",
|
||||||
(stat(PERF_PATH PERF_SF, &sbuf)) ? "No" :
|
!p->have_samples ? "No" : "Yes (PMU: cpum_sf)");
|
||||||
"Yes (PMU: " PERF_SF ")");
|
|
||||||
|
|
||||||
printf("Current sampling buffer settings for %s:\n",
|
printf("Current sampling buffer settings for"
|
||||||
PERF_SF);
|
" cpum_sf:\n");
|
||||||
printf(" Basic-sampling mode\n");
|
printf(" Basic-sampling mode\n");
|
||||||
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Minimum: %6d"
|
printf(" Minimum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n", p->min_sfb, text);
|
" sample-data-blocks (%6s)\n", p->min_sfb, text);
|
||||||
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
|
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Maximum: %6d"
|
printf(" Maximum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n\n", p->max_sfb,
|
" sample-data-blocks (%6s)\n\n", p->max_sfb,
|
||||||
text);
|
text);
|
||||||
|
|
||||||
@@ -2739,13 +2717,13 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
|
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
|
||||||
total = fdiag * p->min_sfb
|
total = fdiag * p->min_sfb
|
||||||
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Minimum: %6ld"
|
printf(" Minimum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n",
|
" sample-data-blocks (%6s)\n",
|
||||||
fdiag * p->min_sfb, text);
|
fdiag * p->min_sfb, text);
|
||||||
total = fdiag * p->max_sfb
|
total = fdiag * p->max_sfb
|
||||||
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
|
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Maximum: %6ld"
|
printf(" Maximum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
|
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
|
||||||
text);
|
text);
|
||||||
@@ -2755,27 +2733,6 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
warnx("No CPU-measurement sampling facility detected");
|
warnx("No CPU-measurement sampling facility detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read CPU Measurement sampling facility device driver minimum and maximum
|
|
||||||
* buffer size
|
|
||||||
*/
|
|
||||||
static int read_sfb(struct cpumf_info *p)
|
|
||||||
{
|
|
||||||
int rc = EXIT_SUCCESS;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "r");
|
|
||||||
if (!fp) {
|
|
||||||
warn(PERF_SFB_SIZE);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
if (fscanf(fp, "%d,%d", &p->min_sfb, &p->max_sfb) != 2) {
|
|
||||||
warnx("Can not parse %s", PERF_SFB_SIZE);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the counter name for z15 counter numbered 265. It is either named
|
/* Set the counter name for z15 counter numbered 265. It is either named
|
||||||
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
|
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
|
||||||
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
||||||
@@ -2803,81 +2760,23 @@ static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
|||||||
/* Read allnecessary information from /sysfs file /proc/service_levels */
|
/* Read allnecessary information from /sysfs file /proc/service_levels */
|
||||||
static int read_info(void)
|
static int read_info(void)
|
||||||
{
|
{
|
||||||
char *linep = NULL;
|
int rc = EXIT_FAILURE;
|
||||||
size_t line_sz;
|
|
||||||
ssize_t nbytes;
|
|
||||||
FILE *slp;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(&cpumf, 0, sizeof cpumf);
|
cpumf.have_counter = libcpumf_cpumcf_info(&cpumf.first_vn,
|
||||||
slp = fopen(SERVICELEVEL, "r");
|
&cpumf.second_vn,
|
||||||
if (!slp) {
|
&cpumf.authorization);
|
||||||
warn(SERVICELEVEL);
|
cpumf.have_samples = libcpumf_cpumsf_info(&cpumf.min_rate,
|
||||||
return EXIT_FAILURE;
|
&cpumf.max_rate,
|
||||||
}
|
&cpumf.cpu_speed,
|
||||||
|
&cpumf.basic_sample_sz,
|
||||||
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
|
&cpumf.diag_sample_sz);
|
||||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
if (cpumf.have_samples)
|
||||||
rc = sscanf(linep, "CPU-MF: Counter facility:"
|
libcpumf_sfb_info(&cpumf.min_sfb, &cpumf.max_sfb);
|
||||||
" version=%f authorization=%x",
|
|
||||||
&cpumf.version, &cpumf.authorization);
|
|
||||||
if (rc != 2) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.have_counter = 1;
|
|
||||||
cpumf.first_vn = (int)cpumf.version;
|
|
||||||
cpumf.second_vn = ((int)(10 * cpumf.version) % 10);
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
|
|
||||||
&cpumf.min_rate, &cpumf.max_rate,
|
|
||||||
&cpumf.cpu_speed);
|
|
||||||
if (rc != 3) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.have_samples = 1;
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" mode=basic sample_size=%u",
|
|
||||||
&cpumf.basic_sample_sz);
|
|
||||||
if (rc != 1) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" mode=diagnostic sample_size=%u",
|
|
||||||
&cpumf.diag_sample_sz);
|
|
||||||
if (rc != 1) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cpumf.have_samples) {
|
|
||||||
rc = read_sfb(&cpumf);
|
|
||||||
if (rc == EXIT_FAILURE)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.machine_type = util_arch_machine_type();
|
cpumf.machine_type = util_arch_machine_type();
|
||||||
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN) {
|
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN)
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
goto out;
|
else
|
||||||
}
|
rc = EXIT_SUCCESS;
|
||||||
rc = EXIT_SUCCESS;
|
|
||||||
out:
|
|
||||||
fclose(slp);
|
|
||||||
free(linep);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3051,14 +2950,18 @@ int main(int argc, char **argv)
|
|||||||
case ACTION_CNT:
|
case ACTION_CNT:
|
||||||
case ACTION_CNTALL:
|
case ACTION_CNTALL:
|
||||||
all = ret == ACTION_CNTALL;
|
all = ret == ACTION_CNTALL;
|
||||||
ret = read_cpumf_type(CPUMF_CF_TYPE, "counter");
|
ret = libcpumf_pmutype(S390_CPUMF_CF);
|
||||||
if (ret == EXIT_SUCCESS)
|
if (ret >= EXIT_SUCCESS) {
|
||||||
|
set_prefix(ret);
|
||||||
show_counter(all);
|
show_counter(all);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_SAMPLE:
|
case ACTION_SAMPLE:
|
||||||
ret = read_cpumf_type(CPUMF_SF_TYPE, "sampling");
|
ret = libcpumf_pmutype(S390_CPUMF_SF);
|
||||||
if (ret == EXIT_SUCCESS)
|
if (ret >= EXIT_SUCCESS) {
|
||||||
|
set_prefix(ret);
|
||||||
show_sample();
|
show_sample();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_NONE:
|
case ACTION_NONE:
|
||||||
case ACTION_INFO:
|
case ACTION_INFO:
|
||||||
|
|||||||
+34
-88
@@ -38,17 +38,18 @@
|
|||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_scandir.h"
|
#include "lib/util_scandir.h"
|
||||||
#include "lib/util_libc.h"
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
#include "lshwc.h"
|
#include "lshwc.h"
|
||||||
|
|
||||||
#define SERVICELEVEL "/proc/service_levels"
|
|
||||||
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
|
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
||||||
#define MAXCTRS 512
|
#define MAXCTRS 512
|
||||||
#define IOCTLSLEEP 60U
|
#define IOCTLSLEEP 60U
|
||||||
|
|
||||||
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
|
static unsigned int read_interval = IOCTLSLEEP;
|
||||||
|
static int cfvn, csvn, authorization;
|
||||||
static unsigned long loop_count = 1;
|
static unsigned long loop_count = 1;
|
||||||
static unsigned char *ioctlbuffer;
|
static unsigned char *ioctlbuffer;
|
||||||
static bool allcpu;
|
static bool allcpu;
|
||||||
@@ -151,20 +152,6 @@ static unsigned long getnumber(char *word, char stopchar)
|
|||||||
return no;
|
return no;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove all whitespace from string. */
|
|
||||||
static void kill_whitespace(char *s)
|
|
||||||
{
|
|
||||||
char *cp = s;
|
|
||||||
|
|
||||||
for (; *s != '\0'; ++s) {
|
|
||||||
if (isspace(*s))
|
|
||||||
continue;
|
|
||||||
if (isprint(*s))
|
|
||||||
*cp++ = *s;
|
|
||||||
}
|
|
||||||
*cp = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read file to get all online CPUs */
|
/* Read file to get all online CPUs */
|
||||||
static bool get_cpus(char *file, char *buf, size_t bufsz)
|
static bool get_cpus(char *file, char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
@@ -242,29 +229,34 @@ static char *show_ctrset(unsigned long set)
|
|||||||
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
||||||
{
|
{
|
||||||
uint64_t *words = start->cpumask;
|
uint64_t *words = start->cpumask;
|
||||||
unsigned long i, no_a, no_b;
|
unsigned int i, no_a, no_b;
|
||||||
char *cp, *tokens[16]; /* Used to parse command line params */
|
cpu_set_t cpulist;
|
||||||
char cpubuf[256];
|
int rc;
|
||||||
|
|
||||||
|
CPU_ZERO(&cpulist);
|
||||||
start->data_bytes = 0;
|
start->data_bytes = 0;
|
||||||
if (parm)
|
start->counter_sets = S390_HWCTR_ALL; /* Default all counter sets */
|
||||||
kill_whitespace(parm);
|
|
||||||
if (!parm || *parm == ':') {
|
if (parm) { /* CPU list with optional counter set */
|
||||||
/* No CPU list or just counter sets */
|
char *cp = strchr(parm, ':');
|
||||||
if (!get_cpus(CPUS_ONLINE, cpubuf, sizeof(cpubuf)))
|
|
||||||
exit(EXIT_FAILURE);
|
if (cp) { /* Handle counter set */
|
||||||
if (parm)
|
*cp = '\0';
|
||||||
strcat(cpubuf, parm);
|
start->counter_sets = parse_ctrset(++cp);
|
||||||
parm = cpubuf;
|
}
|
||||||
|
|
||||||
|
if (strlen(parm) > 0) /* Handle CPU list */
|
||||||
|
rc = libcpumf_cpuset(parm, &cpulist);
|
||||||
|
else
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
|
||||||
|
if (rc)
|
||||||
|
errx(EXIT_FAILURE, "Cannot use CPU list %s", parm);
|
||||||
|
} else { /* No CPU list and no counter sets */
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
|
||||||
|
if (rc)
|
||||||
|
err(EXIT_FAILURE, "Cannot read file " S390_CPUS_ONLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
cp = strchr(parm, ':');
|
|
||||||
if (cp) { /* Handle counter set */
|
|
||||||
*cp = '\0';
|
|
||||||
start->counter_sets = parse_ctrset(++cp);
|
|
||||||
} else {
|
|
||||||
start->counter_sets = S390_HWCTR_ALL;
|
|
||||||
}
|
|
||||||
/* Check with authorized counter sets */
|
/* Check with authorized counter sets */
|
||||||
if ((start->counter_sets & authorization) != start->counter_sets) {
|
if ((start->counter_sets & authorization) != start->counter_sets) {
|
||||||
unsigned int noton = ~(start->counter_sets & authorization);
|
unsigned int noton = ~(start->counter_sets & authorization);
|
||||||
@@ -276,19 +268,10 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
show_ctrset(noton));
|
show_ctrset(noton));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
|
for (rc = 0; rc < CPU_SETSIZE; ++rc)
|
||||||
++i, parm = NULL) {
|
if (CPU_ISSET(rc, &cpulist))
|
||||||
cp = strchr(tokens[i], '-'); /* Range character? */
|
if (!check_set(rc, rc, start->counter_sets))
|
||||||
if (cp) {
|
errx(EXIT_FAILURE, "Invalid CPU %d", rc);
|
||||||
no_a = getnumber(tokens[i], *cp);
|
|
||||||
no_b = getnumber(++cp, '\0');
|
|
||||||
} else {
|
|
||||||
no_b = getnumber(tokens[i], '\0');
|
|
||||||
no_a = no_b;
|
|
||||||
}
|
|
||||||
if (!check_set(no_a, no_b, start->counter_sets))
|
|
||||||
errx(EXIT_FAILURE, "Invalid CPU list %s", tokens[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
||||||
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
||||||
@@ -298,14 +281,8 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
words[no_b] |= 1ULL << no_a;
|
words[no_b] |= 1ULL << no_a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* no_b is highest used index, swap array */
|
/* no_b is highest used index */
|
||||||
start->cpumask_len = (no_b + 1) * 8;
|
start->cpumask_len = (no_b + 1) * CHAR_BIT;
|
||||||
for (no_a = 0; no_a < no_b; ++no_a, --no_b) {
|
|
||||||
uint64_t tmp = words[no_a];
|
|
||||||
|
|
||||||
words[no_a] = words[no_b];
|
|
||||||
words[no_b] = tmp;
|
|
||||||
}
|
|
||||||
start->version = S390_HWCTR_START_VERSION;
|
start->version = S390_HWCTR_START_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,37 +615,6 @@ static int do_it(char *s)
|
|||||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read counter first and second version number */
|
|
||||||
static bool get_cvn(void)
|
|
||||||
{
|
|
||||||
char *linep = NULL;
|
|
||||||
bool good = false;
|
|
||||||
size_t line_sz;
|
|
||||||
ssize_t nbytes;
|
|
||||||
FILE *slp;
|
|
||||||
|
|
||||||
slp = fopen(SERVICELEVEL, "r");
|
|
||||||
if (!slp) {
|
|
||||||
warn(SERVICELEVEL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
|
|
||||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = sscanf(linep, "CPU-MF: Counter facility: version=%d.%d authorization=%x",
|
|
||||||
&cfvn, &csvn, &authorization);
|
|
||||||
good = rc == 3;
|
|
||||||
if (!good)
|
|
||||||
warnx("Cannot parse line %s", linep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(slp);
|
|
||||||
free(linep);
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("OPTIONS"),
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
{
|
{
|
||||||
@@ -752,7 +698,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
have_support();
|
have_support();
|
||||||
if (!get_cvn())
|
if (!libcpumf_cpumcf_info(&cfvn, &csvn, &authorization))
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
if (!check_setpossible())
|
if (!check_setpossible())
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
+3
-1
@@ -408,8 +408,10 @@ static int read_line(void)
|
|||||||
{
|
{
|
||||||
bzero(line_buffer, LINE_LENGTH);
|
bzero(line_buffer, LINE_LENGTH);
|
||||||
line_ptr = line_buffer;
|
line_ptr = line_buffer;
|
||||||
if (!fgets(line_buffer, LINE_LENGTH, stdin))
|
if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
|
||||||
|
clearerr(stdin);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
while (*line_ptr && !isgraph(*line_ptr))
|
while (*line_ptr && !isgraph(*line_ptr))
|
||||||
line_ptr++;
|
line_ptr++;
|
||||||
|
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ stage3b_reloc.elf:
|
|||||||
|
|
||||||
%.elf: %.o
|
%.elf: %.o
|
||||||
case $* in \
|
case $* in \
|
||||||
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
stage3a) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
||||||
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
stage3b) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
||||||
stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
stage3b_reloc) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
||||||
esac; \
|
esac; \
|
||||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||||
@chmod a-x $@
|
@chmod a-x $@
|
||||||
|
|||||||
@@ -28,13 +28,23 @@ static inline void __noreturn load_psw(struct psw_t psw)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long get_kernel_cmdline_size(void)
|
||||||
|
{
|
||||||
|
unsigned long size = *(volatile unsigned long *)MAX_COMMAND_LINE_SIZE;
|
||||||
|
|
||||||
|
if (size != 0)
|
||||||
|
return size;
|
||||||
|
|
||||||
|
return LEGACY_COMMAND_LINE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
void __noreturn start(void)
|
void __noreturn start(void)
|
||||||
{
|
{
|
||||||
volatile struct stage3b_args *args = &loader_parms;
|
volatile struct stage3b_args *args = &loader_parms;
|
||||||
volatile struct memblob *kernel = &args->kernel;
|
volatile struct memblob *kernel = &args->kernel;
|
||||||
volatile struct memblob *cmdline = &args->cmdline;
|
volatile struct memblob *cmdline = &args->cmdline;
|
||||||
volatile struct memblob *initrd = &args->initrd;
|
volatile struct memblob *initrd = &args->initrd;
|
||||||
volatile struct psw_t psw = args->psw;
|
struct psw_t psw = args->psw;
|
||||||
|
|
||||||
/* set up ASCII and line-mode */
|
/* set up ASCII and line-mode */
|
||||||
sclp_setup(SCLP_LINE_ASCII_INIT);
|
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||||
@@ -42,14 +52,14 @@ void __noreturn start(void)
|
|||||||
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
||||||
panic(EINTERNAL, "Invalid kernel\n");
|
panic(EINTERNAL, "Invalid kernel\n");
|
||||||
|
|
||||||
if (cmdline->size > COMMAND_LINE_SIZE)
|
|
||||||
panic(EINTERNAL, "Command line is too large\n");
|
|
||||||
|
|
||||||
/* move the kernel and cut the kernel header */
|
/* move the kernel and cut the kernel header */
|
||||||
memmove((void *)IMAGE_LOAD_ADDRESS,
|
memmove((void *)IMAGE_LOAD_ADDRESS,
|
||||||
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
||||||
kernel->size - IMAGE_LOAD_ADDRESS);
|
kernel->size - IMAGE_LOAD_ADDRESS);
|
||||||
|
|
||||||
|
if (cmdline->size > get_kernel_cmdline_size())
|
||||||
|
panic(EINTERNAL, "Command line is too large\n");
|
||||||
|
|
||||||
/* move the kernel cmdline */
|
/* move the kernel cmdline */
|
||||||
memmove((void *)COMMAND_LINE,
|
memmove((void *)COMMAND_LINE,
|
||||||
(void *)cmdline->src,
|
(void *)cmdline->src,
|
||||||
|
|||||||
+28
-14
@@ -87,13 +87,23 @@ CRLs. Optional.
|
|||||||
.TP
|
.TP
|
||||||
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
||||||
Specifies the root CA certificate for the verification. If omitted,
|
Specifies the root CA certificate for the verification. If omitted,
|
||||||
the DigiCert root CA certificate installed on the system is used. Use
|
the system wide root CAs installed on the system is used. Use
|
||||||
this only if you trust the specified certificate. Optional.
|
this only if you trust the specified certificate. Optional.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no-verify\fR
|
\fB\-\-no-verify\fR
|
||||||
Do not require the host-key documents to be valid. For testing
|
Do not require the host-key documents to be valid. For testing
|
||||||
purposes, do not use for a production image. Optional.
|
purposes, do not use for a production image. Optional.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
|
||||||
|
Specifies the encryption key you want to use for the PV guest dump. 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. Optional.
|
||||||
|
.TP
|
||||||
\fB\-\-enable\-pckmo\fR
|
\fB\-\-enable\-pckmo\fR
|
||||||
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
||||||
functions. This is the default. Optional.
|
functions. This is the default. Optional.
|
||||||
@@ -105,21 +115,25 @@ functions. Optional.
|
|||||||
\fB\-v\fR, \fB\-\-version\fR
|
\fB\-v\fR, \fB\-\-version\fR
|
||||||
Prints version information, then exits.
|
Prints version information, then exits.
|
||||||
|
|
||||||
.SH EXAMPLE
|
.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
|
.PP
|
||||||
Generate a protected virtualization image in
|
.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
|
||||||
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
|
|
||||||
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
Generate a protected virtualization image with PV guest dump support:
|
||||||
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR,
|
|
||||||
the IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
|
||||||
host-key document in \fI\,host_key.crt\/\fR:
|
|
||||||
.PP
|
|
||||||
.Vb 1
|
|
||||||
.EX
|
|
||||||
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt \-o \fI\,/boot/vmlinuz.pv\/\fR
|
|
||||||
.EE
|
|
||||||
.Ve
|
|
||||||
.PP
|
.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
|
.SH NOTES
|
||||||
.IP "1." 4
|
.IP "1." 4
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ BODY_FILE=$(mktemp)
|
|||||||
ISSUER_DN_FILE=$(mktemp)
|
ISSUER_DN_FILE=$(mktemp)
|
||||||
SUBJECT_DN_FILE=$(mktemp)
|
SUBJECT_DN_FILE=$(mktemp)
|
||||||
DEF_ISSUER_DN_FILE=$(mktemp)
|
DEF_ISSUER_DN_FILE=$(mktemp)
|
||||||
|
CANONICAL_ISSUER_DN_FILE=$(mktemp)
|
||||||
CRL_SERIAL_FILE=$(mktemp)
|
CRL_SERIAL_FILE=$(mktemp)
|
||||||
|
|
||||||
# Cleanup on exit
|
# Cleanup on exit
|
||||||
@@ -30,7 +31,7 @@ cleanup()
|
|||||||
{
|
{
|
||||||
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
||||||
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
||||||
$CRL_SERIAL_FILE
|
$CANONICAL_ISSUER_DN_FILE $CRL_SERIAL_FILE
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
@@ -47,13 +48,21 @@ set -e
|
|||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
cat <<-EOF
|
cat <<-EOF
|
||||||
Usage: `basename $1` host-key-doc signing-key-cert [-c CA-cert] [-r CRL]
|
Usage: `basename $1` [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
|
||||||
|
|
||||||
Verify an IBM Secure Execution host key document against
|
Verify an IBM Secure Execution host key document against
|
||||||
a signing key.
|
a signing key.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-d disable default issuer check of host-key-doc
|
||||||
|
-c CA-cert trusted CA certificate
|
||||||
|
-r CRL list of revoked host-key-docs
|
||||||
|
|
||||||
Note that in order to have the full trust chain verified
|
Note that in order to have the full trust chain verified
|
||||||
it is necessary to provide the issueing CA's certificate.
|
it is necessary to provide the issuing CA's certificate.
|
||||||
|
The default issuer check may be disabled if a non-default
|
||||||
|
signing key certificate needs to be verified against the
|
||||||
|
CA certificate.
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@@ -121,20 +130,34 @@ default_issuer()
|
|||||||
commonName = International Business Machines Corporation
|
commonName = International Business Machines Corporation
|
||||||
countryName = US
|
countryName = US
|
||||||
localityName = Poughkeepsie
|
localityName = Poughkeepsie
|
||||||
organizationalUnitName = IBM Z Host Key Signing Service
|
organizationalUnitName = Key Signing Service
|
||||||
organizationName = International Business Machines Corporation
|
organizationName = International Business Machines Corporation
|
||||||
stateOrProvinceName = New York
|
stateOrProvinceName = New York
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_issuer_files()
|
# As organizationalUnitName can have an arbitrary prefix but must
|
||||||
|
# end with "Key Signing Service" let's normalize the OU name by
|
||||||
|
# stripping off the prefix
|
||||||
|
verify_default_issuer()
|
||||||
{
|
{
|
||||||
default_issuer > $DEF_ISSUER_DN_FILE
|
default_issuer > $DEF_ISSUER_DN_FILE
|
||||||
|
|
||||||
if ! diff $ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
|
||||||
|
$ISSUER_DN_FILE > $CANONICAL_ISSUER_DN_FILE
|
||||||
|
|
||||||
|
if ! diff $CANONICAL_ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
||||||
then
|
then
|
||||||
echo Incorrect default issuer >&2 && exit 1
|
echo Incorrect default issuer >&2 && exit 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_issuer_files()
|
||||||
|
{
|
||||||
|
if [ $1 -eq 1 ]
|
||||||
|
then
|
||||||
|
verify_default_issuer
|
||||||
|
fi
|
||||||
|
|
||||||
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
||||||
then
|
then
|
||||||
@@ -196,14 +219,16 @@ check_file()
|
|||||||
# check args
|
# check args
|
||||||
CRL_FILE=
|
CRL_FILE=
|
||||||
CA_FILE=
|
CA_FILE=
|
||||||
|
CHECK_DEFAULT_ISSUER=1
|
||||||
|
|
||||||
args=$(getopt -qu "r:c:h" $*)
|
args=$(getopt -qu "dr:c:h" $*)
|
||||||
if [ $? = 0 ]
|
if [ $? = 0 ]
|
||||||
then
|
then
|
||||||
set -- $args
|
set -- $args
|
||||||
while [ $1 != "" ]
|
while [ $1 != "" ]
|
||||||
do
|
do
|
||||||
case $1 in
|
case $1 in
|
||||||
|
-d) CHECK_DEFAULT_ISSUER=0; shift;;
|
||||||
-r) CRL_FILE=$2; shift 2;;
|
-r) CRL_FILE=$2; shift 2;;
|
||||||
-c) CA_FILE=$2; shift 2;;
|
-c) CA_FILE=$2; shift 2;;
|
||||||
-h) usage $0; exit 0;;
|
-h) usage $0; exit 0;;
|
||||||
@@ -244,7 +269,7 @@ exit 1
|
|||||||
# Verify the issuer
|
# Verify the issuer
|
||||||
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
||||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
verify_issuer_files
|
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||||
|
|
||||||
# Verify dates
|
# Verify dates
|
||||||
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
||||||
@@ -261,7 +286,7 @@ then
|
|||||||
echo -n "CRL "
|
echo -n "CRL "
|
||||||
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
||||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
verify_issuer_files
|
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||||
|
|
||||||
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
||||||
|
|
||||||
|
|||||||
@@ -29,9 +29,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PV_CERTS_SECURITY_LEVEL 2
|
#define PV_CERTS_SECURITY_LEVEL 2
|
||||||
|
|
||||||
/* SKID for DigiCert Assured ID Root CA */
|
|
||||||
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
|
|
||||||
|
|
||||||
union ecdh_pub_key {
|
union ecdh_pub_key {
|
||||||
struct {
|
struct {
|
||||||
uint8_t x[80];
|
uint8_t x[80];
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||||
#define PV_VERSION_1 0x00000100U
|
#define PV_VERSION_1 0x00000100U
|
||||||
|
|
||||||
|
/* Internal helper macro */
|
||||||
|
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
|
||||||
|
|
||||||
/* Plaintext control flags */
|
/* Plaintext control flags */
|
||||||
#define PV_PCF_PCKM_ECC (1ULL << 5) /* PCKMO encrypt-ECC-key functions allowed */
|
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34) /* dumping of the configuration is allowed */
|
||||||
#define PV_PCF_PCKMO_AES (1ULL << 6) /* PCKMO encrypt-AES-key functions allowed */
|
#define PV_PCF_NO_DECRYPTION __PV_BIT(35) /* prevent Ultravisor decryption during unpack operation */
|
||||||
#define PV_PCF_PCKMO_DEA_TDEA (1ULL << 7) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||||
#define PV_PCF_NO_DECRYPTION (1ULL << 28) /* prevent Ultravisor decryption during unpack operation */
|
#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 */
|
||||||
|
|
||||||
/* maxima for the PV version 1 */
|
/* maxima for the PV version 1 */
|
||||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||||
|
|||||||
+85
-44
@@ -64,13 +64,17 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
{
|
{
|
||||||
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
||||||
|
|
||||||
if (args->pcf && args->allow_pckmo != PV_NOT_SET) {
|
/* Check for mutually exclusive arguments */
|
||||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
if (args->pcf && !(args->allow_pckmo == PV_NOT_SET &&
|
||||||
_("The '--x-pcf' and '--(enable|disable)-pckmo' options are mutually"
|
args->allow_dump == PV_NOT_SET)) {
|
||||||
" exclusive.\nUse 'genprotimg --help' for more information"));
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for unused arguments */
|
||||||
if (args->unused_values->len > 0) {
|
if (args->unused_values->len > 0) {
|
||||||
g_autofree gchar *unused = NULL;
|
g_autofree gchar *unused = NULL;
|
||||||
|
|
||||||
@@ -88,6 +92,14 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for mandatory arguments */
|
||||||
|
if (args->allow_dump == PV_TRUE && !args->cust_comm_key_path) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Option '--allow-dump' requires the '--comm-key' option.\nUse 'genprotimg "
|
||||||
|
"--help' for more information"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!args->output_path) {
|
if (!args->output_path) {
|
||||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
||||||
@@ -111,7 +123,7 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
||||||
g_set_error(
|
g_set_error(
|
||||||
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
_("Either specify the IBM Z signing key and (DigiCert) intermediate CA certificate\n"
|
_("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"
|
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
||||||
"host-key document verification completely (at your own risk)."));
|
"host-key document verification completely (at your own risk)."));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -155,14 +167,14 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
|||||||
{
|
{
|
||||||
gchar **args_option = NULL;
|
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"))
|
if (g_str_equal(option, "--root-ca"))
|
||||||
args_option = &args->root_ca_path;
|
args_option = &args->root_ca_path;
|
||||||
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||||
args_option = &args->output_path;
|
args_option = &args->output_path;
|
||||||
if (g_str_equal(option, "--x-comp-key"))
|
if (g_str_equal(option, "--x-comp-key"))
|
||||||
args_option = &args->xts_key_path;
|
args_option = &args->xts_key_path;
|
||||||
if (g_str_equal(option, "--x-comm-key"))
|
|
||||||
args_option = &args->cust_comm_key_path;
|
|
||||||
if (g_str_equal(option, "--x-header-key"))
|
if (g_str_equal(option, "--x-header-key"))
|
||||||
args_option = &args->cust_root_key_path;
|
args_option = &args->cust_root_key_path;
|
||||||
if (g_str_equal(option, "--x-pcf"))
|
if (g_str_equal(option, "--x-pcf"))
|
||||||
@@ -188,19 +200,6 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean cb_enable_disable_flag(const gchar *option, const gchar *value G_GNUC_UNUSED,
|
|
||||||
PvArgs *args, GError **err G_GNUC_UNUSED)
|
|
||||||
{
|
|
||||||
if (g_str_equal(option, "--enable-pckmo"))
|
|
||||||
args->allow_pckmo = PV_TRUE;
|
|
||||||
else if (g_str_equal(option, "--disable-pckmo"))
|
|
||||||
args->allow_pckmo = PV_FALSE;
|
|
||||||
else
|
|
||||||
g_assert_not_reached();
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
||||||
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
||||||
GError **err G_GNUC_UNUSED)
|
GError **err G_GNUC_UNUSED)
|
||||||
@@ -217,8 +216,51 @@ static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
|
|||||||
return TRUE;
|
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->allow_##FLAG == PV_NOT_SET || \
|
||||||
|
args->allow_##FLAG == VALUE)) { \
|
||||||
|
g_set_error(err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \
|
||||||
|
"'--enable-" #FLAG "' and '--disable-" #FLAG \
|
||||||
|
"' are mutually exclusive"); \
|
||||||
|
return FALSE; \
|
||||||
|
} \
|
||||||
|
args->allow_##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(FLAG, ENABLE_DESC, DISABLE_DESC) \
|
||||||
|
{ \
|
||||||
|
.long_name = "enable-" #FLAG, \
|
||||||
|
.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-" #FLAG, \
|
||||||
|
.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 INDENT " "
|
||||||
|
|
||||||
|
/* Define the callbacks for mutually exclusive command line flags */
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(dump)
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(pckmo)
|
||||||
|
|
||||||
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
@@ -282,21 +324,28 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
||||||
"(optional)."),
|
"(optional)."),
|
||||||
.arg_description = _("PARMFILE") },
|
.arg_description = _("PARMFILE") },
|
||||||
{.long_name = "enable-pckmo",
|
MUT_EXCL_BOOL_FLAG(
|
||||||
.short_name = 0,
|
dump,
|
||||||
.flags = G_OPTION_FLAG_NO_ARG,
|
_("Enable PV guest dumps (optional). This option\n" INDENT
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
"requires the '--comm-key' option."),
|
||||||
.arg_data = cb_enable_disable_flag,
|
_("Disable PV guest dumps (default) (optional).")),
|
||||||
.description = _("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
MUT_EXCL_BOOL_FLAG(
|
||||||
"ECC PCKMO key encryption functions (default)\n" INDENT
|
pckmo,
|
||||||
"(optional).")},
|
_("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||||
{.long_name = "disable-pckmo",
|
"ECC PCKMO key encryption functions (default)\n" INDENT
|
||||||
.short_name = 0,
|
"(optional)."),
|
||||||
.flags = G_OPTION_FLAG_NO_ARG,
|
_("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
"ECC PCKMO key encryption functions (optional).")),
|
||||||
.arg_data = cb_enable_disable_flag,
|
{ .long_name = "comm-key",
|
||||||
.description = _("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
.short_name = 0,
|
||||||
"ECC PCKMO key encryption functions (optional).")},
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _(
|
||||||
|
"FILE contains the key with which you encrypt\n" INDENT
|
||||||
|
"the PV guest dump (optional). Required by\n" INDENT
|
||||||
|
"the '--enable-dump' option."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
{ .long_name = "crl",
|
{ .long_name = "crl",
|
||||||
.short_name = 0,
|
.short_name = 0,
|
||||||
.flags = G_OPTION_FLAG_NONE,
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
@@ -355,15 +404,6 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
};
|
};
|
||||||
|
|
||||||
GOptionEntry x_entries[] = {
|
GOptionEntry x_entries[] = {
|
||||||
{ .long_name = "x-comm-key",
|
|
||||||
.short_name = 0,
|
|
||||||
.flags = G_OPTION_FLAG_FILENAME,
|
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
|
||||||
.arg_data = cb_set_string_option,
|
|
||||||
.description = _(
|
|
||||||
"Use FILE as the customer communication key.\n" INDENT
|
|
||||||
"Optional; default: auto-generated."),
|
|
||||||
.arg_description = _("FILE") },
|
|
||||||
{ .long_name = "x-comp-key",
|
{ .long_name = "x-comp-key",
|
||||||
.short_name = 0,
|
.short_name = 0,
|
||||||
.flags = G_OPTION_FLAG_FILENAME,
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
@@ -446,6 +486,7 @@ PvArgs *pv_args_new(void)
|
|||||||
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
||||||
|
|
||||||
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
args->allow_dump = PV_NOT_SET;
|
||||||
args->allow_pckmo = PV_NOT_SET;
|
args->allow_pckmo = PV_NOT_SET;
|
||||||
return g_steal_pointer(&args);
|
return g_steal_pointer(&args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ typedef struct {
|
|||||||
gboolean offline;
|
gboolean offline;
|
||||||
gchar *pcf;
|
gchar *pcf;
|
||||||
gchar *scf;
|
gchar *scf;
|
||||||
|
PvTristate allow_dump;
|
||||||
PvTristate allow_pckmo;
|
PvTristate allow_pckmo;
|
||||||
gchar *psw_addr; /* PSW address which will be used for the start of
|
gchar *psw_addr; /* PSW address which will be used for the start of
|
||||||
* the actual component (e.g. Linux kernel)
|
* the actual component (e.g. Linux kernel)
|
||||||
|
|||||||
@@ -248,19 +248,6 @@ gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
|||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert uint64_t address to byte array */
|
|
||||||
static void uint64_to_uint8_buf(uint8_t dst[8], uint64_t addr)
|
|
||||||
{
|
|
||||||
uint8_t *p = (uint8_t *)&addr;
|
|
||||||
|
|
||||||
g_assert(dst);
|
|
||||||
|
|
||||||
for (gint i = 0; i < 8; i++) {
|
|
||||||
/* cppcheck-suppress objectIndex */
|
|
||||||
dst[i] = p[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
@@ -273,11 +260,8 @@ int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
uint64_t cur_be = GUINT64_TO_BE(cur);
|
uint64_t cur_be = GUINT64_TO_BE(cur);
|
||||||
uint8_t addr_buf[8];
|
|
||||||
|
|
||||||
uint64_to_uint8_buf(addr_buf, cur_be);
|
if (EVP_DigestUpdate(ctx, &cur_be, sizeof(cur_be)) != 1) {
|
||||||
|
|
||||||
if (EVP_DigestUpdate(ctx, addr_buf, sizeof(addr_buf)) != 1) {
|
|
||||||
g_set_error(err, PV_CRYPTO_ERROR,
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
PV_CRYPTO_ERROR_INTERNAL,
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
_("EVP_DigestUpdate failed"));
|
_("EVP_DigestUpdate failed"));
|
||||||
|
|||||||
@@ -229,7 +229,9 @@ static gint pv_img_set_psw_addr(PvImage *img, const gchar *psw_addr_s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
||||||
const gchar *scf_s, PvTristate allow_pckmo, GError **err)
|
const gchar *scf_s,
|
||||||
|
PvTristate allow_dump,
|
||||||
|
PvTristate allow_pckmo, GError **err)
|
||||||
{
|
{
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
|
|
||||||
@@ -247,6 +249,11 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
|||||||
img->scf = flags;
|
img->scf = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allow_dump == PV_TRUE)
|
||||||
|
img->pcf |= PV_PCF_ALLOW_DUMPING;
|
||||||
|
else if (allow_dump == PV_FALSE)
|
||||||
|
img->pcf &= ~PV_PCF_ALLOW_DUMPING;
|
||||||
|
|
||||||
if (allow_pckmo == PV_TRUE)
|
if (allow_pckmo == PV_TRUE)
|
||||||
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
|
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
|
||||||
else if (allow_pckmo == PV_FALSE)
|
else if (allow_pckmo == PV_FALSE)
|
||||||
@@ -304,9 +311,10 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
||||||
* DigiCert intermediate CA) that are required to establish a chain of
|
* intermediate CA) that are required to establish a chain of trust
|
||||||
* trust starting from the host-key document up to the root CA (if not
|
* starting from the host-key document up to the root CA (if not
|
||||||
* otherwise specified that's the DigiCert Assured ID Root CA).
|
* otherwise specified that can be one of the system wide installed
|
||||||
|
* root CAs, e.g. DigiCert).
|
||||||
*/
|
*/
|
||||||
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
||||||
if (!untrusted_certs_with_path)
|
if (!untrusted_certs_with_path)
|
||||||
@@ -341,9 +349,8 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
* For this we must check:
|
* For this we must check:
|
||||||
*
|
*
|
||||||
* 1. Can a chain of trust be established ending in a root CA
|
* 1. Can a chain of trust be established ending in a root CA
|
||||||
* 2. Is the correct root CA ued? It has either to be the
|
* 2. Is the correct root CA used? It has either to be a system CA
|
||||||
* 'DigiCert Assured ID Root CA' or the root CA specified via
|
* or the root CA specified via command line.
|
||||||
* command line.
|
|
||||||
*/
|
*/
|
||||||
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
||||||
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
||||||
@@ -364,17 +371,12 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Verify the build chain of trust chain. If the user passes a
|
/* If there is a chain of trust using either the provided root
|
||||||
* trusted root CA on the command line then the check for the
|
* CA on the command line or a system wide trusted root CA.
|
||||||
* Subject Key Identifier (SKID) is skipped, otherwise let's
|
|
||||||
* check if the SKID meets our expectation.
|
|
||||||
*/
|
*/
|
||||||
if (!root_ca_path &&
|
if (check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
||||||
check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
err) < 0)
|
||||||
get_digicert_assured_id_root_ca_skid(),
|
|
||||||
err) < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
||||||
if (!ibm_signing_crls) {
|
if (!ibm_signing_crls) {
|
||||||
@@ -588,7 +590,7 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
|||||||
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
||||||
|
|
||||||
if (args->root_ca_path)
|
if (args->root_ca_path)
|
||||||
g_warning(_("A different root CA than the default DigiCert root CA is selected. Ensure that this root CA is trusted."));
|
g_warning(_("The root CA is selected through the command line. Ensure that this root CA is trusted."));
|
||||||
|
|
||||||
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
||||||
if (!ret->comps)
|
if (!ret->comps)
|
||||||
@@ -608,7 +610,9 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* set the control flags: PCF and SCF */
|
/* set the control flags: PCF and SCF */
|
||||||
if (pv_img_set_control_flags(ret, args->pcf, args->scf, args->allow_pckmo, err) < 0)
|
if (pv_img_set_control_flags(ret, args->pcf, args->scf,
|
||||||
|
args->allow_dump, args->allow_pckmo,
|
||||||
|
err) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* read in the keys */
|
/* read in the keys */
|
||||||
|
|||||||
@@ -440,7 +440,7 @@ static int check_signature_algo_match(const EVP_PKEY *pkey, const X509 *subject,
|
|||||||
|
|
||||||
static X509_CRL *load_crl_from_bio(BIO *bio)
|
static X509_CRL *load_crl_from_bio(BIO *bio)
|
||||||
{
|
{
|
||||||
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, 0, NULL);
|
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
|
||||||
gint rc;
|
gint rc;
|
||||||
|
|
||||||
if (crl)
|
if (crl)
|
||||||
@@ -1079,8 +1079,8 @@ int store_set_verify_param(X509_STORE *store, GError **err)
|
|||||||
g_abort();
|
g_abort();
|
||||||
|
|
||||||
/* The maximum depth level of the chain of trust for the verification of
|
/* The maximum depth level of the chain of trust for the verification of
|
||||||
* the IBM Z signing key is 2, i.e. IBM Z signing key -> (DigiCert)
|
* the IBM Z signing key is 2, i.e. IBM Z signing key -> intermediate CA
|
||||||
* intermediate CA -> (DigiCert) root CA
|
* -> root CA
|
||||||
*/
|
*/
|
||||||
X509_VERIFY_PARAM_set_depth(param, 2);
|
X509_VERIFY_PARAM_set_depth(param, 2);
|
||||||
|
|
||||||
@@ -1267,46 +1267,38 @@ static int security_level_to_bits(int level)
|
|||||||
return security_bits[level];
|
return security_bits[level];
|
||||||
}
|
}
|
||||||
|
|
||||||
static ASN1_OCTET_STRING *digicert_assured_id_root_ca;
|
|
||||||
|
|
||||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void)
|
|
||||||
{
|
|
||||||
pv_crypto_init();
|
|
||||||
return digicert_assured_id_root_ca;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used for the caching of the downloaded CRLs */
|
/* Used for the caching of the downloaded CRLs */
|
||||||
static GHashTable *cached_crls;
|
static GHashTable *cached_crls;
|
||||||
|
|
||||||
void pv_crypto_init(void)
|
void pv_crypto_init(void)
|
||||||
{
|
{
|
||||||
if (digicert_assured_id_root_ca)
|
if (cached_crls)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
||||||
(GDestroyNotify)X509_CRL_free);
|
(GDestroyNotify)X509_CRL_free);
|
||||||
digicert_assured_id_root_ca = s2i_ASN1_OCTET_STRING(
|
|
||||||
NULL, NULL, DIGICERT_ASSURED_ID_ROOT_CA_SKID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pv_crypto_cleanup(void)
|
void pv_crypto_cleanup(void)
|
||||||
{
|
{
|
||||||
if (!digicert_assured_id_root_ca)
|
if (!cached_crls)
|
||||||
return;
|
return;
|
||||||
g_clear_pointer(&cached_crls, g_hash_table_destroy);
|
g_clear_pointer(&cached_crls, g_hash_table_destroy);
|
||||||
g_clear_pointer(&digicert_assured_id_root_ca, ASN1_OCTET_STRING_free);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
||||||
const ASN1_OCTET_STRING *skid, GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
const ASN1_OCTET_STRING *ca_skid = NULL;
|
const X509_NAME *ca_x509_subject = NULL;
|
||||||
|
g_autofree gchar *ca_subject = NULL;
|
||||||
gint len = sk_X509_num(chain);
|
gint len = sk_X509_num(chain);
|
||||||
X509 *ca = NULL;
|
X509 *ca = NULL;
|
||||||
|
|
||||||
g_assert(skid);
|
|
||||||
/* at least one root and one leaf certificate must be defined */
|
/* at least one root and one leaf certificate must be defined */
|
||||||
g_assert(len >= 2);
|
if (len < 2) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("there must be at least on root and one leaf certificate in the chain of trust"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* get the root certificate of the chain of trust */
|
/* get the root certificate of the chain of trust */
|
||||||
ca = sk_X509_value(chain, len - 1);
|
ca = sk_X509_value(chain, len - 1);
|
||||||
@@ -1316,19 +1308,21 @@ gint check_chain_parameters(const STACK_OF_X509 *chain,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ca_skid = X509_get0_subject_key_id(ca);
|
ca_x509_subject = X509_get_subject_name(ca);
|
||||||
if (!ca_skid) {
|
if (!ca_x509_subject) {
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
_("malformed root certificate"));
|
_("subject of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_STRING_cmp(ca_skid, skid) != 0) {
|
ca_subject = X509_NAME_oneline(ca_x509_subject, NULL, 0);
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_WRONG_CA_USED,
|
if (!ca_subject) {
|
||||||
_("expecting DigiCert root CA to be used"));
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("subject name of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_info("Root CA used: '%s'", ca_subject);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
|
|||||||
gint verify_flags, GError **err);
|
gint verify_flags, GError **err);
|
||||||
void pv_crypto_init(void);
|
void pv_crypto_init(void);
|
||||||
void pv_crypto_cleanup(void);
|
void pv_crypto_cleanup(void);
|
||||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void);
|
|
||||||
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
||||||
gint verify_flags, int level, GError **err);
|
gint verify_flags, int level, GError **err);
|
||||||
X509 *load_cert_from_file(const char *path, GError **err);
|
X509 *load_cert_from_file(const char *path, GError **err);
|
||||||
@@ -138,8 +137,7 @@ X509_STORE *store_setup(const gchar *root_ca_path,
|
|||||||
int store_set_verify_param(X509_STORE *store, GError **err);
|
int store_set_verify_param(X509_STORE *store, GError **err);
|
||||||
X509_CRL *load_crl_by_cert(X509 *cert, 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);
|
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
||||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
gint check_chain_parameters(const STACK_OF_X509 *chain, GError **err);
|
||||||
const ASN1_OCTET_STRING *skid, GError **err);
|
|
||||||
X509_NAME *c2b_name(const X509_NAME *name);
|
X509_NAME *c2b_name(const X509_NAME *name);
|
||||||
|
|
||||||
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||||
|
|||||||
+6
-6
@@ -16,17 +16,17 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"hmcdrvfs", \
|
"hmcdrvfs", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0")
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
ALL_CFLAGS += -DFUSE_USE_VERSION=26 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
|
ALL_CFLAGS += -DFUSE_USE_VERSION=30 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
|
||||||
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
|
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
|
||||||
|
|
||||||
OBJECTS = hmcdrvfs.o
|
OBJECTS = hmcdrvfs.o
|
||||||
|
|||||||
@@ -111,9 +111,6 @@ allow access by other users
|
|||||||
.B -o allow_root
|
.B -o allow_root
|
||||||
allow access by root
|
allow access by root
|
||||||
.TP
|
.TP
|
||||||
.B -o nonempty
|
|
||||||
allow mounts over non-empty file/dir
|
|
||||||
.TP
|
|
||||||
.B -o default_permissions
|
.B -o default_permissions
|
||||||
enable permission checking by kernel
|
enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+9
-6
@@ -990,7 +990,7 @@ static int hmcdrv_cache_dir(const char *dir, fuse_fill_dir_t filler, void *buf)
|
|||||||
hmcdrv_cache_refresh(path, &st, symlink);
|
hmcdrv_cache_refresh(path, &st, symlink);
|
||||||
|
|
||||||
if ((filler != NULL) &&
|
if ((filler != NULL) &&
|
||||||
(filler(buf, fname, &st, 0) != 0))
|
(filler(buf, fname, &st, 0, 0) != 0))
|
||||||
filler = NULL; /* stop filling */
|
filler = NULL; /* stop filling */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
strftime(symlink, sizeof(symlink),
|
strftime(symlink, sizeof(symlink),
|
||||||
@@ -1109,7 +1109,8 @@ static struct hmcdrv_fuse_file *hmcdrv_file_get(const char *path)
|
|||||||
*
|
*
|
||||||
* Note: The most important function which FUSE calls (very often).
|
* Note: The most important function which FUSE calls (very often).
|
||||||
*/
|
*/
|
||||||
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf)
|
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *UNUSED(fi))
|
||||||
{
|
{
|
||||||
struct hmcdrv_fuse_file *fp;
|
struct hmcdrv_fuse_file *fp;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@@ -1175,12 +1176,13 @@ static int hmcdrv_fuse_opendir(const char *UNUSED(path),
|
|||||||
*/
|
*/
|
||||||
static int hmcdrv_fuse_readdir(const char *path, void *buf,
|
static int hmcdrv_fuse_readdir(const char *path, void *buf,
|
||||||
fuse_fill_dir_t filler, off_t UNUSED(offset),
|
fuse_fill_dir_t filler, off_t UNUSED(offset),
|
||||||
struct fuse_file_info *UNUSED(fi))
|
struct fuse_file_info *UNUSED(fi),
|
||||||
|
enum fuse_readdir_flags UNUSED(flags))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
pthread_mutex_lock(&hmcdrv_ctx.mutex);
|
pthread_mutex_lock(&hmcdrv_ctx.mutex);
|
||||||
ret = hmcdrv_cache_dir(path, filler, buf);
|
ret = hmcdrv_cache_dir(path, filler, buf);
|
||||||
@@ -1232,7 +1234,8 @@ static int hmcdrv_fuse_read(const char *path, char *buf, size_t size,
|
|||||||
* Return: value to be passed in the private_data field of fuse_context to
|
* Return: value to be passed in the private_data field of fuse_context to
|
||||||
* all file operations and as a parameter to the destroy() method
|
* all file operations and as a parameter to the destroy() method
|
||||||
*/
|
*/
|
||||||
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn))
|
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn),
|
||||||
|
struct fuse_config *UNUSED(cfg))
|
||||||
{
|
{
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -23,11 +23,11 @@ else # HAVE_FUSE
|
|||||||
# FUSE
|
# FUSE
|
||||||
#
|
#
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -I/usr/include/fuse
|
FUSE_CFLAGS = -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -67,8 +67,9 @@ check-dep-fuse:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"hsavmcore", \
|
"hsavmcore", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
touch check-dep-fuse
|
touch check-dep-fuse
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ sudo reboot
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo dnf install -y fuse fuse-devel systemd-devel
|
sudo dnf install -y fuse3 fuse3-devel systemd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ sudo reboot
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo zypper install -y fuse fuse-devel systemd-devel
|
sudo zypper install -y fuse3 fuse3-devel systemd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt-get install -y make gcc kdump-tools fuse libfuse-dev libsystemd-dev
|
sudo apt-get install -y make gcc kdump-tools fuse3 libfuse3-dev libsystemd-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
+11
-6
@@ -15,7 +15,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
|
|
||||||
#include "lib/util_log.h"
|
#include "lib/util_log.h"
|
||||||
@@ -31,8 +31,11 @@ struct vmcore_overlay {
|
|||||||
bool fuse_debug;
|
bool fuse_debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
|
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void)fi;
|
||||||
|
|
||||||
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
|
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@@ -54,18 +57,20 @@ static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
|
|||||||
|
|
||||||
static int vmcore_fuse_readdir(const char *path, void *buf,
|
static int vmcore_fuse_readdir(const char *path, void *buf,
|
||||||
fuse_fill_dir_t filler, off_t offset,
|
fuse_fill_dir_t filler, off_t offset,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
(void)offset;
|
(void)offset;
|
||||||
(void)fi;
|
(void)fi;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (strcmp(path, ROOT_DIR) != 0)
|
if (strcmp(path, ROOT_DIR) != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* We have only one file */
|
/* We have only one file */
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
filler(buf, VMCORE_FILE, NULL, 0);
|
filler(buf, VMCORE_FILE, NULL, 0, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,10 +23,11 @@
|
|||||||
#define INITRD_SIZE _AC(0x10410, UL)
|
#define INITRD_SIZE _AC(0x10410, UL)
|
||||||
#define OLDMEM_BASE _AC(0x10418, UL)
|
#define OLDMEM_BASE _AC(0x10418, UL)
|
||||||
#define OLDMEM_SIZE _AC(0x10420, UL)
|
#define OLDMEM_SIZE _AC(0x10420, UL)
|
||||||
|
#define MAX_COMMAND_LINE_SIZE _AC(0x10430, UL)
|
||||||
#define COMMAND_LINE _AC(0x10480, UL)
|
#define COMMAND_LINE _AC(0x10480, UL)
|
||||||
|
|
||||||
/* Parameter sizes */
|
/* Parameter sizes */
|
||||||
#define COMMAND_LINE_SIZE 896
|
#define LEGACY_COMMAND_LINE_SIZE 896
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
/* 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 LIBCPUMF_H
|
||||||
|
#define LIBCPUMF_H
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define S390_CPUMF_CF "/sys/devices/cpum_cf/"
|
||||||
|
#define S390_CPUMF_CFDIAG "/sys/devices/cpum_cf_diag/"
|
||||||
|
#define S390_CPUMF_SF "/sys/devices/cpum_sf/"
|
||||||
|
#define S390_CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
|
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
|
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read out the PMU type from a given file.
|
||||||
|
*
|
||||||
|
* Return the PMU type number assigned to this PMU by the kernel. This is
|
||||||
|
* a non zero number.
|
||||||
|
* If the PMU does not exist return -1 and set errno.
|
||||||
|
*
|
||||||
|
* @param[in] dirname Name of the event directory in sysfs
|
||||||
|
*/
|
||||||
|
int libcpumf_pmutype(const char *dirname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read out the CPU list from a given file name, for example from files
|
||||||
|
* /sys/devices/system/cpu/online or /sys/devices/system/cpu/possible.
|
||||||
|
*
|
||||||
|
* Return the cpu_set_t created from parsing the CPU list in the second
|
||||||
|
* parameter.
|
||||||
|
* Return code of zero indicates proper conversion and -1 indicates an
|
||||||
|
* error.
|
||||||
|
*
|
||||||
|
* @param[in] buffer Comma separated string of a CPU list
|
||||||
|
* @param[in] filename Name of a sysfs CPU list file name
|
||||||
|
* @param[out] mask Converted buffer into cpu_set_t mask structure
|
||||||
|
*/
|
||||||
|
int libcpumf_cpuset(const char *buffer, cpu_set_t *mask);
|
||||||
|
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Counting Facility hardware information
|
||||||
|
*
|
||||||
|
* Return true if CPU Measurement Counter facility information has been
|
||||||
|
* retrieved and is valid.
|
||||||
|
*
|
||||||
|
* Return false if the information could not be extracted from the file.
|
||||||
|
*
|
||||||
|
* @param[out] cfvn Contains CPUMF counter first version number
|
||||||
|
* @param[out] csvn Contains CPUMF counter second version number
|
||||||
|
* @param[out] auth Contains CPUMF counter set authorization level
|
||||||
|
*/
|
||||||
|
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Counter Facility is available.
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_cpumcf(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Sampling Facility hardware information
|
||||||
|
*
|
||||||
|
* Read all necessary information from /sysfs file /proc/service_levels
|
||||||
|
* to return CPU Measurement Counter Sampling facility information
|
||||||
|
* characteristics.
|
||||||
|
* Return true on success and false when the data can not be retrieved.
|
||||||
|
*
|
||||||
|
* @param[out] min Minimum supported sampling interval
|
||||||
|
* @param[out] max Maximum supported sampling interval
|
||||||
|
* @param[out] speed Current CPU speed, number of CPU cylces per
|
||||||
|
* microsecond
|
||||||
|
* @param[out] basic_sz Basic sample size in bytes
|
||||||
|
* @param[out] diag_sz Diagnostic sample size in bytes
|
||||||
|
*/
|
||||||
|
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||||
|
unsigned long *speed, int *basic_sz, int *diag_sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Sampling Facility is available.
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_cpumsf(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Sampling Facility buffer sizes are
|
||||||
|
* available.
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_sfb(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Sampling Facility supported sampling buffer sizes.
|
||||||
|
*
|
||||||
|
* Return the minimum and maximum CPU Measurement sampling facitity buffer
|
||||||
|
* sizes supported.
|
||||||
|
* Return true on success and false otherwise.
|
||||||
|
*
|
||||||
|
* @param[out] min Minimum supported sampling buffer size
|
||||||
|
* @param[out] max Maximum supported sampling buffer size
|
||||||
|
*/
|
||||||
|
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
include ../common.mak
|
||||||
|
|
||||||
|
lib = libcpumf.a
|
||||||
|
|
||||||
|
examples = libcpumf_example
|
||||||
|
|
||||||
|
all: $(lib)
|
||||||
|
examples: $(lib) $(examples)
|
||||||
|
|
||||||
|
objects = libcpumf_pmutype.o libcpumf_cpuset.o libcpumf_support.o
|
||||||
|
|
||||||
|
$(lib): $(objects)
|
||||||
|
|
||||||
|
install: all
|
||||||
|
|
||||||
|
libcpumf_example: libcpumf_example.o $(lib)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(lib) $(examples)
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
int libcpumf_cpuset(const char *parm, cpu_set_t *mask)
|
||||||
|
{
|
||||||
|
char *cp, *buffer = strdup(parm);
|
||||||
|
int to, from, rc;
|
||||||
|
|
||||||
|
if (!buffer) /* Errno set to ENOMEM */
|
||||||
|
return -1;
|
||||||
|
/* Check for invalid characters, such as 11.12 instead 11-12
|
||||||
|
* but allow blanks and newline. Newline is appended
|
||||||
|
* when the string is taken from sysfs files, for example
|
||||||
|
* /sys/devices/system/cpu/online
|
||||||
|
*/
|
||||||
|
if (strspn(buffer, "0123456789-,\n ") != strlen(buffer)) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
CPU_ZERO(mask);
|
||||||
|
for (; (cp = strtok(buffer, ",")); buffer = NULL) {
|
||||||
|
char *dash = strchr(cp, '-'); /* Range character? */
|
||||||
|
bool is_ok;
|
||||||
|
|
||||||
|
if (dash) {
|
||||||
|
rc = sscanf(cp, "%d-%d", &from, &to);
|
||||||
|
is_ok = rc == 2;
|
||||||
|
} else {
|
||||||
|
rc = sscanf(cp, "%d", &to);
|
||||||
|
from = to;
|
||||||
|
is_ok = rc == 1;
|
||||||
|
}
|
||||||
|
if (!is_ok) {
|
||||||
|
errno = ERANGE;
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for (; from <= to; ++from)
|
||||||
|
CPU_SET(from, mask);
|
||||||
|
}
|
||||||
|
rc = 0;
|
||||||
|
out:
|
||||||
|
free(buffer);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask)
|
||||||
|
{
|
||||||
|
char *txt = NULL;
|
||||||
|
ssize_t ret = -1;
|
||||||
|
size_t len = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(filename, "r");
|
||||||
|
if (!fp)
|
||||||
|
return ret;
|
||||||
|
/* Read out file, one line expected */
|
||||||
|
ret = getline(&txt, &len, fp);
|
||||||
|
fclose(fp);
|
||||||
|
if (ret > 0)
|
||||||
|
ret = libcpumf_cpuset(txt, mask);
|
||||||
|
free(txt);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
unsigned long min, max, speed, sfb_min, sfb_max;
|
||||||
|
int rc, pmu, cfvn, csvn, auth;
|
||||||
|
cpu_set_t set;
|
||||||
|
|
||||||
|
pmu = libcpumf_pmutype(S390_CPUMF_CF);
|
||||||
|
if (pmu >= 0)
|
||||||
|
printf("PMU %stype %d\n", S390_CPUMF_CF, pmu);
|
||||||
|
else
|
||||||
|
printf("PMU %stype error %d\n", S390_CPUMF_CF, errno);
|
||||||
|
pmu = libcpumf_pmutype(S390_CPUMF_SF);
|
||||||
|
if (pmu >= 0)
|
||||||
|
printf("PMU %stype %d\n", S390_CPUMF_SF, pmu);
|
||||||
|
else
|
||||||
|
printf("PMU %stype error %d\n", S390_CPUMF_SF, errno);
|
||||||
|
pmu = libcpumf_pmutype(S390_CPUMF_CFDIAG);
|
||||||
|
if (pmu >= 0)
|
||||||
|
printf("PMU %stype %d\n", S390_CPUMF_CFDIAG, pmu);
|
||||||
|
else
|
||||||
|
printf("PMU %stype error %d\n", S390_CPUMF_CFDIAG, errno);
|
||||||
|
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &set);
|
||||||
|
if (rc == 0) {
|
||||||
|
puts("Online CPUs:");
|
||||||
|
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||||
|
if (CPU_ISSET(i, &set))
|
||||||
|
printf("%d ", i);
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
rc = libcpumf_cpuset("0-7,9,11-12 ,15", &set);
|
||||||
|
if (rc == 0) {
|
||||||
|
puts("String CPUs:");
|
||||||
|
for (int i = 0; i < CPU_SETSIZE; ++i)
|
||||||
|
if (CPU_ISSET(i, &set))
|
||||||
|
printf("%d ", i);
|
||||||
|
putchar('\n');
|
||||||
|
} else {
|
||||||
|
printf("libcpumf_cpuset input invalid %d\n", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("CPUMCF support %d\n", libcpumf_have_cpumcf());
|
||||||
|
rc = libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
|
||||||
|
printf("libcpumf_cpumcf_info %d", rc);
|
||||||
|
if (rc)
|
||||||
|
printf(" cfvn %d csvn %d authorization %#x", cfvn, csvn, auth);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
printf("CPUMSF support %d\n", libcpumf_have_cpumsf());
|
||||||
|
rc = libcpumf_cpumsf_info(&min, &max, &speed, &cfvn, &csvn);
|
||||||
|
printf("libcpumf_cpumsf_info %d", rc);
|
||||||
|
if (rc)
|
||||||
|
printf(" min %ld max %ld speed %#lx basic %d diag %d", min,
|
||||||
|
max, speed, cfvn, csvn);
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
printf("CPUMSF have sfb %d\n", libcpumf_have_sfb());
|
||||||
|
rc = libcpumf_sfb_info(&sfb_min, &sfb_max);
|
||||||
|
printf("libcpumf_sfb_info %d", rc);
|
||||||
|
if (rc)
|
||||||
|
printf(" sfb_min %lu sfb_max %lu", sfb_min, sfb_max);
|
||||||
|
putchar('\n');
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
int libcpumf_pmutype(const char *dirname)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
char *fn;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = asprintf(&fn, "%s/type", dirname);
|
||||||
|
if (ret == -1) /* No memory, errno set */
|
||||||
|
return ret;
|
||||||
|
file = fopen(fn, "r");
|
||||||
|
free(fn);
|
||||||
|
ret = -1; /* Errno set on file open error */
|
||||||
|
if (file) {
|
||||||
|
/* Read out a single number from that file */
|
||||||
|
if (fscanf(file, "%u", &ret) != 1)
|
||||||
|
/* Unexpected format error, set errno */
|
||||||
|
errno = -ERANGE;
|
||||||
|
fclose(file);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
|
#define SERVICELEVEL "/proc/service_levels"
|
||||||
|
|
||||||
|
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth)
|
||||||
|
{
|
||||||
|
char *linep = NULL;
|
||||||
|
bool rc = false;
|
||||||
|
size_t line_sz;
|
||||||
|
ssize_t nbytes;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(SERVICELEVEL, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(EXIT_FAILURE, SERVICELEVEL);
|
||||||
|
|
||||||
|
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
|
||||||
|
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
||||||
|
int cnt = sscanf(linep, "CPU-MF: Counter facility:"
|
||||||
|
" version=%d.%d authorization=%x",
|
||||||
|
cfvn, csvn, auth);
|
||||||
|
if (cnt != 3) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
rc = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
fclose(fp);
|
||||||
|
free(linep);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_cpumcf(void)
|
||||||
|
{
|
||||||
|
int cfvn, csvn, auth;
|
||||||
|
|
||||||
|
return libcpumf_cpumcf_info(&cfvn, &csvn, &auth);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||||
|
unsigned long *speed, int *basic_sz, int *diag_sz)
|
||||||
|
{
|
||||||
|
char *linep = NULL;
|
||||||
|
bool rc = true;
|
||||||
|
size_t line_sz;
|
||||||
|
ssize_t nbytes;
|
||||||
|
int hit = 0;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(SERVICELEVEL, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(EXIT_FAILURE, SERVICELEVEL);
|
||||||
|
|
||||||
|
while ((nbytes = getline(&linep, &line_sz, fp)) != EOF) {
|
||||||
|
int ok;
|
||||||
|
|
||||||
|
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
|
||||||
|
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||||
|
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
|
||||||
|
min, max, speed);
|
||||||
|
if (ok != 3) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hit += 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
|
||||||
|
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||||
|
" mode=basic sample_size=%u", basic_sz);
|
||||||
|
if (ok != 1) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hit += 1;
|
||||||
|
}
|
||||||
|
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
|
||||||
|
ok = sscanf(linep, "CPU-MF: Sampling facility:"
|
||||||
|
" mode=diagnostic sample_size=%u",
|
||||||
|
diag_sz);
|
||||||
|
if (ok != 1) {
|
||||||
|
warnx("Can not parse line %s", linep);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
hit += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
fclose(fp);
|
||||||
|
free(linep);
|
||||||
|
if (hit != 3)
|
||||||
|
rc = false;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_cpumsf(void)
|
||||||
|
{
|
||||||
|
unsigned long a, b, c;
|
||||||
|
int basic_sz, diag_sz;
|
||||||
|
|
||||||
|
return libcpumf_cpumsf_info(&a, &b, &c, &basic_sz, &diag_sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_have_sfb(void)
|
||||||
|
{
|
||||||
|
unsigned long a, b;
|
||||||
|
|
||||||
|
return libcpumf_sfb_info(&a, &b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max)
|
||||||
|
{
|
||||||
|
int rc = false;
|
||||||
|
FILE *fp;
|
||||||
|
|
||||||
|
fp = fopen(S390_CPUMSF_BUFFERSZ, "r");
|
||||||
|
if (!fp)
|
||||||
|
err(EXIT_FAILURE, "%s", S390_CPUMSF_BUFFERSZ);
|
||||||
|
if (fscanf(fp, "%lu,%lu", min, max) == 2)
|
||||||
|
rc = true;
|
||||||
|
fclose(fp);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
+1
-1
@@ -96,7 +96,7 @@ int dasd_sys_ese(char *devnode)
|
|||||||
return (rc == 1) ? 1 : 0;
|
return (rc == 1) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask)
|
static int dasd_get_pm_from_chpid(char *busid, unsigned int chpid, int *mask)
|
||||||
{
|
{
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
int count, i;
|
int count, i;
|
||||||
|
|||||||
@@ -1549,6 +1549,59 @@ int SK_EP11_reencipher_key(const struct sk_ext_ep11_lib *ep11_lib,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(blob, lrb.payload, lrb.pllen);
|
||||||
|
|
||||||
|
/* re-encipher MACed SPKI */
|
||||||
|
rb.domain = domain;
|
||||||
|
lrb.domain = domain;
|
||||||
|
|
||||||
|
resp_len = sizeof(resp);
|
||||||
|
req_len = ep11.dll_xcpa_cmdblock(req, sizeof(req), XCP_ADM_REENCRYPT,
|
||||||
|
&rb, NULL, key_token + hdr->len,
|
||||||
|
key_token_length - hdr->len);
|
||||||
|
if (req_len < 0) {
|
||||||
|
sk_debug(debug, "Failed to build XCP command block");
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv = ep11.dll_m_admin(resp, &resp_len, NULL, NULL, req, req_len, NULL,
|
||||||
|
0, ep11_lib->target);
|
||||||
|
if (rv != CKR_OK || resp_len == 0) {
|
||||||
|
sk_debug(debug, "Command XCP_ADM_REENCRYPT failed. "
|
||||||
|
"rc = 0x%lx, resp_len = %ld", rv, resp_len);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ep11.dll_xcpa_internal_rv(resp, resp_len, &lrb, &rv);
|
||||||
|
if (rc != 0) {
|
||||||
|
sk_debug(debug, "Failed to parse response. rc = %d", rc);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rv != CKR_OK) {
|
||||||
|
sk_debug(debug, "Failed to re-encrypt the EP11 secure key. "
|
||||||
|
"rc = 0x%lx", rv);
|
||||||
|
switch (rv) {
|
||||||
|
case CKR_IBM_WKID_MISMATCH:
|
||||||
|
sk_debug(debug, "The EP11 secure key is currently "
|
||||||
|
"encrypted under a different master that does "
|
||||||
|
"not match the master key in the CURRENT "
|
||||||
|
"master key register of APQN %02X.%04X",
|
||||||
|
card, domain);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key_token_length - hdr->len != lrb.pllen) {
|
||||||
|
sk_debug(debug, "Re-encrypted EP11 secure key size has "
|
||||||
|
"changed: org-len: %lu, new-len: %lu",
|
||||||
|
hdr->len - sizeof(*hdr), lrb.pllen);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(key_token + hdr->len, lrb.payload, lrb.pllen);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ install:
|
|||||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' cpictl > \
|
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' cpictl > \
|
||||||
$(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
$(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
chown $(OWNER):$(GROUP) $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||||
chmod 775 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
chmod 755 $(DESTDIR)$(TOOLS_LIBDIR)/cpictl
|
||||||
|
|
||||||
@for i in $(MAN_PAGES); \
|
@for i in $(MAN_PAGES); \
|
||||||
do \
|
do \
|
||||||
|
|||||||
+241
-9
@@ -24,6 +24,9 @@ readonly SYSTEM_NAME_PATH="/sys/firmware/cpi/system_name"
|
|||||||
readonly SYSPLEX_NAME_PATH="/sys/firmware/cpi/sysplex_name"
|
readonly SYSPLEX_NAME_PATH="/sys/firmware/cpi/sysplex_name"
|
||||||
readonly CPI_SET="/sys/firmware/cpi/set"
|
readonly CPI_SET="/sys/firmware/cpi/set"
|
||||||
|
|
||||||
|
# Location of os-release file - can be specified externally for testing purpose
|
||||||
|
readonly OS_RELEASE=${CPI_OS_RELEASE:-"/etc/os-release"}
|
||||||
|
|
||||||
declare LEVEL
|
declare LEVEL
|
||||||
declare TYPE
|
declare TYPE
|
||||||
declare NAME
|
declare NAME
|
||||||
@@ -37,6 +40,16 @@ readonly EXIT_FAILURE=1
|
|||||||
readonly EXIT_ARG_TOO_LONG=3
|
readonly EXIT_ARG_TOO_LONG=3
|
||||||
readonly EXIT_INVALID_CHARS=4
|
readonly EXIT_INVALID_CHARS=4
|
||||||
|
|
||||||
|
# Distro-IDs as supported by SE/HMC firmware
|
||||||
|
readonly DISTRO_GENERIC=0
|
||||||
|
readonly DISTRO_RHEL=1
|
||||||
|
readonly DISTRO_SLES=2
|
||||||
|
readonly DISTRO_UBUNTU=3
|
||||||
|
readonly DISTRO_FEDORA=4
|
||||||
|
readonly DISTRO_OPENSUSE=5
|
||||||
|
readonly DISTRO_DEBIAN=6
|
||||||
|
readonly DISTRO_RHCOS=7
|
||||||
|
|
||||||
print_help_and_exit()
|
print_help_and_exit()
|
||||||
{
|
{
|
||||||
cat <<EndHelp
|
cat <<EndHelp
|
||||||
@@ -49,7 +62,8 @@ Configure the Control-Program-Information (CPI) settings.
|
|||||||
sysplex name with values taken from environment
|
sysplex name with values taken from environment
|
||||||
variables
|
variables
|
||||||
-h, --help Print this help, then exit
|
-h, --help Print this help, then exit
|
||||||
-L, --level LEVEL Set and commit OS level to LEVEL (format xx.yy.zzABCD)
|
-L, --level LEVEL Set and commit OS level to LEVEL. Format: 0x<level> or
|
||||||
|
[[[flags:]distro_id:distro_version:]kernel_version]
|
||||||
-N, --name SYSTEM Set and commit the system name to SYSTEM
|
-N, --name SYSTEM Set and commit the system name to SYSTEM
|
||||||
-S, --sysplex SYSPLEX Set and commit the sysplex name to SYSPLEX
|
-S, --sysplex SYSPLEX Set and commit the sysplex name to SYSPLEX
|
||||||
-T, --type TYPE Set and commit OS type to TYPE
|
-T, --type TYPE Set and commit OS type to TYPE
|
||||||
@@ -109,7 +123,7 @@ fail_with()
|
|||||||
|
|
||||||
cpi_commit()
|
cpi_commit()
|
||||||
{
|
{
|
||||||
echo 1 > "$CPI_SET"
|
echo 1 > "$CPI_SET" 2> /dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
do_length_check()
|
do_length_check()
|
||||||
@@ -129,15 +143,233 @@ cpi_set_bit()
|
|||||||
LEVEL=$(printf '0x%x' $((LEVEL | (1 << (63 - $1)) )) )
|
LEVEL=$(printf '0x%x' $((LEVEL | (1 << (63 - $1)) )) )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# split_version - Split generic version string into array of sub-versions
|
||||||
|
#
|
||||||
|
# @version: Version string
|
||||||
|
# @delim: Characters that delimit sub-versions in version string
|
||||||
|
# @num: Number of sub-versions
|
||||||
|
#
|
||||||
|
# Print @num sub-versions of @version where each sub-version is delimited by
|
||||||
|
# any of the characters in @delim. Print 0 in place of non-decimal or missing
|
||||||
|
# sub-versions.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# version=10 delim=. num=3 => 10 0 0
|
||||||
|
# version=4.8 delim=. num=2 => 4 8
|
||||||
|
#
|
||||||
|
split_version()
|
||||||
|
{
|
||||||
|
local version="$1" delim="$2" num="$3"
|
||||||
|
local list i subver
|
||||||
|
|
||||||
|
IFS="$delim" read -r -a list <<< "$version"
|
||||||
|
|
||||||
|
for (( i=0; i<num; i++ )) ; do
|
||||||
|
subver="${list[i]:-0}"
|
||||||
|
# Handle non-number sub-versions
|
||||||
|
[[ "$subver" =~ ^[0-9]+$ ]] || subver=0
|
||||||
|
# Force decimal interpretation in case of leading zeroes
|
||||||
|
subver=$(( 10#$subver ))
|
||||||
|
printf "%s " "$subver"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# split_kver - Split Linux kernel version string into array of sub-versions
|
||||||
|
#
|
||||||
|
# @version: Linux kernel version string
|
||||||
|
# @num: Number of sub-versions
|
||||||
|
#
|
||||||
|
# Print @num sub-versions of the specified kernel @version. Print 0 in place
|
||||||
|
# of non-decimal or missing sub-versions.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# version=2.4-13 num=4 => 2 4 0 13
|
||||||
|
# version=3.0.93_3.0.101-0.8.2_0.8.1 num=6 => 3 0 93 3 0 101
|
||||||
|
# version=4.12.14-lp150.11.4 num=5 => 4 12 14 0 11
|
||||||
|
#
|
||||||
|
split_kver()
|
||||||
|
{
|
||||||
|
local version="$1" num="$2"
|
||||||
|
local main extra
|
||||||
|
|
||||||
|
# Separate extra version to handle short main version (e.g. 2.4-13)
|
||||||
|
IFS="-_" read -r main extra <<< "$version"
|
||||||
|
|
||||||
|
split_version "$main" "." $(( num > 3 ? 3 : num ))
|
||||||
|
[[ "$num" -gt 3 ]] && split_version "$extra" ".-_" $(( num - 3 ))
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# bytes_to_word - Convert byte array to hexadecimal word
|
||||||
|
#
|
||||||
|
# @bytes: List of numbers representing byte values
|
||||||
|
#
|
||||||
|
# Print a big-endian hexadecimal representation of the word that results from
|
||||||
|
# combining the specified byte values.
|
||||||
|
#
|
||||||
|
bytes_to_word()
|
||||||
|
{
|
||||||
|
printf "0x"
|
||||||
|
printf "%02x" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# get_system_level - Print system level word for specified distribution version
|
||||||
|
#
|
||||||
|
# @distro: Distro ID (ID value from /etc/os-release)
|
||||||
|
# @ver_str: Distro version string (VERSION_ID from /etc/os-release)
|
||||||
|
# @kver_str: Kernel version string (output of 'uname -r')
|
||||||
|
# @flags: Optional statistics flags
|
||||||
|
#
|
||||||
|
# Print a 64 bit hexadecimal system level in a format as understood by firmware.
|
||||||
|
#
|
||||||
|
# The format is 0xabccddeeeeffgghh, where
|
||||||
|
# - a=statistics flags
|
||||||
|
# - b=distro id
|
||||||
|
# - c=distro major version
|
||||||
|
# - d=distro minor version(s)
|
||||||
|
# - e=kernel sublevel 2
|
||||||
|
# - f=kernel version
|
||||||
|
# - g=kernel patchlevel
|
||||||
|
# - h=kernel sublevel 1
|
||||||
|
#
|
||||||
|
get_system_level()
|
||||||
|
{
|
||||||
|
local distro="$1" ver_str="$2" kver_str="$3" flags="${4:-0}"
|
||||||
|
local distro_id d_major d_minor d_minor2
|
||||||
|
local k_ver k_patchlvl k_sublvl k_sublvl2 bytes=()
|
||||||
|
|
||||||
|
# Extract list of sub-version numbers from version strings
|
||||||
|
read -r d_major d_minor d_minor2 <<< "$(split_version "$ver_str" "._-" 3)"
|
||||||
|
read -r k_ver k_patchlvl k_sublvl k_sublvl2 <<< "$(split_kver "$kver_str" 4)"
|
||||||
|
|
||||||
|
# Handle excessive sublevel numbers consistently
|
||||||
|
if [[ "$k_sublvl2" -gt 65535 ]] ; then
|
||||||
|
k_sublvl2=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Apply distro-specific logic
|
||||||
|
case "$distro" in
|
||||||
|
"rhel")
|
||||||
|
distro_id=$DISTRO_RHEL
|
||||||
|
;;
|
||||||
|
|
||||||
|
"sles")
|
||||||
|
distro_id=$DISTRO_SLES
|
||||||
|
;;
|
||||||
|
|
||||||
|
"ubuntu")
|
||||||
|
distro_id=$DISTRO_UBUNTU
|
||||||
|
|
||||||
|
# Encode minor and update version numbers in minor field
|
||||||
|
(( d_minor=((d_minor & 0xf) * 0x10) + (d_minor2 & 0xf) ))
|
||||||
|
;;
|
||||||
|
|
||||||
|
"fedora")
|
||||||
|
distro_id=$DISTRO_FEDORA
|
||||||
|
;;
|
||||||
|
|
||||||
|
"opensuse-leap")
|
||||||
|
distro_id=$DISTRO_OPENSUSE
|
||||||
|
;;
|
||||||
|
|
||||||
|
"debian")
|
||||||
|
distro_id=$DISTRO_DEBIAN
|
||||||
|
;;
|
||||||
|
|
||||||
|
"rhcos")
|
||||||
|
distro_id=$DISTRO_RHCOS
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
distro_id=$DISTRO_GENERIC
|
||||||
|
|
||||||
|
# Reset unsupported fields
|
||||||
|
d_major=0
|
||||||
|
d_minor=0
|
||||||
|
k_sublvl2=0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Assemble byte data
|
||||||
|
(( bytes[0] = (flags & 0xf) * 0x10 + distro_id ))
|
||||||
|
(( bytes[1] = d_major ))
|
||||||
|
(( bytes[2] = d_minor ))
|
||||||
|
(( bytes[3] = (k_sublvl2 / 256) & 0xff ))
|
||||||
|
(( bytes[4] = k_sublvl2 & 0xff ))
|
||||||
|
(( bytes[5] = k_ver ))
|
||||||
|
(( bytes[6] = k_patchlvl ))
|
||||||
|
(( bytes[7] = k_sublvl ))
|
||||||
|
|
||||||
|
# Print as single hex word
|
||||||
|
bytes_to_word "${bytes[@]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_distro()
|
||||||
|
{
|
||||||
|
local line ID="linux" VERSION_ID="0" VERSION="" update
|
||||||
|
|
||||||
|
[[ ! -e "$OS_RELEASE" ]] && return
|
||||||
|
|
||||||
|
# Only import required variables
|
||||||
|
while read -r line ; do
|
||||||
|
if [[ "$line" =~ ^ID= ]] || [[ "$line" =~ ^VERSION_ID= ]] ||
|
||||||
|
[[ "$line" =~ ^VERSION= ]] ; then
|
||||||
|
eval "$line"
|
||||||
|
fi
|
||||||
|
done <"$OS_RELEASE"
|
||||||
|
|
||||||
|
if [[ "$ID" == "ubuntu" ]] ; then
|
||||||
|
# Extract update version number only found in VERSION, e.g.
|
||||||
|
# VERSION_ID="18.04" VERSION="18.04.5 LTS"
|
||||||
|
update="${VERSION/*$VERSION_ID/}"
|
||||||
|
update="${update%% *}"
|
||||||
|
VERSION_ID="$VERSION_ID$update"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$ID:$VERSION_ID"
|
||||||
|
}
|
||||||
|
|
||||||
cpi_set_oslevel()
|
cpi_set_oslevel()
|
||||||
{
|
{
|
||||||
local kver=$(echo "${1:-$(uname -r)}" | grep -E -o '^[0-9]+[.][0-9]+[.][0-9]+')
|
local level="${1:-}"
|
||||||
local maj=$((${kver%%.*} % 256))
|
local flags list distro_id distro_ver kver id ver
|
||||||
local min=${kver#*.}
|
|
||||||
min=$((${min%.*} % 256))
|
if [[ "$level" =~ ^0x ]] && ! [[ "$level" =~ : ]] ; then
|
||||||
local rev=$((${kver##*.} % 256))
|
# Format: level=0x<hex>
|
||||||
local hexlevel=$(printf '0x%02x%02x%02x' $maj $min $rev)
|
printf -v LEVEL "0x%016x" "$level" 2>/dev/null ||
|
||||||
LEVEL=$(printf '0x%016x' $(((LEVEL & 0xFFFFFFFFFF000000) | hexlevel)))
|
fail_with "$PRG: Invalid hexadecimal number in $level" \
|
||||||
|
$EXIT_INVALID_CHARS
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Format: level=[[[flags:]distro_id:distro_ver:]kver]
|
||||||
|
IFS=":" read -r -a list <<< "$level:"
|
||||||
|
kver="${list[*]: -1: 1}"
|
||||||
|
distro_ver="${list[*]: -2: 1}"
|
||||||
|
distro_id="${list[*]: -3: 1}"
|
||||||
|
flags="${list[*]: -4: 1}"
|
||||||
|
|
||||||
|
if [[ -z "$kver" ]] ; then
|
||||||
|
# Use version of currently running kernel
|
||||||
|
kver="$(uname -r)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$distro_ver" ]] || [[ -z "$distro_id" ]] ; then
|
||||||
|
# Use distro ID and version from os-release file
|
||||||
|
IFS=":" read -r id ver <<< "$(get_distro)"
|
||||||
|
distro_id=${distro_id:-$id}
|
||||||
|
distro_ver=${distro_ver:-$ver}
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -z "$flags" ]] ; then
|
||||||
|
# Keep statistics flags from current system level
|
||||||
|
flags=$(( (LEVEL >> 60) & 0xf ))
|
||||||
|
fi
|
||||||
|
|
||||||
|
LEVEL=$(get_system_level "$distro_id" "$distro_ver" "$kver" "$flags")
|
||||||
}
|
}
|
||||||
|
|
||||||
cpi_set_type()
|
cpi_set_type()
|
||||||
|
|||||||
+679
-596
File diff suppressed because it is too large
Load Diff
+37
-5
@@ -1,6 +1,6 @@
|
|||||||
.\" lszcrypt.8
|
.\" lszcrypt.8
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright 2019 IBM Corp.
|
.\" Copyright IBM Corp. 2019, 2022
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -10,13 +10,14 @@
|
|||||||
.\" nroff -man lszcrypt.8
|
.\" nroff -man lszcrypt.8
|
||||||
.\" to process this source
|
.\" to process this source
|
||||||
.\"
|
.\"
|
||||||
.TH LSZCRYPT 8 "OCT 2020" "s390-tools"
|
.TH LSZCRYPT 8 "FEB 2022" "s390-tools"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
lszcrypt \- display zcrypt device and configuration information
|
lszcrypt \- display zcrypt device and configuration information
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.TP 9
|
.TP 9
|
||||||
.B lszcrypt
|
.B lszcrypt
|
||||||
.RB "[ " -V " ] "
|
.RB "[" <filteroptions> "]"
|
||||||
|
.RB "[" -V "]"
|
||||||
[
|
[
|
||||||
.I <device-id>
|
.I <device-id>
|
||||||
[...]]
|
[...]]
|
||||||
@@ -31,7 +32,12 @@ lszcrypt \- display zcrypt device and configuration information
|
|||||||
.TP
|
.TP
|
||||||
.B lszcrypt -h
|
.B lszcrypt -h
|
||||||
.TP
|
.TP
|
||||||
|
.B lszcrypt -s
|
||||||
|
.TP
|
||||||
.B lszcrypt -v
|
.B lszcrypt -v
|
||||||
|
. TP
|
||||||
|
.B <filteroptions>
|
||||||
|
[--accelonly|--ccaonly|--ep11only] [--cardonly|--queueonly]
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The
|
The
|
||||||
.B lszcrypt
|
.B lszcrypt
|
||||||
@@ -109,8 +115,26 @@ B - indicate both (control and usage domain)
|
|||||||
.B -h, --help
|
.B -h, --help
|
||||||
Displays help text and exits.
|
Displays help text and exits.
|
||||||
.TP 8
|
.TP 8
|
||||||
|
.B -s, --serial
|
||||||
|
Shows the serial numbers for CCA and EP11 crypto cards.
|
||||||
|
.TP 8
|
||||||
.B -v, --version
|
.B -v, --version
|
||||||
Displays version information and exits.
|
Displays version information and exits.
|
||||||
|
.TP 8
|
||||||
|
.B --accelonly
|
||||||
|
Show only information for cards/queues in Accelerator mode.
|
||||||
|
.TP 8
|
||||||
|
.B --ccaonly
|
||||||
|
Show only information for cards/queues in CCA-Coprocessor mode.
|
||||||
|
.TP 8
|
||||||
|
.B --ep11only
|
||||||
|
Show only information for cards/queues in EP11-Coprocessor mode.
|
||||||
|
.TP 8
|
||||||
|
.B --cardonly
|
||||||
|
Show only information for cards but no queue info.
|
||||||
|
.TP 8
|
||||||
|
.B --queueonly
|
||||||
|
Show only information for queues but no card info.
|
||||||
.SH LISTING DETAILS
|
.SH LISTING DETAILS
|
||||||
Here is an explanation of the columns displayed. Please note that some
|
Here is an explanation of the columns displayed. Please note that some
|
||||||
of the columns show up in verbose mode only.
|
of the columns show up in verbose mode only.
|
||||||
@@ -123,7 +147,7 @@ dot for a queue line.
|
|||||||
.B TYPE and HWTYPE
|
.B TYPE and HWTYPE
|
||||||
The HWTYPE is a numeric value showing which type of hardware the zcrypt
|
The HWTYPE is a numeric value showing which type of hardware the zcrypt
|
||||||
device driver presumes that this crypto card is. The currently known values
|
device driver presumes that this crypto card is. The currently known values
|
||||||
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6 and 13=CEX7.
|
are 7=CEX3C, 8=CEX3A, 10=CEX4, 11=CEX5, 12=CEX6, 13=CEX7 and 14=CEX8.
|
||||||
.br
|
.br
|
||||||
The TYPE is a human readable value showing the hardware type and the basic
|
The TYPE is a human readable value showing the hardware type and the basic
|
||||||
function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So
|
function type (A=Accelerator, C=CCA Coprocessor, P=EP11 Coprocessor). So
|
||||||
@@ -154,6 +178,9 @@ cryptographic operations. 'offline' is displayed when a card or queue
|
|||||||
is switched to (software) offline. If a card is 'deconfigured' via
|
is switched to (software) offline. If a card is 'deconfigured' via
|
||||||
HMC, SE or chzcrypt the field shows 'deconfig'.
|
HMC, SE or chzcrypt the field shows 'deconfig'.
|
||||||
.br
|
.br
|
||||||
|
A crypto card may also reach a 'checkstopped' state. lszcrypt shows
|
||||||
|
this as 'chkstop'.
|
||||||
|
.br
|
||||||
If a queue is not bound to a device driver there is no detailed
|
If a queue is not bound to a device driver there is no detailed
|
||||||
information available and thus the status shows only '-'.
|
information available and thus the status shows only '-'.
|
||||||
.br
|
.br
|
||||||
@@ -204,12 +231,17 @@ operations within the guests.
|
|||||||
.B DRIVER
|
.B DRIVER
|
||||||
.br
|
.br
|
||||||
Shows which card or queue device driver currently handles this crypto
|
Shows which card or queue device driver currently handles this crypto
|
||||||
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX7
|
resource. Currently known drivers are cex4card/cex4queue (CEX4-CEX8
|
||||||
hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware),
|
hardware), cex2card/cex2cqueue (CEX2C and CEX3C hardware),
|
||||||
cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved
|
cex2acard/cex2aqueue (CEX2A and CEX3A hardware) and vfio_ap (queue reserved
|
||||||
for use by kvm hypervisor for kvm guests and not accessible to host
|
for use by kvm hypervisor for kvm guests and not accessible to host
|
||||||
applications). It is also valid to have no driver handling a queue which is
|
applications). It is also valid to have no driver handling a queue which is
|
||||||
shown as a -no-driver- entry.
|
shown as a -no-driver- entry.
|
||||||
|
.SH NOTES
|
||||||
|
Use only one of the mode filtering options --accelonly, --ccaonly, --ep11only.
|
||||||
|
Same with card/queue filtering: Use only one of --cardonly, --queueonly.
|
||||||
|
However, one of the mode filtering options and one of the card/queue filtering
|
||||||
|
can be combined.
|
||||||
.SH EXAMPLES
|
.SH EXAMPLES
|
||||||
.TP
|
.TP
|
||||||
.B lszcrypt
|
.B lszcrypt
|
||||||
|
|||||||
+210
-20
@@ -1,7 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* lszcrypt - Display zcrypt devices and configuration settings
|
* lszcrypt - Display zcrypt devices and configuration settings
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2008, 2020
|
* Copyright IBM Corp. 2008, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -29,6 +29,11 @@
|
|||||||
*/
|
*/
|
||||||
static struct lszcrypt_l {
|
static struct lszcrypt_l {
|
||||||
int verbose;
|
int verbose;
|
||||||
|
int showaccel;
|
||||||
|
int showcca;
|
||||||
|
int showep11;
|
||||||
|
int showcard;
|
||||||
|
int showqueue;
|
||||||
} l;
|
} l;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -39,6 +44,7 @@ static struct lszcrypt_l {
|
|||||||
#define CAP_CCA "CCA Secure Key"
|
#define CAP_CCA "CCA Secure Key"
|
||||||
#define CAP_RNG "Long RNG"
|
#define CAP_RNG "Long RNG"
|
||||||
#define CAP_EP11 "EP11 Secure Key"
|
#define CAP_EP11 "EP11 Secure Key"
|
||||||
|
#define CAP_APMMS "AP bus max message size limit %ld Kb"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Card types
|
* Card types
|
||||||
@@ -95,6 +101,13 @@ static const struct util_prg prg = {
|
|||||||
/*
|
/*
|
||||||
* Configuration of command line options
|
* Configuration of command line options
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define OPT_ACCELONLY 0x81
|
||||||
|
#define OPT_CCAONLY 0x82
|
||||||
|
#define OPT_EP11ONLY 0x83
|
||||||
|
#define OPT_CARDONLY 0x84
|
||||||
|
#define OPT_QUEUEONLY 0x85
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
{
|
{
|
||||||
.option = {"bus", 0, NULL, 'b'},
|
.option = {"bus", 0, NULL, 'b'},
|
||||||
@@ -113,6 +126,35 @@ static struct util_opt opt_vec[] = {
|
|||||||
.option = {"verbose", 0, NULL, 'V'},
|
.option = {"verbose", 0, NULL, 'V'},
|
||||||
.desc = "Print verbose messages",
|
.desc = "Print verbose messages",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.option = {"accelonly", 0, NULL, OPT_ACCELONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards/queues in Accelerator mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"ccaonly", 0, NULL, OPT_CCAONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards/queues in CCA-Coprocessor mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"ep11only", 0, NULL, OPT_EP11ONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards/queues in EP11-Coprocessor mode",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"cardonly", 0, NULL, OPT_CARDONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from cards but no queue info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"queueonly", 0, NULL, OPT_QUEUEONLY},
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
.desc = "Show only information from queues but no card info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = {"serial", 0, NULL, 's'},
|
||||||
|
.desc = "Show the serial numbers for CCA and EP11 crypto cards",
|
||||||
|
},
|
||||||
UTIL_OPT_HELP,
|
UTIL_OPT_HELP,
|
||||||
UTIL_OPT_VERSION,
|
UTIL_OPT_VERSION,
|
||||||
UTIL_OPT_END
|
UTIL_OPT_END
|
||||||
@@ -247,13 +289,94 @@ static void show_domains(void)
|
|||||||
show_domains_util_rec(domain_array);
|
show_domains_util_rec(domain_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show serialnumbers
|
||||||
|
*/
|
||||||
|
static void show_serialnumbers(void)
|
||||||
|
{
|
||||||
|
struct util_rec *rec = util_rec_new_wide("-");
|
||||||
|
struct dirent **dev_vec;
|
||||||
|
int i, count;
|
||||||
|
char *ap, *path, *device, *grp_dev, card[16], buf[256];
|
||||||
|
long config = -1, online = -1, chkstop = -1;
|
||||||
|
unsigned long facility;
|
||||||
|
|
||||||
|
/* check if ap driver is available */
|
||||||
|
ap = util_path_sysfs("bus/ap");
|
||||||
|
if (!util_path_is_dir(ap))
|
||||||
|
errx(EXIT_FAILURE, "Crypto device driver not available.");
|
||||||
|
|
||||||
|
/* define the record */
|
||||||
|
util_rec_def(rec, "card", UTIL_REC_ALIGN_LEFT, 8, "CARD.DOM");
|
||||||
|
util_rec_def(rec, "type", UTIL_REC_ALIGN_LEFT, 5, "TYPE");
|
||||||
|
util_rec_def(rec, "mode", UTIL_REC_ALIGN_LEFT, 11, "MODE");
|
||||||
|
util_rec_def(rec, "status", UTIL_REC_ALIGN_LEFT, 10, "STATUS");
|
||||||
|
util_rec_def(rec, "serialnr", UTIL_REC_ALIGN_LEFT, 8, "SERIALNR");
|
||||||
|
|
||||||
|
/* scan the devices */
|
||||||
|
path = util_path_sysfs("devices/ap/");
|
||||||
|
count = util_scandir(&dev_vec, alphasort, path, "card[0-9a-fA-F]+");
|
||||||
|
if (count < 1)
|
||||||
|
errx(EXIT_FAILURE, "No crypto card devices found.");
|
||||||
|
util_rec_print_hdr(rec);
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
device = dev_vec[i]->d_name;
|
||||||
|
grp_dev = util_path_sysfs("devices/ap/%s", device);
|
||||||
|
if (!util_path_is_dir(grp_dev))
|
||||||
|
errx(EXIT_FAILURE, "Error - cryptographic device %s does not exist.", device);
|
||||||
|
if (!util_path_is_readable("%s/type", grp_dev) ||
|
||||||
|
!util_path_is_readable("%s/online", grp_dev))
|
||||||
|
goto next;
|
||||||
|
strcpy(card, device + 4);
|
||||||
|
util_rec_set(rec, "card", card);
|
||||||
|
util_file_read_line(buf, sizeof(buf), "%s/type", grp_dev);
|
||||||
|
util_rec_set(rec, "type", buf);
|
||||||
|
util_file_read_ul(&facility, 16, "%s/ap_functions", grp_dev);
|
||||||
|
if (facility & MASK_COPRO)
|
||||||
|
util_rec_set(rec, "mode", "CCA-Coproc");
|
||||||
|
else if (facility & MASK_EP11)
|
||||||
|
util_rec_set(rec, "mode", "EP11-Coproc");
|
||||||
|
else
|
||||||
|
goto next;
|
||||||
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
|
if (util_path_is_readable("%s/chkstop", grp_dev))
|
||||||
|
util_file_read_l(&chkstop, 10, "%s/chkstop", grp_dev);
|
||||||
|
if (util_path_is_readable("%s/online", grp_dev))
|
||||||
|
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
||||||
|
if (config == 0) {
|
||||||
|
util_rec_set(rec, "status", "deconfig");
|
||||||
|
} else {
|
||||||
|
if (chkstop > 0)
|
||||||
|
util_rec_set(rec, "status", "chkstop");
|
||||||
|
else if (online > 0)
|
||||||
|
util_rec_set(rec, "status", "online");
|
||||||
|
else if (online == 0)
|
||||||
|
util_rec_set(rec, "status", "offline");
|
||||||
|
else
|
||||||
|
util_rec_set(rec, "status", "-");
|
||||||
|
}
|
||||||
|
if (util_file_read_line(buf, sizeof(buf), "%s/serialnr", grp_dev))
|
||||||
|
util_rec_set(rec, "serialnr", "-");
|
||||||
|
else {
|
||||||
|
buf[8] = '\0';
|
||||||
|
util_rec_set(rec, "serialnr", buf);
|
||||||
|
}
|
||||||
|
util_rec_print(rec);
|
||||||
|
next:
|
||||||
|
free(grp_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Show capability
|
* Show capability
|
||||||
*/
|
*/
|
||||||
static void show_capability(const char *id_str)
|
static void show_capability(const char *id_str)
|
||||||
{
|
{
|
||||||
unsigned long func_val;
|
unsigned long func_val;
|
||||||
long hwtype, id;
|
long hwtype, id, max_msg_size;
|
||||||
char *p, *ap, *dev, card[16], cbuf[256];
|
char *p, *ap, *dev, card[16], cbuf[256];
|
||||||
|
|
||||||
/* check if ap driver is available */
|
/* check if ap driver is available */
|
||||||
@@ -272,6 +395,9 @@ static void show_capability(const char *id_str)
|
|||||||
/* If sysfs attribute is missing, set functions to 0 */
|
/* If sysfs attribute is missing, set functions to 0 */
|
||||||
if (util_file_read_ul(&func_val, 16, "%s/ap_functions", dev))
|
if (util_file_read_ul(&func_val, 16, "%s/ap_functions", dev))
|
||||||
func_val = 0x00000000;
|
func_val = 0x00000000;
|
||||||
|
/* try to read the ap bus max message size for this card */
|
||||||
|
if (util_file_read_l(&max_msg_size, 10, "%s/max_msg_size", dev))
|
||||||
|
max_msg_size = 0;
|
||||||
/* Skip devices, which are not supported by zcrypt layer */
|
/* Skip devices, which are not supported by zcrypt layer */
|
||||||
if (!util_path_is_readable("%s/type", dev) ||
|
if (!util_path_is_readable("%s/type", dev) ||
|
||||||
!util_path_is_readable("%s/online", dev)) {
|
!util_path_is_readable("%s/online", dev)) {
|
||||||
@@ -289,9 +415,9 @@ static void show_capability(const char *id_str)
|
|||||||
case 6:
|
case 6:
|
||||||
case 8:
|
case 8:
|
||||||
if (func_val & MASK_RSA4K)
|
if (func_val & MASK_RSA4K)
|
||||||
printf("%s", CAP_RSA4K);
|
printf("%s\n", CAP_RSA4K);
|
||||||
else
|
else
|
||||||
printf("%s", CAP_RSA2K);
|
printf("%s\n", CAP_RSA2K);
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
case 9:
|
case 9:
|
||||||
@@ -300,37 +426,39 @@ static void show_capability(const char *id_str)
|
|||||||
printf("%s (%s)\n", CAP_CCA, cbuf);
|
printf("%s (%s)\n", CAP_CCA, cbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", CAP_CCA);
|
printf("%s\n", CAP_CCA);
|
||||||
printf("%s", CAP_RNG);
|
printf("%s\n", CAP_RNG);
|
||||||
break;
|
break;
|
||||||
case 10: /* CEX4S */
|
case 10: /* CEX4S */
|
||||||
case 11: /* CEX5S */
|
case 11: /* CEX5S */
|
||||||
case 12: /* CEX6S */
|
case 12: /* CEX6S */
|
||||||
case 13: /* CEX7S */
|
case 13: /* CEX7S */
|
||||||
|
case 14: /* CEX8S */
|
||||||
if (func_val & MASK_ACCEL) {
|
if (func_val & MASK_ACCEL) {
|
||||||
if (func_val & MASK_RSA4K)
|
if (func_val & MASK_RSA4K)
|
||||||
printf("%s", CAP_RSA4K);
|
printf("%s\n", CAP_RSA4K);
|
||||||
else
|
else
|
||||||
printf("%s", CAP_RSA2K);
|
printf("%s\n", CAP_RSA2K);
|
||||||
} else if (func_val & MASK_COPRO) {
|
} else if (func_val & MASK_COPRO) {
|
||||||
printf("%s\n", CAP_RSA4K);
|
printf("%s\n", CAP_RSA4K);
|
||||||
if (cbuf[0])
|
if (cbuf[0])
|
||||||
printf("%s (%s)\n", CAP_CCA, cbuf);
|
printf("%s (%s)\n", CAP_CCA, cbuf);
|
||||||
else
|
else
|
||||||
printf("%s\n", CAP_CCA);
|
printf("%s\n", CAP_CCA);
|
||||||
printf("%s", CAP_RNG);
|
printf("%s\n", CAP_RNG);
|
||||||
} else if (func_val & MASK_EP11) {
|
} else if (func_val & MASK_EP11) {
|
||||||
printf("%s", CAP_EP11);
|
printf("%s\n", CAP_EP11);
|
||||||
} else {
|
} else {
|
||||||
printf("Detailed capability information for %s (hardware type %ld) is not available.",
|
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
|
||||||
card, hwtype);
|
card, hwtype);
|
||||||
}
|
}
|
||||||
|
if (max_msg_size > 0)
|
||||||
|
printf(CAP_APMMS "\n", max_msg_size / 1024);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printf("Detailed capability information for %s (hardware type %ld) is not available.",
|
printf("Detailed capability information for %s (hardware type %ld) is not available.\n",
|
||||||
card, hwtype);
|
card, hwtype);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -375,7 +503,7 @@ static int read_driver(const char *dir, const char *subdir, char *buf, size_t bu
|
|||||||
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
||||||
const char *sub_dev)
|
const char *sub_dev)
|
||||||
{
|
{
|
||||||
long config = -1, online = -1;
|
long config = -1, online = -1, chkstop = -1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
|
|
||||||
@@ -386,6 +514,8 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
|
|
||||||
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
|
if (util_path_is_readable("%s/%s/config", grp_dev, sub_dev))
|
||||||
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
|
util_file_read_l(&config, 10, "%s/%s/config", grp_dev, sub_dev);
|
||||||
|
if (util_path_is_readable("%s/%s/chkstop", grp_dev, sub_dev))
|
||||||
|
util_file_read_l(&chkstop, 10, "%s/%s/chkstop", grp_dev, sub_dev);
|
||||||
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
|
if (util_path_is_readable("%s/%s/online", grp_dev, sub_dev))
|
||||||
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
|
util_file_read_l(&online, 10, "%s/%s/online", grp_dev, sub_dev);
|
||||||
|
|
||||||
@@ -393,7 +523,9 @@ static void read_subdev_rec_default(struct util_rec *rec, const char *grp_dev,
|
|||||||
if (config == 0) {
|
if (config == 0) {
|
||||||
util_rec_set(rec, "status", "deconfig");
|
util_rec_set(rec, "status", "deconfig");
|
||||||
} else {
|
} else {
|
||||||
if (online > 0)
|
if (chkstop > 0)
|
||||||
|
util_rec_set(rec, "status", "chkstop");
|
||||||
|
else if (online > 0)
|
||||||
util_rec_set(rec, "status", "online");
|
util_rec_set(rec, "status", "online");
|
||||||
else if (online == 0)
|
else if (online == 0)
|
||||||
util_rec_set(rec, "status", "offline");
|
util_rec_set(rec, "status", "offline");
|
||||||
@@ -489,6 +621,9 @@ static void show_subdevice(struct util_rec *rec, const char *grp_dev,
|
|||||||
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev)))
|
!util_path_is_readable("%s/%s/online", grp_dev, sub_dev)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!l.showqueue)
|
||||||
|
return;
|
||||||
|
|
||||||
util_rec_set(rec, "card", sub_dev);
|
util_rec_set(rec, "card", sub_dev);
|
||||||
read_subdev_rec_default(rec, grp_dev, sub_dev);
|
read_subdev_rec_default(rec, grp_dev, sub_dev);
|
||||||
read_subdev_rec_verbose(rec, grp_dev, sub_dev);
|
read_subdev_rec_verbose(rec, grp_dev, sub_dev);
|
||||||
@@ -516,7 +651,7 @@ static void show_subdevices(struct util_rec *rec, const char *grp_dev)
|
|||||||
*/
|
*/
|
||||||
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
||||||
{
|
{
|
||||||
long config = -1, online = -1;
|
long config = -1, online = -1, chkstop = -1;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
unsigned long facility;
|
unsigned long facility;
|
||||||
|
|
||||||
@@ -537,12 +672,16 @@ static void read_rec_default(struct util_rec *rec, const char *grp_dev)
|
|||||||
|
|
||||||
if (util_path_is_readable("%s/config", grp_dev))
|
if (util_path_is_readable("%s/config", grp_dev))
|
||||||
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
util_file_read_l(&config, 10, "%s/config", grp_dev);
|
||||||
|
if (util_path_is_readable("%s/chkstop", grp_dev))
|
||||||
|
util_file_read_l(&chkstop, 10, "%s/chkstop", grp_dev);
|
||||||
if (util_path_is_readable("%s/online", grp_dev))
|
if (util_path_is_readable("%s/online", grp_dev))
|
||||||
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
util_file_read_l(&online, 10, "%s/online", grp_dev);
|
||||||
if (config == 0) {
|
if (config == 0) {
|
||||||
util_rec_set(rec, "status", "deconfig");
|
util_rec_set(rec, "status", "deconfig");
|
||||||
} else {
|
} else {
|
||||||
if (online > 0)
|
if (chkstop > 0)
|
||||||
|
util_rec_set(rec, "status", "chkstop");
|
||||||
|
else if (online > 0)
|
||||||
util_rec_set(rec, "status", "online");
|
util_rec_set(rec, "status", "online");
|
||||||
else if (online == 0)
|
else if (online == 0)
|
||||||
util_rec_set(rec, "status", "offline");
|
util_rec_set(rec, "status", "offline");
|
||||||
@@ -603,7 +742,7 @@ static void read_rec_verbose(struct util_rec *rec, const char *grp_dev)
|
|||||||
*/
|
*/
|
||||||
static void show_device(struct util_rec *rec, const char *device)
|
static void show_device(struct util_rec *rec, const char *device)
|
||||||
{
|
{
|
||||||
char *grp_dev, card[16];
|
char *grp_dev, card[16], type[16], t = '\0';
|
||||||
|
|
||||||
strcpy(card, &device[4]);
|
strcpy(card, &device[4]);
|
||||||
grp_dev = util_path_sysfs("devices/ap/%s", device);
|
grp_dev = util_path_sysfs("devices/ap/%s", device);
|
||||||
@@ -621,11 +760,21 @@ static void show_device(struct util_rec *rec, const char *device)
|
|||||||
}
|
}
|
||||||
util_rec_set(rec, "card", card);
|
util_rec_set(rec, "card", card);
|
||||||
|
|
||||||
|
if (util_file_read_line(type, sizeof(type), "%s/type", grp_dev) == 0)
|
||||||
|
t = type[strlen(type) - 1];
|
||||||
|
|
||||||
|
if ((t == 'A' && !l.showaccel) ||
|
||||||
|
(t == 'C' && !l.showcca) ||
|
||||||
|
(t == 'P' && !l.showep11))
|
||||||
|
goto out_free;
|
||||||
|
|
||||||
read_rec_default(rec, grp_dev);
|
read_rec_default(rec, grp_dev);
|
||||||
read_rec_verbose(rec, grp_dev);
|
read_rec_verbose(rec, grp_dev);
|
||||||
|
|
||||||
util_rec_print(rec);
|
if (l.showcard)
|
||||||
show_subdevices(rec, grp_dev);
|
util_rec_print(rec);
|
||||||
|
if (l.showqueue)
|
||||||
|
show_subdevices(rec, grp_dev);
|
||||||
out_free:
|
out_free:
|
||||||
free(grp_dev);
|
free(grp_dev);
|
||||||
}
|
}
|
||||||
@@ -799,9 +948,27 @@ int main(int argc, char **argv)
|
|||||||
case 'd':
|
case 'd':
|
||||||
show_domains();
|
show_domains();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
case 's':
|
||||||
|
show_serialnumbers();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
case 'V':
|
case 'V':
|
||||||
l.verbose++;
|
l.verbose++;
|
||||||
break;
|
break;
|
||||||
|
case OPT_ACCELONLY:
|
||||||
|
l.showaccel = 1;
|
||||||
|
break;
|
||||||
|
case OPT_CCAONLY:
|
||||||
|
l.showcca = 1;
|
||||||
|
break;
|
||||||
|
case OPT_EP11ONLY:
|
||||||
|
l.showep11 = 1;
|
||||||
|
break;
|
||||||
|
case OPT_CARDONLY:
|
||||||
|
l.showcard = 1;
|
||||||
|
break;
|
||||||
|
case OPT_QUEUEONLY:
|
||||||
|
l.showqueue = 1;
|
||||||
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
util_prg_print_help();
|
util_prg_print_help();
|
||||||
util_opt_print_help();
|
util_opt_print_help();
|
||||||
@@ -815,6 +982,29 @@ int main(int argc, char **argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (l.showaccel + l.showcca + l.showep11) {
|
||||||
|
case 0:
|
||||||
|
l.showaccel = l.showcca = l.showep11 = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("Only one of --accelonly or --ccaonly or --ep11only can be specified");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (l.showcard + l.showqueue) {
|
||||||
|
case 0:
|
||||||
|
l.showcard = l.showqueue = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
warnx("Only one of --cardonly or --queueonly can be specified");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
if (optind == argc)
|
if (optind == argc)
|
||||||
show_devices_all();
|
show_devices_all();
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" zcryptctl.8
|
.\" zcryptctl.8
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright 2018 IBM Corp.
|
.\" Copyright 2018, 2022 IBM Corp.
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
.\" nroff -man zcryptctl.8
|
.\" nroff -man zcryptctl.8
|
||||||
.\" to process this source
|
.\" to process this source
|
||||||
.\"
|
.\"
|
||||||
.TH ZCRYPTCTL 8 "AUG 2018" "s390-tools"
|
.TH ZCRYPTCTL 8 "JAN 2022" "s390-tools"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
zcryptctl \- display information and administrate zcrypt multiple device nodes
|
zcryptctl \- display information and administrate zcrypt multiple device nodes
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
@@ -35,6 +35,11 @@ zcryptctl \- display information and administrate zcrypt multiple device nodes
|
|||||||
.B deldom
|
.B deldom
|
||||||
.I node-name domain-nr
|
.I node-name domain-nr
|
||||||
.TP
|
.TP
|
||||||
|
.B zcryptctl addctrl
|
||||||
|
.R |
|
||||||
|
.B delctrl
|
||||||
|
.I node-name domain-nr
|
||||||
|
.TP
|
||||||
.B zcryptctl addioctl
|
.B zcryptctl addioctl
|
||||||
.R |
|
.R |
|
||||||
.B delioctl
|
.B delioctl
|
||||||
@@ -57,6 +62,7 @@ driver. Each zcrypt device node can be restricted in terms of crypto
|
|||||||
cards, domains, and available ioctls. Such a device node can be used
|
cards, domains, and available ioctls. Such a device node can be used
|
||||||
as a base for container solutions like Docker to control and restrict
|
as a base for container solutions like Docker to control and restrict
|
||||||
the access to crypto resources.
|
the access to crypto resources.
|
||||||
|
See the NOTES section below for information on control domains.
|
||||||
.SH COMMANDS
|
.SH COMMANDS
|
||||||
.TP 8
|
.TP 8
|
||||||
.B zcryptctl list
|
.B zcryptctl list
|
||||||
@@ -96,6 +102,14 @@ Update the filter for the specified zcrypt device node and add or
|
|||||||
delete a domain to be accessible through this node. The symbol
|
delete a domain to be accessible through this node. The symbol
|
||||||
\fBALL\fP can be used to enable or disable all domains.
|
\fBALL\fP can be used to enable or disable all domains.
|
||||||
.TP
|
.TP
|
||||||
|
.B zcryptctl addctrl
|
||||||
|
.R |
|
||||||
|
.B delctrl
|
||||||
|
.I node-name domain-nr
|
||||||
|
Update the filter for the specified zcrypt device node and add or
|
||||||
|
delete a control domain to be accessible through this node. The symbol
|
||||||
|
\fBALL\fP can be used to enable or disable all domains.
|
||||||
|
.TP
|
||||||
.B zcryptctl addioctl
|
.B zcryptctl addioctl
|
||||||
.R |
|
.R |
|
||||||
.B delioctl
|
.B delioctl
|
||||||
@@ -116,19 +130,20 @@ line and the settings are applied. Syntax is simple:
|
|||||||
.IP "node=<node-name>"
|
.IP "node=<node-name>"
|
||||||
.IP "aps=<list of ap numbers separated by space, tab or ','>"
|
.IP "aps=<list of ap numbers separated by space, tab or ','>"
|
||||||
.IP "doms=<list of domain numbers separated by space, tab or ','>"
|
.IP "doms=<list of domain numbers separated by space, tab or ','>"
|
||||||
|
.IP "ctrls=<list of control domain numbers separated by space, tab or ','>"
|
||||||
.IP "ioctls=<list of ioctl as numeric or symbolic number separated by space, tab or ','>"
|
.IP "ioctls=<list of ioctl as numeric or symbolic number separated by space, tab or ','>"
|
||||||
.LP
|
.LP
|
||||||
Empty lines are ignored and the '#' marks the rest of the
|
Empty lines are ignored and the '#' marks the rest of the
|
||||||
line as comment.
|
line as comment.
|
||||||
.LP
|
.LP
|
||||||
The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP,
|
The \fBnode=\fP line creates a new zcrypt device node, the \fBaps=\fP,
|
||||||
\fBdoms=\fP and \fBioctls=\fP lines customize the previously created
|
\fBdoms=\fP, \fBctrls=\fP and \fBioctls=\fP lines customize the
|
||||||
node. The symbol \fBALL\fP is also recognized for aps, doms, and
|
previously created node. The symbol \fBALL\fP is also recognized for
|
||||||
ioctls.
|
aps, doms, and ioctls.
|
||||||
.LP
|
.LP
|
||||||
Each action must fit into one line, spreading over multiple lines is
|
Each action must fit into one line, spreading over multiple lines is
|
||||||
not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP
|
not supported. But you can use more than one \fBaps=\fP, \fBdoms=\fP,
|
||||||
and \fBioctls=\fP lines to customize the very same node.
|
\fBctrls=\fP and \fBioctls=\fP lines to customize the very same node.
|
||||||
.LP
|
.LP
|
||||||
Processing stops when a line cannot be parsed or the current action
|
Processing stops when a line cannot be parsed or the current action
|
||||||
fails. In this case the exit status is non zero but the successful
|
fails. In this case the exit status is non zero but the successful
|
||||||
@@ -139,6 +154,17 @@ actions until the failure occurs are not rolled back.
|
|||||||
List the current configuration in a form suitable for input to the
|
List the current configuration in a form suitable for input to the
|
||||||
\fBzcryptctl config\fP command.
|
\fBzcryptctl config\fP command.
|
||||||
.LP
|
.LP
|
||||||
|
.SH NOTES
|
||||||
|
|
||||||
|
Control domain filtering is only supported for custom device
|
||||||
|
<nodename> if the \fBadmask\fP file in sysfs under
|
||||||
|
/sys/class/zcrypt/<nodename>/admask exists. If this file does not
|
||||||
|
exist, the kernel is too old and does not support control command
|
||||||
|
filtering. This is the same effect as setting the control domain mask
|
||||||
|
to ALL. Note that, even though you can allow more than available to
|
||||||
|
the system, you can only send control commands to control domains
|
||||||
|
available to the system.
|
||||||
|
|
||||||
.SH EXIT STATUS
|
.SH EXIT STATUS
|
||||||
On successful completion of the command the exit status is 0. A non
|
On successful completion of the command the exit status is 0. A non
|
||||||
zero return code (and some kind of failure message) is emitted if the
|
zero return code (and some kind of failure message) is emitted if the
|
||||||
|
|||||||
+121
-4
@@ -2,7 +2,7 @@
|
|||||||
* zcryptctl - Maintain zcrypt multi device nodes.
|
* zcryptctl - Maintain zcrypt multi device nodes.
|
||||||
*
|
*
|
||||||
* by Harald Freudenberger <freude@linux.ibm.com>
|
* by Harald Freudenberger <freude@linux.ibm.com>
|
||||||
* Copyright IBM Corp. 2018
|
* Copyright IBM Corp. 2018, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -58,6 +58,8 @@
|
|||||||
#define CMD_DEL_IOCTL 0x0009
|
#define CMD_DEL_IOCTL 0x0009
|
||||||
#define CMD_CONFIG 0x000A
|
#define CMD_CONFIG 0x000A
|
||||||
#define CMD_LISTCONFIG 0x000B
|
#define CMD_LISTCONFIG 0x000B
|
||||||
|
#define CMD_ADD_CTRL 0x000C
|
||||||
|
#define CMD_DEL_CTRL 0x000D
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program configuration
|
* Program configuration
|
||||||
@@ -70,7 +72,7 @@ static const struct util_prg prg = {
|
|||||||
{
|
{
|
||||||
.owner = "IBM Corp.",
|
.owner = "IBM Corp.",
|
||||||
.pub_first = 2018,
|
.pub_first = 2018,
|
||||||
.pub_last = 2018,
|
.pub_last = 2022,
|
||||||
},
|
},
|
||||||
UTIL_PRG_COPYRIGHT_END
|
UTIL_PRG_COPYRIGHT_END
|
||||||
}
|
}
|
||||||
@@ -345,6 +347,18 @@ static int cmd_list(int cmd,
|
|||||||
if (test_bit(i, buf))
|
if (test_bit(i, buf))
|
||||||
printf("%c%d", n++ == 0 ? tab : ',', i);
|
printf("%c%d", n++ == 0 ? tab : ',', i);
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
|
if (cmd == CMD_LISTCONFIG)
|
||||||
|
printf(" ctrls =");
|
||||||
|
else
|
||||||
|
printf(" control domains:");
|
||||||
|
if (read_dn_attr(de->d_name, "admask", buf, sizeof(buf)) != 0)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Could not fetch admask attribute from sysfs for zcrypt node '%s'",
|
||||||
|
de->d_name);
|
||||||
|
for (i = n = 0; i < MAX_ZDEV_DOMAINS_EXT; i++)
|
||||||
|
if (test_bit(i, buf))
|
||||||
|
printf("%c%d", n++ == 0 ? tab : ',', i);
|
||||||
|
putchar('\n');
|
||||||
if (cmd == CMD_LISTCONFIG)
|
if (cmd == CMD_LISTCONFIG)
|
||||||
printf(" ioctls =");
|
printf(" ioctls =");
|
||||||
else
|
else
|
||||||
@@ -526,6 +540,52 @@ static int cmd_add_del_dom(int cmd, const char *node, const char *arg)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void add_del_ctrl(int cmd, const char *node, int dom)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
|
if (cmd == CMD_ADD_CTRL)
|
||||||
|
sprintf(buf, "+%d", dom);
|
||||||
|
else
|
||||||
|
sprintf(buf, "-%d", dom);
|
||||||
|
rc = write_dn_attr(node, "admask", buf);
|
||||||
|
if (rc != 0)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Could not write into sysfs entry to %s domain %d for zdev node '%s'",
|
||||||
|
cmd == CMD_ADD_CTRL ? "add" : "remove", dom, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmd_add_del_ctrl(int cmd, const char *node, const char *arg)
|
||||||
|
{
|
||||||
|
int dom, all = 0;
|
||||||
|
|
||||||
|
if (strcasecmp(arg, "ALL") == 0) {
|
||||||
|
all = 1;
|
||||||
|
} else {
|
||||||
|
if (sscanf(arg, "%i", &dom) != 1)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Invalid domain argument '%s'", arg);
|
||||||
|
if (dom < 0 || dom >= MAX_ZDEV_DOMAINS_EXT)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Domain argument '%s' out of range [0..%d]",
|
||||||
|
arg, MAX_ZDEV_DOMAINS_EXT - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!all) {
|
||||||
|
add_del_ctrl(cmd, node, dom);
|
||||||
|
printf("Control domain %d %s\n", dom,
|
||||||
|
(cmd == CMD_ADD_CTRL ? "added" : "removed"));
|
||||||
|
} else {
|
||||||
|
for (dom = 0; dom < MAX_ZDEV_DOMAINS_EXT; dom++)
|
||||||
|
add_del_ctrl(cmd, node, dom);
|
||||||
|
printf("All control domains %s\n",
|
||||||
|
(cmd == CMD_ADD_CTRL ? "added" : "removed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void add_del_ioctl(int cmd, const char *node, int ioctlnr)
|
static void add_del_ioctl(int cmd, const char *node, int ioctlnr)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
@@ -694,12 +754,34 @@ static int cmd_config(int cmd _UNUSED_,
|
|||||||
break;
|
break;
|
||||||
if (!_match_string(&p, buf))
|
if (!_match_string(&p, buf))
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
"Missing argument(s) for aps=... at '%-8.8s...' in line %d '%s'",
|
"Missing argument(s) for doms=... at '%-8.8s...' in line %d '%s'",
|
||||||
p, nr, line);
|
p, nr, line);
|
||||||
cmd_add_del_dom(CMD_ADD_DOM, node, buf);
|
cmd_add_del_dom(CMD_ADD_DOM, node, buf);
|
||||||
while (isblank(*p) || *p == ',')
|
while (isblank(*p) || *p == ',')
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
} else if (_match_keyword(&p, "ctrls")) {
|
||||||
|
if (!havenode)
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Missing node=... before processing any ctrls=... statements in line %d '%s'",
|
||||||
|
nr, line);
|
||||||
|
if (!_match_character(&p, '='))
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Missing '=' at '%-8.8s...' in line %d '%s'",
|
||||||
|
p, nr, line);
|
||||||
|
while (1) {
|
||||||
|
while (isspace(*p))
|
||||||
|
p++;
|
||||||
|
if (*p == '\0' || *p == '#')
|
||||||
|
break;
|
||||||
|
if (!_match_string(&p, buf))
|
||||||
|
errx(EXIT_FAILURE,
|
||||||
|
"Missing argument(s) for ctrls=... at '%-8.8s...' in line %d '%s'",
|
||||||
|
p, nr, line);
|
||||||
|
cmd_add_del_ctrl(CMD_ADD_CTRL, node, buf);
|
||||||
|
while (isblank(*p) || *p == ',')
|
||||||
|
p++;
|
||||||
|
}
|
||||||
} else if (_match_keyword(&p, "ioctls")) {
|
} else if (_match_keyword(&p, "ioctls")) {
|
||||||
if (!havenode)
|
if (!havenode)
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
@@ -810,13 +892,35 @@ static struct zcryptctl_cmds_s {
|
|||||||
.cmd = CMD_DEL_DOM,
|
.cmd = CMD_DEL_DOM,
|
||||||
.command = "deldom",
|
.command = "deldom",
|
||||||
.function = cmd_add_del_dom,
|
.function = cmd_add_del_dom,
|
||||||
.usage = "zcryptctl deldom <adapter>",
|
.usage = "zcryptctl deldom <domain>",
|
||||||
.description =
|
.description =
|
||||||
"Update the filter for the specified zcrypt device node and\n"
|
"Update the filter for the specified zcrypt device node and\n"
|
||||||
"remove a crypto domain from the allowed domains list. The\n"
|
"remove a crypto domain from the allowed domains list. The\n"
|
||||||
"domain argument may be a number in the range 0-255 or the\n"
|
"domain argument may be a number in the range 0-255 or the\n"
|
||||||
"symbol ALL.",
|
"symbol ALL.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.cmd = CMD_ADD_CTRL,
|
||||||
|
.command = "addctrl",
|
||||||
|
.function = cmd_add_del_ctrl,
|
||||||
|
.usage = "zcryptctl addctrl <domain>",
|
||||||
|
.description =
|
||||||
|
"Update the filter for the specified zcrypt device node and\n"
|
||||||
|
"add a crypto control domain to be accessible via this node.\n"
|
||||||
|
"The domain argument may be a number in the range 0-255 or\n"
|
||||||
|
"the symbol ALL.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.cmd = CMD_DEL_CTRL,
|
||||||
|
.command = "delctrl",
|
||||||
|
.function = cmd_add_del_ctrl,
|
||||||
|
.usage = "zcryptctl delctrl <domain>",
|
||||||
|
.description =
|
||||||
|
"Update the filter for the specified zcrypt device node and\n"
|
||||||
|
"remove a crypto control domain from the allowed domains list.\n"
|
||||||
|
"The domain argument may be a number in the range 0-255 or\n"
|
||||||
|
"the symbol ALL.",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.cmd = CMD_ADD_IOCTL,
|
.cmd = CMD_ADD_IOCTL,
|
||||||
.command = "addioctl",
|
.command = "addioctl",
|
||||||
@@ -1003,6 +1107,19 @@ int main(int argc, char *argv[])
|
|||||||
argv[optind + 1],
|
argv[optind + 1],
|
||||||
argv[optind + 2]);
|
argv[optind + 2]);
|
||||||
break;
|
break;
|
||||||
|
case CMD_ADD_CTRL:
|
||||||
|
case CMD_DEL_CTRL:
|
||||||
|
if (optind + 1 >= argc)
|
||||||
|
errx(EXIT_FAILURE, "Missing node name argument");
|
||||||
|
if (optind + 2 >= argc)
|
||||||
|
errx(EXIT_FAILURE, "Missing domain argument");
|
||||||
|
if (check_nodename(argv[optind + 1]) != 0)
|
||||||
|
errx(EXIT_FAILURE, "Invalid or unknown nodename '%s'",
|
||||||
|
argv[optind + 1]);
|
||||||
|
rc = zcryptctl_cmds[cmdindex].function(c,
|
||||||
|
argv[optind + 1],
|
||||||
|
argv[optind + 2]);
|
||||||
|
break;
|
||||||
case CMD_ADD_IOCTL:
|
case CMD_ADD_IOCTL:
|
||||||
case CMD_DEL_IOCTL:
|
case CMD_DEL_IOCTL:
|
||||||
if (optind + 1 >= argc)
|
if (optind + 1 >= argc)
|
||||||
|
|||||||
+16
-14
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* zcryptstats - Show usage statistics of IBM Crypto Express adapters
|
* zcryptstats - Show usage statistics of IBM Crypto Express adapters
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2019
|
* Copyright IBM Corp. 2019, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -148,8 +148,9 @@ struct chsc_cmb_area {
|
|||||||
#define CRYPTO_TYPE_CEX5S 11
|
#define CRYPTO_TYPE_CEX5S 11
|
||||||
#define CRYPTO_TYPE_CEX6S 12
|
#define CRYPTO_TYPE_CEX6S 12
|
||||||
#define CRYPTO_TYPE_CEX7S 13
|
#define CRYPTO_TYPE_CEX7S 13
|
||||||
|
#define CRYPTO_TYPE_CEX8S 14
|
||||||
|
|
||||||
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX7S
|
#define CRYPTO_TYPE_TOLERATION CRYPTO_TYPE_CEX8S
|
||||||
|
|
||||||
struct crypto_counter {
|
struct crypto_counter {
|
||||||
const char *name;
|
const char *name;
|
||||||
@@ -236,8 +237,8 @@ static const struct crypto_mode mode_pcica[1] = {
|
|||||||
.counters = counter_pcica },
|
.counters = counter_pcica },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_CEX4567_MODES 11
|
#define NUM_CEX45678_MODES 11
|
||||||
static const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
|
static const struct crypto_mode mode_cex45678[NUM_CEX45678_MODES] = {
|
||||||
{ 0 },
|
{ 0 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
@@ -257,7 +258,7 @@ static const struct crypto_mode mode_cex4567[NUM_CEX4567_MODES] = {
|
|||||||
.counters = counter_ep11 },
|
.counters = counter_ep11 },
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NUM_CRYPTO_TYPES 14
|
#define NUM_CRYPTO_TYPES 15
|
||||||
static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
|
static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
|
||||||
{ 0 },
|
{ 0 },
|
||||||
{ 0 },
|
{ 0 },
|
||||||
@@ -276,14 +277,16 @@ static const struct crypto_type crypto_types[NUM_CRYPTO_TYPES] = {
|
|||||||
.modes = mode_accel },
|
.modes = mode_accel },
|
||||||
{ .name = "CEX3C", .num_modes = NUM_COPROC_MODES,
|
{ .name = "CEX3C", .num_modes = NUM_COPROC_MODES,
|
||||||
.modes = mode_coproc },
|
.modes = mode_coproc },
|
||||||
{ .name = "CEX4", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX4", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
{ .name = "CEX5", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX5", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
{ .name = "CEX6", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX6", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
{ .name = "CEX7", .num_modes = NUM_CEX4567_MODES,
|
{ .name = "CEX7", .num_modes = NUM_CEX45678_MODES,
|
||||||
.modes = mode_cex4567 },
|
.modes = mode_cex45678 },
|
||||||
|
{ .name = "CEX8", .num_modes = NUM_CEX45678_MODES,
|
||||||
|
.modes = mode_cex45678 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -2424,4 +2427,3 @@ out:
|
|||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+56
-8
@@ -7,6 +7,7 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -16,6 +17,7 @@
|
|||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
||||||
#define LSBLK_CMDLINE "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINT,PKNAME 2>/dev/null"
|
#define LSBLK_CMDLINE "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINT,PKNAME 2>/dev/null"
|
||||||
|
#define LSBLK_CMDLINE2 "lsblk -P -o NAME,MAJ:MIN,FSTYPE,UUID,MOUNTPOINTS,PKNAME 2>/dev/null"
|
||||||
|
|
||||||
struct blkinfo {
|
struct blkinfo {
|
||||||
struct devnode *devnode;
|
struct devnode *devnode;
|
||||||
@@ -82,6 +84,26 @@ void blkinfo_print(struct blkinfo *blkinfo, int level)
|
|||||||
printf("%*sparent=%s\n", level, "", blkinfo->parent);
|
printf("%*sparent=%s\n", level, "", blkinfo->parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert each occurrence of '\xnn' in @str to character with hex code <nn>. */
|
||||||
|
static void hex_unescape(char *str)
|
||||||
|
{
|
||||||
|
unsigned int c;
|
||||||
|
|
||||||
|
while ((str = strstr(str, "\\x"))) {
|
||||||
|
if (isxdigit(str[2]) && isxdigit(str[3]) &&
|
||||||
|
sscanf(str + 2, "%2x", &c) == 1) {
|
||||||
|
str[0] = (char)c;
|
||||||
|
|
||||||
|
/* Move remainder of str including nul behind <c>. */
|
||||||
|
memmove(str + /* <c> */ 1,
|
||||||
|
str + /* '\xnn' */ 4,
|
||||||
|
strlen(str + 4) + /* <nul> */ 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static char *isolate_keyword(char **line_ptr, const char *keyword)
|
static char *isolate_keyword(char **line_ptr, const char *keyword)
|
||||||
{
|
{
|
||||||
char *start, *end;
|
char *start, *end;
|
||||||
@@ -102,30 +124,58 @@ static char *isolate_keyword(char **line_ptr, const char *keyword)
|
|||||||
return start;
|
return start;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct blkinfo *blkinfo_from_line(char *line)
|
static void add_blkinfos_from_line(struct util_list *blkinfos,
|
||||||
|
char *line)
|
||||||
{
|
{
|
||||||
char *name, *majmin, *fstype, *uuid, *mountpoint, *parent;
|
char *name, *majmin, *fstype, *uuid, *mountpoint, *mountpoints, *parent;
|
||||||
|
struct blkinfo *blkinfo;
|
||||||
|
|
||||||
name = isolate_keyword(&line, "NAME=\"");
|
name = isolate_keyword(&line, "NAME=\"");
|
||||||
majmin = isolate_keyword(&line, "MAJ:MIN=\"");
|
majmin = isolate_keyword(&line, "MAJ:MIN=\"");
|
||||||
|
if (!majmin)
|
||||||
|
majmin = isolate_keyword(&line, "MAJ_MIN=\"");
|
||||||
fstype = isolate_keyword(&line, "FSTYPE=\"");
|
fstype = isolate_keyword(&line, "FSTYPE=\"");
|
||||||
uuid = isolate_keyword(&line, "UUID=\"");
|
uuid = isolate_keyword(&line, "UUID=\"");
|
||||||
mountpoint = isolate_keyword(&line, "MOUNTPOINT=\"");
|
mountpoint = isolate_keyword(&line, "MOUNTPOINT=\"");
|
||||||
|
mountpoints = isolate_keyword(&line, "MOUNTPOINTS=\"");
|
||||||
parent = isolate_keyword(&line, "PKNAME=\"");
|
parent = isolate_keyword(&line, "PKNAME=\"");
|
||||||
|
|
||||||
return blkinfo_new(name, majmin, fstype, uuid, mountpoint, parent);
|
if (!mountpoints) {
|
||||||
|
/* Handle old lsblk output format. */
|
||||||
|
blkinfo = blkinfo_new(name, majmin, fstype, uuid, mountpoint,
|
||||||
|
parent);
|
||||||
|
ptrlist_add(blkinfos, blkinfo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore newline mount point separator encoded as hex. */
|
||||||
|
hex_unescape(mountpoints);
|
||||||
|
|
||||||
|
/* Represent each mount point as a separate blkinfo to support
|
||||||
|
* resolution of multi-mount point file systems like btrfs
|
||||||
|
* subvolumes. */
|
||||||
|
while ((mountpoint = strsep(&mountpoints, "\n"))) {
|
||||||
|
blkinfo = blkinfo_new(name, majmin, fstype, uuid, mountpoint,
|
||||||
|
parent);
|
||||||
|
ptrlist_add(blkinfos, blkinfo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct util_list *blkinfos_read(void)
|
static struct util_list *blkinfos_read(void)
|
||||||
{
|
{
|
||||||
char *output, *curr, *next;
|
char *output, *curr, *next;
|
||||||
struct util_list *blkinfos;
|
struct util_list *blkinfos;
|
||||||
struct blkinfo *blkinfo;
|
|
||||||
|
|
||||||
if (cached_blkinfos)
|
if (cached_blkinfos)
|
||||||
return cached_blkinfos;
|
return cached_blkinfos;
|
||||||
|
|
||||||
output = misc_read_cmd_output(LSBLK_CMDLINE, 0, 1);
|
output = misc_read_cmd_output(LSBLK_CMDLINE2, 0, 1);
|
||||||
|
if (output && !*output) {
|
||||||
|
/* No output might indicate no support for new lsblk command-
|
||||||
|
* line format - fall back to old format. */
|
||||||
|
free(output);
|
||||||
|
output = misc_read_cmd_output(LSBLK_CMDLINE, 0, 1);
|
||||||
|
}
|
||||||
if (!output)
|
if (!output)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -134,9 +184,7 @@ static struct util_list *blkinfos_read(void)
|
|||||||
/* Iterate over each line. */
|
/* Iterate over each line. */
|
||||||
next = output;
|
next = output;
|
||||||
while ((curr = strsep(&next, "\n"))) {
|
while ((curr = strsep(&next, "\n"))) {
|
||||||
blkinfo = blkinfo_from_line(curr);
|
add_blkinfos_from_line(blkinfos, curr);
|
||||||
if (blkinfo)
|
|
||||||
ptrlist_add(blkinfos, blkinfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free(output);
|
free(output);
|
||||||
|
|||||||
+6
-6
@@ -804,17 +804,17 @@ void ccw_unblacklist_id_range(const char *range)
|
|||||||
|
|
||||||
static char ***id_bitmap_new(void)
|
static char ***id_bitmap_new(void)
|
||||||
{
|
{
|
||||||
return misc_malloc(sizeof(char **) * CSSID_MAX);
|
return misc_malloc(sizeof(char **) * (CSSID_MAX + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void id_bitmap_free(char ***id_bitmap)
|
static void id_bitmap_free(char ***id_bitmap)
|
||||||
{
|
{
|
||||||
unsigned int cssid, ssid;
|
unsigned int cssid, ssid;
|
||||||
|
|
||||||
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
|
for (cssid = 0; cssid <= CSSID_MAX; cssid++) {
|
||||||
if (!id_bitmap[cssid])
|
if (!id_bitmap[cssid])
|
||||||
continue;
|
continue;
|
||||||
for (ssid = 0; ssid < SSID_MAX; ssid++)
|
for (ssid = 0; ssid <= SSID_MAX; ssid++)
|
||||||
free(id_bitmap[cssid][ssid]);
|
free(id_bitmap[cssid][ssid]);
|
||||||
free(id_bitmap[cssid]);
|
free(id_bitmap[cssid]);
|
||||||
}
|
}
|
||||||
@@ -965,15 +965,15 @@ static struct util_list *cio_ignore_get_ranges(bool autoconf)
|
|||||||
ranges = strlist_new();
|
ranges = strlist_new();
|
||||||
|
|
||||||
id_bitmap = id_bitmap_collect(autoconf);
|
id_bitmap = id_bitmap_collect(autoconf);
|
||||||
for (cssid = 0; cssid < CSSID_MAX; cssid++) {
|
for (cssid = 0; cssid <= CSSID_MAX; cssid++) {
|
||||||
if (!id_bitmap[cssid])
|
if (!id_bitmap[cssid])
|
||||||
continue;
|
continue;
|
||||||
for (ssid = 0; ssid < SSID_MAX; ssid++) {
|
for (ssid = 0; ssid <= SSID_MAX; ssid++) {
|
||||||
if (!id_bitmap[cssid][ssid])
|
if (!id_bitmap[cssid][ssid])
|
||||||
continue;
|
continue;
|
||||||
first = NULL;
|
first = NULL;
|
||||||
last = NULL;
|
last = NULL;
|
||||||
for (devno = 0; devno < DEVNO_MAX; devno++) {
|
for (devno = 0; devno <= DEVNO_MAX; devno++) {
|
||||||
if (!id_bitmap_get(id_bitmap, cssid, ssid,
|
if (!id_bitmap_get(id_bitmap, cssid, ssid,
|
||||||
devno)) {
|
devno)) {
|
||||||
if (first) {
|
if (first) {
|
||||||
|
|||||||
+11
-4
@@ -2088,12 +2088,18 @@ static exit_code_t devtype_remove_settings(struct devtype *dt, config_t config,
|
|||||||
found = strlist_new();
|
found = strlist_new();
|
||||||
notfound = strlist_new();
|
notfound = strlist_new();
|
||||||
|
|
||||||
if (SCOPE_ACTIVE(config))
|
if (SCOPE_ACTIVE(config)) {
|
||||||
remove_settings(dt->active_settings, names, found, notfound, 1);
|
rc = remove_settings(dt->active_settings, names, found,
|
||||||
|
notfound, 1);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
if (SCOPE_PERSISTENT(config)) {
|
if (SCOPE_PERSISTENT(config)) {
|
||||||
remove_settings(dt->persistent_settings, names, found,
|
rc = remove_settings(dt->persistent_settings, names, found,
|
||||||
notfound, 0);
|
notfound, 0);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!util_list_is_empty(notfound)) {
|
if (!util_list_is_empty(notfound)) {
|
||||||
@@ -2104,6 +2110,7 @@ static exit_code_t devtype_remove_settings(struct devtype *dt, config_t config,
|
|||||||
rc = EXIT_SETTING_NOT_FOUND;
|
rc = EXIT_SETTING_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
strlist_free(found);
|
strlist_free(found);
|
||||||
strlist_free(notfound);
|
strlist_free(notfound);
|
||||||
|
|
||||||
|
|||||||
+7
-6
@@ -30,8 +30,9 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zdsfs", \
|
"zdsfs", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zdsfs", \
|
"zdsfs", \
|
||||||
"curl/curl.h", \
|
"curl/curl.h", \
|
||||||
@@ -39,13 +40,13 @@ check_dep:
|
|||||||
"HAVE_CURL=0")
|
"HAVE_CURL=0")
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
CURL_CFLAGS = $(shell pkg-config --silence-errors --cflags libcurl)
|
CURL_CFLAGS = $(shell pkg-config --silence-errors --cflags libcurl)
|
||||||
CURL_LDLIBS = $(shell pkg-config --silence-errors --libs libcurl)
|
CURL_LDLIBS = $(shell pkg-config --silence-errors --libs libcurl)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
CURL_CFLAGS = -I/usr/include/s390x-linux-gnu/curl
|
CURL_CFLAGS = -I/usr/include/s390x-linux-gnu/curl
|
||||||
CURL_LDLIBS = -lcurl
|
CURL_LDLIBS = -lcurl
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -227,9 +227,6 @@ Allow access by other users
|
|||||||
\fB\-o\fR allow_root
|
\fB\-o\fR allow_root
|
||||||
Allow access by root
|
Allow access by root
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR nonempty
|
|
||||||
Allow mounts over non\-empty file/dir
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR default_permissions
|
\fB\-o\fR default_permissions
|
||||||
Enable permission checking by kernel
|
Enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
+12
-10
@@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* The fuse version define tells fuse that we want to use the new API */
|
/* The fuse version define tells fuse that we want to use the new API */
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -312,7 +312,8 @@ void keepalive_start(void)
|
|||||||
setup_timer(zdsfsinfo.keepalive);
|
setup_timer(zdsfsinfo.keepalive);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int zdsfs_getattr(const char *path, struct stat *stbuf)
|
static int zdsfs_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *UNUSED(fi))
|
||||||
{
|
{
|
||||||
char normds[MAXDSNAMELENGTH];
|
char normds[MAXDSNAMELENGTH];
|
||||||
size_t dssize;
|
size_t dssize;
|
||||||
@@ -524,7 +525,8 @@ static int zdsfs_update_vtoc(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi))
|
off_t UNUSED(offset), struct fuse_file_info *UNUSED(fi),
|
||||||
|
enum fuse_readdir_flags UNUSED(flags))
|
||||||
{
|
{
|
||||||
char normds[MAXDSNAMELENGTH];
|
char normds[MAXDSNAMELENGTH];
|
||||||
char *mbrname;
|
char *mbrname;
|
||||||
@@ -544,9 +546,9 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
* type one: the root directory contains all data sets
|
* type one: the root directory contains all data sets
|
||||||
*/
|
*/
|
||||||
if (strcmp(path, "/") == 0) {
|
if (strcmp(path, "/") == 0) {
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
filler(buf, METADATAFILE, NULL, 0);
|
filler(buf, METADATAFILE, NULL, 0, 0);
|
||||||
/* note that we do not need to distinguish between
|
/* note that we do not need to distinguish between
|
||||||
* normal files and directories here, that is done
|
* normal files and directories here, that is done
|
||||||
* in the rdf_getattr function
|
* in the rdf_getattr function
|
||||||
@@ -558,7 +560,7 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
lzds_dataset_get_is_supported(ds, &issupported);
|
lzds_dataset_get_is_supported(ds, &issupported);
|
||||||
if (issupported) {
|
if (issupported) {
|
||||||
lzds_dataset_get_name(ds, &dsname);
|
lzds_dataset_get_name(ds, &dsname);
|
||||||
filler(buf, dsname, NULL, 0);
|
filler(buf, dsname, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lzds_dsiterator_free(dsit);
|
lzds_dsiterator_free(dsit);
|
||||||
@@ -572,14 +574,14 @@ static int zdsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
lzds_dataset_get_is_PDS(ds, &ispds);
|
lzds_dataset_get_is_PDS(ds, &ispds);
|
||||||
if (ispds) {
|
if (ispds) {
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
rc = lzds_dataset_alloc_memberiterator(ds, &it);
|
rc = lzds_dataset_alloc_memberiterator(ds, &it);
|
||||||
if (rc)
|
if (rc)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
while (!lzds_memberiterator_get_next_member(it, &member)) {
|
while (!lzds_memberiterator_get_next_member(it, &member)) {
|
||||||
lzds_pdsmember_get_name(member, &mbrname);
|
lzds_pdsmember_get_name(member, &mbrname);
|
||||||
filler(buf, mbrname, NULL, 0);
|
filler(buf, mbrname, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
lzds_memberiterator_free(it);
|
lzds_memberiterator_free(it);
|
||||||
} else
|
} else
|
||||||
|
|||||||
+11
-10
@@ -15,8 +15,9 @@ check_dep_fuse:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"zgetdump mount support", \
|
"zgetdump mount support", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -41,28 +42,28 @@ check_dep_zlib:
|
|||||||
|
|
||||||
all: check_dep_fuse check_dep_zlib zgetdump
|
all: check_dep_fuse check_dep_zlib zgetdump
|
||||||
|
|
||||||
OBJECTS = zgetdump.o opts.o zg.o \
|
OBJECTS = zgetdump.o opts.o zg.o zg_error.o zg_print.o \
|
||||||
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
|
dfi.o dfi_mem_chunk.o dfi_vmcoreinfo.o \
|
||||||
dfi_lkcd.o dfi_elf.o \
|
dfi_lkcd.o dfi_elf.o \
|
||||||
dfi_s390.o dfi_s390_ext.o\
|
dfi_s390.o dfi_s390_ext.o\
|
||||||
dfi_s390mv.o dfi_s390mv_ext.o \
|
dfi_s390mv.o dfi_s390mv_ext.o \
|
||||||
dfi_s390tape.o dfi_kdump.o \
|
dfi_s390tape.o dfi_kdump.o \
|
||||||
dfi_devmem.o dfo.o \
|
dfi_devmem.o dfo.o dfo_mem_chunk.o \
|
||||||
dfo_elf.o dfo_s390.o \
|
dfo_elf.o dfo_s390.o \
|
||||||
df_s390.o \
|
df_elf.o df_s390.o \
|
||||||
dt.o dt_s390sv.o dt_s390sv_ext.o \
|
dt.o dt_s390sv.o dt_s390sv_ext.o \
|
||||||
dt_s390mv.o dt_s390mv_ext.o \
|
dt_s390mv.o dt_s390mv_ext.o \
|
||||||
dt_scsi.o stdout.o \
|
dt_scsi.o output.o
|
||||||
|
|
||||||
ifeq ("$(HAVE_FUSE)","0")
|
ifeq ("$(HAVE_FUSE)","0")
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
|
FUSE_CFLAGS = -DHAVE_FUSE=0 -D_FILE_OFFSET_BITS=64
|
||||||
FUSE_LDLIBS =
|
FUSE_LDLIBS =
|
||||||
else ifneq ($(shell sh -c 'command -v pkg-config'),)
|
else ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = -DHAVE_FUSE=1 $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -DHAVE_FUSE=1 -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
LDLIBS += -lz $(FUSE_LDLIBS)
|
LDLIBS += -lz $(FUSE_LDLIBS)
|
||||||
ALL_CFLAGS += $(FUSE_CFLAGS)
|
ALL_CFLAGS += $(FUSE_CFLAGS)
|
||||||
|
|||||||
+191
@@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2018, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "df_elf.h"
|
||||||
|
|
||||||
|
#define NOTE_NAME_CORE "CORE"
|
||||||
|
#define NOTE_NAME_LINUX "LINUX"
|
||||||
|
#define NOTE_NAME_VMCOREINFO "VMCOREINFO"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize ELF header
|
||||||
|
*/
|
||||||
|
void *ehdr_init(Elf64_Ehdr *ehdr, Elf64_Half phnum)
|
||||||
|
{
|
||||||
|
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
|
||||||
|
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
|
||||||
|
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
||||||
|
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
||||||
|
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
||||||
|
ehdr->e_ident[EI_ABIVERSION] = 0;
|
||||||
|
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
|
||||||
|
ehdr->e_type = ET_CORE;
|
||||||
|
ehdr->e_machine = EM_S390;
|
||||||
|
ehdr->e_version = EV_CURRENT;
|
||||||
|
ehdr->e_entry = 0;
|
||||||
|
ehdr->e_phoff = sizeof(Elf64_Ehdr);
|
||||||
|
ehdr->e_shoff = 0;
|
||||||
|
ehdr->e_flags = 0;
|
||||||
|
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
|
||||||
|
ehdr->e_phentsize = sizeof(Elf64_Phdr);
|
||||||
|
ehdr->e_phnum = phnum;
|
||||||
|
ehdr->e_shentsize = 0;
|
||||||
|
ehdr->e_shnum = 0;
|
||||||
|
ehdr->e_shstrndx = 0;
|
||||||
|
return ehdr + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize ELF note
|
||||||
|
*/
|
||||||
|
void *nt_init(void *buf, Elf64_Word type, const void *desc, int d_len,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
Elf64_Nhdr *note;
|
||||||
|
u64 len;
|
||||||
|
|
||||||
|
note = (Elf64_Nhdr *)buf;
|
||||||
|
note->n_namesz = strlen(name) + 1;
|
||||||
|
note->n_descsz = d_len;
|
||||||
|
note->n_type = type;
|
||||||
|
len = sizeof(Elf64_Nhdr);
|
||||||
|
|
||||||
|
memcpy(buf + len, name, note->n_namesz);
|
||||||
|
len = ROUNDUP(len + note->n_namesz, 4);
|
||||||
|
|
||||||
|
memcpy(buf + len, desc, note->n_descsz);
|
||||||
|
len = ROUNDUP(len + note->n_descsz, 4);
|
||||||
|
|
||||||
|
return PTR_ADD(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize prstatus note
|
||||||
|
*/
|
||||||
|
void *nt_prstatus(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
struct nt_prstatus_64 nt_prstatus;
|
||||||
|
static int cpu_nr = 1;
|
||||||
|
|
||||||
|
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
|
||||||
|
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
|
||||||
|
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
|
||||||
|
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
|
||||||
|
nt_prstatus.pr_pid = cpu_nr;
|
||||||
|
cpu_nr++;
|
||||||
|
|
||||||
|
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
|
||||||
|
NOTE_NAME_CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize fpregset (floating point) note
|
||||||
|
*/
|
||||||
|
void *nt_fpregset(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
struct nt_fpregset_64 nt_fpregset;
|
||||||
|
|
||||||
|
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
|
||||||
|
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
|
||||||
|
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
|
||||||
|
|
||||||
|
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
|
||||||
|
NOTE_NAME_CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize timer note
|
||||||
|
*/
|
||||||
|
void *nt_s390_timer(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
|
||||||
|
NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize TOD clock comparator note
|
||||||
|
*/
|
||||||
|
void *nt_s390_tod_cmp(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
|
||||||
|
sizeof(cpu->todcmp), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize TOD programmable register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_tod_preg(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
|
||||||
|
sizeof(cpu->todpreg), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize control register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_ctrs(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
|
||||||
|
NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize prefix register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_prefix(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
|
||||||
|
sizeof(cpu->prefix), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vxrs_low register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_vxrs_low(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
|
||||||
|
sizeof(cpu->vxrs_low), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vxrs_high register note
|
||||||
|
*/
|
||||||
|
void *nt_s390_vxrs_high(void *ptr, const struct dfi_cpu *cpu)
|
||||||
|
{
|
||||||
|
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
|
||||||
|
sizeof(cpu->vxrs_high), NOTE_NAME_LINUX);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize prpsinfo note
|
||||||
|
*/
|
||||||
|
void *nt_prpsinfo(void *ptr)
|
||||||
|
{
|
||||||
|
struct nt_prpsinfo_64 prpsinfo;
|
||||||
|
|
||||||
|
memset(&prpsinfo, 0, sizeof(prpsinfo));
|
||||||
|
prpsinfo.pr_state = 0;
|
||||||
|
prpsinfo.pr_sname = 'R';
|
||||||
|
prpsinfo.pr_zomb = 0;
|
||||||
|
strcpy(prpsinfo.pr_fname, "vmlinux");
|
||||||
|
|
||||||
|
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo),
|
||||||
|
NOTE_NAME_CORE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize vmcoreinfo note
|
||||||
|
*/
|
||||||
|
void *nt_vmcoreinfo(void *ptr, const char *vmcoreinfo)
|
||||||
|
{
|
||||||
|
if (!vmcoreinfo)
|
||||||
|
return ptr;
|
||||||
|
return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo),
|
||||||
|
NOTE_NAME_VMCOREINFO);
|
||||||
|
}
|
||||||
+17
-1
@@ -17,8 +17,8 @@
|
|||||||
|
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#include "dfo.h"
|
|
||||||
#include "zg.h"
|
#include "zg.h"
|
||||||
|
#include "dfi.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* S390 CPU timer note (u64)
|
* S390 CPU timer note (u64)
|
||||||
@@ -116,4 +116,20 @@ static inline void df_elf_ensure_s390x(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *ehdr_init(Elf64_Ehdr *ehdr, Elf64_Half phnum);
|
||||||
|
|
||||||
|
void *nt_init(void *buf, Elf64_Word type, const void *desc, int d_len,
|
||||||
|
const char *name);
|
||||||
|
void *nt_prstatus(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_fpregset(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_timer(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_tod_cmp(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_tod_preg(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_ctrs(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_prefix(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_vxrs_low(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_s390_vxrs_high(void *ptr, const struct dfi_cpu *cpu);
|
||||||
|
void *nt_prpsinfo(void *ptr);
|
||||||
|
void *nt_vmcoreinfo(void *ptr, const char *vmcoreinfo);
|
||||||
|
|
||||||
#endif /* DF_ELF_H */
|
#endif /* DF_ELF_H */
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ const char *dfi_arch_str(enum dfi_arch arch)
|
|||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
ABORT("dfi_arch_str: Invalid dfi arch: %d", arch);
|
ABORT("dfi_arch_str: Invalid dfi arch: %d", arch);
|
||||||
|
return NULL; /* UNREACHABLE */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -784,6 +785,7 @@ int dfi_init(void)
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
ERR_EXIT("No valid dump found on \"%s\"", g.opts.device);
|
ERR_EXIT("No valid dump found on \"%s\"", g.opts.device);
|
||||||
|
return -1; /* UNREACHABLE */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -556,7 +556,6 @@ static int open_dump(void)
|
|||||||
}
|
}
|
||||||
if (mv_dumper_read() != 0)
|
if (mv_dumper_read() != 0)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
zg_close(g.fh);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-108
@@ -9,16 +9,13 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <time.h>
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include "lib/util_list.h"
|
#include "zg.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
#include "dfi_mem_chunk.h"
|
|
||||||
#include "dfo.h"
|
#include "dfo.h"
|
||||||
|
|
||||||
#define dfo_chunk_iterate(dfo_chunk) \
|
|
||||||
util_list_iterate(&l.dump.chunk_list, dfo_chunk)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFO vector
|
* DFO vector
|
||||||
*/
|
*/
|
||||||
@@ -28,70 +25,14 @@ static struct dfo *dfo_vec[] = {
|
|||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump (output) information
|
|
||||||
*/
|
|
||||||
struct dump {
|
|
||||||
u64 off; /* Current file offset in dump */
|
|
||||||
u64 size; /* Size of dump in bytes */
|
|
||||||
unsigned int chunk_cnt; /* Number of dump chunks */
|
|
||||||
struct util_list chunk_list; /* DFO chunk list */
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* File local static data
|
||||||
*/
|
*/
|
||||||
static struct {
|
static struct {
|
||||||
struct dump dump;
|
u64 off; /* Current file offset in dump */
|
||||||
struct dfo *dfo;
|
struct dfo *dfo;
|
||||||
} l;
|
} l;
|
||||||
|
|
||||||
/*
|
|
||||||
* Add dump chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
|
|
||||||
{
|
|
||||||
struct dfo_chunk *dfo_chunk;
|
|
||||||
|
|
||||||
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
|
|
||||||
dfo_chunk->start = start;
|
|
||||||
dfo_chunk->end = start + size - 1;
|
|
||||||
dfo_chunk->data = data;
|
|
||||||
dfo_chunk->read_fn = read_fn;
|
|
||||||
util_list_add_head(&l.dump.chunk_list, dfo_chunk);
|
|
||||||
l.dump.chunk_cnt++;
|
|
||||||
l.dump.size = MAX(l.dump.size, dfo_chunk->end + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump chunk function: Copy zero pages for chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
(void) dfo_chunk;
|
|
||||||
(void) off;
|
|
||||||
|
|
||||||
memset(buf, 0, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump chunk function: Copy given buffer for chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
memcpy(buf, dfo_chunk->data + off, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump chunk function: Copy given memory range for chunk
|
|
||||||
*/
|
|
||||||
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
|
||||||
{
|
|
||||||
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
|
|
||||||
|
|
||||||
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get DFO name
|
* Get DFO name
|
||||||
*/
|
*/
|
||||||
@@ -125,55 +66,17 @@ void dfo_init(void)
|
|||||||
{
|
{
|
||||||
if (!l.dfo)
|
if (!l.dfo)
|
||||||
ABORT("DFO not set");
|
ABORT("DFO not set");
|
||||||
util_list_init(&l.dump.chunk_list, struct dfo_chunk, list);
|
if (dfo_chunk_init())
|
||||||
|
ABORT("DFO memory chunk init failed");
|
||||||
l.dfo->init();
|
l.dfo->init();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Find dump chunk for offset "off"
|
|
||||||
*
|
|
||||||
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
|
|
||||||
* overlap, the last registered chunk wins. The dfo_chunk_find() function
|
|
||||||
* reflects that by returning the first memory chunk that is found in
|
|
||||||
* the dfo chunk list.
|
|
||||||
*
|
|
||||||
* In addition to that it calculates the "virtual end" of that chunk. An
|
|
||||||
* overlapping chunk can limit the "virtual end" of an underlying chunk so
|
|
||||||
* that the "virtual end" of that chunk is lower than the "real end".
|
|
||||||
*
|
|
||||||
* Example:
|
|
||||||
*
|
|
||||||
* chunk 1.: |------|
|
|
||||||
* chunk 2.: |---------------------|
|
|
||||||
* off.....: ^
|
|
||||||
* virt end: ^
|
|
||||||
* real end: ^
|
|
||||||
*
|
|
||||||
* In this case chunk 2 will be returned and "end" is set to the start of
|
|
||||||
* chunk 1.
|
|
||||||
*/
|
|
||||||
static struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
|
|
||||||
{
|
|
||||||
struct dfo_chunk *dfo_chunk;
|
|
||||||
|
|
||||||
*end = U64_MAX;
|
|
||||||
dfo_chunk_iterate(dfo_chunk) {
|
|
||||||
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
|
|
||||||
*end = MIN(*end, dfo_chunk->end);
|
|
||||||
return dfo_chunk;
|
|
||||||
} else if (dfo_chunk->start > off) {
|
|
||||||
*end = MIN(*end, dfo_chunk->start - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Seek to output dump offset "off"
|
* Seek to output dump offset "off"
|
||||||
*/
|
*/
|
||||||
void dfo_seek(u64 off)
|
void dfo_seek(u64 off)
|
||||||
{
|
{
|
||||||
l.dump.off = off;
|
l.off = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -183,7 +86,7 @@ u64 dfo_read(void *buf, u64 cnt)
|
|||||||
{
|
{
|
||||||
struct dfo_chunk *dfo_chunk;
|
struct dfo_chunk *dfo_chunk;
|
||||||
u64 copied = 0, end, size;
|
u64 copied = 0, end, size;
|
||||||
u64 off = l.dump.off;
|
u64 off = l.off;
|
||||||
|
|
||||||
while (copied != cnt) {
|
while (copied != cnt) {
|
||||||
dfo_chunk = dfo_chunk_find(off, &end);
|
dfo_chunk = dfo_chunk_find(off, &end);
|
||||||
@@ -196,7 +99,7 @@ u64 dfo_read(void *buf, u64 cnt)
|
|||||||
off += size;
|
off += size;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
l.dump.off = off;
|
l.off = off;
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,5 +108,5 @@ out:
|
|||||||
*/
|
*/
|
||||||
u64 dfo_size(void)
|
u64 dfo_size(void)
|
||||||
{
|
{
|
||||||
return l.dump.size;
|
return dfo_chunk_dump_size();
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-31
@@ -12,37 +12,12 @@
|
|||||||
#ifndef DFO_H
|
#ifndef DFO_H
|
||||||
#define DFO_H
|
#define DFO_H
|
||||||
|
|
||||||
#include "lib/util_list.h"
|
u64 dfo_read(void *buf, u64 cnt);
|
||||||
#include "zg.h"
|
void dfo_seek(u64 addr);
|
||||||
|
u64 dfo_size(void);
|
||||||
struct dfo_chunk;
|
const char *dfo_name(void);
|
||||||
|
void dfo_init(void);
|
||||||
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
|
int dfo_set(const char *dfo_name);
|
||||||
void *buf, u64 cnt);
|
|
||||||
|
|
||||||
struct dfo_chunk {
|
|
||||||
struct util_list_node list;
|
|
||||||
u64 start;
|
|
||||||
u64 end;
|
|
||||||
dfo_chunk_read_fn read_fn;
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf,
|
|
||||||
u64 cnt);
|
|
||||||
extern void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf,
|
|
||||||
u64 cnt);
|
|
||||||
extern void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf,
|
|
||||||
u64 cnt);
|
|
||||||
extern void dfo_chunk_add(u64 start, u64 size, void *data,
|
|
||||||
dfo_chunk_read_fn read_fn);
|
|
||||||
|
|
||||||
extern u64 dfo_read(void *buf, u64 cnt);
|
|
||||||
extern void dfo_seek(u64 addr);
|
|
||||||
extern u64 dfo_size(void);
|
|
||||||
extern const char *dfo_name(void);
|
|
||||||
extern void dfo_init(void);
|
|
||||||
extern int dfo_set(const char *dfo_name);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* DFO operations
|
* DFO operations
|
||||||
|
|||||||
+26
-211
@@ -19,6 +19,7 @@
|
|||||||
#include "df_elf.h"
|
#include "df_elf.h"
|
||||||
#include "dfi.h"
|
#include "dfi.h"
|
||||||
#include "dfi_mem_chunk.h"
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
#include "dfi_vmcoreinfo.h"
|
#include "dfi_vmcoreinfo.h"
|
||||||
#include "dfo.h"
|
#include "dfo.h"
|
||||||
|
|
||||||
@@ -27,55 +28,19 @@
|
|||||||
#define HDR_BASE_SIZE 0x2000
|
#define HDR_BASE_SIZE 0x2000
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File local static data
|
* Initialize ELF loads program headers
|
||||||
*/
|
*/
|
||||||
static struct {
|
static u64 load_phdrs_init(Elf64_Phdr *phdr, u64 elf_offset)
|
||||||
void *hdr;
|
|
||||||
u32 hdr_size;
|
|
||||||
} l;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize ELF header
|
|
||||||
*/
|
|
||||||
static void *ehdr_init(Elf64_Ehdr *ehdr)
|
|
||||||
{
|
|
||||||
memcpy(ehdr->e_ident, ELFMAG, SELFMAG);
|
|
||||||
ehdr->e_ident[EI_CLASS] = ELFCLASS64;
|
|
||||||
ehdr->e_ident[EI_DATA] = ELFDATA2MSB;
|
|
||||||
ehdr->e_ident[EI_VERSION] = EV_CURRENT;
|
|
||||||
ehdr->e_ident[EI_OSABI] = ELFOSABI_SYSV;
|
|
||||||
ehdr->e_ident[EI_ABIVERSION] = 0;
|
|
||||||
memset(ehdr->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
|
|
||||||
ehdr->e_type = ET_CORE;
|
|
||||||
ehdr->e_machine = EM_S390;
|
|
||||||
ehdr->e_version = EV_CURRENT;
|
|
||||||
ehdr->e_entry = 0;
|
|
||||||
ehdr->e_phoff = sizeof(Elf64_Ehdr);
|
|
||||||
ehdr->e_shoff = 0;
|
|
||||||
ehdr->e_flags = 0;
|
|
||||||
ehdr->e_ehsize = sizeof(Elf64_Ehdr);
|
|
||||||
ehdr->e_phentsize = sizeof(Elf64_Phdr);
|
|
||||||
ehdr->e_phnum = dfi_mem_chunk_cnt() + 1;
|
|
||||||
ehdr->e_shentsize = 0;
|
|
||||||
ehdr->e_shnum = 0;
|
|
||||||
ehdr->e_shstrndx = 0;
|
|
||||||
return ehdr + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize ELF loads
|
|
||||||
*/
|
|
||||||
static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
|
|
||||||
{
|
{
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
u64 mem_size = 0;
|
u64 mem_size = 0;
|
||||||
|
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
phdr->p_type = PT_LOAD;
|
phdr->p_type = PT_LOAD;
|
||||||
phdr->p_offset = loads_offset;
|
phdr->p_offset = elf_offset;
|
||||||
phdr->p_vaddr = mem_chunk->start;
|
phdr->p_vaddr = mem_chunk->start;
|
||||||
phdr->p_paddr = mem_chunk->start;
|
phdr->p_paddr = phdr->p_vaddr;
|
||||||
phdr->p_memsz = mem_chunk->end - mem_chunk->start + 1;
|
phdr->p_memsz = mem_chunk->size;
|
||||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||||
/* Zero memory chunk */
|
/* Zero memory chunk */
|
||||||
phdr->p_filesz = 0;
|
phdr->p_filesz = 0;
|
||||||
@@ -83,7 +48,7 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
|
|||||||
phdr->p_filesz = phdr->p_memsz;
|
phdr->p_filesz = phdr->p_memsz;
|
||||||
phdr->p_flags = PF_R | PF_W | PF_X;
|
phdr->p_flags = PF_R | PF_W | PF_X;
|
||||||
phdr->p_align = PAGE_SIZE;
|
phdr->p_align = PAGE_SIZE;
|
||||||
loads_offset += phdr->p_filesz;
|
elf_offset += phdr->p_filesz;
|
||||||
mem_size += phdr->p_memsz;
|
mem_size += phdr->p_memsz;
|
||||||
phdr++;
|
phdr++;
|
||||||
}
|
}
|
||||||
@@ -91,160 +56,12 @@ static u64 loads_init(Elf64_Phdr *phdr, u64 loads_offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize ELF note
|
* Initialize the program header entries for the notes and the related segment
|
||||||
|
* data.
|
||||||
*/
|
*/
|
||||||
static void *nt_init(void *buf, Elf64_Word type, void *desc, int d_len,
|
static void *notes_init(Elf64_Phdr *phdr, void *segment_start, u64 elf_offset)
|
||||||
const char *name)
|
|
||||||
{
|
{
|
||||||
Elf64_Nhdr *note;
|
void *ptr = segment_start;
|
||||||
u64 len;
|
|
||||||
|
|
||||||
note = (Elf64_Nhdr *)buf;
|
|
||||||
note->n_namesz = strlen(name) + 1;
|
|
||||||
note->n_descsz = d_len;
|
|
||||||
note->n_type = type;
|
|
||||||
len = sizeof(Elf64_Nhdr);
|
|
||||||
|
|
||||||
memcpy(buf + len, name, note->n_namesz);
|
|
||||||
len = ROUNDUP(len + note->n_namesz, 4);
|
|
||||||
|
|
||||||
memcpy(buf + len, desc, note->n_descsz);
|
|
||||||
len = ROUNDUP(len + note->n_descsz, 4);
|
|
||||||
|
|
||||||
return PTR_ADD(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize prstatus note
|
|
||||||
*/
|
|
||||||
static void *nt_prstatus(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
struct nt_prstatus_64 nt_prstatus;
|
|
||||||
static int cpu_nr = 1;
|
|
||||||
|
|
||||||
memset(&nt_prstatus, 0, sizeof(nt_prstatus));
|
|
||||||
memcpy(&nt_prstatus.gprs, cpu->gprs, sizeof(cpu->gprs));
|
|
||||||
memcpy(&nt_prstatus.psw, cpu->psw, sizeof(cpu->psw));
|
|
||||||
memcpy(&nt_prstatus.acrs, cpu->acrs, sizeof(cpu->acrs));
|
|
||||||
nt_prstatus.pr_pid = cpu_nr;
|
|
||||||
cpu_nr++;
|
|
||||||
|
|
||||||
return nt_init(ptr, NT_PRSTATUS, &nt_prstatus, sizeof(nt_prstatus),
|
|
||||||
"CORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize fpregset (floating point) note
|
|
||||||
*/
|
|
||||||
static void *nt_fpregset(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
struct nt_fpregset_64 nt_fpregset;
|
|
||||||
|
|
||||||
memset(&nt_fpregset, 0, sizeof(nt_fpregset));
|
|
||||||
memcpy(&nt_fpregset.fpc, &cpu->fpc, sizeof(cpu->fpc));
|
|
||||||
memcpy(&nt_fpregset.fprs, &cpu->fprs, sizeof(cpu->fprs));
|
|
||||||
|
|
||||||
return nt_init(ptr, NT_FPREGSET, &nt_fpregset, sizeof(nt_fpregset),
|
|
||||||
"CORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize timer note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_timer(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_TIMER, &cpu->timer, sizeof(cpu->timer),
|
|
||||||
"LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize TOD clock comparator note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_tod_cmp(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_TODCMP, &cpu->todcmp,
|
|
||||||
sizeof(cpu->todcmp), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize TOD programmable register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_tod_preg(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_TODPREG, &cpu->todpreg,
|
|
||||||
sizeof(cpu->todpreg), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize control register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_ctrs(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_CTRS, &cpu->ctrs, sizeof(cpu->ctrs),
|
|
||||||
"LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize prefix register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_prefix(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_PREFIX, &cpu->prefix,
|
|
||||||
sizeof(cpu->prefix), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize vxrs_low register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_vxrs_low(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_VXRS_LOW, &cpu->vxrs_low,
|
|
||||||
sizeof(cpu->vxrs_low), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize vxrs_high register note
|
|
||||||
*/
|
|
||||||
static void *nt_s390_vxrs_high(void *ptr, struct dfi_cpu *cpu)
|
|
||||||
{
|
|
||||||
return nt_init(ptr, NT_S390_VXRS_HIGH, &cpu->vxrs_high,
|
|
||||||
sizeof(cpu->vxrs_high), "LINUX");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize prpsinfo note
|
|
||||||
*/
|
|
||||||
static void *nt_prpsinfo(void *ptr)
|
|
||||||
{
|
|
||||||
struct nt_prpsinfo_64 prpsinfo;
|
|
||||||
|
|
||||||
memset(&prpsinfo, 0, sizeof(prpsinfo));
|
|
||||||
prpsinfo.pr_state = 0;
|
|
||||||
prpsinfo.pr_sname = 'R';
|
|
||||||
prpsinfo.pr_zomb = 0;
|
|
||||||
strcpy(prpsinfo.pr_fname, "vmlinux");
|
|
||||||
|
|
||||||
return nt_init(ptr, NT_PRPSINFO, &prpsinfo, sizeof(prpsinfo), "CORE");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize vmcoreinfo note
|
|
||||||
*/
|
|
||||||
static void *nt_vmcoreinfo(void *ptr)
|
|
||||||
{
|
|
||||||
char *vmcoreinfo = dfi_vmcoreinfo_get();
|
|
||||||
|
|
||||||
if (!vmcoreinfo)
|
|
||||||
return ptr;
|
|
||||||
return nt_init(ptr, 0, vmcoreinfo, strlen(vmcoreinfo), "VMCOREINFO");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize notes
|
|
||||||
*/
|
|
||||||
static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|
||||||
{
|
|
||||||
void *ptr_start = ptr;
|
|
||||||
struct dfi_cpu *cpu;
|
struct dfi_cpu *cpu;
|
||||||
|
|
||||||
ptr = nt_prpsinfo(ptr);
|
ptr = nt_prpsinfo(ptr);
|
||||||
@@ -266,24 +83,24 @@ static void *notes_init(Elf64_Phdr *phdr, void *ptr, u64 notes_offset)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
ptr = nt_vmcoreinfo(ptr);
|
ptr = nt_vmcoreinfo(ptr, dfi_vmcoreinfo_get());
|
||||||
memset(phdr, 0, sizeof(*phdr));
|
memset(phdr, 0, sizeof(*phdr));
|
||||||
phdr->p_type = PT_NOTE;
|
phdr->p_type = PT_NOTE;
|
||||||
phdr->p_offset = notes_offset;
|
phdr->p_offset = elf_offset;
|
||||||
phdr->p_filesz = (unsigned long) PTR_SUB(ptr, ptr_start);
|
phdr->p_filesz = PTR_DIFF(ptr, segment_start);
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup dump chunks
|
* Setup dump chunks
|
||||||
*/
|
*/
|
||||||
static void dump_chunks_init(void)
|
static void dump_chunks_init(void *hdr, u64 hdr_size)
|
||||||
{
|
{
|
||||||
struct dfi_mem_chunk *mem_chunk;
|
struct dfi_mem_chunk *mem_chunk;
|
||||||
u64 off = 0;
|
u64 off = 0;
|
||||||
|
|
||||||
dfo_chunk_add(0, l.hdr_size, l.hdr, dfo_chunk_buf_fn);
|
dfo_chunk_add(off, hdr_size, hdr, dfo_chunk_buf_fn);
|
||||||
off = l.hdr_size;
|
off += hdr_size;
|
||||||
dfi_mem_chunk_iterate(mem_chunk) {
|
dfi_mem_chunk_iterate(mem_chunk) {
|
||||||
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
if (mem_chunk->read_fn == dfi_mem_chunk_read_zero)
|
||||||
/* Zero memory chunk */
|
/* Zero memory chunk */
|
||||||
@@ -312,31 +129,29 @@ static void dfo_elf_init(void)
|
|||||||
{
|
{
|
||||||
Elf64_Phdr *phdr_notes, *phdr_loads;
|
Elf64_Phdr *phdr_notes, *phdr_loads;
|
||||||
u32 alloc_size;
|
u32 alloc_size;
|
||||||
|
void *buf, *ptr;
|
||||||
u64 hdr_off;
|
u64 hdr_off;
|
||||||
void *ptr;
|
|
||||||
|
|
||||||
ensure_s390x();
|
ensure_s390x();
|
||||||
alloc_size = HDR_BASE_SIZE +
|
alloc_size = HDR_BASE_SIZE +
|
||||||
dfi_cpu_cnt() * HDR_PER_CPU_SIZE +
|
dfi_cpu_cnt() * HDR_PER_CPU_SIZE +
|
||||||
dfi_mem_chunk_cnt() * HDR_PER_MEMC_SIZE;
|
dfi_mem_chunk_cnt() * HDR_PER_MEMC_SIZE;
|
||||||
l.hdr = zg_alloc(alloc_size);
|
buf = zg_alloc(alloc_size);
|
||||||
/* Init elf header */
|
/* Init elf header */
|
||||||
ptr = ehdr_init(l.hdr);
|
ptr = ehdr_init(buf, dfi_mem_chunk_cnt() + 1);
|
||||||
/* Init program headers */
|
/* Init program headers */
|
||||||
phdr_notes = ptr;
|
phdr_notes = ptr;
|
||||||
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
|
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr));
|
||||||
phdr_loads = ptr;
|
phdr_loads = ptr;
|
||||||
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * dfi_mem_chunk_cnt());
|
ptr = PTR_ADD(ptr, sizeof(Elf64_Phdr) * dfi_mem_chunk_cnt());
|
||||||
/* Init notes */
|
/* Init notes */
|
||||||
hdr_off = PTR_DIFF(ptr, l.hdr);
|
hdr_off = PTR_DIFF(ptr, buf);
|
||||||
ptr = notes_init(phdr_notes, ptr, hdr_off);
|
ptr = notes_init(phdr_notes, ptr, hdr_off);
|
||||||
/* Init loads */
|
hdr_off = PTR_DIFF(ptr, buf);
|
||||||
hdr_off = PTR_DIFF(ptr, l.hdr);
|
load_phdrs_init(phdr_loads, hdr_off);
|
||||||
loads_init(phdr_loads, hdr_off);
|
if (hdr_off > alloc_size)
|
||||||
l.hdr_size = hdr_off;
|
ABORT("hdr_size=%llu alloc_size=%u", hdr_off, alloc_size);
|
||||||
if (l.hdr_size > alloc_size)
|
dump_chunks_init(buf, hdr_off);
|
||||||
ABORT("hdr_size=%u alloc_size=%u", l.hdr_size, alloc_size);
|
|
||||||
dump_chunks_init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "zg.h"
|
||||||
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* File local static data
|
||||||
|
*/
|
||||||
|
static struct {
|
||||||
|
u64 size; /* Size of dump in bytes */
|
||||||
|
unsigned int chunk_cnt; /* Number of dump chunks */
|
||||||
|
struct util_list chunk_list; /* DFO chunk list */
|
||||||
|
} l;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add dump chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn)
|
||||||
|
{
|
||||||
|
struct dfo_chunk *dfo_chunk;
|
||||||
|
|
||||||
|
dfo_chunk = zg_alloc(sizeof(*dfo_chunk));
|
||||||
|
dfo_chunk->start = start;
|
||||||
|
dfo_chunk->end = start + size - 1;
|
||||||
|
dfo_chunk->data = data;
|
||||||
|
dfo_chunk->read_fn = read_fn;
|
||||||
|
util_list_add_head(&l.chunk_list, dfo_chunk);
|
||||||
|
l.chunk_cnt++;
|
||||||
|
l.size = MAX(l.size, dfo_chunk->end + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump chunk function: Copy zero pages for chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_zero_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
(void) dfo_chunk;
|
||||||
|
(void) off;
|
||||||
|
|
||||||
|
memset(buf, 0, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump chunk function: Copy given buffer for chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_buf_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
memcpy(buf, dfo_chunk->data + off, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dump chunk function: Copy given memory range for chunk
|
||||||
|
*/
|
||||||
|
void dfo_chunk_mem_fn(struct dfo_chunk *dfo_chunk, u64 off, void *buf, u64 cnt)
|
||||||
|
{
|
||||||
|
struct dfi_mem_chunk *mem_chunk = dfo_chunk->data;
|
||||||
|
|
||||||
|
mem_chunk->read_fn(mem_chunk, off, buf, cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Find dump chunk for offset "off"
|
||||||
|
*
|
||||||
|
* This function is a bit hacky. DFO chunks can overlap. If two DFO chunks
|
||||||
|
* overlap, the last registered chunk wins. The dfo_chunk_find() function
|
||||||
|
* reflects that by returning the first memory chunk that is found in
|
||||||
|
* the dfo chunk list.
|
||||||
|
*
|
||||||
|
* In addition to that it calculates the "virtual end" of that chunk. An
|
||||||
|
* overlapping chunk can limit the "virtual end" of an underlying chunk so
|
||||||
|
* that the "virtual end" of that chunk is lower than the "real end".
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* chunk 1.: |------|
|
||||||
|
* chunk 2.: |---------------------|
|
||||||
|
* off.....: ^
|
||||||
|
* virt end: ^
|
||||||
|
* real end: ^
|
||||||
|
*
|
||||||
|
* In this case chunk 2 will be returned and "end" is set to the start of
|
||||||
|
* chunk 1.
|
||||||
|
*/
|
||||||
|
struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end)
|
||||||
|
{
|
||||||
|
struct dfo_chunk *dfo_chunk;
|
||||||
|
|
||||||
|
*end = U64_MAX;
|
||||||
|
dfo_chunk_iterate(dfo_chunk) {
|
||||||
|
if (dfo_chunk->start <= off && dfo_chunk->end >= off) {
|
||||||
|
*end = MIN(*end, dfo_chunk->end);
|
||||||
|
return dfo_chunk;
|
||||||
|
} else if (dfo_chunk->start > off) {
|
||||||
|
*end = MIN(*end, dfo_chunk->start - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct util_list *dfo_chunk_list(void)
|
||||||
|
{
|
||||||
|
return &l.chunk_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 dfo_chunk_dump_size(void)
|
||||||
|
{
|
||||||
|
return l.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dfo_chunk_init(void)
|
||||||
|
{
|
||||||
|
util_list_init(&l.chunk_list, struct dfo_chunk, list);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dfo_chunk_deinit(void)
|
||||||
|
{
|
||||||
|
memset(&l, 0, sizeof(l));
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2017, 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 DFO_MEM_CHUNK_H
|
||||||
|
#define DFO_MEM_CHUNK_H
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "lib/util_list.h"
|
||||||
|
|
||||||
|
struct dfo_chunk;
|
||||||
|
|
||||||
|
typedef void (*dfo_chunk_read_fn)(struct dfo_chunk *chunk, u64 off,
|
||||||
|
void *buf, u64 cnt);
|
||||||
|
|
||||||
|
struct dfo_chunk {
|
||||||
|
struct util_list_node list;
|
||||||
|
u64 start;
|
||||||
|
u64 end;
|
||||||
|
dfo_chunk_read_fn read_fn;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
void dfo_chunk_zero_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
|
||||||
|
void dfo_chunk_buf_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
|
||||||
|
void dfo_chunk_mem_fn(struct dfo_chunk *chunk, u64 off, void *buf, u64 cnt);
|
||||||
|
void dfo_chunk_add(u64 start, u64 size, void *data, dfo_chunk_read_fn read_fn);
|
||||||
|
struct dfo_chunk *dfo_chunk_find(u64 off, u64 *end);
|
||||||
|
|
||||||
|
struct util_list *dfo_chunk_list(void);
|
||||||
|
#define dfo_chunk_iterate(dfo_chunk) \
|
||||||
|
util_list_iterate(dfo_chunk_list(), dfo_chunk)
|
||||||
|
|
||||||
|
u64 dfo_chunk_dump_size(void);
|
||||||
|
|
||||||
|
int dfo_chunk_init(void);
|
||||||
|
void dfo_chunk_deinit(void);
|
||||||
|
|
||||||
|
#endif /* DFO_MEM_CHUNK_H */
|
||||||
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include "df_s390.h"
|
#include "df_s390.h"
|
||||||
#include "dfi_mem_chunk.h"
|
#include "dfi_mem_chunk.h"
|
||||||
|
#include "dfo_mem_chunk.h"
|
||||||
#include "dfo.h"
|
#include "dfo.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ static const char optstr[] = "hvVidmus:f:X";
|
|||||||
*/
|
*/
|
||||||
static const char help_text[] =
|
static const char help_text[] =
|
||||||
"Usage: zgetdump DUMP [-s SYS] [-f FMT] > DUMP_FILE\n"
|
"Usage: zgetdump DUMP [-s SYS] [-f FMT] > DUMP_FILE\n"
|
||||||
|
" DUMP [-s SYS] [-f FMT] DUMP_FILE\n"
|
||||||
" -m DUMP [-s SYS] [-f FMT] DIR\n"
|
" -m DUMP [-s SYS] [-f FMT] DIR\n"
|
||||||
" -i DUMP [-s SYS]\n"
|
" -i DUMP [-s SYS]\n"
|
||||||
" -d DUMPDEV\n"
|
" -d DUMPDEV\n"
|
||||||
@@ -86,6 +87,7 @@ static void init_defaults(struct options *opts)
|
|||||||
{
|
{
|
||||||
opts->prog_name = "zgetdump";
|
opts->prog_name = "zgetdump";
|
||||||
opts->action = ZG_ACTION_COPY;
|
opts->action = ZG_ACTION_COPY;
|
||||||
|
opts->output_path = NULL;
|
||||||
#ifdef __s390x__
|
#ifdef __s390x__
|
||||||
opts->fmt = "elf";
|
opts->fmt = "elf";
|
||||||
#else
|
#else
|
||||||
@@ -166,6 +168,14 @@ static void device_set(struct options *opts, const char *path)
|
|||||||
opts->device = zg_strdup(path);
|
opts->device = zg_strdup(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set output path
|
||||||
|
*/
|
||||||
|
static void output_set(struct options *opts, const char *path)
|
||||||
|
{
|
||||||
|
opts->output_path = zg_strdup(path);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set FUSE debug options
|
* Set FUSE debug options
|
||||||
*/
|
*/
|
||||||
@@ -229,6 +239,14 @@ static void parse_pos_args(struct options *opts, char *argv[], int argc)
|
|||||||
|
|
||||||
switch (opts->action) {
|
switch (opts->action) {
|
||||||
case ZG_ACTION_COPY:
|
case ZG_ACTION_COPY:
|
||||||
|
if (pos_args == 0)
|
||||||
|
ERR_EXIT("No device or dump specified");
|
||||||
|
if (pos_args > 2)
|
||||||
|
ERR_EXIT("Too many positional parameters specified");
|
||||||
|
device_set(opts, argv[optind]);
|
||||||
|
if (pos_args > 1)
|
||||||
|
output_set(opts, argv[optind + 1]);
|
||||||
|
break;
|
||||||
case ZG_ACTION_DUMP_INFO:
|
case ZG_ACTION_DUMP_INFO:
|
||||||
case ZG_ACTION_DEVICE_INFO:
|
case ZG_ACTION_DEVICE_INFO:
|
||||||
if (pos_args == 0)
|
if (pos_args == 0)
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ struct options {
|
|||||||
int action_specified;
|
int action_specified;
|
||||||
enum zg_action action;
|
enum zg_action action;
|
||||||
char *device;
|
char *device;
|
||||||
|
/* If `output_path == NULL` the output is written to `stdout` */
|
||||||
|
const char *output_path;
|
||||||
char *mount_point;
|
char *mount_point;
|
||||||
int fmt_specified;
|
int fmt_specified;
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* zgetdump - Tool for copying and converting System z dumps
|
* zgetdump - Tool for copying and converting System z dumps
|
||||||
*
|
*
|
||||||
* Write dump to standard output (stdout)
|
* Write dump to the file descriptor (fd)
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2001, 2017
|
* Copyright IBM Corp. 2001, 2017
|
||||||
*
|
*
|
||||||
@@ -12,9 +12,9 @@
|
|||||||
#include "zg.h"
|
#include "zg.h"
|
||||||
#include "dfi.h"
|
#include "dfi.h"
|
||||||
#include "dfo.h"
|
#include "dfo.h"
|
||||||
#include "stdout.h"
|
#include "output.h"
|
||||||
|
|
||||||
int stdout_write_dump(void)
|
int write_dump(FILE *stream)
|
||||||
{
|
{
|
||||||
const u64 output_size = dfo_size();
|
const u64 output_size = dfo_size();
|
||||||
char buf[8UL * PAGE_SIZE];
|
char buf[8UL * PAGE_SIZE];
|
||||||
@@ -28,15 +28,13 @@ int stdout_write_dump(void)
|
|||||||
STDERR("\n");
|
STDERR("\n");
|
||||||
zg_progress_init("Copying dump", output_size);
|
zg_progress_init("Copying dump", output_size);
|
||||||
while (written != output_size) {
|
while (written != output_size) {
|
||||||
ssize_t rc;
|
size_t rc;
|
||||||
u64 cnt;
|
u64 cnt;
|
||||||
|
|
||||||
cnt = dfo_read(buf, sizeof(buf));
|
cnt = dfo_read(buf, sizeof(buf));
|
||||||
rc = write(STDOUT_FILENO, buf, cnt);
|
rc = fwrite(buf, cnt, 1, stream);
|
||||||
if (rc == -1)
|
if (rc != 1 && ferror(stream))
|
||||||
ERR_EXIT_ERRNO("Error: Write failed");
|
ERR_EXIT("Error: Write failed");
|
||||||
if (rc != (ssize_t) cnt)
|
|
||||||
ERR_EXIT("Error: Could not write full block");
|
|
||||||
written += cnt;
|
written += cnt;
|
||||||
zg_progress(written);
|
zg_progress(written);
|
||||||
};
|
};
|
||||||
@@ -5,9 +5,11 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef STDOUT_H
|
#ifndef OUTPUT_H
|
||||||
#define STDOUT_H
|
#define OUTPUT_H
|
||||||
|
|
||||||
int stdout_write_dump(void);
|
#include <stdio.h>
|
||||||
|
|
||||||
#endif /* STDOUT_H */
|
int write_dump(FILE *stream);
|
||||||
|
|
||||||
|
#endif /* OUTPUT_H */
|
||||||
+13
-8
@@ -9,7 +9,7 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 25
|
#define FUSE_USE_VERSION 30
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -84,8 +84,11 @@ static void stat_dump_init(void)
|
|||||||
/*
|
/*
|
||||||
* FUSE callback: Getattr
|
* FUSE callback: Getattr
|
||||||
*/
|
*/
|
||||||
static int zfuse_getattr(const char *path, struct stat *stat)
|
static int zfuse_getattr(const char *path, struct stat *stat,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (strcmp(path, "/") == 0) {
|
if (strcmp(path, "/") == 0) {
|
||||||
*stat = l.stat_root;
|
*stat = l.stat_root;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -101,17 +104,19 @@ static int zfuse_getattr(const char *path, struct stat *stat)
|
|||||||
* FUSE callback: Readdir - Return ".", ".." and dump file
|
* FUSE callback: Readdir - Return ".", ".." and dump file
|
||||||
*/
|
*/
|
||||||
static int zfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int zfuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
off_t offset, struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
(void) offset;
|
(void) offset;
|
||||||
(void) fi;
|
(void) fi;
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
if (strcmp(path, "/") != 0)
|
if (strcmp(path, "/") != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
filler(buf, &l.path[1], NULL, 0);
|
filler(buf, &l.path[1], NULL, 0, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,7 +211,7 @@ int zfuse_mount_dump(void)
|
|||||||
fuse_opt_add_arg(&args, "zgetdump");
|
fuse_opt_add_arg(&args, "zgetdump");
|
||||||
fuse_opt_add_arg(&args, "-s");
|
fuse_opt_add_arg(&args, "-s");
|
||||||
snprintf(tmp_str, sizeof(tmp_str),
|
snprintf(tmp_str, sizeof(tmp_str),
|
||||||
"-ofsname=%s,ro,default_permissions,nonempty",
|
"-ofsname=%s,ro,default_permissions",
|
||||||
g.opts.device);
|
g.opts.device);
|
||||||
fuse_opt_add_arg(&args, tmp_str);
|
fuse_opt_add_arg(&args, tmp_str);
|
||||||
fuse_opt_add_arg(&args, g.opts.mount_point);
|
fuse_opt_add_arg(&args, g.opts.mount_point);
|
||||||
@@ -214,7 +219,7 @@ int zfuse_mount_dump(void)
|
|||||||
stat_root_init();
|
stat_root_init();
|
||||||
stat_dump_init();
|
stat_dump_init();
|
||||||
snprintf(l.path, sizeof(l.path), "/dump.%s", dfo_name());
|
snprintf(l.path, sizeof(l.path), "/dump.%s", dfo_name());
|
||||||
return fuse_main(args.argc, args.argv, &zfuse_ops);
|
return fuse_main(args.argc, args.argv, &zfuse_ops, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+1
-1
@@ -280,7 +280,7 @@ off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check)
|
|||||||
{
|
{
|
||||||
off_t rc;
|
off_t rc;
|
||||||
|
|
||||||
if (off >= zg_fh->sb.st_size)
|
if (S_ISREG(zg_fh->sb.st_mode) && off >= zg_fh->sb.st_size)
|
||||||
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
|
ERR_EXIT("Trying to seek past file end \"%s\"", zg_fh->path);
|
||||||
|
|
||||||
rc = lseek(zg_fh->fh, off, SEEK_SET);
|
rc = lseek(zg_fh->fh, off, SEEK_SET);
|
||||||
|
|||||||
+42
-71
@@ -45,79 +45,50 @@
|
|||||||
/*
|
/*
|
||||||
* Memory functions
|
* Memory functions
|
||||||
*/
|
*/
|
||||||
extern void *zg_alloc(unsigned int size);
|
void *zg_alloc(unsigned int size);
|
||||||
extern void *zg_realloc(void *ptr, unsigned int size);
|
void *zg_realloc(void *ptr, unsigned int size);
|
||||||
extern void zg_free(void *ptr);
|
void zg_free(void *ptr);
|
||||||
extern char *zg_strdup(const char *str);
|
char *zg_strdup(const char *str);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At exit functions
|
* At exit functions
|
||||||
*/
|
*/
|
||||||
typedef void (*zg_atexit_fn_t)(void);
|
typedef void (*zg_atexit_fn_t)(void);
|
||||||
extern void zg_atexit(zg_atexit_fn_t fn);
|
void zg_atexit(zg_atexit_fn_t fn);
|
||||||
extern void __noreturn zg_exit(int rc);
|
void __noreturn zg_exit(int rc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Temporary device node functions
|
* Temporary device node functions
|
||||||
*/
|
*/
|
||||||
extern char *zg_devnode_create(dev_t dev);
|
char *zg_devnode_create(dev_t dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Progress bar functions
|
* Progress bar functions
|
||||||
*/
|
*/
|
||||||
extern void zg_progress_init(const char *msg, u64 mem_size);
|
void zg_progress_init(const char *msg, u64 mem_size);
|
||||||
extern void zg_progress(u64 addr);
|
void zg_progress(u64 addr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Error and print functions
|
* Error and print functions
|
||||||
*/
|
*/
|
||||||
#define ERR(x...) \
|
|
||||||
do { \
|
|
||||||
fprintf(stderr, "%s: ", "zgetdump"); \
|
|
||||||
fprintf(stderr, x); \
|
|
||||||
fprintf(stderr, "\n"); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define ERR_EXIT(x...) \
|
void zg_err(const char *fmt, ...);
|
||||||
do { \
|
void zg_err_exit(const char *fmt, ...);
|
||||||
ERR(x); \
|
void zg_err_exit_errno(const char *fmt, ...);
|
||||||
zg_exit(1); \
|
void zg_abort(const char *fmt, ...);
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define ABORT(x...) \
|
#define ERR(fmt, ...) zg_err(fmt, ## __VA_ARGS__)
|
||||||
do { \
|
#define ERR_EXIT(fmt, ...) zg_err_exit(fmt, ## __VA_ARGS__)
|
||||||
ERR("Internal Error: " x); \
|
#define ERR_EXIT_ERRNO(fmt, ...) zg_err_exit_errno(fmt, ## __VA_ARGS__)
|
||||||
abort(); \
|
#define ABORT(fmt, ...) zg_abort(fmt, ## __VA_ARGS__)
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define ERR_EXIT_ERRNO(x...) \
|
void zg_stderr(const char *fmt, ...);
|
||||||
do { \
|
void zg_stderr_pr(const char *fmt, ...);
|
||||||
fflush(stdout); \
|
void zg_stdout(const char *fmt, ...);
|
||||||
fprintf(stderr, "%s: ", "zgetdump"); \
|
|
||||||
fprintf(stderr, x); \
|
|
||||||
fprintf(stderr, " (%s)", strerror(errno)); \
|
|
||||||
fprintf(stderr, "\n"); \
|
|
||||||
zg_exit(1); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define STDERR(x...) \
|
|
||||||
do { \
|
|
||||||
fprintf(stderr, x); \
|
|
||||||
fflush(stderr); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define STDERR_PR(x...) \
|
|
||||||
do { \
|
|
||||||
fprintf(stderr, "\r%s: ", "zgetdump"); \
|
|
||||||
fprintf(stderr, x); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#define STDOUT(x...) \
|
|
||||||
do { \
|
|
||||||
fprintf(stdout, x); \
|
|
||||||
fflush(stdout); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
|
#define STDERR(fmt, ...) zg_stderr(fmt, ## __VA_ARGS__)
|
||||||
|
#define STDERR_PR(fmt, ...) zg_stderr_pr(fmt, ## __VA_ARGS__)
|
||||||
|
#define STDOUT(fmt, ...) zg_stdout(fmt, ## __VA_ARGS__)
|
||||||
/*
|
/*
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
@@ -140,9 +111,9 @@ static inline u32 zg_csum_partial(const void *buf, int len, u32 sum)
|
|||||||
/*
|
/*
|
||||||
* Pointer atrithmetic
|
* Pointer atrithmetic
|
||||||
*/
|
*/
|
||||||
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
|
#define PTR_SUB(x, y) ((void *)(((char *) (x)) - ((unsigned long) (y))))
|
||||||
#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
|
#define PTR_ADD(x, y) ((void *)(((char *) (x)) + ((unsigned long) (y))))
|
||||||
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
|
#define PTR_DIFF(x, y) ((unsigned long)PTR_SUB(x, y))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* File functions
|
* File functions
|
||||||
@@ -167,22 +138,22 @@ enum zg_check {
|
|||||||
ZG_CHECK_NONE,
|
ZG_CHECK_NONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char *zg_path(struct zg_fh *zg_fh);
|
const char *zg_path(struct zg_fh *zg_fh);
|
||||||
extern const struct stat *zg_stat(struct zg_fh *zg_fh);
|
const struct stat *zg_stat(struct zg_fh *zg_fh);
|
||||||
extern struct zg_fh *zg_open(const char *path, int flags, enum zg_check check);
|
struct zg_fh *zg_open(const char *path, int flags, enum zg_check check);
|
||||||
extern void zg_close(struct zg_fh *zg_fh);
|
void zg_close(struct zg_fh *zg_fh);
|
||||||
extern ssize_t zg_read(struct zg_fh *zg_fh, void *buf, size_t cnt,
|
ssize_t zg_read(struct zg_fh *zg_fh, void *buf, size_t cnt,
|
||||||
enum zg_check check);
|
enum zg_check check);
|
||||||
extern ssize_t zg_gets(struct zg_fh *zg_fh, void *buf, size_t cnt,
|
ssize_t zg_gets(struct zg_fh *zg_fh, void *buf, size_t cnt,
|
||||||
enum zg_check check);
|
enum zg_check check);
|
||||||
extern u64 zg_size(struct zg_fh *zg_fh);
|
u64 zg_size(struct zg_fh *zg_fh);
|
||||||
extern off_t zg_tell(struct zg_fh *zg_fh, enum zg_check check);
|
off_t zg_tell(struct zg_fh *zg_fh, enum zg_check check);
|
||||||
extern off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check);
|
off_t zg_seek(struct zg_fh *zg_fh, off_t off, enum zg_check check);
|
||||||
extern off_t zg_seek_end(struct zg_fh *zg_fh, off_t off, enum zg_check check);
|
off_t zg_seek_end(struct zg_fh *zg_fh, off_t off, enum zg_check check);
|
||||||
extern off_t zg_seek_cur(struct zg_fh *zg_fh, off_t off, enum zg_check check);
|
off_t zg_seek_cur(struct zg_fh *zg_fh, off_t off, enum zg_check check);
|
||||||
extern int zg_ioctl(struct zg_fh *zg_fh, int rq, void *data, const char *op,
|
int zg_ioctl(struct zg_fh *zg_fh, int rq, void *data, const char *op,
|
||||||
enum zg_check check);
|
enum zg_check check);
|
||||||
extern enum zg_type zg_type(struct zg_fh *zg_fh);
|
enum zg_type zg_type(struct zg_fh *zg_fh);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* zgetdump actions
|
* zgetdump actions
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "lib/util_libc.h"
|
||||||
|
#include "zg.h"
|
||||||
|
|
||||||
|
static inline void _zg_err(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: ", "zgetdump");
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _zg_err_errno(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
const int errno_backup = errno;
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
fprintf(stderr, "%s: ", "zgetdump");
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fprintf(stderr, " (%s)", strerror(errno_backup));
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_err(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_err(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_err_exit(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_err(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
zg_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_err_exit_errno(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_err_errno(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
zg_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_abort(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
char *newfmt;
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
newfmt = util_strcat_realloc(util_strdup("Internal Error: "), fmt);
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_err(newfmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
free(newfmt);
|
||||||
|
|
||||||
|
abort();
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2001, 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "zg.h"
|
||||||
|
|
||||||
|
static inline void _zg_stderr(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
fflush(stderr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _zg_stderr_pr(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "\r%s: ", "zgetdump");
|
||||||
|
vfprintf(stderr, fmt, ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _zg_stdout(const char *fmt, va_list ap)
|
||||||
|
{
|
||||||
|
vfprintf(stdout, fmt, ap);
|
||||||
|
fflush(stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_stderr(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_stderr(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_stderr_pr(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_stderr_pr(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void zg_stdout(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
_zg_stdout(fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ zgetdump \- Tool for copying and converting System z dumps
|
|||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|
||||||
\fBzgetdump\fR DUMP [-s SYS] [-f FMT] > DUMP_FILE
|
\fBzgetdump\fR DUMP [-s SYS] [-f FMT] > DUMP_FILE
|
||||||
|
.br
|
||||||
|
DUMP [-s SYS] [-f FMT] DUMP_FILE
|
||||||
.br
|
.br
|
||||||
-m DUMP [-s SYS] [-f FMT] DIR
|
-m DUMP [-s SYS] [-f FMT] DIR
|
||||||
.br
|
.br
|
||||||
|
|||||||
+35
-7
@@ -30,7 +30,7 @@
|
|||||||
#include "dt.h"
|
#include "dt.h"
|
||||||
#include "dfi.h"
|
#include "dfi.h"
|
||||||
#include "dfo.h"
|
#include "dfo.h"
|
||||||
#include "stdout.h"
|
#include "output.h"
|
||||||
#include "zfuse.h"
|
#include "zfuse.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -156,18 +156,46 @@ static int do_mount(void)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static FILE *open_file_for_writing(const char *output)
|
||||||
* Run "copy to stdout" action
|
|
||||||
*/
|
|
||||||
static int do_copy(void)
|
|
||||||
{
|
{
|
||||||
|
FILE *stream;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (output) {
|
||||||
|
fd = open(output,
|
||||||
|
O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC,
|
||||||
|
0600);
|
||||||
|
if (fd == -1)
|
||||||
|
ERR_EXIT_ERRNO("Could not open '%s' exclusively", output);
|
||||||
|
} else {
|
||||||
|
fd = dup(STDOUT_FILENO);
|
||||||
|
if (fd == -1)
|
||||||
|
ERR_EXIT_ERRNO("Could not dup() stdout");
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = fdopen(fd, "w");
|
||||||
|
if (!stream)
|
||||||
|
ERR_EXIT_ERRNO("Could not fdopen()");
|
||||||
|
fd = -1;
|
||||||
|
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Run "copy to output" action
|
||||||
|
*/
|
||||||
|
static int do_copy(const char *output)
|
||||||
|
{
|
||||||
|
FILE *stream;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (dfi_init() != 0)
|
if (dfi_init() != 0)
|
||||||
ERR_EXIT("Dump cannot be processed (is not complete)");
|
ERR_EXIT("Dump cannot be processed (is not complete)");
|
||||||
dfo_init();
|
dfo_init();
|
||||||
kdump_select_check();
|
kdump_select_check();
|
||||||
rc = stdout_write_dump();
|
stream = open_file_for_writing(output);
|
||||||
|
rc = write_dump(stream);
|
||||||
|
fclose(stream);
|
||||||
dfi_exit();
|
dfi_exit();
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -185,7 +213,7 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
switch (g.opts.action) {
|
switch (g.opts.action) {
|
||||||
case ZG_ACTION_COPY:
|
case ZG_ACTION_COPY:
|
||||||
return do_copy();
|
return do_copy(g.opts.output_path);
|
||||||
case ZG_ACTION_DUMP_INFO:
|
case ZG_ACTION_DUMP_INFO:
|
||||||
return do_dump_info();
|
return do_dump_info();
|
||||||
case ZG_ACTION_DEVICE_INFO:
|
case ZG_ACTION_DEVICE_INFO:
|
||||||
|
|||||||
+6
-6
@@ -68,11 +68,11 @@ stage3.exec: head.o stage3.o kdump3.o libc.o ebcdic.o ebcdic_conv.o sclp.o \
|
|||||||
}' \
|
}' \
|
||||||
); \
|
); \
|
||||||
case $$STAGE in \
|
case $$STAGE in \
|
||||||
0) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0";; \
|
0) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0";; \
|
||||||
1) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0x18";; \
|
1) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0x18";; \
|
||||||
1b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-Ttext,0xE000";; \
|
1b) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-Ttext,0xE000";; \
|
||||||
2) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage2.lds";; \
|
2) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage2.lds";; \
|
||||||
3) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3.lds";; \
|
3) SFLAGS="$(NO_PIE_LDFLAGS) -nostdlib -Wl,-T,stage3.lds";; \
|
||||||
esac; \
|
esac; \
|
||||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ stage3.bin: stage3.exec
|
|||||||
$< $@
|
$< $@
|
||||||
|
|
||||||
data.o: $(FILES)
|
data.o: $(FILES)
|
||||||
$(LD) $(NO_PIE_LDFLAGS) -r -b binary -o data.o $(FILES)
|
$(LINK) $(NO_PIE_LDFLAGS) -static -nostdlib -Wl,--relocatable -Wl,--format,binary -o data.o $(FILES)
|
||||||
|
|
||||||
data.h: data.o
|
data.h: data.o
|
||||||
rm -f data.h
|
rm -f data.h
|
||||||
|
|||||||
@@ -97,6 +97,33 @@ char *strcpy(char *dest, const char *src)
|
|||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy \a src to buffer \a dest of size \a size. At most size - 1
|
||||||
|
* chars will be copied. \a dest will always be NUL terminated.
|
||||||
|
*
|
||||||
|
* Note: If the return value is greater than or equal to size truncation
|
||||||
|
* occurred.
|
||||||
|
*
|
||||||
|
* @param[in] dest Destination buffer
|
||||||
|
* @param[in] src Source string
|
||||||
|
* @param[in] size Size of destination buffer
|
||||||
|
*
|
||||||
|
* @returns strlen Length of \a src string
|
||||||
|
*/
|
||||||
|
size_t strlcpy(char *dest, const char *src, size_t size)
|
||||||
|
{
|
||||||
|
size_t str_len = strlen(src);
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (size) {
|
||||||
|
len = MIN(size - 1, str_len);
|
||||||
|
memcpy(dest, src, len);
|
||||||
|
dest[len] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return str_len;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return string length
|
* Return string length
|
||||||
*/
|
*/
|
||||||
|
|||||||
+2
-1
@@ -54,13 +54,14 @@ char *strcat(char *, const char *);
|
|||||||
int strncmp(const char *, const char *, unsigned long);
|
int strncmp(const char *, const char *, unsigned long);
|
||||||
int strlen(const char *);
|
int strlen(const char *);
|
||||||
char *strcpy(char *, const char *);
|
char *strcpy(char *, const char *);
|
||||||
|
size_t strlcpy(char *dest, const char *src, size_t size);
|
||||||
char *strchr(const char *str, char c);
|
char *strchr(const char *str, char c);
|
||||||
unsigned int strhash(unsigned char *str, unsigned int hash_size);
|
unsigned int strhash(unsigned char *str, unsigned int hash_size);
|
||||||
unsigned long get_zeroed_page(void);
|
unsigned long get_zeroed_page(void);
|
||||||
void free_page(unsigned long);
|
void free_page(unsigned long);
|
||||||
void initialize(void);
|
void initialize(void);
|
||||||
void libc_stop(unsigned long) __noreturn;
|
void libc_stop(unsigned long) __noreturn;
|
||||||
void start(void);
|
void __noreturn start(void);
|
||||||
void pgm_check_handler(void);
|
void pgm_check_handler(void);
|
||||||
void pgm_check_handler_fn(void);
|
void pgm_check_handler_fn(void);
|
||||||
void panic_notify(unsigned long reason);
|
void panic_notify(unsigned long reason);
|
||||||
|
|||||||
+1
-1
@@ -188,7 +188,7 @@ boot:
|
|||||||
|
|
||||||
/* append 'BOOT_IMAGE=<num>' to parmline */
|
/* append 'BOOT_IMAGE=<num>' to parmline */
|
||||||
snprintf(endstring, sizeof(endstring), " BOOT_IMAGE=%u", value);
|
snprintf(endstring, sizeof(endstring), " BOOT_IMAGE=%u", value);
|
||||||
if ((strlen(cmd_line_extra) + strlen(endstring)) < COMMAND_LINE_SIZE)
|
if ((strlen(cmd_line_extra) + strlen(endstring)) < LEGACY_COMMAND_LINE_SIZE)
|
||||||
strcat(cmd_line_extra, endstring);
|
strcat(cmd_line_extra, endstring);
|
||||||
|
|
||||||
sclp_setup(SCLP_DISABLE);
|
sclp_setup(SCLP_DISABLE);
|
||||||
|
|||||||
+3
-2
@@ -75,15 +75,16 @@ out_free_page:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void execute(uint64_t psw)
|
static __noreturn void execute(uint64_t psw)
|
||||||
{
|
{
|
||||||
asm volatile(
|
asm volatile(
|
||||||
" lpsw %[psw]\n"
|
" lpsw %[psw]\n"
|
||||||
: : [psw] "Q" (psw) : "cc"
|
: : [psw] "Q" (psw) : "cc"
|
||||||
);
|
);
|
||||||
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(void)
|
void __noreturn start(void)
|
||||||
{
|
{
|
||||||
struct stage2_descr stage2_descr;
|
struct stage2_descr stage2_descr;
|
||||||
struct subchannel_id subchannel_id;
|
struct subchannel_id subchannel_id;
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ static void store_status(void)
|
|||||||
* Block followed by a valid checksum (as defined in lowcore.h and set
|
* Block followed by a valid checksum (as defined in lowcore.h and set
|
||||||
* by ipl.c). In case of match use diag308 to IPL.
|
* by ipl.c). In case of match use diag308 to IPL.
|
||||||
*/
|
*/
|
||||||
static void dump_exit(unsigned long code)
|
static __noreturn void dump_exit(unsigned long code)
|
||||||
{
|
{
|
||||||
struct ipib_info *ipib_info = (struct ipib_info *)&S390_lowcore.ipib;
|
struct ipib_info *ipib_info = (struct ipib_info *)&S390_lowcore.ipib;
|
||||||
uint32_t ipib_len, csum;
|
uint32_t ipib_len, csum;
|
||||||
@@ -406,6 +406,7 @@ static void dump_exit(unsigned long code)
|
|||||||
libc_stop(code);
|
libc_stop(code);
|
||||||
diag308(DIAG308_SET, (void *) ipib_info->ipib);
|
diag308(DIAG308_SET, (void *) ipib_info->ipib);
|
||||||
diag308(DIAG308_IPL, NULL);
|
diag308(DIAG308_IPL, NULL);
|
||||||
|
__builtin_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -420,7 +421,7 @@ void panic_notify(unsigned long code)
|
|||||||
/*
|
/*
|
||||||
* Create stand-alone dump
|
* Create stand-alone dump
|
||||||
*/
|
*/
|
||||||
void start(void)
|
void __noreturn start(void)
|
||||||
{
|
{
|
||||||
init_early();
|
init_early();
|
||||||
dt_device_parm_setup();
|
dt_device_parm_setup();
|
||||||
|
|||||||
+66
-69
@@ -159,8 +159,8 @@ static void hash_table_add(struct env_hash_entry *items,
|
|||||||
(*new_idx)++;
|
(*new_idx)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct env_hash_entry *hash_table_find(struct env_hash_entry **buckets,
|
static struct env_hash_entry *hash_table_find(struct env_hash_entry **buckets,
|
||||||
char *name)
|
char *name)
|
||||||
{
|
{
|
||||||
struct env_hash_entry *item;
|
struct env_hash_entry *item;
|
||||||
|
|
||||||
@@ -232,7 +232,8 @@ static void parse_envblk(struct env_hash_entry *items,
|
|||||||
* CMDL_LEN: length of the command line to be processed
|
* CMDL_LEN: length of the command line to be processed
|
||||||
* BUCKETS: hash table of pairs (NAME, VALUE)
|
* BUCKETS: hash table of pairs (NAME, VALUE)
|
||||||
*/
|
*/
|
||||||
void process_parm_line(struct env_hash_entry **buckets, unsigned int cmdl_len)
|
void process_parm_line(struct env_hash_entry **buckets, unsigned int cmdl_len,
|
||||||
|
unsigned int max_len)
|
||||||
{
|
{
|
||||||
struct env_hash_entry *item;
|
struct env_hash_entry *item;
|
||||||
char empty_str = 0;
|
char empty_str = 0;
|
||||||
@@ -282,7 +283,7 @@ void process_parm_line(struct env_hash_entry **buckets, unsigned int cmdl_len)
|
|||||||
*/
|
*/
|
||||||
len = strlen(val);
|
len = strlen(val);
|
||||||
|
|
||||||
if (cmdl_len + len - (end - start + 1) >= COMMAND_LINE_SIZE)
|
if (cmdl_len + len - (end - start + 1) >= max_len)
|
||||||
/* VALUE doesn't fit */
|
/* VALUE doesn't fit */
|
||||||
break;
|
break;
|
||||||
/*
|
/*
|
||||||
@@ -306,7 +307,7 @@ void process_parm_line(struct env_hash_entry **buckets, unsigned int cmdl_len)
|
|||||||
/**
|
/**
|
||||||
* LEN: length of the command line to be processed
|
* LEN: length of the command line to be processed
|
||||||
*/
|
*/
|
||||||
static void handle_environment(unsigned int len)
|
static void handle_environment(unsigned int len, unsigned int max_len)
|
||||||
{
|
{
|
||||||
struct env_hash_entry *buckets[STR_HASH_SIZE];
|
struct env_hash_entry *buckets[STR_HASH_SIZE];
|
||||||
struct env_hash_entry *items;
|
struct env_hash_entry *items;
|
||||||
@@ -326,30 +327,76 @@ static void handle_environment(unsigned int len)
|
|||||||
* find environment variables in the command line and
|
* find environment variables in the command line and
|
||||||
* replace them with their values as found in the hash table
|
* replace them with their values as found in the hash table
|
||||||
*/
|
*/
|
||||||
process_parm_line(buckets, len);
|
process_parm_line(buckets, len, max_len);
|
||||||
free_page((unsigned long)items);
|
free_page((unsigned long)items);
|
||||||
}
|
}
|
||||||
|
|
||||||
void start(void)
|
static void verify_secure_boot(void)
|
||||||
{
|
{
|
||||||
unsigned int subchannel_id;
|
|
||||||
unsigned char *cextra = (unsigned char *)COMMAND_LINE_EXTRA;
|
|
||||||
unsigned char *cmdline = (unsigned char *)COMMAND_LINE;
|
|
||||||
unsigned int cmdline_len = 0, cextra_len = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IPL process is secure we have to use default IPL values and
|
* IPL process is secure we have to use default IPL values and
|
||||||
* check if the psw jump address is within at the start of a
|
* check if the psw jump address is within at the start of a
|
||||||
* verified component. If it is not IPL is aborted.
|
* verified component. If it is not IPL is aborted.
|
||||||
*/
|
*/
|
||||||
if (secure_boot_enabled()) {
|
if (_stage3_parms.image_addr != IMAGE_LOAD_ADDRESS ||
|
||||||
if (_stage3_parms.image_addr != IMAGE_LOAD_ADDRESS ||
|
_stage3_parms.load_psw != DEFAULT_PSW_LOAD)
|
||||||
_stage3_parms.load_psw != DEFAULT_PSW_LOAD)
|
panic(ESECUREBOOT, "%s", msg_sipl_inval);
|
||||||
panic(ESECUREBOOT, "%s", msg_sipl_inval);
|
|
||||||
|
|
||||||
if (!is_verified_address(_stage3_parms.load_psw & PSW32_ADDR_MASK))
|
if (!is_verified_address(_stage3_parms.load_psw & PSW32_ADDR_MASK))
|
||||||
panic(ESECUREBOOT, "%s", msg_sipl_unverified);
|
panic(ESECUREBOOT, "%s", msg_sipl_unverified);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_cmdline(void)
|
||||||
|
{
|
||||||
|
char *cextra = (char *)COMMAND_LINE_EXTRA;
|
||||||
|
char *cmdline = (char *)COMMAND_LINE;
|
||||||
|
unsigned int cmdline_len = 0;
|
||||||
|
unsigned int max_cmdline_len = *(unsigned long *)MAX_COMMAND_LINE_SIZE;
|
||||||
|
|
||||||
|
if (!max_cmdline_len)
|
||||||
|
max_cmdline_len = LEGACY_COMMAND_LINE_SIZE;
|
||||||
|
|
||||||
|
/* if valid command line is given, copy it into new kernel space */
|
||||||
|
if (_stage3_parms.parm_addr != UNSPECIFIED_ADDRESS) {
|
||||||
|
strlcpy(cmdline, (void *)(unsigned long *)_stage3_parms.parm_addr,
|
||||||
|
max_cmdline_len);
|
||||||
}
|
}
|
||||||
|
/* determine length of original parm line */
|
||||||
|
cmdline_len = MIN((unsigned int)strlen(cmdline), max_cmdline_len - 1);
|
||||||
|
|
||||||
|
/* convert extra parameter to ascii */
|
||||||
|
if (!_stage3_parms.extra_parm || !*cextra)
|
||||||
|
goto noextra;
|
||||||
|
|
||||||
|
/* Handle extra kernel parameters specified in DASD boot menu. */
|
||||||
|
ebcdic_to_ascii((unsigned char *)cextra, (unsigned char *)cextra, COMMAND_LINE_EXTRA_SIZE);
|
||||||
|
|
||||||
|
while (isspace(*cextra))
|
||||||
|
cextra++;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if extra parm string starts with '=' replace original string,
|
||||||
|
* else append
|
||||||
|
*/
|
||||||
|
if (*cextra == 0x3d) {
|
||||||
|
strlcpy(cmdline, cextra+1, max_cmdline_len);
|
||||||
|
} else if (*cextra && cmdline_len + 1 <= max_cmdline_len - 1) {
|
||||||
|
/* add blank */
|
||||||
|
cmdline[cmdline_len++] = 0x20;
|
||||||
|
strlcpy(cmdline + cmdline_len, cextra, max_cmdline_len - cmdline_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
noextra:
|
||||||
|
handle_environment(strlen(cmdline), max_cmdline_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void start(void)
|
||||||
|
{
|
||||||
|
unsigned int subchannel_id;
|
||||||
|
|
||||||
|
if (secure_boot_enabled())
|
||||||
|
verify_secure_boot();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cut the kernel header
|
* cut the kernel header
|
||||||
*/
|
*/
|
||||||
@@ -362,57 +409,7 @@ void start(void)
|
|||||||
*(unsigned int *)__LC_IPLDEV = subchannel_id;
|
*(unsigned int *)__LC_IPLDEV = subchannel_id;
|
||||||
*(unsigned long long *)IPL_DEVICE = subchannel_id;
|
*(unsigned long long *)IPL_DEVICE = subchannel_id;
|
||||||
|
|
||||||
/* if valid command line is given, copy it into new kernel space */
|
setup_cmdline();
|
||||||
if (_stage3_parms.parm_addr != UNSPECIFIED_ADDRESS) {
|
|
||||||
memcpy(cmdline,
|
|
||||||
(void *)(unsigned long *)_stage3_parms.parm_addr,
|
|
||||||
COMMAND_LINE_SIZE);
|
|
||||||
/* terminate \0 */
|
|
||||||
cmdline[COMMAND_LINE_SIZE - 1] = 0;
|
|
||||||
}
|
|
||||||
/* determine length of original parm line */
|
|
||||||
cmdline_len = MIN(strlen((const char *)cmdline),
|
|
||||||
COMMAND_LINE_SIZE - 1);
|
|
||||||
|
|
||||||
/* convert extra parameter to ascii */
|
|
||||||
if (!_stage3_parms.extra_parm || !*cextra)
|
|
||||||
goto noextra;
|
|
||||||
|
|
||||||
/* Handle extra kernel parameters specified in DASD boot menu. */
|
|
||||||
ebcdic_to_ascii(cextra, cextra, COMMAND_LINE_SIZE);
|
|
||||||
|
|
||||||
/* determine length of extra parameter */
|
|
||||||
cextra_len = MIN(strlen((const char *)cextra), COMMAND_LINE_SIZE - 1);
|
|
||||||
|
|
||||||
/* remove leading whitespace of extra parameter */
|
|
||||||
while (cextra_len > 0 && *cextra == 0x20) {
|
|
||||||
cextra++;
|
|
||||||
cextra_len--;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* if extra parm string starts with '=' replace original string,
|
|
||||||
* else append
|
|
||||||
*/
|
|
||||||
if (*cextra == 0x3d && cextra_len >= 1) {
|
|
||||||
/* skip '=' */
|
|
||||||
cextra++;
|
|
||||||
cextra_len--;
|
|
||||||
memcpy(cmdline, cextra, cextra_len);
|
|
||||||
cmdline[cextra_len] = 0;
|
|
||||||
} else if (cmdline_len + 1 <= COMMAND_LINE_SIZE - 1) {
|
|
||||||
/* add blank */
|
|
||||||
cmdline[cmdline_len] = 0x20;
|
|
||||||
cmdline_len++;
|
|
||||||
/* check if length is within max value */
|
|
||||||
cextra_len = (cmdline_len + cextra_len <= COMMAND_LINE_SIZE - 1) ?
|
|
||||||
cextra_len : (COMMAND_LINE_SIZE - 1 - cmdline_len);
|
|
||||||
/* append string */
|
|
||||||
memcpy(cmdline + cmdline_len, cextra, cextra_len);
|
|
||||||
/* terminate 0 */
|
|
||||||
cmdline[cmdline_len + cextra_len] = 0;
|
|
||||||
}
|
|
||||||
noextra:
|
|
||||||
handle_environment(cmdline_len + cextra_len);
|
|
||||||
|
|
||||||
/* copy initrd start address and size intop new kernle space */
|
/* copy initrd start address and size intop new kernle space */
|
||||||
*(unsigned long long *)INITRD_START = _stage3_parms.initrd_addr;
|
*(unsigned long long *)INITRD_START = _stage3_parms.initrd_addr;
|
||||||
|
|||||||
+36
-89
@@ -218,12 +218,25 @@ iplstart:
|
|||||||
la %r2,_initrd_addr # store ramdisk address
|
la %r2,_initrd_addr # store ramdisk address
|
||||||
mvc INITRD_START-PARMAREA(8,%r12),0(%r2)
|
mvc INITRD_START-PARMAREA(8,%r12),0(%r2)
|
||||||
|
|
||||||
|
# copy kernel to final destination
|
||||||
|
|
||||||
|
l %r6,.Lkernsize
|
||||||
|
sl %r6,.Lkernoff
|
||||||
|
l %r2,.Lkernoff # 0x10000
|
||||||
|
lr %r3,%r6
|
||||||
|
l %r4,.Loffset # 0x4000
|
||||||
|
a %r4,.Lkernoff
|
||||||
|
lr %r5,%r6
|
||||||
|
mvcl %r2,%r4
|
||||||
|
l %r12,.Lparmarea
|
||||||
|
|
||||||
#
|
#
|
||||||
# Load parameter file
|
# Load parameter file
|
||||||
#
|
#
|
||||||
|
|
||||||
l %r4,_parm_addr+4
|
l %r4,_parm_addr+4
|
||||||
|
chi %r4,-1
|
||||||
|
be .Lnopf
|
||||||
.Lagain1:
|
.Lagain1:
|
||||||
lr %r2,%r4 # load parmfile
|
lr %r2,%r4 # load parmfile
|
||||||
bas %r14,.Lloader
|
bas %r14,.Lloader
|
||||||
@@ -236,31 +249,35 @@ iplstart:
|
|||||||
clc 0(3,%r4),.L_eof # if it is EOFx
|
clc 0(3,%r4),.L_eof # if it is EOFx
|
||||||
bz .Lagain1 # skip dateset trailer
|
bz .Lagain1 # skip dateset trailer
|
||||||
|
|
||||||
chi %r2,COMMAND_LINE_SIZE-1 # truncate if line too long
|
lt %r3,MAX_COMMAND_LINE_SIZE-PARMAREA+4(%r12)
|
||||||
|
jnz 0f
|
||||||
|
lhi %r3,LEGACY_COMMAND_LINE_SIZE
|
||||||
|
0: cr %r2,%r3 # truncate if line too long
|
||||||
bnh .Lnotrunc
|
bnh .Lnotrunc
|
||||||
la %r2,COMMAND_LINE_SIZE-1
|
lr %r2,%r3
|
||||||
.Lnotrunc:
|
.Lnotrunc:
|
||||||
|
|
||||||
la %r5,0(%r4,%r2) # search for EBCDIC chars
|
la %r5,0(%r4,%r2) # search for EBCDIC chars
|
||||||
lr %r3,%r2
|
ahi %r5,-1
|
||||||
|
lr %r6,%r2
|
||||||
.Lidebc:
|
.Lidebc:
|
||||||
tm 0(%r5),0x80 # high order bit set ?
|
tm 0(%r5),0x80 # high order bit set ?
|
||||||
bo .Ldocv # yes -> convert from EBCDIC
|
bo .Ldocv # yes -> convert from EBCDIC
|
||||||
ahi %r5,-1
|
ahi %r5,-1
|
||||||
bct %r3,.Lidebc
|
bct %r6,.Lidebc
|
||||||
b .Lnocv
|
b .Lnocv
|
||||||
.Ldocv:
|
.Ldocv:
|
||||||
la %r3,_ebcasc
|
lr %r6,%r2
|
||||||
tr 0(256,%r4),0(%r3) # convert parameters to ascii
|
la %r5,_ebcasc
|
||||||
tr 256(256,%r4),0(%r3)
|
0: tr 0(1,%r4),0(%r5)
|
||||||
tr 512(256,%r4),0(%r3)
|
ahi %r4,1
|
||||||
tr 768(127,%r4),0(%r3)
|
brct %r6,0b
|
||||||
|
l %r4,_parm_addr+4
|
||||||
.Lnocv:
|
.Lnocv:
|
||||||
la %r3,COMMAND_LINE-PARMAREA(%r12) # load adr. of command line
|
lr %r5,%r2
|
||||||
mvc 0(256,%r3),0(%r4)
|
ahi %r5,-1
|
||||||
mvc 256(256,%r3),256(%r4)
|
la %r6,COMMAND_LINE-PARMAREA(%r12)
|
||||||
mvc 512(256,%r3),512(%r4)
|
lr %r7,%r2
|
||||||
mvc 768(127,%r3),768(%r4)
|
mvcl %r6,%r4
|
||||||
slr %r0,%r0
|
slr %r0,%r0
|
||||||
b .Lcntlp
|
b .Lcntlp
|
||||||
.Ldelspc:
|
.Ldelspc:
|
||||||
@@ -284,6 +301,8 @@ iplstart:
|
|||||||
|
|
||||||
.Lagain2:
|
.Lagain2:
|
||||||
l %r2,INITRD_START-PARMAREA+4(%r12) # load ramdisk
|
l %r2,INITRD_START-PARMAREA+4(%r12) # load ramdisk
|
||||||
|
chi %r2,-1
|
||||||
|
be .Lnoinitrd
|
||||||
bas %r14,.Lloader
|
bas %r14,.Lloader
|
||||||
|
|
||||||
st %r2,INITRD_SIZE-PARMAREA+4(%r12) # store ramdisk size
|
st %r2,INITRD_SIZE-PARMAREA+4(%r12) # store ramdisk size
|
||||||
@@ -298,86 +317,14 @@ iplstart:
|
|||||||
clc 0(3,%r2),.L_eof
|
clc 0(3,%r2),.L_eof
|
||||||
bz .Lagain2
|
bz .Lagain2
|
||||||
|
|
||||||
#
|
.Lnoinitrd:
|
||||||
# Copy kernel image to final position
|
mvc 0(8,0),_load_psw # copy load psw
|
||||||
#
|
|
||||||
|
|
||||||
la %r2,_load_psw # prepare copy code
|
|
||||||
la %r3,.Lcopypsw
|
|
||||||
mvc 0(8,%r3),0(%r2) # copy load psw
|
|
||||||
|
|
||||||
l %r4,_initrd_addr+4
|
|
||||||
ahi %r4,-0x100
|
|
||||||
|
|
||||||
la %r2,.Lcopystart # get copy code addr (from)
|
|
||||||
mvc 0(.Lcopyend-.Lcopystart,%r4),0(%r2) # copy code
|
|
||||||
|
|
||||||
l %r1,.Loffset # temp kernel address (from)
|
|
||||||
|
|
||||||
l %r2,4(%r3) # get kernel addr from psw (to)
|
|
||||||
n %r2,.Lpswmask
|
|
||||||
s %r2,.Lkernoff
|
|
||||||
|
|
||||||
l %r3,.Lkernsize # (length)
|
|
||||||
br %r4 # branch to copy routine
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copy kernel, then load PSW
|
|
||||||
#
|
|
||||||
# R1 = from
|
|
||||||
# R2 = to
|
|
||||||
# R3 = length
|
|
||||||
#
|
|
||||||
|
|
||||||
.align 8
|
|
||||||
.Lcopystart:
|
|
||||||
clr %r1,%r2
|
|
||||||
je .Lcopyfinish # kernel is already at dest
|
|
||||||
jh .Lcopytolower # need move to lower address
|
|
||||||
|
|
||||||
# Copy last to first
|
|
||||||
|
|
||||||
ar %r1,%r3 # start from last long
|
|
||||||
ar %r2,%r3
|
|
||||||
lhi %r4,-4 # set addr increment to -4
|
|
||||||
j .Lcopygo
|
|
||||||
|
|
||||||
# Copy first to last
|
|
||||||
|
|
||||||
.Lcopytolower:
|
|
||||||
lhi %r4,4 # set addr increment to 4
|
|
||||||
|
|
||||||
.Lcopygo:
|
|
||||||
ahi %r3,3 # get size in longs
|
|
||||||
srl %r3,2
|
|
||||||
|
|
||||||
.Lcopyloop:
|
|
||||||
l %r0,0(%r1) # copy longs
|
|
||||||
st %r0,0(%r2)
|
|
||||||
ar %r1,%r4
|
|
||||||
ar %r2,%r4
|
|
||||||
brct %r3,.Lcopyloop
|
|
||||||
|
|
||||||
.Lcopyfinish:
|
|
||||||
bras %r13,.Lcopyload # set up base register
|
|
||||||
.Lcopyload:
|
|
||||||
sr %r0,%r0
|
|
||||||
la %r1,.Lcopypsw-.Lcopyload(%r13)
|
|
||||||
mvc 0(8,%r0),0(%r1) # copy load psw to 0
|
|
||||||
|
|
||||||
lm %r0,%r15,.Lvmparam-.Lcopyload(%r13) # load saved registers
|
|
||||||
lpsw 0 # start kernel
|
lpsw 0 # start kernel
|
||||||
|
|
||||||
.align 8
|
.align 8
|
||||||
.Lcopypsw:
|
|
||||||
.quad 0
|
|
||||||
.Lvmparam:
|
.Lvmparam:
|
||||||
.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 # vm parameter space
|
.long 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 # vm parameter space
|
||||||
|
|
||||||
.Lcopyend:
|
|
||||||
|
|
||||||
.Lpswmask:
|
|
||||||
.long 0x7fffffff
|
|
||||||
.Lkernsize:
|
.Lkernsize:
|
||||||
.long 0
|
.long 0
|
||||||
.Lkernoff:
|
.Lkernoff:
|
||||||
|
|||||||
+11
-13
@@ -13,6 +13,8 @@
|
|||||||
#ifndef JOB_H
|
#ifndef JOB_H
|
||||||
#define JOB_H
|
#define JOB_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
#include "zipl.h"
|
#include "zipl.h"
|
||||||
|
|
||||||
@@ -39,13 +41,19 @@ struct job_target_data {
|
|||||||
blocknum_t targetoffset;
|
blocknum_t targetoffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct job_ipl_data {
|
struct job_common_ipl_data {
|
||||||
char* image;
|
char* image;
|
||||||
char* parmline;
|
char* parmline;
|
||||||
char* ramdisk;
|
char* ramdisk;
|
||||||
address_t image_addr;
|
address_t image_addr;
|
||||||
address_t parm_addr;
|
address_t parm_addr;
|
||||||
address_t ramdisk_addr;
|
address_t ramdisk_addr;
|
||||||
|
bool optional;
|
||||||
|
bool ignore;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct job_ipl_data {
|
||||||
|
struct job_common_ipl_data common;
|
||||||
address_t envblk_addr;
|
address_t envblk_addr;
|
||||||
int is_kdump;
|
int is_kdump;
|
||||||
};
|
};
|
||||||
@@ -61,13 +69,8 @@ struct job_segment_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct job_dump_data {
|
struct job_dump_data {
|
||||||
|
struct job_common_ipl_data common;
|
||||||
char* device;
|
char* device;
|
||||||
char* image;
|
|
||||||
char* parmline;
|
|
||||||
char* ramdisk;
|
|
||||||
address_t image_addr;
|
|
||||||
address_t parm_addr;
|
|
||||||
address_t ramdisk_addr;
|
|
||||||
uint64_t mem;
|
uint64_t mem;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,13 +83,8 @@ struct job_mvdump_data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct job_ipl_tape_data {
|
struct job_ipl_tape_data {
|
||||||
|
struct job_common_ipl_data common;
|
||||||
char* device;
|
char* device;
|
||||||
char* image;
|
|
||||||
char* parmline;
|
|
||||||
char* ramdisk;
|
|
||||||
address_t image_addr;
|
|
||||||
address_t parm_addr;
|
|
||||||
address_t ramdisk_addr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#define SCAN_SECTION_NUM 9
|
#define SCAN_SECTION_NUM 9
|
||||||
#define SCAN_KEYWORD_NUM 22
|
#define SCAN_KEYWORD_NUM 23
|
||||||
#define SCAN_KEYWORD_ONLY_NUM 1
|
#define SCAN_KEYWORD_ONLY_NUM 1
|
||||||
#define SCAN_AUTOMENU_NAME "zipl-automatic-menu"
|
#define SCAN_AUTOMENU_NAME "zipl-automatic-menu"
|
||||||
|
|
||||||
@@ -52,6 +52,7 @@ enum scan_keyword_id {
|
|||||||
scan_keyword_defaultauto = 19,
|
scan_keyword_defaultauto = 19,
|
||||||
scan_keyword_kdump = 20,
|
scan_keyword_kdump = 20,
|
||||||
scan_keyword_secure = 21,
|
scan_keyword_secure = 21,
|
||||||
|
scan_keyword_optional = 22,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum scan_section_type {
|
enum scan_section_type {
|
||||||
|
|||||||
+2
-1
@@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
#define ADDRESS_LIMIT 0x80000000UL
|
#define ADDRESS_LIMIT 0x80000000UL
|
||||||
#define UNSPECIFIED_ADDRESS -1UL
|
#define UNSPECIFIED_ADDRESS -1UL
|
||||||
#define MAXIMUM_PARMLINE_SIZE 0x380UL
|
#define LEGACY_MAXIMUM_PARMLINE_SIZE 0x380UL
|
||||||
|
#define MAXIMUM_PARMLINE_SIZE 0x10000UL
|
||||||
#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000UL
|
#define MAXIMUM_PHYSICAL_BLOCKSIZE 0x1000UL
|
||||||
|
|
||||||
#define BOOTMAP_FILENAME "bootmap"
|
#define BOOTMAP_FILENAME "bootmap"
|
||||||
|
|||||||
@@ -447,6 +447,23 @@ This option cannot be used together with either
|
|||||||
.BR 'segment' .
|
.BR 'segment' .
|
||||||
.PP
|
.PP
|
||||||
|
|
||||||
|
.B optional
|
||||||
|
=
|
||||||
|
.IR 0 / 1
|
||||||
|
(configuration only)
|
||||||
|
.IP
|
||||||
|
.B Configuration section:
|
||||||
|
.br
|
||||||
|
If this option is set to 1 the configuration section will only be included in
|
||||||
|
the boot menu if the referenced image file exists, and running
|
||||||
|
.B zipl
|
||||||
|
will not fail if the image file is missing.
|
||||||
|
|
||||||
|
The default value for
|
||||||
|
.B 'optional'
|
||||||
|
is 0.
|
||||||
|
.PP
|
||||||
|
|
||||||
.B parameters
|
.B parameters
|
||||||
=
|
=
|
||||||
.I kernel\-parameters
|
.I kernel\-parameters
|
||||||
|
|||||||
@@ -394,6 +394,10 @@ store_stage2_menu(void* data, size_t size, struct job_data* job)
|
|||||||
return 0;
|
return 0;
|
||||||
/* Config texts */
|
/* Config texts */
|
||||||
for (i = 0; i < job->data.menu.num; i++) {
|
for (i = 0; i < job->data.menu.num; i++) {
|
||||||
|
if (job->data.menu.entry[i].data.ipl.common.ignore) {
|
||||||
|
params->config[job->data.menu.entry[i].pos] = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const char *kdump_str = "";
|
const char *kdump_str = "";
|
||||||
if (job->data.menu.entry[i].data.ipl.is_kdump)
|
if (job->data.menu.entry[i].data.ipl.is_kdump)
|
||||||
kdump_str = " (kdump)";
|
kdump_str = " (kdump)";
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user