📄 z90main.c
字号:
/* * linux/drivers/s390/misc/z90main.c * * z90crypt 1.3.1 * * Copyright (C) 2001, 2004 IBM Corporation * Author(s): Robert Burroughs (burrough@us.ibm.com) * Eric Rossman (edrossma@us.ibm.com) * * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <asm/uaccess.h> // copy_(from|to)_user#include <linux/compat.h>#include <linux/compiler.h>#include <linux/delay.h> // mdelay#include <linux/init.h>#include <linux/interrupt.h> // for tasklets#include <linux/ioctl32.h>#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/proc_fs.h>#include <linux/syscalls.h>#include <linux/version.h>#include "z90crypt.h"#include "z90common.h"#ifndef Z90CRYPT_USE_HOTPLUG#include <linux/miscdevice.h>#endif#define VERSION_CODE(vers, rel, seq) (((vers)<<16) | ((rel)<<8) | (seq))#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) /* version < 2.4 */# error "This kernel is too old: not supported"#endif#if LINUX_VERSION_CODE > VERSION_CODE(2,7,0) /* version > 2.6 */# error "This kernel is too recent: not supported by this file"#endif#define VERSION_Z90MAIN_C "$Revision: 1.31 $"static char z90cmain_version[] __initdata = "z90main.o (" VERSION_Z90MAIN_C "/" VERSION_Z90COMMON_H "/" VERSION_Z90CRYPT_H ")";extern char z90chardware_version[];/** * Defaults that may be modified. */#ifndef Z90CRYPT_USE_HOTPLUG/** * You can specify a different minor at compile time. */#ifndef Z90CRYPT_MINOR#define Z90CRYPT_MINOR MISC_DYNAMIC_MINOR#endif#else/** * You can specify a different major at compile time. */#ifndef Z90CRYPT_MAJOR#define Z90CRYPT_MAJOR 0#endif#endif/** * You can specify a different domain at compile time or on the insmod * command line. */#ifndef DOMAIN_INDEX#define DOMAIN_INDEX -1#endif/** * This is the name under which the device is registered in /proc/modules. */#define REG_NAME "z90crypt"/** * Cleanup should run every CLEANUPTIME seconds and should clean up requests * older than CLEANUPTIME seconds in the past. */#ifndef CLEANUPTIME#define CLEANUPTIME 15#endif/** * Config should run every CONFIGTIME seconds */#ifndef CONFIGTIME#define CONFIGTIME 30#endif/** * The first execution of the config task should take place * immediately after initialization */#ifndef INITIAL_CONFIGTIME#define INITIAL_CONFIGTIME 1#endif/** * Reader should run every READERTIME milliseconds */#ifndef READERTIME#define READERTIME 2#endif/** * turn long device array index into device pointer */#define LONG2DEVPTR(ndx) (z90crypt.device_p[(ndx)])/** * turn short device array index into long device array index */#define SHRT2LONG(ndx) (z90crypt.overall_device_x.device_index[(ndx)])/** * turn short device array index into device pointer */#define SHRT2DEVPTR(ndx) LONG2DEVPTR(SHRT2LONG(ndx))/** * Status for a work-element */#define STAT_DEFAULT 0x00 // request has not been processed#define STAT_ROUTED 0x80 // bit 7: requests get routed to specific device // else, device is determined each write#define STAT_FAILED 0x40 // bit 6: this bit is set if the request failed // before being sent to the hardware.#define STAT_WRITTEN 0x30 // bits 5-4: work to be done, not sent to device// 0x20 // UNUSED state#define STAT_READPEND 0x10 // bits 5-4: work done, we're returning data now#define STAT_NOWORK 0x00 // bits off: no work on any queue#define STAT_RDWRMASK 0x30 // mask for bits 5-4/** * Macros to check the status RDWRMASK */#define CHK_RDWRMASK(statbyte) ((statbyte) & STAT_RDWRMASK)#define SET_RDWRMASK(statbyte, newval) \ {(statbyte) &= ~STAT_RDWRMASK; (statbyte) |= newval;}/** * Audit Trail. Progress of a Work element * audit[0]: Unless noted otherwise, these bits are all set by the process */#define FP_COPYFROM 0x80 // Caller's buffer has been copied to work element#define FP_BUFFREQ 0x40 // Low Level buffer requested#define FP_BUFFGOT 0x20 // Low Level buffer obtained#define FP_SENT 0x10 // Work element sent to a crypto device // (may be set by process or by reader task)#define FP_PENDING 0x08 // Work element placed on pending queue // (may be set by process or by reader task)#define FP_REQUEST 0x04 // Work element placed on request queue#define FP_ASLEEP 0x02 // Work element about to sleep#define FP_AWAKE 0x01 // Work element has been awakened/** * audit[1]: These bits are set by the reader task and/or the cleanup task */#define FP_NOTPENDING 0x80 // Work element removed from pending queue#define FP_AWAKENING 0x40 // Caller about to be awakened#define FP_TIMEDOUT 0x20 // Caller timed out#define FP_RESPSIZESET 0x10 // Response size copied to work element#define FP_RESPADDRCOPIED 0x08 // Response address copied to work element#define FP_RESPBUFFCOPIED 0x04 // Response buffer copied to work element#define FP_REMREQUEST 0x02 // Work element removed from request queue#define FP_SIGNALED 0x01 // Work element was awakened by a signal/** * audit[2]: unused *//** * state of the file handle in private_data.status */#define STAT_OPEN 0#define STAT_CLOSED 1/** * PID() expands to the process ID of the current process */#define PID() (current->pid)/** * Selected Constants. The number of APs and the number of devices */#ifndef Z90CRYPT_NUM_APS#define Z90CRYPT_NUM_APS 64#endif#ifndef Z90CRYPT_NUM_DEVS#define Z90CRYPT_NUM_DEVS Z90CRYPT_NUM_APS#endif#ifndef Z90CRYPT_NUM_TYPES#define Z90CRYPT_NUM_TYPES 3#endif/** * Buffer size for receiving responses. The maximum Response Size * is actually the maximum request size, since in an error condition * the request itself may be returned unchanged. */#ifndef MAX_RESPONSE_SIZE#define MAX_RESPONSE_SIZE 0x0000077C#endif/** * A count and status-byte mask */struct status { int st_count; // # of enabled devices int disabled_count; // # of disabled devices int user_disabled_count; // # of devices disabled via proc fs unsigned char st_mask[Z90CRYPT_NUM_APS]; // current status mask};/** * The array of device indexes is a mechanism for fast indexing into * a long (and sparse) array. For instance, if APs 3, 9 and 47 are * installed, z90CDeviceIndex[0] is 3, z90CDeviceIndex[1] is 9, and * z90CDeviceIndex[2] is 47. */struct device_x { int device_index[Z90CRYPT_NUM_DEVS];};/** * All devices are arranged in a single array: 64 APs */struct device { int dev_type; // PCICA, PCICC, or PCIXCC enum devstat dev_stat; // current device status int dev_self_x; // Index in array int disabled; // Set when device is in error int user_disabled; // Set when device is disabled by user int dev_q_depth; // q depth unsigned char * dev_resp_p; // Response buffer address int dev_resp_l; // Response Buffer length int dev_caller_count; // Number of callers int dev_total_req_cnt; // # requests for device since load struct list_head dev_caller_list; // List of callers};/** * There's a struct status and a struct device_x for each device type. */struct hdware_block { struct status hdware_mask; struct status type_mask[Z90CRYPT_NUM_TYPES]; struct device_x type_x_addr[Z90CRYPT_NUM_TYPES]; unsigned char device_type_array[Z90CRYPT_NUM_APS];};/** * z90crypt is the topmost data structure in the hierarchy. */struct z90crypt { int max_count; // Nr of possible crypto devices struct status mask; int q_depth_array[Z90CRYPT_NUM_DEVS]; int dev_type_array[Z90CRYPT_NUM_DEVS]; struct device_x overall_device_x; // array device indexes struct device * device_p[Z90CRYPT_NUM_DEVS]; int terminating; int domain_established;// TRUE: domain has been found int cdx; // Crypto Domain Index int len; // Length of this data structure struct hdware_block *hdware_info;};/** * An array of these structures is pointed to from dev_caller * The length of the array depends on the device type. For APs, * there are 8. * * The caller buffer is allocated to the user at OPEN. At WRITE, * it contains the request; at READ, the response. The function * send_to_crypto_device converts the request to device-dependent * form and use the caller's OPEN-allocated buffer for the response. */struct caller { int caller_buf_l; // length of original request unsigned char * caller_buf_p; // Original request on WRITE int caller_dev_dep_req_l; // len device dependent request unsigned char * caller_dev_dep_req_p; // Device dependent form unsigned char caller_id[8]; // caller-supplied message id struct list_head caller_liste; unsigned char caller_dev_dep_req[MAX_RESPONSE_SIZE];};/** * Function prototypes from z90hardware.c */enum hdstat query_online(int, int, int, int *, int *);enum devstat reset_device(int, int, int);enum devstat send_to_AP(int, int, int, unsigned char *);enum devstat receive_from_AP(int, int, int, unsigned char *, unsigned char *);int convert_request(unsigned char *, int, short, int, int, int *, unsigned char *);int convert_response(unsigned char *, unsigned char *, int *, unsigned char *);/** * Low level function prototypes */static int create_z90crypt(int *);static int refresh_z90crypt(int *);static int find_crypto_devices(struct status *);static int create_crypto_device(int);static int destroy_crypto_device(int);static void destroy_z90crypt(void);static int refresh_index_array(struct status *, struct device_x *);static int probe_device_type(struct device *);/** * proc fs definitions */static struct proc_dir_entry *z90crypt_entry;/** * data structures *//** * work_element.opener points back to this structure */struct priv_data { pid_t opener_pid; unsigned char status; // 0: open 1: closed};/** * A work element is allocated for each request */struct work_element { struct priv_data *priv_data; pid_t pid; int devindex; // index of device processing this w_e // (If request did not specify device, // -1 until placed onto a queue) int devtype; struct list_head liste; // used for requestq and pendingq char buffer[128]; // local copy of user request int buff_size; // size of the buffer for the request char resp_buff[RESPBUFFSIZE]; int resp_buff_size; char __user * resp_addr; // address of response in user space unsigned int funccode; // function code of request wait_queue_head_t waitq; unsigned long requestsent; // time at which the request was sent atomic_t alarmrung; // wake-up signal unsigned char caller_id[8]; // pid + counter, for this w_e unsigned char status[1]; // bits to mark status of the request unsigned char audit[3]; // record of work element's progress unsigned char * requestptr; // address of request buffer int retcode; // return code of request};/** * High level function prototypes */static int z90crypt_open(struct inode *, struct file *);static int z90crypt_release(struct inode *, struct file *);static ssize_t z90crypt_read(struct file *, char __user *, size_t, loff_t *);static ssize_t z90crypt_write(struct file *, const char __user *, size_t, loff_t *);static int z90crypt_ioctl(struct inode *, struct file *, unsigned int, unsigned long);static void z90crypt_reader_task(unsigned long);static void z90crypt_schedule_reader_task(unsigned long);static void z90crypt_config_task(unsigned long);static void z90crypt_cleanup_task(unsigned long);static int z90crypt_status(char *, char **, off_t, int, int *, void *);static int z90crypt_status_write(struct file *, const char __user *, unsigned long, void *);/** * Hotplug support */#ifdef Z90CRYPT_USE_HOTPLUG#define Z90CRYPT_HOTPLUG_ADD 1#define Z90CRYPT_HOTPLUG_REMOVE 2static void z90crypt_hotplug_event(int, int, int);#endif/** * Storage allocated at initialization and used throughout the life of * this insmod */#ifdef Z90CRYPT_USE_HOTPLUGstatic int z90crypt_major = Z90CRYPT_MAJOR;#endifstatic int domain = DOMAIN_INDEX;static struct z90crypt z90crypt;static int quiesce_z90crypt;static spinlock_t queuespinlock;static struct list_head request_list;static int requestq_count;static struct list_head pending_list;static int pendingq_count;static struct tasklet_struct reader_tasklet;static struct timer_list reader_timer;static struct timer_list config_timer;static struct timer_list cleanup_timer;static atomic_t total_open;static atomic_t z90crypt_step;static struct file_operations z90crypt_fops = { .owner = THIS_MODULE, .read = z90crypt_read, .write = z90crypt_write, .ioctl = z90crypt_ioctl, .open = z90crypt_open, .release = z90crypt_release};#ifndef Z90CRYPT_USE_HOTPLUGstatic struct miscdevice z90crypt_misc_device = { .minor = Z90CRYPT_MINOR, .name = DEV_NAME, .fops = &z90crypt_fops, .devfs_name = DEV_NAME};#endif/** * Documentation values. */MODULE_AUTHOR("zLinux Crypto Team: Robert H. Burroughs, Eric D. Rossman" "and Jochen Roehrig");MODULE_DESCRIPTION("zLinux Cryptographic Coprocessor device driver, " "Copyright 2001, 2004 IBM Corporation");MODULE_LICENSE("GPL");module_param(domain, int, 0);MODULE_PARM_DESC(domain, "domain index for device");#ifdef CONFIG_COMPAT/** * ioctl32 conversion routines */struct ica_rsa_modexpo_32 { // For 32-bit callers compat_uptr_t inputdata; unsigned int inputdatalength; compat_uptr_t outputdata; unsigned int outputdatalength; compat_uptr_t b_key; compat_uptr_t n_modulus;};static inttrans_modexpo32(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file){ struct ica_rsa_modexpo_32 __user *mex32u = compat_ptr(arg); struct ica_rsa_modexpo_32 mex32k; struct ica_rsa_modexpo __user *mex64; int ret = 0; unsigned int i; if (!access_ok(VERIFY_WRITE, mex32u, sizeof(struct ica_rsa_modexpo_32))) return -EFAULT; mex64 = compat_alloc_user_space(sizeof(struct ica_rsa_modexpo)); if (!access_ok(VERIFY_WRITE, mex64, sizeof(struct ica_rsa_modexpo))) return -EFAULT; if (copy_from_user(&mex32k, mex32u, sizeof(struct ica_rsa_modexpo_32))) return -EFAULT; if (__put_user(compat_ptr(mex32k.inputdata), &mex64->inputdata) || __put_user(mex32k.inputdatalength, &mex64->inputdatalength) || __put_user(compat_ptr(mex32k.outputdata), &mex64->outputdata) || __put_user(mex32k.outputdatalength, &mex64->outputdatalength) || __put_user(compat_ptr(mex32k.b_key), &mex64->b_key) || __put_user(compat_ptr(mex32k.n_modulus), &mex64->n_modulus)) return -EFAULT; ret = sys_ioctl(fd, cmd, (unsigned long)mex64); if (!ret) if (__get_user(i, &mex64->outputdatalength) || __put_user(i, &mex32u->outputdatalength)) ret = -EFAULT; return ret;}struct ica_rsa_modexpo_crt_32 { // For 32-bit callers compat_uptr_t inputdata; unsigned int inputdatalength; compat_uptr_t outputdata; unsigned int outputdatalength; compat_uptr_t bp_key; compat_uptr_t bq_key; compat_uptr_t np_prime; compat_uptr_t nq_prime; compat_uptr_t u_mult_inv;};static int
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -