mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
[S390] zcrypt secure key cryptography extension.
Allow the user space to send extended cprb messages directly to the PCIXCC / CEX2C cards. This allows the CCA library to construct special crypto requests that use "secure" keys that are stored on the card. Signed-off-by: Ralph Wuerthner <rwuerthn@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
fe3a1be59c
commit
5432114baf
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_api.c
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
@ -392,6 +392,41 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
||||
{
|
||||
struct zcrypt_device *zdev;
|
||||
int rc;
|
||||
|
||||
spin_lock_bh(&zcrypt_device_lock);
|
||||
list_for_each_entry(zdev, &zcrypt_device_list, list) {
|
||||
if (!zdev->online || !zdev->ops->send_cprb ||
|
||||
(xcRB->user_defined != AUTOSELECT &&
|
||||
AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)
|
||||
)
|
||||
continue;
|
||||
zcrypt_device_get(zdev);
|
||||
get_device(&zdev->ap_dev->device);
|
||||
zdev->request_count++;
|
||||
__zcrypt_decrease_preference(zdev);
|
||||
spin_unlock_bh(&zcrypt_device_lock);
|
||||
if (try_module_get(zdev->ap_dev->drv->driver.owner)) {
|
||||
rc = zdev->ops->send_cprb(zdev, xcRB);
|
||||
module_put(zdev->ap_dev->drv->driver.owner);
|
||||
}
|
||||
else
|
||||
rc = -EAGAIN;
|
||||
spin_lock_bh(&zcrypt_device_lock);
|
||||
zdev->request_count--;
|
||||
__zcrypt_increase_preference(zdev);
|
||||
put_device(&zdev->ap_dev->device);
|
||||
zcrypt_device_put(zdev);
|
||||
spin_unlock_bh(&zcrypt_device_lock);
|
||||
return rc;
|
||||
}
|
||||
spin_unlock_bh(&zcrypt_device_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void zcrypt_status_mask(char status[AP_DEVICES])
|
||||
{
|
||||
struct zcrypt_device *zdev;
|
||||
@ -535,6 +570,18 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
return rc;
|
||||
return put_user(crt.outputdatalength, &ucrt->outputdatalength);
|
||||
}
|
||||
case ZSECSENDCPRB: {
|
||||
struct ica_xcRB __user *uxcRB = (void __user *) arg;
|
||||
struct ica_xcRB xcRB;
|
||||
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
|
||||
return -EFAULT;
|
||||
do {
|
||||
rc = zcrypt_send_cprb(&xcRB);
|
||||
} while (rc == -EAGAIN);
|
||||
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
|
||||
return -EFAULT;
|
||||
return rc;
|
||||
}
|
||||
case Z90STAT_STATUS_MASK: {
|
||||
char status[AP_DEVICES];
|
||||
zcrypt_status_mask(status);
|
||||
@ -683,6 +730,67 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
|
||||
return rc;
|
||||
}
|
||||
|
||||
struct compat_ica_xcRB {
|
||||
unsigned short agent_ID;
|
||||
unsigned int user_defined;
|
||||
unsigned short request_ID;
|
||||
unsigned int request_control_blk_length;
|
||||
unsigned char padding1[16 - sizeof (compat_uptr_t)];
|
||||
compat_uptr_t request_control_blk_addr;
|
||||
unsigned int request_data_length;
|
||||
char padding2[16 - sizeof (compat_uptr_t)];
|
||||
compat_uptr_t request_data_address;
|
||||
unsigned int reply_control_blk_length;
|
||||
char padding3[16 - sizeof (compat_uptr_t)];
|
||||
compat_uptr_t reply_control_blk_addr;
|
||||
unsigned int reply_data_length;
|
||||
char padding4[16 - sizeof (compat_uptr_t)];
|
||||
compat_uptr_t reply_data_addr;
|
||||
unsigned short priority_window;
|
||||
unsigned int status;
|
||||
} __attribute__((packed));
|
||||
|
||||
static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
|
||||
struct compat_ica_xcRB xcRB32;
|
||||
struct ica_xcRB xcRB64;
|
||||
long rc;
|
||||
|
||||
if (copy_from_user(&xcRB32, uxcRB32, sizeof(xcRB32)))
|
||||
return -EFAULT;
|
||||
xcRB64.agent_ID = xcRB32.agent_ID;
|
||||
xcRB64.user_defined = xcRB32.user_defined;
|
||||
xcRB64.request_ID = xcRB32.request_ID;
|
||||
xcRB64.request_control_blk_length =
|
||||
xcRB32.request_control_blk_length;
|
||||
xcRB64.request_control_blk_addr =
|
||||
compat_ptr(xcRB32.request_control_blk_addr);
|
||||
xcRB64.request_data_length =
|
||||
xcRB32.request_data_length;
|
||||
xcRB64.request_data_address =
|
||||
compat_ptr(xcRB32.request_data_address);
|
||||
xcRB64.reply_control_blk_length =
|
||||
xcRB32.reply_control_blk_length;
|
||||
xcRB64.reply_control_blk_addr =
|
||||
compat_ptr(xcRB32.reply_control_blk_addr);
|
||||
xcRB64.reply_data_length = xcRB32.reply_data_length;
|
||||
xcRB64.reply_data_addr =
|
||||
compat_ptr(xcRB32.reply_data_addr);
|
||||
xcRB64.priority_window = xcRB32.priority_window;
|
||||
xcRB64.status = xcRB32.status;
|
||||
do {
|
||||
rc = zcrypt_send_cprb(&xcRB64);
|
||||
} while (rc == -EAGAIN);
|
||||
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
|
||||
xcRB32.reply_data_length = xcRB64.reply_data_length;
|
||||
xcRB32.status = xcRB64.status;
|
||||
if (copy_to_user(uxcRB32, &xcRB32, sizeof(xcRB32)))
|
||||
return -EFAULT;
|
||||
return rc;
|
||||
}
|
||||
|
||||
long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
@ -690,6 +798,8 @@ long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
return trans_modexpo32(filp, cmd, arg);
|
||||
if (cmd == ICARSACRT)
|
||||
return trans_modexpo_crt32(filp, cmd, arg);
|
||||
if (cmd == ZSECSENDCPRB)
|
||||
return trans_xcRB32(filp, cmd, arg);
|
||||
return zcrypt_unlocked_ioctl(filp, cmd, arg);
|
||||
}
|
||||
#endif
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_api.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
@ -106,6 +106,7 @@ struct zcrypt_ops {
|
||||
long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *);
|
||||
long (*rsa_modexpo_crt)(struct zcrypt_device *,
|
||||
struct ica_rsa_modexpo_crt *);
|
||||
long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *);
|
||||
};
|
||||
|
||||
struct zcrypt_device {
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_cca_key.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_cex2a.c
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_cex2a.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_error.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_mono.c
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_pcica.c
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_pcica.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_pcicc.c
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_pcicc.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_pcixcc.c
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
@ -60,6 +60,15 @@
|
||||
|
||||
#define PCIXCC_CLEANUP_TIME (15*HZ)
|
||||
|
||||
#define CEIL4(x) ((((x)+3)/4)*4)
|
||||
|
||||
struct response_type {
|
||||
struct completion work;
|
||||
int type;
|
||||
};
|
||||
#define PCIXCC_RESPONSE_TYPE_ICA 0
|
||||
#define PCIXCC_RESPONSE_TYPE_XCRB 1
|
||||
|
||||
static struct ap_device_id zcrypt_pcixcc_ids[] = {
|
||||
{ AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) },
|
||||
{ AP_DEVICE(AP_DEVICE_TYPE_CEX2C) },
|
||||
@ -243,6 +252,108 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a XCRB message to a type6 CPRB message.
|
||||
*
|
||||
* @zdev: crypto device pointer
|
||||
* @ap_msg: pointer to AP message
|
||||
* @xcRB: pointer to user input data
|
||||
*
|
||||
* Returns 0 on success or -EFAULT.
|
||||
*/
|
||||
struct type86_fmt2_msg {
|
||||
struct type86_hdr hdr;
|
||||
struct type86_fmt2_ext fmt2;
|
||||
} __attribute__((packed));
|
||||
|
||||
static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
|
||||
struct ap_message *ap_msg,
|
||||
struct ica_xcRB *xcRB)
|
||||
{
|
||||
static struct type6_hdr static_type6_hdrX = {
|
||||
.type = 0x06,
|
||||
.offset1 = 0x00000058,
|
||||
};
|
||||
struct {
|
||||
struct type6_hdr hdr;
|
||||
struct ica_CPRBX cprbx;
|
||||
} __attribute__((packed)) *msg = ap_msg->message;
|
||||
|
||||
int rcblen = CEIL4(xcRB->request_control_blk_length);
|
||||
int replylen;
|
||||
char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
|
||||
char *function_code;
|
||||
|
||||
/* length checks */
|
||||
ap_msg->length = sizeof(struct type6_hdr) +
|
||||
CEIL4(xcRB->request_control_blk_length) +
|
||||
xcRB->request_data_length;
|
||||
if (ap_msg->length > PCIXCC_MAX_XCRB_MESSAGE_SIZE) {
|
||||
PRINTK("Combined message is too large (%ld/%d/%d).\n",
|
||||
sizeof(struct type6_hdr),
|
||||
xcRB->request_control_blk_length,
|
||||
xcRB->request_data_length);
|
||||
return -EFAULT;
|
||||
}
|
||||
if (CEIL4(xcRB->reply_control_blk_length) >
|
||||
PCIXCC_MAX_XCRB_REPLY_SIZE) {
|
||||
PDEBUG("Reply CPRB length is too large (%d).\n",
|
||||
xcRB->request_control_blk_length);
|
||||
return -EFAULT;
|
||||
}
|
||||
if (CEIL4(xcRB->reply_data_length) > PCIXCC_MAX_XCRB_DATA_SIZE) {
|
||||
PDEBUG("Reply data block length is too large (%d).\n",
|
||||
xcRB->reply_data_length);
|
||||
return -EFAULT;
|
||||
}
|
||||
replylen = CEIL4(xcRB->reply_control_blk_length) +
|
||||
CEIL4(xcRB->reply_data_length) +
|
||||
sizeof(struct type86_fmt2_msg);
|
||||
if (replylen > PCIXCC_MAX_XCRB_RESPONSE_SIZE) {
|
||||
PDEBUG("Reply CPRB + data block > PCIXCC_MAX_XCRB_RESPONSE_SIZE"
|
||||
" (%d/%d/%d).\n",
|
||||
sizeof(struct type86_fmt2_msg),
|
||||
xcRB->reply_control_blk_length,
|
||||
xcRB->reply_data_length);
|
||||
xcRB->reply_control_blk_length = PCIXCC_MAX_XCRB_RESPONSE_SIZE -
|
||||
(sizeof(struct type86_fmt2_msg) +
|
||||
CEIL4(xcRB->reply_data_length));
|
||||
PDEBUG("Capping Reply CPRB length at %d\n",
|
||||
xcRB->reply_control_blk_length);
|
||||
}
|
||||
|
||||
/* prepare type6 header */
|
||||
msg->hdr = static_type6_hdrX;
|
||||
memcpy(msg->hdr.agent_id , &(xcRB->agent_ID), sizeof(xcRB->agent_ID));
|
||||
msg->hdr.ToCardLen1 = xcRB->request_control_blk_length;
|
||||
if (xcRB->request_data_length) {
|
||||
msg->hdr.offset2 = msg->hdr.offset1 + rcblen;
|
||||
msg->hdr.ToCardLen2 = xcRB->request_data_length;
|
||||
}
|
||||
msg->hdr.FromCardLen1 = xcRB->reply_control_blk_length;
|
||||
msg->hdr.FromCardLen2 = xcRB->reply_data_length;
|
||||
|
||||
/* prepare CPRB */
|
||||
if (copy_from_user(&(msg->cprbx), xcRB->request_control_blk_addr,
|
||||
xcRB->request_control_blk_length))
|
||||
return -EFAULT;
|
||||
if (msg->cprbx.cprb_len + sizeof(msg->hdr.function_code) >
|
||||
xcRB->request_control_blk_length) {
|
||||
PDEBUG("cprb_len too large (%d/%d)\n", msg->cprbx.cprb_len,
|
||||
xcRB->request_control_blk_length);
|
||||
return -EFAULT;
|
||||
}
|
||||
function_code = ((unsigned char *)&msg->cprbx) + msg->cprbx.cprb_len;
|
||||
memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code));
|
||||
|
||||
/* copy data block */
|
||||
if (xcRB->request_data_length &&
|
||||
copy_from_user(req_data, xcRB->request_data_address,
|
||||
xcRB->request_data_length))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy results from a type 86 ICA reply message back to user space.
|
||||
*
|
||||
@ -363,6 +474,37 @@ static int convert_type86_ica(struct zcrypt_device *zdev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy results from a type 86 XCRB reply message back to user space.
|
||||
*
|
||||
* @zdev: crypto device pointer
|
||||
* @reply: reply AP message.
|
||||
* @xcRB: pointer to XCRB
|
||||
*
|
||||
* Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error.
|
||||
*/
|
||||
static int convert_type86_xcrb(struct zcrypt_device *zdev,
|
||||
struct ap_message *reply,
|
||||
struct ica_xcRB *xcRB)
|
||||
{
|
||||
struct type86_fmt2_msg *msg = reply->message;
|
||||
char *data = reply->message;
|
||||
|
||||
/* Copy CPRB to user */
|
||||
if (copy_to_user(xcRB->reply_control_blk_addr,
|
||||
data + msg->fmt2.offset1, msg->fmt2.count1))
|
||||
return -EFAULT;
|
||||
xcRB->reply_control_blk_length = msg->fmt2.count1;
|
||||
|
||||
/* Copy data buffer to user */
|
||||
if (msg->fmt2.count2)
|
||||
if (copy_to_user(xcRB->reply_data_addr,
|
||||
data + msg->fmt2.offset2, msg->fmt2.count2))
|
||||
return -EFAULT;
|
||||
xcRB->reply_data_length = msg->fmt2.count2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int convert_response_ica(struct zcrypt_device *zdev,
|
||||
struct ap_message *reply,
|
||||
char __user *outputdata,
|
||||
@ -391,6 +533,36 @@ static int convert_response_ica(struct zcrypt_device *zdev,
|
||||
}
|
||||
}
|
||||
|
||||
static int convert_response_xcrb(struct zcrypt_device *zdev,
|
||||
struct ap_message *reply,
|
||||
struct ica_xcRB *xcRB)
|
||||
{
|
||||
struct type86x_reply *msg = reply->message;
|
||||
|
||||
/* Response type byte is the second byte in the response. */
|
||||
switch (((unsigned char *) reply->message)[1]) {
|
||||
case TYPE82_RSP_CODE:
|
||||
case TYPE88_RSP_CODE:
|
||||
xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
|
||||
return convert_error(zdev, reply);
|
||||
case TYPE86_RSP_CODE:
|
||||
if (msg->hdr.reply_code) {
|
||||
memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32));
|
||||
return convert_error(zdev, reply);
|
||||
}
|
||||
if (msg->cprbx.cprb_ver_id == 0x02)
|
||||
return convert_type86_xcrb(zdev, reply, xcRB);
|
||||
/* no break, incorrect cprb version is an unknown response */
|
||||
default: /* Unknown response type, this should NEVER EVER happen */
|
||||
PRINTK("Unrecognized Message Header: %08x%08x\n",
|
||||
*(unsigned int *) reply->message,
|
||||
*(unsigned int *) (reply->message+4));
|
||||
xcRB->status = 0x0008044DL; /* HDD_InvalidParm */
|
||||
zdev->online = 0;
|
||||
return -EAGAIN; /* repeat the request on a different device. */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called from the AP bus code after a crypto request
|
||||
* "msg" has finished with the reply message "reply".
|
||||
@ -407,6 +579,8 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
|
||||
.type = TYPE82_RSP_CODE,
|
||||
.reply_code = REP82_ERROR_MACHINE_FAILURE,
|
||||
};
|
||||
struct response_type *resp_type =
|
||||
(struct response_type *) msg->private;
|
||||
struct type86x_reply *t86r = reply->message;
|
||||
int length;
|
||||
|
||||
@ -415,12 +589,27 @@ static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,
|
||||
memcpy(msg->message, &error_reply, sizeof(error_reply));
|
||||
else if (t86r->hdr.type == TYPE86_RSP_CODE &&
|
||||
t86r->cprbx.cprb_ver_id == 0x02) {
|
||||
length = sizeof(struct type86x_reply) + t86r->length - 2;
|
||||
length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
|
||||
memcpy(msg->message, reply->message, length);
|
||||
switch (resp_type->type) {
|
||||
case PCIXCC_RESPONSE_TYPE_ICA:
|
||||
length = sizeof(struct type86x_reply)
|
||||
+ t86r->length - 2;
|
||||
length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
|
||||
memcpy(msg->message, reply->message, length);
|
||||
break;
|
||||
case PCIXCC_RESPONSE_TYPE_XCRB:
|
||||
length = t86r->fmt2.offset2 + t86r->fmt2.count2;
|
||||
length = min(PCIXCC_MAX_XCRB_RESPONSE_SIZE, length);
|
||||
memcpy(msg->message, reply->message, length);
|
||||
break;
|
||||
default:
|
||||
PRINTK("Invalid internal response type: %i\n",
|
||||
resp_type->type);
|
||||
memcpy(msg->message, &error_reply,
|
||||
sizeof error_reply);
|
||||
}
|
||||
} else
|
||||
memcpy(msg->message, reply->message, sizeof error_reply);
|
||||
complete((struct completion *) msg->private);
|
||||
complete(&(resp_type->work));
|
||||
}
|
||||
|
||||
static atomic_t zcrypt_step = ATOMIC_INIT(0);
|
||||
@ -436,7 +625,9 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
|
||||
struct ica_rsa_modexpo *mex)
|
||||
{
|
||||
struct ap_message ap_msg;
|
||||
struct completion work;
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_ICA,
|
||||
};
|
||||
int rc;
|
||||
|
||||
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
@ -444,14 +635,14 @@ static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,
|
||||
return -ENOMEM;
|
||||
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg.private = &work;
|
||||
ap_msg.private = &resp_type;
|
||||
rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
init_completion(&work);
|
||||
init_completion(&resp_type.work);
|
||||
ap_queue_message(zdev->ap_dev, &ap_msg);
|
||||
rc = wait_for_completion_interruptible_timeout(
|
||||
&work, PCIXCC_CLEANUP_TIME);
|
||||
&resp_type.work, PCIXCC_CLEANUP_TIME);
|
||||
if (rc > 0)
|
||||
rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,
|
||||
mex->outputdatalength);
|
||||
@ -478,7 +669,9 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
|
||||
struct ica_rsa_modexpo_crt *crt)
|
||||
{
|
||||
struct ap_message ap_msg;
|
||||
struct completion work;
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_ICA,
|
||||
};
|
||||
int rc;
|
||||
|
||||
ap_msg.message = (void *) get_zeroed_page(GFP_KERNEL);
|
||||
@ -486,14 +679,14 @@ static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,
|
||||
return -ENOMEM;
|
||||
ap_msg.psmid = (((unsigned long long) current->pid) << 32) +
|
||||
atomic_inc_return(&zcrypt_step);
|
||||
ap_msg.private = &work;
|
||||
ap_msg.private = &resp_type;
|
||||
rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);
|
||||
if (rc)
|
||||
goto out_free;
|
||||
init_completion(&work);
|
||||
init_completion(&resp_type.work);
|
||||
ap_queue_message(zdev->ap_dev, &ap_msg);
|
||||
rc = wait_for_completion_interruptible_timeout(
|
||||
&work, PCIXCC_CLEANUP_TIME);
|
||||
&resp_type.work, PCIXCC_CLEANUP_TIME);
|
||||
if (rc > 0)
|
||||
rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,
|
||||
crt->outputdatalength);
|
||||
@ -509,12 +702,56 @@ out_free:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the PCIXCC/CEX2C
|
||||
* device to handle a send_cprb request.
|
||||
* @zdev: pointer to zcrypt_device structure that identifies the
|
||||
* PCIXCC/CEX2C device to the request distributor
|
||||
* @xcRB: pointer to the send_cprb request buffer
|
||||
*/
|
||||
long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
|
||||
{
|
||||
struct ap_message ap_msg;
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_XCRB,
|
||||
};
|
||||
int rc;
|
||||
|
||||
ap_msg.message = (void *) kmalloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE, GFP_KERNEL);
|
||||
if (!ap_msg.message)
|
||||
return -ENOMEM;
|
||||
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_timeout(
|
||||
&resp_type.work, PCIXCC_CLEANUP_TIME);
|
||||
if (rc > 0)
|
||||
rc = convert_response_xcrb(zdev, &ap_msg, xcRB);
|
||||
else {
|
||||
/* Signal pending or message timed out. */
|
||||
ap_cancel_message(zdev->ap_dev, &ap_msg);
|
||||
if (rc == 0)
|
||||
/* Message timed out. */
|
||||
rc = -ETIME;
|
||||
}
|
||||
out_free:
|
||||
memset(ap_msg.message, 0x0, ap_msg.length);
|
||||
kfree(ap_msg.message);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* The crypto operations for a PCIXCC/CEX2C card.
|
||||
*/
|
||||
static struct zcrypt_ops zcrypt_pcixcc_ops = {
|
||||
.rsa_modexpo = zcrypt_pcixcc_modexpo,
|
||||
.rsa_modexpo_crt = zcrypt_pcixcc_modexpo_crt,
|
||||
.send_cprb = zcrypt_pcixcc_send_cprb,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* linux/drivers/s390/crypto/zcrypt_pcixcc.h
|
||||
*
|
||||
* zcrypt 2.0.0
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* include/asm-s390/zcrypt.h
|
||||
*
|
||||
* zcrypt 2.0.0 (user-visible header)
|
||||
* zcrypt 2.1.0 (user-visible header)
|
||||
*
|
||||
* Copyright (C) 2001, 2006 IBM Corporation
|
||||
* Author(s): Robert Burroughs
|
||||
@ -79,6 +79,83 @@ struct ica_rsa_modexpo_crt {
|
||||
char __user * u_mult_inv;
|
||||
};
|
||||
|
||||
/**
|
||||
* CPRBX
|
||||
* Note that all shorts and ints are big-endian.
|
||||
* All pointer fields are 16 bytes long, and mean nothing.
|
||||
*
|
||||
* A request CPRB is followed by a request_parameter_block.
|
||||
*
|
||||
* The request (or reply) parameter block is organized thus:
|
||||
* function code
|
||||
* VUD block
|
||||
* key block
|
||||
*/
|
||||
struct ica_CPRBX {
|
||||
unsigned short cprb_len; /* CPRB length 220 */
|
||||
unsigned char cprb_ver_id; /* CPRB version id. 0x02 */
|
||||
unsigned char pad_000[3]; /* Alignment pad bytes */
|
||||
unsigned char func_id[2]; /* function id 0x5432 */
|
||||
unsigned char cprb_flags[4]; /* Flags */
|
||||
unsigned int req_parml; /* request parameter buffer len */
|
||||
unsigned int req_datal; /* request data buffer */
|
||||
unsigned int rpl_msgbl; /* reply message block length */
|
||||
unsigned int rpld_parml; /* replied parameter block len */
|
||||
unsigned int rpl_datal; /* reply data block len */
|
||||
unsigned int rpld_datal; /* replied data block len */
|
||||
unsigned int req_extbl; /* request extension block len */
|
||||
unsigned char pad_001[4]; /* reserved */
|
||||
unsigned int rpld_extbl; /* replied extension block len */
|
||||
unsigned char padx000[16 - sizeof (char *)];
|
||||
unsigned char * req_parmb; /* request parm block 'address' */
|
||||
unsigned char padx001[16 - sizeof (char *)];
|
||||
unsigned char * req_datab; /* request data block 'address' */
|
||||
unsigned char padx002[16 - sizeof (char *)];
|
||||
unsigned char * rpl_parmb; /* reply parm block 'address' */
|
||||
unsigned char padx003[16 - sizeof (char *)];
|
||||
unsigned char * rpl_datab; /* reply data block 'address' */
|
||||
unsigned char padx004[16 - sizeof (char *)];
|
||||
unsigned char * req_extb; /* request extension block 'addr'*/
|
||||
unsigned char padx005[16 - sizeof (char *)];
|
||||
unsigned char * rpl_extb; /* reply extension block 'addres'*/
|
||||
unsigned short ccp_rtcode; /* server return code */
|
||||
unsigned short ccp_rscode; /* server reason code */
|
||||
unsigned int mac_data_len; /* Mac Data Length */
|
||||
unsigned char logon_id[8]; /* Logon Identifier */
|
||||
unsigned char mac_value[8]; /* Mac Value */
|
||||
unsigned char mac_content_flgs;/* Mac content flag byte */
|
||||
unsigned char pad_002; /* Alignment */
|
||||
unsigned short domain; /* Domain */
|
||||
unsigned char usage_domain[4];/* Usage domain */
|
||||
unsigned char cntrl_domain[4];/* Control domain */
|
||||
unsigned char S390enf_mask[4];/* S/390 enforcement mask */
|
||||
unsigned char pad_004[36]; /* reserved */
|
||||
};
|
||||
|
||||
/**
|
||||
* xcRB
|
||||
*/
|
||||
struct ica_xcRB {
|
||||
unsigned short agent_ID;
|
||||
unsigned int user_defined;
|
||||
unsigned short request_ID;
|
||||
unsigned int request_control_blk_length;
|
||||
unsigned char padding1[16 - sizeof (char *)];
|
||||
char __user * request_control_blk_addr;
|
||||
unsigned int request_data_length;
|
||||
char padding2[16 - sizeof (char *)];
|
||||
char __user * request_data_address;
|
||||
unsigned int reply_control_blk_length;
|
||||
char padding3[16 - sizeof (char *)];
|
||||
char __user * reply_control_blk_addr;
|
||||
unsigned int reply_data_length;
|
||||
char padding4[16 - sizeof (char *)];
|
||||
char __user * reply_data_addr;
|
||||
unsigned short priority_window;
|
||||
unsigned int status;
|
||||
} __attribute__((packed));
|
||||
#define AUTOSELECT ((unsigned int)0xFFFFFFFF)
|
||||
|
||||
#define ZCRYPT_IOCTL_MAGIC 'z'
|
||||
|
||||
/**
|
||||
@ -187,6 +264,7 @@ struct ica_rsa_modexpo_crt {
|
||||
*/
|
||||
#define ICARSAMODEXPO _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x05, 0)
|
||||
#define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0)
|
||||
#define ZSECSENDCPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0)
|
||||
|
||||
/* New status calls */
|
||||
#define Z90STAT_TOTALCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int)
|
||||
|
Loading…
Reference in New Issue
Block a user