mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
s390 updates for the 4.20 merge window
- Improved access control for the zcrypt driver, multiple device nodes
can now be created with different access control lists
- Extend the pkey API to provide random protected keys, this is useful
for encrypted swap device with ephemeral protected keys
- Add support for virtually mapped kernel stacks
- Rework the early boot code, this moves the memory detection into the
boot code that runs prior to decompression.
- Add KASAN support
- Bug fixes and cleanups
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQEcBAABCAAGBQJbzXKpAAoJEDjwexyKj9rg98YH/jZ5/kEYV44JsACroTNBC782
6QLCvoCvSgXUAqRwnIfnxrcjrUVNW2aK6rOSsI/I8rQDsSA3boJ7FimoEI2BsUZG
dcMy0hC47AYB7yKREQX3gdDEj8f0bn8v2ize5F6gwLkIx0A+aBUSivRQeYMaF8sn
N/5OkSJwjCb+ZkNmDa3SHif+hC5+iL+q1hfuBdQkeCBok9pAqhyosRkgLe8CQgUV
HGrvaWJ4FudIpg4tu2jL2OsNoZFX2pK5d+Up886+KGKQEUfiXKYtdmzX17Vd7PIk
Vkf7EWUipzIA7UtrJ6pljoFsrNa+83jm4j5Dgy0ohadCVUBYLORte3yEl4P1EoM=
=MMf0
-----END PGP SIGNATURE-----
Merge tag 's390-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Martin Schwidefsky:
- Improved access control for the zcrypt driver, multiple device nodes
can now be created with different access control lists
- Extend the pkey API to provide random protected keys, this is useful
for encrypted swap device with ephemeral protected keys
- Add support for virtually mapped kernel stacks
- Rework the early boot code, this moves the memory detection into the
boot code that runs prior to decompression.
- Add KASAN support
- Bug fixes and cleanups
* tag 's390-4.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (83 commits)
s390/pkey: move pckmo subfunction available checks away from module init
s390/kasan: support preemptible kernel build
s390/pkey: Load pkey kernel module automatically
s390/perf: Return error when debug_register fails
s390/sthyi: Fix machine name validity indication
s390/zcrypt: fix broken zcrypt_send_cprb in-kernel api function
s390/vmalloc: fix VMALLOC_START calculation
s390/mem_detect: add missing include
s390/dumpstack: print psw mask and address again
s390/crypto: Enhance paes cipher to accept variable length key material
s390/pkey: Introduce new API for transforming key blobs
s390/pkey: Introduce new API for random protected key verification
s390/pkey: Add sysfs attributes to emit secure key blobs
s390/pkey: Add sysfs attributes to emit protected key blobs
s390/pkey: Define protected key blob format
s390/pkey: Introduce new API for random protected key generation
s390/zcrypt: add ap_adapter_mask sysfs attribute
s390/zcrypt: provide apfs failure code on type 86 error reply
s390/zcrypt: zcrypt device driver cleanup
s390/kasan: add support for mem= kernel parameter
...
This commit is contained in:
commit
e2b623fbe6
121 changed files with 3712 additions and 1183 deletions
|
|
@ -3309,10 +3309,8 @@ dasd_exit(void)
|
|||
dasd_proc_exit();
|
||||
#endif
|
||||
dasd_eer_exit();
|
||||
if (dasd_page_cache != NULL) {
|
||||
kmem_cache_destroy(dasd_page_cache);
|
||||
dasd_page_cache = NULL;
|
||||
}
|
||||
kmem_cache_destroy(dasd_page_cache);
|
||||
dasd_page_cache = NULL;
|
||||
dasd_gendisk_exit();
|
||||
dasd_devmap_exit();
|
||||
if (dasd_debug_area != NULL) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ endif
|
|||
GCOV_PROFILE_sclp_early_core.o := n
|
||||
KCOV_INSTRUMENT_sclp_early_core.o := n
|
||||
UBSAN_SANITIZE_sclp_early_core.o := n
|
||||
KASAN_SANITIZE_sclp_early_core.o := n
|
||||
|
||||
CFLAGS_sclp_early_core.o += -D__NO_FORTIFY
|
||||
|
||||
|
|
|
|||
|
|
@ -58,22 +58,31 @@ struct mon_private {
|
|||
|
||||
static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
|
||||
{
|
||||
struct appldata_product_id id;
|
||||
struct appldata_parameter_list *parm_list;
|
||||
struct appldata_product_id *id;
|
||||
int rc;
|
||||
|
||||
memcpy(id.prod_nr, "LNXAPPL", 7);
|
||||
id.prod_fn = myhdr->applid;
|
||||
id.record_nr = myhdr->record_num;
|
||||
id.version_nr = myhdr->version;
|
||||
id.release_nr = myhdr->release;
|
||||
id.mod_lvl = myhdr->mod_level;
|
||||
rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen);
|
||||
id = kmalloc(sizeof(*id), GFP_KERNEL);
|
||||
parm_list = kmalloc(sizeof(*parm_list), GFP_KERNEL);
|
||||
rc = -ENOMEM;
|
||||
if (!id || !parm_list)
|
||||
goto out;
|
||||
memcpy(id->prod_nr, "LNXAPPL", 7);
|
||||
id->prod_fn = myhdr->applid;
|
||||
id->record_nr = myhdr->record_num;
|
||||
id->version_nr = myhdr->version;
|
||||
id->release_nr = myhdr->release;
|
||||
id->mod_lvl = myhdr->mod_level;
|
||||
rc = appldata_asm(parm_list, id, fcn,
|
||||
(void *) buffer, myhdr->datalen);
|
||||
if (rc <= 0)
|
||||
return rc;
|
||||
goto out;
|
||||
pr_err("Writing monitor data failed with rc=%i\n", rc);
|
||||
if (rc == 5)
|
||||
return -EPERM;
|
||||
return -EINVAL;
|
||||
rc = (rc == 5) ? -EPERM : -EINVAL;
|
||||
out:
|
||||
kfree(id);
|
||||
kfree(parm_list);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@
|
|||
typedef unsigned int sclp_cmdw_t;
|
||||
|
||||
#define SCLP_CMDW_READ_CPU_INFO 0x00010001
|
||||
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
|
||||
#define SCLP_CMDW_READ_STORAGE_INFO 0x00040001
|
||||
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
|
||||
#define SCLP_CMDW_READ_EVENT_DATA 0x00770005
|
||||
#define SCLP_CMDW_WRITE_EVENT_DATA 0x00760005
|
||||
#define SCLP_CMDW_WRITE_EVENT_MASK 0x00780005
|
||||
|
|
@ -156,6 +159,54 @@ struct read_cpu_info_sccb {
|
|||
u8 reserved[4096 - 16];
|
||||
} __attribute__((packed, aligned(PAGE_SIZE)));
|
||||
|
||||
struct read_info_sccb {
|
||||
struct sccb_header header; /* 0-7 */
|
||||
u16 rnmax; /* 8-9 */
|
||||
u8 rnsize; /* 10 */
|
||||
u8 _pad_11[16 - 11]; /* 11-15 */
|
||||
u16 ncpurl; /* 16-17 */
|
||||
u16 cpuoff; /* 18-19 */
|
||||
u8 _pad_20[24 - 20]; /* 20-23 */
|
||||
u8 loadparm[8]; /* 24-31 */
|
||||
u8 _pad_32[42 - 32]; /* 32-41 */
|
||||
u8 fac42; /* 42 */
|
||||
u8 fac43; /* 43 */
|
||||
u8 _pad_44[48 - 44]; /* 44-47 */
|
||||
u64 facilities; /* 48-55 */
|
||||
u8 _pad_56[66 - 56]; /* 56-65 */
|
||||
u8 fac66; /* 66 */
|
||||
u8 _pad_67[76 - 67]; /* 67-83 */
|
||||
u32 ibc; /* 76-79 */
|
||||
u8 _pad80[84 - 80]; /* 80-83 */
|
||||
u8 fac84; /* 84 */
|
||||
u8 fac85; /* 85 */
|
||||
u8 _pad_86[91 - 86]; /* 86-90 */
|
||||
u8 fac91; /* 91 */
|
||||
u8 _pad_92[98 - 92]; /* 92-97 */
|
||||
u8 fac98; /* 98 */
|
||||
u8 hamaxpow; /* 99 */
|
||||
u32 rnsize2; /* 100-103 */
|
||||
u64 rnmax2; /* 104-111 */
|
||||
u32 hsa_size; /* 112-115 */
|
||||
u8 fac116; /* 116 */
|
||||
u8 fac117; /* 117 */
|
||||
u8 fac118; /* 118 */
|
||||
u8 fac119; /* 119 */
|
||||
u16 hcpua; /* 120-121 */
|
||||
u8 _pad_122[124 - 122]; /* 122-123 */
|
||||
u32 hmfai; /* 124-127 */
|
||||
u8 _pad_128[4096 - 128]; /* 128-4095 */
|
||||
} __packed __aligned(PAGE_SIZE);
|
||||
|
||||
struct read_storage_sccb {
|
||||
struct sccb_header header;
|
||||
u16 max_id;
|
||||
u16 assigned;
|
||||
u16 standby;
|
||||
u16 :16;
|
||||
u32 entries[0];
|
||||
} __packed;
|
||||
|
||||
static inline void sclp_fill_core_info(struct sclp_core_info *info,
|
||||
struct read_cpu_info_sccb *sccb)
|
||||
{
|
||||
|
|
@ -275,6 +326,7 @@ unsigned int sclp_early_con_check_vt220(struct init_sccb *sccb);
|
|||
int sclp_early_set_event_mask(struct init_sccb *sccb,
|
||||
sccb_mask_t receive_mask,
|
||||
sccb_mask_t send_mask);
|
||||
int sclp_early_get_info(struct read_info_sccb *info);
|
||||
|
||||
/* useful inlines */
|
||||
|
||||
|
|
|
|||
|
|
@ -460,15 +460,6 @@ static int sclp_mem_freeze(struct device *dev)
|
|||
return -EPERM;
|
||||
}
|
||||
|
||||
struct read_storage_sccb {
|
||||
struct sccb_header header;
|
||||
u16 max_id;
|
||||
u16 assigned;
|
||||
u16 standby;
|
||||
u16 :16;
|
||||
u32 entries[0];
|
||||
} __packed;
|
||||
|
||||
static const struct dev_pm_ops sclp_mem_pm_ops = {
|
||||
.freeze = sclp_mem_freeze,
|
||||
};
|
||||
|
|
@ -498,7 +489,7 @@ static int __init sclp_detect_standby_memory(void)
|
|||
for (id = 0; id <= sclp_max_storage_id; id++) {
|
||||
memset(sccb, 0, PAGE_SIZE);
|
||||
sccb->header.length = PAGE_SIZE;
|
||||
rc = sclp_sync_request(0x00040001 | id << 8, sccb);
|
||||
rc = sclp_sync_request(SCLP_CMDW_READ_STORAGE_INFO | id << 8, sccb);
|
||||
if (rc)
|
||||
goto out;
|
||||
switch (sccb->header.response_code) {
|
||||
|
|
|
|||
|
|
@ -15,80 +15,17 @@
|
|||
#include "sclp_sdias.h"
|
||||
#include "sclp.h"
|
||||
|
||||
#define SCLP_CMDW_READ_SCP_INFO 0x00020001
|
||||
#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
|
||||
|
||||
struct read_info_sccb {
|
||||
struct sccb_header header; /* 0-7 */
|
||||
u16 rnmax; /* 8-9 */
|
||||
u8 rnsize; /* 10 */
|
||||
u8 _pad_11[16 - 11]; /* 11-15 */
|
||||
u16 ncpurl; /* 16-17 */
|
||||
u16 cpuoff; /* 18-19 */
|
||||
u8 _pad_20[24 - 20]; /* 20-23 */
|
||||
u8 loadparm[8]; /* 24-31 */
|
||||
u8 _pad_32[42 - 32]; /* 32-41 */
|
||||
u8 fac42; /* 42 */
|
||||
u8 fac43; /* 43 */
|
||||
u8 _pad_44[48 - 44]; /* 44-47 */
|
||||
u64 facilities; /* 48-55 */
|
||||
u8 _pad_56[66 - 56]; /* 56-65 */
|
||||
u8 fac66; /* 66 */
|
||||
u8 _pad_67[76 - 67]; /* 67-83 */
|
||||
u32 ibc; /* 76-79 */
|
||||
u8 _pad80[84 - 80]; /* 80-83 */
|
||||
u8 fac84; /* 84 */
|
||||
u8 fac85; /* 85 */
|
||||
u8 _pad_86[91 - 86]; /* 86-90 */
|
||||
u8 fac91; /* 91 */
|
||||
u8 _pad_92[98 - 92]; /* 92-97 */
|
||||
u8 fac98; /* 98 */
|
||||
u8 hamaxpow; /* 99 */
|
||||
u32 rnsize2; /* 100-103 */
|
||||
u64 rnmax2; /* 104-111 */
|
||||
u8 _pad_112[116 - 112]; /* 112-115 */
|
||||
u8 fac116; /* 116 */
|
||||
u8 fac117; /* 117 */
|
||||
u8 fac118; /* 118 */
|
||||
u8 fac119; /* 119 */
|
||||
u16 hcpua; /* 120-121 */
|
||||
u8 _pad_122[124 - 122]; /* 122-123 */
|
||||
u32 hmfai; /* 124-127 */
|
||||
u8 _pad_128[4096 - 128]; /* 128-4095 */
|
||||
} __packed __aligned(PAGE_SIZE);
|
||||
|
||||
static struct sclp_ipl_info sclp_ipl_info;
|
||||
|
||||
struct sclp_info sclp;
|
||||
EXPORT_SYMBOL(sclp);
|
||||
|
||||
static int __init sclp_early_read_info(struct read_info_sccb *sccb)
|
||||
{
|
||||
int i;
|
||||
sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
|
||||
SCLP_CMDW_READ_SCP_INFO};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
||||
memset(sccb, 0, sizeof(*sccb));
|
||||
sccb->header.length = sizeof(*sccb);
|
||||
sccb->header.function_code = 0x80;
|
||||
sccb->header.control_mask[2] = 0x80;
|
||||
if (sclp_early_cmd(commands[i], sccb))
|
||||
break;
|
||||
if (sccb->header.response_code == 0x10)
|
||||
return 0;
|
||||
if (sccb->header.response_code != 0x1f0)
|
||||
break;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
|
||||
{
|
||||
struct sclp_core_entry *cpue;
|
||||
u16 boot_cpu_address, cpu;
|
||||
|
||||
if (sclp_early_read_info(sccb))
|
||||
if (sclp_early_get_info(sccb))
|
||||
return;
|
||||
|
||||
sclp.facilities = sccb->facilities;
|
||||
|
|
@ -147,6 +84,8 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb)
|
|||
sclp_ipl_info.has_dump = 1;
|
||||
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
|
||||
|
||||
if (sccb->hsa_size)
|
||||
sclp.hsa_size = (sccb->hsa_size - 1) * PAGE_SIZE;
|
||||
sclp.mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
|
||||
sclp.mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
|
||||
sclp.mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
|
||||
|
|
@ -189,61 +128,6 @@ int __init sclp_early_get_core_info(struct sclp_core_info *info)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb)
|
||||
{
|
||||
memset(sccb, 0, sizeof(*sccb));
|
||||
sccb->hdr.length = sizeof(*sccb);
|
||||
sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf);
|
||||
sccb->evbuf.hdr.type = EVTYP_SDIAS;
|
||||
sccb->evbuf.event_qual = SDIAS_EQ_SIZE;
|
||||
sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP;
|
||||
sccb->evbuf.event_id = 4712;
|
||||
sccb->evbuf.dbs = 1;
|
||||
if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb))
|
||||
return -EIO;
|
||||
if (sccb->hdr.response_code != 0x20)
|
||||
return -EIO;
|
||||
if (sccb->evbuf.blk_cnt == 0)
|
||||
return 0;
|
||||
return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
|
||||
}
|
||||
|
||||
static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb)
|
||||
{
|
||||
memset(sccb, 0, PAGE_SIZE);
|
||||
sccb->hdr.length = PAGE_SIZE;
|
||||
if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb))
|
||||
return -EIO;
|
||||
if ((sccb->hdr.response_code != 0x20) && (sccb->hdr.response_code != 0x220))
|
||||
return -EIO;
|
||||
if (sccb->evbuf.blk_cnt == 0)
|
||||
return 0;
|
||||
return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE;
|
||||
}
|
||||
|
||||
static void __init sclp_early_hsa_size_detect(void *sccb)
|
||||
{
|
||||
unsigned long flags;
|
||||
long size = -EIO;
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK))
|
||||
goto out;
|
||||
size = sclp_early_hsa_size_init(sccb);
|
||||
/* First check for synchronous response (LPAR) */
|
||||
if (size)
|
||||
goto out_mask;
|
||||
if (!(S390_lowcore.ext_params & 1))
|
||||
sclp_early_wait_irq();
|
||||
size = sclp_early_hsa_copy_wait(sccb);
|
||||
out_mask:
|
||||
sclp_early_set_event_mask(sccb, 0, 0);
|
||||
out:
|
||||
raw_local_irq_restore(flags);
|
||||
if (size > 0)
|
||||
sclp.hsa_size = size;
|
||||
}
|
||||
|
||||
static void __init sclp_early_console_detect(struct init_sccb *sccb)
|
||||
{
|
||||
if (sccb->header.response_code != 0x20)
|
||||
|
|
@ -262,7 +146,6 @@ void __init sclp_early_detect(void)
|
|||
|
||||
sclp_early_facilities_detect(sccb);
|
||||
sclp_early_init_core_info(sccb);
|
||||
sclp_early_hsa_size_detect(sccb);
|
||||
|
||||
/*
|
||||
* Turn off SCLP event notifications. Also save remote masks in the
|
||||
|
|
|
|||
|
|
@ -9,9 +9,13 @@
|
|||
#include <asm/lowcore.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/mem_detect.h>
|
||||
#include "sclp.h"
|
||||
#include "sclp_rw.h"
|
||||
|
||||
static struct read_info_sccb __bootdata(sclp_info_sccb);
|
||||
static int __bootdata(sclp_info_sccb_valid);
|
||||
char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data);
|
||||
int sclp_init_state __section(.data) = sclp_init_state_uninitialized;
|
||||
/*
|
||||
|
|
@ -234,3 +238,115 @@ void sclp_early_printk_force(const char *str)
|
|||
{
|
||||
__sclp_early_printk(str, strlen(str), 1);
|
||||
}
|
||||
|
||||
int __init sclp_early_read_info(void)
|
||||
{
|
||||
int i;
|
||||
struct read_info_sccb *sccb = &sclp_info_sccb;
|
||||
sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED,
|
||||
SCLP_CMDW_READ_SCP_INFO};
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(commands); i++) {
|
||||
memset(sccb, 0, sizeof(*sccb));
|
||||
sccb->header.length = sizeof(*sccb);
|
||||
sccb->header.function_code = 0x80;
|
||||
sccb->header.control_mask[2] = 0x80;
|
||||
if (sclp_early_cmd(commands[i], sccb))
|
||||
break;
|
||||
if (sccb->header.response_code == 0x10) {
|
||||
sclp_info_sccb_valid = 1;
|
||||
return 0;
|
||||
}
|
||||
if (sccb->header.response_code != 0x1f0)
|
||||
break;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
int __init sclp_early_get_info(struct read_info_sccb *info)
|
||||
{
|
||||
if (!sclp_info_sccb_valid)
|
||||
return -EIO;
|
||||
|
||||
*info = sclp_info_sccb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init sclp_early_get_memsize(unsigned long *mem)
|
||||
{
|
||||
unsigned long rnmax;
|
||||
unsigned long rnsize;
|
||||
struct read_info_sccb *sccb = &sclp_info_sccb;
|
||||
|
||||
if (!sclp_info_sccb_valid)
|
||||
return -EIO;
|
||||
|
||||
rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
|
||||
rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
|
||||
rnsize <<= 20;
|
||||
*mem = rnsize * rnmax;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __init sclp_early_get_hsa_size(unsigned long *hsa_size)
|
||||
{
|
||||
if (!sclp_info_sccb_valid)
|
||||
return -EIO;
|
||||
|
||||
*hsa_size = 0;
|
||||
if (sclp_info_sccb.hsa_size)
|
||||
*hsa_size = (sclp_info_sccb.hsa_size - 1) * PAGE_SIZE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SCLP_STORAGE_INFO_FACILITY 0x0000400000000000UL
|
||||
|
||||
void __weak __init add_mem_detect_block(u64 start, u64 end) {}
|
||||
int __init sclp_early_read_storage_info(void)
|
||||
{
|
||||
struct read_storage_sccb *sccb = (struct read_storage_sccb *)&sclp_early_sccb;
|
||||
int rc, id, max_id = 0;
|
||||
unsigned long rn, rzm;
|
||||
sclp_cmdw_t command;
|
||||
u16 sn;
|
||||
|
||||
if (!sclp_info_sccb_valid)
|
||||
return -EIO;
|
||||
|
||||
if (!(sclp_info_sccb.facilities & SCLP_STORAGE_INFO_FACILITY))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
rzm = sclp_info_sccb.rnsize ?: sclp_info_sccb.rnsize2;
|
||||
rzm <<= 20;
|
||||
|
||||
for (id = 0; id <= max_id; id++) {
|
||||
memset(sclp_early_sccb, 0, sizeof(sclp_early_sccb));
|
||||
sccb->header.length = sizeof(sclp_early_sccb);
|
||||
command = SCLP_CMDW_READ_STORAGE_INFO | (id << 8);
|
||||
rc = sclp_early_cmd(command, sccb);
|
||||
if (rc)
|
||||
goto fail;
|
||||
|
||||
max_id = sccb->max_id;
|
||||
switch (sccb->header.response_code) {
|
||||
case 0x0010:
|
||||
for (sn = 0; sn < sccb->assigned; sn++) {
|
||||
if (!sccb->entries[sn])
|
||||
continue;
|
||||
rn = sccb->entries[sn] >> 16;
|
||||
add_mem_detect_block((rn - 1) * rzm, rn * rzm);
|
||||
}
|
||||
break;
|
||||
case 0x0310:
|
||||
case 0x0410:
|
||||
break;
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
mem_detect.count = 0;
|
||||
return -EIO;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#define SCLP_ATYPE_PCI 2
|
||||
|
||||
#define SCLP_ERRNOTIFY_AQ_RESET 0
|
||||
#define SCLP_ERRNOTIFY_AQ_REPAIR 1
|
||||
#define SCLP_ERRNOTIFY_AQ_INFO_LOG 2
|
||||
|
||||
|
|
@ -111,9 +112,14 @@ static int sclp_pci_check_report(struct zpci_report_error_header *report)
|
|||
if (report->version != 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (report->action != SCLP_ERRNOTIFY_AQ_REPAIR &&
|
||||
report->action != SCLP_ERRNOTIFY_AQ_INFO_LOG)
|
||||
switch (report->action) {
|
||||
case SCLP_ERRNOTIFY_AQ_RESET:
|
||||
case SCLP_ERRNOTIFY_AQ_REPAIR:
|
||||
case SCLP_ERRNOTIFY_AQ_INFO_LOG:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (report->length > (PAGE_SIZE - sizeof(struct err_notify_sccb)))
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -971,7 +971,7 @@ tape_3590_print_mim_msg_f0(struct tape_device *device, struct irb *irb)
|
|||
snprintf(exception, BUFSIZE, "Data degraded");
|
||||
break;
|
||||
case 0x03:
|
||||
snprintf(exception, BUFSIZE, "Data degraded in partion %i",
|
||||
snprintf(exception, BUFSIZE, "Data degraded in partition %i",
|
||||
sense->fmt.f70.mp);
|
||||
break;
|
||||
case 0x04:
|
||||
|
|
|
|||
|
|
@ -153,7 +153,7 @@ static struct vmlogrdr_priv_t sys_ser[] = {
|
|||
}
|
||||
};
|
||||
|
||||
#define MAXMINOR (sizeof(sys_ser)/sizeof(struct vmlogrdr_priv_t))
|
||||
#define MAXMINOR ARRAY_SIZE(sys_ser)
|
||||
|
||||
static char FENCE[] = {"EOR"};
|
||||
static int vmlogrdr_major = 0;
|
||||
|
|
|
|||
|
|
@ -608,6 +608,36 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver)
|
|||
}
|
||||
EXPORT_SYMBOL(ccwgroup_driver_unregister);
|
||||
|
||||
static int __ccwgroupdev_check_busid(struct device *dev, void *id)
|
||||
{
|
||||
char *bus_id = id;
|
||||
|
||||
return (strcmp(bus_id, dev_name(dev)) == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_ccwgroupdev_by_busid() - obtain device from a bus id
|
||||
* @gdrv: driver the device is owned by
|
||||
* @bus_id: bus id of the device to be searched
|
||||
*
|
||||
* This function searches all devices owned by @gdrv for a device with a bus
|
||||
* id matching @bus_id.
|
||||
* Returns:
|
||||
* If a match is found, its reference count of the found device is increased
|
||||
* and it is returned; else %NULL is returned.
|
||||
*/
|
||||
struct ccwgroup_device *get_ccwgroupdev_by_busid(struct ccwgroup_driver *gdrv,
|
||||
char *bus_id)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = driver_find_device(&gdrv->driver, NULL, bus_id,
|
||||
__ccwgroupdev_check_busid);
|
||||
|
||||
return dev ? to_ccwgroupdev(dev) : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_ccwgroupdev_by_busid);
|
||||
|
||||
/**
|
||||
* ccwgroup_probe_ccwdev() - probe function for slave devices
|
||||
* @cdev: ccw device to be probed
|
||||
|
|
|
|||
|
|
@ -595,19 +595,11 @@ static inline int qdio_inbound_q_done(struct qdio_q *q)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int contains_aobs(struct qdio_q *q)
|
||||
{
|
||||
return !q->is_input_q && q->u.out.use_cq;
|
||||
}
|
||||
|
||||
static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
|
||||
{
|
||||
unsigned char state = 0;
|
||||
int j, b = start;
|
||||
|
||||
if (!contains_aobs(q))
|
||||
return;
|
||||
|
||||
for (j = 0; j < count; ++j) {
|
||||
get_buf_state(q, b, &state, 0);
|
||||
if (state == SLSB_P_OUTPUT_PENDING) {
|
||||
|
|
@ -618,8 +610,6 @@ static inline void qdio_handle_aobs(struct qdio_q *q, int start, int count)
|
|||
q->u.out.sbal_state[b].flags |=
|
||||
QDIO_OUTBUF_STATE_FLAG_PENDING;
|
||||
q->u.out.aobs[b] = NULL;
|
||||
} else if (state == SLSB_P_OUTPUT_EMPTY) {
|
||||
q->u.out.sbal_state[b].aob = NULL;
|
||||
}
|
||||
b = next_buf(b);
|
||||
}
|
||||
|
|
@ -638,7 +628,6 @@ static inline unsigned long qdio_aob_for_buffer(struct qdio_output_q *q,
|
|||
q->aobs[bufnr] = aob;
|
||||
}
|
||||
if (q->aobs[bufnr]) {
|
||||
q->sbal_state[bufnr].aob = q->aobs[bufnr];
|
||||
q->aobs[bufnr]->user1 = (u64) q->sbal_state[bufnr].user;
|
||||
phys_aob = virt_to_phys(q->aobs[bufnr]);
|
||||
WARN_ON_ONCE(phys_aob & 0xFF);
|
||||
|
|
@ -666,10 +655,10 @@ static void qdio_kick_handler(struct qdio_q *q)
|
|||
qperf_inc(q, outbound_handler);
|
||||
DBF_DEV_EVENT(DBF_INFO, q->irq_ptr, "koh: s:%02x c:%02x",
|
||||
start, count);
|
||||
if (q->u.out.use_cq)
|
||||
qdio_handle_aobs(q, start, count);
|
||||
}
|
||||
|
||||
qdio_handle_aobs(q, start, count);
|
||||
|
||||
q->handler(q->irq_ptr->cdev, q->qdio_error, q->nr, start, count,
|
||||
q->irq_ptr->int_parm);
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ struct qaob *qdio_allocate_aob(void)
|
|||
{
|
||||
return kmem_cache_zalloc(qdio_aob_cache, GFP_ATOMIC);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(qdio_allocate_aob);
|
||||
|
||||
void qdio_release_aob(struct qaob *aob)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o
|
|||
zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o
|
||||
obj-$(CONFIG_ZCRYPT) += zcrypt.o
|
||||
# adapter drivers depend on ap.o and zcrypt.o
|
||||
obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o
|
||||
obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o
|
||||
|
||||
# pkey kernel module
|
||||
pkey-objs := pkey_api.o
|
||||
|
|
|
|||
|
|
@ -65,12 +65,11 @@ static struct device *ap_root_device;
|
|||
DEFINE_SPINLOCK(ap_list_lock);
|
||||
LIST_HEAD(ap_card_list);
|
||||
|
||||
/* Default permissions (card and domain masking) */
|
||||
static struct ap_perms {
|
||||
DECLARE_BITMAP(apm, AP_DEVICES);
|
||||
DECLARE_BITMAP(aqm, AP_DOMAINS);
|
||||
} ap_perms;
|
||||
static DEFINE_MUTEX(ap_perms_mutex);
|
||||
/* Default permissions (ioctl, card and domain masking) */
|
||||
struct ap_perms ap_perms;
|
||||
EXPORT_SYMBOL(ap_perms);
|
||||
DEFINE_MUTEX(ap_perms_mutex);
|
||||
EXPORT_SYMBOL(ap_perms_mutex);
|
||||
|
||||
static struct ap_config_info *ap_configuration;
|
||||
static bool initialised;
|
||||
|
|
@ -944,21 +943,9 @@ static int modify_bitmap(const char *str, unsigned long *bitmap, int bits)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* process_mask_arg() - parse a bitmap string and clear/set the
|
||||
* bits in the bitmap accordingly. The string may be given as
|
||||
* absolute value, a hex string like 0x1F2E3D4C5B6A" simple over-
|
||||
* writing the current content of the bitmap. Or as relative string
|
||||
* like "+1-16,-32,-0x40,+128" where only single bits or ranges of
|
||||
* bits are cleared or set. Distinction is done based on the very
|
||||
* first character which may be '+' or '-' for the relative string
|
||||
* and othewise assume to be an absolute value string. If parsing fails
|
||||
* a negative errno value is returned. All arguments and bitmaps are
|
||||
* big endian order.
|
||||
*/
|
||||
static int process_mask_arg(const char *str,
|
||||
unsigned long *bitmap, int bits,
|
||||
struct mutex *lock)
|
||||
int ap_parse_mask_str(const char *str,
|
||||
unsigned long *bitmap, int bits,
|
||||
struct mutex *lock)
|
||||
{
|
||||
unsigned long *newmap, size;
|
||||
int rc;
|
||||
|
|
@ -989,6 +976,7 @@ static int process_mask_arg(const char *str,
|
|||
kfree(newmap);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(ap_parse_mask_str);
|
||||
|
||||
/*
|
||||
* AP bus attributes.
|
||||
|
|
@ -1049,6 +1037,21 @@ static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf)
|
|||
|
||||
static BUS_ATTR_RO(ap_usage_domain_mask);
|
||||
|
||||
static ssize_t ap_adapter_mask_show(struct bus_type *bus, char *buf)
|
||||
{
|
||||
if (!ap_configuration) /* QCI not supported */
|
||||
return snprintf(buf, PAGE_SIZE, "not supported\n");
|
||||
|
||||
return snprintf(buf, PAGE_SIZE,
|
||||
"0x%08x%08x%08x%08x%08x%08x%08x%08x\n",
|
||||
ap_configuration->apm[0], ap_configuration->apm[1],
|
||||
ap_configuration->apm[2], ap_configuration->apm[3],
|
||||
ap_configuration->apm[4], ap_configuration->apm[5],
|
||||
ap_configuration->apm[6], ap_configuration->apm[7]);
|
||||
}
|
||||
|
||||
static BUS_ATTR_RO(ap_adapter_mask);
|
||||
|
||||
static ssize_t ap_interrupts_show(struct bus_type *bus, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n",
|
||||
|
|
@ -1161,7 +1164,7 @@ static ssize_t apmask_store(struct bus_type *bus, const char *buf,
|
|||
{
|
||||
int rc;
|
||||
|
||||
rc = process_mask_arg(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);
|
||||
rc = ap_parse_mask_str(buf, ap_perms.apm, AP_DEVICES, &ap_perms_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1192,7 +1195,7 @@ static ssize_t aqmask_store(struct bus_type *bus, const char *buf,
|
|||
{
|
||||
int rc;
|
||||
|
||||
rc = process_mask_arg(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);
|
||||
rc = ap_parse_mask_str(buf, ap_perms.aqm, AP_DOMAINS, &ap_perms_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
|
|
@ -1207,6 +1210,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
|
|||
&bus_attr_ap_domain,
|
||||
&bus_attr_ap_control_domain_mask,
|
||||
&bus_attr_ap_usage_domain_mask,
|
||||
&bus_attr_ap_adapter_mask,
|
||||
&bus_attr_config_time,
|
||||
&bus_attr_poll_thread,
|
||||
&bus_attr_ap_interrupts,
|
||||
|
|
@ -1218,11 +1222,10 @@ static struct bus_attribute *const ap_bus_attrs[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* ap_select_domain(): Select an AP domain.
|
||||
*
|
||||
* Pick one of the 16 AP domains.
|
||||
* ap_select_domain(): Select an AP domain if possible and we haven't
|
||||
* already done so before.
|
||||
*/
|
||||
static int ap_select_domain(void)
|
||||
static void ap_select_domain(void)
|
||||
{
|
||||
int count, max_count, best_domain;
|
||||
struct ap_queue_status status;
|
||||
|
|
@ -1237,7 +1240,7 @@ static int ap_select_domain(void)
|
|||
if (ap_domain_index >= 0) {
|
||||
/* Domain has already been selected. */
|
||||
spin_unlock_bh(&ap_domain_lock);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
best_domain = -1;
|
||||
max_count = 0;
|
||||
|
|
@ -1264,11 +1267,8 @@ static int ap_select_domain(void)
|
|||
if (best_domain >= 0) {
|
||||
ap_domain_index = best_domain;
|
||||
AP_DBF(DBF_DEBUG, "new ap_domain_index=%d\n", ap_domain_index);
|
||||
spin_unlock_bh(&ap_domain_lock);
|
||||
return 0;
|
||||
}
|
||||
spin_unlock_bh(&ap_domain_lock);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1346,8 +1346,7 @@ static void ap_scan_bus(struct work_struct *unused)
|
|||
AP_DBF(DBF_DEBUG, "%s running\n", __func__);
|
||||
|
||||
ap_query_configuration(ap_configuration);
|
||||
if (ap_select_domain() != 0)
|
||||
goto out;
|
||||
ap_select_domain();
|
||||
|
||||
for (id = 0; id < AP_DEVICES; id++) {
|
||||
/* check if device is registered */
|
||||
|
|
@ -1467,12 +1466,11 @@ static void ap_scan_bus(struct work_struct *unused)
|
|||
}
|
||||
} /* end device loop */
|
||||
|
||||
if (defdomdevs < 1)
|
||||
if (ap_domain_index >= 0 && defdomdevs < 1)
|
||||
AP_DBF(DBF_INFO,
|
||||
"no queue device with default domain %d available\n",
|
||||
ap_domain_index);
|
||||
|
||||
out:
|
||||
mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ);
|
||||
}
|
||||
|
||||
|
|
@ -1496,21 +1494,22 @@ static int __init ap_debug_init(void)
|
|||
static void __init ap_perms_init(void)
|
||||
{
|
||||
/* all resources useable if no kernel parameter string given */
|
||||
memset(&ap_perms.ioctlm, 0xFF, sizeof(ap_perms.ioctlm));
|
||||
memset(&ap_perms.apm, 0xFF, sizeof(ap_perms.apm));
|
||||
memset(&ap_perms.aqm, 0xFF, sizeof(ap_perms.aqm));
|
||||
|
||||
/* apm kernel parameter string */
|
||||
if (apm_str) {
|
||||
memset(&ap_perms.apm, 0, sizeof(ap_perms.apm));
|
||||
process_mask_arg(apm_str, ap_perms.apm, AP_DEVICES,
|
||||
&ap_perms_mutex);
|
||||
ap_parse_mask_str(apm_str, ap_perms.apm, AP_DEVICES,
|
||||
&ap_perms_mutex);
|
||||
}
|
||||
|
||||
/* aqm kernel parameter string */
|
||||
if (aqm_str) {
|
||||
memset(&ap_perms.aqm, 0, sizeof(ap_perms.aqm));
|
||||
process_mask_arg(aqm_str, ap_perms.aqm, AP_DOMAINS,
|
||||
&ap_perms_mutex);
|
||||
ap_parse_mask_str(aqm_str, ap_perms.aqm, AP_DOMAINS,
|
||||
&ap_perms_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1533,7 +1532,7 @@ static int __init ap_module_init(void)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* set up the AP permissions (ap and aq masks) */
|
||||
/* set up the AP permissions (ioctls, ap and aq masks) */
|
||||
ap_perms_init();
|
||||
|
||||
/* Get AP configuration data if available */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
#define AP_DEVICES 256 /* Number of AP devices. */
|
||||
#define AP_DOMAINS 256 /* Number of AP domains. */
|
||||
#define AP_IOCTLS 256 /* Number of ioctls. */
|
||||
#define AP_RESET_TIMEOUT (HZ*0.7) /* Time in ticks for reset timeouts. */
|
||||
#define AP_CONFIG_TIME 30 /* Time in seconds between AP bus rescans. */
|
||||
#define AP_POLL_TIME 1 /* Time in ticks between receive polls. */
|
||||
|
|
@ -257,6 +258,14 @@ void ap_queue_resume(struct ap_device *ap_dev);
|
|||
struct ap_card *ap_card_create(int id, int queue_depth, int raw_device_type,
|
||||
int comp_device_type, unsigned int functions);
|
||||
|
||||
struct ap_perms {
|
||||
unsigned long ioctlm[BITS_TO_LONGS(AP_IOCTLS)];
|
||||
unsigned long apm[BITS_TO_LONGS(AP_DEVICES)];
|
||||
unsigned long aqm[BITS_TO_LONGS(AP_DOMAINS)];
|
||||
};
|
||||
extern struct ap_perms ap_perms;
|
||||
extern struct mutex ap_perms_mutex;
|
||||
|
||||
/*
|
||||
* check APQN for owned/reserved by ap bus and default driver(s).
|
||||
* Checks if this APQN is or will be in use by the ap bus
|
||||
|
|
@ -280,4 +289,20 @@ int ap_owned_by_def_drv(int card, int queue);
|
|||
int ap_apqn_in_matrix_owned_by_def_drv(unsigned long *apm,
|
||||
unsigned long *aqm);
|
||||
|
||||
/*
|
||||
* ap_parse_mask_str() - helper function to parse a bitmap string
|
||||
* and clear/set the bits in the bitmap accordingly. The string may be
|
||||
* given as absolute value, a hex string like 0x1F2E3D4C5B6A" simple
|
||||
* overwriting the current content of the bitmap. Or as relative string
|
||||
* like "+1-16,-32,-0x40,+128" where only single bits or ranges of
|
||||
* bits are cleared or set. Distinction is done based on the very
|
||||
* first character which may be '+' or '-' for the relative string
|
||||
* and othewise assume to be an absolute value string. If parsing fails
|
||||
* a negative errno value is returned. All arguments and bitmaps are
|
||||
* big endian order.
|
||||
*/
|
||||
int ap_parse_mask_str(const char *str,
|
||||
unsigned long *bitmap, int bits,
|
||||
struct mutex *lock);
|
||||
|
||||
#endif /* _AP_BUS_H_ */
|
||||
|
|
|
|||
|
|
@ -16,9 +16,12 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/cpufeature.h>
|
||||
#include <asm/zcrypt.h>
|
||||
#include <asm/cpacf.h>
|
||||
#include <asm/pkey.h>
|
||||
#include <crypto/aes.h>
|
||||
|
||||
#include "zcrypt_api.h"
|
||||
|
||||
|
|
@ -32,6 +35,9 @@ MODULE_DESCRIPTION("s390 protected key interface");
|
|||
/* Size of vardata block used for some of the cca requests/replies */
|
||||
#define VARDATASIZE 4096
|
||||
|
||||
/* mask of available pckmo subfunctions, fetched once at module init */
|
||||
static cpacf_mask_t pckmo_functions;
|
||||
|
||||
/*
|
||||
* debug feature data and functions
|
||||
*/
|
||||
|
|
@ -55,6 +61,24 @@ static void __exit pkey_debug_exit(void)
|
|||
debug_unregister(debug_info);
|
||||
}
|
||||
|
||||
/* Key token types */
|
||||
#define TOKTYPE_NON_CCA 0x00 /* Non-CCA key token */
|
||||
#define TOKTYPE_CCA_INTERNAL 0x01 /* CCA internal key token */
|
||||
|
||||
/* For TOKTYPE_NON_CCA: */
|
||||
#define TOKVER_PROTECTED_KEY 0x01 /* Protected key token */
|
||||
|
||||
/* For TOKTYPE_CCA_INTERNAL: */
|
||||
#define TOKVER_CCA_AES 0x04 /* CCA AES key token */
|
||||
|
||||
/* header part of a key token */
|
||||
struct keytoken_header {
|
||||
u8 type; /* one of the TOKTYPE values */
|
||||
u8 res0[3];
|
||||
u8 version; /* one of the TOKVER values */
|
||||
u8 res1[3];
|
||||
} __packed;
|
||||
|
||||
/* inside view of a secure key token (only type 0x01 version 0x04) */
|
||||
struct secaeskeytoken {
|
||||
u8 type; /* 0x01 for internal key token */
|
||||
|
|
@ -71,6 +95,17 @@ struct secaeskeytoken {
|
|||
u8 tvv[4]; /* token validation value */
|
||||
} __packed;
|
||||
|
||||
/* inside view of a protected key token (only type 0x00 version 0x01) */
|
||||
struct protaeskeytoken {
|
||||
u8 type; /* 0x00 for PAES specific key tokens */
|
||||
u8 res0[3];
|
||||
u8 version; /* should be 0x01 for protected AES key token */
|
||||
u8 res1[3];
|
||||
u32 keytype; /* key type, one of the PKEY_KEYTYPE values */
|
||||
u32 len; /* bytes actually stored in protkey[] */
|
||||
u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Simple check if the token is a valid CCA secure AES key
|
||||
* token. If keybitsize is given, the bitsize of the key is
|
||||
|
|
@ -80,16 +115,16 @@ static int check_secaeskeytoken(const u8 *token, int keybitsize)
|
|||
{
|
||||
struct secaeskeytoken *t = (struct secaeskeytoken *) token;
|
||||
|
||||
if (t->type != 0x01) {
|
||||
if (t->type != TOKTYPE_CCA_INTERNAL) {
|
||||
DEBUG_ERR(
|
||||
"%s secure token check failed, type mismatch 0x%02x != 0x01\n",
|
||||
__func__, (int) t->type);
|
||||
"%s secure token check failed, type mismatch 0x%02x != 0x%02x\n",
|
||||
__func__, (int) t->type, TOKTYPE_CCA_INTERNAL);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (t->version != 0x04) {
|
||||
if (t->version != TOKVER_CCA_AES) {
|
||||
DEBUG_ERR(
|
||||
"%s secure token check failed, version mismatch 0x%02x != 0x04\n",
|
||||
__func__, (int) t->version);
|
||||
"%s secure token check failed, version mismatch 0x%02x != 0x%02x\n",
|
||||
__func__, (int) t->version, TOKVER_CCA_AES);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (keybitsize > 0 && t->bitsize != keybitsize) {
|
||||
|
|
@ -647,6 +682,16 @@ int pkey_clr2protkey(u32 keytype,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the needed pckmo subfunction is available.
|
||||
* These subfunctions can be enabled/disabled by customers
|
||||
* in the LPAR profile or may even change on the fly.
|
||||
*/
|
||||
if (!cpacf_test_func(&pckmo_functions, fc)) {
|
||||
DEBUG_ERR("%s pckmo functions not available\n", __func__);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
/* prepare param block */
|
||||
memset(paramblock, 0, sizeof(paramblock));
|
||||
memcpy(paramblock, clrkey->clrkey, keysize);
|
||||
|
|
@ -1051,6 +1096,166 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL(pkey_verifykey);
|
||||
|
||||
/*
|
||||
* Generate a random protected key
|
||||
*/
|
||||
int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey)
|
||||
{
|
||||
struct pkey_clrkey clrkey;
|
||||
int keysize;
|
||||
int rc;
|
||||
|
||||
switch (keytype) {
|
||||
case PKEY_KEYTYPE_AES_128:
|
||||
keysize = 16;
|
||||
break;
|
||||
case PKEY_KEYTYPE_AES_192:
|
||||
keysize = 24;
|
||||
break;
|
||||
case PKEY_KEYTYPE_AES_256:
|
||||
keysize = 32;
|
||||
break;
|
||||
default:
|
||||
DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
|
||||
keytype);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* generate a dummy random clear key */
|
||||
get_random_bytes(clrkey.clrkey, keysize);
|
||||
|
||||
/* convert it to a dummy protected key */
|
||||
rc = pkey_clr2protkey(keytype, &clrkey, protkey);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* replace the key part of the protected key with random bytes */
|
||||
get_random_bytes(protkey->protkey, keysize);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pkey_genprotkey);
|
||||
|
||||
/*
|
||||
* Verify if a protected key is still valid
|
||||
*/
|
||||
int pkey_verifyprotkey(const struct pkey_protkey *protkey)
|
||||
{
|
||||
unsigned long fc;
|
||||
struct {
|
||||
u8 iv[AES_BLOCK_SIZE];
|
||||
u8 key[MAXPROTKEYSIZE];
|
||||
} param;
|
||||
u8 null_msg[AES_BLOCK_SIZE];
|
||||
u8 dest_buf[AES_BLOCK_SIZE];
|
||||
unsigned int k;
|
||||
|
||||
switch (protkey->type) {
|
||||
case PKEY_KEYTYPE_AES_128:
|
||||
fc = CPACF_KMC_PAES_128;
|
||||
break;
|
||||
case PKEY_KEYTYPE_AES_192:
|
||||
fc = CPACF_KMC_PAES_192;
|
||||
break;
|
||||
case PKEY_KEYTYPE_AES_256:
|
||||
fc = CPACF_KMC_PAES_256;
|
||||
break;
|
||||
default:
|
||||
DEBUG_ERR("%s unknown/unsupported keytype %d\n", __func__,
|
||||
protkey->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(null_msg, 0, sizeof(null_msg));
|
||||
|
||||
memset(param.iv, 0, sizeof(param.iv));
|
||||
memcpy(param.key, protkey->protkey, sizeof(param.key));
|
||||
|
||||
k = cpacf_kmc(fc | CPACF_ENCRYPT, ¶m, null_msg, dest_buf,
|
||||
sizeof(null_msg));
|
||||
if (k != sizeof(null_msg)) {
|
||||
DEBUG_ERR("%s protected key is not valid\n", __func__);
|
||||
return -EKEYREJECTED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(pkey_verifyprotkey);
|
||||
|
||||
/*
|
||||
* Transform a non-CCA key token into a protected key
|
||||
*/
|
||||
static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen,
|
||||
struct pkey_protkey *protkey)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
struct protaeskeytoken *t;
|
||||
|
||||
switch (hdr->version) {
|
||||
case TOKVER_PROTECTED_KEY:
|
||||
if (keylen != sizeof(struct protaeskeytoken))
|
||||
return -EINVAL;
|
||||
|
||||
t = (struct protaeskeytoken *)key;
|
||||
protkey->len = t->len;
|
||||
protkey->type = t->keytype;
|
||||
memcpy(protkey->protkey, t->protkey,
|
||||
sizeof(protkey->protkey));
|
||||
|
||||
return pkey_verifyprotkey(protkey);
|
||||
default:
|
||||
DEBUG_ERR("%s unknown/unsupported non-CCA token version %d\n",
|
||||
__func__, hdr->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a CCA internal key token into a protected key
|
||||
*/
|
||||
static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen,
|
||||
struct pkey_protkey *protkey)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
|
||||
switch (hdr->version) {
|
||||
case TOKVER_CCA_AES:
|
||||
if (keylen != sizeof(struct secaeskeytoken))
|
||||
return -EINVAL;
|
||||
|
||||
return pkey_skey2pkey((struct pkey_seckey *)key,
|
||||
protkey);
|
||||
default:
|
||||
DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n",
|
||||
__func__, hdr->version);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a key blob (of any type) into a protected key
|
||||
*/
|
||||
int pkey_keyblob2pkey(const __u8 *key, __u32 keylen,
|
||||
struct pkey_protkey *protkey)
|
||||
{
|
||||
struct keytoken_header *hdr = (struct keytoken_header *)key;
|
||||
|
||||
if (keylen < sizeof(struct keytoken_header))
|
||||
return -EINVAL;
|
||||
|
||||
switch (hdr->type) {
|
||||
case TOKTYPE_NON_CCA:
|
||||
return pkey_nonccatok2pkey(key, keylen, protkey);
|
||||
case TOKTYPE_CCA_INTERNAL:
|
||||
return pkey_ccainttok2pkey(key, keylen, protkey);
|
||||
default:
|
||||
DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__,
|
||||
hdr->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(pkey_keyblob2pkey);
|
||||
|
||||
/*
|
||||
* File io functions
|
||||
*/
|
||||
|
|
@ -1167,6 +1372,58 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
case PKEY_GENPROTK: {
|
||||
struct pkey_genprotk __user *ugp = (void __user *) arg;
|
||||
struct pkey_genprotk kgp;
|
||||
|
||||
if (copy_from_user(&kgp, ugp, sizeof(kgp)))
|
||||
return -EFAULT;
|
||||
rc = pkey_genprotkey(kgp.keytype, &kgp.protkey);
|
||||
DEBUG_DBG("%s pkey_genprotkey()=%d\n", __func__, rc);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(ugp, &kgp, sizeof(kgp)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
case PKEY_VERIFYPROTK: {
|
||||
struct pkey_verifyprotk __user *uvp = (void __user *) arg;
|
||||
struct pkey_verifyprotk kvp;
|
||||
|
||||
if (copy_from_user(&kvp, uvp, sizeof(kvp)))
|
||||
return -EFAULT;
|
||||
rc = pkey_verifyprotkey(&kvp.protkey);
|
||||
DEBUG_DBG("%s pkey_verifyprotkey()=%d\n", __func__, rc);
|
||||
break;
|
||||
}
|
||||
case PKEY_KBLOB2PROTK: {
|
||||
struct pkey_kblob2pkey __user *utp = (void __user *) arg;
|
||||
struct pkey_kblob2pkey ktp;
|
||||
__u8 __user *ukey;
|
||||
__u8 *kkey;
|
||||
|
||||
if (copy_from_user(&ktp, utp, sizeof(ktp)))
|
||||
return -EFAULT;
|
||||
if (ktp.keylen < MINKEYBLOBSIZE ||
|
||||
ktp.keylen > MAXKEYBLOBSIZE)
|
||||
return -EINVAL;
|
||||
ukey = ktp.key;
|
||||
kkey = kmalloc(ktp.keylen, GFP_KERNEL);
|
||||
if (kkey == NULL)
|
||||
return -ENOMEM;
|
||||
if (copy_from_user(kkey, ukey, ktp.keylen)) {
|
||||
kfree(kkey);
|
||||
return -EFAULT;
|
||||
}
|
||||
rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey);
|
||||
DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc);
|
||||
kfree(kkey);
|
||||
if (rc)
|
||||
break;
|
||||
if (copy_to_user(utp, &ktp, sizeof(ktp)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
/* unknown/unsupported ioctl cmd */
|
||||
return -ENOTTY;
|
||||
|
|
@ -1178,6 +1435,236 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
/*
|
||||
* Sysfs and file io operations
|
||||
*/
|
||||
|
||||
/*
|
||||
* Sysfs attribute read function for all protected key binary attributes.
|
||||
* The implementation can not deal with partial reads, because a new random
|
||||
* protected key blob is generated with each read. In case of partial reads
|
||||
* (i.e. off != 0 or count < key blob size) -EINVAL is returned.
|
||||
*/
|
||||
static ssize_t pkey_protkey_aes_attr_read(u32 keytype, bool is_xts, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
struct protaeskeytoken protkeytoken;
|
||||
struct pkey_protkey protkey;
|
||||
int rc;
|
||||
|
||||
if (off != 0 || count < sizeof(protkeytoken))
|
||||
return -EINVAL;
|
||||
if (is_xts)
|
||||
if (count < 2 * sizeof(protkeytoken))
|
||||
return -EINVAL;
|
||||
|
||||
memset(&protkeytoken, 0, sizeof(protkeytoken));
|
||||
protkeytoken.type = TOKTYPE_NON_CCA;
|
||||
protkeytoken.version = TOKVER_PROTECTED_KEY;
|
||||
protkeytoken.keytype = keytype;
|
||||
|
||||
rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
protkeytoken.len = protkey.len;
|
||||
memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
|
||||
|
||||
memcpy(buf, &protkeytoken, sizeof(protkeytoken));
|
||||
|
||||
if (is_xts) {
|
||||
rc = pkey_genprotkey(protkeytoken.keytype, &protkey);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
protkeytoken.len = protkey.len;
|
||||
memcpy(&protkeytoken.protkey, &protkey.protkey, protkey.len);
|
||||
|
||||
memcpy(buf + sizeof(protkeytoken), &protkeytoken,
|
||||
sizeof(protkeytoken));
|
||||
|
||||
return 2 * sizeof(protkeytoken);
|
||||
}
|
||||
|
||||
return sizeof(protkeytoken);
|
||||
}
|
||||
|
||||
static ssize_t protkey_aes_128_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t protkey_aes_192_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t protkey_aes_256_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t protkey_aes_128_xts_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t protkey_aes_256_xts_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_protkey_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static BIN_ATTR_RO(protkey_aes_128, sizeof(struct protaeskeytoken));
|
||||
static BIN_ATTR_RO(protkey_aes_192, sizeof(struct protaeskeytoken));
|
||||
static BIN_ATTR_RO(protkey_aes_256, sizeof(struct protaeskeytoken));
|
||||
static BIN_ATTR_RO(protkey_aes_128_xts, 2 * sizeof(struct protaeskeytoken));
|
||||
static BIN_ATTR_RO(protkey_aes_256_xts, 2 * sizeof(struct protaeskeytoken));
|
||||
|
||||
static struct bin_attribute *protkey_attrs[] = {
|
||||
&bin_attr_protkey_aes_128,
|
||||
&bin_attr_protkey_aes_192,
|
||||
&bin_attr_protkey_aes_256,
|
||||
&bin_attr_protkey_aes_128_xts,
|
||||
&bin_attr_protkey_aes_256_xts,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group protkey_attr_group = {
|
||||
.name = "protkey",
|
||||
.bin_attrs = protkey_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* Sysfs attribute read function for all secure key ccadata binary attributes.
|
||||
* The implementation can not deal with partial reads, because a new random
|
||||
* protected key blob is generated with each read. In case of partial reads
|
||||
* (i.e. off != 0 or count < key blob size) -EINVAL is returned.
|
||||
*/
|
||||
static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf,
|
||||
loff_t off, size_t count)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (off != 0 || count < sizeof(struct secaeskeytoken))
|
||||
return -EINVAL;
|
||||
if (is_xts)
|
||||
if (count < 2 * sizeof(struct secaeskeytoken))
|
||||
return -EINVAL;
|
||||
|
||||
rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (is_xts) {
|
||||
buf += sizeof(struct pkey_seckey);
|
||||
rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return 2 * sizeof(struct secaeskeytoken);
|
||||
}
|
||||
|
||||
return sizeof(struct secaeskeytoken);
|
||||
}
|
||||
|
||||
static ssize_t ccadata_aes_128_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ccadata_aes_192_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_192, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ccadata_aes_256_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, false, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ccadata_aes_128_xts_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_128, true, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static ssize_t ccadata_aes_256_xts_read(struct file *filp,
|
||||
struct kobject *kobj,
|
||||
struct bin_attribute *attr,
|
||||
char *buf, loff_t off,
|
||||
size_t count)
|
||||
{
|
||||
return pkey_ccadata_aes_attr_read(PKEY_KEYTYPE_AES_256, true, buf,
|
||||
off, count);
|
||||
}
|
||||
|
||||
static BIN_ATTR_RO(ccadata_aes_128, sizeof(struct secaeskeytoken));
|
||||
static BIN_ATTR_RO(ccadata_aes_192, sizeof(struct secaeskeytoken));
|
||||
static BIN_ATTR_RO(ccadata_aes_256, sizeof(struct secaeskeytoken));
|
||||
static BIN_ATTR_RO(ccadata_aes_128_xts, 2 * sizeof(struct secaeskeytoken));
|
||||
static BIN_ATTR_RO(ccadata_aes_256_xts, 2 * sizeof(struct secaeskeytoken));
|
||||
|
||||
static struct bin_attribute *ccadata_attrs[] = {
|
||||
&bin_attr_ccadata_aes_128,
|
||||
&bin_attr_ccadata_aes_192,
|
||||
&bin_attr_ccadata_aes_256,
|
||||
&bin_attr_ccadata_aes_128_xts,
|
||||
&bin_attr_ccadata_aes_256_xts,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group ccadata_attr_group = {
|
||||
.name = "ccadata",
|
||||
.bin_attrs = ccadata_attrs,
|
||||
};
|
||||
|
||||
static const struct attribute_group *pkey_attr_groups[] = {
|
||||
&protkey_attr_group,
|
||||
&ccadata_attr_group,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct file_operations pkey_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = nonseekable_open,
|
||||
|
|
@ -1190,6 +1677,7 @@ static struct miscdevice pkey_dev = {
|
|||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.mode = 0666,
|
||||
.fops = &pkey_fops,
|
||||
.groups = pkey_attr_groups,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -1197,14 +1685,23 @@ static struct miscdevice pkey_dev = {
|
|||
*/
|
||||
static int __init pkey_init(void)
|
||||
{
|
||||
cpacf_mask_t pckmo_functions;
|
||||
cpacf_mask_t kmc_functions;
|
||||
|
||||
/* check for pckmo instructions available */
|
||||
/*
|
||||
* The pckmo instruction should be available - even if we don't
|
||||
* actually invoke it. This instruction comes with MSA 3 which
|
||||
* is also the minimum level for the kmc instructions which
|
||||
* are able to work with protected keys.
|
||||
*/
|
||||
if (!cpacf_query(CPACF_PCKMO, &pckmo_functions))
|
||||
return -EOPNOTSUPP;
|
||||
if (!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_128_KEY) ||
|
||||
!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_192_KEY) ||
|
||||
!cpacf_test_func(&pckmo_functions, CPACF_PCKMO_ENC_AES_256_KEY))
|
||||
|
||||
/* check for kmc instructions available */
|
||||
if (!cpacf_query(CPACF_KMC, &kmc_functions))
|
||||
return -EOPNOTSUPP;
|
||||
if (!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_128) ||
|
||||
!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_192) ||
|
||||
!cpacf_test_func(&kmc_functions, CPACF_KMC_PAES_256))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
pkey_debug_init();
|
||||
|
|
@ -1222,5 +1719,5 @@ static void __exit pkey_exit(void)
|
|||
pkey_debug_exit();
|
||||
}
|
||||
|
||||
module_init(pkey_init);
|
||||
module_cpu_feature_match(MSA, pkey_init);
|
||||
module_exit(pkey_exit);
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Copyright IBM Corp. 2001, 2018
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
|
|
@ -11,6 +9,7 @@
|
|||
* Major cleanup & driver split: Martin Schwidefsky <schwidefsky@de.ibm.com>
|
||||
* Ralph Wuerthner <rwuerthn@de.ibm.com>
|
||||
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
|
||||
* Multiple device nodes: Harald Freudenberger <freude@linux.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
|
@ -24,6 +23,8 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/hw_random.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
|
|
@ -108,6 +109,375 @@ struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant)
|
|||
}
|
||||
EXPORT_SYMBOL(zcrypt_msgtype);
|
||||
|
||||
/*
|
||||
* Multi device nodes extension functions.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
|
||||
struct zcdn_device;
|
||||
|
||||
static struct class *zcrypt_class;
|
||||
static dev_t zcrypt_devt;
|
||||
static struct cdev zcrypt_cdev;
|
||||
|
||||
struct zcdn_device {
|
||||
struct device device;
|
||||
struct ap_perms perms;
|
||||
};
|
||||
|
||||
#define to_zcdn_dev(x) container_of((x), struct zcdn_device, device)
|
||||
|
||||
#define ZCDN_MAX_NAME 32
|
||||
|
||||
static int zcdn_create(const char *name);
|
||||
static int zcdn_destroy(const char *name);
|
||||
|
||||
/* helper function, matches the name for find_zcdndev_by_name() */
|
||||
static int __match_zcdn_name(struct device *dev, const void *data)
|
||||
{
|
||||
return strcmp(dev_name(dev), (const char *)data) == 0;
|
||||
}
|
||||
|
||||
/* helper function, matches the devt value for find_zcdndev_by_devt() */
|
||||
static int __match_zcdn_devt(struct device *dev, const void *data)
|
||||
{
|
||||
return dev->devt == *((dev_t *) data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find zcdn device by name.
|
||||
* Returns reference to the zcdn device which needs to be released
|
||||
* with put_device() after use.
|
||||
*/
|
||||
static inline struct zcdn_device *find_zcdndev_by_name(const char *name)
|
||||
{
|
||||
struct device *dev =
|
||||
class_find_device(zcrypt_class, NULL,
|
||||
(void *) name,
|
||||
__match_zcdn_name);
|
||||
|
||||
return dev ? to_zcdn_dev(dev) : NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find zcdn device by devt value.
|
||||
* Returns reference to the zcdn device which needs to be released
|
||||
* with put_device() after use.
|
||||
*/
|
||||
static inline struct zcdn_device *find_zcdndev_by_devt(dev_t devt)
|
||||
{
|
||||
struct device *dev =
|
||||
class_find_device(zcrypt_class, NULL,
|
||||
(void *) &devt,
|
||||
__match_zcdn_devt);
|
||||
|
||||
return dev ? to_zcdn_dev(dev) : NULL;
|
||||
}
|
||||
|
||||
static ssize_t ioctlmask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int i, rc;
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
for (i = 0; i < sizeof(zcdndev->perms.ioctlm) / sizeof(long); i++)
|
||||
snprintf(buf + 2 + 2 * i * sizeof(long),
|
||||
PAGE_SIZE - 2 - 2 * i * sizeof(long),
|
||||
"%016lx", zcdndev->perms.ioctlm[i]);
|
||||
buf[2 + 2 * i * sizeof(long)] = '\n';
|
||||
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
|
||||
rc = 2 + 2 * i * sizeof(long) + 1;
|
||||
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t ioctlmask_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
rc = ap_parse_mask_str(buf, zcdndev->perms.ioctlm,
|
||||
AP_IOCTLS, &ap_perms_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(ioctlmask);
|
||||
|
||||
static ssize_t apmask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int i, rc;
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
for (i = 0; i < sizeof(zcdndev->perms.apm) / sizeof(long); i++)
|
||||
snprintf(buf + 2 + 2 * i * sizeof(long),
|
||||
PAGE_SIZE - 2 - 2 * i * sizeof(long),
|
||||
"%016lx", zcdndev->perms.apm[i]);
|
||||
buf[2 + 2 * i * sizeof(long)] = '\n';
|
||||
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
|
||||
rc = 2 + 2 * i * sizeof(long) + 1;
|
||||
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t apmask_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
rc = ap_parse_mask_str(buf, zcdndev->perms.apm,
|
||||
AP_DEVICES, &ap_perms_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(apmask);
|
||||
|
||||
static ssize_t aqmask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int i, rc;
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
buf[0] = '0';
|
||||
buf[1] = 'x';
|
||||
for (i = 0; i < sizeof(zcdndev->perms.aqm) / sizeof(long); i++)
|
||||
snprintf(buf + 2 + 2 * i * sizeof(long),
|
||||
PAGE_SIZE - 2 - 2 * i * sizeof(long),
|
||||
"%016lx", zcdndev->perms.aqm[i]);
|
||||
buf[2 + 2 * i * sizeof(long)] = '\n';
|
||||
buf[2 + 2 * i * sizeof(long) + 1] = '\0';
|
||||
rc = 2 + 2 * i * sizeof(long) + 1;
|
||||
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t aqmask_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
rc = ap_parse_mask_str(buf, zcdndev->perms.aqm,
|
||||
AP_DOMAINS, &ap_perms_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(aqmask);
|
||||
|
||||
static struct attribute *zcdn_dev_attrs[] = {
|
||||
&dev_attr_ioctlmask.attr,
|
||||
&dev_attr_apmask.attr,
|
||||
&dev_attr_aqmask.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group zcdn_dev_attr_group = {
|
||||
.attrs = zcdn_dev_attrs
|
||||
};
|
||||
|
||||
static const struct attribute_group *zcdn_dev_attr_groups[] = {
|
||||
&zcdn_dev_attr_group,
|
||||
NULL
|
||||
};
|
||||
|
||||
static ssize_t zcdn_create_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
char name[ZCDN_MAX_NAME];
|
||||
|
||||
strncpy(name, skip_spaces(buf), sizeof(name));
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
|
||||
rc = zcdn_create(strim(name));
|
||||
|
||||
return rc ? rc : count;
|
||||
}
|
||||
|
||||
static const struct class_attribute class_attr_zcdn_create =
|
||||
__ATTR(create, 0600, NULL, zcdn_create_store);
|
||||
|
||||
static ssize_t zcdn_destroy_store(struct class *class,
|
||||
struct class_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc;
|
||||
char name[ZCDN_MAX_NAME];
|
||||
|
||||
strncpy(name, skip_spaces(buf), sizeof(name));
|
||||
name[sizeof(name) - 1] = '\0';
|
||||
|
||||
rc = zcdn_destroy(strim(name));
|
||||
|
||||
return rc ? rc : count;
|
||||
}
|
||||
|
||||
static const struct class_attribute class_attr_zcdn_destroy =
|
||||
__ATTR(destroy, 0600, NULL, zcdn_destroy_store);
|
||||
|
||||
static void zcdn_device_release(struct device *dev)
|
||||
{
|
||||
struct zcdn_device *zcdndev = to_zcdn_dev(dev);
|
||||
|
||||
ZCRYPT_DBF(DBF_INFO, "releasing zcdn device %d:%d\n",
|
||||
MAJOR(dev->devt), MINOR(dev->devt));
|
||||
|
||||
kfree(zcdndev);
|
||||
}
|
||||
|
||||
static int zcdn_create(const char *name)
|
||||
{
|
||||
dev_t devt;
|
||||
int i, rc = 0;
|
||||
char nodename[ZCDN_MAX_NAME];
|
||||
struct zcdn_device *zcdndev;
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* check if device node with this name already exists */
|
||||
if (name[0]) {
|
||||
zcdndev = find_zcdndev_by_name(name);
|
||||
if (zcdndev) {
|
||||
put_device(&zcdndev->device);
|
||||
rc = -EEXIST;
|
||||
goto unlockout;
|
||||
}
|
||||
}
|
||||
|
||||
/* find an unused minor number */
|
||||
for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
|
||||
devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
|
||||
zcdndev = find_zcdndev_by_devt(devt);
|
||||
if (zcdndev)
|
||||
put_device(&zcdndev->device);
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (i == ZCRYPT_MAX_MINOR_NODES) {
|
||||
rc = -ENOSPC;
|
||||
goto unlockout;
|
||||
}
|
||||
|
||||
/* alloc and prepare a new zcdn device */
|
||||
zcdndev = kzalloc(sizeof(*zcdndev), GFP_KERNEL);
|
||||
if (!zcdndev) {
|
||||
rc = -ENOMEM;
|
||||
goto unlockout;
|
||||
}
|
||||
zcdndev->device.release = zcdn_device_release;
|
||||
zcdndev->device.class = zcrypt_class;
|
||||
zcdndev->device.devt = devt;
|
||||
zcdndev->device.groups = zcdn_dev_attr_groups;
|
||||
if (name[0])
|
||||
strncpy(nodename, name, sizeof(nodename));
|
||||
else
|
||||
snprintf(nodename, sizeof(nodename),
|
||||
ZCRYPT_NAME "_%d", (int) MINOR(devt));
|
||||
nodename[sizeof(nodename)-1] = '\0';
|
||||
if (dev_set_name(&zcdndev->device, nodename)) {
|
||||
rc = -EINVAL;
|
||||
goto unlockout;
|
||||
}
|
||||
rc = device_register(&zcdndev->device);
|
||||
if (rc) {
|
||||
put_device(&zcdndev->device);
|
||||
goto unlockout;
|
||||
}
|
||||
|
||||
ZCRYPT_DBF(DBF_INFO, "created zcdn device %d:%d\n",
|
||||
MAJOR(devt), MINOR(devt));
|
||||
|
||||
unlockout:
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int zcdn_destroy(const char *name)
|
||||
{
|
||||
int rc = 0;
|
||||
struct zcdn_device *zcdndev;
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
/* try to find this zcdn device */
|
||||
zcdndev = find_zcdndev_by_name(name);
|
||||
if (!zcdndev) {
|
||||
rc = -ENOENT;
|
||||
goto unlockout;
|
||||
}
|
||||
|
||||
/*
|
||||
* The zcdn device is not hard destroyed. It is subject to
|
||||
* reference counting and thus just needs to be unregistered.
|
||||
*/
|
||||
put_device(&zcdndev->device);
|
||||
device_unregister(&zcdndev->device);
|
||||
|
||||
unlockout:
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void zcdn_destroy_all(void)
|
||||
{
|
||||
int i;
|
||||
dev_t devt;
|
||||
struct zcdn_device *zcdndev;
|
||||
|
||||
mutex_lock(&ap_perms_mutex);
|
||||
for (i = 0; i < ZCRYPT_MAX_MINOR_NODES; i++) {
|
||||
devt = MKDEV(MAJOR(zcrypt_devt), MINOR(zcrypt_devt) + i);
|
||||
zcdndev = find_zcdndev_by_devt(devt);
|
||||
if (zcdndev) {
|
||||
put_device(&zcdndev->device);
|
||||
device_unregister(&zcdndev->device);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* zcrypt_read (): Not supported beyond zcrypt 1.3.1.
|
||||
*
|
||||
|
|
@ -137,6 +507,23 @@ static ssize_t zcrypt_write(struct file *filp, const char __user *buf,
|
|||
*/
|
||||
static int zcrypt_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct ap_perms *perms = &ap_perms;
|
||||
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
if (filp->f_inode->i_cdev == &zcrypt_cdev) {
|
||||
struct zcdn_device *zcdndev;
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
|
||||
/* find returns a reference, no get_device() needed */
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
if (zcdndev)
|
||||
perms = &zcdndev->perms;
|
||||
}
|
||||
#endif
|
||||
filp->private_data = (void *) perms;
|
||||
|
||||
atomic_inc(&zcrypt_open_count);
|
||||
return nonseekable_open(inode, filp);
|
||||
}
|
||||
|
|
@ -148,10 +535,55 @@ static int zcrypt_open(struct inode *inode, struct file *filp)
|
|||
*/
|
||||
static int zcrypt_release(struct inode *inode, struct file *filp)
|
||||
{
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
if (filp->f_inode->i_cdev == &zcrypt_cdev) {
|
||||
struct zcdn_device *zcdndev;
|
||||
|
||||
if (mutex_lock_interruptible(&ap_perms_mutex))
|
||||
return -ERESTARTSYS;
|
||||
zcdndev = find_zcdndev_by_devt(filp->f_inode->i_rdev);
|
||||
mutex_unlock(&ap_perms_mutex);
|
||||
if (zcdndev) {
|
||||
/* 2 puts here: one for find, one for open */
|
||||
put_device(&zcdndev->device);
|
||||
put_device(&zcdndev->device);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
atomic_dec(&zcrypt_open_count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int zcrypt_check_ioctl(struct ap_perms *perms,
|
||||
unsigned int cmd)
|
||||
{
|
||||
int rc = -EPERM;
|
||||
int ioctlnr = (cmd & _IOC_NRMASK) >> _IOC_NRSHIFT;
|
||||
|
||||
if (ioctlnr > 0 && ioctlnr < AP_IOCTLS) {
|
||||
if (test_bit_inv(ioctlnr, perms->ioctlm))
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
ZCRYPT_DBF(DBF_WARN,
|
||||
"ioctl check failed: ioctlnr=0x%04x rc=%d\n",
|
||||
ioctlnr, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline bool zcrypt_check_card(struct ap_perms *perms, int card)
|
||||
{
|
||||
return test_bit_inv(card, perms->apm) ? true : false;
|
||||
}
|
||||
|
||||
static inline bool zcrypt_check_queue(struct ap_perms *perms, int queue)
|
||||
{
|
||||
return test_bit_inv(queue, perms->aqm) ? true : false;
|
||||
}
|
||||
|
||||
static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc,
|
||||
struct zcrypt_queue *zq,
|
||||
unsigned int weight)
|
||||
|
|
@ -213,7 +645,8 @@ static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq,
|
|||
/*
|
||||
* zcrypt ioctls.
|
||||
*/
|
||||
static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
|
||||
static long zcrypt_rsa_modexpo(struct ap_perms *perms,
|
||||
struct ica_rsa_modexpo *mex)
|
||||
{
|
||||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
|
|
@ -250,6 +683,9 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
|
|||
if (zc->min_mod_size > mex->inputdatalength ||
|
||||
zc->max_mod_size < mex->inputdatalength)
|
||||
continue;
|
||||
/* check if device node has admission for this card */
|
||||
if (!zcrypt_check_card(perms, zc->card->id))
|
||||
continue;
|
||||
/* get weight index of the card device */
|
||||
weight = zc->speed_rating[func_code];
|
||||
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
||||
|
|
@ -258,6 +694,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex)
|
|||
/* check if device is online and eligible */
|
||||
if (!zq->online || !zq->ops->rsa_modexpo)
|
||||
continue;
|
||||
/* check if device node has admission for this queue */
|
||||
if (!zcrypt_check_queue(perms,
|
||||
AP_QID_QUEUE(zq->queue->qid)))
|
||||
continue;
|
||||
if (zcrypt_queue_compare(zq, pref_zq,
|
||||
weight, pref_weight))
|
||||
continue;
|
||||
|
|
@ -287,7 +727,8 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
||||
static long zcrypt_rsa_crt(struct ap_perms *perms,
|
||||
struct ica_rsa_modexpo_crt *crt)
|
||||
{
|
||||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
|
|
@ -324,6 +765,9 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
|||
if (zc->min_mod_size > crt->inputdatalength ||
|
||||
zc->max_mod_size < crt->inputdatalength)
|
||||
continue;
|
||||
/* check if device node has admission for this card */
|
||||
if (!zcrypt_check_card(perms, zc->card->id))
|
||||
continue;
|
||||
/* get weight index of the card device */
|
||||
weight = zc->speed_rating[func_code];
|
||||
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
||||
|
|
@ -332,6 +776,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt)
|
|||
/* check if device is online and eligible */
|
||||
if (!zq->online || !zq->ops->rsa_modexpo_crt)
|
||||
continue;
|
||||
/* check if device node has admission for this queue */
|
||||
if (!zcrypt_check_queue(perms,
|
||||
AP_QID_QUEUE(zq->queue->qid)))
|
||||
continue;
|
||||
if (zcrypt_queue_compare(zq, pref_zq,
|
||||
weight, pref_weight))
|
||||
continue;
|
||||
|
|
@ -361,7 +809,8 @@ out:
|
|||
return rc;
|
||||
}
|
||||
|
||||
long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
||||
static long _zcrypt_send_cprb(struct ap_perms *perms,
|
||||
struct ica_xcRB *xcRB)
|
||||
{
|
||||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
|
|
@ -373,6 +822,7 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|||
|
||||
trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB);
|
||||
|
||||
xcRB->status = 0;
|
||||
ap_init_message(&ap_msg);
|
||||
rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain);
|
||||
if (rc)
|
||||
|
|
@ -389,6 +839,9 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|||
if (xcRB->user_defined != AUTOSELECT &&
|
||||
xcRB->user_defined != zc->card->id)
|
||||
continue;
|
||||
/* check if device node has admission for this card */
|
||||
if (!zcrypt_check_card(perms, zc->card->id))
|
||||
continue;
|
||||
/* get weight index of the card device */
|
||||
weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY];
|
||||
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
||||
|
|
@ -400,6 +853,10 @@ long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
|||
((*domain != (unsigned short) AUTOSELECT) &&
|
||||
(*domain != AP_QID_QUEUE(zq->queue->qid))))
|
||||
continue;
|
||||
/* check if device node has admission for this queue */
|
||||
if (!zcrypt_check_queue(perms,
|
||||
AP_QID_QUEUE(zq->queue->qid)))
|
||||
continue;
|
||||
if (zcrypt_queue_compare(zq, pref_zq,
|
||||
weight, pref_weight))
|
||||
continue;
|
||||
|
|
@ -433,6 +890,11 @@ out:
|
|||
AP_QID_CARD(qid), AP_QID_QUEUE(qid));
|
||||
return rc;
|
||||
}
|
||||
|
||||
long zcrypt_send_cprb(struct ica_xcRB *xcRB)
|
||||
{
|
||||
return _zcrypt_send_cprb(&ap_perms, xcRB);
|
||||
}
|
||||
EXPORT_SYMBOL(zcrypt_send_cprb);
|
||||
|
||||
static bool is_desired_ep11_card(unsigned int dev_id,
|
||||
|
|
@ -459,7 +921,8 @@ static bool is_desired_ep11_queue(unsigned int dev_qid,
|
|||
return false;
|
||||
}
|
||||
|
||||
static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
||||
static long zcrypt_send_ep11_cprb(struct ap_perms *perms,
|
||||
struct ep11_urb *xcrb)
|
||||
{
|
||||
struct zcrypt_card *zc, *pref_zc;
|
||||
struct zcrypt_queue *zq, *pref_zq;
|
||||
|
|
@ -510,6 +973,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
|||
if (targets &&
|
||||
!is_desired_ep11_card(zc->card->id, target_num, targets))
|
||||
continue;
|
||||
/* check if device node has admission for this card */
|
||||
if (!zcrypt_check_card(perms, zc->card->id))
|
||||
continue;
|
||||
/* get weight index of the card device */
|
||||
weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY];
|
||||
if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight))
|
||||
|
|
@ -522,6 +988,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
|
|||
!is_desired_ep11_queue(zq->queue->qid,
|
||||
target_num, targets)))
|
||||
continue;
|
||||
/* check if device node has admission for this queue */
|
||||
if (!zcrypt_check_queue(perms,
|
||||
AP_QID_QUEUE(zq->queue->qid)))
|
||||
continue;
|
||||
if (zcrypt_queue_compare(zq, pref_zq,
|
||||
weight, pref_weight))
|
||||
continue;
|
||||
|
|
@ -788,7 +1258,13 @@ static int zcrypt_requestq_count(void)
|
|||
static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc;
|
||||
struct ap_perms *perms =
|
||||
(struct ap_perms *) filp->private_data;
|
||||
|
||||
rc = zcrypt_check_ioctl(perms, cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
switch (cmd) {
|
||||
case ICARSAMODEXPO: {
|
||||
|
|
@ -798,12 +1274,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
if (copy_from_user(&mex, umex, sizeof(mex)))
|
||||
return -EFAULT;
|
||||
do {
|
||||
rc = zcrypt_rsa_modexpo(&mex);
|
||||
rc = zcrypt_rsa_modexpo(perms, &mex);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_rsa_modexpo(&mex);
|
||||
rc = zcrypt_rsa_modexpo(perms, &mex);
|
||||
} while (rc == -EAGAIN);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSAMODEXPO rc=%d\n", rc);
|
||||
|
|
@ -818,12 +1294,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
if (copy_from_user(&crt, ucrt, sizeof(crt)))
|
||||
return -EFAULT;
|
||||
do {
|
||||
rc = zcrypt_rsa_crt(&crt);
|
||||
rc = zcrypt_rsa_crt(perms, &crt);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_rsa_crt(&crt);
|
||||
rc = zcrypt_rsa_crt(perms, &crt);
|
||||
} while (rc == -EAGAIN);
|
||||
if (rc) {
|
||||
ZCRYPT_DBF(DBF_DEBUG, "ioctl ICARSACRT rc=%d\n", rc);
|
||||
|
|
@ -838,15 +1314,16 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
if (copy_from_user(&xcRB, uxcRB, sizeof(xcRB)))
|
||||
return -EFAULT;
|
||||
do {
|
||||
rc = zcrypt_send_cprb(&xcRB);
|
||||
rc = _zcrypt_send_cprb(perms, &xcRB);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_send_cprb(&xcRB);
|
||||
rc = _zcrypt_send_cprb(perms, &xcRB);
|
||||
} while (rc == -EAGAIN);
|
||||
if (rc)
|
||||
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d\n", rc);
|
||||
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDCPRB rc=%d status=0x%x\n",
|
||||
rc, xcRB.status);
|
||||
if (copy_to_user(uxcRB, &xcRB, sizeof(xcRB)))
|
||||
return -EFAULT;
|
||||
return rc;
|
||||
|
|
@ -858,12 +1335,12 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd,
|
|||
if (copy_from_user(&xcrb, uxcrb, sizeof(xcrb)))
|
||||
return -EFAULT;
|
||||
do {
|
||||
rc = zcrypt_send_ep11_cprb(&xcrb);
|
||||
rc = zcrypt_send_ep11_cprb(perms, &xcrb);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_send_ep11_cprb(&xcrb);
|
||||
rc = zcrypt_send_ep11_cprb(perms, &xcrb);
|
||||
} while (rc == -EAGAIN);
|
||||
if (rc)
|
||||
ZCRYPT_DBF(DBF_DEBUG, "ioctl ZSENDEP11CPRB rc=%d\n", rc);
|
||||
|
|
@ -989,8 +1466,8 @@ struct compat_ica_rsa_modexpo {
|
|||
compat_uptr_t n_modulus;
|
||||
};
|
||||
|
||||
static long trans_modexpo32(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
static long trans_modexpo32(struct ap_perms *perms, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct compat_ica_rsa_modexpo __user *umex32 = compat_ptr(arg);
|
||||
struct compat_ica_rsa_modexpo mex32;
|
||||
|
|
@ -1006,12 +1483,12 @@ static long trans_modexpo32(struct file *filp, unsigned int cmd,
|
|||
mex64.b_key = compat_ptr(mex32.b_key);
|
||||
mex64.n_modulus = compat_ptr(mex32.n_modulus);
|
||||
do {
|
||||
rc = zcrypt_rsa_modexpo(&mex64);
|
||||
rc = zcrypt_rsa_modexpo(perms, &mex64);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_rsa_modexpo(&mex64);
|
||||
rc = zcrypt_rsa_modexpo(perms, &mex64);
|
||||
} while (rc == -EAGAIN);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -1031,8 +1508,8 @@ struct compat_ica_rsa_modexpo_crt {
|
|||
compat_uptr_t u_mult_inv;
|
||||
};
|
||||
|
||||
static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
static long trans_modexpo_crt32(struct ap_perms *perms, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct compat_ica_rsa_modexpo_crt __user *ucrt32 = compat_ptr(arg);
|
||||
struct compat_ica_rsa_modexpo_crt crt32;
|
||||
|
|
@ -1051,12 +1528,12 @@ static long trans_modexpo_crt32(struct file *filp, unsigned int cmd,
|
|||
crt64.nq_prime = compat_ptr(crt32.nq_prime);
|
||||
crt64.u_mult_inv = compat_ptr(crt32.u_mult_inv);
|
||||
do {
|
||||
rc = zcrypt_rsa_crt(&crt64);
|
||||
rc = zcrypt_rsa_crt(perms, &crt64);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_rsa_crt(&crt64);
|
||||
rc = zcrypt_rsa_crt(perms, &crt64);
|
||||
} while (rc == -EAGAIN);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
|
@ -1084,8 +1561,8 @@ struct compat_ica_xcRB {
|
|||
unsigned int status;
|
||||
} __packed;
|
||||
|
||||
static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
static long trans_xcRB32(struct ap_perms *perms, struct file *filp,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct compat_ica_xcRB __user *uxcRB32 = compat_ptr(arg);
|
||||
struct compat_ica_xcRB xcRB32;
|
||||
|
|
@ -1115,12 +1592,12 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
|||
xcRB64.priority_window = xcRB32.priority_window;
|
||||
xcRB64.status = xcRB32.status;
|
||||
do {
|
||||
rc = zcrypt_send_cprb(&xcRB64);
|
||||
rc = _zcrypt_send_cprb(perms, &xcRB64);
|
||||
} while (rc == -EAGAIN);
|
||||
/* on failure: retry once again after a requested rescan */
|
||||
if ((rc == -ENODEV) && (zcrypt_process_rescan()))
|
||||
do {
|
||||
rc = zcrypt_send_cprb(&xcRB64);
|
||||
rc = _zcrypt_send_cprb(perms, &xcRB64);
|
||||
} while (rc == -EAGAIN);
|
||||
xcRB32.reply_control_blk_length = xcRB64.reply_control_blk_length;
|
||||
xcRB32.reply_data_length = xcRB64.reply_data_length;
|
||||
|
|
@ -1133,12 +1610,20 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
|
|||
static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int rc;
|
||||
struct ap_perms *perms =
|
||||
(struct ap_perms *) filp->private_data;
|
||||
|
||||
rc = zcrypt_check_ioctl(perms, cmd);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (cmd == ICARSAMODEXPO)
|
||||
return trans_modexpo32(filp, cmd, arg);
|
||||
return trans_modexpo32(perms, filp, cmd, arg);
|
||||
if (cmd == ICARSACRT)
|
||||
return trans_modexpo_crt32(filp, cmd, arg);
|
||||
return trans_modexpo_crt32(perms, filp, cmd, arg);
|
||||
if (cmd == ZSECSENDCPRB)
|
||||
return trans_xcRB32(filp, cmd, arg);
|
||||
return trans_xcRB32(perms, filp, cmd, arg);
|
||||
return zcrypt_unlocked_ioctl(filp, cmd, arg);
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1256,6 +1741,67 @@ void zcrypt_debug_exit(void)
|
|||
debug_unregister(zcrypt_dbf_info);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
|
||||
static int __init zcdn_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* create a new class 'zcrypt' */
|
||||
zcrypt_class = class_create(THIS_MODULE, ZCRYPT_NAME);
|
||||
if (IS_ERR(zcrypt_class)) {
|
||||
rc = PTR_ERR(zcrypt_class);
|
||||
goto out_class_create_failed;
|
||||
}
|
||||
zcrypt_class->dev_release = zcdn_device_release;
|
||||
|
||||
/* alloc device minor range */
|
||||
rc = alloc_chrdev_region(&zcrypt_devt,
|
||||
0, ZCRYPT_MAX_MINOR_NODES,
|
||||
ZCRYPT_NAME);
|
||||
if (rc)
|
||||
goto out_alloc_chrdev_failed;
|
||||
|
||||
cdev_init(&zcrypt_cdev, &zcrypt_fops);
|
||||
zcrypt_cdev.owner = THIS_MODULE;
|
||||
rc = cdev_add(&zcrypt_cdev, zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
|
||||
if (rc)
|
||||
goto out_cdev_add_failed;
|
||||
|
||||
/* need some class specific sysfs attributes */
|
||||
rc = class_create_file(zcrypt_class, &class_attr_zcdn_create);
|
||||
if (rc)
|
||||
goto out_class_create_file_1_failed;
|
||||
rc = class_create_file(zcrypt_class, &class_attr_zcdn_destroy);
|
||||
if (rc)
|
||||
goto out_class_create_file_2_failed;
|
||||
|
||||
return 0;
|
||||
|
||||
out_class_create_file_2_failed:
|
||||
class_remove_file(zcrypt_class, &class_attr_zcdn_create);
|
||||
out_class_create_file_1_failed:
|
||||
cdev_del(&zcrypt_cdev);
|
||||
out_cdev_add_failed:
|
||||
unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
|
||||
out_alloc_chrdev_failed:
|
||||
class_destroy(zcrypt_class);
|
||||
out_class_create_failed:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void zcdn_exit(void)
|
||||
{
|
||||
class_remove_file(zcrypt_class, &class_attr_zcdn_create);
|
||||
class_remove_file(zcrypt_class, &class_attr_zcdn_destroy);
|
||||
zcdn_destroy_all();
|
||||
cdev_del(&zcrypt_cdev);
|
||||
unregister_chrdev_region(zcrypt_devt, ZCRYPT_MAX_MINOR_NODES);
|
||||
class_destroy(zcrypt_class);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* zcrypt_api_init(): Module initialization.
|
||||
*
|
||||
|
|
@ -1269,15 +1815,27 @@ int __init zcrypt_api_init(void)
|
|||
if (rc)
|
||||
goto out;
|
||||
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
rc = zcdn_init();
|
||||
if (rc)
|
||||
goto out;
|
||||
#endif
|
||||
|
||||
/* Register the request sprayer. */
|
||||
rc = misc_register(&zcrypt_misc_device);
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
goto out_misc_register_failed;
|
||||
|
||||
zcrypt_msgtype6_init();
|
||||
zcrypt_msgtype50_init();
|
||||
|
||||
return 0;
|
||||
|
||||
out_misc_register_failed:
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
zcdn_exit();
|
||||
#endif
|
||||
zcrypt_debug_exit();
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1289,6 +1847,9 @@ out:
|
|||
*/
|
||||
void __exit zcrypt_api_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_ZCRYPT_MULTIDEVNODES
|
||||
zcdn_exit();
|
||||
#endif
|
||||
misc_deregister(&zcrypt_misc_device);
|
||||
zcrypt_msgtype6_exit();
|
||||
zcrypt_msgtype50_exit();
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Copyright IBM Corp. 2001, 2018
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
* Cornelia Huck <cornelia.huck@de.ibm.com>
|
||||
|
|
@ -22,17 +20,8 @@
|
|||
#include "ap_bus.h"
|
||||
|
||||
/**
|
||||
* device type for an actual device is either PCICA, PCICC, PCIXCC_MCL2,
|
||||
* PCIXCC_MCL3, CEX2C, or CEX2A
|
||||
*
|
||||
* NOTE: PCIXCC_MCL3 refers to a PCIXCC with May 2004 version of Licensed
|
||||
* Internal Code (LIC) (EC J12220 level 29).
|
||||
* PCIXCC_MCL2 refers to any LIC before this level.
|
||||
* Supported device types
|
||||
*/
|
||||
#define ZCRYPT_PCICA 1
|
||||
#define ZCRYPT_PCICC 2
|
||||
#define ZCRYPT_PCIXCC_MCL2 3
|
||||
#define ZCRYPT_PCIXCC_MCL3 4
|
||||
#define ZCRYPT_CEX2C 5
|
||||
#define ZCRYPT_CEX2A 6
|
||||
#define ZCRYPT_CEX3C 7
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2006
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
@ -43,8 +41,8 @@
|
|||
#define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME
|
||||
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \
|
||||
"Copyright IBM Corp. 2001, 2012");
|
||||
MODULE_DESCRIPTION("CEX2A/CEX3A Cryptographic Coprocessor device driver, " \
|
||||
"Copyright IBM Corp. 2001, 2018");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct ap_device_id zcrypt_cex2a_card_ids[] = {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2006
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
@ -14,7 +12,7 @@
|
|||
#define _ZCRYPT_CEX2A_H_
|
||||
|
||||
/**
|
||||
* The type 50 message family is associated with a CEX2A card.
|
||||
* The type 50 message family is associated with CEXxA cards.
|
||||
*
|
||||
* The four members of the family are described below.
|
||||
*
|
||||
|
|
@ -111,7 +109,7 @@ struct type50_crb3_msg {
|
|||
} __packed;
|
||||
|
||||
/**
|
||||
* The type 80 response family is associated with a CEX2A card.
|
||||
* The type 80 response family is associated with a CEXxA cards.
|
||||
*
|
||||
* Note that all unsigned char arrays are right-justified and left-padded
|
||||
* with zeroes.
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Copyright IBM Corp. 2001, 2018
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
*
|
||||
|
|
@ -25,39 +23,22 @@
|
|||
#include "zcrypt_api.h"
|
||||
#include "zcrypt_error.h"
|
||||
#include "zcrypt_msgtype6.h"
|
||||
#include "zcrypt_pcixcc.h"
|
||||
#include "zcrypt_cex2c.h"
|
||||
#include "zcrypt_cca_key.h"
|
||||
|
||||
#define PCIXCC_MIN_MOD_SIZE 16 /* 128 bits */
|
||||
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
|
||||
#define PCIXCC_MAX_MOD_SIZE 256 /* 2048 bits */
|
||||
#define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE
|
||||
#define CEX2C_MIN_MOD_SIZE 16 /* 128 bits */
|
||||
#define CEX2C_MAX_MOD_SIZE 256 /* 2048 bits */
|
||||
#define CEX3C_MIN_MOD_SIZE 16 /* 128 bits */
|
||||
#define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */
|
||||
|
||||
#define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */
|
||||
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
|
||||
|
||||
#define PCIXCC_MAX_XCRB_MESSAGE_SIZE (12*1024)
|
||||
|
||||
#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
|
||||
#define CEX2C_MAX_XCRB_MESSAGE_SIZE (12*1024)
|
||||
#define CEX2C_CLEANUP_TIME (15*HZ)
|
||||
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \
|
||||
"Copyright IBM Corp. 2001, 2012");
|
||||
MODULE_DESCRIPTION("CEX2C/CEX3C Cryptographic Coprocessor device driver, " \
|
||||
"Copyright IBM Corp. 2001, 2018");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
|
||||
{ .dev_type = AP_DEVICE_TYPE_PCIXCC,
|
||||
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
|
||||
static struct ap_device_id zcrypt_cex2c_card_ids[] = {
|
||||
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
|
||||
.match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE },
|
||||
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
|
||||
|
|
@ -65,11 +46,9 @@ static struct ap_device_id zcrypt_pcixcc_card_ids[] = {
|
|||
{ /* end of list */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids);
|
||||
MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_card_ids);
|
||||
|
||||
static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
|
||||
{ .dev_type = AP_DEVICE_TYPE_PCIXCC,
|
||||
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
|
||||
static struct ap_device_id zcrypt_cex2c_queue_ids[] = {
|
||||
{ .dev_type = AP_DEVICE_TYPE_CEX2C,
|
||||
.match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
|
||||
{ .dev_type = AP_DEVICE_TYPE_CEX3C,
|
||||
|
|
@ -77,16 +56,16 @@ static struct ap_device_id zcrypt_pcixcc_queue_ids[] = {
|
|||
{ /* end of list */ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids);
|
||||
MODULE_DEVICE_TABLE(ap, zcrypt_cex2c_queue_ids);
|
||||
|
||||
/**
|
||||
* Large random number detection function. Its sends a message to a pcixcc
|
||||
* Large random number detection function. Its sends a message to a CEX2C/CEX3C
|
||||
* card to find out if large random numbers are supported.
|
||||
* @ap_dev: pointer to the AP device.
|
||||
*
|
||||
* Returns 1 if large random numbers are supported, 0 if not and < 0 on error.
|
||||
*/
|
||||
static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq)
|
||||
static int zcrypt_cex2c_rng_supported(struct ap_queue *aq)
|
||||
{
|
||||
struct ap_message ap_msg;
|
||||
unsigned long long psmid;
|
||||
|
|
@ -147,13 +126,11 @@ out_free:
|
|||
}
|
||||
|
||||
/**
|
||||
* Probe function for PCIXCC/CEX2C card devices. 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.
|
||||
* Probe function for CEX2C/CEX3C card devices. It always accepts the
|
||||
* AP device since the bus_match already checked the hardware type.
|
||||
* @ap_dev: pointer to the AP card device.
|
||||
*/
|
||||
static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
|
||||
static int zcrypt_cex2c_card_probe(struct ap_device *ap_dev)
|
||||
{
|
||||
/*
|
||||
* Normalized speed ratings per crypto adapter
|
||||
|
|
@ -179,9 +156,9 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
|
|||
zc->type_string = "CEX2C";
|
||||
memcpy(zc->speed_rating, CEX2C_SPEED_IDX,
|
||||
sizeof(CEX2C_SPEED_IDX));
|
||||
zc->min_mod_size = PCIXCC_MIN_MOD_SIZE;
|
||||
zc->max_mod_size = PCIXCC_MAX_MOD_SIZE;
|
||||
zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE;
|
||||
zc->min_mod_size = CEX2C_MIN_MOD_SIZE;
|
||||
zc->max_mod_size = CEX2C_MAX_MOD_SIZE;
|
||||
zc->max_exp_bit_length = CEX2C_MAX_MOD_SIZE;
|
||||
break;
|
||||
case AP_DEVICE_TYPE_CEX3C:
|
||||
zc->user_space_type = ZCRYPT_CEX3C;
|
||||
|
|
@ -208,10 +185,10 @@ static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* This is called to remove the PCIXCC/CEX2C card driver information
|
||||
* This is called to remove the CEX2C/CEX3C card driver information
|
||||
* if an AP card device is removed.
|
||||
*/
|
||||
static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
|
||||
static void zcrypt_cex2c_card_remove(struct ap_device *ap_dev)
|
||||
{
|
||||
struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private;
|
||||
|
||||
|
|
@ -219,33 +196,31 @@ static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev)
|
|||
zcrypt_card_unregister(zc);
|
||||
}
|
||||
|
||||
static struct ap_driver zcrypt_pcixcc_card_driver = {
|
||||
.probe = zcrypt_pcixcc_card_probe,
|
||||
.remove = zcrypt_pcixcc_card_remove,
|
||||
.ids = zcrypt_pcixcc_card_ids,
|
||||
static struct ap_driver zcrypt_cex2c_card_driver = {
|
||||
.probe = zcrypt_cex2c_card_probe,
|
||||
.remove = zcrypt_cex2c_card_remove,
|
||||
.ids = zcrypt_cex2c_card_ids,
|
||||
.flags = AP_DRIVER_FLAG_DEFAULT,
|
||||
};
|
||||
|
||||
/**
|
||||
* Probe function for PCIXCC/CEX2C queue devices. 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.
|
||||
* Probe function for CEX2C/CEX3C queue devices. It always accepts the
|
||||
* AP device since the bus_match already checked the hardware type.
|
||||
* @ap_dev: pointer to the AP card device.
|
||||
*/
|
||||
static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
|
||||
static int zcrypt_cex2c_queue_probe(struct ap_device *ap_dev)
|
||||
{
|
||||
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
|
||||
struct zcrypt_queue *zq;
|
||||
int rc;
|
||||
|
||||
zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE);
|
||||
zq = zcrypt_queue_alloc(CEX2C_MAX_XCRB_MESSAGE_SIZE);
|
||||
if (!zq)
|
||||
return -ENOMEM;
|
||||
zq->queue = aq;
|
||||
zq->online = 1;
|
||||
atomic_set(&zq->load, 0);
|
||||
rc = zcrypt_pcixcc_rng_supported(aq);
|
||||
rc = zcrypt_cex2c_rng_supported(aq);
|
||||
if (rc < 0) {
|
||||
zcrypt_queue_free(zq);
|
||||
return rc;
|
||||
|
|
@ -257,7 +232,7 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
|
|||
zq->ops = zcrypt_msgtype(MSGTYPE06_NAME,
|
||||
MSGTYPE06_VARIANT_NORNG);
|
||||
ap_queue_init_reply(aq, &zq->reply);
|
||||
aq->request_timeout = PCIXCC_CLEANUP_TIME,
|
||||
aq->request_timeout = CEX2C_CLEANUP_TIME;
|
||||
aq->private = zq;
|
||||
rc = zcrypt_queue_register(zq);
|
||||
if (rc) {
|
||||
|
|
@ -268,10 +243,10 @@ static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* This is called to remove the PCIXCC/CEX2C queue driver information
|
||||
* This is called to remove the CEX2C/CEX3C queue driver information
|
||||
* if an AP queue device is removed.
|
||||
*/
|
||||
static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
|
||||
static void zcrypt_cex2c_queue_remove(struct ap_device *ap_dev)
|
||||
{
|
||||
struct ap_queue *aq = to_ap_queue(&ap_dev->device);
|
||||
struct zcrypt_queue *zq = aq->private;
|
||||
|
|
@ -281,37 +256,37 @@ static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev)
|
|||
zcrypt_queue_unregister(zq);
|
||||
}
|
||||
|
||||
static struct ap_driver zcrypt_pcixcc_queue_driver = {
|
||||
.probe = zcrypt_pcixcc_queue_probe,
|
||||
.remove = zcrypt_pcixcc_queue_remove,
|
||||
static struct ap_driver zcrypt_cex2c_queue_driver = {
|
||||
.probe = zcrypt_cex2c_queue_probe,
|
||||
.remove = zcrypt_cex2c_queue_remove,
|
||||
.suspend = ap_queue_suspend,
|
||||
.resume = ap_queue_resume,
|
||||
.ids = zcrypt_pcixcc_queue_ids,
|
||||
.ids = zcrypt_cex2c_queue_ids,
|
||||
.flags = AP_DRIVER_FLAG_DEFAULT,
|
||||
};
|
||||
|
||||
int __init zcrypt_pcixcc_init(void)
|
||||
int __init zcrypt_cex2c_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ap_driver_register(&zcrypt_pcixcc_card_driver,
|
||||
THIS_MODULE, "pcixcccard");
|
||||
rc = ap_driver_register(&zcrypt_cex2c_card_driver,
|
||||
THIS_MODULE, "cex2card");
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = ap_driver_register(&zcrypt_pcixcc_queue_driver,
|
||||
THIS_MODULE, "pcixccqueue");
|
||||
rc = ap_driver_register(&zcrypt_cex2c_queue_driver,
|
||||
THIS_MODULE, "cex2cqueue");
|
||||
if (rc)
|
||||
ap_driver_unregister(&zcrypt_pcixcc_card_driver);
|
||||
ap_driver_unregister(&zcrypt_cex2c_card_driver);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void zcrypt_pcixcc_exit(void)
|
||||
void zcrypt_cex2c_exit(void)
|
||||
{
|
||||
ap_driver_unregister(&zcrypt_pcixcc_queue_driver);
|
||||
ap_driver_unregister(&zcrypt_pcixcc_card_driver);
|
||||
ap_driver_unregister(&zcrypt_cex2c_queue_driver);
|
||||
ap_driver_unregister(&zcrypt_cex2c_card_driver);
|
||||
}
|
||||
|
||||
module_init(zcrypt_pcixcc_init);
|
||||
module_exit(zcrypt_pcixcc_exit);
|
||||
module_init(zcrypt_cex2c_init);
|
||||
module_exit(zcrypt_cex2c_exit);
|
||||
|
|
@ -1,8 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Copyright IBM Corp. 2001, 2018
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
*
|
||||
|
|
@ -11,10 +9,10 @@
|
|||
* MSGTYPE restruct: Holger Dengler <hd@linux.vnet.ibm.com>
|
||||
*/
|
||||
|
||||
#ifndef _ZCRYPT_PCIXCC_H_
|
||||
#define _ZCRYPT_PCIXCC_H_
|
||||
#ifndef _ZCRYPT_CEX2C_H_
|
||||
#define _ZCRYPT_CEX2C_H_
|
||||
|
||||
int zcrypt_pcixcc_init(void);
|
||||
void zcrypt_pcixcc_exit(void);
|
||||
int zcrypt_cex2c_init(void);
|
||||
void zcrypt_cex2c_exit(void);
|
||||
|
||||
#endif /* _ZCRYPT_PCIXCC_H_ */
|
||||
#endif /* _ZCRYPT_CEX2C_H_ */
|
||||
|
|
@ -37,8 +37,8 @@
|
|||
#define CEX4_CLEANUP_TIME (900*HZ)
|
||||
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \
|
||||
"Copyright IBM Corp. 2012");
|
||||
MODULE_DESCRIPTION("CEX4/CEX5/CEX6 Cryptographic Card device driver, " \
|
||||
"Copyright IBM Corp. 2018");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static struct ap_device_id zcrypt_cex4_card_ids[] = {
|
||||
|
|
@ -66,8 +66,9 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = {
|
|||
MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids);
|
||||
|
||||
/**
|
||||
* Probe function for CEX4 card device. It always accepts the AP device
|
||||
* since the bus_match already checked the hardware type.
|
||||
* Probe function for CEX4/CEX5/CEX6 card device. It always
|
||||
* accepts the AP device since the bus_match already checked
|
||||
* the hardware type.
|
||||
* @ap_dev: pointer to the AP device.
|
||||
*/
|
||||
static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
|
||||
|
|
@ -199,7 +200,7 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* This is called to remove the CEX4 card driver information
|
||||
* This is called to remove the CEX4/CEX5/CEX6 card driver information
|
||||
* if an AP card device is removed.
|
||||
*/
|
||||
static void zcrypt_cex4_card_remove(struct ap_device *ap_dev)
|
||||
|
|
@ -218,8 +219,9 @@ static struct ap_driver zcrypt_cex4_card_driver = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Probe function for CEX4 queue device. It always accepts the AP device
|
||||
* since the bus_match already checked the hardware type.
|
||||
* Probe function for CEX4/CEX5/CEX6 queue device. It always
|
||||
* accepts the AP device since the bus_match already checked
|
||||
* the hardware type.
|
||||
* @ap_dev: pointer to the AP device.
|
||||
*/
|
||||
static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
|
||||
|
|
@ -265,8 +267,8 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* This is called to remove the CEX4 queue driver information
|
||||
* if an AP queue device is removed.
|
||||
* This is called to remove the CEX4/CEX5/CEX6 queue driver
|
||||
* information if an AP queue device is removed.
|
||||
*/
|
||||
static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2006
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
@ -16,6 +14,7 @@
|
|||
#include <linux/atomic.h>
|
||||
#include "zcrypt_debug.h"
|
||||
#include "zcrypt_api.h"
|
||||
#include "zcrypt_msgtype6.h"
|
||||
|
||||
/**
|
||||
* Reply Messages
|
||||
|
|
@ -114,6 +113,27 @@ static inline int convert_error(struct zcrypt_queue *zq,
|
|||
card, queue, ehdr->reply_code);
|
||||
return -EAGAIN;
|
||||
case REP82_ERROR_TRANSPORT_FAIL:
|
||||
/* Card or infrastructure failure, disable card */
|
||||
atomic_set(&zcrypt_rescan_req, 1);
|
||||
zq->online = 0;
|
||||
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
|
||||
card, queue);
|
||||
/* For type 86 response show the apfs value (failure reason) */
|
||||
if (ehdr->type == TYPE86_RSP_CODE) {
|
||||
struct {
|
||||
struct type86_hdr hdr;
|
||||
struct type86_fmt2_ext fmt2;
|
||||
} __packed * head = reply->message;
|
||||
unsigned int apfs = *((u32 *)head->fmt2.apfs);
|
||||
|
||||
ZCRYPT_DBF(DBF_ERR,
|
||||
"device=%02x.%04x reply=0x%02x apfs=0x%x => online=0 rc=EAGAIN\n",
|
||||
card, queue, apfs, ehdr->reply_code);
|
||||
} else
|
||||
ZCRYPT_DBF(DBF_ERR,
|
||||
"device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n",
|
||||
card, queue, ehdr->reply_code);
|
||||
return -EAGAIN;
|
||||
case REP82_ERROR_MACHINE_FAILURE:
|
||||
// REP88_ERROR_MODULE_FAILURE // '10' CEX2A
|
||||
/* If a card fails disable it and repeat the request. */
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
@ -27,13 +25,13 @@
|
|||
#include "zcrypt_error.h"
|
||||
#include "zcrypt_msgtype50.h"
|
||||
|
||||
/* 4096 bits */
|
||||
/* >= CEX3A: 4096 bits */
|
||||
#define CEX3A_MAX_MOD_SIZE 512
|
||||
|
||||
/* max outputdatalength + type80_hdr */
|
||||
/* CEX2A: max outputdatalength + type80_hdr */
|
||||
#define CEX2A_MAX_RESPONSE_SIZE 0x110
|
||||
|
||||
/* 512 bit modulus, (max outputdatalength) + type80_hdr */
|
||||
/* >= CEX3A: 512 bit modulus, (max outputdatalength) + type80_hdr */
|
||||
#define CEX3A_MAX_RESPONSE_SIZE 0x210
|
||||
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
|
|
@ -42,7 +40,7 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
/**
|
||||
* The type 50 message family is associated with a CEX2A card.
|
||||
* The type 50 message family is associated with a CEXxA cards.
|
||||
*
|
||||
* The four members of the family are described below.
|
||||
*
|
||||
|
|
@ -139,7 +137,7 @@ struct type50_crb3_msg {
|
|||
} __packed;
|
||||
|
||||
/**
|
||||
* The type 80 response family is associated with a CEX2A card.
|
||||
* The type 80 response family is associated with a CEXxA cards.
|
||||
*
|
||||
* Note that all unsigned char arrays are right-justified and left-padded
|
||||
* with zeroes.
|
||||
|
|
@ -273,7 +271,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq,
|
|||
/*
|
||||
* CEX2A and CEX3A w/o FW update can handle requests up to
|
||||
* 256 byte modulus (2k keys).
|
||||
* CEX3A with FW update and CEX4A cards are able to handle
|
||||
* CEX3A with FW update and newer CEXxA cards are able to handle
|
||||
* 512 byte modulus (4k keys).
|
||||
*/
|
||||
if (mod_len <= 128) { /* up to 1024 bit key size */
|
||||
|
|
@ -356,7 +354,7 @@ static int convert_type80(struct zcrypt_queue *zq,
|
|||
unsigned char *data;
|
||||
|
||||
if (t80h->len < sizeof(*t80h) + outputdatalength) {
|
||||
/* The result is too short, the CEX2A card may not do that.. */
|
||||
/* The result is too short, the CEXxA card may not do that.. */
|
||||
zq->online = 0;
|
||||
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
|
||||
AP_QID_CARD(zq->queue->qid),
|
||||
|
|
@ -447,10 +445,10 @@ out:
|
|||
static atomic_t zcrypt_step = ATOMIC_INIT(0);
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the CEX2A
|
||||
* The request distributor calls this function if it picked the CEXxA
|
||||
* device to handle a modexpo request.
|
||||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* CEX2A device to the request distributor
|
||||
* CEXxA device to the request distributor
|
||||
* @mex: pointer to the modexpo request buffer
|
||||
*/
|
||||
static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq,
|
||||
|
|
@ -493,10 +491,10 @@ out_free:
|
|||
}
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the CEX2A
|
||||
* The request distributor calls this function if it picked the CEXxA
|
||||
* device to handle a modexpo_crt request.
|
||||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* CEX2A device to the request distributor
|
||||
* CEXxA device to the request distributor
|
||||
* @crt: pointer to the modexpoc_crt request buffer
|
||||
*/
|
||||
static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
@ -29,8 +27,7 @@
|
|||
#include "zcrypt_msgtype6.h"
|
||||
#include "zcrypt_cca_key.h"
|
||||
|
||||
#define PCIXCC_MIN_MOD_SIZE_OLD 64 /* 512 bits */
|
||||
#define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
|
||||
#define CEXXC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */
|
||||
|
||||
#define CEIL4(x) ((((x)+3)/4)*4)
|
||||
|
||||
|
|
@ -38,9 +35,9 @@ struct response_type {
|
|||
struct completion work;
|
||||
int type;
|
||||
};
|
||||
#define PCIXCC_RESPONSE_TYPE_ICA 0
|
||||
#define PCIXCC_RESPONSE_TYPE_XCRB 1
|
||||
#define PCIXCC_RESPONSE_TYPE_EP11 2
|
||||
#define CEXXC_RESPONSE_TYPE_ICA 0
|
||||
#define CEXXC_RESPONSE_TYPE_XCRB 1
|
||||
#define CEXXC_RESPONSE_TYPE_EP11 2
|
||||
|
||||
MODULE_AUTHOR("IBM Corporation");
|
||||
MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \
|
||||
|
|
@ -111,7 +108,7 @@ struct function_and_rules_block {
|
|||
} __packed;
|
||||
|
||||
/**
|
||||
* The following is used to initialize the CPRBX passed to the PCIXCC/CEX2C
|
||||
* The following is used to initialize the CPRBX passed to the CEXxC/CEXxP
|
||||
* card in a type6 message. The 3 fields that must be filled in at execution
|
||||
* time are req_parml, rpl_parml and usage_domain.
|
||||
* Everything about this interface is ascii/big-endian, since the
|
||||
|
|
@ -294,7 +291,7 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq,
|
|||
/* message header, cprbx and f&r */
|
||||
msg->hdr = static_type6_hdrX;
|
||||
msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
|
||||
msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
|
||||
msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
|
||||
|
||||
msg->cprbx = static_cprbx;
|
||||
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
|
||||
|
|
@ -364,7 +361,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq,
|
|||
/* message header, cprbx and f&r */
|
||||
msg->hdr = static_type6_hdrX;
|
||||
msg->hdr.ToCardLen1 = size - sizeof(msg->hdr);
|
||||
msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
|
||||
msg->hdr.FromCardLen1 = CEXXC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr);
|
||||
|
||||
msg->cprbx = static_cprbx;
|
||||
msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid);
|
||||
|
|
@ -658,16 +655,6 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
|
|||
(int) service_rc, (int) service_rs);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (service_rc == 8 && service_rs == 783) {
|
||||
zq->zcard->min_mod_size =
|
||||
PCIXCC_MIN_MOD_SIZE_OLD;
|
||||
ZCRYPT_DBF(DBF_DEBUG,
|
||||
"device=%02x.%04x rc/rs=%d/%d => rc=EAGAIN\n",
|
||||
AP_QID_CARD(zq->queue->qid),
|
||||
AP_QID_QUEUE(zq->queue->qid),
|
||||
(int) service_rc, (int) service_rs);
|
||||
return -EAGAIN;
|
||||
}
|
||||
zq->online = 0;
|
||||
pr_err("Cryptographic device %02x.%04x failed and was set offline\n",
|
||||
AP_QID_CARD(zq->queue->qid),
|
||||
|
|
@ -697,7 +684,7 @@ static int convert_type86_ica(struct zcrypt_queue *zq,
|
|||
if (pad_len > 0) {
|
||||
if (pad_len < 10)
|
||||
return -EINVAL;
|
||||
/* 'restore' padding left in the PCICC/PCIXCC card. */
|
||||
/* 'restore' padding left in the CEXXC card. */
|
||||
if (copy_to_user(outputdata, static_pad, pad_len - 1))
|
||||
return -EFAULT;
|
||||
if (put_user(0, outputdata + pad_len - 1))
|
||||
|
|
@ -955,13 +942,13 @@ static void zcrypt_msgtype6_receive(struct ap_queue *aq,
|
|||
if (t86r->hdr.type == TYPE86_RSP_CODE &&
|
||||
t86r->cprbx.cprb_ver_id == 0x02) {
|
||||
switch (resp_type->type) {
|
||||
case PCIXCC_RESPONSE_TYPE_ICA:
|
||||
case CEXXC_RESPONSE_TYPE_ICA:
|
||||
length = sizeof(struct type86x_reply)
|
||||
+ t86r->length - 2;
|
||||
length = min(PCIXCC_MAX_ICA_RESPONSE_SIZE, length);
|
||||
length = min(CEXXC_MAX_ICA_RESPONSE_SIZE, length);
|
||||
memcpy(msg->message, reply->message, length);
|
||||
break;
|
||||
case PCIXCC_RESPONSE_TYPE_XCRB:
|
||||
case CEXXC_RESPONSE_TYPE_XCRB:
|
||||
length = t86r->fmt2.offset2 + t86r->fmt2.count2;
|
||||
length = min(MSGTYPE06_MAX_MSG_SIZE, length);
|
||||
memcpy(msg->message, reply->message, length);
|
||||
|
|
@ -1004,7 +991,7 @@ static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq,
|
|||
if (t86r->hdr.type == TYPE86_RSP_CODE &&
|
||||
t86r->cprbx.cprb_ver_id == 0x04) {
|
||||
switch (resp_type->type) {
|
||||
case PCIXCC_RESPONSE_TYPE_EP11:
|
||||
case CEXXC_RESPONSE_TYPE_EP11:
|
||||
length = t86r->fmt2.offset1 + t86r->fmt2.count1;
|
||||
length = min(MSGTYPE06_MAX_MSG_SIZE, length);
|
||||
memcpy(msg->message, reply->message, length);
|
||||
|
|
@ -1022,10 +1009,10 @@ out:
|
|||
static atomic_t zcrypt_step = ATOMIC_INIT(0);
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the PCIXCC/CEX2C
|
||||
* The request distributor calls this function if it picked the CEXxC
|
||||
* device to handle a modexpo request.
|
||||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* PCIXCC/CEX2C device to the request distributor
|
||||
* CEXxC device to the request distributor
|
||||
* @mex: pointer to the modexpo request buffer
|
||||
*/
|
||||
static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
|
||||
|
|
@ -1033,7 +1020,7 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq,
|
|||
{
|
||||
struct ap_message ap_msg;
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_ICA,
|
||||
.type = CEXXC_RESPONSE_TYPE_ICA,
|
||||
};
|
||||
int rc;
|
||||
|
||||
|
|
@ -1066,10 +1053,10 @@ out_free:
|
|||
}
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the PCIXCC/CEX2C
|
||||
* The request distributor calls this function if it picked the CEXxC
|
||||
* device to handle a modexpo_crt request.
|
||||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* PCIXCC/CEX2C device to the request distributor
|
||||
* CEXxC device to the request distributor
|
||||
* @crt: pointer to the modexpoc_crt request buffer
|
||||
*/
|
||||
static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
|
||||
|
|
@ -1077,7 +1064,7 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq,
|
|||
{
|
||||
struct ap_message ap_msg;
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_ICA,
|
||||
.type = CEXXC_RESPONSE_TYPE_ICA,
|
||||
};
|
||||
int rc;
|
||||
|
||||
|
|
@ -1122,7 +1109,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
|
|||
unsigned int *func_code, unsigned short **dom)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_XCRB,
|
||||
.type = CEXXC_RESPONSE_TYPE_XCRB,
|
||||
};
|
||||
|
||||
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
|
||||
|
|
@ -1131,18 +1118,17 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB,
|
|||
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);
|
||||
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
|
||||
if (!ap_msg->private)
|
||||
return -ENOMEM;
|
||||
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
|
||||
return XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom);
|
||||
}
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the PCIXCC/CEX2C
|
||||
* The request distributor calls this function if it picked the CEXxC
|
||||
* device to handle a send_cprb request.
|
||||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* PCIXCC/CEX2C device to the request distributor
|
||||
* CEXxC device to the request distributor
|
||||
* @xcRB: pointer to the send_cprb request buffer
|
||||
*/
|
||||
static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq,
|
||||
|
|
@ -1178,7 +1164,7 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
|
|||
unsigned int *func_code)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_EP11,
|
||||
.type = CEXXC_RESPONSE_TYPE_EP11,
|
||||
};
|
||||
|
||||
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
|
||||
|
|
@ -1187,10 +1173,9 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb,
|
|||
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);
|
||||
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
|
||||
if (!ap_msg->private)
|
||||
return -ENOMEM;
|
||||
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
|
||||
return xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code);
|
||||
}
|
||||
|
||||
|
|
@ -1273,7 +1258,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
|
|||
unsigned int *domain)
|
||||
{
|
||||
struct response_type resp_type = {
|
||||
.type = PCIXCC_RESPONSE_TYPE_XCRB,
|
||||
.type = CEXXC_RESPONSE_TYPE_XCRB,
|
||||
};
|
||||
|
||||
ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL);
|
||||
|
|
@ -1282,10 +1267,9 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
|
|||
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);
|
||||
ap_msg->private = kmemdup(&resp_type, sizeof(resp_type), GFP_KERNEL);
|
||||
if (!ap_msg->private)
|
||||
return -ENOMEM;
|
||||
memcpy(ap_msg->private, &resp_type, sizeof(resp_type));
|
||||
|
||||
rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain);
|
||||
|
||||
|
|
@ -1294,10 +1278,10 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code,
|
|||
}
|
||||
|
||||
/**
|
||||
* The request distributor calls this function if it picked the PCIXCC/CEX2C
|
||||
* The request distributor calls this function if it picked the CEXxC
|
||||
* device to generate random data.
|
||||
* @zq: pointer to zcrypt_queue structure that identifies the
|
||||
* PCIXCC/CEX2C device to the request distributor
|
||||
* CEXxC device to the request distributor
|
||||
* @buffer: pointer to a memory page to return random data
|
||||
*/
|
||||
static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
|
||||
|
|
@ -1332,7 +1316,7 @@ static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq,
|
|||
}
|
||||
|
||||
/**
|
||||
* The crypto operations for a PCIXCC/CEX2C card.
|
||||
* The crypto operations for a CEXxC card.
|
||||
*/
|
||||
static struct zcrypt_ops zcrypt_msgtype6_norng_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
@ -24,7 +22,7 @@
|
|||
#define MSGTYPE06_MAX_MSG_SIZE (12*1024)
|
||||
|
||||
/**
|
||||
* The type 6 message family is associated with PCICC or PCIXCC cards.
|
||||
* The type 6 message family is associated with CEXxC/CEXxP cards.
|
||||
*
|
||||
* It contains a message header followed by a CPRB, both of which
|
||||
* are described below.
|
||||
|
|
@ -43,13 +41,8 @@ struct type6_hdr {
|
|||
unsigned int offset2; /* 0x00000000 */
|
||||
unsigned int offset3; /* 0x00000000 */
|
||||
unsigned int offset4; /* 0x00000000 */
|
||||
unsigned char agent_id[16]; /* PCICC: */
|
||||
/* 0x0100 */
|
||||
/* 0x4343412d4150504c202020 */
|
||||
/* 0x010101 */
|
||||
/* PCIXCC: */
|
||||
/* 0x4341000000000000 */
|
||||
/* 0x0000000000000000 */
|
||||
unsigned char agent_id[16]; /* 0x4341000000000000 */
|
||||
/* 0x0000000000000000 */
|
||||
unsigned char rqid[2]; /* rqid. internal to 603 */
|
||||
unsigned char reserved5[2]; /* 0x0000 */
|
||||
unsigned char function_code[2]; /* for PKD, 0x5044 (ascii 'PD') */
|
||||
|
|
@ -65,7 +58,7 @@ struct type6_hdr {
|
|||
} __packed;
|
||||
|
||||
/**
|
||||
* The type 86 message family is associated with PCICC and PCIXCC cards.
|
||||
* The type 86 message family is associated with CEXxC/CEXxP cards.
|
||||
*
|
||||
* It contains a message header followed by a CPRB. The CPRB is
|
||||
* the same as the request CPRB, which is described above.
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* zcrypt 2.1.0
|
||||
*
|
||||
* Copyright IBM Corp. 2001, 2012
|
||||
* Author(s): Robert Burroughs
|
||||
* Eric Rossman (edrossma@us.ibm.com)
|
||||
|
|
|
|||
Loading…
Reference in a new issue