mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
405 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 | ||
|
|
a6f844d642 | ||
|
|
7f059bef13 | ||
|
|
4543d23dcf | ||
|
|
12f7dbbb3d | ||
|
|
f7c048d0eb | ||
|
|
80e54ac888 | ||
|
|
26148740df | ||
|
|
3ab06d77fb | ||
|
|
386392690d | ||
|
|
72df42ea4e | ||
|
|
6c0f429805 | ||
|
|
0466760ec1 | ||
|
|
8ddc31ea77 | ||
|
|
60f862b21c | ||
|
|
a66f6bb075 | ||
|
|
2b015183aa | ||
|
|
b4142a9966 | ||
|
|
c1d08e1380 | ||
|
|
85c9a49e63 | ||
|
|
4939531fe5 | ||
|
|
84abb27077 | ||
|
|
6826316350 | ||
|
|
b95a3c24b8 | ||
|
|
1f8496aa92 | ||
|
|
9aa59bfc4b | ||
|
|
fa111404cb | ||
|
|
5094354c39 | ||
|
|
844058bf4d | ||
|
|
dc49b4fcf0 | ||
|
|
647e8b5c37 | ||
|
|
1ae4fd18fe | ||
|
|
561883b1d8 | ||
|
|
953af2cc67 | ||
|
|
8f37000137 | ||
|
|
ba7bf2f6d3 | ||
|
|
4a8e52a019 | ||
|
|
446ace09ad | ||
|
|
012b842652 | ||
|
|
fed12a71cf | ||
|
|
5cd9ad13e5 | ||
|
|
f2d5b649e1 | ||
|
|
a957e3efd6 | ||
|
|
463189bf60 | ||
|
|
aa2e8e1caa | ||
|
|
7bc15537c8 | ||
|
|
901f082f1a | ||
|
|
cd2647ab78 | ||
|
|
48bcfc3366 | ||
|
|
57f3527799 | ||
|
|
f51dc05f7f | ||
|
|
3f9ead5731 | ||
|
|
b4e4cd6cd5 | ||
|
|
e97c85bb80 | ||
|
|
c6443cf977 | ||
|
|
6a439e6771 | ||
|
|
2134aff491 | ||
|
|
b41ac66f36 | ||
|
|
9aa368af54 | ||
|
|
2e6cf81c2a | ||
|
|
ae27066c15 | ||
|
|
47fcc71f96 | ||
|
|
5ac171d224 | ||
|
|
67dbf094b2 | ||
|
|
3669fd4d8a | ||
|
|
b01ef782f0 | ||
|
|
a177ae2439 | ||
|
|
13fef6dbe0 | ||
|
|
508253c666 | ||
|
|
773d01e674 | ||
|
|
2da206f5a6 | ||
|
|
bf71e3bb1f | ||
|
|
6f7982dae5 | ||
|
|
f64b4087dd | ||
|
|
a739584d6f | ||
|
|
cce5f510c3 | ||
|
|
2515832469 | ||
|
|
6c5c5f7e55 | ||
|
|
736c69379d | ||
|
|
130880159a | ||
|
|
d7b1cbad8b | ||
|
|
a58460b5c7 | ||
|
|
acdce2a7a9 | ||
|
|
0981df62c0 | ||
|
|
4e28f6749b | ||
|
|
5f08033bb8 | ||
|
|
8231ec5f38 | ||
|
|
9e62005818 | ||
|
|
a0dba6bfdb | ||
|
|
ebc3384b9f | ||
|
|
e9bf141264 | ||
|
|
d8b8114e6f | ||
|
|
c4e4b926b4 | ||
|
|
6324f62da7 | ||
|
|
3ade063ea2 | ||
|
|
92a3b30323 | ||
|
|
673ff375d9 | ||
|
|
4e2ebe0370 | ||
|
|
78b053326c | ||
|
|
ab06a5d88a | ||
|
|
a0a71efde0 | ||
|
|
b4b2202ff5 | ||
|
|
a26f61c4fe | ||
|
|
a28b396d9e | ||
|
|
0012eaf68e | ||
|
|
c22d282e67 | ||
|
|
071522f7d2 | ||
|
|
ae7217806b | ||
|
|
9f6150db34 | ||
|
|
b39bdfbf6e | ||
|
|
71fe58111c | ||
|
|
5e46632767 | ||
|
|
1bd64f5b0f | ||
|
|
d311506dc4 | ||
|
|
08e4520a4f | ||
|
|
46fd42af0c | ||
|
|
a8b0d7ace8 | ||
|
|
a29b3c8997 | ||
|
|
27dce3317a | ||
|
|
4382901daa | ||
|
|
bcbb6fcae6 | ||
|
|
b16a6d4fe1 | ||
|
|
0d15a07c0a | ||
|
|
5394cd363c | ||
|
|
0906293cd8 | ||
|
|
a9e13a2d69 | ||
|
|
ee2c6d4160 | ||
|
|
455ad953a9 | ||
|
|
02a0d12988 | ||
|
|
be47b51890 | ||
|
|
2677a4182d | ||
|
|
812df795c3 | ||
|
|
a0d6edf03c | ||
|
|
81920f7cfd | ||
|
|
40dd63e2ac | ||
|
|
a8579a0727 | ||
|
|
2ab27bdaf2 | ||
|
|
03fef264bd | ||
|
|
927a48e607 | ||
|
|
fbcb3f384a | ||
|
|
c7fe21b019 | ||
|
|
50a4740443 | ||
|
|
164d4817ec | ||
|
|
abec41f514 | ||
|
|
fcb503ea3c | ||
|
|
2eea614bbf | ||
|
|
3a13cb43f2 | ||
|
|
e8fca95592 | ||
|
|
b5604850ab | ||
|
|
18efac6306 | ||
|
|
18f8db2225 | ||
|
|
f1a13749df | ||
|
|
b5da337d1e | ||
|
|
a67888f36a | ||
|
|
e1f174ae22 | ||
|
|
7503d88b3b | ||
|
|
43039943cd | ||
|
|
b2e02d202a | ||
|
|
1faa5d2957 | ||
|
|
d62e075450 | ||
|
|
983233730c | ||
|
|
ad024c06e1 | ||
|
|
e2843232d5 | ||
|
|
b79d17d233 | ||
|
|
11b401b599 | ||
|
|
69c5ee2e52 | ||
|
|
3ee625d74f | ||
|
|
832268ecb0 | ||
|
|
5fb6434548 | ||
|
|
5894e3f700 | ||
|
|
e384f06014 | ||
|
|
1627c6a39f | ||
|
|
bb8f17a7da | ||
|
|
8b3d3dd4bd | ||
|
|
a5c04e5746 | ||
|
|
c5ae1a41da | ||
|
|
970c697983 | ||
|
|
cff4b0384f | ||
|
|
724f800dc5 | ||
|
|
4cdfe91ca9 | ||
|
|
a44db0f367 | ||
|
|
03ddcd6267 | ||
|
|
5c468a220e | ||
|
|
4ba65eaa74 | ||
|
|
58cae4fecd | ||
|
|
9b84de4b0a | ||
|
|
e679a88d88 | ||
|
|
6acf6ed76d | ||
|
|
e7abf256f6 | ||
|
|
0d407904dd | ||
|
|
2238eb820f | ||
|
|
81013f0c70 | ||
|
|
697c5dc405 | ||
|
|
e9deec4c62 | ||
|
|
d60b7770fd | ||
|
|
70925f9aff | ||
|
|
ef88fac874 | ||
|
|
4bd16ba8ea | ||
|
|
f6a7da141c | ||
|
|
1bbd34e500 | ||
|
|
c2f8988444 | ||
|
|
d2990db15f | ||
|
|
fd3d79335a | ||
|
|
07b3837e68 | ||
|
|
13a1227a02 | ||
|
|
52118a8d02 | ||
|
|
ee89b850fe | ||
|
|
5160f41079 | ||
|
|
5b0115fdb4 | ||
|
|
ae305b5158 |
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
|
||||||
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# Check https://editorconfig.org for details
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
end_of_line = lf
|
||||||
|
insert_final_newline = true
|
||||||
|
charset = utf-8
|
||||||
|
indent_style = tab
|
||||||
|
tab_width = 8
|
||||||
|
|
||||||
|
[*.sh]
|
||||||
|
shell_variant = bash # used by `shfmt`
|
||||||
|
|
||||||
|
[*.y{a,}ml]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 2
|
||||||
|
|
||||||
|
[*.py]
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -16,12 +16,14 @@ TAGS
|
|||||||
#
|
#
|
||||||
# Ignore generated executables and other generated files
|
# Ignore generated executables and other generated files
|
||||||
#
|
#
|
||||||
|
ap_tools/ap-check
|
||||||
cmsfs-fuse/cmsfs-fuse
|
cmsfs-fuse/cmsfs-fuse
|
||||||
cpacfstats/cpacfstats
|
cpacfstats/cpacfstats
|
||||||
cpacfstats/cpacfstatsd
|
cpacfstats/cpacfstatsd
|
||||||
cpumf/chcpumf
|
cpumf/chcpumf
|
||||||
cpumf/lscpumf
|
cpumf/lscpumf
|
||||||
cpumf/lshwc
|
cpumf/lshwc
|
||||||
|
cpumf/pai
|
||||||
cpuplugd/cpuplugd
|
cpuplugd/cpuplugd
|
||||||
dasdfmt/dasdfmt
|
dasdfmt/dasdfmt
|
||||||
dasdinfo/dasdinfo
|
dasdinfo/dasdinfo
|
||||||
@@ -45,6 +47,8 @@ iucvterm/src/iucvconn
|
|||||||
iucvterm/src/iucvtty
|
iucvterm/src/iucvtty
|
||||||
iucvterm/src/ttyrun
|
iucvterm/src/ttyrun
|
||||||
iucvterm/test/test_afiucv
|
iucvterm/test/test_afiucv
|
||||||
|
libap/check-dep-lock
|
||||||
|
libap/check-dep-json
|
||||||
libekmfweb/check-dep-libekmfweb
|
libekmfweb/check-dep-libekmfweb
|
||||||
libekmfweb/detect-openssl-version.dep
|
libekmfweb/detect-openssl-version.dep
|
||||||
libekmfweb/libekmfweb.so
|
libekmfweb/libekmfweb.so
|
||||||
@@ -64,6 +68,8 @@ lsstp/lsstp
|
|||||||
mon_tools/mon_fsstatd
|
mon_tools/mon_fsstatd
|
||||||
mon_tools/mon_procd
|
mon_tools/mon_procd
|
||||||
osasnmpd/osasnmpd
|
osasnmpd/osasnmpd
|
||||||
|
pvattest/src/pvattest
|
||||||
|
pvattest/tools/exchange_info
|
||||||
qetharp/qetharp
|
qetharp/qetharp
|
||||||
qethqoat/qethqoat
|
qethqoat/qethqoat
|
||||||
systemd/cpacfstatsd.service
|
systemd/cpacfstatsd.service
|
||||||
@@ -72,7 +78,6 @@ systemd/ttyrun-getty@.service
|
|||||||
tape390/tape390_crypt
|
tape390/tape390_crypt
|
||||||
tape390/tape390_display
|
tape390/tape390_display
|
||||||
tunedasd/src/tunedasd
|
tunedasd/src/tunedasd
|
||||||
vmconvert/vmconvert
|
|
||||||
vmcp/vmcp
|
vmcp/vmcp
|
||||||
vmur/vmur
|
vmur/vmur
|
||||||
zconf/chp/chchp
|
zconf/chp/chchp
|
||||||
@@ -89,6 +94,9 @@ zdev/src/chzdev_usage.c
|
|||||||
zdev/src/lszdev
|
zdev/src/lszdev
|
||||||
zdev/src/lszdev_usage.c
|
zdev/src/lszdev_usage.c
|
||||||
zdsfs/zdsfs
|
zdsfs/zdsfs
|
||||||
|
zdump/.check_dep_fuse
|
||||||
|
zdump/.check_dep_zgetdump
|
||||||
|
zdump/.detect_openssl.dep.c
|
||||||
zdump/zgetdump
|
zdump/zgetdump
|
||||||
zfcpdump/10-zfcpdump.install
|
zfcpdump/10-zfcpdump.install
|
||||||
zfcpdump/cpioinit
|
zfcpdump/cpioinit
|
||||||
@@ -101,6 +109,7 @@ ziomon/ziorep_traffic
|
|||||||
ziomon/ziorep_utilization
|
ziomon/ziorep_utilization
|
||||||
zipl/boot/*.bin
|
zipl/boot/*.bin
|
||||||
zipl/boot/*.exec
|
zipl/boot/*.exec
|
||||||
|
zipl/boot/.loaders
|
||||||
zipl/boot/data.h
|
zipl/boot/data.h
|
||||||
zipl/src/chreipl_helper.device-mapper
|
zipl/src/chreipl_helper.device-mapper
|
||||||
zdev/src/zdev_id
|
zdev/src/zdev_id
|
||||||
@@ -117,3 +126,4 @@ zkey/kmip/zkey-kmip.so
|
|||||||
zkey/zkey
|
zkey/zkey
|
||||||
zkey/zkey-cryptsetup
|
zkey/zkey-cryptsetup
|
||||||
zpcictl/zpcictl
|
zpcictl/zpcictl
|
||||||
|
**/.detect-openssl.dep.c
|
||||||
|
|||||||
13
AUTHORS.md
13
AUTHORS.md
@@ -5,10 +5,11 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Alexandra Winter
|
- Alexandra Winter
|
||||||
- Alexey Ishchuk
|
- Alexey Ishchuk
|
||||||
- Andreas Herrmann
|
- Andreas Herrmann
|
||||||
- Andre Wild
|
- André Wild
|
||||||
- Antoinette Kaschner
|
- Antoinette Kaschner
|
||||||
- Arnd Bergmann
|
- Arnd Bergmann
|
||||||
- Axel Wirbser
|
- Axel Wirbser
|
||||||
|
- Balint Reczey
|
||||||
- Benjamin Block
|
- Benjamin Block
|
||||||
- Brian C. Lane
|
- Brian C. Lane
|
||||||
- Carsten Otte
|
- Carsten Otte
|
||||||
@@ -19,6 +20,8 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Clemens von Mann
|
- Clemens von Mann
|
||||||
- Colin Walters
|
- Colin Walters
|
||||||
- Dan Horak
|
- Dan Horak
|
||||||
|
- Dan Horák
|
||||||
|
- Daniel S. Haischt
|
||||||
- Despina Papadopoulou
|
- Despina Papadopoulou
|
||||||
- Dimitri John Ledkov
|
- Dimitri John Ledkov
|
||||||
- Eberhard Pasch
|
- Eberhard Pasch
|
||||||
@@ -33,11 +36,13 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Fedor Loshakov
|
- Fedor Loshakov
|
||||||
- Felix Beck
|
- Felix Beck
|
||||||
- Frank Blaschka
|
- Frank Blaschka
|
||||||
|
- Frank Heimes
|
||||||
- Frank Munzert
|
- Frank Munzert
|
||||||
- Frank Pavlic
|
- Frank Pavlic
|
||||||
- Fritz Elfert
|
- Fritz Elfert
|
||||||
- Gerald Schaefer
|
- Gerald Schaefer
|
||||||
- Gerhard Tonn
|
- Gerhard Tonn
|
||||||
|
- Graham Inggs
|
||||||
- Guevenc Guelce
|
- Guevenc Guelce
|
||||||
- Hannes Reinecke
|
- Hannes Reinecke
|
||||||
- Hans-Joachim Picht
|
- Hans-Joachim Picht
|
||||||
@@ -52,7 +57,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Ingo Franzki
|
- Ingo Franzki
|
||||||
- Ingo Tuchscherer
|
- Ingo Tuchscherer
|
||||||
- Jan Glauber
|
- Jan Glauber
|
||||||
- Jan Hoeppner
|
- Jan Höppner
|
||||||
- Jan Willeke
|
- Jan Willeke
|
||||||
- Jason J. Herne
|
- Jason J. Herne
|
||||||
- Javier Martinez Canillas
|
- Javier Martinez Canillas
|
||||||
@@ -74,8 +79,10 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Martin Peschke
|
- Martin Peschke
|
||||||
- Martin Petermann
|
- Martin Petermann
|
||||||
- Martin Schwidefsky
|
- Martin Schwidefsky
|
||||||
|
- Matthew Rosato
|
||||||
- Maxim Shchetynin
|
- Maxim Shchetynin
|
||||||
- Melissa Howland
|
- Melissa Howland
|
||||||
|
- Mete Durlu
|
||||||
- Michael Ernst
|
- Michael Ernst
|
||||||
- Michael Holzheu
|
- Michael Holzheu
|
||||||
- Michael Mueller
|
- Michael Mueller
|
||||||
@@ -83,6 +90,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Mikhail Zaslonko
|
- Mikhail Zaslonko
|
||||||
- Nikita Dubrovskii
|
- Nikita Dubrovskii
|
||||||
- Niklas Schnelle
|
- Niklas Schnelle
|
||||||
|
- Nikolay Gueorguiev
|
||||||
- Peter Oberparleiter
|
- Peter Oberparleiter
|
||||||
- Peter Tiedemann
|
- Peter Tiedemann
|
||||||
- Philipp Kern
|
- Philipp Kern
|
||||||
@@ -103,6 +111,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Stefan Raspl
|
- Stefan Raspl
|
||||||
- Stefan Reimbold
|
- Stefan Reimbold
|
||||||
- Stefan Weinhuber
|
- Stefan Weinhuber
|
||||||
|
- Steffen Eiden
|
||||||
- Steffen Maier
|
- Steffen Maier
|
||||||
- Steffen Thoss
|
- Steffen Thoss
|
||||||
- Susanne Wintenberger
|
- Susanne Wintenberger
|
||||||
|
|||||||
168
CHANGELOG.md
168
CHANGELOG.md
@@ -1,5 +1,173 @@
|
|||||||
Release history for s390-tools (MIT version)
|
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
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- ap_tools: Introduce ap_tools and the ap-check tool
|
||||||
|
- cpumf/pai: Add Processor Activity Instrumentation tool
|
||||||
|
- libpv: New library for PV tools
|
||||||
|
- pvattest: Add new tool to create, perform, and verify attestation measurements
|
||||||
|
- zipl/zdump: Add Next Gen Dump (NGDump) support
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- Move man pages to System commands section (lscpumf, lshwc, pai, dbginfo.sh, zfcpdbf, zipl-switch-to-blscfg)
|
||||||
|
- README.md: Add 70-chreipl-fcp-mpath.rules to the list of udev rule descriptions
|
||||||
|
- Remove SysV related daemon scripts (cpacfstatsd, cpuplugd, mon_statd)
|
||||||
|
- genprotimg: Move man page to section 1 for user commands
|
||||||
|
- hyptop: increase initial update interval
|
||||||
|
- libseckey: Adapt keymgmt_match() implementation to OpenSSL
|
||||||
|
- libutil: Add util_exit_code
|
||||||
|
- libutil: Introduce util_udev
|
||||||
|
- zdev: Introduce the ap device type
|
||||||
|
- zipl-editenv: Add zIPL multienvironment support
|
||||||
|
- zipl: Implement sorting BLS entries by versions
|
||||||
|
- zkey: Add initramfs hook
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cmsfs-fuse: Fix enabling of hard_remove option
|
||||||
|
- s390-tools: Fix typos that were detected by lintian as 'typo-in-manual-page'
|
||||||
|
- zkey-kmip: Fix possible use after free
|
||||||
|
- zkey: Fix EP11 host library version checking
|
||||||
|
- zkey_kmip: Setup ext-lib once the APQNs have been configured
|
||||||
|
|
||||||
|
* __v2.21.0 (2022-04-20)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.17
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- libcpumf: Create library libcpumf for CPU Measurement functions
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- chreipl-fcp-mpath: bundle a pre-cooked version of the manpage for build
|
||||||
|
environments without access to `pandoc`
|
||||||
|
- dbginfo.sh: Add multipath info to map paths to FC addressing and prio group
|
||||||
|
- dbginfo.sh: Collect config files of systemd-modules-load.service
|
||||||
|
- dbginfo.sh: Sort list of environment variables for readability
|
||||||
|
- dbginfo.sh: Replace "which" by builtin command "type"
|
||||||
|
- dbginfo.sh: Rework script formatting (indents, order)
|
||||||
|
- dbginfo.sh: Update sysfs collection (excludes, messages)
|
||||||
|
- genprotimg: Add Protected Virtualization (PV) dump support
|
||||||
|
- genprotimg: Remove DigiCert root CA pinning
|
||||||
|
- lszcrypt: Add CEX8S support
|
||||||
|
- zcryptctl: Add control domain handling
|
||||||
|
- zcryptstats: Add CEX8 support
|
||||||
|
- zipl: Allow optional entries that are left out when files are missing
|
||||||
|
- zipl: make IPL sections defined with BLS to inherit a target field
|
||||||
|
- zpcictl: Add option to trigger firmware reset
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cpictl: Handle excessive kernel version numbers
|
||||||
|
- dbginfo.sh: Collect all places where modprobe.d config files could exist
|
||||||
|
- fdasd: Fix endless menu loop on EOF
|
||||||
|
- zdump/dfi: Fix segfault due to double free
|
||||||
|
- zdump: Fix /dev/mem reading
|
||||||
|
- zpcictl: Fix race of SCLP reset and Linux recovery
|
||||||
|
|
||||||
|
* __v2.20.0 (2022-02-04)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.16
|
||||||
|
|
||||||
|
Add new tools / libraries:
|
||||||
|
- Add EditorConfig configuration
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- s390-tools switches to Fuse 3 as Fuse 2 is deprecated.
|
||||||
|
Affected tools: cmsfs, hmcdrvfs, hsavmcore, zdsfs, zdump
|
||||||
|
- chreipl-fcp-mpath: don't compress the manpage before installing it
|
||||||
|
- cpictl: Report extended version information
|
||||||
|
- genprotimg: Add extended kernel command line support
|
||||||
|
- zdev: modify the lsblk output parser in lszdev
|
||||||
|
- zipl: Add support for longer kernel command lines (now supports up to 64k length)
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cpictl: Suppress messages for unwritable sysfs files
|
||||||
|
- dbginfo.sh: Fix missing syslog for step create_package
|
||||||
|
- lshwc: Fix CPU list parameter setup for device driver
|
||||||
|
- zdev: Check for errors when removing a devtype setting
|
||||||
|
- zdev: Fix path resolution for multi-mount point file systems
|
||||||
|
|
||||||
* __v2.19.0 (2021-11-10)__
|
* __v2.19.0 (2021-11-10)__
|
||||||
|
|
||||||
For Linux kernel version: 5.15
|
For Linux kernel version: 5.15
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ Coding guidelines for s390-tools
|
|||||||
For s390-tools the preferred language is C. We provide libraries, e.g.
|
For s390-tools the preferred language is C. We provide libraries, e.g.
|
||||||
[`libutil`](libutil) that should be used by all tools if possible.
|
[`libutil`](libutil) that should be used by all tools if possible.
|
||||||
|
|
||||||
The coding style is based on the Linux [kernel guidelines]. Therefore, use
|
The coding style is based on the Linux [kernel guidelines]. Therefore, use the
|
||||||
the [checkpatch] tool for verification before you submit a patch.
|
[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
|
[kernel guidelines]: https://www.kernel.org/doc/html/latest/process/coding-style.html
|
||||||
[checkpatch]: https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl
|
[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,
|
might not follow all recommendations. Note that when changing existing code,
|
||||||
consistency could have priority over applying rules.
|
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
|
Standard abbreviations
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
|
|||||||
10
Makefile
10
Makefile
@@ -9,14 +9,14 @@ include common.mak
|
|||||||
# TOOLS: Tools that can have a dependency to base libraries or libraries
|
# TOOLS: Tools that can have a dependency to base libraries or libraries
|
||||||
#
|
#
|
||||||
BASELIB_DIRS = libutil libseckey
|
BASELIB_DIRS = libutil libseckey
|
||||||
LIB_DIRS = libvtoc libzds libdasd libvmdump libccw libvmcp libekmfweb \
|
LIB_DIRS = libvtoc libzds libdasd libccw libvmcp libekmfweb \
|
||||||
libkmipclient
|
libkmipclient libcpumf libap libpv
|
||||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||||
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
ziomon iucvterm hyptop cmsfs-fuse qethqoat zfcpdump zdsfs cpumf \
|
||||||
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||||
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath
|
genprotimg lsstp hsci hsavmcore chreipl-fcp-mpath ap_tools pvattest
|
||||||
|
|
||||||
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)
|
SUB_DIRS = $(BASELIB_DIRS) $(LIB_DIRS) $(TOOL_DIRS)
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ endif
|
|||||||
|
|
||||||
#
|
#
|
||||||
# We have to build the base libraries before the other libraries are built,
|
# We have to build the base libraries before the other libraries are built,
|
||||||
# and then build the other libraries before the tools are built. Otherwise the
|
# and then build the other libraries before the tools are built. Otherwise the
|
||||||
# other libraries and tools would trigger parallel "make -C" builds for the
|
# other libraries and tools would trigger parallel "make -C" builds for the
|
||||||
# base libraries and the other libraries in case of "make -j".
|
# base libraries and the other libraries in case of "make -j".
|
||||||
#
|
#
|
||||||
|
|||||||
95
README.md
95
README.md
@@ -33,6 +33,9 @@ Package contents
|
|||||||
* genprotimg:
|
* genprotimg:
|
||||||
Create a protected virtualization image.
|
Create a protected virtualization image.
|
||||||
|
|
||||||
|
* pvattest:
|
||||||
|
Create, perform, and verify protected virtualization attestation measurements.
|
||||||
|
|
||||||
* udev rules:
|
* udev rules:
|
||||||
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
|
- 59-dasd.rules: rules for unique DASD device nodes created in /dev/disk/.
|
||||||
- 57-osasnmpd.rules: udev rules for osasnmpd.
|
- 57-osasnmpd.rules: udev rules for osasnmpd.
|
||||||
@@ -40,6 +43,9 @@ Package contents
|
|||||||
- 40-z90crypt.rules: udev rules for z90crypt driver
|
- 40-z90crypt.rules: udev rules for z90crypt driver
|
||||||
- 90-cpi.rules: udev rule to update Control-Program-Information when KVM is
|
- 90-cpi.rules: udev rule to update Control-Program-Information when KVM is
|
||||||
used.
|
used.
|
||||||
|
- 70-chreipl-fcp-mpath.rules: udev rules to monitor multipath events for
|
||||||
|
re-IPL path failover and to adjust the re-IPL
|
||||||
|
device in case needed.
|
||||||
|
|
||||||
* systemd units:
|
* systemd units:
|
||||||
- cpi.service: Unit to apply CPI settings
|
- cpi.service: Unit to apply CPI settings
|
||||||
@@ -50,10 +56,11 @@ Package contents
|
|||||||
- ttyrun-getty@.service: Instance unit to manage ttyrun
|
- ttyrun-getty@.service: Instance unit to manage ttyrun
|
||||||
|
|
||||||
* zipl:
|
* zipl:
|
||||||
Make DASDs or tapes bootable for system IPL or system dump.
|
Make DASDs, SCSIs, NVMes or tapes bootable for system IPL or system dump.
|
||||||
|
|
||||||
* zgetdump:
|
* zgetdump:
|
||||||
Retrieve system dumps from either tapes or DASDs.
|
Retrieve system dumps from either tapes, DASDs, SCSIs or NVMes.
|
||||||
|
Decrypt Protected Virtualization (PV) dumps from IBM Secure Execution guests.
|
||||||
|
|
||||||
* qetharp:
|
* qetharp:
|
||||||
Read and flush the ARP cache on OSA Express network cards.
|
Read and flush the ARP cache on OSA Express network cards.
|
||||||
@@ -91,11 +98,6 @@ Package contents
|
|||||||
* tunedasd:
|
* tunedasd:
|
||||||
Adjust tunable parameters on DASD devices.
|
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:
|
* vmcp:
|
||||||
Send commands from Linux as a z/VM guest to the z/VM control program (CP).
|
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
|
Call vmcp with the CP command as an argument. The response of z/VM is
|
||||||
@@ -274,6 +276,10 @@ Package contents
|
|||||||
Use multipath information to change the configured FCP re-IPL path on
|
Use multipath information to change the configured FCP re-IPL path on
|
||||||
detecting issues with the current path.
|
detecting issues with the current path.
|
||||||
|
|
||||||
|
* ap-check:
|
||||||
|
A utility called by mdevctl to assist in managing vfio_ap-passthrough
|
||||||
|
devices.
|
||||||
|
|
||||||
For more information refer to the following publications:
|
For more information refer to the following publications:
|
||||||
|
|
||||||
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
|
* "Device Drivers, Features, and Commands" chapter "Useful Linux commands"
|
||||||
@@ -292,30 +298,32 @@ build options:
|
|||||||
|
|
||||||
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
| __LIBRARY__ | __BUILD OPTION__ | __TOOLS__ |
|
||||||
|----------------|:------------------:|:-------------------------------------:|
|
|----------------|:------------------:|:-------------------------------------:|
|
||||||
| fuse | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
| fuse3 | `HAVE_FUSE` | cmsfs-fuse, zdsfs, hmcdrvfs, zgetdump,|
|
||||||
| | | hsavmcore |
|
| | | hsavmcore |
|
||||||
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
| zlib | `HAVE_ZLIB` | zgetdump, dump2tar |
|
||||||
| ncurses | `HAVE_NCURSES` | hyptop |
|
| ncurses | `HAVE_NCURSES` | hyptop |
|
||||||
| pfm | `HAVE_PFM` | cpacfstats |
|
|
||||||
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
| net-snmp | `HAVE_SNMP` | osasnmpd |
|
||||||
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
| glibc-static | `HAVE_LIBC_STATIC` | zfcpdump |
|
||||||
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
| openssl | `HAVE_OPENSSL` | genprotimg, zkey, libekmfweb, |
|
||||||
| | | libkmipclient |
|
| | | libkmipclient, pvattest, zgetdump |
|
||||||
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||||
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
| json-c | `HAVE_JSONC` | zkey-cryptsetup, libekmfweb, |
|
||||||
| | | libkmipclient |
|
| | | libkmipclient |
|
||||||
| glib2 | `HAVE_GLIB2` | genprotimg |
|
| glib2 | `HAVE_GLIB2` | genprotimg, pvattest, zgetdump |
|
||||||
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient |
|
| libcurl | `HAVE_LIBCURL` | genprotimg, libekmfweb, libkmipclient,|
|
||||||
|
| | | pvattest |
|
||||||
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
| libxml2 | `HAVE_LIBXML2` | libkmipclient |
|
||||||
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
| systemd | `HAVE_SYSTEMD` | hsavmcore |
|
||||||
|
| libudev | `HAVE_LIBUDEV` | cpacfstatsd |
|
||||||
|
|
||||||
This table lists additional build or install options:
|
This table lists additional build or install options:
|
||||||
|
|
||||||
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
| __COMPONENT__ | __OPTION__ | __TOOLS__ |
|
||||||
|------------------|:----------------------------:|:-----------------------:|
|
|------------------|:----------------------------:|:------------------------:|
|
||||||
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath |
|
| dracut | `HAVE_DRACUT` | zdev, chreipl-fcp-mpath, |
|
||||||
| initramfs-tools | `HAVE_INITRAMFS` | zdev |
|
| | | zipl |
|
||||||
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
|
| initramfs-tools | `HAVE_INITRAMFS` | zdev, zipl |
|
||||||
|
| | `ZDEV_ALWAYS_UPDATE_INITRD` | zdev |
|
||||||
|
|
||||||
The s390-tools build process uses "pkg-config" if available and hard-coded
|
The s390-tools build process uses "pkg-config" if available and hard-coded
|
||||||
compiler and linker options otherwise.
|
compiler and linker options otherwise.
|
||||||
@@ -337,6 +345,16 @@ the different tools are provided:
|
|||||||
|
|
||||||
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
|
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
|
||||||
|
|
||||||
|
* pvattest:
|
||||||
|
For building pvattest you need OpenSSL version 1.1.1 or newer
|
||||||
|
installed (openssl-devel.rpm). Also required is glib2.56 or newer
|
||||||
|
(glib2-devel.rpm) and libcurl.
|
||||||
|
Tip: you may skip the pvattest build by adding
|
||||||
|
`HAVE_OPENSSL=0`, `HAVE_LIBCURL=0`, or `HAVE_GLIB2=0`.
|
||||||
|
|
||||||
|
The runtime requirements are: openssl-libs (>= 1.1.1) and
|
||||||
|
glib2.56 or newer.
|
||||||
|
|
||||||
* osasnmpd:
|
* osasnmpd:
|
||||||
You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)
|
You need at least the NET-SNMP 5.1.x package (net-snmp-devel.rpm)
|
||||||
installed, before building the osasnmpd subagent.
|
installed, before building the osasnmpd subagent.
|
||||||
@@ -353,14 +371,21 @@ the different tools are provided:
|
|||||||
- Packages: blktrace, multipath-tools, sg3-utils
|
- Packages: blktrace, multipath-tools, sg3-utils
|
||||||
- Tools: rsync, tar, lsscsi
|
- 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:
|
* cmsfs-fuse/zdsfs/hmcdrvfs/zgetdump:
|
||||||
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
The tools cmsfs-fuse, zdsfs, hmcdrvfs, and zgetdump depend on FUSE.
|
||||||
FUSE is provided by installing the fuse and libfuse packages and by a
|
FUSE is provided by installing the fuse3 and libfuse3 packages and by a
|
||||||
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
|
kernel compiled with `CONFIG_FUSE_FS`. For compiling the s390-tools package
|
||||||
the fuse-devel package is required.
|
the fuse3-devel package is required.
|
||||||
The cmsfs-fuse tool requires FUSE version 2.8.1 or newer for full
|
The cmsfs-fuse tool requires FUSE version 3.0 or newer for full
|
||||||
functionality.
|
functionality.
|
||||||
For further information about FUSE see: http://fuse.sourceforge.net
|
For further information about FUSE see: https://github.com/libfuse/libfuse
|
||||||
|
|
||||||
* hyptop:
|
* hyptop:
|
||||||
The ncurses-devel package is required to build hyptop.
|
The ncurses-devel package is required to build hyptop.
|
||||||
@@ -380,14 +405,13 @@ the different tools are provided:
|
|||||||
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
As of s390-tools-1.13.0, the minimum required kernel level is 2.6.38.
|
||||||
|
|
||||||
* cpacfstats:
|
* cpacfstats:
|
||||||
For building the cpacfstats tools you need libpfm version 4 or
|
For building the cpacfstats tools you need libudev installed
|
||||||
newer installed (libpfm-devel.rpm). Tip: you may skip the cpacfstats
|
(systemd-devel.rpm). Tip: you may skip the cpacfstats build by
|
||||||
build by adding `HAVE_PFN=0` to the make invocation. To run the
|
adding `HAVE_LIBUDEV=0` to the make invocation. To run the
|
||||||
cpacfstats daemon the kernel needs to have performance
|
cpacfstats daemon the kernel needs to have performance events
|
||||||
events enabled (check for `CONFIG_PERF_EVENTS=y`) and you need libpfm
|
enabled (check for `CONFIG_PERF_EVENTS=y`). A new group 'cpacfstats'
|
||||||
version 4 or newer installed. A new group 'cpacfstats' needs to be
|
needs to be created and all users intending to use the tool should
|
||||||
created and all users intending to use the tool should be added to
|
be added to this group.
|
||||||
this group.
|
|
||||||
|
|
||||||
* zdev:
|
* zdev:
|
||||||
Depending on the boot loader and initial RAM-disk mechanism used by a
|
Depending on the boot loader and initial RAM-disk mechanism used by a
|
||||||
@@ -456,7 +480,7 @@ the different tools are provided:
|
|||||||
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
`HAVE_JSONC=0`, or `HAVE_LIBCURL=0` to the make invocation.
|
||||||
|
|
||||||
* hsavmcore:
|
* hsavmcore:
|
||||||
For building the hsavmcore tool you need fuse version 2.6 and optionally
|
For building the hsavmcore tool you need fuse version 3.0 and optionally
|
||||||
systemd which is enabled by default, to disable systemd support,
|
systemd which is enabled by default, to disable systemd support,
|
||||||
add `HAVE_SYSTEMD=0` to the make invocation.
|
add `HAVE_SYSTEMD=0` to the make invocation.
|
||||||
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
|
Tip: you may skip the hsavmcore build by adding `HAVE_FUSE=0`
|
||||||
@@ -478,5 +502,12 @@ the different tools are provided:
|
|||||||
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
Summarized: chreipl-fcp-mpath requires GNU Bash, GNU Core Utilities,
|
||||||
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
util-linux, udev, and multipath-tools. When using `HAVE_DRACUT=1` with the
|
||||||
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
make invocation, it also requires dracut. When using `ENABLE_DOC=1` with the
|
||||||
make invocation to build a man page and render the README.md as HTML, make
|
make invocation to build a fresh man page (instead of using the pre-cooked
|
||||||
further requires pandoc, GNU awk, and GNU Gzip for the build process.
|
version) and render the README.md as HTML, make further requires pandoc and
|
||||||
|
GNU awk for the build process.
|
||||||
|
|
||||||
|
* ap-check:
|
||||||
|
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.
|
||||||
|
|||||||
54
ap_tools/Makefile
Normal file
54
ap_tools/Makefile
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
include ../common.mak
|
||||||
|
|
||||||
|
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_JSONC},0)
|
||||||
|
all:
|
||||||
|
$(SKIP) HAVE_JSONC=0
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(SKIP) HAVE_JSONC=0
|
||||||
|
else
|
||||||
|
LDLIBS += -ljson-c
|
||||||
|
|
||||||
|
all: ap-check
|
||||||
|
|
||||||
|
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); \
|
||||||
|
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:
|
||||||
|
rm -f *.o *~ ap-check core
|
||||||
|
|
||||||
|
.PHONY: all install clean
|
||||||
919
ap_tools/ap-check.c
Normal file
919
ap_tools/ap-check.c
Normal file
@@ -0,0 +1,919 @@
|
|||||||
|
/*
|
||||||
|
* ap-check - Validate vfio-ap mediated device configuration changes
|
||||||
|
*
|
||||||
|
* This tool in intended to be driven via the callout API of the mdevctl
|
||||||
|
* utility (https://github.com/mdevctl/mdevctl/)
|
||||||
|
*
|
||||||
|
* 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 <dirent.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "lib/ap.h"
|
||||||
|
#include "lib/util_base.h"
|
||||||
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/util_opt.h"
|
||||||
|
#include "lib/util_path.h"
|
||||||
|
|
||||||
|
#include "ap-check.h"
|
||||||
|
|
||||||
|
static const struct mdevctl_action mdevctl_action_table[NUM_MDEVCTL_ACTIONS] = {
|
||||||
|
{MDEVCTL_ACTION_DEFINE, "define"},
|
||||||
|
{MDEVCTL_ACTION_LIST, "list"},
|
||||||
|
{MDEVCTL_ACTION_MODIFY, "modify"},
|
||||||
|
{MDEVCTL_ACTION_START, "start"},
|
||||||
|
{MDEVCTL_ACTION_STOP, "stop"},
|
||||||
|
{MDEVCTL_ACTION_TYPES, "types"},
|
||||||
|
{MDEVCTL_ACTION_UNDEFINE, "undefine"},
|
||||||
|
{MDEVCTL_ACTION_ATTRIBUTES, "attributes"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct mdevctl_event mdevctl_event_table[NUM_MDEVCTL_EVENTS] = {
|
||||||
|
{MDEVCTL_EVENT_PRE, "pre"},
|
||||||
|
{MDEVCTL_EVENT_POST, "post"},
|
||||||
|
{MDEVCTL_EVENT_GET, "get"}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert mdevctl action string to an enumerated value
|
||||||
|
*/
|
||||||
|
static enum mdevctl_action_id validate_action(char *action)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_MDEVCTL_ACTIONS; i++) {
|
||||||
|
if (strcmp(action, mdevctl_action_table[i].action) == 0)
|
||||||
|
return mdevctl_action_table[i].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MDEVCTL_ACTION_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Convert mdevctl event string to an enumerated value
|
||||||
|
*/
|
||||||
|
static enum mdevctl_event_id validate_event(char *event)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < NUM_MDEVCTL_EVENTS; i++) {
|
||||||
|
if (strcmp(event, mdevctl_event_table[i].event) == 0)
|
||||||
|
return mdevctl_event_table[i].id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MDEVCTL_EVENT_UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct util_opt opt_vec[] = {
|
||||||
|
UTIL_OPT_SECTION("DEVICE"),
|
||||||
|
{
|
||||||
|
.option = { "e", required_argument, NULL, 'e' },
|
||||||
|
.argument = "EVENT",
|
||||||
|
.desc = "The type of callout being issued",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "a", required_argument, NULL, 'a' },
|
||||||
|
.argument = "ACTION",
|
||||||
|
.desc = "The action being performed on the specified device",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "s", required_argument, NULL, 's' },
|
||||||
|
.argument = "STATE",
|
||||||
|
.desc = "The state of the associated mdevctl command",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "u", required_argument, NULL, 'u' },
|
||||||
|
.argument = "UUID",
|
||||||
|
.desc = "Universally Unique ID for the mediated device",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "p", required_argument, NULL, 'p' },
|
||||||
|
.argument = "PDEV",
|
||||||
|
.desc = "Parent device name, e.g. matrix",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.option = { "t", required_argument, NULL, 't' },
|
||||||
|
.argument = "TYPE",
|
||||||
|
.desc = "Mediated device type, e.g. vfio_ap-passthrough",
|
||||||
|
},
|
||||||
|
UTIL_OPT_END
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize the ap_check anchor struct.
|
||||||
|
*/
|
||||||
|
static void ap_check_init(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
anc->uuid = anc->parent = anc->type = NULL;
|
||||||
|
anc->dev = vfio_ap_device_new();
|
||||||
|
anc->cleanup_lock = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free memory of ap_check anchor struct.
|
||||||
|
*/
|
||||||
|
static void ap_check_cleanup(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
if (anc->uuid)
|
||||||
|
free(anc->uuid);
|
||||||
|
if (anc->parent)
|
||||||
|
free(anc->parent);
|
||||||
|
if (anc->type)
|
||||||
|
free(anc->type);
|
||||||
|
if (anc->dev)
|
||||||
|
vfio_ap_device_free(anc->dev);
|
||||||
|
if (anc->cleanup_lock)
|
||||||
|
ap_release_lock_callout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exit ap_check
|
||||||
|
*/
|
||||||
|
static void __noreturn ap_check_exit(struct ap_check_anchor *anc, int rc)
|
||||||
|
{
|
||||||
|
ap_check_cleanup(anc);
|
||||||
|
exit(rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* parses the command line
|
||||||
|
*/
|
||||||
|
static void ap_check_parse(struct ap_check_anchor *anc,
|
||||||
|
int argc, char *argv[])
|
||||||
|
{
|
||||||
|
bool action = false, event = false, state = false, bad_opts = false;
|
||||||
|
int opt;
|
||||||
|
|
||||||
|
util_opt_init(opt_vec, NULL);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
opt = util_opt_getopt_long(argc, argv);
|
||||||
|
if (opt == -1)
|
||||||
|
break;
|
||||||
|
switch (opt) {
|
||||||
|
case 'e':
|
||||||
|
if (event) {
|
||||||
|
bad_opts = true;
|
||||||
|
} else {
|
||||||
|
anc->event = validate_event(optarg);
|
||||||
|
event = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
if (action) {
|
||||||
|
bad_opts = true;
|
||||||
|
} else {
|
||||||
|
anc->action = validate_action(optarg);
|
||||||
|
action = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
if (state) {
|
||||||
|
bad_opts = true;
|
||||||
|
} else {
|
||||||
|
/* Ignore the state */
|
||||||
|
state = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (anc->uuid)
|
||||||
|
bad_opts = true;
|
||||||
|
else
|
||||||
|
anc->uuid = util_strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'p':
|
||||||
|
if (anc->parent)
|
||||||
|
bad_opts = true;
|
||||||
|
else
|
||||||
|
anc->parent = util_strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
if (anc->type)
|
||||||
|
bad_opts = true;
|
||||||
|
else
|
||||||
|
anc->type = util_strdup(optarg);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unknown operand\n");
|
||||||
|
ap_check_exit(anc, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure we got all expected input values */
|
||||||
|
if (!(action && event && state && anc->uuid && anc->parent &&
|
||||||
|
anc->type) || bad_opts) {
|
||||||
|
fprintf(stderr, "Duplicate or missing operand\n");
|
||||||
|
ap_check_exit(anc, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for invalid UUID */
|
||||||
|
if (!is_valid_uuid(anc->uuid)) {
|
||||||
|
fprintf(stderr, "Invalid UUID specified\n");
|
||||||
|
ap_check_exit(anc, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
anc->dev->uuid = util_strdup(anc->uuid);
|
||||||
|
|
||||||
|
/* Check for valid type */
|
||||||
|
if (strcmp(anc->type, VFIO_AP_TYPE) != 0)
|
||||||
|
ap_check_exit(anc, APC_EXIT_UNKNOWN_TYPE);
|
||||||
|
|
||||||
|
/* Check for invalid parent - currently only 'matrix' supported */
|
||||||
|
if (strcmp(anc->parent, "matrix") != 0) {
|
||||||
|
fprintf(stderr, "Invalid parent specified\n");
|
||||||
|
ap_check_exit(anc, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Call a function for each entry in a directory:
|
||||||
|
* int callback(const char *abs_path, const char *rel_path, void *data)
|
||||||
|
* Continues for all entries in the directory regardless of callback return
|
||||||
|
* code. Will return 0 or, if one or more callbacks failed, the first nonzero
|
||||||
|
* rc received.
|
||||||
|
*/
|
||||||
|
static int path_for_each(const char *path,
|
||||||
|
int (*callback)(const char *, const char *, void *),
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct dirent *de;
|
||||||
|
int rc = 0;
|
||||||
|
int r = 0;
|
||||||
|
DIR *dir;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
dir = opendir(path);
|
||||||
|
if (!dir)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while ((de = readdir(dir))) {
|
||||||
|
if (strcmp(de->d_name, ".") == 0 ||
|
||||||
|
strcmp(de->d_name, "..") == 0)
|
||||||
|
continue;
|
||||||
|
util_asprintf(&p, "%s/%s", path, de->d_name);
|
||||||
|
r = callback(p, de->d_name, data);
|
||||||
|
/* Save first nonzero return code for caller */
|
||||||
|
if (rc == 0 && r != 0)
|
||||||
|
rc = r;
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Report an error message when the specified configuration will conflict
|
||||||
|
* with an existing device
|
||||||
|
*/
|
||||||
|
static void conflict_error(const char *uuid, unsigned int a, unsigned int d,
|
||||||
|
bool persistent)
|
||||||
|
{
|
||||||
|
if (uuid) {
|
||||||
|
if (persistent) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"APQN %u.%u is defined for autostart by %s\n",
|
||||||
|
a, d, uuid);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "APQN %u.%u already in use by %s\n",
|
||||||
|
a, d, uuid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (persistent) {
|
||||||
|
fprintf(stderr, "AQPN %u.%u is not defined for "
|
||||||
|
"vfio_ap-passthrough use by the persistent "
|
||||||
|
"ap bus mask settings\n", a, d);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "AQPN %u.%u is not allowed for "
|
||||||
|
"vfio_ap-passthrough use by the active ap "
|
||||||
|
"bus mask settings\n", a, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare the list of adapters and domains for two devices, reporting error
|
||||||
|
* messages for any conflicts that occur. A conflict occurs when both devices
|
||||||
|
* have the same adapter + domain pair.
|
||||||
|
* The function below takes advantage of the fact that the lists are known to
|
||||||
|
* be sorted in numeric order; therefore we can use this information to run
|
||||||
|
* the lists in parallel rather than always starting from the beginning.
|
||||||
|
*/
|
||||||
|
static int find_apqn_conflicts(const char *uuid,
|
||||||
|
struct util_list *adapters,
|
||||||
|
struct util_list *domains,
|
||||||
|
struct util_list *adapters2,
|
||||||
|
struct util_list *domains2,
|
||||||
|
bool persistent)
|
||||||
|
{
|
||||||
|
struct vfio_ap_node *a, *a2, *d, *d2;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Checks for conflicts with the device */
|
||||||
|
a = util_list_start(adapters);
|
||||||
|
a2 = util_list_start(adapters2);
|
||||||
|
while ((a != NULL) && (a2 != NULL)) {
|
||||||
|
if (a->id == a2->id) {
|
||||||
|
d = util_list_start(domains);
|
||||||
|
d2 = util_list_start(domains2);
|
||||||
|
while ((d != NULL) && (d2 != NULL)) {
|
||||||
|
if (d->id == d2->id) {
|
||||||
|
/* Report error, look for more */
|
||||||
|
conflict_error(uuid, a->id, d->id,
|
||||||
|
persistent);
|
||||||
|
rc = -1;
|
||||||
|
d = util_list_next(domains, d);
|
||||||
|
d2 = util_list_next(domains2, d2);
|
||||||
|
} else if (d->id > d2->id) {
|
||||||
|
d2 = util_list_next(domains2, d2);
|
||||||
|
} else {
|
||||||
|
d = util_list_next(domains, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a = util_list_next(adapters, a);
|
||||||
|
a2 = util_list_next(adapters2, a2);
|
||||||
|
} else if (a->id > a2->id) {
|
||||||
|
a2 = util_list_next(adapters2, a2);
|
||||||
|
} else {
|
||||||
|
a = util_list_next(adapters, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the provided path maps to a valid vfio-ap device configuration,
|
||||||
|
* determine if its current configuration will conflict with the proposed
|
||||||
|
* changes.
|
||||||
|
*/
|
||||||
|
static int check_other_mdev_cfg_cb(const char *path,
|
||||||
|
const char *filename,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct other_mdev_cb_data *cbdata = data;
|
||||||
|
struct vfio_ap_device *dev = cbdata->dev;
|
||||||
|
struct vfio_ap_device *dev2 = NULL;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
/* Skip anything that isn't an mdev config */
|
||||||
|
if (!is_valid_uuid(filename))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Skip if this is the input device */
|
||||||
|
if (strcasecmp(cbdata->uuid, filename) == 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Read the device config */
|
||||||
|
dev2 = vfio_ap_device_new();
|
||||||
|
if (vfio_ap_read_device_config(path, dev2) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* If wrong device type, skip */
|
||||||
|
if (strcmp(dev2->type, VFIO_AP_TYPE) != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* If not AUTO device, skip */
|
||||||
|
if (dev2->manual)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Perform mdev-to-mdev apqn conflict analysis */
|
||||||
|
rc = find_apqn_conflicts(filename, dev->adapters, dev->domains,
|
||||||
|
dev2->adapters, dev2->domains, true);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (dev2 != NULL)
|
||||||
|
vfio_ap_device_free(dev2);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform conflict analysis against all other vfio-ap persistent
|
||||||
|
* configurations.
|
||||||
|
*/
|
||||||
|
int check_other_mdevs_cfg(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
struct other_mdev_cb_data cb_data;
|
||||||
|
|
||||||
|
if (!util_path_is_dir(VFIO_AP_CONFIG_PATH))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
cb_data.uuid = anc->uuid;
|
||||||
|
cb_data.dev = anc->dev;
|
||||||
|
|
||||||
|
return path_for_each(VFIO_AP_CONFIG_PATH, check_other_mdev_cfg_cb,
|
||||||
|
&cb_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the provided path maps to a valid device, determine if its current
|
||||||
|
* configuration will conflict with the proposed changes.
|
||||||
|
*/
|
||||||
|
static int check_other_mdev_sysfs_cb(const char *path, const char *filename,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
struct other_mdev_cb_data *cbdata = data;
|
||||||
|
struct vfio_ap_device *dev = cbdata->dev;
|
||||||
|
struct vfio_ap_device *dev2;
|
||||||
|
char *matrix_path;
|
||||||
|
char buf[80];
|
||||||
|
int rc = 0;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
if (!is_valid_uuid(filename) || path == NULL ||
|
||||||
|
strcasecmp(filename, cbdata->uuid) == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
dev2 = vfio_ap_device_new();
|
||||||
|
matrix_path = path_get_vfio_ap_attr(filename, "matrix");
|
||||||
|
f = fopen(matrix_path, "r");
|
||||||
|
while (fgets(buf, sizeof(buf), f))
|
||||||
|
vfio_ap_parse_matrix(dev2, buf);
|
||||||
|
vfio_ap_sort_matrix_results(dev2);
|
||||||
|
fclose(f);
|
||||||
|
free(matrix_path);
|
||||||
|
|
||||||
|
/* Look for conflicts between target device and this device */
|
||||||
|
rc = find_apqn_conflicts(filename, dev->adapters, dev->domains,
|
||||||
|
dev2->adapters, dev2->domains, false);
|
||||||
|
|
||||||
|
vfio_ap_device_free(dev2);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Run conflict analysis against all other active vfio-ap devices */
|
||||||
|
static int check_other_mdevs_sysfs(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
struct other_mdev_cb_data cb_data;
|
||||||
|
char *root;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
cb_data.uuid = anc->uuid;
|
||||||
|
cb_data.dev = anc->dev;
|
||||||
|
|
||||||
|
root = path_get_vfio_ap_mdev("");
|
||||||
|
if (util_path_is_dir(root))
|
||||||
|
rc = path_for_each(root, check_other_mdev_sysfs_cb, &cb_data);
|
||||||
|
|
||||||
|
free(root);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if there are any conflicts between the specified device and
|
||||||
|
* the active apmask/aqmask settings. This is done by treating the masks
|
||||||
|
* as a temporary vfio_ap_device with all of the associated APQNs owned by
|
||||||
|
* the system.
|
||||||
|
*/
|
||||||
|
static int check_sysfs_mask_conflicts(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
struct vfio_ap_device *sysdev = vfio_ap_device_new();
|
||||||
|
char *apmask = util_zalloc(AP_MASK_SIZE);
|
||||||
|
char *aqmask = util_zalloc(AP_MASK_SIZE);
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (ap_read_sysfs_masks(apmask, aqmask, AP_MASK_SIZE) != 0) {
|
||||||
|
fprintf(stderr, "Error reading system AP settings\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the masks to a device with the associated APQNs */
|
||||||
|
ap_mask_to_list(apmask, sysdev->adapters);
|
||||||
|
ap_mask_to_list(aqmask, sysdev->domains);
|
||||||
|
|
||||||
|
/* Perform conflict analysis */
|
||||||
|
rc = find_apqn_conflicts(NULL, anc->dev->adapters,
|
||||||
|
anc->dev->domains, sysdev->adapters,
|
||||||
|
sysdev->domains, false);
|
||||||
|
out:
|
||||||
|
free(apmask);
|
||||||
|
free(aqmask);
|
||||||
|
vfio_ap_device_free(sysdev);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if there are any conflicts between the specified device and
|
||||||
|
* the apmask/aqmask settings stored in udev. This is done by treating
|
||||||
|
* the masks as a temporary vfio_ap_device with all of the associated
|
||||||
|
* AQPNs owned by the system.
|
||||||
|
*/
|
||||||
|
static int check_cfg_mask_conflicts(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
struct vfio_ap_device *sysdev = vfio_ap_device_new();
|
||||||
|
char *apmask = util_zalloc(AP_MASK_SIZE);
|
||||||
|
char *aqmask = util_zalloc(AP_MASK_SIZE);
|
||||||
|
bool read_ap = false, read_aq = false;
|
||||||
|
char *path;
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
path = path_get_ap_udev();
|
||||||
|
if (!ap_read_udev_masks(path, apmask, aqmask, &read_ap, &read_aq)) {
|
||||||
|
fprintf(stderr, "Error reading system AP settings\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert the masks to a device with the associated APQNs */
|
||||||
|
ap_mask_to_list(apmask, sysdev->adapters);
|
||||||
|
ap_mask_to_list(aqmask, sysdev->domains);
|
||||||
|
|
||||||
|
/* Perform conflict analysis */
|
||||||
|
rc = find_apqn_conflicts(NULL, anc->dev->adapters,
|
||||||
|
anc->dev->domains, sysdev->adapters,
|
||||||
|
sysdev->domains, true);
|
||||||
|
out:
|
||||||
|
free(apmask);
|
||||||
|
free(aqmask);
|
||||||
|
free(path);
|
||||||
|
vfio_ap_device_free(sysdev);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subroutine to handle checking shared between DEFINE and MODIFY actions. */
|
||||||
|
static int ap_check_changes(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
int rc = 0, rc2;
|
||||||
|
|
||||||
|
rc = ap_get_lock_callout();
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "Failed to acquire configuration lock %d\n",
|
||||||
|
rc);
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
anc->cleanup_lock = true;
|
||||||
|
|
||||||
|
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
|
||||||
|
fprintf(stderr, "Failed to read device config\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(anc->dev->type, anc->type) != 0) {
|
||||||
|
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!anc->dev->manual) {
|
||||||
|
/* Check against all other AUTO config files */
|
||||||
|
rc = check_other_mdevs_cfg(anc);
|
||||||
|
/* Check against the system UDEV rule for apmask/aqmask */
|
||||||
|
rc2 = check_cfg_mask_conflicts(anc);
|
||||||
|
/* If either hit an error, reflect this */
|
||||||
|
rc = rc != 0 ? rc : rc2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If successful, lock must remain held until post callout */
|
||||||
|
if (rc == 0)
|
||||||
|
anc->cleanup_lock = false;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if defining the specified device is a valid operation.
|
||||||
|
* mdevctl can reach us for a DEFINE under the following circumstances:
|
||||||
|
* 1) the device does not exist
|
||||||
|
* 2) the device is active but does not have a config file, so this action
|
||||||
|
* would be to generate a config file based upon the active device.
|
||||||
|
* DEFINE has no effect on an active device (if one exists) it only creates
|
||||||
|
* the configuration file. The config file might be empty or may have various
|
||||||
|
* attributes if being fed by --jsonfile or an active device.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_define(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
char *path = path_get_vfio_ap_mdev_config(anc->uuid);
|
||||||
|
|
||||||
|
if (util_path_is_readable(path)) {
|
||||||
|
fprintf(stderr, "Config already exists\n");
|
||||||
|
free(path);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
return ap_check_changes(anc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if modifying the specified device is a valid operation.
|
||||||
|
* mdevctl can reach us for a MODIFY under the following circumstances:
|
||||||
|
* 1) Modifying a MANUAL device
|
||||||
|
* 2) Modifying an AUTO device
|
||||||
|
* In the case of MANUAL, we don't take any action because changes made via
|
||||||
|
* MODIFY don't take affect on the active mdev until a STOP/START cycle.
|
||||||
|
* In the case of AUTO, we must compare the contents of the proposed device
|
||||||
|
* with the contents of stashed AUTO mdev configurations + the system.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_modify(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
char *path = path_get_vfio_ap_mdev_config(anc->uuid);
|
||||||
|
FILE *fd = fopen(path, "r");
|
||||||
|
|
||||||
|
/* Determine if a base config file already exists for UUID */
|
||||||
|
free(path);
|
||||||
|
if (fd == NULL) {
|
||||||
|
fprintf(stderr, "Config doesn't exist\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
|
||||||
|
return ap_check_changes(anc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if starting the specified device is a valid operation.
|
||||||
|
* mdevctl can reach us for a START under the following circumstances:
|
||||||
|
* 1) STARTing a MANUAL device
|
||||||
|
* 1a) Where the MANUAL device is defined (has a config file)
|
||||||
|
* 1b) Where the MANUAL device is NOT defined (no config file).
|
||||||
|
* For vfio-ap this case provides an mdev with no adapters/domains.
|
||||||
|
* 1c) Where the MANUAL device is NOT defined but a full configuration is
|
||||||
|
* provided via --jsonfile
|
||||||
|
* 2) STARTing an AUTO device
|
||||||
|
* 2a) Where the AUTO device is defined (has a config file)
|
||||||
|
* 2b) Where the AUTO device is NOT defined but a full configuration is
|
||||||
|
* provided via --jsonfile
|
||||||
|
* In each case, we must compare the proposed device with the contents of
|
||||||
|
* active mdevs + the system.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_start(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
int rc = 0, rc2;
|
||||||
|
|
||||||
|
/* Can only start a device if vfio_ap is built-in or loaded */
|
||||||
|
if (!util_path_is_dir(VFIO_AP_PATH)) {
|
||||||
|
fprintf(stderr, "vfio_ap module is not loaded\n");
|
||||||
|
ap_check_exit(anc, EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ap_get_lock_callout();
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "Failed to acquire configuration lock %d\n",
|
||||||
|
rc);
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
anc->cleanup_lock = true;
|
||||||
|
|
||||||
|
if (vfio_ap_read_device_config(NULL, anc->dev) != 0) {
|
||||||
|
fprintf(stderr, "Failed to read device config\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(anc->dev->type, anc->type) != 0) {
|
||||||
|
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ensure device with control domains also has usage domains */
|
||||||
|
if (util_list_is_empty(anc->dev->domains) &&
|
||||||
|
!util_list_is_empty(anc->dev->controls)) {
|
||||||
|
fprintf(stderr, "At least one usage domain must be specified\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check against all other active vfio-ap devices */
|
||||||
|
rc = check_other_mdevs_sysfs(anc);
|
||||||
|
/* Check against the system sysfs values for apmask/aqmask */
|
||||||
|
rc2 = check_sysfs_mask_conflicts(anc);
|
||||||
|
/* If either hit an error, reflect this */
|
||||||
|
rc = rc != 0 ? rc : rc2;
|
||||||
|
|
||||||
|
/* If successful, lock must remain held until post callout */
|
||||||
|
if (rc == 0)
|
||||||
|
anc->cleanup_lock = false;
|
||||||
|
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Acquire the appropriate serialization so that the specified device can be
|
||||||
|
* STOPped.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_stop(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = ap_get_lock_callout();
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "Failed to acquire configuration lock %d\n",
|
||||||
|
rc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The lock must remain held until post callout */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine if UNDEFINEing the specified device is a valid operation.
|
||||||
|
* mdevctl can reach us for an UNDEFINE under the following circumstances:
|
||||||
|
* 1) UNDEFINEing an active device
|
||||||
|
* 2) UNDEFINEing an inactive device
|
||||||
|
* UNDEFINE has no effect on the active device, it only removes the config
|
||||||
|
* file.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_undefine(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
char *path = path_get_vfio_ap_mdev_config(anc->uuid);
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
rc = ap_get_lock_callout();
|
||||||
|
if (rc) {
|
||||||
|
fprintf(stderr, "Failed to acquire configuration lock %d\n",
|
||||||
|
rc);
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
anc->cleanup_lock = true;
|
||||||
|
|
||||||
|
if (vfio_ap_read_device_config(path, anc->dev) != 0) {
|
||||||
|
fprintf(stderr, "Failed to read device config\n");
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(anc->dev->type, anc->type) != 0) {
|
||||||
|
fprintf(stderr, "Invalid mdev_type: %s\n", anc->dev->type);
|
||||||
|
rc = -1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Success: lock must remain held until post callout */
|
||||||
|
anc->cleanup_lock = false;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(path);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For callouts where the "pre" callout would have acquired the lock, it is
|
||||||
|
* now safe to remove the lock as all changes have been committed.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_post(void)
|
||||||
|
{
|
||||||
|
return ap_release_lock_callout();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the specified device, print the attributes to stdout in JSON format */
|
||||||
|
static int ap_check_handle_get_attributes(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
struct vfio_ap_device *dev = anc->dev;
|
||||||
|
struct vfio_ap_node *node;
|
||||||
|
bool has_attr = false;
|
||||||
|
char buf[80];
|
||||||
|
char *path;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
|
path = path_get_vfio_ap_attr(anc->uuid, "matrix");
|
||||||
|
f = fopen(path, "r");
|
||||||
|
while (fgets(buf, sizeof(buf), f))
|
||||||
|
vfio_ap_parse_matrix(dev, buf);
|
||||||
|
vfio_ap_sort_matrix_results(dev);
|
||||||
|
fclose(f);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
path = path_get_vfio_ap_attr(anc->uuid, "control_domains");
|
||||||
|
f = fopen(path, "r");
|
||||||
|
while (fgets(buf, sizeof(buf), f))
|
||||||
|
vfio_ap_parse_control(dev, buf);
|
||||||
|
fclose(f);
|
||||||
|
free(path);
|
||||||
|
|
||||||
|
printf("[{");
|
||||||
|
|
||||||
|
if (!util_list_is_empty(dev->adapters)) {
|
||||||
|
util_list_iterate(dev->adapters, node) {
|
||||||
|
if (has_attr)
|
||||||
|
printf("},{");
|
||||||
|
printf("\"assign_adapter\": \"%u\"", node->id);
|
||||||
|
has_attr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!util_list_is_empty(dev->domains)) {
|
||||||
|
util_list_iterate(dev->domains, node) {
|
||||||
|
if (has_attr)
|
||||||
|
printf("},{");
|
||||||
|
printf("\"assign_domain\": \"%u\"", node->id);
|
||||||
|
has_attr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!util_list_is_empty(dev->controls)) {
|
||||||
|
util_list_iterate(dev->controls, node) {
|
||||||
|
if (has_attr)
|
||||||
|
printf("},{");
|
||||||
|
printf("\"assign_control_domain\": \"%u\"", node->id);
|
||||||
|
has_attr = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("}]\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determine which mdevctl action is being checked and handle accordingly.
|
||||||
|
*/
|
||||||
|
static int ap_check_handle_action(struct ap_check_anchor *anc)
|
||||||
|
{
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
switch (anc->event) {
|
||||||
|
case MDEVCTL_EVENT_PRE:
|
||||||
|
switch (anc->action) {
|
||||||
|
case MDEVCTL_ACTION_DEFINE:
|
||||||
|
rc = ap_check_handle_define(anc);
|
||||||
|
break;
|
||||||
|
case MDEVCTL_ACTION_MODIFY:
|
||||||
|
rc = ap_check_handle_modify(anc);
|
||||||
|
break;
|
||||||
|
case MDEVCTL_ACTION_START:
|
||||||
|
rc = ap_check_handle_start(anc);
|
||||||
|
break;
|
||||||
|
case MDEVCTL_ACTION_STOP:
|
||||||
|
rc = ap_check_handle_stop();
|
||||||
|
break;
|
||||||
|
case MDEVCTL_ACTION_UNDEFINE:
|
||||||
|
rc = ap_check_handle_undefine(anc);
|
||||||
|
break;
|
||||||
|
case MDEVCTL_ACTION_LIST:
|
||||||
|
case MDEVCTL_ACTION_TYPES:
|
||||||
|
default:
|
||||||
|
/* Ignore some actions including unknown ones */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MDEVCTL_EVENT_POST:
|
||||||
|
switch (anc->action) {
|
||||||
|
case MDEVCTL_ACTION_DEFINE:
|
||||||
|
case MDEVCTL_ACTION_MODIFY:
|
||||||
|
case MDEVCTL_ACTION_START:
|
||||||
|
case MDEVCTL_ACTION_STOP:
|
||||||
|
case MDEVCTL_ACTION_UNDEFINE:
|
||||||
|
ap_check_handle_post();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore other post events */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MDEVCTL_EVENT_GET:
|
||||||
|
switch (anc->action) {
|
||||||
|
case MDEVCTL_ACTION_ATTRIBUTES:
|
||||||
|
rc = ap_check_handle_get_attributes(anc);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore some actions including unknown ones */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
/* Ignore any unknown events */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
struct ap_check_anchor anchor;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ap_check_init(&anchor);
|
||||||
|
|
||||||
|
ap_check_parse(&anchor, argc, argv);
|
||||||
|
|
||||||
|
rc = ap_check_handle_action(&anchor);
|
||||||
|
|
||||||
|
ap_check_exit(&anchor, rc);
|
||||||
|
}
|
||||||
74
ap_tools/ap-check.h
Normal file
74
ap_tools/ap-check.h
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* ap-check - Validate vfio-ap mediated device configuration changes
|
||||||
|
*
|
||||||
|
* 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 AP_CHECK_H
|
||||||
|
#define AP_CHECK_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* List of all of the supported mdevctl actions
|
||||||
|
*/
|
||||||
|
enum mdevctl_action_id {
|
||||||
|
MDEVCTL_ACTION_DEFINE = 0,
|
||||||
|
MDEVCTL_ACTION_LIST,
|
||||||
|
MDEVCTL_ACTION_MODIFY,
|
||||||
|
MDEVCTL_ACTION_START,
|
||||||
|
MDEVCTL_ACTION_STOP,
|
||||||
|
MDEVCTL_ACTION_TYPES,
|
||||||
|
MDEVCTL_ACTION_UNDEFINE,
|
||||||
|
MDEVCTL_ACTION_ATTRIBUTES,
|
||||||
|
/* UNKNOWN must always be the last in the list */
|
||||||
|
MDEVCTL_ACTION_UNKNOWN,
|
||||||
|
};
|
||||||
|
#define NUM_MDEVCTL_ACTIONS MDEVCTL_ACTION_UNKNOWN
|
||||||
|
|
||||||
|
struct mdevctl_action {
|
||||||
|
enum mdevctl_action_id id;
|
||||||
|
const char action[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
enum mdevctl_event_id {
|
||||||
|
MDEVCTL_EVENT_PRE = 0,
|
||||||
|
MDEVCTL_EVENT_POST,
|
||||||
|
MDEVCTL_EVENT_GET,
|
||||||
|
MDEVCTL_EVENT_UNKNOWN,
|
||||||
|
};
|
||||||
|
#define NUM_MDEVCTL_EVENTS MDEVCTL_EVENT_UNKNOWN
|
||||||
|
|
||||||
|
struct mdevctl_event {
|
||||||
|
enum mdevctl_event_id id;
|
||||||
|
const char event[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
/* ap-check special exit codes */
|
||||||
|
#define APC_EXIT_UNKNOWN_TYPE 2
|
||||||
|
|
||||||
|
struct ap_check_anchor {
|
||||||
|
enum mdevctl_event_id event;
|
||||||
|
enum mdevctl_action_id action;
|
||||||
|
char *uuid;
|
||||||
|
char *parent;
|
||||||
|
char *type;
|
||||||
|
struct vfio_ap_device *dev;
|
||||||
|
/* Active Masks */
|
||||||
|
char apmask[80];
|
||||||
|
char aqmask[80];
|
||||||
|
/* Persistent Masks */
|
||||||
|
char p_apmask[80];
|
||||||
|
char p_aqmask[80];
|
||||||
|
bool cleanup_lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct other_mdev_cb_data {
|
||||||
|
const char *uuid;
|
||||||
|
struct vfio_ap_device *dev;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* AP_CHECK_H */
|
||||||
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 "$@"
|
||||||
@@ -32,7 +32,7 @@ Usage: $cmd [-t LAST_GIT_TAG]
|
|||||||
Add all new authors since last release to the $authors_file file. Without
|
Add all new authors since last release to the $authors_file file. Without
|
||||||
the -t option the tool uses the last available git tag as last release.
|
the -t option the tool uses the last available git tag as last release.
|
||||||
|
|
||||||
The tool should be called form the s390-tools master branch.
|
The tool runs on the s390-tools master branch.
|
||||||
|
|
||||||
OPTIONS
|
OPTIONS
|
||||||
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
|
-t, --tag LAST_GIT_TAG Use git tag LAST_GIT_TAG as starting point
|
||||||
@@ -116,7 +116,7 @@ echo "$cmd: Adding new authors since tag: $release_tag_last"
|
|||||||
# Print authors list without header
|
# Print authors list without header
|
||||||
tail -n +4 $authors_file_path
|
tail -n +4 $authors_file_path
|
||||||
# Add the new authors
|
# Add the new authors
|
||||||
git log --format="- %an" $release_tag_last..
|
git log --format="- %an" $release_tag_last..master
|
||||||
# Then sort everything and remove duplicates
|
# Then sort everything and remove duplicates
|
||||||
} | sort | uniq > $authors_file_tmp
|
} | sort | uniq > $authors_file_tmp
|
||||||
# Create new AUTHORS file with header ...
|
# Create new AUTHORS file with header ...
|
||||||
|
|||||||
1
chreipl-fcp-mpath/.chreipl-fcp-mpath.7.cksum
Normal file
1
chreipl-fcp-mpath/.chreipl-fcp-mpath.7.cksum
Normal file
@@ -0,0 +1 @@
|
|||||||
|
8e604dab39577678bc9f24bfe5e2ee35354b2f4b1759edd16093157b1ecce9d3 README.md
|
||||||
2
chreipl-fcp-mpath/.gitignore
vendored
2
chreipl-fcp-mpath/.gitignore
vendored
@@ -9,5 +9,3 @@
|
|||||||
/README.html
|
/README.html
|
||||||
/README.pdf
|
/README.pdf
|
||||||
/chreipl-fcp-mpath.md
|
/chreipl-fcp-mpath.md
|
||||||
/chreipl-fcp-mpath.7
|
|
||||||
/chreipl-fcp-mpath.7.gz
|
|
||||||
|
|||||||
@@ -11,9 +11,9 @@
|
|||||||
# - chreipl-fcp-mpath.mak
|
# - chreipl-fcp-mpath.mak
|
||||||
# bash:
|
# bash:
|
||||||
# - bash
|
# - bash
|
||||||
|
# GNU coreutils:
|
||||||
|
# - sha256sum
|
||||||
# If $(ENABLE_DOC) is `1`:
|
# If $(ENABLE_DOC) is `1`:
|
||||||
# GNU Gzip:
|
|
||||||
# - gzip
|
|
||||||
# GNU awk:
|
# GNU awk:
|
||||||
# - gawk
|
# - gawk
|
||||||
|
|
||||||
@@ -102,20 +102,41 @@ chreiplzfcpmp-doc-man-meta = \
|
|||||||
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
-V footer="s390-tools $(S390_TOOLS_RELEASE)"
|
||||||
|
|
||||||
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
chreipl-fcp-mpath.7: PANDOCFLAGS += $(chreiplzfcpmp-doc-man-meta)
|
||||||
|
chreipl-fcp-mpath.7: .chreipl-fcp-mpath.7.cksum
|
||||||
|
|
||||||
.INTERMEDIATE: chreipl-fcp-mpath.md
|
.INTERMEDIATE: chreipl-fcp-mpath.md
|
||||||
chreipl-fcp-mpath.md: README.md
|
chreipl-fcp-mpath.md: README.md
|
||||||
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
gawk -- '/NOT-IN-MAN \{/,/NOT-IN-MAN \}/ { next } { print }' $(<) > $(@)
|
||||||
|
|
||||||
|
.chreipl-fcp-mpath.7.cksum: README.md
|
||||||
|
sha256sum $(<) > $(@)
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-doc-clean
|
.PHONY: chreipl-fcp-mpath-doc-clean
|
||||||
chreipl-fcp-mpath-doc-clean:
|
chreipl-fcp-mpath-doc-clean:
|
||||||
rm -f README.html README.pdf chreipl-fcp-mpath.md chreipl-fcp-mpath.7
|
rm -f README.html README.pdf chreipl-fcp-mpath.md
|
||||||
|
|
||||||
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
chreipl-fcp-mpath: chreipl-fcp-mpath-doc
|
||||||
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-doc-clean
|
||||||
|
|
||||||
|
else # $(ENABLE_DOC) != 1
|
||||||
|
|
||||||
|
# We bundle a pre-cooked man page with the source-code so that distributions
|
||||||
|
# don't need `pandoc` in order to be able to ship the man page. As of this
|
||||||
|
# writing multiple distributions don't have a packaged version of it.
|
||||||
|
#
|
||||||
|
# In order to remember to regenerate this pre-cooked version whenever the
|
||||||
|
# README.md is changed, we also generate a checksum of the README.md, bundle
|
||||||
|
# that as well, and compare that whenever `make` is called. This way, the
|
||||||
|
# freshness of the man page can be checked, even if `pandoc` is not available,
|
||||||
|
# or ENABLE_DOC disabled.
|
||||||
|
|
||||||
|
MANPAGE_FRESH := $(shell sha256sum --check .chreipl-fcp-mpath.7.cksum >/dev/null && echo 1 || echo 0)
|
||||||
|
ifeq ($(MANPAGE_FRESH),0)
|
||||||
|
$(warning chreipl-fcp-mpath.7 is outdated, please regenerate it by calling `make ENABLE_DOC=1`)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
endif # $(ENABLE_DOC) == 1
|
||||||
|
|
||||||
#
|
#
|
||||||
## Install
|
## Install
|
||||||
#
|
#
|
||||||
@@ -133,6 +154,7 @@ install: chreipl-fcp-mpath-install
|
|||||||
|
|
||||||
# install udev rules
|
# install udev rules
|
||||||
INSTDIRS += $(UDEVRULESDIR)
|
INSTDIRS += $(UDEVRULESDIR)
|
||||||
|
$(DESTDIR)$(UDEVRULESDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-udev-rules
|
.PHONY: chreipl-fcp-mpath-install-udev-rules
|
||||||
chreipl-fcp-mpath-install-udev-rules: | $(DESTDIR)$(UDEVRULESDIR)
|
chreipl-fcp-mpath-install-udev-rules: | $(DESTDIR)$(UDEVRULESDIR)
|
||||||
@@ -144,6 +166,7 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-rules
|
|||||||
|
|
||||||
# install udev helper programs
|
# install udev helper programs
|
||||||
INSTDIRS += $(UDEVDIR)
|
INSTDIRS += $(UDEVDIR)
|
||||||
|
$(DESTDIR)$(UDEVDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-udev-helper
|
.PHONY: chreipl-fcp-mpath-install-udev-helper
|
||||||
chreipl-fcp-mpath-install-udev-helper: | $(DESTDIR)$(UDEVDIR)
|
chreipl-fcp-mpath-install-udev-helper: | $(DESTDIR)$(UDEVDIR)
|
||||||
@@ -154,6 +177,7 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-udev-helper
|
|||||||
|
|
||||||
# install common library files
|
# install common library files
|
||||||
INSTDIRS += $(CHREIPLZFCPMPDIR)
|
INSTDIRS += $(CHREIPLZFCPMPDIR)
|
||||||
|
$(DESTDIR)$(CHREIPLZFCPMPDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-libfiles
|
.PHONY: chreipl-fcp-mpath-install-libfiles
|
||||||
chreipl-fcp-mpath-install-libfiles: | $(DESTDIR)$(CHREIPLZFCPMPDIR)
|
chreipl-fcp-mpath-install-libfiles: | $(DESTDIR)$(CHREIPLZFCPMPDIR)
|
||||||
@@ -167,6 +191,7 @@ ifeq ($(HAVE_DRACUT),1)
|
|||||||
|
|
||||||
# install dracut config files
|
# install dracut config files
|
||||||
INSTDIRS += $(DRACUTCONFDIR)
|
INSTDIRS += $(DRACUTCONFDIR)
|
||||||
|
$(DESTDIR)$(DRACUTCONFDIR): install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-dracut-config
|
.PHONY: chreipl-fcp-mpath-install-dracut-config
|
||||||
chreipl-fcp-mpath-install-dracut-config: | $(DESTDIR)$(DRACUTCONFDIR)
|
chreipl-fcp-mpath-install-dracut-config: | $(DESTDIR)$(DRACUTCONFDIR)
|
||||||
@@ -178,28 +203,18 @@ chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-dracut-config
|
|||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(ENABLE_DOC),1)
|
|
||||||
|
|
||||||
# chreipl-fcp-mpath: install man page
|
# chreipl-fcp-mpath: install man page
|
||||||
INSTDIRS += $(MANDIR)
|
INSTDIRS += $(MANDIR)
|
||||||
|
$(DESTDIR)$(MANDIR)/man7: install_dirs
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-man-page
|
.PHONY: chreipl-fcp-mpath-install-man-page
|
||||||
chreipl-fcp-mpath-install-man-page: | $(DESTDIR)$(MANDIR)/man7
|
chreipl-fcp-mpath-install-man-page: | $(DESTDIR)$(MANDIR)/man7
|
||||||
chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
|
chreipl-fcp-mpath-install-man-page: chreipl-fcp-mpath.7
|
||||||
$(GZIP) -fk --best chreipl-fcp-mpath.7
|
|
||||||
$(INSTALL_DATA) -t $(DESTDIR)$(MANDIR)/man7 \
|
$(INSTALL_DATA) -t $(DESTDIR)$(MANDIR)/man7 \
|
||||||
chreipl-fcp-mpath.7.gz
|
chreipl-fcp-mpath.7
|
||||||
|
|
||||||
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
chreipl-fcp-mpath-install: chreipl-fcp-mpath-install-man-page
|
||||||
|
|
||||||
.PHONY: chreipl-fcp-mpath-install-man-page-clean
|
|
||||||
chreipl-fcp-mpath-install-man-page-clean:
|
|
||||||
rm -f chreipl-fcp-mpath.7.gz
|
|
||||||
|
|
||||||
chreipl-fcp-mpath-clean: chreipl-fcp-mpath-install-man-page-clean
|
|
||||||
|
|
||||||
endif
|
|
||||||
|
|
||||||
#
|
#
|
||||||
## Utility
|
## Utility
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -120,19 +120,20 @@ in place, but the toolset has some software dependencies besides the
|
|||||||
requirements in section [Requirements](#requirements):
|
requirements in section [Requirements](#requirements):
|
||||||
|
|
||||||
- GNU Bash;
|
- GNU Bash;
|
||||||
- GNU Core Utilities (mktemp, readlink, sync, truncate);
|
- GNU Core Utilities (mktemp, readlink, sync, truncate, sha256sum);
|
||||||
- util-linux (flock, hexdump, logger);
|
- util-linux (flock, hexdump, logger);
|
||||||
- udev / systemd-udev;
|
- udev / systemd-udev;
|
||||||
- multipath-tools.
|
- multipath-tools.
|
||||||
|
|
||||||
To make use of the optional dracut configuration you need: dracut.
|
To make use of the optional dracut configuration you need: dracut.
|
||||||
|
|
||||||
To build and install the documentation (man page) you need:
|
To build a fresh version of the documentation (man page) you need:
|
||||||
|
|
||||||
- pandoc;
|
- pandoc;
|
||||||
- GNU Core Utilities (date);
|
- GNU Core Utilities (date);
|
||||||
- GNU awk;
|
- GNU awk;
|
||||||
- GNU Gzip.
|
|
||||||
|
otherwise the pre-cooked version shipped with the source will be used.
|
||||||
|
|
||||||
INSTALLATION
|
INSTALLATION
|
||||||
============
|
============
|
||||||
@@ -161,7 +162,7 @@ steps and copies the resulting components to their final destination.
|
|||||||
| Option | Values | Default | Effect
|
| Option | Values | Default | Effect
|
||||||
| :----- | :----: | :-----: | :-----
|
| :----- | :----: | :-----: | :-----
|
||||||
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
| HAVE_DRACUT | 0, 1 | 0 | Install a dracut configuration file that includes **chreipl-fcp-mpath** in the initial ramdisks built with **dracut**.
|
||||||
| ENABLE_DOC | 0, 1 | 0 | Build and install a man page for **chreipl-fcp-mpath**.
|
| ENABLE_DOC | 0, 1 | 0 | Build a fresh version of the man page for **chreipl-fcp-mpath**.
|
||||||
|
|
||||||
Specify any options as arguments for both the **make** and **make install**
|
Specify any options as arguments for both the **make** and **make install**
|
||||||
command as shown in the following example:
|
command as shown in the following example:
|
||||||
@@ -196,8 +197,8 @@ the boot record to find the new initial ramdisk.
|
|||||||
|
|
||||||
~ # zipl
|
~ # zipl
|
||||||
|
|
||||||
With dracut and documentation enabled, **make install** deploys the following
|
With dracut enabled, **make install** deploys the following files to these
|
||||||
files to these default locations:
|
default locations:
|
||||||
|
|
||||||
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
/usr/lib/chreipl-fcp-mpath/chreipl-fcp-mpath-common.sh
|
||||||
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
/usr/lib/dracut/dracut.conf.d/70-chreipl-fcp-mpath.conf
|
||||||
@@ -207,7 +208,7 @@ files to these default locations:
|
|||||||
/usr/lib/udev/chreipl-fcp-mpath-record-volume-identifier
|
/usr/lib/udev/chreipl-fcp-mpath-record-volume-identifier
|
||||||
/usr/lib/udev/chreipl-fcp-mpath-try-change-ipl-path
|
/usr/lib/udev/chreipl-fcp-mpath-try-change-ipl-path
|
||||||
/usr/lib/udev/rules.d/70-chreipl-fcp-mpath.rules
|
/usr/lib/udev/rules.d/70-chreipl-fcp-mpath.rules
|
||||||
/usr/share/man/man7/chreipl-fcp-mpath.7.gz
|
/usr/share/man/man7/chreipl-fcp-mpath.7
|
||||||
|
|
||||||
UNINSTALL
|
UNINSTALL
|
||||||
=========
|
=========
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#!/bin/bash
|
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
#
|
#
|
||||||
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
|
# chreipl-fcp-mpath: use multipath information to change FCP IPL target
|
||||||
|
|||||||
183
chreipl-fcp-mpath/chreipl-fcp-mpath.7
Normal file
183
chreipl-fcp-mpath/chreipl-fcp-mpath.7
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
.\" Automatically generated by Pandoc 2.16.1
|
||||||
|
.\"
|
||||||
|
.TH "CHREIPL-FCP-MPATH" "7" "2022-02-24" "s390-tools 2.20.0-build-20220224" "Administrator Manual"
|
||||||
|
.hy
|
||||||
|
.SH NAME
|
||||||
|
.PP
|
||||||
|
chreipl-fcp-mpath - use multipath information for re-IPL path failover
|
||||||
|
on a running Linux instance
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
The IPL process of Linux on Z or LinuxONE from an FCP-attached SCSI
|
||||||
|
volume uses exactly one path to the volume.
|
||||||
|
If this path is unavailable, the IPL fails.
|
||||||
|
.PP
|
||||||
|
The \f[B]chreipl-fcp-mpath\f[R] toolset monitors \f[B]udev\f[R] events
|
||||||
|
about paths to the re-IPL volume.
|
||||||
|
If the currently configured re-IPL path becomes unavailable, the toolset
|
||||||
|
checks for operational paths to the same volume.
|
||||||
|
If available, it reconfigures the re-IPL settings to use an operational
|
||||||
|
path.
|
||||||
|
.PP
|
||||||
|
Thus, re-IPL from an FCP-attached SCSI volume can be successful despite
|
||||||
|
path failures on a running Linux instance if at least one path to the
|
||||||
|
re-IPL volume remains operational.
|
||||||
|
.PP
|
||||||
|
\f[B]Chreipl-fcp-mpath\f[R] requires \f[B]udev\f[R],
|
||||||
|
\f[B]multipathd\f[R] and \f[B]dm-multipath\f[R].
|
||||||
|
Once installed, the toolset runs automatically and autonomously.
|
||||||
|
No user intervention is possible or required.
|
||||||
|
.PP
|
||||||
|
Other than installing the toolset, there is no user interface for
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
.SS Requirements
|
||||||
|
.PP
|
||||||
|
The \f[B]chreipl-fcp-mpath\f[R] tool has the following requirements on
|
||||||
|
the Linux instance that is being monitored:
|
||||||
|
.IP \[bu] 2
|
||||||
|
The Linux instance must have started successfully, during IPL.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The running Linux instance must use \f[B]dm-multipath\f[R] and
|
||||||
|
\f[B]multipathd\f[R] for the configured re-IPL volume - a volume that
|
||||||
|
contains a zipl boot record and has one of its paths used in the re-IPL
|
||||||
|
configuration.
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]udev\f[R] must run.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The toolset must observe at least one event about the configured re-IPL
|
||||||
|
path.
|
||||||
|
Examples for such events are: the SCSI disk comes online, or a path of
|
||||||
|
the corresponding multipath device goes down or comes back online.
|
||||||
|
.RS 2
|
||||||
|
.IP \[bu] 2
|
||||||
|
The WWID of the re-IPL volume must not change while the Linux instance
|
||||||
|
is running.
|
||||||
|
.RE
|
||||||
|
.IP \[bu] 2
|
||||||
|
When the configured re-IPL path becomes unavailable while the Linux
|
||||||
|
instance is running, at least one operational path to the re-IPL volume
|
||||||
|
must be available, or must become available.
|
||||||
|
If no such path is available when the Linux instance is rebooted, the
|
||||||
|
re-IPL path is not changed.
|
||||||
|
.IP \[bu] 2
|
||||||
|
The tool assumes that any manually reconfigured re-IPL device is valid
|
||||||
|
and operational.
|
||||||
|
.RS 2
|
||||||
|
.PP
|
||||||
|
The tool treats a newly configured re-IPL device like the initially
|
||||||
|
configured re-IPL device.
|
||||||
|
In particular, if the newly configured re-IPL device fulfills the
|
||||||
|
requirements of the tool, re-IPL path failover takes place if the
|
||||||
|
configured re-IPL path becomes unavailable.
|
||||||
|
.RE
|
||||||
|
.SS Caution with Manual Changes to the Configured re-IPL Target
|
||||||
|
.PP
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R] is designed to accept operator-inititated
|
||||||
|
changes of the re-IPL device.
|
||||||
|
However, concurrent changes by the operator and tool driven changes can
|
||||||
|
result in the operator change being overwritten.
|
||||||
|
.PP
|
||||||
|
To avoid this problem, change the re-IPL device only during steady-state
|
||||||
|
operations, when no path events happen.
|
||||||
|
Alternatively, make sure that no events are processed while you change
|
||||||
|
the device.
|
||||||
|
See EXAMPLES for one way to suspend event processing.
|
||||||
|
.SH MESSAGES
|
||||||
|
.PP
|
||||||
|
During monitoring and event processing, \f[B]chreipl-fcp-mpath\f[R]
|
||||||
|
writes messages to the syslog.
|
||||||
|
.PP
|
||||||
|
When the configured re-IPL path is changed to a different path to the
|
||||||
|
same volume (priority \f[I]daemon.notice\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
Changed re-IPL path to: <device-bus-id>:<wwpn>:<lun>.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
When a path event indicates that the last available path has become
|
||||||
|
non-operational (priority \f[I]daemon.alert\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
The re-IPL device cannot be changed because no operational path to the
|
||||||
|
re-IPL volume remains.
|
||||||
|
The next re-IPL might fail unless you re-attach or enable at least one
|
||||||
|
valid path to the re-IPL volume.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
When changing the configured re-IPL device failed because of an error
|
||||||
|
with the used Linux kernel interface (priority \f[I]daemon.crit\f[R]):
|
||||||
|
.RS
|
||||||
|
.PP
|
||||||
|
Changing the re-IPL device failed.
|
||||||
|
The current re-IPL settings might be inconsistent.
|
||||||
|
Check and correct the settings (see the README.md of chreipl-fcp-mpath)
|
||||||
|
to make sure that the current re-IPL device is valid.
|
||||||
|
.RE
|
||||||
|
.PP
|
||||||
|
A failure to change the re-IPL device can indicate an inconsistent
|
||||||
|
setting that cannot be corrected automatically by
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
As a result, the next re-IPL might fail or might not use the intended
|
||||||
|
re-IPL device.
|
||||||
|
.PP
|
||||||
|
You can use the following tools to check and correct the current
|
||||||
|
settings:
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]lsreipl\f[R] to confirm that the intended re-IPL device is
|
||||||
|
configured;
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]chreipl\f[R] to change the re-IPL device;
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[B]lszfcp\f[R] to inspect the state of available paths to the re-IPL
|
||||||
|
device.
|
||||||
|
.SH EXAMPLES
|
||||||
|
.SS Manual Changes to the Configured re-IPL Device
|
||||||
|
.PP
|
||||||
|
As outlined in DESCRIPTION, be cautious when manually changing the
|
||||||
|
configured re-IPL device.
|
||||||
|
Assure that your reconfiguration actions do not collide with concurrent
|
||||||
|
automatic event processing by \f[B]chreipl-fcp-mpath\f[R].
|
||||||
|
You can avoid such collisions, by stopping event processing, making your
|
||||||
|
changes, and then re-enabling event processing.
|
||||||
|
You need \f[I]root\f[R] privileges for running the commands in the
|
||||||
|
following example:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # udevadm settle
|
||||||
|
\[ti] # udevadm control --stop-exec-queue
|
||||||
|
\[ti] # chreipl ...
|
||||||
|
\[ti] # udevadm control --start-exec-queue
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SS Listing messages with journalctl
|
||||||
|
.PP
|
||||||
|
If your Linux instance includes \f[B]journalctl\f[R], use the following
|
||||||
|
command to list all messages that are issued by
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R]:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # journalctl -t chreipl-fcp-mpath
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.PP
|
||||||
|
To list only messages that were issued since the last IPL, use this
|
||||||
|
command:
|
||||||
|
.IP
|
||||||
|
.nf
|
||||||
|
\f[C]
|
||||||
|
\[ti] # journalctl -t chreipl-fcp-mpath -b
|
||||||
|
\f[R]
|
||||||
|
.fi
|
||||||
|
.SH REPORTING BUGS
|
||||||
|
.PP
|
||||||
|
Use the \f[B]Issues\f[R] functionality on GitHub to report any bugs in
|
||||||
|
\f[B]chreipl-fcp-mpath\f[R]: s390-tools
|
||||||
|
Issues (https://github.com/ibm-s390-linux/s390-tools/issues).
|
||||||
|
.SH SEE ALSO
|
||||||
|
.PP
|
||||||
|
\f[B]chreipl\f[R](8), \f[B]dracut\f[R](8), \f[B]journalctl\f[R](1),
|
||||||
|
\f[B]lsreipl(8)\f[R], \f[B]lszfcp\f[R](8), \f[B]multipath\f[R](8),
|
||||||
|
\f[B]multipathd\f[R](8), \f[B]udev\f[R](7), \f[B]udevadm\f[R](8),
|
||||||
|
\f[B]zipl\f[R](8)
|
||||||
@@ -27,11 +27,7 @@ ENABLE_DOC = 0
|
|||||||
|
|
||||||
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
|
# https://www.gnu.org/software/make/manual/make.html#Directory-Variables
|
||||||
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
|
CHREIPLZFCPMPDIR = $(USRLIBDIR)/chreipl-fcp-mpath
|
||||||
UDEVDIR = $(USRLIBDIR)/udev
|
|
||||||
UDEVRULESDIR = $(UDEVDIR)/rules.d
|
|
||||||
UDEVRUNDIR = /run/udev
|
UDEVRUNDIR = /run/udev
|
||||||
DRACUTDIR = $(USRLIBDIR)/dracut
|
|
||||||
DRACUTCONFDIR = $(DRACUTDIR)/dracut.conf.d
|
|
||||||
DEBUGOUTDIR = $(UDEVRUNDIR)
|
DEBUGOUTDIR = $(UDEVRUNDIR)
|
||||||
|
|
||||||
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps
|
INSTALL_EXEC = $(INSTALL) -g $(GROUP) -o $(OWNER) --preserve-timestamps
|
||||||
|
|||||||
@@ -16,17 +16,18 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"cmsfs-fuse", \
|
"cmsfs-fuse", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
|
|
||||||
all: check_dep cmsfs-fuse
|
all: check_dep cmsfs-fuse
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
|
ALL_CFLAGS += -DHAVE_SETXATTR $(FUSE_CFLAGS)
|
||||||
LDLIBS += $(FUSE_LDLIBS) -lm
|
LDLIBS += $(FUSE_LDLIBS) -lm
|
||||||
|
|||||||
@@ -80,9 +80,6 @@ Allow access by other users
|
|||||||
\fB\-o\fR allow_root
|
\fB\-o\fR allow_root
|
||||||
Allow access by root
|
Allow access by root
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR nonempty
|
|
||||||
Allow mounts over non\-empty file/dir
|
|
||||||
.TP
|
|
||||||
\fB\-o\fR default_permissions
|
\fB\-o\fR default_permissions
|
||||||
Enable permission checking by kernel
|
Enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -1516,7 +1516,7 @@ static void walk_dir_block(struct fst_entry *fst, struct walk_file *walk,
|
|||||||
decode_edf_name(file, fst->name, fst->type);
|
decode_edf_name(file, fst->name, fst->type);
|
||||||
if (!file_unlinked(file)) {
|
if (!file_unlinked(file)) {
|
||||||
cache_fst_addr(walk->addr, file);
|
cache_fst_addr(walk->addr, file);
|
||||||
walk->filler(walk->buf, file, NULL, 0);
|
walk->filler(walk->buf, file, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1728,8 +1728,11 @@ static off_t get_file_size_logical(struct fst_entry *fst)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_getattr(const char *path, struct stat *stbuf)
|
static int cmsfs_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
int mask = (cmsfs.allow_other) ? 0444 : 0440;
|
int mask = (cmsfs.allow_other) ? 0444 : 0440;
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
|
|
||||||
@@ -1783,13 +1786,15 @@ static int cmsfs_getattr(const char *path, struct stat *stbuf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
off_t offset, struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
struct walk_file walk;
|
struct walk_file walk;
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
|
|
||||||
(void) offset;
|
(void) offset;
|
||||||
(void) fi;
|
(void) fi;
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Offset is ignored and 0 passed to the filler fn so the whole
|
* Offset is ignored and 0 passed to the filler fn so the whole
|
||||||
@@ -1800,8 +1805,8 @@ static int cmsfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
|
|||||||
if (strcmp(path, "/") != 0)
|
if (strcmp(path, "/") != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
memset(&walk, 0, sizeof(walk));
|
memset(&walk, 0, sizeof(walk));
|
||||||
/* readdir is possible without open so fi->fh is not set */
|
/* readdir is possible without open so fi->fh is not set */
|
||||||
@@ -2683,13 +2688,16 @@ static int cmsfs_statfs(const char *path, struct statvfs *buf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_utimens(const char *path, const struct timespec ts[2])
|
static int cmsfs_utimens(const char *path, const struct timespec ts[2],
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
off_t fst_addr;
|
off_t fst_addr;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@@ -2825,7 +2833,8 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_rename(const char *path, const char *new_path)
|
static int cmsfs_rename(const char *path, const char *new_path,
|
||||||
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct fst_entry fst, fst_new;
|
struct fst_entry fst, fst_new;
|
||||||
off_t fst_addr, fst_addr_new;
|
off_t fst_addr, fst_addr_new;
|
||||||
@@ -2835,6 +2844,8 @@ static int cmsfs_rename(const char *path, const char *new_path)
|
|||||||
struct file *f;
|
struct file *f;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
(void) flags;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EACCES;
|
return -EACCES;
|
||||||
|
|
||||||
@@ -3232,13 +3243,16 @@ static void update_fst(struct file *f, off_t addr)
|
|||||||
unhide_null_blocks(f);
|
unhide_null_blocks(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_truncate(const char *path, off_t size)
|
static int cmsfs_truncate(const char *path, off_t size,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
off_t fst_addr, len;
|
off_t fst_addr, len;
|
||||||
struct file *f;
|
struct file *f;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
|
(void) fi;
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
if (cmsfs.readonly)
|
||||||
return -EROFS;
|
return -EROFS;
|
||||||
|
|
||||||
@@ -4478,6 +4492,15 @@ static void destroy_file_object(struct file *f)
|
|||||||
free(f);
|
free(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *cmsfs_oper_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
|
||||||
|
{
|
||||||
|
(void)conn;
|
||||||
|
|
||||||
|
/* force immediate file removal */
|
||||||
|
cfg->hard_remove = 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static struct file_operations fops_fixed = {
|
static struct file_operations fops_fixed = {
|
||||||
.cache_data = cache_file_fixed,
|
.cache_data = cache_file_fixed,
|
||||||
.write_data = extend_block_fixed,
|
.write_data = extend_block_fixed,
|
||||||
@@ -4493,6 +4516,7 @@ static struct file_operations fops_variable = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct fuse_operations cmsfs_oper = {
|
static struct fuse_operations cmsfs_oper = {
|
||||||
|
.init = cmsfs_oper_init,
|
||||||
.getattr = cmsfs_getattr,
|
.getattr = cmsfs_getattr,
|
||||||
.statfs = cmsfs_statfs,
|
.statfs = cmsfs_statfs,
|
||||||
.readdir = cmsfs_readdir,
|
.readdir = cmsfs_readdir,
|
||||||
@@ -4669,8 +4693,6 @@ int main(int argc, char *argv[])
|
|||||||
fuse_opt_add_arg(&args, "-oro");
|
fuse_opt_add_arg(&args, "-oro");
|
||||||
/* force single threaded mode which requires no locking */
|
/* force single threaded mode which requires no locking */
|
||||||
fuse_opt_add_arg(&args, "-s");
|
fuse_opt_add_arg(&args, "-s");
|
||||||
/* force immediate file removal */
|
|
||||||
fuse_opt_add_arg(&args, "-ohard_remove");
|
|
||||||
|
|
||||||
if (cmsfs.mode == BINARY_MODE &&
|
if (cmsfs.mode == BINARY_MODE &&
|
||||||
(cmsfs.codepage_from != NULL || cmsfs.codepage_to != NULL))
|
(cmsfs.codepage_from != NULL || cmsfs.codepage_to != NULL))
|
||||||
|
|||||||
64
common.mak
64
common.mak
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
|||||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
||||||
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
# "make DISTRELEASE=%{release}" and "make install DISTRELEASE=%{release}"
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
RELEASE = 19
|
RELEASE = 26
|
||||||
PATCHLEVEL = 0
|
PATCHLEVEL = 0
|
||||||
DISTRELEASE = build-$(shell date +%Y%m%d)
|
DISTRELEASE = build-$(shell date +%Y%m%d)
|
||||||
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
S390_TOOLS_RELEASE = $(VERSION).$(RELEASE).$(PATCHLEVEL)-$(DISTRELEASE)
|
||||||
@@ -59,12 +59,11 @@ define cmd_define
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
$(eval $(call cmd_define, AS," AS ",$(CROSS_COMPILE)as))
|
||||||
$(eval $(call cmd_define, LINK," LINK ",$(CROSS_COMPILE)gcc))
|
|
||||||
$(eval $(call cmd_define, LD," LD ",$(CROSS_COMPILE)ld))
|
|
||||||
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
$(eval $(call cmd_define, CC," CC ",$(CROSS_COMPILE)gcc))
|
||||||
|
$(eval $(call cmd_define, LINK," LINK ",$(CC)))
|
||||||
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
$(eval $(call cmd_define, HOSTCC," HOSTCC ",gcc))
|
||||||
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CROSS_COMPILE)g++))
|
|
||||||
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
$(eval $(call cmd_define, CXX," CXX ",$(CROSS_COMPILE)g++))
|
||||||
|
$(eval $(call cmd_define, LINKXX," LINKXX ",$(CXX)))
|
||||||
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
$(eval $(call cmd_define, CPP," CPP ",$(CROSS_COMPILE)gcc -E))
|
||||||
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
$(eval $(call cmd_define, AR," AR ",$(CROSS_COMPILE)ar))
|
||||||
$(eval $(call cmd_define, NM," NM ",$(CROSS_COMPILE)nm))
|
$(eval $(call cmd_define, NM," NM ",$(CROSS_COMPILE)nm))
|
||||||
@@ -92,13 +91,12 @@ ifneq ("${V}","1")
|
|||||||
else
|
else
|
||||||
echocmd=
|
echocmd=
|
||||||
endif
|
endif
|
||||||
|
DEFAULT_CFLAGS = -g -fstack-protector-all -W -Wall -Wformat-security
|
||||||
ifeq ("${W}","1")
|
ifeq ("${W}","1")
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security -Wextra
|
DEFAULT_CFLAGS += -Wextra -Wshadow -Wundef -Wuninitialized -Wdouble-promotion -Wconversion
|
||||||
else
|
|
||||||
DEFAULT_CFLAGS = -g -rdynamic -fstack-protector-all -W -Wall -Wformat-security
|
|
||||||
endif
|
endif
|
||||||
ifeq ("${D}","1")
|
ifeq ("${D}","1")
|
||||||
DEFAULT_CFLAGS += -Og
|
DEFAULT_CFLAGS += -Og -g3 -ggdb3
|
||||||
else
|
else
|
||||||
DEFAULT_CFLAGS += -O3
|
DEFAULT_CFLAGS += -O3
|
||||||
endif
|
endif
|
||||||
@@ -120,9 +118,9 @@ endif
|
|||||||
# Returns "yes" on success and nothing otherwise
|
# Returns "yes" on success and nothing otherwise
|
||||||
#
|
#
|
||||||
define check_header_prereq
|
define check_header_prereq
|
||||||
$(shell printf "#include <%s>\n int main(void) {return 0;}" $1 | \
|
$(shell printf "#include <%s>\n int main(void) {return 0;}\n" $1 | \
|
||||||
( $(CC) $(filter-out --coverage, $(ALL_CFLAGS)) $(ALL_CPPFLAGS) \
|
( $(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
|
endef
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -135,7 +133,7 @@ endef
|
|||||||
# $5: Additional compiler & linker options (optional)
|
# $5: Additional compiler & linker options (optional)
|
||||||
#
|
#
|
||||||
check_dep=\
|
check_dep=\
|
||||||
printf "\#include <%s>\n int main(void) {return 0;}" $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 ]; \
|
if [ $$? != 0 ]; \
|
||||||
then \
|
then \
|
||||||
printf " REQCHK %s (%s)\n" $1 $2; \
|
printf " REQCHK %s (%s)\n" $1 $2; \
|
||||||
@@ -147,6 +145,20 @@ then \
|
|||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
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
|
# Support alternate install root
|
||||||
#
|
#
|
||||||
@@ -195,6 +207,11 @@ ZFCPDUMP_DIR = $(TOOLS_LIBDIR)/zfcpdump
|
|||||||
SYSTEMDSYSTEMUNITDIR =
|
SYSTEMDSYSTEMUNITDIR =
|
||||||
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
USRINCLUDEDIR = $(INSTALLDIR)/usr/include
|
||||||
ZKEYKMSPLUGINDIR = $(USRLIB64DIR)/zkey
|
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)
|
ifeq ($(LIBDIR),$(INSTALLDIR)/lib)
|
||||||
SOINSTALLDIR = $(USRLIB64DIR)
|
SOINSTALLDIR = $(USRLIB64DIR)
|
||||||
@@ -252,15 +269,13 @@ export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
|
|||||||
|
|
||||||
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
||||||
NO_PIE_CFLAGS := -fno-pie
|
NO_PIE_CFLAGS := -fno-pie
|
||||||
NO_PIE_LINKFLAGS := -no-pie
|
|
||||||
NO_PIE_LDFLAGS := -no-pie
|
NO_PIE_LDFLAGS := -no-pie
|
||||||
else
|
else
|
||||||
NO_PIE_CFLAGS :=
|
NO_PIE_CFLAGS :=
|
||||||
NO_PIE_LINKFLAGS :=
|
|
||||||
NO_PIE_LDFLAGS :=
|
NO_PIE_LDFLAGS :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Overwrite implicite makefile rules for having nice compile output
|
# Overwrite implicit makefile rules for having nice compile output
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
ifeq ("${C}","1")
|
ifeq ("${C}","1")
|
||||||
$(CHECKTOOL) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
$(CHECKTOOL) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||||
@@ -363,14 +378,14 @@ $(rootdir)/libzds/libzds.a: $(rootdir)/libzds
|
|||||||
$(MAKE) -C $(rootdir)/libzds/ libzds.a
|
$(MAKE) -C $(rootdir)/libzds/ libzds.a
|
||||||
.PHONY: $(rootdir)/libzds
|
.PHONY: $(rootdir)/libzds
|
||||||
|
|
||||||
$(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
|
|
||||||
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
|
|
||||||
.PHONY: $(rootdir)/libvmdump
|
|
||||||
|
|
||||||
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
||||||
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||||
.PHONY: $(rootdir)/libvmcp
|
.PHONY: $(rootdir)/libvmcp
|
||||||
|
|
||||||
|
$(rootdir)/libcpumf/libcpumf.a: $(rootdir)/libcpumf
|
||||||
|
$(MAKE) -C $(rootdir)/libcpumf/ libcpumf.a
|
||||||
|
.PHONY: $(rootdir)/libcpumf
|
||||||
|
|
||||||
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
$(rootdir)/libekmfweb/libekmfweb.so: $(rootdir)/libekmfweb
|
||||||
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
$(MAKE) -C $(rootdir)/libekmfweb/ libekmfweb.so
|
||||||
.PHONY: $(rootdir)/libekmfweb
|
.PHONY: $(rootdir)/libekmfweb
|
||||||
@@ -383,8 +398,16 @@ $(rootdir)/libkmipclient/libkmipclient.so: $(rootdir)/libkmipclient
|
|||||||
$(MAKE) -C $(rootdir)/libkmipclient/ libkmipclient.so
|
$(MAKE) -C $(rootdir)/libkmipclient/ libkmipclient.so
|
||||||
.PHONY: $(rootdir)/libkmipclient
|
.PHONY: $(rootdir)/libkmipclient
|
||||||
|
|
||||||
$(rootdir)/zipl/boot/data.o:
|
$(rootdir)/libap/libap.a: $(rootdir)/libap
|
||||||
$(MAKE) -C $(rootdir)/zipl/boot/ data.o
|
$(MAKE) -C $(rootdir)/libap/ libap.a
|
||||||
|
.PHONY: $(rootdir)/libap
|
||||||
|
|
||||||
|
$(rootdir)/libpv/libpv.a: $(rootdir)/libpv
|
||||||
|
$(MAKE) -C $(rootdir)/libpv libpv.a
|
||||||
|
.PHONY: $(rootdir)/libpv
|
||||||
|
|
||||||
|
$(rootdir)/zipl/boot/.loaders:
|
||||||
|
$(MAKE) -C $(rootdir)/zipl/boot/ .loaders
|
||||||
|
|
||||||
install_dirs:
|
install_dirs:
|
||||||
for dir in $(INSTDIRS); do \
|
for dir in $(INSTDIRS); do \
|
||||||
@@ -409,4 +432,3 @@ clean_dep:
|
|||||||
|
|
||||||
clean: clean_echo clean_gcov clean_dep
|
clean: clean_echo clean_gcov clean_dep
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,28 @@
|
|||||||
include ../common.mak
|
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_CPPFLAGS += -DVERSION=$(VERSION)
|
||||||
|
|
||||||
all: cpacfstats cpacfstatsd
|
all: check_dep cpacfstats cpacfstatsd
|
||||||
|
|
||||||
cpacfstatsd: cpacfstatsd.o stats_sock.o perf_crypto.o
|
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
|
cpacfstats: cpacfstats.o stats_sock.o
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
@@ -16,6 +33,8 @@ install: all
|
|||||||
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -m 644 cpacfstatsd.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
$(INSTALL) -m 644 cpacfstats.1 $(DESTDIR)$(MANDIR)/man1
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o *~ cpacfstatsd cpacfstats
|
rm -f *.o *~ cpacfstatsd cpacfstats
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
.\" cpacfstats.1
|
.\" cpacfstats.1
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright IBM Corp. 2015, 2020
|
.\" Copyright IBM Corp. 2015, 2022
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
@@ -32,7 +32,9 @@ cpacfstats \- enable, disable and display CPACF statistical data
|
|||||||
.RB ]
|
.RB ]
|
||||||
.RB [ \-p | \-\-print
|
.RB [ \-p | \-\-print
|
||||||
.I counter
|
.I counter
|
||||||
|
.RB [ \-n | \-\-nonzero]
|
||||||
.RB ]
|
.RB ]
|
||||||
|
.RB [ \-j | \-\-json ]
|
||||||
.
|
.
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The cpacfstats client application interacts with the cpacfstatsd daemon and
|
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 activities of the system. There is a slight performance penalty with
|
||||||
CPACF counters enabled.
|
CPACF counters enabled.
|
||||||
|
|
||||||
Note: All cryptographic counters are bound to physical CPUs. If you use
|
CPACF activity counters come in two flavors: CPU-MF and PAI. CPU-MF
|
||||||
dedicated CPUs for your LPAR, you obtain only your CPACF activities. If
|
counters are only available on LPARs and have to be authorized. If
|
||||||
your CPUs are shared with other LPARs, their cryptographic activities might
|
they are available, the counters
|
||||||
distort the results. CPACF performance counters are available on LPARs
|
.B des,
|
||||||
only. For security reasons only members of the group \fIcpacfstats\fR are
|
.B aes,
|
||||||
allowed to run the cpacfstats client application.
|
.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:
|
Example usage scenario:
|
||||||
.P
|
.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
|
\fBecc\fR, or \fBall\fR. If the counter argument is omitted, all
|
||||||
performance counters are reset to 0.
|
performance counters are reset to 0.
|
||||||
.TP
|
.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
|
Display the value of one or all CPACF performance counters. The
|
||||||
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
|
optional counter argument can be one of: \fBdes\fR, \fBaes\fR,
|
||||||
\fBsha\fR, \fBprng\fR, \fBecc\fR, or \fBall\fR. If the counter
|
\fBsha\fR, \fBprng\fR, \fBecc\fR, \fBpai_user\fR, \fBpai_kernel\fR, or
|
||||||
argument is omitted or if there is no argument, all performance
|
\fBall\fR. If the counter argument is omitted or if there is no
|
||||||
counters are displayed.
|
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
|
.TP
|
||||||
The default command is --print all.
|
The default command is --print all.
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* cpacfstats client implementation
|
* 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
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -39,17 +39,187 @@ static const char *const usage =
|
|||||||
"\t-d, --disable [counter] Disable one or all counters\n"
|
"\t-d, --disable [counter] Disable one or all counters\n"
|
||||||
"\t-r, --reset [counter] Reset one or all counter values\n"
|
"\t-r, --reset [counter] Reset one or all counter values\n"
|
||||||
"\t-p, --print [counter] Print 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[] = {
|
static const char *const counter_str[] = {
|
||||||
[DES_FUNCTIONS] = "des",
|
[DES_FUNCTIONS] = "des",
|
||||||
[AES_FUNCTIONS] = "aes",
|
[AES_FUNCTIONS] = "aes",
|
||||||
[SHA_FUNCTIONS] = "sha",
|
[SHA_FUNCTIONS] = "sha",
|
||||||
[PRNG_FUNCTIONS] = "rng",
|
[PRNG_FUNCTIONS] = "rng",
|
||||||
[ECC_FUNCTIONS] = "ecc",
|
[ECC_FUNCTIONS] = "ecc",
|
||||||
[ALL_COUNTER] = "all"
|
[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)
|
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_ctr = ctr;
|
||||||
m.query.m_cmd = cmd;
|
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;
|
struct msg m;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = recv_msg(s, &m);
|
rc = recv_msg(s, &m, 0);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (m.head.m_ver != VERSION) {
|
if (m.head.m_ver != VERSION) {
|
||||||
eprint("Received msg with wrong version %d != %d\n",
|
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",
|
printf(" %s counter: error state %d\n",
|
||||||
counter_str[ctr], state);
|
counter_str[ctr], state);
|
||||||
else if (state == DISABLED)
|
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, ...)
|
int eprint(const char *format, ...)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@@ -128,7 +444,7 @@ int main(int argc, char *argv[])
|
|||||||
{
|
{
|
||||||
enum ctr_e ctr = ALL_COUNTER;
|
enum ctr_e ctr = ALL_COUNTER;
|
||||||
enum cmd_e cmd = PRINT;
|
enum cmd_e cmd = PRINT;
|
||||||
int i, j, s, state;
|
int i, j, s, state, num, json = 0;
|
||||||
uint64_t value;
|
uint64_t value;
|
||||||
|
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
@@ -140,98 +456,108 @@ int main(int argc, char *argv[])
|
|||||||
{ "disable", 0, NULL, 'd' },
|
{ "disable", 0, NULL, 'd' },
|
||||||
{ "reset", 0, NULL, 'r' },
|
{ "reset", 0, NULL, 'r' },
|
||||||
{ "print", 0, NULL, 'p' },
|
{ "print", 0, NULL, 'p' },
|
||||||
|
{ "nonzero", 0, NULL, 'n' },
|
||||||
|
{ "json", 0, NULL, 'j' },
|
||||||
{ NULL, 0, NULL, 0 } };
|
{ NULL, 0, NULL, 0 } };
|
||||||
while (1) {
|
while (1) {
|
||||||
opt = getopt_long(argc, argv,
|
opt = getopt_long(argc, argv,
|
||||||
"hvedrp", long_opts, &idx);
|
"hvedrpnj", long_opts, &idx);
|
||||||
if (opt == -1)
|
if (opt == -1)
|
||||||
break; /* no more arguments */
|
break; /* no more arguments */
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf(usage, name);
|
printf(usage, name);
|
||||||
exit(0);
|
return 0;
|
||||||
break;
|
|
||||||
case 'v':
|
case 'v':
|
||||||
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
|
printf("%s: Linux on System z CPACF Crypto Activity Counters Client\n"
|
||||||
"Version %s\n%s\n",
|
"Version %s\n%s\n",
|
||||||
name, RELEASE_STRING, COPYRIGHT);
|
name, RELEASE_STRING, COPYRIGHT);
|
||||||
exit(0);
|
return 0;
|
||||||
break;
|
|
||||||
case 'e':
|
case 'e':
|
||||||
cmd = ENABLE;
|
cmd = ENABLE;
|
||||||
|
json = 0;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
cmd = DISABLE;
|
cmd = DISABLE;
|
||||||
|
json = 0;
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
cmd = RESET;
|
cmd = RESET;
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
cmd = PRINT;
|
cmd = PRINT;
|
||||||
|
json = 0;
|
||||||
|
break;
|
||||||
|
case 'n':
|
||||||
|
paiprintnonzero = 1;
|
||||||
|
break;
|
||||||
|
case 'j':
|
||||||
|
cmd = PRINT;
|
||||||
|
json = 1;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
eprint("Invalid argument, try -h or --help for more information\n");
|
eprint("Invalid argument, try -h or --help for more information\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* there may be an optional counter argument */
|
/* there may be an optional counter argument */
|
||||||
if (optind > 0 && optind < argc) {
|
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)
|
if (strcmp(argv[optind], counter_str[i]) == 0)
|
||||||
break;
|
break;
|
||||||
if (i > ALL_COUNTER) {
|
if (i >= NUM_COUNTER) {
|
||||||
eprint("Unknown counter '%s'\n", argv[optind]);
|
eprint("Unknown counter '%s'\n", argv[optind]);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
ctr = (enum ctr_e) i;
|
ctr = (enum ctr_e) i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (json)
|
||||||
|
ctr = ALL_COUNTER;
|
||||||
|
|
||||||
/* try to open and connect socket to the cpacfstatsd daemon */
|
/* try to open and connect socket to the cpacfstatsd daemon */
|
||||||
s = open_socket(CLIENT);
|
s = open_socket(CLIENT);
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
eprint("Can't connect to daemon\n");
|
eprint("Can't connect to daemon\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* send query */
|
/* send query */
|
||||||
if (send_query(s, cmd, ctr) != 0) {
|
if (send_query(s, cmd, ctr) != 0) {
|
||||||
eprint("Error on sending query message to daemon\n");
|
eprint("Error on sending query message to daemon\n");
|
||||||
close(s);
|
close(s);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (i = 0; i < ALL_COUNTER; i++) {
|
/* The -1 is for ALL_COUNTER which is not sent, +1 for
|
||||||
/* receive answer */
|
* hotplug state. */
|
||||||
if (recv_answer(s, &j, &state, &value) != 0) {
|
num = NUM_COUNTER - 1 + 1;
|
||||||
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);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
|
/* +1 for hotplug state */
|
||||||
|
num = 1 + 1;
|
||||||
|
}
|
||||||
|
if (json)
|
||||||
|
putchar('[');
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
/* receive answer */
|
/* receive answer */
|
||||||
if (recv_answer(s, &j, &state, &value) != 0) {
|
if (recv_answer(s, &j, &state, &value) != 0) {
|
||||||
eprint("Error on receiving answer message from daemon\n");
|
eprint("Error on receiving answer message from daemon\n");
|
||||||
close(s);
|
return EXIT_FAILURE;
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
if (state < 0) {
|
if (state < 0) {
|
||||||
eprint("Received bad status code %d from daemon\n",
|
eprint("Received bad status code %d from daemon\n",
|
||||||
state);
|
state);
|
||||||
close(s);
|
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 connection */
|
||||||
close(s);
|
close(s);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* common function prototypes and definitions
|
* 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
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -14,13 +14,27 @@
|
|||||||
|
|
||||||
#include "lib/zt_common.h"
|
#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, ...);
|
int eprint(const char *format, ...);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Counter names
|
* 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 {
|
enum ctr_e {
|
||||||
DES_FUNCTIONS = 0,
|
DES_FUNCTIONS = 0,
|
||||||
@@ -28,7 +42,11 @@ enum ctr_e {
|
|||||||
SHA_FUNCTIONS,
|
SHA_FUNCTIONS,
|
||||||
PRNG_FUNCTIONS,
|
PRNG_FUNCTIONS,
|
||||||
ECC_FUNCTIONS,
|
ECC_FUNCTIONS,
|
||||||
ALL_COUNTER
|
ALL_COUNTER,
|
||||||
|
PAI_USER,
|
||||||
|
PAI_KERNEL,
|
||||||
|
NUM_COUNTER,
|
||||||
|
HOTPLUG_DETECTED = 0xffff
|
||||||
};
|
};
|
||||||
|
|
||||||
enum type_e {
|
enum type_e {
|
||||||
@@ -50,7 +68,7 @@ enum state_e {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* query send from clent to daemon
|
* query send from client to daemon
|
||||||
* Consist of:
|
* Consist of:
|
||||||
* enum counter
|
* enum counter
|
||||||
* enum command
|
* enum command
|
||||||
@@ -63,7 +81,7 @@ struct msg_query {
|
|||||||
/*
|
/*
|
||||||
* answer send from daemon to client
|
* answer send from daemon to client
|
||||||
* Consist of:
|
* 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
|
* status code: < 0 error, 0 disabled, > 0 enabled
|
||||||
* counter value
|
* counter value
|
||||||
*/
|
*/
|
||||||
@@ -99,17 +117,20 @@ struct msg {
|
|||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
int open_socket(int mode);
|
int open_socket(int mode);
|
||||||
int send_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 recv_msg(int sfd, struct msg *m, int timeout);
|
||||||
|
|
||||||
/* perf_crypto.c */
|
/* perf_crypto.c */
|
||||||
|
|
||||||
int perf_init(void);
|
int perf_init(void);
|
||||||
|
void perf_stop(void);
|
||||||
void perf_close(void);
|
void perf_close(void);
|
||||||
int perf_enable_ctr(enum ctr_e ctr);
|
int perf_enable_ctr(enum ctr_e ctr);
|
||||||
int perf_disable_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_read_ctr(enum ctr_e ctr, uint64_t *value);
|
||||||
int perf_ecc_supported(void);
|
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
|
#endif
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* cpacfstatsd daemon implementation
|
* 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
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
#include "cpacfstats.h"
|
#include "cpacfstats.h"
|
||||||
|
|
||||||
|
static volatile int stopsig;
|
||||||
|
|
||||||
static const char *const name = "cpacfstatsd";
|
static const char *const name = "cpacfstatsd";
|
||||||
|
|
||||||
@@ -43,15 +44,12 @@ static const char *const usage =
|
|||||||
|
|
||||||
static int daemonized;
|
static int daemonized;
|
||||||
|
|
||||||
static int ctr_state[ALL_COUNTER];
|
|
||||||
|
|
||||||
|
|
||||||
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
static int recv_query(int s, enum ctr_e *ctr, enum cmd_e *cmd)
|
||||||
{
|
{
|
||||||
struct msg m;
|
struct msg m;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = recv_msg(s, &m);
|
rc = recv_msg(s, &m, DEFAULT_RECV_TIMEOUT);
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
if (m.head.m_ver != VERSION) {
|
if (m.head.m_ver != VERSION) {
|
||||||
eprint("Received msg with wrong version %d != %d\n",
|
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_state = state;
|
||||||
m.answer.m_value = value;
|
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)
|
static int do_enable(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
uint64_t value;
|
uint64_t value = 0;
|
||||||
int i, rc = 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 (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == DISABLED) {
|
state = perf_ctr_state(i);
|
||||||
|
if (state == DISABLED) {
|
||||||
rc = perf_enable_ctr(i);
|
rc = perf_enable_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ctr_state[i] = ENABLED;
|
state = ENABLED;
|
||||||
}
|
}
|
||||||
if (ctr_state[i] == UNSUPPORTED) {
|
if (state != UNSUPPORTED) {
|
||||||
send_answer(s, i, UNSUPPORTED, 0);
|
|
||||||
} else {
|
|
||||||
rc = perf_read_ctr(i, &value);
|
rc = perf_read_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
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;
|
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)
|
static int do_disable(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
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 (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
if (perf_ctr_state(i) == ENABLED) {
|
||||||
rc = perf_disable_ctr(i);
|
rc = perf_disable_ctr(i);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_reset(int s, enum ctr_e ctr)
|
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 (i == (int) ctr || ctr == ALL_COUNTER) {
|
||||||
if (ctr_state[i] == ENABLED) {
|
state = perf_ctr_state(i);
|
||||||
rc = perf_reset_ctr(i);
|
if (state == ENABLED) {
|
||||||
|
rc = perf_reset_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int do_print(int s, enum ctr_e ctr)
|
static int do_print(int s, enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int i, rc = 0;
|
int i, rc = 0, state;
|
||||||
uint64_t value;
|
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 (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);
|
rc = perf_read_ctr(i, &value);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
send_answer(s, i, rc, 0);
|
send_answer(s, i, rc, 0);
|
||||||
break;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -324,18 +389,8 @@ static void remove_pidfile(void)
|
|||||||
|
|
||||||
void signalhandler(int sig)
|
void signalhandler(int sig)
|
||||||
{
|
{
|
||||||
if (sig == SIGTERM)
|
perf_stop();
|
||||||
eprint("Caught signal SIGTERM, terminating...\n");
|
stopsig = sig;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -381,7 +436,7 @@ int main(int argc, char *argv[])
|
|||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'h':
|
case 'h':
|
||||||
printf(usage, name);
|
printf(usage, name);
|
||||||
exit(0);
|
return 0;
|
||||||
case 'f':
|
case 'f':
|
||||||
foreground = 1;
|
foreground = 1;
|
||||||
break;
|
break;
|
||||||
@@ -389,40 +444,37 @@ int main(int argc, char *argv[])
|
|||||||
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
|
printf("%s: Linux on System z CPACF Crypto Activity Counters Daemon\n"
|
||||||
"Version %s\n%s\n",
|
"Version %s\n%s\n",
|
||||||
name, RELEASE_STRING, COPYRIGHT);
|
name, RELEASE_STRING, COPYRIGHT);
|
||||||
exit(0);
|
return 0;
|
||||||
default:
|
default:
|
||||||
printf("%s: Invalid argument, try -h or --help for more information\n",
|
printf("%s: Invalid argument, try -h or --help for more information\n",
|
||||||
name);
|
name);
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_pidfile() != 0) {
|
if (check_pidfile() != 0) {
|
||||||
eprint("Stalled pid file or daemon allready running, terminating\n");
|
eprint("Stalled pid file or daemon allready running, terminating\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foreground) {
|
if (!foreground) {
|
||||||
if (become_daemon() != 0) {
|
if (become_daemon() != 0) {
|
||||||
eprint("Couldn't daemonize\n");
|
eprint("Couldn't daemonize\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (perf_init() != 0) {
|
if (perf_init() != 0) {
|
||||||
eprint("Couldn't initialize perf lib\n");
|
eprint("Couldn't initialize perf lib\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
atexit(perf_close);
|
atexit(perf_close);
|
||||||
|
|
||||||
if (!perf_ecc_supported())
|
|
||||||
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
|
||||||
|
|
||||||
sfd = open_socket(SERVER);
|
sfd = open_socket(SERVER);
|
||||||
if (sfd < 0) {
|
if (sfd < 0) {
|
||||||
eprint("Couldn't initialize server socket\n");
|
eprint("Couldn't initialize server socket\n");
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
atexit(remove_sock);
|
atexit(remove_sock);
|
||||||
|
|
||||||
@@ -432,17 +484,19 @@ int main(int argc, char *argv[])
|
|||||||
if (sigaction(SIGINT, &act, 0) != 0) {
|
if (sigaction(SIGINT, &act, 0) != 0) {
|
||||||
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
|
eprint("Couldn't establish signal handler for SIGINT, errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (sigaction(SIGTERM, &act, 0) != 0) {
|
if (sigaction(SIGTERM, &act, 0) != 0) {
|
||||||
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
|
eprint("Couldn't establish signal handler for SIGTERM, errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
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");
|
eprint("Running\n");
|
||||||
|
|
||||||
while (1) {
|
while (!stopsig) {
|
||||||
enum ctr_e ctr;
|
enum ctr_e ctr;
|
||||||
enum cmd_e cmd;
|
enum cmd_e cmd;
|
||||||
int s;
|
int s;
|
||||||
@@ -453,7 +507,7 @@ int main(int argc, char *argv[])
|
|||||||
continue;
|
continue;
|
||||||
eprint("Accept() failure, errno=%d [%s]\n",
|
eprint("Accept() failure, errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
exit(1);
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = recv_query(s, &ctr, &cmd);
|
rc = recv_query(s, &ctr, &cmd);
|
||||||
@@ -480,5 +534,13 @@ cleanup:
|
|||||||
close(s);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* low level perf functions
|
* 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
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -16,14 +16,21 @@
|
|||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <linux/perf_event.h>
|
#include <linux/perf_event.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <signal.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <libudev.h>
|
||||||
|
|
||||||
#include "cpacfstats.h"
|
#include "cpacfstats.h"
|
||||||
|
#include "../include/lib/zt_common.h"
|
||||||
|
|
||||||
/* correlation between counter and perf counter string */
|
/* correlation between counter and perf counter string */
|
||||||
static const struct {
|
static const struct {
|
||||||
@@ -38,25 +45,83 @@ static const struct {
|
|||||||
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
{"cpum_cf", "ECC_FUNCTION_COUNT", ECC_FUNCTIONS}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
static struct pmf_data {
|
||||||
* We need one filedescriptor per CPU per counter.
|
int pmutype;
|
||||||
* So perf_init builds this:
|
int eventid;
|
||||||
*
|
} pmf_counter_data[ALL_COUNTER];
|
||||||
* 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 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,
|
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
|
||||||
int cpu, int group_fd, unsigned long flags)
|
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);
|
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)
|
const char *pmu, const char *event)
|
||||||
{
|
{
|
||||||
FILE *f;
|
FILE *f;
|
||||||
int eventid;
|
|
||||||
int pmutype;
|
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
|
|
||||||
if (snprintf(buf, PATH_MAX, "/sys/bus/event_source/devices/%s/events/%s",
|
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));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fscanf(f, "event=0x%x\n", &eventid) != 1) {
|
if (fscanf(f, "event=0x%x\n", eventid) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
eprint("Event file %s has invalid format\n", buf);
|
eprint("Event file %s has invalid format\n", buf);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -121,21 +217,257 @@ static int perf_event_encode(struct perf_event_attr *attr,
|
|||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (fscanf(f, "%d\n", &pmutype) != 1) {
|
if (fscanf(f, "%d\n", pmutype) != 1) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
eprint("Type file %s has invalid format\n", buf);
|
eprint("Type file %s has invalid format\n", buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
attr->type = pmutype;
|
|
||||||
attr->config = eventid;
|
|
||||||
return 0;
|
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 perf_init(void)
|
||||||
{
|
{
|
||||||
int i, cpus, ctr, cpu, *fds;
|
int ecc_supported, i, num;
|
||||||
|
unsigned long maxfd;
|
||||||
memset(ctr_fds, 0, sizeof(ctr_fds));
|
struct rlimit rlim;
|
||||||
|
FILE *f;
|
||||||
|
|
||||||
/* initialize performance monitoring library */
|
/* initialize performance monitoring library */
|
||||||
if (!perf_supported()) {
|
if (!perf_supported()) {
|
||||||
@@ -143,99 +475,105 @@ int perf_init(void)
|
|||||||
return -1;
|
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 */
|
/* Check if ECC is supported on current hardware */
|
||||||
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
ecc_supported = perf_counter_supported("cpum_cf", "ECC_FUNCTION_COUNT");
|
||||||
|
|
||||||
/* get number of logical processors */
|
if (!cpumf_authorized()) {
|
||||||
cpus = sysconf(_SC_NPROCESSORS_ONLN);
|
for (i = 0; i < ALL_COUNTER; ++i)
|
||||||
|
ctr_state[i] = UNSUPPORTED;
|
||||||
/* for each counter */
|
num -= ALL_COUNTER;
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
} else if (!ecc_supported) {
|
||||||
|
ctr_state[ECC_FUNCTIONS] = UNSUPPORTED;
|
||||||
/* Skip ECC counters completely if unsupported */
|
--num;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
void perf_close(void)
|
||||||
{
|
{
|
||||||
int ctr, *fds;
|
struct percpucounter *walk, *next;
|
||||||
|
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
pthread_kill(hotplugthread, SIGINT);
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
pthread_join(hotplugthread, NULL);
|
||||||
close(*fds);
|
walk = root;
|
||||||
*fds = 0;
|
while (walk) {
|
||||||
}
|
next = walk->next;
|
||||||
free(ctr_fds[ctr]);
|
freepercpucounter(walk);
|
||||||
ctr_fds[ctr] = NULL;
|
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 perf_enable_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -243,24 +581,64 @@ int perf_enable_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_ENABLE, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_ENABLE, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_ENABLE) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
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;
|
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 perf_disable_ctr(enum ctr_e ctr)
|
||||||
{
|
{
|
||||||
int *fds, ec, rc = 0;
|
struct percpucounter *pcpu;
|
||||||
|
int ec, rc = 0;
|
||||||
|
|
||||||
if (ctr == ALL_COUNTER) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
@@ -268,70 +646,183 @@ int perf_disable_ctr(enum ctr_e ctr)
|
|||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_DISABLE, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_DISABLE, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_DISABLE) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
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;
|
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) {
|
if (ctr == ALL_COUNTER) {
|
||||||
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
for (ctr = 0; ctr < ALL_COUNTER; ctr++) {
|
||||||
rc = perf_reset_ctr(ctr);
|
rc = perf_reset_ctr(ctr, value);
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (ctr < ALL_COUNTER) {
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = ioctl(*fds, PERF_EVENT_IOC_RESET, 0);
|
ec = ioctl(pcpu->ctr_fds[ctr], PERF_EVENT_IOC_RESET, 0);
|
||||||
if (ec < 0) {
|
if (ec < 0) {
|
||||||
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
eprint("Ioctl(PERF_EVENT_IOC_RESET) failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
rc = -1;
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int perf_read_ctr(enum ctr_e ctr, uint64_t *value)
|
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;
|
uint64_t val;
|
||||||
|
|
||||||
if (!value)
|
if (!value)
|
||||||
return -1;
|
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;
|
*value = 0;
|
||||||
|
|
||||||
for (fds = ctr_fds[ctr]; fds && *fds; fds++) {
|
foreachcpu(pcpu) {
|
||||||
ec = read(*fds, &val, sizeof(val));
|
ec = read(pcpu->ctr_fds[ctr], &val, sizeof(val));
|
||||||
if (ec != sizeof(val)) {
|
if (ec != sizeof(val)) {
|
||||||
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
eprint("Read() on perf file descriptor failed with errno=%d [%s]\n",
|
||||||
errno, strerror(errno));
|
errno, strerror(errno));
|
||||||
|
rc = -1;
|
||||||
} else {
|
} else {
|
||||||
*value += val;
|
*value += val;
|
||||||
rc = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
endforeachcpu();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int perf_ecc_supported(void)
|
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
|
* 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
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <grp.h>
|
#include <grp.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/socket.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;
|
int n, len;
|
||||||
|
|
||||||
@@ -166,7 +211,7 @@ int send_msg(int sfd, struct msg *m)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
n = __write(sfd, m, len);
|
n = timeout ? __timedwrite(sfd, m, len, timeout) : __write(sfd, m, len);
|
||||||
if (n != len) {
|
if (n != len) {
|
||||||
eprint("Write() error: write()=%d expected %d, errno=%d [%s]\n",
|
eprint("Write() error: write()=%d expected %d, errno=%d [%s]\n",
|
||||||
n, len, errno, strerror(errno));
|
n, len, errno, strerror(errno));
|
||||||
@@ -176,12 +221,12 @@ int send_msg(int sfd, struct msg *m)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int recv_msg(int sfd, struct msg *m)
|
int recv_msg(int sfd, struct msg *m, int timeout)
|
||||||
{
|
{
|
||||||
int n, len;
|
int n, len;
|
||||||
|
|
||||||
len = sizeof(m->head);
|
len = sizeof(m->head);
|
||||||
n = __read(sfd, m, len);
|
n = timeout ? __timedread(sfd, m, len, timeout) : __read(sfd, m, len);
|
||||||
if (n != len) {
|
if (n != len) {
|
||||||
eprint("Recv() error: read()=%d expected %d, errno=%d [%s]\n",
|
eprint("Recv() error: read()=%d expected %d, errno=%d [%s]\n",
|
||||||
n, len, errno, strerror(errno));
|
n, len, errno, strerror(errno));
|
||||||
@@ -200,7 +245,8 @@ int recv_msg(int sfd, struct msg *m)
|
|||||||
return -1;
|
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) {
|
if (n != len) {
|
||||||
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
eprint("Recv() error: recv()=%d expected %d, errno=%d [%s]\n",
|
||||||
n, len, errno, strerror(errno));
|
n, len, errno, strerror(errno));
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
BIN_FILES = lscpumf chcpumf lshwc
|
BIN_FILES = lscpumf chcpumf lshwc pai
|
||||||
MAN_FILES = lscpumf.1 chcpumf.8 lshwc.1
|
MAN_FILES = lscpumf.8 chcpumf.8 lshwc.8 pai.8
|
||||||
|
|
||||||
all: $(BIN_FILES)
|
all: $(BIN_FILES)
|
||||||
|
|
||||||
libs = $(rootdir)/libutil/libutil.a
|
libs = $(rootdir)/libcpumf/libcpumf.a $(rootdir)/libutil/libutil.a
|
||||||
|
|
||||||
lscpumf: lscpumf.o $(libs)
|
lscpumf: lscpumf.o $(libs)
|
||||||
chcpumf: chcpumf.o $(libs)
|
chcpumf: chcpumf.o $(libs)
|
||||||
lshwc: lshwc.o $(libs)
|
lshwc: lshwc.o $(libs)
|
||||||
|
pai: pai.o $(libs)
|
||||||
|
|
||||||
install: all install-man
|
install: all install-man
|
||||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||||
@@ -22,8 +23,8 @@ clean:
|
|||||||
|
|
||||||
install-man:
|
install-man:
|
||||||
for man in $(MAN_FILES); do \
|
for man in $(MAN_FILES); do \
|
||||||
msection=`echo $$man |sed 's/.*\.\([1-9]\)$$/man\1/'` ; \
|
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 man/$$man \
|
||||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 -D man/$$man $(DESTDIR)$(MANDIR)/$$msection/$$man ; \
|
$(DESTDIR)$(MANDIR)/man8 ; \
|
||||||
done
|
done
|
||||||
|
|
||||||
.PHONY: all install clean
|
.PHONY: all install clean
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* chcpumf - Change CPU Measurement Facility Characteristics
|
* chcpumf - Change CPU Measurement Facility Characteristics
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2020
|
* Copyright IBM Corp. 2020, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -20,9 +20,9 @@
|
|||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
|
||||||
#include "defines.h"
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
static int verbose;
|
static unsigned int verbose;
|
||||||
static unsigned long min_sdb, max_sdb;
|
static unsigned long min_sdb, max_sdb;
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
@@ -85,55 +85,30 @@ static long parse_buffersize(char *string)
|
|||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_sfb(unsigned long *min, unsigned long *max)
|
static int write_sfb(unsigned int min, unsigned int max)
|
||||||
{
|
|
||||||
unsigned long cur_min_sdb, cur_max_sdb;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
if (geteuid())
|
|
||||||
errx(EXIT_FAILURE, "Must run as root");
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "r");
|
|
||||||
if (!fp)
|
|
||||||
err(EXIT_FAILURE, PERF_SFB_SIZE);
|
|
||||||
if (fscanf(fp, "%ld,%ld", &cur_min_sdb, &cur_max_sdb) != 2) {
|
|
||||||
fclose(fp);
|
|
||||||
errx(EXIT_FAILURE, "Can not parse file " PERF_SFB_SIZE);
|
|
||||||
} else {
|
|
||||||
if (*min == 0)
|
|
||||||
*min = cur_min_sdb;
|
|
||||||
if (*max == 0)
|
|
||||||
*max = cur_max_sdb;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
if (*min >= *max)
|
|
||||||
errx(EXIT_FAILURE,
|
|
||||||
"The specified maximum must be greater than the minimum");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int write_sfb(unsigned long min, unsigned long max)
|
|
||||||
{
|
{
|
||||||
int rc = EXIT_SUCCESS;
|
int rc = EXIT_SUCCESS;
|
||||||
char text[64];
|
char text[64];
|
||||||
size_t len;
|
size_t len;
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "w");
|
fp = fopen(S390_CPUMSF_BUFFERSZ, "w");
|
||||||
if (!fp)
|
if (!fp)
|
||||||
err(EXIT_FAILURE, PERF_SFB_SIZE);
|
err(EXIT_FAILURE, S390_CPUMSF_BUFFERSZ);
|
||||||
snprintf(text, sizeof text, "%ld,%ld", min, max);
|
snprintf(text, sizeof(text), "%u,%u", min, max);
|
||||||
len = strlen(text) + 1;
|
len = strlen(text) + 1;
|
||||||
if (fwrite(text, 1, len, fp) != len) {
|
if (fwrite(text, 1, len, fp) != len) {
|
||||||
warn(PERF_SFB_SIZE);
|
warn(S390_CPUMSF_BUFFERSZ);
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (fclose(fp)) {
|
if (fclose(fp)) {
|
||||||
warn(PERF_SFB_SIZE);
|
warn(S390_CPUMSF_BUFFERSZ);
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
if (verbose && rc != EXIT_FAILURE)
|
if (verbose && rc != EXIT_FAILURE)
|
||||||
warnx("Sampling buffer sizes:\n"
|
warnx("Sampling buffer sizes:\n"
|
||||||
" Minimum:%7ld sample-data-blocks\n"
|
" Minimum:%7d sample-data-blocks\n"
|
||||||
" Maximum:%7ld sample-data-blocks\n",
|
" Maximum:%7d sample-data-blocks\n",
|
||||||
min, max);
|
min, max);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -183,15 +158,21 @@ static int parse_args(int argc, char **argv)
|
|||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct stat sbuf;
|
unsigned long my_min, my_max;
|
||||||
|
|
||||||
util_prg_init(&prg);
|
util_prg_init(&prg);
|
||||||
util_opt_init(opt_vec, NULL);
|
util_opt_init(opt_vec, NULL);
|
||||||
|
|
||||||
parse_args(argc, argv);
|
parse_args(argc, argv);
|
||||||
if (stat(PERF_PATH PERF_SF, &sbuf))
|
if (geteuid())
|
||||||
|
errx(EXIT_FAILURE, "Must run as root");
|
||||||
|
if (!libcpumf_have_sfb())
|
||||||
errx(EXIT_FAILURE,
|
errx(EXIT_FAILURE,
|
||||||
"No CPU-measurement sampling facility detected");
|
"No CPU-measurement sampling facility detected");
|
||||||
read_sfb(&min_sdb, &max_sdb);
|
libcpumf_sfb_info(&my_min, &my_max);
|
||||||
|
if (!min_sdb)
|
||||||
|
min_sdb = my_min;
|
||||||
|
if (!max_sdb)
|
||||||
|
max_sdb = my_max;
|
||||||
return write_sfb(min_sdb, max_sdb);
|
return write_sfb(min_sdb, max_sdb);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/*
|
|
||||||
* Defines for CPU Measurement Facility Characteristics
|
|
||||||
*
|
|
||||||
* Copyright IBM Corp. 2020
|
|
||||||
*
|
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DEFINES_H
|
|
||||||
#define DEFINES_H
|
|
||||||
|
|
||||||
#define PERF_SFB_SIZE "/sys/module/kernel/parameters/cpum_sfb_size"
|
|
||||||
#define PERF_PATH "/sys/bus/event_source/devices/"
|
|
||||||
#define PERF_SF "cpum_sf"
|
|
||||||
#define PERF_CF "cpum_cf"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
786
cpumf/lscpumf.c
786
cpumf/lscpumf.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* lscpumf - Show CPU Measurement Facility Characteristics
|
* lscpumf - Show CPU Measurement Facility Characteristics
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2020
|
* Copyright IBM Corp. 2020, 2022
|
||||||
*
|
*
|
||||||
* s390-tools is free software; you can redistribute it and/or modify
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the MIT license. See LICENSE for details.
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
@@ -26,9 +26,10 @@
|
|||||||
#include "lib/util_arch.h"
|
#include "lib/util_arch.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
|
|
||||||
#include "defines.h"
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
#define ACTION_NONE 0
|
#define ACTION_NONE 0
|
||||||
#define ACTION_INFO 1
|
#define ACTION_INFO 1
|
||||||
@@ -45,9 +46,6 @@ static bool actions[ACTION_SAMPLE + 1]; /* Specified command line options */
|
|||||||
#define PER_SDBT_SIZE 511
|
#define PER_SDBT_SIZE 511
|
||||||
|
|
||||||
/* File names to read data from */
|
/* File names to read data from */
|
||||||
#define SERVICELEVEL "/proc/service_levels"
|
|
||||||
#define CPUMF_CF_TYPE "/sys/devices/cpum_cf/type"
|
|
||||||
#define CPUMF_SF_TYPE "/sys/devices/cpum_sf/type"
|
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("OPTIONS"),
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
@@ -92,19 +90,18 @@ static char prefix[32]; /* Counter prefix */
|
|||||||
static bool show_names;
|
static bool show_names;
|
||||||
|
|
||||||
static struct cpumf_info {
|
static struct cpumf_info {
|
||||||
unsigned int first_vn; /* Counter facility first version nr */
|
int first_vn; /* Counter facility first version nr */
|
||||||
unsigned int second_vn; /* Counter facility second version nr */
|
int second_vn; /* Counter facility second version nr */
|
||||||
unsigned int authorization; /* Counter facility authorization */
|
int authorization; /* Counter facility authorization */
|
||||||
float version;
|
|
||||||
unsigned long min_rate; /* Minimum sampling rate */
|
unsigned long min_rate; /* Minimum sampling rate */
|
||||||
unsigned long max_rate; /* Maximum sampling rate */
|
unsigned long max_rate; /* Maximum sampling rate */
|
||||||
unsigned long cpu_speed; /* CPU Cycles per micro second */
|
unsigned long cpu_speed; /* CPU Cycles per micro second */
|
||||||
unsigned int basic_sample_sz; /* # of Bytes per basic sample */
|
int basic_sample_sz; /* # of Bytes per basic sample */
|
||||||
unsigned int diag_sample_sz; /* # of bytes per diagnostic sample */
|
int diag_sample_sz; /* # of bytes per diagnostic sample */
|
||||||
unsigned char have_counter; /* CPUM counter facility detected */
|
bool have_counter; /* CPUM counter facility detected */
|
||||||
unsigned char have_samples; /* CPUM sampling facility detected */
|
bool have_samples; /* CPUM sampling facility detected */
|
||||||
unsigned int min_sfb; /* Minimum sampling buffer size */
|
unsigned long min_sfb; /* Minimum sampling buffer size */
|
||||||
unsigned int max_sfb; /* Maximum sampling buffer size */
|
unsigned long max_sfb; /* Maximum sampling buffer size */
|
||||||
unsigned short machine_type; /* Machine Type */
|
unsigned short machine_type; /* Machine Type */
|
||||||
} cpumf;
|
} cpumf;
|
||||||
|
|
||||||
@@ -2559,32 +2556,598 @@ static struct counters cpumcf_z15_counters[] = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct counters cpumcf_z16_counters[] = {
|
||||||
|
{
|
||||||
|
.ctrnum = 128,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "L1D_RO_EXCL_WRITES",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache where"
|
||||||
|
"\n\t\tthe line was originally in a Read-Only state in the"
|
||||||
|
"\n\t\tcache but has been updated to be in the Exclusive"
|
||||||
|
"\n\t\tstate that allows stores to the cache line.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 129,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DTLB2_WRITES",
|
||||||
|
.desc = "A translation has been written into The Translation"
|
||||||
|
"\n\t\tLookaside Buffer 2 (TLB2) and the request was made"
|
||||||
|
"\n\t\tby the Level-1 Data cache. This is a replacement"
|
||||||
|
"\n\t\tfor what was provided for the DTLB on z13 and prior"
|
||||||
|
"\n\t\tmachines.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 130,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DTLB2_MISSES",
|
||||||
|
.desc = "A TLB2 miss is in progress for a request made by"
|
||||||
|
"\n\t\tthe Level-1 Data cache. Incremented by one for"
|
||||||
|
"\n\t\tevery TLB2 miss in progress for the Level-1 Data"
|
||||||
|
"\n\t\tcache on this cycle. This is a replacement for what"
|
||||||
|
"\n\t\twas provided for the DTLB on z13 and prior"
|
||||||
|
"\n\t\tmachines.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 131,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "CRSTE_1MB_WRITES",
|
||||||
|
.desc = "A translation entry was written into the Combined"
|
||||||
|
"\n\t\tRegion and Segment Table Entry array in the Level-2"
|
||||||
|
"\n\t\tTLB for a one-megabyte page.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 132,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DTLB2_GPAGE_WRITES",
|
||||||
|
.desc = "A translation entry for a two-gigabyte page was"
|
||||||
|
"\n\t\twritten into the Level-2 TLB.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 134,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ITLB2_WRITES",
|
||||||
|
.desc = "A translation entry has been written into the"
|
||||||
|
"\n\t\tTranslation Lookaside Buffer 2 (TLB2) and the"
|
||||||
|
"\n\t\trequest was made by the instruction cache. This is"
|
||||||
|
"\n\t\ta replacement for what was provided for the ITLB on"
|
||||||
|
"\n\t\tz13 and prior machines.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 135,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ITLB2_MISSES",
|
||||||
|
.desc = "A TLB2 miss is in progress for a request made by"
|
||||||
|
"\n\t\tthe Level-1 Instruction cache. Incremented by one"
|
||||||
|
"\n\t\tfor every TLB2 miss in progress for the Level-1"
|
||||||
|
"\n\t\tInstruction cache in a cycle. This is a replacement"
|
||||||
|
"\n\t\tfor what was provided for the ITLB on z13 and prior"
|
||||||
|
"\n\t\tmachines.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 137,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TLB2_PTE_WRITES",
|
||||||
|
.desc = "A translation entry was written into the Page Table"
|
||||||
|
"\n\t\tEntry array in the Level-2 TLB.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 138,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TLB2_CRSTE_WRITES",
|
||||||
|
.desc = "Translation entries were written into the Combined"
|
||||||
|
"\n\t\tRegion and Segment Table Entry array and the Page"
|
||||||
|
"\n\t\tTable Entry array in the Level-2 TLB.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 139,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TLB2_ENGINES_BUSY",
|
||||||
|
.desc = "The number of Level-2 TLB translation engines busy"
|
||||||
|
"\n\t\tin a cycle.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 140,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TX_C_TEND",
|
||||||
|
.desc = "A TEND instruction has completed in a constrained"
|
||||||
|
"\n\t\ttransactional-execution mode.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 141,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TX_NC_TEND",
|
||||||
|
.desc = "A TEND instruction has completed in a non-"
|
||||||
|
"\n\t\tconstrained transactional-execution mode.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 143,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "L1C_TLB2_MISSES",
|
||||||
|
.desc = "Increments by one for any cycle where a level-1"
|
||||||
|
"\n\t\tcache or level-2 TLB miss is in progress.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 145,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_REQ",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestor’s Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 146,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_REQ_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestor’s Level-2 cache with"
|
||||||
|
"\n\t\tintervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 147,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_REQ_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestor’s Level-2 cache after using"
|
||||||
|
"\n\t\tchip level horizontal persistence, Chip-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 148,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_REQ_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestor’s Level-2 cache after using"
|
||||||
|
"\n\t\tdrawer level horizontal persistence, Drawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 149,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_CHIP",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 150,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_CHIP_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip Level-2 cache with intervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 151,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_CHIP_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip Level-2 cache after using chip"
|
||||||
|
"\n\t\tlevel horizontal persistence, Chip-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 152,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_CHIP_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip Level-2 cache using drawer level"
|
||||||
|
"\n\t\thorizontal persistence, Drawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 153,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_MODULE",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Module Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 154,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_DRAWER",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Drawer Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 155,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_OFF_DRAWER",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an Off-Drawer Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 156,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_CHIP_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom On-Chip memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 157,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_MODULE_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom On-Module memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 158,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_ON_DRAWER_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom On-Drawer memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 159,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DCW_OFF_DRAWER_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Data cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom Off-Drawer memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 160,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_ON_MODULE_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tInstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an On-Module Level-2"
|
||||||
|
"\n\t\tcache with intervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 161,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_ON_MODULE_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tInstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an On-Module Level-2"
|
||||||
|
"\n\t\tcache using chip horizontal persistence, Chip-HP"
|
||||||
|
"\n\t\thit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 162,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_ON_MODULE_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tInstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an On-Module Level-2"
|
||||||
|
"\n\t\tcache using drawer level horizontal persistence,"
|
||||||
|
"\n\t\tDrawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 163,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_ON_DRAWER_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tInstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an On-Drawer Level-2"
|
||||||
|
"\n\t\tcache with intervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 164,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_ON_DRAWER_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tinstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an On-Drawer Level-2"
|
||||||
|
"\n\t\tcache using chip level horizontal persistence, Chip-"
|
||||||
|
"\n\t\tHP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 165,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_ON_DRAWER_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tinstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an On-Drawer Level-2"
|
||||||
|
"\n\t\tcache using drawer level horizontal persistence,"
|
||||||
|
"\n\t\tDrawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 166,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_OFF_DRAWER_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tinstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an Off-Drawer Level-2"
|
||||||
|
"\n\t\tcache with intervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 167,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_OFF_DRAWER_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tinstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an Off-Drawer Level-2"
|
||||||
|
"\n\t\tcache using chip level horizontal persistence, Chip-"
|
||||||
|
"\n\t\tHP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 168,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "IDCW_OFF_DRAWER_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Data or Level-1"
|
||||||
|
"\n\t\tInstruction cache directory where the returned"
|
||||||
|
"\n\t\tcache line was sourced from an Off-Drawer Level-2"
|
||||||
|
"\n\t\tcache using drawer level horizontal persistence,"
|
||||||
|
"\n\t\tDrawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 169,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_REQ",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tthe requestors Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 170,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_REQ_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestors Level-2 cache with"
|
||||||
|
"\n\t\tintervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 171,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_REQ_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestors Level-2 cache using chip level"
|
||||||
|
"\n\t\thorizontal persistence, Chip-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 172,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_REQ_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom the requestor’s Level-2 cache using drawer"
|
||||||
|
"\n\t\tlevel horizontal persistence, Drawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 173,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_CHIP",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 174,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_CHIP_IV",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tan On-Chip Level-2 cache with intervention.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 175,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_CHIP_CHIP_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip Level-2 cache using chip level"
|
||||||
|
"\n\t\thorizontal persistence, Chip-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 176,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_CHIP_DRAWER_HIT",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Chip level 2 cache using drawer level"
|
||||||
|
"\n\t\thorizontal persistence, Drawer-HP hit.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 177,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_MODULE",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom an On-Module Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 178,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_DRAWER",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tan On-Drawer Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 179,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_OFF_DRAWER",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tan Off-Drawer Level-2 cache.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 180,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_CHIP_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom On-Chip memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 181,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_MODULE_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom On-Module memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 182,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_ON_DRAWER_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom On-Drawer memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 183,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "ICW_OFF_DRAWER_MEMORY",
|
||||||
|
.desc = "A directory write to the Level-1 Instruction cache"
|
||||||
|
"\n\t\tdirectory where the returned cache line was sourced"
|
||||||
|
"\n\t\tfrom Off-Drawer memory.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 224,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "BCD_DFP_EXECUTION_SLOTS",
|
||||||
|
.desc = "Count of floating point execution slots used for"
|
||||||
|
"\n\t\tfinished Binary Coded Decimal to Decimal Floating"
|
||||||
|
"\n\t\tPoint conversions. Instructions: CDZT, CXZT, CZDT,"
|
||||||
|
"\n\t\tCZXT.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 225,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "VX_BCD_EXECUTION_SLOTS",
|
||||||
|
.desc = "Count of floating point execution slots used for"
|
||||||
|
"\n\t\tfinished vector arithmetic Binary Coded Decimal"
|
||||||
|
"\n\t\tinstructions. Instructions: VAP, VSP, VMP, VMSP,"
|
||||||
|
"\n\t\tVDP, VSDP, VRP, VLIP, VSRP, VPSOP, VCP, VTP, VPKZ,"
|
||||||
|
"\n\t\tVUPKZ, VCVB, VCVBG, VCVD, VCVDG.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 226,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DECIMAL_INSTRUCTIONS",
|
||||||
|
.desc = "Decimal instruction dispatched. Instructions: CVB,"
|
||||||
|
"\n\t\tCVD, AP, CP, DP, ED, EDMK, MP, SRP, SP, ZAP.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 232,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "LAST_HOST_TRANSLATIONS",
|
||||||
|
.desc = "Last Host Translation done",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 244,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TX_NC_TABORT",
|
||||||
|
.desc = "A transaction abort has occurred in a non-"
|
||||||
|
"\n\t\tconstrained transactional-execution mode.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 245,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TX_C_TABORT_NO_SPECIAL",
|
||||||
|
.desc = "A transaction abort has occurred in a constrained"
|
||||||
|
"\n\t\ttransactional-execution mode and the CPU is not"
|
||||||
|
"\n\t\tusing any special logic to allow the transaction to"
|
||||||
|
"\n\t\tcomplete.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 246,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "TX_C_TABORT_SPECIAL",
|
||||||
|
.desc = "A transaction abort has occurred in a constrained"
|
||||||
|
"\n\t\ttransactional-execution mode and the CPU is using"
|
||||||
|
"\n\t\tspecial logic to allow the transaction to complete.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 248,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DFLT_ACCESS",
|
||||||
|
.desc = "Cycles CPU spent obtaining access to Deflate unit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 253,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DFLT_CYCLES",
|
||||||
|
.desc = "Cycles CPU is using Deflate unit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 256,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "SORTL",
|
||||||
|
.desc = "Increments by one for every SORT LISTS instruction"
|
||||||
|
"\n\t\texecuted.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 265,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DFLT_CC",
|
||||||
|
.desc = "Increments by one for every DEFLATE CONVERSION CALL"
|
||||||
|
"\n\t\tinstruction executed.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 266,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "DFLT_CCFINISH",
|
||||||
|
.desc = "Increments by one for every DEFLATE CONVERSION CALL"
|
||||||
|
"\n\t\tinstruction executed that ended in Condition Codes"
|
||||||
|
"\n\t\t0, 1 or 2.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 267,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "NNPA_INVOCATIONS",
|
||||||
|
.desc = "Increments by one for every Neural Network"
|
||||||
|
"\n\t\tProcessing Assist instruction executed.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 268,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "NNPA_COMPLETIONS",
|
||||||
|
.desc = "Increments by one for every Neural Network"
|
||||||
|
"\n\t\tProcessing Assist instruction executed that ended"
|
||||||
|
"\n\t\tin Condition Codes 0, 1 or 2.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 269,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "NNPA_WAIT_LOCK",
|
||||||
|
.desc = "Cycles CPU spent obtaining access to IBM Z"
|
||||||
|
"\n\t\tIntegrated Accelerator for AI.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 270,
|
||||||
|
.ctrset = CPUMF_CTRSET_EXTENDED,
|
||||||
|
.name = "NNPA_HOLD_LOCK",
|
||||||
|
.desc = "Cycles CPU is using IBM Z Integrated Accelerator"
|
||||||
|
"\n\t\tfor AI.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 448,
|
||||||
|
.ctrset = CPUMF_CTRSET_MT_DIAG,
|
||||||
|
.name = "MT_DIAG_CYCLES_ONE_THR_ACTIVE",
|
||||||
|
.desc = "Cycle count with one thread active",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.ctrnum = 449,
|
||||||
|
.ctrset = CPUMF_CTRSET_MT_DIAG,
|
||||||
|
.name = "MT_DIAG_CYCLES_TWO_THR_ACTIVE",
|
||||||
|
.desc = "Cycle count with two threads active",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
/* Return the type number of the CPU Measurement facility from the sysfs file.
|
/* Return the type number of the CPU Measurement facility from the sysfs file.
|
||||||
* If the type number is equal to PERF_TYPE_RAW, then the prefix is 'r' to
|
* If the type number is equal to PERF_TYPE_RAW, then the prefix is 'r' to
|
||||||
* specify the raw counter number by the perf tool.
|
* specify the raw counter number by the perf tool.
|
||||||
* If perf_pmu_register() kernel function assigned any other (higher) type
|
* If perf_pmu_register() kernel function assigned any other (higher) type
|
||||||
* number, set the prefix to <type-nr>:
|
* number, set the prefix to <type-nr>:
|
||||||
*/
|
*/
|
||||||
static int read_cpumf_type(const char *filename, const char *type)
|
static void set_prefix(int nr)
|
||||||
{
|
{
|
||||||
int nr, rc = EXIT_FAILURE;
|
if (nr == PERF_TYPE_RAW)
|
||||||
FILE *fp = fopen(filename, "r");
|
strcat(prefix, "r");
|
||||||
|
else
|
||||||
if (fp == NULL) {
|
snprintf(prefix, sizeof(prefix), "%d:", nr);
|
||||||
warnx("No CPU-measurement %s facility detected", type);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
if (fscanf(fp, "%d", &nr) != 1) {
|
|
||||||
warnx("Can not parse file %s", filename);
|
|
||||||
} else {
|
|
||||||
rc = EXIT_SUCCESS;
|
|
||||||
if (nr == PERF_TYPE_RAW)
|
|
||||||
strcat(prefix, "r");
|
|
||||||
else
|
|
||||||
snprintf(prefix, sizeof prefix, "%d:", nr);
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse tool parameters. In case of --help or --version, print
|
/* Parse tool parameters. In case of --help or --version, print
|
||||||
@@ -2661,8 +3224,6 @@ static unsigned long div_ceil(unsigned long a, unsigned long b)
|
|||||||
|
|
||||||
static void show_info(struct cpumf_info *p, int details)
|
static void show_info(struct cpumf_info *p, int details)
|
||||||
{
|
{
|
||||||
struct stat sbuf;
|
|
||||||
|
|
||||||
if (!p->have_counter && !p->have_samples) {
|
if (!p->have_counter && !p->have_samples) {
|
||||||
warnx("No CPU-measurement facilities detected");
|
warnx("No CPU-measurement facilities detected");
|
||||||
return;
|
return;
|
||||||
@@ -2672,7 +3233,7 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
if (details) {
|
if (details) {
|
||||||
printf("----------------------------------------------"
|
printf("----------------------------------------------"
|
||||||
"----------------------------\n");
|
"----------------------------\n");
|
||||||
printf("Version: %3.1f\n\n", p->version);
|
printf("Version: %d.%d\n\n", p->first_vn, p->second_vn);
|
||||||
printf("Authorized counter sets:\n");
|
printf("Authorized counter sets:\n");
|
||||||
if (!p->authorization)
|
if (!p->authorization)
|
||||||
printf(" None\n");
|
printf(" None\n");
|
||||||
@@ -2689,8 +3250,7 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
if (0x8000 & p->authorization)
|
if (0x8000 & p->authorization)
|
||||||
printf(" Coprocessor Group counter Set\n");
|
printf(" Coprocessor Group counter Set\n");
|
||||||
printf("\nLinux perf event support: %s\n\n",
|
printf("\nLinux perf event support: %s\n\n",
|
||||||
(stat(PERF_PATH PERF_CF, &sbuf)) ? "No" :
|
!p->have_counter ? "No" : "Yes (PMU: cpum_cf)");
|
||||||
"Yes (PMU: " PERF_CF ")");
|
|
||||||
|
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
@@ -2718,19 +3278,18 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
p->diag_sample_sz);
|
p->diag_sample_sz);
|
||||||
|
|
||||||
printf("\nLinux perf event support: %s\n\n",
|
printf("\nLinux perf event support: %s\n\n",
|
||||||
(stat(PERF_PATH PERF_SF, &sbuf)) ? "No" :
|
!p->have_samples ? "No" : "Yes (PMU: cpum_sf)");
|
||||||
"Yes (PMU: " PERF_SF ")");
|
|
||||||
|
|
||||||
printf("Current sampling buffer settings for %s:\n",
|
printf("Current sampling buffer settings for"
|
||||||
PERF_SF);
|
" cpum_sf:\n");
|
||||||
printf(" Basic-sampling mode\n");
|
printf(" Basic-sampling mode\n");
|
||||||
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
total = p->min_sfb + div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Minimum: %6d"
|
printf(" Minimum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n", p->min_sfb, text);
|
" sample-data-blocks (%6s)\n", p->min_sfb, text);
|
||||||
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
|
total = p->max_sfb + div_ceil(p->max_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Maximum: %6d"
|
printf(" Maximum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n\n", p->max_sfb,
|
" sample-data-blocks (%6s)\n\n", p->max_sfb,
|
||||||
text);
|
text);
|
||||||
|
|
||||||
@@ -2739,13 +3298,13 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
|
fdiag = div_ceil(p->diag_sample_sz, p->basic_sample_sz);
|
||||||
total = fdiag * p->min_sfb
|
total = fdiag * p->min_sfb
|
||||||
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
+ div_ceil(p->min_sfb, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Minimum: %6ld"
|
printf(" Minimum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n",
|
" sample-data-blocks (%6s)\n",
|
||||||
fdiag * p->min_sfb, text);
|
fdiag * p->min_sfb, text);
|
||||||
total = fdiag * p->max_sfb
|
total = fdiag * p->max_sfb
|
||||||
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
|
+ div_ceil(p->max_sfb * fdiag, PER_SDBT_SIZE);
|
||||||
human(text, sizeof text, PAGE_SIZE * total);
|
human(text, sizeof(text), PAGE_SIZE * total);
|
||||||
printf(" Maximum: %6ld"
|
printf(" Maximum: %6ld"
|
||||||
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
|
" sample-data-blocks (%6s)\n", fdiag * p->max_sfb,
|
||||||
text);
|
text);
|
||||||
@@ -2755,43 +3314,23 @@ static void show_info(struct cpumf_info *p, int details)
|
|||||||
warnx("No CPU-measurement sampling facility detected");
|
warnx("No CPU-measurement sampling facility detected");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read CPU Measurement sampling facility device driver minimum and maximum
|
|
||||||
* buffer size
|
|
||||||
*/
|
|
||||||
static int read_sfb(struct cpumf_info *p)
|
|
||||||
{
|
|
||||||
int rc = EXIT_SUCCESS;
|
|
||||||
FILE *fp;
|
|
||||||
|
|
||||||
fp = fopen(PERF_SFB_SIZE, "r");
|
|
||||||
if (!fp) {
|
|
||||||
warn(PERF_SFB_SIZE);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
if (fscanf(fp, "%d,%d", &p->min_sfb, &p->max_sfb) != 2) {
|
|
||||||
warnx("Can not parse %s", PERF_SFB_SIZE);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
fclose(fp);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set the counter name for z15 counter numbered 265. It is either named
|
/* Set the counter name for z15 counter numbered 265. It is either named
|
||||||
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
|
* DFLT_CCERROR or DFLT_CCFINISH, depending on the linux version. The
|
||||||
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
* counter was renamed from CCERROR to CCFINISH in linux version 5.8.
|
||||||
* Check for existence of file /sys/devices/cpum_cf/events/DLFT_CCERROR.
|
* 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)
|
static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
||||||
{
|
{
|
||||||
|
char *ctrname, *path;
|
||||||
struct stat sbuf;
|
struct stat sbuf;
|
||||||
char *ctrname;
|
|
||||||
size_t i = 0;
|
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";
|
ctrname = "DFLT_CCERROR";
|
||||||
else
|
else
|
||||||
ctrname = "DFLT_CCFINISH";
|
ctrname = "DFLT_CCFINISH";
|
||||||
|
free(path);
|
||||||
/* Find DFLT_CC{FINISH,ERROR} in table and set name */
|
/* Find DFLT_CC{FINISH,ERROR} in table and set name */
|
||||||
for (struct counters *p = cp; i < cp_cnt; ++i, ++p)
|
for (struct counters *p = cp; i < cp_cnt; ++i, ++p)
|
||||||
if (p->ctrnum == 265) {
|
if (p->ctrnum == 265) {
|
||||||
@@ -2803,81 +3342,23 @@ static void read_ccerror(struct counters *cp, size_t cp_cnt)
|
|||||||
/* Read allnecessary information from /sysfs file /proc/service_levels */
|
/* Read allnecessary information from /sysfs file /proc/service_levels */
|
||||||
static int read_info(void)
|
static int read_info(void)
|
||||||
{
|
{
|
||||||
char *linep = NULL;
|
int rc = EXIT_FAILURE;
|
||||||
size_t line_sz;
|
|
||||||
ssize_t nbytes;
|
|
||||||
FILE *slp;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
memset(&cpumf, 0, sizeof cpumf);
|
cpumf.have_counter = libcpumf_cpumcf_info(&cpumf.first_vn,
|
||||||
slp = fopen(SERVICELEVEL, "r");
|
&cpumf.second_vn,
|
||||||
if (!slp) {
|
&cpumf.authorization);
|
||||||
warn(SERVICELEVEL);
|
cpumf.have_samples = libcpumf_cpumsf_info(&cpumf.min_rate,
|
||||||
return EXIT_FAILURE;
|
&cpumf.max_rate,
|
||||||
}
|
&cpumf.cpu_speed,
|
||||||
|
&cpumf.basic_sample_sz,
|
||||||
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
|
&cpumf.diag_sample_sz);
|
||||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
if (cpumf.have_samples)
|
||||||
rc = sscanf(linep, "CPU-MF: Counter facility:"
|
libcpumf_sfb_info(&cpumf.min_sfb, &cpumf.max_sfb);
|
||||||
" version=%f authorization=%x",
|
|
||||||
&cpumf.version, &cpumf.authorization);
|
|
||||||
if (rc != 2) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.have_counter = 1;
|
|
||||||
cpumf.first_vn = (int)cpumf.version;
|
|
||||||
cpumf.second_vn = ((int)(10 * cpumf.version) % 10);
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: min", 30)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" min_rate=%ld max_rate=%ld cpu_speed=%ld",
|
|
||||||
&cpumf.min_rate, &cpumf.max_rate,
|
|
||||||
&cpumf.cpu_speed);
|
|
||||||
if (rc != 3) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.have_samples = 1;
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=basic", 37)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" mode=basic sample_size=%u",
|
|
||||||
&cpumf.basic_sample_sz);
|
|
||||||
if (rc != 1) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!strncmp(linep, "CPU-MF: Sampling facility: mode=diag", 36)) {
|
|
||||||
rc = sscanf(linep, "CPU-MF: Sampling facility:"
|
|
||||||
" mode=diagnostic sample_size=%u",
|
|
||||||
&cpumf.diag_sample_sz);
|
|
||||||
if (rc != 1) {
|
|
||||||
warnx("Can not parse line %s", linep);
|
|
||||||
rc = EXIT_FAILURE;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cpumf.have_samples) {
|
|
||||||
rc = read_sfb(&cpumf);
|
|
||||||
if (rc == EXIT_FAILURE)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
cpumf.machine_type = util_arch_machine_type();
|
cpumf.machine_type = util_arch_machine_type();
|
||||||
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN) {
|
if (cpumf.machine_type == UTIL_ARCH_MACHINE_TYPE_UNKNOWN)
|
||||||
rc = EXIT_FAILURE;
|
rc = EXIT_FAILURE;
|
||||||
goto out;
|
else
|
||||||
}
|
rc = EXIT_SUCCESS;
|
||||||
rc = EXIT_SUCCESS;
|
|
||||||
out:
|
|
||||||
fclose(slp);
|
|
||||||
free(linep);
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2991,6 +3472,9 @@ static struct counters *get_counter(int ctrset, size_t *len)
|
|||||||
*len = ARRAY_SIZE(cpumcf_z15_counters);
|
*len = ARRAY_SIZE(cpumcf_z15_counters);
|
||||||
read_ccerror(cp, *len);
|
read_ccerror(cp, *len);
|
||||||
break;
|
break;
|
||||||
|
case UTIL_ARCH_MACHINE_TYPE_Z16:
|
||||||
|
cp = cpumcf_z16_counters;
|
||||||
|
*len = ARRAY_SIZE(cpumcf_z16_counters);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -3051,14 +3535,18 @@ int main(int argc, char **argv)
|
|||||||
case ACTION_CNT:
|
case ACTION_CNT:
|
||||||
case ACTION_CNTALL:
|
case ACTION_CNTALL:
|
||||||
all = ret == ACTION_CNTALL;
|
all = ret == ACTION_CNTALL;
|
||||||
ret = read_cpumf_type(CPUMF_CF_TYPE, "counter");
|
ret = libcpumf_pmutype(S390_CPUMF_CF);
|
||||||
if (ret == EXIT_SUCCESS)
|
if (ret >= EXIT_SUCCESS) {
|
||||||
|
set_prefix(ret);
|
||||||
show_counter(all);
|
show_counter(all);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_SAMPLE:
|
case ACTION_SAMPLE:
|
||||||
ret = read_cpumf_type(CPUMF_SF_TYPE, "sampling");
|
ret = libcpumf_pmutype(S390_CPUMF_SF);
|
||||||
if (ret == EXIT_SUCCESS)
|
if (ret >= EXIT_SUCCESS) {
|
||||||
|
set_prefix(ret);
|
||||||
show_sample();
|
show_sample();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ACTION_NONE:
|
case ACTION_NONE:
|
||||||
case ACTION_INFO:
|
case ACTION_INFO:
|
||||||
|
|||||||
159
cpumf/lshwc.c
159
cpumf/lshwc.c
@@ -38,17 +38,19 @@
|
|||||||
#include "lib/util_path.h"
|
#include "lib/util_path.h"
|
||||||
#include "lib/util_scandir.h"
|
#include "lib/util_scandir.h"
|
||||||
#include "lib/util_libc.h"
|
#include "lib/util_libc.h"
|
||||||
|
#include "lib/util_file.h"
|
||||||
|
#include "lib/libcpumf.h"
|
||||||
|
|
||||||
#include "lshwc.h"
|
#include "lshwc.h"
|
||||||
|
|
||||||
#define SERVICELEVEL "/proc/service_levels"
|
|
||||||
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
|
#define CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
#define CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
#define CPUS_KERNELMAX "/sys/devices/system/cpu/kernel_max"
|
||||||
#define MAXCTRS 512
|
#define MAXCTRS 512
|
||||||
#define IOCTLSLEEP 60U
|
#define IOCTLSLEEP 60U
|
||||||
|
|
||||||
static unsigned int read_interval = IOCTLSLEEP, cfvn, csvn, authorization;
|
static unsigned int read_interval = IOCTLSLEEP;
|
||||||
|
static int cfvn, csvn, authorization;
|
||||||
static unsigned long loop_count = 1;
|
static unsigned long loop_count = 1;
|
||||||
static unsigned char *ioctlbuffer;
|
static unsigned char *ioctlbuffer;
|
||||||
static bool allcpu;
|
static bool allcpu;
|
||||||
@@ -61,25 +63,6 @@ static struct ctrname { /* List of defined counters */
|
|||||||
unsigned long *ccv; /* Per CPU counter value */
|
unsigned long *ccv; /* Per CPU counter value */
|
||||||
} ctrname[MAXCTRS];
|
} ctrname[MAXCTRS];
|
||||||
|
|
||||||
/* Open file and extract counter number */
|
|
||||||
static int read_counter(const char *p)
|
|
||||||
{
|
|
||||||
FILE *fp = fopen(p, "r");
|
|
||||||
int rc = 0, ctr;
|
|
||||||
|
|
||||||
if (fp) {
|
|
||||||
rc = fscanf(fp, "event=%x", &ctr);
|
|
||||||
fclose(fp);
|
|
||||||
}
|
|
||||||
return rc == 1 ? ctr : -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_countername(char *name, int nr)
|
|
||||||
{
|
|
||||||
ctrname[nr].name = strdup(name);
|
|
||||||
return ctrname[nr].name ? 0 : -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool read_counternames(void)
|
static bool read_counternames(void)
|
||||||
{
|
{
|
||||||
struct dirent **namelist = NULL;
|
struct dirent **namelist = NULL;
|
||||||
@@ -95,13 +78,12 @@ static bool read_counternames(void)
|
|||||||
}
|
}
|
||||||
for (i = 0; i < count && ctr >= 0; i++) {
|
for (i = 0; i < count && ctr >= 0; i++) {
|
||||||
util_asprintf(&ctrpath, "%s/%s", path, namelist[i]->d_name);
|
util_asprintf(&ctrpath, "%s/%s", path, namelist[i]->d_name);
|
||||||
ctr = read_counter(ctrpath);
|
if (util_file_read_va(ctrpath, "event=%x", &ctr) == 1)
|
||||||
|
ctrname[ctr].name = util_strdup(namelist[i]->d_name);
|
||||||
|
else
|
||||||
|
warnx("Cannot parse %s", ctrpath);
|
||||||
free(ctrpath);
|
free(ctrpath);
|
||||||
if (ctr >= 0)
|
|
||||||
ctr = add_countername(namelist[i]->d_name, ctr);
|
|
||||||
}
|
}
|
||||||
if (ctr < 0)
|
|
||||||
warnx("Cannot parse %s", path);
|
|
||||||
util_scandir_free(namelist, count);
|
util_scandir_free(namelist, count);
|
||||||
free(path);
|
free(path);
|
||||||
return ctr < 0 ? false : true;
|
return ctr < 0 ? false : true;
|
||||||
@@ -151,20 +133,6 @@ static unsigned long getnumber(char *word, char stopchar)
|
|||||||
return no;
|
return no;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remove all whitespace from string. */
|
|
||||||
static void kill_whitespace(char *s)
|
|
||||||
{
|
|
||||||
char *cp = s;
|
|
||||||
|
|
||||||
for (; *s != '\0'; ++s) {
|
|
||||||
if (isspace(*s))
|
|
||||||
continue;
|
|
||||||
if (isprint(*s))
|
|
||||||
*cp++ = *s;
|
|
||||||
}
|
|
||||||
*cp = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read file to get all online CPUs */
|
/* Read file to get all online CPUs */
|
||||||
static bool get_cpus(char *file, char *buf, size_t bufsz)
|
static bool get_cpus(char *file, char *buf, size_t bufsz)
|
||||||
{
|
{
|
||||||
@@ -242,29 +210,34 @@ static char *show_ctrset(unsigned long set)
|
|||||||
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
||||||
{
|
{
|
||||||
uint64_t *words = start->cpumask;
|
uint64_t *words = start->cpumask;
|
||||||
unsigned long i, no_a, no_b;
|
unsigned int i, no_a, no_b;
|
||||||
char *cp, *tokens[16]; /* Used to parse command line params */
|
cpu_set_t cpulist;
|
||||||
char cpubuf[256];
|
int rc;
|
||||||
|
|
||||||
|
CPU_ZERO(&cpulist);
|
||||||
start->data_bytes = 0;
|
start->data_bytes = 0;
|
||||||
if (parm)
|
start->counter_sets = S390_HWCTR_ALL; /* Default all counter sets */
|
||||||
kill_whitespace(parm);
|
|
||||||
if (!parm || *parm == ':') {
|
if (parm) { /* CPU list with optional counter set */
|
||||||
/* No CPU list or just counter sets */
|
char *cp = strchr(parm, ':');
|
||||||
if (!get_cpus(CPUS_ONLINE, cpubuf, sizeof(cpubuf)))
|
|
||||||
exit(EXIT_FAILURE);
|
if (cp) { /* Handle counter set */
|
||||||
if (parm)
|
*cp = '\0';
|
||||||
strcat(cpubuf, parm);
|
start->counter_sets = parse_ctrset(++cp);
|
||||||
parm = cpubuf;
|
}
|
||||||
|
|
||||||
|
if (strlen(parm) > 0) /* Handle CPU list */
|
||||||
|
rc = libcpumf_cpuset(parm, &cpulist);
|
||||||
|
else
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
|
||||||
|
if (rc)
|
||||||
|
errx(EXIT_FAILURE, "Cannot use CPU list %s", parm);
|
||||||
|
} else { /* No CPU list and no counter sets */
|
||||||
|
rc = libcpumf_cpuset_fn(S390_CPUS_ONLINE, &cpulist);
|
||||||
|
if (rc)
|
||||||
|
err(EXIT_FAILURE, "Cannot read file " S390_CPUS_ONLINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
cp = strchr(parm, ':');
|
|
||||||
if (cp) { /* Handle counter set */
|
|
||||||
*cp = '\0';
|
|
||||||
start->counter_sets = parse_ctrset(++cp);
|
|
||||||
} else {
|
|
||||||
start->counter_sets = S390_HWCTR_ALL;
|
|
||||||
}
|
|
||||||
/* Check with authorized counter sets */
|
/* Check with authorized counter sets */
|
||||||
if ((start->counter_sets & authorization) != start->counter_sets) {
|
if ((start->counter_sets & authorization) != start->counter_sets) {
|
||||||
unsigned int noton = ~(start->counter_sets & authorization);
|
unsigned int noton = ~(start->counter_sets & authorization);
|
||||||
@@ -276,19 +249,10 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
show_ctrset(noton));
|
show_ctrset(noton));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(tokens) && (tokens[i] = strtok(parm, ","));
|
for (rc = 0; rc < CPU_SETSIZE; ++rc)
|
||||||
++i, parm = NULL) {
|
if (CPU_ISSET(rc, &cpulist))
|
||||||
cp = strchr(tokens[i], '-'); /* Range character? */
|
if (!check_set(rc, rc, start->counter_sets))
|
||||||
if (cp) {
|
errx(EXIT_FAILURE, "Invalid CPU %d", rc);
|
||||||
no_a = getnumber(tokens[i], *cp);
|
|
||||||
no_b = getnumber(++cp, '\0');
|
|
||||||
} else {
|
|
||||||
no_b = getnumber(tokens[i], '\0');
|
|
||||||
no_a = no_b;
|
|
||||||
}
|
|
||||||
if (!check_set(no_a, no_b, start->counter_sets))
|
|
||||||
errx(EXIT_FAILURE, "Invalid CPU list %s", tokens[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
/* Convert the CPU list to a bitmask for kernel cpumask_t */
|
||||||
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
for (i = 0, no_b = 0; i < max_possible_cpus; ++i) {
|
||||||
@@ -298,14 +262,8 @@ static void parse_cpulist(char *parm, struct s390_hwctr_start *start)
|
|||||||
words[no_b] |= 1ULL << no_a;
|
words[no_b] |= 1ULL << no_a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* no_b is highest used index, swap array */
|
/* no_b is highest used index */
|
||||||
start->cpumask_len = (no_b + 1) * 8;
|
start->cpumask_len = (no_b + 1) * CHAR_BIT;
|
||||||
for (no_a = 0; no_a < no_b; ++no_a, --no_b) {
|
|
||||||
uint64_t tmp = words[no_a];
|
|
||||||
|
|
||||||
words[no_a] = words[no_b];
|
|
||||||
words[no_b] = tmp;
|
|
||||||
}
|
|
||||||
start->version = S390_HWCTR_START_VERSION;
|
start->version = S390_HWCTR_START_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,6 +356,8 @@ static void line(char *header)
|
|||||||
putchar(',');
|
putchar(',');
|
||||||
printf("%ld", ctrname[i].total);
|
printf("%ld", ctrname[i].total);
|
||||||
comma = true;
|
comma = true;
|
||||||
|
ctrname[i].total = 0;
|
||||||
|
ctrname[i].hitcnt = false;
|
||||||
}
|
}
|
||||||
putchar('\n');
|
putchar('\n');
|
||||||
}
|
}
|
||||||
@@ -488,7 +448,7 @@ static bool add_countervalue(size_t idx, unsigned int cpu, unsigned long value)
|
|||||||
ctrname[idx].ccv = calloc(max_possible_cpus,
|
ctrname[idx].ccv = calloc(max_possible_cpus,
|
||||||
sizeof(unsigned long));
|
sizeof(unsigned long));
|
||||||
if (ctrname[idx].ccv)
|
if (ctrname[idx].ccv)
|
||||||
ctrname[idx].ccv[cpu] += value;
|
ctrname[idx].ccv[cpu] = value;
|
||||||
ctrname[idx].total += value;
|
ctrname[idx].total += value;
|
||||||
ctrname[idx].hitcnt = true;
|
ctrname[idx].hitcnt = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -500,10 +460,8 @@ static int test_read(struct s390_hwctr_read *read)
|
|||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
|
|
||||||
/* Clear previous hit counters */
|
/* Clear previous hit counters */
|
||||||
for (unsigned int i = 0; i < max_possible_cpus; ++i) {
|
for (unsigned int i = 0; i < max_possible_cpus; ++i)
|
||||||
check[i].sets_hit = 0;
|
|
||||||
check[i].cpu_hit = false;
|
check[i].cpu_hit = false;
|
||||||
}
|
|
||||||
|
|
||||||
/* Iterate over all CPUs */
|
/* Iterate over all CPUs */
|
||||||
for (unsigned int i = 0; i < read->no_cpus; ++i) {
|
for (unsigned int i = 0; i < read->no_cpus; ++i) {
|
||||||
@@ -638,37 +596,6 @@ static int do_it(char *s)
|
|||||||
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
return rc ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read counter first and second version number */
|
|
||||||
static bool get_cvn(void)
|
|
||||||
{
|
|
||||||
char *linep = NULL;
|
|
||||||
bool good = false;
|
|
||||||
size_t line_sz;
|
|
||||||
ssize_t nbytes;
|
|
||||||
FILE *slp;
|
|
||||||
|
|
||||||
slp = fopen(SERVICELEVEL, "r");
|
|
||||||
if (!slp) {
|
|
||||||
warn(SERVICELEVEL);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
while ((nbytes = getline(&linep, &line_sz, slp)) != EOF) {
|
|
||||||
if (!strncmp(linep, "CPU-MF: Counter facility:", 25)) {
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
rc = sscanf(linep, "CPU-MF: Counter facility: version=%d.%d authorization=%x",
|
|
||||||
&cfvn, &csvn, &authorization);
|
|
||||||
good = rc == 3;
|
|
||||||
if (!good)
|
|
||||||
warnx("Cannot parse line %s", linep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose(slp);
|
|
||||||
free(linep);
|
|
||||||
return good;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("OPTIONS"),
|
UTIL_OPT_SECTION("OPTIONS"),
|
||||||
{
|
{
|
||||||
@@ -752,7 +679,7 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
have_support();
|
have_support();
|
||||||
if (!get_cvn())
|
if (!libcpumf_cpumcf_info(&cfvn, &csvn, &authorization))
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
if (!check_setpossible())
|
if (!check_setpossible())
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
\" lscpumf.1
|
\" lscpumf.8
|
||||||
.\"
|
.\"
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright IBM Corp. 2014, 2020
|
.\" Copyright IBM Corp. 2014, 2020
|
||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\" ----------------------------------------------------------------------
|
.\" ----------------------------------------------------------------------
|
||||||
.TH lscpumf "1" "May 2020" "s390-tools" "CPU-MF management programs"
|
.TH lscpumf "8" "May 2022" "s390-tools" "CPU-MF management programs"
|
||||||
.
|
.
|
||||||
.ds c \fBlscpumf\fP
|
.ds c \fBlscpumf\fP
|
||||||
.
|
.
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
.\" lshwc.1
|
.\" lshwc.8
|
||||||
.\"
|
.\"
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright IBM Corp. 2021
|
.\" Copyright IBM Corp. 2021
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
.\" ----------------------------------------------------------------------
|
.\" ----------------------------------------------------------------------
|
||||||
.ds c \fBlshwc\fP
|
.ds c \fBlshwc\fP
|
||||||
.
|
.
|
||||||
.TH \*c "1" "February 2021" "s390-tools" "CPU-MF management programs"
|
.TH \*c "8" "May 2022" "s390-tools" "CPU-MF management programs"
|
||||||
.
|
.
|
||||||
.SH NAME
|
.SH NAME
|
||||||
\*c \- extract CPU Measurement Facilities counter sets
|
\*c \- extract CPU Measurement Facilities counter sets
|
||||||
@@ -130,5 +130,5 @@ Date,Time,CPU,PROBLEM_STATE_CPU_CYCLES(32),PROBLEM_STATE_INSTRUCTIONS(33)
|
|||||||
.ft
|
.ft
|
||||||
.fi
|
.fi
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR lscpumf (1)
|
.BR lscpumf (8)
|
||||||
.BR chcpumf (8)
|
.BR chcpumf (8)
|
||||||
268
cpumf/man/pai.8
Normal file
268
cpumf/man/pai.8
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
.\" pai.8
|
||||||
|
.\"
|
||||||
|
.\"
|
||||||
|
.\" 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.
|
||||||
|
.\" ----------------------------------------------------------------------
|
||||||
|
.ds c \fBpai\fP
|
||||||
|
.
|
||||||
|
.TH \*c "8" "May 2022" "s390-tools" "PAI Management Programs"
|
||||||
|
.
|
||||||
|
.SH NAME
|
||||||
|
\*c \- record and report Processor Activity Instrumentation (PAI) counters
|
||||||
|
.
|
||||||
|
.SH SYNOPSIS
|
||||||
|
\*c
|
||||||
|
.RB [ \-V ][ \-m | \-\-mapsize
|
||||||
|
.IR size ]
|
||||||
|
.RB [ \-i | \-\-interval
|
||||||
|
.IR ms ]
|
||||||
|
.BR \-c | \-\-crypto [ \fIcpulist ][: \fIdata\fR "] [" \fIloops\fP ]
|
||||||
|
.br
|
||||||
|
\*c
|
||||||
|
.RB [ \-V ][ \-m | \-\-mapsize
|
||||||
|
.IR size ]
|
||||||
|
.RB [ \-i | \-\-interval
|
||||||
|
.IR ms ]
|
||||||
|
.BR \-n | \-\-nnpa [ \fIcpulist ][: \fIdata\fR "] [" \fIloops\fP ]
|
||||||
|
.br
|
||||||
|
\*c
|
||||||
|
.RB [ \-V ][ \-H | \-\-humantime ][ \-S | \-\-summary "] " \-r | \-\-report " [" \fIfiles\fP ]
|
||||||
|
.br
|
||||||
|
\*c
|
||||||
|
.BR \-h | \-\-help
|
||||||
|
.br
|
||||||
|
\*c
|
||||||
|
.BR \-v | \-\-version
|
||||||
|
.
|
||||||
|
.
|
||||||
|
.SH DESCRIPTION
|
||||||
|
\*c
|
||||||
|
counters tally calls for specific CPU instructions.
|
||||||
|
The \*c command records PAI counters in a ring buffer.
|
||||||
|
\*c can record counter data for all CPUs or for selected CPUs.
|
||||||
|
The main command options are
|
||||||
|
.B \-c
|
||||||
|
for recording cryptographic CPU instructions,
|
||||||
|
.B \-n
|
||||||
|
for recording NNPA CPU instructions
|
||||||
|
and
|
||||||
|
.B \-r
|
||||||
|
for reporting.
|
||||||
|
If all three options are omitted, option
|
||||||
|
.B \-r
|
||||||
|
is assumed and a message is printed.
|
||||||
|
Recording stores data, by CPU, in files
|
||||||
|
.I paicrypto.<XXX>,
|
||||||
|
for option
|
||||||
|
.B \-c
|
||||||
|
or
|
||||||
|
.I painnpa.<XXX>,
|
||||||
|
for option
|
||||||
|
.B \-n
|
||||||
|
where <XXX> specifies the CPU number with leading
|
||||||
|
zeros.
|
||||||
|
The files are created in the working directory,
|
||||||
|
existing files are overwritten.
|
||||||
|
Reporting evaluates files that are created by recording.
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
.BR \-c ", " \-\-crypto "\fR[\fIcpulist\fR][:\fIdata\fR]"
|
||||||
|
Records data for all (default) or a specified list of CPUs.
|
||||||
|
The CPU list is a comma-separated list of CPU numbers and ranges.
|
||||||
|
In a range, a hyphen separates the first CPU number
|
||||||
|
from the last CPU number.
|
||||||
|
By default \*c lists all CPUs.
|
||||||
|
.RS
|
||||||
|
The optional data specification
|
||||||
|
follows the colon
|
||||||
|
and determines additional collection of data.
|
||||||
|
The specification consists of alphabetic
|
||||||
|
characters that can be upper or lower case:
|
||||||
|
.IP c|C
|
||||||
|
Include task rename system calls
|
||||||
|
.B exec
|
||||||
|
and
|
||||||
|
.BR prctl .
|
||||||
|
.IP f|F
|
||||||
|
Include task creation and deletion system calls
|
||||||
|
.B fork
|
||||||
|
and
|
||||||
|
.BR exit .
|
||||||
|
.IP s|S
|
||||||
|
Include context switch records created by the kernel scheduler.
|
||||||
|
.IP k|K
|
||||||
|
Include only PAI cryptographic counters changed during system call
|
||||||
|
execution.
|
||||||
|
.IP u|U
|
||||||
|
Include only PAI cryptographic counters changed during user space
|
||||||
|
execution.
|
||||||
|
.RE
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-n ", " \-\-nnpa "\fR[\fIcpulist\fR][:\fIdata\fR]"
|
||||||
|
Records data for all (default) or a specified list of CPUs.
|
||||||
|
The CPU list is a comma-separated list of CPU numbers and ranges.
|
||||||
|
In a range, a hyphen separates the first CPU number
|
||||||
|
from the last CPU number.
|
||||||
|
By default \*c lists all CPUs.
|
||||||
|
.RS
|
||||||
|
The optional data specification
|
||||||
|
follows the colon
|
||||||
|
and determines additional collection of data.
|
||||||
|
The specification consists of alphabetic
|
||||||
|
characters that can be upper or lower case:
|
||||||
|
.IP c|C
|
||||||
|
Include task rename system calls
|
||||||
|
.B exec
|
||||||
|
and
|
||||||
|
.BR prctl .
|
||||||
|
.IP f|F
|
||||||
|
Include task creation and deletion system calls
|
||||||
|
.B fork
|
||||||
|
and
|
||||||
|
.BR exit .
|
||||||
|
.IP s|S
|
||||||
|
Include context switch records created by the kernel scheduler.
|
||||||
|
.RE
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-r ", " \-\-report
|
||||||
|
Generates a report from the specified files.
|
||||||
|
Files is a list of blank-separated file names.
|
||||||
|
If no files are specified,
|
||||||
|
uses all files named
|
||||||
|
.I paicrypto.<X>,
|
||||||
|
in the working directory, where
|
||||||
|
.I <X>
|
||||||
|
is a CPU number that
|
||||||
|
identifies the CPU for which the data was recorded.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-h ", " \-\-help
|
||||||
|
Displays help information, then exits.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-v ", " \-\-version
|
||||||
|
Displays version information, then exits.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-V ", " \-\-verbose
|
||||||
|
Displays the following information during reporting:
|
||||||
|
the file name and the hexadecimal offset for each sample header.
|
||||||
|
Displays the following information during recording:
|
||||||
|
the read position in the ring buffer,
|
||||||
|
the file name, and the hexadecimal offset for each sample header.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-H ", " \-\-humantime
|
||||||
|
Changes the time stamp format for sample entries from a hexadecimal
|
||||||
|
number to a human readable <seconds>.<nanoseconds> format.
|
||||||
|
The time stamp specifies the elapsed time since Linux was booted.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-S ", " \-\-summary
|
||||||
|
Prints a summary of counter names and
|
||||||
|
counter numbers with non-zero values.
|
||||||
|
The summary is the last line in the command output.
|
||||||
|
It shows the sum of the counter values of all processed files.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-i ", " \-\-interval "\ ms"
|
||||||
|
Specifies the waiting time,
|
||||||
|
in milliseconds,
|
||||||
|
between ring buffer read operations during recording.
|
||||||
|
The default is 1000 milliseconds.
|
||||||
|
Argument
|
||||||
|
.B loops
|
||||||
|
is an integer that specifies the number of
|
||||||
|
read operations during recording. The default is 1.
|
||||||
|
.
|
||||||
|
.TP
|
||||||
|
.BR \-m ", " \-\-mapsize "\ size"
|
||||||
|
Specifies the size of the ring buffer
|
||||||
|
that holds the collected data.
|
||||||
|
The value specifies the number of 4 KB pages
|
||||||
|
to be allocated and must be a power of 2.
|
||||||
|
The default size is 512 pages.
|
||||||
|
The ring buffer is created with the
|
||||||
|
.IR mmap (2)
|
||||||
|
system call.
|
||||||
|
.
|
||||||
|
.SH ARGUMENT
|
||||||
|
The command line options determine how command line
|
||||||
|
arguments are interpreted.
|
||||||
|
For option
|
||||||
|
.B \-c
|
||||||
|
to start recording, the argument specifies
|
||||||
|
the number of read operations.
|
||||||
|
If omitted, the default is one.
|
||||||
|
For option
|
||||||
|
.B \-r
|
||||||
|
to start reporting, the argument specifies
|
||||||
|
the file names to be read.
|
||||||
|
If omitted all files in the current directory
|
||||||
|
with file name
|
||||||
|
.I paicryto.<X>
|
||||||
|
are read.
|
||||||
|
.SH "Concurrency with perf tool"
|
||||||
|
The following concurrency restrictions apply
|
||||||
|
for \*c and the
|
||||||
|
.B perf
|
||||||
|
tool.
|
||||||
|
Both tools use the
|
||||||
|
.IR perf_event_open ()
|
||||||
|
system call and use the same device driver.
|
||||||
|
The device driver supports limited concurrency:
|
||||||
|
.IP Counting:
|
||||||
|
Counting pai events can run in parallel.
|
||||||
|
.IP Sampling:
|
||||||
|
Only one sampling event pai_crypto/CRYPTO_ALL can be active at any one time.
|
||||||
|
If a sampling event is active, no pai counting event can be active.
|
||||||
|
Both tools stop with an error message if they detect a collision
|
||||||
|
reported by the device driver.
|
||||||
|
.SH "EXAMPLES"
|
||||||
|
This example collects cryptographic counter on CPU 0.
|
||||||
|
The program runs for 10 seconds
|
||||||
|
(10 intervals of 1000 milliseconds).
|
||||||
|
.sp 1
|
||||||
|
.nf
|
||||||
|
.ft CW
|
||||||
|
# \*c -c0 10
|
||||||
|
.ft R
|
||||||
|
.fi
|
||||||
|
.sp 1
|
||||||
|
This example displays the data
|
||||||
|
that is collected in the first example.
|
||||||
|
Each data line shows the time stamp in jiffies,
|
||||||
|
followed by the CPU number,
|
||||||
|
the event number,
|
||||||
|
process and thread identifier (pid/tid) separated by slash (/),
|
||||||
|
and a comma-separated list of counter number, colon (:),
|
||||||
|
and the counter value n hexadecimal notation.
|
||||||
|
.sp 1
|
||||||
|
.nf
|
||||||
|
.ft CW
|
||||||
|
# \*c -r
|
||||||
|
0x62a668f2fa 0 event 4096 sample pid 4956/4956 9:0xa7,73:0x8,74:0x18
|
||||||
|
0x6319c75653 0 event 4096 sample pid 4972/4972 32:0x1
|
||||||
|
0x6319e2ddee 0 event 4096 sample pid 4972/4972 32:0x1
|
||||||
|
0x631d3e44f5 0 event 4096 sample pid 4972/4972 32:0x2
|
||||||
|
0x631d4cfc2e 0 event 4096 sample pid 4972/4972 32:0x3
|
||||||
|
0x631d529fdd 0 event 4096 sample pid 4972/4972 32:0x2
|
||||||
|
0x631d84cfa0 0 event 4096 sample pid 4972/4972 73:0x1
|
||||||
|
0x636e9826bc 0 event 4096 sample pid 4984/4984 9:0xa7,73:0x8,74:0x18
|
||||||
|
0x636f81a137 0 event 4096 sample pid 4984/4984 9:0x2,74:0x7
|
||||||
|
0x6378026e54 0 event 4096 sample pid 4984/4984 73:0x2
|
||||||
|
0x637bcdc8da 0 event 4096 sample pid 4984/4984 73:0x2
|
||||||
|
0x637bd426cd 0 event 4096 sample pid 4984/4984 73:0x6
|
||||||
|
0x637c503384 0 event 4096 sample pid 4984/4984 73:0x2
|
||||||
|
0x64991d83ba 0 event 4096 sample pid 5026/5026 9:0xb0,73:0x8,74:0x18
|
||||||
|
#
|
||||||
|
.ft R
|
||||||
|
.fi
|
||||||
|
.sp 1
|
||||||
|
.SH "SEE ALSO"
|
||||||
|
perf(1)
|
||||||
1125
cpumf/pai.c
Normal file
1125
cpumf/pai.c
Normal file
File diff suppressed because it is too large
Load Diff
105
cpumf/pai.h
Normal file
105
cpumf/pai.h
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/*
|
||||||
|
* pai - Extract CPU Processor Activity Instrumentation (PAI) facility data.
|
||||||
|
*
|
||||||
|
* 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 PAI_H
|
||||||
|
#define PAI_H
|
||||||
|
|
||||||
|
#define S390_EVT_PAI_CRYPTO 0x1000
|
||||||
|
|
||||||
|
enum { /* Event attribute specifications */
|
||||||
|
S390_EVTATTR_CTX_SWITCH = 1,
|
||||||
|
S390_EVTATTR_COMM = 2,
|
||||||
|
S390_EVTATTR_FORK = 4,
|
||||||
|
S390_EVTATTR_USERSPACE = 8,
|
||||||
|
S390_EVTATTR_KERNELSPACE = 16
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pai_event {
|
||||||
|
struct util_list_node node; /* List node */
|
||||||
|
struct perf_event_attr attr; /* Perf_event_open(2) attr */
|
||||||
|
int fd; /* Perf event file descriptor */
|
||||||
|
void *map_addr; /* Sampling data mapping address */
|
||||||
|
size_t map_size; /* Sampling size mapping size */
|
||||||
|
char file_name[16]; /* File name of sampled data */
|
||||||
|
int file_fd; /* Map data output file descriptor */
|
||||||
|
int cpu; /* Perf_event_open(2) CPU */
|
||||||
|
unsigned long flags; /* Perf_event_open(2) flags */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pai_event_out { /* Output for CRYPTO_ALL event */
|
||||||
|
__u32 type; /* Header type, see PERF_RECORD_xxx */
|
||||||
|
__u16 misc; /* Header misc, value depends on type */
|
||||||
|
__u64 time; /* Time stamp valid for all entries */
|
||||||
|
__u32 cpu; /* CPU number valid for all entries */
|
||||||
|
union {
|
||||||
|
/* Fields from PERF_RECORD_FORK|EXIT */
|
||||||
|
struct {
|
||||||
|
__u32 pid, ppid;
|
||||||
|
__u32 tid, ptid;
|
||||||
|
__u64 time;
|
||||||
|
} s_fork;
|
||||||
|
/* Fields from PERF_RECORD_COMM */
|
||||||
|
struct {
|
||||||
|
__u32 pid, tid;
|
||||||
|
__u8 cmd[16];
|
||||||
|
} s_comm;
|
||||||
|
/* Fields from PERF_RECORD_SWITCH_CPU_WIDE */
|
||||||
|
struct {
|
||||||
|
__u32 next_prev_pid, next_prev_tid;
|
||||||
|
} s_cs;
|
||||||
|
/* Fields from PERF_RECORD_LOST_SAMPLES */
|
||||||
|
struct {
|
||||||
|
__u64 lost;
|
||||||
|
} s_lost;
|
||||||
|
/* Relevant fields from PERF_RECORD_SAMPLE, time and cpu
|
||||||
|
* are stored above
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
|
__u64 ip;
|
||||||
|
__u64 period;
|
||||||
|
__u32 pid, tid;
|
||||||
|
} s_sample;
|
||||||
|
/* Fields from PERF_RECORD_[UN]THROTTLE */
|
||||||
|
struct {
|
||||||
|
__u64 time;
|
||||||
|
__u64 id;
|
||||||
|
__u64 stream_id;
|
||||||
|
} s_throttle;
|
||||||
|
} u;
|
||||||
|
/* Information on last context switch out */
|
||||||
|
struct cs_switch {
|
||||||
|
unsigned char valid;
|
||||||
|
__u32 topid, totid;
|
||||||
|
__u32 frompid, fromtid;
|
||||||
|
} cs_switch;
|
||||||
|
void *raw; /* Pointer to key/value array for crypto counters */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct data_pos { /* Perf event mapped ring buffer */
|
||||||
|
__u64 data_head; /* Head in the data section */
|
||||||
|
__u64 data_tail; /* User-space written tail */
|
||||||
|
__u64 data_offset; /* Where the buffer starts */
|
||||||
|
__u64 data_size; /* Data buffer size */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct event_name { /* Event list for number to name xlate */
|
||||||
|
char *name; /* Event name */
|
||||||
|
__u64 config; /* Event config value */
|
||||||
|
__u64 total; /* Total counter value */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pmu_events { /* Event list for PMU number to name xlate */
|
||||||
|
struct util_list_node node; /* List node */
|
||||||
|
char *name; /* PMU name */
|
||||||
|
int type; /* PMU type */
|
||||||
|
int lstlen; /* # of entries in lst */
|
||||||
|
unsigned long base; /* Base event number */
|
||||||
|
struct event_name *lst; /* List of event names */
|
||||||
|
};
|
||||||
|
#endif /* PAI_H */
|
||||||
@@ -1107,8 +1107,8 @@ static void dasdfmt_write_labels(volume_label_t *vlabel,
|
|||||||
} else {
|
} else {
|
||||||
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
|
vlabel->ldl_version = 0xf2; /* EBCDIC '2' */
|
||||||
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
|
vlabel->formatted_blocks = cylinders * heads * geo.sectors;
|
||||||
rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
|
rc = write(fd, (void *)vlabel + sizeof(vlabel->volkey),
|
||||||
- sizeof(vlabel->volkey)));
|
(sizeof(*vlabel) - sizeof(vlabel->volkey)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ Print DASD uid without z/VM minidisk token
|
|||||||
|
|
||||||
z/VM may provide an additional token that can be used to distinguish
|
z/VM may provide an additional token that can be used to distinguish
|
||||||
between different minidisks (see --extended-uid option). To remain
|
between different minidisks (see --extended-uid option). To remain
|
||||||
compatibile with systems that were installed on older Linux or z/VM
|
compatible with systems that were installed on older Linux or z/VM
|
||||||
levels, the -u option will print the uid excluding any z/VM-provided
|
levels, the -u option will print the uid excluding any z/VM-provided
|
||||||
minidisk token.
|
minidisk token.
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
#include "lib/dasd_sys.h"
|
#include "lib/dasd_sys.h"
|
||||||
#include "lib/libzds.h"
|
#include "lib/libzds.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
#include "lib/util_libc.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
#include "lib/util_sys.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++) {
|
for (i = 0; i < size; i++) {
|
||||||
if ((i / 16) * 16 == i) {
|
if ((i / 16) * 16 == i) {
|
||||||
printf("\n| ");
|
printf("\n| ");
|
||||||
strncpy(asc, (char *)dumpstr + i, 16);
|
util_strlcpy(asc, (char *)dumpstr + i, 16);
|
||||||
strncpy(ebc, (char *)dumpstr + i, 16);
|
util_strlcpy(ebc, (char *)dumpstr + i, 16);
|
||||||
asc[16] = '\0';
|
|
||||||
ebc[16] = '\0';
|
|
||||||
}
|
}
|
||||||
printf("%02X", dumpstr[i]);
|
printf("%02X", dumpstr[i]);
|
||||||
if (((i + 1) / 4) * 4 == i + 1)
|
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,
|
||||||
begin + (unsigned long long)i);
|
begin + (unsigned long long)i);
|
||||||
|
|
||||||
strncpy(asc, (char *)dumpstr + i, 8);
|
util_strlcpy(asc, (char *)dumpstr + i, 8);
|
||||||
strncpy(ebc, (char *)dumpstr + i, 8);
|
util_strlcpy(ebc, (char *)dumpstr + i, 8);
|
||||||
}
|
}
|
||||||
printf("%02X", dumpstr[i]);
|
printf("%02X", dumpstr[i]);
|
||||||
if (((i + 1) / 4) * 4 == i + 1)
|
if (((i + 1) / 4) * 4 == i + 1)
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: cpacfstatsd
|
|
||||||
# Required-Start: $local_fs
|
|
||||||
# Required-Stop: $local_fs
|
|
||||||
# Should-Start:
|
|
||||||
# Should-Stop:
|
|
||||||
# Default-Start: 2 3 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: Start the cpacfstatsd daemon for Linux on System z
|
|
||||||
# Description: CPACF statistics collection daemon process for Linux on System z
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
DAEMON=cpacfstatsd
|
|
||||||
DAEMON_PATH=/usr/sbin/cpacfstatsd
|
|
||||||
RUN_PID_FILE=/run/cpacfstatsd.pid
|
|
||||||
RETVAL=0
|
|
||||||
OPTIONS=""
|
|
||||||
|
|
||||||
# source function library
|
|
||||||
. /lib/lsb/init-functions
|
|
||||||
|
|
||||||
start()
|
|
||||||
{
|
|
||||||
if [ ! -f $RUN_PID_FILE ]; then
|
|
||||||
echo -n $"Starting $DAEMON:"
|
|
||||||
$DAEMON_PATH $OPTIONS
|
|
||||||
if [ $? == "0" ]; then
|
|
||||||
log_success_msg
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
else
|
|
||||||
echo "$DAEMON (pid $(cat $RUN_PID_FILE)) is already running..."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop()
|
|
||||||
{
|
|
||||||
echo -n $"Stopping $DAEMON:"
|
|
||||||
if [ -f $RUN_PID_FILE ]; then
|
|
||||||
killproc $DAEMON_PATH -TERM
|
|
||||||
log_success_msg
|
|
||||||
rm -f $RUN_PID_FILE
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
restart() {
|
|
||||||
stop
|
|
||||||
sleep 1
|
|
||||||
start
|
|
||||||
}
|
|
||||||
|
|
||||||
status()
|
|
||||||
{
|
|
||||||
if [ ! -f $RUN_PID_FILE ]; then
|
|
||||||
echo "$DAEMON is not running."
|
|
||||||
echo
|
|
||||||
else
|
|
||||||
echo "$DAEMON (pid $(cat $RUN_PID_FILE)) is running."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# How are we called?
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
restart
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $DAEMON {start|stop|status|restart}"
|
|
||||||
RETVAL=1
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit $RETVAL
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: cpuplugd
|
|
||||||
# Required-Start: $local_fs $remote_fs
|
|
||||||
# Required-Stop: $local_fs $remote_fs
|
|
||||||
# Should-Start:
|
|
||||||
# Should-Stop:
|
|
||||||
# Default-Start: 2 3 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: Start the cpu hotplug daemon for Linux on System z
|
|
||||||
# Description: Starts the cpuplugd. It uses the configuration
|
|
||||||
# file /etc/cpuplugd.conf
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
# chkconfig: 235 01 99
|
|
||||||
|
|
||||||
DAEMON=cpuplugd
|
|
||||||
DAEMON_PATH=/usr/sbin/cpuplugd
|
|
||||||
CONFIG_FILE=/etc/cpuplugd.conf
|
|
||||||
RUN_PID_FILE=/run/cpuplugd.pid
|
|
||||||
RETVAL=0
|
|
||||||
OPTIONS="-c $CONFIG_FILE"
|
|
||||||
|
|
||||||
# source function library
|
|
||||||
. /lib/lsb/init-functions
|
|
||||||
|
|
||||||
start()
|
|
||||||
{
|
|
||||||
if [ ! -f $RUN_PID_FILE ]; then
|
|
||||||
echo -n $"Starting $DAEMON:"
|
|
||||||
$DAEMON_PATH $OPTIONS
|
|
||||||
if [ $? == "0" ]; then
|
|
||||||
log_success_msg
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
else
|
|
||||||
echo "$DAEMON (pid $(cat $RUN_PID_FILE)) is already running..."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop()
|
|
||||||
{
|
|
||||||
echo -n $"Stopping $DAEMON:"
|
|
||||||
if [ -f $RUN_PID_FILE ]; then
|
|
||||||
killproc $DAEMON_PATH -TERM
|
|
||||||
log_success_msg
|
|
||||||
rm -f $RUN_PID_FILE
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
restart() {
|
|
||||||
stop
|
|
||||||
#
|
|
||||||
# We have to wait 2-3 seconds here. When the daemon is stopped it takes
|
|
||||||
# the time we sleep to reactivate cpus. If we restart to fast and
|
|
||||||
# cpuplugd wasn't able to restore some settings we may get a undesired
|
|
||||||
# online cpu count after cpuplugd shutdown
|
|
||||||
#
|
|
||||||
sleep 4
|
|
||||||
start
|
|
||||||
}
|
|
||||||
|
|
||||||
status()
|
|
||||||
{
|
|
||||||
if [ ! -f $RUN_PID_FILE ]; then
|
|
||||||
echo "$DAEMON is not running."
|
|
||||||
echo
|
|
||||||
else
|
|
||||||
echo "$DAEMON (pid $(cat $RUN_PID_FILE), options: $OPTIONS) is running."
|
|
||||||
echo
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
reload()
|
|
||||||
{
|
|
||||||
echo -n $"Reloading $DAEMON: "
|
|
||||||
if [ -f $RUN_PID_FILE ]; then
|
|
||||||
killproc $DAEMON_PATH -HUP
|
|
||||||
log_success_msg
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
RETVAL=$?
|
|
||||||
echo
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# How are we called?
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
restart
|
|
||||||
;;
|
|
||||||
reload|force-reload)
|
|
||||||
reload
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $DAEMON {start|stop|status|restart|reload}"
|
|
||||||
RETVAL=1
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit $RETVAL
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
# Provides: mon_statd
|
|
||||||
# Required-Start: $local_fs $remote_fs
|
|
||||||
# Required-Stop: $local_fs $remote_fs
|
|
||||||
# Should-Start:
|
|
||||||
# Should-Stop:
|
|
||||||
# Default-Start: 2 3 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: Configure the mon_fsstatd and mon_procd daemons.
|
|
||||||
# Description: Configures the mon_fsstatd and mon_procd daemons. It uses the
|
|
||||||
# configuration file /etc/sysconfig/mon_statd.
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
# chkconfig: 235 01 99
|
|
||||||
|
|
||||||
DAEMON=mon_statd
|
|
||||||
FSSTATD=mon_fsstatd
|
|
||||||
PROCD=mon_procd
|
|
||||||
FSSTATD_PATH=/usr/sbin/$FSSTATD
|
|
||||||
PROCD_PATH=/usr/sbin/$PROCD
|
|
||||||
CONFIG_FILE=/etc/sysconfig/$DAEMON
|
|
||||||
FSSTATD_PID_FILE=/run/$FSSTATD.pid
|
|
||||||
PROCD_PID_FILE=/run/$PROCD.pid
|
|
||||||
|
|
||||||
# source function library
|
|
||||||
. /lib/lsb/init-functions
|
|
||||||
|
|
||||||
# Source config file
|
|
||||||
if [ -f $CONFIG_FILE ]; then
|
|
||||||
. $CONFIG_FILE
|
|
||||||
fi
|
|
||||||
|
|
||||||
UDEVSETTLE=/usr/bin/udevadm
|
|
||||||
if [ ! -e $UDEVSETTLE ]
|
|
||||||
then
|
|
||||||
UDEVSETTLE=/sbin/udevsettle
|
|
||||||
UDEVSETTLE_CALL="$UDEVSETTLE --timeout=10"
|
|
||||||
else
|
|
||||||
UDEVSETTLE_CALL="$UDEVSETTLE settle --timeout=10"
|
|
||||||
fi
|
|
||||||
|
|
||||||
load_kernel_module()
|
|
||||||
{
|
|
||||||
if [ ! -e /dev/monwriter ]; then
|
|
||||||
echo "Loading monwriter module..."
|
|
||||||
modprobe monwriter 2>&1
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
if [ -e $UDEVSETTLE ]
|
|
||||||
then
|
|
||||||
$UDEVSETTLE_CALL
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start_daemon()
|
|
||||||
{
|
|
||||||
local daemon_name=$1
|
|
||||||
local daemon_interval=$2
|
|
||||||
local daemon_pid_file=$3
|
|
||||||
local daemon_path=$4
|
|
||||||
|
|
||||||
if [ ! -f $daemon_pid_file ]; then
|
|
||||||
load_kernel_module
|
|
||||||
echo -n "Starting $daemon_name:"
|
|
||||||
$daemon_path -i $daemon_interval
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
log_success_msg
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "$daemon_name (pid $(cat $daemon_pid_file)) is already running..."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
start()
|
|
||||||
{
|
|
||||||
if [ "$FSSTAT" = "yes" ]; then
|
|
||||||
start_daemon $FSSTATD $FSSTAT_INTERVAL $FSSTATD_PID_FILE \
|
|
||||||
$FSSTATD_PATH
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ "$PROC" = "yes" ]; then
|
|
||||||
start_daemon $PROCD $PROC_INTERVAL $PROCD_PID_FILE \
|
|
||||||
$PROCD_PATH
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop_daemon()
|
|
||||||
{
|
|
||||||
local daemon_name=$1
|
|
||||||
local daemon_pid_file=$2
|
|
||||||
local daemon_path=$3
|
|
||||||
|
|
||||||
echo -n "Stopping $daemon_name:"
|
|
||||||
if [ -f $daemon_pid_file ]; then
|
|
||||||
killproc $daemon_path -TERM
|
|
||||||
log_success_msg
|
|
||||||
rm -f $daemon_pid_file
|
|
||||||
else
|
|
||||||
log_failure_msg
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
stop()
|
|
||||||
{
|
|
||||||
if [ "$FSSTAT" = "yes" ]; then
|
|
||||||
stop_daemon $FSSTATD $FSSTATD_PID_FILE $FSSTATD_PATH
|
|
||||||
fi
|
|
||||||
if [ "$PROC" = "yes" ]; then
|
|
||||||
stop_daemon $PROCD $PROCD_PID_FILE $PROCD_PATH
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
restart() {
|
|
||||||
stop
|
|
||||||
start
|
|
||||||
}
|
|
||||||
|
|
||||||
status_daemon()
|
|
||||||
{
|
|
||||||
local daemon_name=$1
|
|
||||||
local daemon_pid_file=$2
|
|
||||||
local daemon_interval=$3
|
|
||||||
|
|
||||||
if [ ! -f $daemon_pid_file ]; then
|
|
||||||
echo "$daemon_name is not running."
|
|
||||||
else
|
|
||||||
echo "$daemon_name (pid $(cat $daemon_pid_file), interval: $daemon_interval) is running."
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
status()
|
|
||||||
{
|
|
||||||
status_daemon $FSSTATD $FSSTATD_PID_FILE $FSSTAT_INTERVAL
|
|
||||||
status_daemon $PROCD $PROCD_PID_FILE $PROC_INTERVAL
|
|
||||||
}
|
|
||||||
|
|
||||||
# How are we called?
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
restart|reload|force-reload)
|
|
||||||
restart
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $DAEMON {start|stop|status|restart|reload}"
|
|
||||||
exit 1
|
|
||||||
esac
|
|
||||||
|
|
||||||
exit 0
|
|
||||||
@@ -408,8 +408,10 @@ static int read_line(void)
|
|||||||
{
|
{
|
||||||
bzero(line_buffer, LINE_LENGTH);
|
bzero(line_buffer, LINE_LENGTH);
|
||||||
line_ptr = line_buffer;
|
line_ptr = line_buffer;
|
||||||
if (!fgets(line_buffer, LINE_LENGTH, stdin))
|
if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
|
||||||
|
clearerr(stdin);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
while (*line_ptr && !isgraph(*line_ptr))
|
while (*line_ptr && !isgraph(*line_ptr))
|
||||||
line_ptr++;
|
line_ptr++;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \
|
|||||||
-fno-delete-null-pointer-checks -fno-stack-protector \
|
-fno-delete-null-pointer-checks -fno-stack-protector \
|
||||||
-fexec-charset=IBM1047 -m64 -mpacked-stack \
|
-fexec-charset=IBM1047 -m64 -mpacked-stack \
|
||||||
-mstack-size=4096 -mstack-guard=128 -msoft-float \
|
-mstack-size=4096 -mstack-guard=128 -msoft-float \
|
||||||
-Wall -Wformat-security -Wextra -Werror
|
-Wall -Wformat-security -Wextra -Werror \
|
||||||
|
-Wno-array-bounds
|
||||||
|
|
||||||
FILES := stage3a.bin stage3b.bin stage3b_reloc.bin
|
FILES := stage3a.bin stage3b.bin stage3b_reloc.bin
|
||||||
|
|
||||||
@@ -68,27 +69,15 @@ endif
|
|||||||
|
|
||||||
stage3b_reloc.o: stage3b.bin
|
stage3b_reloc.o: stage3b.bin
|
||||||
|
|
||||||
stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS)
|
stage3a.elf: head.o stage3a_init.o $(ZIPL_OBJS)
|
||||||
stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS)
|
stage3b.elf: head.o $(ZIPL_OBJS)
|
||||||
stage3b_reloc.elf:
|
|
||||||
|
|
||||||
%.elf: %.o
|
%.elf: %.lds %.o
|
||||||
case $* in \
|
$(LINK) $(NO_PIE_LDFLAGS) $(NO_WARN_RWX_SEGMENTS_LDFLAGS) -Wl,-T,$< -Wl,--build-id=none -m64 -static -nostdlib $(filter %.o, $^) -o $@
|
||||||
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
|
||||||
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
|
||||||
stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
|
||||||
esac; \
|
|
||||||
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
|
||||||
@chmod a-x $@
|
@chmod a-x $@
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(OBJCOPY) -O binary \
|
$(OBJCOPY) -O binary $< $@
|
||||||
--only-section=.text* \
|
|
||||||
--only-section=.ex_table* \
|
|
||||||
--only-section=.fixup* \
|
|
||||||
--only-section=.data* \
|
|
||||||
--only-section=.rodata* \
|
|
||||||
$< $@
|
|
||||||
@chmod a-x $@
|
@chmod a-x $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|||||||
@@ -29,3 +29,8 @@ _start:
|
|||||||
brasl %r14, initialize
|
brasl %r14, initialize
|
||||||
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
.Lstack: .long STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||||
.previous
|
.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
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x0;
|
|
||||||
|
|
||||||
. = HEAP_ADDRESS;
|
. = HEAP_ADDRESS;
|
||||||
__heap_start = .;
|
__heap_start = .;
|
||||||
.heap : {
|
.heap : {
|
||||||
@@ -46,7 +44,7 @@ SECTIONS
|
|||||||
. = STAGE3A_INIT_ENTRY;
|
. = STAGE3A_INIT_ENTRY;
|
||||||
__text_init_start = .;
|
__text_init_start = .;
|
||||||
.text : {
|
.text : {
|
||||||
stage3a_init.o(.text.init)
|
*(.text.init)
|
||||||
__text_init_stop = ABSOLUTE(.);
|
__text_init_stop = ABSOLUTE(.);
|
||||||
/* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
/* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||||
* otherwise the text data could be overwritten by the original zipl stage3
|
* otherwise the text data could be overwritten by the original zipl stage3
|
||||||
@@ -56,8 +54,8 @@ SECTIONS
|
|||||||
. = 0x1000;
|
. = 0x1000;
|
||||||
ASSERT(ABSOLUTE(.) == STAGE3A_ENTRY,
|
ASSERT(ABSOLUTE(.) == STAGE3A_ENTRY,
|
||||||
"Text section doesn't conform to the described memory layout");
|
"Text section doesn't conform to the described memory layout");
|
||||||
head.o(.text.start)
|
*(.text.start)
|
||||||
*(.text)
|
*(.text .text.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
.ex_table ALIGN(16) : {
|
.ex_table ALIGN(16) : {
|
||||||
@@ -74,7 +72,7 @@ SECTIONS
|
|||||||
|
|
||||||
.rodata ALIGN(16) : {
|
.rodata ALIGN(16) : {
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
*(.rodata.*)
|
*(.rodata*)
|
||||||
}
|
}
|
||||||
|
|
||||||
.data ALIGN(16) : {
|
.data ALIGN(16) : {
|
||||||
@@ -90,14 +88,10 @@ SECTIONS
|
|||||||
ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
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 */
|
/* Sections to be discarded */
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
|
*(.interp)
|
||||||
|
*(.note.GNU-stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,3 +26,8 @@ _init:
|
|||||||
br %r1
|
br %r1
|
||||||
.Lstage3a_entry: .long STAGE3A_ENTRY
|
.Lstage3a_entry: .long STAGE3A_ENTRY
|
||||||
.previous
|
.previous
|
||||||
|
|
||||||
|
/* The code doesn't require an executable stack */
|
||||||
|
#if defined(__linux__) && defined(__ELF__)
|
||||||
|
.section .note.GNU-stack,"",%progbits
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -28,13 +28,23 @@ static inline void __noreturn load_psw(struct psw_t psw)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long get_kernel_cmdline_size(void)
|
||||||
|
{
|
||||||
|
unsigned long size = *(volatile unsigned long *)MAX_COMMAND_LINE_SIZE;
|
||||||
|
|
||||||
|
if (size != 0)
|
||||||
|
return size;
|
||||||
|
|
||||||
|
return LEGACY_COMMAND_LINE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
void __noreturn start(void)
|
void __noreturn start(void)
|
||||||
{
|
{
|
||||||
volatile struct stage3b_args *args = &loader_parms;
|
volatile struct stage3b_args *args = &loader_parms;
|
||||||
volatile struct memblob *kernel = &args->kernel;
|
volatile struct memblob *kernel = &args->kernel;
|
||||||
volatile struct memblob *cmdline = &args->cmdline;
|
volatile struct memblob *cmdline = &args->cmdline;
|
||||||
volatile struct memblob *initrd = &args->initrd;
|
volatile struct memblob *initrd = &args->initrd;
|
||||||
volatile struct psw_t psw = args->psw;
|
struct psw_t psw = args->psw;
|
||||||
|
|
||||||
/* set up ASCII and line-mode */
|
/* set up ASCII and line-mode */
|
||||||
sclp_setup(SCLP_LINE_ASCII_INIT);
|
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||||
@@ -42,14 +52,14 @@ void __noreturn start(void)
|
|||||||
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
||||||
panic(EINTERNAL, "Invalid kernel\n");
|
panic(EINTERNAL, "Invalid kernel\n");
|
||||||
|
|
||||||
if (cmdline->size > COMMAND_LINE_SIZE)
|
|
||||||
panic(EINTERNAL, "Command line is too large\n");
|
|
||||||
|
|
||||||
/* move the kernel and cut the kernel header */
|
/* move the kernel and cut the kernel header */
|
||||||
memmove((void *)IMAGE_LOAD_ADDRESS,
|
memmove((void *)IMAGE_LOAD_ADDRESS,
|
||||||
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
||||||
kernel->size - IMAGE_LOAD_ADDRESS);
|
kernel->size - IMAGE_LOAD_ADDRESS);
|
||||||
|
|
||||||
|
if (cmdline->size > get_kernel_cmdline_size())
|
||||||
|
panic(EINTERNAL, "Command line is too large\n");
|
||||||
|
|
||||||
/* move the kernel cmdline */
|
/* move the kernel cmdline */
|
||||||
memmove((void *)COMMAND_LINE,
|
memmove((void *)COMMAND_LINE,
|
||||||
(void *)cmdline->src,
|
(void *)cmdline->src,
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ ENTRY(_start)
|
|||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
. = 0x0;
|
|
||||||
|
|
||||||
. = HEAP_ADDRESS;
|
. = HEAP_ADDRESS;
|
||||||
__heap_start = .;
|
__heap_start = .;
|
||||||
.heap : {
|
.heap : {
|
||||||
@@ -34,8 +32,8 @@ SECTIONS
|
|||||||
|
|
||||||
. = STAGE3B_ENTRY;
|
. = STAGE3B_ENTRY;
|
||||||
.text : {
|
.text : {
|
||||||
head.o(.text.start)
|
*(.text.start)
|
||||||
*(.text)
|
*(.text .text.*)
|
||||||
}
|
}
|
||||||
|
|
||||||
.ex_table ALIGN(16) : {
|
.ex_table ALIGN(16) : {
|
||||||
@@ -52,7 +50,7 @@ SECTIONS
|
|||||||
|
|
||||||
.rodata ALIGN(16) : {
|
.rodata ALIGN(16) : {
|
||||||
*(.rodata)
|
*(.rodata)
|
||||||
*(.rodata.*)
|
*(.rodata*)
|
||||||
}
|
}
|
||||||
|
|
||||||
.data ALIGN(16) : {
|
.data ALIGN(16) : {
|
||||||
@@ -74,14 +72,12 @@ SECTIONS
|
|||||||
}
|
}
|
||||||
__stack_end = .;
|
__stack_end = .;
|
||||||
|
|
||||||
/* List this explicitly as otherwise .note.gnu.build-id will be
|
ASSERT(. <= IMAGE_ENTRY, "stage3b size must be smaller than 0x10000 bytes")
|
||||||
* put at 0x0 */
|
|
||||||
.notes : {
|
|
||||||
*(.note.*)
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sections to be discarded */
|
/* Sections to be discarded */
|
||||||
/DISCARD/ : {
|
/DISCARD/ : {
|
||||||
*(.eh_frame)
|
*(.eh_frame)
|
||||||
|
*(.interp)
|
||||||
|
*(.note.GNU-stack)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
.org 0x0
|
.org 0x0
|
||||||
.section .text.start
|
.section .text.start
|
||||||
.globl stage3b_reloc_start
|
.globl _start
|
||||||
stage3b_reloc_start:
|
_start:
|
||||||
/* Might be called after a diag308 so better set
|
/* Might be called after a diag308 so better set
|
||||||
* architecture and addressing mode
|
* architecture and addressing mode
|
||||||
*/
|
*/
|
||||||
@@ -53,3 +53,8 @@ stage3b_start:
|
|||||||
.incbin "stage3b.bin"
|
.incbin "stage3b.bin"
|
||||||
stage3b_end:
|
stage3b_end:
|
||||||
.previous
|
.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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,8 +4,8 @@ include ../../common.mak
|
|||||||
all:
|
all:
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man1
|
||||||
$(INSTALL) -m 644 -c genprotimg.8 $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -m 644 -c genprotimg.1 $(DESTDIR)$(MANDIR)/man1
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
.\" s390-tools is free software; you can redistribute it and/or modify
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
.\" it under the terms of the MIT license. See LICENSE for details.
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
.\"
|
.\"
|
||||||
.TH GENPROTIMG 8 "November 2020" "s390-tools"
|
.TH GENPROTIMG 1 "May 2022" "s390-tools"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
genprotimg \- Create a protected virtualization image
|
genprotimg \- Create a protected virtualization image
|
||||||
|
|
||||||
@@ -62,7 +62,8 @@ host.
|
|||||||
Specifies the certificate that is used to establish a chain of trust
|
Specifies the certificate that is used to establish a chain of trust
|
||||||
for the verification of the host-key documents. Specify this option
|
for the verification of the host-key documents. Specify this option
|
||||||
twice to specify the IBM Z signing key and the intermediate CA
|
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
|
.TP
|
||||||
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
||||||
Specifies the output file. Required.
|
Specifies the output file. Required.
|
||||||
@@ -87,12 +88,23 @@ CRLs. Optional.
|
|||||||
.TP
|
.TP
|
||||||
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
\fB\-\-root\-ca\fR=\fI\,FILE\/\fR
|
||||||
Specifies the root CA certificate for the verification. If omitted,
|
Specifies the root CA certificate for the verification. If omitted,
|
||||||
the DigiCert root CA certificate installed on the system is used. Use
|
the system wide root CAs installed on the system is used. Use
|
||||||
this only if you trust the specified certificate. Optional.
|
this only if you trust the specified certificate. Optional.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-no-verify\fR
|
\fB\-\-no-verify\fR
|
||||||
Do not require the host-key documents to be valid. For testing
|
Does not require the host-key documents to be valid.
|
||||||
purposes, do not use for a production image. Optional.
|
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
|
||||||
|
secure, random, plaintext AES-256 GCM key. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-\-enable\-dump\fR
|
||||||
|
Enable PV guest dumps. Requires the \fB\-\-comm-key\fR option. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-\-disable\-dump\fR
|
||||||
|
Disable PV guest dumps. This is the default. Optional.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-enable\-pckmo\fR
|
\fB\-\-enable\-pckmo\fR
|
||||||
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
Enable the support for the DEA, TDEA, AES, and ECC PCKMO key encryption
|
||||||
@@ -105,21 +117,25 @@ functions. Optional.
|
|||||||
\fB\-v\fR, \fB\-\-version\fR
|
\fB\-v\fR, \fB\-\-version\fR
|
||||||
Prints version information, then exits.
|
Prints version information, then exits.
|
||||||
|
|
||||||
.SH EXAMPLE
|
.SH EXAMPLES
|
||||||
|
|
||||||
|
These are examples to generate a protected virtualization image in
|
||||||
|
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR, the
|
||||||
|
initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
||||||
|
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR, the
|
||||||
|
IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
||||||
|
host-key document in \fI\,host_key.crt\/\fR. An AES-256 GCM key is stored in
|
||||||
|
\fI\,comm-key\/\fR, which is used for the PV guest dump support in the second
|
||||||
|
example.
|
||||||
|
|
||||||
|
Generate a protected virtualization image:
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
Generate a protected virtualization image in
|
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||||
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
|
|
||||||
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
Generate a protected virtualization image with PV guest dump support:
|
||||||
\fI\,parmfile\/\fR, the intermediate CA in \fI\,DigiCertCA.crt\/\fR,
|
|
||||||
the IBM Z signing key in \fI\,ibm-z-host-key-signing.crt\/\fR, and the
|
|
||||||
host-key document in \fI\,host_key.crt\/\fR:
|
|
||||||
.PP
|
|
||||||
.Vb 1
|
|
||||||
.EX
|
|
||||||
\& genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt \-o \fI\,/boot/vmlinuz.pv\/\fR
|
|
||||||
.EE
|
|
||||||
.Ve
|
|
||||||
.PP
|
.PP
|
||||||
|
.B genprotimg \-i \fI\,vmlinuz\/\fR \-r \fI\,initramfs\/\fR \-p \fI\,parmfile\/\fR \-k \fI\,host_key.crt\/\fR \-C \fI\,ibm-z-host-key-signing.crt\/\fR \-C \fI\,DigiCertCA.crt\fR \-o \fI\,/boot/vmlinuz.pv\/\fR \-\-enable\-dump \-\-comm\-key \fI\,comm-key\fR
|
||||||
|
|
||||||
.SH NOTES
|
.SH NOTES
|
||||||
.IP "1." 4
|
.IP "1." 4
|
||||||
@@ -23,6 +23,7 @@ BODY_FILE=$(mktemp)
|
|||||||
ISSUER_DN_FILE=$(mktemp)
|
ISSUER_DN_FILE=$(mktemp)
|
||||||
SUBJECT_DN_FILE=$(mktemp)
|
SUBJECT_DN_FILE=$(mktemp)
|
||||||
DEF_ISSUER_DN_FILE=$(mktemp)
|
DEF_ISSUER_DN_FILE=$(mktemp)
|
||||||
|
CANONICAL_ISSUER_DN_FILE=$(mktemp)
|
||||||
CRL_SERIAL_FILE=$(mktemp)
|
CRL_SERIAL_FILE=$(mktemp)
|
||||||
|
|
||||||
# Cleanup on exit
|
# Cleanup on exit
|
||||||
@@ -30,7 +31,7 @@ cleanup()
|
|||||||
{
|
{
|
||||||
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
||||||
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
||||||
$CRL_SERIAL_FILE
|
$CANONICAL_ISSUER_DN_FILE $CRL_SERIAL_FILE
|
||||||
}
|
}
|
||||||
trap cleanup EXIT
|
trap cleanup EXIT
|
||||||
|
|
||||||
@@ -47,13 +48,21 @@ set -e
|
|||||||
usage()
|
usage()
|
||||||
{
|
{
|
||||||
cat <<-EOF
|
cat <<-EOF
|
||||||
Usage: `basename $1` host-key-doc signing-key-cert [-c CA-cert] [-r CRL]
|
Usage: `basename $1` [-d] [-c CA-cert] [-r CRL] host-key-doc signing-key-cert
|
||||||
|
|
||||||
Verify an IBM Secure Execution host key document against
|
Verify an IBM Secure Execution host key document against
|
||||||
a signing key.
|
a signing key.
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-d disable default issuer check of host-key-doc
|
||||||
|
-c CA-cert trusted CA certificate
|
||||||
|
-r CRL list of revoked host-key-docs
|
||||||
|
|
||||||
Note that in order to have the full trust chain verified
|
Note that in order to have the full trust chain verified
|
||||||
it is necessary to provide the issueing CA's certificate.
|
it is necessary to provide the issuing CA's certificate.
|
||||||
|
The default issuer check may be disabled if a non-default
|
||||||
|
signing key certificate needs to be verified against the
|
||||||
|
CA certificate.
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
@@ -121,20 +130,34 @@ default_issuer()
|
|||||||
commonName = International Business Machines Corporation
|
commonName = International Business Machines Corporation
|
||||||
countryName = US
|
countryName = US
|
||||||
localityName = Poughkeepsie
|
localityName = Poughkeepsie
|
||||||
organizationalUnitName = IBM Z Host Key Signing Service
|
organizationalUnitName = Key Signing Service
|
||||||
organizationName = International Business Machines Corporation
|
organizationName = International Business Machines Corporation
|
||||||
stateOrProvinceName = New York
|
stateOrProvinceName = New York
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_issuer_files()
|
# As organizationalUnitName can have an arbitrary prefix but must
|
||||||
|
# end with "Key Signing Service" let's normalize the OU name by
|
||||||
|
# stripping off the prefix
|
||||||
|
verify_default_issuer()
|
||||||
{
|
{
|
||||||
default_issuer > $DEF_ISSUER_DN_FILE
|
default_issuer > $DEF_ISSUER_DN_FILE
|
||||||
|
|
||||||
if ! diff $ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
sed "s/\(^[ ]*organizationalUnitName[ ]*=[ ]*\).*\(Key Signing Service$\)/\1\2/" \
|
||||||
|
$ISSUER_DN_FILE > $CANONICAL_ISSUER_DN_FILE
|
||||||
|
|
||||||
|
if ! diff $CANONICAL_ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
||||||
then
|
then
|
||||||
echo Incorrect default issuer >&2 && exit 1
|
echo Incorrect default issuer >&2 && exit 1
|
||||||
fi
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_issuer_files()
|
||||||
|
{
|
||||||
|
if [ $1 -eq 1 ]
|
||||||
|
then
|
||||||
|
verify_default_issuer
|
||||||
|
fi
|
||||||
|
|
||||||
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
||||||
then
|
then
|
||||||
@@ -196,14 +219,16 @@ check_file()
|
|||||||
# check args
|
# check args
|
||||||
CRL_FILE=
|
CRL_FILE=
|
||||||
CA_FILE=
|
CA_FILE=
|
||||||
|
CHECK_DEFAULT_ISSUER=1
|
||||||
|
|
||||||
args=$(getopt -qu "r:c:h" $*)
|
args=$(getopt -qu "dr:c:h" $*)
|
||||||
if [ $? = 0 ]
|
if [ $? = 0 ]
|
||||||
then
|
then
|
||||||
set -- $args
|
set -- $args
|
||||||
while [ $1 != "" ]
|
while [ $1 != "" ]
|
||||||
do
|
do
|
||||||
case $1 in
|
case $1 in
|
||||||
|
-d) CHECK_DEFAULT_ISSUER=0; shift;;
|
||||||
-r) CRL_FILE=$2; shift 2;;
|
-r) CRL_FILE=$2; shift 2;;
|
||||||
-c) CA_FILE=$2; shift 2;;
|
-c) CA_FILE=$2; shift 2;;
|
||||||
-h) usage $0; exit 0;;
|
-h) usage $0; exit 0;;
|
||||||
@@ -244,7 +269,7 @@ exit 1
|
|||||||
# Verify the issuer
|
# Verify the issuer
|
||||||
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
||||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
verify_issuer_files
|
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||||
|
|
||||||
# Verify dates
|
# Verify dates
|
||||||
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
||||||
@@ -261,7 +286,7 @@ then
|
|||||||
echo -n "CRL "
|
echo -n "CRL "
|
||||||
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
||||||
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
verify_issuer_files
|
verify_issuer_files $CHECK_DEFAULT_ISSUER
|
||||||
|
|
||||||
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corp. 2020, 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef COMMON_H
|
#ifndef COMMON_H
|
||||||
#define COMMON_H
|
#define COMMON_H
|
||||||
|
|
||||||
#define GETTEXT_PACKAGE "genprotimg"
|
#define GETTEXT_PACKAGE "genprotimg"
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
#include <glib/gi18n-lib.h>
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
#include "boot/linux_layout.h"
|
#include "boot/linux_layout.h"
|
||||||
#include "boot/s390.h"
|
#include "boot/s390.h"
|
||||||
|
|||||||
@@ -29,9 +29,6 @@
|
|||||||
*/
|
*/
|
||||||
#define PV_CERTS_SECURITY_LEVEL 2
|
#define PV_CERTS_SECURITY_LEVEL 2
|
||||||
|
|
||||||
/* SKID for DigiCert Assured ID Root CA */
|
|
||||||
#define DIGICERT_ASSURED_ID_ROOT_CA_SKID "45EBA2AFF492CB82312D518BA7A7219DF36DC80F"
|
|
||||||
|
|
||||||
union ecdh_pub_key {
|
union ecdh_pub_key {
|
||||||
struct {
|
struct {
|
||||||
uint8_t x[80];
|
uint8_t x[80];
|
||||||
|
|||||||
@@ -24,11 +24,15 @@
|
|||||||
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||||
#define PV_VERSION_1 0x00000100U
|
#define PV_VERSION_1 0x00000100U
|
||||||
|
|
||||||
|
/* Internal helper macro */
|
||||||
|
#define __PV_BIT(nr) (1ULL << (63 - (nr)))
|
||||||
|
|
||||||
/* Plaintext control flags */
|
/* Plaintext control flags */
|
||||||
#define PV_PCF_PCKM_ECC (1ULL << 5) /* PCKMO encrypt-ECC-key functions allowed */
|
#define PV_PCF_ALLOW_DUMPING __PV_BIT(34) /* dumping of the configuration is allowed */
|
||||||
#define PV_PCF_PCKMO_AES (1ULL << 6) /* PCKMO encrypt-AES-key functions allowed */
|
#define PV_PCF_NO_DECRYPTION __PV_BIT(35) /* prevent Ultravisor decryption during unpack operation */
|
||||||
#define PV_PCF_PCKMO_DEA_TDEA (1ULL << 7) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
#define PV_PCF_PCKMO_DEA_TDEA __PV_BIT(56) /* PCKMO encrypt-DEA/TDEA-key functions allowed */
|
||||||
#define PV_PCF_NO_DECRYPTION (1ULL << 28) /* prevent Ultravisor decryption during unpack operation */
|
#define PV_PCF_PCKMO_AES __PV_BIT(57) /* PCKMO encrypt-AES-key functions allowed */
|
||||||
|
#define PV_PCF_PCKM_ECC __PV_BIT(58) /* PCKMO encrypt-ECC-key functions allowed */
|
||||||
|
|
||||||
/* maxima for the PV version 1 */
|
/* maxima for the PV version 1 */
|
||||||
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||||
|
|||||||
@@ -64,13 +64,17 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
{
|
{
|
||||||
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
||||||
|
|
||||||
if (args->pcf && args->allow_pckmo != PV_NOT_SET) {
|
/* Check for mutually exclusive arguments */
|
||||||
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
if (args->pcf && !(args->allow_pckmo == PV_NOT_SET &&
|
||||||
_("The '--x-pcf' and '--(enable|disable)-pckmo' options are mutually"
|
args->allow_dump == PV_NOT_SET)) {
|
||||||
" exclusive.\nUse 'genprotimg --help' for more information"));
|
g_set_error(
|
||||||
|
err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||||
|
_("The '--x-pcf' option cannot be used with the '--(enable|disable)-pckmo' or"
|
||||||
|
" '--(enable|disable)-dump' flags.\nUse 'genprotimg --help' for more information"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for unused arguments */
|
||||||
if (args->unused_values->len > 0) {
|
if (args->unused_values->len > 0) {
|
||||||
g_autofree gchar *unused = NULL;
|
g_autofree gchar *unused = NULL;
|
||||||
|
|
||||||
@@ -88,6 +92,14 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check for mandatory arguments */
|
||||||
|
if (args->allow_dump == PV_TRUE && !args->cust_comm_key_path) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Option '--allow-dump' requires the '--comm-key' option.\nUse 'genprotimg "
|
||||||
|
"--help' for more information"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!args->output_path) {
|
if (!args->output_path) {
|
||||||
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
||||||
@@ -111,7 +123,7 @@ static gint pv_args_validate_options(PvArgs *args, GError **err)
|
|||||||
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
g_strv_length(args->untrusted_cert_paths) == 0)) {
|
||||||
g_set_error(
|
g_set_error(
|
||||||
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
_("Either specify the IBM Z signing key and (DigiCert) intermediate CA certificate\n"
|
_("Either specify the IBM Z signing key and intermediate CA certificate\n"
|
||||||
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
"by using the '--cert' option, or use the '--no-verify' flag to disable the\n"
|
||||||
"host-key document verification completely (at your own risk)."));
|
"host-key document verification completely (at your own risk)."));
|
||||||
return -1;
|
return -1;
|
||||||
@@ -155,14 +167,14 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
|||||||
{
|
{
|
||||||
gchar **args_option = NULL;
|
gchar **args_option = NULL;
|
||||||
|
|
||||||
|
if (g_str_equal(option, "--comm-key"))
|
||||||
|
args_option = &args->cust_comm_key_path;
|
||||||
if (g_str_equal(option, "--root-ca"))
|
if (g_str_equal(option, "--root-ca"))
|
||||||
args_option = &args->root_ca_path;
|
args_option = &args->root_ca_path;
|
||||||
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||||
args_option = &args->output_path;
|
args_option = &args->output_path;
|
||||||
if (g_str_equal(option, "--x-comp-key"))
|
if (g_str_equal(option, "--x-comp-key"))
|
||||||
args_option = &args->xts_key_path;
|
args_option = &args->xts_key_path;
|
||||||
if (g_str_equal(option, "--x-comm-key"))
|
|
||||||
args_option = &args->cust_comm_key_path;
|
|
||||||
if (g_str_equal(option, "--x-header-key"))
|
if (g_str_equal(option, "--x-header-key"))
|
||||||
args_option = &args->cust_root_key_path;
|
args_option = &args->cust_root_key_path;
|
||||||
if (g_str_equal(option, "--x-pcf"))
|
if (g_str_equal(option, "--x-pcf"))
|
||||||
@@ -188,19 +200,6 @@ static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean cb_enable_disable_flag(const gchar *option, const gchar *value G_GNUC_UNUSED,
|
|
||||||
PvArgs *args, GError **err G_GNUC_UNUSED)
|
|
||||||
{
|
|
||||||
if (g_str_equal(option, "--enable-pckmo"))
|
|
||||||
args->allow_pckmo = PV_TRUE;
|
|
||||||
else if (g_str_equal(option, "--disable-pckmo"))
|
|
||||||
args->allow_pckmo = PV_FALSE;
|
|
||||||
else
|
|
||||||
g_assert_not_reached();
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
||||||
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
||||||
GError **err G_GNUC_UNUSED)
|
GError **err G_GNUC_UNUSED)
|
||||||
@@ -217,8 +216,51 @@ static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE) (cb_##FLAG##_##VALUE)
|
||||||
|
#define DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, VALUE) \
|
||||||
|
static gboolean MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, VALUE)( \
|
||||||
|
const gchar *option G_GNUC_UNUSED, const gchar *value G_GNUC_UNUSED, \
|
||||||
|
PvArgs *args, GError **err) \
|
||||||
|
{ \
|
||||||
|
if (!(args->allow_##FLAG == PV_NOT_SET || \
|
||||||
|
args->allow_##FLAG == VALUE)) { \
|
||||||
|
g_set_error(err, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, \
|
||||||
|
"'--enable-" #FLAG "' and '--disable-" #FLAG \
|
||||||
|
"' are mutually exclusive"); \
|
||||||
|
return FALSE; \
|
||||||
|
} \
|
||||||
|
args->allow_##FLAG = VALUE; \
|
||||||
|
return TRUE; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_MUT_EXCL_BOOL_FLAG_CBS(FLAG) \
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_TRUE) \
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CB(FLAG, PV_FALSE)
|
||||||
|
|
||||||
|
#define MUT_EXCL_BOOL_FLAG(FLAG, ENABLE_DESC, DISABLE_DESC) \
|
||||||
|
{ \
|
||||||
|
.long_name = "enable-" #FLAG, \
|
||||||
|
.short_name = 0, \
|
||||||
|
.flags = G_OPTION_FLAG_NO_ARG, \
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK, \
|
||||||
|
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_TRUE), \
|
||||||
|
.description = ENABLE_DESC, \
|
||||||
|
}, \
|
||||||
|
{ \
|
||||||
|
.long_name = "disable-" #FLAG, \
|
||||||
|
.short_name = 0, \
|
||||||
|
.flags = G_OPTION_FLAG_NO_ARG, \
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK, \
|
||||||
|
.arg_data = MUT_EXCL_BOOL_FLAG_CB_NAME(FLAG, PV_FALSE), \
|
||||||
|
.description = DISABLE_DESC, \
|
||||||
|
}
|
||||||
|
|
||||||
#define INDENT " "
|
#define INDENT " "
|
||||||
|
|
||||||
|
/* Define the callbacks for mutually exclusive command line flags */
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(dump)
|
||||||
|
DEFINE_MUT_EXCL_BOOL_FLAG_CBS(pckmo)
|
||||||
|
|
||||||
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
@@ -238,7 +280,8 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
.arg_data = &args->host_keys,
|
.arg_data = &args->host_keys,
|
||||||
.description =
|
.description =
|
||||||
_("FILE specifies a host-key document. At least\n" INDENT
|
_("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") },
|
.arg_description = _("FILE") },
|
||||||
{ .long_name = "cert",
|
{ .long_name = "cert",
|
||||||
.short_name = 'C',
|
.short_name = 'C',
|
||||||
@@ -282,21 +325,28 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
||||||
"(optional)."),
|
"(optional)."),
|
||||||
.arg_description = _("PARMFILE") },
|
.arg_description = _("PARMFILE") },
|
||||||
{.long_name = "enable-pckmo",
|
MUT_EXCL_BOOL_FLAG(
|
||||||
.short_name = 0,
|
dump,
|
||||||
.flags = G_OPTION_FLAG_NO_ARG,
|
_("Enable PV guest dumps (optional). This option\n" INDENT
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
"requires the '--comm-key' option."),
|
||||||
.arg_data = cb_enable_disable_flag,
|
_("Disable PV guest dumps (default) (optional).")),
|
||||||
.description = _("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
MUT_EXCL_BOOL_FLAG(
|
||||||
"ECC PCKMO key encryption functions (default)\n" INDENT
|
pckmo,
|
||||||
"(optional).")},
|
_("Enable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||||
{.long_name = "disable-pckmo",
|
"ECC PCKMO key encryption functions (default)\n" INDENT
|
||||||
.short_name = 0,
|
"(optional)."),
|
||||||
.flags = G_OPTION_FLAG_NO_ARG,
|
_("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
"ECC PCKMO key encryption functions (optional).")),
|
||||||
.arg_data = cb_enable_disable_flag,
|
{ .long_name = "comm-key",
|
||||||
.description = _("Disable the support for the DEA, TDEA, AES, and\n" INDENT
|
.short_name = 0,
|
||||||
"ECC PCKMO key encryption functions (optional).")},
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _(
|
||||||
|
"FILE contains the key with which you encrypt\n" INDENT
|
||||||
|
"the PV guest dump (optional). Required by\n" INDENT
|
||||||
|
"the '--enable-dump' option."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
{ .long_name = "crl",
|
{ .long_name = "crl",
|
||||||
.short_name = 0,
|
.short_name = 0,
|
||||||
.flags = G_OPTION_FLAG_NONE,
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
@@ -355,15 +405,6 @@ gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
|||||||
};
|
};
|
||||||
|
|
||||||
GOptionEntry x_entries[] = {
|
GOptionEntry x_entries[] = {
|
||||||
{ .long_name = "x-comm-key",
|
|
||||||
.short_name = 0,
|
|
||||||
.flags = G_OPTION_FLAG_FILENAME,
|
|
||||||
.arg = G_OPTION_ARG_CALLBACK,
|
|
||||||
.arg_data = cb_set_string_option,
|
|
||||||
.description = _(
|
|
||||||
"Use FILE as the customer communication key.\n" INDENT
|
|
||||||
"Optional; default: auto-generated."),
|
|
||||||
.arg_description = _("FILE") },
|
|
||||||
{ .long_name = "x-comp-key",
|
{ .long_name = "x-comp-key",
|
||||||
.short_name = 0,
|
.short_name = 0,
|
||||||
.flags = G_OPTION_FLAG_FILENAME,
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
@@ -446,6 +487,7 @@ PvArgs *pv_args_new(void)
|
|||||||
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
||||||
|
|
||||||
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
args->allow_dump = PV_NOT_SET;
|
||||||
args->allow_pckmo = PV_NOT_SET;
|
args->allow_pckmo = PV_NOT_SET;
|
||||||
return g_steal_pointer(&args);
|
return g_steal_pointer(&args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ typedef struct {
|
|||||||
gboolean offline;
|
gboolean offline;
|
||||||
gchar *pcf;
|
gchar *pcf;
|
||||||
gchar *scf;
|
gchar *scf;
|
||||||
|
PvTristate allow_dump;
|
||||||
PvTristate allow_pckmo;
|
PvTristate allow_pckmo;
|
||||||
gchar *psw_addr; /* PSW address which will be used for the start of
|
gchar *psw_addr; /* PSW address which will be used for the start of
|
||||||
* the actual component (e.g. Linux kernel)
|
* the actual component (e.g. Linux kernel)
|
||||||
|
|||||||
@@ -248,19 +248,6 @@ gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
|||||||
g_assert_not_reached();
|
g_assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert uint64_t address to byte array */
|
|
||||||
static void uint64_to_uint8_buf(uint8_t dst[8], uint64_t addr)
|
|
||||||
{
|
|
||||||
uint8_t *p = (uint8_t *)&addr;
|
|
||||||
|
|
||||||
g_assert(dst);
|
|
||||||
|
|
||||||
for (gint i = 0; i < 8; i++) {
|
|
||||||
/* cppcheck-suppress objectIndex */
|
|
||||||
dst[i] = p[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
@@ -273,11 +260,8 @@ int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
uint64_t cur_be = GUINT64_TO_BE(cur);
|
uint64_t cur_be = GUINT64_TO_BE(cur);
|
||||||
uint8_t addr_buf[8];
|
|
||||||
|
|
||||||
uint64_to_uint8_buf(addr_buf, cur_be);
|
if (EVP_DigestUpdate(ctx, &cur_be, sizeof(cur_be)) != 1) {
|
||||||
|
|
||||||
if (EVP_DigestUpdate(ctx, addr_buf, sizeof(addr_buf)) != 1) {
|
|
||||||
g_set_error(err, PV_CRYPTO_ERROR,
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
PV_CRYPTO_ERROR_INTERNAL,
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
_("EVP_DigestUpdate failed"));
|
_("EVP_DigestUpdate failed"));
|
||||||
|
|||||||
@@ -229,7 +229,9 @@ static gint pv_img_set_psw_addr(PvImage *img, const gchar *psw_addr_s,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
||||||
const gchar *scf_s, PvTristate allow_pckmo, GError **err)
|
const gchar *scf_s,
|
||||||
|
PvTristate allow_dump,
|
||||||
|
PvTristate allow_pckmo, GError **err)
|
||||||
{
|
{
|
||||||
uint64_t flags;
|
uint64_t flags;
|
||||||
|
|
||||||
@@ -247,6 +249,11 @@ static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
|||||||
img->scf = flags;
|
img->scf = flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (allow_dump == PV_TRUE)
|
||||||
|
img->pcf |= PV_PCF_ALLOW_DUMPING;
|
||||||
|
else if (allow_dump == PV_FALSE)
|
||||||
|
img->pcf &= ~PV_PCF_ALLOW_DUMPING;
|
||||||
|
|
||||||
if (allow_pckmo == PV_TRUE)
|
if (allow_pckmo == PV_TRUE)
|
||||||
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
|
img->pcf |= PV_PCF_PCKM_ECC | PV_PCF_PCKMO_AES | PV_PCF_PCKMO_DEA_TDEA;
|
||||||
else if (allow_pckmo == PV_FALSE)
|
else if (allow_pckmo == PV_FALSE)
|
||||||
@@ -304,9 +311,10 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
/* Load all untrusted certificates (e.g. IBM Z signing key and
|
||||||
* DigiCert intermediate CA) that are required to establish a chain of
|
* intermediate CA) that are required to establish a chain of trust
|
||||||
* trust starting from the host-key document up to the root CA (if not
|
* starting from the host-key document up to the root CA (if not
|
||||||
* otherwise specified that's the DigiCert Assured ID Root CA).
|
* otherwise specified that can be one of the system wide installed
|
||||||
|
* root CAs, e.g. DigiCert).
|
||||||
*/
|
*/
|
||||||
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
untrusted_certs_with_path = load_certificates(untrusted_cert_paths, err);
|
||||||
if (!untrusted_certs_with_path)
|
if (!untrusted_certs_with_path)
|
||||||
@@ -341,9 +349,8 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
* For this we must check:
|
* For this we must check:
|
||||||
*
|
*
|
||||||
* 1. Can a chain of trust be established ending in a root CA
|
* 1. Can a chain of trust be established ending in a root CA
|
||||||
* 2. Is the correct root CA ued? It has either to be the
|
* 2. Is the correct root CA used? It has either to be a system CA
|
||||||
* 'DigiCert Assured ID Root CA' or the root CA specified via
|
* or the root CA specified via command line.
|
||||||
* command line.
|
|
||||||
*/
|
*/
|
||||||
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
for (gint i = 0; i < sk_X509_num(ibm_signing_certs); ++i) {
|
||||||
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
X509 *ibm_signing_cert = sk_X509_value(ibm_signing_certs, i);
|
||||||
@@ -364,17 +371,12 @@ static gint pv_img_hostkey_verify(GSList *host_key_certs,
|
|||||||
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
if (verify_cert(ibm_signing_cert, ctx, err) < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
/* Verify the build chain of trust chain. If the user passes a
|
/* If there is a chain of trust using either the provided root
|
||||||
* trusted root CA on the command line then the check for the
|
* CA on the command line or a system wide trusted root CA.
|
||||||
* Subject Key Identifier (SKID) is skipped, otherwise let's
|
|
||||||
* check if the SKID meets our expectation.
|
|
||||||
*/
|
*/
|
||||||
if (!root_ca_path &&
|
if (check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
||||||
check_chain_parameters(X509_STORE_CTX_get0_chain(ctx),
|
err) < 0)
|
||||||
get_digicert_assured_id_root_ca_skid(),
|
|
||||||
err) < 0) {
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
|
|
||||||
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
ibm_signing_crls = store_ctx_find_valid_crls(ctx, ibm_signing_cert, err);
|
||||||
if (!ibm_signing_crls) {
|
if (!ibm_signing_crls) {
|
||||||
@@ -588,7 +590,7 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
|||||||
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
||||||
|
|
||||||
if (args->root_ca_path)
|
if (args->root_ca_path)
|
||||||
g_warning(_("A different root CA than the default DigiCert root CA is selected. Ensure that this root CA is trusted."));
|
g_warning(_("The root CA is selected through the command line. Ensure that this root CA is trusted."));
|
||||||
|
|
||||||
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
||||||
if (!ret->comps)
|
if (!ret->comps)
|
||||||
@@ -608,7 +610,9 @@ PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* set the control flags: PCF and SCF */
|
/* set the control flags: PCF and SCF */
|
||||||
if (pv_img_set_control_flags(ret, args->pcf, args->scf, args->allow_pckmo, err) < 0)
|
if (pv_img_set_control_flags(ret, args->pcf, args->scf,
|
||||||
|
args->allow_dump, args->allow_pckmo,
|
||||||
|
err) < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* read in the keys */
|
/* read in the keys */
|
||||||
|
|||||||
@@ -440,14 +440,14 @@ static int check_signature_algo_match(const EVP_PKEY *pkey, const X509 *subject,
|
|||||||
|
|
||||||
static X509_CRL *load_crl_from_bio(BIO *bio)
|
static X509_CRL *load_crl_from_bio(BIO *bio)
|
||||||
{
|
{
|
||||||
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, 0, NULL);
|
g_autoptr(X509_CRL) crl = PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL);
|
||||||
gint rc;
|
gint rc;
|
||||||
|
|
||||||
if (crl)
|
if (crl)
|
||||||
return g_steal_pointer(&crl);
|
return g_steal_pointer(&crl);
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
rc = BIO_reset(bio);
|
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;
|
return NULL;
|
||||||
|
|
||||||
/* maybe the CRL is stored in DER format */
|
/* 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);
|
return g_steal_pointer(&cert);
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
rc = BIO_reset(bio);
|
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,
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
_("unable to load certificate: '%s'"), path);
|
_("unable to load certificate: '%s'"), path);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1079,8 +1079,8 @@ int store_set_verify_param(X509_STORE *store, GError **err)
|
|||||||
g_abort();
|
g_abort();
|
||||||
|
|
||||||
/* The maximum depth level of the chain of trust for the verification of
|
/* The maximum depth level of the chain of trust for the verification of
|
||||||
* the IBM Z signing key is 2, i.e. IBM Z signing key -> (DigiCert)
|
* the IBM Z signing key is 2, i.e. IBM Z signing key -> intermediate CA
|
||||||
* intermediate CA -> (DigiCert) root CA
|
* -> root CA
|
||||||
*/
|
*/
|
||||||
X509_VERIFY_PARAM_set_depth(param, 2);
|
X509_VERIFY_PARAM_set_depth(param, 2);
|
||||||
|
|
||||||
@@ -1267,46 +1267,38 @@ static int security_level_to_bits(int level)
|
|||||||
return security_bits[level];
|
return security_bits[level];
|
||||||
}
|
}
|
||||||
|
|
||||||
static ASN1_OCTET_STRING *digicert_assured_id_root_ca;
|
|
||||||
|
|
||||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void)
|
|
||||||
{
|
|
||||||
pv_crypto_init();
|
|
||||||
return digicert_assured_id_root_ca;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Used for the caching of the downloaded CRLs */
|
/* Used for the caching of the downloaded CRLs */
|
||||||
static GHashTable *cached_crls;
|
static GHashTable *cached_crls;
|
||||||
|
|
||||||
void pv_crypto_init(void)
|
void pv_crypto_init(void)
|
||||||
{
|
{
|
||||||
if (digicert_assured_id_root_ca)
|
if (cached_crls)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
cached_crls = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
|
||||||
(GDestroyNotify)X509_CRL_free);
|
(GDestroyNotify)X509_CRL_free);
|
||||||
digicert_assured_id_root_ca = s2i_ASN1_OCTET_STRING(
|
|
||||||
NULL, NULL, DIGICERT_ASSURED_ID_ROOT_CA_SKID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pv_crypto_cleanup(void)
|
void pv_crypto_cleanup(void)
|
||||||
{
|
{
|
||||||
if (!digicert_assured_id_root_ca)
|
if (!cached_crls)
|
||||||
return;
|
return;
|
||||||
g_clear_pointer(&cached_crls, g_hash_table_destroy);
|
g_clear_pointer(&cached_crls, g_hash_table_destroy);
|
||||||
g_clear_pointer(&digicert_assured_id_root_ca, ASN1_OCTET_STRING_free);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
||||||
const ASN1_OCTET_STRING *skid, GError **err)
|
GError **err)
|
||||||
{
|
{
|
||||||
const ASN1_OCTET_STRING *ca_skid = NULL;
|
const X509_NAME *ca_x509_subject = NULL;
|
||||||
|
g_autofree gchar *ca_subject = NULL;
|
||||||
gint len = sk_X509_num(chain);
|
gint len = sk_X509_num(chain);
|
||||||
X509 *ca = NULL;
|
X509 *ca = NULL;
|
||||||
|
|
||||||
g_assert(skid);
|
|
||||||
/* at least one root and one leaf certificate must be defined */
|
/* at least one root and one leaf certificate must be defined */
|
||||||
g_assert(len >= 2);
|
if (len < 2) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("there must be at least on root and one leaf certificate in the chain of trust"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* get the root certificate of the chain of trust */
|
/* get the root certificate of the chain of trust */
|
||||||
ca = sk_X509_value(chain, len - 1);
|
ca = sk_X509_value(chain, len - 1);
|
||||||
@@ -1316,19 +1308,21 @@ gint check_chain_parameters(const STACK_OF_X509 *chain,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
ca_skid = X509_get0_subject_key_id(ca);
|
ca_x509_subject = X509_get_subject_name(ca);
|
||||||
if (!ca_skid) {
|
if (!ca_x509_subject) {
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_MALFORMED_ROOT_CA,
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
_("malformed root certificate"));
|
_("subject of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASN1_STRING_cmp(ca_skid, skid) != 0) {
|
ca_subject = X509_NAME_oneline(ca_x509_subject, NULL, 0);
|
||||||
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_WRONG_CA_USED,
|
if (!ca_subject) {
|
||||||
_("expecting DigiCert root CA to be used"));
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("subject name of the root CA cannot be retrieved"));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_info("Root CA used: '%s'", ca_subject);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ int check_crl_valid_for_cert(X509_CRL *crl, X509 *cert,
|
|||||||
gint verify_flags, GError **err);
|
gint verify_flags, GError **err);
|
||||||
void pv_crypto_init(void);
|
void pv_crypto_init(void);
|
||||||
void pv_crypto_cleanup(void);
|
void pv_crypto_cleanup(void);
|
||||||
const ASN1_OCTET_STRING *get_digicert_assured_id_root_ca_skid(void);
|
|
||||||
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
gint verify_host_key(X509 *host_key, GSList *issuer_pairs,
|
||||||
gint verify_flags, int level, GError **err);
|
gint verify_flags, int level, GError **err);
|
||||||
X509 *load_cert_from_file(const char *path, GError **err);
|
X509 *load_cert_from_file(const char *path, GError **err);
|
||||||
@@ -138,8 +137,7 @@ X509_STORE *store_setup(const gchar *root_ca_path,
|
|||||||
int store_set_verify_param(X509_STORE *store, GError **err);
|
int store_set_verify_param(X509_STORE *store, GError **err);
|
||||||
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
|
X509_CRL *load_crl_by_cert(X509 *cert, GError **err);
|
||||||
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
STACK_OF_X509_CRL *try_load_crls_by_certs(GSList *certs_with_path);
|
||||||
gint check_chain_parameters(const STACK_OF_X509 *chain,
|
gint check_chain_parameters(const STACK_OF_X509 *chain, GError **err);
|
||||||
const ASN1_OCTET_STRING *skid, GError **err);
|
|
||||||
X509_NAME *c2b_name(const X509_NAME *name);
|
X509_NAME *c2b_name(const X509_NAME *name);
|
||||||
|
|
||||||
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
STACK_OF_X509 *delete_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||||
|
|||||||
@@ -16,17 +16,17 @@ check_dep:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"hmcdrvfs", \
|
"hmcdrvfs", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0")
|
||||||
|
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse
|
FUSE_CFLAGS = -D_FILE_OFFSET_BITS=64 -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
ALL_CFLAGS += -DFUSE_USE_VERSION=26 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
|
ALL_CFLAGS += -DFUSE_USE_VERSION=30 -D_LARGEFILE_SOURCE $(FUSE_CFLAGS)
|
||||||
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
|
LDLIBS += $(FUSE_LDLIBS) -lpthread -lrt -ldl -lm
|
||||||
|
|
||||||
OBJECTS = hmcdrvfs.o
|
OBJECTS = hmcdrvfs.o
|
||||||
@@ -52,7 +52,7 @@ install-scripts: lshmc
|
|||||||
cat $$i | \
|
cat $$i | \
|
||||||
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
sed -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||||
>$(DESTDIR)$(USRSBINDIR)/$$i; \
|
>$(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(USRSBINDIR)/$$i; \
|
chown $(OWNER):$(GROUP) $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||||
chmod 755 $(DESTDIR)$(USRSBINDIR)/$$i; \
|
chmod 755 $(DESTDIR)$(USRSBINDIR)/$$i; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
|||||||
@@ -111,9 +111,6 @@ allow access by other users
|
|||||||
.B -o allow_root
|
.B -o allow_root
|
||||||
allow access by root
|
allow access by root
|
||||||
.TP
|
.TP
|
||||||
.B -o nonempty
|
|
||||||
allow mounts over non-empty file/dir
|
|
||||||
.TP
|
|
||||||
.B -o default_permissions
|
.B -o default_permissions
|
||||||
enable permission checking by kernel
|
enable permission checking by kernel
|
||||||
.TP
|
.TP
|
||||||
|
|||||||
@@ -990,7 +990,7 @@ static int hmcdrv_cache_dir(const char *dir, fuse_fill_dir_t filler, void *buf)
|
|||||||
hmcdrv_cache_refresh(path, &st, symlink);
|
hmcdrv_cache_refresh(path, &st, symlink);
|
||||||
|
|
||||||
if ((filler != NULL) &&
|
if ((filler != NULL) &&
|
||||||
(filler(buf, fname, &st, 0) != 0))
|
(filler(buf, fname, &st, 0, 0) != 0))
|
||||||
filler = NULL; /* stop filling */
|
filler = NULL; /* stop filling */
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
strftime(symlink, sizeof(symlink),
|
strftime(symlink, sizeof(symlink),
|
||||||
@@ -1109,7 +1109,8 @@ static struct hmcdrv_fuse_file *hmcdrv_file_get(const char *path)
|
|||||||
*
|
*
|
||||||
* Note: The most important function which FUSE calls (very often).
|
* Note: The most important function which FUSE calls (very often).
|
||||||
*/
|
*/
|
||||||
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf)
|
static int hmcdrv_fuse_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *UNUSED(fi))
|
||||||
{
|
{
|
||||||
struct hmcdrv_fuse_file *fp;
|
struct hmcdrv_fuse_file *fp;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
@@ -1175,12 +1176,13 @@ static int hmcdrv_fuse_opendir(const char *UNUSED(path),
|
|||||||
*/
|
*/
|
||||||
static int hmcdrv_fuse_readdir(const char *path, void *buf,
|
static int hmcdrv_fuse_readdir(const char *path, void *buf,
|
||||||
fuse_fill_dir_t filler, off_t UNUSED(offset),
|
fuse_fill_dir_t filler, off_t UNUSED(offset),
|
||||||
struct fuse_file_info *UNUSED(fi))
|
struct fuse_file_info *UNUSED(fi),
|
||||||
|
enum fuse_readdir_flags UNUSED(flags))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
|
|
||||||
pthread_mutex_lock(&hmcdrv_ctx.mutex);
|
pthread_mutex_lock(&hmcdrv_ctx.mutex);
|
||||||
ret = hmcdrv_cache_dir(path, filler, buf);
|
ret = hmcdrv_cache_dir(path, filler, buf);
|
||||||
@@ -1232,7 +1234,8 @@ static int hmcdrv_fuse_read(const char *path, char *buf, size_t size,
|
|||||||
* Return: value to be passed in the private_data field of fuse_context to
|
* Return: value to be passed in the private_data field of fuse_context to
|
||||||
* all file operations and as a parameter to the destroy() method
|
* all file operations and as a parameter to the destroy() method
|
||||||
*/
|
*/
|
||||||
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn))
|
static void *hmcdrv_fuse_init(struct fuse_conn_info *UNUSED(conn),
|
||||||
|
struct fuse_config *UNUSED(cfg))
|
||||||
{
|
{
|
||||||
pthread_mutexattr_t attr;
|
pthread_mutexattr_t attr;
|
||||||
|
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ else # HAVE_FUSE
|
|||||||
# FUSE
|
# FUSE
|
||||||
#
|
#
|
||||||
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse)
|
FUSE_CFLAGS = $(shell pkg-config --silence-errors --cflags fuse3)
|
||||||
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse)
|
FUSE_LDLIBS = $(shell pkg-config --silence-errors --libs fuse3)
|
||||||
else
|
else
|
||||||
FUSE_CFLAGS = -I/usr/include/fuse
|
FUSE_CFLAGS = -I/usr/include/fuse3
|
||||||
FUSE_LDLIBS = -lfuse
|
FUSE_LDLIBS = -lfuse3
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -67,8 +67,9 @@ check-dep-fuse:
|
|||||||
$(call check_dep, \
|
$(call check_dep, \
|
||||||
"hsavmcore", \
|
"hsavmcore", \
|
||||||
"fuse.h", \
|
"fuse.h", \
|
||||||
"fuse-devel or libfuse-dev", \
|
"fuse3-devel or libfuse3-dev", \
|
||||||
"HAVE_FUSE=0")
|
"HAVE_FUSE=0", \
|
||||||
|
"-DFUSE_USE_VERSION=30")
|
||||||
touch check-dep-fuse
|
touch check-dep-fuse
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ sudo reboot
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo dnf install -y fuse fuse-devel systemd-devel
|
sudo dnf install -y fuse3 fuse3-devel systemd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ sudo reboot
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo zypper install -y fuse fuse-devel systemd-devel
|
sudo zypper install -y fuse3 fuse3-devel systemd-devel
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
## Dependencies
|
## Dependencies
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
sudo apt-get install -y make gcc kdump-tools fuse libfuse-dev libsystemd-dev
|
sudo apt-get install -y make gcc kdump-tools fuse3 libfuse3-dev libsystemd-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
## Build hsavmcore
|
## Build hsavmcore
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#define FUSE_USE_VERSION 26
|
#define FUSE_USE_VERSION 30
|
||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
|
|
||||||
#include "lib/util_log.h"
|
#include "lib/util_log.h"
|
||||||
@@ -31,8 +31,11 @@ struct vmcore_overlay {
|
|||||||
bool fuse_debug;
|
bool fuse_debug;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
|
static int vmcore_fuse_getattr(const char *path, struct stat *stbuf,
|
||||||
|
struct fuse_file_info *fi)
|
||||||
{
|
{
|
||||||
|
(void)fi;
|
||||||
|
|
||||||
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
|
struct vmcore_overlay *overlay = fuse_get_context()->private_data;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
@@ -54,18 +57,20 @@ static int vmcore_fuse_getattr(const char *path, struct stat *stbuf)
|
|||||||
|
|
||||||
static int vmcore_fuse_readdir(const char *path, void *buf,
|
static int vmcore_fuse_readdir(const char *path, void *buf,
|
||||||
fuse_fill_dir_t filler, off_t offset,
|
fuse_fill_dir_t filler, off_t offset,
|
||||||
struct fuse_file_info *fi)
|
struct fuse_file_info *fi,
|
||||||
|
enum fuse_readdir_flags flags)
|
||||||
{
|
{
|
||||||
(void)offset;
|
(void)offset;
|
||||||
(void)fi;
|
(void)fi;
|
||||||
|
(void)flags;
|
||||||
|
|
||||||
if (strcmp(path, ROOT_DIR) != 0)
|
if (strcmp(path, ROOT_DIR) != 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
/* We have only one file */
|
/* We have only one file */
|
||||||
filler(buf, ".", NULL, 0);
|
filler(buf, ".", NULL, 0, 0);
|
||||||
filler(buf, "..", NULL, 0);
|
filler(buf, "..", NULL, 0, 0);
|
||||||
filler(buf, VMCORE_FILE, NULL, 0);
|
filler(buf, VMCORE_FILE, NULL, 0, 0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ all:
|
|||||||
install: hsci
|
install: hsci
|
||||||
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
$(SED) -e 's/%S390_TOOLS_VERSION%/$(S390_TOOLS_RELEASE)/' \
|
||||||
< hsci >$(DESTDIR)$(BINDIR)/hsci; \
|
< hsci >$(DESTDIR)$(BINDIR)/hsci; \
|
||||||
chown $(OWNER).$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
|
chown $(OWNER):$(GROUP) $(DESTDIR)$(BINDIR)/hsci; \
|
||||||
chmod 755 $(DESTDIR)$(BINDIR)/hsci; \
|
chmod 755 $(DESTDIR)$(BINDIR)/hsci; \
|
||||||
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
$(INSTALL) -d -m 755 $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man8
|
||||||
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 hsci.8 \
|
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 hsci.8 \
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "table.h"
|
#include "table.h"
|
||||||
|
|
||||||
#define SD_DG_INIT_INTERVAL_MS 200
|
#define SD_DG_INIT_INTERVAL_SEC 1
|
||||||
#define SD_SYS_ID_SIZE 9
|
#define SD_SYS_ID_SIZE 9
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ void sd_update(void)
|
|||||||
*/
|
*/
|
||||||
void sd_dg_register(struct sd_dg *dg, int has_core_data)
|
void sd_dg_register(struct sd_dg *dg, int has_core_data)
|
||||||
{
|
{
|
||||||
struct timespec ts = {0, SD_DG_INIT_INTERVAL_MS * 1000000};
|
struct timespec ts = {SD_DG_INIT_INTERVAL_SEC, 0};
|
||||||
struct sd_sys_item *sys_item;
|
struct sd_sys_item *sys_item;
|
||||||
struct sd_cpu_item *cpu_item;
|
struct sd_cpu_item *cpu_item;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|||||||
229
include/boot/boot_defs.h
Normal file
229
include/boot/boot_defs.h
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
/*
|
||||||
|
* Boot and dump related definitions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
#ifndef BOOT_DEFS_H
|
||||||
|
#define BOOT_DEFS_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
|
#define ZIPL_MAGIC "zIPL"
|
||||||
|
#define ZIPL_MAGIC_SIZE 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ECKD dump parameter
|
||||||
|
*/
|
||||||
|
struct eckd_dump_param {
|
||||||
|
uint32_t blk_start;
|
||||||
|
uint32_t blk_end;
|
||||||
|
uint16_t blk_size;
|
||||||
|
uint8_t num_heads;
|
||||||
|
uint8_t bpt;
|
||||||
|
char reserved[4];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FBA dump parameter
|
||||||
|
*/
|
||||||
|
struct fba_dump_param {
|
||||||
|
uint32_t res1;
|
||||||
|
uint32_t blk_start;
|
||||||
|
uint32_t res2;
|
||||||
|
uint32_t blk_end;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SCSI dump parameter
|
||||||
|
*/
|
||||||
|
struct scsi_dump_param {
|
||||||
|
uint64_t block;
|
||||||
|
uint64_t reserved;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Layout of block pointer for linear devices
|
||||||
|
* e.g. SCSI
|
||||||
|
*/
|
||||||
|
struct linear_blockptr {
|
||||||
|
uint64_t blockno;
|
||||||
|
uint16_t size;
|
||||||
|
uint16_t blockct;
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
uint16_t size;
|
||||||
|
uint8_t blockct;
|
||||||
|
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_TYPE_EXECUTE = 0x01,
|
||||||
|
COMPONENT_TYPE_LOAD = 0x02,
|
||||||
|
COMPONENT_TYPE_SIGNATURE = 0x03
|
||||||
|
} component_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
COMPONENT_HEADER_IPL = 0x00,
|
||||||
|
COMPONENT_HEADER_DUMP = 0x01
|
||||||
|
} component_header_type;
|
||||||
|
|
||||||
|
struct component_header {
|
||||||
|
uint8_t magic[4];
|
||||||
|
uint8_t type;
|
||||||
|
uint8_t reserved[27];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct signature_header {
|
||||||
|
uint8_t format;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
uint32_t length;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
uint64_t load_address;
|
||||||
|
uint64_t load_psw;
|
||||||
|
struct signature_header sig_head;
|
||||||
|
} component_data;
|
||||||
|
|
||||||
|
struct component_entry {
|
||||||
|
uint8_t data[23];
|
||||||
|
uint8_t type;
|
||||||
|
component_data compdat;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/* SCSI dump super block */
|
||||||
|
|
||||||
|
struct scsi_dump_sb {
|
||||||
|
uint64_t magic;
|
||||||
|
uint64_t version;
|
||||||
|
uint64_t part_start;
|
||||||
|
uint64_t part_size;
|
||||||
|
uint64_t dump_offset;
|
||||||
|
uint64_t dump_size;
|
||||||
|
uint64_t csum_offset;
|
||||||
|
uint64_t csum_size;
|
||||||
|
uint64_t csum;
|
||||||
|
};
|
||||||
|
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 */
|
||||||
|
#define SCSI_DUMP_SB_SEED 0x12345678
|
||||||
|
#define SCSI_DUMP_SB_CSUM_SIZE 4096
|
||||||
|
|
||||||
|
/* Boot info */
|
||||||
|
|
||||||
|
#define BOOT_INFO_VERSION 1
|
||||||
|
#define BOOT_INFO_MAGIC "zIPL"
|
||||||
|
|
||||||
|
#define BOOT_INFO_DEV_TYPE_ECKD 0x00
|
||||||
|
#define BOOT_INFO_DEV_TYPE_FBA 0x01
|
||||||
|
#define BOOT_INFO_DEV_TYPE_SCSI 0x02
|
||||||
|
|
||||||
|
#define BOOT_INFO_BP_TYPE_IPL 0x00
|
||||||
|
#define BOOT_INFO_BP_TYPE_DUMP 0x01
|
||||||
|
|
||||||
|
#ifdef __s390x__
|
||||||
|
#define BOOT_INFO_FLAGS_ARCH 0x01
|
||||||
|
#else
|
||||||
|
#define BOOT_INFO_FLAGS_ARCH 0x00
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct boot_info_bp_dump {
|
||||||
|
union {
|
||||||
|
struct eckd_dump_param eckd;
|
||||||
|
struct fba_dump_param fba;
|
||||||
|
struct scsi_dump_param scsi;
|
||||||
|
} param;
|
||||||
|
uint8_t unused[16];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct boot_info_bp_ipl {
|
||||||
|
union {
|
||||||
|
struct eckd_blockptr_legacy eckd_legacy;
|
||||||
|
struct eckd_blockptr eckd;
|
||||||
|
struct linear_blockptr lin;
|
||||||
|
} bm_ptr;
|
||||||
|
uint8_t unused[16];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct boot_info {
|
||||||
|
char magic[4];
|
||||||
|
uint8_t version;
|
||||||
|
uint8_t bp_type;
|
||||||
|
uint8_t dev_type;
|
||||||
|
uint8_t flags;
|
||||||
|
union {
|
||||||
|
struct boot_info_bp_dump dump;
|
||||||
|
struct boot_info_bp_ipl ipl;
|
||||||
|
} bp;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define DISK_LAYOUT_ID 0x00000001
|
||||||
|
|
||||||
|
struct scsi_mbr {
|
||||||
|
uint8_t magic[4];
|
||||||
|
uint32_t version_id;
|
||||||
|
uint8_t reserved[8];
|
||||||
|
struct linear_blockptr program_table_pointer;
|
||||||
|
uint8_t reserved2[0x50];
|
||||||
|
struct boot_info boot_info;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#endif /* BOOT_DEFS_H */
|
||||||
@@ -23,10 +23,11 @@
|
|||||||
#define INITRD_SIZE _AC(0x10410, UL)
|
#define INITRD_SIZE _AC(0x10410, UL)
|
||||||
#define OLDMEM_BASE _AC(0x10418, UL)
|
#define OLDMEM_BASE _AC(0x10418, UL)
|
||||||
#define OLDMEM_SIZE _AC(0x10420, UL)
|
#define OLDMEM_SIZE _AC(0x10420, UL)
|
||||||
|
#define MAX_COMMAND_LINE_SIZE _AC(0x10430, UL)
|
||||||
#define COMMAND_LINE _AC(0x10480, UL)
|
#define COMMAND_LINE _AC(0x10480, UL)
|
||||||
|
|
||||||
/* Parameter sizes */
|
/* Parameter sizes */
|
||||||
#define COMMAND_LINE_SIZE 896
|
#define LEGACY_COMMAND_LINE_SIZE 896
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|||||||
@@ -14,12 +14,18 @@
|
|||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
#include "linux_layout.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_DESC _AC(0x78, UL)
|
||||||
#define STAGE2_ENTRY _AC(0x2018, UL)
|
#define STAGE2_ENTRY _AC(0x2018, UL)
|
||||||
#define STAGE2_HEAP_ADDRESS _AC(0x6000, UL)
|
#define STAGE2_HEAP_ADDRESS _AC(0x6000, UL)
|
||||||
#define STAGE2_HEAP_SIZE _AC(0x3000, UL)
|
#define STAGE2_HEAP_SIZE _AC(0x3000, UL)
|
||||||
#define STAGE2_STACK_ADDRESS _AC(0xe400, UL)
|
#define STAGE2_STACK_ADDRESS _AC(0xe400, UL)
|
||||||
#define STAGE2_STACK_SIZE _AC(0x1c00, UL)
|
#define STAGE2_STACK_SIZE _AC(0x1c00, UL)
|
||||||
|
#define STAGE2_MAX_SIZE _AC(0x3000, UL)
|
||||||
|
|
||||||
#define STAGE3_ENTRY _AC(0xa000, UL)
|
#define STAGE3_ENTRY _AC(0xa000, UL)
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
#define __LC_IPLDEV 0x0c6c
|
#define __LC_IPLDEV 0x0c6c
|
||||||
#define __LC_OS_INFO 0x0e18
|
#define __LC_OS_INFO 0x0e18
|
||||||
|
|
||||||
|
#define LOWCORE_SIZE _AC(0x2000, UL)
|
||||||
|
|
||||||
#define PAGE_SIZE _AC(4096, UL)
|
#define PAGE_SIZE _AC(4096, UL)
|
||||||
|
|
||||||
/* Minimum size of a stack frame in bytes */
|
/* Minimum size of a stack frame in bytes */
|
||||||
@@ -56,6 +58,26 @@ struct psw32_t {
|
|||||||
|
|
||||||
void load_wait_psw(uint64_t, struct psw_t *);
|
void load_wait_psw(uint64_t, struct psw_t *);
|
||||||
|
|
||||||
|
struct subchannel_id {
|
||||||
|
uint32_t cssid:8;
|
||||||
|
uint32_t:4;
|
||||||
|
uint32_t m:1;
|
||||||
|
uint32_t ssid:2;
|
||||||
|
uint32_t one:1;
|
||||||
|
uint32_t sch_no:16;
|
||||||
|
} __packed __aligned(4);
|
||||||
|
|
||||||
|
struct tpi_info {
|
||||||
|
struct subchannel_id schid;
|
||||||
|
uint32_t intparm;
|
||||||
|
uint32_t adapter_IO:1;
|
||||||
|
uint32_t directed_irq:1;
|
||||||
|
uint32_t isc:3;
|
||||||
|
uint32_t:12;
|
||||||
|
uint32_t type:3;
|
||||||
|
uint32_t:12;
|
||||||
|
} __packed __aligned(4);
|
||||||
|
|
||||||
struct _lowcore {
|
struct _lowcore {
|
||||||
uint8_t pad_0x0000[0x0014-0x0000]; /* 0x0000 */
|
uint8_t pad_0x0000[0x0014-0x0000]; /* 0x0000 */
|
||||||
uint32_t ipl_parmblock_ptr; /* 0x0014 */
|
uint32_t ipl_parmblock_ptr; /* 0x0014 */
|
||||||
@@ -78,10 +100,15 @@ struct _lowcore {
|
|||||||
uint8_t pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */
|
uint8_t pad_0x00a4[0x00a8-0x00a4]; /* 0x00a4 */
|
||||||
uint64_t trans_exc_code; /* 0x00a8 */
|
uint64_t trans_exc_code; /* 0x00a8 */
|
||||||
uint64_t monitor_code; /* 0x00b0 */
|
uint64_t monitor_code; /* 0x00b0 */
|
||||||
uint16_t subchannel_id; /* 0x00b8 */
|
union {
|
||||||
uint16_t subchannel_nr; /* 0x00ba */
|
struct {
|
||||||
uint32_t io_int_parm; /* 0x00bc */
|
uint16_t subchannel_id; /* 0x00b8 */
|
||||||
uint32_t io_int_word; /* 0x00c0 */
|
uint16_t subchannel_nr; /* 0x00ba */
|
||||||
|
uint32_t io_int_parm; /* 0x00bc */
|
||||||
|
uint32_t io_int_word; /* 0x00c0 */
|
||||||
|
};
|
||||||
|
struct tpi_info tpi_info; /* 0x00b8 */
|
||||||
|
};
|
||||||
uint8_t pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */
|
uint8_t pad_0x00c4[0x00c8-0x00c4]; /* 0x00c4 */
|
||||||
uint32_t stfl_fac_list; /* 0x00c8 */
|
uint32_t stfl_fac_list; /* 0x00c8 */
|
||||||
uint8_t pad_0x00cc[0x00e8-0x00cc]; /* 0x00cc */
|
uint8_t pad_0x00cc[0x00e8-0x00cc]; /* 0x00cc */
|
||||||
@@ -210,6 +237,7 @@ struct _lowcore {
|
|||||||
/* align to the top of the prefix area */
|
/* align to the top of the prefix area */
|
||||||
uint8_t pad_0x1900[0x2000-0x1900]; /* 0x1900 */
|
uint8_t pad_0x1900[0x2000-0x1900]; /* 0x1900 */
|
||||||
} __packed __aligned(8192);
|
} __packed __aligned(8192);
|
||||||
|
STATIC_ASSERT(sizeof(struct _lowcore) == LOWCORE_SIZE)
|
||||||
|
|
||||||
#define S390_lowcore (*((struct _lowcore *) 0))
|
#define S390_lowcore (*((struct _lowcore *) 0))
|
||||||
|
|
||||||
|
|||||||
95
include/lib/ap.h
Normal file
95
include/lib/ap.h
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/*
|
||||||
|
* libap - A collection of tools for ap/vfio-ap management
|
||||||
|
*
|
||||||
|
* 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_AP_H
|
||||||
|
#define LIB_AP_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "lib/util_list.h"
|
||||||
|
|
||||||
|
#define VFIO_AP_PATH "/sys/devices/vfio_ap"
|
||||||
|
#define VFIO_AP_PARENT_PATH "devices/vfio_ap/matrix"
|
||||||
|
#define VFIO_AP_CONFIG_PATH "/etc/mdevctl.d/matrix"
|
||||||
|
#define VFIO_AP_TYPE "vfio_ap-passthrough"
|
||||||
|
#define AP_UDEV_FILE "/etc/udev/rules.d/41-ap.rules"
|
||||||
|
#define AP_LOCKFILE "/run/lock/s390apconfig.lock"
|
||||||
|
|
||||||
|
#define AP_LOCK_RETRIES 15
|
||||||
|
|
||||||
|
/* apmask and aqmask are each represented as 67 character strings with:
|
||||||
|
* '0x' leading characters
|
||||||
|
* 64 hex digits (to represent 256 bits)
|
||||||
|
* terminating character
|
||||||
|
*/
|
||||||
|
#define AP_MASK_SIZE 67
|
||||||
|
#define AP_MAX_MASK_VALUE 255
|
||||||
|
|
||||||
|
/* List structure used for keeping track of lists of adapter/domain IDs */
|
||||||
|
struct vfio_ap_node {
|
||||||
|
struct util_list_node node; /* prev/next list info */
|
||||||
|
unsigned int id; /* list entry (adapter, domain, etc) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Structure used to represent a vfio_ap-passthrough device configuration.
|
||||||
|
* The list of adapters and domains can be used to derive the APQNs for the
|
||||||
|
* device. The type value is used to verify that the device (when read from
|
||||||
|
* a mdevctl config file) is of type vfio_ap-passthrough. The manual value
|
||||||
|
* represents whether the device is started on-demand after boot (true) or
|
||||||
|
* automatically during boot (false).
|
||||||
|
*/
|
||||||
|
struct vfio_ap_device {
|
||||||
|
char *uuid; /* Unique ID for this mdev */
|
||||||
|
struct util_list *adapters; /* List of adapters for device */
|
||||||
|
struct util_list *domains; /* List of usage domains for device */
|
||||||
|
struct util_list *controls; /* List of control domains for device */
|
||||||
|
char *type; /* mdev type string */
|
||||||
|
bool manual; /* manual/auto start setting for mdev */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* General Utility Functions */
|
||||||
|
void print_ap_device(struct vfio_ap_device *dev);
|
||||||
|
bool is_valid_uuid(const char *uuid);
|
||||||
|
int ap_test_bit(int n, const char *hexbytestr);
|
||||||
|
void ap_set_bit(int n, char *hexbytestr, bool val);
|
||||||
|
|
||||||
|
/* Path-related functions */
|
||||||
|
char *path_get_vfio_ap_mdev(const char *uuid);
|
||||||
|
char *path_get_vfio_ap_mdev_config(const char *uuid);
|
||||||
|
char *path_get_vfio_ap_attr(const char *uuid, const char *attr);
|
||||||
|
char *path_get_ap_udev(void);
|
||||||
|
|
||||||
|
/* Functions for manipulating sysfs to read active device info */
|
||||||
|
void vfio_ap_parse_matrix(struct vfio_ap_device *dev, char *matrix);
|
||||||
|
void vfio_ap_sort_matrix_results(struct vfio_ap_device *dev);
|
||||||
|
void vfio_ap_parse_control(struct vfio_ap_device *dev, char *control);
|
||||||
|
|
||||||
|
/* Functions for reading JSON device config */
|
||||||
|
int vfio_ap_read_device_config(const char *path, struct vfio_ap_device *dev);
|
||||||
|
|
||||||
|
/* Functions for managing vfio_ap device structures */
|
||||||
|
struct vfio_ap_device *vfio_ap_device_new(void);
|
||||||
|
void vfio_ap_device_clear(struct vfio_ap_device *dev);
|
||||||
|
void vfio_ap_device_free(struct vfio_ap_device *dev);
|
||||||
|
|
||||||
|
/* Functions for acquiring current vfio_ap device info */
|
||||||
|
int ap_read_sysfs_masks(char *ap, char *aq, int size);
|
||||||
|
bool ap_read_udev_masks(char *path, char *ap, char *aq, bool *read_ap,
|
||||||
|
bool *read_aq);
|
||||||
|
void ap_mask_to_list(char *mask, struct util_list *list);
|
||||||
|
void ap_list_remove_all(struct util_list *list);
|
||||||
|
|
||||||
|
/* Lock Functions */
|
||||||
|
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 <stdio.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
/* A bus id of a DASD is 8 characters long. E.g. 0.0.4711 */
|
/* the definition of a BUSID in the DASD driver is 20 */
|
||||||
#define DASD_BUS_ID_SIZE 9
|
#define DASD_BUS_ID_SIZE 20
|
||||||
|
|
||||||
typedef struct dasd_information2_t {
|
typedef struct dasd_information2_t {
|
||||||
unsigned int devno; /* S/390 devno */
|
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_RECORD_ID 4
|
||||||
#define DASD_FMT_ERR_KEY_LENGTH 5
|
#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__
|
#ifndef __linux__
|
||||||
/* definition from hdreg.h */
|
/* definition from hdreg.h */
|
||||||
struct hd_geometry {
|
struct hd_geometry {
|
||||||
@@ -207,27 +269,29 @@ struct hd_geometry {
|
|||||||
#define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2)
|
#define BIODASDRSRV _IO(DASD_IOCTL_LETTER, 2)
|
||||||
/* Release the device for the current LPAR */
|
/* Release the device for the current LPAR */
|
||||||
#define BIODASDRLSE _IO(DASD_IOCTL_LETTER, 3)
|
#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) */
|
/* Get information on a dasd device (enhanced) */
|
||||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
|
#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 BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
|
||||||
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER, 1, format_data_t)
|
#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 */
|
/* Release Allocated Space */
|
||||||
#define BIODASDRAS _IOW(DASD_IOCTL_LETTER, 3, format_data_t)
|
#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 */
|
/* Check device format according to format_data_t */
|
||||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_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> */
|
#ifndef __linux__ /* from <linux/hdreg.h> */
|
||||||
#define HDIO_GETGEO 0x0301
|
#define HDIO_GETGEO 0x0301
|
||||||
#endif
|
#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_reread_partition_table(const char *device, int ntries);
|
||||||
int dasd_disk_reserve(const char *device);
|
int dasd_disk_reserve(const char *device);
|
||||||
int dasd_disk_release(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 */
|
#endif /* LIB_DASD_BASE_H */
|
||||||
|
|||||||
166
include/lib/libcpumf.h
Normal file
166
include/lib/libcpumf.h
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBCPUMF_H
|
||||||
|
#define LIBCPUMF_H
|
||||||
|
|
||||||
|
#include <sched.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define S390_CPUMF_CF "/sys/devices/cpum_cf/"
|
||||||
|
#define S390_CPUMF_CFDIAG "/sys/devices/cpum_cf_diag/"
|
||||||
|
#define S390_CPUMF_SF "/sys/devices/cpum_sf/"
|
||||||
|
#define S390_CPUS_POSSIBLE "/sys/devices/system/cpu/possible"
|
||||||
|
#define S390_CPUS_ONLINE "/sys/devices/system/cpu/online"
|
||||||
|
#define S390_CPUMSF_BUFFERSZ "/sys/module/kernel/parameters/cpum_sfb_size"
|
||||||
|
#define S390_SYSFS_PAI_CRYPTO "/sys/devices/pai_crypto/"
|
||||||
|
#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.
|
||||||
|
*
|
||||||
|
* Return the PMU type number assigned to this PMU by the kernel. This is
|
||||||
|
* a non zero number.
|
||||||
|
*
|
||||||
|
* @param[in] dirname Name of the event directory in sysfs
|
||||||
|
* @retval >=0 Number of PMU assigned by the kernel
|
||||||
|
* @retval -1 PMU unknown to kernel
|
||||||
|
*/
|
||||||
|
int libcpumf_pmutype(const char *dirname);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read out the PMU name from a given type.
|
||||||
|
*
|
||||||
|
* Return the PMU name this PMU was registered in kernel. If the PMU was
|
||||||
|
* registered without a name, it is not listed in the directory.
|
||||||
|
* The caller must free the memory returned by name.
|
||||||
|
*
|
||||||
|
* @param[in] wanted_type Type number of the PMU
|
||||||
|
* @param[out] name Name of the PMU (when retval is 0)
|
||||||
|
* @retval 0 PMU wanted_type detected and PMU name valid
|
||||||
|
* @retval -1 No PMU with wanted_type
|
||||||
|
*/
|
||||||
|
int libcpumf_pmuname(unsigned int wanted_type, char **name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read out the CPU list from a given file name, for example from files
|
||||||
|
* /sys/devices/system/cpu/online or /sys/devices/system/cpu/possible.
|
||||||
|
*
|
||||||
|
* Return the cpu_set_t created from parsing the CPU list in the second
|
||||||
|
* parameter.
|
||||||
|
*
|
||||||
|
* @param[in] buffer Comma separated string of a CPU list
|
||||||
|
* @param[in] filename Name of a sysfs CPU list file name
|
||||||
|
* @param[out] mask Converted buffer into cpu_set_t mask structure
|
||||||
|
* @retval 0 Successful conversion of cpulist
|
||||||
|
* @retval -1 Unsuccessful conversion of cpulist
|
||||||
|
*/
|
||||||
|
int libcpumf_cpuset(const char *buffer, cpu_set_t *mask);
|
||||||
|
int libcpumf_cpuset_fn(const char *filename, cpu_set_t *mask);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Counting Facility hardware information
|
||||||
|
*
|
||||||
|
* Return true if CPU Measurement Counter facility information has been
|
||||||
|
* retrieved and is valid.
|
||||||
|
*
|
||||||
|
* Return false if the information could not be extracted from the file.
|
||||||
|
*
|
||||||
|
* @param[out] cfvn Contains CPUMF counter first version number
|
||||||
|
* @param[out] csvn Contains CPUMF counter second version number
|
||||||
|
* @param[out] auth Contains CPUMF counter set authorization level
|
||||||
|
* @retval true Information returned in parameters is valid
|
||||||
|
* @retval false Information could not be retrieved
|
||||||
|
*/
|
||||||
|
bool libcpumf_cpumcf_info(int *cfvn, int *csvn, int *auth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Counter Facility is available.
|
||||||
|
*
|
||||||
|
* @retval true CPU Measurement Counter Facility is available
|
||||||
|
* @retval false CPU Measurement Counter Facility is not available
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_cpumcf(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Sampling Facility hardware information
|
||||||
|
*
|
||||||
|
* Read all necessary information from /sysfs file /proc/service_levels
|
||||||
|
* to return CPU Measurement Counter Sampling facility information
|
||||||
|
* characteristics.
|
||||||
|
* Return true on success and false when the data can not be retrieved.
|
||||||
|
*
|
||||||
|
* @param[out] min Minimum supported sampling interval
|
||||||
|
* @param[out] max Maximum supported sampling interval
|
||||||
|
* @param[out] speed Current CPU speed, number of CPU cylces per
|
||||||
|
* microsecond
|
||||||
|
* @param[out] basic_sz Basic sample size in bytes
|
||||||
|
* @param[out] diag_sz Diagnostic sample size in bytes
|
||||||
|
* @retval true Information returned in parameters is valid
|
||||||
|
* @retval false Information could not be retrieved
|
||||||
|
*/
|
||||||
|
bool libcpumf_cpumsf_info(unsigned long *min, unsigned long *max,
|
||||||
|
unsigned long *speed, int *basic_sz, int *diag_sz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Sampling Facility is available.
|
||||||
|
*
|
||||||
|
* @retval true CPU Measurement Sampling Facility is available
|
||||||
|
* @retval false CPU Measurement Sampling Facility is not available
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_cpumsf(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if CPU Measurement Sampling Facility buffer sizes are
|
||||||
|
* available.
|
||||||
|
*
|
||||||
|
* @retval true CPU Measurement Sampling Facility buffer sizes are
|
||||||
|
* available
|
||||||
|
* @retval false CPU Measurement Sampling Facility buffer sizes are
|
||||||
|
* not available
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_sfb(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read CPU Measurement Sampling Facility supported sampling buffer sizes.
|
||||||
|
*
|
||||||
|
* Return the minimum and maximum CPU Measurement sampling facitity buffer
|
||||||
|
* sizes supported.
|
||||||
|
* Return true on success and false otherwise.
|
||||||
|
*
|
||||||
|
* @param[out] min Minimum supported sampling buffer size
|
||||||
|
* @param[out] max Maximum supported sampling buffer size
|
||||||
|
* @retval true Information returned in parameters is valid
|
||||||
|
* @retval false Information could not be retrieved
|
||||||
|
*/
|
||||||
|
bool libcpumf_sfb_info(unsigned long *min, unsigned long *max);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if PAI_CRYPTO counter Facility is supported.
|
||||||
|
*
|
||||||
|
* @retval true PAI_CRYPTO counter Facility is available
|
||||||
|
* @retval false PAI_CRYPTO counter Facility is not available
|
||||||
|
*/
|
||||||
|
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.
|
||||||
|
*
|
||||||
|
* @retval true PAI_NNPA counter Facility is available
|
||||||
|
* @retval false PAI_NNPA counter Facility is not available
|
||||||
|
*/
|
||||||
|
bool libcpumf_have_pai_nnpa(void);
|
||||||
|
#endif
|
||||||
@@ -26,6 +26,7 @@ enum util_arch_machine_type {
|
|||||||
UTIL_ARCH_MACHINE_TYPE_Z14_ZR1 = 3907,
|
UTIL_ARCH_MACHINE_TYPE_Z14_ZR1 = 3907,
|
||||||
UTIL_ARCH_MACHINE_TYPE_Z15 = 8561,
|
UTIL_ARCH_MACHINE_TYPE_Z15 = 8561,
|
||||||
UTIL_ARCH_MACHINE_TYPE_Z15_T02 = 8562,
|
UTIL_ARCH_MACHINE_TYPE_Z15_T02 = 8562,
|
||||||
|
UTIL_ARCH_MACHINE_TYPE_Z16 = 3931,
|
||||||
};
|
};
|
||||||
|
|
||||||
int util_arch_machine_type(void);
|
int util_arch_machine_type(void);
|
||||||
|
|||||||
21
include/lib/util_exit_code.h
Normal file
21
include/lib/util_exit_code.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* @defgroup util_exit_code_h util_exit_code: General purpose exit codes
|
||||||
|
* @{
|
||||||
|
* @brief General purpose exit codes
|
||||||
|
*
|
||||||
|
* 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_EXIT_CODE_H
|
||||||
|
#define LIB_UTIL_EXIT_CODE_H
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
UTIL_EXIT_OK = 0, /* Program finished successfully */
|
||||||
|
UTIL_EXIT_RUNTIME_ERROR = 15, /* A run-time error occurred */
|
||||||
|
UTIL_EXIT_OUT_OF_MEMORY = 22, /* Not enough available memory */
|
||||||
|
} util_exit_code_t;
|
||||||
|
|
||||||
|
#endif /** LIB_UTIL_EXIT_CODE_H @} */
|
||||||
@@ -11,6 +11,8 @@
|
|||||||
#ifndef LIB_UTIL_FILE_H
|
#ifndef LIB_UTIL_FILE_H
|
||||||
#define LIB_UTIL_FILE_H
|
#define LIB_UTIL_FILE_H
|
||||||
|
|
||||||
|
#include "lib/util_exit_code.h"
|
||||||
|
|
||||||
int util_file_read_line(char *str, size_t size, const char *fmt, ...);
|
int util_file_read_line(char *str, size_t size, const char *fmt, ...);
|
||||||
int util_file_read_i(int *val, int base, const char *fmt, ...);
|
int util_file_read_i(int *val, int base, const char *fmt, ...);
|
||||||
int util_file_read_l(long *val, int base, const char *fmt, ...);
|
int util_file_read_l(long *val, int base, const char *fmt, ...);
|
||||||
@@ -26,4 +28,10 @@ int util_file_write_ul(unsigned long val, int base, const char *fmt, ...);
|
|||||||
int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...);
|
int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...);
|
||||||
|
|
||||||
int util_file_read_va(const char *path, const char *fmt, ...);
|
int util_file_read_va(const char *path, const char *fmt, ...);
|
||||||
|
|
||||||
|
util_exit_code_t util_file_read_fd_buf(FILE *fd, void **buffer_ptr,
|
||||||
|
size_t *size_ptr);
|
||||||
|
char *util_file_read_fd(FILE *fd, int chomp);
|
||||||
|
char *util_file_read_text_file(const char *path, int chomp);
|
||||||
|
|
||||||
#endif /** LIB_UTIL_FILE_H @} */
|
#endif /** LIB_UTIL_FILE_H @} */
|
||||||
|
|||||||
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 @} */
|
||||||
44
include/lib/util_udev.h
Normal file
44
include/lib/util_udev.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* @defgroup util_udev_h util_udev: UDEV interface
|
||||||
|
* @{
|
||||||
|
* @brief Work with UDEV files
|
||||||
|
*
|
||||||
|
* 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_UDEV_H
|
||||||
|
#define LIB_UTIL_UDEV_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "lib/util_exit_code.h"
|
||||||
|
#include "lib/util_list.h"
|
||||||
|
|
||||||
|
/* Single key-operator-value entry in a udev rule line.*/
|
||||||
|
struct util_udev_entry_node {
|
||||||
|
struct util_list_node node;
|
||||||
|
char *key;
|
||||||
|
char *op;
|
||||||
|
char *value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Single udev line in a udev rule file. */
|
||||||
|
struct util_udev_line_node {
|
||||||
|
struct util_list_node node;
|
||||||
|
struct util_list entries;
|
||||||
|
char *line;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Udev rule file. */
|
||||||
|
struct util_udev_file {
|
||||||
|
struct util_list lines;
|
||||||
|
};
|
||||||
|
|
||||||
|
util_exit_code_t util_udev_read_file(const char *path,
|
||||||
|
struct util_udev_file **file_ptr);
|
||||||
|
void util_udev_free_file(struct util_udev_file *file);
|
||||||
|
void util_udev_file_print(struct util_udev_file *file);
|
||||||
|
|
||||||
|
#endif /** LIB_UTIL_UDEV_H @} */
|
||||||
@@ -97,6 +97,24 @@ typedef struct volume_label
|
|||||||
unsigned long long formatted_blocks; /* valid when ldl_version >= f2 */
|
unsigned long long formatted_blocks; /* valid when ldl_version >= f2 */
|
||||||
} __attribute__ ((packed)) volume_label_t;
|
} __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
|
typedef struct extent
|
||||||
{
|
{
|
||||||
u_int8_t typeind; /* extent type indicator */
|
u_int8_t typeind; /* extent type indicator */
|
||||||
|
|||||||
@@ -21,15 +21,21 @@
|
|||||||
* Usage example:
|
* Usage example:
|
||||||
* #define IMAGE_ENTRY _AC(0x10000, UL)
|
* #define IMAGE_ENTRY _AC(0x10000, UL)
|
||||||
*/
|
*/
|
||||||
|
#ifndef _AC
|
||||||
#ifdef __ASSEMBLER__
|
#ifdef __ASSEMBLER__
|
||||||
#define _AC(X, TYPE) X
|
#define _AC(X, TYPE) X
|
||||||
#else
|
#else
|
||||||
#define _AC(X, TYPE) X##TYPE
|
#define _AC(X, TYPE) X##TYPE
|
||||||
#endif
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLER__
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#ifndef sizeof_field
|
||||||
|
#define sizeof_field(type, field) (sizeof((type *)0)->field)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef UNUSED
|
#ifdef UNUSED
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
|
||||||
@@ -48,6 +54,10 @@
|
|||||||
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
#define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
|
#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 RELEASE_STRING STRINGIFY (S390_TOOLS_RELEASE)
|
||||||
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
#define TOOLS_LIBDIR STRINGIFY (S390_TOOLS_LIBDIR)
|
||||||
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
#define TOOLS_SYSCONFDIR STRINGIFY (S390_TOOLS_SYSCONFDIR)
|
||||||
@@ -60,6 +70,7 @@
|
|||||||
#define __may_alias __attribute__((may_alias))
|
#define __may_alias __attribute__((may_alias))
|
||||||
#define __section(x) __attribute__((__section__(#x)))
|
#define __section(x) __attribute__((__section__(#x)))
|
||||||
#define __noinline __attribute__((__noinline__))
|
#define __noinline __attribute__((__noinline__))
|
||||||
|
#define __big_endian
|
||||||
/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
/* The Linux kernel (in stddef.h) and glibc (sys/cdefs.h) define
|
||||||
* __always_inline. Therefore undefine it first to allow the headers
|
* __always_inline. Therefore undefine it first to allow the headers
|
||||||
* to be included first.
|
* to be included first.
|
||||||
|
|||||||
439
include/libpv/cert.h
Normal file
439
include/libpv/cert.h
Normal file
@@ -0,0 +1,439 @@
|
|||||||
|
/*
|
||||||
|
* Certificate functions and definitions.
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBPV_CERT_H
|
||||||
|
#define LIBPV_CERT_H
|
||||||
|
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
|
#include <openssl/err.h>
|
||||||
|
|
||||||
|
#include "libpv/common.h"
|
||||||
|
|
||||||
|
#define PV_IBM_Z_SUBJECT_COMMON_NAME "International Business Machines Corporation"
|
||||||
|
#define PV_IBM_Z_SUBJECT_COUNTRY_NAME "US"
|
||||||
|
#define PV_IBM_Z_SUBJECT_LOCALITY_NAME "Poughkeepsie"
|
||||||
|
#define PV_IBM_Z_SUBJECT_ORGANIZATIONAL_UNIT_NAME_SUFFIX "Key Signing Service"
|
||||||
|
#define PV_IBM_Z_SUBJECT_ORGANIZATION_NAME "International Business Machines Corporation"
|
||||||
|
#define PV_IBM_Z_SUBJECT_STATE "New York"
|
||||||
|
#define PV_IMB_Z_SUBJECT_ENTRY_COUNT 6
|
||||||
|
|
||||||
|
/* Minimum security level for the keys/certificates used to establish a chain of
|
||||||
|
* trust (see https://www.openssl.org/docs/man1.1.1/man3/X509_VERIFY_PARAM_set_auth_level.html
|
||||||
|
* for details).
|
||||||
|
*/
|
||||||
|
#define PV_CERTS_SECURITY_LEVEL 2
|
||||||
|
|
||||||
|
/** pv_cert_init:
|
||||||
|
*
|
||||||
|
* Should not be called by user.
|
||||||
|
* Use pv_init() instead which
|
||||||
|
* calls this function during creation.
|
||||||
|
*
|
||||||
|
* Sets up data structures for caching CRLs.
|
||||||
|
*/
|
||||||
|
void pv_cert_init(void);
|
||||||
|
|
||||||
|
/** pv_cert_cleanup:
|
||||||
|
*
|
||||||
|
* Should not be called by user.
|
||||||
|
* Use pv_cleanup() instead which
|
||||||
|
* calls this function during creation.
|
||||||
|
*
|
||||||
|
* Cleans up data structures for caching CRLs.
|
||||||
|
*/
|
||||||
|
void pv_cert_cleanup(void);
|
||||||
|
|
||||||
|
#define PV_CERT_ERROR g_quark_from_static_string("pv-cert-error-quark")
|
||||||
|
typedef enum {
|
||||||
|
PV_CERT_ERROR_CERT_REVOKED,
|
||||||
|
PV_CERT_ERROR_CERT_SIGNATURE_INVALID,
|
||||||
|
PV_CERT_ERROR_CERT_SUBJECT_ISSUER_MISMATCH,
|
||||||
|
PV_CERT_ERROR_CRL_DOWNLOAD_FAILED,
|
||||||
|
PV_CERT_ERROR_CRL_SIGNATURE_INVALID,
|
||||||
|
PV_CERT_ERROR_CRL_SUBJECT_ISSUER_MISMATCH,
|
||||||
|
PV_CERT_ERROR_FAILED_DOWNLOAD_CRL,
|
||||||
|
PV_CERT_ERROR_INTERNAL,
|
||||||
|
PV_CERT_ERROR_INVALID_PARM,
|
||||||
|
PV_CERT_ERROR_INVALID_SIGNATURE_ALGORITHM,
|
||||||
|
PV_CERT_ERROR_INVALID_VALIDITY_PERIOD,
|
||||||
|
PV_CERT_ERROR_LOAD_CRL,
|
||||||
|
PV_CERT_ERROR_LOAD_DEFAULT_CA,
|
||||||
|
PV_CERT_ERROR_LOAD_ROOT_CA,
|
||||||
|
PV_CERT_ERROR_MALFORMED_CERTIFICATE,
|
||||||
|
PV_CERT_ERROR_MALFORMED_ROOT_CA,
|
||||||
|
PV_CERT_ERROR_NO_CRL,
|
||||||
|
PV_CERT_ERROR_NO_CRLDP,
|
||||||
|
PV_CERT_ERROR_NO_IBM_Z_SIGNING_KEY,
|
||||||
|
PV_CERT_ERROR_NO_ISSUER_IBM_Z_FOUND,
|
||||||
|
PV_CERT_ERROR_NO_PUBLIC_KEY,
|
||||||
|
PV_CERT_ERROR_READ_CERTIFICATE,
|
||||||
|
PV_CERT_ERROR_READ_CRL,
|
||||||
|
PV_CERT_ERROR_SIGNATURE_ALGORITHM_MISMATCH,
|
||||||
|
PV_CERT_ERROR_SKID_AKID_MISMATCH,
|
||||||
|
PV_CERT_ERROR_VERIFICATION_FAILED,
|
||||||
|
PV_CERT_ERROR_WRONG_CA_USED,
|
||||||
|
} PvCertErrors;
|
||||||
|
|
||||||
|
/** PvX509WithPath - X509 certificate associated with a path
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
X509 *cert;
|
||||||
|
char *path;
|
||||||
|
} PvX509WithPath;
|
||||||
|
|
||||||
|
/** pv_x509_with_path_new:
|
||||||
|
*
|
||||||
|
* @cert: X509 certificate
|
||||||
|
* @path: Path of that X509 certificate
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): new X509 with path
|
||||||
|
*/
|
||||||
|
PvX509WithPath *pv_x509_with_path_new(X509 *cert, const char *path);
|
||||||
|
|
||||||
|
/** pv_x509_with_path_free:
|
||||||
|
*
|
||||||
|
* Frees the path and the PvX509WithPath; Decreases the refcount of the X509
|
||||||
|
*/
|
||||||
|
void pv_x509_with_path_free(PvX509WithPath *cert);
|
||||||
|
|
||||||
|
typedef STACK_OF(DIST_POINT) STACK_OF_DIST_POINT;
|
||||||
|
typedef STACK_OF(X509) STACK_OF_X509;
|
||||||
|
typedef STACK_OF(X509_CRL) STACK_OF_X509_CRL;
|
||||||
|
typedef GSList PvCertWithPathList;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
X509 *cert;
|
||||||
|
STACK_OF_X509_CRL *crls;
|
||||||
|
} PvX509Pair;
|
||||||
|
|
||||||
|
/** pv_x509_pair_new_take:
|
||||||
|
* @cert: ptr to X509
|
||||||
|
* @crls: ptr to CRLs
|
||||||
|
*
|
||||||
|
* Takes a X509 and the associated CRLs and builds a pair.
|
||||||
|
* Both, *cert and *crls will be NULL afterwards, and owned by the pair.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): New PvX509Pair
|
||||||
|
*/
|
||||||
|
PvX509Pair *pv_x509_pair_new_take(X509 **cert, STACK_OF_X509_CRL **crls);
|
||||||
|
|
||||||
|
/** pv_x509_pair_free:
|
||||||
|
*
|
||||||
|
* Decreases the refcount of the X509 and crls.
|
||||||
|
* Frees the PvX509Pair.
|
||||||
|
*/
|
||||||
|
void pv_x509_pair_free(PvX509Pair *pair);
|
||||||
|
|
||||||
|
void STACK_OF_DIST_POINT_free(STACK_OF_DIST_POINT *stack);
|
||||||
|
void STACK_OF_X509_free(STACK_OF_X509 *stack);
|
||||||
|
void STACK_OF_X509_CRL_free(STACK_OF_X509_CRL *stack);
|
||||||
|
|
||||||
|
/** pv_x509_from_pem_der_data:
|
||||||
|
*
|
||||||
|
* @data: GBytes containing the cert in PEM format
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): X509 cert
|
||||||
|
*/
|
||||||
|
X509 *pv_x509_from_pem_der_data(GBytes *data, GError **error);
|
||||||
|
|
||||||
|
/** pv_x509_get_ec_pubkey:
|
||||||
|
*
|
||||||
|
* @cert: X509 to extract elliptic curve pubkey from
|
||||||
|
* @nid: numerical identifier of the expected curve
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): corresponding pupkey for the given certificate
|
||||||
|
*/
|
||||||
|
EVP_PKEY *pv_x509_get_ec_pubkey(X509 *cert, int nid, GError **error);
|
||||||
|
|
||||||
|
/** pv_get_ec_pubkeys:
|
||||||
|
*
|
||||||
|
* @certs_with_path: List of PvX509WithPath
|
||||||
|
* @nid: numerical identifier of the expected curve
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): List of corresponding public keys for the given certificate
|
||||||
|
*/
|
||||||
|
GSList *pv_get_ec_pubkeys(PvCertWithPathList *certs_with_path, int nid, GError **error);
|
||||||
|
|
||||||
|
/* pv_load_certificates:
|
||||||
|
*
|
||||||
|
* @cert_paths: list of cert paths.
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* @cert_paths must contain at least one element, otherwise an error is
|
||||||
|
* reported.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): List of PvX509WithPath corresponding to the given paths
|
||||||
|
*/
|
||||||
|
PvCertWithPathList *pv_load_certificates(char **cert_paths, GError **error);
|
||||||
|
|
||||||
|
/* pv_load_first_cert_from_file:
|
||||||
|
*
|
||||||
|
* @path: location of the x509
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* This function reads in only the first certificate and ignores all other. This
|
||||||
|
* is only relevant for the PEM file format. For the host-key document and the
|
||||||
|
* root CA this behavior is expected.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): PvX509WithPath corresponding to the given path
|
||||||
|
*/
|
||||||
|
X509 *pv_load_first_cert_from_file(const char *path, GError **error);
|
||||||
|
|
||||||
|
/* pv_load_first_crl_from_file:
|
||||||
|
*
|
||||||
|
* @path: location of the x509 CRL
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* This function reads in only the first CRL and ignores all other. This
|
||||||
|
* is only relevant for the PEM file format.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): X509_CRL corresponding to the given path
|
||||||
|
*/
|
||||||
|
X509_CRL *pv_load_first_crl_from_file(const char *path, GError **error);
|
||||||
|
|
||||||
|
/** pv_store_setup_crl_download:
|
||||||
|
*
|
||||||
|
* @st: X509_STORE
|
||||||
|
*/
|
||||||
|
void pv_store_setup_crl_download(X509_STORE *st);
|
||||||
|
|
||||||
|
/** pv_load_first_crl_by_cert:
|
||||||
|
* @cert: X509 to specify the download location.
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* This function returns the first X509_CRL found from the CRL distribution
|
||||||
|
* points specified in @cert.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): x509 CRL corresponding to the given X509
|
||||||
|
*/
|
||||||
|
X509_CRL *pv_load_first_crl_by_cert(X509 *cert, GError **error);
|
||||||
|
|
||||||
|
/** pv_try_load_crls_by_certs:
|
||||||
|
*
|
||||||
|
* @certs_with_path: List of PvX509WithPath
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): Stack of CRLs corresponding to the given X509
|
||||||
|
*/
|
||||||
|
STACK_OF_X509_CRL *pv_try_load_crls_by_certs(PvCertWithPathList *certs_with_path);
|
||||||
|
|
||||||
|
/** pv_store_setup:
|
||||||
|
*
|
||||||
|
* @root_ca_path: Location of the rootCA or NULL if SystemRoot CA shall be used
|
||||||
|
* @crl_paths: List of CRL paths or NULL
|
||||||
|
* @cert_with_crl_paths: List of (untrusted) X509 paths
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* The untrusted certs need to be verified before actually verifying a Host Key Document.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): X509_store with given input data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
X509_STORE *pv_store_setup(char *root_ca_path, char **crl_paths, char **cert_with_crl_paths,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
/** pv_get_x509_stack:
|
||||||
|
*
|
||||||
|
* x509_with_path_list: list of PvX509WithPath
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): Stack of X509 corresponding to the given x509 with path
|
||||||
|
*/
|
||||||
|
STACK_OF_X509 *pv_get_x509_stack(const GSList *x509_with_path_list);
|
||||||
|
|
||||||
|
/** pv_init_store_ctx:
|
||||||
|
*
|
||||||
|
* @ctx: a uninitialized Store CTX
|
||||||
|
* @trusted: X509_STORE with a trusted rootCA
|
||||||
|
* @chain: untrusted X509s
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Can be called multiple times on the same context if X509_STORE_CTX_cleanup(ctx)
|
||||||
|
* was called before.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success
|
||||||
|
* -1 in failure
|
||||||
|
*/
|
||||||
|
int pv_init_store_ctx(X509_STORE_CTX *ctx, X509_STORE *trusted, STACK_OF_X509 *chain,
|
||||||
|
GError **error) PV_NONNULL(1, 2, 3);
|
||||||
|
|
||||||
|
/** pv_init_store_ctx:
|
||||||
|
*
|
||||||
|
* @trusted: X509_STORE with a trusted rootCA
|
||||||
|
* @chain: untrusted X509s
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): X509_STORE_CTX setup with the input data
|
||||||
|
*/
|
||||||
|
X509_STORE_CTX *pv_create_store_ctx(X509_STORE *trusted, STACK_OF_X509 *chain, GError **error)
|
||||||
|
PV_NONNULL(1, 2);
|
||||||
|
/** pv_remove_ibm_signing_certs:
|
||||||
|
*
|
||||||
|
* @certs: Stack of X509s
|
||||||
|
*
|
||||||
|
* Returns: (transfer full):
|
||||||
|
* List of all IBM Z signing key certificates in @certs and remove them
|
||||||
|
* from the chain.
|
||||||
|
* Empty stack if no IBM Z signing key is found.
|
||||||
|
*/
|
||||||
|
STACK_OF_X509 *pv_remove_ibm_signing_certs(STACK_OF_X509 *certs);
|
||||||
|
|
||||||
|
/** pv_c2b_name:
|
||||||
|
*
|
||||||
|
* Workaround to fix the mismatch between issuer name of the
|
||||||
|
* IBM Z signing CRLs and the IBM Z signing key subject name.
|
||||||
|
*
|
||||||
|
* In RFC 5280 the attributes of a (subject/issuer) name is not mandatory
|
||||||
|
* ordered. The problem is that our certificates are not consistent in the order
|
||||||
|
* (see https://tools.ietf.org/html/rfc5280#section-4.1.2.4 for details).
|
||||||
|
*
|
||||||
|
* This function tries to reorder the name attributes such that
|
||||||
|
* further OpenSSL calls can work with it. The caller is
|
||||||
|
* responsible to free the returned value.
|
||||||
|
*/
|
||||||
|
X509_NAME *pv_c2b_name(const X509_NAME *name);
|
||||||
|
|
||||||
|
/** pv_verify_host_key:
|
||||||
|
*
|
||||||
|
* @host_key: X509 to be verified
|
||||||
|
* @issuer_pairs: IBM signing key X509+CRLs Pairs used for verification
|
||||||
|
* @level: Security level. see PV_CERTS_SECURITY_LEVEL
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if Host key could be verified with one of the IBM signing keys
|
||||||
|
* -1 if no IBM signing key could verify the authenticity of the given host key
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int pv_verify_host_key(X509 *host_key, GSList *issuer_pairs, int verify_flags, int level,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
|
/** pv_verify_cert:
|
||||||
|
*
|
||||||
|
* @ctx: trusted store ctx used for verification
|
||||||
|
* @cert: X509 to be verified
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Cannot be used to verify host keys with IBM signing keys, as IBM signing
|
||||||
|
* keys are no intermediate CAs. Use pv_verify_host_key() instead.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if @cert could be verified
|
||||||
|
* -1 if @cert could not be verified
|
||||||
|
*/
|
||||||
|
int pv_verify_cert(X509_STORE_CTX *ctx, X509 *cert, GError **error) PV_NONNULL(1, 2);
|
||||||
|
|
||||||
|
/** pv_check_crl_valid_for_cert:
|
||||||
|
*
|
||||||
|
* @crl: CRL to be verified
|
||||||
|
* @cert: Cert that probably issued the given CRL
|
||||||
|
* @verify_flags: X509 Verification flags (X509_V_FLAG_<TYPE>)
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Verify whether a revocation list @crl is valid and is issued by @cert. For
|
||||||
|
* this multiple steps must be done:
|
||||||
|
*
|
||||||
|
* 1. verify issuer of the CRL matches with the suject name of @cert
|
||||||
|
* 2. verify the validity period of the CRL
|
||||||
|
* 3. verify the signature of the CRL
|
||||||
|
*
|
||||||
|
* Important: This function does not verify whether @cert is allowed to issue a
|
||||||
|
* CRL.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if @crl is valid and issued by @cert
|
||||||
|
* -1 otherwise
|
||||||
|
*/
|
||||||
|
int pv_verify_crl(X509_CRL *crl, X509 *cert, int verify_flags, GError **error);
|
||||||
|
|
||||||
|
/** pv_check_chain_parameters:
|
||||||
|
*
|
||||||
|
* @chain: chain of trust to be validated
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Verifies that chain has at least a RootCA ans intermediate CA
|
||||||
|
* and logs the used ROD CA subject
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 @chain is valid
|
||||||
|
* -1 otherwise
|
||||||
|
*/
|
||||||
|
int pv_check_chain_parameters(const STACK_OF_X509 *chain, GError **error);
|
||||||
|
|
||||||
|
/** pv_store_set_verify_param:
|
||||||
|
*
|
||||||
|
* @store: X509_STORE to set parameters
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 on success
|
||||||
|
* -1 on failure
|
||||||
|
*/
|
||||||
|
int pv_store_set_verify_param(X509_STORE *store, GError **error);
|
||||||
|
|
||||||
|
/** pv_store_ctx_find_valid_crls:
|
||||||
|
*
|
||||||
|
* @ctx: STORE_CTX for searching CRLs
|
||||||
|
* @cert: X509 to match CRLs aggainst
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): STACK of CRLs related to given @crl fin @ctx
|
||||||
|
*/
|
||||||
|
STACK_OF_X509_CRL *pv_store_ctx_find_valid_crls(X509_STORE_CTX *ctx, X509 *cert, GError **error)
|
||||||
|
PV_NONNULL(1, 2);
|
||||||
|
|
||||||
|
/** pv_verify_host_key_doc:
|
||||||
|
*
|
||||||
|
* @host_key_certs_with_path: X509s to be verified
|
||||||
|
* @trusted. X509_STORE with a rusted RootCA
|
||||||
|
* @untrusted_certs: STACK OF untrusted X509s
|
||||||
|
* @online: true if CRLs shall be downloaded
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if all given HKDs could be verified using the chain of trust.
|
||||||
|
* -1 otherwise
|
||||||
|
*/
|
||||||
|
int pv_verify_host_key_doc(PvCertWithPathList *host_key_certs_with_path, X509_STORE *trusted,
|
||||||
|
STACK_OF_X509 *untrusted_certs, gboolean online, GError **error)
|
||||||
|
PV_NONNULL(1, 2, 3);
|
||||||
|
|
||||||
|
/** pv_verify_host_key_docs_by_path:
|
||||||
|
*
|
||||||
|
* @host_key_paths: locations of X509 to be verified
|
||||||
|
* @optional_root_ca_path: rootCA location or NULL if Default shall be used
|
||||||
|
* @optional_crl_paths: locations of CRLs or NULL
|
||||||
|
* @untrusted_cert_paths: locations of IntermediateCAs including the IBM signing key
|
||||||
|
* @online: true if CRLs shall be downloaded
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 if all given HKDs could be verfied using the chain of trust.
|
||||||
|
* -1 otherwise
|
||||||
|
*/
|
||||||
|
int pv_verify_host_key_docs_by_path(char **host_key_paths, char *optional_root_ca_path,
|
||||||
|
char **optional_crl_paths, char **untrusted_cert_paths,
|
||||||
|
gboolean online, GError **error) PV_NONNULL(1, 4);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(AUTHORITY_KEYID, AUTHORITY_KEYID_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509WithPath, pv_x509_with_path_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_DIST_POINT, STACK_OF_DIST_POINT_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509, STACK_OF_X509_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(STACK_OF_X509_CRL, STACK_OF_X509_CRL_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_CRL, X509_CRL_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_NAME, X509_NAME_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_VERIFY_PARAM, X509_VERIFY_PARAM_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvX509Pair, pv_x509_pair_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE, X509_STORE_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_STORE_CTX, X509_STORE_CTX_free)
|
||||||
|
|
||||||
|
#endif /* LIBPV_CERT_H */
|
||||||
35
include/libpv/common.h
Normal file
35
include/libpv/common.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Libpv common definitions.
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef LIBPV_COMMON_H
|
||||||
|
#define LIBPV_COMMON_H
|
||||||
|
|
||||||
|
/* must be included before any (other) glib header to verify that
|
||||||
|
* the glib version is supported
|
||||||
|
*/
|
||||||
|
#include "libpv/glib-helper.h"
|
||||||
|
|
||||||
|
#include <glib/gi18n.h>
|
||||||
|
|
||||||
|
#include "libpv/openssl-compat.h"
|
||||||
|
#include "libpv/macros.h"
|
||||||
|
|
||||||
|
/** pv_init:
|
||||||
|
*
|
||||||
|
* Must be called before any libpv call.
|
||||||
|
*/
|
||||||
|
int pv_init(void);
|
||||||
|
|
||||||
|
/** pv_cleanup:
|
||||||
|
*
|
||||||
|
* Must be called when done with using libpv.
|
||||||
|
*/
|
||||||
|
void pv_cleanup(void);
|
||||||
|
|
||||||
|
#endif /* LIBPV_COMMON_H */
|
||||||
202
include/libpv/crypto.h
Normal file
202
include/libpv/crypto.h
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
/*
|
||||||
|
* General cryptography helper functions and definitions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBPV_CRYPTO_H
|
||||||
|
#define LIBPV_CRYPTO_H
|
||||||
|
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
|
||||||
|
#include "libpv/common.h"
|
||||||
|
|
||||||
|
typedef struct pv_cipher_parms {
|
||||||
|
const EVP_CIPHER *cipher;
|
||||||
|
size_t tag_size;
|
||||||
|
GBytes *key;
|
||||||
|
union {
|
||||||
|
GBytes *iv;
|
||||||
|
GBytes *tweak;
|
||||||
|
};
|
||||||
|
} PvCipherParms;
|
||||||
|
|
||||||
|
typedef union {
|
||||||
|
struct {
|
||||||
|
uint8_t x[80];
|
||||||
|
uint8_t y[80];
|
||||||
|
};
|
||||||
|
uint8_t data[160];
|
||||||
|
} PvEcdhPubKey;
|
||||||
|
G_STATIC_ASSERT(sizeof(PvEcdhPubKey) == 160);
|
||||||
|
|
||||||
|
typedef GSList PvEvpKeyList;
|
||||||
|
|
||||||
|
enum PvCryptoMode {
|
||||||
|
PV_ENCRYPT,
|
||||||
|
PV_DECRYPT,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** pv_get_openssl_errors:
|
||||||
|
*
|
||||||
|
* Returns the last OpenSSL error messages.
|
||||||
|
* Caller is responsible to free the returned value.
|
||||||
|
*
|
||||||
|
* Returns: String representing the error.
|
||||||
|
*/
|
||||||
|
char *pv_get_openssl_errors(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pv_BIO_reset:
|
||||||
|
* @b: BIO to reset
|
||||||
|
*
|
||||||
|
* Resets a BIO to its initial state.
|
||||||
|
*
|
||||||
|
* Returns: 0 in case of success, -1 otherwise.
|
||||||
|
*/
|
||||||
|
int pv_BIO_reset(BIO *b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pv_generate_rand_data:
|
||||||
|
* @size: number of generated random bytes using a crypographically secure pseudo random generator
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Creates a new #GBytes with @size random bytes using a cryptographically
|
||||||
|
* secure pseudo random generator.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
|
||||||
|
*/
|
||||||
|
GBytes *pv_generate_rand_data(size_t size, GError **error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pv_generate_key:
|
||||||
|
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure key should be generated
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Creates a random key for @cipher using a cryptographically secure pseudo
|
||||||
|
* random generator.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
|
||||||
|
*/
|
||||||
|
GBytes *pv_generate_key(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pv_generate_iv:
|
||||||
|
* @cipher: specifies the OpenSSL cipher for which a cryptographically secure IV should be generated
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Creates a random IV for @cipher using a cryptographically secure pseudo
|
||||||
|
* random generator.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): a new #GBytes, or %NULL in case of an error
|
||||||
|
*/
|
||||||
|
GBytes *pv_generate_iv(const EVP_CIPHER *cipher, GError **error) PV_NONNULL(1);
|
||||||
|
|
||||||
|
/* Symmetric en/decryption functions */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pv_gcm_encrypt:
|
||||||
|
* @plain: data to encrypt
|
||||||
|
* @aad: (optional): additional data that should be authenticated with the key
|
||||||
|
* @parms:
|
||||||
|
* @cipher: (out): location to store the ciphertext
|
||||||
|
* @tag: (out): location to store the generated GCM tag
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Encrypts the @plain data and authenticates @aad data.
|
||||||
|
*
|
||||||
|
* Returns: number of bytes, or -1 in case of an error
|
||||||
|
*/
|
||||||
|
int64_t pv_gcm_encrypt(GBytes *plain, GBytes *aad, const PvCipherParms *parms, GBytes **cipher,
|
||||||
|
GBytes **tag, GError **error) PV_NONNULL(1, 3, 4, 5);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* pv_gcm_decrypt:
|
||||||
|
* @cipher: ciphertext to decrypt
|
||||||
|
* @aad: (optional): additional date to authenticate
|
||||||
|
* @tag: the GCM tag
|
||||||
|
* @parms:
|
||||||
|
* @plain: (out): location to store the decrypted data
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Decrypts the @cipher data and authenticates the @aad data.
|
||||||
|
*
|
||||||
|
* Returns: number of bytes, or -1 in case of an error
|
||||||
|
*/
|
||||||
|
int64_t pv_gcm_decrypt(GBytes *cipher, GBytes *aad, GBytes *tag, const PvCipherParms *parms,
|
||||||
|
GBytes **plain, GError **error) PV_NONNULL(1, 3, 4, 5);
|
||||||
|
|
||||||
|
/** pv_hkdf_extract_and_expand:
|
||||||
|
* @derived_key_len: size of the output key
|
||||||
|
* @key: input key
|
||||||
|
* @salt: salt for the extraction
|
||||||
|
* @info: infor for the expansion
|
||||||
|
* @md: EVP mode of operation
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Performs a RFC 5869 HKDF.
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): Result of RFC 5869 HKDF
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
GBytes *pv_hkdf_extract_and_expand(size_t derived_key_len, GBytes *key, GBytes *salt, GBytes *info,
|
||||||
|
const EVP_MD *md, GError **error) PV_NONNULL(2, 3, 4, 5);
|
||||||
|
|
||||||
|
/** pv_generate_ec_key:
|
||||||
|
*
|
||||||
|
* @nid: Numerical identifier of the curve
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): new random key based on the given curve
|
||||||
|
*/
|
||||||
|
EVP_PKEY *pv_generate_ec_key(int nid, GError **error);
|
||||||
|
|
||||||
|
/** pv_evp_pkey_to_ecdh_pub_key:
|
||||||
|
*
|
||||||
|
* @key: input key in EVP_PKEY format
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: the public part of the input @key in ECDH format.
|
||||||
|
*/
|
||||||
|
PvEcdhPubKey *pv_evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **error) PV_NONNULL(1);
|
||||||
|
|
||||||
|
/** pv_derive_exchange_key:
|
||||||
|
* @cust: Customer Key
|
||||||
|
* @host: Host key
|
||||||
|
* @error: return location for a #GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): Shared Secret of @cust and @host
|
||||||
|
*/
|
||||||
|
GBytes *pv_derive_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **error) PV_NONNULL(1, 2);
|
||||||
|
|
||||||
|
GQuark pv_crypto_error_quark(void);
|
||||||
|
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
|
||||||
|
typedef enum {
|
||||||
|
PV_CRYPTO_ERROR_DERIVE,
|
||||||
|
PV_CRYPTO_ERROR_HKDF_FAIL,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||||
|
PV_CRYPTO_ERROR_KEYGENERATION,
|
||||||
|
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||||
|
PV_CRYPTO_ERROR_READ_FILE,
|
||||||
|
PV_CRYPTO_ERROR_NO_MATCH_TAG,
|
||||||
|
} PvCryptoErrors;
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_INTEGER, ASN1_INTEGER_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(ASN1_OCTET_STRING, ASN1_OCTET_STRING_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
|
||||||
|
|
||||||
|
#endif /* LIBPV_CRYPTO_H */
|
||||||
53
include/libpv/curl.h
Normal file
53
include/libpv/curl.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Libcurl utils
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBPV_CURL_H
|
||||||
|
#define LIBPV_CURL_H
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
#include "libpv/common.h"
|
||||||
|
|
||||||
|
#define CRL_DOWNLOAD_TIMEOUT_MS 3000
|
||||||
|
#define CRL_DOWNLOAD_MAX_SIZE 0x100000
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CURL, curl_easy_cleanup)
|
||||||
|
|
||||||
|
/** curl_download:
|
||||||
|
* @url: URL to specify location of data
|
||||||
|
* @timeout_ms: time to wait until fail
|
||||||
|
* @max_size: Maximum size of the downloaded data
|
||||||
|
* @error: return location for a GError
|
||||||
|
*
|
||||||
|
* Returns: (nullable) (transfer full): Downloaded data as #GByteArray
|
||||||
|
*/
|
||||||
|
GByteArray *curl_download(const char *url, long timeout_ms, uint max_size, GError **err);
|
||||||
|
|
||||||
|
/** pv_curl_init:
|
||||||
|
*
|
||||||
|
* Should not be called by user.
|
||||||
|
* Use pv_init() instead which
|
||||||
|
* calls this function during creation.
|
||||||
|
*/
|
||||||
|
int pv_curl_init(void);
|
||||||
|
|
||||||
|
/** pv_curl_cleanup:
|
||||||
|
*
|
||||||
|
* Should not be called by user.
|
||||||
|
* Use pv_cleanup() instead which
|
||||||
|
* calls this function during creation.
|
||||||
|
*/
|
||||||
|
void pv_curl_cleanup(void);
|
||||||
|
|
||||||
|
#define PV_CURL_ERROR g_quark_from_static_string("pv-curl-error-quark")
|
||||||
|
typedef enum {
|
||||||
|
PV_CURL_ERROR_CURL_INIT_FAILED,
|
||||||
|
PV_CURL_ERROR_DOWNLOAD_FAILED,
|
||||||
|
} PvCurlErrors;
|
||||||
|
|
||||||
|
#endif /* LIBPV_CURL_H */
|
||||||
126
include/libpv/glib-helper.h
Normal file
126
include/libpv/glib-helper.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* Glib convenience functions
|
||||||
|
* Shall be used instead of manually including glib.
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2022
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
#ifndef LIBPV_GLIB_HELPER_H
|
||||||
|
#define LIBPV_GLIB_HELPER_H
|
||||||
|
|
||||||
|
#if defined(GLIB_VERSION_MIN_REQUIRED)
|
||||||
|
#if GLIB_VERSION_MIN_REQUIRED < GLIB_VERSION_2_56
|
||||||
|
#error "GLIB_VERSION must be at least 2.56"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#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>
|
||||||
|
|
||||||
|
#include "libpv/macros.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
|
||||||
|
DO_PRAGMA(clang diagnostic push) \
|
||||||
|
DO_PRAGMA(clang diagnostic ignored "-Wunused-function") \
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__) \
|
||||||
|
DO_PRAGMA(clang diagnostic pop)
|
||||||
|
#else
|
||||||
|
#define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define pv_wrapped_g_assert(__expr) g_assert(__expr)
|
||||||
|
|
||||||
|
/** pv_sec_gbytes_new_take:
|
||||||
|
*
|
||||||
|
* #g_bytes_new_take() with secure cleanup
|
||||||
|
*/
|
||||||
|
GBytes *pv_sec_gbytes_new_take(void *data, size_t size);
|
||||||
|
|
||||||
|
/** pv_sec_gbytes_new:
|
||||||
|
*
|
||||||
|
* #g_bytes_new() with secure cleanup
|
||||||
|
*/
|
||||||
|
GBytes *pv_sec_gbytes_new(const void *data, size_t size);
|
||||||
|
|
||||||
|
/** pv_file_get_content_as_secure_bytes:
|
||||||
|
*
|
||||||
|
* @filename: path to file for reading in
|
||||||
|
*
|
||||||
|
* read file and save as secure gbytes
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* Content of file as #GBytes with secure cleanup
|
||||||
|
*/
|
||||||
|
GBytes *pv_file_get_content_as_secure_bytes(const char *filename);
|
||||||
|
|
||||||
|
/** pv_file_get_content_as_g_bytes:
|
||||||
|
*
|
||||||
|
* @filename: path to file for reading in
|
||||||
|
*
|
||||||
|
* read file and save as gbytes
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* Content of file as #GBytes
|
||||||
|
*/
|
||||||
|
GBytes *pv_file_get_content_as_g_bytes(const char *filename, GError **error);
|
||||||
|
|
||||||
|
/** pv_file_seek:
|
||||||
|
*
|
||||||
|
* fseek with error reporting
|
||||||
|
*/
|
||||||
|
int pv_file_seek(FILE *file, long offset, int whence, GError **error);
|
||||||
|
|
||||||
|
/** pv_file_write:
|
||||||
|
*
|
||||||
|
* fwrite with error reporting
|
||||||
|
*/
|
||||||
|
size_t pv_file_write(FILE *file, const void *ptr, size_t size, GError **error);
|
||||||
|
|
||||||
|
/** pv_file_close:
|
||||||
|
*
|
||||||
|
* fclose with error reporting
|
||||||
|
*/
|
||||||
|
long pv_file_close(FILE *file, GError **error);
|
||||||
|
|
||||||
|
/** pv_file_tell:
|
||||||
|
*
|
||||||
|
* ftell with error reporting
|
||||||
|
*/
|
||||||
|
long pv_file_tell(FILE *file, GError **error);
|
||||||
|
|
||||||
|
/** pv_file_open:
|
||||||
|
*
|
||||||
|
* fopen with error reporting
|
||||||
|
*/
|
||||||
|
FILE *pv_file_open(const char *filename, const char *mode, GError **error);
|
||||||
|
|
||||||
|
/** pv_gbytes_memcpy:
|
||||||
|
*
|
||||||
|
* 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, size_t *copied);
|
||||||
|
|
||||||
|
#define PV_GLIB_HELPER_ERROR g_quark_from_static_string("pv-glib-helper_error-quark")
|
||||||
|
typedef enum {
|
||||||
|
PV_GLIB_HELPER_FILE_ERROR,
|
||||||
|
} pv_glib_helper_error_e;
|
||||||
|
|
||||||
|
void pv_auto_close_file(FILE *file);
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(FILE, pv_auto_close_file)
|
||||||
|
|
||||||
|
#endif /* LIBPV_GLIB_HELPER_H */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user