aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390
diff options
context:
space:
mode:
authorFelix Beck <felix.beck@de.ibm.com>2009-12-07 06:51:55 -0500
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2009-12-07 06:51:35 -0500
commita6a5d73a56540b5e59dff83bc8f2b2725591346a (patch)
tree84a293aa41b9326cebcc38afc069d839b76da2f7 /drivers/s390
parent468ffddf19c1417947cac931c240b0d600e4b5bf (diff)
[S390] zcrypt: special command support for cex3 exploitation
Support for special command is implemented in the AP Bus in the NQAP function __ap_send. This is extended for a further parameter special. When set, the special bit, in GR0 will be set. Therefor the ap_message struct is extended for a further bit. Thus calling functions of __ap_send can use the special parameter in ap_message to give to __ap_send. Affected is in the first place ap_queue_message, which is called by the actual card driver. The second part of this support is that the card driver for the CEX3C needs to set this special bit, when an according CPRB is sent to the driver. Signed-off-by: Felix Beck <felix.beck@de.ibm.com> Signed-off-by: Ralph Wuerthner <ralph.wuerthner@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390')
-rw-r--r--drivers/s390/crypto/ap_bus.c20
-rw-r--r--drivers/s390/crypto/ap_bus.h3
-rw-r--r--drivers/s390/crypto/zcrypt_pcixcc.c5
3 files changed, 23 insertions, 5 deletions
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 1294876bf7b4..21077f4b8c50 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -282,6 +282,7 @@ static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
282 * @psmid: The program supplied message identifier 282 * @psmid: The program supplied message identifier
283 * @msg: The message text 283 * @msg: The message text
284 * @length: The message length 284 * @length: The message length
285 * @special: Special Bit
285 * 286 *
286 * Returns AP queue status structure. 287 * Returns AP queue status structure.
287 * Condition code 1 on NQAP can't happen because the L bit is 1. 288 * Condition code 1 on NQAP can't happen because the L bit is 1.
@@ -289,7 +290,8 @@ static int ap_queue_enable_interruption(ap_qid_t qid, void *ind)
289 * because a segment boundary was reached. The NQAP is repeated. 290 * because a segment boundary was reached. The NQAP is repeated.
290 */ 291 */
291static inline struct ap_queue_status 292static inline struct ap_queue_status
292__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) 293__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length,
294 unsigned int special)
293{ 295{
294 typedef struct { char _[length]; } msgblock; 296 typedef struct { char _[length]; } msgblock;
295 register unsigned long reg0 asm ("0") = qid | 0x40000000UL; 297 register unsigned long reg0 asm ("0") = qid | 0x40000000UL;
@@ -299,6 +301,9 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
299 register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); 301 register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32);
300 register unsigned long reg5 asm ("5") = (unsigned int) psmid; 302 register unsigned long reg5 asm ("5") = (unsigned int) psmid;
301 303
304 if (special == 1)
305 reg0 |= 0x400000UL;
306
302 asm volatile ( 307 asm volatile (
303 "0: .long 0xb2ad0042\n" /* DQAP */ 308 "0: .long 0xb2ad0042\n" /* DQAP */
304 " brc 2,0b" 309 " brc 2,0b"
@@ -312,13 +317,15 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length)
312{ 317{
313 struct ap_queue_status status; 318 struct ap_queue_status status;
314 319
315 status = __ap_send(qid, psmid, msg, length); 320 status = __ap_send(qid, psmid, msg, length, 0);
316 switch (status.response_code) { 321 switch (status.response_code) {
317 case AP_RESPONSE_NORMAL: 322 case AP_RESPONSE_NORMAL:
318 return 0; 323 return 0;
319 case AP_RESPONSE_Q_FULL: 324 case AP_RESPONSE_Q_FULL:
320 case AP_RESPONSE_RESET_IN_PROGRESS: 325 case AP_RESPONSE_RESET_IN_PROGRESS:
321 return -EBUSY; 326 return -EBUSY;
327 case AP_RESPONSE_REQ_FAC_NOT_INST:
328 return -EINVAL;
322 default: /* Device is gone. */ 329 default: /* Device is gone. */
323 return -ENODEV; 330 return -ENODEV;
324 } 331 }
@@ -1008,7 +1015,7 @@ static int ap_probe_device_type(struct ap_device *ap_dev)
1008 } 1015 }
1009 1016
1010 status = __ap_send(ap_dev->qid, 0x0102030405060708ULL, 1017 status = __ap_send(ap_dev->qid, 0x0102030405060708ULL,
1011 msg, sizeof(msg)); 1018 msg, sizeof(msg), 0);
1012 if (status.response_code != AP_RESPONSE_NORMAL) { 1019 if (status.response_code != AP_RESPONSE_NORMAL) {
1013 rc = -ENODEV; 1020 rc = -ENODEV;
1014 goto out_free; 1021 goto out_free;
@@ -1243,7 +1250,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
1243 /* Start the next request on the queue. */ 1250 /* Start the next request on the queue. */
1244 ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list); 1251 ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list);
1245 status = __ap_send(ap_dev->qid, ap_msg->psmid, 1252 status = __ap_send(ap_dev->qid, ap_msg->psmid,
1246 ap_msg->message, ap_msg->length); 1253 ap_msg->message, ap_msg->length, ap_msg->special);
1247 switch (status.response_code) { 1254 switch (status.response_code) {
1248 case AP_RESPONSE_NORMAL: 1255 case AP_RESPONSE_NORMAL:
1249 atomic_inc(&ap_poll_requests); 1256 atomic_inc(&ap_poll_requests);
@@ -1261,6 +1268,7 @@ static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
1261 *flags |= 2; 1268 *flags |= 2;
1262 break; 1269 break;
1263 case AP_RESPONSE_MESSAGE_TOO_BIG: 1270 case AP_RESPONSE_MESSAGE_TOO_BIG:
1271 case AP_RESPONSE_REQ_FAC_NOT_INST:
1264 return -EINVAL; 1272 return -EINVAL;
1265 default: 1273 default:
1266 return -ENODEV; 1274 return -ENODEV;
@@ -1302,7 +1310,8 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms
1302 if (list_empty(&ap_dev->requestq) && 1310 if (list_empty(&ap_dev->requestq) &&
1303 ap_dev->queue_count < ap_dev->queue_depth) { 1311 ap_dev->queue_count < ap_dev->queue_depth) {
1304 status = __ap_send(ap_dev->qid, ap_msg->psmid, 1312 status = __ap_send(ap_dev->qid, ap_msg->psmid,
1305 ap_msg->message, ap_msg->length); 1313 ap_msg->message, ap_msg->length,
1314 ap_msg->special);
1306 switch (status.response_code) { 1315 switch (status.response_code) {
1307 case AP_RESPONSE_NORMAL: 1316 case AP_RESPONSE_NORMAL:
1308 list_add_tail(&ap_msg->list, &ap_dev->pendingq); 1317 list_add_tail(&ap_msg->list, &ap_dev->pendingq);
@@ -1317,6 +1326,7 @@ static int __ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_ms
1317 ap_dev->requestq_count++; 1326 ap_dev->requestq_count++;
1318 ap_dev->total_request_count++; 1327 ap_dev->total_request_count++;
1319 return -EBUSY; 1328 return -EBUSY;
1329 case AP_RESPONSE_REQ_FAC_NOT_INST:
1320 case AP_RESPONSE_MESSAGE_TOO_BIG: 1330 case AP_RESPONSE_MESSAGE_TOO_BIG:
1321 ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL)); 1331 ap_dev->drv->receive(ap_dev, ap_msg, ERR_PTR(-EINVAL));
1322 return -EINVAL; 1332 return -EINVAL;
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index fcf2497556dd..c37466713b32 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -87,6 +87,7 @@ struct ap_queue_status {
87#define AP_RESPONSE_INDEX_TOO_BIG 0x11 87#define AP_RESPONSE_INDEX_TOO_BIG 0x11
88#define AP_RESPONSE_NO_FIRST_PART 0x13 88#define AP_RESPONSE_NO_FIRST_PART 0x13
89#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15 89#define AP_RESPONSE_MESSAGE_TOO_BIG 0x15
90#define AP_RESPONSE_REQ_FAC_NOT_INST 0x16
90 91
91/* 92/*
92 * Known device types 93 * Known device types
@@ -161,6 +162,7 @@ struct ap_message {
161 size_t length; /* Message length. */ 162 size_t length; /* Message length. */
162 163
163 void *private; /* ap driver private pointer. */ 164 void *private; /* ap driver private pointer. */
165 unsigned int special:1; /* Used for special commands. */
164}; 166};
165 167
166#define AP_DEVICE(dt) \ 168#define AP_DEVICE(dt) \
@@ -176,6 +178,7 @@ static inline void ap_init_message(struct ap_message *ap_msg)
176{ 178{
177 ap_msg->psmid = 0; 179 ap_msg->psmid = 0;
178 ap_msg->length = 0; 180 ap_msg->length = 0;
181 ap_msg->special = 0;
179} 182}
180 183
181/* 184/*
diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c
index 11ca6dc99b23..addaaddaf994 100644
--- a/drivers/s390/crypto/zcrypt_pcixcc.c
+++ b/drivers/s390/crypto/zcrypt_pcixcc.c
@@ -326,6 +326,11 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
326 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len; 326 function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
327 memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); 327 memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
328 328
329 if (memcmp(function_code, "US", 2) == 0)
330 ap_msg->special = 1;
331 else
332 ap_msg->special = 0;
333
329 /* copy data block */ 334 /* copy data block */
330 if (xcRB->request_data_length && 335 if (xcRB->request_data_length &&
331 copy_from_user(req_data, xcRB->request_data_address, 336 copy_from_user(req_data, xcRB->request_data_address,