diff options
Diffstat (limited to 'drivers/s390/crypto/zcrypt_msgtype6.c')
-rw-r--r-- | drivers/s390/crypto/zcrypt_msgtype6.c | 403 |
1 files changed, 294 insertions, 109 deletions
diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index f71949685ff5..957a88d5768b 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = { .func_id = {0x54, 0x32}, }; +int speed_idx_cca(int req_type) +{ + switch (req_type) { + case 0x4142: + case 0x4149: + case 0x414D: + case 0x4341: + case 0x4344: + case 0x4354: + case 0x4358: + case 0x444B: + case 0x4558: + case 0x4643: + case 0x4651: + case 0x4C47: + case 0x4C4B: + case 0x4C51: + case 0x4F48: + case 0x504F: + case 0x5053: + case 0x5058: + case 0x5343: + case 0x5344: + case 0x5345: + case 0x5350: + return LOW; + case 0x414B: + case 0x4345: + case 0x4349: + case 0x434D: + case 0x4847: + case 0x4849: + case 0x484D: + case 0x4850: + case 0x4851: + case 0x4954: + case 0x4958: + case 0x4B43: + case 0x4B44: + case 0x4B45: + case 0x4B47: + case 0x4B48: + case 0x4B49: + case 0x4B4E: + case 0x4B50: + case 0x4B52: + case 0x4B54: + case 0x4B58: + case 0x4D50: + case 0x4D53: + case 0x4D56: + case 0x4D58: + case 0x5044: + case 0x5045: + case 0x5046: + case 0x5047: + case 0x5049: + case 0x504B: + case 0x504D: + case 0x5254: + case 0x5347: + case 0x5349: + case 0x534B: + case 0x534D: + case 0x5356: + case 0x5358: + case 0x5443: + case 0x544B: + case 0x5647: + return HIGH; + default: + return MEDIUM; + } +} + +int speed_idx_ep11(int req_type) +{ + switch (req_type) { + case 1: + case 2: + case 36: + case 37: + case 38: + case 39: + case 40: + return LOW; + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 26: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + return HIGH; + default: + return MEDIUM; + } +} + + /** * Convert a ICAMEX message to a type6 MEX message. * @@ -297,9 +403,9 @@ struct type86_fmt2_msg { struct type86_fmt2_ext fmt2; } __packed; -static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, - struct ap_message *ap_msg, - struct ica_xcRB *xcRB) +static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, + struct ica_xcRB *xcRB, + unsigned int *fcode) { static struct type6_hdr static_type6_hdrX = { .type = 0x06, @@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); + *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; + if (memcmp(function_code, "US", 2) == 0) ap_msg->special = 1; else @@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, return 0; } -static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, - struct ap_message *ap_msg, - struct ep11_urb *xcRB) +static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, + struct ep11_urb *xcRB, + unsigned int *fcode) { - unsigned int lfmt; - static struct type6_hdr static_type6_ep11_hdr = { .type = 0x06, .rqid = {0x00, 0x01}, @@ -421,7 +527,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, unsigned char dom_tag; /* fixed value 0x4 */ unsigned char dom_len; /* fixed value 0x4 */ unsigned int dom_val; /* domain id */ - } __packed * payload_hdr; + } __packed * payload_hdr = NULL; if (CEIL4(xcRB->req_len) < xcRB->req_len) return -EINVAL; /* overflow after alignment*/ @@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, return -EFAULT; } - /* - The target domain field within the cprb body/payload block will be - replaced by the usage domain for non-management commands only. - Therefore we check the first bit of the 'flags' parameter for - management command indication. - 0 - non management command - 1 - management command - */ - if (!((msg->cprbx.flags & 0x80) == 0x80)) { - msg->cprbx.target_id = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); - - if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ - switch (msg->pld_lenfmt & 0x03) { - case 1: - lfmt = 2; - break; - case 2: - lfmt = 3; - break; - default: - return -EINVAL; - } - } else { - lfmt = 1; /* length format #1 */ - } - payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); - payload_hdr->dom_val = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); - } + *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF); return 0; } @@ -989,6 +1066,36 @@ out_free: return rc; } +unsigned int get_cprb_fc(struct ica_xcRB *xcRB, + struct ap_message *ap_msg, + int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + int rc; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code); + if (rc) { + kzfree(ap_msg->message); + kzfree(ap_msg->private); + } + return rc; +} + /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a send_cprb request. @@ -997,37 +1104,55 @@ out_free: * @xcRB: pointer to the send_cprb request buffer */ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, - struct ica_xcRB *xcRB) + struct ica_xcRB *xcRB, + struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, - }; int rc; + struct response_type *rtype = (struct response_type *)(ap_msg->private); - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); - if (rc) - goto out_free; - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_xcrb(zdev, &ap_msg, xcRB); + rc = convert_response_xcrb(zdev, ap_msg, xcRB); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); -out_free: - kzfree(ap_msg.message); + ap_cancel_message(zdev->ap_dev, ap_msg); + + kzfree(ap_msg->message); + kzfree(ap_msg->private); + return rc; +} + +unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, + struct ap_message *ap_msg, + int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_EP11, + }; + int rc; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive_ep11; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + rc = xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code); + if (rc) { + kzfree(ap_msg->message); + kzfree(ap_msg->private); + } return rc; } @@ -1039,41 +1164,101 @@ out_free: * @xcRB: pointer to the ep11 user request block */ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, - struct ep11_urb *xcrb) + struct ep11_urb *xcrb, + struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_EP11, - }; int rc; + unsigned int lfmt; + struct response_type *rtype = (struct response_type *)(ap_msg->private); + struct { + struct type6_hdr hdr; + struct ep11_cprb cprbx; + unsigned char pld_tag; /* fixed value 0x30 */ + unsigned char pld_lenfmt; /* payload length format */ + } __packed * msg = ap_msg->message; + struct pld_hdr { + unsigned char func_tag; /* fixed value 0x4 */ + unsigned char func_len; /* fixed value 0x4 */ + unsigned int func_val; /* function ID */ + unsigned char dom_tag; /* fixed value 0x4 */ + unsigned char dom_len; /* fixed value 0x4 */ + unsigned int dom_val; /* domain id */ + } __packed * payload_hdr = NULL; - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive_ep11; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb); - if (rc) - goto out_free; - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + + /** + * The target domain field within the cprb body/payload block will be + * replaced by the usage domain for non-management commands only. + * Therefore we check the first bit of the 'flags' parameter for + * management command indication. + * 0 - non management command + * 1 - management command + */ + if (!((msg->cprbx.flags & 0x80) == 0x80)) { + msg->cprbx.target_id = (unsigned int) + AP_QID_QUEUE(zdev->ap_dev->qid); + + if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ + switch (msg->pld_lenfmt & 0x03) { + case 1: + lfmt = 2; + break; + case 2: + lfmt = 3; + break; + default: + return -EINVAL; + } + } else { + lfmt = 1; /* length format #1 */ + } + payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); + payload_hdr->dom_val = (unsigned int) + AP_QID_QUEUE(zdev->ap_dev->qid); + } + + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb); + rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zdev->ap_dev, ap_msg); -out_free: - kzfree(ap_msg.message); + kzfree(ap_msg->message); + kzfree(ap_msg->private); return rc; } +unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + + rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE); + + *func_code = HWRNG; + return 0; +} + /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to generate random data. @@ -1081,36 +1266,36 @@ out_free: * PCIXCC/CEX2C device to the request distributor * @buffer: pointer to a memory page to return random data */ - static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, - char *buffer) + char *buffer, struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, - }; + struct { + struct type6_hdr hdr; + struct CPRBX cprbx; + char function_code[2]; + short int rule_length; + char rule[8]; + short int verb_length; + short int key_length; + } __packed * msg = ap_msg->message; + struct response_type *rtype = (struct response_type *)(ap_msg->private); int rc; - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_rng(zdev, &ap_msg, buffer); + rc = convert_response_rng(zdev, ap_msg, buffer); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); - kfree(ap_msg.message); + ap_cancel_message(zdev->ap_dev, ap_msg); + + kzfree(ap_msg->message); + kzfree(ap_msg->private); return rc; } |