mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Compare commits
558 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab35d92028 | ||
|
|
39ceb02404 | ||
|
|
454f1427d3 | ||
|
|
1b65b23b43 | ||
|
|
0c583ec1a6 | ||
|
|
0ac7ce964e | ||
|
|
4eea67cd6f | ||
|
|
9a68a25ab6 | ||
|
|
1a150b2fe0 | ||
|
|
0843b7db36 | ||
|
|
cc069af26d | ||
|
|
d978fc6141 | ||
|
|
2fe5f27975 | ||
|
|
93a0cb254e | ||
|
|
eb4e806cdc | ||
|
|
19f747847f | ||
|
|
ce65c39e18 | ||
|
|
6c04f97773 | ||
|
|
cb11d6baec | ||
|
|
c673bacd7e | ||
|
|
6cf7f31746 | ||
|
|
c4a0933165 | ||
|
|
e67f630086 | ||
|
|
465348ced9 | ||
|
|
f148df4cc3 | ||
|
|
4d61a21811 | ||
|
|
e0ffb3c584 | ||
|
|
f4f2220693 | ||
|
|
fb62cc9e14 | ||
|
|
c91d8bd5f9 | ||
|
|
4753340e79 | ||
|
|
f742ed73e1 | ||
|
|
65b9fc442c | ||
|
|
2c106425e8 | ||
|
|
11bdab2629 | ||
|
|
b06af6026f | ||
|
|
1086548607 | ||
|
|
fbf8513d43 | ||
|
|
67496afe57 | ||
|
|
16b2799150 | ||
|
|
c063273b14 | ||
|
|
d2f8f972cf | ||
|
|
2d600570df | ||
|
|
3356d6f4fa | ||
|
|
67aef9bbf3 | ||
|
|
5d2871d626 | ||
|
|
6fcf64ebe0 | ||
|
|
e51663bbca | ||
|
|
f99560f734 | ||
|
|
303a3707e2 | ||
|
|
a37170b8be | ||
|
|
305235a7bc | ||
|
|
2568863f58 | ||
|
|
b0f82d22f9 | ||
|
|
b83c8944f1 | ||
|
|
f454c6825f | ||
|
|
c55ceabc67 | ||
|
|
2e28291c75 | ||
|
|
24fe8c1d1b | ||
|
|
67e76b8ebd | ||
|
|
97ab8fb4e9 | ||
|
|
c07104dbc7 | ||
|
|
c871050097 | ||
|
|
7e37a1d4e0 | ||
|
|
d884fb8db4 | ||
|
|
0e385a81ca | ||
|
|
675c854fa3 | ||
|
|
9d39a4bd47 | ||
|
|
400167f512 | ||
|
|
4fa9656613 | ||
|
|
87b54fc884 | ||
|
|
299fd2b772 | ||
|
|
36fed0e6c6 | ||
|
|
f7430027b4 | ||
|
|
8874b90825 | ||
|
|
6fe9e6c55c | ||
|
|
cc16e41595 | ||
|
|
bac3f93772 | ||
|
|
971970989b | ||
|
|
d415b8efed | ||
|
|
33031241c3 | ||
|
|
49cbaba302 | ||
|
|
304c3d8086 | ||
|
|
d77234ddb6 | ||
|
|
bc0d40c580 | ||
|
|
a1697a581d | ||
|
|
f75f4aff8f | ||
|
|
729a98fcb3 | ||
|
|
f52aeabca4 | ||
|
|
0be7efc956 | ||
|
|
88e6a18f96 | ||
|
|
a7e47685e0 | ||
|
|
b48aa5f435 | ||
|
|
d91e728e3c | ||
|
|
ce4704f365 | ||
|
|
2ca442feed | ||
|
|
82c86fa8bd | ||
|
|
e7f446432b | ||
|
|
1a87d3a3b4 | ||
|
|
0de533aef9 | ||
|
|
27a6409a4a | ||
|
|
6f9337d101 | ||
|
|
27f6c0a167 | ||
|
|
0652c687e3 | ||
|
|
16a62dff03 | ||
|
|
094905af87 | ||
|
|
dcce14923c | ||
|
|
1fd78d9f5e | ||
|
|
9d1baaa594 | ||
|
|
efcfbce386 | ||
|
|
3d74c534bf | ||
|
|
ca2ffe9e18 | ||
|
|
52192908eb | ||
|
|
d4cee7e65a | ||
|
|
bfbf456b83 | ||
|
|
235e997a77 | ||
|
|
c079e48d7d | ||
|
|
4762e65acb | ||
|
|
cb614ed1ee | ||
|
|
8face3e63e | ||
|
|
ea14f5471c | ||
|
|
b2ae5a91ac | ||
|
|
edfb6a03d8 | ||
|
|
5eace91ee7 | ||
|
|
86856f98db | ||
|
|
154734efc7 | ||
|
|
c7fcb457b0 | ||
|
|
244bf4e550 | ||
|
|
0f7ed7d4fc | ||
|
|
121d5d8013 | ||
|
|
abe0ba7412 | ||
|
|
2227bb8330 | ||
|
|
aa09b29248 | ||
|
|
2790d4faaa | ||
|
|
bbc46edaf5 | ||
|
|
e5c0fb249b | ||
|
|
b6d8e5833c | ||
|
|
d71628326d | ||
|
|
8bfe18e674 | ||
|
|
275105fe3d | ||
|
|
19259aeb65 | ||
|
|
125df52887 | ||
|
|
852fb9dfb8 | ||
|
|
b0fe75b92f | ||
|
|
bc987c8d18 | ||
|
|
a86e41a518 | ||
|
|
0d9e42264d | ||
|
|
7fede7021e | ||
|
|
e7d79d5c5c | ||
|
|
7d4b1e18b6 | ||
|
|
b0cc0e4737 | ||
|
|
b7bb90c552 | ||
|
|
560b672bfa | ||
|
|
0fab6bdf2a | ||
|
|
b56c74fe7b | ||
|
|
663d362ff3 | ||
|
|
d4027e6506 | ||
|
|
ddde3f354f | ||
|
|
298fab68fe | ||
|
|
b47007b8ac | ||
|
|
91c35543ca | ||
|
|
9de85f4295 | ||
|
|
e15e8a1bfa | ||
|
|
4fc0c3cfef | ||
|
|
a0ed6709cf | ||
|
|
552a915465 | ||
|
|
1091b0bf65 | ||
|
|
016a0a56fc | ||
|
|
0b4cbf0041 | ||
|
|
d854aed4b8 | ||
|
|
7f8e31e861 | ||
|
|
a5b58038a0 | ||
|
|
c2244a5795 | ||
|
|
ea7cc9ea60 | ||
|
|
b32c031474 | ||
|
|
bfc3dd018c | ||
|
|
625b81130a | ||
|
|
bf8872e94a | ||
|
|
a84d1c5d58 | ||
|
|
696e8458f0 | ||
|
|
95c7258ea7 | ||
|
|
21de913a5e | ||
|
|
7a2a96e8a3 | ||
|
|
7a569c7e33 | ||
|
|
dc2ac0c916 | ||
|
|
367598b187 | ||
|
|
c01bcfa73a | ||
|
|
fe457e2082 | ||
|
|
1d25112589 | ||
|
|
27a8c4434c | ||
|
|
e6a3b18104 | ||
|
|
36292cb166 | ||
|
|
49da03e2e7 | ||
|
|
139dff3525 | ||
|
|
94227b44d5 | ||
|
|
a9f4ae2db3 | ||
|
|
15b7f9d83f | ||
|
|
214580a704 | ||
|
|
96f13ead2b | ||
|
|
8023a72b11 | ||
|
|
abc1875300 | ||
|
|
7d4c8c2781 | ||
|
|
f0afc6c89a | ||
|
|
8565e591bd | ||
|
|
80443ab629 | ||
|
|
8b3cc6e4c1 | ||
|
|
5693c16894 | ||
|
|
8bf5f8d0e2 | ||
|
|
99ab2db6ad | ||
|
|
784ac7d190 | ||
|
|
53f166673d | ||
|
|
d4ea321a97 | ||
|
|
1a63894487 | ||
|
|
e3fc9478bf | ||
|
|
f110a77b68 | ||
|
|
712433d7f9 | ||
|
|
2c4c210ca8 | ||
|
|
58e2135d87 | ||
|
|
5dbe73403f | ||
|
|
819513ab38 | ||
|
|
7e6d782699 | ||
|
|
cc82be3135 | ||
|
|
1b318fe114 | ||
|
|
87f47f60e4 | ||
|
|
0f55dab2de | ||
|
|
b58adc26f4 | ||
|
|
91509973fe | ||
|
|
39520546c5 | ||
|
|
8d1a7fecd0 | ||
|
|
a6507b330d | ||
|
|
d37dc68693 | ||
|
|
b0007fea98 | ||
|
|
1e248abd53 | ||
|
|
61baa23e48 | ||
|
|
261763f133 | ||
|
|
f4b2da6c9d | ||
|
|
1f607fed3d | ||
|
|
bf9fd47918 | ||
|
|
5aec1dc2a1 | ||
|
|
cf730a9632 | ||
|
|
73bab8e1a1 | ||
|
|
f97d048643 | ||
|
|
d8c630e5f4 | ||
|
|
45132ce1ee | ||
|
|
57a797350c | ||
|
|
75e3afb6a0 | ||
|
|
7915c9257b | ||
|
|
6014d07cb1 | ||
|
|
5d2ebe5301 | ||
|
|
ab510cff39 | ||
|
|
8c06dea4e5 | ||
|
|
0efacac5b8 | ||
|
|
6ea645b345 | ||
|
|
331b54d573 | ||
|
|
7e7a77675d | ||
|
|
dc2e439550 | ||
|
|
75d4317f20 | ||
|
|
58a7462f65 | ||
|
|
7c7e10ed8f | ||
|
|
0c1a63ce5e | ||
|
|
6825645a21 | ||
|
|
e764f460c4 | ||
|
|
63089835b0 | ||
|
|
e4cd42900f | ||
|
|
7f033938b8 | ||
|
|
f2dee9f542 | ||
|
|
c7a255fcd9 | ||
|
|
be7b854969 | ||
|
|
05a0f8e0eb | ||
|
|
43fcb694bf | ||
|
|
8be43a1f16 | ||
|
|
7b4a05e5a3 | ||
|
|
9911a95144 | ||
|
|
9c56255a70 | ||
|
|
a20cabccc4 | ||
|
|
f67758160e | ||
|
|
e84287e76e | ||
|
|
0c78add815 | ||
|
|
94b7a8f68d | ||
|
|
4036e80b26 | ||
|
|
a236180ad8 | ||
|
|
a9684b9154 | ||
|
|
6d31760872 | ||
|
|
b0dcc61ed5 | ||
|
|
a3e37953fe | ||
|
|
abf18cb711 | ||
|
|
22a4d45e3b | ||
|
|
e693173eef | ||
|
|
11bfa1d3c8 | ||
|
|
3ed8ab4e2a | ||
|
|
5a0c93443c | ||
|
|
b0c7965234 | ||
|
|
cdb23f8d22 | ||
|
|
60bda7ed0d | ||
|
|
4ff6519961 | ||
|
|
90dc65659f | ||
|
|
ec9c67189e | ||
|
|
951bd1ae54 | ||
|
|
ed6e3b7270 | ||
|
|
79ce120553 | ||
|
|
b45b564681 | ||
|
|
c8d0fca36c | ||
|
|
bbd88f26c9 | ||
|
|
79bfa818ed | ||
|
|
299144264d | ||
|
|
a69470d7e0 | ||
|
|
b26dbfe832 | ||
|
|
d95dc6d698 | ||
|
|
847f16f632 | ||
|
|
bc053a975a | ||
|
|
e9c030f202 | ||
|
|
dffd41943e | ||
|
|
58189b8786 | ||
|
|
b165500b69 | ||
|
|
5f2ddad6a8 | ||
|
|
28deb03178 | ||
|
|
8f1fa2a83c | ||
|
|
7677d3c0b4 | ||
|
|
6f7cb68dcf | ||
|
|
4d008849f7 | ||
|
|
d921c230ab | ||
|
|
6151889dcd | ||
|
|
224dc2e414 | ||
|
|
5a10aa73a9 | ||
|
|
428d41034e | ||
|
|
cf265cc46a | ||
|
|
84623f39dc | ||
|
|
8cbdfebc4f | ||
|
|
4951044213 | ||
|
|
667516681e | ||
|
|
10ce432196 | ||
|
|
320a49fc1a | ||
|
|
f0d18ddf2b | ||
|
|
2962248e7b | ||
|
|
773c8672ac | ||
|
|
637750f299 | ||
|
|
a17b52a043 | ||
|
|
d14051e309 | ||
|
|
d85cf20981 | ||
|
|
7df8edd88a | ||
|
|
6d382d30d9 | ||
|
|
9f8d245f92 | ||
|
|
cf39f26dee | ||
|
|
83106991ab | ||
|
|
b631c74df5 | ||
|
|
c675096899 | ||
|
|
5a9e93fb5b | ||
|
|
aefc8cd3ff | ||
|
|
a208463e49 | ||
|
|
a931428908 | ||
|
|
c2297a0a7e | ||
|
|
70a79fab3c | ||
|
|
b5a7b13e71 | ||
|
|
52b2cb8424 | ||
|
|
03b2bf028b | ||
|
|
81f9a67d6f | ||
|
|
c15f481181 | ||
|
|
4170cceb52 | ||
|
|
a648dbb014 | ||
|
|
322d51e5e4 | ||
|
|
a1db08160d | ||
|
|
31b77e1646 | ||
|
|
a4acf7c991 | ||
|
|
17cade6e7f | ||
|
|
90ea5d9e5d | ||
|
|
6accffd583 | ||
|
|
4e5afb9b71 | ||
|
|
9f247795f3 | ||
|
|
71976f8e4b | ||
|
|
851f685993 | ||
|
|
9100327092 | ||
|
|
e2d433bb10 | ||
|
|
d6925a30da | ||
|
|
fe4cc7c479 | ||
|
|
fa3cabc8af | ||
|
|
5a9b56f814 | ||
|
|
20145b6d06 | ||
|
|
9561a0b983 | ||
|
|
97fa88299f | ||
|
|
aaaebb2030 | ||
|
|
ff2a403bd2 | ||
|
|
66ed1727f9 | ||
|
|
c33cc5a619 | ||
|
|
cd46297d7c | ||
|
|
07b11982e3 | ||
|
|
35348c302b | ||
|
|
35312d0c47 | ||
|
|
342c6a3707 | ||
|
|
e2a8d85916 | ||
|
|
8f0496b26a | ||
|
|
d03be73536 | ||
|
|
a87268d62e | ||
|
|
9cc06a0529 | ||
|
|
3b1ccce515 | ||
|
|
ffe91d1b30 | ||
|
|
f35c5d01fd | ||
|
|
b23c35c390 | ||
|
|
177cf8cfeb | ||
|
|
f05f7d656b | ||
|
|
0bf4f1b957 | ||
|
|
cd38119888 | ||
|
|
cadef5c0ff | ||
|
|
02e1c783f6 | ||
|
|
07e30951f8 | ||
|
|
0a0b4c3826 | ||
|
|
eade995185 | ||
|
|
0eba8d11df | ||
|
|
257490366b | ||
|
|
5ef1320a7b | ||
|
|
f2f572fa70 | ||
|
|
e655f0cd7b | ||
|
|
68b46eea7a | ||
|
|
9894e391ef | ||
|
|
5982fd98bf | ||
|
|
d5291eed1c | ||
|
|
34260f1736 | ||
|
|
b9b3d2d230 | ||
|
|
4cf8f5f46c | ||
|
|
eba744a25e | ||
|
|
80e0c41b89 | ||
|
|
cdc787db1b | ||
|
|
ef4dc7a45b | ||
|
|
cb3e949772 | ||
|
|
f02de298c1 | ||
|
|
eb0dc13c88 | ||
|
|
d08bd23c1e | ||
|
|
724f1fea2c | ||
|
|
dcc63e6dfc | ||
|
|
576034e94a | ||
|
|
3ec49ba7bd | ||
|
|
60c687238d | ||
|
|
57b992ffa1 | ||
|
|
1f07a41d5a | ||
|
|
512b47c004 | ||
|
|
818ffbc4b0 | ||
|
|
5e65df7375 | ||
|
|
4eb80d14a0 | ||
|
|
7247a61e0b | ||
|
|
c856f28e11 | ||
|
|
ca30cfd341 | ||
|
|
58ecf1f363 | ||
|
|
d36ff82999 | ||
|
|
d4398aea89 | ||
|
|
672548ce30 | ||
|
|
344965bd29 | ||
|
|
d6a96f07c1 | ||
|
|
6a99d95d4f | ||
|
|
3f1bd3bb66 | ||
|
|
0fbc4edd29 | ||
|
|
b8a9f0d1d3 | ||
|
|
d280e5b1fa | ||
|
|
e04acab0ed | ||
|
|
d868ce5ec7 | ||
|
|
dec58c349e | ||
|
|
d82f5e1f49 | ||
|
|
156450f359 | ||
|
|
c0392efa39 | ||
|
|
3c5644ccfd | ||
|
|
3fb356ebd2 | ||
|
|
fe68ec513d | ||
|
|
a86fb8b091 | ||
|
|
f32bff9688 | ||
|
|
7d355b0fec | ||
|
|
ab4445c261 | ||
|
|
e14363373b | ||
|
|
d9ca409978 | ||
|
|
13596f18da | ||
|
|
80b66da1d8 | ||
|
|
3eb9af9c97 | ||
|
|
f093d0bfd4 | ||
|
|
6a2f4fd376 | ||
|
|
e2f92e4079 | ||
|
|
c944f23d7e | ||
|
|
5872f8a21b | ||
|
|
a090a1ffe8 | ||
|
|
5e24f74fde | ||
|
|
340da73bb7 | ||
|
|
f642019bcc | ||
|
|
7cc542352e | ||
|
|
cf99ea019e | ||
|
|
15c22ec742 | ||
|
|
45ac847dc9 | ||
|
|
4a223c70f2 | ||
|
|
26d636f234 | ||
|
|
aade05b01d | ||
|
|
c3821f0821 | ||
|
|
ac0ac48f6f | ||
|
|
54519b4465 | ||
|
|
9f2e406525 | ||
|
|
edaad2a927 | ||
|
|
262a827ab4 | ||
|
|
4b33d80595 | ||
|
|
4c401162c0 | ||
|
|
168acec5ea | ||
|
|
aab339d3e3 | ||
|
|
1f459af568 | ||
|
|
46f09a0adc | ||
|
|
f65003a14e | ||
|
|
e092b4024a | ||
|
|
9d7bab18a4 | ||
|
|
8688d47e3d | ||
|
|
04bb72c0dc | ||
|
|
1c065082d2 | ||
|
|
38642e6905 | ||
|
|
ebdf888a2f | ||
|
|
9745e4678a | ||
|
|
33a17df9fc | ||
|
|
4ff7aeff39 | ||
|
|
edb75870b5 | ||
|
|
a3c746846d | ||
|
|
4044accf03 | ||
|
|
943e7e7198 | ||
|
|
4f00cb6346 | ||
|
|
9d55086720 | ||
|
|
eaa2ef6ba4 | ||
|
|
37c3752b31 | ||
|
|
8585efadbe | ||
|
|
13648dd6f4 | ||
|
|
427dff3450 | ||
|
|
08bc0a947a | ||
|
|
c3d583fe9c | ||
|
|
983a72dab9 | ||
|
|
811152c08a | ||
|
|
6a1b9cf10a | ||
|
|
599b141b8a | ||
|
|
b9e47e356b | ||
|
|
5e2a477bbf | ||
|
|
bba34cb975 | ||
|
|
a674011c0d | ||
|
|
c78b5cd2ba | ||
|
|
f3e374ac77 | ||
|
|
1e6a9dbd56 | ||
|
|
564a2601f6 | ||
|
|
f4eb7e4907 | ||
|
|
c5a91199e3 | ||
|
|
144bddbf5b | ||
|
|
36ef451e6b | ||
|
|
1064e5b9cc | ||
|
|
d121ffa3f0 | ||
|
|
57f18c5f59 | ||
|
|
3b2a8777b1 | ||
|
|
89ead069f9 | ||
|
|
05de40cdeb | ||
|
|
a74103dba7 | ||
|
|
b4868c21bf | ||
|
|
8826028bdc | ||
|
|
09aa7f2010 | ||
|
|
e7d3638c6b | ||
|
|
68b0b4c268 | ||
|
|
caeb4470cd | ||
|
|
8b11ea73ac | ||
|
|
45e20a5044 | ||
|
|
105b30a805 | ||
|
|
70a7fc3e72 | ||
|
|
2d3774932b | ||
|
|
a5c1923d32 | ||
|
|
0348a8443e | ||
|
|
dba9616a5b |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -46,6 +46,7 @@ libutil/util_prg_example
|
|||||||
libutil/util_rec_example
|
libutil/util_rec_example
|
||||||
libutil/util_scandir_example
|
libutil/util_scandir_example
|
||||||
libzds/libzds.a
|
libzds/libzds.a
|
||||||
|
libvmcp/vmcp_example
|
||||||
mon_tools/mon_fsstatd
|
mon_tools/mon_fsstatd
|
||||||
mon_tools/mon_procd
|
mon_tools/mon_procd
|
||||||
osasnmpd/osasnmpd
|
osasnmpd/osasnmpd
|
||||||
@@ -67,6 +68,8 @@ zconf/qeth/lsqeth
|
|||||||
zconf/scm/lsscm
|
zconf/scm/lsscm
|
||||||
zconf/zcrypt/chzcrypt
|
zconf/zcrypt/chzcrypt
|
||||||
zconf/zcrypt/lszcrypt
|
zconf/zcrypt/lszcrypt
|
||||||
|
zconf/zcrypt/zcryptctl
|
||||||
|
zconf/zcrypt/zcryptstats
|
||||||
zdev/src/chzdev
|
zdev/src/chzdev
|
||||||
zdev/src/chzdev_usage.c
|
zdev/src/chzdev_usage.c
|
||||||
zdev/src/lszdev
|
zdev/src/lszdev
|
||||||
@@ -75,7 +78,8 @@ zdsfs/zdsfs
|
|||||||
zdump/zgetdump
|
zdump/zgetdump
|
||||||
zfcpdump/cpioinit
|
zfcpdump/cpioinit
|
||||||
zfcpdump/zfcpdump_part
|
zfcpdump/zfcpdump_part
|
||||||
zfcpdump/zfcpdump_part.rd
|
zfcpdump/zfcpdump-initrd
|
||||||
|
zfcpdump/10-zfcpdump.install
|
||||||
ziomon/ziomon_mgr
|
ziomon/ziomon_mgr
|
||||||
ziomon/ziomon_util
|
ziomon/ziomon_util
|
||||||
ziomon/ziomon_zfcpdd
|
ziomon/ziomon_zfcpdd
|
||||||
@@ -86,4 +90,10 @@ zipl/boot/*.exec
|
|||||||
zipl/boot/data.h
|
zipl/boot/data.h
|
||||||
zipl/src/chreipl_helper.device-mapper
|
zipl/src/chreipl_helper.device-mapper
|
||||||
zipl/src/zipl
|
zipl/src/zipl
|
||||||
|
zipl/src/zipl_helper.device-mapper
|
||||||
zkey/zkey
|
zkey/zkey
|
||||||
|
zkey/zkey-cryptsetup
|
||||||
|
zkey/check-dep-zkey
|
||||||
|
zkey/check-dep-zkey-cryptsetup
|
||||||
|
zkey/detect-libcryptsetup.dep
|
||||||
|
zpcictl/zpcictl
|
||||||
|
|||||||
@@ -16,8 +16,10 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Clemens von Mann
|
- Clemens von Mann
|
||||||
- Dan Horak
|
- Dan Horak
|
||||||
- Despina Papadopoulou
|
- Despina Papadopoulou
|
||||||
|
- Dimitri John Ledkov
|
||||||
- Eberhard Pasch
|
- Eberhard Pasch
|
||||||
- Einar Lueck
|
- Einar Lueck
|
||||||
|
- Eric Sandeen
|
||||||
- Erwin Vicari
|
- Erwin Vicari
|
||||||
- Eugene Crosser
|
- Eugene Crosser
|
||||||
- Eugene Dvurechenski
|
- Eugene Dvurechenski
|
||||||
@@ -45,6 +47,8 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Jan Glauber
|
- Jan Glauber
|
||||||
- Jan Hoeppner
|
- Jan Hoeppner
|
||||||
- Jan Willeke
|
- Jan Willeke
|
||||||
|
- Jason J. Herne
|
||||||
|
- Javier Martinez Canillas
|
||||||
- Jean-Baptiste Joret
|
- Jean-Baptiste Joret
|
||||||
- Jens Remus
|
- Jens Remus
|
||||||
- Jochen Roehrig
|
- Jochen Roehrig
|
||||||
@@ -53,7 +57,9 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Kittipon Meesompop
|
- Kittipon Meesompop
|
||||||
- Klaus-Dieter Wacker
|
- Klaus-Dieter Wacker
|
||||||
- Lakhvich Dmitriy
|
- Lakhvich Dmitriy
|
||||||
|
- Marc Hartmayer
|
||||||
- Mark Dettinger
|
- Mark Dettinger
|
||||||
|
- Mark Post
|
||||||
- Martin Kammerer
|
- Martin Kammerer
|
||||||
- Martin Peschke
|
- Martin Peschke
|
||||||
- Martin Petermann
|
- Martin Petermann
|
||||||
@@ -65,6 +71,7 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Michael Mueller
|
- Michael Mueller
|
||||||
- Mijo Safradin
|
- Mijo Safradin
|
||||||
- Mikhail Zaslonko
|
- Mikhail Zaslonko
|
||||||
|
- Niklas Schnelle
|
||||||
- Peter Oberparleiter
|
- Peter Oberparleiter
|
||||||
- Peter Tiedemann
|
- Peter Tiedemann
|
||||||
- Philipp Kern
|
- Philipp Kern
|
||||||
@@ -94,8 +101,10 @@ List of all individuals having contributed content to s390-tools
|
|||||||
- Thomas Richter
|
- Thomas Richter
|
||||||
- Thomas Spatzier
|
- Thomas Spatzier
|
||||||
- Thomas Weber
|
- Thomas Weber
|
||||||
|
- Tuan Hoang
|
||||||
- Ursula Braun
|
- Ursula Braun
|
||||||
- Utz Bacher
|
- Utz Bacher
|
||||||
|
- Vasily Gorbik
|
||||||
- Viktor Mihajlovski
|
- Viktor Mihajlovski
|
||||||
- Volker Sameske
|
- Volker Sameske
|
||||||
- Wolfgang Taphorn
|
- Wolfgang Taphorn
|
||||||
|
|||||||
248
CHANGELOG.md
248
CHANGELOG.md
@@ -1,5 +1,253 @@
|
|||||||
Release history for s390-tools (MIT version)
|
Release history for s390-tools (MIT version)
|
||||||
--------------------------------------------
|
--------------------------------------------
|
||||||
|
* __v2.13.0 (2020-05-06)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.5 / 5.6
|
||||||
|
|
||||||
|
Add new tool:
|
||||||
|
- genprotimg: Add genprotimg to create protected virtualization images
|
||||||
|
- genprotimg: Add sample script to verify host keys
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- dbginfo: Gather bridge related data (using 'bridge')
|
||||||
|
- dbginfo: Removed collection of /var/log/opencryptoki/
|
||||||
|
- dbginfo: collect softnet_stat
|
||||||
|
- dbginfo: gather ethtool output for per-queue coalescing
|
||||||
|
- ipl_tools: Support clear attribute for FCP and CCW re-IPL
|
||||||
|
- zdev: Report FC Endpoint Security of zfcp devices
|
||||||
|
- zdev/dracut/95zdev/module-setup.sh: Add ctcm kernel module
|
||||||
|
- cpumf/data: Add new deflate counters for IBM z15
|
||||||
|
- zkey: Add support for EP11 secure keys
|
||||||
|
- zpcictl: Initiate recover after reset
|
||||||
|
- zipl: Add support for NVMe devices
|
||||||
|
- zipl: A multitude of code and stability improvements
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- zipl: Prevent endless loop during IPL
|
||||||
|
- zipl/libc: Fix potential buffer overflow in printf
|
||||||
|
- zkey: Fix listing of keys on file systems reporting DT_UNKNOWN
|
||||||
|
- zkey: Fix display of clear key size for XTS, CCA-AESCIPHER, and EP11-AES XTS keys
|
||||||
|
|
||||||
|
|
||||||
|
* __v2.12.0 (2019-12-17)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.4
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- dbginfo: Gather qdisc related data (using 'tc')
|
||||||
|
- dbginfo: Gather extended network statistics (using 'ip link')
|
||||||
|
- dbginfo: Collect all files under /usr/lib/systemd/system/
|
||||||
|
- cpumf/cpumf_helper: Add IBM z15 machine name
|
||||||
|
- zkey: Display MKVP when validating a secure key
|
||||||
|
- zkey: Cross check APQNs when generating, validating, or importing secure keys,
|
||||||
|
and when changing APQN associations
|
||||||
|
- zkey: Check crypto card level during APQN cross checking
|
||||||
|
- zkey: Add support for generating, validating, and re-enciphering AES CIPHER keys
|
||||||
|
- zkey-cryptsetup: Add --to-new and --from-old options
|
||||||
|
- zkey-cryptsetup: Allow setkey to set different key types
|
||||||
|
- lszcrypt/chzcrypt: CEX7S exploitation support
|
||||||
|
- zcryptstats: Add support for CEX7 crypto card
|
||||||
|
- zipl: Ship a minimal zipl.conf
|
||||||
|
- zipl: Add value of target= as search path for BLS case
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- dasdview: Fix exit status in error cases
|
||||||
|
- zipl: Fix various compile warnings
|
||||||
|
- zipl: Fix dependency generation in zipl/boot
|
||||||
|
- zipl: Fix entry point for stand-alone kdump
|
||||||
|
- zipl: Add missing options to help output
|
||||||
|
|
||||||
|
* __v2.11.0 (2019-09-06)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.3
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- dasdfmt: Add support for thin-provisioned volumes
|
||||||
|
- lsdasd: Add support for thin-provisioned volumes
|
||||||
|
- libdasd: Provide function to utilise release space ioctl
|
||||||
|
- libdasd: Provide function to read ese sysfs attribute
|
||||||
|
- dbginfo: Add lspci (PCI devices) and smc_dbg (SMC sockets)
|
||||||
|
- dbginfo: Gather ethtool related data
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- zipl: Fix freeing of uninitialized pointer
|
||||||
|
- zipl: Set correct secure IPL default value
|
||||||
|
|
||||||
|
* __v2.10.0 (2019-07-31)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.2
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- zdev: Add zfcp dix parameter handling
|
||||||
|
- cpumf: Add support for CPU-Measurement Facility counters SVN 6
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- libutil: Add functions to test path is read/write-only
|
||||||
|
- zdev: Fix reporting of read-only sysfs attributes
|
||||||
|
- zdev: Improve handling of invalid udev rules
|
||||||
|
- zipl: Fix stfle zero padding
|
||||||
|
- zipl: Fix build issues
|
||||||
|
- zipl: Remove trailing spaces from the fields defined in BLS files
|
||||||
|
- zipl: Do not overwrite BOOT_IMAGE entry
|
||||||
|
- zkey: Fix auto-detection of clear key bitsize for XTS keys
|
||||||
|
|
||||||
|
* __v2.9.0 (2019-05-21)__
|
||||||
|
|
||||||
|
For Linux kernel version: 5.0 / 5.1
|
||||||
|
|
||||||
|
Add new tool:
|
||||||
|
- zcryptstats: Add zcryptstats to display usage statistics of
|
||||||
|
IBM Crypto Express adapters
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- lszfcp: New command line option to show module parameters
|
||||||
|
- lszfcp: Sdev attributes for scsi_disk, block, integrity, queue, iosched
|
||||||
|
- lszfcp: Add new output marker for non-good SCSI devices (luns)
|
||||||
|
- lszfcp: Add new output marker for non-good fc_rports
|
||||||
|
- lszfcp: Clean up whitespace (mixed indentation, trailing)
|
||||||
|
- lschp: Add support for specifying a CHPID
|
||||||
|
- zipl: Add secure boot capabilities
|
||||||
|
- zkey: Add common passphrase options for cryptsetup and crypttab
|
||||||
|
- zkey: Add batch-mode option to cryptsetup and zkey-cryptsetup
|
||||||
|
- libu2s: Remove the entire library and provide more robust functionality
|
||||||
|
in libdasd and libutil instead
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- lszfcp: Allow to show zfcp_units without associated SCSI device
|
||||||
|
- lszfcp: Attribute details for: css, zfcp_port, zfcp_unit
|
||||||
|
- lszfcp: Allow to also enumerate FCP device that have never been online
|
||||||
|
- lszfcp: Fix error message if no zfcp-attached SCSI device found
|
||||||
|
- lszfcp: Fix to show defunct FCP devices again
|
||||||
|
- lszfcp: Fix to show non-good target ports again
|
||||||
|
- lszfcp: Fix missing block & sg device output without CONFIG_SYSFS_DEPRECATED
|
||||||
|
- lszfcp: New command line option for extended output format
|
||||||
|
- zfcpdbf: Warn about ambiguous payload records with dup reqid & payarea
|
||||||
|
- zpcictl: Check for regular directory to prevent possible buffer overflow
|
||||||
|
|
||||||
|
* __v2.8.0 (2019-02-15)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.20
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- Switch to using /run directory instead of the legacy /var/run
|
||||||
|
- zkey: Add --pbkdf pbkdf2 to generated cryptsetup luksFormat command
|
||||||
|
- zdsfs: Add online VTOC refresh
|
||||||
|
- pkey: Support autoloading kernel pkey module
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- zkey: Avoid EPERM on key change if user is not owner of key file
|
||||||
|
- cpumf/cpumf_helper: Always return list reference for --sfb-size
|
||||||
|
|
||||||
|
* __v2.7.1 (2018-12-13)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.19
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- zkey: Enhance file read/write error handling
|
||||||
|
- cmsfs-fuse: Write more than a single line in linefeed mode
|
||||||
|
- zpcictl: Add warning for unsupported operations
|
||||||
|
- zipl: Use the BLS "title" field as the IPL section name
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- cmsfs-fuse: Fix iconv buffer aliasing
|
||||||
|
- cmsfs-fuse: Fix memory leak in cmsfs_rename()
|
||||||
|
- fdasd: Fix possible integer overflow
|
||||||
|
- fdasd: Fix resource leak in fdasd_parse_conffile()
|
||||||
|
- zdev: Fix memory leak in misc_readlink()
|
||||||
|
- dasdinfo: Display error messages on stderr
|
||||||
|
- zkey: Include /sbin into PATH when executing commands
|
||||||
|
- Makefile: Fix parallel build
|
||||||
|
- GCC8 warning fixes across the board for:
|
||||||
|
cmsfs-fuse, dasdinfo, dasdview, dump2tar, fdasd, hmcdrvfs, hyptop,
|
||||||
|
ip_watcher, libvmdump, libvtoc, lsqeth, lszcrypt, qethqoat, zdev, zdsfs,
|
||||||
|
zgetdump, zipl, zpcictl
|
||||||
|
|
||||||
|
* __v2.7.0 (2018-10-31)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.19
|
||||||
|
|
||||||
|
Add new tool:
|
||||||
|
- zcryptctl: Add zcryptctl for multiple zcrypt node management
|
||||||
|
- zpcictl: Add zpcictl for reporting defective PCI devices
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- qethqoat: Add OSA-Express7S support
|
||||||
|
- lszcrypt: Add support for alternative zcrypt device drivers
|
||||||
|
- zfcpdump: Add install script for zfcpdump
|
||||||
|
- zipl: Make zipl work with XFS by using the FIEMAP mapping ioctl
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- lstape: Fix output with SCSI lin_tape and multiple paths to same unit
|
||||||
|
- lstape: Fix output without SCSI generic (sg)
|
||||||
|
- lsluns: Fix to prevent error messages if there are non-zfcp SCSI devices
|
||||||
|
- lstape: Fix to prevent error messages if there are non-zfcp SCSI devices
|
||||||
|
- lstape: Fix description of --type and <devbusid> filter for channel tapes
|
||||||
|
- lstape: Fix SCSI output description in man page
|
||||||
|
- lstape: Fix SCSI HBA CCW device bus-ID e.g. for virtio-scsi-ccw
|
||||||
|
- Direct --help and --version output to stdout for several tools
|
||||||
|
- osasnmpd: Start without real OSA devices
|
||||||
|
|
||||||
|
* __v2.6.0 (2018-08-10)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.18
|
||||||
|
|
||||||
|
Add new tool:
|
||||||
|
- zkey: Add zkey-cryptsetup tool
|
||||||
|
Changes of existing tools:
|
||||||
|
- netboot: add BOOTIF support
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- mon_procd: fix parsing of /proc/<pid>/stat
|
||||||
|
- netboot: Include compressed kernel modules in initramfs
|
||||||
|
- netboot: Send client architecture and handle path prefix
|
||||||
|
|
||||||
|
* __v2.5.0 (2018-06-08)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.17
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- zdev: Add support for reading firmware configuration files
|
||||||
|
- zipl: Add BootLoaderSpec support
|
||||||
|
- scripts: Add script to switch zipl config to a BootLoaderSpec setup
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- lsluns: Print a message if no adapter or port exists
|
||||||
|
|
||||||
|
* __v2.4.0 (2018-05-07)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.16
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- dbginfo: Gather nvme related data
|
||||||
|
- zipl: Rewrite helper script in C
|
||||||
|
- libutil: Add function util_strstrip
|
||||||
|
- libvmcp: Introduce libvmcp
|
||||||
|
- zipl: Extend DASD stand-alone dumpers to drop zero pages
|
||||||
|
- zgetdump: Add verbose option
|
||||||
|
- zgetdump: Add 'Dump file size' field for zgetdump -i output
|
||||||
|
- cpumf: Add IBM z14 ZR1 to the CPU Measurement Facility model list
|
||||||
|
- zkey: Add build dependency to OpenSSL (libcrypto)
|
||||||
|
- zkey: Add keystore implementation
|
||||||
|
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- hmcdrvfs: fix parsing of link count >= 1000
|
||||||
|
- zgetdump: Avoid Segfault on processing dumps with memory limit
|
||||||
|
- chreipl: correct fcp reipl sysfs write sequence
|
||||||
|
- udev: Replace WAIT_FOR with TEST keyword
|
||||||
|
|
||||||
|
* __v2.3.0 (2018-01-30)__
|
||||||
|
|
||||||
|
For Linux kernel version: 4.15
|
||||||
|
|
||||||
|
Changes of existing tools:
|
||||||
|
- lscpumf: Add support for IBM z14 hardware counters
|
||||||
|
- libdasd: Introduce libdasd and use for dasd tools
|
||||||
|
- zipl: Always build and link without PIE
|
||||||
|
|
||||||
|
Bug Fixes:
|
||||||
|
- zgetdump: Fix handling of DASD multi-volume dump for partitions above 4 GB
|
||||||
|
- zdev: Fix zdev dracut module aborting on unknown root device
|
||||||
|
|
||||||
* __v2.2.0 (2017-12-07)__
|
* __v2.2.0 (2017-12-07)__
|
||||||
|
|
||||||
|
|||||||
6
Makefile
6
Makefile
@@ -3,12 +3,14 @@ ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/ar
|
|||||||
# Include common definitions
|
# Include common definitions
|
||||||
include common.mak
|
include common.mak
|
||||||
|
|
||||||
LIB_DIRS = libvtoc libu2s libutil libzds libdasd libvmdump libccw
|
LIB_DIRS = libvtoc libutil libzds libdasd libvmdump libccw libvmcp
|
||||||
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
TOOL_DIRS = zipl zdump fdasd dasdfmt dasdview tunedasd \
|
||||||
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
tape390 osasnmpd qetharp ip_watcher qethconf scripts zconf \
|
||||||
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
vmconvert vmcp man mon_tools dasdinfo vmur cpuplugd ipl_tools \
|
||||||
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
|
systemd hmcdrvfs cpacfstats zdev dump2tar zkey netboot etc zpcictl \
|
||||||
|
genprotimg
|
||||||
|
|
||||||
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
|
SUB_DIRS = $(LIB_DIRS) $(TOOL_DIRS)
|
||||||
|
|
||||||
all: $(TOOL_DIRS)
|
all: $(TOOL_DIRS)
|
||||||
|
|||||||
33
README.md
33
README.md
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
s390-tools
|
s390-tools
|
||||||
==========
|
==========
|
||||||
|
|
||||||
@@ -31,6 +30,9 @@ Package contents
|
|||||||
* dasdinfo:
|
* dasdinfo:
|
||||||
Display unique DASD ID, either UID or volser.
|
Display unique DASD ID, either UID or volser.
|
||||||
|
|
||||||
|
* genprotimg:
|
||||||
|
Create a protected virtualization image.
|
||||||
|
|
||||||
* 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.
|
||||||
@@ -129,6 +131,7 @@ Package contents
|
|||||||
or show encryption state of attached LUNs.
|
or show encryption state of attached LUNs.
|
||||||
- lszcrypt: Show Information about zcrypt devices and configuration.
|
- lszcrypt: Show Information about zcrypt devices and configuration.
|
||||||
- chzcrypt: Modify the zcrypt configuration.
|
- chzcrypt: Modify the zcrypt configuration.
|
||||||
|
- zcryptstats: Display usage statistics of IBM Crypto Express adapters.
|
||||||
- znetconf: List and configure network devices for s390 network adapters.
|
- znetconf: List and configure network devices for s390 network adapters.
|
||||||
- cio_ignore: Query and modify the contents of the CIO device driver
|
- cio_ignore: Query and modify the contents of the CIO device driver
|
||||||
blacklist.
|
blacklist.
|
||||||
@@ -264,12 +267,17 @@ build options:
|
|||||||
| pfm | `HAVE_PFM` | cpacfstats |
|
| 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 |
|
||||||
|
| cryptsetup | `HAVE_CRYPTSETUP2` | zkey-cryptsetup |
|
||||||
|
| json-c | `HAVE_JSONC` | zkey-cryptsetup |
|
||||||
|
| glib2 | `HAVE_GLIB2` | genprotimg |
|
||||||
|
|
||||||
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 |
|
| dracut | `HAVE_DRACUT` | zdev |
|
||||||
|
| initramfs-tools| `HAVE_INITRAMFS` | 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.
|
||||||
@@ -280,6 +288,17 @@ Build and runtime requirements for specific tools
|
|||||||
In the following more details on the build an runtime requirements of
|
In the following more details on the build an runtime requirements of
|
||||||
the different tools are provided:
|
the different tools are provided:
|
||||||
|
|
||||||
|
* dbginfo.sh:
|
||||||
|
The tar package is required to archive collected data.
|
||||||
|
|
||||||
|
* genprotimg:
|
||||||
|
For building genprotimg you need OpenSSL version 1.1.0 or newer
|
||||||
|
installed (openssl-devel.rpm). Also required is glib2
|
||||||
|
(glib2-devel.rpm). Tip: you may skip the genprotimg build by adding
|
||||||
|
`HAVE_OPENSSL=0` or `HAVE_GLIB2=0`.
|
||||||
|
|
||||||
|
The runtime requirements are: openssl-libs (>= 1.1.0) and glib2.
|
||||||
|
|
||||||
* osasnmpd:
|
* 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.
|
||||||
@@ -366,3 +385,15 @@ the different tools are provided:
|
|||||||
For running znetconf these programs are required:
|
For running znetconf these programs are required:
|
||||||
- modprobe (kmod)
|
- modprobe (kmod)
|
||||||
- vmcp (s390-tools)
|
- vmcp (s390-tools)
|
||||||
|
|
||||||
|
* zkey:
|
||||||
|
For building the zkey tools you need openssl version 0.9.7 or newer installed
|
||||||
|
(openssl-devel.rpm). Also required are cryptsetup version 2.0.3 or newer
|
||||||
|
(cryptsetup-devel.rpm), and json-c version 0.12 or newer (json-c-devel.rpm).
|
||||||
|
Tip: you may skip the zkey build by adding `HAVE_OPENSSL=0`, and you may
|
||||||
|
may skip the zkey-cryptsetup build by adding `HAVE_CRYPTSETUP2=0`, or
|
||||||
|
`HAVE_JSONC=0` to the make invocation.
|
||||||
|
A new group 'zkeyadm' needs to be created and all users intending to use the
|
||||||
|
tool must be added to this group. The owner of the default key repository
|
||||||
|
'/etc/zkey/repository' must be set to group 'zkeyadm' with write permission
|
||||||
|
for this group.
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ cmsfs-fuse uses a configuration file for automatic translation based on the file
|
|||||||
Upon startup, cmsfs-fuse evaluates the file .cmsfs-fuse/filetypes.conf in the user's home directory. If the file does not
|
Upon startup, cmsfs-fuse evaluates the file .cmsfs-fuse/filetypes.conf in the user's home directory. If the file does not
|
||||||
exist cmsfs-fuse evaluates the file /etc/cmsfs-fuse/filetypes.conf.
|
exist cmsfs-fuse evaluates the file /etc/cmsfs-fuse/filetypes.conf.
|
||||||
|
|
||||||
The filetypes.conf file contains the CMS file types that are automaticaly translated to ASCII if cmsfs-fuse is started
|
The filetypes.conf file contains the CMS file types that are automatically translated to ASCII if cmsfs-fuse is started
|
||||||
with the -t option. The syntax of the configuration file is one file type per line. Lines that start with a # followed by a space are treated as
|
with the -t option. The syntax of the configuration file is one file type per line. Lines that start with a # followed by a space are treated as
|
||||||
comments and are ignored. The file type is 8 characters long and must consist of valid CMS file name characters only.
|
comments and are ignored. The file type is 8 characters long and must consist of valid CMS file name characters only.
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Main function
|
* Main function
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2010, 2017
|
* Copyright IBM Corp. 2010, 2018
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include <fuse.h>
|
#include <fuse.h>
|
||||||
#include <fuse_opt.h>
|
#include <fuse_opt.h>
|
||||||
#include <iconv.h>
|
#include <iconv.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#ifdef HAVE_SETXATTR
|
#ifdef HAVE_SETXATTR
|
||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
|
#include "lib/util_libc.h"
|
||||||
#include "lib/util_list.h"
|
#include "lib/util_list.h"
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
@@ -76,7 +78,7 @@ static const struct fuse_opt cmsfs_opts[] = {
|
|||||||
|
|
||||||
static void usage(const char *progname)
|
static void usage(const char *progname)
|
||||||
{
|
{
|
||||||
fprintf(stderr,
|
fprintf(stdout,
|
||||||
"Usage: %s DEVICE MOUNTPOINT [OPTIONS]\n"
|
"Usage: %s DEVICE MOUNTPOINT [OPTIONS]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Use the cmsfs-fuse command to read and write files stored on a z/VM CMS disk.\n"
|
"Use the cmsfs-fuse command to read and write files stored on a z/VM CMS disk.\n"
|
||||||
@@ -232,6 +234,8 @@ struct file {
|
|||||||
int null_records;
|
int null_records;
|
||||||
/* write cache for text mode */
|
/* write cache for text mode */
|
||||||
char *wcache;
|
char *wcache;
|
||||||
|
/* buffer for iconv */
|
||||||
|
char *iconv_buf;
|
||||||
/* used bytes in write cache */
|
/* used bytes in write cache */
|
||||||
int wcache_used;
|
int wcache_used;
|
||||||
/* committed written bytes to FUSE */
|
/* committed written bytes to FUSE */
|
||||||
@@ -601,7 +605,7 @@ static struct file *file_open(const char *name)
|
|||||||
char uc_name[MAX_FNAME];
|
char uc_name[MAX_FNAME];
|
||||||
struct file *f;
|
struct file *f;
|
||||||
|
|
||||||
strncpy(uc_name, name, MAX_FNAME);
|
util_strlcpy(uc_name, name, MAX_FNAME);
|
||||||
str_toupper(uc_name);
|
str_toupper(uc_name);
|
||||||
|
|
||||||
util_list_iterate(&open_file_list, f)
|
util_list_iterate(&open_file_list, f)
|
||||||
@@ -923,7 +927,6 @@ static void set_record(struct file *f, int *record, off_t addr, int len,
|
|||||||
static void add_record_ext(struct record *rec, struct record_ext *ext)
|
static void add_record_ext(struct record *rec, struct record_ext *ext)
|
||||||
{
|
{
|
||||||
struct record_ext *tmp;
|
struct record_ext *tmp;
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
if (rec->ext == NULL) {
|
if (rec->ext == NULL) {
|
||||||
rec->ext = ext;
|
rec->ext = ext;
|
||||||
@@ -931,9 +934,7 @@ static void add_record_ext(struct record *rec, struct record_ext *ext)
|
|||||||
ext->next = NULL;
|
ext->next = NULL;
|
||||||
} else {
|
} else {
|
||||||
tmp = rec->ext;
|
tmp = rec->ext;
|
||||||
i++;
|
|
||||||
while (tmp->next != NULL) {
|
while (tmp->next != NULL) {
|
||||||
i++;
|
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
}
|
}
|
||||||
tmp->next = ext;
|
tmp->next = ext;
|
||||||
@@ -1567,7 +1568,7 @@ static off_t lookup_file(const char *name, struct fst_entry *fst, int flag)
|
|||||||
off_t faddr = 0;
|
off_t faddr = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
strncpy(uc_name, name, MAX_FNAME);
|
util_strlcpy(uc_name, name, MAX_FNAME);
|
||||||
str_toupper(uc_name);
|
str_toupper(uc_name);
|
||||||
|
|
||||||
if (flag == HIDE_UNLINKED && file_unlinked(uc_name))
|
if (flag == HIDE_UNLINKED && file_unlinked(uc_name))
|
||||||
@@ -1851,7 +1852,26 @@ static int cmsfs_open(const char *path, struct fuse_file_info *fi)
|
|||||||
if (f->wcache == NULL)
|
if (f->wcache == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
strncpy(f->path, path, MAX_FNAME + 1);
|
/*
|
||||||
|
* For fixed-length records f->fst->record_len contains
|
||||||
|
* the fixed record length, which will not change. For
|
||||||
|
* variable-length records it contains the (current) maximum
|
||||||
|
* record length, which could be increased later by appending
|
||||||
|
* new records, so use MAX_RECORD_LEN for the iconv buffer.
|
||||||
|
* The MAX_RECORD_LEN is not valid for fixed-length records,
|
||||||
|
* only for variable-length records, so use the actual record
|
||||||
|
* length (f->fst->record_len) for fixed-length records.
|
||||||
|
*/
|
||||||
|
if (f->fst->record_format == RECORD_LEN_FIXED)
|
||||||
|
f->iconv_buf = malloc(f->fst->record_len + 1);
|
||||||
|
else
|
||||||
|
f->iconv_buf = malloc(MAX_RECORD_LEN + 1);
|
||||||
|
if (f->iconv_buf == NULL) {
|
||||||
|
destroy_file_object(f);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
util_strlcpy(f->path, path, MAX_FNAME + 1);
|
||||||
str_toupper(f->path);
|
str_toupper(f->path);
|
||||||
|
|
||||||
f->use_count = 1;
|
f->use_count = 1;
|
||||||
@@ -2108,7 +2128,7 @@ static int cmsfs_create(const char *path, mode_t mode,
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
/* force uppercase */
|
/* force uppercase */
|
||||||
strncpy(uc_name, path + 1, MAX_FNAME);
|
util_strlcpy(uc_name, path + 1, MAX_FNAME);
|
||||||
str_toupper(uc_name);
|
str_toupper(uc_name);
|
||||||
|
|
||||||
rc = encode_edf_name(uc_name, fname, ftype);
|
rc = encode_edf_name(uc_name, fname, ftype);
|
||||||
@@ -2550,14 +2570,13 @@ static void get_block_data_from_record(struct record *rec, off_t offset,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int convert_text(iconv_t conv, char *buf, int size)
|
static int convert_text(iconv_t conv, char *in_buf, char *out_buf, int size)
|
||||||
{
|
{
|
||||||
size_t out_count = size;
|
size_t out_count = size;
|
||||||
size_t in_count = size;
|
size_t in_count = size;
|
||||||
char *data_ptr = buf;
|
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = iconv(conv, &data_ptr, &in_count, &data_ptr, &out_count);
|
rc = iconv(conv, &in_buf, &in_count, &out_buf, &out_count);
|
||||||
if ((rc == -1) || (in_count != 0)) {
|
if ((rc == -1) || (in_count != 0)) {
|
||||||
DEBUG("Code page translation EBCDIC-ASCII failed\n");
|
DEBUG("Code page translation EBCDIC-ASCII failed\n");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
@@ -2618,14 +2637,15 @@ static int cmsfs_read(const char *path, char *buf, size_t size, off_t offset,
|
|||||||
/* read one record */
|
/* read one record */
|
||||||
if (addr == NULL_BLOCK)
|
if (addr == NULL_BLOCK)
|
||||||
memset(buf, 0, chunk);
|
memset(buf, 0, chunk);
|
||||||
else {
|
else if (f->translate) {
|
||||||
rc = _read(buf, chunk, addr);
|
rc = _read(f->iconv_buf, chunk, addr);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
rc = convert_text(cmsfs.iconv_from, f->iconv_buf, buf, chunk);
|
||||||
|
if (rc < 0)
|
||||||
if (f->translate) {
|
return rc;
|
||||||
rc = convert_text(cmsfs.iconv_from, buf, chunk);
|
} else {
|
||||||
|
rc = _read(buf, chunk, addr);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@@ -2757,7 +2777,7 @@ static int delete_file(const char *path)
|
|||||||
fst_last = find_last_fdir_entry(cmsfs.fdir, cmsfs.dir_levels);
|
fst_last = find_last_fdir_entry(cmsfs.fdir, cmsfs.dir_levels);
|
||||||
|
|
||||||
/* remove unlinked file from fcache */
|
/* remove unlinked file from fcache */
|
||||||
strncpy(file, path + 1, MAX_FNAME);
|
util_strlcpy(file, path + 1, MAX_FNAME);
|
||||||
str_toupper(file);
|
str_toupper(file);
|
||||||
invalidate_htab_entry(file);
|
invalidate_htab_entry(file);
|
||||||
|
|
||||||
@@ -2841,20 +2861,21 @@ static int cmsfs_rename(const char *path, const char *new_path)
|
|||||||
str_toupper(uc_new_name);
|
str_toupper(uc_new_name);
|
||||||
|
|
||||||
rc = encode_edf_name(uc_new_name, fname, ftype);
|
rc = encode_edf_name(uc_new_name, fname, ftype);
|
||||||
|
free(uc_new_name);
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
memcpy(&fst.name[0], fname, 8);
|
memcpy(&fst.name[0], fname, 8);
|
||||||
memcpy(&fst.type[0], ftype, 8);
|
memcpy(&fst.type[0], ftype, 8);
|
||||||
|
|
||||||
strncpy(uc_old_name, path + 1, MAX_FNAME);
|
util_strlcpy(uc_old_name, path + 1, MAX_FNAME);
|
||||||
str_toupper(uc_old_name);
|
str_toupper(uc_old_name);
|
||||||
invalidate_htab_entry(uc_old_name);
|
invalidate_htab_entry(uc_old_name);
|
||||||
|
|
||||||
/* update name in file object if the file is opened */
|
/* update name in file object if the file is opened */
|
||||||
f = file_open(uc_old_name);
|
f = file_open(uc_old_name);
|
||||||
if (f != NULL) {
|
if (f != NULL) {
|
||||||
strncpy(f->path, new_path, MAX_FNAME + 1);
|
util_strlcpy(f->path, new_path, MAX_FNAME + 1);
|
||||||
str_toupper(f->path);
|
str_toupper(f->path);
|
||||||
memcpy(f->fst->name, fname, 8);
|
memcpy(f->fst->name, fname, 8);
|
||||||
memcpy(f->fst->type, ftype, 8);
|
memcpy(f->fst->type, ftype, 8);
|
||||||
@@ -3743,7 +3764,7 @@ static int extend_block_variable(struct file *f, const char *buf, int len,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEBUG("%s: wrote %d record bytes\n", __func__, rlen);
|
DEBUG("%s: wrote %d record bytes\n", __func__, rlen);
|
||||||
if (size <= 0)
|
if (size == 0)
|
||||||
return copied;
|
return copied;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4167,22 +4188,13 @@ static ssize_t find_newline(const char *buf, int len)
|
|||||||
return pos - buf;
|
return pos - buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmsfs_write(const char *path, const char *buf, size_t size,
|
static int cmsfs_write_strings(struct file *f, const char *buf,
|
||||||
off_t offset, struct fuse_file_info *fi)
|
size_t size, off_t offset)
|
||||||
{
|
{
|
||||||
int scan_len = MIN(size, (size_t)MAX_RECORD_LEN + 1);
|
int scan_len = MIN(size, (size_t)MAX_RECORD_LEN + 1);
|
||||||
int rc, nl_byte = 1, null_record = 0, pad = 0;
|
int rc, nl_byte = 1, null_record = 0, pad = 0;
|
||||||
struct file *f = get_fobj(fi);
|
|
||||||
ssize_t rsize;
|
ssize_t rsize;
|
||||||
|
|
||||||
(void) path;
|
|
||||||
|
|
||||||
if (cmsfs.readonly)
|
|
||||||
return -EROFS;
|
|
||||||
|
|
||||||
if (!f->linefeed)
|
|
||||||
return do_write(f, buf, size, offset);
|
|
||||||
|
|
||||||
/* remove already committed bytes */
|
/* remove already committed bytes */
|
||||||
offset -= f->wcache_commited;
|
offset -= f->wcache_commited;
|
||||||
|
|
||||||
@@ -4222,7 +4234,7 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* translate */
|
/* translate */
|
||||||
rc = convert_text(cmsfs.iconv_to, f->wcache, f->wcache_used);
|
rc = convert_text(cmsfs.iconv_to, f->wcache, f->iconv_buf, f->wcache_used);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@@ -4232,6 +4244,7 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
|
|||||||
*/
|
*/
|
||||||
if (!f->wcache_used) {
|
if (!f->wcache_used) {
|
||||||
*f->wcache = FILLER_EBCDIC;
|
*f->wcache = FILLER_EBCDIC;
|
||||||
|
*f->iconv_buf = FILLER_EBCDIC;
|
||||||
f->wcache_used = 1;
|
f->wcache_used = 1;
|
||||||
nl_byte = 0;
|
nl_byte = 0;
|
||||||
null_record = 1;
|
null_record = 1;
|
||||||
@@ -4242,7 +4255,7 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
|
|||||||
offset += f->pad_bytes;
|
offset += f->pad_bytes;
|
||||||
BUG(offset < 0);
|
BUG(offset < 0);
|
||||||
|
|
||||||
rc = do_write(f, f->wcache, f->wcache_used, offset);
|
rc = do_write(f, f->iconv_buf, f->wcache_used, offset);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@@ -4257,6 +4270,36 @@ static int cmsfs_write(const char *path, const char *buf, size_t size,
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cmsfs_write(const char *path, const char *buf, size_t size,
|
||||||
|
off_t offset, struct fuse_file_info *fi)
|
||||||
|
{
|
||||||
|
struct file *f = get_fobj(fi);
|
||||||
|
int rc, written, nbytes;
|
||||||
|
|
||||||
|
(void) path;
|
||||||
|
|
||||||
|
if (cmsfs.readonly)
|
||||||
|
return -EROFS;
|
||||||
|
|
||||||
|
if (!f->linefeed)
|
||||||
|
return do_write(f, buf, size, offset);
|
||||||
|
|
||||||
|
/* Limit the size to what we can report back as written */
|
||||||
|
nbytes = MIN(size, (size_t) INT_MAX);
|
||||||
|
|
||||||
|
written = 0;
|
||||||
|
while (nbytes) {
|
||||||
|
rc = cmsfs_write_strings(f, buf, nbytes, offset);
|
||||||
|
if (rc < 0)
|
||||||
|
return written ? written : rc;
|
||||||
|
written += rc;
|
||||||
|
offset += rc;
|
||||||
|
buf += rc;
|
||||||
|
nbytes -= rc;
|
||||||
|
}
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
static int cmsfs_unlink(const char *path)
|
static int cmsfs_unlink(const char *path)
|
||||||
{
|
{
|
||||||
struct fst_entry fst;
|
struct fst_entry fst;
|
||||||
@@ -4284,7 +4327,7 @@ static int flush_wcache(struct file *f)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* translate */
|
/* translate */
|
||||||
rc = convert_text(cmsfs.iconv_to, f->wcache, f->wcache_used);
|
rc = convert_text(cmsfs.iconv_to, f->wcache, f->iconv_buf, f->wcache_used);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
@@ -4292,7 +4335,7 @@ static int flush_wcache(struct file *f)
|
|||||||
offset -= (f->fst->nr_records - f->null_records);
|
offset -= (f->fst->nr_records - f->null_records);
|
||||||
BUG(offset < 0);
|
BUG(offset < 0);
|
||||||
|
|
||||||
rc = do_write(f, f->wcache, f->wcache_used, offset);
|
rc = do_write(f, f->iconv_buf, f->wcache_used, offset);
|
||||||
purge_wcache(f);
|
purge_wcache(f);
|
||||||
f->null_records = 0;
|
f->null_records = 0;
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
@@ -4415,6 +4458,7 @@ static void destroy_file_object(struct file *f)
|
|||||||
struct record *rec;
|
struct record *rec;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
free(f->iconv_buf);
|
||||||
free(f->wcache);
|
free(f->wcache);
|
||||||
free(f->wstate);
|
free(f->wstate);
|
||||||
|
|
||||||
@@ -4498,14 +4542,23 @@ static int cmsfs_process_args(void *data, const char *arg, int key,
|
|||||||
return 1;
|
return 1;
|
||||||
case KEY_HELP:
|
case KEY_HELP:
|
||||||
usage(outargs->argv[0]);
|
usage(outargs->argv[0]);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Usage output needs to go to stdout to be consistent with
|
||||||
|
* coding guidelines. FUSE versions before 3.0.0 print help
|
||||||
|
* output to stderr. Redirect stderr to stdout here to enforce
|
||||||
|
* consistent behavior.
|
||||||
|
*/
|
||||||
|
fflush(stderr);
|
||||||
|
dup2(STDOUT_FILENO, STDERR_FILENO);
|
||||||
|
|
||||||
fuse_opt_add_arg(outargs, "-ho");
|
fuse_opt_add_arg(outargs, "-ho");
|
||||||
cmsfs_fuse_main(outargs, &cmsfs_oper);
|
cmsfs_fuse_main(outargs, &cmsfs_oper);
|
||||||
exit(0);
|
exit(0);
|
||||||
case KEY_VERSION:
|
case KEY_VERSION:
|
||||||
fprintf(stderr, COMP "FUSE file system for CMS disks "
|
fprintf(stdout, COMP "FUSE file system for CMS disks "
|
||||||
"program version %s\n", RELEASE_STRING);
|
"program version %s\n", RELEASE_STRING);
|
||||||
fprintf(stderr, "Copyright IBM Corp. 2010, 2017\n");
|
fprintf(stdout, "Copyright IBM Corp. 2010, 2017\n");
|
||||||
fuse_opt_add_arg(outargs, "--version");
|
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "lib/util_libc.h"
|
||||||
#include "lib/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#include "cmsfs-fuse.h"
|
#include "cmsfs-fuse.h"
|
||||||
@@ -65,7 +66,7 @@ static void add_filetype(char *name, struct util_list *list)
|
|||||||
entry = malloc(sizeof(*entry));
|
entry = malloc(sizeof(*entry));
|
||||||
if (entry == NULL)
|
if (entry == NULL)
|
||||||
DIE_PERROR("malloc failed");
|
DIE_PERROR("malloc failed");
|
||||||
strncpy(entry->name, name, MAX_TYPE_LEN);
|
util_strlcpy(entry->name, name, MAX_TYPE_LEN);
|
||||||
util_list_add_head(list, entry);
|
util_list_add_head(list, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
#include "cmsfs-fuse.h"
|
#include "cmsfs-fuse.h"
|
||||||
#include "edf.h"
|
#include "edf.h"
|
||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
|
|||||||
@@ -49,6 +49,4 @@ extern FILE *logfile;
|
|||||||
fprintf(stderr, COMP "Warning, " __VA_ARGS__); \
|
fprintf(stderr, COMP "Warning, " __VA_ARGS__); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
31
common.mak
31
common.mak
@@ -5,7 +5,7 @@ COMMON_INCLUDED = true
|
|||||||
# The variable "DISTRELEASE" should be overwritten in rpm spec files with:
|
# 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 = 2
|
RELEASE = 13
|
||||||
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)
|
||||||
@@ -182,9 +182,10 @@ GROUP = $(shell id -gn)
|
|||||||
export INSTALLDIR BINDIR LIBDIR MANDIR OWNER GROUP
|
export INSTALLDIR BINDIR LIBDIR MANDIR OWNER GROUP
|
||||||
|
|
||||||
# Special defines for zfcpdump
|
# Special defines for zfcpdump
|
||||||
ZFCPDUMP_PART_IMAGE = zfcpdump_part.image
|
ZFCPDUMP_IMAGE = zfcpdump-image
|
||||||
ZFCPDUMP_PART_RD = zfcpdump_part.rd
|
ZFCPDUMP_INITRD = zfcpdump-initrd
|
||||||
export ZFCPDUMP_DIR ZFCPDUMP_PART_IMAGE ZFCPDUMP_PART_RD
|
ZFCPDUMP_FLAVOR = zfcpdump
|
||||||
|
export ZFCPDUMP_DIR ZFCPDUMP_IMAGE ZFCPDUMP_INITRD ZFCPDUMP_FLAVOR
|
||||||
|
|
||||||
CFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
|
CFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
|
||||||
HOSTCFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
|
HOSTCFLAGS ?= $(DEFAULT_CFLAGS) $(OPT_FLAGS)
|
||||||
@@ -218,18 +219,28 @@ endif
|
|||||||
export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
|
export AS LD CC CPP AR NM STRIP OBJCOPY OBJDUMP INSTALL CFLAGS CXXFLAGS \
|
||||||
LDFLAGS CPPFLAGS ALL_CFLAGS ALL_CXXFLAGS ALL_LDFLAGS ALL_CPPFLAGS
|
LDFLAGS CPPFLAGS ALL_CFLAGS ALL_CXXFLAGS ALL_LDFLAGS ALL_CPPFLAGS
|
||||||
|
|
||||||
|
ifneq ($(shell $(CC_SILENT) -dumpspecs 2>/dev/null | grep -e '[^f]no-pie'),)
|
||||||
|
NO_PIE_CFLAGS := -fno-pie
|
||||||
|
NO_PIE_LINKFLAGS := -no-pie
|
||||||
|
NO_PIE_LDFLAGS := -no-pie
|
||||||
|
else
|
||||||
|
NO_PIE_CFLAGS :=
|
||||||
|
NO_PIE_LINKFLAGS :=
|
||||||
|
NO_PIE_LDFLAGS :=
|
||||||
|
endif
|
||||||
|
|
||||||
# Overwrite implicite makefile rules for having nice compile output
|
# Overwrite implicite makefile rules for having nice compile output
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
|
||||||
ifeq ("${C}","1")
|
ifeq ("${C}","1")
|
||||||
$(CHECKTOOL) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
$(CHECKTOOL) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||||
endif
|
endif
|
||||||
|
$(CC) $(ALL_CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@
|
$(CXX) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
%: %.o
|
%: %.o
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
%.a:
|
%.a:
|
||||||
$(AR) rcs $@ $^
|
$(AR) rcs $@ $^
|
||||||
@@ -320,14 +331,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)/libu2s/libu2s.a: $(rootdir)/libu2s
|
|
||||||
$(MAKE) -C $(rootdir)/libu2s/ libu2s.a
|
|
||||||
.PHONY: $(rootdir)/libu2s
|
|
||||||
|
|
||||||
$(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
|
$(rootdir)/libvmdump/libvmdump.a: $(rootdir)/libvmdump
|
||||||
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
|
$(MAKE) -C $(rootdir)/libvmdump/ libvmdump.a
|
||||||
.PHONY: $(rootdir)/libvmdump
|
.PHONY: $(rootdir)/libvmdump
|
||||||
|
|
||||||
|
$(rootdir)/libvmcp/libvmcp.a: $(rootdir)/libvmcp
|
||||||
|
$(MAKE) -C $(rootdir)/libvmcp/ libvmcp.a
|
||||||
|
.PHONY: $(rootdir)/libvmcp
|
||||||
|
|
||||||
$(rootdir)/zipl/boot/data.o:
|
$(rootdir)/zipl/boot/data.o:
|
||||||
$(MAKE) -C $(rootdir)/zipl/boot/ data.o
|
$(MAKE) -C $(rootdir)/zipl/boot/ data.o
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ The default command is --print all.
|
|||||||
.
|
.
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.nf
|
.nf
|
||||||
/var/run/cpacfstatsd_socket
|
/run/cpacfstatsd_socket
|
||||||
.fi
|
.fi
|
||||||
.
|
.
|
||||||
.SH RETURN VALUE
|
.SH RETURN VALUE
|
||||||
|
|||||||
@@ -78,8 +78,8 @@ struct msg_answer {
|
|||||||
|
|
||||||
#define BACKLOG 10
|
#define BACKLOG 10
|
||||||
|
|
||||||
#define SOCKET_FILE "/var/run/cpacfstatsd_socket"
|
#define SOCKET_FILE "/run/cpacfstatsd_socket"
|
||||||
#define PID_FILE "/var/run/cpacfstatsd.pid"
|
#define PID_FILE "/run/cpacfstatsd.pid"
|
||||||
|
|
||||||
#define CPACFSTATS_GROUP "cpacfstats"
|
#define CPACFSTATS_GROUP "cpacfstats"
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ restart the daemon to ensure correct summing of the per-CPU performance
|
|||||||
counters.
|
counters.
|
||||||
|
|
||||||
The starting daemon first checks for any stale pid file
|
The starting daemon first checks for any stale pid file
|
||||||
/var/run/cpacfstatsd.pid. If this file exists, and the process ID in the
|
/run/cpacfstatsd.pid. If this file exists, and the process ID in the
|
||||||
file belongs to an active process, an error message is printed to the
|
file belongs to an active process, an error message is printed to the
|
||||||
console and the program terminates.
|
console and the program terminates.
|
||||||
|
|
||||||
@@ -81,8 +81,8 @@ daemon startup and initialization failures.
|
|||||||
|
|
||||||
.SH FILES
|
.SH FILES
|
||||||
.nf
|
.nf
|
||||||
/var/run/cpacfstatsd_socket
|
/run/cpacfstatsd_socket
|
||||||
/var/run/cpacfstatsd.pid
|
/run/cpacfstatsd.pid
|
||||||
.fi
|
.fi
|
||||||
|
|
||||||
.SH RETURN VALUE
|
.SH RETURN VALUE
|
||||||
|
|||||||
@@ -4,10 +4,13 @@ include ../common.mak
|
|||||||
|
|
||||||
|
|
||||||
CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf
|
CPUMF_DATADIR = $(TOOLS_DATADIR)/cpumf
|
||||||
DATA_FILES = cpum-cf-hw-counter.map cpum-cf-generic.ctr \
|
DATA_FILES = cpum-cf-hw-counter.map \
|
||||||
|
cpum-cf-cfvn-1.ctr cpum-cf-cfvn-3.ctr \
|
||||||
|
cpum-cf-csvn-12345.ctr cpum-cf-csvn-6.ctr \
|
||||||
cpum-cf-extended-z10.ctr cpum-cf-extended-z196.ctr \
|
cpum-cf-extended-z10.ctr cpum-cf-extended-z196.ctr \
|
||||||
cpum-cf-extended-zEC12.ctr cpum-sf-modes.ctr \
|
cpum-cf-extended-zEC12.ctr cpum-sf-modes.ctr \
|
||||||
cpum-cf-extended-z13.ctr
|
cpum-cf-extended-z13.ctr cpum-cf-extended-z14.ctr \
|
||||||
|
cpum-cf-extended-z15.ctr
|
||||||
LIB_FILES = bin/cpumf_helper
|
LIB_FILES = bin/cpumf_helper
|
||||||
USRBIN_SCRIPTS = bin/lscpumf
|
USRBIN_SCRIPTS = bin/lscpumf
|
||||||
USRSBIN_SCRIPTS = bin/chcpumf
|
USRSBIN_SCRIPTS = bin/chcpumf
|
||||||
|
|||||||
212
cpumf/bin/cpumf_helper.in
Normal file → Executable file
212
cpumf/bin/cpumf_helper.in
Normal file → Executable file
@@ -12,8 +12,6 @@ use warnings;
|
|||||||
use Carp qw/croak/;
|
use Carp qw/croak/;
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
use Getopt::Long qw/:config no_ignore_case/;
|
use Getopt::Long qw/:config no_ignore_case/;
|
||||||
use Pod::Usage;
|
|
||||||
|
|
||||||
|
|
||||||
# Global constants
|
# Global constants
|
||||||
my $SERVICE_LEVELS = '/proc/service_levels';
|
my $SERVICE_LEVELS = '/proc/service_levels';
|
||||||
@@ -51,10 +49,11 @@ sub cpumf_get_sfb_size()
|
|||||||
my $val = "0,0";
|
my $val = "0,0";
|
||||||
my $SFBSIZE;
|
my $SFBSIZE;
|
||||||
|
|
||||||
return $val unless open($SFBSIZE, '<', $CPUM_SFB_SIZE);
|
if (open($SFBSIZE, '<', $CPUM_SFB_SIZE)) {
|
||||||
$val = <$SFBSIZE>;
|
$val = <$SFBSIZE>;
|
||||||
chomp($val);
|
chomp($val);
|
||||||
close($SFBSIZE);
|
close($SFBSIZE);
|
||||||
|
}
|
||||||
|
|
||||||
return [split /,/, $val];
|
return [split /,/, $val];
|
||||||
}
|
}
|
||||||
@@ -172,7 +171,7 @@ sub cpumf_parse_ctrdef($;$)
|
|||||||
|
|
||||||
# Parse short description (optional)
|
# Parse short description (optional)
|
||||||
if ($line =~ m/^Short-Description:\s*(\S.*)?$/) {
|
if ($line =~ m/^Short-Description:\s*(\S.*)?$/) {
|
||||||
$h->{ctr}->{shortdesc} = $1 || "";
|
$h->{$ctr}->{shortdesc} = $1 || "";
|
||||||
|
|
||||||
# Parse start of counter description
|
# Parse start of counter description
|
||||||
} elsif ($line =~ m/^Description:\s*(\S.*)?$/) {
|
} elsif ($line =~ m/^Description:\s*(\S.*)?$/) {
|
||||||
@@ -210,6 +209,9 @@ my $system_z_hwtype_map = {
|
|||||||
2828 => 'IBM zEnterprise BC12',
|
2828 => 'IBM zEnterprise BC12',
|
||||||
2964 => 'IBM z13',
|
2964 => 'IBM z13',
|
||||||
2965 => 'IBM z13s',
|
2965 => 'IBM z13s',
|
||||||
|
3906 => 'IBM z14',
|
||||||
|
3907 => 'IBM z14 ZR1',
|
||||||
|
8561 => 'IBM z15',
|
||||||
};
|
};
|
||||||
|
|
||||||
sub get_hardware_type()
|
sub get_hardware_type()
|
||||||
@@ -228,6 +230,28 @@ sub get_hardware_type()
|
|||||||
return $type;
|
return $type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_cpum_cf_version()
|
||||||
|
{
|
||||||
|
my $SL;
|
||||||
|
|
||||||
|
my $v = {
|
||||||
|
cfvn => 0,
|
||||||
|
csvn => 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
return $v unless open($SL, '<', $SERVICE_LEVELS);
|
||||||
|
while (my $line = <$SL>) {
|
||||||
|
# CPU-MF: Counter facility: version=3.5
|
||||||
|
if ($line =~ m/^CPU-MF: Counter facility: version=(\d+)\.(\d+)/) {
|
||||||
|
$v->{cfvn} = $1; # Counter First Version Number
|
||||||
|
$v->{csvn} = $2; # Counter Second Version Number
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close($SL);
|
||||||
|
return $v
|
||||||
|
}
|
||||||
|
|
||||||
sub cpumf_load_ctrdef($;$)
|
sub cpumf_load_ctrdef($;$)
|
||||||
{
|
{
|
||||||
my $hw_type = shift();
|
my $hw_type = shift();
|
||||||
@@ -236,10 +260,25 @@ sub cpumf_load_ctrdef($;$)
|
|||||||
my $ctrmap = cpumf_hardware_counter_map();
|
my $ctrmap = cpumf_hardware_counter_map();
|
||||||
return unless $ctrmap;
|
return unless $ctrmap;
|
||||||
|
|
||||||
|
# Obtain CPU-MF counter facility versions
|
||||||
|
my $version = get_cpum_cf_version();
|
||||||
|
|
||||||
|
# List of "generic" counter sets
|
||||||
|
my @def = ();
|
||||||
|
push @def, "cfvn-" . $version->{cfvn};
|
||||||
|
if ($version->{csvn} >= 1 && $version->{csvn} <= 6) {
|
||||||
|
push @def, "csvn-12345";
|
||||||
|
}
|
||||||
|
if ($version->{csvn} == 6) {
|
||||||
|
push @def, "csvn-6";
|
||||||
|
}
|
||||||
|
|
||||||
my $h = {};
|
my $h = {};
|
||||||
# Load generic counter sets
|
# Load counter set definition
|
||||||
cpumf_parse_ctrdef($ctrmap->{0}, $h) or
|
foreach my $ent (@def) {
|
||||||
croak "Failed to read generic counter definition: $!\n";
|
cpumf_parse_ctrdef($ctrmap->{$ent}, $h) or
|
||||||
|
croak "Failed to read counter definition for $ent: $!\n";
|
||||||
|
}
|
||||||
# Load hardware model specific counter set(s)
|
# Load hardware model specific counter set(s)
|
||||||
if ($hw_type && $ctrmap->{$hw_type}) {
|
if ($hw_type && $ctrmap->{$hw_type}) {
|
||||||
# Hardware-model specific counter sets are:
|
# Hardware-model specific counter sets are:
|
||||||
@@ -311,6 +350,62 @@ sub cpumf_hardware_counter_map()
|
|||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $cpumf_helper_str = <<'END_MESSAGE';
|
||||||
|
|
||||||
|
cpumf_helper - Helper module for managing CPU-Measurement Facilities (CPU-MF)
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-i, --info:
|
||||||
|
Displays detailed information about installed and available
|
||||||
|
CPU-measurement facilities and the related Linux support.
|
||||||
|
|
||||||
|
-c, --counter authorization_value
|
||||||
|
Displays counter information for the current System z hardware.
|
||||||
|
The authorization value provides information about the authorized
|
||||||
|
counter sets. The value must be specified in decimal format.
|
||||||
|
|
||||||
|
To display all supported counters, specify C<65535> (FFFF hex).
|
||||||
|
|
||||||
|
To display supported counters for a particular System z hardware,
|
||||||
|
use the --ctr-def option and specify the System z hardware type.
|
||||||
|
|
||||||
|
--hardware-type
|
||||||
|
Displays the System z hardware type.
|
||||||
|
|
||||||
|
--ctr-def ctr-definition
|
||||||
|
Displays detailed information about the specified counter definition.
|
||||||
|
Valid counter definitions start with C<cfvn-> or <csvn-> followed by
|
||||||
|
the counter first/second version number of the CPU-Measurement Counter
|
||||||
|
Facility. To display counter information of model-specific counter
|
||||||
|
sets, specify the System z hardware type for I<ctr-definition>.
|
||||||
|
|
||||||
|
--ctr-set-names
|
||||||
|
Displays the mapping of counter set IDs to counter set names.
|
||||||
|
The counter set IDs are numbers that are used in counter definitions.
|
||||||
|
|
||||||
|
--ctr-set-ids
|
||||||
|
Displays the counter set IDs. The counter set IDs are numbers that
|
||||||
|
match the authorization bits (see QUERY COUNTER INFORMATION).
|
||||||
|
The output format is a list. To get the ID for a particular counter
|
||||||
|
set, use an index number as follows:
|
||||||
|
|
||||||
|
0: Basic Counter Set
|
||||||
|
1: Problem-State Counter Set
|
||||||
|
2: Crypto-Activity Counter Set
|
||||||
|
3: Extended Counter Set
|
||||||
|
4: MT-diagnostic Counter Set
|
||||||
|
5: Coprocessor Group Counter Set
|
||||||
|
|
||||||
|
--ctr-sf
|
||||||
|
Displays the counter definitions for the sampling facility support.
|
||||||
|
These counter definitions are specific to Linux perf infrastructure.
|
||||||
|
|
||||||
|
--sfb-size
|
||||||
|
Displays the size of the sampling facility buffer (SFB). The minimum
|
||||||
|
and maximum numbers are measured in units of sample-data-blocks. A
|
||||||
|
sample-data-block uses about 4 kilobytes.
|
||||||
|
|
||||||
|
END_MESSAGE
|
||||||
|
|
||||||
sub cpumf_helper_main()
|
sub cpumf_helper_main()
|
||||||
{
|
{
|
||||||
@@ -322,14 +417,14 @@ sub cpumf_helper_main()
|
|||||||
GetOptions(
|
GetOptions(
|
||||||
"i|info" => \$conf->{opt_info},
|
"i|info" => \$conf->{opt_info},
|
||||||
"c|counter=i" => \$conf->{opt_ctr},
|
"c|counter=i" => \$conf->{opt_ctr},
|
||||||
"ctr-def=i" => \$conf->{opt_ctrdef},
|
"ctr-def=s" => \$conf->{opt_ctrdef},
|
||||||
"hardware-type" => \$conf->{opt_hwtype},
|
"hardware-type" => \$conf->{opt_hwtype},
|
||||||
"ctr-set-names" => \$conf->{opt_ctrset_names},
|
"ctr-set-names" => \$conf->{opt_ctrset_names},
|
||||||
"ctr-set-ids" => \$conf->{opt_ctrset_ids},
|
"ctr-set-ids" => \$conf->{opt_ctrset_ids},
|
||||||
"sfb-size" => \$conf->{opt_sfb_size},
|
"sfb-size" => \$conf->{opt_sfb_size},
|
||||||
"ctr-sf" => \$conf->{opt_sf_ctr},
|
"ctr-sf" => \$conf->{opt_sf_ctr},
|
||||||
) or pod2usage(-message =>"One or more options are not valid",
|
) or die("One or more options are not valid\n" . $cpumf_helper_str);
|
||||||
-exitval => 1);
|
|
||||||
|
|
||||||
# Setting up Data::Dumper to create parseable Perl output
|
# Setting up Data::Dumper to create parseable Perl output
|
||||||
local $Data::Dumper::Purity = 1;
|
local $Data::Dumper::Purity = 1;
|
||||||
@@ -381,8 +476,7 @@ sub cpumf_helper_main()
|
|||||||
$result = cpumf_counter_set_ids();
|
$result = cpumf_counter_set_ids();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
pod2usage(-message => "No option specified",
|
die("No option specified\n" . $cpumf_helper_str);
|
||||||
-exitval => 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Display result
|
# Display result
|
||||||
@@ -393,91 +487,3 @@ sub cpumf_helper_main()
|
|||||||
&cpumf_helper_main();
|
&cpumf_helper_main();
|
||||||
__DATA__
|
__DATA__
|
||||||
__END__
|
__END__
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
B<cpumf_helper> - Helper module for managing CPU-Measurement Facilities (CPU-MF)
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
The B<cpumf_helper> program is not intended for ordinary use.
|
|
||||||
|
|
||||||
=head1 OPTIONS
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=item B<-i>, B<--info>
|
|
||||||
|
|
||||||
Displays detailed information about installed and available CPU-measurement
|
|
||||||
facilities and the related Linux support.
|
|
||||||
|
|
||||||
=item B<-c>, B<--counter> I<authorization_value>
|
|
||||||
|
|
||||||
Displays counter information for the current System z hardware. The
|
|
||||||
authorization value provides information about the authorized counter sets. The
|
|
||||||
value must be specified in decimal format.
|
|
||||||
|
|
||||||
To display all supported counters, specify C<65535> (FFFF hex).
|
|
||||||
|
|
||||||
To display supported counters for a particular System z hardware, use the
|
|
||||||
B<--ctr-def> option and specify the System z hardware type.
|
|
||||||
|
|
||||||
=item B<--hardware-type>
|
|
||||||
|
|
||||||
Displays the System z hardware type.
|
|
||||||
|
|
||||||
=item B<--ctr-def> I<hardware_type>
|
|
||||||
|
|
||||||
Displays detailed information about a particular counter set for the specified
|
|
||||||
System z hardware type, I<hardware_type>. If you specify zero for
|
|
||||||
I<hardware_type>, type-independent counter sets are displayed.
|
|
||||||
|
|
||||||
=item B<--ctr-set-names>
|
|
||||||
|
|
||||||
Displays the mapping of counter set IDs to counter set names. The counter set
|
|
||||||
IDs are numbers that are used in counter definitions.
|
|
||||||
|
|
||||||
=item B<--ctr-set-ids>
|
|
||||||
|
|
||||||
Displays the counter set IDs. The counter set IDs are numbers that match the
|
|
||||||
authorization bits (see QUERY COUNTER INFORMATION). The output format is a
|
|
||||||
list. To get the ID for a particular counter set, use an index number as
|
|
||||||
follows:
|
|
||||||
|
|
||||||
=over 16
|
|
||||||
|
|
||||||
=item 0: Basic Counter Set
|
|
||||||
|
|
||||||
=item 1: Problem-State Counter Set
|
|
||||||
|
|
||||||
=item 2: Crypto-Activity Counter Set
|
|
||||||
|
|
||||||
=item 3: Extended Counter Set
|
|
||||||
|
|
||||||
=item 4: MT-diagnostic Counter Set
|
|
||||||
|
|
||||||
=item 5: Coprocessor Group Counter Set
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=item B<--ctr-sf>
|
|
||||||
|
|
||||||
Displays the counter definitions for the sampling facility support. These
|
|
||||||
counter definitions are specific to Linux perf infrastructure.
|
|
||||||
|
|
||||||
=item B<--sfb-size>
|
|
||||||
|
|
||||||
Displays the size of the sampling facility buffer (SFB). The minimum and
|
|
||||||
maximum numbers are measured in units of sample-data-blocks. A
|
|
||||||
sample-data-block uses about 4 kilobytes.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 FILES
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
L<lscpumf(1)>, L<chcpumf(1)>
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|||||||
60
cpumf/data/cpum-cf-cfvn-1.ctr
Normal file
60
cpumf/data/cpum-cf-cfvn-1.ctr
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
Counter: 0 Name:CPU_CYCLES
|
||||||
|
Short-Description:CPU Cycles
|
||||||
|
Description:
|
||||||
|
Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 1 Name:INSTRUCTIONS
|
||||||
|
Short-Description:Instructions
|
||||||
|
Description:
|
||||||
|
Instruction Count
|
||||||
|
.
|
||||||
|
Counter: 2 Name:L1I_DIR_WRITES
|
||||||
|
Short-Description:L1I Directory Writes
|
||||||
|
Description:
|
||||||
|
Level-1 I-Cache Directory Write Count
|
||||||
|
.
|
||||||
|
Counter: 3 Name:L1I_PENALTY_CYCLES
|
||||||
|
Short-Description:L1I Penalty Cycles
|
||||||
|
Description:
|
||||||
|
Level-1 I-Cache Penalty Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 4 Name:L1D_DIR_WRITES
|
||||||
|
Short-Description:L1D Directory Writes
|
||||||
|
Description:
|
||||||
|
Level-1 D-Cache Directory Write Count
|
||||||
|
.
|
||||||
|
Counter: 5 Name:L1D_PENALTY_CYCLES
|
||||||
|
Short-Description:L1D Penalty Cycles
|
||||||
|
Description:
|
||||||
|
Level-1 D-Cache Penalty Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
|
||||||
|
Short-Description:Problem-State CPU Cycles
|
||||||
|
Description:
|
||||||
|
Problem-State Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
|
||||||
|
Short-Description:Problem-State Instructions
|
||||||
|
Description:
|
||||||
|
Problem-State Instruction Count
|
||||||
|
.
|
||||||
|
Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES
|
||||||
|
Short-Description:Problem-State L1I Directory Writes
|
||||||
|
Description:
|
||||||
|
Problem-State Level-1 I-Cache Directory Write Count
|
||||||
|
.
|
||||||
|
Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES
|
||||||
|
Short-Description:Problem-State L1I Penalty Cycles
|
||||||
|
Description:
|
||||||
|
Problem-State Level-1 I-Cache Penalty Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES
|
||||||
|
Short-Description:Problem-State L1D Directory Writes
|
||||||
|
Description:
|
||||||
|
Problem-State Level-1 D-Cache Directory Write Count
|
||||||
|
.
|
||||||
|
Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES
|
||||||
|
Short-Description:Problem-State L1D Penalty Cycles
|
||||||
|
Description:
|
||||||
|
Problem-State Level-1 D-Cache Penalty Cycle Count
|
||||||
|
.
|
||||||
40
cpumf/data/cpum-cf-cfvn-3.ctr
Normal file
40
cpumf/data/cpum-cf-cfvn-3.ctr
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
Counter: 0 Name:CPU_CYCLES
|
||||||
|
Short-Description:CPU Cycles
|
||||||
|
Description:
|
||||||
|
Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 1 Name:INSTRUCTIONS
|
||||||
|
Short-Description:Instructions
|
||||||
|
Description:
|
||||||
|
Instruction Count
|
||||||
|
.
|
||||||
|
Counter: 2 Name:L1I_DIR_WRITES
|
||||||
|
Short-Description:L1I Directory Writes
|
||||||
|
Description:
|
||||||
|
Level-1 I-Cache Directory Write Count
|
||||||
|
.
|
||||||
|
Counter: 3 Name:L1I_PENALTY_CYCLES
|
||||||
|
Short-Description:L1I Penalty Cycles
|
||||||
|
Description:
|
||||||
|
Level-1 I-Cache Penalty Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 4 Name:L1D_DIR_WRITES
|
||||||
|
Short-Description:L1D Directory Writes
|
||||||
|
Description:
|
||||||
|
Level-1 D-Cache Directory Write Count
|
||||||
|
.
|
||||||
|
Counter: 5 Name:L1D_PENALTY_CYCLES
|
||||||
|
Short-Description:L1D Penalty Cycles
|
||||||
|
Description:
|
||||||
|
Level-1 D-Cache Penalty Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
|
||||||
|
Short-Description:Problem-State CPU Cycles
|
||||||
|
Description:
|
||||||
|
Problem-State Cycle Count
|
||||||
|
.
|
||||||
|
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
|
||||||
|
Short-Description:Problem-State Instructions
|
||||||
|
Description:
|
||||||
|
Problem-State Instruction Count
|
||||||
|
.
|
||||||
@@ -1,130 +1,98 @@
|
|||||||
Counter: 0 Name:CPU_CYCLES
|
|
||||||
Description:
|
|
||||||
Cycle Count
|
|
||||||
.
|
|
||||||
Counter: 1 Name:INSTRUCTIONS
|
|
||||||
Description:
|
|
||||||
Instruction Count
|
|
||||||
.
|
|
||||||
Counter: 2 Name:L1I_DIR_WRITES
|
|
||||||
Description:
|
|
||||||
Level-1 I-Cache Directory Write Count
|
|
||||||
.
|
|
||||||
Counter: 3 Name:L1I_PENALTY_CYCLES
|
|
||||||
Description:
|
|
||||||
Level-1 I-Cache Penalty Cycle Count
|
|
||||||
.
|
|
||||||
Counter: 4 Name:L1D_DIR_WRITES
|
|
||||||
Description:
|
|
||||||
Level-1 D-Cache Directory Write Count
|
|
||||||
.
|
|
||||||
Counter: 5 Name:L1D_PENALTY_CYCLES
|
|
||||||
Description:
|
|
||||||
Level-1 D-Cache Penalty Cycle Count
|
|
||||||
.
|
|
||||||
Counter: 32 Name:PROBLEM_STATE_CPU_CYCLES
|
|
||||||
Description:
|
|
||||||
Problem-State Cycle Count
|
|
||||||
.
|
|
||||||
Counter: 33 Name:PROBLEM_STATE_INSTRUCTIONS
|
|
||||||
Description:
|
|
||||||
Problem-State Instruction Count
|
|
||||||
.
|
|
||||||
Counter: 34 Name:PROBLEM_STATE_L1I_DIR_WRITES
|
|
||||||
Description:
|
|
||||||
Problem-State Level-1 I-Cache Directory Write Count
|
|
||||||
.
|
|
||||||
Counter: 35 Name:PROBLEM_STATE_L1I_PENALTY_CYCLES
|
|
||||||
Description:
|
|
||||||
Problem-State Level-1 I-Cache Penalty Cycle Count
|
|
||||||
.
|
|
||||||
Counter: 36 Name:PROBLEM_STATE_L1D_DIR_WRITES
|
|
||||||
Description:
|
|
||||||
Problem-State Level-1 D-Cache Directory Write Count
|
|
||||||
.
|
|
||||||
Counter: 37 Name:PROBLEM_STATE_L1D_PENALTY_CYCLES
|
|
||||||
Description:
|
|
||||||
Problem-State Level-1 D-Cache Penalty Cycle Count
|
|
||||||
.
|
|
||||||
Counter: 64 Name:PRNG_FUNCTIONS
|
Counter: 64 Name:PRNG_FUNCTIONS
|
||||||
|
Short-Description:PRNG Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of the PRNG functions issued by the CPU
|
Total number of the PRNG functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 65 Name:PRNG_CYCLES
|
Counter: 65 Name:PRNG_CYCLES
|
||||||
|
Short-Description:PRNG Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
||||||
performing PRNG functions issued by the CPU
|
performing PRNG functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 66 Name:PRNG_BLOCKED_FUNCTIONS
|
Counter: 66 Name:PRNG_BLOCKED_FUNCTIONS
|
||||||
|
Short-Description:PRNG Blocked Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of the PRNG functions that are issued by the CPU and are
|
Total number of the PRNG functions that are issued by the CPU and are
|
||||||
blocked because the DEA/AES coprocessor is busy performing a function
|
blocked because the DEA/AES coprocessor is busy performing a function
|
||||||
issued by another CPU
|
issued by another CPU
|
||||||
.
|
.
|
||||||
Counter: 67 Name:PRNG_BLOCKED_CYCLES
|
Counter: 67 Name:PRNG_BLOCKED_CYCLES
|
||||||
|
Short-Description:PRNG Blocked Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles blocked for the PRNG functions issued by
|
Total number of CPU cycles blocked for the PRNG functions issued by
|
||||||
the CPU because the DEA/AES coprocessor is busy performing a function
|
the CPU because the DEA/AES coprocessor is busy performing a function
|
||||||
issued by another CPU
|
issued by another CPU
|
||||||
.
|
.
|
||||||
Counter: 68 Name:SHA_FUNCTIONS
|
Counter: 68 Name:SHA_FUNCTIONS
|
||||||
|
Short-Description:SHA Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of SHA functions issued by the CPU
|
Total number of SHA functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 69 Name:SHA_CYCLES
|
Counter: 69 Name:SHA_CYCLES
|
||||||
|
Short-Description:SHA Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles when the SHA coprocessor is busy performing
|
Total number of CPU cycles when the SHA coprocessor is busy performing
|
||||||
the SHA functions issued by the CPU
|
the SHA functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 70 Name:SHA_BLOCKED_FUNCTIONS
|
Counter: 70 Name:SHA_BLOCKED_FUNCTIONS
|
||||||
|
Short-Description:SHA Blocked Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of the SHA functions that are issued by the CPU and are
|
Total number of the SHA functions that are issued by the CPU and are
|
||||||
blocked because the SHA coprocessor is busy performing a function issued
|
blocked because the SHA coprocessor is busy performing a function issued
|
||||||
by another CPU
|
by another CPU
|
||||||
.
|
.
|
||||||
Counter: 71 Name:SHA_BLOCKED_CYCLES
|
Counter: 71 Name:SHA_BLOCKED_CYCLES
|
||||||
|
Short-Description:SHA Bloced Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles blocked for the SHA functions issued by the
|
Total number of CPU cycles blocked for the SHA functions issued by the
|
||||||
CPU because the SHA coprocessor is busy performing a function issued
|
CPU because the SHA coprocessor is busy performing a function issued
|
||||||
by another CPU
|
by another CPU
|
||||||
.
|
.
|
||||||
Counter: 72 Name:DEA_FUNCTIONS
|
Counter: 72 Name:DEA_FUNCTIONS
|
||||||
|
Short-Description:DEA Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of the DEA functions issued by the CPU
|
Total number of the DEA functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 73 Name:DEA_CYCLES
|
Counter: 73 Name:DEA_CYCLES
|
||||||
|
Short-Description:DEA Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
||||||
performing the DEA functions issued by the CPU
|
performing the DEA functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 74 Name:DEA_BLOCKED_FUNCTIONS
|
Counter: 74 Name:DEA_BLOCKED_FUNCTIONS
|
||||||
|
Short-Description:DEA Blocked Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of the DEA functions that are issued by the CPU and are
|
Total number of the DEA functions that are issued by the CPU and are
|
||||||
blocked because the DEA/AES coprocessor is busy performing a function
|
blocked because the DEA/AES coprocessor is busy performing a function
|
||||||
issued by another CPU
|
issued by another CPU
|
||||||
.
|
.
|
||||||
Counter: 75 Name:DEA_BLOCKED_CYCLES
|
Counter: 75 Name:DEA_BLOCKED_CYCLES
|
||||||
|
Short-Description:DEA Blocked Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles blocked for the DEA functions issued by the
|
Total number of CPU cycles blocked for the DEA functions issued by the
|
||||||
CPU because the DEA/AES coprocessor is busy performing a function issued
|
CPU because the DEA/AES coprocessor is busy performing a function issued
|
||||||
by another CPU
|
by another CPU
|
||||||
.
|
.
|
||||||
Counter: 76 Name:AES_FUNCTIONS
|
Counter: 76 Name:AES_FUNCTIONS
|
||||||
|
Short-Description:AES Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of AES functions issued by the CPU
|
Total number of AES functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 77 Name:AES_CYCLES
|
Counter: 77 Name:AES_CYCLES
|
||||||
|
Short-Description:AES Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
Total number of CPU cycles when the DEA/AES coprocessor is busy
|
||||||
performing the AES functions issued by the CPU
|
performing the AES functions issued by the CPU
|
||||||
.
|
.
|
||||||
Counter: 78 Name:AES_BLOCKED_FUNCTIONS
|
Counter: 78 Name:AES_BLOCKED_FUNCTIONS
|
||||||
|
Short-Description:AES Blocked Functions
|
||||||
Description:
|
Description:
|
||||||
Total number of AES functions that are issued by the CPU and are blocked
|
Total number of AES functions that are issued by the CPU and are blocked
|
||||||
because the DEA/AES coprocessor is busy performing a function issued
|
because the DEA/AES coprocessor is busy performing a function issued
|
||||||
by another CPU
|
by another CPU
|
||||||
.
|
.
|
||||||
Counter: 79 Name:AES_BLOCKED_CYCLES
|
Counter: 79 Name:AES_BLOCKED_CYCLES
|
||||||
|
Short-Description:AES Blocked Cycles
|
||||||
Description:
|
Description:
|
||||||
Total number of CPU cycles blocked for the AES functions issued by the
|
Total number of CPU cycles blocked for the AES functions issued by the
|
||||||
CPU because the DEA/AES coprocessor is busy performing a function issued
|
CPU because the DEA/AES coprocessor is busy performing a function issued
|
||||||
33
cpumf/data/cpum-cf-csvn-6.ctr
Normal file
33
cpumf/data/cpum-cf-csvn-6.ctr
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
Counter: 80 Name:ECC_FUNCTION_COUNT
|
||||||
|
Short-Description:ECC Function Count
|
||||||
|
Description:
|
||||||
|
This counter counts the
|
||||||
|
total number of the elliptic-curve cryptography (ECC)
|
||||||
|
functions issued by the CPU.
|
||||||
|
.
|
||||||
|
Counter: 81 Name:ECC_CYCLES_COUNT
|
||||||
|
Short-Description:ECC Cycles Count
|
||||||
|
Description:
|
||||||
|
This counter counts the total
|
||||||
|
number of CPU cycles when the ECC coprocessor is
|
||||||
|
busy performing the elliptic-curve cryptography
|
||||||
|
(ECC) functions issued by the CPU.
|
||||||
|
.
|
||||||
|
Counter: 82 Name:ECC_BLOCKED_FUNCTION_COUNT
|
||||||
|
Short-Description:Ecc Blocked Function Count
|
||||||
|
Description:
|
||||||
|
This counter
|
||||||
|
counts the total number of the elliptic-curve
|
||||||
|
cryptography (ECC) functions that are issued by the CPU
|
||||||
|
and are blocked because the ECC coprocessor is
|
||||||
|
busy performing a function issued by another CPU.
|
||||||
|
.
|
||||||
|
Counter: 83 Name:ECC_BLOCKED_CYCLES_COUNT
|
||||||
|
Short-Description:ECC Blocked Cycles Count
|
||||||
|
Description:
|
||||||
|
This counter counts
|
||||||
|
the total number of CPU cycles blocked for the elliptic-curve
|
||||||
|
cryptography (ECC) functions issued by the
|
||||||
|
CPU because the ECC coprocessor is busy perform-
|
||||||
|
ing a function issued by another CPU.
|
||||||
|
.
|
||||||
@@ -1,96 +1,114 @@
|
|||||||
Counter: 128 Name:L1I_L2_SOURCED_WRITES
|
Counter: 128 Name:L1I_L2_SOURCED_WRITES
|
||||||
|
Short-Description:L1I L2 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from the Level-2 (L1.5) cache
|
cache line was sourced from the Level-2 (L1.5) cache
|
||||||
.
|
.
|
||||||
Counter: 129 Name:L1D_L2_SOURCED_WRITES
|
Counter: 129 Name:L1D_L2_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the installed
|
A directory write to the Level-1 D-Cache directory where the installed
|
||||||
cache line was sourced from the Level-2 (L1.5) cache
|
cache line was sourced from the Level-2 (L1.5) cache
|
||||||
.
|
.
|
||||||
Counter: 130 Name:L1I_L3_LOCAL_WRITES
|
Counter: 130 Name:L1I_L3_LOCAL_WRITES
|
||||||
|
Short-Description:L1I L3 Local Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the installed
|
A directory write to the Level-1 I-Cache directory where the installed
|
||||||
cache line was sourced from the Level-3 cache that is on the same book
|
cache line was sourced from the Level-3 cache that is on the same book
|
||||||
as the Instruction cache (Local L2 cache)
|
as the Instruction cache (Local L2 cache)
|
||||||
.
|
.
|
||||||
Counter: 131 Name:L1D_L3_LOCAL_WRITES
|
Counter: 131 Name:L1D_L3_LOCAL_WRITES
|
||||||
|
Short-Description:L1D L3 Local Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the installtion
|
A directory write to the Level-1 D-Cache directory where the installtion
|
||||||
cache line was source from the Level-3 cache that is on the same book
|
cache line was source from the Level-3 cache that is on the same book
|
||||||
as the Data cache (Local L2 cache)
|
as the Data cache (Local L2 cache)
|
||||||
.
|
.
|
||||||
Counter: 132 Name:L1I_L3_REMOTE_WRITES
|
Counter: 132 Name:L1I_L3_REMOTE_WRITES
|
||||||
|
Short-Description:L1I L3 Remote Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the installed
|
A directory write to the Level-1 I-Cache directory where the installed
|
||||||
cache line was sourced from a Level-3 cache that is not on the same
|
cache line was sourced from a Level-3 cache that is not on the same
|
||||||
book as the Instruction cache (Remote L2 cache)
|
book as the Instruction cache (Remote L2 cache)
|
||||||
.
|
.
|
||||||
Counter: 133 Name:L1D_L3_REMOTE_WRITES
|
Counter: 133 Name:L1D_L3_REMOTE_WRITES
|
||||||
|
Short-Description:L1D L3 Remote Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the installed
|
A directory write to the Level-1 D-Cache directory where the installed
|
||||||
cache line was sourced from a Level-3 cache that is not on the same
|
cache line was sourced from a Level-3 cache that is not on the same
|
||||||
book as the Data cache (Remote L2 cache)
|
book as the Data cache (Remote L2 cache)
|
||||||
.
|
.
|
||||||
Counter: 134 Name:L1D_LMEM_SOURCED_WRITES
|
Counter: 134 Name:L1D_LMEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Local Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the installed
|
A directory write to the Level-1 D-Cache directory where the installed
|
||||||
cache line was sourced from memory that is attached to the same book
|
cache line was sourced from memory that is attached to the same book
|
||||||
as the Data cache (Local Memory)
|
as the Data cache (Local Memory)
|
||||||
.
|
.
|
||||||
Counter: 135 Name:L1I_LMEM_SOURCED_WRITES
|
Counter: 135 Name:L1I_LMEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Local Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache where the installed cache
|
A directory write to the Level-1 I-Cache where the installed cache
|
||||||
line was sourced from memory that is attached to the s ame book as the
|
line was sourced from memory that is attached to the s ame book as the
|
||||||
Instruction cahe (local Memory)
|
Instruction cache (Local Memory)
|
||||||
.
|
.
|
||||||
Counter: 136 Name:L1D_RO_EXCL_WRITES
|
Counter: 136 Name:L1D_RO_EXCL_WRITES
|
||||||
|
Short-Description:L1D Read-only Exclusive Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache where the line was originally
|
A directory write to the Level-1 D-Cache where the line was originally
|
||||||
in a Read-Only state in the cache but has been updated to be in the
|
in a Read-Only state in the cache but has been updated to be in the
|
||||||
Exclusive state that allows stores to the cache line
|
Exclusive state that allows stores to the cache line
|
||||||
.
|
.
|
||||||
Counter: 137 Name:L1I_CACHELINE_INVALIDATES
|
Counter: 137 Name:L1I_CACHELINE_INVALIDATES
|
||||||
|
Short-Description:L1I Cacheline Invalidates
|
||||||
Description:
|
Description:
|
||||||
A cache line in the Level-1 I-Cache has been invalidated by a store on
|
A cache line in the Level-1 I-Cache has been invalidated by a store on
|
||||||
the same CPU as the Level-1 I-Cache
|
the same CPU as the Level-1 I-Cache
|
||||||
.
|
.
|
||||||
Counter: 138 Name:ITLB1_WRITES
|
Counter: 138 Name:ITLB1_WRITES
|
||||||
|
Short-Description:ITLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written into the Level-1 Instruction
|
A translation entry has been written into the Level-1 Instruction
|
||||||
Translation Lookaside Buffer
|
Translation Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter: 139 Name:DTLB1_WRITES
|
Counter: 139 Name:DTLB1_WRITES
|
||||||
|
Short-Description:DTLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer
|
Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter: 140 Name:TLB2_PTE_WRITES
|
Counter: 140 Name:TLB2_PTE_WRITES
|
||||||
|
Short-Description:TLB2 PTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Page Table
|
A translation entry has been written to the Level-2 TLB Page Table
|
||||||
Entry arrays
|
Entry arrays
|
||||||
.
|
.
|
||||||
Counter: 141 Name:TLB2_CRSTE_WRITES
|
Counter: 141 Name:TLB2_CRSTE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Common Region
|
A translation entry has been written to the Level-2 TLB Common Region
|
||||||
Segment Table Entry arrays
|
Segment Table Entry arrays
|
||||||
.
|
.
|
||||||
Counter: 142 Name:TLB2_CRSTE_HPAGE_WRITES
|
Counter: 142 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Common Region
|
A translation entry has been written to the Level-2 TLB Common Region
|
||||||
Segment Table Entry arrays for a one-megabyte large page translation
|
Segment Table Entry arrays for a one-megabyte large page translation
|
||||||
.
|
.
|
||||||
Counter: 145 Name:ITLB1_MISSES
|
Counter: 145 Name:ITLB1_MISSES
|
||||||
|
Short-Description:ITLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||||
cycle an ITLB1 miss is in progress
|
cycle an ITLB1 miss is in progress
|
||||||
.
|
.
|
||||||
Counter: 146 Name:DTLB1_MISSES
|
Counter: 146 Name:DTLB1_MISSES
|
||||||
|
Short-Description:DTLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||||
an DTLB1 miss is in progress
|
an DTLB1 miss is in progress
|
||||||
.
|
.
|
||||||
Counter: 147 Name:L2C_STORES_SENT
|
Counter: 147 Name:L2C_STORES_SENT
|
||||||
|
Short-Description:L2C Stores Sent
|
||||||
Description:
|
Description:
|
||||||
Incremented by one for every store sent to Level-2 (L1.5) cache
|
Incremented by one for every store sent to Level-2 (L1.5) cache
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -16,288 +16,343 @@
|
|||||||
#
|
#
|
||||||
# Extended Counter Set
|
# Extended Counter Set
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
Counter:128 Name:L1D_WRITES_RO_EXCL
|
Counter:128 Name:L1D_RO_EXCL_WRITES
|
||||||
|
Short-Description:L1D Read-only Exclusive Writes
|
||||||
|
Description:
|
||||||
A directory write to the Level-1 Data cache where the line was
|
A directory write to the Level-1 Data cache where the line was
|
||||||
originally in a Read-Only state in the cache but has been updated
|
originally in a Read-Only state in the cache but has been updated
|
||||||
to be in the Exclusive state that allows stores to the cache line.
|
to be in the Exclusive state that allows stores to the cache line.
|
||||||
.
|
.
|
||||||
Counter:129 Name:DTLB1_WRITES
|
Counter:129 Name:DTLB1_WRITES
|
||||||
|
Short-Description:DTLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer
|
Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter:130 Name:DTLB1_MISSES
|
Counter:130 Name:DTLB1_MISSES
|
||||||
|
Short-Description:DTLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||||
a DTLB1 miss is in progress.
|
a DTLB1 miss is in progress.
|
||||||
.
|
.
|
||||||
Counter:131 Name:DTLB1_HPAGE_WRITES
|
Counter:131 Name:DTLB1_HPAGE_WRITES
|
||||||
|
Short-Description:DTLB1 One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer for a one-megabyte page
|
Lookaside Buffer for a one-megabyte page
|
||||||
.
|
.
|
||||||
Counter:132 Name:DTLB1_GPAGE_WRITES
|
Counter:132 Name:DTLB1_GPAGE_WRITES
|
||||||
|
Short-Description:DTLB1 Two-Gigabyte Page Writes
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer for a two-gigabyte page.
|
Lookaside Buffer for a two-gigabyte page.
|
||||||
.
|
.
|
||||||
Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2D Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from the Level-2 Data cache
|
cache line was sourced from the Level-2 Data cache
|
||||||
.
|
.
|
||||||
Counter:134 Name:ITLB1_WRITES
|
Counter:134 Name:ITLB1_WRITES
|
||||||
|
Short-Description:ITLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Instruction
|
A translation entry has been written to the Level-1 Instruction
|
||||||
Translation Lookaside Buffer
|
Translation Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter:135 Name:ITLB1_MISSES
|
Counter:135 Name:ITLB1_MISSES
|
||||||
|
Short-Description:ITLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||||
cycle an ITLB1 miss is in progress
|
cycle an ITLB1 miss is in progress
|
||||||
.
|
.
|
||||||
Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
||||||
|
Short-Description:L1I L2I Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from the Level-2 Instruction cache
|
returned cache line was sourced from the Level-2 Instruction cache
|
||||||
.
|
.
|
||||||
Counter:137 Name:TLB2_PTE_WRITES
|
Counter:137 Name:TLB2_PTE_WRITES
|
||||||
|
Short-Description:TLB2 PTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Page Table
|
A translation entry has been written to the Level-2 TLB Page Table
|
||||||
Entry arrays
|
Entry arrays
|
||||||
.
|
.
|
||||||
Counter:138 Name:TLB2_CRSTE_HPAGE_WRITES
|
Counter:138 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Combined Region
|
A translation entry has been written to the Level-2 TLB Combined Region
|
||||||
Segment Table Entry arrays for a one-megabyte large page translation
|
Segment Table Entry arrays for a one-megabyte large page translation
|
||||||
.
|
.
|
||||||
Counter:139 Name:TLB2_CRSTE_WRITES
|
Counter:139 Name:TLB2_CRSTE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Combined Region
|
A translation entry has been written to the Level-2 TLB Combined Region
|
||||||
Segment Table Entry arrays
|
Segment Table Entry arrays
|
||||||
.
|
.
|
||||||
Counter:140 Name:TX_C_TEND
|
Counter:140 Name:TX_C_TEND
|
||||||
|
Short-Description:Completed TEND instructions in constrained TX mode
|
||||||
Description:
|
Description:
|
||||||
A TEND instruction has completed in a constrained transactional-execution
|
A TEND instruction has completed in a constrained transactional-execution
|
||||||
mode
|
mode
|
||||||
.
|
.
|
||||||
Counter:141 Name:TX_NC_TEND
|
Counter:141 Name:TX_NC_TEND
|
||||||
|
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||||
Description:
|
Description:
|
||||||
A TEND instruction has completed in a non-constrained
|
A TEND instruction has completed in a non-constrained
|
||||||
transactional-execution mode
|
transactional-execution mode
|
||||||
.
|
.
|
||||||
Counter:143 Name:L1C_TLB1_MISSES
|
Counter:143 Name:L1C_TLB1_MISSES
|
||||||
|
Short-Description:L1C TLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Increments by one for any cycle where a Level-1 cache or Level-1 TLB miss
|
Increments by one for any cycle where a Level-1 cache or Level-1 TLB miss
|
||||||
is in progress.
|
is in progress.
|
||||||
.
|
.
|
||||||
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Chip Level-3 cache without intervention
|
cache line was sourced from an On-Chip Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:145 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
Counter:145 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Chip Level-3 cache with intervention
|
cache line was sourced from an On-Chip Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:146 Name:L1D_ONNODE_L4_SOURCED_WRITES
|
Counter:146 Name:L1D_ONNODE_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Node L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Node Level-4 cache
|
cache line was sourced from an On-Node Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:147 Name:L1D_ONNODE_L3_SOURCED_WRITES_IV
|
Counter:147 Name:L1D_ONNODE_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Node L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Node Level-3 cache with intervention
|
cache line was sourced from an On-Node Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:148 Name:L1D_ONNODE_L3_SOURCED_WRITES
|
Counter:148 Name:L1D_ONNODE_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Node L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Node Level-3 cache without intervention
|
cache line was sourced from an On-Node Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:149 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
Counter:149 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Drawer L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Drawer Level-4 cache
|
cache line was sourced from an On-Drawer Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:150 Name:L1D_ONDRAWER_L3_SOURCED_WRITES_IV
|
Counter:150 Name:L1D_ONDRAWER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Drawer L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Drawer Level-3 cache with intervention
|
cache line was sourced from an On-Drawer Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:151 Name:L1D_ONDRAWER_L3_SOURCED_WRITES
|
Counter:151 Name:L1D_ONDRAWER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Drawer L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On-Drawer Level-3 cache without intervention
|
cache line was sourced from an On-Drawer Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:152 Name:L1D_OFFDRAWER_SCOL_L4_SOURCED_WRITES
|
Counter:152 Name:L1D_OFFDRAWER_SCOL_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Same-Column L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off-Drawer Same-Column Level-4 cache
|
cache line was sourced from an Off-Drawer Same-Column Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:153 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
|
Counter:153 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Drawer Same-Column L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off-Drawer Same-Column Level-3 cache with
|
cache line was sourced from an Off-Drawer Same-Column Level-3 cache with
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:154 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES
|
Counter:154 Name:L1D_OFFDRAWER_SCOL_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Same-Column L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off-Drawer Same-Column Level-3 cache
|
cache line was sourced from an Off-Drawer Same-Column Level-3 cache
|
||||||
without intervention
|
without intervention
|
||||||
.
|
.
|
||||||
Counter:155 Name:L1D_OFFDRAWER_FCOL_L4_SOURCED_WRITES
|
Counter:155 Name:L1D_OFFDRAWER_FCOL_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off-Drawer Far-Column Level-4 cache
|
cache line was sourced from an Off-Drawer Far-Column Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:156 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
|
Counter:156 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off-Drawer Far-Column Level-3 cache with
|
cache line was sourced from an Off-Drawer Far-Column Level-3 cache with
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:157 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES
|
Counter:157 Name:L1D_OFFDRAWER_FCOL_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Far-Column L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off-Drawer Far-Column Level-3 cache
|
cache line was sourced from an Off-Drawer Far-Column Level-3 cache
|
||||||
without intervention
|
without intervention
|
||||||
.
|
.
|
||||||
Counter:158 Name:L1D_ONNODE_MEM_SOURCED_WRITES
|
Counter:158 Name:L1D_ONNODE_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Node Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from On-Node memory
|
cache line was sourced from On-Node memory
|
||||||
.
|
.
|
||||||
Counter:159 Name:L1D_ONDRAWER_MEM_SOURCED_WRITES
|
Counter:159 Name:L1D_ONDRAWER_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Drawer Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from On-Drawer memory
|
cache line was sourced from On-Drawer memory
|
||||||
.
|
.
|
||||||
Counter:160 Name:L1D_OFFDRAWER_MEM_SOURCED_WRITES
|
Counter:160 Name:L1D_OFFDRAWER_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from On-Drawer memory
|
cache line was sourced from On-Drawer memory
|
||||||
.
|
.
|
||||||
Counter:161 Name:L1D_ONCHIP_MEM_SOURCED_WRITES
|
Counter:161 Name:L1D_ONCHIP_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from On-Chip memory
|
cache line was sourced from On-Chip memory
|
||||||
.
|
.
|
||||||
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an On-Chip Level-3 cache without
|
returned cache line was sourced from an On-Chip Level-3 cache without
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:163 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
Counter:163 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an On Chip Level-3 cache with
|
returned cache line was sourced from an On Chip Level-3 cache with
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:164 Name:L1I_ONNODE_L4_SOURCED_WRITES
|
Counter:164 Name:L1I_ONNODE_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an On-Node Level-4 cache
|
returned cache line was sourced from an On-Node Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:165 Name:L1I_ONNODE_L3_SOURCED_WRITES_IV
|
Counter:165 Name:L1I_ONNODE_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Node L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an On-Node Level-3 cache
|
the returned cache line was sourced from an On-Node Level-3 cache
|
||||||
with intervention
|
with intervention
|
||||||
.
|
.
|
||||||
Counter:166 Name:L1I_ONNODE_L3_SOURCED_WRITES
|
Counter:166 Name:L1I_ONNODE_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Node L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an On-Node Level-3 cache
|
the returned cache line was sourced from an On-Node Level-3 cache
|
||||||
without intervention
|
without intervention
|
||||||
.
|
.
|
||||||
Counter:167 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
Counter:167 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Drawer L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an On-Drawer Level-4 cache
|
the returned cache line was sourced from an On-Drawer Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:168 Name:L1I_ONDRAWER_L3_SOURCED_WRITES_IV
|
Counter:168 Name:L1I_ONDRAWER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Drawer L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an On-Drawer Level-3 cache
|
the returned cache line was sourced from an On-Drawer Level-3 cache
|
||||||
with intervention
|
with intervention
|
||||||
.
|
.
|
||||||
Counter:169 Name:L1I_ONDRAWER_L3_SOURCED_WRITES
|
Counter:169 Name:L1I_ONDRAWER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Drawer L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an On-Drawer Level-3 cache
|
the returned cache line was sourced from an On-Drawer Level-3 cache
|
||||||
without intervention
|
without intervention
|
||||||
.
|
.
|
||||||
Counter:170 Name:L1I_OFFDRAWER_SCOL_L4_SOURCED_WRITES
|
Counter:170 Name:L1I_OFFDRAWER_SCOL_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Same-Column L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an Off-Drawer Same-Column
|
the returned cache line was sourced from an Off-Drawer Same-Column
|
||||||
Level-4 cache
|
Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:171 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
|
Counter:171 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Drawer Same-Column L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an Off-Drawer Same-Column
|
the returned cache line was sourced from an Off-Drawer Same-Column
|
||||||
Level-3 cache with intervention
|
Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:172 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES
|
Counter:172 Name:L1I_OFFDRAWER_SCOL_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Same-Column L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an Off-Drawer Same-Column
|
the returned cache line was sourced from an Off-Drawer Same-Column
|
||||||
Level-3 cache without intervention
|
Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:173 Name:L1I_OFFDRAWER_FCOL_L4_SOURCED_WRITES
|
Counter:173 Name:L1I_OFFDRAWER_FCOL_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Far-Column L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an Off-Drawer Far-Column
|
the returned cache line was sourced from an Off-Drawer Far-Column
|
||||||
Level-4 cache
|
Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:174 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
|
Counter:174 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Drawer Far-Column L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an Off-Drawer Far-Column
|
the returned cache line was sourced from an Off-Drawer Far-Column
|
||||||
Level-3 cache with intervention
|
Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:175 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES
|
Counter:175 Name:L1I_OFFDRAWER_FCOL_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Far-Column L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from an Off-Drawer Far-Column
|
the returned cache line was sourced from an Off-Drawer Far-Column
|
||||||
Level-3 cache without intervention
|
Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:176 Name:L1I_ONNODE_MEM_SOURCED_WRITES
|
Counter:176 Name:L1I_ONNODE_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Node Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from On-Node memory
|
the returned cache line was sourced from On-Node memory
|
||||||
.
|
.
|
||||||
Counter:177 Name:L1I_ONDRAWER_MEM_SOURCED_WRITES
|
Counter:177 Name:L1I_ONDRAWER_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Drawer Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from On-Drawer memory
|
the returned cache line was sourced from On-Drawer memory
|
||||||
.
|
.
|
||||||
Counter:178 Name:L1I_OFFDRAWER_MEM_SOURCED_WRITES
|
Counter:178 Name:L1I_OFFDRAWER_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from On-Drawer memory
|
the returned cache line was sourced from On-Drawer memory
|
||||||
.
|
.
|
||||||
Counter:179 Name:L1I_ONCHIP_MEM_SOURCED_WRITES
|
Counter:179 Name:L1I_ONCHIP_MEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where
|
A directory write to the Level-1 Instruction cache directory where
|
||||||
the returned cache line was sourced from On-Chip memory
|
the returned cache line was sourced from On-Chip memory
|
||||||
.
|
.
|
||||||
Counter:218 Name:TX_NC_TABORT
|
Counter:218 Name:TX_NC_TABORT
|
||||||
|
Short-Description:Aborted transactions in non-constrained TX mode
|
||||||
Description:
|
Description:
|
||||||
A transaction abort has occurred in a non-constrained
|
A transaction abort has occurred in a non-constrained
|
||||||
transactional-execution mode
|
transactional-execution mode
|
||||||
.
|
.
|
||||||
Counter:219 Name:TX_C_TABORT_NO_SPECIAL
|
Counter:219 Name:TX_C_TABORT_NO_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||||
Description:
|
Description:
|
||||||
A transaction abort has occurred in a constrained transactional-execution
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
mode and the CPU is not using any special logic to allow the transaction
|
mode and the CPU is not using any special logic to allow the transaction
|
||||||
to complete
|
to complete
|
||||||
.
|
.
|
||||||
Counter:220 Name:TX_C_TABORT_SPECIAL
|
Counter:220 Name:TX_C_TABORT_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||||
Description:
|
Description:
|
||||||
A transaction abort has occurred in a constrained transactional-execution
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
mode and the CPU is using special logic to allow the transaction to
|
mode and the CPU is using special logic to allow the transaction to
|
||||||
@@ -307,10 +362,12 @@ complete
|
|||||||
# MT-diagnostic counter set
|
# MT-diagnostic counter set
|
||||||
# ---------------------------------------------------------------------
|
# ---------------------------------------------------------------------
|
||||||
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
||||||
|
Short-Description:Cycle count with one thread active
|
||||||
Description:
|
Description:
|
||||||
Cycle count with one thread active
|
Cycle count with one thread active
|
||||||
.
|
.
|
||||||
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
||||||
|
Short-Description:Cycle count with two threads active
|
||||||
Description:
|
Description:
|
||||||
Cycle count with two threads active
|
Cycle count with two threads active
|
||||||
.
|
.
|
||||||
|
|||||||
357
cpumf/data/cpum-cf-extended-z14.ctr
Normal file
357
cpumf/data/cpum-cf-extended-z14.ctr
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
# Counter decriptions for the
|
||||||
|
# IBM z14 extended counter and MT-diagnostic counter set
|
||||||
|
#
|
||||||
|
# Notes for transactional-execution mode symbolic names:
|
||||||
|
# TX .. transactional-execution mode
|
||||||
|
# NC .. nonconstrained
|
||||||
|
# C .. constrained
|
||||||
|
#
|
||||||
|
# Undefined counters in the extended counter set:
|
||||||
|
# 142
|
||||||
|
# 158-161
|
||||||
|
# 176-223
|
||||||
|
# 227-231
|
||||||
|
# 233-242
|
||||||
|
# 246-255
|
||||||
|
# Undefined counters in the MT-diagnostic counter set:
|
||||||
|
# 450-495
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Extended Counter Set
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
Counter:128 Name:L1D_RO_EXCL_WRITES
|
||||||
|
Short-Description:L1D Read-only Exclusive Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache where the line was
|
||||||
|
originally in a Read-Only state in the cache but has been updated
|
||||||
|
to be in the Exclusive state that allows stores to the cache line
|
||||||
|
.
|
||||||
|
Counter:129 Name:DTLB2_WRITES
|
||||||
|
Short-Description:DTLB2 Writes
|
||||||
|
Description:
|
||||||
|
A translation has been written into The Translation Lookaside
|
||||||
|
Buffer 2 (TLB2) and the request was made by the data cache
|
||||||
|
.
|
||||||
|
Counter:130 Name:DTLB2_MISSES
|
||||||
|
Short-Description:DTLB2 Misses
|
||||||
|
Description:
|
||||||
|
A TLB2 miss is in progress for a request made by the data cache.
|
||||||
|
Incremented by one for every TLB2 miss in progress for the Level-1
|
||||||
|
Data cache on this cycle
|
||||||
|
.
|
||||||
|
Counter:131 Name:DTLB2_HPAGE_WRITES
|
||||||
|
Short-Description:DTLB2 One-Megabyte Page Writes
|
||||||
|
Description:
|
||||||
|
A translation entry was written into the Combined Region and Segment
|
||||||
|
Table Entry array in the Level-2 TLB for a one-megabyte page or a
|
||||||
|
Last Host Translation was done
|
||||||
|
.
|
||||||
|
Counter:132 Name:DTLB2_GPAGE_WRITES
|
||||||
|
Short-Description:DTLB2 Two-Gigabyte Page Writes
|
||||||
|
Description:
|
||||||
|
A translation entry for a two-gigabyte page was written into the
|
||||||
|
Level-2 TLB
|
||||||
|
.
|
||||||
|
Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2D Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the
|
||||||
|
returned cache line was sourced from the Level-2 Data cache
|
||||||
|
.
|
||||||
|
Counter:134 Name:ITLB2_WRITES
|
||||||
|
Short-Description:ITLB2 Writes
|
||||||
|
Description:
|
||||||
|
A translation entry has been written into the Translation Lookaside
|
||||||
|
Buffer 2 (TLB2) and the request was made by the instruction cache
|
||||||
|
.
|
||||||
|
Counter:135 Name:ITLB2_MISSES
|
||||||
|
Short-Description:ITLB2 Misses
|
||||||
|
Description:
|
||||||
|
A TLB2 miss is in progress for a request made by the instruction cache.
|
||||||
|
Incremented by one for every TLB2 miss in progress for the Level-1
|
||||||
|
Instruction cache in a cycle
|
||||||
|
.
|
||||||
|
Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
||||||
|
Short-Description:L1I L2I Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from the Level-2 Instruction cache
|
||||||
|
.
|
||||||
|
Counter:137 Name:TLB2_PTE_WRITES
|
||||||
|
Short-Description:TLB2 PTE Writes
|
||||||
|
Description:
|
||||||
|
A translation entry was written into the Page Table Entry array in the
|
||||||
|
Level-2 TLB
|
||||||
|
.
|
||||||
|
Counter:138 Name:TLB2_CRSTE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE Writes
|
||||||
|
Description:
|
||||||
|
Translation entries were written into the Combined Region and Segment
|
||||||
|
Table Entry array and the Page Table Entry array in the Level-2 TLB
|
||||||
|
.
|
||||||
|
Counter:139 Name:TLB2_ENGINES_BUSY
|
||||||
|
Short-Description:TLB2 Engines Busy
|
||||||
|
Description:
|
||||||
|
The number of Level-2 TLB translation engines busy in a cycle
|
||||||
|
.
|
||||||
|
Counter:140 Name:TX_C_TEND
|
||||||
|
Short-Description:Completed TEND instructions in constrained TX mode
|
||||||
|
Description:
|
||||||
|
A TEND instruction has completed in a constrained transactional-execution
|
||||||
|
mode
|
||||||
|
.
|
||||||
|
Counter:141 Name:TX_NC_TEND
|
||||||
|
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||||
|
Description:
|
||||||
|
A TEND instruction has completed in a non-constrained
|
||||||
|
transactional-execution mode
|
||||||
|
.
|
||||||
|
Counter:143 Name:L1C_TLB2_MISSES
|
||||||
|
Short-Description:L1C TLB2 Misses
|
||||||
|
Description:
|
||||||
|
Increments by one for any cycle where a level-1 cache or level-2 TLB miss
|
||||||
|
is in progress
|
||||||
|
.
|
||||||
|
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Chip Level-3 cache without intervention
|
||||||
|
.
|
||||||
|
Counter:145 Name:L1D_ONCHIP_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Chip memory
|
||||||
|
.
|
||||||
|
Counter:146 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Chip Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:147 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Cluster Level-3 cache withountervention
|
||||||
|
.
|
||||||
|
Counter:148 Name:L1D_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:149 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Cluster Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:150 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Cluster Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:151 Name:L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from Off-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:152 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Cluster Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:153 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Drawer Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:154 Name:L1D_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from Off-Drawer memory
|
||||||
|
.
|
||||||
|
Counter:155 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Drawer L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Drawer Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:156 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:157 Name:L1D_OFFDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from Off-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:158 Name:L1D_ONCHIP_L3_SOURCED_WRITES_RO
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes read-only
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Chip L3 but a read-only invalidate was
|
||||||
|
done to remove other copies of the cache line
|
||||||
|
.
|
||||||
|
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache ine was sourced from an On-Chip Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:163 Name:L1I_ONCHIP_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache ine was sourced from On-Chip memory
|
||||||
|
.
|
||||||
|
Counter:164 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache ine was sourced from an On-Chip Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:165 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an On-Cluster Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:166 Name:L1I_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an On-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:167 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from On-Cluster Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:168 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Cluster Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:169 Name:L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from Off-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:170 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Cluster Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:171 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Drawer Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:172 Name:L1I_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from Off-Drawer memory
|
||||||
|
.
|
||||||
|
Counter:173 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Drawer L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Drawer Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:174 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from On-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:175 Name:L1I_OFFDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from Off-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:224 Name:BCD_DFP_EXECUTION_SLOTS
|
||||||
|
Short-Description:BCD DFP Execution Slots
|
||||||
|
Description:
|
||||||
|
Count of floating point execution slots used for finished Binary Coded
|
||||||
|
Decimal to Decimal Floating Point conversions. Instructions: CDZT,
|
||||||
|
CXZT, CZDT, CZXT
|
||||||
|
.
|
||||||
|
Counter:225 Name:VX_BCD_EXECUTION_SLOTS
|
||||||
|
Short-Description:VX BCD Execution Slots
|
||||||
|
Description:
|
||||||
|
Count of floating point execution slots used for finished vector arithmetic
|
||||||
|
Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP,
|
||||||
|
VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG
|
||||||
|
.
|
||||||
|
Counter:226 Name:DECIMAL_INSTRUCTIONS
|
||||||
|
Short-Description:Decimal Instructions
|
||||||
|
Description:
|
||||||
|
Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED,
|
||||||
|
EDMK, MP, SRP, SP, ZAP
|
||||||
|
.
|
||||||
|
Counter:232 Name:LAST_HOST_TRANSLATIONS
|
||||||
|
Short-Description:Last host translation done
|
||||||
|
Description:
|
||||||
|
Last Host Translation done
|
||||||
|
.
|
||||||
|
Counter:243 Name:TX_NC_TABORT
|
||||||
|
Short-Description:Aborted transactions in non-constrained TX mode
|
||||||
|
Description:
|
||||||
|
A transaction abort has occurred in a non-constrained
|
||||||
|
transactional-execution mode
|
||||||
|
.
|
||||||
|
Counter:244 Name:TX_C_TABORT_NO_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||||
|
Description:
|
||||||
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
|
mode and the CPU is not using any special logic to allow the transaction
|
||||||
|
to complete
|
||||||
|
.
|
||||||
|
Counter:245 Name:TX_C_TABORT_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||||
|
Description:
|
||||||
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
|
mode and the CPU is using special logic to allow the transaction to
|
||||||
|
complete
|
||||||
|
.
|
||||||
|
#
|
||||||
|
# MT-diagnostic counter set
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
||||||
|
Short-Description:Cycle count with one thread active
|
||||||
|
Description:
|
||||||
|
Cycle count with one thread active
|
||||||
|
.
|
||||||
|
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
||||||
|
Short-Description:Cycle count with two threads active
|
||||||
|
Description:
|
||||||
|
Cycle count with two threads active
|
||||||
|
.
|
||||||
376
cpumf/data/cpum-cf-extended-z15.ctr
Normal file
376
cpumf/data/cpum-cf-extended-z15.ctr
Normal file
@@ -0,0 +1,376 @@
|
|||||||
|
# Counter decriptions for the
|
||||||
|
# IBM z14 extended counter and MT-diagnostic counter set
|
||||||
|
#
|
||||||
|
# Notes for transactional-execution mode symbolic names:
|
||||||
|
# TX .. transactional-execution mode
|
||||||
|
# NC .. nonconstrained
|
||||||
|
# C .. constrained
|
||||||
|
#
|
||||||
|
# Undefined counters in the extended counter set:
|
||||||
|
# 142
|
||||||
|
# 158-161
|
||||||
|
# 176-223
|
||||||
|
# 227-231
|
||||||
|
# 233-242
|
||||||
|
# 246-255
|
||||||
|
# Undefined counters in the MT-diagnostic counter set:
|
||||||
|
# 450-495
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Extended Counter Set
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
Counter:128 Name:L1D_RO_EXCL_WRITES
|
||||||
|
Short-Description:L1D Read-only Exclusive Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache where the line was
|
||||||
|
originally in a Read-Only state in the cache but has been updated
|
||||||
|
to be in the Exclusive state that allows stores to the cache line
|
||||||
|
.
|
||||||
|
Counter:129 Name:DTLB2_WRITES
|
||||||
|
Short-Description:DTLB2 Writes
|
||||||
|
Description:
|
||||||
|
A translation has been written into The Translation Lookaside
|
||||||
|
Buffer 2 (TLB2) and the request was made by the data cache
|
||||||
|
.
|
||||||
|
Counter:130 Name:DTLB2_MISSES
|
||||||
|
Short-Description:DTLB2 Misses
|
||||||
|
Description:
|
||||||
|
A TLB2 miss is in progress for a request made by the data cache.
|
||||||
|
Incremented by one for every TLB2 miss in progress for the Level-1
|
||||||
|
Data cache on this cycle
|
||||||
|
.
|
||||||
|
Counter:131 Name:DTLB2_HPAGE_WRITES
|
||||||
|
Short-Description:DTLB2 One-Megabyte Page Writes
|
||||||
|
Description:
|
||||||
|
A translation entry was written into the Combined Region and Segment
|
||||||
|
Table Entry array in the Level-2 TLB for a one-megabyte page
|
||||||
|
.
|
||||||
|
Counter:132 Name:DTLB2_GPAGE_WRITES
|
||||||
|
Short-Description:DTLB2 Two-Gigabyte Page Writes
|
||||||
|
Description:
|
||||||
|
A translation entry for a two-gigabyte page was written into the
|
||||||
|
Level-2 TLB
|
||||||
|
.
|
||||||
|
Counter:133 Name:L1D_L2D_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2D Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the
|
||||||
|
returned cache line was sourced from the Level-2 Data cache
|
||||||
|
.
|
||||||
|
Counter:134 Name:ITLB2_WRITES
|
||||||
|
Short-Description:ITLB2 Writes
|
||||||
|
Description:
|
||||||
|
A translation entry has been written into the Translation Lookaside
|
||||||
|
Buffer 2 (TLB2) and the request was made by the instruction cache
|
||||||
|
.
|
||||||
|
Counter:135 Name:ITLB2_MISSES
|
||||||
|
Short-Description:ITLB2 Misses
|
||||||
|
Description:
|
||||||
|
A TLB2 miss is in progress for a request made by the instruction cache.
|
||||||
|
Incremented by one for every TLB2 miss in progress for the Level-1
|
||||||
|
Instruction cache in a cycle
|
||||||
|
.
|
||||||
|
Counter:136 Name:L1I_L2I_SOURCED_WRITES
|
||||||
|
Short-Description:L1I L2I Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from the Level-2 Instruction cache
|
||||||
|
.
|
||||||
|
Counter:137 Name:TLB2_PTE_WRITES
|
||||||
|
Short-Description:TLB2 PTE Writes
|
||||||
|
Description:
|
||||||
|
A translation entry was written into the Page Table Entry array in the
|
||||||
|
Level-2 TLB
|
||||||
|
.
|
||||||
|
Counter:138 Name:TLB2_CRSTE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE Writes
|
||||||
|
Description:
|
||||||
|
Translation entries were written into the Combined Region and Segment
|
||||||
|
Table Entry array and the Page Table Entry array in the Level-2 TLB
|
||||||
|
.
|
||||||
|
Counter:139 Name:TLB2_ENGINES_BUSY
|
||||||
|
Short-Description:TLB2 Engines Busy
|
||||||
|
Description:
|
||||||
|
The number of Level-2 TLB translation engines busy in a cycle
|
||||||
|
.
|
||||||
|
Counter:140 Name:TX_C_TEND
|
||||||
|
Short-Description:Completed TEND instructions in constrained TX mode
|
||||||
|
Description:
|
||||||
|
A TEND instruction has completed in a constrained transactional-execution
|
||||||
|
mode
|
||||||
|
.
|
||||||
|
Counter:141 Name:TX_NC_TEND
|
||||||
|
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||||
|
Description:
|
||||||
|
A TEND instruction has completed in a non-constrained
|
||||||
|
transactional-execution mode
|
||||||
|
.
|
||||||
|
Counter:143 Name:L1C_TLB2_MISSES
|
||||||
|
Short-Description:L1C TLB2 Misses
|
||||||
|
Description:
|
||||||
|
Increments by one for any cycle where a level-1 cache or level-2 TLB miss
|
||||||
|
is in progress
|
||||||
|
.
|
||||||
|
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Chip Level-3 cache without intervention
|
||||||
|
.
|
||||||
|
Counter:145 Name:L1D_ONCHIP_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Chip memory
|
||||||
|
.
|
||||||
|
Counter:146 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Chip Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:147 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Cluster Level-3 cache withountervention
|
||||||
|
.
|
||||||
|
Counter:148 Name:L1D_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:149 Name:L1D_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an On-Cluster Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:150 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Cluster Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:151 Name:L1D_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from Off-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:152 Name:L1D_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Cluster Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:153 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Drawer Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:154 Name:L1D_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from Off-Drawer memory
|
||||||
|
.
|
||||||
|
Counter:155 Name:L1D_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Drawer L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from an Off-Drawer Level-3 cache with intervention
|
||||||
|
.
|
||||||
|
Counter:156 Name:L1D_ONDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:157 Name:L1D_OFFDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from Off-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:158 Name:L1D_ONCHIP_L3_SOURCED_WRITES_RO
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes read-only
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
|
cache line was sourced from On-Chip L3 but a read-only invalidate was
|
||||||
|
done to remove other copies of the cache line
|
||||||
|
.
|
||||||
|
Counter:162 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache ine was sourced from an On-Chip Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:163 Name:L1I_ONCHIP_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache ine was sourced from On-Chip memory
|
||||||
|
.
|
||||||
|
Counter:164 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache ine was sourced from an On-Chip Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:165 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an On-Cluster Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:166 Name:L1I_ONCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an On-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:167 Name:L1I_ONCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from On-Cluster Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:168 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Cluster L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Cluster Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:169 Name:L1I_OFFCLUSTER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Cluster Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from Off-Cluster memory
|
||||||
|
.
|
||||||
|
Counter:170 Name:L1I_OFFCLUSTER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Cluster L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Cluster Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:171 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer L3 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Drawer Level-3 cache without
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:172 Name:L1I_OFFDRAWER_MEMORY_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer Memory Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from Off-Drawer memory
|
||||||
|
.
|
||||||
|
Counter:173 Name:L1I_OFFDRAWER_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Drawer L3 Sourced Writes with Intervention
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from an Off-Drawer Level-3 cache with
|
||||||
|
intervention
|
||||||
|
.
|
||||||
|
Counter:174 Name:L1I_ONDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from On-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:175 Name:L1I_OFFDRAWER_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Drawer L4 Sourced Writes
|
||||||
|
Description:
|
||||||
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
|
returned cache line was sourced from Off-Drawer Level-4 cache
|
||||||
|
.
|
||||||
|
Counter:224 Name:BCD_DFP_EXECUTION_SLOTS
|
||||||
|
Short-Description:BCD DFP Execution Slots
|
||||||
|
Description:
|
||||||
|
Count of floating point execution slots used for finished Binary Coded
|
||||||
|
Decimal to Decimal Floating Point conversions. Instructions: CDZT,
|
||||||
|
CXZT, CZDT, CZXT
|
||||||
|
.
|
||||||
|
Counter:225 Name:VX_BCD_EXECUTION_SLOTS
|
||||||
|
Short-Description:VX BCD Execution Slots
|
||||||
|
Description:
|
||||||
|
Count of floating point execution slots used for finished vector arithmetic
|
||||||
|
Binary Coded Decimal instructions. Instructions: VAP, VSP, VMPVMSP, VDP,
|
||||||
|
VSDP, VRP, VLIP, VSRP, VPSOPVCP, VTP, VPKZ, VUPKZ, VCVB, VCVBG, VCVDVCVDG
|
||||||
|
.
|
||||||
|
Counter:226 Name:DECIMAL_INSTRUCTIONS
|
||||||
|
Short-Description:Decimal Instructions
|
||||||
|
Description:
|
||||||
|
Decimal instructions dispatched. Instructions: CVB, CVD, AP, CP, DP, ED,
|
||||||
|
EDMK, MP, SRP, SP, ZAP
|
||||||
|
.
|
||||||
|
Counter:232 Name:LAST_HOST_TRANSLATIONS
|
||||||
|
Short-Description:Last host translation done
|
||||||
|
Description:
|
||||||
|
Last Host Translation done
|
||||||
|
.
|
||||||
|
Counter:243 Name:TX_NC_TABORT
|
||||||
|
Short-Description:Aborted transactions in non-constrained TX mode
|
||||||
|
Description:
|
||||||
|
A transaction abort has occurred in a non-constrained
|
||||||
|
transactional-execution mode
|
||||||
|
.
|
||||||
|
Counter:244 Name:TX_C_TABORT_NO_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||||
|
Description:
|
||||||
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
|
mode and the CPU is not using any special logic to allow the transaction
|
||||||
|
to complete
|
||||||
|
.
|
||||||
|
Counter:245 Name:TX_C_TABORT_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||||
|
Description:
|
||||||
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
|
mode and the CPU is using special logic to allow the transaction to
|
||||||
|
complete
|
||||||
|
.
|
||||||
|
Counter:247 Name:DFLT_ACCESS
|
||||||
|
Short-Description:Cycles CPU spent obtaining access to Deflate unit
|
||||||
|
Description:
|
||||||
|
Cycles CPU spent obtaining access to Deflate unit
|
||||||
|
.
|
||||||
|
Counter:252 Name:DFLT_CYCLES
|
||||||
|
Short-Description:Cycles CPU is using Deflate unit
|
||||||
|
Description:
|
||||||
|
Cycles CPU is using Deflate unit
|
||||||
|
.
|
||||||
|
Counter:264 Name:DFLT_CC
|
||||||
|
Short-Description:Increments by one for every DEFLATE CONVERSION CALL instruction executed
|
||||||
|
Description:
|
||||||
|
Increments by one for every DEFLATE CONVERSION CALL instruction executed
|
||||||
|
.
|
||||||
|
Counter:265 Name:DFLT_CCERROR
|
||||||
|
Short-Description:Increments by one for every DEFLATE CONVERSION CALL instruction executed that ended in Condition Codes 0, 1 or 2
|
||||||
|
Description:
|
||||||
|
Increments by one for every DEFLATE CONVERSION CALL instruction executed that ended in Condition Codes 0, 1 or 2
|
||||||
|
.
|
||||||
|
#
|
||||||
|
# MT-diagnostic counter set
|
||||||
|
# ---------------------------------------------------------------------
|
||||||
|
Counter:448 Name:MT_DIAG_CYCLES_ONE_THR_ACTIVE
|
||||||
|
Short-Description:Cycle count with one thread active
|
||||||
|
Description:
|
||||||
|
Cycle count with one thread active
|
||||||
|
.
|
||||||
|
Counter:449 Name:MT_DIAG_CYCLES_TWO_THR_ACTIVE
|
||||||
|
Short-Description:Cycle count with two threads active
|
||||||
|
Description:
|
||||||
|
Cycle count with two threads active
|
||||||
|
.
|
||||||
@@ -1,121 +1,145 @@
|
|||||||
Counter: 128 Name:L1D_L2_SOURCED_WRITES
|
Counter: 128 Name:L1D_L2_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the returned
|
A directory write to the Level-1 D-Cache directory where the returned
|
||||||
cache line was sourced from the Level-2 cache
|
cache line was sourced from the Level-2 cache
|
||||||
.
|
.
|
||||||
Counter: 129 Name:L1I_L2_SOURCED_WRITES
|
Counter: 129 Name:L1I_L2_SOURCED_WRITES
|
||||||
|
Short-Description:L1I L2 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from the Level-2 cache
|
cache line was sourced from the Level-2 cache
|
||||||
.
|
.
|
||||||
Counter: 130 Name:DTLB1_MISSES
|
Counter: 130 Name:DTLB1_MISSES
|
||||||
|
Short-Description:DTLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||||
a DTLB1 miss is in progress.
|
a DTLB1 miss is in progress.
|
||||||
.
|
.
|
||||||
Counter: 131 Name:ITLB1_MISSES
|
Counter: 131 Name:ITLB1_MISSES
|
||||||
|
Short-Description:ITLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||||
cycle a ITLB1 miss is in progress.
|
cycle a ITLB1 miss is in progress.
|
||||||
.
|
.
|
||||||
Counter: 133 Name:L2C_STORES_SENT
|
Counter: 133 Name:L2C_STORES_SENT
|
||||||
|
Short-Description:L2C Stores Sent
|
||||||
Description:
|
Description:
|
||||||
Incremented by one for every store sent to Level-2 cache
|
Incremented by one for every store sent to Level-2 cache
|
||||||
.
|
.
|
||||||
Counter: 134 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
|
Counter: 134 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Book L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the returned
|
A directory write to the Level-1 D-Cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-3 cache
|
cache line was sourced from an Off Book Level-3 cache
|
||||||
.
|
.
|
||||||
Counter: 135 Name:L1D_ONBOOK_L4_SOURCED_WRITES
|
Counter: 135 Name:L1D_ONBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the returned
|
A directory write to the Level-1 D-Cache directory where the returned
|
||||||
cache line was sourced from an On Book Level-4 cache
|
cache line was sourced from an On Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter: 136 Name:L1I_ONBOOK_L4_SOURCED_WRITES
|
Counter: 136 Name:L1I_ONBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from an On Book Level-4 cache
|
cache line was sourced from an On Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter: 137 Name:L1D_RO_EXCL_WRITES
|
Counter: 137 Name:L1D_RO_EXCL_WRITES
|
||||||
|
Short-Description:L1D Read-only Exclusive Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache where the line was originally
|
A directory write to the Level-1 D-Cache where the line was originally
|
||||||
in a Read-Only state in the cache but has been updated to be in the
|
in a Read-Only state in the cache but has been updated to be in the
|
||||||
Exclusive state that allows stores to the cache line
|
Exclusive state that allows stores to the cache line
|
||||||
.
|
.
|
||||||
Counter: 138 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
|
Counter: 138 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the returned
|
A directory write to the Level-1 D-Cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-4 cache
|
cache line was sourced from an Off Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter: 139 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
|
Counter: 139 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-4 cache
|
cache line was sourced from an Off Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter: 140 Name:DTLB1_HPAGE_WRITES
|
Counter: 140 Name:DTLB1_HPAGE_WRITES
|
||||||
|
Short-Description:DTLB1 One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer for a one-megabyte page
|
Lookaside Buffer for a one-megabyte page
|
||||||
.
|
.
|
||||||
Counter: 141 Name:L1D_LMEM_SOURCED_WRITES
|
Counter: 141 Name:L1D_LMEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Local Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache where the installed cache line
|
A directory write to the Level-1 D-Cache where the installed cache line
|
||||||
was sourced from memory that is attached to the same book as the Data
|
was sourced from memory that is attached to the same book as the Data
|
||||||
cache (Local Memory)
|
cache (Local Memory)
|
||||||
.
|
.
|
||||||
Counter: 142 Name:L1I_LMEM_SOURCED_WRITES
|
Counter: 142 Name:L1I_LMEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Local Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache where the installed cache
|
A directory write to the Level-1 I-Cache where the installed cache
|
||||||
line was sourced from memory that is attached to the same book as the
|
line was sourced from memory that is attached to the same book as the
|
||||||
Instruction cache (Local Memory)
|
Instruction cache (Local Memory)
|
||||||
.
|
.
|
||||||
Counter: 143 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
|
Counter: 143 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Book L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-3 cache
|
cache line was sourced from an Off Book Level-3 cache
|
||||||
.
|
.
|
||||||
Counter: 144 Name:DTLB1_WRITES
|
Counter: 144 Name:DTLB1_WRITES
|
||||||
|
Short-Description:DTLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer
|
Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter: 145 Name:ITLB1_WRITES
|
Counter: 145 Name:ITLB1_WRITES
|
||||||
|
Short-Description:ITLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Instruction
|
A translation entry has been written to the Level-1 Instruction
|
||||||
Translation Lookaside Buffer
|
Translation Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter: 146 Name:TLB2_PTE_WRITES
|
Counter: 146 Name:TLB2_PTE_WRITES
|
||||||
|
Short-Description:TLB2 PTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Page Table
|
A translation entry has been written to the Level-2 TLB Page Table
|
||||||
Entry arrays
|
Entry arrays
|
||||||
.
|
.
|
||||||
Counter: 147 Name:TLB2_CRSTE_HPAGE_WRITES
|
Counter: 147 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Common Region
|
A translation entry has been written to the Level-2 TLB Common Region
|
||||||
Segment Table Entry arrays for a one-megabyte large page translation
|
Segment Table Entry arrays for a one-megabyte large page translation
|
||||||
.
|
.
|
||||||
Counter: 148 Name:TLB2_CRSTE_WRITES
|
Counter: 148 Name:TLB2_CRSTE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Common Region
|
A translation entry has been written to the Level-2 TLB Common Region
|
||||||
Segment Table Entry arrays
|
Segment Table Entry arrays
|
||||||
.
|
.
|
||||||
Counter: 150 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
Counter: 150 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the returned
|
A directory write to the Level-1 D-Cache directory where the returned
|
||||||
cache line was sourced from an On Chip Level-3 cache
|
cache line was sourced from an On Chip Level-3 cache
|
||||||
.
|
.
|
||||||
Counter: 152 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
|
Counter: 152 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache directory where the returned
|
A directory write to the Level-1 D-Cache directory where the returned
|
||||||
cache line was sourced from an Off Chip/On Book Level-3 cache
|
cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||||
.
|
.
|
||||||
Counter: 153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
Counter: 153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from an On Chip Level-3 cache
|
cache line was sourced from an On Chip Level-3 cache
|
||||||
.
|
.
|
||||||
Counter: 155 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
|
Counter: 155 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 I-Cache directory where the returned
|
A directory write to the Level-1 I-Cache directory where the returned
|
||||||
cache line was sourced from an Off Chip/On Book Level-3 cache
|
cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||||
|
|||||||
@@ -1,98 +1,117 @@
|
|||||||
Counter: 128 Name:DTLB1_MISSES
|
Counter: 128 Name:DTLB1_MISSES
|
||||||
|
Short-Description:DTLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
Level-1 Data TLB miss in progress. Incremented by one for every cycle
|
||||||
a DTLB1 miss is in progress.
|
a DTLB1 miss is in progress.
|
||||||
.
|
.
|
||||||
Counter:129 Name:ITLB1_MISSES
|
Counter:129 Name:ITLB1_MISSES
|
||||||
|
Short-Description:ITLB1 Misses
|
||||||
Description:
|
Description:
|
||||||
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
Level-1 Instruction TLB miss in progress. Incremented by one for every
|
||||||
cycle a ITLB1 miss is in progress.
|
cycle a ITLB1 miss is in progress.
|
||||||
.
|
.
|
||||||
Counter:130 Name:L1D_L2I_SOURCED_WRITES
|
Counter:130 Name:L1D_L2I_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2I Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from the Level-2 Instruction cache
|
cache line was sourced from the Level-2 Instruction cache
|
||||||
.
|
.
|
||||||
Counter:131 Name:L1I_L2I_SOURCED_WRITES
|
Counter:131 Name:L1I_L2I_SOURCED_WRITES
|
||||||
|
Short-Description:L1I L2I Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from the Level-2 Instruction cache
|
returned cache line was sourced from the Level-2 Instruction cache
|
||||||
.
|
.
|
||||||
Counter:132 Name:L1D_L2D_SOURCED_WRITES
|
Counter:132 Name:L1D_L2D_SOURCED_WRITES
|
||||||
|
Short-Description:L1D L2D Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from the Level-2 Data cache
|
cache line was sourced from the Level-2 Data cache
|
||||||
.
|
.
|
||||||
Counter:133 Name:DTLB1_WRITES
|
Counter:133 Name:DTLB1_WRITES
|
||||||
|
Short-Description:DTLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer
|
Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter:135 Name:L1D_LMEM_SOURCED_WRITES
|
Counter:135 Name:L1D_LMEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Local Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache where the installed cache line
|
A directory write to the Level-1 Data cache where the installed cache line
|
||||||
was sourced from memory that is attached to the same book as the Data
|
was sourced from memory that is attached to the same book as the Data
|
||||||
cache (Local Memory)
|
cache (Local Memory)
|
||||||
.
|
.
|
||||||
Counter:137 Name:L1I_LMEM_SOURCED_WRITES
|
Counter:137 Name:L1I_LMEM_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Local Memory Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache where the installed cache
|
A directory write to the Level-1 Instruction cache where the installed cache
|
||||||
line was sourced from memory that is attached to the same book as the
|
line was sourced from memory that is attached to the same book as the
|
||||||
Instruction cache (Local Memory)
|
Instruction cache (Local Memory)
|
||||||
.
|
.
|
||||||
Counter:138 Name:L1D_RO_EXCL_WRITES
|
Counter:138 Name:L1D_RO_EXCL_WRITES
|
||||||
|
Short-Description:L1D Read-only Exclusive Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 D-Cache where the line was originally
|
A directory write to the Level-1 D-Cache where the line was originally
|
||||||
in a Read-Only state in the cache but has been updated to be in the
|
in a Read-Only state in the cache but has been updated to be in the
|
||||||
Exclusive state that allows stores to the cache line
|
Exclusive state that allows stores to the cache line
|
||||||
.
|
.
|
||||||
Counter:139 Name:DTLB1_HPAGE_WRITES
|
Counter:139 Name:DTLB1_HPAGE_WRITES
|
||||||
|
Short-Description:DTLB1 One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Data Translation
|
A translation entry has been written to the Level-1 Data Translation
|
||||||
Lookaside Buffer for a one-megabyte page
|
Lookaside Buffer for a one-megabyte page
|
||||||
.
|
.
|
||||||
Counter:140 Name:ITLB1_WRITES
|
Counter:140 Name:ITLB1_WRITES
|
||||||
|
Short-Description:ITLB1 Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-1 Instruction
|
A translation entry has been written to the Level-1 Instruction
|
||||||
Translation Lookaside Buffer
|
Translation Lookaside Buffer
|
||||||
.
|
.
|
||||||
Counter:141 Name:TLB2_PTE_WRITES
|
Counter:141 Name:TLB2_PTE_WRITES
|
||||||
|
Short-Description:TLB2 PTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Page Table
|
A translation entry has been written to the Level-2 TLB Page Table
|
||||||
Entry arrays
|
Entry arrays
|
||||||
.
|
.
|
||||||
Counter:142 Name:TLB2_CRSTE_HPAGE_WRITES
|
Counter:142 Name:TLB2_CRSTE_HPAGE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE One-Megabyte Page Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Common Region
|
A translation entry has been written to the Level-2 TLB Common Region
|
||||||
Segment Table Entry arrays for a one-megabyte large page translation
|
Segment Table Entry arrays for a one-megabyte large page translation
|
||||||
.
|
.
|
||||||
Counter:143 Name:TLB2_CRSTE_WRITES
|
Counter:143 Name:TLB2_CRSTE_WRITES
|
||||||
|
Short-Description:TLB2 CRSTE Writes
|
||||||
Description:
|
Description:
|
||||||
A translation entry has been written to the Level-2 TLB Common Region
|
A translation entry has been written to the Level-2 TLB Common Region
|
||||||
Segment Table Entry arrays
|
Segment Table Entry arrays
|
||||||
.
|
.
|
||||||
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
Counter:144 Name:L1D_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On Chip Level-3 cache without intervention
|
cache line was sourced from an On Chip Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:145 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
|
Counter:145 Name:L1D_OFFCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off Chip/On Book Level-3 cache without
|
cache line was sourced from an Off Chip/On Book Level-3 cache without
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:146 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
|
Counter:146 Name:L1D_OFFBOOK_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Book L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-3 cache without intervention
|
cache line was sourced from an Off Book Level-3 cache without intervention
|
||||||
.
|
.
|
||||||
Counter:147 Name:L1D_ONBOOK_L4_SOURCED_WRITES
|
Counter:147 Name:L1D_ONBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D On-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an On Book Level-4 cache
|
cache line was sourced from an On Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:148 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
|
Counter:148 Name:L1D_OFFBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1D Off-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-4 cache
|
cache line was sourced from an Off Book Level-4 cache
|
||||||
@@ -104,16 +123,19 @@ cache line was sourced from an Off Book Level-4 cache
|
|||||||
# C .. constrained
|
# C .. constrained
|
||||||
#
|
#
|
||||||
Counter:149 Name:TX_NC_TEND
|
Counter:149 Name:TX_NC_TEND
|
||||||
|
Short-Description:Completed TEND instructions in non-constrained TX mode
|
||||||
Description:
|
Description:
|
||||||
A TEND instruction has completed in a nonconstrained
|
A TEND instruction has completed in a nonconstrained
|
||||||
transactional-execution mode
|
transactional-execution mode
|
||||||
.
|
.
|
||||||
Counter:150 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
Counter:150 Name:L1D_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D On-Chip L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from a On Chip Level-3 cache with intervention
|
cache line was sourced from a On Chip Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:151 Name:L1D_OFFCHIP_L3_SOURCED_WRITES_IV
|
Counter:151 Name:L1D_OFFCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Chip L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off Chip/On Book Level-3 cache with
|
cache line was sourced from an Off Chip/On Book Level-3 cache with
|
||||||
@@ -121,73 +143,86 @@ intervention
|
|||||||
.
|
.
|
||||||
# XXX Remove SOURCED from L1D_OFFBOOK_L3_SOURCED_WRITES...
|
# XXX Remove SOURCED from L1D_OFFBOOK_L3_SOURCED_WRITES...
|
||||||
Counter:152 Name:L1D_OFFBOOK_L3_SOURCED_WRITES_IV
|
Counter:152 Name:L1D_OFFBOOK_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1D Off-Book L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Data cache directory where the returned
|
A directory write to the Level-1 Data cache directory where the returned
|
||||||
cache line was sourced from an Off Book Level-3 cache with intervention
|
cache line was sourced from an Off Book Level-3 cache with intervention
|
||||||
.
|
.
|
||||||
Counter:153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
Counter:153 Name:L1I_ONCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an On Chip Level-3 cache without
|
returned cache line was sourced from an On Chip Level-3 cache without
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:154 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
|
Counter:154 Name:L1I_OFFCHIP_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Chip L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an Off Chip/On Book Level-3 cache
|
returned cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||||
without intervention
|
without intervention
|
||||||
.
|
.
|
||||||
Counter:155 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
|
Counter:155 Name:L1I_OFFBOOK_L3_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Book L3 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an Off Book Level-3 cache without
|
returned cache line was sourced from an Off Book Level-3 cache without
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:156 Name:L1I_ONBOOK_L4_SOURCED_WRITES
|
Counter:156 Name:L1I_ONBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I On-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an On Book Level-4 cache
|
returned cache line was sourced from an On Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:157 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
|
Counter:157 Name:L1I_OFFBOOK_L4_SOURCED_WRITES
|
||||||
|
Short-Description:L1I Off-Book L4 Sourced Writes
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an Off Book Level-4 cache
|
returned cache line was sourced from an Off Book Level-4 cache
|
||||||
.
|
.
|
||||||
Counter:158 Name:TX_C_TEND
|
Counter:158 Name:TX_C_TEND
|
||||||
|
Short-Description:Completed TEND instructions in constrained TX mode
|
||||||
Description:
|
Description:
|
||||||
A TEND instruction has completed in a constrained transactional-execution
|
A TEND instruction has completed in a constrained transactional-execution
|
||||||
mode
|
mode
|
||||||
.
|
.
|
||||||
Counter:159 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
Counter:159 Name:L1I_ONCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I On-Chip L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an On Chip Level-3 cache with
|
returned cache line was sourced from an On Chip Level-3 cache with
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:160 Name:L1I_OFFCHIP_L3_SOURCED_WRITES_IV
|
Counter:160 Name:L1I_OFFCHIP_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Chip L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an Off Chip/On Book Level-3 cache
|
returned cache line was sourced from an Off Chip/On Book Level-3 cache
|
||||||
with intervention
|
with intervention
|
||||||
.
|
.
|
||||||
Counter:161 Name:L1I_OFFBOOK_L3_SOURCED_WRITES_IV
|
Counter:161 Name:L1I_OFFBOOK_L3_SOURCED_WRITES_IV
|
||||||
|
Short-Description:L1I Off-Book L3 Sourced Writes with Intervention
|
||||||
Description:
|
Description:
|
||||||
A directory write to the Level-1 Instruction cache directory where the
|
A directory write to the Level-1 Instruction cache directory where the
|
||||||
returned cache line was sourced from an Off Book Level-3 cache with
|
returned cache line was sourced from an Off Book Level-3 cache with
|
||||||
intervention
|
intervention
|
||||||
.
|
.
|
||||||
Counter:177 Name:TX_NC_TABORT
|
Counter:177 Name:TX_NC_TABORT
|
||||||
|
Short-Description:Aborted transactions in non-constrained TX mode
|
||||||
Description:
|
Description:
|
||||||
A transaction abort has occurred in a nonconstrained
|
A transaction abort has occurred in a nonconstrained
|
||||||
transactional-execution mode
|
transactional-execution mode
|
||||||
.
|
.
|
||||||
Counter:178 Name:TX_C_TABORT_NO_SPECIAL
|
Counter:178 Name:TX_C_TABORT_NO_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode not using special completion logic
|
||||||
Description:
|
Description:
|
||||||
A transaction abort has occurred in a constrained transactional-execution
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
mode and the CPU is not using any special logic to allow the transaction
|
mode and the CPU is not using any special logic to allow the transaction
|
||||||
to complete
|
to complete
|
||||||
.
|
.
|
||||||
Counter:179 Name:TX_C_TABORT_SPECIAL
|
Counter:179 Name:TX_C_TABORT_SPECIAL
|
||||||
|
Short-Description:Aborted transactions in constrained TX mode using special completion logic
|
||||||
Description:
|
Description:
|
||||||
A transaction abort has occurred in a constrained transactional-execution
|
A transaction abort has occurred in a constrained transactional-execution
|
||||||
mode and the CPU is using special logic to allow the transaction to
|
mode and the CPU is using special logic to allow the transaction to
|
||||||
|
|||||||
@@ -1,11 +1,23 @@
|
|||||||
# CPU-measurement facilities
|
# CPU-measurement facilities
|
||||||
#
|
#
|
||||||
# Mapping of IBM System z hardware types to extended counter set defintions
|
# Mapping of:
|
||||||
|
# 1. CPU-MF counter first/second version numbers to "generic" counter
|
||||||
|
# definitions
|
||||||
|
# 2. IBM z Systems hardware to respective extended counter set definitions
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
{
|
{
|
||||||
# Definition # File name
|
# Definition # File name
|
||||||
0 => 'cpum-cf-generic.ctr',
|
|
||||||
|
# CFVN
|
||||||
|
'cfvn-1' => 'cpum-cf-cfvn-1.ctr',
|
||||||
|
'cfvn-3' => 'cpum-cf-cfvn-3.ctr',
|
||||||
|
|
||||||
|
# CSVN
|
||||||
|
'csvn-12345' => 'cpum-cf-csvn-12345.ctr',
|
||||||
|
'csvn-6' => 'cpum-cf-csvn-6.ctr',
|
||||||
|
|
||||||
|
# Extended counters
|
||||||
2097 => 'cpum-cf-extended-z10.ctr',
|
2097 => 'cpum-cf-extended-z10.ctr',
|
||||||
2098 => 'cpum-cf-extended-z10.ctr',
|
2098 => 'cpum-cf-extended-z10.ctr',
|
||||||
2817 => 'cpum-cf-extended-z196.ctr',
|
2817 => 'cpum-cf-extended-z196.ctr',
|
||||||
@@ -14,4 +26,8 @@
|
|||||||
2828 => 'cpum-cf-extended-zEC12.ctr',
|
2828 => 'cpum-cf-extended-zEC12.ctr',
|
||||||
2964 => 'cpum-cf-extended-z13.ctr',
|
2964 => 'cpum-cf-extended-z13.ctr',
|
||||||
2965 => 'cpum-cf-extended-z13.ctr',
|
2965 => 'cpum-cf-extended-z13.ctr',
|
||||||
|
3906 => 'cpum-cf-extended-z14.ctr',
|
||||||
|
3907 => 'cpum-cf-extended-z14.ctr',
|
||||||
|
8561 => 'cpum-cf-extended-z15.ctr',
|
||||||
|
8562 => 'cpum-cf-extended-z15.ctr',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,11 +3,13 @@
|
|||||||
#
|
#
|
||||||
# Basic-sampling mode
|
# Basic-sampling mode
|
||||||
Counter: 0xB0000 Name:SF_CYCLES_BASIC
|
Counter: 0xB0000 Name:SF_CYCLES_BASIC
|
||||||
|
Short-Description:Sample CPU Cycles Using Basic-sampling Mode
|
||||||
Description:
|
Description:
|
||||||
Sample CPU cycles using basic-sampling mode
|
Sample CPU cycles using basic-sampling mode
|
||||||
.
|
.
|
||||||
# Diagnostic-sampling mode (includes basic-sampling)
|
# Diagnostic-sampling mode (includes basic-sampling)
|
||||||
Counter: 0xBD000 Name:SF_CYCLES_BASIC_DIAG
|
Counter: 0xBD000 Name:SF_CYCLES_BASIC_DIAG
|
||||||
|
Short-Description:Sample CPU Cycle Using Diagnostic-sampling Mode (not for ordinary use)
|
||||||
Description:
|
Description:
|
||||||
Sample CPU cycle using diagnostic-sampling mode (not for ordinary use)
|
Sample CPU cycle using diagnostic-sampling mode (not for ordinary use)
|
||||||
.
|
.
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ LDLIBS += -lm
|
|||||||
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
|
OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o
|
||||||
|
|
||||||
cpuplugd: $(OBJECTS)
|
cpuplugd: $(OBJECTS)
|
||||||
$(LINK) $(ALL_LDFLAGS) $^ $(LOADLIBES) $(LDLIBS) -o $@
|
$(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f cpuplugd $(OBJECTS)
|
rm -f cpuplugd $(OBJECTS)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Config file parsing
|
* Config file parsing
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2007, 2017
|
* Copyright IBM Corp. 2007, 2018
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
@@ -201,6 +201,7 @@ void parse_configfile(char *file)
|
|||||||
linebuffer);
|
linebuffer);
|
||||||
parse_configline(linebuffer);
|
parse_configline(linebuffer);
|
||||||
}
|
}
|
||||||
|
fclose(filp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -161,8 +161,8 @@ int is_online(int cpuid)
|
|||||||
retval = 1;
|
retval = 1;
|
||||||
if (state == 0)
|
if (state == 0)
|
||||||
retval = 0;
|
retval = 0;
|
||||||
fclose(filp);
|
|
||||||
}
|
}
|
||||||
|
fclose(filp);
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
@@ -220,8 +220,8 @@ int cpu_is_configured(int cpuid)
|
|||||||
retval = 1;
|
retval = 1;
|
||||||
if (state == 0)
|
if (state == 0)
|
||||||
retval = 0;
|
retval = 0;
|
||||||
fclose(filp);
|
|
||||||
}
|
}
|
||||||
|
fclose(filp);
|
||||||
}
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
#define NAME "cpuplugd"
|
#define NAME "cpuplugd"
|
||||||
#define MAX_HISTORY 100
|
#define MAX_HISTORY 100
|
||||||
#define PIDFILE "/var/run/cpuplugd.pid"
|
#define PIDFILE "/run/cpuplugd.pid"
|
||||||
#define LOCKFILE "/var/lock/cpuplugd.lock"
|
#define LOCKFILE "/var/lock/cpuplugd.lock"
|
||||||
#define PROCINFO_LINE 512
|
#define PROCINFO_LINE 512
|
||||||
#define CPUSTAT_SIZE 1024
|
#define CPUSTAT_SIZE 1024
|
||||||
@@ -152,7 +152,6 @@ struct symbol_names {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern int foreground;
|
extern int foreground;
|
||||||
extern int debug;
|
|
||||||
extern char *configfile;
|
extern char *configfile;
|
||||||
extern int debug; /* is verbose specified? */
|
extern int debug; /* is verbose specified? */
|
||||||
extern int memory;
|
extern int memory;
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ all: dasdfmt
|
|||||||
|
|
||||||
libs = $(rootdir)/libdasd/libdasd.a \
|
libs = $(rootdir)/libdasd/libdasd.a \
|
||||||
$(rootdir)/libvtoc/libvtoc.a \
|
$(rootdir)/libvtoc/libvtoc.a \
|
||||||
$(rootdir)/libu2s/libu2s.a \
|
|
||||||
$(rootdir)/libutil/libutil.a
|
$(rootdir)/libutil/libutil.a
|
||||||
|
|
||||||
dasdfmt: dasdfmt.o $(libs)
|
dasdfmt: dasdfmt.o $(libs)
|
||||||
|
|||||||
@@ -122,6 +122,8 @@ Format the first two tracks and write label and partition information. Only use
|
|||||||
this option if you are sure that the target DASD already contains a regular
|
this option if you are sure that the target DASD already contains a regular
|
||||||
format with the specified blocksize. A blocksize can optionally be specified
|
format with the specified blocksize. A blocksize can optionally be specified
|
||||||
using \fB-b\fR (\fB--blocksize\fR).
|
using \fB-b\fR (\fB--blocksize\fR).
|
||||||
|
.br
|
||||||
|
For thin-provisioned DASD ESE volumes this is the default mode.
|
||||||
.IP expand
|
.IP expand
|
||||||
Format all unformatted tracks at the end of the target DASD. This mode assumes
|
Format all unformatted tracks at the end of the target DASD. This mode assumes
|
||||||
that tracks at the beginning of the DASD volume have already been correctly
|
that tracks at the beginning of the DASD volume have already been correctly
|
||||||
@@ -136,6 +138,10 @@ using \fB-b\fR (\fB--blocksize\fR).
|
|||||||
Perform a complete format check on a DASD volume. A blocksize can be specified
|
Perform a complete format check on a DASD volume. A blocksize can be specified
|
||||||
with \fB-b\fR (\fB--blocksize\fR).
|
with \fB-b\fR (\fB--blocksize\fR).
|
||||||
|
|
||||||
|
.TP
|
||||||
|
\fB--no-discard\fR
|
||||||
|
Omit a full space release when formatting a thin-provisioned DASD ESE volume.
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
\fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR
|
\fB-r\fR \fIcylindercount\fR or \fB--requestsize\fR=\fIcylindercount\fR
|
||||||
Number of cylinders to be processed in one formatting step.
|
Number of cylinders to be processed in one formatting step.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* dasdfmt - Format DASD ECKD devices for use by Linux
|
* dasdfmt - Format DASD ECKD devices for use by Linux
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 1999, 2017
|
* Copyright IBM Corp. 1999, 2017
|
||||||
|
* Copyright Red Hat Inc. 2017
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
@@ -12,6 +13,7 @@
|
|||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
|
||||||
|
#include "lib/dasd_base.h"
|
||||||
#include "lib/dasd_sys.h"
|
#include "lib/dasd_sys.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
#include "lib/util_prg.h"
|
#include "lib/util_prg.h"
|
||||||
@@ -26,6 +28,7 @@
|
|||||||
#define SEC_PER_HOUR (60 * 60)
|
#define SEC_PER_HOUR (60 * 60)
|
||||||
|
|
||||||
static int filedes;
|
static int filedes;
|
||||||
|
static char dev_filename[PATH_MAX];
|
||||||
static int disk_disabled;
|
static int disk_disabled;
|
||||||
static format_data_t format_params;
|
static format_data_t format_params;
|
||||||
static format_mode_t mode;
|
static format_mode_t mode;
|
||||||
@@ -33,7 +36,6 @@ static char *prog_name;
|
|||||||
static volatile sig_atomic_t program_interrupt_in_progress;
|
static volatile sig_atomic_t program_interrupt_in_progress;
|
||||||
static int reqsize;
|
static int reqsize;
|
||||||
|
|
||||||
|
|
||||||
static const struct util_prg prg = {
|
static const struct util_prg prg = {
|
||||||
.desc = "Use dasdfmt to format a DASD ECKD device for use by Linux.\n"
|
.desc = "Use dasdfmt to format a DASD ECKD device for use by Linux.\n"
|
||||||
"DEVICE is the node of the device (e.g. '/dev/dasda').",
|
"DEVICE is the node of the device (e.g. '/dev/dasda').",
|
||||||
@@ -51,6 +53,7 @@ static const struct util_prg prg = {
|
|||||||
/* Defines for options with no short command */
|
/* Defines for options with no short command */
|
||||||
#define OPT_CHECK 128
|
#define OPT_CHECK 128
|
||||||
#define OPT_NOZERO 129
|
#define OPT_NOZERO 129
|
||||||
|
#define OPT_NODISCARD 130
|
||||||
|
|
||||||
static struct util_opt opt_vec[] = {
|
static struct util_opt opt_vec[] = {
|
||||||
UTIL_OPT_SECTION("FORMAT ACTIONS"),
|
UTIL_OPT_SECTION("FORMAT ACTIONS"),
|
||||||
@@ -103,6 +106,11 @@ static struct util_opt opt_vec[] = {
|
|||||||
.desc = "Prevent storage server from modifying record 0",
|
.desc = "Prevent storage server from modifying record 0",
|
||||||
.flags = UTIL_OPT_FLAG_NOSHORT,
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.option = { "no-discard", no_argument, NULL, OPT_NODISCARD },
|
||||||
|
.desc = "Do not discard space before formatting",
|
||||||
|
.flags = UTIL_OPT_FLAG_NOSHORT,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.option = { NULL, no_argument, NULL, 'y' },
|
.option = { NULL, no_argument, NULL, 'y' },
|
||||||
.desc = "Start formatting without further user-confirmation",
|
.desc = "Start formatting without further user-confirmation",
|
||||||
@@ -265,24 +273,6 @@ static void draw_progress(dasdfmt_info_t *info, int cyl, unsigned int cylinders,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reread_partition_table(void)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
int rc = -1;
|
|
||||||
|
|
||||||
/* If the BLKRRPART ioctl fails, it is most likely due to
|
|
||||||
the device just beeing in use by udev. So it is worthwhile
|
|
||||||
to retry the ioctl after a second as it is likely to succeed.
|
|
||||||
*/
|
|
||||||
while (rc && (i < 5)) {
|
|
||||||
++i;
|
|
||||||
rc = ioctl(filedes, BLKRRPART, NULL);
|
|
||||||
if (rc)
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper function for recs_per_track.
|
* Helper function for recs_per_track.
|
||||||
*/
|
*/
|
||||||
@@ -312,16 +302,18 @@ static unsigned int recs_per_track(struct dasd_eckd_characteristics *rdc,
|
|||||||
kn = ceil_quot(kl + 6, 232) + 1;
|
kn = ceil_quot(kl + 6, 232) + 1;
|
||||||
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
|
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
|
||||||
9 + ceil_quot(dl + 6 * dn, 34));
|
9 + ceil_quot(dl + 6 * dn, 34));
|
||||||
} else
|
} else {
|
||||||
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
|
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
|
||||||
|
}
|
||||||
case 0x9345:
|
case 0x9345:
|
||||||
dn = ceil_quot(dl + 6, 232) + 1;
|
dn = ceil_quot(dl + 6, 232) + 1;
|
||||||
if (kl) {
|
if (kl) {
|
||||||
kn = ceil_quot(kl + 6, 232) + 1;
|
kn = ceil_quot(kl + 6, 232) + 1;
|
||||||
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
|
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
|
||||||
ceil_quot(dl + 6 * dn, 34));
|
ceil_quot(dl + 6 * dn, 34));
|
||||||
} else
|
} else {
|
||||||
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
|
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -404,7 +396,7 @@ static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata,
|
|||||||
break;
|
break;
|
||||||
case DASD_FMT_ERR_RECORD_ID:
|
case DASD_FMT_ERR_RECORD_ID:
|
||||||
ERRMSG("Invalid record ID at cyl: %d trk: %d rec: %d.\n",
|
ERRMSG("Invalid record ID at cyl: %d trk: %d rec: %d.\n",
|
||||||
cyl, head, cdata->rec);
|
cyl, head, cdata->rec);
|
||||||
break;
|
break;
|
||||||
case DASD_FMT_ERR_KEY_LENGTH:
|
case DASD_FMT_ERR_KEY_LENGTH:
|
||||||
ERRMSG("Invalid key length (found %d, expected %d) "
|
ERRMSG("Invalid key length (found %d, expected %d) "
|
||||||
@@ -414,6 +406,30 @@ static void evaluate_format_error(dasdfmt_info_t *info, format_check_t *cdata,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void disk_enable(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = dasd_disk_enable(filedes);
|
||||||
|
if (err != 0)
|
||||||
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||||
|
"BIODASDENABLE failed (%s)\n", prog_name,
|
||||||
|
strerror(err));
|
||||||
|
disk_disabled = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void disk_disable(const char *device)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = dasd_disk_disable(device, &filedes);
|
||||||
|
if (err != 0)
|
||||||
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
||||||
|
"BIODASDDISABLE failed. (%s)\n", prog_name,
|
||||||
|
strerror(err));
|
||||||
|
disk_disabled = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* signal handler:
|
* signal handler:
|
||||||
* enables the disk again in case of SIGTERM, SIGINT and SIGQUIT
|
* enables the disk again in case of SIGTERM, SIGINT and SIGQUIT
|
||||||
@@ -428,27 +444,18 @@ static void program_interrupt_signal(int sig)
|
|||||||
|
|
||||||
if (disk_disabled) {
|
if (disk_disabled) {
|
||||||
printf("Re-accessing the device...\n");
|
printf("Re-accessing the device...\n");
|
||||||
rc = ioctl(filedes, BIODASDENABLE, &format_params);
|
disk_enable();
|
||||||
if (rc)
|
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (signal handler) IOCTL "
|
|
||||||
"BIODASDENABLE failed (%s)\n", prog_name,
|
|
||||||
strerror(errno));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Rereading the partition table...\n");
|
printf("Rereading the partition table...\n");
|
||||||
rc = reread_partition_table();
|
rc = dasd_reread_partition_table(dev_filename, 5);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
ERRMSG("%s: (signal handler) Re-reading partition table "
|
ERRMSG("%s: (signal handler) Re-reading partition table "
|
||||||
"failed. (%s)\n", prog_name, strerror(errno));
|
"failed. (%s)\n", prog_name, strerror(rc));
|
||||||
} else {
|
} else {
|
||||||
printf("Exiting...\n");
|
printf("Exiting...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = close(filedes);
|
|
||||||
if (rc)
|
|
||||||
ERRMSG("%s: (signal handler) Unable to close device (%s)\n",
|
|
||||||
prog_name, strerror(errno));
|
|
||||||
|
|
||||||
signal(sig, SIG_DFL);
|
signal(sig, SIG_DFL);
|
||||||
raise(sig);
|
raise(sig);
|
||||||
}
|
}
|
||||||
@@ -497,30 +504,15 @@ static void get_device_name(char *devname,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static void get_blocksize(const char *device, unsigned int *blksize)
|
||||||
* Retrieve DASD information
|
|
||||||
*/
|
|
||||||
static void get_device_info(dasdfmt_info_t *info)
|
|
||||||
{
|
{
|
||||||
dasd_information2_t dasd_info;
|
int err;
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDINFO2, &dasd_info))
|
err = dasd_get_blocksize(device, blksize);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
|
if (err != 0)
|
||||||
"device information failed (%s).\n",
|
|
||||||
prog_name, strerror(errno));
|
|
||||||
|
|
||||||
info->dasd_info = dasd_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Retrieve blocksize of device
|
|
||||||
*/
|
|
||||||
static void get_blocksize(unsigned int *blksize)
|
|
||||||
{
|
|
||||||
if (ioctl(filedes, BLKSSZGET, blksize) != 0)
|
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to get the blocksize "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to get the blocksize "
|
||||||
"of the device failed (%s).\n", prog_name,
|
"of the device failed (%s).\n", prog_name,
|
||||||
strerror(errno));
|
strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -534,7 +526,7 @@ static void check_blocksize(dasdfmt_info_t *info, unsigned int blksize)
|
|||||||
info->dasd_info.format == DASD_FORMAT_NONE)
|
info->dasd_info.format == DASD_FORMAT_NONE)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
get_blocksize(&dev_blksize);
|
get_blocksize(dev_filename, &dev_blksize);
|
||||||
if (dev_blksize != blksize) {
|
if (dev_blksize != blksize) {
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a "
|
ERRMSG_EXIT(EXIT_FAILURE, "WARNING: Device is formatted with a "
|
||||||
"different blocksize (%d).\nUse --mode=full to "
|
"different blocksize (%d).\nUse --mode=full to "
|
||||||
@@ -576,16 +568,15 @@ static void check_layout(dasdfmt_info_t *info, unsigned int intensity)
|
|||||||
*/
|
*/
|
||||||
static void check_disk(dasdfmt_info_t *info, char *devname)
|
static void check_disk(dasdfmt_info_t *info, char *devname)
|
||||||
{
|
{
|
||||||
int ro, errno_save;
|
int err;
|
||||||
|
bool ro;
|
||||||
|
|
||||||
if (ioctl(filedes, BLKROGET, &ro) != 0) {
|
err = dasd_is_ro(devname, &ro);
|
||||||
errno_save = errno;
|
if (err != 0)
|
||||||
close(filedes);
|
|
||||||
ERRMSG_EXIT(EXIT_FAILURE,
|
ERRMSG_EXIT(EXIT_FAILURE,
|
||||||
"%s: the ioctl call to retrieve read/write "
|
"%s: the ioctl call to retrieve read/write "
|
||||||
"status information failed (%s)\n",
|
"status information failed (%s)\n",
|
||||||
prog_name, strerror(errno_save));
|
prog_name, strerror(err));
|
||||||
}
|
|
||||||
|
|
||||||
if (ro)
|
if (ro)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n");
|
ERRMSG_EXIT(EXIT_FAILURE, "Disk is read only!\n");
|
||||||
@@ -775,9 +766,11 @@ static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
|
|||||||
.stop_unit = p->stop_unit
|
.stop_unit = p->stop_unit
|
||||||
}, 0
|
}, 0
|
||||||
};
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDCHECKFMT, &cdata)) {
|
err = dasd_check_format(dev_filename, &cdata);
|
||||||
if (errno == ENOTTY) {
|
if (err != 0) {
|
||||||
|
if (err == ENOTTY) {
|
||||||
ERRMSG("%s: Missing kernel support for format checking",
|
ERRMSG("%s: Missing kernel support for format checking",
|
||||||
prog_name);
|
prog_name);
|
||||||
if (mode == EXPAND) {
|
if (mode == EXPAND) {
|
||||||
@@ -788,7 +781,7 @@ static format_check_t check_track_format(dasdfmt_info_t *info, format_data_t *p)
|
|||||||
ERRMSG_EXIT(EXIT_FAILURE, ".\n");
|
ERRMSG_EXIT(EXIT_FAILURE, ".\n");
|
||||||
}
|
}
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n",
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Could no check format: %s\n",
|
||||||
prog_name, strerror(errno));
|
prog_name, strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
return cdata;
|
return cdata;
|
||||||
@@ -804,7 +797,7 @@ static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders,
|
|||||||
format_data_t step = *format_params;
|
format_data_t step = *format_params;
|
||||||
unsigned long step_value;
|
unsigned long step_value;
|
||||||
unsigned long cur_trk;
|
unsigned long cur_trk;
|
||||||
int cyl = 0;
|
int cyl = 0, err;
|
||||||
|
|
||||||
check_hashmarks(info);
|
check_hashmarks(info);
|
||||||
|
|
||||||
@@ -827,10 +820,11 @@ static int process_tracks(dasdfmt_info_t *info, unsigned int cylinders,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ioctl(filedes, BIODASDFMT, &step) != 0)
|
err = dasd_format_disk(filedes, &step);
|
||||||
|
if (err != 0)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call "
|
||||||
"to format tracks failed. (%s)\n",
|
"to format tracks failed. (%s)\n",
|
||||||
prog_name, strerror(errno));
|
prog_name, strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
cyl = cur_trk / heads + 1;
|
cyl = cur_trk / heads + 1;
|
||||||
@@ -933,6 +927,8 @@ static void dasdfmt_print_info(dasdfmt_info_t *info, char *devname,
|
|||||||
printf("Drive Geometry: %d Cylinders * %d Heads = %d Tracks\n",
|
printf("Drive Geometry: %d Cylinders * %d Heads = %d Tracks\n",
|
||||||
cylinders, heads, (cylinders * heads));
|
cylinders, heads, (cylinders * heads));
|
||||||
|
|
||||||
|
printf("Device Type: %s Provisioned\n",
|
||||||
|
info->ese ? "Thinly" : "Fully");
|
||||||
printf("\nI am going to format the device ");
|
printf("\nI am going to format the device ");
|
||||||
printf("%s in the following way:\n", devname);
|
printf("%s in the following way:\n", devname);
|
||||||
printf(" Device number of device : 0x%x\n", info->dasd_info.devno);
|
printf(" Device number of device : 0x%x\n", info->dasd_info.devno);
|
||||||
@@ -951,7 +947,10 @@ static void dasdfmt_print_info(dasdfmt_info_t *info, char *devname,
|
|||||||
(p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no");
|
(p->intensity & DASD_FMT_INT_COMPAT) ? "yes" : "no");
|
||||||
printf(" Blocksize : %d\n", p->blksize);
|
printf(" Blocksize : %d\n", p->blksize);
|
||||||
printf(" Mode : %s\n", mode_str[mode]);
|
printf(" Mode : %s\n", mode_str[mode]);
|
||||||
|
if (info->ese) {
|
||||||
|
printf(" Full Space Release : %s\n",
|
||||||
|
(info->no_discard || mode == FULL) ? "no" : "yes");
|
||||||
|
}
|
||||||
if (info->testmode)
|
if (info->testmode)
|
||||||
printf("Test mode active, omitting ioctl.\n");
|
printf("Test mode active, omitting ioctl.\n");
|
||||||
}
|
}
|
||||||
@@ -965,7 +964,7 @@ static int dasdfmt_get_volser(char *devname, dasd_information2_t *dasd_info,
|
|||||||
unsigned int blksize;
|
unsigned int blksize;
|
||||||
volume_label_t vlabel;
|
volume_label_t vlabel;
|
||||||
|
|
||||||
get_blocksize(&blksize);
|
get_blocksize(devname, &blksize);
|
||||||
|
|
||||||
if ((strncmp(dasd_info->type, "ECKD", 4) == 0) &&
|
if ((strncmp(dasd_info->type, "ECKD", 4) == 0) &&
|
||||||
!dasd_info->FBA_layout) {
|
!dasd_info->FBA_layout) {
|
||||||
@@ -992,25 +991,25 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
|||||||
format5_label_t f5;
|
format5_label_t f5;
|
||||||
format7_label_t f7;
|
format7_label_t f7;
|
||||||
unsigned int blksize;
|
unsigned int blksize;
|
||||||
int rc;
|
int rc, fd;
|
||||||
void *ipl1_record, *ipl2_record;
|
void *ipl1_record, *ipl2_record;
|
||||||
int ipl1_record_len, ipl2_record_len;
|
int ipl1_record_len, ipl2_record_len;
|
||||||
|
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Retrieving dasd information... ");
|
printf("Retrieving dasd information... ");
|
||||||
|
|
||||||
get_blocksize(&blksize);
|
get_blocksize(dev_filename, &blksize);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't rely on the cylinders returned by HDIO_GETGEO, they might be
|
* Don't rely on the cylinders returned by HDIO_GETGEO, they might be
|
||||||
* to small. geo is only used to get the number of sectors, which may
|
* to small. geo is only used to get the number of sectors, which may
|
||||||
* vary depending on the format.
|
* vary depending on the format.
|
||||||
*/
|
*/
|
||||||
if (ioctl(filedes, HDIO_GETGEO, &geo) != 0)
|
rc = dasd_get_geo(dev_filename, &geo);
|
||||||
|
if (rc != 0)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: (write labels) IOCTL "
|
||||||
"HDIO_GETGEO failed (%s).\n",
|
"HDIO_GETGEO failed (%s).\n",
|
||||||
prog_name, strerror(errno));
|
prog_name, strerror(rc));
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
@@ -1036,26 +1035,40 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
|||||||
ipl2_record_len = sizeof(ipl2.data);
|
ipl2_record_len = sizeof(ipl2.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lseek(filedes, 0, SEEK_SET) != 0)
|
fd = open(dev_filename, O_RDWR);
|
||||||
|
if (fd < 0)
|
||||||
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device "
|
||||||
|
"'%s' (%s)\n", prog_name, dev_filename,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
if (lseek(fd, 0, SEEK_SET) != 0) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command 0 failed "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command 0 failed "
|
||||||
"(%s)\n", prog_name, strerror(errno));
|
"(%s)\n", prog_name, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
rc = write(filedes, ipl1_record, ipl1_record_len);
|
rc = write(fd, ipl1_record, ipl1_record_len);
|
||||||
if (rc != ipl1_record_len)
|
if (rc != ipl1_record_len) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL1 "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL1 "
|
||||||
"failed, only wrote %d bytes.\n", prog_name, rc);
|
"failed, only wrote %d bytes.\n", prog_name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
label_position = blksize;
|
label_position = blksize;
|
||||||
rc = lseek(filedes, label_position, SEEK_SET);
|
rc = lseek(fd, label_position, SEEK_SET);
|
||||||
if (rc != label_position)
|
if (rc != label_position) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
||||||
"(%s).\n", prog_name, label_position,
|
"(%s).\n", prog_name, label_position,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
rc = write(filedes, ipl2_record, ipl2_record_len);
|
rc = write(fd, ipl2_record, ipl2_record_len);
|
||||||
if (rc != ipl2_record_len)
|
if (rc != ipl2_record_len) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL2 "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Writing the bootstrap IPL2 "
|
||||||
"failed, only wrote %d bytes.\n", prog_name, rc);
|
"failed, only wrote %d bytes.\n", prog_name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
/* write VTOC */
|
/* write VTOC */
|
||||||
vtoc_init_format4_label(&f4, geo.cylinders, cylinders, heads,
|
vtoc_init_format4_label(&f4, geo.cylinders, cylinders, heads,
|
||||||
@@ -1071,32 +1084,36 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
|||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Writing label...\n");
|
printf("Writing label...\n");
|
||||||
|
|
||||||
rc = lseek(filedes, label_position, SEEK_SET);
|
rc = lseek(fd, label_position, SEEK_SET);
|
||||||
if (rc != label_position)
|
if (rc != label_position) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
||||||
"(%s).\n", prog_name, label_position,
|
"(%s).\n", prog_name, label_position,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: cdl volume labels do not contain the 'formatted_blocks' part
|
* Note: cdl volume labels do not contain the 'formatted_blocks' part
|
||||||
* and ldl labels do not contain the key field
|
* and ldl labels do not contain the key field
|
||||||
*/
|
*/
|
||||||
if (info->cdl_format) {
|
if (info->cdl_format) {
|
||||||
rc = write(filedes, vlabel, (sizeof(*vlabel) -
|
rc = write(fd, vlabel, (sizeof(*vlabel) -
|
||||||
sizeof(vlabel->formatted_blocks)));
|
sizeof(vlabel->formatted_blocks)));
|
||||||
} 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(filedes, &vlabel->vollbl, (sizeof(*vlabel)
|
rc = write(fd, &vlabel->vollbl, (sizeof(*vlabel)
|
||||||
- sizeof(vlabel->volkey)));
|
- sizeof(vlabel->volkey)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
if (((rc != sizeof(*vlabel) - sizeof(vlabel->formatted_blocks)) &&
|
||||||
info->cdl_format) ||
|
info->cdl_format) ||
|
||||||
((rc != (sizeof(*vlabel) - sizeof(vlabel->volkey))) &&
|
((rc != (sizeof(*vlabel) - sizeof(vlabel->volkey))) &&
|
||||||
(!info->cdl_format)))
|
!info->cdl_format)) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing volume label "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing volume label "
|
||||||
"(%d).\n", prog_name, rc);
|
"(%d).\n", prog_name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Writing VTOC... ");
|
printf("Writing VTOC... ");
|
||||||
@@ -1104,48 +1121,62 @@ static void dasdfmt_write_labels(dasdfmt_info_t *info, volume_label_t *vlabel,
|
|||||||
label_position = (VTOC_START_CC * heads + VTOC_START_HH) *
|
label_position = (VTOC_START_CC * heads + VTOC_START_HH) *
|
||||||
geo.sectors * blksize;
|
geo.sectors * blksize;
|
||||||
|
|
||||||
rc = lseek(filedes, label_position, SEEK_SET);
|
rc = lseek(fd, label_position, SEEK_SET);
|
||||||
if (rc != label_position)
|
if (rc != label_position) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek command to %i failed "
|
||||||
"(%s).\n", prog_name, label_position,
|
"(%s).\n", prog_name, label_position,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
/* write VTOC FMT4 DSCB */
|
/* write VTOC FMT4 DSCB */
|
||||||
rc = write(filedes, &f4, sizeof(format4_label_t));
|
rc = write(fd, &f4, sizeof(format4_label_t));
|
||||||
if (rc != sizeof(format4_label_t))
|
if (rc != sizeof(format4_label_t)) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT4 label "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT4 label "
|
||||||
"(%d).\n", prog_name, rc);
|
"(%d).\n", prog_name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
label_position += blksize;
|
label_position += blksize;
|
||||||
|
|
||||||
rc = lseek(filedes, label_position, SEEK_SET);
|
rc = lseek(fd, label_position, SEEK_SET);
|
||||||
if (rc != label_position)
|
if (rc != label_position) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed (%s).\n",
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed (%s).\n",
|
||||||
prog_name, label_position, strerror(errno));
|
prog_name, label_position, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
/* write VTOC FMT5 DSCB */
|
/* write VTOC FMT5 DSCB */
|
||||||
rc = write(filedes, &f5, sizeof(format5_label_t));
|
rc = write(fd, &f5, sizeof(format5_label_t));
|
||||||
if (rc != sizeof(format5_label_t))
|
if (rc != sizeof(format5_label_t)) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT5 label "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT5 label "
|
||||||
"(%d).\n", prog_name, rc);
|
"(%d).\n", prog_name, rc);
|
||||||
|
}
|
||||||
|
|
||||||
if ((cylinders * heads) > BIG_DISK_SIZE) {
|
if ((cylinders * heads) > BIG_DISK_SIZE) {
|
||||||
label_position += blksize;
|
label_position += blksize;
|
||||||
|
|
||||||
rc = lseek(filedes, label_position, SEEK_SET);
|
rc = lseek(fd, label_position, SEEK_SET);
|
||||||
if (rc != label_position)
|
if (rc != label_position) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: lseek to %i failed "
|
||||||
"(%s).\n", prog_name, label_position,
|
"(%s).\n", prog_name, label_position,
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
/* write VTOC FMT 7 DSCB (only on big disks) */
|
/* write VTOC FMT 7 DSCB (only on big disks) */
|
||||||
rc = write(filedes, &f7, sizeof(format7_label_t));
|
rc = write(fd, &f7, sizeof(format7_label_t));
|
||||||
if (rc != sizeof(format7_label_t))
|
if (rc != sizeof(format7_label_t)) {
|
||||||
|
close(fd);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT7 "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Error writing FMT7 "
|
||||||
"label (rc=%d).\n", prog_name, rc);
|
"label (rc=%d).\n", prog_name, rc);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fsync(filedes);
|
fsync(fd);
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
@@ -1214,6 +1245,26 @@ static void dasdfmt_format(dasdfmt_info_t *info, unsigned int cylinders,
|
|||||||
process_tracks(info, cylinders, heads, format_params);
|
process_tracks(info, cylinders, heads, format_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void dasdfmt_release_space(dasdfmt_info_t *info)
|
||||||
|
{
|
||||||
|
format_data_t r = {
|
||||||
|
.start_unit = 0,
|
||||||
|
.stop_unit = 0,
|
||||||
|
.intensity = DASD_FMT_INT_ESE_FULL,
|
||||||
|
};
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
if (!info->ese || info->no_discard)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printf("Releasing space for the entire device...\n");
|
||||||
|
err = dasd_release_space(dev_filename, &r);
|
||||||
|
if (err) {
|
||||||
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: Could not release space (%s)\n",
|
||||||
|
prog_name, strerror(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
||||||
unsigned int cylinders,
|
unsigned int cylinders,
|
||||||
unsigned int heads, format_data_t *p)
|
unsigned int heads, format_data_t *p)
|
||||||
@@ -1225,27 +1276,25 @@ static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
|||||||
.intensity = ((p->intensity & ~DASD_FMT_INT_FMT_NOR0)
|
.intensity = ((p->intensity & ~DASD_FMT_INT_FMT_NOR0)
|
||||||
| DASD_FMT_INT_INVAL)
|
| DASD_FMT_INT_INVAL)
|
||||||
};
|
};
|
||||||
|
int err;
|
||||||
|
|
||||||
if (!((info->withoutprompt) && (info->verbosity < 1)))
|
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||||
printf("Formatting the device. This may take a while "
|
printf("Formatting the device. This may take a while "
|
||||||
"(get yourself a coffee).\n");
|
"(get yourself a coffee).\n");
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Detaching the device...\n");
|
printf("Detaching the device...\n");
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDDISABLE, p) != 0)
|
disk_disable(dev_filename);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
|
||||||
"BIODASDDISABLE failed. (%s)\n", prog_name,
|
|
||||||
strerror(errno));
|
|
||||||
disk_disabled = 1;
|
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Invalidate first track...\n");
|
printf("Invalidate first track...\n");
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDFMT, &temp) != 0)
|
err = dasd_format_disk(filedes, &temp);
|
||||||
|
if (err != 0)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (invalidate first track) IOCTL "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: (invalidate first track) IOCTL "
|
||||||
"BIODASDFMT failed. (%s)\n", prog_name,
|
"BIODASDFMT failed. (%s)\n", prog_name,
|
||||||
strerror(errno));
|
strerror(err));
|
||||||
|
|
||||||
/* except track 0 from standard formatting procss */
|
/* except track 0 from standard formatting procss */
|
||||||
p->start_unit = 1;
|
p->start_unit = 1;
|
||||||
@@ -1260,19 +1309,16 @@ static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
|||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Revalidate first track...\n");
|
printf("Revalidate first track...\n");
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDFMT, &temp) != 0)
|
err = dasd_format_disk(filedes, &temp);
|
||||||
|
if (err != 0)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (re-validate first track) IOCTL"
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: (re-validate first track) IOCTL"
|
||||||
" BIODASDFMT failed (%s)\n", prog_name,
|
" BIODASDFMT failed (%s)\n", prog_name,
|
||||||
strerror(errno));
|
strerror(err));
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Re-accessing the device...\n");
|
printf("Re-accessing the device...\n");
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDENABLE, p) != 0)
|
disk_enable();
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
|
||||||
"BIODASDENABLE failed. (%s)\n", prog_name,
|
|
||||||
strerror(errno));
|
|
||||||
disk_disabled = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1281,18 +1327,14 @@ static void dasdfmt_prepare_and_format(dasdfmt_info_t *info,
|
|||||||
static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
|
static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
|
||||||
unsigned int heads, format_data_t *p)
|
unsigned int heads, format_data_t *p)
|
||||||
{
|
{
|
||||||
if (!((info->withoutprompt) && (info->verbosity < 1)))
|
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||||
printf("Formatting the device. This may take a while "
|
printf("Formatting the device. This may take a while "
|
||||||
"(get yourself a coffee).\n");
|
"(get yourself a coffee).\n");
|
||||||
|
|
||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Detaching the device...\n");
|
printf("Detaching the device...\n");
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDDISABLE, p) != 0)
|
disk_disable(dev_filename);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
|
||||||
"BIODASDDISABLE failed. (%s)\n", prog_name,
|
|
||||||
strerror(errno));
|
|
||||||
disk_disabled = 1;
|
|
||||||
|
|
||||||
dasdfmt_format(info, cylinders, heads, p);
|
dasdfmt_format(info, cylinders, heads, p);
|
||||||
|
|
||||||
@@ -1302,11 +1344,7 @@ static void dasdfmt_expand_format(dasdfmt_info_t *info, unsigned int cylinders,
|
|||||||
if (info->verbosity > 0)
|
if (info->verbosity > 0)
|
||||||
printf("Re-accessing the device...\n");
|
printf("Re-accessing the device...\n");
|
||||||
|
|
||||||
if (ioctl(filedes, BIODASDENABLE, p) != 0)
|
disk_enable();
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: (prepare device) IOCTL "
|
|
||||||
"BIODASDENABLE failed. (%s)\n", prog_name,
|
|
||||||
strerror(errno));
|
|
||||||
disk_disabled = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1318,9 +1356,12 @@ static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders,
|
|||||||
{
|
{
|
||||||
format_check_t cdata = { .expect = {0}, 0 };
|
format_check_t cdata = { .expect = {0}, 0 };
|
||||||
format_data_t tmp = *p;
|
format_data_t tmp = *p;
|
||||||
|
int err;
|
||||||
|
|
||||||
if (info->force) {
|
if (info->force) {
|
||||||
printf("Skipping format check due to --force.\n");
|
printf("Skipping format check due to --force.\n");
|
||||||
|
} else if (info->ese) {
|
||||||
|
printf("Skipping format check due to thin-provisioned device.\n");
|
||||||
} else {
|
} else {
|
||||||
check_blocksize(info, p->blksize);
|
check_blocksize(info, p->blksize);
|
||||||
|
|
||||||
@@ -1344,25 +1385,20 @@ static void dasdfmt_quick_format(dasdfmt_info_t *info, unsigned int cylinders,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((info->withoutprompt) && (info->verbosity < 1)))
|
if (!(info->withoutprompt && (info->verbosity < 1)))
|
||||||
printf("Formatting the first two tracks of the device.\n");
|
printf("Formatting the first two tracks of the device.\n");
|
||||||
|
|
||||||
/* Disable the device before we do anything */
|
/* Disable the device before we do anything */
|
||||||
if (ioctl(filedes, BIODASDDISABLE, p))
|
disk_disable(dev_filename);
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to disable the device "
|
|
||||||
"failed. (%s)\n", prog_name, strerror(errno));
|
|
||||||
disk_disabled = 1;
|
|
||||||
|
|
||||||
/* Now do the actual formatting of our first two tracks */
|
/* Now do the actual formatting of our first two tracks */
|
||||||
if (ioctl(filedes, BIODASDFMT, p))
|
err = dasd_format_disk(filedes, p);
|
||||||
|
if (err != 0)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to format the device "
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to format the device "
|
||||||
"failed. (%s)\n", prog_name, strerror(errno));
|
"failed. (%s)\n", prog_name, strerror(err));
|
||||||
|
|
||||||
/* Re-Enable the device so that we can continue working with it */
|
/* Re-Enable the device so that we can continue working with it */
|
||||||
if (ioctl(filedes, BIODASDENABLE, p))
|
disk_enable();
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl to enable the device "
|
|
||||||
"failed. (%s)\n", prog_name, strerror(errno));
|
|
||||||
disk_disabled = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
||||||
@@ -1371,7 +1407,7 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
|||||||
unsigned int heads)
|
unsigned int heads)
|
||||||
{
|
{
|
||||||
char inp_buffer[5];
|
char inp_buffer[5];
|
||||||
int count;
|
int count, err;
|
||||||
|
|
||||||
p->start_unit = 0;
|
p->start_unit = 0;
|
||||||
|
|
||||||
@@ -1391,7 +1427,7 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
|||||||
if ((info->verbosity > 0) || !info->withoutprompt || info->testmode)
|
if ((info->verbosity > 0) || !info->withoutprompt || info->testmode)
|
||||||
dasdfmt_print_info(info, devname, vlabel, cylinders, heads, p);
|
dasdfmt_print_info(info, devname, vlabel, cylinders, heads, p);
|
||||||
|
|
||||||
count = u2s_get_host_access_count(devname);
|
count = dasd_get_host_access_count(devname);
|
||||||
if (info->force_host) {
|
if (info->force_host) {
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
ERRMSG_EXIT(EXIT_FAILURE,
|
ERRMSG_EXIT(EXIT_FAILURE,
|
||||||
@@ -1435,6 +1471,7 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
|||||||
dasdfmt_prepare_and_format(info, cylinders, heads, p);
|
dasdfmt_prepare_and_format(info, cylinders, heads, p);
|
||||||
break;
|
break;
|
||||||
case QUICK:
|
case QUICK:
|
||||||
|
dasdfmt_release_space(info);
|
||||||
dasdfmt_quick_format(info, cylinders, heads, p);
|
dasdfmt_quick_format(info, cylinders, heads, p);
|
||||||
break;
|
break;
|
||||||
case EXPAND:
|
case EXPAND:
|
||||||
@@ -1448,15 +1485,29 @@ static void do_format_dasd(dasdfmt_info_t *info, char *devname,
|
|||||||
dasdfmt_write_labels(info, vlabel, cylinders, heads);
|
dasdfmt_write_labels(info, vlabel, cylinders, heads);
|
||||||
|
|
||||||
printf("Rereading the partition table... ");
|
printf("Rereading the partition table... ");
|
||||||
if (reread_partition_table()) {
|
err = dasd_reread_partition_table(dev_filename, 5);
|
||||||
|
if (err != 0) {
|
||||||
ERRMSG("%s: error during rereading the partition "
|
ERRMSG("%s: error during rereading the partition "
|
||||||
"table: %s.\n", prog_name, strerror(errno));
|
"table: %s.\n", prog_name, strerror(err));
|
||||||
} else {
|
} else {
|
||||||
printf("ok\n");
|
printf("ok\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void eval_format_mode(dasdfmt_info_t *info)
|
||||||
|
{
|
||||||
|
if (!info->force && info->mode_specified && info->ese && mode == EXPAND) {
|
||||||
|
ERRMSG_EXIT(EXIT_FAILURE,
|
||||||
|
"WARNING: The specified device is thin-provisioned\n"
|
||||||
|
"Format mode 'expand' is not feasible.\n"
|
||||||
|
"Use --mode=full or --mode=quick to perform a clean format\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->mode_specified)
|
||||||
|
mode = info->ese ? QUICK : FULL;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
dasdfmt_info_t info = {
|
dasdfmt_info_t info = {
|
||||||
@@ -1465,7 +1516,6 @@ int main(int argc, char *argv[])
|
|||||||
volume_label_t vlabel;
|
volume_label_t vlabel;
|
||||||
char old_volser[7];
|
char old_volser[7];
|
||||||
|
|
||||||
char dev_filename[PATH_MAX];
|
|
||||||
char str[ERR_LENGTH];
|
char str[ERR_LENGTH];
|
||||||
char buf[7];
|
char buf[7];
|
||||||
|
|
||||||
@@ -1493,8 +1543,6 @@ int main(int argc, char *argv[])
|
|||||||
format_params.blksize = DEFAULT_BLOCKSIZE;
|
format_params.blksize = DEFAULT_BLOCKSIZE;
|
||||||
format_params.intensity = DASD_FMT_INT_COMPAT;
|
format_params.intensity = DASD_FMT_INT_COMPAT;
|
||||||
|
|
||||||
mode = FULL;
|
|
||||||
|
|
||||||
/*************** parse parameters **********************/
|
/*************** parse parameters **********************/
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -1598,6 +1646,10 @@ int main(int argc, char *argv[])
|
|||||||
"invalid. Consult the man page for "
|
"invalid. Consult the man page for "
|
||||||
"more information.\n",
|
"more information.\n",
|
||||||
prog_name, optarg);
|
prog_name, optarg);
|
||||||
|
info.mode_specified = 1;
|
||||||
|
break;
|
||||||
|
case OPT_NODISCARD:
|
||||||
|
info.no_discard = 1;
|
||||||
break;
|
break;
|
||||||
case OPT_CHECK:
|
case OPT_CHECK:
|
||||||
info.check = 1;
|
info.check = 1;
|
||||||
@@ -1636,18 +1688,20 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
get_device_name(dev_filename, optind, argc, argv);
|
get_device_name(dev_filename, optind, argc, argv);
|
||||||
|
|
||||||
filedes = open(dev_filename, O_RDWR);
|
rc = dasd_get_info(dev_filename, &info.dasd_info);
|
||||||
if (filedes == -1)
|
if (rc != 0)
|
||||||
ERRMSG_EXIT(EXIT_FAILURE, "%s: Unable to open device %s: %s\n",
|
ERRMSG_EXIT(EXIT_FAILURE, "%s: the ioctl call to retrieve "
|
||||||
prog_name, dev_filename, strerror(errno));
|
"device information failed (%s).\n",
|
||||||
|
prog_name, strerror(rc));
|
||||||
|
|
||||||
get_device_info(&info);
|
info.ese = dasd_sys_ese(dev_filename);
|
||||||
|
eval_format_mode(&info);
|
||||||
|
|
||||||
/* Either let the user specify the blksize or get it from the kernel */
|
/* Either let the user specify the blksize or get it from the kernel */
|
||||||
if (!info.blksize_specified) {
|
if (!info.blksize_specified) {
|
||||||
if (!(mode == FULL ||
|
if (!(mode == FULL ||
|
||||||
info.dasd_info.format == DASD_FORMAT_NONE) || info.check)
|
info.dasd_info.format == DASD_FORMAT_NONE) || info.check)
|
||||||
get_blocksize(&format_params.blksize);
|
get_blocksize(dev_filename, &format_params.blksize);
|
||||||
else
|
else
|
||||||
format_params = ask_user_for_blksize(format_params);
|
format_params = ask_user_for_blksize(format_params);
|
||||||
}
|
}
|
||||||
@@ -1686,9 +1740,5 @@ int main(int argc, char *argv[])
|
|||||||
do_format_dasd(&info, dev_filename, &vlabel,
|
do_format_dasd(&info, dev_filename, &vlabel,
|
||||||
&format_params, cylinders, heads);
|
&format_params, cylinders, heads);
|
||||||
|
|
||||||
if (close(filedes) != 0)
|
|
||||||
ERRMSG("%s: error during close: %s\ncontinuing...\n",
|
|
||||||
prog_name, strerror(errno));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,124 +27,6 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* SECTION: Definition needed for DASD-API (see dasd.h) *
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define DASD_IOCTL_LETTER 'D'
|
|
||||||
|
|
||||||
/*
|
|
||||||
* struct dasd_information2_t
|
|
||||||
* represents any data about the device, which is visible to userspace.
|
|
||||||
* including format and features.
|
|
||||||
*/
|
|
||||||
typedef struct dasd_information2_t {
|
|
||||||
unsigned int devno; /* S/390 devno */
|
|
||||||
unsigned int real_devno; /* for aliases */
|
|
||||||
unsigned int schid; /* S/390 subchannel identifier */
|
|
||||||
unsigned int cu_type : 16; /* from SenseID */
|
|
||||||
unsigned int cu_model : 8; /* from SenseID */
|
|
||||||
unsigned int dev_type : 16; /* from SenseID */
|
|
||||||
unsigned int dev_model : 8; /* from SenseID */
|
|
||||||
unsigned int open_count;
|
|
||||||
unsigned int req_queue_len;
|
|
||||||
unsigned int chanq_len; /* length of chanq */
|
|
||||||
char type[4]; /* from discipline.name, */
|
|
||||||
/* 'none' for unknown */
|
|
||||||
unsigned int status; /* current device level */
|
|
||||||
unsigned int label_block; /* where to find the VOLSER */
|
|
||||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
|
||||||
unsigned int characteristics_size;
|
|
||||||
unsigned int confdata_size;
|
|
||||||
char characteristics[64]; /* from read_device_characteristics */
|
|
||||||
char configuration_data[256]; /* from read_configuration_data */
|
|
||||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
|
||||||
unsigned int features; /* dasd features like 'ro',... */
|
|
||||||
unsigned int reserved0; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved1; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved2; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved3; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved4; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved5; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved6; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved7; /* reserved for further use ,... */
|
|
||||||
} dasd_information2_t;
|
|
||||||
|
|
||||||
|
|
||||||
struct dasd_eckd_characteristics {
|
|
||||||
unsigned short cu_type;
|
|
||||||
struct {
|
|
||||||
unsigned char support:2;
|
|
||||||
unsigned char async:1;
|
|
||||||
unsigned char reserved:1;
|
|
||||||
unsigned char cache_info:1;
|
|
||||||
unsigned char model:3;
|
|
||||||
} __attribute__ ((packed)) cu_model;
|
|
||||||
unsigned short dev_type;
|
|
||||||
unsigned char dev_model;
|
|
||||||
struct {
|
|
||||||
unsigned char mult_burst:1;
|
|
||||||
unsigned char RT_in_LR:1;
|
|
||||||
unsigned char reserved1:1;
|
|
||||||
unsigned char RD_IN_LR:1;
|
|
||||||
unsigned char reserved2:4;
|
|
||||||
unsigned char reserved3:8;
|
|
||||||
unsigned char defect_wr:1;
|
|
||||||
unsigned char XRC_supported:1;
|
|
||||||
unsigned char reserved4:1;
|
|
||||||
unsigned char striping:1;
|
|
||||||
unsigned char reserved5:4;
|
|
||||||
unsigned char cfw:1;
|
|
||||||
unsigned char reserved6:2;
|
|
||||||
unsigned char cache:1;
|
|
||||||
unsigned char dual_copy:1;
|
|
||||||
unsigned char dfw:1;
|
|
||||||
unsigned char reset_alleg:1;
|
|
||||||
unsigned char sense_down:1;
|
|
||||||
} __attribute__ ((packed)) facilities;
|
|
||||||
unsigned char dev_class;
|
|
||||||
unsigned char unit_type;
|
|
||||||
unsigned short no_cyl;
|
|
||||||
unsigned short trk_per_cyl;
|
|
||||||
unsigned char sec_per_trk;
|
|
||||||
unsigned char byte_per_track[3];
|
|
||||||
unsigned short home_bytes;
|
|
||||||
unsigned char formula;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
unsigned char f1;
|
|
||||||
unsigned short f2;
|
|
||||||
unsigned short f3;
|
|
||||||
} __attribute__ ((packed)) f_0x01;
|
|
||||||
struct {
|
|
||||||
unsigned char f1;
|
|
||||||
unsigned char f2;
|
|
||||||
unsigned char f3;
|
|
||||||
unsigned char f4;
|
|
||||||
unsigned char f5;
|
|
||||||
} __attribute__ ((packed)) f_0x02;
|
|
||||||
} __attribute__ ((packed)) factors;
|
|
||||||
unsigned short first_alt_trk;
|
|
||||||
unsigned short no_alt_trk;
|
|
||||||
unsigned short first_dia_trk;
|
|
||||||
unsigned short no_dia_trk;
|
|
||||||
unsigned short first_sup_trk;
|
|
||||||
unsigned short no_sup_trk;
|
|
||||||
unsigned char MDR_ID;
|
|
||||||
unsigned char OBR_ID;
|
|
||||||
unsigned char director;
|
|
||||||
unsigned char rd_trk_set;
|
|
||||||
unsigned short max_rec_zero;
|
|
||||||
unsigned char reserved1;
|
|
||||||
unsigned char RWANY_in_LR;
|
|
||||||
unsigned char factor6;
|
|
||||||
unsigned char factor7;
|
|
||||||
unsigned char factor8;
|
|
||||||
unsigned char reserved2[3];
|
|
||||||
unsigned char reserved3[6];
|
|
||||||
unsigned int long_no_cyl;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Represents possible format modes that can be specified when formatting
|
* Represents possible format modes that can be specified when formatting
|
||||||
* a DASD.
|
* a DASD.
|
||||||
@@ -159,113 +41,16 @@ static const char mode_str[3][10] = {
|
|||||||
"Full", "Quick", "Expand"
|
"Full", "Quick", "Expand"
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
* struct format_data_t
|
|
||||||
* represents all data necessary to format a dasd
|
|
||||||
*/
|
|
||||||
typedef struct format_data_t {
|
|
||||||
unsigned int start_unit; /* from track */
|
|
||||||
unsigned int stop_unit; /* to track */
|
|
||||||
unsigned int blksize; /* sectorsize */
|
|
||||||
unsigned int intensity;
|
|
||||||
} format_data_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* values to be used for format_data_t.intensity
|
|
||||||
* 0/8: normal format
|
|
||||||
* 1/9: also write record zero
|
|
||||||
* 3/11: also write home address
|
|
||||||
* 4/12: invalidate track
|
|
||||||
*/
|
|
||||||
#define DASD_FMT_INT_FMT_R0 1 /* write record zero */
|
|
||||||
#define DASD_FMT_INT_FMT_HA 2 /* write home address, also set FMT_R0 ! */
|
|
||||||
#define DASD_FMT_INT_INVAL 4 /* invalidate tracks */
|
|
||||||
#define DASD_FMT_INT_COMPAT 8 /* use OS/390 compatible disk layout */
|
|
||||||
#define DASD_FMT_INT_FMT_NOR0 16 /* remove permission to write record zero */
|
|
||||||
|
|
||||||
/*
|
|
||||||
* struct format_check_t
|
|
||||||
* represents all data necessary to evaluate the format of
|
|
||||||
* different tracks of a dasd
|
|
||||||
*/
|
|
||||||
typedef struct format_check_t {
|
|
||||||
/* Input */
|
|
||||||
struct format_data_t expect;
|
|
||||||
|
|
||||||
/* Output */
|
|
||||||
unsigned int result; /* Error indication (DASD_FMT_ERR_*) */
|
|
||||||
unsigned int unit; /* Track that is in error */
|
|
||||||
unsigned int rec; /* Record that is in error */
|
|
||||||
unsigned int num_records; /* Records in the track in error */
|
|
||||||
unsigned int blksize; /* Block-size of first record in error */
|
|
||||||
unsigned int key_length; /* Key length of first record in error */
|
|
||||||
} format_check_t;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* values to be used in format_check_t for indicating
|
|
||||||
* possible format errors
|
|
||||||
*/
|
|
||||||
#define DASD_FMT_ERR_TOO_FEW_RECORDS 1
|
|
||||||
#define DASD_FMT_ERR_TOO_MANY_RECORDS 2
|
|
||||||
#define DASD_FMT_ERR_BLKSIZE 3
|
|
||||||
#define DASD_FMT_ERR_RECORD_ID 4
|
|
||||||
#define DASD_FMT_ERR_KEY_LENGTH 5
|
|
||||||
|
|
||||||
/*
|
|
||||||
* values to be used for dasd_information2_t.format
|
|
||||||
* 0x00: NOT formatted
|
|
||||||
* 0x01: Linux disc layout
|
|
||||||
* 0x02: Common disc layout
|
|
||||||
*/
|
|
||||||
#define DASD_FORMAT_NONE 0
|
|
||||||
#define DASD_FORMAT_LDL 1
|
|
||||||
#define DASD_FORMAT_CDL 2
|
|
||||||
|
|
||||||
/* Disable the volume (for Linux) */
|
|
||||||
#define BIODASDDISABLE _IO(DASD_IOCTL_LETTER,0)
|
|
||||||
/* Enable the volume (for Linux) */
|
|
||||||
#define BIODASDENABLE _IO(DASD_IOCTL_LETTER,1)
|
|
||||||
|
|
||||||
/* Get information on a dasd device (enhanced) */
|
|
||||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER, 3, dasd_information2_t)
|
|
||||||
|
|
||||||
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
|
|
||||||
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t)
|
|
||||||
|
|
||||||
/* Check device format according to format_data_t */
|
|
||||||
#define BIODASDCHECKFMT _IOWR(DASD_IOCTL_LETTER, 2, format_check_t)
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h ) *
|
|
||||||
****************************************************************************/
|
|
||||||
/* re-read partition table */
|
|
||||||
#define BLKRRPART _IO(0x12,95)
|
|
||||||
/* get block device sector size */
|
|
||||||
#define BLKSSZGET _IO(0x12,104)
|
|
||||||
/* get read-only status (0 = read_write) */
|
|
||||||
#define BLKROGET _IO(0x12,94)
|
|
||||||
|
|
||||||
/* get device geometry */
|
|
||||||
#define HDIO_GETGEO 0x0301
|
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
* SECTION: DASDFMT internal types *
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#define DASD_PARTN_BITS 2
|
#define DASD_PARTN_BITS 2
|
||||||
#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
|
#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
|
||||||
|
|
||||||
#define EXIT_MISUSE 1
|
#define EXIT_MISUSE 1
|
||||||
#define EXIT_BUSY 2
|
#define EXIT_BUSY 2
|
||||||
#define LABEL_LENGTH 14
|
|
||||||
#define VLABEL_CHARS 84
|
|
||||||
#define LINE_LENGTH 80
|
|
||||||
#define ERR_LENGTH 90
|
#define ERR_LENGTH 90
|
||||||
|
|
||||||
#define DEFAULT_BLOCKSIZE 4096
|
#define DEFAULT_BLOCKSIZE 4096
|
||||||
/* requestsize - number of cylinders in one format step */
|
/* requestsize - number of cylinders in one format step */
|
||||||
#define DEFAULT_REQUESTSIZE 10
|
#define DEFAULT_REQUESTSIZE 10
|
||||||
#define USABLE_PARTITIONS ((1 << DASD_PARTN_BITS) - 1)
|
|
||||||
|
|
||||||
#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
|
#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
|
||||||
#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
|
#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
|
||||||
@@ -307,6 +92,9 @@ typedef struct dasdfmt_info {
|
|||||||
int force_host;
|
int force_host;
|
||||||
int layout_specified;
|
int layout_specified;
|
||||||
int check;
|
int check;
|
||||||
|
int mode_specified;
|
||||||
|
int ese;
|
||||||
|
int no_discard;
|
||||||
} dasdfmt_info_t;
|
} dasdfmt_info_t;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
include ../common.mak
|
include ../common.mak
|
||||||
|
|
||||||
libs = $(rootdir)/libu2s/libu2s.a \
|
libs = $(rootdir)/libutil/libutil.a \
|
||||||
$(rootdir)/libutil/libutil.a
|
$(rootdir)/libdasd/libdasd.a
|
||||||
|
|
||||||
all: dasdinfo
|
all: dasdinfo
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ Print DASD uid
|
|||||||
This option prints the full uid of the DASD. When z/VM provides two
|
This option prints the full uid of the DASD. When z/VM provides two
|
||||||
virtual devices that are actually located on the same real device, the
|
virtual devices that are actually located on the same real device, the
|
||||||
first four tokens of the uid will be identical for both devices. z/VM
|
first four tokens of the uid will be identical for both devices. z/VM
|
||||||
may provide an additional token that allows to distinguish between
|
may provide an additional token that can be used to distinguish between
|
||||||
different minidisks. You need both support in the Linux kernel and
|
different minidisks. You need both support in the Linux kernel and
|
||||||
z/VM to receive such an additional token.
|
z/VM to receive such an additional token.
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ available by applying the PTFs for VM APAR VM64273 on z/VM 5.2.0 and higher.
|
|||||||
.BI "-u|--uid"
|
.BI "-u|--uid"
|
||||||
Print DASD uid without z/VM minidisk token
|
Print DASD uid without z/VM minidisk token
|
||||||
|
|
||||||
z/VM may provide an additional token that allows 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
|
compatibile 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
|
||||||
|
|||||||
@@ -22,17 +22,15 @@
|
|||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "lib/dasd_base.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_file.h"
|
#include "lib/util_file.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/zt_common.h"
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
#define RD_BUFFER_SIZE 80
|
#define RD_BUFFER_SIZE 80
|
||||||
#define BLKSSZGET _IO(0x12,104)
|
|
||||||
#define DASD_IOCTL_LETTER 'D'
|
|
||||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,struct dasd_information)
|
|
||||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,struct dasd_information2)
|
|
||||||
#define TEMP_DEV_MAX_RETRIES 1000
|
#define TEMP_DEV_MAX_RETRIES 1000
|
||||||
|
|
||||||
static const struct util_prg prg = {
|
static const struct util_prg prg = {
|
||||||
@@ -100,67 +98,7 @@ struct volume_label {
|
|||||||
char volid[6];
|
char volid[6];
|
||||||
} __attribute__ ((packed));
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
struct dasd_information2 {
|
static char EBCtoASC[256] = {
|
||||||
unsigned int devno;
|
|
||||||
unsigned int real_devno;
|
|
||||||
unsigned int schid;
|
|
||||||
unsigned int cu_type : 16;
|
|
||||||
unsigned int cu_model : 8;
|
|
||||||
unsigned int dev_type : 16;
|
|
||||||
unsigned int dev_model : 8;
|
|
||||||
unsigned int open_count;
|
|
||||||
unsigned int req_queue_len;
|
|
||||||
unsigned int chanq_len;
|
|
||||||
char type[4];
|
|
||||||
unsigned int status;
|
|
||||||
unsigned int label_block;
|
|
||||||
unsigned int FBA_layout;
|
|
||||||
unsigned int characteristics_size;
|
|
||||||
unsigned int confdata_size;
|
|
||||||
char characteristics[64];
|
|
||||||
char configuration_data[256];
|
|
||||||
unsigned int format;
|
|
||||||
unsigned int features;
|
|
||||||
unsigned int reserved0;
|
|
||||||
unsigned int reserved1;
|
|
||||||
unsigned int reserved2;
|
|
||||||
unsigned int reserved3;
|
|
||||||
unsigned int reserved4;
|
|
||||||
unsigned int reserved5;
|
|
||||||
unsigned int reserved6;
|
|
||||||
unsigned int reserved7;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dasd_information {
|
|
||||||
unsigned int devno;
|
|
||||||
unsigned int real_devno;
|
|
||||||
unsigned int schid;
|
|
||||||
unsigned int cu_type : 16;
|
|
||||||
unsigned int cu_model : 8;
|
|
||||||
unsigned int dev_type : 16;
|
|
||||||
unsigned int dev_model : 8;
|
|
||||||
unsigned int open_count;
|
|
||||||
unsigned int req_queue_len;
|
|
||||||
unsigned int chanq_len;
|
|
||||||
char type[4];
|
|
||||||
unsigned int status;
|
|
||||||
unsigned int label_block;
|
|
||||||
unsigned int FBA_layout;
|
|
||||||
unsigned int characteristics_size;
|
|
||||||
unsigned int confdata_size;
|
|
||||||
char characteristics[64];
|
|
||||||
char configuration_data[256];
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dasd_data
|
|
||||||
{
|
|
||||||
struct dasd_information2 dasd_info;
|
|
||||||
int dasd_info_version;
|
|
||||||
int blksize;
|
|
||||||
};
|
|
||||||
|
|
||||||
static char EBCtoASC[256] =
|
|
||||||
{
|
|
||||||
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
/* 0x00 NUL SOH STX ETX *SEL HT *RNL DEL */
|
||||||
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
0x00, 0x01, 0x02, 0x03, 0x07, 0x09, 0x07, 0x7F,
|
||||||
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
/* 0x08 -GE -SPS -RPT VT FF CR SO SI */
|
||||||
@@ -227,12 +165,12 @@ static char EBCtoASC[256] =
|
|||||||
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
0x38, 0x39, 0x07, 0x07, 0x9A, 0x07, 0x07, 0x07
|
||||||
};
|
};
|
||||||
|
|
||||||
static char *dinfo_ebcdic_dec (char *source, char *target, int l)
|
static char *dinfo_ebcdic_dec(char *source, char *target, int l)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < l; i++)
|
for (i = 0; i < l; i++)
|
||||||
target[i]=EBCtoASC[(unsigned char)(source[i])];
|
target[i] = EBCtoASC[(unsigned char)(source[i])];
|
||||||
|
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
@@ -242,51 +180,49 @@ static int dinfo_read_dasd_uid(char *uidfile, char *readbuf)
|
|||||||
return util_file_read_line(readbuf, RD_BUFFER_SIZE, uidfile);
|
return util_file_read_line(readbuf, RD_BUFFER_SIZE, uidfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dinfo_read_dasd_vlabel (char *device, struct volume_label *vlabel,
|
static int dinfo_read_dasd_vlabel(char *device, struct volume_label *vlabel,
|
||||||
char *readbuf)
|
char *readbuf)
|
||||||
{
|
{
|
||||||
struct dasd_data data;
|
|
||||||
struct volume_label tmp;
|
struct volume_label tmp;
|
||||||
int vlsize = sizeof(struct volume_label);
|
int vlsize = sizeof(struct volume_label);
|
||||||
|
dasd_information2_t dasd_info;
|
||||||
unsigned long vlabel_start;
|
unsigned long vlabel_start;
|
||||||
|
unsigned int blksize;
|
||||||
char vollbl[5];
|
char vollbl[5];
|
||||||
int f;
|
int f;
|
||||||
char *space;
|
char *space;
|
||||||
|
|
||||||
if ((f = open(device, O_RDONLY)) < 0) {
|
if (dasd_get_blocksize(device, &blksize) != 0) {
|
||||||
printf("Could not open device node.\n");
|
warnx("Unable to figure out block size");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(f, BLKSSZGET, &data.blksize) != 0) {
|
if (dasd_get_info(device, &dasd_info) != 0) {
|
||||||
printf("Unable to figure out block size.\n");
|
warnx("Unable to figure out DASD information");
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(f, BIODASDINFO2, &data.dasd_info) == 0)
|
f = open(device, O_RDONLY);
|
||||||
data.dasd_info_version = 2;
|
if (f < 0) {
|
||||||
else {
|
warnx("Could not open device node");
|
||||||
if (ioctl(f, BIODASDINFO, &data.dasd_info) != 0) {
|
goto error;
|
||||||
printf("Unable to figure out DASD informations.\n");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vlabel_start = data.dasd_info.label_block * data.blksize;
|
vlabel_start = dasd_info.label_block * blksize;
|
||||||
if (lseek(f, vlabel_start, SEEK_SET) < 0)
|
if (lseek(f, vlabel_start, SEEK_SET) < 0)
|
||||||
goto error;
|
goto error_close;
|
||||||
|
|
||||||
bzero(vlabel, vlsize);
|
bzero(vlabel, vlsize);
|
||||||
|
|
||||||
if (read(f, vlabel, vlsize) != vlsize) {
|
if (read(f, vlabel, vlsize) != vlsize) {
|
||||||
printf("Could not read volume label.\n");
|
warnx("Could not read volume label");
|
||||||
goto error;
|
goto error_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.dasd_info.FBA_layout) {
|
if (dasd_info.FBA_layout) {
|
||||||
bzero(&tmp, vlsize);
|
bzero(&tmp, vlsize);
|
||||||
memcpy(&tmp, vlabel, vlsize);
|
memcpy(&tmp, vlabel, vlsize);
|
||||||
memcpy(vlabel->vollbl, &tmp, vlsize-4);
|
memcpy(vlabel->vollbl, &tmp, vlsize - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(f);
|
close(f);
|
||||||
@@ -301,16 +237,17 @@ static int dinfo_read_dasd_vlabel (char *device, struct volume_label *vlabel,
|
|||||||
(strncmp(vollbl, "CMS1", 4) == 0)) {
|
(strncmp(vollbl, "CMS1", 4) == 0)) {
|
||||||
strncpy(readbuf, vlabel->volid, 6);
|
strncpy(readbuf, vlabel->volid, 6);
|
||||||
dinfo_ebcdic_dec(readbuf, readbuf, 6);
|
dinfo_ebcdic_dec(readbuf, readbuf, 6);
|
||||||
space = strchr(readbuf,' ');
|
space = strchr(readbuf, ' ');
|
||||||
if (space)
|
if (space)
|
||||||
*space = 0;
|
*space = 0;
|
||||||
} else
|
} else {
|
||||||
strcpy(readbuf, "");
|
strcpy(readbuf, "");
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
error:
|
error_close:
|
||||||
close(f);
|
close(f);
|
||||||
|
error:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,10 +256,9 @@ static void *dinfo_malloc(size_t size)
|
|||||||
void *result;
|
void *result;
|
||||||
|
|
||||||
result = malloc(size);
|
result = malloc(size);
|
||||||
if (result == NULL) {
|
if (result == NULL)
|
||||||
printf("Could not allocate %lld bytes of memory",
|
warnx("Could not allocate %lu bytes of memory", size);
|
||||||
(unsigned long long) size);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +268,7 @@ static char *dinfo_make_path(char *dirname, char *filename)
|
|||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
len = strlen(dirname) + strlen(filename) + 2;
|
len = strlen(dirname) + strlen(filename) + 2;
|
||||||
result = (char *) dinfo_malloc(len);
|
result = (char *)dinfo_malloc(len);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
sprintf(result, "%s/%s", dirname, filename);
|
sprintf(result, "%s/%s", dirname, filename);
|
||||||
@@ -342,8 +278,8 @@ static char *dinfo_make_path(char *dirname, char *filename)
|
|||||||
static int dinfo_create_devnode(dev_t dev, char **devno)
|
static int dinfo_create_devnode(dev_t dev, char **devno)
|
||||||
{
|
{
|
||||||
char *result;
|
char *result;
|
||||||
char * pathname[] = { "/dev", getenv("TMPDIR"), "/tmp",
|
char *pathname[] = { "/dev", getenv("TMPDIR"), "/tmp",
|
||||||
getenv("HOME"), "." , "/"};
|
getenv("HOME"), ".", "/"};
|
||||||
char filename[] = "dasdinfo0000";
|
char filename[] = "dasdinfo0000";
|
||||||
mode_t mode;
|
mode_t mode;
|
||||||
unsigned int path;
|
unsigned int path;
|
||||||
@@ -354,10 +290,10 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
|||||||
mode = S_IFBLK | S_IRWXU;
|
mode = S_IFBLK | S_IRWXU;
|
||||||
|
|
||||||
/* Try several locations for the temporary device node. */
|
/* Try several locations for the temporary device node. */
|
||||||
for (path=0; path < sizeof(pathname) / sizeof(pathname[0]); path++) {
|
for (path = 0; path < ARRAY_SIZE(pathname); path++) {
|
||||||
if (pathname[path] == NULL)
|
if (pathname[path] == NULL)
|
||||||
continue;
|
continue;
|
||||||
for (retry=0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
|
for (retry = 0; retry < TEMP_DEV_MAX_RETRIES; retry++) {
|
||||||
sprintf(filename, "dasdinfo%04d", retry);
|
sprintf(filename, "dasdinfo%04d", retry);
|
||||||
result = dinfo_make_path(pathname[path], filename);
|
result = dinfo_make_path(pathname[path], filename);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
@@ -366,7 +302,8 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
|||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
/* Need this test to cover
|
/* Need this test to cover
|
||||||
* 'nodev'-mounted
|
* 'nodev'-mounted
|
||||||
* filesystems. */
|
* filesystems.
|
||||||
|
*/
|
||||||
fd = open(result, O_RDONLY);
|
fd = open(result, O_RDONLY);
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
close(fd);
|
close(fd);
|
||||||
@@ -375,21 +312,20 @@ static int dinfo_create_devnode(dev_t dev, char **devno)
|
|||||||
}
|
}
|
||||||
remove(result);
|
remove(result);
|
||||||
retry = TEMP_DEV_MAX_RETRIES;
|
retry = TEMP_DEV_MAX_RETRIES;
|
||||||
} else if (errno != EEXIST)
|
} else if (errno != EEXIST) {
|
||||||
retry = TEMP_DEV_MAX_RETRIES;
|
retry = TEMP_DEV_MAX_RETRIES;
|
||||||
|
}
|
||||||
free(result);
|
free(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("Error: Unable to create temporary device node");
|
warnx("Error: Unable to create temporary device node");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dinfo_free_devnode(char *device)
|
static void dinfo_free_devnode(char *device)
|
||||||
{
|
{
|
||||||
if (remove(device)) {
|
if (remove(device))
|
||||||
printf("Warning: Could not remove "
|
warnx("Warning: Could not remove temporary file %s", device);
|
||||||
"temporary file %s", device);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dinfo_extract_dev(dev_t *dev, char *str)
|
static int dinfo_extract_dev(dev_t *dev, char *str)
|
||||||
@@ -399,9 +335,10 @@ static int dinfo_extract_dev(dev_t *dev, char *str)
|
|||||||
int ma, mi;
|
int ma, mi;
|
||||||
|
|
||||||
bzero(tmp, RD_BUFFER_SIZE);
|
bzero(tmp, RD_BUFFER_SIZE);
|
||||||
strncpy(tmp, str, RD_BUFFER_SIZE);
|
util_strlcpy(tmp, str, RD_BUFFER_SIZE);
|
||||||
if ((p = strchr(tmp, ':')) == NULL) {
|
p = strchr(tmp, ':');
|
||||||
printf("Error: unable to extract major/minor\n");
|
if (p == NULL) {
|
||||||
|
warnx("Error: unable to extract major/minor");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,7 +357,7 @@ static int dinfo_get_dev_from_blockdev(char *blockdev, dev_t *dev)
|
|||||||
|
|
||||||
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
||||||
if (!readbuf) {
|
if (!readbuf) {
|
||||||
printf("Error: Not enough memory to allocate readbuffer\n");
|
warnx("Error: Not enough memory to allocate readbuffer");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (util_file_read_line(readbuf, RD_BUFFER_SIZE,
|
if (util_file_read_line(readbuf, RD_BUFFER_SIZE,
|
||||||
@@ -439,6 +376,7 @@ dinfo_is_busiddir(const char *fpath, const struct stat *UNUSED(sb),
|
|||||||
char *tempdir;
|
char *tempdir;
|
||||||
char linkdir[128];
|
char linkdir[128];
|
||||||
ssize_t i;
|
ssize_t i;
|
||||||
|
|
||||||
if (tflag != FTW_D || (strncmp((fpath + ftwbuf->base), searchbusid,
|
if (tflag != FTW_D || (strncmp((fpath + ftwbuf->base), searchbusid,
|
||||||
strlen(searchbusid)) != 0))
|
strlen(searchbusid)) != 0))
|
||||||
return FTW_CONTINUE;
|
return FTW_CONTINUE;
|
||||||
@@ -454,7 +392,7 @@ dinfo_is_busiddir(const char *fpath, const struct stat *UNUSED(sb),
|
|||||||
if ((i < 0) || (i >= 128))
|
if ((i < 0) || (i >= 128))
|
||||||
return -1;
|
return -1;
|
||||||
/* append '\0' because readlink returns non zero terminated string */
|
/* append '\0' because readlink returns non zero terminated string */
|
||||||
tempdir[i+1] = '\0';
|
tempdir[i + 1] = '\0';
|
||||||
if (strstr(linkdir, "dasd") == NULL)
|
if (strstr(linkdir, "dasd") == NULL)
|
||||||
return FTW_CONTINUE;
|
return FTW_CONTINUE;
|
||||||
free(busiddir);
|
free(busiddir);
|
||||||
@@ -470,15 +408,17 @@ dinfo_find_entry(const char *dir, const char *searchstring,
|
|||||||
{
|
{
|
||||||
DIR *directory = NULL;
|
DIR *directory = NULL;
|
||||||
struct dirent *dir_entry = NULL;
|
struct dirent *dir_entry = NULL;
|
||||||
|
|
||||||
directory = opendir(dir);
|
directory = opendir(dir);
|
||||||
if (directory == NULL)
|
if (directory == NULL)
|
||||||
return -1;
|
return -1;
|
||||||
while ((dir_entry = readdir(directory)) != NULL) {
|
while ((dir_entry = readdir(directory)) != NULL) {
|
||||||
/* compare if the found entry has exactly the same name
|
/* compare if the found entry has exactly the same name and type
|
||||||
and type as searched */
|
* as searched
|
||||||
|
*/
|
||||||
if ((strncmp(dir_entry->d_name, searchstring,
|
if ((strncmp(dir_entry->d_name, searchstring,
|
||||||
strlen(searchstring)) == 0)
|
strlen(searchstring)) == 0) &&
|
||||||
&& (dir_entry->d_type & type)) {
|
(dir_entry->d_type & type)) {
|
||||||
*result = strdup(dir_entry->d_name);
|
*result = strdup(dir_entry->d_name);
|
||||||
if (*result == NULL)
|
if (*result == NULL)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -548,21 +488,22 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
|||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
|
||||||
if (stat(devnode, &stat_buffer) != 0) {
|
if (stat(devnode, &stat_buffer) != 0) {
|
||||||
printf("Error: could not stat %s\n", devnode);
|
warnx("Error: could not stat %s", devnode);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sprintf(stat_dev, "%d:%d", major(stat_buffer.st_rdev),
|
sprintf(stat_dev, "%d:%d", major(stat_buffer.st_rdev),
|
||||||
minor(stat_buffer.st_rdev));
|
minor(stat_buffer.st_rdev));
|
||||||
|
|
||||||
if ((directory = opendir("/sys/block/")) == NULL) {
|
directory = opendir("/sys/block/");
|
||||||
printf("Error: could not open directory /sys/block\n");
|
if (directory == NULL) {
|
||||||
|
warnx("Error: could not open directory /sys/block");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
readbuf = dinfo_malloc(RD_BUFFER_SIZE);
|
||||||
if (!readbuf) {
|
if (!readbuf) {
|
||||||
printf("Error: Not enough memory to allocate readbuffer\n");
|
warnx("Error: Not enough memory to allocate readbuffer");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,7 +514,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (strncmp(stat_dev, readbuf,
|
if (strncmp(stat_dev, readbuf,
|
||||||
MAX(strlen(stat_dev), strlen(readbuf)-1)) == 0) {
|
MAX(strlen(stat_dev), strlen(readbuf) - 1)) == 0) {
|
||||||
rc = snprintf(*uidfile, RD_BUFFER_SIZE,
|
rc = snprintf(*uidfile, RD_BUFFER_SIZE,
|
||||||
"/sys/block/%s/device/uid",
|
"/sys/block/%s/device/uid",
|
||||||
dir_entry->d_name);
|
dir_entry->d_name);
|
||||||
@@ -591,7 +532,7 @@ static int dinfo_get_uid_from_devnode(char **uidfile, char *devnode)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char * argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct utsname uname_buf;
|
struct utsname uname_buf;
|
||||||
int version, release;
|
int version, release;
|
||||||
@@ -635,13 +576,13 @@ int main(int argc, char * argv[])
|
|||||||
print_vlabel = 1;
|
print_vlabel = 1;
|
||||||
break;
|
break;
|
||||||
case 'i':
|
case 'i':
|
||||||
busid=strdup(optarg);
|
busid = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b':
|
||||||
blockdev=strdup(optarg);
|
blockdev = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
devnode=strdup(optarg);
|
devnode = strdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
export = 1;
|
export = 1;
|
||||||
@@ -661,28 +602,26 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
uname(&uname_buf);
|
uname(&uname_buf);
|
||||||
sscanf(uname_buf.release, "%d.%d", &version,&release);
|
sscanf(uname_buf.release, "%d.%d", &version, &release);
|
||||||
if (strcmp(uname_buf.sysname,"Linux") ||
|
if (strcmp(uname_buf.sysname, "Linux") ||
|
||||||
version < 2 || (version == 2 && release < 6)) {
|
version < 2 || (version == 2 && release < 6)) {
|
||||||
printf("%s %d.%d is not supported\n", uname_buf.sysname,
|
warnx("%s %d.%d is not supported", uname_buf.sysname,
|
||||||
version,release);
|
version, release);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!busid && !blockdev && !devnode) {
|
if (!busid && !blockdev && !devnode) {
|
||||||
printf("Error: please specify a device using either -b, -i "
|
warnx("Error: please specify a device using either -b, -i or -d");
|
||||||
"or -d\n");
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((busid && blockdev) || (busid && devnode) || (blockdev && devnode)) {
|
if ((busid && blockdev) || (busid && devnode) || (blockdev && devnode)) {
|
||||||
printf("Error: please specify device only once, either -b, -i "
|
warnx("Error: please specify device only once, either -b, -i or -d");
|
||||||
"or -d\n");
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!print_uid && !print_extended_uid && !print_vlabel) {
|
if (!print_uid && !print_extended_uid && !print_vlabel) {
|
||||||
printf("Error: no action specified (e.g. -u)\n");
|
warnx("Error: no action specified (e.g. -u)");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -693,9 +632,9 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
/* try to read the uid attribute */
|
/* try to read the uid attribute */
|
||||||
if (busid) {
|
if (busid) {
|
||||||
sprintf(uidfile,"/sys/bus/ccw/devices/%s/uid", busid);
|
sprintf(uidfile, "/sys/bus/ccw/devices/%s/uid", busid);
|
||||||
} else if (blockdev) {
|
} else if (blockdev) {
|
||||||
sprintf(uidfile,"/sys/block/%s/device/uid", blockdev);
|
sprintf(uidfile, "/sys/block/%s/device/uid", blockdev);
|
||||||
} else if (devnode) {
|
} else if (devnode) {
|
||||||
if (dinfo_get_uid_from_devnode(&uidfile, devnode) != 0)
|
if (dinfo_get_uid_from_devnode(&uidfile, devnode) != 0)
|
||||||
goto error;
|
goto error;
|
||||||
@@ -715,12 +654,11 @@ int main(int argc, char * argv[])
|
|||||||
if (!srchuid)
|
if (!srchuid)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (srchuid) {
|
if (srchuid)
|
||||||
srchuid[0] = '\0';
|
srchuid[0] = '\0';
|
||||||
}
|
if (export)
|
||||||
if (export) {
|
|
||||||
printf("ID_UID=%s\n", readbuf);
|
printf("ID_UID=%s\n", readbuf);
|
||||||
} else
|
else
|
||||||
printf("%s\n", readbuf);
|
printf("%s\n", readbuf);
|
||||||
if (!print_vlabel && !print_extended_uid)
|
if (!print_vlabel && !print_extended_uid)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -729,9 +667,9 @@ int main(int argc, char * argv[])
|
|||||||
|
|
||||||
if (print_extended_uid) {
|
if (print_extended_uid) {
|
||||||
if (dinfo_read_dasd_uid(uidfile, readbuf) == 0) {
|
if (dinfo_read_dasd_uid(uidfile, readbuf) == 0) {
|
||||||
if (export) {
|
if (export)
|
||||||
printf("ID_XUID=%s\n", readbuf);
|
printf("ID_XUID=%s\n", readbuf);
|
||||||
} else
|
else
|
||||||
printf("%s\n", readbuf);
|
printf("%s\n", readbuf);
|
||||||
if (!print_vlabel)
|
if (!print_vlabel)
|
||||||
goto out;
|
goto out;
|
||||||
@@ -768,15 +706,15 @@ int main(int argc, char * argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dinfo_read_dasd_vlabel(device, &vlabel, readbuf) == 0) {
|
if (dinfo_read_dasd_vlabel(device, &vlabel, readbuf) == 0) {
|
||||||
if (export) {
|
if (export)
|
||||||
printf("ID_SERIAL=%s\n",readbuf);
|
printf("ID_SERIAL=%s\n", readbuf);
|
||||||
} else
|
else
|
||||||
printf("%s\n", readbuf);
|
printf("%s\n", readbuf);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
error:
|
error:
|
||||||
printf("Error: could not read unique DASD ID\n");
|
warnx("Error: could not read unique DASD ID");
|
||||||
rc = 1;
|
rc = 1;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ all: dasdview
|
|||||||
libs = $(rootdir)/libdasd/libdasd.a \
|
libs = $(rootdir)/libdasd/libdasd.a \
|
||||||
$(rootdir)/libzds/libzds.a \
|
$(rootdir)/libzds/libzds.a \
|
||||||
$(rootdir)/libvtoc/libvtoc.a \
|
$(rootdir)/libvtoc/libvtoc.a \
|
||||||
$(rootdir)/libu2s/libu2s.a \
|
|
||||||
$(rootdir)/libutil/libutil.a
|
$(rootdir)/libutil/libutil.a
|
||||||
|
|
||||||
dasdview: dasdview.o $(libs)
|
dasdview: dasdview.o $(libs)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,145 +11,11 @@
|
|||||||
#define DASDVIEW_H
|
#define DASDVIEW_H
|
||||||
|
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "lib/u2s.h"
|
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* SECTION: Definitions needed for DASD-API (see dasd.h)
|
* SECTION: Definitions needed for DASD-API (see dasd.h)
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#define DASD_IOCTL_LETTER 'D'
|
|
||||||
|
|
||||||
/*
|
|
||||||
* struct dasd_information_t
|
|
||||||
* represents any data about the device, which is visible to userspace.
|
|
||||||
* including foramt and features.
|
|
||||||
*/
|
|
||||||
typedef struct dasd_information_t {
|
|
||||||
unsigned int devno; /* S/390 devno */
|
|
||||||
unsigned int real_devno; /* for aliases */
|
|
||||||
unsigned int schid; /* S/390 subchannel identifier */
|
|
||||||
unsigned int cu_type : 16; /* from SenseID */
|
|
||||||
unsigned int cu_model : 8; /* from SenseID */
|
|
||||||
unsigned int dev_type : 16; /* from SenseID */
|
|
||||||
unsigned int dev_model : 8; /* from SenseID */
|
|
||||||
unsigned int open_count;
|
|
||||||
unsigned int req_queue_len;
|
|
||||||
unsigned int chanq_len; /* length of chanq */
|
|
||||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
|
||||||
unsigned int status; /* current device level */
|
|
||||||
unsigned int label_block; /* where to find the VOLSER */
|
|
||||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
|
||||||
unsigned int characteristics_size;
|
|
||||||
unsigned int confdata_size;
|
|
||||||
char characteristics[64]; /* from read_device_characteristics */
|
|
||||||
char configuration_data[256]; /* from read_configuration_data */
|
|
||||||
} dasd_information_t;
|
|
||||||
|
|
||||||
typedef struct dasd_information2_t {
|
|
||||||
unsigned int devno; /* S/390 devno */
|
|
||||||
unsigned int real_devno; /* for aliases */
|
|
||||||
unsigned int schid; /* S/390 subchannel identifier */
|
|
||||||
unsigned int cu_type : 16; /* from SenseID */
|
|
||||||
unsigned int cu_model : 8; /* from SenseID */
|
|
||||||
unsigned int dev_type : 16; /* from SenseID */
|
|
||||||
unsigned int dev_model : 8; /* from SenseID */
|
|
||||||
unsigned int open_count;
|
|
||||||
unsigned int req_queue_len;
|
|
||||||
unsigned int chanq_len; /* length of chanq */
|
|
||||||
char type[4]; /* from discipline.name, 'none' for unknown */
|
|
||||||
unsigned int status; /* current device level */
|
|
||||||
unsigned int label_block; /* where to find the VOLSER */
|
|
||||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
|
||||||
unsigned int characteristics_size;
|
|
||||||
unsigned int confdata_size;
|
|
||||||
unsigned char characteristics[64];/*from read_device_characteristics */
|
|
||||||
unsigned char configuration_data[256];/*from read_configuration_data */
|
|
||||||
unsigned int format; /* format info like formatted/cdl/ldl/... */
|
|
||||||
unsigned int features; /* dasd features like 'ro',... */
|
|
||||||
unsigned int reserved0; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved1; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved2; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved3; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved4; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved5; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved6; /* reserved for further use ,... */
|
|
||||||
unsigned int reserved7; /* reserved for further use ,... */
|
|
||||||
} dasd_information2_t;
|
|
||||||
|
|
||||||
struct dasd_eckd_characteristics {
|
|
||||||
unsigned short cu_type;
|
|
||||||
struct {
|
|
||||||
unsigned char support:2;
|
|
||||||
unsigned char async:1;
|
|
||||||
unsigned char reserved:1;
|
|
||||||
unsigned char cache_info:1;
|
|
||||||
unsigned char model:3;
|
|
||||||
} __attribute__ ((packed)) cu_model;
|
|
||||||
unsigned short dev_type;
|
|
||||||
unsigned char dev_model;
|
|
||||||
struct {
|
|
||||||
unsigned char mult_burst:1;
|
|
||||||
unsigned char RT_in_LR:1;
|
|
||||||
unsigned char reserved1:1;
|
|
||||||
unsigned char RD_IN_LR:1;
|
|
||||||
unsigned char reserved2:4;
|
|
||||||
unsigned char reserved3:8;
|
|
||||||
unsigned char defect_wr:1;
|
|
||||||
unsigned char XRC_supported:1;
|
|
||||||
unsigned char reserved4:1;
|
|
||||||
unsigned char striping:1;
|
|
||||||
unsigned char reserved5:4;
|
|
||||||
unsigned char cfw:1;
|
|
||||||
unsigned char reserved6:2;
|
|
||||||
unsigned char cache:1;
|
|
||||||
unsigned char dual_copy:1;
|
|
||||||
unsigned char dfw:1;
|
|
||||||
unsigned char reset_alleg:1;
|
|
||||||
unsigned char sense_down:1;
|
|
||||||
} __attribute__ ((packed)) facilities;
|
|
||||||
unsigned char dev_class;
|
|
||||||
unsigned char unit_type;
|
|
||||||
unsigned short no_cyl;
|
|
||||||
unsigned short trk_per_cyl;
|
|
||||||
unsigned char sec_per_trk;
|
|
||||||
unsigned char byte_per_track[3];
|
|
||||||
unsigned short home_bytes;
|
|
||||||
unsigned char formula;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
unsigned char f1;
|
|
||||||
unsigned short f2;
|
|
||||||
unsigned short f3;
|
|
||||||
} __attribute__ ((packed)) f_0x01;
|
|
||||||
struct {
|
|
||||||
unsigned char f1;
|
|
||||||
unsigned char f2;
|
|
||||||
unsigned char f3;
|
|
||||||
unsigned char f4;
|
|
||||||
unsigned char f5;
|
|
||||||
} __attribute__ ((packed)) f_0x02;
|
|
||||||
} __attribute__ ((packed)) factors;
|
|
||||||
unsigned short first_alt_trk;
|
|
||||||
unsigned short no_alt_trk;
|
|
||||||
unsigned short first_dia_trk;
|
|
||||||
unsigned short no_dia_trk;
|
|
||||||
unsigned short first_sup_trk;
|
|
||||||
unsigned short no_sup_trk;
|
|
||||||
unsigned char MDR_ID;
|
|
||||||
unsigned char OBR_ID;
|
|
||||||
unsigned char director;
|
|
||||||
unsigned char rd_trk_set;
|
|
||||||
unsigned short max_rec_zero;
|
|
||||||
unsigned char reserved1;
|
|
||||||
unsigned char RWANY_in_LR;
|
|
||||||
unsigned char factor6;
|
|
||||||
unsigned char factor7;
|
|
||||||
unsigned char factor8;
|
|
||||||
unsigned char reserved2[3];
|
|
||||||
unsigned char reserved3[6];
|
|
||||||
unsigned int long_no_cyl;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* values to be used for dasd_information2_t.format
|
* values to be used for dasd_information2_t.format
|
||||||
* 0x00: NOT formatted
|
* 0x00: NOT formatted
|
||||||
@@ -170,21 +36,6 @@ struct dasd_eckd_characteristics {
|
|||||||
#define DASD_FEATURE_READONLY 1
|
#define DASD_FEATURE_READONLY 1
|
||||||
#define DASD_FEATURE_USEDIAG 2
|
#define DASD_FEATURE_USEDIAG 2
|
||||||
|
|
||||||
/* Get information on a dasd device (enhanced) */
|
|
||||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
|
|
||||||
#define BIODASDINFO2 _IOR(DASD_IOCTL_LETTER,3,dasd_information2_t)
|
|
||||||
|
|
||||||
/********************************************************************************
|
|
||||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h)
|
|
||||||
*******************************************************************************/
|
|
||||||
/* get block device sector size */
|
|
||||||
#define BLKSSZGET _IO(0x12,104)
|
|
||||||
/* return device size in bytes (u64 *arg) */
|
|
||||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t)
|
|
||||||
|
|
||||||
/* get device geometry */
|
|
||||||
#define HDIO_GETGEO 0x0301
|
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* SECTION: DASDVIEW internal types
|
* SECTION: DASDVIEW internal types
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
@@ -215,7 +66,7 @@ typedef struct dasdview_info
|
|||||||
char device[PATH_MAX];
|
char device[PATH_MAX];
|
||||||
dasd_information2_t dasd_info;
|
dasd_information2_t dasd_info;
|
||||||
int dasd_info_version;
|
int dasd_info_version;
|
||||||
int blksize;
|
unsigned int blksize;
|
||||||
struct hd_geometry geo;
|
struct hd_geometry geo;
|
||||||
u_int32_t hw_cylinders;
|
u_int32_t hw_cylinders;
|
||||||
|
|
||||||
@@ -257,7 +108,7 @@ typedef struct dasdview_info
|
|||||||
int f8c;
|
int f8c;
|
||||||
int f9c;
|
int f9c;
|
||||||
|
|
||||||
char busid[U2S_BUS_ID_SIZE];
|
char busid[DASD_BUS_ID_SIZE];
|
||||||
int busid_valid;
|
int busid_valid;
|
||||||
int raw_track_access;
|
int raw_track_access;
|
||||||
struct zdsroot *zdsroot;
|
struct zdsroot *zdsroot;
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ static void set_time(char *dest, size_t len, time_t value)
|
|||||||
#define SET_TIME_FIELD(obj, name, value) \
|
#define SET_TIME_FIELD(obj, name, value) \
|
||||||
set_time((obj)->name, sizeof((obj)->name), (time_t) (value))
|
set_time((obj)->name, sizeof((obj)->name), (time_t) (value))
|
||||||
#define SET_STR_FIELD(obj, name, value) \
|
#define SET_STR_FIELD(obj, name, value) \
|
||||||
strncpy((obj)->name, (value), sizeof((obj)->name))
|
util_strlcpy((obj)->name, (value), sizeof((obj)->name))
|
||||||
|
|
||||||
/* Initialize the tar file @header with the provided data */
|
/* Initialize the tar file @header with the provided data */
|
||||||
static void init_header(struct tar_header *header, const char *filename,
|
static void init_header(struct tar_header *header, const char *filename,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
DAEMON=cpacfstatsd
|
DAEMON=cpacfstatsd
|
||||||
DAEMON_PATH=/usr/sbin/cpacfstatsd
|
DAEMON_PATH=/usr/sbin/cpacfstatsd
|
||||||
RUN_PID_FILE=/var/run/cpacfstatsd.pid
|
RUN_PID_FILE=/run/cpacfstatsd.pid
|
||||||
RETVAL=0
|
RETVAL=0
|
||||||
OPTIONS=""
|
OPTIONS=""
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
DAEMON=cpuplugd
|
DAEMON=cpuplugd
|
||||||
DAEMON_PATH=/usr/sbin/cpuplugd
|
DAEMON_PATH=/usr/sbin/cpuplugd
|
||||||
CONFIG_FILE=/etc/cpuplugd.conf
|
CONFIG_FILE=/etc/cpuplugd.conf
|
||||||
RUN_PID_FILE=/var/run/cpuplugd.pid
|
RUN_PID_FILE=/run/cpuplugd.pid
|
||||||
RETVAL=0
|
RETVAL=0
|
||||||
OPTIONS="-c $CONFIG_FILE"
|
OPTIONS="-c $CONFIG_FILE"
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ DUMP_CONFIG_FILE=/etc/sysconfig/dumpconf
|
|||||||
CMDFULL=$0
|
CMDFULL=$0
|
||||||
CMD="dumpconf"
|
CMD="dumpconf"
|
||||||
LOCKFILE=/var/lock/$CMD
|
LOCKFILE=/var/lock/$CMD
|
||||||
PIDFILE=/var/run/$CMD.pid
|
PIDFILE=/run/$CMD.pid
|
||||||
ERRMSG="Check $DUMP_CONFIG_FILE!"
|
ERRMSG="Check $DUMP_CONFIG_FILE!"
|
||||||
|
|
||||||
RETVAL=0
|
RETVAL=0
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ PROCD=mon_procd
|
|||||||
FSSTATD_PATH=/usr/sbin/$FSSTATD
|
FSSTATD_PATH=/usr/sbin/$FSSTATD
|
||||||
PROCD_PATH=/usr/sbin/$PROCD
|
PROCD_PATH=/usr/sbin/$PROCD
|
||||||
CONFIG_FILE=/etc/sysconfig/$DAEMON
|
CONFIG_FILE=/etc/sysconfig/$DAEMON
|
||||||
FSSTATD_PID_FILE=/var/run/$FSSTATD.pid
|
FSSTATD_PID_FILE=/run/$FSSTATD.pid
|
||||||
PROCD_PID_FILE=/var/run/$PROCD.pid
|
PROCD_PID_FILE=/run/$PROCD.pid
|
||||||
|
|
||||||
# source function library
|
# source function library
|
||||||
. /lib/lsb/init-functions
|
. /lib/lsb/init-functions
|
||||||
|
|||||||
2
etc/modules-load.d/s390-pkey.conf
Normal file
2
etc/modules-load.d/s390-pkey.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Load protected key support module on s390 early at boot
|
||||||
|
pkey
|
||||||
@@ -7,7 +7,7 @@ SUBSYSTEM!="block", GOTO="ra_end"
|
|||||||
|
|
||||||
ACTION!="add", GOTO="ra_change"
|
ACTION!="add", GOTO="ra_change"
|
||||||
# on device add set initial readahead to 512 (instead of in kernel 128)
|
# on device add set initial readahead to 512 (instead of in kernel 128)
|
||||||
KERNEL=="sd*[!0-9]", WAIT_FOR="queue/read_ahead_kb", ATTR{queue/read_ahead_kb}="512"
|
KERNEL=="sd*[!0-9]", TEST=="queue/read_ahead_kb", ATTR{queue/read_ahead_kb}="512"
|
||||||
|
|
||||||
LABEL="ra_change"
|
LABEL="ra_change"
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ include ../common.mak
|
|||||||
libs = $(rootdir)/libvtoc/libvtoc.a \
|
libs = $(rootdir)/libvtoc/libvtoc.a \
|
||||||
$(rootdir)/libzds/libzds.a \
|
$(rootdir)/libzds/libzds.a \
|
||||||
$(rootdir)/libdasd/libdasd.a \
|
$(rootdir)/libdasd/libdasd.a \
|
||||||
$(rootdir)/libu2s/libu2s.a \
|
|
||||||
$(rootdir)/libutil/libutil.a
|
$(rootdir)/libutil/libutil.a
|
||||||
|
|
||||||
all: fdasd
|
all: fdasd
|
||||||
|
|||||||
162
fdasd/fdasd.c
162
fdasd/fdasd.c
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* fdasd - Create or modify partitions on ECKD DASDs
|
* fdasd - Create or modify partitions on ECKD DASDs
|
||||||
*
|
*
|
||||||
* Copyright IBM Corp. 2001, 2017
|
* Copyright IBM Corp. 2001, 2018
|
||||||
*
|
*
|
||||||
* 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.
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/sysmacros.h>
|
#include <sys/sysmacros.h>
|
||||||
|
|
||||||
|
#include "lib/dasd_base.h"
|
||||||
#include "lib/dasd_sys.h"
|
#include "lib/dasd_sys.h"
|
||||||
#include "lib/util_base.h"
|
#include "lib/util_base.h"
|
||||||
#include "lib/util_opt.h"
|
#include "lib/util_opt.h"
|
||||||
@@ -74,7 +75,7 @@ static int get_part_name_by_dsname(char *dsname, char **name)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < UTIL_ARRAY_SIZE(partition_types); i++) {
|
for (i = 0; i < ARRAY_SIZE(partition_types); i++) {
|
||||||
if (strstr(dsname, partition_types[i].dsname) != NULL) {
|
if (strstr(dsname, partition_types[i].dsname) != NULL) {
|
||||||
*name = partition_types[i].name;
|
*name = partition_types[i].name;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -96,7 +97,7 @@ static int get_part_type_by_dsname(char *dsname, int *type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < UTIL_ARRAY_SIZE(partition_types); i++) {
|
for (i = 0; i < ARRAY_SIZE(partition_types); i++) {
|
||||||
if (strstr(dsname, partition_types[i].dsname) != NULL) {
|
if (strstr(dsname, partition_types[i].dsname) != NULL) {
|
||||||
*type = partition_types[i].type;
|
*type = partition_types[i].type;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -111,7 +112,7 @@ static int get_part_type_by_dsname(char *dsname, int *type)
|
|||||||
*/
|
*/
|
||||||
static int get_part_dsname_by_type(unsigned int type, char **dsname)
|
static int get_part_dsname_by_type(unsigned int type, char **dsname)
|
||||||
{
|
{
|
||||||
if (type > UTIL_ARRAY_SIZE(partition_types))
|
if (type > ARRAY_SIZE(partition_types))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (type == 0)
|
if (type == 0)
|
||||||
@@ -220,8 +221,7 @@ static u_int32_t get_usable_cylinders(fdasd_anchor_t *anc)
|
|||||||
return anc->f4->DS4DCYL;
|
return anc->f4->DS4DCYL;
|
||||||
/* normal volume */
|
/* normal volume */
|
||||||
if (anc->f4->DS4DEVCT.DS4DEVFG & ALTERNATE_CYLINDERS_USED)
|
if (anc->f4->DS4DEVCT.DS4DEVFG & ALTERNATE_CYLINDERS_USED)
|
||||||
cyl = anc->f4->DS4DEVCT.DS4DSCYL -
|
cyl = anc->f4->DS4DEVCT.DS4DSCYL - (u_int16_t)anc->f4->DS4DEVAC;
|
||||||
(u_int16_t) anc->f4->DS4DEVAC;
|
|
||||||
else
|
else
|
||||||
cyl = anc->f4->DS4DEVCT.DS4DSCYL;
|
cyl = anc->f4->DS4DEVCT.DS4DSCYL;
|
||||||
|
|
||||||
@@ -230,9 +230,8 @@ static u_int32_t get_usable_cylinders(fdasd_anchor_t *anc)
|
|||||||
|
|
||||||
static void get_addr_of_highest_f1_f8_label(fdasd_anchor_t *anc, cchhb_t *addr)
|
static void get_addr_of_highest_f1_f8_label(fdasd_anchor_t *anc, cchhb_t *addr)
|
||||||
{
|
{
|
||||||
|
|
||||||
u_int8_t record;
|
u_int8_t record;
|
||||||
/* We have to count the follwing labels:
|
/* We have to count the following labels:
|
||||||
* one format 4
|
* one format 4
|
||||||
* one format 5
|
* one format 5
|
||||||
* format 7 only if we have moren then BIG_DISK_SIZE tracks
|
* format 7 only if we have moren then BIG_DISK_SIZE tracks
|
||||||
@@ -259,7 +258,7 @@ static void fdasd_check_volser(char *volser, int devno)
|
|||||||
{
|
{
|
||||||
int from, to;
|
int from, to;
|
||||||
|
|
||||||
for (from = 0, to = 0; volser[from] && from < VOLSER_LENGTH; from++)
|
for (from = 0, to = 0; from < VOLSER_LENGTH && volser[from]; from++)
|
||||||
if ((volser[from] >= 0x23 &&
|
if ((volser[from] >= 0x23 &&
|
||||||
volser[from] <= 0x25) || /* # $ % */
|
volser[from] <= 0x25) || /* # $ % */
|
||||||
(volser[from] >= 0x30 &&
|
(volser[from] >= 0x30 &&
|
||||||
@@ -398,7 +397,7 @@ static void fdasd_error(fdasd_anchor_t *anc, enum fdasd_failure why, char *str)
|
|||||||
fputc('\n', stderr);
|
fputc('\n', stderr);
|
||||||
fputs(err_str, stderr);
|
fputs(err_str, stderr);
|
||||||
|
|
||||||
fdasd_exit(anc, -1);
|
fdasd_exit(anc, EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -728,9 +727,9 @@ static int fdasd_parse_conffile(fdasd_anchor_t *anc,
|
|||||||
|
|
||||||
memset(buffer, 0, sizeof(buffer));
|
memset(buffer, 0, sizeof(buffer));
|
||||||
rc = read(fd, buffer, sizeof(buffer) - 1);
|
rc = read(fd, buffer, sizeof(buffer) - 1);
|
||||||
|
close(fd);
|
||||||
if (rc < 0)
|
if (rc < 0)
|
||||||
return -1;
|
return -1;
|
||||||
close(fd);
|
|
||||||
|
|
||||||
for (i = 0; i < rc; i++)
|
for (i = 0; i < rc; i++)
|
||||||
buffer[i] = toupper(buffer[i]);
|
buffer[i] = toupper(buffer[i]);
|
||||||
@@ -769,7 +768,7 @@ static int fdasd_parse_conffile(fdasd_anchor_t *anc,
|
|||||||
} else {
|
} else {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
anc->confdata[i].start = strtol(token[0],
|
anc->confdata[i].start = strtol(token[0],
|
||||||
(char **) NULL, 10);
|
(char **)NULL, 10);
|
||||||
if (errno != 0 || anc->confdata[i].start == 0) {
|
if (errno != 0 || anc->confdata[i].start == 0) {
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
snprintf(err_str, ERROR_STRING_SIZE,
|
||||||
"invalid partition start in config "
|
"invalid partition start in config "
|
||||||
@@ -784,7 +783,7 @@ static int fdasd_parse_conffile(fdasd_anchor_t *anc,
|
|||||||
} else {
|
} else {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
anc->confdata[i].stop = strtol(token[1],
|
anc->confdata[i].stop = strtol(token[1],
|
||||||
(char **) NULL, 10);
|
(char **)NULL, 10);
|
||||||
if (errno != 0 || anc->confdata[i].stop == 0) {
|
if (errno != 0 || anc->confdata[i].stop == 0) {
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
snprintf(err_str, ERROR_STRING_SIZE,
|
||||||
"invalid partition end in config "
|
"invalid partition end in config "
|
||||||
@@ -884,9 +883,9 @@ static void fdasd_check_conffile_input(fdasd_anchor_t *anc,
|
|||||||
anc->fspace_trk = start - FIRST_USABLE_TRK;
|
anc->fspace_trk = start - FIRST_USABLE_TRK;
|
||||||
|
|
||||||
if (i < USABLE_PARTITIONS - 1) {
|
if (i < USABLE_PARTITIONS - 1) {
|
||||||
if (anc->confdata[i+1].start != 0)
|
if (anc->confdata[i + 1].start != 0)
|
||||||
part_info->fspace_trk =
|
part_info->fspace_trk =
|
||||||
anc->confdata[i+1].start-stop-1;
|
anc->confdata[i + 1].start - stop - 1;
|
||||||
else
|
else
|
||||||
part_info->fspace_trk = last_trk - stop;
|
part_info->fspace_trk = last_trk - stop;
|
||||||
} else if (i == USABLE_PARTITIONS - 1) {
|
} else if (i == USABLE_PARTITIONS - 1) {
|
||||||
@@ -916,8 +915,8 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
|||||||
if (!S_ISBLK(dst.st_mode)) {
|
if (!S_ISBLK(dst.st_mode)) {
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
snprintf(err_str, ERROR_STRING_SIZE,
|
||||||
"Device '%s' (%d/%d) is not a block device\n", name,
|
"Device '%s' (%d/%d) is not a block device\n", name,
|
||||||
(unsigned short) major(dst.st_rdev),
|
(unsigned short)major(dst.st_rdev),
|
||||||
(unsigned short) minor(dst.st_rdev));
|
(unsigned short)minor(dst.st_rdev));
|
||||||
fdasd_error(anc, device_verification_failed, err_str);
|
fdasd_error(anc, device_verification_failed, err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -925,8 +924,8 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
|||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
snprintf(err_str, ERROR_STRING_SIZE,
|
||||||
"Partition '%s' (%d/%d) detected where device is "
|
"Partition '%s' (%d/%d) detected where device is "
|
||||||
"required\n", name,
|
"required\n", name,
|
||||||
(unsigned short) major(dst.st_rdev),
|
(unsigned short)major(dst.st_rdev),
|
||||||
(unsigned short) minor(dst.st_rdev));
|
(unsigned short)minor(dst.st_rdev));
|
||||||
fdasd_error(anc, device_verification_failed, err_str);
|
fdasd_error(anc, device_verification_failed, err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -936,7 +935,7 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
|||||||
fdasd_error(anc, device_verification_failed, err_str);
|
fdasd_error(anc, device_verification_failed, err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
count = u2s_get_host_access_count(name);
|
count = dasd_get_host_access_count(name);
|
||||||
if (anc->force_host) {
|
if (anc->force_host) {
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
snprintf(err_str, ERROR_STRING_SIZE,
|
||||||
@@ -962,8 +961,8 @@ static void fdasd_verify_device(fdasd_anchor_t *anc, char *name)
|
|||||||
|
|
||||||
if (anc->verbose) {
|
if (anc->verbose) {
|
||||||
printf("Verification successful for '%s' (%d/%d)\n", name,
|
printf("Verification successful for '%s' (%d/%d)\n", name,
|
||||||
(unsigned short) major(dst.st_rdev),
|
(unsigned short)major(dst.st_rdev),
|
||||||
(unsigned short) minor(dst.st_rdev));
|
(unsigned short)minor(dst.st_rdev));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,15 +1027,13 @@ static void fdasd_verify_options(fdasd_anchor_t *anc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anc->auto_partition &&
|
if (anc->auto_partition && (options.conffile || anc->print_table)) {
|
||||||
(options.conffile || anc->print_table)) {
|
|
||||||
fdasd_error(anc, parser_failed,
|
fdasd_error(anc, parser_failed,
|
||||||
"Option 'auto' cannot be used with "
|
"Option 'auto' cannot be used with "
|
||||||
"'config' and 'table'.\n");
|
"'config' and 'table'.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.conffile &&
|
if (options.conffile && anc->print_table) {
|
||||||
(anc->print_table)) {
|
|
||||||
fdasd_error(anc, parser_failed,
|
fdasd_error(anc, parser_failed,
|
||||||
"Option 'config' cannot be used with"
|
"Option 'config' cannot be used with"
|
||||||
" 'table'.\n");
|
" 'table'.\n");
|
||||||
@@ -1208,7 +1205,7 @@ static void fdasd_list_known_partitions(void)
|
|||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = VALID_PARTITION_OFFSET;
|
for (i = VALID_PARTITION_OFFSET;
|
||||||
i < UTIL_ARRAY_SIZE(partition_types); i++) {
|
i < ARRAY_SIZE(partition_types); i++) {
|
||||||
printf("%3d %s\n",
|
printf("%3d %s\n",
|
||||||
partition_types[i].type, partition_types[i].name);
|
partition_types[i].type, partition_types[i].name);
|
||||||
}
|
}
|
||||||
@@ -1232,26 +1229,13 @@ static int fdasd_get_volser(fdasd_anchor_t *anc, char *volser)
|
|||||||
*/
|
*/
|
||||||
static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
|
static void fdasd_reread_partition_table(fdasd_anchor_t *anc)
|
||||||
{
|
{
|
||||||
char err_str[ERROR_STRING_SIZE];
|
|
||||||
int fd;
|
|
||||||
|
|
||||||
if (!anc->silent)
|
if (!anc->silent)
|
||||||
printf("rereading partition table...\n");
|
printf("rereading partition table...\n");
|
||||||
|
|
||||||
fd = open(options.device, O_RDONLY);
|
if (dasd_reread_partition_table(options.device, 1) != 0) {
|
||||||
if (fd < 0) {
|
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
|
||||||
"Could not open device '%s' "
|
|
||||||
"in read-only mode!\n", options.device);
|
|
||||||
fdasd_error(anc, unable_to_open_disk, err_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ioctl(fd, BLKRRPART, NULL) != 0) {
|
|
||||||
close(fd);
|
|
||||||
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
|
fdasd_error(anc, unable_to_ioctl, "Error while rereading "
|
||||||
"partition table.\nPlease reboot!");
|
"partition table.\nPlease reboot!");
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1273,7 +1257,7 @@ static void fdasd_write_vtoc_labels(fdasd_anchor_t *anc)
|
|||||||
printf("DSCBs: ");
|
printf("DSCBs: ");
|
||||||
|
|
||||||
blk = (cchhb2blk(&anc->vlabel->vtoc, &geo) - 1) * anc->blksize;
|
blk = (cchhb2blk(&anc->vlabel->vtoc, &geo) - 1) * anc->blksize;
|
||||||
if (blk <= 0)
|
if (cchhb2blk(&anc->vlabel->vtoc, &geo) == 0 || blk == 0)
|
||||||
fdasd_error(anc, vlabel_corrupted, "");
|
fdasd_error(anc, vlabel_corrupted, "");
|
||||||
maxblk = blk + anc->blksize * 9; /* f4+f5+f7+3*f8+3*f9 */
|
maxblk = blk + anc->blksize * 9; /* f4+f5+f7+3*f8+3*f9 */
|
||||||
|
|
||||||
@@ -1326,7 +1310,7 @@ static void fdasd_write_vtoc_labels(fdasd_anchor_t *anc)
|
|||||||
volser[VOLSER_LENGTH] = ' ';
|
volser[VOLSER_LENGTH] = ' ';
|
||||||
strncpy(c1, volser, VOLSER_LENGTH + 1);
|
strncpy(c1, volser, VOLSER_LENGTH + 1);
|
||||||
c1 = strchr(ch, ' ');
|
c1 = strchr(ch, ' ');
|
||||||
strncpy(c1, s2, 31);
|
memcpy(c1, s2, 31);
|
||||||
} else {
|
} else {
|
||||||
if (get_part_type_by_dsname(ch, &part_info->type))
|
if (get_part_type_by_dsname(ch, &part_info->type))
|
||||||
part_info->type = PARTITION_NATIVE;
|
part_info->type = PARTITION_NATIVE;
|
||||||
@@ -1335,25 +1319,25 @@ static void fdasd_write_vtoc_labels(fdasd_anchor_t *anc)
|
|||||||
while (getpos(anc, k) > -1)
|
while (getpos(anc, k) > -1)
|
||||||
k++;
|
k++;
|
||||||
|
|
||||||
setpos(anc, k, i-1);
|
setpos(anc, k, i - 1);
|
||||||
|
|
||||||
strncpy(ch, "LINUX.V "
|
memcpy(ch, "LINUX.V "
|
||||||
" ", 44);
|
" ", 44);
|
||||||
|
|
||||||
strncpy(volser, anc->vlabel->volid, VOLSER_LENGTH);
|
strncpy(volser, anc->vlabel->volid, VOLSER_LENGTH);
|
||||||
vtoc_ebcdic_dec(volser, volser, VOLSER_LENGTH);
|
vtoc_ebcdic_dec(volser, volser, VOLSER_LENGTH);
|
||||||
strncpy(c1, volser, VOLSER_LENGTH);
|
memcpy(c1, volser, VOLSER_LENGTH);
|
||||||
|
|
||||||
c1 = strchr(ch, ' ');
|
c1 = strchr(ch, ' ');
|
||||||
strncpy(c1, ".PART", 5);
|
memcpy(c1, ".PART", 5);
|
||||||
c1 += 5;
|
c1 += 5;
|
||||||
|
|
||||||
sprintf(dsno, "%04d.", k + 1);
|
sprintf(dsno, "%04d.", k + 1);
|
||||||
strncpy(c1, dsno, 5);
|
memcpy(c1, dsno, 5);
|
||||||
c1 += 5;
|
c1 += 5;
|
||||||
|
|
||||||
get_part_dsname_by_type(part_info->type, &dsname);
|
get_part_dsname_by_type(part_info->type, &dsname);
|
||||||
strncpy(c1, dsname, strlen(dsname)); /* We don't want \0 */
|
memcpy(c1, dsname, strlen(dsname)); /* We don't want \0 */
|
||||||
}
|
}
|
||||||
vtoc_ebcdic_enc(ch, ch, 44);
|
vtoc_ebcdic_enc(ch, ch, 44);
|
||||||
if (anc->verbose)
|
if (anc->verbose)
|
||||||
@@ -1414,7 +1398,7 @@ static void fdasd_write_labels(fdasd_anchor_t *anc)
|
|||||||
if (anc->vtoc_changed)
|
if (anc->vtoc_changed)
|
||||||
fdasd_write_vtoc_labels(anc);
|
fdasd_write_vtoc_labels(anc);
|
||||||
|
|
||||||
if ((anc->vtoc_changed) || (anc->vlabel_changed))
|
if (anc->vtoc_changed || anc->vlabel_changed)
|
||||||
fdasd_reread_partition_table(anc);
|
fdasd_reread_partition_table(anc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1500,9 +1484,9 @@ static void fdasd_reuse_vtoc(fdasd_anchor_t *anc)
|
|||||||
|
|
||||||
if (!anc->silent) {
|
if (!anc->silent) {
|
||||||
snprintf(str, INPUT_BUF_SIZE,
|
snprintf(str, INPUT_BUF_SIZE,
|
||||||
"WARNING: this will re-create your VTOC "
|
"WARNING: this will re-create your VTOC "
|
||||||
"entries using the partition\n "
|
"entries using the partition\n "
|
||||||
"information of your existing VTOC. Continue?");
|
"information of your existing VTOC. Continue?");
|
||||||
|
|
||||||
if (yes_no(str) != 0)
|
if (yes_no(str) != 0)
|
||||||
return;
|
return;
|
||||||
@@ -1637,9 +1621,11 @@ static void fdasd_change_part_type(fdasd_anchor_t *anc)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
part_type = 0;
|
part_type = 0;
|
||||||
while (part_type < 1 || part_type > UTIL_ARRAY_SIZE(partition_types) - 1) {
|
while (part_type < 1 ||
|
||||||
while (!isdigit(part_type =
|
part_type > ARRAY_SIZE(partition_types) - 1) {
|
||||||
read_char("new partition type: ")));
|
do {
|
||||||
|
part_type = read_char("new partition type: ");
|
||||||
|
} while (!isdigit(part_type));
|
||||||
part_type -= 48;
|
part_type -= 48;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1650,7 +1636,7 @@ static void fdasd_change_part_type(fdasd_anchor_t *anc)
|
|||||||
|
|
||||||
ch = strstr(part_info->f1->DS1DSNAM, "PART") + 9;
|
ch = strstr(part_info->f1->DS1DSNAM, "PART") + 9;
|
||||||
if (ch != NULL)
|
if (ch != NULL)
|
||||||
strncpy(ch, str, 6);
|
memcpy(ch, str, 6);
|
||||||
vtoc_ebcdic_enc(part_info->f1->DS1DSNAM, part_info->f1->DS1DSNAM, 44);
|
vtoc_ebcdic_enc(part_info->f1->DS1DSNAM, part_info->f1->DS1DSNAM, 44);
|
||||||
anc->vtoc_changed++;
|
anc->vtoc_changed++;
|
||||||
}
|
}
|
||||||
@@ -2008,7 +1994,7 @@ static int fdasd_check_volume(fdasd_anchor_t *anc)
|
|||||||
printf(" VOL1\n");
|
printf(" VOL1\n");
|
||||||
|
|
||||||
blk = (cchhb2blk(&vlabel->vtoc, &geo) - 1) * anc->blksize;
|
blk = (cchhb2blk(&vlabel->vtoc, &geo) - 1) * anc->blksize;
|
||||||
if (blk > 0) {
|
if (cchhb2blk(&vlabel->vtoc, &geo) > 0 && blk > 0) {
|
||||||
rc = fdasd_valid_vtoc_pointer(anc, blk);
|
rc = fdasd_valid_vtoc_pointer(anc, blk);
|
||||||
|
|
||||||
if (anc->print_table && (rc < 0))
|
if (anc->print_table && (rc < 0))
|
||||||
@@ -2094,7 +2080,8 @@ static void fdasd_check_disk_access(fdasd_anchor_t *anc)
|
|||||||
{
|
{
|
||||||
char err_str[ERROR_STRING_SIZE];
|
char err_str[ERROR_STRING_SIZE];
|
||||||
format1_label_t f1;
|
format1_label_t f1;
|
||||||
int fd, pos, ro;
|
int fd, pos;
|
||||||
|
bool ro;
|
||||||
|
|
||||||
fd = open(options.device, O_RDONLY);
|
fd = open(options.device, O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
@@ -2127,7 +2114,9 @@ static void fdasd_check_disk_access(fdasd_anchor_t *anc)
|
|||||||
fdasd_error(anc, unable_to_seek_disk, err_str);
|
fdasd_error(anc, unable_to_seek_disk, err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, BLKROGET, &ro) != 0) {
|
close(fd);
|
||||||
|
|
||||||
|
if (dasd_is_ro(options.device, &ro) != 0) {
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
snprintf(err_str, ERROR_STRING_SIZE,
|
||||||
"Could not get read-only status for device '%s'.",
|
"Could not get read-only status for device '%s'.",
|
||||||
options.device);
|
options.device);
|
||||||
@@ -2138,8 +2127,6 @@ static void fdasd_check_disk_access(fdasd_anchor_t *anc)
|
|||||||
"You will not be able to save any changes.\n\n",
|
"You will not be able to save any changes.\n\n",
|
||||||
options.device);
|
options.device);
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2171,16 +2158,18 @@ static unsigned int recs_per_track(unsigned short dev_type, unsigned int kl,
|
|||||||
kn = ceil_quot(kl + 6, 232) + 1;
|
kn = ceil_quot(kl + 6, 232) + 1;
|
||||||
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
|
return 1729 / (10 + 9 + ceil_quot(kl + 6 * kn, 34) +
|
||||||
9 + ceil_quot(dl + 6 * dn, 34));
|
9 + ceil_quot(dl + 6 * dn, 34));
|
||||||
} else
|
} else {
|
||||||
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
|
return 1729 / (10 + 9 + ceil_quot(dl + 6 * dn, 34));
|
||||||
|
}
|
||||||
case DASD_9345_TYPE:
|
case DASD_9345_TYPE:
|
||||||
dn = ceil_quot(dl + 6, 232) + 1;
|
dn = ceil_quot(dl + 6, 232) + 1;
|
||||||
if (kl) {
|
if (kl) {
|
||||||
kn = ceil_quot(kl + 6, 232) + 1;
|
kn = ceil_quot(kl + 6, 232) + 1;
|
||||||
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
|
return 1420 / (18 + 7 + ceil_quot(kl + 6 * kn, 34) +
|
||||||
ceil_quot(dl + 6 * dn, 34));
|
ceil_quot(dl + 6 * dn, 34));
|
||||||
} else
|
} else {
|
||||||
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
|
return 1420 / (18 + 7 + ceil_quot(dl + 6 * dn, 34));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2214,21 +2203,12 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
|||||||
struct dasd_eckd_characteristics *characteristics;
|
struct dasd_eckd_characteristics *characteristics;
|
||||||
unsigned long long size_in_bytes;
|
unsigned long long size_in_bytes;
|
||||||
char err_str[ERROR_STRING_SIZE];
|
char err_str[ERROR_STRING_SIZE];
|
||||||
dasd_information_t dasd_info;
|
dasd_information2_t dasd_info;
|
||||||
int fd, blksize = 0;
|
unsigned int blksize = 0;
|
||||||
|
|
||||||
fd = open(options.device, O_RDONLY);
|
if (dasd_get_blocksize_in_bytes(options.device, &size_in_bytes) != 0)
|
||||||
if (fd < 0) {
|
|
||||||
snprintf(err_str, ERROR_STRING_SIZE,
|
|
||||||
"Could not open device '%s' "
|
|
||||||
"in read-only mode!\n", options.device);
|
|
||||||
fdasd_error(anc, unable_to_open_disk, err_str);
|
|
||||||
}
|
|
||||||
if (ioctl(fd, BLKGETSIZE64, &size_in_bytes) != 0) {
|
|
||||||
close(fd);
|
|
||||||
fdasd_error(anc, unable_to_ioctl,
|
fdasd_error(anc, unable_to_ioctl,
|
||||||
"Could not retrieve disk size.");
|
"Could not retrieve disk size.");
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
* If anc->force_virtual is set, we do no real geometry detection.
|
* If anc->force_virtual is set, we do no real geometry detection.
|
||||||
* anc->dev_type and anc->blksize have already been set via command
|
* anc->dev_type and anc->blksize have already been set via command
|
||||||
@@ -2247,7 +2227,6 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
|||||||
geo.start = 0;
|
geo.start = 0;
|
||||||
anc->label_pos = 2 * anc->blksize;
|
anc->label_pos = 2 * anc->blksize;
|
||||||
anc->devno = 0;
|
anc->devno = 0;
|
||||||
close(fd);
|
|
||||||
if (anc->verbose) {
|
if (anc->verbose) {
|
||||||
printf("The force option is active. "
|
printf("The force option is active. "
|
||||||
"The following geometry will be used:\n"
|
"The following geometry will be used:\n"
|
||||||
@@ -2259,24 +2238,21 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ioctl(fd, HDIO_GETGEO, &geo) != 0) {
|
if (dasd_get_geo(options.device, &geo) != 0) {
|
||||||
close(fd);
|
|
||||||
fdasd_error(anc, unable_to_ioctl,
|
fdasd_error(anc, unable_to_ioctl,
|
||||||
"Could not retrieve disk geometry information.");
|
"Could not retrieve disk geometry information.");
|
||||||
}
|
}
|
||||||
if (ioctl(fd, BLKSSZGET, &blksize) != 0) {
|
if (dasd_get_blocksize(options.device, &blksize) != 0) {
|
||||||
close(fd);
|
|
||||||
fdasd_error(anc, unable_to_ioctl,
|
fdasd_error(anc, unable_to_ioctl,
|
||||||
"Could not retrieve blocksize information.");
|
"Could not retrieve blocksize information.");
|
||||||
}
|
}
|
||||||
/* get disk type */
|
/* get disk type */
|
||||||
if (ioctl(fd, BIODASDINFO, &dasd_info) != 0) {
|
if (dasd_get_info(options.device, &dasd_info) != 0) {
|
||||||
if (anc->verbose)
|
if (anc->verbose)
|
||||||
printf("BIODASDINFO ioctl failed,"
|
printf("BIODASDINFO ioctl failed,"
|
||||||
" use disk geometry only.\n");
|
" use disk geometry only.\n");
|
||||||
/* verify that the geometry matches a 3390 DASD */
|
/* verify that the geometry matches a 3390 DASD */
|
||||||
if (!fdasd_verify_geometry(DASD_3390_TYPE, blksize, &geo)) {
|
if (!fdasd_verify_geometry(DASD_3390_TYPE, blksize, &geo)) {
|
||||||
close(fd);
|
|
||||||
fdasd_error(anc, wrong_disk_type,
|
fdasd_error(anc, wrong_disk_type,
|
||||||
"Disk geometry does not match a DASD device"
|
"Disk geometry does not match a DASD device"
|
||||||
" of type 3390.");
|
" of type 3390.");
|
||||||
@@ -2356,8 +2332,6 @@ static void fdasd_get_geometry(fdasd_anchor_t *anc)
|
|||||||
anc->label_pos = dasd_info.label_block * blksize;
|
anc->label_pos = dasd_info.label_block * blksize;
|
||||||
anc->devno = dasd_info.devno;
|
anc->devno = dasd_info.devno;
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2384,10 +2358,8 @@ fdasd_read_int(unsigned long low, unsigned long dflt, unsigned long high,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
while (!isdigit(read_char(msg_txt))
|
while (!isdigit(read_char(msg_txt)) &&
|
||||||
&& (*line_ptr != '-' &&
|
(*line_ptr != '-' && *line_ptr != '+' && *line_ptr != '\0'))
|
||||||
*line_ptr != '+' &&
|
|
||||||
*line_ptr != '\0'))
|
|
||||||
continue;
|
continue;
|
||||||
if ((*line_ptr == '+' || *line_ptr == '-') && base != lower) {
|
if ((*line_ptr == '+' || *line_ptr == '-') && base != lower) {
|
||||||
if (*line_ptr == '+')
|
if (*line_ptr == '+')
|
||||||
@@ -2411,13 +2383,13 @@ fdasd_read_int(unsigned long low, unsigned long dflt, unsigned long high,
|
|||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
case 'M':
|
case 'M':
|
||||||
trk *= (1024*1024);
|
trk *= (1024 * 1024);
|
||||||
trk /= anc->blksize;
|
trk /= anc->blksize;
|
||||||
trk /= geo.sectors;
|
trk /= geo.sectors;
|
||||||
break;
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
case 'G':
|
case 'G':
|
||||||
trk *= (1024*1024*1024);
|
trk *= (1024 * 1024 * 1024);
|
||||||
trk /= anc->blksize;
|
trk /= anc->blksize;
|
||||||
trk /= geo.sectors;
|
trk /= geo.sectors;
|
||||||
break;
|
break;
|
||||||
@@ -2546,7 +2518,6 @@ static int fdasd_get_partition_data(fdasd_anchor_t *anc, extent_t *part_extent,
|
|||||||
limit = part_tmp->start_trk - 1;
|
limit = part_tmp->start_trk - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start == limit) {
|
if (start == limit) {
|
||||||
@@ -2642,7 +2613,7 @@ static void fdasd_enqueue_new_partition(fdasd_anchor_t *anc)
|
|||||||
FIRST_USABLE_TRK;
|
FIRST_USABLE_TRK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* there are partitons in front of the new one */
|
/* there are partitions in front of the new one */
|
||||||
if (part_info->start_trk == part_info->prev->end_trk + 1) {
|
if (part_info->start_trk == part_info->prev->end_trk + 1) {
|
||||||
/* new partition is right behind the previous one */
|
/* new partition is right behind the previous one */
|
||||||
part_info->fspace_trk = part_info->prev->fspace_trk -
|
part_info->fspace_trk = part_info->prev->fspace_trk -
|
||||||
@@ -2797,7 +2768,7 @@ static void fdasd_remove_partition(fdasd_anchor_t *anc)
|
|||||||
/*
|
/*
|
||||||
* writes a standard volume label and a standard VTOC with
|
* writes a standard volume label and a standard VTOC with
|
||||||
* only one partition to disc. With this function is it
|
* only one partition to disc. With this function is it
|
||||||
* possible to create one partiton in non-interactive mode,
|
* possible to create one partition in non-interactive mode,
|
||||||
* which can be used within shell scripts
|
* which can be used within shell scripts
|
||||||
*/
|
*/
|
||||||
static void fdasd_auto_partition(fdasd_anchor_t *anc)
|
static void fdasd_auto_partition(fdasd_anchor_t *anc)
|
||||||
@@ -3067,8 +3038,7 @@ int main(int argc, char *argv[])
|
|||||||
fdasd_recreate_vtoc(&anchor);
|
fdasd_recreate_vtoc(&anchor);
|
||||||
anchor.option_recreate = 0;
|
anchor.option_recreate = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|||||||
117
fdasd/fdasd.h
117
fdasd/fdasd.h
@@ -14,125 +14,8 @@
|
|||||||
* SECTION: Definitions needed for DASD-API (see dasd.h) *
|
* SECTION: Definitions needed for DASD-API (see dasd.h) *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
#define DASD_IOCTL_LETTER 'D'
|
|
||||||
|
|
||||||
#define DASD_PARTN_BITS 2
|
#define DASD_PARTN_BITS 2
|
||||||
|
|
||||||
/*
|
|
||||||
* struct dasd_information_t
|
|
||||||
* represents any data about the device, which is visible to userspace.
|
|
||||||
* including foramt and featueres.
|
|
||||||
*/
|
|
||||||
typedef struct dasd_information_t {
|
|
||||||
unsigned int devno; /* S/390 devno */
|
|
||||||
unsigned int real_devno; /* for aliases */
|
|
||||||
unsigned int schid; /* S/390 subchannel identifier */
|
|
||||||
unsigned int cu_type : 16; /* from SenseID */
|
|
||||||
unsigned int cu_model : 8; /* from SenseID */
|
|
||||||
unsigned int dev_type : 16; /* from SenseID */
|
|
||||||
unsigned int dev_model : 8; /* from SenseID */
|
|
||||||
unsigned int open_count;
|
|
||||||
unsigned int req_queue_len;
|
|
||||||
unsigned int chanq_len; /* length of chanq */
|
|
||||||
char type[4]; /* from discipline.name, 'none' for */
|
|
||||||
/* unknown */
|
|
||||||
unsigned int status; /* current device level */
|
|
||||||
unsigned int label_block; /* where to find the VOLSER */
|
|
||||||
unsigned int FBA_layout; /* fixed block size (like AIXVOL) */
|
|
||||||
unsigned int characteristics_size;
|
|
||||||
unsigned int confdata_size;
|
|
||||||
char characteristics[64]; /* from read_device_characteristics */
|
|
||||||
char configuration_data[256]; /* from read_configuration_data */
|
|
||||||
} dasd_information_t;
|
|
||||||
|
|
||||||
struct dasd_eckd_characteristics {
|
|
||||||
unsigned short cu_type;
|
|
||||||
struct {
|
|
||||||
unsigned char support:2;
|
|
||||||
unsigned char async:1;
|
|
||||||
unsigned char reserved:1;
|
|
||||||
unsigned char cache_info:1;
|
|
||||||
unsigned char model:3;
|
|
||||||
} __attribute__ ((packed)) cu_model;
|
|
||||||
unsigned short dev_type;
|
|
||||||
unsigned char dev_model;
|
|
||||||
struct {
|
|
||||||
unsigned char mult_burst:1;
|
|
||||||
unsigned char RT_in_LR:1;
|
|
||||||
unsigned char reserved1:1;
|
|
||||||
unsigned char RD_IN_LR:1;
|
|
||||||
unsigned char reserved2:4;
|
|
||||||
unsigned char reserved3:8;
|
|
||||||
unsigned char defect_wr:1;
|
|
||||||
unsigned char XRC_supported:1;
|
|
||||||
unsigned char reserved4:1;
|
|
||||||
unsigned char striping:1;
|
|
||||||
unsigned char reserved5:4;
|
|
||||||
unsigned char cfw:1;
|
|
||||||
unsigned char reserved6:2;
|
|
||||||
unsigned char cache:1;
|
|
||||||
unsigned char dual_copy:1;
|
|
||||||
unsigned char dfw:1;
|
|
||||||
unsigned char reset_alleg:1;
|
|
||||||
unsigned char sense_down:1;
|
|
||||||
} __attribute__ ((packed)) facilities;
|
|
||||||
unsigned char dev_class;
|
|
||||||
unsigned char unit_type;
|
|
||||||
unsigned short no_cyl;
|
|
||||||
unsigned short trk_per_cyl;
|
|
||||||
unsigned char sec_per_trk;
|
|
||||||
unsigned char byte_per_track[3];
|
|
||||||
unsigned short home_bytes;
|
|
||||||
unsigned char formula;
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
unsigned char f1;
|
|
||||||
unsigned short f2;
|
|
||||||
unsigned short f3;
|
|
||||||
} __attribute__ ((packed)) f_0x01;
|
|
||||||
struct {
|
|
||||||
unsigned char f1;
|
|
||||||
unsigned char f2;
|
|
||||||
unsigned char f3;
|
|
||||||
unsigned char f4;
|
|
||||||
unsigned char f5;
|
|
||||||
} __attribute__ ((packed)) f_0x02;
|
|
||||||
} __attribute__ ((packed)) factors;
|
|
||||||
unsigned short first_alt_trk;
|
|
||||||
unsigned short no_alt_trk;
|
|
||||||
unsigned short first_dia_trk;
|
|
||||||
unsigned short no_dia_trk;
|
|
||||||
unsigned short first_sup_trk;
|
|
||||||
unsigned short no_sup_trk;
|
|
||||||
unsigned char MDR_ID;
|
|
||||||
unsigned char OBR_ID;
|
|
||||||
unsigned char director;
|
|
||||||
unsigned char rd_trk_set;
|
|
||||||
unsigned short max_rec_zero;
|
|
||||||
unsigned char reserved1;
|
|
||||||
unsigned char RWANY_in_LR;
|
|
||||||
unsigned char factor6;
|
|
||||||
unsigned char factor7;
|
|
||||||
unsigned char factor8;
|
|
||||||
unsigned char reserved2[3];
|
|
||||||
unsigned char reserved3[6];
|
|
||||||
unsigned int long_no_cyl;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
/* Get information on a dasd device (enhanced) */
|
|
||||||
#define BIODASDINFO _IOR(DASD_IOCTL_LETTER,1,dasd_information_t)
|
|
||||||
|
|
||||||
/*****************************************************************************
|
|
||||||
* SECTION: Further IOCTL Definitions (see fs.h and hdreq.h) *
|
|
||||||
*****************************************************************************/
|
|
||||||
#define BLKROGET _IO(0x12,94) /* get read-only status (0 = read_write) */
|
|
||||||
#define BLKRRPART _IO(0x12,95) /* re-read partition table */
|
|
||||||
#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
|
|
||||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* device size in bytes (u64 *arg)*/
|
|
||||||
|
|
||||||
/* get device geometry */
|
|
||||||
#define HDIO_GETGEO 0x0301
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* SECTION: FDASD internal types *
|
* SECTION: FDASD internal types *
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|||||||
5
genprotimg/.gitignore
vendored
Normal file
5
genprotimg/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
tags
|
||||||
|
compile_commands.json
|
||||||
|
src/.check-dep-genprotimg
|
||||||
|
src/.detect-openssl.dep.c
|
||||||
|
src/genprotimg
|
||||||
27
genprotimg/Makefile
Normal file
27
genprotimg/Makefile
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# Common definitions
|
||||||
|
include ../common.mak
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := all
|
||||||
|
|
||||||
|
PKGDATADIR := "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
|
||||||
|
TESTS :=
|
||||||
|
SUBDIRS := boot src man
|
||||||
|
RECURSIVE_TARGETS := all-recursive install-recursive clean-recursive
|
||||||
|
|
||||||
|
all: all-recursive
|
||||||
|
|
||||||
|
install: all install-recursive
|
||||||
|
$(INSTALL) -d -m 755 "$(PKGDATADIR)"
|
||||||
|
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 boot/stage3a.bin "$(PKGDATADIR)"
|
||||||
|
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 644 boot/stage3b_reloc.bin "$(PKGDATADIR)"
|
||||||
|
$(INSTALL) -g $(GROUP) -o $(OWNER) -m 755 samples/check_hostkeydoc "$(PKGDATADIR)"
|
||||||
|
|
||||||
|
clean: clean-recursive
|
||||||
|
|
||||||
|
$(RECURSIVE_TARGETS):
|
||||||
|
@target=`echo $@ |sed s/-recursive//`; \
|
||||||
|
for d in $(SUBDIRS); do \
|
||||||
|
$(MAKE) -C $$d $$target; \
|
||||||
|
done
|
||||||
|
|
||||||
|
.PHONY: all install clean $(RECURSIVE_TARGETS)
|
||||||
85
genprotimg/README.md
Normal file
85
genprotimg/README.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
# genprotimg
|
||||||
|
|
||||||
|
`genprotimg` takes a kernel, key files, optionally an initrd image,
|
||||||
|
optionally a file containing the kernel command line parameters, and
|
||||||
|
generates a single, bootable image file. The generated image file
|
||||||
|
consists of a concatenation of a plain text boot loader, the encrypted
|
||||||
|
components for kernel, initrd, kernel command line, and the
|
||||||
|
integrity-protected PV header, containing the metadata necessary for
|
||||||
|
running the guest in protected mode. See [Memory Layout](#memory-layout)
|
||||||
|
for details about the internal structure of the created image.
|
||||||
|
|
||||||
|
It is possible to use the generated image as a kernel for zipl or for
|
||||||
|
a direct kernel boot using QEMU.
|
||||||
|
|
||||||
|
## Getting started
|
||||||
|
|
||||||
|
If all dependencies are met a simple `make` call in the source tree
|
||||||
|
should be enough for building `genprotimg`.
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
The main idea of `genprotimg` is:
|
||||||
|
|
||||||
|
1. read in all keys, IVs, and other information needed for the
|
||||||
|
encryption of the components and the generation of the PV header
|
||||||
|
2. add stub stage3a (so we can calculate the memory addresses)
|
||||||
|
3. add components: prepare the components (alignment and encryption)
|
||||||
|
and add them to the memory layout
|
||||||
|
4. build and add stage3b: generate the stage3b and add it to the memory layout
|
||||||
|
5. generate the PV header: generate the hashes (pld, ald, and tld) of
|
||||||
|
the components and create the PV header and IPIB
|
||||||
|
6. parameterize the stub stage3a: uses the IPIB and PV header
|
||||||
|
7. write the final image to the specified output path
|
||||||
|
|
||||||
|
### Boot Loader
|
||||||
|
|
||||||
|
The boot loader consists of two parts:
|
||||||
|
|
||||||
|
1. stage3a boot loader (cleartext), this loader is responsible for the
|
||||||
|
transition into the protected mode by doing diag308 subcode 8 and
|
||||||
|
10 calls.
|
||||||
|
2. stage3b boot loader (encrypted), this loader is very similar to the
|
||||||
|
normal zipl stage3 boot loader. It will be loaded by the Ultravisor
|
||||||
|
after the successful transition into protected mode. Like the zipl
|
||||||
|
stage3 boot loader it moves the kernel and patches in the values
|
||||||
|
for initrd and parmline.
|
||||||
|
|
||||||
|
The loaders have the following constraints:
|
||||||
|
|
||||||
|
1. It must be possible to place stage3a and stage3b at a location
|
||||||
|
greater than 0x10000 because the zipl stage3 loader zeroes out
|
||||||
|
everything at addresses lower than 0x10000 of the image.
|
||||||
|
2. As the stage3 loader of zipl assumes that the passed kernel image
|
||||||
|
looks like a normal kernel image, the zipl stage3 loader modifies the
|
||||||
|
content at the memory area 0x10400 - 0x10800, therefore we leave this
|
||||||
|
area unused in our stage3a loader.
|
||||||
|
3. The default entry address used by the zipl stage3 loader is 0x10000
|
||||||
|
so we add a simple branch to 0x11000 at 0x10000 so the zipl stage3
|
||||||
|
loader can modify the area 0x10400 - 0x10800 without affecting the
|
||||||
|
stage3a loader.
|
||||||
|
|
||||||
|
#### Detail about stage3b
|
||||||
|
|
||||||
|
The stage3b.bin is linked at address 0x9000, therefore it will not
|
||||||
|
work at another address. The relocation support for the stage3b
|
||||||
|
loader, so that it can be placed at addresses != 0x9000, is added in
|
||||||
|
the loader with the name stage3b_reloc.bin. By default, if we're
|
||||||
|
talking about stage3b we refer to stage3b_reloc.bin.
|
||||||
|
|
||||||
|
### Memory Layout
|
||||||
|
|
||||||
|
The memory layout of the bootable file looks like:
|
||||||
|
|
||||||
|
| Start | End | Use |
|
||||||
|
|------------------------|------------|-----------------------------------------------------------------------|
|
||||||
|
| 0 | 0x7 | Short PSW, starting instruction at 0x11000 |
|
||||||
|
| 0x10000 | 0x10012 | Branch to 0x11000 |
|
||||||
|
| 0x10013 | 0x10fff | Left intentionally unused |
|
||||||
|
| 0x11000 | 0x12fff | Stage3a |
|
||||||
|
| 0x13000 | 0x13fff | IPIB used as argument for the diag308 call |
|
||||||
|
| 0x14000 | 0x1[45]fff | UV header used for the diag308 call (size can be either 1 or 2 pages) |
|
||||||
|
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted kernel |
|
||||||
|
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted kernel parameters |
|
||||||
|
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted initrd |
|
||||||
|
| NEXT_PAGE_ALIGNED_ADDR | | Encrypted stage3b_reloc |
|
||||||
4
genprotimg/boot/.gitignore
vendored
Normal file
4
genprotimg/boot/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.elf
|
||||||
|
*.lds
|
||||||
|
*.bin
|
||||||
|
*.d
|
||||||
97
genprotimg/boot/Makefile
Normal file
97
genprotimg/boot/Makefile
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
# Common definitions
|
||||||
|
include ../../common.mak
|
||||||
|
|
||||||
|
ZIPL_DIR := $(rootdir)/zipl
|
||||||
|
ZIPL_BOOT_DIR := $(ZIPL_DIR)/boot
|
||||||
|
|
||||||
|
INCLUDE_PATHS := $(ZIPL_BOOT_DIR) $(ZIPL_DIR)/include $(rootdir)/include
|
||||||
|
INCLUDE_PARMS := $(addprefix -I,$(INCLUDE_PATHS))
|
||||||
|
|
||||||
|
ALL_CFLAGS := $(NO_PIE_CFLAGS) -Os -g \
|
||||||
|
$(INCLUDE_PARMS) \
|
||||||
|
-DENABLE_SCLP_ASCII=1 \
|
||||||
|
-DS390_TOOLS_RELEASE=$(S390_TOOLS_RELEASE) \
|
||||||
|
-fno-builtin -ffreestanding -fno-asynchronous-unwind-tables \
|
||||||
|
-fno-delete-null-pointer-checks \
|
||||||
|
-fexec-charset=IBM1047 -m64 -mpacked-stack \
|
||||||
|
-mstack-size=4096 -mstack-guard=128 -msoft-float \
|
||||||
|
-Wall -Wformat-security -Wextra -Werror
|
||||||
|
|
||||||
|
FILES := stage3a.bin stage3b.bin stage3b_reloc.bin
|
||||||
|
|
||||||
|
ZIPL_SRCS_C := libc.c ebcdic.c ebcdic_conv.c sclp.c
|
||||||
|
ZIPL_SRCS_ASM := entry.S
|
||||||
|
|
||||||
|
ZIPL_OBJS_C := $(ZIPL_SRCS_C:%.c=%.o)
|
||||||
|
ZIPL_OBJS_ASM := $(ZIPL_SRCS_ASM:%.S=%.o)
|
||||||
|
ZIPL_OBJS := $(ZIPL_OBJS_C) $(ZIPL_OBJS_ASM)
|
||||||
|
|
||||||
|
|
||||||
|
all: $(FILES)
|
||||||
|
|
||||||
|
# Prevent make from using some default rules...
|
||||||
|
%: %.S
|
||||||
|
|
||||||
|
%.o: %.S Makefile
|
||||||
|
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.o: %.c Makefile
|
||||||
|
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
|
||||||
|
# Dependencies for the .lds generation
|
||||||
|
sources_lds_S = $(wildcard *.lds.S)
|
||||||
|
dependencies_lds_S = $(sources_lds_S:%.lds.S=.%.lds.d)
|
||||||
|
# Include all ".lds.d" dependency files for all make targets except for "clean"
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(dependencies_lds_S)
|
||||||
|
endif
|
||||||
|
|
||||||
|
%.lds: %.lds.S Makefile
|
||||||
|
$(CPP) -Wp,-MD,.$@.d,-MT,$@ $(INCLUDE_PARMS) -P -C -o $@ $<
|
||||||
|
|
||||||
|
# Special rules for zipl object files
|
||||||
|
$(ZIPL_OBJS_C): %.o : $(ZIPL_BOOT_DIR)/%.c
|
||||||
|
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(ZIPL_OBJS_ASM): %.o : $(ZIPL_BOOT_DIR)/%.S
|
||||||
|
$(CC) $(ALL_CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
dependencies_zipl_c := $(ZIPL_SRCS_C:%.c=.%.o.d)
|
||||||
|
|
||||||
|
$(dependencies_zipl_c): .%.o.d : $(ZIPL_BOOT_DIR)/%.c
|
||||||
|
$(CC_SILENT) -MM $(ALL_CPPFLAGS) $(ALL_CFLAGS) $< > $@
|
||||||
|
|
||||||
|
ifneq ($(MAKECMDGOALS),clean)
|
||||||
|
-include $(dependencies_zipl_c)
|
||||||
|
endif
|
||||||
|
|
||||||
|
stage3b_reloc.o: stage3b.bin
|
||||||
|
|
||||||
|
stage3a.elf: head.o stage3a_init.o stage3a.o stage3a.lds $(ZIPL_OBJS)
|
||||||
|
stage3b.elf: head.o stage3b.o stage3b.lds $(ZIPL_OBJS)
|
||||||
|
stage3b_reloc.elf:
|
||||||
|
|
||||||
|
%.elf: %.o
|
||||||
|
case $* in \
|
||||||
|
stage3a) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3a.lds";; \
|
||||||
|
stage3b) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-T,stage3b.lds";; \
|
||||||
|
stage3b_reloc) SFLAGS="$(NO_PIE_LINKFLAGS) -nostdlib -Wl,-estage3b_reloc_start,-Ttext,0";; \
|
||||||
|
esac; \
|
||||||
|
$(LINK) $$SFLAGS -m64 $(filter %.o, $^) -o $@
|
||||||
|
@chmod a-x $@
|
||||||
|
|
||||||
|
%.bin: %.elf
|
||||||
|
$(OBJCOPY) -O binary \
|
||||||
|
--only-section=.text* \
|
||||||
|
--only-section=.ex_table* \
|
||||||
|
--only-section=.fixup* \
|
||||||
|
--only-section=.data* \
|
||||||
|
--only-section=.rodata* \
|
||||||
|
$< $@
|
||||||
|
@chmod a-x $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o *.elf *.bin *.map .*.d *.lds
|
||||||
|
|
||||||
|
.PHONY: all clean
|
||||||
25
genprotimg/boot/common_memory_layout.h
Normal file
25
genprotimg/boot/common_memory_layout.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Common memory layout for stage3a and stage3b bootloader.
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMMON_MEMORY_LAYOUT_H
|
||||||
|
#define COMMON_MEMORY_LAYOUT_H
|
||||||
|
|
||||||
|
#include "boot/loaders_layout.h"
|
||||||
|
|
||||||
|
#define STACK_ADDRESS STAGE3_STACK_ADDRESS
|
||||||
|
#define STACK_SIZE STAGE3_STACK_SIZE
|
||||||
|
|
||||||
|
#define HEAP_ADDRESS STAGE3_HEAP_ADDRESS
|
||||||
|
#define HEAP_SIZE STAGE3_HEAP_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLER__ */
|
||||||
|
#endif /* COMMON_MEMORY_LAYOUT_H */
|
||||||
29
genprotimg/boot/head.S
Normal file
29
genprotimg/boot/head.S
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Entry code for stage 3a boot loader
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "common_memory_layout.h"
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/sigp.h"
|
||||||
|
|
||||||
|
.section .text.start
|
||||||
|
.globl _start
|
||||||
|
_start:
|
||||||
|
/* Might be called after a diag308 so better set
|
||||||
|
* architecture and addressing mode
|
||||||
|
*/
|
||||||
|
lhi %r1, 1
|
||||||
|
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||||
|
sam64
|
||||||
|
|
||||||
|
/* Initialize stack */
|
||||||
|
lgfi %r15, STACK_ADDRESS + STACK_SIZE - STACK_FRAME_OVERHEAD
|
||||||
|
brasl %r14, initialize
|
||||||
|
.previous
|
||||||
62
genprotimg/boot/stage3a.c
Normal file
62
genprotimg/boot/stage3a.c
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Main program for stage3a bootloader
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libc.h"
|
||||||
|
#include "stage3a.h"
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/ipl.h"
|
||||||
|
#include "sclp.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
|
||||||
|
static volatile struct stage3a_args __section(".loader_parms") loader_parms;
|
||||||
|
|
||||||
|
void __noreturn start(void)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
volatile struct stage3a_args *args = &loader_parms;
|
||||||
|
/* calculate the IPIB memory address */
|
||||||
|
struct ipl_parameter_block *ipib = (void *)((uint64_t)args + args->ipib_offs);
|
||||||
|
|
||||||
|
/* Calculate the PV header memory address and set it and its
|
||||||
|
* size in the IPIB. This allows the PV header to be position
|
||||||
|
* independent.
|
||||||
|
*/
|
||||||
|
ipib->pv.pv_hdr_addr = (uint64_t)args + args->hdr_offs;
|
||||||
|
ipib->pv.pv_hdr_size = args->hdr_size;
|
||||||
|
|
||||||
|
/* set up ASCII and line-mode */
|
||||||
|
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||||
|
|
||||||
|
/* test if Secure Execution Unpack facility is available */
|
||||||
|
stfle(S390_lowcore.stfle_fac_list,
|
||||||
|
ARRAY_SIZE(S390_lowcore.stfle_fac_list));
|
||||||
|
rc = test_facility(UNPACK_FACILITY);
|
||||||
|
if (rc == 0)
|
||||||
|
panic(ENOPV, "Secure unpack facility is not available\n");
|
||||||
|
|
||||||
|
rc = diag308(DIAG308_SET_PV, ipib);
|
||||||
|
if (rc != DIAG308_RC_OK)
|
||||||
|
panic(EPV, "Protected boot setup has failed: 0x%x\n", rc);
|
||||||
|
|
||||||
|
rc = diag308(DIAG308_UNPACK_PV, 0x0);
|
||||||
|
if (rc != DIAG308_RC_OK) {
|
||||||
|
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||||
|
panic(EPV, "Protected boot has failed: 0x%x\n", rc);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void panic_notify(unsigned long UNUSED(rc))
|
||||||
|
{
|
||||||
|
}
|
||||||
34
genprotimg/boot/stage3a.h
Normal file
34
genprotimg/boot/stage3a.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Main program for stage3a bootloader.
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STAGE3A_H
|
||||||
|
#define STAGE3A_H
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "boot/loaders_layout.h"
|
||||||
|
|
||||||
|
#define STAGE3A_INIT_ENTRY IMAGE_ENTRY
|
||||||
|
#define STAGE3A_ENTRY (STAGE3A_INIT_ENTRY + _AC(0x1000, UL))
|
||||||
|
#define STAGE3A_LOAD_ADDRESS IMAGE_LOAD_ADDRESS
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Must not have any padding */
|
||||||
|
struct stage3a_args {
|
||||||
|
uint64_t hdr_offs;
|
||||||
|
uint64_t hdr_size;
|
||||||
|
uint64_t ipib_offs;
|
||||||
|
};
|
||||||
|
STATIC_ASSERT(sizeof(struct stage3a_args) == 3 * 8)
|
||||||
|
|
||||||
|
#endif /* __ASSEMBLER__ */
|
||||||
|
#endif /* STAGE3A_H */
|
||||||
103
genprotimg/boot/stage3a.lds.S
Normal file
103
genprotimg/boot/stage3a.lds.S
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
* Memory layout for stage 3a
|
||||||
|
* ==========================
|
||||||
|
*
|
||||||
|
* General memory layout
|
||||||
|
* ---------------------
|
||||||
|
*
|
||||||
|
* 0x00000 - 0x01fff Lowcore
|
||||||
|
* 0x02000 - 0x05fff Memory allocation (heap)
|
||||||
|
* 0x0f000 - 0x0ffff Stack
|
||||||
|
* 0x10000 - 0x10012 Jump to the "actual" stage3a code
|
||||||
|
* 0x11000 - 0x12fff Stage3a code + arguments (offsets and lengths to the
|
||||||
|
* actual data: IPIB and UV header)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stage3a.h"
|
||||||
|
#include "common_memory_layout.h"
|
||||||
|
|
||||||
|
OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||||
|
OUTPUT_ARCH(s390:64-bit)
|
||||||
|
|
||||||
|
ENTRY(_init)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x0;
|
||||||
|
|
||||||
|
. = HEAP_ADDRESS;
|
||||||
|
__heap_start = .;
|
||||||
|
.heap : {
|
||||||
|
. = . + HEAP_SIZE;
|
||||||
|
ASSERT(__heap_stop - __heap_start == HEAP_SIZE,
|
||||||
|
"Heap section doesn't conform to the described memory layout");
|
||||||
|
}
|
||||||
|
__heap_stop = .;
|
||||||
|
|
||||||
|
. = STACK_ADDRESS;
|
||||||
|
__stack_start = .;
|
||||||
|
.stack : {
|
||||||
|
. = . + STACK_SIZE;
|
||||||
|
ASSERT(__stack_end - __stack_start == STACK_SIZE,
|
||||||
|
"Stack section doesn't conform to the described memory layout");
|
||||||
|
}
|
||||||
|
__stack_end = .;
|
||||||
|
|
||||||
|
. = STAGE3A_INIT_ENTRY;
|
||||||
|
__text_init_start = .;
|
||||||
|
.text : {
|
||||||
|
stage3a_init.o(.text.init)
|
||||||
|
__text_init_stop = ABSOLUTE(.);
|
||||||
|
/* Text size of text_init must be smaller than 'PARMAREA - IMAGE_ENTRY',
|
||||||
|
* otherwise the text data could be overwritten by the original zipl stage3
|
||||||
|
* boot loader */
|
||||||
|
ASSERT(__text_init_stop - __text_init_start < PARMAREA - IMAGE_ENTRY,
|
||||||
|
"Text size must be smaller than 'PARMAREA - IMAGE_ENTRY'");
|
||||||
|
. = 0x1000;
|
||||||
|
ASSERT(ABSOLUTE(.) == STAGE3A_ENTRY,
|
||||||
|
"Text section doesn't conform to the described memory layout");
|
||||||
|
head.o(.text.start)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.ex_table ALIGN(16) : {
|
||||||
|
__ex_table_start = .;
|
||||||
|
*(.ex_table)
|
||||||
|
__ex_table_stop = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss ALIGN(16) : {
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss)
|
||||||
|
__bss_stop = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata ALIGN(16) : {
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data ALIGN(16) : {
|
||||||
|
*(.data)
|
||||||
|
. = ALIGN(16);
|
||||||
|
/* The IPIB offset and the UV header offset and size will be
|
||||||
|
* saved in 'loader_parms' */
|
||||||
|
__loader_parms_start = .;
|
||||||
|
KEEP(*(.loader_parms));
|
||||||
|
__loader_parms_stop = .;
|
||||||
|
ASSERT(__loader_parms_stop - __loader_parms_start == 3 * 8,
|
||||||
|
"Data size must be equal to 'sizeof(struct stage3a_args)'");
|
||||||
|
ASSERT(ABSOLUTE(.) < 0x13000, "Data section doesn't conform to the described memory layout");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* List this explicitly as otherwise .note.gnu.build-id will be
|
||||||
|
* put at 0x0 */
|
||||||
|
.notes : {
|
||||||
|
*(.note.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections to be discarded */
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.eh_frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
26
genprotimg/boot/stage3a_init.S
Normal file
26
genprotimg/boot/stage3a_init.S
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Entry code for stage 3a boot loader
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stage3a.h"
|
||||||
|
#include "boot/sigp.h"
|
||||||
|
|
||||||
|
.section .text.init
|
||||||
|
.globl _init
|
||||||
|
_init:
|
||||||
|
/* set architecture and switch to 64bit */
|
||||||
|
lhi %r1, 1
|
||||||
|
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||||
|
sam64
|
||||||
|
/* The original stage3 boot loader will try to store the
|
||||||
|
* kernel command line and the address and size of the
|
||||||
|
* ramdisk. Simply ignore this by starting at 0x11000.
|
||||||
|
*/
|
||||||
|
lgfi %r1, STAGE3A_ENTRY
|
||||||
|
br %r1
|
||||||
|
.previous
|
||||||
77
genprotimg/boot/stage3b.c
Normal file
77
genprotimg/boot/stage3b.c
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Main program for stage3b bootloader
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libc.h"
|
||||||
|
#include "stage3b.h"
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/linux_layout.h"
|
||||||
|
#include "boot/loaders_layout.h"
|
||||||
|
#include "sclp.h"
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
|
||||||
|
static volatile struct stage3b_args __section(".loader_parms") loader_parms;
|
||||||
|
|
||||||
|
static inline void __noreturn load_psw(struct psw_t psw)
|
||||||
|
{
|
||||||
|
asm volatile("lpswe %0" : : "Q"(psw) : "cc");
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __noreturn start(void)
|
||||||
|
{
|
||||||
|
volatile struct stage3b_args *args = &loader_parms;
|
||||||
|
volatile struct memblob *kernel = &args->kernel;
|
||||||
|
volatile struct memblob *cmdline = &args->cmdline;
|
||||||
|
volatile struct memblob *initrd = &args->initrd;
|
||||||
|
volatile struct psw_t psw = args->psw;
|
||||||
|
|
||||||
|
/* set up ASCII and line-mode */
|
||||||
|
sclp_setup(SCLP_LINE_ASCII_INIT);
|
||||||
|
|
||||||
|
if (kernel->size < IMAGE_LOAD_ADDRESS)
|
||||||
|
panic(EINTERNAL, "Invalid kernel\n");
|
||||||
|
|
||||||
|
if (cmdline->size > COMMAND_LINE_SIZE)
|
||||||
|
panic(EINTERNAL, "Command line is too large\n");
|
||||||
|
|
||||||
|
/* move the kernel and cut the kernel header */
|
||||||
|
memmove((void *)IMAGE_LOAD_ADDRESS,
|
||||||
|
(void *)(kernel->src + IMAGE_LOAD_ADDRESS),
|
||||||
|
kernel->size - IMAGE_LOAD_ADDRESS);
|
||||||
|
|
||||||
|
/* move the kernel cmdline */
|
||||||
|
memmove((void *)COMMAND_LINE,
|
||||||
|
(void *)cmdline->src,
|
||||||
|
cmdline->size);
|
||||||
|
/* the initrd does not need to be moved */
|
||||||
|
|
||||||
|
if (initrd->size != 0) {
|
||||||
|
/* copy initrd start address and size into new kernel space */
|
||||||
|
*(unsigned long long *)INITRD_START = initrd->src;
|
||||||
|
*(unsigned long long *)INITRD_SIZE = initrd->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disable ASCII and line-mode */
|
||||||
|
sclp_setup(SCLP_DISABLE);
|
||||||
|
|
||||||
|
/* use lpswe instead of diag308 as a I/O subsystem reset is not
|
||||||
|
* needed as this was already done by the diag308 subcode 10 call
|
||||||
|
* in stage3a
|
||||||
|
*/
|
||||||
|
load_psw(psw);
|
||||||
|
}
|
||||||
|
|
||||||
|
void panic_notify(unsigned long UNUSED(rc))
|
||||||
|
{
|
||||||
|
}
|
||||||
42
genprotimg/boot/stage3b.h
Normal file
42
genprotimg/boot/stage3b.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Main program for stage3b bootloader
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STAGE3B_H
|
||||||
|
#define STAGE3B_H
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "boot/loaders_layout.h"
|
||||||
|
|
||||||
|
#define STAGE3B_ENTRY STAGE3_ENTRY
|
||||||
|
#define STAGE3B_LOAD_ADDRESS STAGE3B_ENTRY
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef __ASSEMBLER__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
|
||||||
|
/* Must not have any padding included */
|
||||||
|
struct memblob {
|
||||||
|
uint64_t src;
|
||||||
|
uint64_t size;
|
||||||
|
};
|
||||||
|
STATIC_ASSERT(sizeof(struct memblob) == 2 * 8)
|
||||||
|
|
||||||
|
/* Must not have any padding included */
|
||||||
|
struct stage3b_args {
|
||||||
|
struct memblob kernel;
|
||||||
|
struct memblob cmdline;
|
||||||
|
struct memblob initrd;
|
||||||
|
struct psw_t psw;
|
||||||
|
};
|
||||||
|
STATIC_ASSERT(sizeof(struct stage3b_args) == 3 * sizeof(struct memblob) + 16)
|
||||||
|
#endif /* __ASSEMBLER__ */
|
||||||
|
#endif /* STAGE3B_H */
|
||||||
87
genprotimg/boot/stage3b.lds.S
Normal file
87
genprotimg/boot/stage3b.lds.S
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Memory layout for stage 3b
|
||||||
|
* ==========================
|
||||||
|
*
|
||||||
|
* General memory layout
|
||||||
|
* ---------------------
|
||||||
|
*
|
||||||
|
* 0x00000 - 0x01fff Lowcore
|
||||||
|
* 0x02000 - 0x05fff Memory allocation (heap)
|
||||||
|
* 0x0a000 - 0x0efff Stage3b code
|
||||||
|
* 0x0f000 - 0x0ffff Stack
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stage3b.h"
|
||||||
|
#include "common_memory_layout.h"
|
||||||
|
|
||||||
|
OUTPUT_FORMAT("elf64-s390", "elf64-s390", "elf64-s390")
|
||||||
|
OUTPUT_ARCH(s390:64-bit)
|
||||||
|
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x0;
|
||||||
|
|
||||||
|
. = HEAP_ADDRESS;
|
||||||
|
__heap_start = .;
|
||||||
|
.heap : {
|
||||||
|
. = . + HEAP_SIZE;
|
||||||
|
ASSERT(__heap_stop - __heap_start == HEAP_SIZE,
|
||||||
|
"Heap section doesn't conform to the described memory layout");
|
||||||
|
}
|
||||||
|
__heap_stop = .;
|
||||||
|
|
||||||
|
. = STAGE3B_ENTRY;
|
||||||
|
.text : {
|
||||||
|
head.o(.text.start)
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.ex_table ALIGN(16) : {
|
||||||
|
__ex_table_start = .;
|
||||||
|
*(.ex_table)
|
||||||
|
__ex_table_stop = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss ALIGN(16) : {
|
||||||
|
__bss_start = .;
|
||||||
|
*(.bss)
|
||||||
|
__bss_stop = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata ALIGN(16) : {
|
||||||
|
*(.rodata)
|
||||||
|
*(.rodata.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data ALIGN(16) : {
|
||||||
|
*(.data)
|
||||||
|
. = ALIGN(16);
|
||||||
|
__loader_parms_start = .;
|
||||||
|
KEEP(*(.loader_parms));
|
||||||
|
__loader_parms_end = .;
|
||||||
|
ASSERT(__loader_parms_end - __loader_parms_start == 3 * 16 + 16,
|
||||||
|
"Data size must be equal to 'sizeof(struct stage3b_args)'");
|
||||||
|
}
|
||||||
|
|
||||||
|
. = STACK_ADDRESS;
|
||||||
|
__stack_start = .;
|
||||||
|
.stack : {
|
||||||
|
. = . + STACK_SIZE;
|
||||||
|
ASSERT(__stack_end - __stack_start == STACK_SIZE,
|
||||||
|
"Stack section doesn't conform to the described memory layout");
|
||||||
|
}
|
||||||
|
__stack_end = .;
|
||||||
|
|
||||||
|
/* List this explicitly as otherwise .note.gnu.build-id will be
|
||||||
|
* put at 0x0 */
|
||||||
|
.notes : {
|
||||||
|
*(.note.*)
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections to be discarded */
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.eh_frame)
|
||||||
|
}
|
||||||
|
}
|
||||||
53
genprotimg/boot/stage3b_reloc.S
Normal file
53
genprotimg/boot/stage3b_reloc.S
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Relocator code for stage 3b boot loader
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "stage3b.h"
|
||||||
|
#include "boot/sigp.h"
|
||||||
|
|
||||||
|
.macro MEMCPY dst,src,len
|
||||||
|
lgr %r0, \dst
|
||||||
|
lgr %r1, \len
|
||||||
|
lgr %r2, \src
|
||||||
|
lgr %r3, \len
|
||||||
|
|
||||||
|
20: mvcle %r0, %r2, 0
|
||||||
|
jo 20b
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.org 0x0
|
||||||
|
.section .text.start
|
||||||
|
.globl stage3b_reloc_start
|
||||||
|
stage3b_reloc_start:
|
||||||
|
/* Might be called after a diag308 so better set
|
||||||
|
* architecture and addressing mode
|
||||||
|
*/
|
||||||
|
lhi %r1, 1
|
||||||
|
sigp %r1, %r0, SIGP_SET_ARCHITECTURE
|
||||||
|
sam64
|
||||||
|
|
||||||
|
.copy_stage3b:
|
||||||
|
/* Location of stage3b in memory */
|
||||||
|
larl %r8, stage3b_start
|
||||||
|
|
||||||
|
/* Destination for stage3b */
|
||||||
|
lgfi %r9, STAGE3B_LOAD_ADDRESS
|
||||||
|
|
||||||
|
/* Size of stage3b */
|
||||||
|
lghi %r11, stage3b_end - stage3b_start
|
||||||
|
|
||||||
|
/* Copy the stage3b loader to address STAGE3B_LOAD_ADDRESS */
|
||||||
|
MEMCPY %r9, %r8, %r11
|
||||||
|
|
||||||
|
/* Branch to STAGE3B_ENTRY */
|
||||||
|
lgfi %r9, STAGE3B_ENTRY
|
||||||
|
br %r9
|
||||||
|
stage3b_start:
|
||||||
|
.incbin "stage3b.bin"
|
||||||
|
stage3b_end:
|
||||||
|
.previous
|
||||||
12
genprotimg/man/Makefile
Normal file
12
genprotimg/man/Makefile
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
# Common definitions
|
||||||
|
include ../../common.mak
|
||||||
|
|
||||||
|
all:
|
||||||
|
|
||||||
|
install:
|
||||||
|
$(INSTALL) -d -m 755 $(DESTDIR)$(MANDIR)/man8
|
||||||
|
$(INSTALL) -m 644 -c genprotimg.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
|
|
||||||
|
clean:
|
||||||
|
|
||||||
|
.PHONY: all install clean
|
||||||
97
genprotimg/man/genprotimg.8
Normal file
97
genprotimg/man/genprotimg.8
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
.\" Copyright 2020 IBM Corp.
|
||||||
|
.\" s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
.\" it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
.\"
|
||||||
|
.TH GENPROTIMG 8 "March 2020" "s390-tools"
|
||||||
|
.SH NAME
|
||||||
|
genprotimg \- Create a protected virtualization image
|
||||||
|
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.SY
|
||||||
|
.B genprotimg
|
||||||
|
\fB\-k\fR \fIHOST_KEY_DOCUMENT\fR...
|
||||||
|
\fB\-i\fR \fIVMLINUZ\fR
|
||||||
|
[\fB\-r\fR \fIRAMDISK\fR]
|
||||||
|
[\fB\-p\fR \fIPARMFILE\fR]
|
||||||
|
\fB\-o\fR \fIOUTFILE\fR
|
||||||
|
[\fIOPTION\fR]...
|
||||||
|
.YS
|
||||||
|
|
||||||
|
.SH DESCRIPTION
|
||||||
|
.PP
|
||||||
|
Use \fBgenprotimg\fR to generate a single bootable image file with
|
||||||
|
encrypted and integrity-protected parts. The command requires a kernel
|
||||||
|
image, a host-key document, and an output file name. Optionally,
|
||||||
|
specify an initial RAM filesystem, and a file containing the kernel
|
||||||
|
parameters. Should special circumstances require it, you can
|
||||||
|
optionally specify your own keys for the encryption by using the
|
||||||
|
experimental options. In the resulting image file, a plain text boot
|
||||||
|
loader, the encrypted components for kernel, initial RAM disk, kernel
|
||||||
|
parameters, and the encrypted and integrity-protected header are
|
||||||
|
concatenated. The header contains metadata necessary for running the
|
||||||
|
guest in protected mode.
|
||||||
|
.PP
|
||||||
|
Use this image file as a kernel image for zipl or for a direct kernel
|
||||||
|
boot using QEMU.
|
||||||
|
|
||||||
|
.SH OPTIONS
|
||||||
|
.TP
|
||||||
|
\fB\-h\fR, \fB\-\-help\fR
|
||||||
|
Prints usage information, then exits.
|
||||||
|
.TP
|
||||||
|
\fB\-\-help-experimental\fR
|
||||||
|
Prints experimental usage information, then exits.
|
||||||
|
.TP
|
||||||
|
\fB\-\-help-all\fR
|
||||||
|
Prints all usage information, then exits.
|
||||||
|
.TP
|
||||||
|
\fB\-V\fR, \fB\-\-verbose\fR
|
||||||
|
Provides more detailed output.
|
||||||
|
.TP
|
||||||
|
\fB\-k\fR, \fB\-\-host-key-document\fR=\fI\,HOST_KEY_DOCUMENT\/\fR
|
||||||
|
Specifies a host-key document. At least one is required. Specify this
|
||||||
|
option multiple times to enable the image to run on more than one
|
||||||
|
host.
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR, \fB\-\-output\fR=\fI\,OUTPUT_FILE\/\fR
|
||||||
|
Specifies the output file. Required.
|
||||||
|
.TP
|
||||||
|
\fB\-i\fR, \fB\-\-image\fR=\fI\,VMLINUZ\/\fR
|
||||||
|
Specifies the Linux kernel image file. Required.
|
||||||
|
.TP
|
||||||
|
\fB\-r\fR, \fB\-\-ramdisk\fR=\fI\,RAMDISK\/\fR
|
||||||
|
Specifies the RAM disk image. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-p\fR, \fB\-\-parmfile\fR=\fI\,PARMFILE\/\fR
|
||||||
|
Specifies the kernel command line stored in \fI\,PARMFILE\/\fR. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-\-no-verify\fR
|
||||||
|
Do not require the host-key documents to be valid. For testing
|
||||||
|
purposes, do not use for a production image. Optional.
|
||||||
|
.TP
|
||||||
|
\fB\-v\fR, \fB\-\-version\fR
|
||||||
|
Prints version information, then exits.
|
||||||
|
|
||||||
|
.SH EXAMPLE
|
||||||
|
.PP
|
||||||
|
Generate a protected virtualization image in
|
||||||
|
\fI\,/boot/vmlinuz.pv\/\fR, using the kernel file \fI\,vmlinuz\/\fR,
|
||||||
|
the initrd in \fI\,initramfs\/\fR, the kernel parameters contained in
|
||||||
|
\fI\,parmfile\/\fR, 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 \-o \fI\,/boot/vmlinuz.pv\/\fR
|
||||||
|
.EE
|
||||||
|
.Ve
|
||||||
|
.PP
|
||||||
|
|
||||||
|
.SH NOTES
|
||||||
|
.IP "1." 4
|
||||||
|
An ELF file cannot be used as a Linux kernel image.
|
||||||
|
.IP "2." 4
|
||||||
|
Remember to re-run \fBzipl\fR after updating a protected
|
||||||
|
virtualization image.
|
||||||
|
|
||||||
|
.SH SEE ALSO
|
||||||
|
\&\fBzipl\fR\|(5), \fBqemu\fR\|(1)
|
||||||
276
genprotimg/samples/check_hostkeydoc
Executable file
276
genprotimg/samples/check_hostkeydoc
Executable file
@@ -0,0 +1,276 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# check_hostkeydoc - Verify an IBM Secure Execution host key document
|
||||||
|
#
|
||||||
|
# Sample script to verify that a host key document is genuine by
|
||||||
|
# verifying the issuer, the validity date and the signature.
|
||||||
|
# Optionally verify the full trust chain using a CA certficate.
|
||||||
|
#
|
||||||
|
# Revocation list checking not yet implemented.
|
||||||
|
#
|
||||||
|
# Sample invocation:
|
||||||
|
#
|
||||||
|
# ./check_hostkeydoc HKD1234.crt signing-key.crt
|
||||||
|
#
|
||||||
|
# Copyright IBM Corp. 2020
|
||||||
|
#
|
||||||
|
# s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
|
||||||
|
|
||||||
|
# Allocate temporary files
|
||||||
|
ISSUER_PUBKEY_FILE=$(mktemp)
|
||||||
|
SIGNATURE_FILE=$(mktemp)
|
||||||
|
BODY_FILE=$(mktemp)
|
||||||
|
ISSUER_DN_FILE=$(mktemp)
|
||||||
|
SUBJECT_DN_FILE=$(mktemp)
|
||||||
|
DEF_ISSUER_DN_FILE=$(mktemp)
|
||||||
|
CRL_SERIAL_FILE=$(mktemp)
|
||||||
|
|
||||||
|
# Cleanup on exit
|
||||||
|
cleanup()
|
||||||
|
{
|
||||||
|
rm -f $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE \
|
||||||
|
$ISSUER_DN_FILE $SUBJECT_DN_FILE $DEF_ISSUER_DN_FILE \
|
||||||
|
$CRL_SERIAL_FILE
|
||||||
|
}
|
||||||
|
trap cleanup EXIT
|
||||||
|
|
||||||
|
# Enhanced error checking for bash
|
||||||
|
if echo $SHELL | grep /bin/bash > /dev/null
|
||||||
|
then
|
||||||
|
set -o pipefail
|
||||||
|
set -o nounset
|
||||||
|
fi
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
usage()
|
||||||
|
{
|
||||||
|
cat <<-EOF
|
||||||
|
Usage: `basename $1` host-key-doc signing-key-cert [-c CA-cert] [-r CRL]
|
||||||
|
|
||||||
|
Verify an IBM Secure Execution host key document against
|
||||||
|
a signing key.
|
||||||
|
|
||||||
|
Note that in order to have the full trust chain verified
|
||||||
|
it is necessary to provide the issueing CA's certificate.
|
||||||
|
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
check_verify_chain()
|
||||||
|
{
|
||||||
|
# Verify certificate chain in case a CA certificate file/bundle
|
||||||
|
# was specified on the command line.
|
||||||
|
if [ $# = 1 ]
|
||||||
|
then
|
||||||
|
cat >&2 <<-EOF
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
No CA certificate specified! Skipping trust chain verification.
|
||||||
|
Make sure that '$1' is a valid certificate.
|
||||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
openssl verify -crl_download -crl_check $2 &&
|
||||||
|
openssl verify -crl_download -crl_check -untrusted $2 $1 ||
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_pubkey()
|
||||||
|
{
|
||||||
|
openssl x509 -in $1 -pubkey -noout > $2
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_signature()
|
||||||
|
{
|
||||||
|
# Assuming that the last field is the signature
|
||||||
|
SIGOFFSET=$(openssl asn1parse -in $1 | tail -1 | cut -d : -f 1)
|
||||||
|
|
||||||
|
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_body()
|
||||||
|
{
|
||||||
|
# Assuming that the first field is the full cert body
|
||||||
|
SIGOFFSET=$(openssl asn1parse -in $1 | head -2 | tail -1 | cut -d : -f 1)
|
||||||
|
|
||||||
|
openssl asn1parse -in $1 -out $2 -strparse $SIGOFFSET -noout
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_signature()
|
||||||
|
{
|
||||||
|
# Assuming that the signature algorith is SHA512 with RSA
|
||||||
|
openssl sha512 -verify $1 -signature $2 $3
|
||||||
|
}
|
||||||
|
|
||||||
|
canonical_dn()
|
||||||
|
{
|
||||||
|
OBJTYPE=$1
|
||||||
|
OBJ=$2
|
||||||
|
DNTYPE=$3
|
||||||
|
OUTPUT=$4
|
||||||
|
|
||||||
|
openssl $OBJTYPE -in $OBJ -$DNTYPE -noout -nameopt multiline \
|
||||||
|
| sort | grep -v $DNTYPE= > $OUTPUT
|
||||||
|
}
|
||||||
|
|
||||||
|
default_issuer()
|
||||||
|
{
|
||||||
|
cat <<-EOF
|
||||||
|
commonName = International Business Machines Corporation
|
||||||
|
countryName = US
|
||||||
|
localityName = Poughkeepsie
|
||||||
|
organizationalUnitName = IBM Z Host Key Signing Service
|
||||||
|
organizationName = International Business Machines Corporation
|
||||||
|
stateOrProvinceName = New York
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_issuer_files()
|
||||||
|
{
|
||||||
|
default_issuer > $DEF_ISSUER_DN_FILE
|
||||||
|
|
||||||
|
if ! diff $ISSUER_DN_FILE $DEF_ISSUER_DN_FILE
|
||||||
|
then
|
||||||
|
echo Incorrect default issuer >&2 && exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if diff $ISSUER_DN_FILE $SUBJECT_DN_FILE
|
||||||
|
then
|
||||||
|
echo Issuer verification OK
|
||||||
|
else
|
||||||
|
echo Issuer verification failed >&2 && exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
cert_time()
|
||||||
|
{
|
||||||
|
DATE=$(openssl x509 -in $1 -$2 -noout | sed "s/^.*=//")
|
||||||
|
|
||||||
|
date -d "$DATE" +%s
|
||||||
|
}
|
||||||
|
|
||||||
|
crl_time()
|
||||||
|
{
|
||||||
|
DATE=$(openssl crl -in $1 -$2 -noout | sed "s/^.*=//")
|
||||||
|
|
||||||
|
date -d "$DATE" +%s
|
||||||
|
}
|
||||||
|
|
||||||
|
verify_dates()
|
||||||
|
{
|
||||||
|
START="$1"
|
||||||
|
END="$2"
|
||||||
|
MSG="${3:-Certificate}"
|
||||||
|
NOW=$(date +%s)
|
||||||
|
|
||||||
|
if [ $START -le $NOW -a $NOW -le $END ]
|
||||||
|
then
|
||||||
|
echo "${MSG} dates are OK"
|
||||||
|
else
|
||||||
|
echo "${MSG} date verification failed" >&2 && exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
crl_serials()
|
||||||
|
{
|
||||||
|
openssl crl -in $1 -text -noout | \
|
||||||
|
grep "Serial Number" > $CRL_SERIAL_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
check_serial()
|
||||||
|
{
|
||||||
|
CERT_SERIAL=$(openssl x509 -in $1 -noout -serial | cut -d = -f 2)
|
||||||
|
|
||||||
|
grep -q $CERT_SERIAL $CRL_SERIAL_FILE
|
||||||
|
}
|
||||||
|
|
||||||
|
check_file()
|
||||||
|
{
|
||||||
|
[ $# = 0 ] ||
|
||||||
|
[ -e "$1" ] ||
|
||||||
|
(echo "File '$1' not found" >&2 && exit 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
# check args
|
||||||
|
CRL_FILE=
|
||||||
|
CA_FILE=
|
||||||
|
|
||||||
|
args=$(getopt -qu "r:c:h" $*)
|
||||||
|
if [ $? = 0 ]
|
||||||
|
then
|
||||||
|
set -- $args
|
||||||
|
while [ $1 != "" ]
|
||||||
|
do
|
||||||
|
case $1 in
|
||||||
|
-r) CRL_FILE=$2; shift 2;;
|
||||||
|
-c) CA_FILE=$2; shift 2;;
|
||||||
|
-h) usage $0; exit 0;;
|
||||||
|
--) shift; break;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
else
|
||||||
|
usage $0 >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $# -ne 2 ]
|
||||||
|
then
|
||||||
|
usage $0 >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
HKD_FILE=$1
|
||||||
|
HKSK_FILE=$2
|
||||||
|
|
||||||
|
# Check whether all specified files exist
|
||||||
|
check_file $HKD_FILE
|
||||||
|
check_file $HKSK_FILE
|
||||||
|
check_file $CA_FILE
|
||||||
|
check_file $CRL_FILE
|
||||||
|
|
||||||
|
# Check trust chain
|
||||||
|
check_verify_chain $HKSK_FILE $CA_FILE
|
||||||
|
|
||||||
|
# Verify host key document signature
|
||||||
|
echo -n "Checking host key document signature: "
|
||||||
|
extract_pubkey $HKSK_FILE $ISSUER_PUBKEY_FILE &&
|
||||||
|
extract_signature $HKD_FILE $SIGNATURE_FILE &&
|
||||||
|
extract_body $HKD_FILE $BODY_FILE &&
|
||||||
|
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
# Verify the issuer
|
||||||
|
canonical_dn x509 $HKD_FILE issuer $ISSUER_DN_FILE
|
||||||
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
|
verify_issuer_files
|
||||||
|
|
||||||
|
# Verify dates
|
||||||
|
verify_dates $(cert_time $HKD_FILE startdate) $(cert_time $HKD_FILE enddate)
|
||||||
|
|
||||||
|
# Check CRL if specified
|
||||||
|
if [ -n "$CRL_FILE" ]
|
||||||
|
then
|
||||||
|
echo -n "Checking CRL signature: "
|
||||||
|
extract_signature $CRL_FILE $SIGNATURE_FILE &&
|
||||||
|
extract_body $CRL_FILE $BODY_FILE &&
|
||||||
|
verify_signature $ISSUER_PUBKEY_FILE $SIGNATURE_FILE $BODY_FILE ||
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
echo -n "CRL "
|
||||||
|
canonical_dn crl $CRL_FILE issuer $ISSUER_DN_FILE
|
||||||
|
canonical_dn x509 $HKSK_FILE subject $SUBJECT_DN_FILE
|
||||||
|
verify_issuer_files
|
||||||
|
|
||||||
|
verify_dates $(crl_time $CRL_FILE lastupdate) $(crl_time $CRL_FILE nextupdate) 'CRL'
|
||||||
|
|
||||||
|
crl_serials $CRL_FILE
|
||||||
|
check_serial $HKD_FILE &&
|
||||||
|
echo "Certificate is revoked, do not use it anymore!" >&2 &&
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# We made it
|
||||||
|
echo All checks reqested for \'$HKD_FILE\' were successful
|
||||||
101
genprotimg/src/Makefile
Normal file
101
genprotimg/src/Makefile
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
# Common definitions
|
||||||
|
include ../../common.mak
|
||||||
|
|
||||||
|
bin_PROGRAM = genprotimg
|
||||||
|
|
||||||
|
PKGDATADIR ?= "$(DESTDIR)$(TOOLS_DATADIR)/genprotimg"
|
||||||
|
SRC_DIR := $(dir $(realpath $(firstword $(MAKEFILE_LIST))))
|
||||||
|
TOP_SRCDIR := $(SRC_DIR)/../
|
||||||
|
ROOT_DIR = $(TOP_SRC_DIR)/../../
|
||||||
|
ZIPL_DIR = $(ROOT_DIR)/zipl
|
||||||
|
LOADER_DIR = $(TOP_SRCDIR)/boot
|
||||||
|
|
||||||
|
INCLUDE_PATHS = "$(SRC_DIR)" "$(TOP_SRCDIR)" "$(ROOTDIR)/include"
|
||||||
|
INCLUDE_PARMS = $(addprefix -I,$(INCLUDE_PATHS))
|
||||||
|
|
||||||
|
WARNINGS := -Wall -Wextra -Wshadow \
|
||||||
|
-Wcast-align -Wwrite-strings -Wmissing-prototypes \
|
||||||
|
-Wmissing-declarations -Wredundant-decls -Wnested-externs -Winline \
|
||||||
|
-Wno-long-long -Wuninitialized -Wconversion -Wstrict-prototypes \
|
||||||
|
-Wpointer-arith -Werror \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
$(bin_PROGRAM)_SRCS := $(bin_PROGRAM).c pv/pv_stage3.c pv/pv_image.c \
|
||||||
|
pv/pv_comp.c pv/pv_hdr.c pv/pv_ipib.c utils/crypto.c utils/file_utils.c \
|
||||||
|
pv/pv_args.c utils/buffer.c pv/pv_comps.c pv/pv_error.c \
|
||||||
|
pv/pv_opt_item.c \
|
||||||
|
$(NULL)
|
||||||
|
$(bin_PROGRAM)_OBJS := $($(bin_PROGRAM)_SRCS:.c=.o)
|
||||||
|
|
||||||
|
ALL_CFLAGS += -std=gnu11 -DPKGDATADIR=$(PKGDATADIR) \
|
||||||
|
$(GLIB2_CFLAGS) $(LIBCRYPTO_CFLAGS) \
|
||||||
|
$(WARNINGS) \
|
||||||
|
$(NULL)
|
||||||
|
ALL_CPPFLAGS += $(INCLUDE_PARMS)
|
||||||
|
LDLIBS += $(GLIB2_LIBS) $(LIBCRYPTO_LIBS)
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(shell sh -c 'command -v pkg-config'),)
|
||||||
|
GLIB2_CFLAGS := $(shell pkg-config --silence-errors --cflags glib-2.0)
|
||||||
|
GLIB2_LIBS := $(shell pkg-config --silence-errors --libs glib-2.0)
|
||||||
|
LIBCRYPTO_CFLAGS := $(shell pkg-config --silence-errors --cflags libcrypto)
|
||||||
|
LIBCRYPTO_LIBS := $(shell pkg-config --silence-errors --libs libcrypto)
|
||||||
|
else
|
||||||
|
GLIB2_CFLAGS := -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include
|
||||||
|
GLIB2_LIBS := -lglib-2.0
|
||||||
|
LIBCRYPTO_CFLAGS :=
|
||||||
|
LIBCRYPTO_LIBS := -lcrypto
|
||||||
|
endif
|
||||||
|
|
||||||
|
BUILD_TARGETS := skip-$(bin_PROGRAM)
|
||||||
|
INSTALL_TARGETS := skip-$(bin_PROGRAM)
|
||||||
|
ifneq (${HAVE_OPENSSL},0)
|
||||||
|
ifneq (${HAVE_GLIB2},0)
|
||||||
|
BUILD_TARGETS := $(bin_PROGRAM)
|
||||||
|
INSTALL_TARGETS := install-$(bin_PROGRAM)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
all: $(BUILD_TARGETS)
|
||||||
|
|
||||||
|
install: $(INSTALL_TARGETS)
|
||||||
|
|
||||||
|
$(bin_PROGRAM): $($(bin_PROGRAM)_OBJS)
|
||||||
|
|
||||||
|
skip-$(bin_PROGRAM):
|
||||||
|
echo " SKIP $(bin_PROGRAM) due to unresolved dependencies"
|
||||||
|
|
||||||
|
install-$(bin_PROGRAM): $(bin_PROGRAM)
|
||||||
|
$(INSTALL) -d -m 755 $(DESTDIR)$(USRBINDIR)
|
||||||
|
$(INSTALL) -c $^ $(DESTDIR)$(USRBINDIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) -f $($(bin_PROGRAM)_OBJS) $(bin_PROGRAM) .check-dep-$(bin_PROGRAM) .detect-openssl.dep.c
|
||||||
|
|
||||||
|
.PHONY: all install clean skip-$(bin_PROGRAM) install-$(bin_PROGRAM)
|
||||||
|
|
||||||
|
$($(bin_PROGRAM)_OBJS): .check-dep-$(bin_PROGRAM)
|
||||||
|
|
||||||
|
.detect-openssl.dep.c:
|
||||||
|
echo "#include <openssl/evp.h>" > $@
|
||||||
|
echo "#if OPENSSL_VERSION_NUMBER < 0x10100000L" >> $@
|
||||||
|
echo " #error openssl version 1.1.0 is required" >> $@
|
||||||
|
echo "#endif" >> $@
|
||||||
|
echo "static void __attribute__((unused)) test(void) {" >> $@
|
||||||
|
echo " EVP_MD_CTX *ctx = EVP_MD_CTX_new();" >> $@
|
||||||
|
echo " EVP_MD_CTX_free(ctx);" >> $@
|
||||||
|
echo "}" >> $@
|
||||||
|
|
||||||
|
.check-dep-$(bin_PROGRAM): .detect-openssl.dep.c
|
||||||
|
$(call check_dep, \
|
||||||
|
"$(bin_PROGRAM)", \
|
||||||
|
"glib.h", \
|
||||||
|
"glib2-devel / libglib2.0-dev", \
|
||||||
|
"HAVE_GLIB2=0")
|
||||||
|
$(call check_dep, \
|
||||||
|
"$(bin_PROGRAM)", \
|
||||||
|
$^, \
|
||||||
|
"openssl-devel / libssl-dev version >= 1.1.0", \
|
||||||
|
"HAVE_OPENSSL=0", \
|
||||||
|
"-I.")
|
||||||
|
touch $@
|
||||||
35
genprotimg/src/common.h
Normal file
35
genprotimg/src/common.h
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#define GETTEXT_PACKAGE "genprotimg"
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gi18n-lib.h>
|
||||||
|
|
||||||
|
#include "boot/linux_layout.h"
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
|
static const gchar tool_name[] = "genprotimg";
|
||||||
|
static const gchar copyright_notice[] = "Copyright IBM Corp. 2020";
|
||||||
|
|
||||||
|
/* default values */
|
||||||
|
#define GENPROTIMG_STAGE3A_PATH (STRINGIFY(PKGDATADIR) "/stage3a.bin")
|
||||||
|
#define GENPROTIMG_STAGE3B_PATH (STRINGIFY(PKGDATADIR) "/stage3b_reloc.bin")
|
||||||
|
|
||||||
|
#define DEFAULT_INITIAL_PSW_ADDR IMAGE_ENTRY
|
||||||
|
#define DEFAULT_INITIAL_PSW_MASK (PSW_MASK_EA | PSW_MASK_BA)
|
||||||
|
|
||||||
|
#define DO_PRAGMA(x) _Pragma(#x)
|
||||||
|
|
||||||
|
# ifdef __clang__
|
||||||
|
# define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
|
||||||
|
DO_PRAGMA(clang diagnostic push) \
|
||||||
|
DO_PRAGMA(clang diagnostic ignored "-Wunused-function") \
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__) \
|
||||||
|
DO_PRAGMA(clang diagnostic pop)
|
||||||
|
# else
|
||||||
|
# define WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(...) \
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(__VA_ARGS__)
|
||||||
|
# endif
|
||||||
|
|
||||||
|
#endif
|
||||||
181
genprotimg/src/genprotimg.c
Normal file
181
genprotimg/src/genprotimg.c
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* genprotimg - build relocatable secure images
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <locale.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "pv/pv_args.h"
|
||||||
|
#include "pv/pv_image.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LOG_LEVEL_CRITICAL = 0,
|
||||||
|
LOG_LEVEL_INFO = 1,
|
||||||
|
LOG_LEVEL_DEBUG = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
static gint log_level = LOG_LEVEL_CRITICAL;
|
||||||
|
static gchar *tmp_dir;
|
||||||
|
|
||||||
|
static void rmdir_recursive(gchar *dir_path, GError **err)
|
||||||
|
{
|
||||||
|
const gchar *file = NULL;
|
||||||
|
g_autoptr(GDir) d = NULL;
|
||||||
|
|
||||||
|
if (!dir_path)
|
||||||
|
return;
|
||||||
|
|
||||||
|
d = g_dir_open(dir_path, 0, err);
|
||||||
|
if (!d) {
|
||||||
|
g_set_error(err, G_FILE_ERROR,
|
||||||
|
(gint)g_file_error_from_errno(errno),
|
||||||
|
_("Failed to open directory '%s': %s"), dir_path,
|
||||||
|
g_strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((file = g_dir_read_name(d)) != NULL) {
|
||||||
|
g_autofree gchar *file_path =
|
||||||
|
g_build_filename(dir_path, file, NULL);
|
||||||
|
/* ignore error */
|
||||||
|
(void)g_unlink(file_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_rmdir(dir_path) != 0) {
|
||||||
|
g_set_error(err, G_FILE_ERROR,
|
||||||
|
(gint)g_file_error_from_errno(errno),
|
||||||
|
_("Failed to remove directory '%s': %s"), dir_path,
|
||||||
|
g_strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sig_term_handler(int signal G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
rmdir_recursive(tmp_dir, NULL);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_handler_cb(const gchar *log_domain G_GNUC_UNUSED,
|
||||||
|
GLogLevelFlags level, const gchar *message,
|
||||||
|
gpointer user_data G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
const gchar *prefix = "";
|
||||||
|
|
||||||
|
/* filter out messages depending on debugging level */
|
||||||
|
if ((level & G_LOG_LEVEL_DEBUG) && log_level < LOG_LEVEL_DEBUG)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((level & G_LOG_LEVEL_INFO) && log_level < LOG_LEVEL_INFO)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (level & G_LOG_LEVEL_WARNING)
|
||||||
|
prefix = "WARNING: ";
|
||||||
|
|
||||||
|
if (level & G_LOG_LEVEL_ERROR)
|
||||||
|
prefix = "ERROR: ";
|
||||||
|
|
||||||
|
if (level & (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_ERROR))
|
||||||
|
g_printerr("%s%s\n", prefix, message);
|
||||||
|
else
|
||||||
|
g_print("%s%s\n", prefix, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_prgname(const gchar *name)
|
||||||
|
{
|
||||||
|
g_set_prgname(name);
|
||||||
|
g_set_application_name(_(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_handler(const gint *signals, const gsize signals_n)
|
||||||
|
{
|
||||||
|
/* set up logging handler */
|
||||||
|
g_log_set_handler(NULL,
|
||||||
|
G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL |
|
||||||
|
G_LOG_FLAG_RECURSION,
|
||||||
|
log_handler_cb, NULL);
|
||||||
|
|
||||||
|
/* set signal handler */
|
||||||
|
for (gsize i = 0; i < signals_n; i++)
|
||||||
|
signal(signals[i], sig_term_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_signal_handler(const gint *signals, const gsize signals_n)
|
||||||
|
{
|
||||||
|
for (gsize i = 0; i < signals_n; i++)
|
||||||
|
signal(signals[i], SIG_DFL);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint main(gint argc, gchar *argv[])
|
||||||
|
{
|
||||||
|
g_autoptr(PvArgs) args = pv_args_new();
|
||||||
|
gint signals[] = { SIGINT, SIGTERM };
|
||||||
|
g_autoptr(PvImage) img = NULL;
|
||||||
|
gint ret = EXIT_FAILURE;
|
||||||
|
GError *err = NULL;
|
||||||
|
|
||||||
|
setlocale(LC_CTYPE, "");
|
||||||
|
setup_prgname(tool_name);
|
||||||
|
setup_handler(signals, G_N_ELEMENTS(signals));
|
||||||
|
|
||||||
|
if (pv_args_parse_options(args, &argc, &argv, &err) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* set new log level */
|
||||||
|
log_level = args->log_level;
|
||||||
|
|
||||||
|
/* if the user has not specified a temporary directory let's
|
||||||
|
* create one
|
||||||
|
*/
|
||||||
|
if (!args->tmp_dir) {
|
||||||
|
tmp_dir = g_dir_make_tmp("genprotimg-XXXXXX", &err);
|
||||||
|
if (!tmp_dir)
|
||||||
|
goto error;
|
||||||
|
args->tmp_dir = g_strdup(tmp_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate and initialize ``pv_img`` data structure */
|
||||||
|
img = pv_img_new(args, GENPROTIMG_STAGE3A_PATH, &err);
|
||||||
|
if (!img)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
/* add user components: `args->comps` must be sorted by the
|
||||||
|
* component type => by memory address
|
||||||
|
*/
|
||||||
|
for (GSList *iterator = args->comps; iterator; iterator = iterator->next) {
|
||||||
|
const PvArg *arg = iterator->data;
|
||||||
|
|
||||||
|
if (pv_img_add_component(img, arg, &err) < 0)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pv_img_finalize(img, GENPROTIMG_STAGE3B_PATH, &err) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (pv_img_write(img, args->output_path, &err) < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
ret = EXIT_SUCCESS;
|
||||||
|
|
||||||
|
error:
|
||||||
|
if (err) {
|
||||||
|
fputs(err->message, stderr);
|
||||||
|
fputc('\n', stderr);
|
||||||
|
g_clear_error(&err);
|
||||||
|
}
|
||||||
|
rmdir_recursive(tmp_dir, NULL);
|
||||||
|
remove_signal_handler(signals, G_N_ELEMENTS(signals));
|
||||||
|
g_free(tmp_dir);
|
||||||
|
exit(ret);
|
||||||
|
}
|
||||||
25
genprotimg/src/include/pv_crypto_def.h
Normal file
25
genprotimg/src/include/pv_crypto_def.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* PV cryptography related definitions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_CRYPTO_DEF_H
|
||||||
|
#define PV_CRYPTO_DEF_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
|
union ecdh_pub_key {
|
||||||
|
struct {
|
||||||
|
uint8_t x[80];
|
||||||
|
uint8_t y[80];
|
||||||
|
};
|
||||||
|
uint8_t data[160];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#endif
|
||||||
84
genprotimg/src/include/pv_hdr_def.h
Normal file
84
genprotimg/src/include/pv_hdr_def.h
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* PV header definitions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_HDR_DEF_H
|
||||||
|
#define PV_HDR_DEF_H
|
||||||
|
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
|
||||||
|
#include "pv_crypto_def.h"
|
||||||
|
|
||||||
|
/* Magic number which is used to identify the file containing the PV
|
||||||
|
* header
|
||||||
|
*/
|
||||||
|
#define PV_MAGIC_NUMBER 0x49424d5365634578ULL
|
||||||
|
#define PV_VERSION_1 0x00000100U
|
||||||
|
|
||||||
|
/* prevent Ultravisor decryption during unpack operation */
|
||||||
|
#define PV_CFLAG_NO_DECRYPTION 0x10000000ULL
|
||||||
|
|
||||||
|
/* maxima for the PV version 1 */
|
||||||
|
#define PV_V1_IPIB_MAX_SIZE PAGE_SIZE
|
||||||
|
#define PV_V1_PV_HDR_MAX_SIZE (2 * PAGE_SIZE)
|
||||||
|
|
||||||
|
typedef struct pv_hdr_key_slot {
|
||||||
|
uint8_t digest_key[SHA256_DIGEST_LENGTH];
|
||||||
|
uint8_t wrapped_key[32];
|
||||||
|
uint8_t tag[AES_256_GCM_TAG_SIZE];
|
||||||
|
} __packed PvHdrKeySlot;
|
||||||
|
|
||||||
|
typedef struct pv_hdr_opt_item {
|
||||||
|
uint32_t otype;
|
||||||
|
uint8_t ibk[32];
|
||||||
|
uint8_t data[];
|
||||||
|
} __packed PvHdrOptItem;
|
||||||
|
|
||||||
|
/* integrity protected data (by GCM tag), but non-encrypted */
|
||||||
|
struct pv_hdr_head {
|
||||||
|
uint64_t magic;
|
||||||
|
uint32_t version;
|
||||||
|
uint32_t phs;
|
||||||
|
uint8_t iv[AES_256_GCM_IV_SIZE];
|
||||||
|
uint32_t res1;
|
||||||
|
uint64_t nks;
|
||||||
|
uint64_t sea;
|
||||||
|
uint64_t nep;
|
||||||
|
uint64_t pcf;
|
||||||
|
union ecdh_pub_key cust_pub_key;
|
||||||
|
uint8_t pld[SHA512_DIGEST_LENGTH];
|
||||||
|
uint8_t ald[SHA512_DIGEST_LENGTH];
|
||||||
|
uint8_t tld[SHA512_DIGEST_LENGTH];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
/* Must not have any padding */
|
||||||
|
struct pv_hdr_encrypted {
|
||||||
|
uint8_t cust_comm_key[32];
|
||||||
|
uint8_t img_enc_key_1[AES_256_XTS_KEY_SIZE / 2];
|
||||||
|
uint8_t img_enc_key_2[AES_256_XTS_KEY_SIZE / 2];
|
||||||
|
struct psw_t psw;
|
||||||
|
uint64_t scf;
|
||||||
|
uint32_t noi;
|
||||||
|
uint32_t res2;
|
||||||
|
};
|
||||||
|
STATIC_ASSERT(sizeof(struct pv_hdr_encrypted) ==
|
||||||
|
32 + 32 + 32 + sizeof(struct psw_t) + 8 + 4 + 4)
|
||||||
|
|
||||||
|
typedef struct pv_hdr {
|
||||||
|
struct pv_hdr_head head;
|
||||||
|
struct pv_hdr_key_slot *slots;
|
||||||
|
struct pv_hdr_encrypted *encrypted;
|
||||||
|
struct pv_hdr_opt_item **optional_items;
|
||||||
|
uint8_t tag[AES_256_GCM_TAG_SIZE];
|
||||||
|
} PvHdr;
|
||||||
|
|
||||||
|
#endif
|
||||||
405
genprotimg/src/pv/pv_args.c
Normal file
405
genprotimg/src/pv/pv_args.c
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
/*
|
||||||
|
* PV arguments related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gprintf.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
#include "pv_error.h"
|
||||||
|
#include "pv_args.h"
|
||||||
|
|
||||||
|
static gchar summary[] =
|
||||||
|
"Use genprotimg to create a protected virtualization kernel image file,\n"
|
||||||
|
"which can be loaded using zipl or QEMU.";
|
||||||
|
|
||||||
|
static gint pv_arg_compare(gconstpointer arg_1, gconstpointer arg_2)
|
||||||
|
{
|
||||||
|
g_assert(arg_1);
|
||||||
|
g_assert(arg_2);
|
||||||
|
|
||||||
|
PvComponentType a = ((PvArg *)arg_1)->type;
|
||||||
|
PvComponentType b = ((PvArg *)arg_2)->type;
|
||||||
|
|
||||||
|
if (a < b)
|
||||||
|
return -1;
|
||||||
|
if (a == b)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_arg_has_type(gconstpointer arg, gconstpointer type)
|
||||||
|
{
|
||||||
|
const PvArg *c = arg;
|
||||||
|
const PvComponentType *t = type;
|
||||||
|
|
||||||
|
g_assert(arg);
|
||||||
|
|
||||||
|
if (c->type == *t)
|
||||||
|
return 0;
|
||||||
|
if (c->type < *t)
|
||||||
|
return -1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_args_set_defaults(PvArgs *args, GError **err G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
if (!args->psw_addr)
|
||||||
|
args->psw_addr =
|
||||||
|
g_strdup_printf("0x%lx", DEFAULT_INITIAL_PSW_ADDR);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_args_validate_options(PvArgs *args, GError **err)
|
||||||
|
{
|
||||||
|
PvComponentType KERNEL = PV_COMP_TYPE_KERNEL;
|
||||||
|
|
||||||
|
if (args->unused_values->len > 0) {
|
||||||
|
g_autofree gchar *unused = NULL;
|
||||||
|
|
||||||
|
for (gsize i = args->unused_values->len; i > 0; i--) {
|
||||||
|
g_autofree gchar *tmp = unused;
|
||||||
|
|
||||||
|
unused = g_strjoin(" ", g_ptr_array_index(args->unused_values, i - 1),
|
||||||
|
tmp,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_INVALID_ARGUMENT,
|
||||||
|
_("Unrecognized arguments: '%s'.\nUse 'genprotimg --help' for more information"),
|
||||||
|
unused);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args->output_path) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Option '--output' is required.\nUse 'genprotimg --help' for more information"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!g_slist_find_custom(args->comps, &KERNEL, pv_arg_has_type)) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Option '--image' is required.\nUse 'genprotimg --help' for more information"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args->host_keys || g_strv_length(args->host_keys) == 0) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Option '--host-key-document' is required.\nUse 'genprotimg --help' for more information"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!args->no_verify) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
_("Use the option '--no-verify' as the verification support is not available yet."));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean cb_add_component(const gchar *option, const gchar *value,
|
||||||
|
PvArgs *args, GError **err)
|
||||||
|
{
|
||||||
|
PvArg *comp = NULL;
|
||||||
|
gint type = -1;
|
||||||
|
|
||||||
|
if (g_str_equal(option, "-i") || g_str_equal(option, "--image"))
|
||||||
|
type = PV_COMP_TYPE_KERNEL;
|
||||||
|
if (g_str_equal(option, "-r") || g_str_equal(option, "--ramdisk"))
|
||||||
|
type = PV_COMP_TYPE_INITRD;
|
||||||
|
if (g_str_equal(option, "-p") || g_str_equal(option, "--parmfile"))
|
||||||
|
type = PV_COMP_TYPE_CMDLINE;
|
||||||
|
|
||||||
|
if (type < 0) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||||
|
_("Invalid option '%s': "), option);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_slist_find_custom(args->comps, &type, pv_arg_has_type)) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||||
|
_("Multiple values for option '%s'"), option);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
comp = pv_arg_new((PvComponentType)type, value);
|
||||||
|
args->comps = g_slist_insert_sorted(args->comps, comp, pv_arg_compare);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean cb_set_string_option(const gchar *option, const gchar *value,
|
||||||
|
PvArgs *args, GError **err)
|
||||||
|
{
|
||||||
|
gchar **args_option = NULL;
|
||||||
|
|
||||||
|
if (g_str_equal(option, "-o") || g_str_equal(option, "--output"))
|
||||||
|
args_option = &args->output_path;
|
||||||
|
if (g_str_equal(option, "--x-comp-key"))
|
||||||
|
args_option = &args->xts_key_path;
|
||||||
|
if (g_str_equal(option, "--x-comm-key"))
|
||||||
|
args_option = &args->cust_comm_key_path;
|
||||||
|
if (g_str_equal(option, "--x-header-key"))
|
||||||
|
args_option = &args->cust_root_key_path;
|
||||||
|
if (g_str_equal(option, "--x-pcf"))
|
||||||
|
args_option = &args->pcf;
|
||||||
|
if (g_str_equal(option, "--x-psw"))
|
||||||
|
args_option = &args->psw_addr;
|
||||||
|
if (g_str_equal(option, "--x-scf"))
|
||||||
|
args_option = &args->scf;
|
||||||
|
|
||||||
|
if (!args_option) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||||
|
_("Invalid option '%s': "), option);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*args_option) {
|
||||||
|
g_set_error(err, PV_PARSE_ERROR, PV_PARSE_ERROR_SYNTAX,
|
||||||
|
_("Multiple values for option '%s'"), option);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*args_option = g_strdup(value);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean cb_set_log_level(const gchar *option G_GNUC_UNUSED,
|
||||||
|
const gchar *value G_GNUC_UNUSED, PvArgs *args,
|
||||||
|
GError **err G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
args->log_level++;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean cb_remaining_values(const gchar *option G_GNUC_UNUSED,
|
||||||
|
const gchar *value, PvArgs *args,
|
||||||
|
GError **err G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
g_ptr_array_add(args->unused_values, g_strdup(value));
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define INDENT " "
|
||||||
|
|
||||||
|
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(GOptionContext) context = NULL;
|
||||||
|
gboolean print_version = FALSE;
|
||||||
|
GOptionGroup *group, *x_group;
|
||||||
|
|
||||||
|
g_autofree gchar *psw_desc = g_strdup_printf(
|
||||||
|
_("Load from the specified hexadecimal ADDRESS.\n" INDENT
|
||||||
|
"Optional; default: '0x%lx'."),
|
||||||
|
DEFAULT_INITIAL_PSW_ADDR);
|
||||||
|
GOptionEntry entries[] = {
|
||||||
|
{ .long_name = "host-key-document",
|
||||||
|
.short_name = 'k',
|
||||||
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
|
.arg = G_OPTION_ARG_FILENAME_ARRAY,
|
||||||
|
.arg_data = &args->host_keys,
|
||||||
|
.description =
|
||||||
|
_("FILE specifies a host-key document. At least\n" INDENT
|
||||||
|
"one is required."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
|
{ .long_name = "output",
|
||||||
|
.short_name = 'o',
|
||||||
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _("Set FILE as the output file."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
|
{ .long_name = "image",
|
||||||
|
.short_name = 'i',
|
||||||
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_add_component,
|
||||||
|
.description = _("Use IMAGE as the Linux kernel image."),
|
||||||
|
.arg_description = _("IMAGE") },
|
||||||
|
{ .long_name = "ramdisk",
|
||||||
|
.short_name = 'r',
|
||||||
|
.flags = G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_add_component,
|
||||||
|
.description = _("Use RAMDISK as the initial RAM disk\n" INDENT
|
||||||
|
"(optional)."),
|
||||||
|
.arg_description = _("RAMDISK") },
|
||||||
|
{ .long_name = "parmfile",
|
||||||
|
.short_name = 'p',
|
||||||
|
.flags = G_OPTION_FLAG_OPTIONAL_ARG | G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_add_component,
|
||||||
|
.description = _("Use the kernel parameters stored in PARMFILE\n" INDENT
|
||||||
|
"(optional)."),
|
||||||
|
.arg_description = _("PARMFILE") },
|
||||||
|
{ .long_name = "no-verify",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
|
.arg = G_OPTION_ARG_NONE,
|
||||||
|
.arg_data = &args->no_verify,
|
||||||
|
.description = _("Disable the host-key document verification\n" INDENT
|
||||||
|
"(optional)."),
|
||||||
|
.arg_description = NULL },
|
||||||
|
{ .long_name = "verbose",
|
||||||
|
.short_name = 'V',
|
||||||
|
.flags = G_OPTION_FLAG_NO_ARG,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_log_level,
|
||||||
|
.description = _("Provide more detailed output (optional)."),
|
||||||
|
.arg_description = NULL },
|
||||||
|
{ .long_name = "version",
|
||||||
|
.short_name = 'v',
|
||||||
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
|
.arg = G_OPTION_ARG_NONE,
|
||||||
|
.arg_data = &print_version,
|
||||||
|
.description = _("Print the version and exit."),
|
||||||
|
.arg_description = NULL },
|
||||||
|
{ .long_name = G_OPTION_REMAINING,
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = 0,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_remaining_values,
|
||||||
|
.description = NULL,
|
||||||
|
.arg_description = NULL },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
GOptionEntry x_entries[] = {
|
||||||
|
{ .long_name = "x-comm-key",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _(
|
||||||
|
"Use FILE as the customer communication key.\n" INDENT
|
||||||
|
"Optional; default: auto-generated."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
|
{ .long_name = "x-comp-key",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _(
|
||||||
|
"Use FILE as the AES 256-bit XTS key\n" INDENT
|
||||||
|
"that is used for the component encryption.\n" INDENT
|
||||||
|
"Optional; default: auto-generated."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
|
{ .long_name = "x-header-key",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_FILENAME,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _(
|
||||||
|
"Use FILE as the AES 256-bit GCM header key\n" INDENT
|
||||||
|
"that protects the PV header.\n" INDENT
|
||||||
|
"Optional; default: auto-generated."),
|
||||||
|
.arg_description = _("FILE") },
|
||||||
|
{ .long_name = "x-pcf",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description =
|
||||||
|
_("Specify the plaintext control flags\n" INDENT
|
||||||
|
"as a hexadecimal value.\n" INDENT
|
||||||
|
"Optional; default: '0x0'."),
|
||||||
|
.arg_description = _("VALUE") },
|
||||||
|
{ .long_name = "x-psw",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = psw_desc,
|
||||||
|
.arg_description = _("ADDRESS") },
|
||||||
|
{ .long_name = "x-scf",
|
||||||
|
.short_name = 0,
|
||||||
|
.flags = G_OPTION_FLAG_NONE,
|
||||||
|
.arg = G_OPTION_ARG_CALLBACK,
|
||||||
|
.arg_data = cb_set_string_option,
|
||||||
|
.description = _("Specify the secret control flags\n" INDENT
|
||||||
|
"as a hexadecimal value.\n" INDENT
|
||||||
|
"Optional; default: '0x0'."),
|
||||||
|
.arg_description = _("VALUE") },
|
||||||
|
{ 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
context = g_option_context_new(
|
||||||
|
_("- Create a protected virtualization image"));
|
||||||
|
g_option_context_set_summary(context, _(summary));
|
||||||
|
group = g_option_group_new(GETTEXT_PACKAGE, _("Application Options:"),
|
||||||
|
_("Show help options"), args, NULL);
|
||||||
|
g_option_group_add_entries(group, entries);
|
||||||
|
g_option_context_set_main_group(context, group);
|
||||||
|
|
||||||
|
x_group = g_option_group_new("experimental", _("Experimental Options:"),
|
||||||
|
_("Show experimental options"), args, NULL);
|
||||||
|
g_option_group_add_entries(x_group, x_entries);
|
||||||
|
g_option_context_add_group(context, x_group);
|
||||||
|
if (!g_option_context_parse(context, argc, argv, err))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (print_version) {
|
||||||
|
g_printf(_("%s version %s\n"), tool_name, RELEASE_STRING);
|
||||||
|
g_printf("%s\n", copyright_notice);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pv_args_set_defaults(args, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return pv_args_validate_options(args, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
PvArgs *pv_args_new(void)
|
||||||
|
{
|
||||||
|
g_autoptr(PvArgs) args = g_new0(PvArgs, 1);
|
||||||
|
|
||||||
|
args->unused_values = g_ptr_array_new_with_free_func(g_free);
|
||||||
|
return g_steal_pointer(&args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pv_args_free(PvArgs *args)
|
||||||
|
{
|
||||||
|
if (!args)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(args->pcf);
|
||||||
|
g_free(args->scf);
|
||||||
|
g_free(args->psw_addr);
|
||||||
|
g_free(args->cust_root_key_path);
|
||||||
|
g_free(args->cust_comm_key_path);
|
||||||
|
g_free(args->gcm_iv_path);
|
||||||
|
g_strfreev(args->host_keys);
|
||||||
|
g_free(args->xts_key_path);
|
||||||
|
g_slist_free_full(args->comps, (GDestroyNotify)pv_arg_free);
|
||||||
|
g_ptr_array_free(args->unused_values, TRUE);
|
||||||
|
g_free(args->output_path);
|
||||||
|
g_free(args->tmp_dir);
|
||||||
|
g_free(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pv_arg_free(PvArg *arg)
|
||||||
|
{
|
||||||
|
if (!arg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(arg->path);
|
||||||
|
g_free(arg);
|
||||||
|
}
|
||||||
|
PvArg *pv_arg_new(PvComponentType type, const gchar *path)
|
||||||
|
{
|
||||||
|
g_autoptr(PvArg) ret = g_new0(struct pv_arg, 1);
|
||||||
|
|
||||||
|
ret->type = type;
|
||||||
|
ret->path = g_strdup(path);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
53
genprotimg/src/pv/pv_args.h
Normal file
53
genprotimg/src/pv/pv_args.h
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* PV arguments related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_ARGS_H
|
||||||
|
#define PV_ARGS_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
|
||||||
|
typedef struct pv_arg {
|
||||||
|
PvComponentType type;
|
||||||
|
gchar *path;
|
||||||
|
} PvArg;
|
||||||
|
|
||||||
|
PvArg *pv_arg_new(PvComponentType type, const gchar *path);
|
||||||
|
void pv_arg_free(PvArg *arg);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gint log_level;
|
||||||
|
gint no_verify;
|
||||||
|
gchar *pcf;
|
||||||
|
gchar *scf;
|
||||||
|
gchar *psw_addr; /* PSW address which will be used for the start of
|
||||||
|
* the actual component (e.g. Linux kernel)
|
||||||
|
*/
|
||||||
|
gchar *cust_root_key_path;
|
||||||
|
gchar *cust_comm_key_path;
|
||||||
|
gchar *gcm_iv_path;
|
||||||
|
gchar **host_keys;
|
||||||
|
gchar *xts_key_path;
|
||||||
|
GSList *comps;
|
||||||
|
gchar *output_path;
|
||||||
|
gchar *tmp_dir;
|
||||||
|
GPtrArray *unused_values;
|
||||||
|
} PvArgs;
|
||||||
|
|
||||||
|
PvArgs *pv_args_new(void);
|
||||||
|
void pv_args_free(PvArgs *args);
|
||||||
|
|
||||||
|
gint pv_args_parse_options(PvArgs *args, gint *argc, gchar **argv[],
|
||||||
|
GError **err);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvArg, pv_arg_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvArgs, pv_args_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
446
genprotimg/src/pv/pv_comp.c
Normal file
446
genprotimg/src/pv/pv_comp.c
Normal file
@@ -0,0 +1,446 @@
|
|||||||
|
/*
|
||||||
|
* PV component related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "utils/align.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
#include "utils/file_utils.h"
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
#include "pv_error.h"
|
||||||
|
|
||||||
|
static void comp_file_free(CompFile *comp)
|
||||||
|
{
|
||||||
|
if (!comp)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(comp->path);
|
||||||
|
g_free(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(CompFile, comp_file_free)
|
||||||
|
|
||||||
|
static PvComponent *pv_component_new(PvComponentType type, gsize size,
|
||||||
|
PvComponentDataType d_type, void **data,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(PvComponent) ret = g_new0(PvComponent, 1);
|
||||||
|
|
||||||
|
g_assert(type >= 0 && type <= UINT16_MAX);
|
||||||
|
|
||||||
|
ret->type = (int)type;
|
||||||
|
ret->d_type = (int)d_type;
|
||||||
|
ret->data = g_steal_pointer(data);
|
||||||
|
ret->orig_size = size;
|
||||||
|
|
||||||
|
if (generate_tweak(&ret->tweak, (uint16_t)type, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(CompFile) file = g_new0(CompFile, 1);
|
||||||
|
gsize size;
|
||||||
|
gint rc;
|
||||||
|
|
||||||
|
g_assert(path != NULL);
|
||||||
|
|
||||||
|
rc = file_size(path, &size, err);
|
||||||
|
if (rc < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
file->path = g_strdup(path);
|
||||||
|
file->size = size;
|
||||||
|
return pv_component_new(type, size, DATA_FILE, (void **)&file, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_assert(buf);
|
||||||
|
|
||||||
|
g_autoptr(Buffer) dup_buf = buffer_dup(buf, FALSE);
|
||||||
|
return pv_component_new(type, buf->size, DATA_BUFFER, (void **)&dup_buf,
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pv_component_free(PvComponent *component)
|
||||||
|
{
|
||||||
|
if (!component)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch ((PvComponentDataType)component->d_type) {
|
||||||
|
case DATA_BUFFER:
|
||||||
|
buffer_clear(&component->buf);
|
||||||
|
break;
|
||||||
|
case DATA_FILE:
|
||||||
|
comp_file_free(component->file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_component_type(const PvComponent *component)
|
||||||
|
{
|
||||||
|
return component->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
const gchar *pv_component_name(const PvComponent *component)
|
||||||
|
{
|
||||||
|
gint type = pv_component_type(component);
|
||||||
|
|
||||||
|
switch ((PvComponentType)type) {
|
||||||
|
case PV_COMP_TYPE_KERNEL:
|
||||||
|
return "kernel";
|
||||||
|
case PV_COMP_TYPE_INITRD:
|
||||||
|
return "ramdisk";
|
||||||
|
case PV_COMP_TYPE_CMDLINE:
|
||||||
|
return "parmline";
|
||||||
|
case PV_COMP_TYPE_STAGE3B:
|
||||||
|
return "stage3b";
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pv_component_size(const PvComponent *component)
|
||||||
|
{
|
||||||
|
switch ((PvComponentDataType)component->d_type) {
|
||||||
|
case DATA_BUFFER:
|
||||||
|
return component->buf->size;
|
||||||
|
case DATA_FILE:
|
||||||
|
return component->file->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pv_component_get_src_addr(const PvComponent *component)
|
||||||
|
{
|
||||||
|
return component->src_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pv_component_get_orig_size(const PvComponent *component)
|
||||||
|
{
|
||||||
|
return component->orig_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pv_component_get_tweak_prefix(const PvComponent *component)
|
||||||
|
{
|
||||||
|
return GUINT64_FROM_BE(component->tweak.cmp_idx.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean pv_component_is_stage3b(const PvComponent *component)
|
||||||
|
{
|
||||||
|
return pv_component_type(component) == PV_COMP_TYPE_STAGE3B;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_path,
|
||||||
|
void *opaque, GError **err)
|
||||||
|
{
|
||||||
|
struct cipher_parms *parms = opaque;
|
||||||
|
|
||||||
|
switch ((PvComponentDataType)component->d_type) {
|
||||||
|
case DATA_BUFFER: {
|
||||||
|
g_autoptr(Buffer) enc_buf = NULL;
|
||||||
|
|
||||||
|
if (!(IS_PAGE_ALIGNED(pv_component_size(component)))) {
|
||||||
|
g_autoptr(Buffer) new = NULL;
|
||||||
|
|
||||||
|
/* create a page aligned copy */
|
||||||
|
new = buffer_dup(component->buf, TRUE);
|
||||||
|
buffer_clear(&component->buf);
|
||||||
|
component->buf = g_steal_pointer(&new);
|
||||||
|
}
|
||||||
|
enc_buf = encrypt_buf(parms, component->buf, err);
|
||||||
|
if (!enc_buf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
buffer_clear(&component->buf);
|
||||||
|
component->buf = g_steal_pointer(&enc_buf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case DATA_FILE: {
|
||||||
|
const gchar *comp_name = pv_component_name(component);
|
||||||
|
gchar *path_in = component->file->path;
|
||||||
|
g_autofree gchar *path_out = NULL;
|
||||||
|
gsize orig_size;
|
||||||
|
gsize prep_size;
|
||||||
|
|
||||||
|
g_assert(path_in);
|
||||||
|
|
||||||
|
path_out = g_build_filename(tmp_path, comp_name, NULL);
|
||||||
|
if (encrypt_file(parms, path_in, path_out, &orig_size,
|
||||||
|
&prep_size, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (component->orig_size != orig_size) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("File has changed during the preparation '%s'"),
|
||||||
|
path_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(component->file->path);
|
||||||
|
component->file->size = prep_size;
|
||||||
|
component->file->path = g_steal_pointer(&path_out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Page align the size of the component */
|
||||||
|
gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
||||||
|
void *opaque G_GNUC_UNUSED, GError **err)
|
||||||
|
{
|
||||||
|
if (IS_PAGE_ALIGNED(pv_component_size(component)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
switch (component->d_type) {
|
||||||
|
case DATA_BUFFER: {
|
||||||
|
g_autoptr(Buffer) buf = NULL;
|
||||||
|
|
||||||
|
buf = buffer_dup(component->buf, TRUE);
|
||||||
|
buffer_clear(&component->buf);
|
||||||
|
component->buf = g_steal_pointer(&buf);
|
||||||
|
return 0;
|
||||||
|
} break;
|
||||||
|
case DATA_FILE: {
|
||||||
|
const gchar *comp_name = pv_component_name(component);
|
||||||
|
g_autofree gchar *path_out =
|
||||||
|
g_build_filename(tmp_path, comp_name, NULL);
|
||||||
|
gchar *path_in = component->file->path;
|
||||||
|
gsize size_out;
|
||||||
|
|
||||||
|
if (pad_file_right(path_out, path_in, &size_out, PAGE_SIZE,
|
||||||
|
err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_free(component->file->path);
|
||||||
|
component->file->path = g_steal_pointer(&path_out);
|
||||||
|
component->file->size = size_out;
|
||||||
|
return 0;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert uint64_t address to byte array */
|
||||||
|
static void uint64_to_uint8_buf(uint8_t dst[8], uint64_t addr)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)&addr;
|
||||||
|
|
||||||
|
g_assert(dst);
|
||||||
|
|
||||||
|
for (gint i = 0; i < 8; i++) {
|
||||||
|
/* cppcheck-suppress objectIndex */
|
||||||
|
dst[i] = p[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
uint64_t addr = pv_component_get_src_addr(comp);
|
||||||
|
uint64_t size = pv_component_size(comp);
|
||||||
|
uint64_t cur = addr;
|
||||||
|
int64_t nep = 0;
|
||||||
|
|
||||||
|
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
|
||||||
|
|
||||||
|
do {
|
||||||
|
uint64_t cur_be = GUINT64_TO_BE(cur);
|
||||||
|
uint8_t addr_buf[8];
|
||||||
|
|
||||||
|
uint64_to_uint8_buf(addr_buf, cur_be);
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, addr_buf, sizeof(addr_buf)) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestUpdate failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur += PAGE_SIZE;
|
||||||
|
nep++;
|
||||||
|
} while (cur < addr + size);
|
||||||
|
|
||||||
|
return nep;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
uint64_t size = pv_component_size(comp);
|
||||||
|
int64_t nep = 0;
|
||||||
|
|
||||||
|
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
|
||||||
|
|
||||||
|
switch (comp->d_type) {
|
||||||
|
case DATA_BUFFER: {
|
||||||
|
const Buffer *buf = comp->buf;
|
||||||
|
|
||||||
|
g_assert(buf->size <= INT64_MAX);
|
||||||
|
g_assert(buf->size == size);
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, buf->data, buf->size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestUpdate failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nep = (int64_t)(buf->size / PAGE_SIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DATA_FILE: {
|
||||||
|
const gchar *in_path = comp->file->path;
|
||||||
|
guchar in_buf[PAGE_SIZE];
|
||||||
|
gsize num_bytes_read_total = 0;
|
||||||
|
gsize num_bytes_read = 0;
|
||||||
|
FILE *f_in;
|
||||||
|
|
||||||
|
f_in = file_open(in_path, "rb", err);
|
||||||
|
if (!f_in)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
/* Read data in blocks. Update the digest
|
||||||
|
* context each read.
|
||||||
|
*/
|
||||||
|
if (file_read(f_in, in_buf, sizeof(*in_buf),
|
||||||
|
sizeof(in_buf), &num_bytes_read,
|
||||||
|
err) < 0) {
|
||||||
|
fclose(f_in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
num_bytes_read_total += num_bytes_read;
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, in_buf, sizeof(in_buf)) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestUpdate failed"));
|
||||||
|
fclose(f_in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
nep++;
|
||||||
|
} while (num_bytes_read_total < pv_component_size(comp) &&
|
||||||
|
num_bytes_read != 0);
|
||||||
|
|
||||||
|
if (num_bytes_read_total != pv_component_size(comp)) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("'%s' has changed during the preparation"),
|
||||||
|
in_path);
|
||||||
|
fclose(f_in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
fclose(f_in);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
return nep;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
uint64_t size = pv_component_size(comp);
|
||||||
|
const union tweak *tweak = &comp->tweak;
|
||||||
|
g_autoptr(BIGNUM) tweak_num = NULL;
|
||||||
|
int64_t nep = 0;
|
||||||
|
|
||||||
|
g_assert(IS_PAGE_ALIGNED(size) && size != 0);
|
||||||
|
|
||||||
|
tweak_num = BN_bin2bn(tweak->data, sizeof(tweak->data), NULL);
|
||||||
|
if (!tweak_num) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("BN_bin2bn failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint64_t cur = 0; cur < size; cur += PAGE_SIZE) {
|
||||||
|
guchar tmp[sizeof(tweak->data)] = { 0 };
|
||||||
|
|
||||||
|
g_assert(BN_num_bytes(tweak_num) >= 0);
|
||||||
|
g_assert(sizeof(tmp) - (guint)BN_num_bytes(tweak_num) > 0);
|
||||||
|
|
||||||
|
if (BN_bn2binpad(tweak_num, tmp, sizeof(tmp)) < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("BN_bn2binpad failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(ctx, tmp, sizeof(tmp)) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestUpdate failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* calculate new tweak value */
|
||||||
|
if (BN_add_word(tweak_num, PAGE_SIZE) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("BN_add_word failed"));
|
||||||
|
}
|
||||||
|
|
||||||
|
nep++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nep;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_component_write(const PvComponent *component, FILE *f, GError **err)
|
||||||
|
{
|
||||||
|
uint64_t offset = pv_component_get_src_addr(component);
|
||||||
|
|
||||||
|
g_assert(f);
|
||||||
|
|
||||||
|
switch (component->d_type) {
|
||||||
|
case DATA_BUFFER: {
|
||||||
|
const Buffer *buf = component->buf;
|
||||||
|
|
||||||
|
if (seek_and_write_buffer(f, buf, offset, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
case DATA_FILE: {
|
||||||
|
const CompFile *file = component->file;
|
||||||
|
|
||||||
|
if (seek_and_write_file(f, file, offset, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
78
genprotimg/src/pv/pv_comp.h
Normal file
78
genprotimg/src/pv/pv_comp.h
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* PV component related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_COMP_H
|
||||||
|
#define PV_COMP_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
|
||||||
|
/* The order of this enum also implicitly defines the order of the
|
||||||
|
* components within the PV image!
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
PV_COMP_TYPE_KERNEL = 0,
|
||||||
|
PV_COMP_TYPE_CMDLINE = 1,
|
||||||
|
PV_COMP_TYPE_INITRD = 2,
|
||||||
|
PV_COMP_TYPE_STAGE3B = 3,
|
||||||
|
} PvComponentType;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DATA_FILE = 0,
|
||||||
|
DATA_BUFFER,
|
||||||
|
} PvComponentDataType;
|
||||||
|
|
||||||
|
typedef struct comp_file {
|
||||||
|
gchar *path;
|
||||||
|
gsize size;
|
||||||
|
} CompFile;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gint type; /* PvComponentType */
|
||||||
|
gint d_type; /* PvComponentDataType */
|
||||||
|
union {
|
||||||
|
struct comp_file *file;
|
||||||
|
Buffer *buf;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
uint64_t src_addr;
|
||||||
|
uint64_t orig_size;
|
||||||
|
union tweak tweak; /* used for the AES XTS encryption */
|
||||||
|
} PvComponent;
|
||||||
|
|
||||||
|
PvComponent *pv_component_new_file(PvComponentType type, const gchar *path,
|
||||||
|
GError **err);
|
||||||
|
PvComponent *pv_component_new_buf(PvComponentType type, const Buffer *buf,
|
||||||
|
GError **err);
|
||||||
|
void pv_component_free(PvComponent *component);
|
||||||
|
gint pv_component_type(const PvComponent *component);
|
||||||
|
const gchar *pv_component_name(const PvComponent *component);
|
||||||
|
uint64_t pv_component_size(const PvComponent *component);
|
||||||
|
uint64_t pv_component_get_src_addr(const PvComponent *component);
|
||||||
|
uint64_t pv_component_get_orig_size(const PvComponent *component);
|
||||||
|
uint64_t pv_component_get_tweak_prefix(const PvComponent *component);
|
||||||
|
gboolean pv_component_is_stage3b(const PvComponent *component);
|
||||||
|
gint pv_component_align_and_encrypt(PvComponent *component, const gchar *tmp_path,
|
||||||
|
void *opaque, GError **err);
|
||||||
|
gint pv_component_align(PvComponent *component, const gchar *tmp_path,
|
||||||
|
void *opaque G_GNUC_UNUSED, GError **err);
|
||||||
|
int64_t pv_component_update_pld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
|
GError **err);
|
||||||
|
int64_t pv_component_update_ald(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
|
GError **err);
|
||||||
|
int64_t pv_component_update_tld(const PvComponent *comp, EVP_MD_CTX *ctx,
|
||||||
|
GError **err);
|
||||||
|
gint pv_component_write(const PvComponent *component, FILE *f, GError **err);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvComponent, pv_component_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
252
genprotimg/src/pv/pv_comps.c
Normal file
252
genprotimg/src/pv/pv_comps.c
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
/*
|
||||||
|
* PV components related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/stage3b.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "utils/align.h"
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
#include "pv_comps.h"
|
||||||
|
#include "pv_error.h"
|
||||||
|
#include "pv_stage3.h"
|
||||||
|
|
||||||
|
struct _pv_img_comps {
|
||||||
|
gboolean finalized;
|
||||||
|
uint64_t next_src;
|
||||||
|
uint64_t nep;
|
||||||
|
EVP_MD_CTX *ald; /* context used for the hash of the addresses */
|
||||||
|
EVP_MD_CTX *pld; /* context used for the hash of the pages content */
|
||||||
|
EVP_MD_CTX *tld; /* context used for the hash of the tweaks */
|
||||||
|
GSList *comps; /* elements sorted by component type */
|
||||||
|
};
|
||||||
|
|
||||||
|
void pv_img_comps_free(PvImgComps *comps)
|
||||||
|
{
|
||||||
|
if (!comps)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EVP_MD_CTX_free(comps->ald);
|
||||||
|
EVP_MD_CTX_free(comps->pld);
|
||||||
|
EVP_MD_CTX_free(comps->tld);
|
||||||
|
g_slist_free_full(comps->comps, (GDestroyNotify)pv_component_free);
|
||||||
|
g_free(comps);
|
||||||
|
}
|
||||||
|
|
||||||
|
PvImgComps *pv_img_comps_new(const EVP_MD *ald_md, const EVP_MD *pld_md,
|
||||||
|
const EVP_MD *tld_md, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(PvImgComps) ret = g_new0(PvImgComps, 1);
|
||||||
|
|
||||||
|
ret->ald = digest_ctx_new(ald_md, err);
|
||||||
|
if (!ret->ald)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret->pld = digest_ctx_new(pld_md, err);
|
||||||
|
if (!ret->pld)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret->tld = digest_ctx_new(tld_md, err);
|
||||||
|
if (!ret->tld)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
guint pv_img_comps_length(const PvImgComps *comps)
|
||||||
|
{
|
||||||
|
return g_slist_length(comps->comps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update hashes and nep */
|
||||||
|
/* Returns 0 in case of success and -1 in case of a failure */
|
||||||
|
static gint pv_img_comps_hash_comp(PvImgComps *comps, const PvComponent *comp,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
int64_t nep_1 = 0;
|
||||||
|
int64_t nep_2 = 0;
|
||||||
|
int64_t nep_3 = 0;
|
||||||
|
|
||||||
|
/* update pld */
|
||||||
|
nep_1 = pv_component_update_pld(comp, comps->pld, err);
|
||||||
|
if (nep_1 < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* update ald */
|
||||||
|
nep_2 = pv_component_update_ald(comp, comps->ald, err);
|
||||||
|
if (nep_2 < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* update tld */
|
||||||
|
nep_3 = pv_component_update_tld(comp, comps->tld, err);
|
||||||
|
if (nep_3 < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_assert(nep_1 == nep_2);
|
||||||
|
g_assert(nep_2 == nep_3);
|
||||||
|
|
||||||
|
/* update comps->nep */
|
||||||
|
g_assert_true(g_uint64_checked_add(&comps->nep, comps->nep,
|
||||||
|
(uint64_t)nep_1));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_assert(comp);
|
||||||
|
g_assert(*comp);
|
||||||
|
g_assert(comps);
|
||||||
|
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||||
|
|
||||||
|
uint64_t src_addr = comps->next_src;
|
||||||
|
uint64_t src_size = pv_component_size(*comp)
|
||||||
|
? PAGE_ALIGN(pv_component_size(*comp))
|
||||||
|
: PAGE_SIZE;
|
||||||
|
|
||||||
|
if (comps->finalized) {
|
||||||
|
g_set_error(err, PV_COMPONENT_ERROR, PV_COMPONENT_ERROR_FINALIZED,
|
||||||
|
_("Failed to add component, image is already finalized"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the address of the component in the memory layout */
|
||||||
|
(*comp)->src_addr = src_addr;
|
||||||
|
|
||||||
|
g_info("%12s:\t0x%012lx (%12ld / %12ld Bytes)",
|
||||||
|
pv_component_name(*comp), pv_component_get_src_addr(*comp),
|
||||||
|
pv_component_size(*comp), pv_component_get_orig_size(*comp));
|
||||||
|
|
||||||
|
/* append the component and pass the responsibility of @comp
|
||||||
|
* to @comps
|
||||||
|
*/
|
||||||
|
comps->comps = g_slist_append(comps->comps, g_steal_pointer(comp));
|
||||||
|
comps->next_src += src_size;
|
||||||
|
|
||||||
|
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||||
|
g_assert(!*comp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stage3b_args *pv_img_comps_get_stage3b_args(const PvImgComps *comps,
|
||||||
|
struct psw_t *psw)
|
||||||
|
{
|
||||||
|
g_autofree struct stage3b_args *ret = g_new0(struct stage3b_args, 1);
|
||||||
|
|
||||||
|
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
|
||||||
|
const PvComponent *img_comp = iterator->data;
|
||||||
|
uint64_t src_addr, dst_size;
|
||||||
|
|
||||||
|
g_assert(img_comp);
|
||||||
|
|
||||||
|
src_addr = pv_component_get_src_addr(img_comp);
|
||||||
|
dst_size = pv_component_get_orig_size(img_comp);
|
||||||
|
|
||||||
|
g_assert(dst_size <= pv_component_size(img_comp));
|
||||||
|
|
||||||
|
switch ((PvComponentType)pv_component_type(img_comp)) {
|
||||||
|
case PV_COMP_TYPE_KERNEL:
|
||||||
|
memblob_init(&ret->kernel, src_addr, dst_size);
|
||||||
|
break;
|
||||||
|
case PV_COMP_TYPE_CMDLINE:
|
||||||
|
memblob_init(&ret->cmdline, src_addr, dst_size);
|
||||||
|
break;
|
||||||
|
case PV_COMP_TYPE_INITRD:
|
||||||
|
memblob_init(&ret->initrd, src_addr, dst_size);
|
||||||
|
break;
|
||||||
|
case PV_COMP_TYPE_STAGE3B:
|
||||||
|
/* nothing needs to be done since it is the
|
||||||
|
* stage3b itself
|
||||||
|
*/
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* for `stage3b_args` big-endian format must be used */
|
||||||
|
ret->psw.mask = GUINT64_TO_BE(psw->mask);
|
||||||
|
ret->psw.addr = GUINT64_TO_BE(psw->addr);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err)
|
||||||
|
{
|
||||||
|
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||||
|
|
||||||
|
if (!IS_PAGE_ALIGNED(offset)) {
|
||||||
|
g_set_error(err, PV_IMAGE_ERROR, PV_IMAGE_ERROR_OFFSET,
|
||||||
|
_("Offset must be page aligned"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pv_img_comps_length(comps) > 0) {
|
||||||
|
g_set_error(err, PV_IMAGE_ERROR, PV_IMAGE_ERROR_OFFSET,
|
||||||
|
_("Offset cannot be changed after a component was added"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
comps->next_src += offset;
|
||||||
|
|
||||||
|
g_assert(IS_PAGE_ALIGNED(comps->next_src));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSList *pv_img_comps_get_comps(const PvImgComps *comps)
|
||||||
|
{
|
||||||
|
return comps->comps;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
|
||||||
|
Buffer **ald_digest, Buffer **tld_digest,
|
||||||
|
uint64_t *nep, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) tmp_pld_digest = NULL;
|
||||||
|
g_autoptr(Buffer) tmp_ald_digest = NULL;
|
||||||
|
g_autoptr(Buffer) tmp_tld_digest = NULL;
|
||||||
|
|
||||||
|
comps->finalized = TRUE;
|
||||||
|
for (GSList *iterator = comps->comps; iterator; iterator = iterator->next) {
|
||||||
|
const PvComponent *comp = iterator->data;
|
||||||
|
|
||||||
|
/* update hashes and nep */
|
||||||
|
if (pv_img_comps_hash_comp(comps, comp, err) < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp_pld_digest = digest_ctx_finalize(comps->pld, err);
|
||||||
|
if (!tmp_pld_digest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp_ald_digest = digest_ctx_finalize(comps->ald, err);
|
||||||
|
if (!tmp_ald_digest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
tmp_tld_digest = digest_ctx_finalize(comps->tld, err);
|
||||||
|
if (!tmp_tld_digest)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
*pld_digest = g_steal_pointer(&tmp_pld_digest);
|
||||||
|
*ald_digest = g_steal_pointer(&tmp_ald_digest);
|
||||||
|
*tld_digest = g_steal_pointer(&tmp_tld_digest);
|
||||||
|
*nep = comps->nep;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n)
|
||||||
|
{
|
||||||
|
return g_slist_nth_data(comps->comps, n);
|
||||||
|
}
|
||||||
42
genprotimg/src/pv/pv_comps.h
Normal file
42
genprotimg/src/pv/pv_comps.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* PV components related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_COMPS_H
|
||||||
|
#define PV_COMPS_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/stage3b.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
|
||||||
|
typedef struct _pv_img_comps PvImgComps;
|
||||||
|
|
||||||
|
PvImgComps *pv_img_comps_new(const EVP_MD *ald_md, const EVP_MD *pld_md,
|
||||||
|
const EVP_MD *tld_md, GError **err);
|
||||||
|
guint pv_img_comps_length(const PvImgComps *comps);
|
||||||
|
GSList *pv_img_comps_get_comps(const PvImgComps *comps);
|
||||||
|
struct stage3b_args *pv_img_comps_get_stage3b_args(const PvImgComps *comps,
|
||||||
|
struct psw_t *psw);
|
||||||
|
gint pv_img_comps_add_component(PvImgComps *comps, PvComponent **comp,
|
||||||
|
GError **err);
|
||||||
|
PvComponent *pv_img_comps_get_nth_comp(PvImgComps *comps, guint n);
|
||||||
|
gint pv_img_comps_set_offset(PvImgComps *comps, gsize offset, GError **err);
|
||||||
|
gint pv_img_comps_finalize(PvImgComps *comps, Buffer **pld_digest,
|
||||||
|
Buffer **ald_digest, Buffer **tld_digest,
|
||||||
|
uint64_t *nep, GError **err);
|
||||||
|
void pv_img_comps_free(PvImgComps *comps);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvImgComps, pv_img_comps_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
37
genprotimg/src/pv/pv_error.c
Normal file
37
genprotimg/src/pv/pv_error.c
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* PV error related functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "pv_error.h"
|
||||||
|
|
||||||
|
GQuark pv_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string("pv-error-quark");
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark pv_crypto_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string("pv-crypto-error-quark");
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark pv_component_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string("pv-component-error-quark");
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark pv_image_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string("pv-image-error-quark");
|
||||||
|
}
|
||||||
|
|
||||||
|
GQuark pv_parse_error_quark(void)
|
||||||
|
{
|
||||||
|
return g_quark_from_static_string("pv-parse-error-quark");
|
||||||
|
}
|
||||||
62
genprotimg/src/pv/pv_error.h
Normal file
62
genprotimg/src/pv/pv_error.h
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* PV error related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_ERROR_H
|
||||||
|
#define PV_ERROR_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
GQuark pv_error_quark(void);
|
||||||
|
GQuark pv_parse_error_quark(void);
|
||||||
|
GQuark pv_component_error_quark(void);
|
||||||
|
GQuark pv_crypto_error_quark(void);
|
||||||
|
GQuark pv_image_error_quark(void);
|
||||||
|
|
||||||
|
#define PV_ERROR pv_error_quark()
|
||||||
|
#define PV_PARSE_ERROR pv_parse_error_quark()
|
||||||
|
#define PV_CRYPTO_ERROR pv_crypto_error_quark()
|
||||||
|
#define PV_COMPONENT_ERROR pv_component_error_quark()
|
||||||
|
#define PV_IMAGE_ERROR pv_image_error_quark()
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PV_ERROR_IPIB_SIZE,
|
||||||
|
PV_ERROR_PV_HDR_SIZE,
|
||||||
|
PV_ERROR_INTERNAL,
|
||||||
|
} PvErrors;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PV_PARSE_ERROR_OK = 0,
|
||||||
|
PV_PARSE_ERROR_SYNTAX,
|
||||||
|
PR_PARSE_ERROR_INVALID_ARGUMENT,
|
||||||
|
PR_PARSE_ERROR_MISSING_ARGUMENT,
|
||||||
|
} PvParseErrors;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PV_COMPONENT_ERROR_UNALIGNED,
|
||||||
|
PV_COMPONENT_ERROR_FINALIZED,
|
||||||
|
} PvComponentErrors;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PV_IMAGE_ERROR_OFFSET,
|
||||||
|
PV_IMAGE_ERROR_FINALIZED,
|
||||||
|
} PvImageErrors;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PV_CRYPTO_ERROR_VERIFICATION,
|
||||||
|
PV_CRYPTO_ERROR_INIT,
|
||||||
|
PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
PV_CRYPTO_ERROR_DERIVE,
|
||||||
|
PV_CRYPTO_ERROR_KEYGENERATION,
|
||||||
|
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||||
|
PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||||
|
} PvCryptoErrors;
|
||||||
|
|
||||||
|
#endif
|
||||||
293
genprotimg/src/pv/pv_hdr.c
Normal file
293
genprotimg/src/pv/pv_hdr.c
Normal file
@@ -0,0 +1,293 @@
|
|||||||
|
/*
|
||||||
|
* PV header related functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "include/pv_crypto_def.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
#include "pv_hdr.h"
|
||||||
|
#include "pv_image.h"
|
||||||
|
|
||||||
|
void pv_hdr_free(PvHdr *hdr)
|
||||||
|
{
|
||||||
|
if (!hdr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(hdr->optional_items);
|
||||||
|
g_free(hdr->encrypted);
|
||||||
|
g_free(hdr->slots);
|
||||||
|
g_free(hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pv_hdr_size(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
return GUINT32_FROM_BE(hdr->head.phs);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean pv_hdr_uses_encryption(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
return !(GUINT64_FROM_BE(hdr->head.pcf) & PV_CFLAG_NO_DECRYPTION);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pv_hdr_enc_size(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
return GUINT64_FROM_BE(hdr->head.sea);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pv_hdr_enc_size_casted(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
uint64_t size = pv_hdr_enc_size(hdr);
|
||||||
|
|
||||||
|
if (size > UINT32_MAX)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
return (uint32_t)size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static guint pv_hdr_tag_size(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
return sizeof(hdr->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pv_hdr_aad_size(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
return pv_hdr_size(hdr) - pv_hdr_enc_size_casted(hdr) -
|
||||||
|
pv_hdr_tag_size(hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t pv_hdr_get_nks(const PvHdr *hdr)
|
||||||
|
{
|
||||||
|
return GUINT64_FROM_BE(hdr->head.nks);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In-place modification of ``buf`` */
|
||||||
|
static gint pv_hdr_encrypt(const PvHdr *hdr, const PvImage *img, Buffer *buf,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
uint32_t hdr_len = pv_hdr_size(hdr);
|
||||||
|
uint32_t aad_len = pv_hdr_aad_size(hdr);
|
||||||
|
guint tag_len = pv_hdr_tag_size(hdr);
|
||||||
|
uint32_t enc_len = pv_hdr_enc_size_casted(hdr);
|
||||||
|
const Buffer aad_part = { .data = buf->data, .size = aad_len };
|
||||||
|
Buffer enc_part = { .data = (uint8_t *)buf->data + aad_len,
|
||||||
|
.size = enc_len };
|
||||||
|
Buffer tag_part = { .data = (uint8_t *)buf->data + hdr_len - tag_len,
|
||||||
|
.size = tag_len };
|
||||||
|
struct cipher_parms parms;
|
||||||
|
int64_t c_len;
|
||||||
|
|
||||||
|
g_assert(aad_part.size + enc_part.size + tag_part.size == buf->size);
|
||||||
|
g_assert(img->cust_root_key->size <= INT_MAX);
|
||||||
|
g_assert(img->gcm_iv->size <= INT_MAX);
|
||||||
|
g_assert(EVP_CIPHER_key_length(img->gcm_cipher) ==
|
||||||
|
(int)img->cust_root_key->size);
|
||||||
|
g_assert(EVP_CIPHER_iv_length(img->gcm_cipher) == (int)img->gcm_iv->size);
|
||||||
|
|
||||||
|
parms.key = img->cust_root_key;
|
||||||
|
parms.iv_or_tweak = img->gcm_iv;
|
||||||
|
parms.cipher = img->gcm_cipher;
|
||||||
|
|
||||||
|
/* in-place encryption */
|
||||||
|
c_len = gcm_encrypt(&enc_part, &aad_part, &parms, &enc_part, &tag_part, err);
|
||||||
|
if (c_len < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_assert(c_len == enc_len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes the unencrypted, but integrity protected part of the PV
|
||||||
|
* header
|
||||||
|
*/
|
||||||
|
static gint pv_hdr_aad_init(PvHdr *hdr, const PvImage *img, GError **err)
|
||||||
|
{
|
||||||
|
g_autofree union ecdh_pub_key *cust_pub_key = NULL;
|
||||||
|
struct pv_hdr_key_slot *hdr_slot = hdr->slots;
|
||||||
|
struct pv_hdr_head *head = &hdr->head;
|
||||||
|
g_autoptr(Buffer) pld = NULL;
|
||||||
|
g_autoptr(Buffer) ald = NULL;
|
||||||
|
g_autoptr(Buffer) tld = NULL;
|
||||||
|
uint64_t nep = 0;
|
||||||
|
|
||||||
|
g_assert(sizeof(head->iv) == img->gcm_iv->size);
|
||||||
|
g_assert(sizeof(head->cust_pub_key) == sizeof(*cust_pub_key));
|
||||||
|
|
||||||
|
cust_pub_key = evp_pkey_to_ecdh_pub_key(img->cust_pub_priv_key, err);
|
||||||
|
if (!cust_pub_key)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
head->magic = GUINT64_TO_BE(PV_MAGIC_NUMBER);
|
||||||
|
head->version = GUINT32_TO_BE(PV_VERSION_1);
|
||||||
|
/* ``phs`` is already set so we can skip it here */
|
||||||
|
memcpy(head->iv, img->gcm_iv->data, sizeof(head->iv));
|
||||||
|
/* ``nks`` is already set so we can skip it here */
|
||||||
|
/* ``sea`` is already set so we can skip it here */
|
||||||
|
head->pcf = GUINT64_TO_BE(img->pcf);
|
||||||
|
memcpy(head->cust_pub_key.data, cust_pub_key,
|
||||||
|
sizeof(head->cust_pub_key));
|
||||||
|
|
||||||
|
if (pv_img_calc_pld_ald_tld_nep(img, &pld, &ald, &tld, &nep, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_assert(sizeof(head->pld) == pld->size);
|
||||||
|
g_assert(sizeof(head->ald) == ald->size);
|
||||||
|
g_assert(sizeof(head->tld) == tld->size);
|
||||||
|
|
||||||
|
head->nep = GUINT64_TO_BE(nep);
|
||||||
|
memcpy(head->pld, pld->data, sizeof(head->pld));
|
||||||
|
memcpy(head->ald, ald->data, sizeof(head->ald));
|
||||||
|
memcpy(head->tld, tld->data, sizeof(head->tld));
|
||||||
|
|
||||||
|
/* set the key slots */
|
||||||
|
for (GSList *iterator = img->key_slots; iterator; iterator = iterator->next) {
|
||||||
|
const PvHdrKeySlot *slot = iterator->data;
|
||||||
|
|
||||||
|
g_assert(slot);
|
||||||
|
|
||||||
|
/* the memory for the slots is pre-allocated so we
|
||||||
|
* have not to allocate and since PvHdrKeySlot is
|
||||||
|
* stored in the big-edian format we can simply use
|
||||||
|
* memcpy.
|
||||||
|
*/
|
||||||
|
memcpy(hdr_slot++, slot, sizeof(*slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initializes the encrypted and also integrity protected part of the
|
||||||
|
* PV header
|
||||||
|
*/
|
||||||
|
static gint pv_hdr_enc_init(PvHdr *hdr, const PvImage *img, GError **err)
|
||||||
|
{
|
||||||
|
struct pv_hdr_encrypted *enc = hdr->encrypted;
|
||||||
|
const PvComponent *stage3b;
|
||||||
|
struct psw_t psw;
|
||||||
|
|
||||||
|
g_assert(sizeof(enc->img_enc_key_1) + sizeof(enc->img_enc_key_2) ==
|
||||||
|
EVP_CIPHER_key_length(img->xts_cipher));
|
||||||
|
g_assert(sizeof(enc->cust_comm_key) == img->cust_comm_key->size);
|
||||||
|
g_assert(img->xts_key->size ==
|
||||||
|
(guint)EVP_CIPHER_key_length(img->xts_cipher));
|
||||||
|
|
||||||
|
stage3b = pv_img_get_stage3b_comp(img, err);
|
||||||
|
if (!stage3b)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memcpy(enc->cust_comm_key, img->cust_comm_key->data,
|
||||||
|
sizeof(enc->cust_comm_key));
|
||||||
|
memcpy(enc->img_enc_key_1, img->xts_key->data,
|
||||||
|
sizeof(enc->img_enc_key_1));
|
||||||
|
memcpy(enc->img_enc_key_2,
|
||||||
|
(uint8_t *)img->xts_key->data + sizeof(enc->img_enc_key_1),
|
||||||
|
sizeof(enc->img_enc_key_2));
|
||||||
|
|
||||||
|
/* Setup program check handler */
|
||||||
|
psw.mask = GUINT64_TO_BE(DEFAULT_INITIAL_PSW_MASK);
|
||||||
|
psw.addr = GUINT64_TO_BE(pv_component_get_src_addr(stage3b));
|
||||||
|
enc->psw = psw;
|
||||||
|
enc->scf = GUINT64_TO_BE(img->scf);
|
||||||
|
enc->noi = GUINT32_TO_BE(g_slist_length(img->optional_items));
|
||||||
|
|
||||||
|
/* set the optional items */
|
||||||
|
for (GSList *iterator = img->optional_items; iterator;
|
||||||
|
iterator = iterator->next) {
|
||||||
|
const struct pv_hdr_opt_item *item = iterator->data;
|
||||||
|
|
||||||
|
g_assert(item);
|
||||||
|
|
||||||
|
/* not supported in the first version */
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PvHdr *pv_hdr_new(const PvImage *img, GError **err)
|
||||||
|
{
|
||||||
|
uint32_t noi = g_slist_length(img->optional_items);
|
||||||
|
uint32_t hdr_size = pv_img_get_pv_hdr_size(img);
|
||||||
|
gsize nks = g_slist_length(img->key_slots);
|
||||||
|
uint32_t sea = pv_img_get_enc_size(img);
|
||||||
|
g_autoptr(PvHdr) ret = NULL;
|
||||||
|
|
||||||
|
g_assert(nks > 0);
|
||||||
|
/* must be a multiple of AES block size */
|
||||||
|
g_assert(sea % AES_BLOCK_SIZE == 0);
|
||||||
|
g_assert(sea >= sizeof(struct pv_hdr_encrypted));
|
||||||
|
|
||||||
|
ret = g_new0(PvHdr, 1);
|
||||||
|
ret->slots = g_new0(struct pv_hdr_key_slot, nks);
|
||||||
|
ret->head.phs = GUINT32_TO_BE(hdr_size);
|
||||||
|
ret->head.nks = GUINT64_TO_BE(nks);
|
||||||
|
ret->head.sea = GUINT64_TO_BE(sea);
|
||||||
|
|
||||||
|
ret->encrypted = g_new0(struct pv_hdr_encrypted, 1);
|
||||||
|
ret->optional_items = g_malloc0(sea - sizeof(struct pv_hdr_encrypted));
|
||||||
|
ret->encrypted->noi = GUINT32_TO_BE(noi);
|
||||||
|
|
||||||
|
if (pv_hdr_aad_init(ret, img, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (pv_hdr_enc_init(ret, img, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pv_hdr_memcpy(const PvHdr *hdr, const Buffer *dst)
|
||||||
|
{
|
||||||
|
uint64_t nks = pv_hdr_get_nks(hdr);
|
||||||
|
uint8_t *data;
|
||||||
|
|
||||||
|
g_assert(dst->size == pv_hdr_size(hdr));
|
||||||
|
g_assert(pv_hdr_enc_size_casted(hdr) >= sizeof(*hdr->encrypted));
|
||||||
|
|
||||||
|
data = memcpy(dst->data, &hdr->head, sizeof(hdr->head));
|
||||||
|
data = memcpy(data + sizeof(hdr->head), hdr->slots,
|
||||||
|
sizeof(struct pv_hdr_key_slot) * nks);
|
||||||
|
data = memcpy(data + sizeof(struct pv_hdr_key_slot) * nks,
|
||||||
|
hdr->encrypted, sizeof(*hdr->encrypted));
|
||||||
|
if (pv_hdr_enc_size_casted(hdr) - sizeof(*hdr->encrypted) > 0) {
|
||||||
|
(void)memcpy(data + sizeof(*hdr->encrypted),
|
||||||
|
hdr->optional_items,
|
||||||
|
pv_hdr_enc_size_casted(hdr) - sizeof(*hdr->encrypted));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
|
||||||
|
enum PvCryptoMode mode, GError **err)
|
||||||
|
{
|
||||||
|
uint32_t hdr_size = pv_hdr_size(hdr);
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
|
||||||
|
ret = buffer_alloc(hdr_size);
|
||||||
|
pv_hdr_memcpy(hdr, ret);
|
||||||
|
|
||||||
|
if (mode == PV_ENCRYPT) {
|
||||||
|
/* The buffer @ret is modified in-place */
|
||||||
|
if (pv_hdr_encrypt(hdr, img, ret, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
} else {
|
||||||
|
/* Simply copy the tag */
|
||||||
|
memcpy((uint8_t *)ret->data + hdr_size - pv_hdr_tag_size(hdr),
|
||||||
|
hdr->tag, pv_hdr_tag_size(hdr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
36
genprotimg/src/pv/pv_hdr.h
Normal file
36
genprotimg/src/pv/pv_hdr.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* PV header related functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_HDR_H
|
||||||
|
#define PV_HDR_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "include/pv_hdr_def.h"
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
|
||||||
|
#include "pv_image.h"
|
||||||
|
|
||||||
|
PvHdr *pv_hdr_new(const PvImage *img, GError **err);
|
||||||
|
void pv_hdr_free(PvHdr *hdr);
|
||||||
|
G_GNUC_UNUSED gboolean pv_hdr_uses_encryption(const PvHdr *hdr);
|
||||||
|
Buffer *pv_hdr_serialize(const PvHdr *hdr, const PvImage *img,
|
||||||
|
enum PvCryptoMode mode, GError **err);
|
||||||
|
uint32_t pv_hdr_size(const PvHdr *hdr);
|
||||||
|
uint32_t pv_hdr_aad_size(const PvHdr *hdr);
|
||||||
|
uint64_t pv_hdr_enc_size(const PvHdr *hdr);
|
||||||
|
uint32_t pv_hdr_enc_size_casted(const PvHdr *hdr);
|
||||||
|
uint64_t pv_hdr_get_nks(const PvHdr *hdr);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvHdr, pv_hdr_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
821
genprotimg/src/pv/pv_image.c
Normal file
821
genprotimg/src/pv/pv_image.c
Normal file
@@ -0,0 +1,821 @@
|
|||||||
|
/*
|
||||||
|
* PV image related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/stage3a.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "include/pv_crypto_def.h"
|
||||||
|
#include "include/pv_hdr_def.h"
|
||||||
|
#include "utils/align.h"
|
||||||
|
#include "utils/crypto.h"
|
||||||
|
#include "utils/file_utils.h"
|
||||||
|
|
||||||
|
#include "pv_args.h"
|
||||||
|
#include "pv_comps.h"
|
||||||
|
#include "pv_error.h"
|
||||||
|
#include "pv_hdr.h"
|
||||||
|
#include "pv_image.h"
|
||||||
|
#include "pv_ipib.h"
|
||||||
|
#include "pv_opt_item.h"
|
||||||
|
#include "pv_stage3.h"
|
||||||
|
|
||||||
|
const PvComponent *pv_img_get_stage3b_comp(const PvImage *img, GError **err)
|
||||||
|
{
|
||||||
|
const PvComponent *comp;
|
||||||
|
|
||||||
|
g_return_val_if_fail(pv_img_comps_length(img->comps) >= 1, NULL);
|
||||||
|
|
||||||
|
comp = pv_img_comps_get_nth_comp(img->comps,
|
||||||
|
pv_img_comps_length(img->comps) - 1);
|
||||||
|
if (!pv_component_is_stage3b(comp)) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Failed to get 'stage3b' component"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return comp;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef gint (*prepare_func)(PvComponent *obj, const gchar *tmp_path,
|
||||||
|
void *opaque, GError **err);
|
||||||
|
|
||||||
|
static gint pv_img_prepare_component(const PvImage *img, PvComponent *comp,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
struct cipher_parms parms = { 0 };
|
||||||
|
g_autoptr(Buffer) tweak = NULL;
|
||||||
|
prepare_func func = NULL;
|
||||||
|
void *opaque = NULL;
|
||||||
|
gint rc;
|
||||||
|
|
||||||
|
if (img->pcf & PV_CFLAG_NO_DECRYPTION) {
|
||||||
|
/* we only need to align the components */
|
||||||
|
func = pv_component_align;
|
||||||
|
opaque = NULL;
|
||||||
|
} else {
|
||||||
|
const EVP_CIPHER *cipher = img->xts_cipher;
|
||||||
|
|
||||||
|
g_assert_cmpint((int)img->xts_key->size, ==,
|
||||||
|
EVP_CIPHER_key_length(cipher));
|
||||||
|
g_assert_cmpint((int)PAGE_SIZE % EVP_CIPHER_block_size(cipher),
|
||||||
|
==, 0);
|
||||||
|
g_assert_cmpint(sizeof(comp->tweak), ==,
|
||||||
|
EVP_CIPHER_iv_length(cipher));
|
||||||
|
g_assert(img->xts_key->size <= UINT_MAX);
|
||||||
|
|
||||||
|
tweak = buffer_alloc(sizeof(comp->tweak.data));
|
||||||
|
memcpy(tweak->data, comp->tweak.data, tweak->size);
|
||||||
|
func = pv_component_align_and_encrypt;
|
||||||
|
parms.cipher = cipher;
|
||||||
|
parms.key = img->xts_key;
|
||||||
|
parms.iv_or_tweak = tweak;
|
||||||
|
|
||||||
|
opaque = &parms;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = (*func)(comp, img->tmp_dir, opaque, err);
|
||||||
|
if (rc < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buffer *pv_img_read_key(const gchar *path, guint key_size,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) tmp_ret = NULL;
|
||||||
|
Buffer *ret = NULL;
|
||||||
|
gsize bytes_read;
|
||||||
|
FILE *f = NULL;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
if (file_size(path, &size, err) != 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (size - key_size != 0) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||||
|
_("Wrong file size '%s': read %zd, expected %u"), path, size,
|
||||||
|
key_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = file_open(path, "rb", err);
|
||||||
|
if (!f)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
tmp_ret = buffer_alloc(size);
|
||||||
|
if (file_read(f, tmp_ret->data, 1, tmp_ret->size, &bytes_read, err) < 0)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (bytes_read - key_size != 0) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_CRYPTO_ERROR_INVALID_KEY_SIZE,
|
||||||
|
_("Wrong file size '%s': read %zd, expected %u"),
|
||||||
|
path, bytes_read, key_size);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = g_steal_pointer(&tmp_ret);
|
||||||
|
err:
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static EVP_PKEY *pv_img_get_cust_pub_priv_key(gint nid, GError **err)
|
||||||
|
{
|
||||||
|
return generate_ec_key(nid, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static HostKeyList *pv_img_get_host_keys(gchar **host_cert_paths,
|
||||||
|
X509_STORE *store, gint nid,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoslist(EVP_PKEY) ret = NULL;
|
||||||
|
|
||||||
|
g_assert(host_cert_paths);
|
||||||
|
|
||||||
|
for (gchar **iterator = host_cert_paths; iterator != NULL && *iterator != NULL;
|
||||||
|
iterator++) {
|
||||||
|
g_autoptr(EVP_PKEY) host_key = NULL;
|
||||||
|
const gchar *path = *iterator;
|
||||||
|
|
||||||
|
g_assert(path);
|
||||||
|
|
||||||
|
host_key = read_ec_pubkey_cert(store, nid, path, err);
|
||||||
|
if (!host_key)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret = g_slist_append(ret, g_steal_pointer(&host_key));
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buffer *pv_img_get_key(const EVP_CIPHER *cipher, const gchar *path,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
gint key_len = EVP_CIPHER_key_length(cipher);
|
||||||
|
|
||||||
|
g_assert(key_len > 0);
|
||||||
|
|
||||||
|
if (path)
|
||||||
|
return pv_img_read_key(path, (guint)key_len, err);
|
||||||
|
|
||||||
|
return generate_aes_key((guint)key_len, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buffer *pv_img_get_iv(const EVP_CIPHER *cipher, const gchar *path,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
gint iv_len = EVP_CIPHER_iv_length(cipher);
|
||||||
|
|
||||||
|
g_assert(iv_len > 0);
|
||||||
|
|
||||||
|
if (path)
|
||||||
|
return pv_img_read_key(path, (guint)iv_len, err);
|
||||||
|
|
||||||
|
return generate_aes_iv((guint)iv_len, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int hex_str_toull(const gchar *nptr, uint64_t *dst,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
uint64_t value;
|
||||||
|
gchar *end;
|
||||||
|
|
||||||
|
g_assert(dst);
|
||||||
|
|
||||||
|
if (!g_str_is_ascii(nptr)) {
|
||||||
|
g_set_error(err, PV_ERROR, EINVAL,
|
||||||
|
_("Invalid value: '%s'. A hexadecimal value is required, for example '0xcfe'"),
|
||||||
|
nptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = g_ascii_strtoull(nptr, &end, 16);
|
||||||
|
if ((value == G_MAXUINT64 && errno == ERANGE) ||
|
||||||
|
(end && *end != '\0')) {
|
||||||
|
g_set_error(err, PV_ERROR, EINVAL,
|
||||||
|
_("Invalid value: '%s'. A hexadecimal value is required, for example '0xcfe'"),
|
||||||
|
nptr);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*dst = value;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_img_set_psw_addr(PvImage *img, const gchar *psw_addr_s,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
if (psw_addr_s) {
|
||||||
|
uint64_t psw_addr;
|
||||||
|
|
||||||
|
if (hex_str_toull(psw_addr_s, &psw_addr, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->initial_psw.addr = psw_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_img_set_control_flags(PvImage *img, const gchar *pcf_s,
|
||||||
|
const gchar *scf_s, GError **err)
|
||||||
|
{
|
||||||
|
uint64_t flags;
|
||||||
|
|
||||||
|
if (pcf_s) {
|
||||||
|
if (hex_str_toull(pcf_s, &flags, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->pcf = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scf_s) {
|
||||||
|
if (hex_str_toull(scf_s, &flags, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->scf = flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read in the keys or auto-generate them */
|
||||||
|
static gint pv_img_set_keys(PvImage *img, const PvArgs *args, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(X509_STORE) store = NULL;
|
||||||
|
|
||||||
|
g_assert(img->xts_cipher);
|
||||||
|
g_assert(img->cust_comm_cipher);
|
||||||
|
g_assert(img->gcm_cipher);
|
||||||
|
g_assert(img->nid);
|
||||||
|
|
||||||
|
img->xts_key = pv_img_get_key(img->xts_cipher, args->xts_key_path, err);
|
||||||
|
if (!img->xts_key)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->cust_comm_key = pv_img_get_key(img->cust_comm_cipher,
|
||||||
|
args->cust_comm_key_path, err);
|
||||||
|
if (!img->cust_comm_key)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->cust_root_key =
|
||||||
|
pv_img_get_key(img->gcm_cipher, args->cust_root_key_path, err);
|
||||||
|
if (!img->cust_root_key)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->gcm_iv = pv_img_get_iv(img->gcm_cipher, args->gcm_iv_path, err);
|
||||||
|
if (!img->gcm_iv)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->cust_pub_priv_key = pv_img_get_cust_pub_priv_key(img->nid, err);
|
||||||
|
if (!img->cust_pub_priv_key)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->host_pub_keys =
|
||||||
|
pv_img_get_host_keys(args->host_keys, store, img->nid, err);
|
||||||
|
if (!img->host_pub_keys)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pv_img_add_host_slot(PvImage *img, PvHdrKeySlot *slot)
|
||||||
|
{
|
||||||
|
img->key_slots = g_slist_append(img->key_slots, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pv_hdr_key_slot_free(PvHdrKeySlot *slot)
|
||||||
|
{
|
||||||
|
if (!slot)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvHdrKeySlot, pv_hdr_key_slot_free)
|
||||||
|
|
||||||
|
static PvHdrKeySlot *pv_hdr_key_slot_new(const EVP_CIPHER *gcm_cipher,
|
||||||
|
const Buffer *cust_root_key,
|
||||||
|
EVP_PKEY *cust_key, EVP_PKEY *host_key,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(PvHdrKeySlot) ret = g_new0(PvHdrKeySlot, 1);
|
||||||
|
g_autofree union ecdh_pub_key *pub = NULL;
|
||||||
|
g_autoptr(Buffer) exchange_key = NULL;
|
||||||
|
g_autoptr(Buffer) digest_key = NULL;
|
||||||
|
g_autoptr(Buffer) iv = NULL;
|
||||||
|
Buffer pub_buf;
|
||||||
|
/* No AAD data is used */
|
||||||
|
Buffer aad = { .data = NULL, .size = 0 };
|
||||||
|
/* Set the output buffers for the encrypted data and the
|
||||||
|
* generated GCM tag
|
||||||
|
*/
|
||||||
|
Buffer enc = { .data = ret->wrapped_key, .size = sizeof(ret->wrapped_key) };
|
||||||
|
Buffer tag = { .data = ret->tag, .size = sizeof(ret->tag) };
|
||||||
|
struct cipher_parms parms;
|
||||||
|
int64_t c_len = 0;
|
||||||
|
|
||||||
|
g_assert(EVP_CIPHER_iv_length(gcm_cipher) >= 0);
|
||||||
|
|
||||||
|
pub = evp_pkey_to_ecdh_pub_key(host_key, err);
|
||||||
|
if (!pub)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
pub_buf.data = pub->data;
|
||||||
|
pub_buf.size = sizeof(*pub);
|
||||||
|
digest_key = sha256_buffer(&pub_buf, err);
|
||||||
|
if (!digest_key)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g_assert(digest_key->size == sizeof(ret->digest_key));
|
||||||
|
/* set `digest_key` field */
|
||||||
|
memcpy(ret->digest_key, digest_key->data, sizeof(ret->digest_key));
|
||||||
|
|
||||||
|
exchange_key = compute_exchange_key(cust_key, host_key, err);
|
||||||
|
if (!exchange_key)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* initialize cipher parameters */
|
||||||
|
g_assert(exchange_key->size <= INT_MAX);
|
||||||
|
g_assert(exchange_key->size == (guint)EVP_CIPHER_key_length(gcm_cipher));
|
||||||
|
|
||||||
|
/* create zero IV */
|
||||||
|
iv = buffer_alloc((guint)EVP_CIPHER_iv_length(gcm_cipher));
|
||||||
|
parms.iv_or_tweak = iv;
|
||||||
|
parms.key = exchange_key;
|
||||||
|
parms.cipher = gcm_cipher;
|
||||||
|
|
||||||
|
/* Encrypt the customer root key that is used for the encryption
|
||||||
|
* of the PV header
|
||||||
|
*/
|
||||||
|
c_len = gcm_encrypt(cust_root_key, &aad, &parms, &enc, &tag, err);
|
||||||
|
if (c_len < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g_assert(c_len == (int64_t)cust_root_key->size);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_img_set_host_slots(PvImage *img, GError **err)
|
||||||
|
{
|
||||||
|
for (GSList *iterator = img->host_pub_keys; iterator; iterator = iterator->next) {
|
||||||
|
EVP_PKEY *host_key = iterator->data;
|
||||||
|
|
||||||
|
g_assert(host_key);
|
||||||
|
|
||||||
|
PvHdrKeySlot *slot = pv_hdr_key_slot_new(img->gcm_cipher,
|
||||||
|
img->cust_root_key,
|
||||||
|
img->cust_pub_priv_key,
|
||||||
|
host_key, err);
|
||||||
|
if (!slot)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
pv_img_add_host_slot(img, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_img_set_comps_offset(PvImage *img, uint64_t offset, GError **err)
|
||||||
|
{
|
||||||
|
return pv_img_comps_set_offset(img->comps, offset, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(PvImage) ret = g_new0(PvImage, 1);
|
||||||
|
uint64_t offset;
|
||||||
|
|
||||||
|
g_assert(args->tmp_dir);
|
||||||
|
g_assert(stage3a_path);
|
||||||
|
|
||||||
|
if (args->no_verify)
|
||||||
|
g_warning(_("host-key document verification is disabled. Your workload is not secured."));
|
||||||
|
|
||||||
|
ret->comps = pv_img_comps_new(EVP_sha512(), EVP_sha512(), EVP_sha512(), err);
|
||||||
|
if (!ret->comps)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
ret->cust_comm_cipher = EVP_aes_256_gcm();
|
||||||
|
ret->gcm_cipher = EVP_aes_256_gcm();
|
||||||
|
ret->initial_psw.addr = DEFAULT_INITIAL_PSW_ADDR;
|
||||||
|
ret->initial_psw.mask = DEFAULT_INITIAL_PSW_MASK;
|
||||||
|
ret->nid = NID_secp521r1;
|
||||||
|
ret->tmp_dir = g_strdup(args->tmp_dir);
|
||||||
|
ret->xts_cipher = EVP_aes_256_xts();
|
||||||
|
|
||||||
|
/* set initial PSW that will be loaded by the stage3b */
|
||||||
|
if (pv_img_set_psw_addr(ret, args->psw_addr, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* set the control flags: PCF and SCF */
|
||||||
|
if (pv_img_set_control_flags(ret, args->pcf, args->scf, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* read in the keys */
|
||||||
|
if (pv_img_set_keys(ret, args, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (pv_img_set_host_slots(ret, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
/* allocate enough memory for the stage3a args and load the
|
||||||
|
* stage3a template into memory and set the loader_psw
|
||||||
|
*/
|
||||||
|
if (pv_img_load_and_set_stage3a(ret, stage3a_path, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
offset = PAGE_ALIGN(STAGE3A_LOAD_ADDRESS + ret->stage3a->size);
|
||||||
|
|
||||||
|
/* shift right all components by the size of stage3a loader */
|
||||||
|
if (pv_img_set_comps_offset(ret, offset, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pv_img_free(PvImage *img)
|
||||||
|
{
|
||||||
|
if (!img)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_slist_free_full(img->optional_items,
|
||||||
|
(GDestroyNotify)pv_opt_item_free);
|
||||||
|
g_slist_free_full(img->key_slots, (GDestroyNotify)pv_hdr_key_slot_free);
|
||||||
|
g_slist_free_full(img->host_pub_keys, (GDestroyNotify)EVP_PKEY_free);
|
||||||
|
EVP_PKEY_free(img->cust_pub_priv_key);
|
||||||
|
buffer_clear(&img->stage3a);
|
||||||
|
pv_img_comps_free(img->comps);
|
||||||
|
g_free(img->tmp_dir);
|
||||||
|
buffer_free(img->xts_key);
|
||||||
|
buffer_free(img->cust_root_key);
|
||||||
|
buffer_free(img->gcm_iv);
|
||||||
|
buffer_free(img->cust_comm_key);
|
||||||
|
g_free(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_img_prepare_and_add_component(PvImage *img, PvComponent **comp,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_assert(comp);
|
||||||
|
g_assert(*comp);
|
||||||
|
|
||||||
|
/* prepares the component: does the alignment and encryption
|
||||||
|
* if required
|
||||||
|
*/
|
||||||
|
if (pv_img_prepare_component(img, *comp, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* calculates the memory layout and adds the component to its
|
||||||
|
* internal list
|
||||||
|
*/
|
||||||
|
if (pv_img_comps_add_component(img->comps, comp, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_assert(!*comp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(PvComponent) comp = NULL;
|
||||||
|
|
||||||
|
comp = pv_component_new_file(arg->type, arg->path, err);
|
||||||
|
if (!comp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (pv_img_prepare_and_add_component(img, &comp, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_assert(!comp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
|
||||||
|
Buffer **tld, uint64_t *nep, GError **err)
|
||||||
|
{
|
||||||
|
return pv_img_comps_finalize(img->comps, pld, ald, tld, nep, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_img_build_stage3b(PvImage *img, Buffer *stage3b, GError **err)
|
||||||
|
{
|
||||||
|
g_autofree struct stage3b_args *args = NULL;
|
||||||
|
|
||||||
|
args = pv_img_comps_get_stage3b_args(img->comps, &img->initial_psw);
|
||||||
|
if (!args) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Cannot generate stage3b arguments"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
build_stage3b(stage3b, args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(PvComponent) comp = NULL;
|
||||||
|
g_autoptr(Buffer) stage3b = NULL;
|
||||||
|
|
||||||
|
stage3b = stage3b_getblob(path, err);
|
||||||
|
if (!stage3b)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* set the stage3b data */
|
||||||
|
if (pv_img_build_stage3b(img, stage3b, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
comp = pv_component_new_buf(PV_COMP_TYPE_STAGE3B, stage3b, err);
|
||||||
|
if (!comp)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (pv_img_prepare_and_add_component(img, &comp, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_assert(!comp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pv_img_get_aad_size(const PvImage *img)
|
||||||
|
{
|
||||||
|
uint32_t key_size, size = 0;
|
||||||
|
|
||||||
|
g_assert(sizeof(struct pv_hdr_head) <= UINT32_MAX);
|
||||||
|
g_assert(sizeof(struct pv_hdr_key_slot) <= UINT32_MAX);
|
||||||
|
|
||||||
|
g_assert_true(g_uint_checked_add(&size, size,
|
||||||
|
(uint32_t)sizeof(struct pv_hdr_head)));
|
||||||
|
g_assert_true(g_uint_checked_mul(&key_size,
|
||||||
|
(uint32_t)sizeof(struct pv_hdr_key_slot),
|
||||||
|
g_slist_length(img->key_slots)));
|
||||||
|
g_assert_true(g_uint_checked_add(&size, size, key_size));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pv_img_get_opt_items_size(const PvImage *img)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
g_assert(img);
|
||||||
|
|
||||||
|
for (GSList *iterator = img->optional_items; iterator;
|
||||||
|
iterator = iterator->next) {
|
||||||
|
const struct pv_hdr_opt_item *item = iterator->data;
|
||||||
|
|
||||||
|
g_assert(item);
|
||||||
|
g_assert_true(g_uint_checked_add(&ret, ret, pv_opt_item_size(item)));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pv_img_get_enc_size(const PvImage *img)
|
||||||
|
{
|
||||||
|
uint32_t ret = 0;
|
||||||
|
|
||||||
|
g_assert(sizeof(struct pv_hdr_encrypted) <= UINT32_MAX);
|
||||||
|
|
||||||
|
g_assert_true(g_uint_checked_add(
|
||||||
|
&ret, ret, (uint32_t)sizeof(struct pv_hdr_encrypted)));
|
||||||
|
g_assert_true(
|
||||||
|
g_uint_checked_add(&ret, ret, pv_img_get_opt_items_size(img)));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pv_img_get_tag_size(const PvImage *img G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
g_assert(sizeof(((struct pv_hdr *)0)->tag) <= UINT32_MAX);
|
||||||
|
|
||||||
|
return (uint32_t)sizeof(((struct pv_hdr *)0)->tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pv_img_get_pv_hdr_size(const PvImage *img)
|
||||||
|
{
|
||||||
|
uint32_t size = 0;
|
||||||
|
|
||||||
|
g_assert_true(
|
||||||
|
g_uint_checked_add(&size, size, pv_img_get_aad_size(img)));
|
||||||
|
g_assert_true(
|
||||||
|
g_uint_checked_add(&size, size, pv_img_get_enc_size(img)));
|
||||||
|
g_assert_true(
|
||||||
|
g_uint_checked_add(&size, size, pv_img_get_tag_size(img)));
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint get_stage3a_data_size(const PvImage *img, gsize *data_size,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
gsize ipib_size, hdr_size;
|
||||||
|
|
||||||
|
g_assert(data_size);
|
||||||
|
g_assert(*data_size == 0);
|
||||||
|
|
||||||
|
ipib_size = pv_ipib_get_size(pv_img_comps_length(img->comps));
|
||||||
|
if (ipib_size > PV_V1_IPIB_MAX_SIZE) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_IPIB_SIZE,
|
||||||
|
_("IPIB size is too large: '%zu' > '%zu'"),
|
||||||
|
ipib_size, PV_V1_IPIB_MAX_SIZE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hdr_size = pv_img_get_pv_hdr_size(img);
|
||||||
|
if (hdr_size > PV_V1_PV_HDR_MAX_SIZE) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_PV_HDR_SIZE,
|
||||||
|
_("PV header size is too large: '%zu' > '%zu'"),
|
||||||
|
hdr_size, PV_V1_PV_HDR_MAX_SIZE);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data_size += PAGE_ALIGN(ipib_size);
|
||||||
|
*data_size += PAGE_ALIGN(hdr_size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) stage3a = NULL;
|
||||||
|
gsize bin_size, data_size = 0;
|
||||||
|
|
||||||
|
if (get_stage3a_data_size(img, &data_size, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
stage3a = stage3a_getblob(path, &bin_size, data_size, err);
|
||||||
|
if (!stage3a)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
img->stage3a_psw.addr = STAGE3A_ENTRY;
|
||||||
|
img->stage3a_psw.mask = DEFAULT_INITIAL_PSW_MASK;
|
||||||
|
|
||||||
|
/* set addresses and size */
|
||||||
|
img->stage3a = g_steal_pointer(&stage3a);
|
||||||
|
img->stage3a_bin_size = bin_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates the PV IPIB and sets the stage3a arguments */
|
||||||
|
static gint pv_img_build_stage3a(Buffer *stage3a, gsize stage3a_bin_size,
|
||||||
|
GSList *comps, const Buffer *hdr, GError **err)
|
||||||
|
{
|
||||||
|
g_autofree struct ipl_parameter_block *ipib = NULL;
|
||||||
|
|
||||||
|
g_assert(stage3a);
|
||||||
|
g_assert(hdr);
|
||||||
|
|
||||||
|
ipib = pv_ipib_new(comps, hdr, err);
|
||||||
|
if (!ipib)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (build_stage3a(stage3a, stage3a_bin_size, hdr, ipib, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
g_info("%12s:\t0x%012lx (%12ld / %12ld Bytes)", "stage3a",
|
||||||
|
STAGE3A_LOAD_ADDRESS, stage3a->size, stage3a->size);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Creates the actual PV header (serialized and AES-GCM encrypted) */
|
||||||
|
static Buffer *pv_img_create_pv_hdr(PvImage *img, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) hdr_buf = NULL;
|
||||||
|
g_autoptr(PvHdr) hdr = NULL;
|
||||||
|
|
||||||
|
hdr = pv_hdr_new(img, err);
|
||||||
|
if (!hdr)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
hdr_buf = pv_hdr_serialize(hdr, img, PV_ENCRYPT, err);
|
||||||
|
if (!hdr_buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&hdr_buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No changes to the components are allowed after calling this
|
||||||
|
* function
|
||||||
|
*/
|
||||||
|
gint pv_img_finalize(PvImage *pv, const gchar *stage3b_path, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) hdr = NULL;
|
||||||
|
|
||||||
|
/* load stage3b template into memory and add it to the list of
|
||||||
|
* components. This must be done before calling
|
||||||
|
* `pv_img_load_and_set_stage3a`.
|
||||||
|
*/
|
||||||
|
if (pv_img_add_stage3b_comp(pv, stage3b_path, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* create the PV header */
|
||||||
|
hdr = pv_img_create_pv_hdr(pv, err);
|
||||||
|
if (!hdr)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
/* generate stage3a. At this point in time the PV header and
|
||||||
|
* the stage3b must be generated and encrypted
|
||||||
|
*/
|
||||||
|
if (pv_img_build_stage3a(pv->stage3a, pv->stage3a_bin_size,
|
||||||
|
pv_img_comps_get_comps(pv->comps), hdr, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint convert_psw_to_short_psw(const struct psw_t *psw, uint64_t *dst,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_assert(psw);
|
||||||
|
g_assert(dst);
|
||||||
|
|
||||||
|
uint64_t psw_addr = psw->addr;
|
||||||
|
uint64_t psw_mask = psw->mask;
|
||||||
|
|
||||||
|
/* test if PSW mask can be converted */
|
||||||
|
if (psw_mask & PSW32_ADDR_MASK) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Failed to convert PSW to short PSW"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test for bit 12 */
|
||||||
|
if (psw_mask & PSW_MASK_BIT_12) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Failed to convert PSW to short PSW"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* test if PSW addr can be converted */
|
||||||
|
if (psw_addr & ~PSW32_ADDR_MASK) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Failed to convert PSW to short PSW"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst = psw_mask;
|
||||||
|
/* set bit 12 to 1 */
|
||||||
|
*dst |= PSW_MASK_BIT_12;
|
||||||
|
*dst |= psw_addr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint write_short_psw(FILE *f, struct psw_t *psw, GError **err)
|
||||||
|
{
|
||||||
|
uint64_t short_psw, short_psw_be;
|
||||||
|
|
||||||
|
if (convert_psw_to_short_psw(psw, &short_psw, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
short_psw_be = GUINT64_TO_BE(short_psw);
|
||||||
|
return file_write(f, &short_psw_be, 1, sizeof(short_psw_be), NULL, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pv_img_write(PvImage *img, const gchar *path, GError **err)
|
||||||
|
{
|
||||||
|
gint ret = -1;
|
||||||
|
FILE *f = file_open(path, "wb", err);
|
||||||
|
|
||||||
|
if (!f)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (write_short_psw(f, &img->stage3a_psw, err) < 0) {
|
||||||
|
g_prefix_error(err, _("Failed to write image '%s': "), path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seek_and_write_buffer(f, img->stage3a, STAGE3A_LOAD_ADDRESS, err) <
|
||||||
|
0) {
|
||||||
|
g_prefix_error(err, _("Failed to write image '%s': "), path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* list is sorted by component type => by address */
|
||||||
|
for (GSList *iterator = pv_img_comps_get_comps(img->comps); iterator;
|
||||||
|
iterator = iterator->next) {
|
||||||
|
gint rc;
|
||||||
|
const PvComponent *comp = iterator->data;
|
||||||
|
|
||||||
|
rc = pv_component_write(comp, f, err);
|
||||||
|
if (rc < 0) {
|
||||||
|
g_prefix_error(err, _("Failed to write image '%s': "),
|
||||||
|
path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
err:
|
||||||
|
if (f)
|
||||||
|
fclose(f);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
68
genprotimg/src/pv/pv_image.h
Normal file
68
genprotimg/src/pv/pv_image.h
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* PV image related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_IMAGE_H
|
||||||
|
#define PV_IMAGE_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
|
||||||
|
#include "pv_args.h"
|
||||||
|
#include "pv_comp.h"
|
||||||
|
#include "pv_comps.h"
|
||||||
|
#include "pv_stage3.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gchar *tmp_dir; /* directory used for temporary files */
|
||||||
|
Buffer *stage3a; /* stage3a containing IPIB and PV header */
|
||||||
|
gsize stage3a_bin_size; /* size of stage3a.bin */
|
||||||
|
struct psw_t stage3a_psw; /* (short) PSW that is written to
|
||||||
|
* location 0 of the created image
|
||||||
|
*/
|
||||||
|
struct psw_t initial_psw; /* PSW loaded by stage3b */
|
||||||
|
EVP_PKEY *cust_pub_priv_key; /* customer private/public key */
|
||||||
|
GSList *host_pub_keys; /* public host keys */
|
||||||
|
gint nid; /* Elliptic Curve used for the key derivation */
|
||||||
|
/* keys and cipher used for the AES-GCM encryption */
|
||||||
|
Buffer *cust_root_key;
|
||||||
|
Buffer *gcm_iv;
|
||||||
|
const EVP_CIPHER *gcm_cipher;
|
||||||
|
/* Information for the IPIB and PV header */
|
||||||
|
uint64_t pcf;
|
||||||
|
uint64_t scf;
|
||||||
|
Buffer *cust_comm_key;
|
||||||
|
const EVP_CIPHER *cust_comm_cipher;
|
||||||
|
Buffer *xts_key;
|
||||||
|
const EVP_CIPHER *xts_cipher;
|
||||||
|
GSList *key_slots;
|
||||||
|
GSList *optional_items;
|
||||||
|
PvImgComps *comps;
|
||||||
|
} PvImage;
|
||||||
|
|
||||||
|
PvImage *pv_img_new(PvArgs *args, const gchar *stage3a_path, GError **err);
|
||||||
|
void pv_img_free(PvImage *img);
|
||||||
|
gint pv_img_add_component(PvImage *img, const PvArg *arg, GError **err);
|
||||||
|
gint pv_img_finalize(PvImage *img, const gchar *stage3b_path, GError **err);
|
||||||
|
gint pv_img_calc_pld_ald_tld_nep(const PvImage *img, Buffer **pld, Buffer **ald,
|
||||||
|
Buffer **tld, uint64_t *nep, GError **err);
|
||||||
|
gint pv_img_load_and_set_stage3a(PvImage *img, const gchar *path, GError **err);
|
||||||
|
const PvComponent *pv_img_get_stage3b_comp(const PvImage *img, GError **err);
|
||||||
|
gint pv_img_add_stage3b_comp(PvImage *img, const gchar *path, GError **err);
|
||||||
|
uint32_t pv_img_get_enc_size(const PvImage *img);
|
||||||
|
uint32_t pv_img_get_pv_hdr_size(const PvImage *img);
|
||||||
|
gint pv_img_write(PvImage *img, const gchar *path, GError **err);
|
||||||
|
|
||||||
|
G_DEFINE_AUTOPTR_CLEANUP_FUNC(PvImage, pv_img_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
128
genprotimg/src/pv/pv_ipib.c
Normal file
128
genprotimg/src/pv/pv_ipib.c
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* PV IPIB related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "boot/ipl.h"
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "include/pv_hdr_def.h"
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
#include "utils/align.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
|
||||||
|
#include "pv_comp.h"
|
||||||
|
#include "pv_error.h"
|
||||||
|
#include "pv_ipib.h"
|
||||||
|
|
||||||
|
uint64_t pv_ipib_get_size(uint32_t num_comp)
|
||||||
|
{
|
||||||
|
gsize ipib_size = sizeof(struct ipl_pl_hdr) +
|
||||||
|
sizeof(struct ipl_pb0_pv) +
|
||||||
|
num_comp * sizeof(struct ipl_pb0_pv_comp);
|
||||||
|
|
||||||
|
/* the minimal size is one page */
|
||||||
|
return MAX(ipib_size, PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint pv_ipib_init(IplParameterBlock *ipib, GSList *comps,
|
||||||
|
const Buffer *hdr)
|
||||||
|
{
|
||||||
|
g_assert(sizeof(struct ipl_pl_hdr) <= UINT32_MAX);
|
||||||
|
g_assert(sizeof(struct ipl_pb0_pv_comp) <= UINT32_MAX);
|
||||||
|
g_assert(sizeof(struct ipl_pb0_pv) <= UINT32_MAX);
|
||||||
|
g_assert(ipib);
|
||||||
|
|
||||||
|
guint comps_length = g_slist_length(comps);
|
||||||
|
uint32_t ipl_pl_hdr_size = (uint32_t)sizeof(struct ipl_pl_hdr);
|
||||||
|
struct ipl_pb0_pv *pv = &ipib->pv;
|
||||||
|
uint32_t ipib_comps_size;
|
||||||
|
uint32_t blk0_len;
|
||||||
|
uint32_t ipib_size;
|
||||||
|
gsize i;
|
||||||
|
|
||||||
|
g_assert_true(
|
||||||
|
g_uint_checked_mul(&ipib_comps_size, comps_length,
|
||||||
|
(uint32_t)sizeof(struct ipl_pb0_pv_comp)));
|
||||||
|
g_assert_true(g_uint_checked_add(&blk0_len, (uint32_t)sizeof(*pv),
|
||||||
|
ipib_comps_size));
|
||||||
|
g_assert(ipl_pl_hdr_size + blk0_len <= PAGE_SIZE);
|
||||||
|
|
||||||
|
ipib_size = MAX(ipl_pl_hdr_size + blk0_len, (uint32_t)PAGE_SIZE);
|
||||||
|
g_assert(pv_ipib_get_size(comps_length) == ipib_size);
|
||||||
|
|
||||||
|
pv->pbt = IPL_TYPE_PV;
|
||||||
|
pv->len = GUINT32_TO_BE(blk0_len);
|
||||||
|
pv->num_comp = GUINT32_TO_BE(comps_length);
|
||||||
|
/* both values will be overwritten during the IPL process by
|
||||||
|
* the stage3a loader
|
||||||
|
*/
|
||||||
|
pv->pv_hdr_addr = GUINT64_TO_BE(0x0);
|
||||||
|
pv->pv_hdr_size = GUINT64_TO_BE(hdr->size);
|
||||||
|
|
||||||
|
ipib->hdr.len = GUINT32_TO_BE(ipib_size);
|
||||||
|
ipib->hdr.version = IPL_PARM_BLOCK_VERSION;
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
for (GSList *iterator = comps; iterator; iterator = iterator->next, i++) {
|
||||||
|
const PvComponent *comp = iterator->data;
|
||||||
|
uint64_t comp_addr, comp_size;
|
||||||
|
|
||||||
|
g_assert(comp);
|
||||||
|
|
||||||
|
comp_addr = pv_component_get_src_addr(comp);
|
||||||
|
comp_size = pv_component_size(comp);
|
||||||
|
|
||||||
|
g_assert(IS_PAGE_ALIGNED(comp_size));
|
||||||
|
|
||||||
|
pv->components[i].addr = GUINT64_TO_BE(comp_addr);
|
||||||
|
pv->components[i].len = GUINT64_TO_BE(comp_size);
|
||||||
|
pv->components[i].tweak_pref =
|
||||||
|
GUINT64_TO_BE(pv_component_get_tweak_prefix(comp));
|
||||||
|
if (i > 0) {
|
||||||
|
/* tweak prefixes of the components must grow
|
||||||
|
* strictly monotonous
|
||||||
|
*/
|
||||||
|
g_assert(GUINT64_FROM_BE(pv->components[i].tweak_pref) >
|
||||||
|
GUINT64_FROM_BE(pv->components[i - 1].tweak_pref));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err)
|
||||||
|
{
|
||||||
|
uint64_t ipib_size = pv_ipib_get_size(g_slist_length(comps));
|
||||||
|
g_autoptr(IplParameterBlock) ret = NULL;
|
||||||
|
|
||||||
|
if (ipib_size > PV_V1_IPIB_MAX_SIZE) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_IPIB_SIZE,
|
||||||
|
_("IPIB size is too large: %lu < %lu"), ipib_size,
|
||||||
|
PAGE_SIZE);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = g_malloc0(ipib_size);
|
||||||
|
if (pv_ipib_init(ret, comps, hdr) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pv_ipib_free(IplParameterBlock *ipib)
|
||||||
|
{
|
||||||
|
if (!ipib)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(ipib);
|
||||||
|
}
|
||||||
27
genprotimg/src/pv/pv_ipib.h
Normal file
27
genprotimg/src/pv/pv_ipib.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* PV IPIB related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_IPIB_H
|
||||||
|
#define PV_IPIB_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/ipl.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
|
||||||
|
typedef struct ipl_parameter_block IplParameterBlock;
|
||||||
|
|
||||||
|
uint64_t pv_ipib_get_size(uint32_t num_comp);
|
||||||
|
IplParameterBlock *pv_ipib_new(GSList *comps, const Buffer *hdr, GError **err);
|
||||||
|
void pv_ipib_free(IplParameterBlock *ipib);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(IplParameterBlock, pv_ipib_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
26
genprotimg/src/pv/pv_opt_item.c
Normal file
26
genprotimg/src/pv/pv_opt_item.c
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* PV optional item related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
#include "pv_opt_item.h"
|
||||||
|
|
||||||
|
uint32_t pv_opt_item_size(const struct pv_hdr_opt_item *item G_GNUC_UNUSED)
|
||||||
|
{
|
||||||
|
/* not implemented yet */
|
||||||
|
g_assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pv_opt_item_free(struct pv_hdr_opt_item *item)
|
||||||
|
{
|
||||||
|
if (!item)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(item);
|
||||||
|
}
|
||||||
20
genprotimg/src/pv/pv_opt_item.h
Normal file
20
genprotimg/src/pv/pv_opt_item.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* PV optional item related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_OPT_ITEM_H
|
||||||
|
#define PV_OPT_ITEM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "include/pv_hdr_def.h"
|
||||||
|
|
||||||
|
uint32_t pv_opt_item_size(const struct pv_hdr_opt_item *item);
|
||||||
|
void pv_opt_item_free(struct pv_hdr_opt_item *item);
|
||||||
|
|
||||||
|
#endif
|
||||||
164
genprotimg/src/pv/pv_stage3.c
Normal file
164
genprotimg/src/pv/pv_stage3.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* PV stage3 loader related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "boot/ipl.h"
|
||||||
|
#include "boot/stage3a.h"
|
||||||
|
#include "boot/stage3b.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "utils/align.h"
|
||||||
|
|
||||||
|
#include "pv_error.h"
|
||||||
|
#include "pv_stage3.h"
|
||||||
|
|
||||||
|
#define STAGE3A_ARGS(data_ptr, loader_size) \
|
||||||
|
((struct stage3a_args *)((uint64_t)data_ptr + loader_size - \
|
||||||
|
sizeof(struct stage3a_args)))
|
||||||
|
|
||||||
|
static Buffer *loader_getblob(const gchar *filename, gsize *loader_size,
|
||||||
|
gsize args_size, gsize data_size,
|
||||||
|
gboolean data_aligned, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(GMappedFile) mapped_file = NULL;
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
gsize size, tmp_loader_size;
|
||||||
|
gchar *loader_data;
|
||||||
|
|
||||||
|
g_assert(loader_size);
|
||||||
|
|
||||||
|
mapped_file = g_mapped_file_new(filename, FALSE, err);
|
||||||
|
if (!mapped_file)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
loader_data = g_mapped_file_get_contents(mapped_file);
|
||||||
|
if (!loader_data) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, G_FILE_ERROR_BADF,
|
||||||
|
_("File '%s' is empty"), filename);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
tmp_loader_size = g_mapped_file_get_length(mapped_file);
|
||||||
|
|
||||||
|
if (tmp_loader_size < args_size) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, G_FILE_ERROR_BADF,
|
||||||
|
_("File size less than expected: %lu < %ln"),
|
||||||
|
tmp_loader_size, loader_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For example, the PV header and IPIB data must be page
|
||||||
|
* aligned.
|
||||||
|
*/
|
||||||
|
size = (data_aligned ? PAGE_ALIGN(tmp_loader_size) : tmp_loader_size) +
|
||||||
|
data_size;
|
||||||
|
|
||||||
|
ret = buffer_alloc(size);
|
||||||
|
|
||||||
|
/* copy the loader "template" */
|
||||||
|
memcpy(ret->data, loader_data, tmp_loader_size);
|
||||||
|
/* reset our dummy data (offsets and length) to zeros */
|
||||||
|
memset((uint8_t *)ret->data + tmp_loader_size - args_size, 0,
|
||||||
|
args_size);
|
||||||
|
*loader_size = tmp_loader_size;
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
|
||||||
|
gsize data_size, GError **err)
|
||||||
|
{
|
||||||
|
return loader_getblob(filename, loader_size,
|
||||||
|
sizeof(struct stage3a_args), data_size, TRUE,
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the memory layout see stage3a.lds */
|
||||||
|
/* Set the right offsets and sizes in the stage3a template + add
|
||||||
|
* the IPIB block with the PV header
|
||||||
|
*/
|
||||||
|
static gint stage3a_set_data(Buffer *loader, gsize loader_size,
|
||||||
|
const Buffer *hdr, struct ipl_parameter_block *ipib,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
uint32_t ipib_size = GUINT32_FROM_BE(ipib->hdr.len);
|
||||||
|
gsize args_size = sizeof(struct stage3a_args);
|
||||||
|
uint32_t hdr_size = (uint32_t)hdr->size;
|
||||||
|
uint64_t args_addr, next_data_addr;
|
||||||
|
|
||||||
|
if (hdr->size > UINT32_MAX) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Invalid header size: %zu"), hdr->size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we assume here that the loader ``stage3a`` is loaded page
|
||||||
|
* aligned in the guest
|
||||||
|
*/
|
||||||
|
args_addr = (uint64_t)loader->data + loader_size - args_size;
|
||||||
|
|
||||||
|
/* therefore `next_data_addr` is also page aligned */
|
||||||
|
next_data_addr = (uint64_t)loader->data + PAGE_ALIGN(loader_size);
|
||||||
|
|
||||||
|
/* copy IPIB data */
|
||||||
|
memcpy((void *)next_data_addr, ipib, ipib_size);
|
||||||
|
|
||||||
|
/* set IPIB offset in relation to the stage3a arguments */
|
||||||
|
STAGE3A_ARGS(loader->data, loader_size)->ipib_offs =
|
||||||
|
GUINT64_TO_BE(next_data_addr - args_addr);
|
||||||
|
|
||||||
|
next_data_addr = next_data_addr + PAGE_ALIGN(ipib_size);
|
||||||
|
/* copy PV header */
|
||||||
|
memcpy((void *)next_data_addr, hdr->data, hdr_size);
|
||||||
|
/* set PV header size and offset in relation to the stage3a
|
||||||
|
* arguments
|
||||||
|
*/
|
||||||
|
STAGE3A_ARGS(loader->data, loader_size)->hdr_offs =
|
||||||
|
GUINT64_TO_BE(next_data_addr - args_addr);
|
||||||
|
STAGE3A_ARGS(loader->data, loader_size)->hdr_size = GUINT64_TO_BE(hdr_size);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint build_stage3a(Buffer *loader, gsize loader_size, const Buffer *hdr,
|
||||||
|
struct ipl_parameter_block *ipib, GError **err)
|
||||||
|
{
|
||||||
|
return stage3a_set_data(loader, loader_size, hdr, ipib, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *stage3b_getblob(const gchar *filename, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
gsize rb_size;
|
||||||
|
|
||||||
|
ret = loader_getblob(filename, &rb_size, sizeof(struct stage3b_args), 0,
|
||||||
|
FALSE, err);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g_assert(ret->size == rb_size);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void build_stage3b(Buffer *stage3b, const struct stage3b_args *args)
|
||||||
|
{
|
||||||
|
g_assert(stage3b->size > sizeof(*args));
|
||||||
|
|
||||||
|
/* at the end of the stage3b there are the stage3b args
|
||||||
|
* positioned
|
||||||
|
*/
|
||||||
|
memcpy((uint8_t *)stage3b->data + stage3b->size - sizeof(*args), args,
|
||||||
|
sizeof(*args));
|
||||||
|
}
|
||||||
|
|
||||||
|
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size)
|
||||||
|
{
|
||||||
|
arg->src = GUINT64_TO_BE(src);
|
||||||
|
arg->size = GUINT64_TO_BE(size);
|
||||||
|
}
|
||||||
30
genprotimg/src/pv/pv_stage3.h
Normal file
30
genprotimg/src/pv/pv_stage3.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* PV stage3 loader related definitions and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_STAGE3_H
|
||||||
|
#define PV_STAGE3_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "boot/ipl.h"
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "boot/stage3b.h"
|
||||||
|
#include "utils/buffer.h"
|
||||||
|
|
||||||
|
Buffer *stage3a_getblob(const gchar *filename, gsize *loader_size,
|
||||||
|
gsize data_size, GError **err);
|
||||||
|
gint build_stage3a(Buffer *dc, gsize dc_size, const Buffer *hdr,
|
||||||
|
struct ipl_parameter_block *ipib, GError **err);
|
||||||
|
Buffer *stage3b_getblob(const gchar *filename, GError **err);
|
||||||
|
void build_stage3b(Buffer *stage3b, const struct stage3b_args *args);
|
||||||
|
void memblob_init(struct memblob *arg, uint64_t src, uint64_t size);
|
||||||
|
|
||||||
|
#endif
|
||||||
24
genprotimg/src/utils/align.h
Normal file
24
genprotimg/src/utils/align.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Alignment utils
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_UTILS_ALIGN_H
|
||||||
|
#define PV_UTILS_ALIGN_H
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
|
#define IS_ALIGNED(addr, size) (!(addr & (size - 1)))
|
||||||
|
|
||||||
|
/* align addr to the next page boundary */
|
||||||
|
#define PAGE_ALIGN(addr) ALIGN((unsigned long)addr, PAGE_SIZE)
|
||||||
|
|
||||||
|
/* test whether an address is aligned to PAGE_SIZE or not */
|
||||||
|
#define IS_PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE)
|
||||||
|
|
||||||
|
#endif
|
||||||
69
genprotimg/src/utils/buffer.c
Normal file
69
genprotimg/src/utils/buffer.c
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Buffer functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "align.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
|
Buffer *buffer_alloc(gsize size)
|
||||||
|
{
|
||||||
|
Buffer *ret = g_new0(Buffer, 1);
|
||||||
|
|
||||||
|
ret->data = g_malloc0(size);
|
||||||
|
ret->size = size;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned)
|
||||||
|
{
|
||||||
|
Buffer *ret;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size = buf->size;
|
||||||
|
if (page_aligned)
|
||||||
|
size = PAGE_ALIGN(size);
|
||||||
|
|
||||||
|
ret = buffer_alloc(size);
|
||||||
|
|
||||||
|
/* content will be 0-right-padded */
|
||||||
|
memcpy(ret->data, buf->data, buf->size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint buffer_write(const Buffer *buf, FILE *file, GError **err)
|
||||||
|
{
|
||||||
|
return file_write(file, buf->data, buf->size, 1, NULL, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_free(Buffer *buf)
|
||||||
|
{
|
||||||
|
if (!buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_free(buf->data);
|
||||||
|
g_free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void buffer_clear(Buffer **buf)
|
||||||
|
{
|
||||||
|
if (!buf || !*buf)
|
||||||
|
return;
|
||||||
|
|
||||||
|
buffer_free(*buf);
|
||||||
|
*buf = NULL;
|
||||||
|
}
|
||||||
31
genprotimg/src/utils/buffer.h
Normal file
31
genprotimg/src/utils/buffer.h
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* Buffer definition and functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_UTILS_BUFFER_H
|
||||||
|
#define PV_UTILS_BUFFER_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
|
||||||
|
typedef struct Buffer {
|
||||||
|
void *data;
|
||||||
|
gsize size; /* in bytes */
|
||||||
|
} Buffer;
|
||||||
|
|
||||||
|
Buffer *buffer_alloc(gsize size);
|
||||||
|
void buffer_free(Buffer *buf);
|
||||||
|
void buffer_clear(Buffer **buf);
|
||||||
|
gint buffer_write(const Buffer *buf, FILE *file, GError **err);
|
||||||
|
Buffer *buffer_dup(const Buffer *buf, gboolean page_aligned);
|
||||||
|
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(Buffer, buffer_free)
|
||||||
|
|
||||||
|
#endif
|
||||||
798
genprotimg/src/utils/crypto.c
Normal file
798
genprotimg/src/utils/crypto.c
Normal file
@@ -0,0 +1,798 @@
|
|||||||
|
/*
|
||||||
|
* General cryptography helper functions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gtypes.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <openssl/aes.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/pem.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "boot/s390.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "include/pv_crypto_def.h"
|
||||||
|
#include "pv/pv_error.h"
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "crypto.h"
|
||||||
|
|
||||||
|
EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EVP_MD_CTX) ctx = EVP_MD_CTX_new();
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
if (EVP_DigestInit_ex(ctx, md, NULL) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestInit_ex failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err)
|
||||||
|
{
|
||||||
|
gint md_size = EVP_MD_size(EVP_MD_CTX_md(ctx));
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
guint digest_size;
|
||||||
|
|
||||||
|
g_assert(md_size > 0);
|
||||||
|
|
||||||
|
ret = buffer_alloc((guint)md_size);
|
||||||
|
if (EVP_DigestFinal_ex(ctx, ret->data, &digest_size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestFinal_ex failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert(digest_size == (guint)md_size);
|
||||||
|
g_assert(digest_size == ret->size);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the digest of @buf using the hash algorithm @md */
|
||||||
|
static Buffer *digest_buffer(const EVP_MD *md, const Buffer *buf, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EVP_MD_CTX) md_ctx = NULL;
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
g_assert(buf);
|
||||||
|
|
||||||
|
md_ctx = digest_ctx_new(md, err);
|
||||||
|
if (!md_ctx)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (EVP_DigestUpdate(md_ctx, buf->data, buf->size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_DigestUpdate failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = digest_ctx_finalize(md_ctx, err);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the SHA256 digest of @buf */
|
||||||
|
Buffer *sha256_buffer(const Buffer *buf, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
|
||||||
|
ret = digest_buffer(EVP_sha256(), buf, err);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g_assert(ret->size == SHA256_DIGEST_LENGTH);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a EVP_PKEY to the key format used in the PV header */
|
||||||
|
union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err)
|
||||||
|
{
|
||||||
|
g_autofree union ecdh_pub_key *ret = g_new0(union ecdh_pub_key, 1);
|
||||||
|
g_autoptr(BIGNUM) pub_x_big = NULL;
|
||||||
|
g_autoptr(BIGNUM) pub_y_big = NULL;
|
||||||
|
g_autoptr(EC_KEY) ec_key = NULL;
|
||||||
|
const EC_POINT *pub_key;
|
||||||
|
const EC_GROUP *grp;
|
||||||
|
|
||||||
|
ec_key = EVP_PKEY_get1_EC_KEY(key);
|
||||||
|
if (!ec_key) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Key has the wrong type"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub_key = EC_KEY_get0_public_key(ec_key);
|
||||||
|
if (!pub_key) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Failed to get public key"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
grp = EC_KEY_get0_group(ec_key);
|
||||||
|
if (!grp) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Failed to get EC group"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub_x_big = BN_new();
|
||||||
|
if (!pub_x_big)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
pub_y_big = BN_new();
|
||||||
|
if (!pub_y_big)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
if (EC_POINT_get_affine_coordinates_GFp(grp, pub_key, pub_x_big,
|
||||||
|
pub_y_big, NULL) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Cannot convert key to internal format"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BN_bn2binpad(pub_x_big, ret->x, sizeof(ret->x)) < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Cannot convert key to internal format"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BN_bn2binpad(pub_y_big, ret->y, sizeof(ret->y)) < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Cannot convert key to internal format"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buffer *derive_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EVP_PKEY_CTX) ctx = NULL;
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
gsize key_size;
|
||||||
|
|
||||||
|
ctx = EVP_PKEY_CTX_new(cust, NULL);
|
||||||
|
if (!ctx)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
if (EVP_PKEY_derive_init(ctx) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Key derivation failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_PKEY_derive_set_peer(ctx, host) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Key derivation failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine buffer length */
|
||||||
|
if (EVP_PKEY_derive(ctx, NULL, &key_size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
|
||||||
|
_("Key derivation failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = buffer_alloc(key_size);
|
||||||
|
if (EVP_PKEY_derive(ctx, ret->data, &key_size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_DERIVE,
|
||||||
|
_("Key derivation failed"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert(ret->size == key_size);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) raw = buffer_alloc(70);
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
g_autoptr(Buffer) key = NULL;
|
||||||
|
guchar *data;
|
||||||
|
|
||||||
|
key = derive_key(cust, host, err);
|
||||||
|
if (!key)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
g_assert(key->size == 66);
|
||||||
|
g_assert(key->size < raw->size);
|
||||||
|
|
||||||
|
/* ANSI X.9.63-2011: 66 bytes x with leading 7 bits and
|
||||||
|
* concatenate 32 bit int '1'
|
||||||
|
*/
|
||||||
|
memcpy(raw->data, key->data, key->size);
|
||||||
|
data = raw->data;
|
||||||
|
data[66] = 0x00;
|
||||||
|
data[67] = 0x00;
|
||||||
|
data[68] = 0x00;
|
||||||
|
data[69] = 0x01;
|
||||||
|
|
||||||
|
ret = sha256_buffer(raw, err);
|
||||||
|
if (!ret)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
gint generate_tweak(union tweak *tweak, uint16_t i, GError **err)
|
||||||
|
{
|
||||||
|
tweak->cmp_idx.idx = GUINT16_TO_BE(i);
|
||||||
|
if (RAND_bytes(tweak->cmp_idx.rand, sizeof(tweak->cmp_idx.rand)) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||||
|
_("Generating a tweak failed because the required amount of random data is not available"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buffer *generate_rand_data(guint size, const gchar *err_msg,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) buf = buffer_alloc(size);
|
||||||
|
|
||||||
|
g_assert(size <= INT_MAX);
|
||||||
|
|
||||||
|
if (RAND_bytes(buf->data, (int)size) != 1) {
|
||||||
|
g_set_error_literal(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_RANDOMIZATION,
|
||||||
|
err_msg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *generate_aes_iv(guint size, GError **err)
|
||||||
|
{
|
||||||
|
return generate_rand_data(size,
|
||||||
|
_("Generating a IV failed because the required amount of random data is not available"),
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *generate_aes_key(guint size, GError **err)
|
||||||
|
{
|
||||||
|
return generate_rand_data(size,
|
||||||
|
_("Generating a key failed because the required amount of random data is not available"),
|
||||||
|
err);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY *generate_ec_key(gint nid, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EVP_PKEY_CTX) ctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL);
|
||||||
|
g_autoptr(EVP_PKEY) ret = NULL;
|
||||||
|
|
||||||
|
if (!ctx)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
if (EVP_PKEY_keygen_init(ctx) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
|
||||||
|
_("EC key could not be auto-generated"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_PKEY_CTX_set_ec_paramgen_curve_nid(ctx, nid) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
|
||||||
|
_("EC key could not be auto-generated"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EVP_PKEY_keygen(ctx, &ret) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_KEYGENERATION,
|
||||||
|
_("EC key could not be auto-generated"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean certificate_uses_correct_curve(EVP_PKEY *key, gint nid,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EC_KEY) ec = NULL;
|
||||||
|
gint rc;
|
||||||
|
|
||||||
|
g_assert(key);
|
||||||
|
|
||||||
|
if (EVP_PKEY_id(key) != EVP_PKEY_EC) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
_("No EC key found"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = EVP_PKEY_get1_EC_KEY(key);
|
||||||
|
if (!ec) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
_("No EC key found"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EC_KEY_check_key(ec) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
_("Invalid EC key"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
||||||
|
if (rc != nid) {
|
||||||
|
/* maybe the NID is unset */
|
||||||
|
if (rc == 0) {
|
||||||
|
g_autoptr(EC_GROUP) grp = EC_GROUP_new_by_curve_name(nid);
|
||||||
|
const EC_POINT *pub = EC_KEY_get0_public_key(ec);
|
||||||
|
g_autoptr(BN_CTX) ctx = BN_CTX_new();
|
||||||
|
|
||||||
|
if (EC_POINT_is_on_curve(grp, pub, ctx) != 1) {
|
||||||
|
g_set_error_literal(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
_("Invalid EC curve"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* NID was set but doesn't match with the expected NID
|
||||||
|
*/
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
_("Wrong NID used: '%d'"),
|
||||||
|
EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean verify_certificate(X509_STORE *store, X509 *cert, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(X509_STORE_CTX) csc = X509_STORE_CTX_new();
|
||||||
|
if (!csc)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
if (X509_STORE_CTX_init(csc, store, cert, NULL) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INIT,
|
||||||
|
_("Failed to initialize X.509 store"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (X509_verify_cert(csc) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_VERIFICATION,
|
||||||
|
_("Failed to verify host-key document"));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static X509 *load_certificate(const gchar *path, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(X509) ret = NULL;
|
||||||
|
g_autoptr(BIO) bio = BIO_new_file(path, "rb");
|
||||||
|
|
||||||
|
if (!bio) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
|
_("Failed to read host-key document: '%s'"), path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = PEM_read_bio_X509(bio, NULL, 0, NULL);
|
||||||
|
if (!ret) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
|
_("Failed to load host-key document: '%s'"), path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY *read_ec_pubkey_cert(X509_STORE *store, gint nid, const gchar *path,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EVP_PKEY) ret = NULL;
|
||||||
|
g_autoptr(X509) cert = NULL;
|
||||||
|
|
||||||
|
cert = load_certificate(path, err);
|
||||||
|
if (!cert)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (store && !verify_certificate(store, cert, err)) {
|
||||||
|
g_prefix_error(err,
|
||||||
|
_("Failed to load host-key document: '%s': "),
|
||||||
|
path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = X509_get_pubkey(cert);
|
||||||
|
if (!ret) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INVALID_PARM,
|
||||||
|
_("Failed to get public key from host-key document: '%s'"),
|
||||||
|
path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!certificate_uses_correct_curve(ret, nid, err)) {
|
||||||
|
g_prefix_error(err,
|
||||||
|
_("Failed to load host-key document: '%s': "),
|
||||||
|
path);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint __encrypt_decrypt_bio(const struct cipher_parms *parms, BIO *b_in,
|
||||||
|
BIO *b_out, gsize *size_in, gsize *size_out,
|
||||||
|
gboolean encrypt, GError **err)
|
||||||
|
{
|
||||||
|
gint num_bytes_read, num_bytes_written;
|
||||||
|
g_autoptr(EVP_CIPHER_CTX) ctx = NULL;
|
||||||
|
g_autoptr(BIGNUM) tweak_num = NULL;
|
||||||
|
const EVP_CIPHER *cipher = parms->cipher;
|
||||||
|
gint cipher_block_size = EVP_CIPHER_block_size(cipher);
|
||||||
|
guchar in_buf[PAGE_SIZE],
|
||||||
|
out_buf[PAGE_SIZE + (guint)cipher_block_size];
|
||||||
|
const Buffer *key = parms->key;
|
||||||
|
const Buffer *tweak = parms->iv_or_tweak;
|
||||||
|
g_autofree guchar *tmp_tweak = NULL;
|
||||||
|
gint out_len, tweak_size;
|
||||||
|
gsize tmp_size_in = 0, tmp_size_out = 0;
|
||||||
|
|
||||||
|
g_assert(cipher_block_size > 0);
|
||||||
|
g_assert(key);
|
||||||
|
g_assert(tweak);
|
||||||
|
g_assert(tweak->size <= INT_MAX);
|
||||||
|
|
||||||
|
/* copy the value for leaving the original value untouched */
|
||||||
|
tmp_tweak = g_malloc0(tweak->size);
|
||||||
|
memcpy(tmp_tweak, tweak->data, tweak->size);
|
||||||
|
tweak_size = (int)tweak->size;
|
||||||
|
tweak_num = BN_bin2bn(tmp_tweak, tweak_size, NULL);
|
||||||
|
if (!tweak_num) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("BN_bin2bn failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx = EVP_CIPHER_CTX_new();
|
||||||
|
if (!ctx)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
/* don't set the key or tweak right away as we want to check
|
||||||
|
* lengths before
|
||||||
|
*/
|
||||||
|
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encrypt) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherInit_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we can set the key and tweak */
|
||||||
|
if (EVP_CipherInit_ex(ctx, NULL, NULL, key->data, tmp_tweak, encrypt) !=
|
||||||
|
1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherInit_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
memset(in_buf, 0, sizeof(in_buf));
|
||||||
|
/* Read in data in 4096 bytes blocks. Update the ciphering
|
||||||
|
* with each read.
|
||||||
|
*/
|
||||||
|
num_bytes_read = BIO_read(b_in, in_buf, (int)PAGE_SIZE);
|
||||||
|
if (num_bytes_read < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Failed to read"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tmp_size_in += (guint)num_bytes_read;
|
||||||
|
|
||||||
|
/* in case we reached the end and it's not the special
|
||||||
|
* case of an empty component we can break here
|
||||||
|
*/
|
||||||
|
if (num_bytes_read == 0 && tmp_size_in != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (EVP_CipherUpdate(ctx, out_buf, &out_len, in_buf,
|
||||||
|
sizeof(in_buf)) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherUpdate failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
g_assert(out_len >= 0);
|
||||||
|
|
||||||
|
num_bytes_written = BIO_write(b_out, out_buf, out_len);
|
||||||
|
if (num_bytes_written < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Failed to write"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
g_assert(num_bytes_written == out_len);
|
||||||
|
|
||||||
|
tmp_size_out += (guint)num_bytes_written;
|
||||||
|
|
||||||
|
/* Set new tweak value. Please keep in mind that the
|
||||||
|
* tweaks are stored in big-endian form. Therefore we
|
||||||
|
* must use the correct OpenSSL functions
|
||||||
|
*/
|
||||||
|
if (BN_add_word(tweak_num, PAGE_SIZE) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("BN_add_word failed"));
|
||||||
|
}
|
||||||
|
g_assert(BN_num_bytes(tweak_num) > 0);
|
||||||
|
g_assert(BN_num_bytes(tweak_num) <= tweak_size);
|
||||||
|
|
||||||
|
if (BN_bn2binpad(tweak_num, tmp_tweak, tweak_size) < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("BN_bn2binpad failed"));
|
||||||
|
};
|
||||||
|
|
||||||
|
/* set new tweak */
|
||||||
|
if (EVP_CipherInit_ex(ctx, NULL, NULL, NULL, tmp_tweak,
|
||||||
|
encrypt) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherInit_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} while (num_bytes_read == PAGE_SIZE);
|
||||||
|
|
||||||
|
/* Now cipher the final block and write it out to file */
|
||||||
|
if (EVP_CipherFinal_ex(ctx, out_buf, &out_len) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherFinal_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
g_assert(out_len >= 0);
|
||||||
|
|
||||||
|
num_bytes_written = BIO_write(b_out, out_buf, out_len);
|
||||||
|
if (num_bytes_written < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Failed to write"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
g_assert(out_len == num_bytes_written);
|
||||||
|
tmp_size_out += (guint)out_len;
|
||||||
|
|
||||||
|
if (BIO_flush(b_out) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Failed to flush"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size_in = tmp_size_in;
|
||||||
|
*size_out = tmp_size_out;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Buffer *__encrypt_decrypt_buffer(const struct cipher_parms *parms,
|
||||||
|
const Buffer *in, gboolean encrypt,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(Buffer) ret = NULL;
|
||||||
|
g_autoptr(BIO) b_out = NULL;
|
||||||
|
g_autoptr(BIO) b_in = NULL;
|
||||||
|
gsize in_size, out_size;
|
||||||
|
gchar *data = NULL;
|
||||||
|
long data_size;
|
||||||
|
|
||||||
|
g_assert(in->size <= INT_MAX);
|
||||||
|
|
||||||
|
b_in = BIO_new_mem_buf(in->data, (int)in->size);
|
||||||
|
if (!b_in)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
b_out = BIO_new(BIO_s_mem());
|
||||||
|
if (!b_out)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
if (__encrypt_decrypt_bio(parms, b_in, b_out, &in_size, &out_size,
|
||||||
|
encrypt, err) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
data_size = BIO_get_mem_data(b_out, &data);
|
||||||
|
if (data_size < 0) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Could not read buffer"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = buffer_alloc((unsigned long)data_size);
|
||||||
|
memcpy(ret->data, data, ret->size);
|
||||||
|
return g_steal_pointer(&ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
return __encrypt_decrypt_buffer(parms, in, TRUE, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
Buffer *decrypt_buf(const struct cipher_parms *parms, const Buffer *in,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
return __encrypt_decrypt_buffer(parms, in, FALSE, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint __encrypt_decrypt_file(const struct cipher_parms *parms,
|
||||||
|
const gchar *path_in, const gchar *path_out,
|
||||||
|
gsize *size_in, gsize *size_out, gboolean encrypt,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(BIO) b_out = NULL;
|
||||||
|
g_autoptr(BIO) b_in = NULL;
|
||||||
|
|
||||||
|
b_in = BIO_new_file(path_in, "rb");
|
||||||
|
if (!b_in) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
|
_("Failed to read file '%s'"), path_in);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
b_out = BIO_new_file(path_out, "wb");
|
||||||
|
if (!b_out) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_READ_CERTIFICATE,
|
||||||
|
_("Failed to write file '%s'"), path_out);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (__encrypt_decrypt_bio(parms, b_in, b_out, size_in, size_out,
|
||||||
|
encrypt, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint encrypt_file(const struct cipher_parms *parms, const gchar *path_in,
|
||||||
|
const gchar *path_out, gsize *in_size, gsize *out_size,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
return __encrypt_decrypt_file(parms, path_in, path_out, in_size,
|
||||||
|
out_size, TRUE, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
G_GNUC_UNUSED static gint decrypt_file(const struct cipher_parms *parms,
|
||||||
|
const gchar *path_in, const gchar *path_out,
|
||||||
|
gsize *in_size, gsize *out_size,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
return __encrypt_decrypt_file(parms, path_in, path_out, in_size,
|
||||||
|
out_size, FALSE, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* GCM mode uses (zero-)padding */
|
||||||
|
static int64_t gcm_encrypt_decrypt(const Buffer *in, const Buffer *aad,
|
||||||
|
const struct cipher_parms *parms,
|
||||||
|
Buffer *out, Buffer *tag,
|
||||||
|
enum PvCryptoMode mode, GError **err)
|
||||||
|
{
|
||||||
|
g_autoptr(EVP_CIPHER_CTX) ctx = NULL;
|
||||||
|
const EVP_CIPHER *cipher = parms->cipher;
|
||||||
|
const Buffer *iv = parms->iv_or_tweak;
|
||||||
|
gboolean encrypt = mode == PV_ENCRYPT;
|
||||||
|
const Buffer *key = parms->key;
|
||||||
|
int64_t ret = -1;
|
||||||
|
gint len = -1;
|
||||||
|
|
||||||
|
g_assert(cipher);
|
||||||
|
g_assert(key);
|
||||||
|
g_assert(iv);
|
||||||
|
/* Checks for later casts */
|
||||||
|
g_assert(aad->size <= INT_MAX);
|
||||||
|
g_assert(in->size <= INT_MAX);
|
||||||
|
g_assert(tag->size <= INT_MAX);
|
||||||
|
g_assert(iv->size <= INT_MAX);
|
||||||
|
g_assert(out->size == in->size);
|
||||||
|
|
||||||
|
ctx = EVP_CIPHER_CTX_new();
|
||||||
|
if (!ctx)
|
||||||
|
g_abort();
|
||||||
|
|
||||||
|
/* First, set the cipher algorithm so we can verify our key/IV lengths
|
||||||
|
*/
|
||||||
|
if (EVP_CipherInit_ex(ctx, cipher, NULL, NULL, NULL, encrypt) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CIPHER_CTX_new failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set IV length */
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, (int)iv->size, NULL) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CIPHER_CTX_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise key and IV */
|
||||||
|
if (EVP_CipherInit_ex(ctx, NULL, NULL, key->data, iv->data, encrypt) !=
|
||||||
|
1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherInit_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aad->size > 0) {
|
||||||
|
/* Provide any AAD data */
|
||||||
|
if (EVP_CipherUpdate(ctx, NULL, &len, aad->data,
|
||||||
|
(int)aad->size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherUpdate failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
g_assert(len == (int)aad->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Provide data to be en/decrypted */
|
||||||
|
if (EVP_CipherUpdate(ctx, out->data, &len, in->data, (int)in->size) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherUpdate failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret = len;
|
||||||
|
|
||||||
|
if (!encrypt) {
|
||||||
|
/* Set expected tag value */
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG,
|
||||||
|
(int)tag->size, tag->data) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Setting the GCM tag failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finalize the en/decryption */
|
||||||
|
if (EVP_CipherFinal_ex(ctx, (guchar *)out->data + len, &len) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR, PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("EVP_CipherFinal_ex failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
ret += len;
|
||||||
|
|
||||||
|
if (encrypt) {
|
||||||
|
/* Get the tag */
|
||||||
|
if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG,
|
||||||
|
(int)tag->size, tag->data) != 1) {
|
||||||
|
g_set_error(err, PV_CRYPTO_ERROR,
|
||||||
|
PV_CRYPTO_ERROR_INTERNAL,
|
||||||
|
_("Getting the GCM tag failed"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert(ret == (int)in->size);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
|
||||||
|
const struct cipher_parms *parms, Buffer *out, Buffer *tag,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
return gcm_encrypt_decrypt(in, aad, parms, out, tag, PV_ENCRYPT, err);
|
||||||
|
}
|
||||||
104
genprotimg/src/utils/crypto.h
Normal file
104
genprotimg/src/utils/crypto.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* General cryptography helper functions and definitions
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_UTILS_CRYPTO_H
|
||||||
|
#define PV_UTILS_CRYPTO_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <openssl/bio.h>
|
||||||
|
#include <openssl/bn.h>
|
||||||
|
#include <openssl/ec.h>
|
||||||
|
#include <openssl/ecdh.h>
|
||||||
|
#include <openssl/evp.h>
|
||||||
|
#include <openssl/rand.h>
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
#include <openssl/x509.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "include/pv_crypto_def.h"
|
||||||
|
#include "lib/zt_common.h"
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
#define AES_256_GCM_IV_SIZE 12
|
||||||
|
#define AES_256_GCM_TAG_SIZE 16
|
||||||
|
|
||||||
|
#define AES_256_XTS_TWEAK_SIZE 16
|
||||||
|
#define AES_256_XTS_KEY_SIZE 64
|
||||||
|
|
||||||
|
enum PvCryptoMode {
|
||||||
|
PV_ENCRYPT,
|
||||||
|
PV_DECRYPT,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GSList HostKeyList;
|
||||||
|
|
||||||
|
/* Register auto cleanup functions */
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIGNUM, BN_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BIO, BIO_free_all)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(BN_CTX, BN_CTX_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_GROUP, EC_GROUP_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_KEY, EC_KEY_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EC_POINT, EC_POINT_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_CIPHER_CTX, EVP_CIPHER_CTX_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_MD_CTX, EVP_MD_CTX_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY, EVP_PKEY_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(EVP_PKEY_CTX, EVP_PKEY_CTX_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509, X509_free)
|
||||||
|
WRAPPED_G_DEFINE_AUTOPTR_CLEANUP_FUNC(X509_LOOKUP, X509_LOOKUP_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)
|
||||||
|
|
||||||
|
union cmp_index {
|
||||||
|
struct {
|
||||||
|
uint16_t idx;
|
||||||
|
guchar rand[6];
|
||||||
|
} __packed;
|
||||||
|
uint64_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The tweak is always stored in big endian format */
|
||||||
|
union tweak {
|
||||||
|
struct {
|
||||||
|
union cmp_index cmp_idx;
|
||||||
|
uint64_t page_idx; /* page index */
|
||||||
|
} __packed;
|
||||||
|
uint8_t data[AES_256_XTS_TWEAK_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cipher_parms {
|
||||||
|
const EVP_CIPHER *cipher;
|
||||||
|
const Buffer *key;
|
||||||
|
const Buffer *iv_or_tweak;
|
||||||
|
};
|
||||||
|
|
||||||
|
EVP_PKEY *read_ec_pubkey_cert(X509_STORE *store, gint nid, const gchar *path,
|
||||||
|
GError **err);
|
||||||
|
Buffer *compute_exchange_key(EVP_PKEY *cust, EVP_PKEY *host, GError **err);
|
||||||
|
Buffer *generate_aes_key(guint size, GError **err);
|
||||||
|
Buffer *generate_aes_iv(guint size, GError **err);
|
||||||
|
EVP_PKEY *generate_ec_key(gint nid, GError **err);
|
||||||
|
gint generate_tweak(union tweak *tweak, uint16_t i, GError **err);
|
||||||
|
union ecdh_pub_key *evp_pkey_to_ecdh_pub_key(EVP_PKEY *key, GError **err);
|
||||||
|
EVP_MD_CTX *digest_ctx_new(const EVP_MD *md, GError **err);
|
||||||
|
Buffer *digest_ctx_finalize(EVP_MD_CTX *ctx, GError **err);
|
||||||
|
Buffer *sha256_buffer(const Buffer *buf, GError **err);
|
||||||
|
int64_t gcm_encrypt(const Buffer *in, const Buffer *aad,
|
||||||
|
const struct cipher_parms *parms, Buffer *out,
|
||||||
|
Buffer *tag, GError **err);
|
||||||
|
gint encrypt_file(const struct cipher_parms *parms, const gchar *in_path,
|
||||||
|
const gchar *path_out, gsize *in_size, gsize *out_size,
|
||||||
|
GError **err);
|
||||||
|
Buffer *encrypt_buf(const struct cipher_parms *parms, const Buffer *in,
|
||||||
|
GError **err);
|
||||||
|
G_GNUC_UNUSED Buffer *decrypt_buf(const struct cipher_parms *parms,
|
||||||
|
const Buffer *in, GError **err);
|
||||||
|
|
||||||
|
#endif
|
||||||
234
genprotimg/src/utils/file_utils.c
Normal file
234
genprotimg/src/utils/file_utils.c
Normal file
@@ -0,0 +1,234 @@
|
|||||||
|
/*
|
||||||
|
* General file utils
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "pv/pv_error.h"
|
||||||
|
|
||||||
|
#include "align.h"
|
||||||
|
#include "buffer.h"
|
||||||
|
#include "common.h"
|
||||||
|
#include "file_utils.h"
|
||||||
|
|
||||||
|
FILE *file_open(const gchar *filename, const gchar *mode, GError **err)
|
||||||
|
{
|
||||||
|
FILE *f = fopen(filename, mode);
|
||||||
|
|
||||||
|
if (!f) {
|
||||||
|
g_set_error(err, G_FILE_ERROR,
|
||||||
|
(gint)g_file_error_from_errno(errno),
|
||||||
|
_("Failed to open file '%s': %s"), filename,
|
||||||
|
g_strerror(errno));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint file_size(const gchar *filename, gsize *size, GError **err)
|
||||||
|
{
|
||||||
|
GStatBuf st_buf;
|
||||||
|
|
||||||
|
g_assert(size);
|
||||||
|
|
||||||
|
if (g_stat(filename, &st_buf) != 0) {
|
||||||
|
g_set_error(err, G_FILE_ERROR,
|
||||||
|
(gint)g_file_error_from_errno(errno),
|
||||||
|
_("Failed to get file status '%s': %s"), filename,
|
||||||
|
g_strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!S_ISREG(st_buf.st_mode)) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("File '%s' is not a regular file"), filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st_buf.st_size < 0) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("Invalid file size for '%s': %zu"), filename,
|
||||||
|
st_buf.st_size);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = (gsize)st_buf.st_size;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns 0 on success, otherwise -1. Stores the total number of
|
||||||
|
* elements successfully read in @count_read
|
||||||
|
*/
|
||||||
|
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
|
||||||
|
gsize *count_read, GError **err)
|
||||||
|
{
|
||||||
|
gsize tmp_count_read;
|
||||||
|
|
||||||
|
tmp_count_read = fread(ptr, size, count, in);
|
||||||
|
if (count_read)
|
||||||
|
*count_read = tmp_count_read;
|
||||||
|
|
||||||
|
if (ferror(in)) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, 0, _("Failed to read file"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
|
||||||
|
gsize *count_written, GError **err)
|
||||||
|
{
|
||||||
|
gsize tmp_count_written;
|
||||||
|
|
||||||
|
tmp_count_written = fwrite(ptr, size, count, out);
|
||||||
|
if (count_written)
|
||||||
|
*count_written = tmp_count_written;
|
||||||
|
|
||||||
|
if (tmp_count_written != count || ferror(out)) {
|
||||||
|
g_set_error(err, G_FILE_ERROR, 0, _("Failed to write file"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint file_seek(FILE *f, uint64_t offset, GError **err)
|
||||||
|
{
|
||||||
|
gint rc;
|
||||||
|
|
||||||
|
if (offset > LONG_MAX) {
|
||||||
|
g_set_error(err, PV_ERROR, 0, _("Offset is too large"));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = fseek(f, (long)offset, SEEK_SET);
|
||||||
|
if (rc != 0) {
|
||||||
|
g_set_error(err, G_FILE_ERROR,
|
||||||
|
(gint)g_file_error_from_errno(errno),
|
||||||
|
_("Failed to seek: '%s'"), g_strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
gsize bytes_read, bytes_written;
|
||||||
|
gsize total_bytes_read = 0;
|
||||||
|
FILE *i = NULL;
|
||||||
|
gchar buf[4096];
|
||||||
|
gint ret = -1;
|
||||||
|
|
||||||
|
if (file_seek(o, offset, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
i = file_open(ifile->path, "rb", err);
|
||||||
|
if (!i)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (file_read(i, buf, 1, sizeof(buf), &bytes_read, err) < 0) {
|
||||||
|
g_prefix_error(err, _("Failed to read file '%s': "),
|
||||||
|
ifile->path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_read == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
total_bytes_read += bytes_read;
|
||||||
|
|
||||||
|
if (file_write(o, buf, bytes_read, 1, &bytes_written, err) < 0)
|
||||||
|
goto err;
|
||||||
|
} while (bytes_written != 0);
|
||||||
|
|
||||||
|
if (ifile->size != total_bytes_read) {
|
||||||
|
g_set_error(err, PV_ERROR, PV_ERROR_INTERNAL,
|
||||||
|
_("'%s' has changed during the preparation"),
|
||||||
|
ifile->path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
err:
|
||||||
|
fclose(i);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint seek_and_write_buffer(FILE *o, const Buffer *buf, uint64_t offset,
|
||||||
|
GError **err)
|
||||||
|
{
|
||||||
|
if (file_seek(o, offset, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (buffer_write(buf, o, err) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gint pad_file_right(const gchar *path_out, const gchar *path_in, gsize *size_out,
|
||||||
|
guint padding, GError **err)
|
||||||
|
{
|
||||||
|
FILE *f_in, *f_out = NULL;
|
||||||
|
guchar buf[padding];
|
||||||
|
gsize num_bytes_written;
|
||||||
|
gsize num_bytes_read;
|
||||||
|
uint64_t size_in = 0;
|
||||||
|
gint ret = -1;
|
||||||
|
|
||||||
|
*size_out = 0;
|
||||||
|
f_in = file_open(path_in, "rb", err);
|
||||||
|
if (!f_in)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
f_out = file_open(path_out, "wb", err);
|
||||||
|
if (!f_out)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
do {
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
if (file_read(f_in, buf, 1, sizeof(buf), &num_bytes_read, err) < 0) {
|
||||||
|
g_prefix_error(err, _("Failed to read file '%s': "),
|
||||||
|
path_in);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_in += num_bytes_read;
|
||||||
|
|
||||||
|
if (file_write(f_out, buf, 1, sizeof(buf), &num_bytes_written, err)) {
|
||||||
|
g_prefix_error(err, _("Failed to write file '%s': "),
|
||||||
|
path_out);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size_out += num_bytes_written;
|
||||||
|
} while (num_bytes_read == padding);
|
||||||
|
|
||||||
|
g_assert(num_bytes_written == ALIGN(num_bytes_read, padding));
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
err:
|
||||||
|
if (f_out)
|
||||||
|
fclose(f_out);
|
||||||
|
if (f_in)
|
||||||
|
fclose(f_in);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
34
genprotimg/src/utils/file_utils.h
Normal file
34
genprotimg/src/utils/file_utils.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* General file utils
|
||||||
|
*
|
||||||
|
* Copyright IBM Corp. 2020
|
||||||
|
*
|
||||||
|
* s390-tools is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the MIT license. See LICENSE for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PV_FILE_UTILS_H
|
||||||
|
#define PV_FILE_UTILS_H
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "pv/pv_comp.h"
|
||||||
|
|
||||||
|
#include "buffer.h"
|
||||||
|
|
||||||
|
FILE *file_open(const gchar *filename, const gchar *mode, GError **err);
|
||||||
|
gint file_size(const gchar *filename, gsize *size, GError **err);
|
||||||
|
gint file_read(FILE *in, void *ptr, gsize size, gsize count,
|
||||||
|
gsize *count_read, GError **err);
|
||||||
|
gint file_write(FILE *out, const void *ptr, gsize size, gsize count,
|
||||||
|
gsize *count_written, GError **err);
|
||||||
|
gint pad_file_right(const gchar *path_out, const gchar *path_in,
|
||||||
|
gsize *size_out, guint padding, GError **err);
|
||||||
|
gint seek_and_write_buffer(FILE *out, const Buffer *buf, uint64_t offset,
|
||||||
|
GError **err);
|
||||||
|
gint seek_and_write_file(FILE *o, const CompFile *ifile, uint64_t offset,
|
||||||
|
GError **err);
|
||||||
|
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user