zcrypt_pcixcc.c

来自「linux 内核源代码」· C语言 代码 · 共 942 行 · 第 1/2 页

C
942
字号
		if (put_user(0, outputdata + pad_len - 1))			return -EFAULT;	}	/* Copy the crypto response to user space. */	if (copy_to_user(outputdata + pad_len, data, reply_len))		return -EFAULT;	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,			    unsigned int outputdatalength){	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:		return convert_error(zdev, reply);	case TYPE86_RSP_CODE:		if (msg->hdr.reply_code)			return convert_error(zdev, reply);		if (msg->cprbx.cprb_ver_id == 0x02)			return convert_type86_ica(zdev, reply,						  outputdata, outputdatalength);		/* 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));		zdev->online = 0;		return -EAGAIN;	/* repeat the request on a different device. */	}}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". * It is called from tasklet context. * @ap_dev: pointer to the AP device * @msg: pointer to the AP message * @reply: pointer to the AP reply message */static void zcrypt_pcixcc_receive(struct ap_device *ap_dev,				  struct ap_message *msg,				  struct ap_message *reply){	static struct error_hdr error_reply = {		.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;	/* Copy the reply message to the request message buffer. */	if (IS_ERR(reply))		memcpy(msg->message, &error_reply, sizeof(error_reply));	else if (t86r->hdr.type == TYPE86_RSP_CODE &&		 t86r->cprbx.cprb_ver_id == 0x02) {		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(&(resp_type->work));}static atomic_t zcrypt_step = ATOMIC_INIT(0);/** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a modexpo request. * @zdev: pointer to zcrypt_device structure that identifies the *	  PCIXCC/CEX2C device to the request distributor * @mex: pointer to the modexpo request buffer */static long zcrypt_pcixcc_modexpo(struct zcrypt_device *zdev,				  struct ica_rsa_modexpo *mex){	struct ap_message ap_msg;	struct response_type resp_type = {		.type = PCIXCC_RESPONSE_TYPE_ICA,	};	int rc;	ap_msg.message = (void *) get_zeroed_page(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 = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex);	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);	if (rc == 0)		rc = convert_response_ica(zdev, &ap_msg, mex->outputdata,					  mex->outputdatalength);	else		/* Signal pending. */		ap_cancel_message(zdev->ap_dev, &ap_msg);out_free:	free_page((unsigned long) ap_msg.message);	return rc;}/** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a modexpo_crt request. * @zdev: pointer to zcrypt_device structure that identifies the *	  PCIXCC/CEX2C device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */static long zcrypt_pcixcc_modexpo_crt(struct zcrypt_device *zdev,				      struct ica_rsa_modexpo_crt *crt){	struct ap_message ap_msg;	struct response_type resp_type = {		.type = PCIXCC_RESPONSE_TYPE_ICA,	};	int rc;	ap_msg.message = (void *) get_zeroed_page(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 = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt);	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);	if (rc == 0)		rc = convert_response_ica(zdev, &ap_msg, crt->outputdata,					  crt->outputdatalength);	else		/* Signal pending. */		ap_cancel_message(zdev->ap_dev, &ap_msg);out_free:	free_page((unsigned long) ap_msg.message);	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 */static 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 = 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(&resp_type.work);	if (rc == 0)		rc = convert_response_xcrb(zdev, &ap_msg, xcRB);	else		/* Signal pending. */		ap_cancel_message(zdev->ap_dev, &ap_msg);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,};/** * Micro-code detection function. Its sends a message to a pcixcc card * to find out the microcode level. * @ap_dev: pointer to the AP device. */static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev){	static unsigned char msg[] = {		0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00,		0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8,		0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,		0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A,		0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20,		0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05,		0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,		0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55,		0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,		0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA,		0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22,		0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB,		0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54,		0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00,		0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00,		0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40,		0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C,		0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF,		0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9,		0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63,		0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5,		0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A,		0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01,		0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28,		0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91,		0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5,		0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C,		0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98,		0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96,		0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19,		0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47,		0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36,		0xF1,0x3D,0x93,0x53	};	unsigned long long psmid;	struct CPRBX *cprbx;	char *reply;	int rc, i;	reply = (void *) get_zeroed_page(GFP_KERNEL);	if (!reply)		return -ENOMEM;	rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg));	if (rc)		goto out_free;	/* Wait for the test message to complete. */	for (i = 0; i < 6; i++) {		mdelay(300);		rc = ap_recv(ap_dev->qid, &psmid, reply, 4096);		if (rc == 0 && psmid == 0x0102030405060708ULL)			break;	}	if (i >= 6) {		/* Got no answer. */		rc = -ENODEV;		goto out_free;	}	cprbx = (struct CPRBX *) (reply + 48);	if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33)		rc = ZCRYPT_PCIXCC_MCL2;	else		rc = ZCRYPT_PCIXCC_MCL3;out_free:	free_page((unsigned long) reply);	return rc;}/** * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device * since the bus_match already checked the hardware type. The PCIXCC * cards come in two flavours: micro code level 2 and micro code level 3. * This is checked by sending a test message to the device. * @ap_dev: pointer to the AP device. */static int zcrypt_pcixcc_probe(struct ap_device *ap_dev){	struct zcrypt_device *zdev;	int rc;	zdev = zcrypt_device_alloc(PCIXCC_MAX_RESPONSE_SIZE);	if (!zdev)		return -ENOMEM;	zdev->ap_dev = ap_dev;	zdev->ops = &zcrypt_pcixcc_ops;	zdev->online = 1;	if (ap_dev->device_type == AP_DEVICE_TYPE_PCIXCC) {		rc = zcrypt_pcixcc_mcl(ap_dev);		if (rc < 0) {			zcrypt_device_free(zdev);			return rc;		}		zdev->user_space_type = rc;		if (rc == ZCRYPT_PCIXCC_MCL2) {			zdev->type_string = "PCIXCC_MCL2";			zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING;			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD;			zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;		} else {			zdev->type_string = "PCIXCC_MCL3";			zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING;			zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;			zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;		}	} else {		zdev->user_space_type = ZCRYPT_CEX2C;		zdev->type_string = "CEX2C";		zdev->speed_rating = CEX2C_SPEED_RATING;		zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE;		zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE;	}	ap_dev->reply = &zdev->reply;	ap_dev->private = zdev;	rc = zcrypt_device_register(zdev);	if (rc)		goto out_free;	return 0; out_free:	ap_dev->private = NULL;	zcrypt_device_free(zdev);	return rc;}/** * This is called to remove the extended PCIXCC/CEX2C driver information * if an AP device is removed. */static void zcrypt_pcixcc_remove(struct ap_device *ap_dev){	struct zcrypt_device *zdev = ap_dev->private;	zcrypt_device_unregister(zdev);}int __init zcrypt_pcixcc_init(void){	return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc");}void zcrypt_pcixcc_exit(void){	ap_driver_unregister(&zcrypt_pcixcc_driver);}#ifndef CONFIG_ZCRYPT_MONOLITHICmodule_init(zcrypt_pcixcc_init);module_exit(zcrypt_pcixcc_exit);#endif

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?