mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
196 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4014087876 | ||
|
|
8a878a0d61 | ||
|
|
2b511aa2b9 | ||
|
|
6d8243d1b1 | ||
|
|
7ecaeb1a3d | ||
|
|
9ada8332d8 | ||
|
|
ca25f71a6e | ||
|
|
67790d3787 | ||
|
|
d301668811 | ||
|
|
6097ee3f9d | ||
|
|
43967feb2c | ||
|
|
8f4535f5eb | ||
|
|
dfe8a4f803 | ||
|
|
fe0d42e295 | ||
|
|
baf7e9aa2e | ||
|
|
60d03262d8 | ||
|
|
4bed503aa7 | ||
|
|
4518bf7d73 | ||
|
|
3d168fac14 | ||
|
|
746a703079 | ||
|
|
4aa5534f1d | ||
|
|
7c24855ba1 | ||
|
|
6222c38495 | ||
|
|
8709a47f6f | ||
|
|
1fb05038cd | ||
|
|
4f5d33988d | ||
|
|
75513ee975 | ||
|
|
b8fff9b750 | ||
|
|
d5f853c460 | ||
|
|
067dd5c7ef | ||
|
|
af1d05c4a4 | ||
|
|
c5ec01420f | ||
|
|
f25984e716 | ||
|
|
7babd82e6f | ||
|
|
d030874050 | ||
|
|
394a6dd5ea | ||
|
|
db6eb7d554 | ||
|
|
032304d503 | ||
|
|
f75c923627 | ||
|
|
bca8fa3f9c | ||
|
|
d713ea6389 | ||
|
|
f9fbe79e4f | ||
|
|
3cc0b4cdea | ||
|
|
eef9f622c0 | ||
|
|
889293e557 | ||
|
|
0c5b9f5d11 | ||
|
|
02af069d48 | ||
|
|
5e0056db8d | ||
|
|
4b5937f142 | ||
|
|
8d8d5e9746 | ||
|
|
5bdabe3e06 | ||
|
|
8a1db94d37 | ||
|
|
1911cba130 | ||
|
|
f4ed0b0ec6 | ||
|
|
6e42c527d7 | ||
|
|
f7d2339c6a | ||
|
|
cf5f373142 | ||
|
|
e09c675b70 | ||
|
|
6bd93f475c | ||
|
|
3f12bdf4c7 | ||
|
|
3aa7f6e298 | ||
|
|
4e28047eb4 | ||
|
|
f654b971d0 | ||
|
|
e742d1c9ae | ||
|
|
803b87e324 | ||
|
|
5107a7be16 | ||
|
|
1178291686 | ||
|
|
c8d1aa55b4 | ||
|
|
25a70ac5a8 | ||
|
|
6235a51d7c | ||
|
|
e1aec24e84 | ||
|
|
d9a6fb3ccf | ||
|
|
a47dd4570a | ||
|
|
8fa1b5a00b | ||
|
|
e537ab902e | ||
|
|
f0fb4a180a | ||
|
|
f957d895cd | ||
|
|
73c3a9e684 | ||
|
|
2ee1387f34 | ||
|
|
10cefb3337 | ||
|
|
7b369318dd | ||
|
|
cf2fb296f0 | ||
|
|
6cbd81f997 | ||
|
|
2025cf751f | ||
|
|
5a052103ae | ||
|
|
2ced5853b4 | ||
|
|
13edbb7d5e | ||
|
|
1643af4578 | ||
|
|
c7ac1e63bd | ||
|
|
fa3dd0ec20 | ||
|
|
34146c3f92 | ||
|
|
298ede17f5 | ||
|
|
d66ace8121 | ||
|
|
2e89722ef0 | ||
|
|
c8ad5f57d0 | ||
|
|
d2317943c0 | ||
|
|
198c9fc052 | ||
|
|
b3551f50a8 | ||
|
|
4ff360e621 | ||
|
|
87e8fa18cf | ||
|
|
4bd135c3c7 | ||
|
|
f69350e8bd | ||
|
|
5768d55a08 | ||
|
|
538264a8cd | ||
|
|
7f09f0e4ad | ||
|
|
e36084d7f2 | ||
|
|
bd18166a21 | ||
|
|
a6f2c38891 | ||
|
|
029a3f8f52 | ||
|
|
dc87aef335 | ||
|
|
d712806b39 | ||
|
|
2734724432 | ||
|
|
6176509076 | ||
|
|
1780efae07 | ||
|
|
922e8cbb2f | ||
|
|
eef0dd4fa4 | ||
|
|
f93f437f8b | ||
|
|
4e6d43e2ac | ||
|
|
922d29ee49 | ||
|
|
25475bdf42 | ||
|
|
09c413b1be | ||
|
|
8944c2f60d | ||
|
|
ff3fe4bf43 | ||
|
|
5fe2e19277 | ||
|
|
b8cf861aea | ||
|
|
6ca3576dbf | ||
|
|
7ea425db5e | ||
|
|
330ddb7adb | ||
|
|
d69b9fab4a | ||
|
|
4e02dc8751 | ||
|
|
0c8be405ce | ||
|
|
24677dc561 | ||
|
|
7e7c38755d | ||
|
|
229cd6d194 | ||
|
|
776e5d41d7 | ||
|
|
8d7e8a87b5 | ||
|
|
e24d8c936c | ||
|
|
39b6c4a273 | ||
|
|
da9b96fb12 | ||
|
|
7d855acd07 | ||
|
|
f961a2bf90 | ||
|
|
9f93af614f | ||
|
|
d529ba07d3 | ||
|
|
0fffb05d01 | ||
|
|
92b8409207 | ||
|
|
bc3134ba5a | ||
|
|
c7f55a182f | ||
|
|
5078be45b8 | ||
|
|
2418ea93fc | ||
|
|
13cac5de44 | ||
|
|
b6687925cc | ||
|
|
7ee51182bf | ||
|
|
ec3e5b4a75 | ||
|
|
0b5aac3d79 | ||
|
|
bea3180836 | ||
|
|
1ffd767977 | ||
|
|
a4e396fdd7 | ||
|
|
972d4fe0a5 | ||
|
|
148460c235 | ||
|
|
8c2f6790fe | ||
|
|
044272ea25 | ||
|
|
7d67dc8f1c | ||
|
|
71461d80bf | ||
|
|
9eac2788d7 | ||
|
|
6ff8202fa9 | ||
|
|
acf30de415 | ||
|
|
a766411306 | ||
|
|
cbcab61c65 | ||
|
|
c3d179f06e | ||
|
|
f42250ca9b | ||
|
|
7217903ce4 | ||
|
|
708abbf380 | ||
|
|
28dbec093b | ||
|
|
daf02f75b1 | ||
|
|
71b0460d11 | ||
|
|
ff62f4d425 | ||
|
|
53c523ab19 | ||
|
|
2285b9527b | ||
|
|
b4648ec4bd | ||
|
|
c6207db8fc | ||
|
|
1bd73c68f9 | ||
|
|
47016441f0 | ||
|
|
eeed384a51 | ||
|
|
cd5d6a5004 | ||
|
|
e4733002da | ||
|
|
15158ee0ca | ||
|
|
dc73c77d73 | ||
|
|
56529261db | ||
|
|
fcb1f7efd1 | ||
|
|
72b5e8b313 | ||
|
|
225964875c | ||
|
|
e580190074 | ||
|
|
8ef593904d | ||
|
|
51b9504720 | ||
|
|
e9d0e267c5 | ||
|
|
b028d4c254 |
12
.checkpatch.conf
Normal file
12
.checkpatch.conf
Normal file
@@ -0,0 +1,12 @@
|
||||
--max-line-length=100
|
||||
--strict
|
||||
|
||||
# Not Linux therefore don't expect a Linux tree
|
||||
--no-tree
|
||||
|
||||
# Ignore the following
|
||||
--ignore PREFER_KERNEL_TYPES
|
||||
--ignore EXECUTE_PERMISSIONS
|
||||
--ignore FILE_PATH_CHANGES
|
||||
--ignore NEW_TYPEDEFS
|
||||
--ignore SPDX_LICENSE_TAG
|
||||
134
.clang-format
Normal file
134
.clang-format
Normal file
@@ -0,0 +1,134 @@
|
||||
# Must be compatible with clang-format 14
|
||||
---
|
||||
AccessModifierOffset: "-4"
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignArrayOfStructures: None
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveBitFields: AcrossComments
|
||||
AlignConsecutiveMacros: AcrossComments
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Right
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: false
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
BitFieldColonSpacing: Both
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: "100"
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: "8"
|
||||
ContinuationIndentWidth: "8"
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
# git grep -h '^#define [^[:space:]]*\(for_each\|iterate\)[^[:space:]]*(' \
|
||||
# | sed "s,^#define \([^[:space:]]*\(for_each\|iterate\)[^[:space:]]*\)(.*$, - '\1'," \
|
||||
# | LC_ALL=C sort -u
|
||||
ForEachMacros:
|
||||
- "dfi_cpu_iterate"
|
||||
- "dfi_mem_chunk_iterate"
|
||||
- "dfo_chunk_iterate"
|
||||
- "for_each_rb_entry"
|
||||
- "ns_range_for_each"
|
||||
- "sd_cpu_item_enable_iterate"
|
||||
- "sd_cpu_item_iterate"
|
||||
- "sd_cpu_iterate"
|
||||
- "sd_cpu_type_iterate"
|
||||
- "sd_sys_item_enable_iterate"
|
||||
- "sd_sys_item_iterate"
|
||||
- "sd_sys_iterate"
|
||||
- "table_col_iterate"
|
||||
- "table_iterate_mark_keys"
|
||||
- "util_list_iterate"
|
||||
- "util_list_iterate_safe"
|
||||
- "util_opt_iterate"
|
||||
- "util_rec_iterate"
|
||||
IncludeBlocks: Preserve
|
||||
# Leave imports as is
|
||||
IncludeCategories:
|
||||
- Regex: .*
|
||||
Priority: 1
|
||||
IndentCaseLabels: false
|
||||
IndentGotoLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: "8"
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MaxEmptyLinesToKeep: "1"
|
||||
NamespaceIndentation: Inner
|
||||
PackConstructorInitializers: CurrentLine
|
||||
PenaltyBreakAssignment: "10"
|
||||
PenaltyBreakBeforeFirstCallParameter: "30"
|
||||
PenaltyBreakComment: "10"
|
||||
PenaltyBreakFirstLessLess: "0"
|
||||
PenaltyBreakString: "10"
|
||||
PenaltyExcessCharacter: "100"
|
||||
PenaltyReturnTypeOnItsOwnLine: "60"
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatementsExceptForEachMacros
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: "1"
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
StatementMacros:
|
||||
- "STATIC_ASSERT"
|
||||
TabWidth: "8"
|
||||
TypenameMacros:
|
||||
- "STACK_OF"
|
||||
UseTab: Always
|
||||
WhitespaceSensitiveMacros:
|
||||
- "STRINGIFY"
|
||||
5
.codespellrc
Normal file
5
.codespellrc
Normal file
@@ -0,0 +1,5 @@
|
||||
[codespell]
|
||||
ignore-words-list = parm,parms
|
||||
skip = ''
|
||||
count = ''
|
||||
quiet-level = 3
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -78,7 +78,6 @@ systemd/ttyrun-getty@.service
|
||||
tape390/tape390_crypt
|
||||
tape390/tape390_display
|
||||
tunedasd/src/tunedasd
|
||||
vmconvert/vmconvert
|
||||
vmcp/vmcp
|
||||
vmur/vmur
|
||||
zconf/chp/chchp
|
||||
@@ -95,6 +94,9 @@ zdev/src/chzdev_usage.c
|
||||
zdev/src/lszdev
|
||||
zdev/src/lszdev_usage.c
|
||||
zdsfs/zdsfs
|
||||
zdump/.check_dep_fuse
|
||||
zdump/.check_dep_zgetdump
|
||||
zdump/.detect_openssl.dep.c
|
||||
zdump/zgetdump
|
||||
zfcpdump/10-zfcpdump.install
|
||||
zfcpdump/cpioinit
|
||||
@@ -107,6 +109,7 @@ ziomon/ziorep_traffic
|
||||
ziomon/ziorep_utilization
|
||||
zipl/boot/*.bin
|
||||
zipl/boot/*.exec
|
||||
zipl/boot/.loaders
|
||||
zipl/boot/data.h
|
||||
zipl/src/chreipl_helper.device-mapper
|
||||
zdev/src/zdev_id
|
||||
|
||||
@@ -9,6 +9,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Antoinette Kaschner
|
||||
- Arnd Bergmann
|
||||
- Axel Wirbser
|
||||
- Balint Reczey
|
||||
- Benjamin Block
|
||||
- Brian C. Lane
|
||||
- Carsten Otte
|
||||
@@ -20,6 +21,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Colin Walters
|
||||
- Dan Horak
|
||||
- Dan Horák
|
||||
- Daniel S. Haischt
|
||||
- Despina Papadopoulou
|
||||
- Dimitri John Ledkov
|
||||
- Eberhard Pasch
|
||||
@@ -88,6 +90,7 @@ List of all individuals having contributed content to s390-tools
|
||||
- Mikhail Zaslonko
|
||||
- Nikita Dubrovskii
|
||||
- Niklas Schnelle
|
||||
- Nikolay Gueorguiev
|
||||
- Peter Oberparleiter
|
||||
- Peter Tiedemann
|
||||
- Philipp Kern
|
||||
|
||||
80
CHANGELOG.md
80
CHANGELOG.md
@@ -1,5 +1,85 @@
|
||||
Release history for s390-tools (MIT version)
|
||||
--------------------------------------------
|
||||
|
||||
* __v2.26.0 (2023-02-14)__
|
||||
|
||||
For Linux kernel version: 6.2
|
||||
|
||||
Remove tools / libraries:
|
||||
- Remove vmconvert and libvmdump in favor of vmdump file support in zdump
|
||||
|
||||
Changes of existing tools:
|
||||
- ipl_tools: Add support for list-directed IPL from ECKD DASD
|
||||
- lszcrypt: Display hardware filtering support capability
|
||||
- vmur: Remove option -c for dump file conversion (See zdump changes)
|
||||
- zdev: Add zfcp ber_stop parameter handling
|
||||
- zdump: Add vmdump dfi for vmdump format to elf format
|
||||
- zkey: Support EP11 host library version
|
||||
|
||||
Bug Fixes:
|
||||
- zipl: Move dump parmline processing and verification
|
||||
- zipl/genprotimg: Various build improvements
|
||||
|
||||
* __v2.25.0 (2022-12-08)__
|
||||
|
||||
For Linux kernel version: 6.1
|
||||
|
||||
Changes of existing tools:
|
||||
- ap_tools: Use new mdevctl installation location
|
||||
- lsdasd/tunedasd/zdev: Add support to handle copy pair relations presented by the DASD driver
|
||||
- zdev: Add --shell command line switch to generate output suitable for shell environments
|
||||
- zipl: Add List-Directed IPL from ECKD DASD to support secure boot
|
||||
|
||||
Bug Fixes:
|
||||
- ipl_tools: Fix chreipl node for NVMes with CONFIG_NVME_MULTIPATH
|
||||
- libdasd: Fix bug that prevented positive ioctl return codes
|
||||
|
||||
* __v2.24.0 (2022-11-09)__
|
||||
|
||||
For Linux kernel version: 6.0
|
||||
|
||||
Add new tools / libraries:
|
||||
- Provide config files for checkpatch, codespell, and clang-format
|
||||
|
||||
Changes of existing tools:
|
||||
- dbginfo.sh: Collect log from various distro tools (YaST, DNF, Anaconda)
|
||||
- dbginfo.sh: add Kubernetes data collection
|
||||
- libutil: Introduce util_lockfile
|
||||
- zdev: Add site-aware device configuration
|
||||
- zdump: Add support to read Protected Virtualization dumps
|
||||
- zipl/boot: Add secure boot trailer
|
||||
|
||||
Bug Fixes:
|
||||
- ap_tools/ap-check: Reject start for control domains without usage
|
||||
- cpumf/lshwc: Fix incremented counter output
|
||||
- cpumf/pai: Fix core dump when summary flag set
|
||||
- dbginfo.sh: Ensure compatibility with /bin/dash shell
|
||||
- dbginfo.sh: Save dbginfo.sh version to dbginfo.log
|
||||
- zipl/src/zipl_helper.device-mapper: Fix bug in error path
|
||||
|
||||
* __v2.23.0 (2022-08-18)__
|
||||
|
||||
For Linux kernel version: 5.19
|
||||
|
||||
Changes of existing tools:
|
||||
- Makefile: use common Make definition for DRACUTDIR
|
||||
- Makefile: use common Make definition for UDEVDIR and UDEVRULESDIR
|
||||
- cpacfstats: Add PAI and hotplug support
|
||||
- cpumf/pai: Omit file write progress information
|
||||
- dbginfo.sh: Get more details on lspci command
|
||||
- dumpconf: Prevent running the service in containers
|
||||
- libcpumf: Detect PMU named pai_ext
|
||||
- pvattest: Improve error reporting and logging
|
||||
- zdev: Add some --type ap examples to manpages
|
||||
- zkey: Use default benchmarked Argon2i with LUKS2
|
||||
|
||||
Bug Fixes:
|
||||
- dbginfo.sh: Fix accidental ftrace buffer shrinkage/free
|
||||
- genprotimg: Fix BIO_reset() returncode handling
|
||||
- libpv: Fix dependency checking
|
||||
- pvattest: Fix dependency checking
|
||||
- zipl: Fix segmentation fault when no parmline is provided
|
||||
|
||||
* __v2.22.0 (2022-06-20)__
|
||||
|
||||
For Linux kernel version: 5.18
|
||||
|
||||
@@ -4,8 +4,10 @@ Coding guidelines for s390-tools
|
||||
For s390-tools the preferred language is C. We provide libraries, e.g.
|
||||
[`libutil`](libutil) that should be used by all tools if possible.
|
||||
|
||||
The coding style is based on the Linux [kernel guidelines]. Therefore, use
|
||||
the [checkpatch] tool for verification before you submit a patch.
|
||||
The coding style is based on the Linux [kernel guidelines]. Therefore, use the
|
||||
[checkpatch] tool for verification before you submit a patch. s390-tools
|
||||
provides a CheckPatch configuration for this - see
|
||||
[`.checkpatch.conf`](.checkpatch.conf).
|
||||
|
||||
[kernel guidelines]: https://www.kernel.org/doc/html/latest/process/coding-style.html
|
||||
[checkpatch]: https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl
|
||||
@@ -17,6 +19,39 @@ This package started in 2001 and has a long "tradition" - therefore, older tools
|
||||
might not follow all recommendations. Note that when changing existing code,
|
||||
consistency could have priority over applying rules.
|
||||
|
||||
Automatic Code Formatting
|
||||
-------------------------
|
||||
|
||||
> **NOTE:** clang-format is a helpful tool but please don't use it blindly!
|
||||
|
||||
s390-tools provides a ClangFormat (https://clang.llvm.org/docs/ClangFormat.html)
|
||||
configuration file - see [`.clang-format`](.clang-format). It can be used to
|
||||
format your C/C++ code automatically.
|
||||
|
||||
Clang-format can format a single file or multiple files at once. For example, to
|
||||
format `main.c` in place, run the following command in a terminal:
|
||||
|
||||
```bash
|
||||
clang-format -i main.c
|
||||
```
|
||||
|
||||
In order to format only your current staged changes use the clang-format git
|
||||
plugin:
|
||||
|
||||
```bash
|
||||
git clang-format --staged
|
||||
```
|
||||
|
||||
See also `git clang-format -h`.
|
||||
|
||||
Automatic Editor Configuration
|
||||
------------------------------
|
||||
|
||||
s390-tools provides a EditorConfig (https://editorconfig.org/) configuration
|
||||
file - see [`.editorconfig`](.editorconfig). EditorConfig defines coding style
|
||||
rules (such as indentation size, use of tabs, etc.) and is supported by most
|
||||
common editors natively or via plugins.
|
||||
|
||||
Standard abbreviations
|
||||
----------------------
|
||||
|
||||
|
||||
4
Makefile
4
Makefile
@@ -9,11 +9,11 @@ include common.mak
|
||||
# TOOLS: Tools that can have a dependency to base libraries or libraries
|
||||
#
|
||||
BASELIB_DIRS = libutil libseckey
|
||||
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
||||
LIB_DIRS = libvtoc libzds libdasd libccw libvmcp libekmfweb \
|
||||
libkmipclient libcpumf libap libpv
|
||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools pvattest
|
||||
|
||||
44
README.md
44
README.md
@@ -60,6 +60,7 @@ Package contents
|
||||
|
||||
* zgetdump:
|
||||
Retrieve system dumps from either tapes, DASDs, SCSIs or NVMes.
|
||||
Decrypt Protected Virtualization (PV) dumps from IBM Secure Execution guests.
|
||||
|
||||
* qetharp:
|
||||
Read and flush the ARP cache on OSA Express network cards.
|
||||
@@ -97,11 +98,6 @@ Package contents
|
||||
* tunedasd:
|
||||
Adjust tunable parameters on DASD devices.
|
||||
|
||||
* vmconvert:
|
||||
Convert system dumps created by the z/VM VMDUMP command into dumps with
|
||||
LKCD format. These LKCD dumps can then be analyzed with the dump analysis
|
||||
tool lcrash.
|
||||
|
||||
* vmcp:
|
||||
Send commands from Linux as a z/VM guest to the z/VM control program (CP).
|
||||
Call vmcp with the CP command as an argument. The response of z/VM is
|
||||
@@ -306,20 +302,19 @@ build options:
|
||||
| | | hsavmcore |
|
||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||
| pfm | `HAVE_PFM` | cpacfstats |
|
||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
||||
| | | libkmipclient, pvattest |
|
||||
| | | libkmipclient, pvattest, zgetdump |
|
||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
||||
| | | libkmipclient |
|
||||
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest |
|
||||
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest, zgetdump |
|
||||
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
|
||||
| | | pvattest |
|
||||
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
||||
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
||||
| liblockfile | `HAVE_LOCKFILE` | ap-check |
|
||||
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
|
||||
|
||||
This table lists additional build or install options:
|
||||
|
||||
@@ -376,6 +371,13 @@ the different tools are provided:
|
||||
- Packages: blktrace, multipath-tools, sg3-utils
|
||||
- Tools: rsync, tar, lsscsi
|
||||
|
||||
* zgetdump
|
||||
For building zgetdump you need OpenSSL version 1.1.0 or newer
|
||||
installed (openssl-devel.rpm). Also required is glib2
|
||||
(glib2-devel.rpm) and zlib (zlib-devel.rpm).
|
||||
Tip: you may skip the zgetdump build by adding
|
||||
`HAVE_OPENSSL=0`, `HAVE_GLIB2=0`, or `HAVE_ZLIB=0`.
|
||||
|
||||
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
||||
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
||||
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
|
||||
@@ -403,14 +405,13 @@ the different tools are provided:
|
||||
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
||||
|
||||
* cpacfstats:
|
||||
For building the cpacfstats tools you need libpfm version 4 or
|
||||
newer installed (libpfm-devel.rpm). Tip: you may skip the cpacfstats
|
||||
build by adding `HAVE_PFN=0` to the make invocation. To run the
|
||||
cpacfstats daemon the kernel needs to have performance
|
||||
events enabled (check for `CONFIG_PERF_EVENTS=y`) and you need libpfm
|
||||
version 4 or newer installed. A new group 'cpacfstats' needs to be
|
||||
created and all users intending to use the tool should be added to
|
||||
this group.
|
||||
For building the cpacfstats tools you need libudev installed
|
||||
(systemd-devel.rpm). Tip: you may skip the cpacfstats build by
|
||||
adding `HAVE_LIBUDEV=0` to the make invocation. To run the
|
||||
cpacfstats daemon the kernel needs to have performance events
|
||||
enabled (check for `CONFIG_PERF_EVENTS=y`). A new group 'cpacfstats'
|
||||
needs to be created and all users intending to use the tool should
|
||||
be added to this group.
|
||||
|
||||
* zdev:
|
||||
Depending on the boot loader and initial RAM-disk mechanism used by a
|
||||
@@ -506,8 +507,7 @@ the different tools are provided:
|
||||
GNU awk for the build process.
|
||||
|
||||
* ap-check:
|
||||
For building the ap-check mdevctl callout utility you need liblockfile
|
||||
version 1.14 or newer installed (liblockfile-devel.rpm). Also required is
|
||||
json-c version 0.13 or newer (json-c-devel.rpm).
|
||||
Tip: you may skip ap-check build by adding `HAVE_LOCKFILE=0` or `HAVE_JSONC=0`
|
||||
to the make invocation.
|
||||
For building the ap-check mdevctl callout utility you need json-c version
|
||||
0.13 or newer (json-c-devel.rpm).
|
||||
Tip: you may skip ap-check build by adding `HAVE_JSONC=0` to the make
|
||||
invocation.
|
||||
|
||||
@@ -1,27 +1,23 @@
|
||||
include ../common.mak
|
||||
|
||||
MDEVCTL_DIR = /etc/mdevctl.d/
|
||||
MDEVCTL_SCRIPTS = /etc/mdevctl.d/scripts.d/
|
||||
MDEVCTL_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
|
||||
MDEVCTL_DIR = /usr/lib/mdevctl/
|
||||
MDEVCTL_SCRIPTS = /usr/lib/mdevctl/scripts.d/
|
||||
MDEVCTL_CALLOUTS = /usr/lib/mdevctl/scripts.d/callouts/
|
||||
MDEVCTL_DEP_DIR = /etc/mdevctl.d/
|
||||
MDEVCTL_DEP_SCRIPTS = /etc/mdevctl.d/scripts.d/
|
||||
MDEVCTL_DEP_CALLOUTS = /etc/mdevctl.d/scripts.d/callouts/
|
||||
|
||||
libs = $(rootdir)/libap/libap.a \
|
||||
$(rootdir)/libutil/libutil.a
|
||||
|
||||
ifeq (${HAVE_LOCKFILE},0)
|
||||
all:
|
||||
$(SKIP) HAVE_LOCKFILE=0
|
||||
|
||||
install:
|
||||
$(SKIP) HAVE_LOCKFILE=0
|
||||
|
||||
else ifeq (${HAVE_JSONC},0)
|
||||
ifeq (${HAVE_JSONC},0)
|
||||
all:
|
||||
$(SKIP) HAVE_JSONC=0
|
||||
|
||||
install:
|
||||
$(SKIP) HAVE_JSONC=0
|
||||
else
|
||||
LDLIBS += -llockfile -ljson-c
|
||||
LDLIBS += -ljson-c
|
||||
|
||||
all: ap-check
|
||||
|
||||
@@ -30,15 +26,26 @@ ap-check: ap-check.o $(libs)
|
||||
install: all
|
||||
@if [ ! -d $(DESTDIR)$(MDEVCTL_CALLOUTS) ]; then \
|
||||
mkdir -p $(DESTDIR)$(MDEVCTL_CALLOUTS); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_DIR); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_SCRIPTS); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(MDEVCTL_CALLOUTS); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(MDEVCTL_DIR); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(MDEVCTL_SCRIPTS); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(MDEVCTL_CALLOUTS); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DIR); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_SCRIPTS); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_CALLOUTS); \
|
||||
fi; \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check \
|
||||
$(DESTDIR)$(MDEVCTL_CALLOUTS)
|
||||
@if [ ! -d $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS) ]; then \
|
||||
mkdir -p $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_DIR); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_SCRIPTS); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_DIR); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_SCRIPTS); \
|
||||
chmod 755 $(DESTDIR)$(MDEVCTL_DEP_CALLOUTS); \
|
||||
fi; \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ap-check.sh \
|
||||
$(DESTDIR)$(MDEVCTL_DEP_CALLOUTS)
|
||||
endif
|
||||
|
||||
clean:
|
||||
|
||||
@@ -133,7 +133,7 @@ static void ap_check_cleanup(struct ap_check_anchor *anc)
|
||||
if (anc->dev)
|
||||
vfio_ap_device_free(anc->dev);
|
||||
if (anc->cleanup_lock)
|
||||
ap_release_lock();
|
||||
ap_release_lock_callout();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -685,6 +685,14 @@ static int ap_check_handle_start(struct ap_check_anchor *anc)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Ensure device with control domains also has usage domains */
|
||||
if (util_list_is_empty(anc->dev->domains) &&
|
||||
!util_list_is_empty(anc->dev->controls)) {
|
||||
fprintf(stderr, "At least one usage domain must be specified\n");
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Check against all other active vfio-ap devices */
|
||||
rc = check_other_mdevs_sysfs(anc);
|
||||
/* Check against the system sysfs values for apmask/aqmask */
|
||||
@@ -767,7 +775,7 @@ out:
|
||||
*/
|
||||
static int ap_check_handle_post(void)
|
||||
{
|
||||
return ap_release_lock();
|
||||
return ap_release_lock_callout();
|
||||
}
|
||||
|
||||
/* For the specified device, print the attributes to stdout in JSON format */
|
||||
|
||||
15
ap_tools/ap-check.sh
Normal file
15
ap_tools/ap-check.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
# ap-check.sh - Wrapper script for 'ap-check' binary
|
||||
#
|
||||
# mdevctl has deprecated the /etc/mdevctl.d/scripts.d/callouts/ location in
|
||||
# newer releases. This wrapper ensures that mdevctl 1.2.0 and older can
|
||||
# still access 'ap-check' for now, and will be removed at a later time.
|
||||
#
|
||||
# Copyright 2022 IBM Corp.
|
||||
#
|
||||
# s390-tools is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the MIT license. See LICENSE for details.
|
||||
#
|
||||
|
||||
[ -e /usr/lib/mdevctl/scripts.d/callouts/ap-check ] && /usr/lib/mdevctl/scripts.d/callouts/ap-check "$@"
|
||||
@@ -27,11 +27,7 @@ ENABLE_DOC = 0
|
||||
|
||||
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
|
||||
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
|
||||
UDEVDIR = $(USRLIBDIR)/udev
|
||||
UDEVRULESDIR = $(UDEVDIR)/rules.d
|
||||
UDEVRUNDIR = /run/udev
|
||||
DRACUTDIR = $(USRLIBDIR)/dracut
|
||||
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
|
||||
DEBUGOUTDIR = $(UDEVRUNDIR)
|
||||
|
||||
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps
|
||||
|
||||
42
common.mak
42
common.mak
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||
VERSION = 2
|
||||
RELEASE = 22
|
||||
RELEASE = 26
|
||||
PATCHLEVEL = 0
|
||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||
@@ -60,8 +60,10 @@ endef
|
||||
|
||||
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
||||
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
||||
$(eval $(call cmd_define, LINK," LINK ",$(CC)))
|
||||
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
||||
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
||||
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CXX)))
|
||||
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
||||
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
||||
$(eval $(call cmd_define, NM," NM ",$(CROSS_COMPILE)nm))
|
||||
@@ -81,8 +83,6 @@ CHECKTOOL = $(call echocmd," CHECK ",/$@)$(CHECK_SILENT)
|
||||
SKIP = echo " SKIP $(call reldir) due to"
|
||||
|
||||
INSTALL = install
|
||||
LINK = $(CC)
|
||||
LINKXX = $(CXX)
|
||||
CP = cp
|
||||
ifneq ("${V}","1")
|
||||
MAKEFLAGS += --quiet
|
||||
@@ -91,7 +91,7 @@ ifneq ("${V}","1")
|
||||
else
|
||||
echocmd=
|
||||
endif
|
||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
||||
DEFAULT_CFLAGS = -g -fstack-protector-all -W -Wall -Wformat-security
|
||||
ifeq ("${W}","1")
|
||||
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
|
||||
endif
|
||||
@@ -120,7 +120,7 @@ endif
|
||||
define check_header_prereq
|
||||
$(shell printf "#include <%s>\n int main(void) {return 0;}\n" $1 | \
|
||||
( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) \
|
||||
$2 -o /dev/null -xc - ) >/dev/null 2>&1 && echo -n yes)
|
||||
$2 -o /dev/null -x c - ) >/dev/null 2>&1 && echo -n yes)
|
||||
endef
|
||||
|
||||
#
|
||||
@@ -133,7 +133,7 @@ endef
|
||||
# $5: Additional compiler & linker options (optional)
|
||||
#
|
||||
check_dep=\
|
||||
printf "\#include <%s>\n int main(void) {return 0;}\n" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -xc - ) > /dev/null 2>&1; \
|
||||
printf "\#include <%s>\n int main(void) {return 0;}\n" $2 | ( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) $5 -o /dev/null -x c - ) > /dev/null 2>&1; \
|
||||
if [ $$? != 0 ]; \
|
||||
then \
|
||||
printf " REQCHK %s (%s)\n" $1 $2; \
|
||||
@@ -145,6 +145,20 @@ then \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
#
|
||||
# Test for linker option
|
||||
#
|
||||
# $1: Linker option
|
||||
#
|
||||
# Returns the linker option if available and nothing otherwise
|
||||
#
|
||||
define test_linker_flag
|
||||
$(shell printf "int main(void) {return 0;}\n" | \
|
||||
( $(CC) "-Wl,$1" -o /dev/null -x c - ) >/dev/null 2>&1 && printf -- '-Wl,%s' "$1")
|
||||
endef
|
||||
|
||||
NO_WARN_RWX_SEGMENTS_LDFLAGS := $(call test_linker_flag,"--no-warn-rwx-segments")
|
||||
|
||||
#
|
||||
# Support alternate install root
|
||||
#
|
||||
@@ -193,6 +207,11 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
|
||||
SYSTEMDSYSTEMUNITDIR =
|
||||
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
||||
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
|
||||
UDEVDIR = $(USRLIBDIR)/udev
|
||||
UDEVRULESDIR = $(UDEVDIR)/rules.d
|
||||
DRACUTDIR = $(USRLIBDIR)/dracut
|
||||
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
|
||||
DRACUTMODDIR = $(DRACUTDIR)/modules.d
|
||||
|
||||
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
|
||||
SOINSTALLDIR = $(USRLIB64DIR)
|
||||
@@ -256,7 +275,7 @@ else
|
||||
NO_PIE_LDFLAGS :=
|
||||
endif
|
||||
|
||||
# Overwrite implicite makefile rules for having nice compile output
|
||||
# Overwrite implicit makefile rules for having nice compile output
|
||||
%.o: %.c
|
||||
ifeq ("${C}","1")
|
||||
$(CHECKTOOL) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||
@@ -359,10 +378,6 @@ $(rootdir)/libzds/libzds.a: $(rootdir)/libzds
|
||||
$(MAKE) -C $(rootdir)/libzds/ libzds.a
|
||||
.PHONY: $(rootdir)/libzds
|
||||
|
||||
$(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
|
||||
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
|
||||
.PHONY: $(rootdir)/libvmdump
|
||||
|
||||
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
||||
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||
.PHONY: $(rootdir)/libvmcp
|
||||
@@ -391,8 +406,8 @@ $(rootdir)/libpv/libpv.a: $(rootdir)/libpv
|
||||
$(MAKE) -C $(rootdir)/libpv libpv.a
|
||||
.PHONY: $(rootdir)/libpv
|
||||
|
||||
$(rootdir)/zipl/boot/data.o:
|
||||
$(MAKE) -C $(rootdir)/zipl/boot/ data.o
|
||||
$(rootdir)/zipl/boot/.loaders:
|
||||
$(MAKE) -C $(rootdir)/zipl/boot/ .loaders
|
||||
|
||||
install_dirs:
|
||||
for dir in $(INSTDIRS); do \
|
||||
@@ -417,4 +432,3 @@ clean_dep:
|
||||
|
||||
clean: clean_echo clean_gcov clean_dep
|
||||
endif
|
||||
|
||||
|
||||
@@ -1,11 +1,28 @@
|
||||
include ../common.mak
|
||||
|
||||
ifeq (${HAVE_LIBUDEV},0)
|
||||
|
||||
all:
|
||||
$(SKIP) HAVE_LIBUDEV=0
|
||||
|
||||
install:
|
||||
$(SKIP) HAVE_LIBUDEV=0
|
||||
|
||||
else
|
||||
|
||||
check_dep:
|
||||
$(call check_dep, \
|
||||
"cpacfstatsd", \
|
||||
"libudev.h", \
|
||||
"systemd-devel", \
|
||||
"HAVE_LIBUDEV=0")
|
||||
|
||||
ALL_CPPFLAGS += -DVERSION=$(VERSION)
|
||||
|
||||
all: cpacfstats cpacfstatsd
|
||||
all: check_dep cpacfstats cpacfstatsd
|
||||
|
||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -ludev -lpthread -o $@
|
||||
|
||||
cpacfstats: cpacfstats.o stats_sock.o
|
||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||
@@ -16,6 +33,8 @@ install: all
|
||||
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
||||
|
||||
endif
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ cpacfstatsd cpacfstats
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.\" cpacfstats.1
|
||||
.\"
|
||||
.\" Copyright IBM Corp. 2015, 2020
|
||||
.\" Copyright IBM Corp. 2015, 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.
|
||||
.\"
|
||||
@@ -32,7 +32,9 @@ cpacfstats \- enable, disable and display CPACF statistical data
|
||||
.RB ]
|
||||
.RB [ \-p | \-\-print
|
||||
.I counter
|
||||
.RB [ \-n | \-\-nonzero]
|
||||
.RB ]
|
||||
.RB [ \-j | \-\-json ]
|
||||
.
|
||||
.SH DESCRIPTION
|
||||
The cpacfstats client application interacts with the cpacfstatsd daemon and
|
||||
@@ -44,12 +46,347 @@ All counters are initially disabled and must be switched on to measure
|
||||
CPACF activities of the system. There is a slight performance penalty with
|
||||
CPACF counters enabled.
|
||||
|
||||
Note: All cryptographic counters are bound to physical CPUs. If you use
|
||||
dedicated CPUs for your LPAR, you obtain only your CPACF activities. If
|
||||
your CPUs are shared with other LPARs, their cryptographic activities might
|
||||
distort the results. CPACF performance counters are available on LPARs
|
||||
only. For security reasons only members of the group \fIcpacfstats\fR are
|
||||
allowed to run the cpacfstats client application.
|
||||
CPACF activity counters come in two flavors: CPU-MF and PAI. CPU-MF
|
||||
counters are only available on LPARs and have to be authorized. If
|
||||
they are available, the counters
|
||||
.B des,
|
||||
.B aes,
|
||||
.B sha,
|
||||
.B rng,
|
||||
and
|
||||
.B ecc
|
||||
are made available. These counters can individually be activated,
|
||||
reset, printed, or deactivated. PAI counters are a lot more detailed.
|
||||
The user interface only offers the counters
|
||||
.B pai_user
|
||||
and
|
||||
.B pai_kernel
|
||||
to count CPACF usage in user-space or kernel-space. When printing
|
||||
these counters, detailed counters are shown. The detailed names are:
|
||||
.RS
|
||||
.IP \(bu
|
||||
KM DES,
|
||||
.IP \(bu
|
||||
KM 2key TDES,
|
||||
.IP \(bu
|
||||
KM TDES,
|
||||
.IP \(bu
|
||||
KM DES protected key,
|
||||
.IP \(bu
|
||||
KM 2key TDES protected key,
|
||||
.IP \(bu
|
||||
KM TDES protected key,
|
||||
.IP \(bu
|
||||
KM AES 128bit,
|
||||
.IP \(bu
|
||||
KM AES 192bit,
|
||||
.IP \(bu
|
||||
KM AES 256bit,
|
||||
.IP \(bu
|
||||
KM AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KM AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KM AES 256bit protected key,
|
||||
.IP \(bu
|
||||
KM AES-XTS 128bit,
|
||||
.IP \(bu
|
||||
KM AES-XTS 256bit,
|
||||
.IP \(bu
|
||||
KM AES-XTS 128bit protected key,
|
||||
.IP \(bu
|
||||
KM AES-XTS 256bit protected key,
|
||||
.IP \(bu
|
||||
KMC DES,
|
||||
.IP \(bu
|
||||
KMC 2key TDES,
|
||||
.IP \(bu
|
||||
KMC TDES,
|
||||
.IP \(bu
|
||||
KMC DES protected key,
|
||||
.IP \(bu
|
||||
KMC 2key TDES protected key,
|
||||
.IP \(bu
|
||||
KMC TDES protected key,
|
||||
.IP \(bu
|
||||
KMC AES 128bit,
|
||||
.IP \(bu
|
||||
KMC AES 192bit,
|
||||
.IP \(bu
|
||||
KMC AES 256bit,
|
||||
.IP \(bu
|
||||
KMC AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KMC AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KMC AES 256bit protected key,
|
||||
.IP \(bu
|
||||
KMC PRNG,
|
||||
.IP \(bu
|
||||
KMA AES 128bit,
|
||||
.IP \(bu
|
||||
KMA AES 192bit,
|
||||
.IP \(bu
|
||||
KMA AES 256bit,
|
||||
.IP \(bu
|
||||
KMA AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KMA AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KMA AES 256bit protected key,
|
||||
.IP \(bu
|
||||
KMF DES,
|
||||
.IP \(bu
|
||||
KMF 2key TDES,
|
||||
.IP \(bu
|
||||
KMF TDES,
|
||||
.IP \(bu
|
||||
KMF DES protected key,
|
||||
.IP \(bu
|
||||
KMF 2key TDES protected key,
|
||||
.IP \(bu
|
||||
KMF TDES protected key,
|
||||
.IP \(bu
|
||||
KMF AES 128bit,
|
||||
.IP \(bu
|
||||
KMF AES 192bit,
|
||||
.IP \(bu
|
||||
KMF AES 256bit,
|
||||
.IP \(bu
|
||||
KMF AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KMF AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KMF AES 256bit protected key,
|
||||
.IP \(bu
|
||||
KMCTR DES,
|
||||
.IP \(bu
|
||||
KMCTR 2key TDES,
|
||||
.IP \(bu
|
||||
KMCTR TDES,
|
||||
.IP \(bu
|
||||
KMCTR DES protected key,
|
||||
.IP \(bu
|
||||
KMCTR 2key TDES protected key,
|
||||
.IP \(bu
|
||||
KMCTR TDES protected key,
|
||||
.IP \(bu
|
||||
KMCTR AES 128bit,
|
||||
.IP \(bu
|
||||
KMCTR AES 192bit,
|
||||
.IP \(bu
|
||||
KMCTR AES 256bit,
|
||||
.IP \(bu
|
||||
KMCTR AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KMCTR AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KMCTR AES 256bit protected key,
|
||||
.IP \(bu
|
||||
KMO DES,
|
||||
.IP \(bu
|
||||
KMO 2key TDES,
|
||||
.IP \(bu
|
||||
KMO TDES,
|
||||
.IP \(bu
|
||||
KMO DES protected key,
|
||||
.IP \(bu
|
||||
KMO 2key TDES protected key,
|
||||
.IP \(bu
|
||||
KMO TDES protected key,
|
||||
.IP \(bu
|
||||
KMO AES 128bit,
|
||||
.IP \(bu
|
||||
KMO AES 192bit,
|
||||
.IP \(bu
|
||||
KMO AES 256bit,
|
||||
.IP \(bu
|
||||
KMO AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KMO AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KMO AES 256bit protected key,
|
||||
.IP \(bu
|
||||
KIMD SHA1,
|
||||
.IP \(bu
|
||||
KIMD SHA256,
|
||||
.IP \(bu
|
||||
KIMD SHA512,
|
||||
.IP \(bu
|
||||
KIMD SHA3-224,
|
||||
.IP \(bu
|
||||
KIMD SHA3-256,
|
||||
.IP \(bu
|
||||
KIMD SHA3-384,
|
||||
.IP \(bu
|
||||
KIMD SHA3-512,
|
||||
.IP \(bu
|
||||
KIMD SHAKE 128,
|
||||
.IP \(bu
|
||||
KIMD SHAKE 256,
|
||||
.IP \(bu
|
||||
KIMD GHASH,
|
||||
.IP \(bu
|
||||
KLMD SHA1,
|
||||
.IP \(bu
|
||||
KLMD SHA256,
|
||||
.IP \(bu
|
||||
KLMD SHA512,
|
||||
.IP \(bu
|
||||
KLMD SHA3-224,
|
||||
.IP \(bu
|
||||
KLMD SHA3-256,
|
||||
.IP \(bu
|
||||
KLMD SHA3-384,
|
||||
.IP \(bu
|
||||
KLMD SHA3-512,
|
||||
.IP \(bu
|
||||
KLMD SHAKE 128,
|
||||
.IP \(bu
|
||||
KLMD SHAKE 256,
|
||||
.IP \(bu
|
||||
KMAC DES,
|
||||
.IP \(bu
|
||||
KMAC 2key TDES,
|
||||
.IP \(bu
|
||||
KMAC TDES,
|
||||
.IP \(bu
|
||||
KMAC DES protected key,
|
||||
.IP \(bu
|
||||
KMAC 2key TDES protected key,
|
||||
.IP \(bu
|
||||
KMAC TDES protected key,
|
||||
.IP \(bu
|
||||
KMAC AES 128bit,
|
||||
.IP \(bu
|
||||
KMAC AES 192bit,
|
||||
.IP \(bu
|
||||
KMAC AES 256bit,
|
||||
.IP \(bu
|
||||
KMAC AES 128bit protected key,
|
||||
.IP \(bu
|
||||
KMAC AES 192bit protected key,
|
||||
.IP \(bu
|
||||
KMAC AES 256bit protected key,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC DES,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC 2key TDES,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC TDES,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC DES protected key,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC 2key TDES protected key,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC TDES protected key,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC AES 128bit,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC AES 192bit,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC AES 256bit,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC AES 128bit protected key,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC AES 192bit protected key,
|
||||
.IP \(bu
|
||||
PCC Last Block CMAC AES 256bit protected key,
|
||||
.IP \(bu
|
||||
PCC XTS Parameter AES 128bit,
|
||||
.IP \(bu
|
||||
PCC XTS Parameter AES 256bit,
|
||||
.IP \(bu
|
||||
PCC XTS Parameter AES 128bit protected key,
|
||||
.IP \(bu
|
||||
PCC XTS Parameter AES 256bit protected key,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult P256,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult P384,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult P521,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult Ed25519,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult Ed448,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult X25519,
|
||||
.IP \(bu
|
||||
PCC Scalar Mult X448,
|
||||
.IP \(bu
|
||||
PRNO SHA512 DRNG,
|
||||
.IP \(bu
|
||||
PRNO TRNG Query Ratio,
|
||||
.IP \(bu
|
||||
PRNO TRNG,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Verify P256,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Verify P384,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Verify P521,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Sign P256,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Sign P384,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Sign P521,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Sign P256 protected key,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Sign P384 protected key,
|
||||
.IP \(bu
|
||||
KDSA ECDSA Sign P521 protected key,
|
||||
.IP \(bu
|
||||
KDSA EdDSA Verify Ed25519,
|
||||
.IP \(bu
|
||||
KDSA EdDSA Verify Ed448,
|
||||
.IP \(bu
|
||||
KDSA EdDSA Sign Ed25519,
|
||||
.IP \(bu
|
||||
KDSA EdDSA Sign Ed448,
|
||||
.IP \(bu
|
||||
KDSA EdDSA Sign Ed25519 protected key,
|
||||
.IP \(bu
|
||||
KDSA EdDSA Sign Ed448 protected key,
|
||||
.IP \(bu
|
||||
PCKMO DES,
|
||||
.IP \(bu
|
||||
PCKMO 2key TDES,
|
||||
.IP \(bu
|
||||
PCMKO TDES,
|
||||
.IP \(bu
|
||||
PCKMO AES 128bit,
|
||||
.IP \(bu
|
||||
PCKMO AES 192bit,
|
||||
.IP \(bu
|
||||
PCMKO AES 256bit,
|
||||
.IP \(bu
|
||||
PCKMO ECC P256,
|
||||
.IP \(bu
|
||||
PCKMO ECC P384,
|
||||
.IP \(bu
|
||||
PCKMO ECC P521,
|
||||
.IP \(bu
|
||||
PCKMO ECC Ed25519,
|
||||
.IP \(bu
|
||||
PCKMO ECC Ed448,
|
||||
.IP \(bu
|
||||
Reserved 1, and
|
||||
.IP \(bu
|
||||
Reserved 2.
|
||||
.RE
|
||||
Note that the counters starting with PCKMO and Reserved are only
|
||||
available in the pai_kernel set. Also note that the counters are
|
||||
designed to count successful operations. In the case of KMA this
|
||||
means only complete GCM operations including final hashing are
|
||||
counted.
|
||||
|
||||
Note: CPU-MF based CPACF performance counters are available on LPARs
|
||||
only. PAI counters are available on all hypervisors. For security
|
||||
reasons only members of the group \fIcpacfstats\fR are allowed to run
|
||||
the cpacfstats client application.
|
||||
|
||||
Example usage scenario:
|
||||
.P
|
||||
@@ -101,12 +438,34 @@ argument can be one of: \fBdes\fR, \fBaes\fR, \fBsha\fR, \fBprng\fR,
|
||||
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
||||
performance counters are reset to 0.
|
||||
.TP
|
||||
\fB\-p\fR or \fB\-\-print\fR [counter]
|
||||
\fB\-p\fR or \fB\-\-print\fR [\fB\-n\fR or \fB\-\-nonzero\fR] [counter]
|
||||
Display the value of one or all CPACF performance counters. The
|
||||
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
|
||||
\fBsha\fR, \fBprng\fR, \fBecc\fR, or \fBall\fR. If the counter
|
||||
argument is omitted or if there is no argument, all performance
|
||||
counters are displayed.
|
||||
\fBsha\fR, \fBprng\fR, \fBecc\fR, \fBpai_user\fR, \fBpai_kernel\fR, or
|
||||
\fBall\fR. If the counter argument is omitted or if there is no
|
||||
argument, all performance counters are displayed. If the optional
|
||||
\fB\-n\fR or \fB\-\-nonzero\fR argument is given, then only PAI
|
||||
counters that have a non-zero value are printed.
|
||||
.TP
|
||||
\fB\-j\fR or \fB\-\-json\fR
|
||||
Display all activated counters in JSON format. The JSON contains an
|
||||
array of counter objects. Each object contains the property
|
||||
.B counter
|
||||
specifying either a CPU-MF counter of one of the detailed PAI counter.
|
||||
Additional properties include
|
||||
.B error
|
||||
an error number if the counter could not be read,
|
||||
.B value
|
||||
the counter value if the counter could be read,
|
||||
.B space
|
||||
for PAI counters to specify
|
||||
.B user
|
||||
or
|
||||
.B kernel
|
||||
space counter set, and
|
||||
.B counterid
|
||||
for PAI counters to specify the PAI counter number as specified in the
|
||||
Principles of Operation.
|
||||
.TP
|
||||
The default command is --print all.
|
||||
.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* cpacfstats client implementation
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2020
|
||||
* Copyright IBM Corp. 2015, 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.
|
||||
@@ -39,17 +39,187 @@ static const char *const usage =
|
||||
"\t-d, --disable [counter] Disable one or all counters\n"
|
||||
"\t-r, --reset [counter] Reset one or all counter values\n"
|
||||
"\t-p, --print [counter] Print one or all counter values\n"
|
||||
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc' or 'all'\n";
|
||||
"\t-n, --nonzero Print all PAI counters\n"
|
||||
"\t-j, --json Print all counter values in JSON format\n"
|
||||
"\tcounter can be: 'aes' 'des' 'rng' 'sha' 'ecc'\n"
|
||||
"\t 'pai_user' 'pai_kernel' or 'all'\n";
|
||||
|
||||
static const char *const counter_str[] = {
|
||||
[DES_FUNCTIONS] = "des",
|
||||
[AES_FUNCTIONS] = "aes",
|
||||
[SHA_FUNCTIONS] = "sha",
|
||||
[PRNG_FUNCTIONS] = "rng",
|
||||
[ECC_FUNCTIONS] = "ecc",
|
||||
[ALL_COUNTER] = "all"
|
||||
[ECC_FUNCTIONS] = "ecc",
|
||||
[ALL_COUNTER] = "all",
|
||||
[PAI_USER] = "pai_user",
|
||||
[PAI_KERNEL] = "pai_kernel"
|
||||
};
|
||||
|
||||
/* Strings for the pai counter details. Note that this is 0-based
|
||||
* while PoP is 1-based.
|
||||
*/
|
||||
static const char *const pai_str[] = {
|
||||
[ 0] = "KM DES",
|
||||
[ 1] = "KM 2key TDES",
|
||||
[ 2] = "KM TDES",
|
||||
[ 3] = "KM DES protected key",
|
||||
[ 4] = "KM 2key TDES protected key",
|
||||
[ 5] = "KM TDES protected key",
|
||||
[ 6] = "KM AES 128bit",
|
||||
[ 7] = "KM AES 192bit",
|
||||
[ 8] = "KM AES 256bit",
|
||||
[ 9] = "KM AES 128bit protected key",
|
||||
[ 10] = "KM AES 192bit protected key",
|
||||
[ 11] = "KM AES 256bit protected key",
|
||||
[ 12] = "KM AES-XTS 128bit",
|
||||
[ 13] = "KM AES-XTS 256bit",
|
||||
[ 14] = "KM AES-XTS 128bit protected key",
|
||||
[ 15] = "KM AES-XTS 256bit protected key",
|
||||
[ 16] = "KMC DES",
|
||||
[ 17] = "KMC 2key TDES",
|
||||
[ 18] = "KMC TDES",
|
||||
[ 19] = "KMC DES protected key",
|
||||
[ 20] = "KMC 2key TDES protected key",
|
||||
[ 21] = "KMC TDES protected key",
|
||||
[ 22] = "KMC AES 128bit",
|
||||
[ 23] = "KMC AES 192bit",
|
||||
[ 24] = "KMC AES 256bit",
|
||||
[ 25] = "KMC AES 128bit protected key",
|
||||
[ 26] = "KMC AES 192bit protected key",
|
||||
[ 27] = "KMC AES 256bit protected key",
|
||||
[ 28] = "KMC PRNG",
|
||||
[ 29] = "KMA AES 128bit",
|
||||
[ 30] = "KMA AES 192bit",
|
||||
[ 31] = "KMA AES 256bit",
|
||||
[ 32] = "KMA AES 128bit protected key",
|
||||
[ 33] = "KMA AES 192bit protected key",
|
||||
[ 34] = "KMA AES 256bit protected key",
|
||||
[ 35] = "KMF DES",
|
||||
[ 36] = "KMF 2key TDES",
|
||||
[ 37] = "KMF TDES",
|
||||
[ 38] = "KMF DES protected key",
|
||||
[ 39] = "KMF 2key TDES protected key",
|
||||
[ 40] = "KMF TDES protected key",
|
||||
[ 41] = "KMF AES 128bit",
|
||||
[ 42] = "KMF AES 192bit",
|
||||
[ 43] = "KMF AES 256bit",
|
||||
[ 44] = "KMF AES 128bit protected key",
|
||||
[ 45] = "KMF AES 192bit protected key",
|
||||
[ 46] = "KMF AES 256bit protected key",
|
||||
[ 47] = "KMCTR DES",
|
||||
[ 48] = "KMCTR 2key TDES",
|
||||
[ 49] = "KMCTR TDES",
|
||||
[ 50] = "KMCTR DES protected key",
|
||||
[ 51] = "KMCTR 2key TDES protected key",
|
||||
[ 52] = "KMCTR TDES protected key",
|
||||
[ 53] = "KMCTR AES 128bit",
|
||||
[ 54] = "KMCTR AES 192bit",
|
||||
[ 55] = "KMCTR AES 256bit",
|
||||
[ 56] = "KMCTR AES 128bit protected key",
|
||||
[ 57] = "KMCTR AES 192bit protected key",
|
||||
[ 58] = "KMCTR AES 256bit protected key",
|
||||
[ 59] = "KMO DES",
|
||||
[ 60] = "KMO 2key TDES",
|
||||
[ 61] = "KMO TDES",
|
||||
[ 62] = "KMO DES protected key",
|
||||
[ 63] = "KMO 2key TDES protected key",
|
||||
[ 64] = "KMO TDES protected key",
|
||||
[ 65] = "KMO AES 128bit",
|
||||
[ 66] = "KMO AES 192bit",
|
||||
[ 67] = "KMO AES 256bit",
|
||||
[ 68] = "KMO AES 128bit protected key",
|
||||
[ 69] = "KMO AES 192bit protected key",
|
||||
[ 70] = "KMO AES 256bit protected key",
|
||||
[ 71] = "KIMD SHA1",
|
||||
[ 72] = "KIMD SHA256",
|
||||
[ 73] = "KIMD SHA512",
|
||||
[ 74] = "KIMD SHA3-224",
|
||||
[ 75] = "KIMD SHA3-256",
|
||||
[ 76] = "KIMD SHA3-384",
|
||||
[ 77] = "KIMD SHA3-512",
|
||||
[ 78] = "KIMD SHAKE 128",
|
||||
[ 79] = "KIMD SHAKE 256",
|
||||
[ 80] = "KIMD GHASH",
|
||||
[ 81] = "KLMD SHA1",
|
||||
[ 82] = "KLMD SHA256",
|
||||
[ 83] = "KLMD SHA512",
|
||||
[ 84] = "KLMD SHA3-224",
|
||||
[ 85] = "KLMD SHA3-256",
|
||||
[ 86] = "KLMD SHA3-384",
|
||||
[ 87] = "KLMD SHA3-512",
|
||||
[ 88] = "KLMD SHAKE 128",
|
||||
[ 89] = "KLMD SHAKE 256",
|
||||
[ 90] = "KMAC DES",
|
||||
[ 91] = "KMAC 2key TDES",
|
||||
[ 92] = "KMAC TDES",
|
||||
[ 93] = "KMAC DES protected key",
|
||||
[ 94] = "KMAC 2key TDES protected key",
|
||||
[ 95] = "KMAC TDES protected key",
|
||||
[ 96] = "KMAC AES 128bit",
|
||||
[ 97] = "KMAC AES 192bit",
|
||||
[ 98] = "KMAC AES 256bit",
|
||||
[ 99] = "KMAC AES 128bit protected key",
|
||||
[100] = "KMAC AES 192bit protected key",
|
||||
[101] = "KMAC AES 256bit protected key",
|
||||
[102] = "PCC Last Block CMAC DES",
|
||||
[103] = "PCC Last Block CMAC 2key TDES",
|
||||
[104] = "PCC Last Block CMAC TDES",
|
||||
[105] = "PCC Last Block CMAC DES protected key",
|
||||
[106] = "PCC Last Block CMAC 2key TDES protected key",
|
||||
[107] = "PCC Last Block CMAC TDES protected key",
|
||||
[108] = "PCC Last Block CMAC AES 128bit",
|
||||
[109] = "PCC Last Block CMAC AES 192bit",
|
||||
[110] = "PCC Last Block CMAC AES 256bit",
|
||||
[111] = "PCC Last Block CMAC AES 128bit protected key",
|
||||
[112] = "PCC Last Block CMAC AES 192bit protected key",
|
||||
[113] = "PCC Last Block CMAC AES 256bit protected key",
|
||||
[114] = "PCC XTS Parameter AES 128bit",
|
||||
[115] = "PCC XTS Parameter AES 256bit",
|
||||
[116] = "PCC XTS Parameter AES 128bit protected key",
|
||||
[117] = "PCC XTS Parameter AES 256bit protected key",
|
||||
[118] = "PCC Scalar Mult P256",
|
||||
[119] = "PCC Scalar Mult P384",
|
||||
[120] = "PCC Scalar Mult P521",
|
||||
[121] = "PCC Scalar Mult Ed25519",
|
||||
[122] = "PCC Scalar Mult Ed448",
|
||||
[123] = "PCC Scalar Mult X25519",
|
||||
[124] = "PCC Scalar Mult X448",
|
||||
[125] = "PRNO SHA512 DRNG",
|
||||
[126] = "PRNO TRNG Query Ratio",
|
||||
[127] = "PRNO TRNG",
|
||||
[128] = "KDSA ECDSA Verify P256",
|
||||
[129] = "KDSA ECDSA Verify P384",
|
||||
[130] = "KDSA ECDSA Verify P521",
|
||||
[131] = "KDSA ECDSA Sign P256",
|
||||
[132] = "KDSA ECDSA Sign P384",
|
||||
[133] = "KDSA ECDSA Sign P521",
|
||||
[134] = "KDSA ECDSA Sign P256 protected key",
|
||||
[135] = "KDSA ECDSA Sign P384 protected key",
|
||||
[136] = "KDSA ECDSA Sign P521 protected key",
|
||||
[137] = "KDSA EdDSA Verify Ed25519",
|
||||
[138] = "KDSA EdDSA Verify Ed448",
|
||||
[139] = "KDSA EdDSA Sign Ed25519",
|
||||
[140] = "KDSA EdDSA Sign Ed448",
|
||||
[141] = "KDSA EdDSA Sign Ed25519 protected key",
|
||||
[142] = "KDSA EdDSA Sign Ed448 protected key",
|
||||
[143] = "PCKMO DES",
|
||||
[144] = "PCKMO 2key TDES",
|
||||
[145] = "PCMKO TDES",
|
||||
[146] = "PCKMO AES 128bit",
|
||||
[147] = "PCKMO AES 192bit",
|
||||
[148] = "PCMKO AES 256bit",
|
||||
[149] = "PCKMO ECC P256",
|
||||
[150] = "PCKMO ECC P384",
|
||||
[151] = "PCKMO ECC P521",
|
||||
[152] = "PCKMO ECC Ed25519",
|
||||
[153] = "PCKMO ECC Ed448",
|
||||
[154] = "Reserved 1",
|
||||
[155] = "Reserved 2"
|
||||
};
|
||||
|
||||
|
||||
static int paiprintnonzero;
|
||||
|
||||
|
||||
static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
|
||||
{
|
||||
@@ -62,7 +232,7 @@ static int send_query(int s, enum cmd_e cmd, enum ctr_e ctr)
|
||||
m.query.m_ctr = ctr;
|
||||
m.query.m_cmd = cmd;
|
||||
|
||||
return send_msg(s, &m);
|
||||
return send_msg(s, &m, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -71,7 +241,7 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
|
||||
struct msg m;
|
||||
int rc;
|
||||
|
||||
rc = recv_msg(s, &m);
|
||||
rc = recv_msg(s, &m, 0);
|
||||
if (rc == 0) {
|
||||
if (m.head.m_ver != VERSION) {
|
||||
eprint("Received msg with wrong version %d != %d\n",
|
||||
@@ -92,9 +262,139 @@ static int recv_answer(int s, int *ctr, int *state, uint64_t *value)
|
||||
}
|
||||
|
||||
|
||||
static void print_answer(int ctr, int state, uint64_t value)
|
||||
static void printjsonsep(void)
|
||||
{
|
||||
if (state < 0)
|
||||
static const char *jsonsep = "";
|
||||
|
||||
fputs(jsonsep, stdout);
|
||||
jsonsep = ",";
|
||||
}
|
||||
|
||||
|
||||
static void json_print_virtual_counter_answer(int s, int ctr,
|
||||
int state, uint64_t value)
|
||||
{
|
||||
int paictr = 0, paistate = 0, ec;
|
||||
uint64_t i, paivalue = 0, maxnum;
|
||||
const char *space;
|
||||
|
||||
switch (ctr) {
|
||||
case HOTPLUG_DETECTED:
|
||||
printjsonsep();
|
||||
printf("{\"counter\":\"hotplug detected\",");
|
||||
if (state < 0)
|
||||
printf("\"error\":%d}", state);
|
||||
else
|
||||
printf("\"value\":%d}", !!value);
|
||||
return;
|
||||
case PAI_USER:
|
||||
maxnum = NUM_PAI_USER;
|
||||
space = "user";
|
||||
break;
|
||||
case PAI_KERNEL:
|
||||
maxnum = NUM_PAI_KERNEL;
|
||||
space = "kernel";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
/* Here, we have validated the PAI counter retrieved, but not
|
||||
* yet printed. */
|
||||
if (state != ENABLED)
|
||||
return;
|
||||
if (value > maxnum) {
|
||||
eprint("Incompatible versions detected!\n");
|
||||
eprint("Expected %"PRIu64" counter space for %s, but got %"PRIu64"\n",
|
||||
maxnum, space, value);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (i = 0; i < value; ++i) {
|
||||
ec = recv_answer(s, &paictr, &paistate, &paivalue);
|
||||
if (ec < 0 || paistate < 0) {
|
||||
eprint("Error on receiving answer message from daemon\n");
|
||||
/* No more data for this virtual event after error. */
|
||||
return;
|
||||
}
|
||||
if (paictr > NUM_PAI_KERNEL) {
|
||||
eprint("Pai counter number too big: %d\n", paictr);
|
||||
} else {
|
||||
printjsonsep();
|
||||
printf("{\"counter\":\"%s\",\"space\":\"%s\",\"counterid\":%d,",
|
||||
pai_str[paictr], space, paictr + 1);
|
||||
if (paistate < 0) {
|
||||
printf("\"error\":%d}", paistate);
|
||||
/* Protocol does not send furter counters. */
|
||||
return;
|
||||
}
|
||||
printf("\"value\":%"PRIu64"}", paivalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void print_virtual_counter_answer(int s,
|
||||
int ctr, int state, uint64_t value)
|
||||
{
|
||||
static const char *const states[] = {
|
||||
[DISABLED] = "disabled",
|
||||
[ENABLED] = "enabled",
|
||||
[UNSUPPORTED] = "unsupported"
|
||||
};
|
||||
int paictr = 0, paistate = 0, ec;
|
||||
uint64_t i, paivalue = 0, maxnum;
|
||||
const char *ctrstr;
|
||||
|
||||
switch (ctr) {
|
||||
case HOTPLUG_DETECTED:
|
||||
if (state >= 0 && value > 0)
|
||||
printf(" hotplug detected\n");
|
||||
return;
|
||||
case PAI_USER:
|
||||
maxnum = NUM_PAI_USER;
|
||||
ctrstr = "pai_user";
|
||||
break;
|
||||
case PAI_KERNEL:
|
||||
maxnum = NUM_PAI_KERNEL;
|
||||
ctrstr = "pai_kernel";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
/* Here, we have validated the PAI counter retrieved, but not
|
||||
* yet printed. */
|
||||
if (state < 0 || state > UNSUPPORTED) {
|
||||
printf(" %11s: error state %d\n", ctrstr, state);
|
||||
/* No details follow if counter in error state. */
|
||||
return;
|
||||
}
|
||||
printf(" %-11s: %s\n", ctrstr, states[state]);
|
||||
if (state != ENABLED)
|
||||
return;
|
||||
if (value > maxnum) {
|
||||
eprint("Incompatible versions detected!\n");
|
||||
eprint("Expected %"PRIu64" counters for %s, but got %"PRIu64"\n",
|
||||
maxnum, ctrstr, value);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
for (i = 0; i < value; ++i) {
|
||||
ec = recv_answer(s, &paictr, &paistate, &paivalue);
|
||||
if (ec < 0 || paistate < 0) {
|
||||
eprint("Error on receiving answer message from daemon\n");
|
||||
/* No more data for this virtual event after error. */
|
||||
return;
|
||||
}
|
||||
if (paictr > NUM_PAI_KERNEL)
|
||||
eprint("Pai counter number too big: %d\n", paictr);
|
||||
else if (!paiprintnonzero || paivalue > 0)
|
||||
printf(" %-45s: %"PRIu64"\n", pai_str[paictr], paivalue);
|
||||
}
|
||||
}
|
||||
|
||||
static void print_answer(int s, int ctr, int state, uint64_t value)
|
||||
{
|
||||
if (ctr > ALL_COUNTER)
|
||||
print_virtual_counter_answer(s, ctr, state, value);
|
||||
else if (state < 0)
|
||||
printf(" %s counter: error state %d\n",
|
||||
counter_str[ctr], state);
|
||||
else if (state == DISABLED)
|
||||
@@ -106,6 +406,22 @@ static void print_answer(int ctr, int state, uint64_t value)
|
||||
}
|
||||
|
||||
|
||||
static void json_print_answer(int s, int ctr, int state, uint64_t value)
|
||||
{
|
||||
if (ctr > ALL_COUNTER) {
|
||||
json_print_virtual_counter_answer(s, ctr, state, value);
|
||||
} else if (state < 0) {
|
||||
printjsonsep();
|
||||
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
||||
printf("\"error\":%d}\n", state);
|
||||
} else if (state == ENABLED) {
|
||||
printjsonsep();
|
||||
printf("{\"counter\":\"%s\",", counter_str[ctr]);
|
||||
printf("\"value\":%"PRIu64"}", value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int eprint(const char *format, ...)
|
||||
{
|
||||
char buf[1024];
|
||||
@@ -128,7 +444,7 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
enum ctr_e ctr = ALL_COUNTER;
|
||||
enum cmd_e cmd = PRINT;
|
||||
int i, j, s, state;
|
||||
int i, j, s, state, num, json = 0;
|
||||
uint64_t value;
|
||||
|
||||
if (argc > 1) {
|
||||
@@ -140,98 +456,108 @@ int main(int argc, char *argv[])
|
||||
{ "disable", 0, NULL, 'd' },
|
||||
{ "reset", 0, NULL, 'r' },
|
||||
{ "print", 0, NULL, 'p' },
|
||||
{ "nonzero", 0, NULL, 'n' },
|
||||
{ "json", 0, NULL, 'j' },
|
||||
{ NULL, 0, NULL, 0 } };
|
||||
while (1) {
|
||||
opt = getopt_long(argc, argv,
|
||||
"hvedrp", long_opts, &idx);
|
||||
"hvedrpnj", long_opts, &idx);
|
||||
if (opt == -1)
|
||||
break; /* no more arguments */
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
printf(usage, name);
|
||||
exit(0);
|
||||
break;
|
||||
return 0;
|
||||
case 'v':
|
||||
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
|
||||
"Version %s\n%s\n",
|
||||
name, RELEASE_STRING, COPYRIGHT);
|
||||
exit(0);
|
||||
break;
|
||||
return 0;
|
||||
case 'e':
|
||||
cmd = ENABLE;
|
||||
json = 0;
|
||||
break;
|
||||
case 'd':
|
||||
cmd = DISABLE;
|
||||
json = 0;
|
||||
break;
|
||||
case 'r':
|
||||
cmd = RESET;
|
||||
break;
|
||||
case 'p':
|
||||
cmd = PRINT;
|
||||
json = 0;
|
||||
break;
|
||||
case 'n':
|
||||
paiprintnonzero = 1;
|
||||
break;
|
||||
case 'j':
|
||||
cmd = PRINT;
|
||||
json = 1;
|
||||
break;
|
||||
default:
|
||||
eprint("Invalid argument, try -h or --help for more information\n");
|
||||
exit(1);
|
||||
break;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
/* there may be an optional counter argument */
|
||||
if (optind > 0 && optind < argc) {
|
||||
for (i = 0; i <= ALL_COUNTER; i++)
|
||||
for (i = 0; i < NUM_COUNTER; i++)
|
||||
if (strcmp(argv[optind], counter_str[i]) == 0)
|
||||
break;
|
||||
if (i > ALL_COUNTER) {
|
||||
if (i >= NUM_COUNTER) {
|
||||
eprint("Unknown counter '%s'\n", argv[optind]);
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ctr = (enum ctr_e) i;
|
||||
}
|
||||
}
|
||||
if (json)
|
||||
ctr = ALL_COUNTER;
|
||||
|
||||
/* try to open and connect socket to the cpacfstatsd daemon */
|
||||
s = open_socket(CLIENT);
|
||||
if (s < 0) {
|
||||
eprint("Can't connect to daemon\n");
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* send query */
|
||||
if (send_query(s, cmd, ctr) != 0) {
|
||||
eprint("Error on sending query message to daemon\n");
|
||||
close(s);
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
/* receive answer */
|
||||
if (recv_answer(s, &j, &state, &value) != 0) {
|
||||
eprint("Error on receiving answer message from daemon\n");
|
||||
exit(1);
|
||||
}
|
||||
if (state < 0) {
|
||||
eprint("Received bad status code %d from daemon\n",
|
||||
state);
|
||||
close(s);
|
||||
exit(1);
|
||||
}
|
||||
print_answer(j, state, value);
|
||||
}
|
||||
/* The -1 is for ALL_COUNTER which is not sent, +1 for
|
||||
* hotplug state. */
|
||||
num = NUM_COUNTER - 1 + 1;
|
||||
} else {
|
||||
/* +1 for hotplug state */
|
||||
num = 1 + 1;
|
||||
}
|
||||
if (json)
|
||||
putchar('[');
|
||||
for (i = 0; i < num; i++) {
|
||||
/* receive answer */
|
||||
if (recv_answer(s, &j, &state, &value) != 0) {
|
||||
eprint("Error on receiving answer message from daemon\n");
|
||||
close(s);
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (state < 0) {
|
||||
eprint("Received bad status code %d from daemon\n",
|
||||
state);
|
||||
state);
|
||||
close(s);
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
print_answer(j, state, value);
|
||||
if (json)
|
||||
json_print_answer(s, j, state, value);
|
||||
else
|
||||
print_answer(s, j, state, value);
|
||||
}
|
||||
if (json)
|
||||
putchar(']');
|
||||
|
||||
/* close connection */
|
||||
close(s);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* common function prototypes and definitions
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2020
|
||||
* Copyright IBM Corp. 2015, 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.
|
||||
@@ -14,13 +14,27 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define COPYRIGHT "Copyright IBM Corp. 2015, 2020"
|
||||
#define COPYRIGHT "Copyright IBM Corp. 2015, 2022"
|
||||
|
||||
#define DEFAULT_SEND_TIMEOUT (30 * 1000)
|
||||
#define DEFAULT_RECV_TIMEOUT (30 * 1000)
|
||||
|
||||
/*
|
||||
* Number of PAI counters for user space. This excludes PCKMO since
|
||||
* this instruction is privileged.
|
||||
*/
|
||||
#define NUM_PAI_USER 143
|
||||
/* Number of PAI counters for kernel space. Contains all counters. */
|
||||
#define NUM_PAI_KERNEL 156
|
||||
|
||||
int eprint(const char *format, ...);
|
||||
|
||||
/*
|
||||
* Counter names
|
||||
* ALL_COUNTER must always be the last member of the enum
|
||||
* ALL_COUNTER specifies the number of physical counters. Virtual
|
||||
* counters might be added afterwards. NUM_COUNTER is the last
|
||||
* managed counter (i.e., a counter that can be activated, reset,
|
||||
* deactivated).
|
||||
*/
|
||||
enum ctr_e {
|
||||
DES_FUNCTIONS = 0,
|
||||
@@ -28,7 +42,11 @@ enum ctr_e {
|
||||
SHA_FUNCTIONS,
|
||||
PRNG_FUNCTIONS,
|
||||
ECC_FUNCTIONS,
|
||||
ALL_COUNTER
|
||||
ALL_COUNTER,
|
||||
PAI_USER,
|
||||
PAI_KERNEL,
|
||||
NUM_COUNTER,
|
||||
HOTPLUG_DETECTED = 0xffff
|
||||
};
|
||||
|
||||
enum type_e {
|
||||
@@ -50,7 +68,7 @@ enum state_e {
|
||||
};
|
||||
|
||||
/*
|
||||
* query send from clent to daemon
|
||||
* query send from client to daemon
|
||||
* Consist of:
|
||||
* enum counter
|
||||
* enum command
|
||||
@@ -63,7 +81,7 @@ struct msg_query {
|
||||
/*
|
||||
* answer send from daemon to client
|
||||
* Consist of:
|
||||
* enum counter
|
||||
* enum counter or PAI counter number if following PAI_USER or PAI_KERNEL
|
||||
* status code: < 0 error, 0 disabled, > 0 enabled
|
||||
* counter value
|
||||
*/
|
||||
@@ -99,17 +117,20 @@ struct msg {
|
||||
} __packed;
|
||||
|
||||
int open_socket(int mode);
|
||||
int send_msg(int sfd, struct msg *m);
|
||||
int recv_msg(int sfd, struct msg *m);
|
||||
int send_msg(int sfd, struct msg *m, int timeout);
|
||||
int recv_msg(int sfd, struct msg *m, int timeout);
|
||||
|
||||
/* perf_crypto.c */
|
||||
|
||||
int perf_init(void);
|
||||
void perf_stop(void);
|
||||
void perf_close(void);
|
||||
int perf_enable_ctr(enum ctr_e ctr);
|
||||
int perf_disable_ctr(enum ctr_e ctr);
|
||||
int perf_reset_ctr(enum ctr_e ctr);
|
||||
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value);
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value);
|
||||
int perf_ecc_supported(void);
|
||||
int perf_ctr_state(enum ctr_e ctr);
|
||||
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* cpacfstatsd daemon implementation
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2017
|
||||
* Copyright IBM Corp. 2015, 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.
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "lib/zt_common.h"
|
||||
#include "cpacfstats.h"
|
||||
|
||||
static volatile int stopsig;
|
||||
|
||||
static const char *const name = "cpacfstatsd";
|
||||
|
||||
@@ -43,15 +44,12 @@ static const char *const usage =
|
||||
|
||||
static int daemonized;
|
||||
|
||||
static int ctr_state[ALL_COUNTER];
|
||||
|
||||
|
||||
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
||||
{
|
||||
struct msg m;
|
||||
int rc;
|
||||
|
||||
rc = recv_msg(s, &m);
|
||||
rc = recv_msg(s, &m, DEFAULT_RECV_TIMEOUT);
|
||||
if (rc == 0) {
|
||||
if (m.head.m_ver != VERSION) {
|
||||
eprint("Received msg with wrong version %d != %d\n",
|
||||
@@ -83,38 +81,82 @@ static int send_answer(int s, int ctr, int state, uint64_t value)
|
||||
m.answer.m_state = state;
|
||||
m.answer.m_value = value;
|
||||
|
||||
return send_msg(s, &m);
|
||||
return send_msg(s, &m, DEFAULT_SEND_TIMEOUT);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print according to protocol for PAI:
|
||||
* - first the state and the number of PAI counters that follow
|
||||
* - if state is ENABLED:
|
||||
* - for each PAI counter the value with state ENABLED
|
||||
* Note that the PAI counters are 0-based, not 1 based as in PoP!
|
||||
* Sending ends with the first error.
|
||||
*/
|
||||
static int do_send_pai(int s, int user)
|
||||
{
|
||||
int ctr, state, i, maxctr, rc = 0;
|
||||
uint64_t value;
|
||||
|
||||
if (user) {
|
||||
ctr = PAI_USER;
|
||||
maxctr = NUM_PAI_USER;
|
||||
} else {
|
||||
ctr = PAI_KERNEL;
|
||||
maxctr = NUM_PAI_KERNEL;
|
||||
}
|
||||
state = perf_ctr_state(ctr);
|
||||
if (state != ENABLED)
|
||||
return rc;
|
||||
for (i = 0; i < maxctr; ++i) {
|
||||
rc = perf_read_pai_ctr(i, user, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_enable(int s, enum ctr_e ctr)
|
||||
{
|
||||
uint64_t value;
|
||||
uint64_t value = 0;
|
||||
int i, rc = 0;
|
||||
int state;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
for (i = 0; i < NUM_COUNTER; i++) {
|
||||
if (i == ALL_COUNTER)
|
||||
continue;
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i] == DISABLED) {
|
||||
state = perf_ctr_state(i);
|
||||
if (state == DISABLED) {
|
||||
rc = perf_enable_ctr(i);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
ctr_state[i] = ENABLED;
|
||||
state = ENABLED;
|
||||
}
|
||||
if (ctr_state[i] == UNSUPPORTED) {
|
||||
send_answer(s, i, UNSUPPORTED, 0);
|
||||
} else {
|
||||
if (state != UNSUPPORTED) {
|
||||
rc = perf_read_ctr(i, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
send_answer(s, i, ENABLED, value);
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
if (i == PAI_USER)
|
||||
rc = do_send_pai(s, 1);
|
||||
if (i == PAI_KERNEL)
|
||||
rc = do_send_pai(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -122,67 +164,90 @@ static int do_enable(int s, enum ctr_e ctr)
|
||||
static int do_disable(int s, enum ctr_e ctr)
|
||||
{
|
||||
int i, rc = 0;
|
||||
uint64_t value;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
for (i = 0; i < NUM_COUNTER; i++) {
|
||||
if (i == ALL_COUNTER)
|
||||
continue;
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i] == ENABLED) {
|
||||
if (perf_ctr_state(i) == ENABLED) {
|
||||
rc = perf_disable_ctr(i);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
ctr_state[i] = 0;
|
||||
}
|
||||
send_answer(s, i, ctr_state[i], 0);
|
||||
send_answer(s, i, perf_ctr_state(i), 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_reset(int s, enum ctr_e ctr)
|
||||
{
|
||||
int i, rc = 0;
|
||||
int i, rc = 0, state;
|
||||
uint64_t value;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
for (i = 0; i < NUM_COUNTER; i++) {
|
||||
if (i == ALL_COUNTER)
|
||||
continue;
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i] == ENABLED) {
|
||||
rc = perf_reset_ctr(i);
|
||||
state = perf_ctr_state(i);
|
||||
if (state == ENABLED) {
|
||||
rc = perf_reset_ctr(i, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
send_answer(s, i, ENABLED, 0);
|
||||
} else {
|
||||
send_answer(s, i, ctr_state[i], 0);
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
if (i == PAI_USER)
|
||||
rc = do_send_pai(s, 1);
|
||||
if (i == PAI_KERNEL)
|
||||
rc = do_send_pai(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int do_print(int s, enum ctr_e ctr)
|
||||
{
|
||||
int i, rc = 0;
|
||||
uint64_t value;
|
||||
int i, rc = 0, state;
|
||||
uint64_t value = 0;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; i++) {
|
||||
for (i = 0; i < NUM_COUNTER; i++) {
|
||||
if (i == ALL_COUNTER)
|
||||
continue;
|
||||
if (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||
if (ctr_state[i] == ENABLED) {
|
||||
state = perf_ctr_state(i);
|
||||
if (state == ENABLED) {
|
||||
rc = perf_read_ctr(i, &value);
|
||||
if (rc != 0) {
|
||||
send_answer(s, i, rc, 0);
|
||||
break;
|
||||
}
|
||||
send_answer(s, i, ENABLED, value);
|
||||
} else {
|
||||
send_answer(s, i, ctr_state[i], 0);
|
||||
}
|
||||
send_answer(s, i, state, value);
|
||||
if (i == PAI_USER)
|
||||
rc = do_send_pai(s, 1);
|
||||
if (i == PAI_KERNEL)
|
||||
rc = do_send_pai(s, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
rc = perf_read_ctr(HOTPLUG_DETECTED, &value);
|
||||
send_answer(s, HOTPLUG_DETECTED, rc, value);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -324,18 +389,8 @@ static void remove_pidfile(void)
|
||||
|
||||
void signalhandler(int sig)
|
||||
{
|
||||
if (sig == SIGTERM)
|
||||
eprint("Caught signal SIGTERM, terminating...\n");
|
||||
else if (sig == SIGINT)
|
||||
eprint("Caught signal SIGINT, terminating...\n");
|
||||
else
|
||||
eprint("Caught signal %d, terminating...\n", sig);
|
||||
|
||||
remove_sock();
|
||||
perf_close();
|
||||
remove_pidfile();
|
||||
|
||||
exit(0);
|
||||
perf_stop();
|
||||
stopsig = sig;
|
||||
}
|
||||
|
||||
|
||||
@@ -381,7 +436,7 @@ int main(int argc, char *argv[])
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
printf(usage, name);
|
||||
exit(0);
|
||||
return 0;
|
||||
case 'f':
|
||||
foreground = 1;
|
||||
break;
|
||||
@@ -389,40 +444,37 @@ int main(int argc, char *argv[])
|
||||
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
|
||||
"Version %s\n%s\n",
|
||||
name, RELEASE_STRING, COPYRIGHT);
|
||||
exit(0);
|
||||
return 0;
|
||||
default:
|
||||
printf("%s: Invalid argument, try -h or --help for more information\n",
|
||||
name);
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (check_pidfile() != 0) {
|
||||
eprint("Stalled pid file or daemon allready running, terminating\n");
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!foreground) {
|
||||
if (become_daemon() != 0) {
|
||||
eprint("Couldn't daemonize\n");
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (perf_init() != 0) {
|
||||
eprint("Couldn't initialize perf lib\n");
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
atexit(perf_close);
|
||||
|
||||
if (!perf_ecc_supported())
|
||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||
|
||||
sfd = open_socket(SERVER);
|
||||
if (sfd < 0) {
|
||||
eprint("Couldn't initialize server socket\n");
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
atexit(remove_sock);
|
||||
|
||||
@@ -432,17 +484,19 @@ int main(int argc, char *argv[])
|
||||
if (sigaction(SIGINT, &act, 0) != 0) {
|
||||
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (sigaction(SIGTERM, &act, 0) != 0) {
|
||||
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* Ignore SIGPIPE such that we see EPIPE as return from write. */
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
eprint("Running\n");
|
||||
|
||||
while (1) {
|
||||
while (!stopsig) {
|
||||
enum ctr_e ctr;
|
||||
enum cmd_e cmd;
|
||||
int s;
|
||||
@@ -453,7 +507,7 @@ int main(int argc, char *argv[])
|
||||
continue;
|
||||
eprint("Accept() failure, errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
exit(1);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
rc = recv_query(s, &ctr, &cmd);
|
||||
@@ -480,5 +534,13 @@ cleanup:
|
||||
close(s);
|
||||
}
|
||||
|
||||
if (stopsig == SIGTERM)
|
||||
eprint("Caught signal SIGTERM, terminating...\n");
|
||||
else if (stopsig == SIGINT)
|
||||
eprint("Caught signal SIGINT, terminating...\n");
|
||||
else
|
||||
eprint("Caught signal %d, terminating...\n", stopsig);
|
||||
remove_pidfile();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* low level perf functions
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2020
|
||||
* Copyright IBM Corp. 2015, 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.
|
||||
@@ -16,14 +16,21 @@
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <linux/perf_event.h>
|
||||
#include <pthread.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#include "cpacfstats.h"
|
||||
#include "../include/lib/zt_common.h"
|
||||
|
||||
/* correlation between counter and perf counter string */
|
||||
static const struct {
|
||||
@@ -38,25 +45,83 @@ static const struct {
|
||||
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
||||
};
|
||||
|
||||
/*
|
||||
* We need one filedescriptor per CPU per counter.
|
||||
* So perf_init builds this:
|
||||
*
|
||||
* ctr_fds - is an array of pointers to file descriptor arrays.
|
||||
* Each file descriptor array has space for number of logical CPUs + 1
|
||||
* filedescriptors (int values). The last element of each file descriptor
|
||||
* array is always 0, assuming there will never appear a filedescriptor
|
||||
* with value 0:
|
||||
*
|
||||
* ctr_fds:
|
||||
* ctr_fds[0] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
|
||||
* ctr_fds[1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
|
||||
* ...
|
||||
* ctr_fds[ALL_COUNTER-1] -> [file descriptor 0] [fd1] ... [fd cpus-1][0]
|
||||
*/
|
||||
static int *ctr_fds[ALL_COUNTER];
|
||||
static struct pmf_data {
|
||||
int pmutype;
|
||||
int eventid;
|
||||
} pmf_counter_data[ALL_COUNTER];
|
||||
|
||||
static int ecc_supported;
|
||||
struct percpucounter {
|
||||
int ctr_fds[ALL_COUNTER];
|
||||
int pai_user[NUM_PAI_USER];
|
||||
int pai_kernel[NUM_PAI_KERNEL];
|
||||
unsigned int cpunum;
|
||||
struct percpucounter *next;
|
||||
};
|
||||
|
||||
static struct percpucounter *root;
|
||||
pthread_mutex_t rootmux = PTHREAD_MUTEX_INITIALIZER;
|
||||
static volatile int hotplugdetected;
|
||||
static unsigned int enabledcounter;
|
||||
pthread_t hotplugthread;
|
||||
|
||||
#define foreachcpu(PCPU) if (pthread_mutex_lock(&rootmux)) return -1; \
|
||||
for ((PCPU) = root; (PCPU) != NULL; (PCPU) = (PCPU)->next)
|
||||
#define endforeachcpu() pthread_mutex_unlock(&rootmux)
|
||||
|
||||
static int ctr_state[NUM_COUNTER];
|
||||
|
||||
static volatile int stoprequested;
|
||||
|
||||
static int paipmutype, paipmueventstart;
|
||||
|
||||
static struct percpucounter *allocpercpucounter(unsigned int cpunum)
|
||||
{
|
||||
struct percpucounter *ppc;
|
||||
|
||||
ppc = malloc(sizeof(struct percpucounter));
|
||||
if (ppc) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
ppc->ctr_fds[i] = -1;
|
||||
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||
ppc->pai_user[i] = -1;
|
||||
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||
ppc->pai_kernel[i] = -1;
|
||||
ppc->cpunum = cpunum;
|
||||
ppc->next = NULL;
|
||||
}
|
||||
return ppc;
|
||||
}
|
||||
|
||||
static void freepercpucounter(struct percpucounter *pcpu)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
(void)close(pcpu->ctr_fds[i]);
|
||||
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||
(void)close(pcpu->pai_user[i]);
|
||||
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||
(void)close(pcpu->pai_kernel[i]);
|
||||
free(pcpu);
|
||||
}
|
||||
|
||||
static struct percpucounter *findcpu(unsigned int cpunum, int unlinkflag)
|
||||
{
|
||||
struct percpucounter **prev = &root, *walk = root;
|
||||
|
||||
while (walk) {
|
||||
if (walk->cpunum == cpunum) {
|
||||
if (unlinkflag)
|
||||
*prev = walk->next;
|
||||
return walk;
|
||||
}
|
||||
prev = &(walk->next);
|
||||
walk = walk->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||
int cpu, int group_fd, unsigned long flags)
|
||||
@@ -85,12 +150,43 @@ static int perf_counter_supported(const char *pmu, const char *counter)
|
||||
return !access(buf, R_OK);
|
||||
}
|
||||
|
||||
static int perf_event_encode(struct perf_event_attr *attr,
|
||||
static int cpumf_authorized(void)
|
||||
{
|
||||
unsigned vermin, vermax, auth;
|
||||
int res = 0, found = 0;
|
||||
size_t linesize = 0;
|
||||
char *line = NULL;
|
||||
FILE *f;
|
||||
|
||||
f = fopen("/proc/service_levels", "r");
|
||||
if (f == NULL) {
|
||||
eprint("Failed to open /proc/service_levels (%d:%s)\n",
|
||||
errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
while (getline(&line, &linesize, f) >= 0) {
|
||||
if (sscanf(line,
|
||||
"CPU-MF: Counter facility: version=%d.%d authorization=%x",
|
||||
&vermin, &vermax, &auth) == 3) {
|
||||
if (auth & 0x8)
|
||||
res = 1;
|
||||
else
|
||||
eprint("CPU-MF counters not authorized.\n");
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
eprint("CPU-MF counters not available.\n");
|
||||
free(line);
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int perf_event_encode(int *pmutype, int *eventid,
|
||||
const char *pmu, const char *event)
|
||||
{
|
||||
FILE *f;
|
||||
int eventid;
|
||||
int pmutype;
|
||||
char buf[PATH_MAX];
|
||||
|
||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
||||
@@ -104,7 +200,7 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
|
||||
if (fscanf(f, "event=0x%x\n", eventid) != 1) {
|
||||
fclose(f);
|
||||
eprint("Event file %s has invalid format\n", buf);
|
||||
return -1;
|
||||
@@ -121,21 +217,257 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fscanf(f, "%d\n", &pmutype) != 1) {
|
||||
if (fscanf(f, "%d\n", pmutype) != 1) {
|
||||
fclose(f);
|
||||
eprint("Type file %s has invalid format\n", buf);
|
||||
return -1;
|
||||
}
|
||||
attr->type = pmutype;
|
||||
attr->config = eventid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int activatecpu(unsigned int cpu)
|
||||
{
|
||||
struct perf_event_attr pfm_event;
|
||||
struct percpucounter *ppc;
|
||||
int fd, i, rc = 0;
|
||||
|
||||
ppc = allocpercpucounter(cpu);
|
||||
if (ppc == NULL) {
|
||||
eprint("Failed to allocate per cpu counter data");
|
||||
return -1;
|
||||
}
|
||||
if (pthread_mutex_lock(&rootmux)) {
|
||||
freepercpucounter(ppc);
|
||||
return -1;
|
||||
}
|
||||
/* activate CPU-MF */
|
||||
for (i = 0; i < ALL_COUNTER; ++i) {
|
||||
if (ctr_state[i] == UNSUPPORTED)
|
||||
continue;
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
pfm_event.type = pmf_counter_data[i].pmutype;
|
||||
pfm_event.config = pmf_counter_data[i].eventid;
|
||||
|
||||
/* fetch file descriptor for this perf event
|
||||
* the counter event should start disabled
|
||||
*/
|
||||
pfm_event.disabled = ctr_state[i] == DISABLED;
|
||||
fd = perf_event_open(
|
||||
&pfm_event,
|
||||
-1, /* pid -1 means all processes */
|
||||
cpu,
|
||||
-1, /* group filedescriptor */
|
||||
0); /* flags */
|
||||
if (fd < 0) {
|
||||
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
ctr_state[i] = UNSUPPORTED;
|
||||
} else {
|
||||
ppc->ctr_fds[i] = fd;
|
||||
}
|
||||
}
|
||||
/* activate pai_user and pai_kernel */
|
||||
/* invariant:
|
||||
(ctr_state[PAI_USER] == UNSUPPORTED) ==
|
||||
(ctr_state[PAI_KERNEL] == UNSUPPORTED) */
|
||||
if (ctr_state[PAI_USER] != UNSUPPORTED) {
|
||||
for (i = 1; i <= NUM_PAI_USER; ++i) {
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
pfm_event.type = paipmutype;
|
||||
pfm_event.config = paipmueventstart + i;
|
||||
pfm_event.exclude_kernel = 1;
|
||||
pfm_event.exclude_user = 0;
|
||||
pfm_event.disabled = ctr_state[PAI_USER] == DISABLED;
|
||||
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
|
||||
if (fd < 0) {
|
||||
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||
goto outevents;
|
||||
} else {
|
||||
ppc->pai_user[i - 1] = fd;
|
||||
}
|
||||
pfm_event.exclude_kernel = 0;
|
||||
pfm_event.exclude_user = 1;
|
||||
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
|
||||
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
|
||||
if (fd < 0) {
|
||||
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||
goto outevents;
|
||||
} else {
|
||||
ppc->pai_kernel[i - 1] = fd;
|
||||
}
|
||||
}
|
||||
for (; i <= NUM_PAI_KERNEL; ++i) {
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
pfm_event.type = paipmutype;
|
||||
pfm_event.config = paipmueventstart + i;
|
||||
pfm_event.exclude_kernel = 0;
|
||||
pfm_event.exclude_user = 1;
|
||||
pfm_event.disabled = ctr_state[PAI_KERNEL] == DISABLED;
|
||||
fd = perf_event_open(&pfm_event, -1, cpu, -1, 0);
|
||||
if (fd < 0) {
|
||||
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||
goto outevents;
|
||||
} else {
|
||||
ppc->pai_kernel[i - 1] = fd;
|
||||
}
|
||||
}
|
||||
}
|
||||
outevents:
|
||||
ppc->next = root;
|
||||
root = ppc;
|
||||
if (enabledcounter)
|
||||
hotplugdetected = 1;
|
||||
pthread_mutex_unlock(&rootmux);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void deactivatecpu(unsigned int cpunum)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
int i;
|
||||
|
||||
if (pthread_mutex_lock(&rootmux))
|
||||
return;
|
||||
pcpu = findcpu(cpunum, 1);
|
||||
if (pcpu != NULL) {
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
(void)close(pcpu->ctr_fds[i]);
|
||||
for (i = 0; i < NUM_PAI_USER; ++i)
|
||||
(void)close(pcpu->pai_user[i]);
|
||||
for (i = 0; i < NUM_PAI_KERNEL; ++i)
|
||||
(void)close(pcpu->pai_kernel[i]);
|
||||
free(pcpu);
|
||||
if (enabledcounter)
|
||||
hotplugdetected = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&rootmux);
|
||||
}
|
||||
|
||||
static int addallcpus(void)
|
||||
{
|
||||
unsigned int start, end;
|
||||
int scanned, rc = 0;
|
||||
FILE *fp;
|
||||
|
||||
/* comma separated list of intervals */
|
||||
if ((fp = fopen("/sys/devices/system/cpu/online", "r")) == NULL) {
|
||||
eprint("Failed to get online cpus (%d:%s)\n",
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (!feof(fp)) {
|
||||
/* scan all intervals of online cpus */
|
||||
scanned = fscanf(fp, "%u-%u", &start, &end);
|
||||
/* take care of singleton intervals */
|
||||
if (scanned == 1)
|
||||
end = start;
|
||||
for (; start <= end; ++start) {
|
||||
if (activatecpu(start)) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/* Skip comma separator */
|
||||
(void)fgetc(fp);
|
||||
}
|
||||
out:
|
||||
fclose(fp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int perf_load_counter_data(void)
|
||||
{
|
||||
int i, res = 0;
|
||||
|
||||
for (i = 0; i < ALL_COUNTER; ++i) {
|
||||
if (ctr_state[i] != UNSUPPORTED)
|
||||
res |= perf_event_encode(&pmf_counter_data[i].pmutype,
|
||||
&pmf_counter_data[i].eventid,
|
||||
pmf_counter_name[i].pmu,
|
||||
pmf_counter_name[i].pfm_name);
|
||||
}
|
||||
if (ctr_state[PAI_USER] != UNSUPPORTED)
|
||||
res |= perf_event_encode(&paipmutype, &paipmueventstart,
|
||||
"pai_crypto", "CRYPTO_ALL");
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *hotplughandler(void *UNUSED(unused))
|
||||
{
|
||||
struct udev *hotplug;
|
||||
struct udev_monitor *monitor;
|
||||
struct pollfd item;
|
||||
|
||||
hotplug = udev_new();
|
||||
if (!hotplug) {
|
||||
eprint("Failed to create hotplug device\n");
|
||||
return NULL;
|
||||
}
|
||||
monitor = udev_monitor_new_from_netlink(hotplug, "udev");
|
||||
udev_monitor_filter_add_match_subsystem_devtype(monitor, "cpu", NULL);
|
||||
udev_monitor_enable_receiving(monitor);
|
||||
item.fd = udev_monitor_get_fd(monitor);
|
||||
item.events = POLLIN;
|
||||
item.revents = 0;
|
||||
while (!stoprequested) {
|
||||
struct udev_device *dev;
|
||||
const char *path, *action;
|
||||
unsigned int cpunum;
|
||||
int rc, on, off;
|
||||
|
||||
errno = 0;
|
||||
rc = poll(&item, 1, -1);
|
||||
if (rc == -1) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
dev = udev_monitor_receive_device(monitor);
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
action = udev_device_get_action(dev);
|
||||
if (action == NULL)
|
||||
continue;
|
||||
off = strcmp(action, "offline") == 0;
|
||||
on = strcmp(action, "online") == 0;
|
||||
if (!on && !off)
|
||||
continue;
|
||||
path = udev_device_get_devpath(dev);
|
||||
if (sscanf(path, "/devices/system/cpu/cpu%u", &cpunum) != 1)
|
||||
continue;
|
||||
if (on && activatecpu(cpunum))
|
||||
eprint("Failed to attach to hotplugged CPU %u\n", cpunum);
|
||||
if (off)
|
||||
deactivatecpu(cpunum);
|
||||
}
|
||||
udev_monitor_unref(monitor);
|
||||
udev_unref(hotplug);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int perf_init(void)
|
||||
{
|
||||
int i, cpus, ctr, cpu, *fds;
|
||||
|
||||
memset(ctr_fds, 0, sizeof(ctr_fds));
|
||||
int ecc_supported, i, num;
|
||||
unsigned long maxfd;
|
||||
struct rlimit rlim;
|
||||
FILE *f;
|
||||
|
||||
/* initialize performance monitoring library */
|
||||
if (!perf_supported()) {
|
||||
@@ -143,99 +475,105 @@ int perf_init(void)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* We currently support all cpumf counters plus two virtual
|
||||
* counters for PAI. */
|
||||
num = ALL_COUNTER + 2;
|
||||
/* Check if ECC is supported on current hardware */
|
||||
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
||||
|
||||
/* get number of logical processors */
|
||||
cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
||||
|
||||
/* for each counter */
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
|
||||
/* Skip ECC counters completely if unsupported */
|
||||
if (ctr == ECC_FUNCTIONS && !ecc_supported)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* allocate an array of ints to store for each CPU
|
||||
* one filedescriptor + a terminating 0
|
||||
*/
|
||||
fds = (int *) calloc(sizeof(int), cpus+1);
|
||||
if (!fds) {
|
||||
eprint("Malloc() of %d byte failed, errno=%d [%s]\n",
|
||||
(int)(sizeof(int) * (cpus+1)),
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctr_fds[ctr] = fds;
|
||||
|
||||
/* search for the counter's corresponding pfm name */
|
||||
for (i = ALL_COUNTER-1; i >= 0; i--)
|
||||
if ((int) pmf_counter_name[i].ctr == ctr)
|
||||
break;
|
||||
if (i < 0) {
|
||||
eprint("Pfm ctr name not found for counter %d, please adjust pmf_counter_name[] in %s\n",
|
||||
ctr, __FILE__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (cpu = 0; cpu < cpus; cpu++) {
|
||||
struct perf_event_attr pfm_event;
|
||||
int fd;
|
||||
|
||||
memset(&pfm_event, 0, sizeof(pfm_event));
|
||||
pfm_event.size = sizeof(pfm_event);
|
||||
if (perf_event_encode(&pfm_event,
|
||||
pmf_counter_name[i].pmu,
|
||||
pmf_counter_name[i].pfm_name)) {
|
||||
eprint("Failed to initialize counter %s for pmu %s\n",
|
||||
pmf_counter_name[i].pfm_name,
|
||||
pmf_counter_name[i].pmu);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* fetch file descriptor for this perf event
|
||||
* the counter event should start disabled
|
||||
*/
|
||||
pfm_event.disabled = 1;
|
||||
fd = perf_event_open(
|
||||
&pfm_event,
|
||||
-1, /* pid -1 means all processes */
|
||||
cpu,
|
||||
-1, /* group filedescriptor */
|
||||
0); /* flags */
|
||||
if (fd < 0) {
|
||||
eprint("Perf_event_open() failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
fds[cpu] = fd;
|
||||
}
|
||||
if (!cpumf_authorized()) {
|
||||
for (i = 0; i < ALL_COUNTER; ++i)
|
||||
ctr_state[i] = UNSUPPORTED;
|
||||
num -= ALL_COUNTER;
|
||||
} else if (!ecc_supported) {
|
||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||
--num;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (!perf_counter_supported("pai_crypto", "CRYPTO_ALL")) {
|
||||
ctr_state[PAI_USER] = UNSUPPORTED;
|
||||
ctr_state[PAI_KERNEL] = UNSUPPORTED;
|
||||
num -= 2;
|
||||
}
|
||||
|
||||
if (num == 0) {
|
||||
eprint("No crypto counters supported!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (perf_load_counter_data())
|
||||
return -1;
|
||||
/* We have to adjust the number of FDs possible since we might
|
||||
* need more than 1024 (the typical soft limit) */
|
||||
f = fopen("/proc/sys/fs/nr_open", "r");
|
||||
if (f == NULL) {
|
||||
eprint("fopen failed for /proc/sys/fs/nr_open with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
if (fscanf(f, "%lu", &maxfd) != 1) {
|
||||
fclose(f);
|
||||
eprint("Failed to parse /proc/sys/fs/nr_open\n");
|
||||
return -1;
|
||||
}
|
||||
fclose(f);
|
||||
rlim.rlim_cur = maxfd;
|
||||
rlim.rlim_max = maxfd;
|
||||
if (setrlimit(RLIMIT_NOFILE, &rlim) == -1) {
|
||||
eprint("setrlimit failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pthread_create(&hotplugthread, NULL, hotplughandler, NULL)) {
|
||||
eprint("Failed to start hotplug handler thread\n");
|
||||
return -1;
|
||||
}
|
||||
return addallcpus();
|
||||
}
|
||||
|
||||
|
||||
void perf_stop(void)
|
||||
{
|
||||
stoprequested = 1;
|
||||
}
|
||||
|
||||
|
||||
void perf_close(void)
|
||||
{
|
||||
int ctr, *fds;
|
||||
struct percpucounter *walk, *next;
|
||||
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
||||
close(*fds);
|
||||
*fds = 0;
|
||||
}
|
||||
free(ctr_fds[ctr]);
|
||||
ctr_fds[ctr] = NULL;
|
||||
pthread_kill(hotplugthread, SIGINT);
|
||||
pthread_join(hotplugthread, NULL);
|
||||
walk = root;
|
||||
while (walk) {
|
||||
next = walk->next;
|
||||
freepercpucounter(walk);
|
||||
walk = next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int enable_array(int *arr, int size)
|
||||
{
|
||||
int i, ec, rc = 0;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
ec = ioctl(arr[i], PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int perf_enable_ctr(enum ctr_e ctr)
|
||||
{
|
||||
int *fds, ec, rc = 0;
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
@@ -243,24 +581,64 @@ int perf_enable_ctr(enum ctr_e ctr)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
||||
ec = ioctl(*fds, PERF_EVENT_IOC_ENABLE, 0);
|
||||
} else if (ctr < ALL_COUNTER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_ENABLE, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
ctr_state[ctr] = ENABLED;
|
||||
++enabledcounter;
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_USER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = enable_array(pcpu->pai_user, NUM_PAI_USER);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
ctr_state[ctr] = ENABLED;
|
||||
++enabledcounter;
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_KERNEL) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = enable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
ctr_state[ctr] = ENABLED;
|
||||
++enabledcounter;
|
||||
endforeachcpu();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static int disable_array(int *arr, int size)
|
||||
{
|
||||
int i, ec, rc = 0;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
ec = ioctl(arr[i], PERF_EVENT_IOC_DISABLE, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int perf_disable_ctr(enum ctr_e ctr)
|
||||
{
|
||||
int *fds, ec, rc = 0;
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
@@ -268,70 +646,183 @@ int perf_disable_ctr(enum ctr_e ctr)
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
||||
ec = ioctl(*fds, PERF_EVENT_IOC_DISABLE, 0);
|
||||
} else if (ctr < ALL_COUNTER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_DISABLE, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
ctr_state[ctr] = DISABLED;
|
||||
--enabledcounter;
|
||||
if (enabledcounter == 0)
|
||||
hotplugdetected = 0;
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_USER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = disable_array(pcpu->pai_user, NUM_PAI_USER);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
ctr_state[ctr] = DISABLED;
|
||||
--enabledcounter;
|
||||
if (enabledcounter == 0)
|
||||
hotplugdetected = 0;
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_KERNEL) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = disable_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
ctr_state[ctr] = DISABLED;
|
||||
--enabledcounter;
|
||||
if (enabledcounter == 0)
|
||||
hotplugdetected = 0;
|
||||
endforeachcpu();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int perf_reset_ctr(enum ctr_e ctr)
|
||||
static int reset_array(int *arr, int size)
|
||||
{
|
||||
int *fds, ec, rc = 0;
|
||||
int ec, rc = 0, i;
|
||||
|
||||
for (i = 0; i < size; ++i) {
|
||||
ec = ioctl(arr[i], PERF_EVENT_IOC_RESET, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int perf_reset_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
|
||||
if (ctr == ALL_COUNTER) {
|
||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||
rc = perf_reset_ctr(ctr);
|
||||
rc = perf_reset_ctr(ctr, value);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
||||
ec = ioctl(*fds, PERF_EVENT_IOC_RESET, 0);
|
||||
} else if (ctr < ALL_COUNTER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_RESET, 0);
|
||||
if (ec < 0) {
|
||||
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
}
|
||||
}
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_USER) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = reset_array(pcpu->pai_user, NUM_PAI_USER);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
endforeachcpu();
|
||||
} else if (ctr == PAI_KERNEL) {
|
||||
foreachcpu(pcpu) {
|
||||
ec = reset_array(pcpu->pai_kernel, NUM_PAI_KERNEL);
|
||||
if (ec < 0)
|
||||
rc = -1;
|
||||
}
|
||||
endforeachcpu();
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
if (rc == 0)
|
||||
rc = perf_read_ctr(ctr, value);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
||||
{
|
||||
int *fds, ec, rc = -1;
|
||||
struct percpucounter *pcpu;
|
||||
int ec, rc = 0;
|
||||
uint64_t val;
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
if (ctr == HOTPLUG_DETECTED) {
|
||||
*value = hotplugdetected;
|
||||
return 0;
|
||||
}
|
||||
if (ctr == PAI_USER) {
|
||||
*value = NUM_PAI_USER;
|
||||
return 0;
|
||||
}
|
||||
if (ctr == PAI_KERNEL) {
|
||||
*value = NUM_PAI_KERNEL;
|
||||
return 0;
|
||||
}
|
||||
if (ctr >= ALL_COUNTER)
|
||||
return -1;
|
||||
*value = 0;
|
||||
|
||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
||||
ec = read(*fds, &val, sizeof(val));
|
||||
foreachcpu(pcpu) {
|
||||
ec = read(pcpu->ctr_fds[ctr], &val, sizeof(val));
|
||||
if (ec != sizeof(val)) {
|
||||
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
} else {
|
||||
*value += val;
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
endforeachcpu();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int perf_ecc_supported(void)
|
||||
{
|
||||
return ecc_supported;
|
||||
return ctr_state[ECC_FUNCTIONS] != UNSUPPORTED;
|
||||
}
|
||||
|
||||
int perf_ctr_state(enum ctr_e ctr) {
|
||||
if (ctr < NUM_COUNTER)
|
||||
return ctr_state[ctr];
|
||||
return UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
int perf_read_pai_ctr(unsigned int ctrnum, int user, uint64_t *value)
|
||||
{
|
||||
struct percpucounter *pcpu;
|
||||
unsigned int maxctr;
|
||||
int *arr, ec, rc = 0;
|
||||
uint64_t val;
|
||||
|
||||
*value = 0;
|
||||
maxctr = user ? NUM_PAI_USER : NUM_PAI_KERNEL;
|
||||
if (ctrnum >= maxctr)
|
||||
return -1;
|
||||
foreachcpu(pcpu) {
|
||||
arr = user ? pcpu->pai_user : pcpu->pai_kernel;
|
||||
ec = read(arr[ctrnum], &val, sizeof(val));
|
||||
if (ec != sizeof(val)) {
|
||||
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
||||
errno, strerror(errno));
|
||||
rc = -1;
|
||||
} else {
|
||||
*value += val;
|
||||
}
|
||||
}
|
||||
endforeachcpu();
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* basic socket and receive/send functions
|
||||
*
|
||||
* Copyright IBM Corp. 2015, 2017
|
||||
* Copyright IBM Corp. 2015, 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.
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <endian.h>
|
||||
#include <errno.h>
|
||||
#include <grp.h>
|
||||
#include <poll.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/socket.h>
|
||||
@@ -148,7 +149,51 @@ static int __read(int fd, void *buf, int buflen)
|
||||
}
|
||||
|
||||
|
||||
int send_msg(int sfd, struct msg *m)
|
||||
static int __timedwrite(int fd, const void *buf, int buflen, int timeout)
|
||||
{
|
||||
struct pollfd pfd = { .fd = fd, .events = POLLOUT };
|
||||
int i = 0, n;
|
||||
|
||||
while (poll(&pfd, 1, timeout) == 1) {
|
||||
n = write(fd, buf + i, buflen - i);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return n;
|
||||
} else if (n == 0) {
|
||||
return i;
|
||||
}
|
||||
i += n;
|
||||
if (buflen == i)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int __timedread(int fd, void *buf, int buflen, int timeout)
|
||||
{
|
||||
struct pollfd pfd = { .fd = fd, .events = POLLIN };
|
||||
int i = 0, n;
|
||||
|
||||
while (poll(&pfd, 1, timeout) == 1) {
|
||||
n = read(fd, buf + i, buflen - i);
|
||||
if (n < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
return n;
|
||||
} else if (n == 0) {
|
||||
return i;
|
||||
}
|
||||
i += n;
|
||||
if (buflen == i)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int send_msg(int sfd, struct msg *m, int timeout)
|
||||
{
|
||||
int n, len;
|
||||
|
||||
@@ -166,7 +211,7 @@ int send_msg(int sfd, struct msg *m)
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = __write(sfd, m, len);
|
||||
n = timeout ? __timedwrite(sfd, m, len, timeout) : __write(sfd, m, len);
|
||||
if (n != len) {
|
||||
eprint("Write() error: write()=%d expected %d, errno=%d [%s]\n",
|
||||
n, len, errno, strerror(errno));
|
||||
@@ -176,12 +221,12 @@ int send_msg(int sfd, struct msg *m)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int recv_msg(int sfd, struct msg *m)
|
||||
int recv_msg(int sfd, struct msg *m, int timeout)
|
||||
{
|
||||
int n, len;
|
||||
|
||||
len = sizeof(m->head);
|
||||
n = __read(sfd, m, len);
|
||||
n = timeout ? __timedread(sfd, m, len, timeout) : __read(sfd, m, len);
|
||||
if (n != len) {
|
||||
eprint("Recv() error: read()=%d expected %d, errno=%d [%s]\n",
|
||||
n, len, errno, strerror(errno));
|
||||
@@ -200,7 +245,8 @@ int recv_msg(int sfd, struct msg *m)
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = __read(sfd, ((char *)m) + sizeof(m->head), len);
|
||||
n = timeout ? __timedread(sfd, ((char *)m) + sizeof(m->head), len, timeout) :
|
||||
__read(sfd, ((char *)m) + sizeof(m->head), len);
|
||||
if (n != len) {
|
||||
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
||||
n, len, errno, strerror(errno));
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "lib/util_arch.h"
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_path.h"
|
||||
#include "lib/util_prg.h"
|
||||
|
||||
#include "lib/libcpumf.h"
|
||||
@@ -3318,17 +3319,18 @@ static void show_info(struct cpumf_info *p, int details)
|
||||
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
||||
* Check for existence of file /sys/devices/cpum_cf/events/DLFT_CCERROR.
|
||||
*/
|
||||
#define CCERROR "/sys/devices/cpum_cf/events/DFLT_CCERROR"
|
||||
static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
||||
{
|
||||
char *ctrname, *path;
|
||||
struct stat sbuf;
|
||||
char *ctrname;
|
||||
size_t i = 0;
|
||||
|
||||
if (!stat(CCERROR, &sbuf))
|
||||
path = util_path_sysfs("devices/cpum_cf/events/DFLT_CCERROR");
|
||||
if (!stat(path, &sbuf))
|
||||
ctrname = "DFLT_CCERROR";
|
||||
else
|
||||
ctrname = "DFLT_CCFINISH";
|
||||
free(path);
|
||||
/* Find DFLT_CC{FINISH,ERROR} in table and set name */
|
||||
for (struct counters *p = cp; i < cp_cnt; ++i, ++p)
|
||||
if (p->ctrnum == 265) {
|
||||
|
||||
@@ -356,6 +356,8 @@ static void line(char *header)
|
||||
putchar(',');
|
||||
printf("%ld", ctrname[i].total);
|
||||
comma = true;
|
||||
ctrname[i].total = 0;
|
||||
ctrname[i].hitcnt = false;
|
||||
}
|
||||
putchar('\n');
|
||||
}
|
||||
@@ -446,7 +448,7 @@ static bool add_countervalue(size_t idx, unsigned int cpu, unsigned long value)
|
||||
ctrname[idx].ccv = calloc(max_possible_cpus,
|
||||
sizeof(unsigned long));
|
||||
if (ctrname[idx].ccv)
|
||||
ctrname[idx].ccv[cpu] += value;
|
||||
ctrname[idx].ccv[cpu] = value;
|
||||
ctrname[idx].total += value;
|
||||
ctrname[idx].hitcnt = true;
|
||||
return true;
|
||||
@@ -458,10 +460,8 @@ static int test_read(struct s390_hwctr_read *read)
|
||||
size_t offset = 0;
|
||||
|
||||
/* Clear previous hit counters */
|
||||
for (unsigned int i = 0; i < max_possible_cpus; ++i) {
|
||||
check[i].sets_hit = 0;
|
||||
for (unsigned int i = 0; i < max_possible_cpus; ++i)
|
||||
check[i].cpu_hit = false;
|
||||
}
|
||||
|
||||
/* Iterate over all CPUs */
|
||||
for (unsigned int i = 0; i < read->no_cpus; ++i) {
|
||||
|
||||
68
cpumf/pai.c
68
cpumf/pai.c
@@ -32,6 +32,7 @@
|
||||
#include <linux/perf_event.h>
|
||||
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_list.h"
|
||||
#include "lib/util_opt.h"
|
||||
@@ -56,6 +57,7 @@ static cpu_set_t cpu_online_mask;
|
||||
static int verbose, humantime;
|
||||
static struct util_list list_pai_event;
|
||||
static struct util_list list_pmu_event;
|
||||
static bool summary;
|
||||
|
||||
/* System call to perf_event_open(2) */
|
||||
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||
@@ -114,7 +116,7 @@ static void ev_alloc(int enr, int cpu, int flags)
|
||||
warnx("NNPA does not support kernel/user space selector");
|
||||
flags &= ~as;
|
||||
}
|
||||
event->attr.type = libcpumf_pmutype(S390_SYSFS_PAI_NNPA);
|
||||
event->attr.type = libcpumf_pmutype(S390_SYSFS_PAI_EXT);
|
||||
break;
|
||||
}
|
||||
event->attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_CPU |
|
||||
@@ -263,9 +265,11 @@ static int savemap(int fd, void *data, struct data_pos *dp)
|
||||
int wrapped;
|
||||
|
||||
d_head_old = d_head;
|
||||
printf("Data head:%#llx tail:%#llx offset:%#llx size:%#llx\n",
|
||||
dp->data_head, dp->data_tail, dp->data_offset,
|
||||
dp->data_size);
|
||||
if (verbose) {
|
||||
printf("Data head:%#llx tail:%#llx offset:%#llx size:%#llx\n",
|
||||
dp->data_head, dp->data_tail, dp->data_offset,
|
||||
dp->data_size);
|
||||
}
|
||||
if (!diff)
|
||||
return 0;
|
||||
wrapped = d_head / dp->data_size != d_prev / dp->data_size;
|
||||
@@ -280,13 +284,16 @@ static int savemap(int fd, void *data, struct data_pos *dp)
|
||||
int part2 = dp->data_size - d_prev;
|
||||
|
||||
diff -= part2;
|
||||
printf("Write %d bytes [%ld,%lld)\n", part2, d_prev,
|
||||
dp->data_size);
|
||||
if (verbose) {
|
||||
printf("Write %d bytes [%ld,%lld)\n", part2, d_prev,
|
||||
dp->data_size);
|
||||
}
|
||||
if (write(fd, data + d_prev, part2) == -1)
|
||||
err(EXIT_FAILURE, "write error for event file");
|
||||
d_prev = 0; /* Start at position zero */
|
||||
}
|
||||
printf("Write %d bytes [%ld,%ld)\n", diff, d_prev, d_head);
|
||||
if (verbose)
|
||||
printf("Write %d bytes [%ld,%ld)\n", diff, d_prev, d_head);
|
||||
if (write(fd, data + d_prev, diff) == -1)
|
||||
err(EXIT_FAILURE, "write error for event file");
|
||||
|
||||
@@ -299,7 +306,10 @@ static void readmap(int fd)
|
||||
struct pai_event *p = perffd_2_event(fd);
|
||||
struct perf_event_mmap_page *area;
|
||||
|
||||
printf("Ring buffer for fd %d %s(%d)\n", fd, p->file_name, p->file_fd);
|
||||
if (verbose) {
|
||||
printf("Ring buffer for fd %d %s(%d)\n", fd, p->file_name,
|
||||
p->file_fd);
|
||||
}
|
||||
area = p->map_addr;
|
||||
savemap(p->file_fd, p->map_addr + area->data_offset,
|
||||
(struct data_pos *)&area->data_head);
|
||||
@@ -383,7 +393,10 @@ static int evtraw_show(__u64 evtnum, unsigned char *p)
|
||||
offset += sizeof(ctr);
|
||||
value = *(__u64 *)(p + offset);
|
||||
offset += sizeof(value);
|
||||
printf("%c%hd:%#llx", offset > 14 ? ',' : ' ', ctr, value);
|
||||
if (!summary) {
|
||||
printf("%c%hd:%#llx", offset > 14 ? ',' : ' ', ctr,
|
||||
value);
|
||||
}
|
||||
lookup_event(evtnum, ctr, value);
|
||||
if (offset + sizeof(ctr) + sizeof(value) > bytes)
|
||||
break;
|
||||
@@ -412,6 +425,12 @@ static const char *evt_selector(struct perf_event_attr *pa)
|
||||
|
||||
static void evt_show(__u64 evtnum, const char *evtsel, struct pai_event_out *ev)
|
||||
{
|
||||
if (summary) {
|
||||
if (ev->type == PERF_RECORD_SAMPLE && ev->raw)
|
||||
evtraw_show(evtnum, ev->raw);
|
||||
return;
|
||||
}
|
||||
|
||||
timestamp(ev->time);
|
||||
printf("%d ", ev->cpu);
|
||||
|
||||
@@ -633,30 +652,13 @@ bypass:
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read perf_event_open() config value for event. */
|
||||
static int read_event(char *dirname, char *filename)
|
||||
{
|
||||
int config, rc = 0;
|
||||
char *pathname;
|
||||
FILE *fp;
|
||||
|
||||
util_asprintf(&pathname, "%s/%s", dirname, filename);
|
||||
fp = fopen(pathname, "r");
|
||||
if (fp) {
|
||||
rc = fscanf(fp, "event=%x", &config);
|
||||
fclose(fp);
|
||||
}
|
||||
free(pathname);
|
||||
return rc == 1 ? config : -1;
|
||||
}
|
||||
|
||||
/* Scan event directory and fill event list. */
|
||||
static int scan_events(struct pmu_events *p)
|
||||
{
|
||||
char *evtname, *evtdir, *path;
|
||||
struct dirent **de_vec;
|
||||
struct event_name *ep;
|
||||
char *evtdir, *path;
|
||||
int count, rc;
|
||||
int evtnr, count, rc;
|
||||
|
||||
path = util_path_sysfs("devices");
|
||||
rc = util_asprintf(&evtdir, "%s/%s/events", path, p->name);
|
||||
@@ -677,8 +679,10 @@ static int scan_events(struct pmu_events *p)
|
||||
if (de_vec[i]->d_type == DT_DIR)
|
||||
continue;
|
||||
ep->name = util_strdup(de_vec[i]->d_name);
|
||||
rc = read_event(evtdir, de_vec[i]->d_name);
|
||||
if (rc == -1 || !ep->name) {
|
||||
util_asprintf(&evtname, "%s/%s", evtdir, de_vec[i]->d_name);
|
||||
rc = util_file_read_va(evtname, "event=%x", &evtnr);
|
||||
free(evtname);
|
||||
if (rc != 1) {
|
||||
for (ep = p->lst, rc = 0; rc < p->lstlen; ++rc, ++ep)
|
||||
free(ep->name);
|
||||
free(p->lst);
|
||||
@@ -686,7 +690,7 @@ static int scan_events(struct pmu_events *p)
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
ep->config = rc;
|
||||
ep->config = evtnr;
|
||||
if (p->base > ep->config)
|
||||
p->base = ep->config;
|
||||
++p->lstlen;
|
||||
@@ -1005,7 +1009,7 @@ static unsigned long check_mapsize(unsigned long n)
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool crypto_record = false, report = false, summary = false;
|
||||
bool crypto_record = false, report = false;
|
||||
bool nnpa_record = false;
|
||||
unsigned long loop_count = 1;
|
||||
int ch, group = 0;
|
||||
|
||||
@@ -1107,8 +1107,8 @@ static void dasdfmt_write_labels(volume_label_t *vlabel,
|
||||
} else {
|
||||
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
|
||||
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
|
||||
rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
|
||||
- sizeof(vlabel->volkey)));
|
||||
rc = write(fd, (void *)vlabel + sizeof(vlabel->volkey),
|
||||
(sizeof(*vlabel) - sizeof(vlabel->volkey)));
|
||||
}
|
||||
|
||||
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "lib/dasd_sys.h"
|
||||
#include "lib/libzds.h"
|
||||
#include "lib/util_base.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
#include "lib/util_sys.h"
|
||||
@@ -1788,10 +1789,8 @@ dasdview_print_format1(unsigned int size, unsigned char *dumpstr)
|
||||
for (i = 0; i < size; i++) {
|
||||
if ((i / 16) * 16 == i) {
|
||||
printf("\n| ");
|
||||
strncpy(asc, (char *)dumpstr + i, 16);
|
||||
strncpy(ebc, (char *)dumpstr + i, 16);
|
||||
asc[16] = '\0';
|
||||
ebc[16] = '\0';
|
||||
util_strlcpy(asc, (char *)dumpstr + i, 16);
|
||||
util_strlcpy(ebc, (char *)dumpstr + i, 16);
|
||||
}
|
||||
printf("%02X", dumpstr[i]);
|
||||
if (((i + 1) / 4) * 4 == i + 1)
|
||||
@@ -1822,8 +1821,8 @@ dasdview_print_format2(unsigned int size, unsigned char *dumpstr,
|
||||
begin + (unsigned long long)i,
|
||||
begin + (unsigned long long)i);
|
||||
|
||||
strncpy(asc, (char *)dumpstr + i, 8);
|
||||
strncpy(ebc, (char *)dumpstr + i, 8);
|
||||
util_strlcpy(asc, (char *)dumpstr + i, 8);
|
||||
util_strlcpy(ebc, (char *)dumpstr + i, 8);
|
||||
}
|
||||
printf("%02X", dumpstr[i]);
|
||||
if (((i + 1) / 4) * 4 == i + 1)
|
||||
|
||||
@@ -69,27 +69,15 @@ endif
|
||||
|
||||
stage3b_reloc.o: stage3b.bin
|
||||
|
||||
stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS)
|
||||
stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS)
|
||||
stage3b_reloc.elf:
|
||||
stage3a.elf: head.o stage3a_init.o $(ZIPL_OBJS)
|
||||
stage3b.elf: head.o $(ZIPL_OBJS)
|
||||
|
||||
%.elf: %.o
|
||||
case $* in \
|
||||
stage3a) SFLAGS="-Wl,-T,stage3a.lds";; \
|
||||
stage3b) SFLAGS="-Wl,-T,stage3b.lds";; \
|
||||
stage3b_reloc) SFLAGS="-Wl,-estage3b_reloc_start,-Ttext,0";; \
|
||||
esac; \
|
||||
$(LINK) $$SFLAGS $(NO_PIE_LDFLAGS) -m64 -static -nostdlib $(filter %.o, $^) -o $@
|
||||
%.elf: %.lds %.o
|
||||
$(LINK) $(NO_PIE_LDFLAGS) $(NO_WARN_RWX_SEGMENTS_LDFLAGS) -Wl,-T,$< -Wl,--build-id=none -m64 -static -nostdlib $(filter %.o, $^) -o $@
|
||||
@chmod a-x $@
|
||||
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -O binary \
|
||||
--only-section=.text* \
|
||||
--only-section=.ex_table* \
|
||||
--only-section=.fixup* \
|
||||
--only-section=.data* \
|
||||
--only-section=.rodata* \
|
||||
$< $@
|
||||
%.bin: %.elf
|
||||
$(OBJCOPY) -O binary $< $@
|
||||
@chmod a-x $@
|
||||
|
||||
clean:
|
||||
|
||||
@@ -29,3 +29,8 @@ _start:
|
||||
brasl %r14, initialize
|
||||
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||
.previous
|
||||
|
||||
/* The code doesn't require an executable stack */
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
@@ -23,8 +23,6 @@ ENTRY(_init)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x0;
|
||||
|
||||
. = HEAP_ADDRESS;
|
||||
__heap_start = .;
|
||||
.heap : {
|
||||
@@ -46,7 +44,7 @@ SECTIONS
|
||||
. = STAGE3A_INIT_ENTRY;
|
||||
__text_init_start = .;
|
||||
.text : {
|
||||
stage3a_init.o(.text.init)
|
||||
*(.text.init)
|
||||
__text_init_stop = ABSOLUTE(.);
|
||||
/* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||
* otherwise the text data could be overwritten by the original zipl stage3
|
||||
@@ -56,8 +54,8 @@ SECTIONS
|
||||
. = 0x1000;
|
||||
ASSERT(ABSOLUTE(.) == STAGE3A_ENTRY,
|
||||
"Text section doesn't conform to the described memory layout");
|
||||
head.o(.text.start)
|
||||
*(.text)
|
||||
*(.text.start)
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
.ex_table ALIGN(16) : {
|
||||
@@ -74,7 +72,7 @@ SECTIONS
|
||||
|
||||
.rodata ALIGN(16) : {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.rodata*)
|
||||
}
|
||||
|
||||
.data ALIGN(16) : {
|
||||
@@ -90,14 +88,10 @@ SECTIONS
|
||||
ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
||||
}
|
||||
|
||||
/* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
* put at 0x0 */
|
||||
.notes : {
|
||||
*(.note.*)
|
||||
}
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
*(.interp)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,3 +26,8 @@ _init:
|
||||
br %r1
|
||||
.Lstage3a_entry: .long STAGE3A_ENTRY
|
||||
.previous
|
||||
|
||||
/* The code doesn't require an executable stack */
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
@@ -21,8 +21,6 @@ ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x0;
|
||||
|
||||
. = HEAP_ADDRESS;
|
||||
__heap_start = .;
|
||||
.heap : {
|
||||
@@ -34,8 +32,8 @@ SECTIONS
|
||||
|
||||
. = STAGE3B_ENTRY;
|
||||
.text : {
|
||||
head.o(.text.start)
|
||||
*(.text)
|
||||
*(.text.start)
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
.ex_table ALIGN(16) : {
|
||||
@@ -52,7 +50,7 @@ SECTIONS
|
||||
|
||||
.rodata ALIGN(16) : {
|
||||
*(.rodata)
|
||||
*(.rodata.*)
|
||||
*(.rodata*)
|
||||
}
|
||||
|
||||
.data ALIGN(16) : {
|
||||
@@ -74,14 +72,12 @@ SECTIONS
|
||||
}
|
||||
__stack_end = .;
|
||||
|
||||
/* List this explicitly as otherwise .note.gnu.build-id will be
|
||||
* put at 0x0 */
|
||||
.notes : {
|
||||
*(.note.*)
|
||||
}
|
||||
ASSERT(. <= IMAGE_ENTRY, "stage3b size must be smaller than 0x10000 bytes")
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
*(.interp)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@
|
||||
|
||||
.org 0x0
|
||||
.section .text.start
|
||||
.globl stage3b_reloc_start
|
||||
stage3b_reloc_start:
|
||||
.globl _start
|
||||
_start:
|
||||
/* Might be called after a diag308 so better set
|
||||
* architecture and addressing mode
|
||||
*/
|
||||
@@ -53,3 +53,8 @@ stage3b_start:
|
||||
.incbin "stage3b.bin"
|
||||
stage3b_end:
|
||||
.previous
|
||||
|
||||
/* The code doesn't require an executable stack */
|
||||
#if defined(__linux__) && defined(__ELF__)
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
19
genprotimg/boot/stage3b_reloc.lds.S
Normal file
19
genprotimg/boot/stage3b_reloc.lds.S
Normal file
@@ -0,0 +1,19 @@
|
||||
OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||
OUTPUT_ARCH(s390:64-bit)
|
||||
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text : {
|
||||
*(.text.start)
|
||||
*(.text .text.*)
|
||||
}
|
||||
|
||||
/* Sections to be discarded */
|
||||
/DISCARD/ : {
|
||||
*(.eh_frame)
|
||||
*(.interp)
|
||||
*(.note.GNU-stack)
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,8 @@ host.
|
||||
Specifies the certificate that is used to establish a chain of trust
|
||||
for the verification of the host-key documents. Specify this option
|
||||
twice to specify the IBM Z signing key and the intermediate CA
|
||||
certificate (signed by the root CA). Required.
|
||||
certificate (signed by the root CA).
|
||||
Required. Ignored if \fB--no-verify\fP is specified.
|
||||
.TP
|
||||
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
||||
Specifies the output file. Required.
|
||||
@@ -91,8 +92,9 @@ the system wide root CAs installed on the system is used. Use
|
||||
this only if you trust the specified certificate. Optional.
|
||||
.TP
|
||||
\fB\-\-no-verify\fR
|
||||
Do not require the host-key documents to be valid. For testing
|
||||
purposes, do not use for a production image. Optional.
|
||||
Does not require the host-key documents to be valid.
|
||||
Do not use for a production image unless you verified
|
||||
the host-key document before. Optional.
|
||||
.TP
|
||||
\fB\-\-comm\-key\fR=\fI\,FILE\/\fR
|
||||
Specifies the encryption key you want to use for the PV guest dump. Use a
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#define GETTEXT_PACKAGE "genprotimg"
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "boot/linux_layout.h"
|
||||
#include "boot/s390.h"
|
||||
|
||||
@@ -280,7 +280,8 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||
.arg_data = &args->host_keys,
|
||||
.description =
|
||||
_("FILE specifies a host-key document. At least\n" INDENT
|
||||
"one is required."),
|
||||
"one is required Specify this option multiple times\n" INDENT
|
||||
"to enable the image to run on more than one host."),
|
||||
.arg_description = _("FILE") },
|
||||
{ .long_name = "cert",
|
||||
.short_name = 'C',
|
||||
|
||||
@@ -447,7 +447,7 @@ static X509_CRL *load_crl_from_bio(BIO *bio)
|
||||
return g_steal_pointer(&crl);
|
||||
ERR_clear_error();
|
||||
rc = BIO_reset(bio);
|
||||
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
|
||||
if (rc != 1 && !(rc == 0 && BIO_method_type(bio) == BIO_TYPE_FILE))
|
||||
return NULL;
|
||||
|
||||
/* maybe the CRL is stored in DER format */
|
||||
@@ -533,7 +533,7 @@ X509 *load_cert_from_file(const char *path, GError **err)
|
||||
return g_steal_pointer(&cert);
|
||||
ERR_clear_error();
|
||||
rc = BIO_reset(bio);
|
||||
if (rc != 1 || (rc != 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
|
||||
if (rc != 1 && !(rc == 0 && BIO_method_type(bio) == BIO_TYPE_FILE)) {
|
||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||
_("unable to load certificate: '%s'"), path);
|
||||
return NULL;
|
||||
|
||||
@@ -52,7 +52,7 @@ install-scripts: lshmc
|
||||
cat $$i | \
|
||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
>$(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||
done
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ all:
|
||||
install: hsci
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< hsci >$(DESTDIR)$(BINDIR)/hsci; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
|
||||
chmod 755 $(DESTDIR)$(BINDIR)/hsci; \
|
||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 hsci.8 \
|
||||
|
||||
@@ -57,11 +57,41 @@ struct linear_blockptr {
|
||||
uint8_t reserved[4];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Format of a boot record on ECKD DASD for List-Directed IPL
|
||||
*/
|
||||
struct eckd_boot_record {
|
||||
uint8_t magic[4];
|
||||
uint32_t version_id;
|
||||
uint8_t unused[8];
|
||||
uint8_t program_table_pointer[16];
|
||||
uint8_t reserved[478];
|
||||
uint16_t os_id;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Layout of block pointer for cylinder/head/sector devices
|
||||
* e.g. ECKD
|
||||
*/
|
||||
struct eckd_blockptr {
|
||||
|
||||
enum blkptr_format_id {
|
||||
/*
|
||||
* this is the old format which serves only CCW-type IPL,
|
||||
* and doesn't fit List-Directed IPL. Still supported for
|
||||
* compatibility reasons.
|
||||
*/
|
||||
LEGACY_BLKPTR_FORMAT_ID,
|
||||
/*
|
||||
* this is the "new" format which serves only List-Directed IPL,
|
||||
* but is also suitable for CCW-type IPL.
|
||||
*/
|
||||
BLKPTR_FORMAT_ID
|
||||
};
|
||||
|
||||
/*
|
||||
* Block pointers format identified as LEGACY_BLKPTR_FORMAT_ID.
|
||||
*/
|
||||
struct eckd_blockptr_legacy {
|
||||
uint16_t cyl;
|
||||
uint16_t head;
|
||||
uint8_t sec;
|
||||
@@ -70,10 +100,22 @@ struct eckd_blockptr {
|
||||
uint8_t reserved[8];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Block pointers format identified as BLKPTR_FORMAT_ID.
|
||||
*/
|
||||
struct eckd_blockptr {
|
||||
uint32_t cyl;
|
||||
uint8_t head;
|
||||
uint8_t sec;
|
||||
uint8_t reserved1[4];
|
||||
uint16_t blockct;
|
||||
uint8_t reserved2[4];
|
||||
} __packed;
|
||||
|
||||
typedef enum {
|
||||
COMPONENT_EXECUTE = 0x01,
|
||||
COMPONENT_LOAD = 0x02,
|
||||
COMPONENT_SIGNATURE = 0x03
|
||||
COMPONENT_TYPE_EXECUTE = 0x01,
|
||||
COMPONENT_TYPE_LOAD = 0x02,
|
||||
COMPONENT_TYPE_SIGNATURE = 0x03
|
||||
} component_type;
|
||||
|
||||
typedef enum {
|
||||
@@ -117,7 +159,8 @@ struct scsi_dump_sb {
|
||||
uint64_t csum_offset;
|
||||
uint64_t csum_size;
|
||||
uint64_t csum;
|
||||
} __packed;
|
||||
};
|
||||
STATIC_ASSERT(sizeof(struct scsi_dump_sb) == 72);
|
||||
|
||||
#define SCSI_DUMP_SB_MAGIC 0x5a46435044554d50ULL /* ZFCPDUMP */
|
||||
/* To avoid a csum entry of 0 a seed is used */
|
||||
@@ -153,6 +196,7 @@ struct boot_info_bp_dump {
|
||||
|
||||
struct boot_info_bp_ipl {
|
||||
union {
|
||||
struct eckd_blockptr_legacy eckd_legacy;
|
||||
struct eckd_blockptr eckd;
|
||||
struct linear_blockptr lin;
|
||||
} bm_ptr;
|
||||
|
||||
@@ -14,12 +14,18 @@
|
||||
#include "lib/zt_common.h"
|
||||
#include "linux_layout.h"
|
||||
|
||||
#define STAGE0_LOAD_ADDRESS _AC(0x0, UL)
|
||||
|
||||
#define STAGE1_LOAD_ADDRESS _AC(0x18, UL)
|
||||
#define STAGE1B_LOAD_ADDRESS _AC(0xe000, UL)
|
||||
|
||||
#define STAGE2_DESC _AC(0x78, UL)
|
||||
#define STAGE2_ENTRY _AC(0x2018, UL)
|
||||
#define STAGE2_HEAP_ADDRESS _AC(0x6000, UL)
|
||||
#define STAGE2_HEAP_SIZE _AC(0x3000, UL)
|
||||
#define STAGE2_STACK_ADDRESS _AC(0xe400, UL)
|
||||
#define STAGE2_STACK_SIZE _AC(0x1c00, UL)
|
||||
#define STAGE2_MAX_SIZE _AC(0x3000, UL)
|
||||
|
||||
#define STAGE3_ENTRY _AC(0xa000, UL)
|
||||
|
||||
|
||||
@@ -90,5 +90,6 @@ void ap_list_remove_all(struct util_list *list);
|
||||
int ap_get_lock(void);
|
||||
int ap_get_lock_callout(void);
|
||||
int ap_release_lock(void);
|
||||
int ap_release_lock_callout(void);
|
||||
|
||||
#endif /* LIB_AP_H */
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
/* A bus id of a DASD is 8 characters long. E.g. 0.0.4711 */
|
||||
#define DASD_BUS_ID_SIZE 9
|
||||
/* the definition of a BUSID in the DASD driver is 20 */
|
||||
#define DASD_BUS_ID_SIZE 20
|
||||
|
||||
typedef struct dasd_information2_t {
|
||||
unsigned int devno; /* S/390 devno */
|
||||
@@ -187,6 +187,68 @@ typedef struct format_check_t {
|
||||
#define DASD_FMT_ERR_RECORD_ID 4
|
||||
#define DASD_FMT_ERR_KEY_LENGTH 5
|
||||
|
||||
/*
|
||||
* struct profile_info_t
|
||||
* holds the profiling information
|
||||
*/
|
||||
typedef struct dasd_profile_info_t {
|
||||
unsigned int dasd_io_reqs; /* # of requests processed at all */
|
||||
unsigned int dasd_io_sects; /* # of sectors processed at all */
|
||||
unsigned int dasd_io_secs[32]; /* request's sizes */
|
||||
unsigned int dasd_io_times[32]; /* requests's times */
|
||||
unsigned int dasd_io_timps[32]; /* requests's times per sector */
|
||||
unsigned int dasd_io_time1[32]; /* time from build to start */
|
||||
unsigned int dasd_io_time2[32]; /* time from start to irq */
|
||||
unsigned int dasd_io_time2ps[32]; /* time from start to irq */
|
||||
unsigned int dasd_io_time3[32]; /* time from irq to end */
|
||||
unsigned int dasd_io_nr_req[32]; /* # of requests in chanq */
|
||||
} dasd_profile_info_t;
|
||||
|
||||
/*
|
||||
* struct attrib_data_t
|
||||
* represents the operation (cache) bits for the device.
|
||||
* Used in DE to influence caching of the DASD.
|
||||
*/
|
||||
typedef struct attrib_data_t {
|
||||
unsigned char operation : 3; /* cache operation mode */
|
||||
unsigned char reserved : 5;
|
||||
unsigned short nr_cyl; /* no of cyliners for read ahaed */
|
||||
unsigned char reserved2[29]; /* for future use */
|
||||
} __attribute__((packed)) attrib_data_t;
|
||||
|
||||
/* definition of operation (cache) bits within attributes of DE */
|
||||
#define DASD_NORMAL_CACHE 0x0
|
||||
#define DASD_BYPASS_CACHE 0x1
|
||||
#define DASD_INHIBIT_LOAD 0x2
|
||||
#define DASD_SEQ_ACCESS 0x3
|
||||
#define DASD_SEQ_PRESTAGE 0x4
|
||||
#define DASD_REC_ACCESS 0x5
|
||||
|
||||
/*
|
||||
* Data returned by Sense Path Group ID (SNID)
|
||||
*/
|
||||
struct dasd_snid_data {
|
||||
struct {
|
||||
__u8 group : 2;
|
||||
__u8 reserve : 2;
|
||||
__u8 mode : 1;
|
||||
__u8 res : 3;
|
||||
} __attribute__((packed)) path_state;
|
||||
__u8 pgid[11];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dasd_snid_ioctl_data {
|
||||
struct dasd_snid_data data;
|
||||
__u8 path_mask;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct dasd_copypair_swap_data {
|
||||
char primary[DASD_BUS_ID_SIZE]; /* BUSID of primary */
|
||||
char secondary[DASD_BUS_ID_SIZE]; /* BUSID of secondary */
|
||||
/* Reserved for future updates. */
|
||||
char reserved[64];
|
||||
};
|
||||
|
||||
#ifndef __linux__
|
||||
/* definition from hdreg.h */
|
||||
struct hd_geometry {
|
||||
@@ -207,27 +269,29 @@ struct hd_geometry {
|
||||
#define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2)
|
||||
/* Release the device for the current LPAR */
|
||||
#define BIODASDRLSE _IO(DASD_IOCTL_LETTER, 3)
|
||||
/* Unconditional reserve the device for the current LPAR */
|
||||
#define BIODASDSLCK _IO(DASD_IOCTL_LETTER, 4)
|
||||
/* reset profiling information of a device */
|
||||
#define BIODASDPRRST _IO(DASD_IOCTL_LETTER, 5)
|
||||
/* retrieve profiling information of a device */
|
||||
#define BIODASDPRRD _IOR(DASD_IOCTL_LETTER, 2, dasd_profile_info_t)
|
||||
/* Get information on a dasd device (enhanced) */
|
||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
|
||||
/* Get Attributes (cache operations) */
|
||||
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER, 5, attrib_data_t)
|
||||
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
|
||||
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER, 1, format_data_t)
|
||||
/* Set Attributes (cache operations) */
|
||||
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER, 2, attrib_data_t)
|
||||
/* Release Allocated Space */
|
||||
#define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t)
|
||||
/* Swap copy pair */
|
||||
#define BIODASDPPRCSWAP _IOW(DASD_IOCTL_LETTER, 4, struct dasd_copypair_swap_data)
|
||||
/* Get Sense Path Group ID (SNID) data */
|
||||
#define BIODASDSNID _IOWR(DASD_IOCTL_LETTER, 1, struct dasd_snid_ioctl_data)
|
||||
/* Check device format according to format_data_t */
|
||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
|
||||
|
||||
/********************************************************************************
|
||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h)
|
||||
*******************************************************************************/
|
||||
/* get read-only status (0 = read_write) */
|
||||
#define BLKROGET _IO(0x12, 94)
|
||||
/* re-read partition table */
|
||||
#define BLKRRPART _IO(0x12, 95)
|
||||
/* get block device sector size */
|
||||
#define BLKSSZGET _IO(0x12, 104)
|
||||
/* return device size in bytes (u64 *arg) */
|
||||
#define BLKGETSIZE64 _IOR(0x12, 114, size_t)
|
||||
|
||||
#ifndef __linux__ /* from <linux/hdreg.h> */
|
||||
#define HDIO_GETGEO 0x0301
|
||||
#endif
|
||||
@@ -245,5 +309,12 @@ int dasd_is_ro(const char *device, bool *ro);
|
||||
int dasd_reread_partition_table(const char *device, int ntries);
|
||||
int dasd_disk_reserve(const char *device);
|
||||
int dasd_disk_release(const char *device);
|
||||
int dasd_slock(const char *device);
|
||||
int dasd_get_cache(const char *device, attrib_data_t *attrib_data);
|
||||
int dasd_set_cache(const char *device, attrib_data_t *attrib_data);
|
||||
int dasd_query_reserve(const char *device);
|
||||
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info);
|
||||
int dasd_reset_profile(const char *device);
|
||||
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data);
|
||||
|
||||
#endif /* LIB_DASD_BASE_H */
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||
#define S390_SYSFS_PAI_CRYPTO "/sys/devices/pai_crypto/"
|
||||
#define S390_SYSFS_PAI_NNPA "/sys/devices/pai_nnpa/"
|
||||
#define S390_SYSFS_PAI_EXT "/sys/devices/pai_ext/"
|
||||
#define S390_SYSFS_PAI_NNPA S390_SYSFS_PAI_EXT "events/NNPA_ALL"
|
||||
|
||||
/**
|
||||
* Read out the PMU type from a given file.
|
||||
@@ -146,6 +147,14 @@ bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
|
||||
*/
|
||||
bool libcpumf_have_pai_crypto(void);
|
||||
|
||||
/**
|
||||
* Return true if PAI_EXTENSION Facility is supported.
|
||||
*
|
||||
* @retval true PAI_EXTENSION counter Facility is available
|
||||
* @retval false PAI_EXTENSION counter Facility is not available
|
||||
*/
|
||||
bool libcpumf_have_pai_ext(void);
|
||||
|
||||
/**
|
||||
* Return true if PAI_NNPA counter Facility is supported. This PMU facility
|
||||
* supports the Neural Network Processing Assist (NNPA) counter set.
|
||||
|
||||
26
include/lib/util_lockfile.h
Normal file
26
include/lib/util_lockfile.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @defgroup util_lockfile_h util_lockfile: File locking utility
|
||||
* @{
|
||||
* @brief Create file-based locks
|
||||
*
|
||||
* 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 LIB_UTIL_LOCKFILE_H
|
||||
#define LIB_UTIL_LOCKFILE_H
|
||||
|
||||
#define UTIL_LOCKFILE_OK 0 /* Lock acquired/released successfully */
|
||||
#define UTIL_LOCKFILE_LOCK_FAIL 1 /* Lock already held, ran out of retries */
|
||||
#define UTIL_LOCKFILE_RELEASE_NONE 2 /* Lock not held */
|
||||
#define UTIL_LOCKFILE_RELEASE_FAIL 3 /* Lock not held by specified pid */
|
||||
#define UTIL_LOCKFILE_ERR 4 /* Other, unexpected error conditions */
|
||||
|
||||
int util_lockfile_lock(char *lockfile, int retries);
|
||||
int util_lockfile_parent_lock(char *lockfile, int retries);
|
||||
|
||||
int util_lockfile_release(char *lockfile);
|
||||
int util_lockfile_parent_release(char *lockfile);
|
||||
|
||||
#endif /** LIB_UTIL_LOCKFILE_H @} */
|
||||
@@ -97,6 +97,24 @@ typedef struct volume_label
|
||||
unsigned long long formatted_blocks; /* valid when ldl_version >= f2 */
|
||||
} __attribute__ ((packed)) volume_label_t;
|
||||
|
||||
/**
|
||||
* This represents a volume label specific for OS/390 compatible disk layout
|
||||
*/
|
||||
struct vol_label_cdl {
|
||||
char volkey[4];
|
||||
char vollbl[4];
|
||||
char opaq[70];
|
||||
cchhb_t br; /* boot record address */
|
||||
char stdv[1]; /* standard version ID */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static inline int is_vol1(char *this)
|
||||
{
|
||||
char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00} /* "VOL1" in EBCDIC */;
|
||||
|
||||
return !strncmp(this, vol1, 4);
|
||||
}
|
||||
|
||||
typedef struct extent
|
||||
{
|
||||
u_int8_t typeind; /* extent type indicator */
|
||||
|
||||
@@ -21,15 +21,21 @@
|
||||
* Usage example:
|
||||
* #define IMAGE_ENTRY _AC(0x10000, UL)
|
||||
*/
|
||||
#ifndef _AC
|
||||
#ifdef __ASSEMBLER__
|
||||
#define _AC(X, TYPE) X
|
||||
#else
|
||||
#define _AC(X, TYPE) X##TYPE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef __ASSEMBLER__
|
||||
|
||||
#ifndef sizeof_field
|
||||
#define sizeof_field(type, field) (sizeof((type *)0)->field)
|
||||
#endif
|
||||
|
||||
#ifdef UNUSED
|
||||
#elif defined(__GNUC__)
|
||||
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||
@@ -48,6 +54,10 @@
|
||||
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
||||
|
||||
#ifndef ROUNDUP
|
||||
# define ROUNDUP(x, y) ((((x) + ((y) - 1)) / (y)) * (y))
|
||||
#endif
|
||||
|
||||
#define RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
|
||||
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
||||
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
||||
@@ -60,6 +70,7 @@
|
||||
#define __may_alias __attribute__((may_alias))
|
||||
#define __section(x) __attribute__((__section__(#x)))
|
||||
#define __noinline __attribute__((__noinline__))
|
||||
#define __big_endian
|
||||
/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
||||
* __always_inline. Therefore undefine it first to allow the headers
|
||||
* to be included first.
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef enum {
|
||||
PV_CERT_ERROR_MALFORMED_ROOT_CA,
|
||||
PV_CERT_ERROR_NO_CRL,
|
||||
PV_CERT_ERROR_NO_CRLDP,
|
||||
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
||||
PV_CERT_ERROR_NO_PUBLIC_KEY,
|
||||
PV_CERT_ERROR_READ_CERTIFICATE,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
#include "libpv/glib-helper.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
#include "libpv/openssl-compat.h"
|
||||
#include "libpv/macros.h"
|
||||
|
||||
@@ -42,11 +42,14 @@ enum PvCryptoMode {
|
||||
PV_DECRYPT,
|
||||
};
|
||||
|
||||
/** pv_get_openssl_error:
|
||||
/** pv_get_openssl_errors:
|
||||
*
|
||||
* Returns: (transfer full): String representing the error.
|
||||
* Returns the last OpenSSL error messages.
|
||||
* Caller is responsible to free the returned value.
|
||||
*
|
||||
* Returns: String representing the error.
|
||||
*/
|
||||
const char *pv_get_openssl_error(void);
|
||||
char *pv_get_openssl_errors(void);
|
||||
|
||||
/**
|
||||
* pv_BIO_reset:
|
||||
@@ -181,7 +184,6 @@ typedef enum {
|
||||
PV_CRYPTO_ERROR_KEYGENERATION,
|
||||
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||
PV_CRYPTO_ERROR_READ_FILE,
|
||||
PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
PV_CRYPTO_ERROR_NO_MATCH_TAG,
|
||||
} PvCryptoErrors;
|
||||
|
||||
|
||||
@@ -18,6 +18,12 @@
|
||||
#define GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_2_56
|
||||
#endif
|
||||
|
||||
#define GLIB_VERSION_MAX_ALLOWED GLIB_VERSION_2_56
|
||||
|
||||
#ifdef __G_LIB_H__
|
||||
#error "glib.h must be included via libpv/glib-helper.h"
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <gmodule.h>
|
||||
#include <stdio.h>
|
||||
@@ -102,9 +108,12 @@ FILE *pv_file_open(const char *filename, const char *mode, GError **error);
|
||||
|
||||
/** pv_gbytes_memcpy:
|
||||
*
|
||||
* memcpy with size check.
|
||||
* memcpy with size check. In case @dst_size is smaller than the size of @src
|
||||
* the error value %NULL is returned and @copied and @dst are left unchanged.
|
||||
*
|
||||
* If @dst and @src data overlap, the behavior is undefined.
|
||||
*/
|
||||
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src);
|
||||
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src, size_t *copied);
|
||||
|
||||
#define PV_GLIB_HELPER_ERROR g_quark_from_static_string("pv-glib-helper_error-quark")
|
||||
typedef enum {
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
#ifndef LIBPV_MACROS_H
|
||||
#define LIBPV_MACROS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PV_NONNULL(...)
|
||||
#define DO_PRAGMA(x) _Pragma(#x)
|
||||
|
||||
/* Most significant bit */
|
||||
#define PV_MSB(idx) ((uint64_t)1 << (63 - (idx)))
|
||||
|
||||
#endif /* LIBPV_MACROS_H */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "boot/s390.h"
|
||||
#include "libpv/crypto.h"
|
||||
#include "libpv/macros.h"
|
||||
|
||||
/* Magic number which is used to identify the file containing the PV
|
||||
* header
|
||||
@@ -22,20 +23,17 @@
|
||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||
#define PV_VERSION_1 0x00000100U
|
||||
|
||||
/* Internal helper macro */
|
||||
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
|
||||
|
||||
/* Plaintext control flags */
|
||||
/* dumping of the configuration is allowed */
|
||||
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34)
|
||||
#define PV_PCF_ALLOW_DUMPING PV_MSB(34)
|
||||
/* prevent Ultravisor decryption during unpack operation */
|
||||
#define PV_PCF_NO_DECRYPTION __PV_BIT(35)
|
||||
#define PV_PCF_NO_DECRYPTION PV_MSB(35)
|
||||
/* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56)
|
||||
#define PV_PCF_PCKMO_DEA_TDEA PV_MSB(56)
|
||||
/* PCKMO encrypt-AES-key functions allowed */
|
||||
#define PV_PCF_PCKMO_AES __PV_BIT(57)
|
||||
#define PV_PCF_PCKMO_AES PV_MSB(57)
|
||||
/* PCKMO encrypt-ECC-key functions allowed */
|
||||
#define PV_PCF_PCKM_ECC __PV_BIT(58)
|
||||
#define PV_PCF_PCKM_ECC PV_MSB(58)
|
||||
|
||||
/* maxima for the PV version 1 */
|
||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||
|
||||
@@ -12,7 +12,7 @@ clean:
|
||||
install: ip_watcher.pl xcec-bridge start_hsnc.sh
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< start_hsnc.sh >$(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/start_hsnc.sh; \
|
||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 ip_watcher.pl \
|
||||
$(DESTDIR)$(USRSBINDIR)
|
||||
|
||||
@@ -23,12 +23,15 @@
|
||||
#define BOOTPARMS_CCW_MAX 64
|
||||
#define BOOTPARMS_FCP_MAX 3452
|
||||
|
||||
#define OPT_BRCHR 0x80
|
||||
|
||||
enum target_type {
|
||||
TT_CCW,
|
||||
TT_FCP,
|
||||
TT_NSS,
|
||||
TT_NODE,
|
||||
TT_NVME,
|
||||
TT_ECKD,
|
||||
};
|
||||
|
||||
enum reipl_type {
|
||||
@@ -36,12 +39,14 @@ enum reipl_type {
|
||||
REIPL_CCW,
|
||||
REIPL_NSS,
|
||||
REIPL_NVME,
|
||||
REIPL_ECKD,
|
||||
};
|
||||
|
||||
static const char *const usage_chreipl =
|
||||
"Usage: %s [TARGET] [ARGS] [OPTIONS]\n"
|
||||
"\n"
|
||||
" chreipl [ccw] [-d] <DEVICE> [OPTIONS]\n"
|
||||
" chreipl [eckd] [-d] <DEVICE> [OPTIONS]\n"
|
||||
" chreipl [fcp] [-d] <DEVICE> [-w] <WWPN> [-l] <LUN> [OPTIONS]\n"
|
||||
" chreipl nvme [-i] <FID> [-s] <NSID> [OPTIONS]\n"
|
||||
" chreipl [node] <NODE|DIR> [OPTIONS]\n"
|
||||
@@ -50,6 +55,7 @@ static const char *const usage_chreipl =
|
||||
"\n"
|
||||
"The following re-IPL targets are supported:\n"
|
||||
" ccw IPL from CCW device\n"
|
||||
" eckd IPL from ECKD device\n"
|
||||
" fcp IPL from FCP device\n"
|
||||
" nvme IPL from NVME device\n"
|
||||
" nss IPL from NSS\n"
|
||||
@@ -66,6 +72,13 @@ static const char *const usage_chreipl =
|
||||
" -L, --loadparm <PARM> Loadparm specification\n"
|
||||
" -c, --clear 0|1 Control if memory is cleared on re-IPL\n"
|
||||
"\n"
|
||||
"Options for eckd target:\n"
|
||||
" -d, --device <DEVICE> Device number of the ECKD IPL device\n"
|
||||
" -b, --bootprog <BPROG> Bootprog specification\n"
|
||||
" --brchr <C,H,R> Boot record location in Cylinder,Head,Record format\n"
|
||||
" -L, --loadparm <PARM> Loadparm specification\n"
|
||||
" -c, --clear 0|1 Control if memory is cleared on re-IPL\n"
|
||||
"\n"
|
||||
"Options for fcp target:\n"
|
||||
" -d, --device <DEVICE> Device number of the adapter of the FCP IPL device\n"
|
||||
" -l --lun <LUN> Logical unit number of the FCP IPL device\n"
|
||||
@@ -114,6 +127,8 @@ static struct locals {
|
||||
int target_type_auto_mode;
|
||||
enum reipl_type reipl_type; /* CCW, FCP, NVME, NSS */
|
||||
int reipl_clear;
|
||||
char *brchr;
|
||||
int brchr_set;
|
||||
} l;
|
||||
|
||||
static void __noreturn print_usage_chreipl_exit(void)
|
||||
@@ -329,6 +344,19 @@ static void parse_ccw_args(char *nargv[], int nargc)
|
||||
set_device(nargv[0]);
|
||||
}
|
||||
|
||||
static void parse_eckd_args(char *nargv[], int nargc)
|
||||
{
|
||||
/*
|
||||
* we might be called like this:
|
||||
* chreipl eckd 4711
|
||||
*/
|
||||
if (l.busid_set)
|
||||
ERR_EXIT("Use either options or positional parameters");
|
||||
if (nargc > 1)
|
||||
ERR_EXIT("Too many arguments specified for \"eckd\" re-IPL type");
|
||||
set_device(nargv[0]);
|
||||
}
|
||||
|
||||
static void parse_nss_args(char *nargv[], int nargc)
|
||||
{
|
||||
/*
|
||||
@@ -369,6 +397,8 @@ static int set_reipl_type(const char *dev_name)
|
||||
l.reipl_type = REIPL_FCP;
|
||||
else if (strncmp(dev_name, "nvme", strlen("nvme")) == 0)
|
||||
l.reipl_type = REIPL_NVME;
|
||||
else if (strncmp(dev_name, "eckd", strlen("eckd")) == 0)
|
||||
l.reipl_type = REIPL_ECKD;
|
||||
else
|
||||
return -1;
|
||||
|
||||
@@ -493,12 +523,15 @@ static void parse_pos_args(char *nargv[], int nargc)
|
||||
case TT_NODE:
|
||||
parse_node_args(nargv, nargc);
|
||||
break;
|
||||
case TT_ECKD:
|
||||
parse_eckd_args(nargv, nargc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_fcp_opts(void)
|
||||
{
|
||||
if (l.nss_name_set)
|
||||
if (l.nss_name_set || l.brchr_set)
|
||||
ERR_EXIT("Invalid option for \"fcp\" target specified");
|
||||
if (!(l.busid_set && l.wwpn_set && l.lun_set))
|
||||
ERR_EXIT("The \"fcp\" target requires device, WWPN, "
|
||||
@@ -507,7 +540,8 @@ static void check_fcp_opts(void)
|
||||
|
||||
static void check_nvme_opts(void)
|
||||
{
|
||||
if (l.nss_name_set || l.wwpn_set || l.lun_set || l.busid_set)
|
||||
if (l.nss_name_set || l.wwpn_set || l.lun_set || l.busid_set ||
|
||||
l.brchr_set)
|
||||
ERR_EXIT("Invalid option for \"nvme\" target specified");
|
||||
if (!(l.fid_set && l.nsid_set))
|
||||
ERR_EXIT("The \"nvme\" target requires FID, and optional NSID");
|
||||
@@ -515,16 +549,25 @@ static void check_nvme_opts(void)
|
||||
|
||||
static void check_ccw_opts(void)
|
||||
{
|
||||
if (l.bootprog_set || l.lun_set || l.wwpn_set || l.nss_name_set)
|
||||
if (l.bootprog_set || l.lun_set || l.wwpn_set || l.nss_name_set ||
|
||||
l.brchr_set)
|
||||
ERR_EXIT("Invalid option for \"ccw\" target specified");
|
||||
if (!l.busid_set)
|
||||
ERR_EXIT("The \"ccw\" target requires device");
|
||||
}
|
||||
|
||||
static void check_eckd_opts(void)
|
||||
{
|
||||
if (l.nss_name_set || l.wwpn_set || l.lun_set || l.fid_set)
|
||||
ERR_EXIT("Invalid option for \"eckd\" target specified");
|
||||
if (!(l.busid_set))
|
||||
ERR_EXIT("The \"eckd\" target requires device");
|
||||
}
|
||||
|
||||
static void check_nss_opts(void)
|
||||
{
|
||||
if (l.bootprog_set || l.loadparm_set || l.busid_set || l.wwpn_set ||
|
||||
l.lun_set)
|
||||
l.lun_set || l.brchr_set)
|
||||
ERR_EXIT("Invalid option for \"nss\" target specified");
|
||||
if (!l.nss_name_set)
|
||||
ERR_EXIT("The \"nss\" target requires NSS name");
|
||||
@@ -563,6 +606,12 @@ static void set_reipl_clear(const char *arg)
|
||||
ERR_EXIT("re-IPL clear argument must be either 1 or 0");
|
||||
}
|
||||
|
||||
static void set_brchr(const char *arg)
|
||||
{
|
||||
l.brchr = strdup(arg);
|
||||
l.brchr_set = 1;
|
||||
}
|
||||
|
||||
static void parse_chreipl_options(int argc, char *argv[])
|
||||
{
|
||||
int opt, idx;
|
||||
@@ -580,6 +629,7 @@ static void parse_chreipl_options(int argc, char *argv[])
|
||||
{ "force", no_argument, NULL, 'f' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "clear", required_argument, NULL, 'c' },
|
||||
{ "brchr", required_argument, NULL, OPT_BRCHR },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
static const char optstr[] = "hd:vw:l:fL:b:n:p:c:i:s:";
|
||||
@@ -592,6 +642,8 @@ static void parse_chreipl_options(int argc, char *argv[])
|
||||
set_target_type(TT_FCP, 0);
|
||||
else if (strcmp(argv[1], "ccw") == 0)
|
||||
set_target_type(TT_CCW, 0);
|
||||
else if (strcmp(argv[1], "eckd") == 0)
|
||||
set_target_type(TT_ECKD, 0);
|
||||
else if (strcmp(argv[1], "nss") == 0)
|
||||
set_target_type(TT_NSS, 0);
|
||||
else if (strcmp(argv[1], "nvme") == 0)
|
||||
@@ -640,6 +692,9 @@ static void parse_chreipl_options(int argc, char *argv[])
|
||||
case 'c':
|
||||
set_reipl_clear(optarg);
|
||||
break;
|
||||
case OPT_BRCHR:
|
||||
set_brchr(optarg);
|
||||
break;
|
||||
case 'v':
|
||||
print_version_exit();
|
||||
default:
|
||||
@@ -737,6 +792,34 @@ static void chreipl_ccw(void)
|
||||
print_ccw(0);
|
||||
}
|
||||
|
||||
static void chreipl_eckd(void)
|
||||
{
|
||||
check_eckd_opts();
|
||||
|
||||
if (!ccw_is_device(l.busid) && !l.force_set) {
|
||||
if (is_ignored(l.busid))
|
||||
ERR_EXIT("Device is on cio_ignore list, try \"cio_ignore -r %s\"?",
|
||||
l.busid);
|
||||
ERR_EXIT("Could not find DASD ECKD device \"%s\"", l.busid);
|
||||
}
|
||||
|
||||
if (l.reipl_clear >= 0) {
|
||||
check_exists("reipl/eckd/clear", "ECKD re-IPL clear attribute");
|
||||
write_str(l.reipl_clear ? "1" : "0", "reipl/eckd/clear");
|
||||
}
|
||||
|
||||
if (!l.brchr_set)
|
||||
l.brchr = "auto";
|
||||
write_str(l.brchr, "reipl/eckd/br_chr");
|
||||
if (!l.bootprog_set)
|
||||
sprintf(l.bootprog, "0");
|
||||
write_str(l.bootprog, "reipl/eckd/bootprog");
|
||||
write_str(l.busid, "reipl/eckd/device");
|
||||
write_str_optional(l.loadparm, "reipl/eckd/loadparm", l.loadparm_set, "loadparm");
|
||||
write_str("eckd", "reipl/reipl_type");
|
||||
print_eckd(0, "eckd");
|
||||
}
|
||||
|
||||
static void chreipl_fcp(void)
|
||||
{
|
||||
check_fcp_opts();
|
||||
@@ -850,6 +933,11 @@ static void chreipl_node(void)
|
||||
l.busid_set = 1;
|
||||
chreipl_ccw();
|
||||
break;
|
||||
case REIPL_ECKD:
|
||||
ccw_busid_get(l.dev, l.busid);
|
||||
l.busid_set = 1;
|
||||
chreipl_eckd();
|
||||
break;
|
||||
case REIPL_FCP:
|
||||
fcp_wwpn_get(l.dev, l.wwpn);
|
||||
l.wwpn_set = 1;
|
||||
@@ -878,6 +966,9 @@ void cmd_chreipl(int argc, char *argv[])
|
||||
case TT_CCW:
|
||||
chreipl_ccw();
|
||||
break;
|
||||
case TT_ECKD:
|
||||
chreipl_eckd();
|
||||
break;
|
||||
case TT_FCP:
|
||||
chreipl_fcp();
|
||||
break;
|
||||
|
||||
@@ -141,6 +141,30 @@ void print_ccw(int show_ipl)
|
||||
print_fw_str("clear: %s\n", dir, "clear");
|
||||
}
|
||||
|
||||
void print_eckd(int show_ipl, const char *name)
|
||||
{
|
||||
char *path_loadparm = show_ipl ? "/sys/firmware/ipl/loadparm" :
|
||||
"/sys/firmware/reipl/eckd/loadparm";
|
||||
char *dir = show_ipl ? "ipl" : "reipl/eckd";
|
||||
char loadparm[9], loadparm_path[PATH_MAX];
|
||||
|
||||
printf("%-12s %s\n", get_ipl_banner(show_ipl), name);
|
||||
|
||||
print_fw_str("Device: %s\n", dir, "device");
|
||||
print_fw_str("bootprog: %s\n", dir, "bootprog");
|
||||
print_fw_str("br_chr: %s\n", dir, "br_chr");
|
||||
print_fw_str("Bootparm: \"%s\"\n", dir, "scp_data");
|
||||
if (access(path_loadparm, R_OK) == 0) {
|
||||
sprintf(loadparm_path, "%s/%s", dir, "loadparm");
|
||||
read_fw_str(loadparm, loadparm_path, sizeof(loadparm));
|
||||
if (strcmp(loadparm, " ") == 0)
|
||||
loadparm[0] = 0;
|
||||
printf("Loadparm: \"%s\"\n", loadparm);
|
||||
}
|
||||
if (!show_ipl)
|
||||
print_fw_str("clear: %s\n", dir, "clear");
|
||||
}
|
||||
|
||||
static void parse_lsreipl_options(int argc, char *argv[])
|
||||
{
|
||||
int opt, idx;
|
||||
@@ -193,6 +217,9 @@ void cmd_lsreipl(int argc, char *argv[])
|
||||
print_nvme(l.ipl_set, 1);
|
||||
else if (strcmp(reipl_type_str, "ccw") == 0)
|
||||
print_ccw(l.ipl_set);
|
||||
else if (strcmp(reipl_type_str, "eckd") == 0 ||
|
||||
strcmp(reipl_type_str, "eckd_dump") == 0)
|
||||
print_eckd(l.ipl_set, reipl_type_str);
|
||||
else if (strcmp(reipl_type_str, "nss") == 0)
|
||||
print_nss(l.ipl_set);
|
||||
else
|
||||
|
||||
@@ -45,6 +45,7 @@ extern void print_ccw(int show_ipl);
|
||||
extern void print_fcp(int show_ipl, int dump);
|
||||
extern void print_nvme(int show_ipl, int dump);
|
||||
extern void print_nss(int show_ipl);
|
||||
extern void print_eckd(int show_ipl, const char *name);
|
||||
|
||||
/*
|
||||
* Helper
|
||||
@@ -75,6 +76,7 @@ extern void fcp_busid_get(const char *device, char *devno);
|
||||
* NVME
|
||||
*/
|
||||
#define FID_MAX_LEN 11 /* 8 characters + 0x + null */
|
||||
#define NVME_DEV_MAX_LEN 15 /* "nvme" + u32 in decimal + null */
|
||||
#define NVME_PATH_MAX (PATH_MAX + NAME_MAX + 1)
|
||||
|
||||
extern void nvme_fid_get(const char *device, char *fid);
|
||||
|
||||
@@ -36,6 +36,9 @@ The first argument specifies the re-IPL target:
|
||||
.RB "- " ccw :
|
||||
Specify a DASD CCW device for reboot
|
||||
.TP
|
||||
.RB "- " eckd :
|
||||
Specify a DASD ECKD device for reboot
|
||||
.TP
|
||||
.RB "- " fcp :
|
||||
Specify a FCP device for reboot
|
||||
.TP
|
||||
@@ -175,6 +178,63 @@ in the installed zIPL environment block for evaluation of zIPL environment
|
||||
variables in the kernel command line:
|
||||
|
||||
\fB# chreipl ccw -d 0.0.7e78 -L 1S2\fP
|
||||
|
||||
.SH eckd
|
||||
Use the eckd re-IPL target for DASD devices that are accessed by the hardware
|
||||
using channel command word (CCW) channels. In contrast to the ccw re-IPL target,
|
||||
the eckd target uses a list-directed bootloader that supports secure boot.
|
||||
.TP
|
||||
.BR "\-d" " or " "\-\-device"
|
||||
Specifies the device bus-ID of the DASD. If the bus-ID starts with "0.0." this
|
||||
prefix can be omitted and the four digit short notation can be used (e.g. 5000 is
|
||||
the same as 0.0.5000).
|
||||
|
||||
.TP
|
||||
.BR "\-b" " or " "\-\-bootprog"
|
||||
Specifies an entry in the ECKD boot configuration by defining the IPL boot
|
||||
program selector. If omitted, '0' is used.
|
||||
|
||||
.TP
|
||||
.BR "\-\-brchr"
|
||||
Specifies the block on the DASD where the boot record is located. If omitted,
|
||||
0 is used. The specification comprises comma-separated values for cylinder, head,
|
||||
and record: "--brchr C,H,R". Alternatively, specifying "0" or "auto" makes the
|
||||
bootloader determine the boot record location from the volume label.
|
||||
|
||||
.TP
|
||||
.BR "\-L" " or " "\-\-loadparm"
|
||||
The loadparm for the eckd re-IPL target is not used to control the ECKD boot
|
||||
configuration that is defined by the
|
||||
.BR zipl (8)
|
||||
boot menu. Instead it can be used to control higher level boot loaders
|
||||
like GRUB. For more details refer to distribution specific documentation.
|
||||
|
||||
.TP
|
||||
.BR "\-c" " or " "\-\-clear"
|
||||
Controls whether memory is cleared on re-IPL. Possible values are 0 to
|
||||
disable and 1 to enable memory clearing on re-IPL.
|
||||
Memory clearing is supported if the "clear" attribute is present in
|
||||
/sys/firmware/reipl/eckd/.
|
||||
|
||||
.PP
|
||||
\fBExamples:\fP
|
||||
.br
|
||||
|
||||
1. Next time reboot from the ECKD device with the bus-ID 0.0.7e78 and boot
|
||||
program selector 0:
|
||||
|
||||
\fB# chreipl eckd 0.0.7e78\fP
|
||||
|
||||
2. Next time reboot from the ECKD device with the bus-ID 0.0.7e78 and boot
|
||||
program selector 2:
|
||||
|
||||
\fB# chreipl eckd -d 0.0.7e78 -b 2\fP
|
||||
|
||||
3. Next time reboot from the ECKD device with the bus-ID 0.0.7e78 and tell
|
||||
the bootloader that the bootrecord is located in Cylinder 3, Head 0, Record 1:
|
||||
|
||||
\fB# chreipl eckd -d 0.0.7e78 --brchr 3,0,1\fP
|
||||
|
||||
.SH fcp
|
||||
Use the fcp re-IPL target for SCSI disks that are accessed by the hardware
|
||||
using Fibre Channel Protocol (FCP) channels.
|
||||
|
||||
@@ -18,15 +18,31 @@
|
||||
#include "lib/util_file.h"
|
||||
#include "ipl_tools.h"
|
||||
|
||||
static void nvme_dev_from_bdev(char *dev_name)
|
||||
{
|
||||
char *delim = strrchr(dev_name, 'n');
|
||||
|
||||
if (delim)
|
||||
*delim = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fid of a device
|
||||
*/
|
||||
void nvme_fid_get(const char *device, char *fid)
|
||||
{
|
||||
char path[PATH_MAX], buf[FID_MAX_LEN];
|
||||
char nvme_dev[NVME_DEV_MAX_LEN];
|
||||
|
||||
snprintf(path, PATH_MAX, "/sys/block/%s/device/device/function_id",
|
||||
device);
|
||||
/*
|
||||
* An NVMe may present multiple namespaces and thus block devices, even
|
||||
* before partitioning, so we need the nvme<NUM> part of the block
|
||||
* device name to get to the PCI function ID.
|
||||
*/
|
||||
util_strlcpy(nvme_dev, device, sizeof(nvme_dev));
|
||||
nvme_dev_from_bdev(nvme_dev);
|
||||
|
||||
snprintf(path, PATH_MAX, "/sys/class/nvme/%s/device/function_id", nvme_dev);
|
||||
if (util_file_read_line(buf, FID_MAX_LEN, path))
|
||||
ERR_EXIT_ERRNO("Could not read from \"%s\"", path);
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ extern ssize_t __write(int, const void*, size_t);
|
||||
extern int strmatch(const char *, const char *);
|
||||
extern int is_regex_valid(const char *);
|
||||
extern int is_client_allowed(const char *, const struct iucvterm_cfg *);
|
||||
extern void userid_cpy(char [8], const char [8]);
|
||||
extern void userid_cpy(char [9], const char [8]);
|
||||
|
||||
extern void iucv_msg_error(const char *, uint32_t);
|
||||
extern void program_error(const char *, const char *);
|
||||
|
||||
@@ -2,17 +2,6 @@ include ../common.mak
|
||||
|
||||
lib = libap.a
|
||||
|
||||
check-dep-lock:
|
||||
touch check-dep-lock
|
||||
ifneq (${HAVE_LOCKFILE},0)
|
||||
$(call check_dep, \
|
||||
"libap", \
|
||||
"lockfile.h", \
|
||||
"liblockfile-devel", \
|
||||
"HAVE_LOCKFILE=0")
|
||||
ALL_CPPFLAGS += -DHAVE_LOCKFILE
|
||||
endif
|
||||
|
||||
check-dep-json:
|
||||
touch check-dep-json
|
||||
ifneq (${HAVE_JSONC},0)
|
||||
@@ -29,7 +18,7 @@ objects = ap.o
|
||||
|
||||
$(lib): $(objects)
|
||||
|
||||
$(objects): check-dep-lock check-dep-json
|
||||
$(objects): check-dep-json
|
||||
|
||||
install: all
|
||||
|
||||
|
||||
45
libap/ap.c
45
libap/ap.c
@@ -22,13 +22,10 @@
|
||||
#include <json-c/json.h>
|
||||
#endif /* HAVE_JSONC */
|
||||
|
||||
#ifdef HAVE_LOCKFILE
|
||||
#include <lockfile.h>
|
||||
#endif /* HAVE_LOCKFILE */
|
||||
|
||||
#include "lib/ap.h"
|
||||
#include "lib/util_file.h"
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_lockfile.h"
|
||||
#include "lib/util_panic.h"
|
||||
#include "lib/util_path.h"
|
||||
#include "lib/util_udev.h"
|
||||
@@ -701,33 +698,28 @@ void ap_list_remove_all(struct util_list *list)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_LOCKFILE
|
||||
static int ap_lockfile_create(int flags)
|
||||
{
|
||||
return lockfile_create(AP_LOCKFILE, AP_LOCK_RETRIES, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire the ap config lock using this process PID (L_PID)
|
||||
* Acquire the ap config lock using this Process ID
|
||||
*
|
||||
* @retval 0 Lock acquired on behalf of this process
|
||||
*
|
||||
* @retval 0 Lock successfully acquired on behalf of L_PID
|
||||
* @retval != 0 Error, lock was not obtained
|
||||
*/
|
||||
int ap_get_lock(void)
|
||||
{
|
||||
return ap_lockfile_create(L_PID);
|
||||
return util_lockfile_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Acquire the ap config lock using the parent process PID (L_PPID) -- intended
|
||||
* for use by the mdevctl callout ap-check utility
|
||||
* Acquire the ap config lock using the Parent Process ID -- intended for use
|
||||
* by the mdevctl callout ap-check utility
|
||||
*
|
||||
* @retval 0 Lock successfully acquired on behalf of L_PPID
|
||||
* @retval 0 Lock acquired on behalf of parent process
|
||||
* @retval != 0 Error, lock was not obtained
|
||||
*/
|
||||
int ap_get_lock_callout(void)
|
||||
{
|
||||
return ap_lockfile_create(L_PPID);
|
||||
return util_lockfile_parent_lock(AP_LOCKFILE, AP_LOCK_RETRIES);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -738,23 +730,10 @@ int ap_get_lock_callout(void)
|
||||
*/
|
||||
int ap_release_lock(void)
|
||||
{
|
||||
return lockfile_remove(AP_LOCKFILE);
|
||||
}
|
||||
#else
|
||||
/* If no liblockfile, actions are performed without acquiring the file lock */
|
||||
int ap_get_lock(void)
|
||||
{
|
||||
return 0;
|
||||
return util_lockfile_release(AP_LOCKFILE);
|
||||
}
|
||||
|
||||
int ap_get_lock_callout(void)
|
||||
int ap_release_lock_callout(void)
|
||||
{
|
||||
return 0;
|
||||
return util_lockfile_parent_release(AP_LOCKFILE);
|
||||
}
|
||||
|
||||
int ap_release_lock(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LOCKFILE */
|
||||
|
||||
@@ -85,5 +85,6 @@ int main(void)
|
||||
}
|
||||
|
||||
printf("PAI NNPA support %d\n", libcpumf_have_pai_nnpa());
|
||||
printf("PAI EXTENSION support %d\n", libcpumf_have_pai_ext());
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -147,6 +147,13 @@ bool libcpumf_have_pai_crypto(void)
|
||||
return (stat(S390_SYSFS_PAI_CRYPTO, &statbuf) == -1) ? false : true;
|
||||
}
|
||||
|
||||
bool libcpumf_have_pai_ext(void)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
return (stat(S390_SYSFS_PAI_EXT, &statbuf) == -1) ? false : true;
|
||||
}
|
||||
|
||||
bool libcpumf_have_pai_nnpa(void)
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/dasd_base.h"
|
||||
|
||||
@@ -27,11 +29,13 @@
|
||||
|
||||
#define RUN_IOCTL(fd, req, argp) \
|
||||
do { \
|
||||
if (ioctl(fd, req, argp) != 0) { \
|
||||
int err = errno; \
|
||||
if (err != EBADF) \
|
||||
int rc = ioctl(fd, req, argp); \
|
||||
if (rc != 0) { \
|
||||
if (rc == -1) \
|
||||
rc = errno; \
|
||||
if (rc != EBADF) \
|
||||
dasd_close_device(fd); \
|
||||
return err; \
|
||||
return rc; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
@@ -321,3 +325,159 @@ int dasd_disk_release(const char *device)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Unconditionally reserve DASD disk
|
||||
*
|
||||
* An existing reserve lock is lifted (steal lock) and the device
|
||||
* is reserved.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_slock(const char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDSLCK, NULL);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the caching algorithm used for the channel programs of this device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[out] attrib_data pointer to dasd attrib data with:
|
||||
* 'cache' is the caching mode
|
||||
* 'no_cyl' the number of cylinders to be cached.
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_get_cache(const char *device, attrib_data_t *attrib_data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDGATTR, attrib_data);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the caching algorithm used for the channel programs of this device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] attrib_data pointer to dasd attrib data with:
|
||||
* 'cache' is the caching mode
|
||||
* 'no_cyl' the number of cylinders to be cached.
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_set_cache(const char *device, attrib_data_t *attrib_data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDSATTR, attrib_data);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get reserve status of device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval errno in case of failure
|
||||
* @retval 0 unreserved
|
||||
* @retval 1 implicit reserved
|
||||
* @retval 2 other reservation
|
||||
* @retval 3 reserved
|
||||
*/
|
||||
int dasd_query_reserve(const char *device)
|
||||
{
|
||||
struct dasd_snid_ioctl_data snid = { 0 };
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDSNID, &snid);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return snid.data.path_state.reserve;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and print the profiling info of the device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] dasd_profile_info pointer to dasd profile info
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_profile(const char *device, dasd_profile_info_t *dasd_profile_info)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDPRRD, dasd_profile_info);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reset the profiling counters of the device.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
*
|
||||
* @retval 0 in case of success
|
||||
* @retval errno in case of failure
|
||||
*/
|
||||
int dasd_reset_profile(const char *device)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDPRRST, NULL);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initiate the swap of a copy pairs primary,secondary relation.
|
||||
* The old secondary will become the new primary and vice versa.
|
||||
*
|
||||
* @param[in] device node device node's name
|
||||
* @param[in] copy_pair data pointer to dasd copypair data with:
|
||||
* 'primary' old primary, becoming secondary
|
||||
* 'secondary' old secondary, becoming primary.
|
||||
*
|
||||
* @retval errno in case of failure
|
||||
* @retval 0 in case of success
|
||||
* @retval 1 swap data invalid
|
||||
* @retval 2 no active device found
|
||||
* @retval 3 wrong primary specified
|
||||
* @retval 4 secondary device not found
|
||||
* @retval 5 swap already running
|
||||
*/
|
||||
int dasd_copy_swap(const char *device, struct dasd_copypair_swap_data *data)
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = dasd_open_device(device, O_RDONLY);
|
||||
RUN_IOCTL(fd, BIODASDPPRCSWAP, data);
|
||||
dasd_close_device(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ endif
|
||||
sources := $(wildcard *.c)
|
||||
objects := $(patsubst %.c,%.o,$(sources))
|
||||
|
||||
all: $(BUILD_TARGETS) .check_dep-$(LIB)
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
$(LIB): $(objects)
|
||||
$(LIB): ALL_CFLAGS += -fPIC
|
||||
@@ -74,7 +74,7 @@ skip-$(LIB):
|
||||
.detect-openssl.dep.c:
|
||||
echo "#include <openssl/evp.h>" > $@
|
||||
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
||||
echo " #error openssl version 1.1.0 is required" >> $@
|
||||
echo " #error openssl version 1.1.1 is required" >> $@
|
||||
echo "#endif" >> $@
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||
@@ -90,7 +90,7 @@ skip-$(LIB):
|
||||
$(call check_dep, \
|
||||
"$(LIB)", \
|
||||
$^, \
|
||||
"openssl-devel / libssl-dev version >= 1.1.0", \
|
||||
"openssl-devel / libssl-dev version >= 1.1.1", \
|
||||
"HAVE_OPENSSL=0", \
|
||||
"-I.")
|
||||
$(call check_dep, \
|
||||
|
||||
35
libpv/cert.c
35
libpv/cert.c
@@ -290,7 +290,9 @@ static char *pv_X509_NAME_oneline(const X509_NAME *name)
|
||||
long len;
|
||||
|
||||
if (X509_NAME_print_ex(key_bio, name, 0, XN_FLAG_RFC2253) == -1) {
|
||||
g_warning(_("Cannot receive X509-NAME from CRL: %s"), pv_get_openssl_error());
|
||||
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||
|
||||
g_warning(_("Cannot receive X509-NAME from CRL: %s"), openssl_err_msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -492,7 +494,9 @@ static X509_CRL *load_crl_by_dist_point(DIST_POINT *crldp, GError **error)
|
||||
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error)
|
||||
{
|
||||
g_autoptr(STACK_OF_DIST_POINT) crldps = NULL;
|
||||
g_autoptr(GError) last_error = NULL;
|
||||
g_autoptr(X509_CRL) ret = NULL;
|
||||
int dist_points_cnt;
|
||||
|
||||
g_assert(cert);
|
||||
|
||||
@@ -503,19 +507,24 @@ X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sk_DIST_POINT_num(crldps); i++) {
|
||||
dist_points_cnt = sk_DIST_POINT_num(crldps);
|
||||
for (int i = 0; i < dist_points_cnt; i++) {
|
||||
DIST_POINT *crldp = sk_DIST_POINT_value(crldps, i);
|
||||
|
||||
g_assert(crldp);
|
||||
|
||||
/* ignore error */
|
||||
ret = load_crl_by_dist_point(crldp, NULL);
|
||||
g_clear_error(&last_error);
|
||||
ret = load_crl_by_dist_point(crldp, &last_error);
|
||||
if (ret)
|
||||
return g_steal_pointer(&ret);
|
||||
}
|
||||
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||
_("failed to download CRL"));
|
||||
/* relabel error */
|
||||
if (last_error)
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||
"%s", last_error->message);
|
||||
else
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||
_("failed to download CRL"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -783,7 +792,7 @@ int pv_store_set_verify_param(X509_STORE *store, GError **error)
|
||||
return 0;
|
||||
|
||||
error:
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||
_("X509 store initialization failed"));
|
||||
return -1;
|
||||
}
|
||||
@@ -1368,14 +1377,14 @@ int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error)
|
||||
|
||||
ca_x509_subject = X509_get_subject_name(ca);
|
||||
if (!ca_x509_subject) {
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||
_("subject of the root CA cannot be retrieved"));
|
||||
return -1;
|
||||
}
|
||||
|
||||
ca_subject = pv_X509_NAME_oneline(ca_x509_subject);
|
||||
if (!ca_subject) {
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||
_("subject name of the root CA cannot be retrieved"));
|
||||
return -1;
|
||||
}
|
||||
@@ -1469,11 +1478,11 @@ static STACK_OF_X509 *get_ibm_signing_certs(STACK_OF_X509 *certs, GError **error
|
||||
ibm_signing_certs = pv_remove_ibm_signing_certs(certs);
|
||||
ibm_signing_certs_count = sk_X509_num(ibm_signing_certs);
|
||||
if (ibm_signing_certs_count < 1) {
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
_("Specify at least one IBM Z signing key"));
|
||||
return NULL;
|
||||
} else if (ibm_signing_certs_count > 1) {
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||
_("Specify only one IBM Z signing key"));
|
||||
return NULL;
|
||||
}
|
||||
@@ -1504,7 +1513,7 @@ static gboolean download_crls(X509_STORE *trusted, PvCertWithPathList *host_key_
|
||||
X509_CRL *crl = sk_X509_CRL_value(downloaded_ibm_signing_crls, i);
|
||||
|
||||
if (X509_STORE_add_crl(trusted, crl) != 1) {
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||
g_set_error(error, PV_CERT_ERROR, PV_CERT_ERROR_INTERNAL,
|
||||
_("failed to load CRL"));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
@@ -19,18 +19,18 @@
|
||||
#include "libpv/glib-helper.h"
|
||||
#include "libpv/hash.h"
|
||||
|
||||
const char *pv_get_openssl_error(void)
|
||||
char *pv_get_openssl_errors(void)
|
||||
{
|
||||
const char *ret;
|
||||
BIO *bio;
|
||||
char *ret;
|
||||
char *buf;
|
||||
BIO *bio;
|
||||
long len;
|
||||
|
||||
bio = BIO_new(BIO_s_mem());
|
||||
ERR_print_errors(bio);
|
||||
len = BIO_get_mem_data(bio, &buf);
|
||||
if (len < 0)
|
||||
ret = "Cannot receive OpenSSL error message.";
|
||||
if (len <= 0 || !buf)
|
||||
ret = g_strdup("Cannot receive OpenSSL error message.");
|
||||
else
|
||||
ret = g_strndup(buf, (size_t)len);
|
||||
BIO_free(bio);
|
||||
@@ -41,7 +41,7 @@ int pv_BIO_reset(BIO *b)
|
||||
{
|
||||
int rc = BIO_reset(b);
|
||||
|
||||
if (rc != 1 && (BIO_method_type(b) == BIO_TYPE_FILE && rc != 0))
|
||||
if (rc != 1 && !(BIO_method_type(b) == BIO_TYPE_FILE && rc == 0))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
@@ -276,7 +276,7 @@ int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherP
|
||||
}
|
||||
|
||||
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
|
||||
const EVP_MD *md, G_GNUC_UNUSED GError **error)
|
||||
const EVP_MD *md, GError **error)
|
||||
{
|
||||
const unsigned char *salt_data, *key_data, *info_data;
|
||||
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
|
||||
@@ -354,7 +354,6 @@ GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *
|
||||
if (EVP_PKEY_derive(ctx, derived_key, &derived_key_len) != 1) {
|
||||
g_set_error(error, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_HKDF_FAIL,
|
||||
"FAILED to derive key via HKDF");
|
||||
printf("%s\n", pv_get_openssl_error());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@@ -168,12 +168,14 @@ GBytes *pv_file_get_content_as_secure_bytes(const char *filename)
|
||||
return pv_sec_gbytes_new_take(g_steal_pointer(&data), data_size);
|
||||
}
|
||||
|
||||
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src)
|
||||
void *pv_gbytes_memcpy(void *dst, size_t dst_size, GBytes *src, size_t *copied)
|
||||
{
|
||||
size_t src_size;
|
||||
const void *src_data = g_bytes_get_data(src, &src_size);
|
||||
|
||||
if (dst_size < src_size)
|
||||
return NULL;
|
||||
if (copied)
|
||||
*copied = src_size;
|
||||
return memcpy(dst, src_data, src_size);
|
||||
}
|
||||
|
||||
12
libpv/hash.c
12
libpv/hash.c
@@ -97,8 +97,10 @@ HMAC_CTX *pv_hmac_ctx_new(GBytes *key, const EVP_MD *md, GError **error)
|
||||
key_data = g_bytes_get_data(key, &key_size);
|
||||
|
||||
if (HMAC_Init_ex(ctx, key_data, (int)key_size, md, NULL) != 1) {
|
||||
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||
|
||||
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
||||
"unable to create HMAC context: %s", pv_get_openssl_error());
|
||||
"unable to create HMAC context: %s", openssl_err_msg);
|
||||
return NULL;
|
||||
}
|
||||
return g_steal_pointer(&ctx);
|
||||
@@ -110,8 +112,10 @@ int pv_hmac_ctx_update_raw(HMAC_CTX *ctx, const void *buf, size_t size, GError *
|
||||
return 0;
|
||||
|
||||
if (HMAC_Update(ctx, buf, size) != 1) {
|
||||
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||
|
||||
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
||||
"unable to add data to HMAC context: %s", pv_get_openssl_error());
|
||||
"unable to add data to HMAC context: %s", openssl_err_msg);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -139,8 +143,10 @@ GBytes *pv_hamc_ctx_finalize(HMAC_CTX *ctx, GError **error)
|
||||
hmac = g_malloc0((unsigned int)md_size);
|
||||
|
||||
if (HMAC_Final(ctx, hmac, &hmac_size) != 1) {
|
||||
g_autofree char *openssl_err_msg = pv_get_openssl_errors();
|
||||
|
||||
g_set_error(error, PV_HASH_ERROR, PV_HASH_ERROR_INTERNAL,
|
||||
"unable to calculate HMAC: %s", pv_get_openssl_error());
|
||||
"unable to calculate HMAC: %s", openssl_err_msg);
|
||||
return NULL;
|
||||
}
|
||||
return g_bytes_new_take(g_steal_pointer(&hmac), hmac_size);
|
||||
|
||||
@@ -552,6 +552,33 @@ static const OSSL_PARAM *sk_prov_cached_params_build(
|
||||
return provctx->cached_parms[index];
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
static bool sk_prov_check_uint_param(const OSSL_PARAM params[],
|
||||
const char *param_name,
|
||||
const struct sk_prov_key *key,
|
||||
int key_type,
|
||||
unsigned int expected_value)
|
||||
{
|
||||
const OSSL_PARAM *p;
|
||||
unsigned int value;
|
||||
|
||||
if (key == NULL)
|
||||
return true;
|
||||
if (key->type != key_type)
|
||||
return true;
|
||||
|
||||
p = OSSL_PARAM_locate_const(params, param_name);
|
||||
if (p == NULL)
|
||||
return true;
|
||||
|
||||
if (OSSL_PARAM_get_uint(p, &value) != 1)
|
||||
return true;
|
||||
|
||||
return value == expected_value;
|
||||
}
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
static struct sk_prov_op_ctx *sk_prov_op_newctx(struct sk_prov_ctx *provctx,
|
||||
const char *propq,
|
||||
int type)
|
||||
@@ -850,6 +877,20 @@ static int sk_prov_asym_op_set_ctx_params(void *vctx, const OSSL_PARAM params[])
|
||||
for (p = params; p != NULL && p->key != NULL; p++)
|
||||
sk_debug_op_ctx(ctx, "param: %s", p->key);
|
||||
|
||||
#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
|
||||
/* OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION is for RSA decrypt only */
|
||||
if (!sk_prov_check_uint_param(params,
|
||||
OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
|
||||
ctx->key, EVP_PKEY_RSA, 0) ||
|
||||
!sk_prov_check_uint_param(params,
|
||||
OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
|
||||
ctx->key, EVP_PKEY_RSA_PSS, 0)) {
|
||||
put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
|
||||
"Implicit rejection is not supported");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
default_set_params_fn = (OSSL_FUNC_asym_cipher_set_ctx_params_fn *)
|
||||
sk_prov_get_default_asym_func(ctx->provctx,
|
||||
ctx->type,
|
||||
@@ -1125,6 +1166,14 @@ static int sk_prov_asym_op_decrypt_init(void *vctx, void *vkey,
|
||||
struct sk_prov_op_ctx *ctx = vctx;
|
||||
struct sk_prov_key *key = vkey;
|
||||
const OSSL_PARAM *p;
|
||||
#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
|
||||
unsigned int implicit_rejection = 0;
|
||||
OSSL_PARAM set_params[] = {
|
||||
OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
|
||||
&implicit_rejection),
|
||||
OSSL_PARAM_END
|
||||
};
|
||||
#endif
|
||||
|
||||
if (ctx == NULL || key == NULL)
|
||||
return 0;
|
||||
@@ -1133,6 +1182,20 @@ static int sk_prov_asym_op_decrypt_init(void *vctx, void *vkey,
|
||||
for (p = params; p != NULL && p->key != NULL; p++)
|
||||
sk_debug_op_ctx(ctx, "param: %s", p->key);
|
||||
|
||||
#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
|
||||
/* OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION is for RSA decrypt only */
|
||||
if (!sk_prov_check_uint_param(params,
|
||||
OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
|
||||
key, EVP_PKEY_RSA, 0) ||
|
||||
!sk_prov_check_uint_param(params,
|
||||
OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION,
|
||||
key, EVP_PKEY_RSA_PSS, 0)) {
|
||||
put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
|
||||
"Implicit rejection is not supported");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
default_decrypt_init_fn = (OSSL_FUNC_asym_cipher_decrypt_init_fn *)
|
||||
sk_prov_get_default_asym_func(ctx->provctx,
|
||||
ctx->type,
|
||||
@@ -1155,6 +1218,26 @@ static int sk_prov_asym_op_decrypt_init(void *vctx, void *vkey,
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef OSSL_ASYM_CIPHER_PARAM_IMPLICIT_REJECTION
|
||||
if ((key->type == EVP_PKEY_RSA || key->type == EVP_PKEY_RSA_PSS) &&
|
||||
key->secure_key != NULL) {
|
||||
/*
|
||||
* By default, implicit rejection is enabled for the default
|
||||
* provider. We currently do not support implicit rejection with
|
||||
* secure keys, so disable implicit rejection in the default
|
||||
* provider operation context to report its status correctly
|
||||
* with get-params.
|
||||
*/
|
||||
implicit_rejection = 0;
|
||||
if (!sk_prov_asym_op_set_ctx_params(ctx, set_params)) {
|
||||
sk_debug_op_ctx(ctx,
|
||||
"ERROR: sk_prov_asym_op_set_ctx_params "
|
||||
"failed");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1361,6 +1444,16 @@ static int sk_prov_sign_op_set_ctx_params(void *vctx, const OSSL_PARAM params[])
|
||||
for (p = params; p != NULL && p->key != NULL; p++)
|
||||
sk_debug_op_ctx(ctx, "param: %s", p->key);
|
||||
|
||||
#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE
|
||||
/* OSSL_SIGNATURE_PARAM_NONCE_TYPE is used for EC sign ops only */
|
||||
if (!sk_prov_check_uint_param(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE,
|
||||
ctx->key, EVP_PKEY_EC, 0)) {
|
||||
put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
|
||||
"Deterministic signature is not supported");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
default_set_params_fn = (OSSL_FUNC_signature_set_ctx_params_fn *)
|
||||
sk_prov_get_default_sign_func(ctx->provctx,
|
||||
ctx->type, OSSL_FUNC_SIGNATURE_SET_CTX_PARAMS);
|
||||
@@ -1701,6 +1794,11 @@ static int sk_prov_sign_op_get_pss_saltlen(struct sk_prov_op_ctx *ctx,
|
||||
salt_len = max_saltlen;
|
||||
else if (strcmp(saltlen, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO) == 0)
|
||||
salt_len = max_saltlen;
|
||||
#ifdef OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX
|
||||
else if (strcmp(saltlen,
|
||||
OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX) == 0)
|
||||
salt_len = MIN(max_saltlen, EVP_MD_size(mgf_md));
|
||||
#endif
|
||||
else
|
||||
salt_len = atoi(saltlen);
|
||||
|
||||
@@ -1729,6 +1827,16 @@ static int sk_prov_sign_op_sign_init(void *vctx, void *vkey,
|
||||
for (p = params; p != NULL && p->key != NULL; p++)
|
||||
sk_debug_op_ctx(ctx, "param: %s", p->key);
|
||||
|
||||
#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE
|
||||
/* OSSL_SIGNATURE_PARAM_NONCE_TYPE is used for EC sign ops only */
|
||||
if (!sk_prov_check_uint_param(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE,
|
||||
key, EVP_PKEY_EC, 0)) {
|
||||
put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
|
||||
"Deterministic signature is not supported");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
default_sign_init_fn = (OSSL_FUNC_signature_sign_init_fn *)
|
||||
sk_prov_get_default_sign_func(ctx->provctx,
|
||||
ctx->type,
|
||||
@@ -1955,6 +2063,16 @@ static int sk_prov_sign_op_digest_sign_init(struct sk_prov_op_ctx *ctx,
|
||||
for (p = params; p != NULL && p->key != NULL; p++)
|
||||
sk_debug_op_ctx(ctx, "param: %s", p->key);
|
||||
|
||||
#ifdef OSSL_SIGNATURE_PARAM_NONCE_TYPE
|
||||
/* OSSL_SIGNATURE_PARAM_NONCE_TYPE is used for EC sign ops only */
|
||||
if (!sk_prov_check_uint_param(params, OSSL_SIGNATURE_PARAM_NONCE_TYPE,
|
||||
key, EVP_PKEY_EC, 0)) {
|
||||
put_error_op_ctx(ctx, SK_PROV_ERR_INVALID_PARAM,
|
||||
"Deterministic signature is not supported");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
default_digest_sign_init_fn =
|
||||
(OSSL_FUNC_signature_digest_sign_init_fn *)
|
||||
sk_prov_get_default_sign_func(ctx->provctx,
|
||||
|
||||
@@ -107,13 +107,12 @@ const char *util_arch_machine_type_to_str(int type)
|
||||
*/
|
||||
unsigned long util_arch_hsa_maxsize(void)
|
||||
{
|
||||
unsigned long size = HSA_SIZE_32M;
|
||||
int type;
|
||||
|
||||
type = util_arch_machine_type();
|
||||
if (type != UTIL_ARCH_MACHINE_TYPE_UNKNOWN &&
|
||||
type >= UTIL_ARCH_MACHINE_TYPE_Z15)
|
||||
size = HSA_SIZE_512M;
|
||||
|
||||
return size;
|
||||
switch (util_arch_machine_type()) {
|
||||
case UTIL_ARCH_MACHINE_TYPE_Z15:
|
||||
case UTIL_ARCH_MACHINE_TYPE_Z15_T02:
|
||||
case UTIL_ARCH_MACHINE_TYPE_Z16:
|
||||
return HSA_SIZE_512M;
|
||||
default:
|
||||
return HSA_SIZE_32M;
|
||||
}
|
||||
}
|
||||
|
||||
301
libutil/util_lockfile.c
Normal file
301
libutil/util_lockfile.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* util - Utility function library
|
||||
*
|
||||
* Created file-based locks
|
||||
*
|
||||
* 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 <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "lib/util_libc.h"
|
||||
#include "lib/util_lockfile.h"
|
||||
#include "lib/util_panic.h"
|
||||
|
||||
#define WAITPID 120 /* Time to wait for pid to be written */
|
||||
#define WAITINC 5 /* Additional time to wait each retry */
|
||||
#define MAXWAIT 60 /* Maximum wait between retries */
|
||||
#define BUFSIZE 40 /* Buffer must be large enough to fit pid string */
|
||||
|
||||
/**
|
||||
* Check if there is a process that exists with the specified identifier.
|
||||
*
|
||||
* @param[in] pid Process Identifier to check
|
||||
*
|
||||
* @retval true Process exists or we lack privelege to check
|
||||
* @retval false Process does not exist
|
||||
*/
|
||||
static bool pid_exists(int pid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Use sig 0 to determine if the owner is still alive */
|
||||
rc = kill(pid, 0);
|
||||
if (rc != 0) {
|
||||
switch (errno) {
|
||||
case EPERM:
|
||||
/* Privilege issue, just assume PID exists */
|
||||
break;
|
||||
case ESRCH:
|
||||
/* PID does not exist, this lock is stale */
|
||||
return false;
|
||||
default:
|
||||
util_assert(false, "Unexpected return from kill: %d\n", rc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for an existing lock that is deemed stale (either the associated PID
|
||||
* is gone or no PID has been written to the file in a reasonable timeframe).
|
||||
* In the case a stale lock is found, remove it.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
*
|
||||
* @retval 0 Either no lock or stale lock was found and removed
|
||||
* @retval 1 Lock is held by another PID and is not stale
|
||||
*/
|
||||
static int handle_stale_lock(char *lockfile)
|
||||
{
|
||||
int fd, rc, pid, len;
|
||||
struct stat info;
|
||||
char buf[BUFSIZE];
|
||||
time_t curr;
|
||||
|
||||
fd = open(lockfile, O_RDONLY);
|
||||
|
||||
if (fd >= 0) {
|
||||
/* Lock exists, see who owns it */
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
if (len > 0) {
|
||||
buf[len] = 0; /* Ensure null terminated string */
|
||||
pid = atoi(buf);
|
||||
if (!pid_exists(pid)) {
|
||||
/* Stale lock detected unlink and retry now */
|
||||
close(fd);
|
||||
unlink(lockfile);
|
||||
return 0;
|
||||
} else if (pid != 0) {
|
||||
/* Lock is held by an active pid, delay */
|
||||
close(fd);
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
* If we reach this point, the PID was 0 which is
|
||||
* unexpected. Proceed under the assumption that the
|
||||
* proper PID hasn't been written yet.
|
||||
*/
|
||||
}
|
||||
/*
|
||||
* PID hasn't been written yet? Either a bad lock or a very
|
||||
* new one.
|
||||
*/
|
||||
time(&curr);
|
||||
rc = fstat(fd, &info);
|
||||
close(fd);
|
||||
if (rc != 0) {
|
||||
/* Can't read file anymore, retry now */
|
||||
return 0;
|
||||
}
|
||||
if (curr > info.st_mtime + WAITPID) {
|
||||
/*
|
||||
* PID should be in the file within 2 minutes,
|
||||
* something went wrong. Treat as stale.
|
||||
*/
|
||||
unlink(lockfile);
|
||||
return 0;
|
||||
}
|
||||
/* Otherwise, assume file was newly created and delay */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Couldn't open, try again immediately */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to create a lockfile at the specified path.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
* @param[in] retries Number of times to retry if lock fails initially
|
||||
* @param[in] pid PID to use for lock ownership
|
||||
*
|
||||
* @retval 0 Lock created with PID as owner
|
||||
* @retval !=0 Lock was not created
|
||||
*/
|
||||
static int do_lockfile_lock(char *lockfile, unsigned int retries, int pid)
|
||||
{
|
||||
int fd, plen, len, rc = 0, snooze = 0;
|
||||
unsigned int tries = retries + 1;
|
||||
char buf[BUFSIZE];
|
||||
char *tpath;
|
||||
|
||||
if (!lockfile)
|
||||
return UTIL_LOCKFILE_ERR;
|
||||
|
||||
plen = snprintf(buf, sizeof(buf), "%d\n", pid);
|
||||
if (plen < 0 || (plen > ((int)sizeof(buf) - 1)))
|
||||
return UTIL_LOCKFILE_ERR;
|
||||
|
||||
/* Allocate temporary lock file with a sufficiently unique path */
|
||||
len = util_asprintf(&tpath, "%s%05d%02x", lockfile, getpid(),
|
||||
(unsigned int)time(NULL) & 255);
|
||||
if (len < 0)
|
||||
return UTIL_LOCKFILE_ERR;
|
||||
|
||||
/* Open the temporary lockfile, write the specified pid */
|
||||
fd = open(tpath, O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0644);
|
||||
if (fd < 0) {
|
||||
rc = UTIL_LOCKFILE_ERR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = write(fd, buf, plen);
|
||||
if (close(fd) != 0) {
|
||||
rc = UTIL_LOCKFILE_ERR;
|
||||
goto cleanup;
|
||||
}
|
||||
if (len != plen) {
|
||||
/* Failed to write the temp lockfile, bail out */
|
||||
rc = UTIL_LOCKFILE_ERR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Link the temprorary file to the real path */
|
||||
do {
|
||||
rc = link(tpath, lockfile);
|
||||
if (rc == 0) {
|
||||
/* Lock successfully acquired */
|
||||
rc = UTIL_LOCKFILE_OK;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Lock already held - check for stale lock */
|
||||
rc = handle_stale_lock(lockfile);
|
||||
/* Only wait if the lock was not stale */
|
||||
if (rc != 0) {
|
||||
tries--;
|
||||
if (tries > 0) {
|
||||
snooze += WAITINC;
|
||||
snooze = (snooze > MAXWAIT) ? MAXWAIT : snooze;
|
||||
sleep(snooze);
|
||||
}
|
||||
}
|
||||
} while (tries > 0);
|
||||
|
||||
/* Exhausted specified number of retries, exit on failure */
|
||||
rc = UTIL_LOCKFILE_LOCK_FAIL;
|
||||
|
||||
cleanup:
|
||||
unlink(tpath);
|
||||
free(tpath);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to release a lockfile at the specified path.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
* @param[in] pid PID that should own the lock
|
||||
*
|
||||
* @retval 0 Lock released
|
||||
* @retval !=0 Lock was not released or did not exist
|
||||
*/
|
||||
static int do_lockfile_release(char *lockfile, int pid)
|
||||
{
|
||||
int fd, len, lpid;
|
||||
char buf[BUFSIZE];
|
||||
|
||||
if (!lockfile)
|
||||
return UTIL_LOCKFILE_ERR;
|
||||
|
||||
/* Open lockfile, read the owning pid if it exists */
|
||||
fd = open(lockfile, O_RDONLY);
|
||||
if (fd < 0)
|
||||
return UTIL_LOCKFILE_RELEASE_NONE;
|
||||
len = read(fd, buf, sizeof(buf));
|
||||
close(fd);
|
||||
if (len <= 0)
|
||||
return UTIL_LOCKFILE_RELEASE_FAIL;
|
||||
buf[len] = 0;
|
||||
lpid = atoi(buf);
|
||||
|
||||
/* Only release the lock if its held by the right pid */
|
||||
if (pid != lpid)
|
||||
return UTIL_LOCKFILE_RELEASE_FAIL;
|
||||
|
||||
unlink(lockfile);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to create a lockfile owned by this process at the specified path.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
* @param[in] retries Number of times to retry if lock fails initially
|
||||
*
|
||||
* @retval 0 Lock created
|
||||
* @retval !=0 Lock was not created
|
||||
*/
|
||||
int util_lockfile_lock(char *lockfile, int retries)
|
||||
{
|
||||
return do_lockfile_lock(lockfile, retries, getpid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to create a lockfile owned by the parent of this process at the
|
||||
* specified path.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
* @param[in] retries Number of times to retry if lock fails initially
|
||||
*
|
||||
* @retval 0 Lock created
|
||||
* @retval !=0 Lock was not created
|
||||
*/
|
||||
int util_lockfile_parent_lock(char *lockfile, int retries)
|
||||
{
|
||||
return do_lockfile_lock(lockfile, retries, getppid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to release a lockfile owned by this process at the specified path.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
*
|
||||
* @retval 0 Lock released
|
||||
* @retval !=0 Lock was not released or did not exist
|
||||
*/
|
||||
int util_lockfile_release(char *lockfile)
|
||||
{
|
||||
return do_lockfile_release(lockfile, getpid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to release a lockfile owned by the parent of this process at the
|
||||
* specified path.
|
||||
*
|
||||
* @param[in] lockfile Path to the lock file
|
||||
*
|
||||
* @retval 0 Lock released
|
||||
* @retval !=0 Lock was not released or did not exist
|
||||
*/
|
||||
int util_lockfile_parent_release(char *lockfile)
|
||||
{
|
||||
return do_lockfile_release(lockfile, getppid());
|
||||
}
|
||||
232
libutil/util_lockfile_example.c
Normal file
232
libutil/util_lockfile_example.c
Normal file
@@ -0,0 +1,232 @@
|
||||
/**
|
||||
* util_lockfile_example - Example program for util_lockfile
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//! [code]
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "lib/util_opt.h"
|
||||
#include "lib/util_prg.h"
|
||||
#include "lib/util_lockfile.h"
|
||||
|
||||
static const struct util_prg prg = {
|
||||
.desc = "Example for util_lockfile.",
|
||||
.copyright_vec = { {
|
||||
.owner = "IBM Corp.",
|
||||
.pub_first = 2022,
|
||||
.pub_last = 2022,
|
||||
},
|
||||
UTIL_PRG_COPYRIGHT_END }
|
||||
};
|
||||
|
||||
static struct util_opt opt_vec[] = {
|
||||
UTIL_OPT_SECTION("OPTIONS"),
|
||||
{
|
||||
.option = { "file", required_argument, NULL, 'f' },
|
||||
.argument = "PATH",
|
||||
.desc = "Use the specified path for a lockfile.",
|
||||
},
|
||||
{
|
||||
.option = { "lock", required_argument, NULL, 'l' },
|
||||
.argument = "RETRIES",
|
||||
.desc = "Acquire the specified file lock using the parent "
|
||||
"process id of this process. If not immediately "
|
||||
"successful, retry for the specified number of times",
|
||||
},
|
||||
{
|
||||
.option = { "release", 0, NULL, 'r' },
|
||||
.desc = "Release the specified lock file using the parent "
|
||||
"process id",
|
||||
},
|
||||
{
|
||||
.option = { "lock-and-release", required_argument, NULL, 'L' },
|
||||
.argument = "RETRIES",
|
||||
.desc = "Acquire the specified file lock using this process "
|
||||
"id, then release it. If not immediately successful, "
|
||||
"retry for the specified number of times.",
|
||||
},
|
||||
UTIL_OPT_HELP,
|
||||
UTIL_OPT_VERSION,
|
||||
UTIL_OPT_END
|
||||
};
|
||||
|
||||
enum prg_action {
|
||||
ACTION_NONE = 0,
|
||||
ACTION_LOCK,
|
||||
ACTION_RELEASE,
|
||||
ACTION_LOCK_AND_RELEASE,
|
||||
};
|
||||
|
||||
static void print_single_action_error(void)
|
||||
{
|
||||
warnx("Only a single action (--lock, --lock-parent, --release, "
|
||||
"--release-parent) is allowed");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
enum prg_action action_id = ACTION_NONE;
|
||||
int opt, rc, retries = 0;
|
||||
char *endp, *path = NULL;
|
||||
|
||||
util_prg_init(&prg);
|
||||
util_opt_init(opt_vec, NULL);
|
||||
|
||||
while (1) {
|
||||
opt = util_opt_getopt_long(argc, argv);
|
||||
if (opt == -1)
|
||||
break;
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
path = optarg;
|
||||
break;
|
||||
case 'L':
|
||||
if (action_id != ACTION_NONE) {
|
||||
print_single_action_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
retries = strtol(optarg, &endp, 0);
|
||||
if (*optarg == '\0' || *endp != '\0' || retries < 0) {
|
||||
warnx("Invalid retry value for "
|
||||
"--lock-and-release: '%s'",
|
||||
optarg);
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
action_id = ACTION_LOCK_AND_RELEASE;
|
||||
break;
|
||||
case 'l':
|
||||
if (action_id != ACTION_NONE) {
|
||||
print_single_action_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
retries = strtol(optarg, &endp, 0);
|
||||
if (*optarg == '\0' || *endp != '\0' || retries < 0) {
|
||||
warnx("Invalid retry value for "
|
||||
"--parent-lock: '%s'",
|
||||
optarg);
|
||||
util_prg_print_parse_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
action_id = ACTION_LOCK;
|
||||
break;
|
||||
case 'r':
|
||||
if (action_id != ACTION_NONE) {
|
||||
print_single_action_error();
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
action_id = ACTION_RELEASE;
|
||||
break;
|
||||
case 'h':
|
||||
util_prg_print_help();
|
||||
util_opt_print_help();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'v':
|
||||
util_prg_print_version();
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
util_opt_print_parse_error(opt, argv);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!path) {
|
||||
warnx("--file is required, see --help for more information");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (action_id == ACTION_NONE) {
|
||||
warnx("One of the following actions must be specified: "
|
||||
"--lock, --release, --lock-and-release");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* Determine which util_lockfile function to call */
|
||||
switch (action_id) {
|
||||
case ACTION_LOCK:
|
||||
rc = util_lockfile_parent_lock(path, retries);
|
||||
switch (rc) {
|
||||
case UTIL_LOCKFILE_OK:
|
||||
printf("lock acquired successfully\n");
|
||||
break;
|
||||
case UTIL_LOCKFILE_LOCK_FAIL:
|
||||
warnx("lock was not acquired; already held");
|
||||
return EXIT_FAILURE;
|
||||
case UTIL_LOCKFILE_ERR:
|
||||
warnx("lock was not acquired; file error");
|
||||
return EXIT_FAILURE;
|
||||
default:
|
||||
warnx("Unknown util_lockfile rc %d", rc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case ACTION_RELEASE:
|
||||
rc = util_lockfile_parent_release(path);
|
||||
switch (rc) {
|
||||
case UTIL_LOCKFILE_OK:
|
||||
printf("lock released successfully\n");
|
||||
break;
|
||||
case UTIL_LOCKFILE_RELEASE_NONE:
|
||||
warnx("lock file did not exist");
|
||||
return EXIT_FAILURE;
|
||||
case UTIL_LOCKFILE_RELEASE_FAIL:
|
||||
warnx("lock was not held by the specified pid");
|
||||
return EXIT_FAILURE;
|
||||
case UTIL_LOCKFILE_ERR:
|
||||
warnx("lock was not released; file error");
|
||||
return EXIT_FAILURE;
|
||||
default:
|
||||
warnx("Unknown util_lockfile rc %d", rc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
case ACTION_LOCK_AND_RELEASE:
|
||||
rc = util_lockfile_lock(path, retries);
|
||||
switch (rc) {
|
||||
case UTIL_LOCKFILE_OK:
|
||||
printf("lock acquired successfully, holding for 2 seconds\n");
|
||||
break;
|
||||
case UTIL_LOCKFILE_LOCK_FAIL:
|
||||
warnx("lock was not acquired; already held");
|
||||
return EXIT_FAILURE;
|
||||
case UTIL_LOCKFILE_ERR:
|
||||
warnx("lock was not acquired; file error");
|
||||
return EXIT_FAILURE;
|
||||
default:
|
||||
warnx("Unknown util_lockfile rc %d", rc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
/* Briefly sleep while holding the lock */
|
||||
sleep(2);
|
||||
rc = util_lockfile_release(path);
|
||||
switch (rc) {
|
||||
case UTIL_LOCKFILE_OK:
|
||||
printf("lock released successfully\n");
|
||||
break;
|
||||
case UTIL_LOCKFILE_RELEASE_NONE:
|
||||
warnx("lock file did not exist");
|
||||
return EXIT_FAILURE;
|
||||
case UTIL_LOCKFILE_RELEASE_FAIL:
|
||||
warnx("lock was not held by the specified pid");
|
||||
return EXIT_FAILURE;
|
||||
case UTIL_LOCKFILE_ERR:
|
||||
warnx("lock was not released; file error");
|
||||
return EXIT_FAILURE;
|
||||
default:
|
||||
warnx("Unknown util_lockfile rc %d", rc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
warnx("Unknown util_lockfile action");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
//! [code]
|
||||
@@ -22,7 +22,7 @@
|
||||
/*
|
||||
* Obtain a backtrace and print it to stderr
|
||||
*
|
||||
* To get symbols, compile the code with "-rdynamic".
|
||||
* To get symbols, link the code with "-rdynamic".
|
||||
*/
|
||||
static void print_backtrace(void)
|
||||
{
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
include ../common.mak
|
||||
|
||||
lib = libvmdump.a
|
||||
|
||||
all: $(lib)
|
||||
|
||||
objects = register_content.o dump.o lkcd_dump.o register_content.o \
|
||||
vmdump_convert.o vm_dump.o
|
||||
|
||||
$(lib): $(objects)
|
||||
|
||||
install: all
|
||||
|
||||
clean:
|
||||
rm -f *.o $(lib)
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Dump base class
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "dump.h"
|
||||
|
||||
int debug = 0;
|
||||
|
||||
void s390TodToTimeval(uint64_t todval, struct timeval *xtime)
|
||||
{
|
||||
/* adjust todclock to 1970 */
|
||||
todval -= 0x8126d60e46000000LL - (0x3c26700LL * 1000000 * 4096);
|
||||
|
||||
todval >>= 12;
|
||||
xtime->tv_sec = todval / 1000000;
|
||||
xtime->tv_usec = todval % 1000000;
|
||||
}
|
||||
|
||||
Dump::Dump(const char *filename, const char *mode)
|
||||
{
|
||||
fh = fopen(filename, mode);
|
||||
if(!fh){
|
||||
throw(DumpErrnoException("Open dump file failed!"));
|
||||
}
|
||||
}
|
||||
|
||||
Dump::~Dump(void)
|
||||
{
|
||||
if(fh){
|
||||
fclose(fh);
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressBar::initProgress(void)
|
||||
{
|
||||
progressPercentage = -1;
|
||||
}
|
||||
|
||||
void ProgressBar::displayProgress(uint64_t value, uint64_t maxValue)
|
||||
{
|
||||
char progress_bar[51];
|
||||
int j;
|
||||
|
||||
if (progressPercentage == (int) (value * 100 / maxValue))
|
||||
fprintf(stderr, "%6lld of %6lld |\r",
|
||||
(long long) value, (long long) maxValue);
|
||||
else { /* percent value has changed */
|
||||
progressPercentage = (value * 100 / maxValue);
|
||||
for (j = 0; j < progressPercentage / 2; j++)
|
||||
progress_bar[j] = '#';
|
||||
for (j = progressPercentage / 2; j < 50; j++)
|
||||
progress_bar[j] = '-';
|
||||
progress_bar[50] = 0;
|
||||
fprintf(stderr, "%6lld of %6lld |%s| %3d%% \r",
|
||||
(long long) value, (long long) maxValue,
|
||||
progress_bar, progressPercentage);
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Dump base class
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef DUMP_H
|
||||
#define DUMP_H
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
extern int debug;
|
||||
|
||||
class DumpException
|
||||
{
|
||||
public:
|
||||
DumpException(void) {
|
||||
msg[0] = 0;
|
||||
errorCode = 0;
|
||||
}
|
||||
DumpException(const char *m) {
|
||||
sprintf(msg, "%s", m);
|
||||
errorCode = 0;
|
||||
}
|
||||
|
||||
const char *what(void) const { return msg; }
|
||||
int code(void) const { return errorCode; }
|
||||
protected:
|
||||
char msg[2048];
|
||||
int errorCode;
|
||||
};
|
||||
|
||||
class DumpErrnoException : public DumpException
|
||||
{
|
||||
public:
|
||||
DumpErrnoException(const char *m) {
|
||||
sprintf(msg, "%s (%s)", m, strerror(errno));
|
||||
errorCode = errno;
|
||||
}
|
||||
};
|
||||
|
||||
class Dump
|
||||
{
|
||||
public:
|
||||
Dump(const char *filename, const char *mode);
|
||||
Dump(void) : fh(0) {}
|
||||
virtual ~Dump(void);
|
||||
typedef enum {DT_VM32, DT_VM64, DT_VM64_BIG, DT_LKCD32, DT_LKCD64,
|
||||
DT_UNKNOWN} DumpType;
|
||||
|
||||
virtual void readMem(char *buf, int size) = 0;
|
||||
virtual int seekMem(uint64_t offset) = 0;
|
||||
virtual uint64_t getMemSize(void) const = 0;
|
||||
virtual struct timeval getDumpTime(void) const = 0;
|
||||
protected:
|
||||
FILE *fh;
|
||||
};
|
||||
|
||||
class ProgressBar
|
||||
{
|
||||
public:
|
||||
ProgressBar(void) { progressPercentage = -1; }
|
||||
void initProgress(void);
|
||||
void displayProgress(uint64_t value, uint64_t maxValue);
|
||||
private:
|
||||
int progressPercentage;
|
||||
};
|
||||
|
||||
void s390TodToTimeval(uint64_t todval, struct timeval *xtime);
|
||||
int vm_convert(const char *inputFileName, const char *outputFileName,
|
||||
const char *progName);
|
||||
|
||||
static inline void dump_read(void *ptr, size_t size, size_t nmemb,
|
||||
FILE *stream)
|
||||
{
|
||||
if (fread(ptr, size, nmemb, stream) != nmemb)
|
||||
throw(DumpErrnoException("fread failed"));
|
||||
}
|
||||
|
||||
static inline void dump_seek(FILE *stream, long offset, int whence)
|
||||
{
|
||||
if (fseek(stream, offset, whence) == -1)
|
||||
throw(DumpErrnoException("fseek failed"));
|
||||
}
|
||||
|
||||
#endif /* DUMP_H */
|
||||
@@ -1,261 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* LKCD dump classes: LKCDDump, LKCDDump32, LKCDDump64
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "lkcd_dump.h"
|
||||
|
||||
LKCDDump::LKCDDump(Dump* dump, const char* arch) {
|
||||
referenceDump = dump;
|
||||
dumpHeader.magic_number = DUMP_MAGIC_NUMBER;
|
||||
dumpHeader.version = DUMP_VERSION_NUMBER;
|
||||
dumpHeader.header_size = sizeof(struct _lkcd_dump_header);
|
||||
dumpHeader.time.tv_sec = dump->getDumpTime().tv_sec;
|
||||
dumpHeader.time.tv_usec = dump->getDumpTime().tv_usec;
|
||||
strcpy(dumpHeader.utsname_machine, arch);
|
||||
dumpHeader.memory_size = dump->getMemSize();
|
||||
dumpHeader.memory_start = 0;
|
||||
dumpHeader.memory_end = dump->getMemSize();
|
||||
dumpHeader.num_dump_pages = dump->getMemSize()/0x1000;
|
||||
dumpHeader.page_size = 0x1000;
|
||||
dumpHeader.dump_compress = DUMP_COMPRESS_GZIP;
|
||||
dumpHeader.dump_level = DUMP_LEVEL_ALL;
|
||||
|
||||
dumpHeaderAsm.magic_number = DUMP_ASM_MAGIC_NUMBER;
|
||||
dumpHeaderAsm.version = 1;
|
||||
dumpHeaderAsm.header_size = sizeof(dumpHeaderAsm);
|
||||
}
|
||||
|
||||
int LKCDDump::compressGZIP(const char *old, uint32_t old_size, char *n,
|
||||
uint32_t new_size)
|
||||
{
|
||||
unsigned long len = old_size;
|
||||
int rc;
|
||||
|
||||
rc = compress((Bytef*)n, &len, (const Bytef*)old, new_size);
|
||||
switch(rc) {
|
||||
case Z_OK:
|
||||
rc = len;
|
||||
break;
|
||||
case Z_BUF_ERROR:
|
||||
/* In this case the compressed output is bigger than */
|
||||
/* the uncompressed */
|
||||
rc = GZIP_NOT_COMPRESSED;
|
||||
break;
|
||||
case Z_MEM_ERROR:
|
||||
throw(DumpException("gzip call failed: out of memory"));
|
||||
case Z_DATA_ERROR:
|
||||
throw(DumpException("gzip call failed: input data " \
|
||||
"corrupted!"));
|
||||
default:
|
||||
throw(DumpException("gzip call failed: unknown error"));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void LKCDDump::writeDump(const char* fileName)
|
||||
{
|
||||
char dump_header_buf[DUMP_HEADER_SIZE] = {};
|
||||
char dump_page_buf[DUMP_BUFFER_SIZE];
|
||||
char dpcpage[DUMP_PAGE_SIZE];
|
||||
uint32_t dp_size,dp_flags;
|
||||
ProgressBar progressBar;
|
||||
char buf[DUMP_PAGE_SIZE];
|
||||
struct _dump_page dp;
|
||||
uint64_t mem_loc = 0;
|
||||
ssize_t buf_loc = 0;
|
||||
int size, fd;
|
||||
|
||||
if (fileName == NULL) {
|
||||
fd = STDOUT_FILENO;
|
||||
} else {
|
||||
fd = open(fileName, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (fd == -1) {
|
||||
char msg[1024];
|
||||
sprintf(msg, "Open of dump '%s' failed.", fileName);
|
||||
throw(DumpErrnoException(msg));
|
||||
}
|
||||
}
|
||||
|
||||
/* write dump header */
|
||||
|
||||
memcpy(dump_header_buf, &dumpHeader, sizeof(dumpHeader));
|
||||
memcpy(&dump_header_buf[sizeof(dumpHeader)], &dumpHeaderAsm,
|
||||
sizeof(dumpHeaderAsm));
|
||||
if (write(fd, dump_header_buf, sizeof(dump_header_buf)) !=
|
||||
sizeof(dump_header_buf)) {
|
||||
throw(DumpErrnoException("write failed"));
|
||||
}
|
||||
|
||||
/* write memory */
|
||||
|
||||
referenceDump->seekMem(0);
|
||||
|
||||
while (mem_loc < dumpHeader.memory_size) {
|
||||
referenceDump->readMem(buf, DUMP_PAGE_SIZE);
|
||||
copyRegsToPage(mem_loc,buf);
|
||||
|
||||
memset(dpcpage, 0, DUMP_PAGE_SIZE);
|
||||
/*
|
||||
* Get the new compressed page size
|
||||
*/
|
||||
size = compressGZIP((char *)buf, DUMP_PAGE_SIZE,
|
||||
(char *)dpcpage, DUMP_PAGE_SIZE);
|
||||
|
||||
/*
|
||||
* If compression failed or compressed was ineffective,
|
||||
* we write an uncompressed page
|
||||
*/
|
||||
if (size == GZIP_NOT_COMPRESSED) {
|
||||
dp_flags = DUMP_DH_RAW;
|
||||
dp_size = DUMP_PAGE_SIZE;
|
||||
} else {
|
||||
dp_flags = DUMP_DH_COMPRESSED;
|
||||
dp_size = size;
|
||||
}
|
||||
dp.address = mem_loc;
|
||||
dp.size = dp_size;
|
||||
dp.flags = dp_flags;
|
||||
memcpy((void *)(dump_page_buf + buf_loc),
|
||||
(const void *)&dp, sizeof(dp));
|
||||
buf_loc += sizeof(dp);
|
||||
/*
|
||||
* Copy the page of memory
|
||||
*/
|
||||
if (dp_flags & DUMP_DH_COMPRESSED) {
|
||||
/* Copy the compressed page */
|
||||
memcpy((void *)(dump_page_buf + buf_loc),
|
||||
(const void *)dpcpage, dp_size);
|
||||
} else {
|
||||
/* Copy directly from memory */
|
||||
memcpy((void *)(dump_page_buf + buf_loc),
|
||||
(const void *)buf, dp_size);
|
||||
}
|
||||
buf_loc += dp_size;
|
||||
if(write(fd, dump_page_buf, buf_loc) != buf_loc){
|
||||
throw(DumpErrnoException("write failed"));
|
||||
}
|
||||
buf_loc = 0;
|
||||
mem_loc += DUMP_PAGE_SIZE;
|
||||
progressBar.displayProgress(mem_loc/(1024*1024),
|
||||
dumpHeader.memory_size/(1024*1024));
|
||||
}
|
||||
|
||||
/*
|
||||
* Write end marker
|
||||
*/
|
||||
dp.address = 0x0;
|
||||
dp.size = 0x0;
|
||||
dp.flags = DUMP_DH_END;
|
||||
if(write(fd, &dp, sizeof(dp)) != sizeof(dp)){
|
||||
throw(DumpErrnoException("write failed"));
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
if (fd != STDOUT_FILENO)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
struct timeval LKCDDump::getDumpTime(void) const
|
||||
{
|
||||
struct timeval rc;
|
||||
|
||||
rc.tv_sec = dumpHeader.time.tv_sec;
|
||||
rc.tv_usec = dumpHeader.time.tv_usec;
|
||||
return rc;
|
||||
}
|
||||
|
||||
LKCDDump32::LKCDDump32(Dump* dump, const RegisterContent32& r)
|
||||
: LKCDDump(dump,"s390")
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
dumpHeaderAsm.real_cpu_cnt = (uint32_t) r.getNumCpus();
|
||||
for (i = 0; i < dumpHeaderAsm.real_cpu_cnt; i++) {
|
||||
if (!r.regSets[i].prefix)
|
||||
continue;
|
||||
dumpHeaderAsm.lc_vec[i] = r.regSets[i].prefix;
|
||||
dumpHeaderAsm.cpu_cnt++;
|
||||
}
|
||||
registerContent = r;
|
||||
}
|
||||
|
||||
void LKCDDump32::copyRegsToPage(uint64_t offset, char *buf)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for(cpu = 0; cpu < registerContent.getNumCpus(); cpu++){
|
||||
if(offset == registerContent.regSets[cpu].prefix){
|
||||
memcpy(buf+0xd8,®isterContent.regSets[cpu].cpuTimer,
|
||||
sizeof(registerContent.regSets[cpu].cpuTimer));
|
||||
memcpy(buf+0xe0,®isterContent.regSets[cpu].clkCmp,
|
||||
sizeof(registerContent.regSets[cpu].clkCmp));
|
||||
memcpy(buf+0x100,®isterContent.regSets[cpu].psw,
|
||||
sizeof(registerContent.regSets[cpu].psw));
|
||||
memcpy(buf+0x108,®isterContent.regSets[cpu].prefix,
|
||||
sizeof(registerContent.regSets[cpu].prefix));
|
||||
memcpy(buf+0x120,®isterContent.regSets[cpu].acrs,
|
||||
sizeof(registerContent.regSets[cpu].acrs));
|
||||
memcpy(buf+0x160,®isterContent.regSets[cpu].fprs,
|
||||
sizeof(registerContent.regSets[cpu].fprs));
|
||||
memcpy(buf+0x180,®isterContent.regSets[cpu].gprs,
|
||||
sizeof(registerContent.regSets[cpu].gprs));
|
||||
memcpy(buf+0x1c0,®isterContent.regSets[cpu].crs,
|
||||
sizeof(registerContent.regSets[cpu].crs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LKCDDump64::LKCDDump64(Dump* dump, const RegisterContent64& r)
|
||||
: LKCDDump(dump,"s390x")
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
dumpHeaderAsm.real_cpu_cnt = (uint32_t) r.getNumCpus();
|
||||
for (i = 0; i < dumpHeaderAsm.real_cpu_cnt; i++) {
|
||||
if (!r.regSets[i].prefix)
|
||||
continue;
|
||||
dumpHeaderAsm.lc_vec[i] = r.regSets[i].prefix;
|
||||
dumpHeaderAsm.cpu_cnt++;
|
||||
}
|
||||
registerContent = r;
|
||||
}
|
||||
|
||||
void LKCDDump64::copyRegsToPage(uint64_t offset, char *buf)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for(cpu = 0; cpu < registerContent.getNumCpus(); cpu++){
|
||||
if(offset == (registerContent.regSets[cpu].prefix + 0x1000)){
|
||||
memcpy(buf+0x328,®isterContent.regSets[cpu].cpuTimer,
|
||||
sizeof(registerContent.regSets[cpu].cpuTimer));
|
||||
memcpy(buf+0x330,®isterContent.regSets[cpu].clkCmp,
|
||||
sizeof(registerContent.regSets[cpu].clkCmp));
|
||||
memcpy(buf+0x300,®isterContent.regSets[cpu].psw,
|
||||
sizeof(registerContent.regSets[cpu].psw));
|
||||
memcpy(buf+0x318,®isterContent.regSets[cpu].prefix,
|
||||
sizeof(registerContent.regSets[cpu].prefix));
|
||||
memcpy(buf+0x340,®isterContent.regSets[cpu].acrs,
|
||||
sizeof(registerContent.regSets[cpu].acrs));
|
||||
memcpy(buf+0x200,®isterContent.regSets[cpu].fprs,
|
||||
sizeof(registerContent.regSets[cpu].fprs));
|
||||
memcpy(buf+0x280,®isterContent.regSets[cpu].gprs,
|
||||
sizeof(registerContent.regSets[cpu].gprs));
|
||||
memcpy(buf+0x380,®isterContent.regSets[cpu].crs,
|
||||
sizeof(registerContent.regSets[cpu].crs));
|
||||
memcpy(buf+0x31c,®isterContent.regSets[cpu].fpCr,
|
||||
sizeof(registerContent.regSets[cpu].fpCr));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* LKCD dump classes: LKCDDump, LKCDDump32, LKCDDump64
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef LKCD_DUMP_H
|
||||
#define LKCD_DUMP_H
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#include "dump.h"
|
||||
#include "register_content.h"
|
||||
|
||||
#define UTS_LEN 65
|
||||
#define DUMP_BUFFER_SIZE 0x2000 /* Size of dump buffer */
|
||||
|
||||
/* Standard header definitions */
|
||||
#define DUMP_HEADER_SIZE 0x10000
|
||||
#define DUMP_MAGIC_NUMBER 0xa8190173618f23edULL /* Dump magic number */
|
||||
#define DUMP_ASM_MAGIC_NUMBER 0x733339302d64756dULL /* asm magic number */
|
||||
#define DUMP_VERSION_NUMBER 0x8 /* Dump version number */
|
||||
#define DUMP_PANIC_LEN 0x100 /* Dump panic string length */
|
||||
|
||||
/* Dump levels - type specific stuff added later */
|
||||
#define DUMP_LEVEL_ALL 0x10 /* Dump all memory RAM and firmware */
|
||||
|
||||
/* Dump compression options */
|
||||
#define DUMP_COMPRESS_GZIP 0x2 /* Use GZIP compression */
|
||||
|
||||
/* Dump header flags */
|
||||
#define DUMP_DH_RAW 0x1 /* Raw page (no compression) */
|
||||
#define DUMP_DH_COMPRESSED 0x2 /* Page is compressed */
|
||||
#define DUMP_DH_END 0x4 /* End marker on a full dump */
|
||||
|
||||
/* Dump page defines */
|
||||
#define DUMP_PAGE_SHIFT 12ULL
|
||||
#define DUMP_PAGE_SIZE (1ULL << DUMP_PAGE_SHIFT)
|
||||
|
||||
#define GZIP_NOT_COMPRESSED -1
|
||||
|
||||
class LKCDDump : public Dump
|
||||
{
|
||||
public:
|
||||
LKCDDump(Dump*, const char *);
|
||||
virtual ~LKCDDump(void) {}
|
||||
inline virtual void readMem(char *UNUSED(buf), int UNUSED(size))
|
||||
{
|
||||
throw(DumpException("LKCDDump::readMem() not implemented!"));
|
||||
}
|
||||
inline int seekMem(uint64_t UNUSED(offset))
|
||||
{
|
||||
throw(DumpException("LKCDDump::seekMem() not implemented!"));
|
||||
}
|
||||
inline virtual uint64_t getMemSize() const
|
||||
{
|
||||
return dumpHeader.memory_size;
|
||||
}
|
||||
virtual struct timeval getDumpTime(void) const;
|
||||
virtual void writeDump(const char *fileName);
|
||||
virtual void copyRegsToPage(uint64_t offset, char *buf) = 0;
|
||||
protected:
|
||||
struct _lkcd_dump_header {
|
||||
uint64_t magic_number; /* dump magic number,unique to verify */
|
||||
/* dump */
|
||||
uint32_t version; /* version number of this dump */
|
||||
uint32_t header_size; /* size of this header */
|
||||
uint32_t dump_level; /* level of this dump */
|
||||
uint32_t page_size; /* page size (e.g. 4K, 8K, 16K, etc.) */
|
||||
uint64_t memory_size; /* size of entire physical memory */
|
||||
uint64_t memory_start; /* start of physical memory */
|
||||
uint64_t memory_end; /* end of physical memory */
|
||||
/* the number of dump pages in this dump specifically */
|
||||
uint32_t num_dump_pages;
|
||||
char panic_string[DUMP_PANIC_LEN];
|
||||
|
||||
/* timeval depends on machine, two long values */
|
||||
struct {uint64_t tv_sec;
|
||||
uint64_t tv_usec;
|
||||
} time; /* the time of the system crash */
|
||||
|
||||
/* the NEW utsname (uname) information -- in character form */
|
||||
/* we do this so we don't have to include utsname.h */
|
||||
/* plus it helps us be more architecture independent */
|
||||
char utsname_sysname[UTS_LEN];
|
||||
char utsname_nodename[UTS_LEN];
|
||||
char utsname_release[UTS_LEN];
|
||||
char utsname_version[UTS_LEN];
|
||||
char utsname_machine[UTS_LEN];
|
||||
char utsname_domainname[UTS_LEN];
|
||||
|
||||
uint64_t current_task;
|
||||
uint32_t dump_compress; /* compression type used in this dump */
|
||||
uint32_t dump_flags; /* any additional flags */
|
||||
uint32_t dump_device; /* any additional flags */
|
||||
uint64_t s390_asm_magic;
|
||||
uint16_t cpu_cnt;
|
||||
uint32_t lowcore_ptr[512];
|
||||
} __packed;
|
||||
|
||||
struct _lkcd_dump_header_asm {
|
||||
uint64_t magic_number;
|
||||
uint32_t version;
|
||||
uint32_t header_size;
|
||||
uint16_t cpu_cnt;
|
||||
uint16_t real_cpu_cnt;
|
||||
uint32_t lc_vec[512];
|
||||
} __packed;
|
||||
|
||||
struct _dump_page {
|
||||
uint64_t address; /* the address of this dump page */
|
||||
uint32_t size; /* the size of this dump page */
|
||||
uint32_t flags; /* flags (DUMP_COMPRESSED, DUMP_RAW */
|
||||
/* or DUMP_END) */
|
||||
} __packed;
|
||||
|
||||
struct _lkcd_dump_header dumpHeader;
|
||||
struct _lkcd_dump_header_asm dumpHeaderAsm;
|
||||
|
||||
private:
|
||||
int compressGZIP(const char *old, uint32_t old_size, char *n,
|
||||
uint32_t new_size);
|
||||
Dump *referenceDump;
|
||||
};
|
||||
|
||||
class LKCDDump32 : public LKCDDump
|
||||
{
|
||||
public:
|
||||
LKCDDump32(Dump *dump, const RegisterContent32 &rc);
|
||||
virtual void copyRegsToPage(uint64_t offset, char *buf);
|
||||
private:
|
||||
RegisterContent32 registerContent;
|
||||
};
|
||||
|
||||
class LKCDDump64 : public LKCDDump
|
||||
{
|
||||
public:
|
||||
LKCDDump64(Dump *dump, const RegisterContent64 &rc);
|
||||
virtual void copyRegsToPage(uint64_t offset, char *buf);
|
||||
private:
|
||||
RegisterContent64 registerContent;
|
||||
};
|
||||
|
||||
#endif /* LKCD_DUMP_H */
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Register content classes
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "register_content.h"
|
||||
#include "dump.h"
|
||||
|
||||
RegisterContent32::RegisterContent32(void)
|
||||
: regSets(), nrCpus(0)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterContent32::RegisterContent32(const RegisterContent32& r)
|
||||
{
|
||||
nrCpus = r.nrCpus;
|
||||
memcpy(®Sets,&r.regSets,sizeof(regSets));
|
||||
}
|
||||
|
||||
void RegisterContent32::addRegisterSet(const RegisterSet32& rs)
|
||||
{
|
||||
if(nrCpus < MAX_CPUS){
|
||||
regSets[nrCpus++] = rs;
|
||||
} else {
|
||||
throw(DumpException("RegisterContent32::addRegisterSet - " \
|
||||
"No more register sets available"));
|
||||
}
|
||||
}
|
||||
|
||||
RegisterSet32 RegisterContent32::getRegisterSet(int cpu){
|
||||
if(cpu <= nrCpus){
|
||||
return regSets[cpu];
|
||||
} else {
|
||||
throw(DumpException("RegisterContent32::getRegisterSet - " \
|
||||
"No register set for cpu"));
|
||||
}
|
||||
}
|
||||
|
||||
RegisterContent64::RegisterContent64(void)
|
||||
: regSets(), nrCpus(0)
|
||||
{
|
||||
}
|
||||
|
||||
RegisterContent64::RegisterContent64(const RegisterContent64& r)
|
||||
{
|
||||
nrCpus = r.nrCpus;
|
||||
memcpy(®Sets,&r.regSets,sizeof(regSets));
|
||||
}
|
||||
|
||||
void RegisterContent64::addRegisterSet(const RegisterSet64& rs)
|
||||
{
|
||||
if(nrCpus < MAX_CPUS){
|
||||
regSets[nrCpus++] = rs;
|
||||
} else {
|
||||
throw(DumpException("RegisterContent64::addRegisterSet - " \
|
||||
"No more register sets available"));
|
||||
}
|
||||
}
|
||||
|
||||
RegisterSet64 RegisterContent64::getRegisterSet(int cpu)
|
||||
{
|
||||
if(cpu <= nrCpus){
|
||||
return regSets[cpu];
|
||||
} else {
|
||||
throw(DumpException("RegisterContent64::getRegisterSet - " \
|
||||
"No register set for cpu"));
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Register content classes
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#ifndef REGISTER_CONTENT_H
|
||||
#define REGISTER_CONTENT_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define MAX_CPUS 512
|
||||
|
||||
class RegisterSet64
|
||||
{
|
||||
public:
|
||||
uint64_t gprs[16];
|
||||
uint64_t crs[16];
|
||||
uint32_t acrs[16];
|
||||
uint64_t fprs[16];
|
||||
uint32_t fpCr;
|
||||
uint64_t psw[2];
|
||||
uint32_t prefix;
|
||||
uint64_t cpuTimer;
|
||||
uint64_t clkCmp;
|
||||
};
|
||||
|
||||
class RegisterSet32
|
||||
{
|
||||
public:
|
||||
uint32_t gprs[16];
|
||||
uint32_t crs[16];
|
||||
uint32_t acrs[16];
|
||||
uint64_t fprs[4];
|
||||
uint32_t psw[2];
|
||||
uint32_t prefix;
|
||||
uint64_t cpuTimer;
|
||||
uint64_t clkCmp;
|
||||
};
|
||||
|
||||
class RegisterContent64{
|
||||
public:
|
||||
RegisterContent64(void);
|
||||
RegisterContent64(const RegisterContent64&);
|
||||
RegisterSet64 getRegisterSet(int cpu);
|
||||
void addRegisterSet(const RegisterSet64&);
|
||||
inline int getNumCpus(void) const { return nrCpus; }
|
||||
|
||||
RegisterSet64 regSets[MAX_CPUS];
|
||||
private:
|
||||
int nrCpus;
|
||||
|
||||
};
|
||||
|
||||
class RegisterContent32{
|
||||
public:
|
||||
RegisterContent32(void);
|
||||
RegisterContent32(const RegisterContent32&);
|
||||
RegisterSet32 getRegisterSet(int cpu);
|
||||
void addRegisterSet(const RegisterSet32&);
|
||||
inline int getNumCpus(void) const { return nrCpus; }
|
||||
|
||||
RegisterSet32 regSets[MAX_CPUS];
|
||||
private:
|
||||
int nrCpus;
|
||||
};
|
||||
|
||||
#endif /* REGISTER_CONTENT_H */
|
||||
@@ -1,624 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Register content classes:
|
||||
* VMDump, VMDumpClassic, VMDump64, VMDump64Big, VMDump32
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "vm_dump.h"
|
||||
|
||||
Dump::DumpType VMDump::getDumpType(const char* inputFileName)
|
||||
{
|
||||
uint8_t fmbk_id[8] = {0xc8, 0xc3, 0xd7, 0xc4, 0xc6, 0xd4, 0xc2, 0xd2};
|
||||
struct _fir_basic fir;
|
||||
struct _fmbk fmbk;
|
||||
struct _adsr adsr;
|
||||
char msg[200];
|
||||
FILE* fh;
|
||||
|
||||
fh = fopen(inputFileName,"r");
|
||||
if (!fh) {
|
||||
sprintf(msg,"Could not open '%s'",inputFileName);
|
||||
throw DumpErrnoException(msg);
|
||||
}
|
||||
|
||||
/* Record 1: adsr */
|
||||
dump_read(&adsr, sizeof(adsr), 1, fh);
|
||||
|
||||
/* Record 2: fmbk */
|
||||
dump_seek(fh, 0x1000, SEEK_SET);
|
||||
if (fread(&fmbk, sizeof(fmbk), 1, fh) != 1) {
|
||||
if(ferror(fh)) {
|
||||
sprintf(msg,"Could not read header of vmdump '%s'",
|
||||
inputFileName);
|
||||
fclose(fh);
|
||||
throw DumpErrnoException(msg);
|
||||
} else{
|
||||
sprintf(msg,"Input file '%s' is not a vmdump",
|
||||
inputFileName);
|
||||
fclose(fh);
|
||||
throw DumpException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if this is a vmdump */
|
||||
if (memcmp(fmbk.id, fmbk_id, 8) != 0 ||
|
||||
adsr.dump_type != 0xe5d4c4e4d4d74040ULL) {
|
||||
fclose(fh);
|
||||
sprintf(msg, "Input file '%s' is not a vmdump", inputFileName);
|
||||
throw DumpException(msg);
|
||||
}
|
||||
|
||||
/* Record 3-7: fir */
|
||||
dump_seek(fh, (fmbk.rec_nr_fir - 1) * 0x1000, SEEK_SET);
|
||||
if(fread(&fir, sizeof(fir), 1, fh) != 1) {
|
||||
if (ferror(fh)) {
|
||||
sprintf(msg,"Could not read header of vmdump '%s'",
|
||||
inputFileName);
|
||||
fclose(fh);
|
||||
throw DumpErrnoException(msg);
|
||||
}
|
||||
else{
|
||||
sprintf(msg, "Could not read header of vmdump '%s'",
|
||||
inputFileName);
|
||||
fclose(fh);
|
||||
throw DumpException(msg);
|
||||
}
|
||||
}
|
||||
fclose(fh);
|
||||
if (fir.fir_format == 0) {
|
||||
return DT_VM32;
|
||||
} else if (fir.fir_format == 0x02) {/*XXX && (fir.dump_format == 0x1))*/
|
||||
return DT_VM64_BIG;
|
||||
} else if (fir.fir_format == 0x82) {
|
||||
return DT_VM64;
|
||||
} else {
|
||||
return DT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
VMDump::VMDump(const char *fileName) : Dump(fileName, "rb")
|
||||
{
|
||||
uint8_t fmbk_id[8] = {0xc8, 0xc3, 0xd7, 0xc4, 0xc6, 0xd4, 0xc2, 0xd2};
|
||||
|
||||
ebcdicAsciiConv = iconv_open("ISO-8859-1", "EBCDIC-US");
|
||||
|
||||
/* Record 1: adsrRecord */
|
||||
|
||||
dump_seek(fh,0,SEEK_SET);
|
||||
dump_read(&adsrRecord,sizeof(adsrRecord),1,fh);
|
||||
|
||||
if(debug) {
|
||||
char buf_asc[1024];
|
||||
char buf[1024];
|
||||
int i;
|
||||
|
||||
fprintf(stderr, "off=%d\n", adsrRecord.sec5_offset);
|
||||
dump_seek(fh, adsrRecord.sec5_offset, SEEK_SET);
|
||||
dump_read(buf, adsrRecord.sec5_len, 1, fh);
|
||||
ebcAsc(buf, buf_asc, adsrRecord.sec5_len);
|
||||
for (i=0; i < adsrRecord.sec5_len; i++) {
|
||||
if ((buf_asc[i]==0) || iscntrl(buf_asc[i]))
|
||||
buf_asc[i]=' ';
|
||||
}
|
||||
buf_asc[adsrRecord.sec5_len] = 0;
|
||||
printf("symptom string1: %s\n",buf_asc);
|
||||
}
|
||||
|
||||
/* Record 2: fmbk */
|
||||
|
||||
dump_seek(fh,0x1000,SEEK_SET);
|
||||
dump_read(&fmbkRecord,sizeof(fmbkRecord),1,fh);
|
||||
|
||||
/* Check if this is a vmdump */
|
||||
if(memcmp(fmbkRecord.id, fmbk_id, 8) != 0) {
|
||||
throw DumpException("Input file is not a vmdump");
|
||||
}
|
||||
|
||||
/* Record 3-7: fir records read by subclasses */
|
||||
|
||||
/* Record 8: albk */
|
||||
|
||||
dump_seek(fh,(fmbkRecord.rec_nr_access-1)*0x1000 ,SEEK_SET);
|
||||
dump_read(&albkRecord,sizeof(albkRecord),1,fh);
|
||||
}
|
||||
|
||||
struct timeval VMDump::getDumpTime(void) const
|
||||
{
|
||||
struct timeval rc;
|
||||
|
||||
s390TodToTimeval(adsrRecord.tod,&rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void VMDump::printDebug(void)
|
||||
{
|
||||
struct timeval time;
|
||||
char fmbk_id[8];
|
||||
char albk_id[8];
|
||||
|
||||
s390TodToTimeval(adsrRecord.tod, &time);
|
||||
|
||||
/* adsr */
|
||||
|
||||
printf("time : %s\n", ctime(&time.tv_sec));
|
||||
printf("stat1 : %x\n", adsrRecord.record_status_flag1);
|
||||
printf("stat2 : %x\n", adsrRecord.record_status_flag2);
|
||||
printf("sec 2 len: %i\n", adsrRecord.sec2_len);
|
||||
printf("sec 2.1 len: %i/%i\n", adsrRecord.sec2_1_len,
|
||||
adsrRecord.sec2_1_offset);
|
||||
printf("sec 3 len: %i/%i\n", adsrRecord.sec3_len,
|
||||
adsrRecord.sec3_offset);
|
||||
printf("sec 4 len: %i/%i\n", adsrRecord.sec4_len,
|
||||
adsrRecord.sec4_offset);
|
||||
printf("sec 5 len: %i/%i\n", adsrRecord.sec5_len,
|
||||
adsrRecord.sec5_offset);
|
||||
printf("sec 6 len: %i/%i\n", adsrRecord.sec6_len,
|
||||
adsrRecord.sec6_offset);
|
||||
|
||||
/* fmbk */
|
||||
|
||||
ebcAsc(fmbkRecord.id, fmbk_id, sizeof(fmbkRecord.id));
|
||||
fmbk_id[7] = 0;
|
||||
printf("id : %s\n", fmbk_id);
|
||||
printf("fir rec nr: %i\n", fmbkRecord.rec_nr_fir);
|
||||
printf("vec rec nr: %i\n", fmbkRecord.rec_nr_vector);
|
||||
printf("access rec nr: %i\n", fmbkRecord.rec_nr_access);
|
||||
|
||||
|
||||
/* albk */
|
||||
|
||||
ebcAsc(albkRecord.id, albk_id, sizeof(albkRecord.id));
|
||||
albk_id[7]=0;
|
||||
printf("ALBK id : %s\n",albk_id);
|
||||
}
|
||||
|
||||
void VMDump::printInfo(void)
|
||||
{
|
||||
struct timeval time;
|
||||
|
||||
s390TodToTimeval(adsrRecord.tod,&time);
|
||||
fprintf(stderr, " date........: %s",ctime(&time.tv_sec));
|
||||
}
|
||||
|
||||
int VMDump::seekMem(uint64_t offset)
|
||||
{
|
||||
if (offset != 0) {
|
||||
return -1;
|
||||
}
|
||||
pageOffset = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void VMDump::readMem(char* buf, int size)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (pageOffset == 0)
|
||||
dump_seek(fh, memoryStartRecord, SEEK_SET);
|
||||
|
||||
if (size % 0x1000 != 0) {
|
||||
throw(DumpException("internal error: VMDump::readMem() " \
|
||||
"can only handle sizes which are multiples of page size"));
|
||||
}
|
||||
|
||||
for(i = 0; i < size; i += 0x1000) {
|
||||
if(testPage(pageOffset)) {
|
||||
dump_read(buf + i, 0x1000, 1, fh);
|
||||
} else {
|
||||
memset(buf + i, 0, 0x1000);
|
||||
}
|
||||
pageOffset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
VMDump::~VMDump(void)
|
||||
{
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VMDumpClassic: traditional 32/64 bit vmdump (before z/VM 5.2) */
|
||||
/*****************************************************************************/
|
||||
|
||||
VMDumpClassic::VMDumpClassic(const char *fileName) : VMDump(fileName)
|
||||
{
|
||||
int storageKeyPages,bitMapPages;
|
||||
|
||||
pageOffset = 0;
|
||||
|
||||
/* Record 9: asibk */
|
||||
|
||||
dump_seek(fh,fmbkRecord.rec_nr_access * 0x1000,SEEK_SET);
|
||||
dump_read(&asibkRecord,sizeof(asibkRecord),1,fh);
|
||||
|
||||
/* Record 10: bitmaps */
|
||||
|
||||
dump_seek(fh,(fmbkRecord.rec_nr_access + 1)* 0x1000 ,SEEK_SET);
|
||||
bitmap = new char[asibkRecord.storage_size_2GB / (0x1000 * 8)];
|
||||
dump_read(bitmap,asibkRecord.storage_size_2GB / (0x1000*8),1,fh);
|
||||
|
||||
bitMapPages=asibkRecord.storage_size_2GB / (0x1000 * 8);
|
||||
if (bitMapPages % 0x1000 != 0)
|
||||
bitMapPages = bitMapPages/0x1000 + 1;
|
||||
else
|
||||
bitMapPages = bitMapPages/0x1000;
|
||||
|
||||
storageKeyPages=asibkRecord.storage_size_2GB / 0x1000;
|
||||
if(storageKeyPages % 0x1000 != 0) {
|
||||
storageKeyPages = storageKeyPages/0x1000 + 1;
|
||||
} else {
|
||||
storageKeyPages = storageKeyPages/0x1000;
|
||||
}
|
||||
|
||||
/* Skip storage keys */
|
||||
|
||||
memoryStartRecord = (fmbkRecord.rec_nr_access + 1) *0x1000 /* 0x9000 */
|
||||
+ (bitMapPages + storageKeyPages)*0x1000;
|
||||
if(debug) {
|
||||
printf("Mem Offset: %llx\n", (long long) memoryStartRecord);
|
||||
}
|
||||
}
|
||||
|
||||
void VMDumpClassic::printInfo(void)
|
||||
{
|
||||
VMDump::printInfo();
|
||||
fprintf(stderr, " storage.....: %i MB\n",
|
||||
asibkRecord.storage_size_2GB/(1024*1024));
|
||||
}
|
||||
|
||||
VMDumpClassic::~VMDumpClassic(void)
|
||||
{
|
||||
delete bitmap;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VMDump32: 32 bit vmdump */
|
||||
/*****************************************************************************/
|
||||
|
||||
VMDump32::VMDump32(const char* filename) : VMDumpClassic(filename)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!fh) {
|
||||
return;
|
||||
}
|
||||
|
||||
dump_seek(fh,(fmbkRecord.rec_nr_fir-1)* 0x1000 ,SEEK_SET);
|
||||
dump_read(&fir32Record,sizeof(fir32Record),1,fh);
|
||||
|
||||
fir32OtherRecords = new _fir_other_32[fir32Record.online_cpus];
|
||||
for(i=0; i < fir32Record.online_cpus; i++) {
|
||||
/* fir other */
|
||||
dump_read(&fir32OtherRecords[i],sizeof(fir32OtherRecords[i]),1,
|
||||
fh);
|
||||
}
|
||||
if(debug)
|
||||
printDebug();
|
||||
}
|
||||
|
||||
RegisterContent32 VMDump32::getRegisterContent(void)
|
||||
{
|
||||
RegisterContent32 rc;
|
||||
RegisterSet32 rs;
|
||||
int cpu;
|
||||
|
||||
/* First CPU */
|
||||
|
||||
memcpy(&rs.gprs, &fir32Record.gprs, sizeof(rs.gprs));
|
||||
memcpy(&rs.crs, &fir32Record.crs, sizeof(rs.crs));
|
||||
memcpy(&rs.acrs, &fir32Record.acrs, sizeof(rs.acrs));
|
||||
memcpy(&rs.psw, &fir32Record.psw, sizeof(rs.psw));
|
||||
memcpy(&rs.prefix, &fir32Record.prefix, sizeof(rs.prefix));
|
||||
memcpy(&rs.fprs, &fir32Record.fprs, sizeof(rs.fprs));
|
||||
memcpy(&rs.cpuTimer, &fir32Record.cpu_timer, sizeof(rs.cpuTimer));
|
||||
memcpy(&rs.clkCmp, &fir32Record.clock_cmp, sizeof(rs.clkCmp));
|
||||
|
||||
rc.addRegisterSet(rs);
|
||||
|
||||
/* Other online cpus */
|
||||
|
||||
for(cpu = 0; cpu < fir32Record.online_cpus; cpu++) {
|
||||
memcpy(&rs.gprs, &fir32OtherRecords[cpu].gprs, sizeof(rs.gprs));
|
||||
memcpy(&rs.crs, &fir32OtherRecords[cpu].crs, sizeof(rs.crs));
|
||||
memcpy(&rs.acrs, &fir32OtherRecords[cpu].acrs, sizeof(rs.acrs));
|
||||
/* No psw for ESA vmdumps */
|
||||
rs.psw[0] = 0xdeadbeef;
|
||||
rs.psw[1] = 0xdeadbeef;
|
||||
memcpy(&rs.prefix, &fir32OtherRecords[cpu].prefix,
|
||||
sizeof(rs.prefix));
|
||||
memcpy(&rs.fprs, &fir32OtherRecords[cpu].fprs, sizeof(rs.fprs));
|
||||
memcpy(&rs.cpuTimer, &fir32OtherRecords[cpu].cpu_timer,
|
||||
sizeof(rs.cpuTimer));
|
||||
memcpy(&rs.clkCmp, &fir32OtherRecords[cpu].clock_cmp,
|
||||
sizeof(rs.clkCmp));
|
||||
rc.addRegisterSet(rs);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void VMDump32::printDebug(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
VMDump::printDebug();
|
||||
printf("prefix: %x\n", fir32Record.prefix);
|
||||
printf("cpus: %x\n", fir32Record.online_cpus);
|
||||
printf("psw: %08x %08x\n", fir32Record.psw[0], fir32Record.psw[1]);
|
||||
|
||||
for (i=0; i < fir32Record.online_cpus; i++) {
|
||||
/* fir other */
|
||||
printf("prefix (%i): %x\n", i, fir32OtherRecords[i].prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
VMDump32::printInfo(void)
|
||||
{
|
||||
fprintf(stderr, "vmdump information:\n");
|
||||
fprintf(stderr, " architecture: 32 bit\n");
|
||||
VMDumpClassic::printInfo();
|
||||
fprintf(stderr, " cpus........: %x\n", fir32Record.online_cpus + 1);
|
||||
}
|
||||
|
||||
|
||||
VMDump32::~VMDump32(void)
|
||||
{
|
||||
delete fir32OtherRecords;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VMDump64: 64 bit vmdump for old vmdump format (z/VM < 5.2) */
|
||||
/*****************************************************************************/
|
||||
|
||||
VMDump64::VMDump64(const char* filename) : VMDumpClassic(filename)
|
||||
{
|
||||
int i;
|
||||
|
||||
if(!fh) {
|
||||
return;
|
||||
}
|
||||
|
||||
dump_seek(fh,(fmbkRecord.rec_nr_fir-1)* 0x1000 ,SEEK_SET);
|
||||
dump_read(&fir64Record,sizeof(fir64Record),1,fh);
|
||||
|
||||
fir64OtherRecords = new _fir_other_64[fir64Record.online_cpus];
|
||||
for (i=0; i < fir64Record.online_cpus; i++) {
|
||||
/* fir other */
|
||||
dump_read(&fir64OtherRecords[i], sizeof(fir64OtherRecords[i]),
|
||||
1, fh);
|
||||
}
|
||||
if(debug)
|
||||
printDebug();
|
||||
}
|
||||
|
||||
void VMDump64::printDebug(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
VMDump::printDebug();
|
||||
printf("prefix: %x\n", fir64Record.prefix);
|
||||
printf("cpus: %x\n", fir64Record.online_cpus);
|
||||
printf("psw: %016llx %016llx\n", (long long)fir64Record.psw[0],
|
||||
(long long)fir64Record.psw[1]);
|
||||
|
||||
for (i=0; i < fir64Record.online_cpus; i++) {
|
||||
/* fir other */
|
||||
printf("prefix (%i): %x\n", i, fir64OtherRecords[i].prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void VMDump64::printInfo(void)
|
||||
{
|
||||
fprintf(stderr, "vmdump information:\n");
|
||||
fprintf(stderr, " architecture: 64 bit\n");
|
||||
VMDumpClassic::printInfo();
|
||||
fprintf(stderr, " cpus........: %x\n",fir64Record.online_cpus + 1);
|
||||
}
|
||||
|
||||
|
||||
RegisterContent64 VMDump64::getRegisterContent(void)
|
||||
{
|
||||
RegisterContent64 rc;
|
||||
RegisterSet64 rs;
|
||||
int cpu;
|
||||
|
||||
/* First CPU */
|
||||
|
||||
memcpy(&rs.gprs, &fir64Record.gprs, sizeof(rs.gprs));
|
||||
memcpy(&rs.crs, &fir64Record.crs, sizeof(rs.crs));
|
||||
memcpy(&rs.acrs, &fir64Record.acrs, sizeof(rs.acrs));
|
||||
memcpy(&rs.psw, &fir64Record.psw, sizeof(rs.psw));
|
||||
memcpy(&rs.prefix, &fir64Record.prefix, sizeof(rs.prefix));
|
||||
memcpy(&rs.fprs, &fir64Record.fprs, sizeof(rs.fprs));
|
||||
memcpy(&rs.cpuTimer, &fir64Record.cpu_timer, sizeof(rs.cpuTimer));
|
||||
memcpy(&rs.clkCmp, &fir64Record.clock_cmp, sizeof(rs.clkCmp));
|
||||
memcpy(&rs.fpCr, &fir64Record.fp_cntrl_reg, sizeof(rs.fpCr));
|
||||
|
||||
rc.addRegisterSet(rs);
|
||||
|
||||
/* other online cpus */
|
||||
|
||||
for (cpu = 0; cpu < fir64Record.online_cpus; cpu++) {
|
||||
memcpy(&rs.gprs, &fir64OtherRecords[cpu].gprs, sizeof(rs.gprs));
|
||||
memcpy(&rs.crs, &fir64OtherRecords[cpu].crs, sizeof(rs.crs));
|
||||
memcpy(&rs.acrs, &fir64OtherRecords[cpu].acrs, sizeof(rs.acrs));
|
||||
memcpy(&rs.psw, &fir64OtherRecords[cpu].psw, sizeof(rs.psw));
|
||||
memcpy(&rs.prefix, &fir64OtherRecords[cpu].prefix,
|
||||
sizeof(rs.prefix));
|
||||
memcpy(&rs.fprs, &fir64OtherRecords[cpu].fprs, sizeof(rs.fprs));
|
||||
memcpy(&rs.cpuTimer, &fir64OtherRecords[cpu].cpu_timer,
|
||||
sizeof(rs.cpuTimer));
|
||||
memcpy(&rs.clkCmp, &fir64OtherRecords[cpu].clock_cmp,
|
||||
sizeof(rs.clkCmp));
|
||||
memcpy(&rs.fpCr, &fir64OtherRecords[cpu].fp_cntrl_reg,
|
||||
sizeof(rs.fpCr));
|
||||
rc.addRegisterSet(rs);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
VMDump64::~VMDump64(void)
|
||||
{
|
||||
delete fir64OtherRecords;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* VMDump64Big: 64 bit vmdump with new big storage dump format */
|
||||
/*****************************************************************************/
|
||||
|
||||
VMDump64Big::VMDump64Big(const char* filename) : VMDump(filename)
|
||||
{
|
||||
uint64_t pageNum, nrDumpedPages;
|
||||
int i, j;
|
||||
|
||||
if(!fh) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Record 9: asibk */
|
||||
|
||||
dump_seek(fh, fmbkRecord.rec_nr_access * 0x1000,SEEK_SET);
|
||||
dump_read(&asibkRecordNew, sizeof(asibkRecordNew), 1, fh);
|
||||
|
||||
/* Record 10: bitmaps: */
|
||||
/* Read all bitmap pages and setup bitmap array */
|
||||
|
||||
pageNum = 0;
|
||||
nrDumpedPages = asibkRecordNew.storage_size_def_store / 0x1000;
|
||||
memoryStartRecord = (fmbkRecord.rec_nr_access + 1) * 0x1000;
|
||||
bitmap = new char[asibkRecordNew.storage_size_def_store/(0x1000 * 8)];
|
||||
if(!bitmap) {
|
||||
throw(DumpErrnoException("out of memory"));
|
||||
}
|
||||
memset(bitmap,0,asibkRecordNew.storage_size_def_store/(0x1000 * 8));
|
||||
|
||||
dump_seek(fh,(fmbkRecord.rec_nr_access + 1)* 0x1000 ,SEEK_SET);
|
||||
|
||||
do {
|
||||
char bmIndexPage[0x1000];
|
||||
|
||||
dump_read(bmIndexPage, sizeof(bmIndexPage), 1, fh);
|
||||
memoryStartRecord += 0x1000;
|
||||
for (i=0; i < 0x1000; i++) {
|
||||
if(testBitmapPage(bmIndexPage, i)) {
|
||||
char bmPage[0x1000];
|
||||
|
||||
dump_read(bmPage,sizeof(bmPage),1,fh);
|
||||
memoryStartRecord += 0x1000;
|
||||
for(j = 0; j < 0x1000; j++) {
|
||||
if(testBitmapKeyPage(bmPage, j)) {
|
||||
setPageBit(pageNum);
|
||||
}
|
||||
pageNum++;
|
||||
if(pageNum == nrDumpedPages) {
|
||||
goto all_bitmaps_read;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pageNum += 0x1000; /* Empty pages */
|
||||
}
|
||||
}
|
||||
} while (pageNum < nrDumpedPages);
|
||||
|
||||
all_bitmaps_read:
|
||||
|
||||
if(debug)
|
||||
printf("Mem Offset: %llx\n", (long long)memoryStartRecord);
|
||||
|
||||
dump_seek(fh, (fmbkRecord.rec_nr_fir-1)* 0x1000, SEEK_SET);
|
||||
dump_read(&fir64Record, sizeof(fir64Record), 1, fh);
|
||||
|
||||
fir64OtherRecords = new _fir_other_64[fir64Record.online_cpus];
|
||||
for (i=0; i < fir64Record.online_cpus; i++) {
|
||||
/* fir other */
|
||||
dump_read(&fir64OtherRecords[i], sizeof(fir64OtherRecords[i]),
|
||||
1, fh);
|
||||
}
|
||||
if(debug)
|
||||
printDebug();
|
||||
}
|
||||
|
||||
void VMDump64Big::printDebug(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
VMDump::printDebug();
|
||||
printf("prefix: %x\n", fir64Record.prefix);
|
||||
printf("cpus: %x\n", fir64Record.online_cpus);
|
||||
printf("psw: %016llx %016llx\n", (long long)fir64Record.psw[0],
|
||||
(long long)fir64Record.psw[1]);
|
||||
|
||||
for (i=0; i < fir64Record.online_cpus; i++) {
|
||||
/* fir other */
|
||||
printf("prefix (%i): %x\n", i, fir64OtherRecords[i].prefix);
|
||||
}
|
||||
}
|
||||
|
||||
void VMDump64Big::printInfo(void)
|
||||
{
|
||||
fprintf(stderr, "vmdump information:\n");
|
||||
fprintf(stderr, " architecture: 64 bit (big)\n");
|
||||
fprintf(stderr, " storage.....: %lli MB\n",
|
||||
(long long)asibkRecordNew.storage_size_def_store / (1024*1024));
|
||||
VMDump::printInfo();
|
||||
fprintf(stderr, " cpus........: %x\n", fir64Record.online_cpus + 1);
|
||||
}
|
||||
|
||||
|
||||
RegisterContent64 VMDump64Big::getRegisterContent(void)
|
||||
{
|
||||
RegisterContent64 rc;
|
||||
RegisterSet64 rs;
|
||||
int cpu;
|
||||
|
||||
/* First CPU */
|
||||
|
||||
memcpy(&rs.gprs, &fir64Record.gprs, sizeof(rs.gprs));
|
||||
memcpy(&rs.crs, &fir64Record.crs, sizeof(rs.crs));
|
||||
memcpy(&rs.acrs, &fir64Record.acrs, sizeof(rs.acrs));
|
||||
memcpy(&rs.psw, &fir64Record.psw, sizeof(rs.psw));
|
||||
memcpy(&rs.prefix, &fir64Record.prefix, sizeof(rs.prefix));
|
||||
memcpy(&rs.fprs, &fir64Record.fprs, sizeof(rs.fprs));
|
||||
memcpy(&rs.cpuTimer, &fir64Record.cpu_timer, sizeof(rs.cpuTimer));
|
||||
memcpy(&rs.clkCmp, &fir64Record.clock_cmp, sizeof(rs.clkCmp));
|
||||
memcpy(&rs.fpCr, &fir64Record.fp_cntrl_reg, sizeof(rs.fpCr));
|
||||
|
||||
rc.addRegisterSet(rs);
|
||||
|
||||
/* other online cpus */
|
||||
|
||||
for(cpu = 0; cpu < fir64Record.online_cpus; cpu++) {
|
||||
memcpy(&rs.gprs, &fir64OtherRecords[cpu].gprs, sizeof(rs.gprs));
|
||||
memcpy(&rs.crs, &fir64OtherRecords[cpu].crs, sizeof(rs.crs));
|
||||
memcpy(&rs.acrs, &fir64OtherRecords[cpu].acrs, sizeof(rs.acrs));
|
||||
memcpy(&rs.psw, &fir64OtherRecords[cpu].psw, sizeof(rs.psw));
|
||||
memcpy(&rs.prefix, &fir64OtherRecords[cpu].prefix,
|
||||
sizeof(rs.prefix));
|
||||
memcpy(&rs.fprs, &fir64OtherRecords[cpu].fprs, sizeof(rs.fprs));
|
||||
memcpy(&rs.cpuTimer, &fir64OtherRecords[cpu].cpu_timer,
|
||||
sizeof(rs.cpuTimer));
|
||||
memcpy(&rs.clkCmp, &fir64OtherRecords[cpu].clock_cmp,
|
||||
sizeof(rs.clkCmp));
|
||||
memcpy(&rs.fpCr, &fir64OtherRecords[cpu].fp_cntrl_reg,
|
||||
sizeof(rs.fpCr));
|
||||
rc.addRegisterSet(rs);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
VMDump64Big::~VMDump64Big(void)
|
||||
{
|
||||
delete bitmap;
|
||||
delete fir64OtherRecords;
|
||||
}
|
||||
@@ -1,484 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Register content classes:
|
||||
* VMDump, VMDumpClassic, VMDump64, VMDump64Big, VMDump32
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
/*===========================*
|
||||
* The format of an vmdump: *
|
||||
*===========================*
|
||||
*---------------------------*
|
||||
* Symptom Record *
|
||||
* (ADSR COPY) Record 1 *
|
||||
*---------------------------*
|
||||
* Dump File Map Record *
|
||||
* (HCPDFMBK COPY) Record 2 *
|
||||
*---------------------------*
|
||||
* Dump File Info Record *
|
||||
* (HCPDFIR COPY) Records 3-7*
|
||||
*---------------------------*
|
||||
* Vector Registers *
|
||||
* (optional) *
|
||||
*---------------------------*
|
||||
* Access Lists (HCPDALBK) *
|
||||
*---------------------------*
|
||||
* Address Space A *
|
||||
* Information and Map *
|
||||
* Record (HCPASIBK) *
|
||||
*---------------------------*
|
||||
* Address Space A *
|
||||
* Bit Maps *
|
||||
*---------------------------*
|
||||
* Address Space A *
|
||||
* Key Maps *
|
||||
*---------------------------*
|
||||
* Address Space A *
|
||||
* Guest Storage *
|
||||
*---------------------------*
|
||||
* Additional Address Spaces *
|
||||
* ASIBK *
|
||||
* Bit Maps *
|
||||
* Key Maps *
|
||||
* Guest Storage *
|
||||
* *NOTE* These probably *
|
||||
* aren't in a Linux guest. *
|
||||
*---------------------------*
|
||||
*/
|
||||
|
||||
#ifndef VMDUMP_H
|
||||
#define VMDUMP_H
|
||||
|
||||
#include <iconv.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#include "dump.h"
|
||||
#include "register_content.h"
|
||||
|
||||
class VMDump : public Dump
|
||||
{
|
||||
public:
|
||||
VMDump(const char *filename);
|
||||
virtual ~VMDump(void);
|
||||
virtual void readMem(char *buf, int size);
|
||||
virtual int seekMem(uint64_t offset);
|
||||
virtual struct timeval getDumpTime(void) const;
|
||||
|
||||
void printDebug(void);
|
||||
void printInfo(void);
|
||||
|
||||
static DumpType getDumpType(const char *);
|
||||
inline int testPage(uint64_t bit) const
|
||||
{
|
||||
return (bitmap[bit/8] & (1 << (7-(bit % 8))));
|
||||
}
|
||||
inline void setPageBit(uint64_t bit) const
|
||||
{
|
||||
bitmap[bit/8] |= (1 << (7-(bit % 8)));
|
||||
}
|
||||
protected:
|
||||
/* Types */
|
||||
struct _adsr {
|
||||
/* Section 1*/
|
||||
uint16_t sr;
|
||||
uint32_t cpu_model;
|
||||
char cpu_serial[6];
|
||||
uint32_t time_zone_conversion_factor;
|
||||
uint64_t tod;
|
||||
char time_stamp_str[4];
|
||||
char date_str[6];
|
||||
char node_name[8];
|
||||
char product_id[4];
|
||||
char feature_level[8];
|
||||
uint8_t record_status_flag1;
|
||||
uint8_t record_status_flag2;
|
||||
uint64_t dump_type;
|
||||
|
||||
/* Section 2*/
|
||||
char arch_level[2];
|
||||
uint16_t sec2_len;
|
||||
uint16_t sec2_1_len;
|
||||
uint16_t sec2_1_offset;
|
||||
uint16_t sec3_len;
|
||||
uint16_t sec3_offset;
|
||||
uint16_t sec4_len;
|
||||
uint16_t sec4_offset;
|
||||
uint16_t sec5_len;
|
||||
uint16_t sec5_offset;
|
||||
uint16_t sec6_len;
|
||||
uint16_t sec6_offset;
|
||||
} __packed;
|
||||
|
||||
struct _fmbk {
|
||||
char id[8];
|
||||
uint32_t rec_nr_fir;
|
||||
uint32_t rec_nr_vector;
|
||||
uint32_t rec_nr_access;
|
||||
uint32_t num_acc_recs;
|
||||
uint32_t num_addr_spaces;
|
||||
uint32_t rec_nr_asibk;
|
||||
} __packed;
|
||||
|
||||
struct _fir_basic {
|
||||
char filler1[15];
|
||||
uint8_t dump_format;/* 0x1 for big storage dump, 0x2 for cp */
|
||||
/* hard abend, 0x3 for cp soft abend */
|
||||
char filler2[171];
|
||||
uint8_t fir_format; /* 0x2 for big esame, 0x82 for esame, */
|
||||
/* 0x00 for esa */
|
||||
} __packed;
|
||||
|
||||
struct _albk {
|
||||
char id[8];
|
||||
} __packed;
|
||||
|
||||
/* Methods */
|
||||
inline void ebcAsc(char *in, char *out, size_t size) const
|
||||
{
|
||||
size_t size_out = size;
|
||||
size_t size_in = size;
|
||||
size_t rc;
|
||||
|
||||
rc = iconv(ebcdicAsciiConv, &in, &size_in, &out, &size_out);
|
||||
if (rc == (size_t) -1)
|
||||
throw(DumpException("Code page translation EBCDIC-ASCII failed"));
|
||||
}
|
||||
|
||||
/* Members */
|
||||
struct _adsr adsrRecord;
|
||||
struct _fmbk fmbkRecord;
|
||||
struct _albk albkRecord;
|
||||
uint64_t memoryStartRecord;
|
||||
char *bitmap;
|
||||
uint64_t pageOffset;
|
||||
private:
|
||||
iconv_t ebcdicAsciiConv;
|
||||
};
|
||||
|
||||
class VMDumpClassic : public VMDump
|
||||
{
|
||||
public:
|
||||
VMDumpClassic(const char *filename);
|
||||
virtual ~VMDumpClassic(void);
|
||||
void printInfo(void);
|
||||
inline virtual uint64_t getMemSize(void) const
|
||||
{
|
||||
return (uint64_t)asibkRecord.storage_size_2GB;
|
||||
}
|
||||
protected:
|
||||
/* Types */
|
||||
struct _asibk {
|
||||
char id[8];
|
||||
char as_token[8];
|
||||
char spaceid[33];
|
||||
char reserved1[3];
|
||||
uint32_t storage_size_2GB;
|
||||
uint32_t dcss_bitmap_first_rec;
|
||||
uint32_t byte_past_highest_defined_byte;
|
||||
uint64_t format_of_as;
|
||||
char dump_id[100];
|
||||
uint32_t nr_of_recs_of_first_bit_map;
|
||||
} __packed;
|
||||
|
||||
|
||||
/* Members */
|
||||
struct _asibk asibkRecord;
|
||||
|
||||
};
|
||||
|
||||
#define MAX_BKEY_PAGES 2
|
||||
|
||||
class VMDump64Big : public VMDump
|
||||
{
|
||||
public:
|
||||
VMDump64Big(const char *filename);
|
||||
virtual ~VMDump64Big(void);
|
||||
RegisterContent64 getRegisterContent(void);
|
||||
|
||||
void printDebug(void);
|
||||
void printInfo(void);
|
||||
|
||||
inline virtual uint64_t getMemSize(void) const
|
||||
{
|
||||
return (uint64_t)asibkRecordNew.storage_size_def_store;
|
||||
}
|
||||
private:
|
||||
inline int testBitmapPage(char *page, uint64_t bit) const
|
||||
{
|
||||
return (page[bit/8] & (1 << (7-(bit % 8))));
|
||||
}
|
||||
|
||||
inline int testBitmapKeyPage(char *page, uint64_t bit) const
|
||||
{
|
||||
return (page[bit] & 0x01);
|
||||
}
|
||||
|
||||
/* types */
|
||||
struct _asibk_64_new {
|
||||
char id[8];
|
||||
char as_token[8];
|
||||
char spaceid[33];
|
||||
char reserved1[2];
|
||||
uint8_t asibk_format;
|
||||
char filler1[12];
|
||||
uint64_t storage_size_with_dcss;
|
||||
uint64_t storage_size_def_store;
|
||||
char filler2[136];
|
||||
uint64_t online_storage_table[8]; /* for "def store config" */
|
||||
uint64_t fence1;
|
||||
uint64_t requested_range_table[8];
|
||||
uint64_t fence2;
|
||||
uint32_t record_number_of_first_bit_map; /* XXX */
|
||||
} __packed;
|
||||
|
||||
struct _fir_64 {
|
||||
char id[8];
|
||||
uint64_t reserved1;
|
||||
uint64_t gprs[16];
|
||||
uint32_t prefix;
|
||||
char reserved2[5];
|
||||
uint64_t tod;
|
||||
char reserved3[8];
|
||||
uint64_t cpu_timer;
|
||||
char reserved4[7];
|
||||
uint8_t flag;
|
||||
uint8_t type;
|
||||
uint8_t complete;
|
||||
uint8_t fir_format; /* 0x82 for esame - 0x00 for esa */
|
||||
uint8_t cont_flags;
|
||||
uint8_t crypto_domain_index_reg;
|
||||
uint8_t virt_cpu_info;
|
||||
uint8_t arch_mode_id;
|
||||
uint64_t psw[2];
|
||||
uint64_t crs[16];
|
||||
uint64_t fprs[16];
|
||||
uint8_t reserved5;
|
||||
uint64_t clock_cmp;
|
||||
char reserved6[3];
|
||||
uint32_t tod_programmable_reg;
|
||||
uint32_t reserved_for_dvf[20];
|
||||
uint32_t acrs[16];
|
||||
uint32_t storage_size_2GB;
|
||||
uint32_t reserved7;
|
||||
uint32_t hcpsys_addr;
|
||||
uint32_t reserved8;
|
||||
uint64_t storage_size;
|
||||
uint32_t snap_area_map_blk;
|
||||
uint32_t reserved9;
|
||||
char loc_mem[256];
|
||||
uint16_t online_cpus;
|
||||
uint16_t cpu_addr;
|
||||
uint16_t section_size_vector;
|
||||
uint16_t reserved10;
|
||||
char asit_primary[8];
|
||||
char space_id_primary[33];
|
||||
char reserved12[3];
|
||||
uint16_t crypto_domain_index_mask;
|
||||
uint16_t reserved11;
|
||||
uint32_t fp_cntrl_reg;
|
||||
uint32_t reserved13;
|
||||
uint64_t reserved14[16];
|
||||
} __packed;
|
||||
|
||||
struct _fir_other_64 {
|
||||
uint16_t cpu_addr;
|
||||
uint16_t vector_sec_size;
|
||||
uint8_t crypto_index_reg;
|
||||
uint8_t virt_cpu_info;
|
||||
uint16_t crypto_index_mask;
|
||||
uint32_t reserved1[2];
|
||||
uint64_t fprs[16];
|
||||
uint64_t gprs[16];
|
||||
uint64_t psw[2];
|
||||
uint32_t reserved2[2];
|
||||
uint32_t prefix;
|
||||
uint32_t fp_cntrl_reg;
|
||||
uint32_t reserved3;
|
||||
uint32_t tod;
|
||||
uint64_t cpu_timer;
|
||||
uint64_t clock_cmp;
|
||||
uint32_t reserved4[2];
|
||||
uint32_t acrs[16];
|
||||
uint64_t crs[16];
|
||||
uint64_t mc_interrupt_code;
|
||||
uint32_t reserved5;
|
||||
uint32_t external_damage_code;
|
||||
uint64_t mc_failing_storage_addr;
|
||||
} __packed;
|
||||
|
||||
/* Members */
|
||||
struct _asibk_64_new asibkRecordNew;
|
||||
struct _fir_64 fir64Record;
|
||||
struct _fir_other_64 *fir64OtherRecords;
|
||||
};
|
||||
|
||||
class VMDump64 : public VMDumpClassic
|
||||
{
|
||||
public:
|
||||
VMDump64(const char *filename);
|
||||
virtual ~VMDump64(void);
|
||||
RegisterContent64 getRegisterContent(void);
|
||||
|
||||
void printDebug(void);
|
||||
void printInfo(void);
|
||||
private:
|
||||
/* Types */
|
||||
struct _fir_64 {
|
||||
char id[8];
|
||||
uint64_t reserved1;
|
||||
uint64_t gprs[16];
|
||||
uint32_t prefix;
|
||||
char reserved2[5];
|
||||
uint64_t tod;
|
||||
char reserved3[8];
|
||||
uint64_t cpu_timer;
|
||||
char reserved4[7];
|
||||
uint8_t flag;
|
||||
uint8_t type;
|
||||
uint8_t complete;
|
||||
uint8_t fir_format; /* 0x82 for esame - 0x00 for esa */
|
||||
uint8_t cont_flags;
|
||||
uint8_t crypto_domain_index_reg;
|
||||
uint8_t virt_cpu_info;
|
||||
uint8_t arch_mode_id;
|
||||
uint64_t psw[2];
|
||||
uint64_t crs[16];
|
||||
uint64_t fprs[16];
|
||||
uint8_t reserved5;
|
||||
uint64_t clock_cmp;
|
||||
char reserved6[3];
|
||||
uint32_t tod_programmable_reg;
|
||||
uint32_t reserved_for_dvf[20];
|
||||
uint32_t acrs[16];
|
||||
uint32_t storage_size_2GB;
|
||||
uint32_t reserved7;
|
||||
uint32_t hcpsys_addr;
|
||||
uint32_t reserved8;
|
||||
uint64_t storage_size;
|
||||
uint32_t snap_area_map_blk;
|
||||
uint32_t reserved9;
|
||||
char loc_mem[256];
|
||||
uint16_t online_cpus;
|
||||
uint16_t cpu_addr;
|
||||
uint16_t section_size_vector;
|
||||
uint16_t reserved10;
|
||||
char asit_primary[8];
|
||||
char space_id_primary[33];
|
||||
char reserved12[3];
|
||||
uint16_t crypto_domain_index_mask;
|
||||
uint16_t reserved11;
|
||||
uint32_t fp_cntrl_reg;
|
||||
uint32_t reserved13;
|
||||
uint64_t reserved14[16];
|
||||
} __packed;
|
||||
|
||||
struct _fir_other_64 {
|
||||
uint16_t cpu_addr;
|
||||
uint16_t vector_sec_size;
|
||||
uint8_t crypto_index_reg;
|
||||
uint8_t virt_cpu_info;
|
||||
uint16_t crypto_index_mask;
|
||||
uint32_t reserved1[2];
|
||||
uint64_t fprs[16];
|
||||
uint64_t gprs[16];
|
||||
uint64_t psw[2];
|
||||
uint32_t reserved2[2];
|
||||
uint32_t prefix;
|
||||
uint32_t fp_cntrl_reg;
|
||||
uint32_t reserved3;
|
||||
uint32_t tod;
|
||||
uint64_t cpu_timer;
|
||||
uint64_t clock_cmp;
|
||||
uint32_t reserved4[2];
|
||||
uint32_t acrs[16];
|
||||
uint64_t crs[16];
|
||||
uint64_t mc_interrupt_code;
|
||||
uint32_t reserved5;
|
||||
uint32_t external_damage_code;
|
||||
uint64_t mc_failing_storage_addr;
|
||||
} __packed;
|
||||
|
||||
/* Members */
|
||||
struct _fir_64 fir64Record;
|
||||
struct _fir_other_64 *fir64OtherRecords;
|
||||
};
|
||||
|
||||
class VMDump32 : public VMDumpClassic
|
||||
{
|
||||
public:
|
||||
VMDump32(const char *filename);
|
||||
virtual ~VMDump32(void);
|
||||
RegisterContent32 getRegisterContent(void);
|
||||
void printDebug(void);
|
||||
void printInfo(void);
|
||||
private:
|
||||
/* Types */
|
||||
struct _fir_32 {
|
||||
uint32_t gprs[16];
|
||||
uint32_t crs[16];
|
||||
uint64_t fprs[4];
|
||||
uint64_t tod;
|
||||
uint64_t cpu_timer;
|
||||
uint64_t clock_cmp;
|
||||
uint8_t flag;
|
||||
uint8_t type;
|
||||
uint8_t complete;
|
||||
uint8_t fir_format;
|
||||
uint32_t storage_size_2GB;
|
||||
char loc_mem[256];
|
||||
uint32_t prefix;
|
||||
uint16_t online_cpus;
|
||||
uint8_t cont_flags;
|
||||
uint8_t crypto_domain_index_reg;
|
||||
uint8_t virt_cpu_info;
|
||||
uint8_t arch_mode_id;
|
||||
uint16_t crypto_domain_index_mask;
|
||||
uint32_t reserved1;
|
||||
uint32_t snap_area_map_blk;
|
||||
uint64_t reserved2;
|
||||
uint32_t hcpsys_addr;
|
||||
uint32_t reserved3[20];
|
||||
uint32_t psw[2];
|
||||
uint16_t cpu_addr;
|
||||
uint16_t section_size_vector;
|
||||
uint32_t acrs[16];
|
||||
char asit_primary[8];
|
||||
char space_id_primary[33];
|
||||
char reserved4[131];
|
||||
} __packed;
|
||||
|
||||
struct _fir_other_32 {
|
||||
uint16_t cpu_addr;
|
||||
uint16_t vector_sec_size;
|
||||
uint32_t prefix;
|
||||
uint8_t crypto_index_reg;
|
||||
uint8_t virt_cpu_info;
|
||||
uint16_t crypto_index_mask;
|
||||
uint32_t reserved1;
|
||||
uint64_t cpu_timer;
|
||||
uint64_t clock_cmp;
|
||||
uint64_t mc_interrupt_code;
|
||||
uint64_t reserved2;
|
||||
uint32_t mc_failing_storage_addr;
|
||||
uint32_t machine_dependent_region_code;
|
||||
uint32_t lixed_logout_area[4];
|
||||
char reserved3[16];
|
||||
uint32_t acrs[16];
|
||||
uint64_t fprs[4];
|
||||
uint32_t gprs[16];
|
||||
uint32_t crs[16];
|
||||
} __packed;
|
||||
|
||||
/* Members */
|
||||
struct _fir_32 fir32Record;
|
||||
struct _fir_other_32 *fir32OtherRecords;
|
||||
};
|
||||
|
||||
#endif /* VMDUMP_H */
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* vmdump - z/VM dump conversion library
|
||||
*
|
||||
* Dump convert function: Converts VMDUMP to LKCD dump
|
||||
*
|
||||
* Copyright IBM Corp. 2004, 2017
|
||||
*
|
||||
* s390-tools is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the MIT license. See LICENSE for details.
|
||||
*/
|
||||
|
||||
#include "lkcd_dump.h"
|
||||
#include "vm_dump.h"
|
||||
|
||||
int vmdump_convert(const char* inputFileName, const char* outputFileName,
|
||||
const char* progName)
|
||||
{
|
||||
/* Do the conversion */
|
||||
try {
|
||||
switch(VMDump::getDumpType(inputFileName)){
|
||||
case Dump::DT_VM64_BIG:
|
||||
{
|
||||
LKCDDump64* lkcddump;
|
||||
VMDump64Big* vmdump;
|
||||
|
||||
vmdump = new VMDump64Big(inputFileName);
|
||||
vmdump->printInfo();
|
||||
lkcddump = new LKCDDump64(vmdump,
|
||||
vmdump->getRegisterContent());
|
||||
lkcddump->writeDump(outputFileName);
|
||||
delete vmdump;
|
||||
delete lkcddump;
|
||||
break;
|
||||
}
|
||||
case Dump::DT_VM64:
|
||||
{
|
||||
LKCDDump64* lkcddump;
|
||||
VMDump64* vmdump;
|
||||
|
||||
vmdump = new VMDump64(inputFileName);
|
||||
vmdump->printInfo();
|
||||
lkcddump = new LKCDDump64(vmdump,
|
||||
vmdump->getRegisterContent());
|
||||
lkcddump->writeDump(outputFileName);
|
||||
delete vmdump;
|
||||
delete lkcddump;
|
||||
break;
|
||||
}
|
||||
case Dump::DT_VM32:
|
||||
{
|
||||
LKCDDump32* lkcddump;
|
||||
VMDump32* vmdump;
|
||||
|
||||
vmdump = new VMDump32(inputFileName);
|
||||
vmdump->printInfo();
|
||||
lkcddump = new LKCDDump32(vmdump,
|
||||
vmdump->getRegisterContent());
|
||||
lkcddump->writeDump(outputFileName);
|
||||
delete vmdump;
|
||||
delete lkcddump;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw DumpException("This is not a vmdump");
|
||||
}
|
||||
} catch (DumpException ex) {
|
||||
printf("%s: %s\n", progName, ex.what());
|
||||
fflush(stdout);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1419,7 +1419,6 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc)
|
||||
|
||||
volume_label_t *vlabel = NULL;
|
||||
char *trackdata = NULL;
|
||||
char vol1[] = {0xe5, 0xd6, 0xd3, 0xf1, 0x00}; /* "VOL1" in EBCDIC */
|
||||
|
||||
errorlog_clear(dasd->log);
|
||||
|
||||
@@ -1431,8 +1430,7 @@ int lzds_dasd_read_rawvtoc(struct dasd *dasd, struct raw_vtoc *rawvtoc)
|
||||
goto cleanup;
|
||||
}
|
||||
/* verify that we have a proper VOL1 label */
|
||||
if (strncmp(vlabel->volkey, vol1, 4) ||
|
||||
strncmp(vlabel->vollbl, vol1, 4)) {
|
||||
if (!is_vol1(vlabel->volkey) || !is_vol1(vlabel->vollbl)) {
|
||||
rc = EINVAL;
|
||||
errorlog_add_message(
|
||||
&dasd->log, NULL, rc,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
include ../common.mak
|
||||
|
||||
ALL_CFLAGS += -Wno-address-of-packed-member
|
||||
|
||||
all: mon_fsstatd mon_procd
|
||||
|
||||
mon_fsstatd: mon_fsstatd.o
|
||||
|
||||
@@ -248,7 +248,7 @@ static void count_users(void)
|
||||
proc_sum.users = 0;
|
||||
setutent();
|
||||
while ((temp = getutent())) {
|
||||
if ((temp->ut_type == USER_PROCESS) && (temp->ut_name))
|
||||
if (temp->ut_type == USER_PROCESS)
|
||||
proc_sum.users++;
|
||||
}
|
||||
endutent();
|
||||
@@ -859,8 +859,6 @@ static void read_tasks(void)
|
||||
}
|
||||
|
||||
while ((entry = readdir(proc_dir))) {
|
||||
if (!entry->d_name)
|
||||
break;
|
||||
if (!isdigit(entry->d_name[0]) || !atoi(entry->d_name))
|
||||
continue;
|
||||
memset(&task, 0, sizeof(struct task_t));
|
||||
|
||||
@@ -15,13 +15,13 @@ install: install-scripts
|
||||
install-scripts: $(SCRIPTS)
|
||||
@if [ ! -d $(DESTDIR)$(NETBOOT_SAMPLEDIR) ]; then \
|
||||
mkdir -p $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
chmod 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR); \
|
||||
fi; \
|
||||
for i in $^; do \
|
||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||
< $$i >$(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
chown $(OWNER):$(GROUP) $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
chmod 755 $(DESTDIR)$(NETBOOT_SAMPLEDIR)/$$i; \
|
||||
done
|
||||
|
||||
|
||||
@@ -9,16 +9,22 @@
|
||||
\fBpvattest [OPTION?] create [OPTIONS] \fP- create an attestation measurement request
|
||||
\fB
|
||||
.SH DESCRIPTION
|
||||
Prepare attestation measurement requests for an IBM Secure Execution guest. Only prepare attestation requests in a trusted environment, such as your workstation. The 'pvattest create' command creates a randomly generated key to protect the attestation request. This key is only valid for this specific request.In order to avoid compromising the attestation, do not publish the protection key and delete it after verification. Every 'create' command generates a new, random protection key.
|
||||
Prepare attestation measurement requests for an IBM Secure Execution guest.
|
||||
Only prepare attestation requests in a trusted environment, such as your workstation.
|
||||
The 'pvattest create' command creates a randomly generated key to protect the attestation request.
|
||||
This key is only valid for this specific request. In order to avoid compromising the attestation,
|
||||
do not publish the protection key and delete it after verification.
|
||||
Every 'create' command generates a new, random protection key.
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B
|
||||
\fB-h\fP, \fB--help\fP
|
||||
Show help options
|
||||
Prints usage information, then exits.
|
||||
.TP
|
||||
.B
|
||||
\fB-k\fP, \fB--host-key-document\fP=\fBFILE\fP
|
||||
Specify one or more host key documents.
|
||||
Specify one or more host key documents. At least one is required.
|
||||
Specify this option multiple times to create an attestation request control block that is usable on multiple hosts.
|
||||
.TP
|
||||
.B
|
||||
\fB-C\fP, \fB--cert\fP=\fBFILE\fP
|
||||
@@ -26,11 +32,14 @@ Specifies the certificate that is used to establish a chain of trust for the v
|
||||
.TP
|
||||
.B
|
||||
\fB--crl\fP=\fBFILE\fP
|
||||
Specify \fBFILE\fP to be a certificate revocation list (optional).
|
||||
Specifies the revocation list that is used to check whether a certificate of the chain of trust is
|
||||
revoked. Specify this option multiple times to use multiple CRLs (optional).
|
||||
.TP
|
||||
.B
|
||||
\fB--root-ca\fP=\fBFILE\fP
|
||||
Use \fBFILE\fP as the trusted root CA instead the root CAs that are installed on the system (optional).
|
||||
Specifies the root CA certificate for the verification. If omitted,
|
||||
the system wide root CAs installed on the system are used. Use
|
||||
this only if you trust the specified certificate. Optional.
|
||||
.TP
|
||||
.B
|
||||
\fB-o\fP, \fB--output\fP=\fBFILE\fP
|
||||
@@ -42,15 +51,16 @@ Save the protection key as GCM-AES256 key in \fBFILE\fP Do not publish this key,
|
||||
.TP
|
||||
.B
|
||||
\fB--no-verify\fP
|
||||
Disable the host-key-document verification. Does not require the host-key documents to be valid. For testing purposes, do not use for a production image. (Optional)
|
||||
Disable the host-key document verification. Does not require the host-key documents to be valid. Do
|
||||
not use for a production request unless you verified the host-key document before (optional).
|
||||
.TP
|
||||
.B
|
||||
\fB--offline\fP
|
||||
Don't download CRLs (optional).
|
||||
Specifies offline mode, in which no attempt is made to download CRLs. (optional).
|
||||
.TP
|
||||
.B
|
||||
\fB-V\fP, \fB--verbose\fP
|
||||
Provide more detailed output (optional)
|
||||
Provide more detailed output (optional).
|
||||
.SH EXAMPLE
|
||||
Create an attestation request with the protection key 'arp.key', write the request to 'arcb.bin', and verify the host-key document using the CA-signed key 'DigiCertCA.crt' and the intermediate key 'IbmSigningKey.crt'.
|
||||
.PP
|
||||
|
||||
@@ -9,7 +9,10 @@
|
||||
\fBpvattest [OPTION?] perform [OPTIONS] \fP- execute an attestation measurement request
|
||||
\fB
|
||||
.SH DESCRIPTION
|
||||
Run a measurement of this system using '/dev/uv'. Works only if this device is available and the attestation Ultravisor facility is present. The input must be an attestation request created with 'pvattest create'. Output will contain the original request, the attestation measurement result, the configuration UID, and if requested in the request Additional Data.
|
||||
Run a measurement of this system using '/dev/uv'. Works only if this device is
|
||||
available and the attestation Ultravisor facility is present.
|
||||
The input must be an attestation request created with 'pvattest create'.
|
||||
Output will contain the original request and the response from the Ultravisor.
|
||||
.RE
|
||||
.PP
|
||||
|
||||
|
||||
@@ -4,12 +4,11 @@ BIN_PROGRAM = pvattest
|
||||
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/$(BIN_PROGRAM)"
|
||||
|
||||
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||
ROOT_DIR = $(rootdir)
|
||||
PVATTESTDIR := $(ROOT_DIR)/pvattest
|
||||
INCLUDE_PATHS = "$(SRC_DIR)" "$(ROOT_DIR)/include"
|
||||
PVATTESTDIR := $(rootdir)/pvattest
|
||||
INCLUDE_PATHS = "$(SRC_DIR)" "$(rootdir)/include"
|
||||
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
|
||||
|
||||
LIBPV_DIR = $(ROOT_DIR)/libpv
|
||||
LIBPV_DIR = $(rootdir)/libpv
|
||||
LIBPV = $(LIBPV_DIR)/libpv.a
|
||||
|
||||
WARNINGS := -Wall -Wextra -Wshadow \
|
||||
@@ -73,7 +72,7 @@ endif
|
||||
endif
|
||||
endif
|
||||
|
||||
all: $(BUILD_TARGETS) .check-dep-$(BIN_PROGRAM)
|
||||
all: $(BUILD_TARGETS)
|
||||
|
||||
install: $(INSTALL_TARGETS)
|
||||
|
||||
@@ -97,7 +96,7 @@ $($(BIN_PROGRAM)_OBJS): .check-dep-$(BIN_PROGRAM)
|
||||
.detect-openssl.dep.c:
|
||||
echo "#include <openssl/evp.h>" > $@
|
||||
echo "#if OPENSSL_VERSION_NUMBER < 0x10101000L" >> $@
|
||||
echo " #error openssl version 1.1.0 is required" >> $@
|
||||
echo " #error openssl version 1.1.1 is required" >> $@
|
||||
echo "#endif" >> $@
|
||||
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||
@@ -112,8 +111,8 @@ $($(BIN_PROGRAM)_OBJS): .check-dep-$(BIN_PROGRAM)
|
||||
"HAVE_GLIB2=0")
|
||||
$(call check_dep, \
|
||||
"$(BIN_PROGRAM)", \
|
||||
"openssl/evp.h", \
|
||||
"openssl-devel / libssl-dev version >= 1.1.0", \
|
||||
$^, \
|
||||
"openssl-devel / libssl-dev version >= 1.1.1", \
|
||||
"HAVE_OPENSSL=0", \
|
||||
"-I.")
|
||||
$(call check_dep, \
|
||||
|
||||
@@ -171,9 +171,9 @@ int arcb_v1_add_key_slot(arcb_v1_t *arcb, EVP_PKEY *evp_host, GError **error)
|
||||
g_assert(g_bytes_get_size(phkh) == sizeof(key_slot->phkh));
|
||||
|
||||
key_slot = g_malloc0(sizeof(*key_slot));
|
||||
pv_gbytes_memcpy(key_slot->warpk, sizeof(key_slot->warpk), warpk);
|
||||
pv_gbytes_memcpy(key_slot->kst, sizeof(key_slot->warpk), tag);
|
||||
pv_gbytes_memcpy(key_slot->phkh, sizeof(key_slot->warpk), phkh);
|
||||
pv_gbytes_memcpy(key_slot->warpk, sizeof(key_slot->warpk), warpk, NULL);
|
||||
pv_gbytes_memcpy(key_slot->kst, sizeof(key_slot->warpk), tag, NULL);
|
||||
pv_gbytes_memcpy(key_slot->phkh, sizeof(key_slot->warpk), phkh, NULL);
|
||||
|
||||
arcb->host_key_slots = g_slist_prepend(arcb->host_key_slots, g_steal_pointer(&key_slot));
|
||||
return 0;
|
||||
@@ -246,7 +246,7 @@ GBytes *arcb_v1_serialize(const arcb_v1_t *arcb, GError **error)
|
||||
/* copy plain data to contiguous memory */
|
||||
hdr.arl = GUINT32_TO_BE((uint32_t)att_req_len);
|
||||
|
||||
pv_gbytes_memcpy(hdr.iv, ARCB_V1_IV_SIZE, arcb->iv);
|
||||
pv_gbytes_memcpy(hdr.iv, ARCB_V1_IV_SIZE, arcb->iv, NULL);
|
||||
hdr.nks = (uint8_t)nks;
|
||||
hdr.sea = GUINT32_TO_BE((uint32_t)sea);
|
||||
ecdh_cpk = pv_evp_pkey_to_ecdh_pub_key(arcb->evp_cust_pub_key, error);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "lib/zt_common.h"
|
||||
#include "libpv/crypto.h"
|
||||
#include "libpv/macros.h"
|
||||
|
||||
#include "types.h"
|
||||
|
||||
@@ -28,18 +29,17 @@
|
||||
#define ARCB_V1_IV_SIZE 12
|
||||
#define ARCB_V1_PHKH_SIZE 32
|
||||
|
||||
#define BIT(bit) ((uint64_t)1 << (63 - (bit)))
|
||||
/* Optional nonce in ARCB */
|
||||
#define ARCB_V1_PAF_NONCE BIT(1)
|
||||
#define ARCB_V1_PAF_NONCE PV_MSB(1)
|
||||
/* Public host key hash used to unseal SE header added to additional data to be measured */
|
||||
#define ARCB_V1_PAF_AAD_PHKH_HEADER BIT(2)
|
||||
#define ARCB_V1_PAF_AAD_PHKH_HEADER PV_MSB(2)
|
||||
/* Public host key hash used to unseal this attestation added to additional data to be measured */
|
||||
#define ARCB_V1_PAF_AAD_PHKH_ATTEST BIT(3)
|
||||
#define ARCB_V1_PAF_AAD_PHKH_ATTEST PV_MSB(3)
|
||||
/* Temporary backup-host-key use allowed */
|
||||
#define ARCB_V1_PAF_TMP_BACKUP_ALLOWED BIT(62)
|
||||
#define ARCB_V1_PAF_TMP_BACKUP_ALLOWED PV_MSB(62)
|
||||
|
||||
/* Global not-host-specific key allowed */
|
||||
#define ARCB_V1_PAF_GLOBAL_NHS_KEY_ALLOWED BIT(63)
|
||||
#define ARCB_V1_PAF_GLOBAL_NHS_KEY_ALLOWED PV_MSB(63)
|
||||
|
||||
#define ARCB_V1_PAF_ALL \
|
||||
(ARCB_V1_PAF_NONCE | ARCB_V1_PAF_AAD_PHKH_HEADER | ARCB_V1_PAF_AAD_PHKH_ATTEST | \
|
||||
|
||||
@@ -156,76 +156,75 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
|
||||
|
||||
/************************* SHARED OPTIONS *************************************/
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_host_key_document(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "host-key-document", .short_name = 'k', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = "Specify one or more host key documents.\n", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_host_key_document(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "host-key-document", .short_name = 'k', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = \
|
||||
"FILE specifies a host-key document. At least one is required.\n" __indent \
|
||||
"Specify this option multiple times to enable the request for\n" __indent \
|
||||
"more than one host.\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_certs(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "cert", .short_name = 'C', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = \
|
||||
"Specifies the certificate that is used to establish a chain\n" __indent \
|
||||
"of trust for the verification of the host-key documents. Specify\n" __indent \
|
||||
"this option twice to specify the IBM Z signing key and the\n" __indent \
|
||||
"intermediate CA certificate (signed by the root CA). Required.\n" __indent \
|
||||
"Ignored when --no-verify is specified.\n", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_certs(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "cert", .short_name = 'C', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = "FILE contains a certificate that is used to\n" __indent \
|
||||
"establish a chain of trust for the verification\n" __indent \
|
||||
"of the host-key documents. The IBM Z signing\n" __indent \
|
||||
"key and intermediate CA certificate (signed\n" __indent \
|
||||
"by the root CA) are required.\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_crls(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "crl", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = "Specify FILE to be a certificate revocation list\n" __indent \
|
||||
"(optional).", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_crls(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "crl", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = "FILE contains a certificate revocation list (optional).\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_root_ca(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = "Use FILE as the trusted root CA instead the\n" __indent \
|
||||
"root CAs that are installed on the system (optional).", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_root_ca(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "root-ca", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME_ARRAY, .arg_data = __arg_data, \
|
||||
.description = "Use FILE as the trusted root CA instead the\n" __indent \
|
||||
"root CAs that are installed on the system (optional).\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_guest_hdr(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "hdr", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||
.description = \
|
||||
"Specify the header of the guest image. Exactly one is required.\n", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_guest_hdr(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "hdr", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||
.description = "FILE specifies the header of the guest image.\n" __indent \
|
||||
"Exactly one is required.\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_input(__arg_data, __additional_text, __indent) \
|
||||
{ \
|
||||
.long_name = "input", .short_name = 'i', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||
.description = "FILE specifies the " __additional_text "\n" __indent \
|
||||
" as input.\n", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_input(__arg_data, __additional_text, __indent) \
|
||||
{ \
|
||||
.long_name = "input", .short_name = 'i', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||
.description = "FILE specifies the " __additional_text " as input.\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
#define _entry_output(__arg_data, __additional_text, __indent) \
|
||||
{ \
|
||||
.long_name = "output", .short_name = 'o', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||
.description = "FILE specifies the output for the\n" __indent __additional_text \
|
||||
".\n", \
|
||||
.arg_description = "FILE", \
|
||||
#define _entry_output(__arg_data, __additional_text, __indent) \
|
||||
{ \
|
||||
.long_name = "output", .short_name = 'o', .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_FILENAME, .arg_data = __arg_data, \
|
||||
.description = "FILE specifies the output for the " __additional_text "\n", \
|
||||
.arg_description = "FILE", \
|
||||
}
|
||||
|
||||
/* NOTE REQUIRED */
|
||||
@@ -254,7 +253,7 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
|
||||
{ \
|
||||
.long_name = "x-phkh-img", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||
.description = "add the public host key hash of the\n" __indent \
|
||||
.description = "Add the public host key hash of the\n" __indent \
|
||||
"image header used to decrypt\n" __indent \
|
||||
"the secure guest to the measurement. (optional)\n" \
|
||||
}
|
||||
@@ -263,34 +262,31 @@ static gboolean hex_str_toull(const char *nptr, uint64_t *dst, GError **error)
|
||||
{ \
|
||||
.long_name = "x-phkh-att", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||
.description = "add the public host key hash of the\n" __indent \
|
||||
.description = "Add the public host key hash of the\n" __indent \
|
||||
"attestation header used to decrypt\n" __indent \
|
||||
"the attestation request to the measurement. (optional)\n" \
|
||||
}
|
||||
|
||||
#define _entry_no_verify(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "no-verify", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||
.description = \
|
||||
"Disable the host-key-document verification.\n" __indent \
|
||||
"Does not require the host-key documents to be valid.\n" __indent \
|
||||
"For testing purposes, do not use for a production image.\n" __indent \
|
||||
"(optional)\n", \
|
||||
#define _entry_no_verify(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "no-verify", .short_name = 0, .flags = G_OPTION_FLAG_NONE, \
|
||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||
.description = "Disable the host-key document verification.\n" __indent \
|
||||
"(optional)\n", \
|
||||
}
|
||||
|
||||
#define _entry_offline_maps_to_online(__arg_data, __indent) \
|
||||
{ \
|
||||
.long_name = "offline", .short_name = 0, .flags = G_OPTION_FLAG_REVERSE, \
|
||||
.arg = G_OPTION_ARG_NONE, .arg_data = __arg_data, \
|
||||
.description = "Don't download CRLs (optional).\n", \
|
||||
.description = "Don't download CRLs. (optional)\n", \
|
||||
}
|
||||
|
||||
#define _entry_verbose(__indent) \
|
||||
{ \
|
||||
.long_name = "verbose", .short_name = 'V', .flags = G_OPTION_FLAG_NO_ARG, \
|
||||
.arg = G_OPTION_ARG_CALLBACK, .arg_data = &increase_log_lvl, \
|
||||
.description = "Provide more detailed output (optional)\n", \
|
||||
.description = "Provide more detailed output. (optional)\n", \
|
||||
.arg_description = NULL, \
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ void att_add_uid(att_meas_ctx_t *meas_ctx, GBytes *config_uid)
|
||||
pv_wrapped_g_assert(config_uid);
|
||||
|
||||
g_assert(g_bytes_get_size(config_uid) == ATT_CONFIG_UID_SIZE);
|
||||
pv_gbytes_memcpy(meas_ctx->config_uid, ATT_CONFIG_UID_SIZE, config_uid);
|
||||
pv_gbytes_memcpy(meas_ctx->config_uid, ATT_CONFIG_UID_SIZE, config_uid, NULL);
|
||||
}
|
||||
|
||||
gboolean att_verify_measurement(const GBytes *calculated_measurement,
|
||||
|
||||
@@ -11,10 +11,10 @@
|
||||
/* Must be included before any other header */
|
||||
#include "config.h"
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "libpv/glib-helper.h"
|
||||
#include <glib/gi18n.h>
|
||||
#include "libpv/macros.h"
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ exchange_format_ctx_t *exchange_ctx_from_file(const char *filename, GError **err
|
||||
}
|
||||
ctx->req_meas_size = GUINT32_FROM_BE(hdr_v1->measurement.size);
|
||||
ctx->req_add_size = GUINT32_FROM_BE(hdr_v1->additional_data.size);
|
||||
ctx->version = GUINT32_TO_BE(hdr->version);
|
||||
ctx->version = GUINT32_FROM_BE(hdr->version);
|
||||
|
||||
return g_steal_pointer(&ctx);
|
||||
}
|
||||
@@ -455,8 +455,8 @@ static void print_entry(const char *name, GBytes *data, const gboolean print_dat
|
||||
fprintf(stream, _("%s (%#lx bytes)"), name, g_bytes_get_size(data));
|
||||
if (print_data) {
|
||||
fprintf(stream, ":\n");
|
||||
printf_hexdump(g_bytes_get_data(data, NULL), g_bytes_get_size(data), 16, " ",
|
||||
stream);
|
||||
pvattest_hexdump(g_bytes_get_data(data, NULL), g_bytes_get_size(data), 16, " ",
|
||||
stream);
|
||||
}
|
||||
fprintf(stream, "\n");
|
||||
}
|
||||
|
||||
@@ -131,26 +131,35 @@ void pvattest_log_plain_logger(const char *log_domain G_GNUC_UNUSED, GLogLevelFl
|
||||
_log_logger(level, message, log_level, FALSE, "");
|
||||
}
|
||||
|
||||
void hexdump(const void *data, size_t size, size_t len, const char *prefix, GLogLevelFlags log_lvl)
|
||||
void pvattest_log_bytes(const void *data, size_t size, size_t width, const char *prefix,
|
||||
gboolean beautify, GLogLevelFlags log_lvl)
|
||||
{
|
||||
const uint8_t *data_b = data;
|
||||
|
||||
pv_wrapped_g_assert(data);
|
||||
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "%s0x0000 ", prefix);
|
||||
if (beautify)
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "%s0x0000 ", prefix);
|
||||
else
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "%s", prefix);
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "%02x", data_b[i]);
|
||||
if (i % 2 == 1)
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, " ");
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "%02x", data_b[i]);
|
||||
if (i % 2 == 1 && beautify)
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, " ");
|
||||
if (i == size - 1)
|
||||
break;
|
||||
if (i % len == len - 1)
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "\n%s0x%04lx ", prefix, i + 1);
|
||||
if (i % width == width - 1) {
|
||||
if (beautify)
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "\n%s0x%04lx ", prefix,
|
||||
i + 1);
|
||||
else
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "\n%s", prefix);
|
||||
}
|
||||
}
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, log_lvl, "\n");
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, log_lvl, "\n");
|
||||
}
|
||||
|
||||
void printf_hexdump(const void *data, size_t size, size_t len, const char *prefix, FILE *stream)
|
||||
void pvattest_hexdump(const void *data, size_t size, size_t width, const char *prefix, FILE *stream)
|
||||
{
|
||||
const uint8_t *data_b = data;
|
||||
|
||||
@@ -164,7 +173,7 @@ void printf_hexdump(const void *data, size_t size, size_t len, const char *prefi
|
||||
fprintf(stream, " ");
|
||||
if (i == size - 1)
|
||||
break;
|
||||
if (i % len == len - 1)
|
||||
if (i % width == width - 1)
|
||||
fprintf(stream, "\n%s0x%04lx ", prefix, i + 1);
|
||||
}
|
||||
fprintf(stream, "\n");
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
#define PVATTEST_LOG_LVL_DEFAULT PVATTEST_LOG_LVL_WARNING
|
||||
#define PVATTEST_LOG_LVL_MAX PVATTEST_LOG_LVL_DEBUG
|
||||
|
||||
#define PVATTEST_HEXDUMP_LOG_DOMAIN "pvattest_hdump"
|
||||
#define PVATTEST_BYTES_LOG_DOMAIN "pvattest_bytes"
|
||||
|
||||
void pvattest_log_increase_log_lvl(int *log_lvl);
|
||||
void pvattest_log_error(const char *format, ...);
|
||||
@@ -45,22 +45,22 @@ void pvattest_log_default_logger(const char *log_domain, GLogLevelFlags level, c
|
||||
*/
|
||||
void pvattest_log_plain_logger(const char *log_domain, GLogLevelFlags level, const char *message,
|
||||
void *user_data);
|
||||
#define dhexdump(v, s) \
|
||||
{ \
|
||||
pvattest_log_debug("%s (%li byte):", #v, s); \
|
||||
hexdump(v, s, 16L, " ", PVATTEST_LOG_LVL_DEBUG); \
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
||||
}
|
||||
#define gbhexdump(v) \
|
||||
#define dhexdump(v, s) \
|
||||
{ \
|
||||
pvattest_log_debug("%s:(%li byte):", #v, g_bytes_get_size(v)); \
|
||||
hexdump(g_bytes_get_data(v, NULL), g_bytes_get_size(v), 16L, " ", \
|
||||
PVATTEST_LOG_LVL_DEBUG); \
|
||||
g_log(PVATTEST_HEXDUMP_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
||||
pvattest_log_debug("%s (%li byte):", #v, s); \
|
||||
pvattest_log_bytes(v, s, 16L, " ", TRUE, PVATTEST_LOG_LVL_DEBUG); \
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
||||
}
|
||||
void hexdump(const void *data, size_t size, size_t len, const char *prefix, GLogLevelFlags log_lvl)
|
||||
PV_NONNULL(1);
|
||||
void printf_hexdump(const void *data, size_t size, size_t len, const char *prefix, FILE *stream)
|
||||
#define gbhexdump(v) \
|
||||
{ \
|
||||
pvattest_log_debug("%s:(%li byte):", #v, g_bytes_get_size(v)); \
|
||||
pvattest_log_bytes(g_bytes_get_data(v, NULL), g_bytes_get_size(v), 16L, " ", \
|
||||
TRUE, PVATTEST_LOG_LVL_DEBUG); \
|
||||
g_log(PVATTEST_BYTES_LOG_DOMAIN, PVATTEST_LOG_LVL_DEBUG, "\n"); \
|
||||
}
|
||||
void pvattest_log_bytes(const void *data, size_t size, size_t width, const char *prefix,
|
||||
gboolean beautify, GLogLevelFlags log_lvl) PV_NONNULL(1);
|
||||
void pvattest_hexdump(const void *data, size_t size, size_t width, const char *prefix, FILE *stream)
|
||||
PV_NONNULL(1, 5);
|
||||
void pvattest_log_GError(const char *info, GError *error) PV_NONNULL(1);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user