From efc598e6c8a93491868ef7dc7c6fd28508898af2 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 11 Jun 2019 11:16:56 +0200 Subject: s390/zcrypt: move cca misc functions to new code file Rework of the pkey code. Moved all the cca generic code away from pkey_api.c into a new file zcrypt_ccamisc.c. This new file is now part of the zcrypt device driver and exports a bunch of cca functions to pkey and may be called from other kernel modules as well. The pkey ioctl API is unchanged. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/Makefile | 2 +- drivers/s390/crypto/pkey_api.c | 967 ++--------------------------------- drivers/s390/crypto/zcrypt_api.c | 2 + drivers/s390/crypto/zcrypt_ccamisc.c | 901 ++++++++++++++++++++++++++++++++ drivers/s390/crypto/zcrypt_ccamisc.h | 95 ++++ 5 files changed, 1036 insertions(+), 931 deletions(-) create mode 100644 drivers/s390/crypto/zcrypt_ccamisc.c create mode 100644 drivers/s390/crypto/zcrypt_ccamisc.h diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index 6ccd93d0b1cb..52aa95c8af4b 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -7,7 +7,7 @@ ap-objs := ap_bus.o ap_card.o ap_queue.o obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o # zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o -zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o +zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o zcrypt_ccamisc.o obj-$(CONFIG_ZCRYPT) += zcrypt.o # adapter drivers depend on ap.o and zcrypt.o obj-$(CONFIG_ZCRYPT) += zcrypt_cex2c.o zcrypt_cex2a.o zcrypt_cex4.o diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 7f418d2d8cdf..9f7c26b6ca04 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -24,17 +24,12 @@ #include #include "zcrypt_api.h" +#include "zcrypt_ccamisc.h" MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 protected key interface"); -/* Size of parameter block used for all cca requests/replies */ -#define PARMBSIZE 512 - -/* 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; @@ -62,40 +57,6 @@ 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 */ - u8 res0[3]; - u8 version; /* should be 0x04 */ - u8 res1[1]; - u8 flag; /* key flags */ - u8 res2[1]; - u64 mkvp; /* master key verification pattern */ - u8 key[32]; /* key value (encrypted) */ - u8 cv[8]; /* control vector */ - u16 bitsize; /* key bit size */ - u16 keysize; /* key byte size */ - 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 */ @@ -107,552 +68,6 @@ struct protaeskeytoken { 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 - * also checked. Returns 0 on success or errno value on failure. - */ -static int check_secaeskeytoken(const u8 *token, int keybitsize) -{ - struct secaeskeytoken *t = (struct secaeskeytoken *) token; - - if (t->type != TOKTYPE_CCA_INTERNAL) { - DEBUG_ERR( - "%s secure token check failed, type mismatch 0x%02x != 0x%02x\n", - __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); - return -EINVAL; - } - if (t->version != TOKVER_CCA_AES) { - DEBUG_ERR( - "%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) { - DEBUG_ERR( - "%s secure token check failed, bitsize mismatch %d != %d\n", - __func__, (int) t->bitsize, keybitsize); - return -EINVAL; - } - - return 0; -} - -/* - * Allocate consecutive memory for request CPRB, request param - * block, reply CPRB and reply param block and fill in values - * for the common fields. Returns 0 on success or errno value - * on failure. - */ -static int alloc_and_prep_cprbmem(size_t paramblen, - u8 **pcprbmem, - struct CPRBX **preqCPRB, - struct CPRBX **prepCPRB) -{ - u8 *cprbmem; - size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen; - struct CPRBX *preqcblk, *prepcblk; - - /* - * allocate consecutive memory for request CPRB, request param - * block, reply CPRB and reply param block - */ - cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); - if (!cprbmem) - return -ENOMEM; - - preqcblk = (struct CPRBX *) cprbmem; - prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen); - - /* fill request cprb struct */ - preqcblk->cprb_len = sizeof(struct CPRBX); - preqcblk->cprb_ver_id = 0x02; - memcpy(preqcblk->func_id, "T2", 2); - preqcblk->rpl_msgbl = cprbplusparamblen; - if (paramblen) { - preqcblk->req_parmb = - ((u8 *) preqcblk) + sizeof(struct CPRBX); - preqcblk->rpl_parmb = - ((u8 *) prepcblk) + sizeof(struct CPRBX); - } - - *pcprbmem = cprbmem; - *preqCPRB = preqcblk; - *prepCPRB = prepcblk; - - return 0; -} - -/* - * Free the cprb memory allocated with the function above. - * If the scrub value is not zero, the memory is filled - * with zeros before freeing (useful if there was some - * clear key material in there). - */ -static void free_cprbmem(void *mem, size_t paramblen, int scrub) -{ - if (scrub) - memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen)); - kfree(mem); -} - -/* - * Helper function to prepare the xcrb struct - */ -static inline void prep_xcrb(struct ica_xcRB *pxcrb, - u16 cardnr, - struct CPRBX *preqcblk, - struct CPRBX *prepcblk) -{ - memset(pxcrb, 0, sizeof(*pxcrb)); - pxcrb->agent_ID = 0x4341; /* 'CA' */ - pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); - pxcrb->request_control_blk_length = - preqcblk->cprb_len + preqcblk->req_parml; - pxcrb->request_control_blk_addr = (void __user *) preqcblk; - pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; - pxcrb->reply_control_blk_addr = (void __user *) prepcblk; -} - -/* - * Helper function which calls zcrypt_send_cprb with - * memory management segment adjusted to kernel space - * so that the copy_from_user called within this - * function do in fact copy from kernel space. - */ -static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb) -{ - int rc; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - rc = zcrypt_send_cprb(xcrb); - set_fs(old_fs); - - return rc; -} - -/* - * Generate (random) AES secure key. - */ -int pkey_genseckey(u16 cardnr, u16 domain, - u32 keytype, struct pkey_seckey *seckey) -{ - int i, rc, keysize; - int seckeysize; - u8 *mem; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct kgreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv1 { - u16 len; - char key_form[8]; - char key_length[8]; - char key_type1[8]; - char key_type2[8]; - } lv1; - struct lv2 { - u16 len; - struct keyid { - u16 len; - u16 attr; - u8 data[SECKEYBLOBSIZE]; - } keyid[6]; - } lv2; - } *preqparm; - struct kgrepparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv3 { - u16 len; - u16 keyblocklen; - struct { - u16 toklen; - u16 tokattr; - u8 tok[0]; - /* ... some more data ... */ - } keyblock; - } lv3; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with KG request */ - preqparm = (struct kgreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "KG", 2); - preqparm->rule_array_len = sizeof(preqparm->rule_array_len); - preqparm->lv1.len = sizeof(struct lv1); - memcpy(preqparm->lv1.key_form, "OP ", 8); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: - keysize = 16; - memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); - break; - case PKEY_KEYTYPE_AES_192: - keysize = 24; - memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); - break; - case PKEY_KEYTYPE_AES_256: - keysize = 32; - memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); - break; - default: - DEBUG_ERR( - "%s unknown/unsupported keytype %d\n", - __func__, keytype); - rc = -EINVAL; - goto out; - } - memcpy(preqparm->lv1.key_type1, "AESDATA ", 8); - preqparm->lv2.len = sizeof(struct lv2); - for (i = 0; i < 6; i++) { - preqparm->lv2.keyid[i].len = sizeof(struct keyid); - preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10); - } - preqcblk->req_parml = sizeof(struct kgreqparm); - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s secure key generate failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct kgrepparm *) prepcblk->rpl_parmb; - - /* check length of the returned secure key token */ - seckeysize = prepparm->lv3.keyblock.toklen - - sizeof(prepparm->lv3.keyblock.toklen) - - sizeof(prepparm->lv3.keyblock.tokattr); - if (seckeysize != SECKEYBLOBSIZE) { - DEBUG_ERR( - "%s secure token size mismatch %d != %d bytes\n", - __func__, seckeysize, SECKEYBLOBSIZE); - rc = -EIO; - goto out; - } - - /* check secure key token */ - rc = check_secaeskeytoken(prepparm->lv3.keyblock.tok, 8*keysize); - if (rc) { - rc = -EIO; - goto out; - } - - /* copy the generated secure key token */ - memcpy(seckey->seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); - -out: - free_cprbmem(mem, PARMBSIZE, 0); - return rc; -} -EXPORT_SYMBOL(pkey_genseckey); - -/* - * Generate an AES secure key with given key value. - */ -int pkey_clr2seckey(u16 cardnr, u16 domain, u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_seckey *seckey) -{ - int rc, keysize, seckeysize; - u8 *mem; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct cmreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - char rule_array[8]; - struct lv1 { - u16 len; - u8 clrkey[0]; - } lv1; - struct lv2 { - u16 len; - struct keyid { - u16 len; - u16 attr; - u8 data[SECKEYBLOBSIZE]; - } keyid; - } lv2; - } *preqparm; - struct lv2 *plv2; - struct cmrepparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv3 { - u16 len; - u16 keyblocklen; - struct { - u16 toklen; - u16 tokattr; - u8 tok[0]; - /* ... some more data ... */ - } keyblock; - } lv3; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with CM request */ - preqparm = (struct cmreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "CM", 2); - memcpy(preqparm->rule_array, "AES ", 8); - preqparm->rule_array_len = - sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); - 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); - rc = -EINVAL; - goto out; - } - preqparm->lv1.len = sizeof(struct lv1) + keysize; - memcpy(preqparm->lv1.clrkey, clrkey->clrkey, keysize); - plv2 = (struct lv2 *) (((u8 *) &preqparm->lv2) + keysize); - plv2->len = sizeof(struct lv2); - plv2->keyid.len = sizeof(struct keyid); - plv2->keyid.attr = 0x30; - preqcblk->req_parml = sizeof(struct cmreqparm) + keysize; - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s clear key import failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct cmrepparm *) prepcblk->rpl_parmb; - - /* check length of the returned secure key token */ - seckeysize = prepparm->lv3.keyblock.toklen - - sizeof(prepparm->lv3.keyblock.toklen) - - sizeof(prepparm->lv3.keyblock.tokattr); - if (seckeysize != SECKEYBLOBSIZE) { - DEBUG_ERR( - "%s secure token size mismatch %d != %d bytes\n", - __func__, seckeysize, SECKEYBLOBSIZE); - rc = -EIO; - goto out; - } - - /* check secure key token */ - rc = check_secaeskeytoken(prepparm->lv3.keyblock.tok, 8*keysize); - if (rc) { - rc = -EIO; - goto out; - } - - /* copy the generated secure key token */ - memcpy(seckey->seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); - -out: - free_cprbmem(mem, PARMBSIZE, 1); - return rc; -} -EXPORT_SYMBOL(pkey_clr2seckey); - -/* - * Derive a proteced key from the secure key blob. - */ -int pkey_sec2protkey(u16 cardnr, u16 domain, - const struct pkey_seckey *seckey, - struct pkey_protkey *protkey) -{ - int rc; - u8 *mem; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct uskreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv1 { - u16 len; - u16 attr_len; - u16 attr_flags; - } lv1; - struct lv2 { - u16 len; - u16 attr_len; - u16 attr_flags; - u8 token[0]; /* cca secure key token */ - } lv2 __packed; - } *preqparm; - struct uskrepparm { - u8 subfunc_code[2]; - u16 rule_array_len; - struct lv3 { - u16 len; - u16 attr_len; - u16 attr_flags; - struct cpacfkeyblock { - u8 version; /* version of this struct */ - u8 flags[2]; - u8 algo; - u8 form; - u8 pad1[3]; - u16 keylen; - u8 key[64]; /* the key (keylen bytes) */ - u16 keyattrlen; - u8 keyattr[32]; - u8 pad2[1]; - u8 vptype; - u8 vp[32]; /* verification pattern */ - } keyblock; - } lv3 __packed; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with USK request */ - preqparm = (struct uskreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "US", 2); - preqparm->rule_array_len = sizeof(preqparm->rule_array_len); - preqparm->lv1.len = sizeof(struct lv1); - preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len); - preqparm->lv1.attr_flags = 0x0001; - preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE; - preqparm->lv2.attr_len = sizeof(struct lv2) - - sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE; - preqparm->lv2.attr_flags = 0x0000; - memcpy(preqparm->lv2.token, seckey->seckey, SECKEYBLOBSIZE); - preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE; - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s unwrap secure key failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - if (prepcblk->ccp_rscode != 0) { - DEBUG_WARN( - "%s unwrap secure key warning, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct uskrepparm *) prepcblk->rpl_parmb; - - /* check the returned keyblock */ - if (prepparm->lv3.keyblock.version != 0x01) { - DEBUG_ERR( - "%s reply param keyblock version mismatch 0x%02x != 0x01\n", - __func__, (int) prepparm->lv3.keyblock.version); - rc = -EIO; - goto out; - } - - /* copy the tanslated protected key */ - switch (prepparm->lv3.keyblock.keylen) { - case 16+32: - protkey->type = PKEY_KEYTYPE_AES_128; - break; - case 24+32: - protkey->type = PKEY_KEYTYPE_AES_192; - break; - case 32+32: - protkey->type = PKEY_KEYTYPE_AES_256; - break; - default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", - __func__, prepparm->lv3.keyblock.keylen); - rc = -EIO; - goto out; - } - protkey->len = prepparm->lv3.keyblock.keylen; - memcpy(protkey->protkey, prepparm->lv3.keyblock.key, protkey->len); - -out: - free_cprbmem(mem, PARMBSIZE, 0); - return rc; -} -EXPORT_SYMBOL(pkey_sec2protkey); - /* * Create a protected key from a clear key value. */ @@ -709,336 +124,30 @@ int pkey_clr2protkey(u32 keytype, } EXPORT_SYMBOL(pkey_clr2protkey); -/* - * query cryptographic facility from adapter - */ -static int query_crypto_facility(u16 cardnr, u16 domain, - const char *keyword, - u8 *rarray, size_t *rarraylen, - u8 *varray, size_t *varraylen) -{ - int rc; - u16 len; - u8 *mem, *ptr; - struct CPRBX *preqcblk, *prepcblk; - struct ica_xcRB xcrb; - struct fqreqparm { - u8 subfunc_code[2]; - u16 rule_array_len; - char rule_array[8]; - struct lv1 { - u16 len; - u8 data[VARDATASIZE]; - } lv1; - u16 dummylen; - } *preqparm; - size_t parmbsize = sizeof(struct fqreqparm); - struct fqrepparm { - u8 subfunc_code[2]; - u8 lvdata[0]; - } *prepparm; - - /* get already prepared memory for 2 cprbs with param block each */ - rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk); - if (rc) - return rc; - - /* fill request cprb struct */ - preqcblk->domain = domain; - - /* fill request cprb param block with FQ request */ - preqparm = (struct fqreqparm *) preqcblk->req_parmb; - memcpy(preqparm->subfunc_code, "FQ", 2); - memcpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array)); - preqparm->rule_array_len = - sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); - preqparm->lv1.len = sizeof(preqparm->lv1); - preqparm->dummylen = sizeof(preqparm->dummylen); - preqcblk->req_parml = parmbsize; - - /* fill xcrb struct */ - prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); - - /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ - rc = _zcrypt_send_cprb(&xcrb); - if (rc) { - DEBUG_ERR( - "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed with errno %d\n", - __func__, (int) cardnr, (int) domain, rc); - goto out; - } - - /* check response returncode and reasoncode */ - if (prepcblk->ccp_rtcode != 0) { - DEBUG_ERR( - "%s unwrap secure key failure, card response %d/%d\n", - __func__, - (int) prepcblk->ccp_rtcode, - (int) prepcblk->ccp_rscode); - rc = -EIO; - goto out; - } - - /* process response cprb param block */ - prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); - prepparm = (struct fqrepparm *) prepcblk->rpl_parmb; - ptr = prepparm->lvdata; - - /* check and possibly copy reply rule array */ - len = *((u16 *) ptr); - if (len > sizeof(u16)) { - ptr += sizeof(u16); - len -= sizeof(u16); - if (rarray && rarraylen && *rarraylen > 0) { - *rarraylen = (len > *rarraylen ? *rarraylen : len); - memcpy(rarray, ptr, *rarraylen); - } - ptr += len; - } - /* check and possible copy reply var array */ - len = *((u16 *) ptr); - if (len > sizeof(u16)) { - ptr += sizeof(u16); - len -= sizeof(u16); - if (varray && varraylen && *varraylen > 0) { - *varraylen = (len > *varraylen ? *varraylen : len); - memcpy(varray, ptr, *varraylen); - } - ptr += len; - } - -out: - free_cprbmem(mem, parmbsize, 0); - return rc; -} - -/* - * Fetch the current and old mkvp values via - * query_crypto_facility from adapter. - */ -static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2]) -{ - int rc, found = 0; - size_t rlen, vlen; - u8 *rarray, *varray, *pg; - - pg = (u8 *) __get_free_page(GFP_KERNEL); - if (!pg) - return -ENOMEM; - rarray = pg; - varray = pg + PAGE_SIZE/2; - rlen = vlen = PAGE_SIZE/2; - - rc = query_crypto_facility(cardnr, domain, "STATICSA", - rarray, &rlen, varray, &vlen); - if (rc == 0 && rlen > 8*8 && vlen > 184+8) { - if (rarray[8*8] == '2') { - /* current master key state is valid */ - mkvp[0] = *((u64 *)(varray + 184)); - mkvp[1] = *((u64 *)(varray + 172)); - found = 1; - } - } - - free_page((unsigned long) pg); - - return found ? 0 : -ENOENT; -} - -/* struct to hold cached mkvp info for each card/domain */ -struct mkvp_info { - struct list_head list; - u16 cardnr; - u16 domain; - u64 mkvp[2]; -}; - -/* a list with mkvp_info entries */ -static LIST_HEAD(mkvp_list); -static DEFINE_SPINLOCK(mkvp_list_lock); - -static int mkvp_cache_fetch(u16 cardnr, u16 domain, u64 mkvp[2]) -{ - int rc = -ENOENT; - struct mkvp_info *ptr; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - memcpy(mkvp, ptr->mkvp, 2 * sizeof(u64)); - rc = 0; - break; - } - } - spin_unlock_bh(&mkvp_list_lock); - - return rc; -} - -static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2]) -{ - int found = 0; - struct mkvp_info *ptr; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); - found = 1; - break; - } - } - if (!found) { - ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); - if (!ptr) { - spin_unlock_bh(&mkvp_list_lock); - return; - } - ptr->cardnr = cardnr; - ptr->domain = domain; - memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); - list_add(&ptr->list, &mkvp_list); - } - spin_unlock_bh(&mkvp_list_lock); -} - -static void mkvp_cache_scrub(u16 cardnr, u16 domain) -{ - struct mkvp_info *ptr; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - list_del(&ptr->list); - kfree(ptr); - break; - } - } - spin_unlock_bh(&mkvp_list_lock); -} - -static void __exit mkvp_cache_free(void) -{ - struct mkvp_info *ptr, *pnext; - - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) { - list_del(&ptr->list); - kfree(ptr); - } - spin_unlock_bh(&mkvp_list_lock); -} - -/* - * Search for a matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. - */ -int pkey_findcard(const struct pkey_seckey *seckey, - u16 *pcardnr, u16 *pdomain, int verify) -{ - struct secaeskeytoken *t = (struct secaeskeytoken *) seckey; - struct zcrypt_device_status_ext *device_status; - u16 card, dom; - u64 mkvp[2]; - int i, rc, oi = -1; - - /* mkvp must not be zero */ - if (t->mkvp == 0) - return -EINVAL; - - /* fetch status of all crypto cards */ - device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, - sizeof(struct zcrypt_device_status_ext), - GFP_KERNEL); - if (!device_status) - return -ENOMEM; - zcrypt_device_status_mask_ext(device_status); - - /* walk through all crypto cards */ - for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { - card = AP_QID_CARD(device_status[i].qid); - dom = AP_QID_QUEUE(device_status[i].qid); - if (device_status[i].online && - device_status[i].functions & 0x04) { - /* an enabled CCA Coprocessor card */ - /* try cached mkvp */ - if (mkvp_cache_fetch(card, dom, mkvp) == 0 && - t->mkvp == mkvp[0]) { - if (!verify) - break; - /* verify: fetch mkvp from adapter */ - if (fetch_mkvp(card, dom, mkvp) == 0) { - mkvp_cache_update(card, dom, mkvp); - if (t->mkvp == mkvp[0]) - break; - } - } - } else { - /* Card is offline and/or not a CCA card. */ - /* del mkvp entry from cache if it exists */ - mkvp_cache_scrub(card, dom); - } - } - if (i >= MAX_ZDEV_ENTRIES_EXT) { - /* nothing found, so this time without cache */ - for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { - if (!(device_status[i].online && - device_status[i].functions & 0x04)) - continue; - card = AP_QID_CARD(device_status[i].qid); - dom = AP_QID_QUEUE(device_status[i].qid); - /* fresh fetch mkvp from adapter */ - if (fetch_mkvp(card, dom, mkvp) == 0) { - mkvp_cache_update(card, dom, mkvp); - if (t->mkvp == mkvp[0]) - break; - if (t->mkvp == mkvp[1] && oi < 0) - oi = i; - } - } - if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) { - /* old mkvp matched, use this card then */ - card = AP_QID_CARD(device_status[oi].qid); - dom = AP_QID_QUEUE(device_status[oi].qid); - } - } - if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) { - if (pcardnr) - *pcardnr = card; - if (pdomain) - *pdomain = dom; - rc = 0; - } else - rc = -ENODEV; - - kfree(device_status); - return rc; -} -EXPORT_SYMBOL(pkey_findcard); - /* * Find card and transform secure key into protected key. */ int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *protkey) + struct pkey_protkey *pkey) { u16 cardnr, domain; int rc, verify; /* - * The pkey_sec2protkey call may fail when a card has been + * The cca_sec2protkey call may fail when a card has been * addressed where the master key was changed after last fetch - * of the mkvp into the cache. So first try without verify then - * with verify enabled (thus refreshing the mkvp for each card). + * of the mkvp into the cache. Try 3 times: First witout verify + * then with verify and last round with verify and old master + * key verification pattern match not ignored. */ - for (verify = 0; verify < 2; verify++) { - rc = pkey_findcard(seckey, &cardnr, &domain, verify); - if (rc) + for (verify = 0; verify < 3; verify++) { + rc = cca_findcard(seckey->seckey, &cardnr, &domain, verify); + if (rc < 0) + continue; + if (rc > 0 && verify < 2) continue; - rc = pkey_sec2protkey(cardnr, domain, seckey, protkey); + rc = cca_sec2protkey(cardnr, domain, seckey->seckey, + pkey->protkey, &pkey->len, &pkey->type); if (rc == 0) break; } @@ -1059,11 +168,10 @@ int pkey_verifykey(const struct pkey_seckey *seckey, { struct secaeskeytoken *t = (struct secaeskeytoken *) seckey; u16 cardnr, domain; - u64 mkvp[2]; int rc; /* check the secure key for valid AES secure key */ - rc = check_secaeskeytoken((u8 *) seckey, 0); + rc = cca_check_secaeskeytoken(debug_info, 3, (u8 *) seckey, 0); if (rc) goto out; if (pattributes) @@ -1072,18 +180,16 @@ int pkey_verifykey(const struct pkey_seckey *seckey, *pkeysize = t->bitsize; /* try to find a card which can handle this key */ - rc = pkey_findcard(seckey, &cardnr, &domain, 1); - if (rc) + rc = cca_findcard(seckey->seckey, &cardnr, &domain, 1); + if (rc < 0) goto out; - /* check mkvp for old mkvp match */ - rc = mkvp_cache_fetch(cardnr, domain, mkvp); - if (rc) - goto out; - if (t->mkvp == mkvp[1] && t->mkvp != mkvp[0]) { + if (rc > 0) { + /* key mkvp matches to old master key mkvp */ DEBUG_DBG("%s secure key has old mkvp\n", __func__); if (pattributes) *pattributes |= PKEY_VERIFY_ATTR_OLD_MKVP; + rc = 0; } if (pcardnr) @@ -1273,9 +379,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kgs, ugs, sizeof(kgs))) return -EFAULT; - rc = pkey_genseckey(kgs.cardnr, kgs.domain, - kgs.keytype, &kgs.seckey); - DEBUG_DBG("%s pkey_genseckey()=%d\n", __func__, rc); + rc = cca_genseckey(kgs.cardnr, kgs.domain, + kgs.keytype, kgs.seckey.seckey); + DEBUG_DBG("%s cca_genseckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ugs, &kgs, sizeof(kgs))) @@ -1288,9 +394,9 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; - rc = pkey_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype, - &kcs.clrkey, &kcs.seckey); - DEBUG_DBG("%s pkey_clr2seckey()=%d\n", __func__, rc); + rc = cca_clr2seckey(kcs.cardnr, kcs.domain, kcs.keytype, + kcs.clrkey.clrkey, kcs.seckey.seckey); + DEBUG_DBG("%s cca_clr2seckey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(ucs, &kcs, sizeof(kcs))) @@ -1304,9 +410,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - rc = pkey_sec2protkey(ksp.cardnr, ksp.domain, - &ksp.seckey, &ksp.protkey); - DEBUG_DBG("%s pkey_sec2protkey()=%d\n", __func__, rc); + rc = cca_sec2protkey(ksp.cardnr, ksp.domain, + ksp.seckey.seckey, ksp.protkey.protkey, + NULL, &ksp.protkey.type); + DEBUG_DBG("%s cca_sec2protkey()=%d\n", __func__, rc); if (rc) break; if (copy_to_user(usp, &ksp, sizeof(ksp))) @@ -1335,10 +442,10 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&kfc, ufc, sizeof(kfc))) return -EFAULT; - rc = pkey_findcard(&kfc.seckey, - &kfc.cardnr, &kfc.domain, 1); - DEBUG_DBG("%s pkey_findcard()=%d\n", __func__, rc); - if (rc) + rc = cca_findcard(kfc.seckey.seckey, + &kfc.cardnr, &kfc.domain, 1); + DEBUG_DBG("%s cca_findcard()=%d\n", __func__, rc); + if (rc < 0) break; if (copy_to_user(ufc, &kfc, sizeof(kfc))) return -EFAULT; @@ -1567,6 +674,7 @@ static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, loff_t off, size_t count) { int rc; + struct pkey_seckey *seckey = (struct pkey_seckey *) buf; if (off != 0 || count < sizeof(struct secaeskeytoken)) return -EINVAL; @@ -1574,13 +682,13 @@ static ssize_t pkey_ccadata_aes_attr_read(u32 keytype, bool is_xts, char *buf, if (count < 2 * sizeof(struct secaeskeytoken)) return -EINVAL; - rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf); + rc = cca_genseckey(-1, -1, keytype, seckey->seckey); if (rc) return rc; if (is_xts) { - buf += sizeof(struct pkey_seckey); - rc = pkey_genseckey(-1, -1, keytype, (struct pkey_seckey *)buf); + seckey++; + rc = cca_genseckey(-1, -1, keytype, seckey->seckey); if (rc) return rc; @@ -1716,7 +824,6 @@ static int __init pkey_init(void) static void __exit pkey_exit(void) { misc_deregister(&pkey_dev); - mkvp_cache_free(); pkey_debug_exit(); } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 1058b4b5cc1e..69ac7bf09a57 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -35,6 +35,7 @@ #include "zcrypt_msgtype6.h" #include "zcrypt_msgtype50.h" +#include "zcrypt_ccamisc.h" /* * Module description. @@ -1874,6 +1875,7 @@ void __exit zcrypt_api_exit(void) misc_deregister(&zcrypt_misc_device); zcrypt_msgtype6_exit(); zcrypt_msgtype50_exit(); + zcrypt_ccamisc_exit(); zcrypt_debug_exit(); } diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c new file mode 100644 index 000000000000..3a76c7b5e33c --- /dev/null +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -0,0 +1,901 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright IBM Corp. 2019 + * Author(s): Harald Freudenberger + * Ingo Franzki + * + * Collection of CCA misc functions used by zcrypt and pkey + */ + +#define KMSG_COMPONENT "zcrypt" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include +#include +#include + +#include "ap_bus.h" +#include "zcrypt_api.h" +#include "zcrypt_debug.h" +#include "zcrypt_msgtype6.h" +#include "zcrypt_ccamisc.h" + +#define DEBUG_DBG(...) ZCRYPT_DBF(DBF_DEBUG, ##__VA_ARGS__) +#define DEBUG_INFO(...) ZCRYPT_DBF(DBF_INFO, ##__VA_ARGS__) +#define DEBUG_WARN(...) ZCRYPT_DBF(DBF_WARN, ##__VA_ARGS__) +#define DEBUG_ERR(...) ZCRYPT_DBF(DBF_ERR, ##__VA_ARGS__) + +/* Size of parameter block used for all cca requests/replies */ +#define PARMBSIZE 512 + +/* Size of vardata block used for some of the cca requests/replies */ +#define VARDATASIZE 4096 + +/* struct to hold cached mkvp info for each CCA card/domain */ +struct mkvp_info { + struct list_head list; + u16 cardnr; + u16 domain; + u64 mkvp[2]; +}; + +/* a list with mkvp_info entries */ +static LIST_HEAD(mkvp_list); +static DEFINE_SPINLOCK(mkvp_list_lock); + +/* + * Simple check if the token is a valid CCA secure AES key + * token. If keybitsize is given, the bitsize of the key is + * also checked. Returns 0 on success or errno value on failure. + */ +int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize) + +{ + struct secaeskeytoken *t = (struct secaeskeytoken *) token; + +#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) + + if (t->type != TOKTYPE_CCA_INTERNAL) { + if (dbg) + DBF("%s token check failed, type 0x%02x != 0x%02x\n", + __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); + return -EINVAL; + } + if (t->version != TOKVER_CCA_AES) { + if (dbg) + DBF("%s token check failed, version 0x%02x != 0x%02x\n", + __func__, (int) t->version, TOKVER_CCA_AES); + return -EINVAL; + } + if (keybitsize > 0 && t->bitsize != keybitsize) { + if (dbg) + DBF("%s token check failed, bitsize %d != %d\n", + __func__, (int) t->bitsize, keybitsize); + return -EINVAL; + } + +#undef DBF + + return 0; +} +EXPORT_SYMBOL(cca_check_secaeskeytoken); + +/* + * Allocate consecutive memory for request CPRB, request param + * block, reply CPRB and reply param block and fill in values + * for the common fields. Returns 0 on success or errno value + * on failure. + */ +static int alloc_and_prep_cprbmem(size_t paramblen, + u8 **pcprbmem, + struct CPRBX **preqCPRB, + struct CPRBX **prepCPRB) +{ + u8 *cprbmem; + size_t cprbplusparamblen = sizeof(struct CPRBX) + paramblen; + struct CPRBX *preqcblk, *prepcblk; + + /* + * allocate consecutive memory for request CPRB, request param + * block, reply CPRB and reply param block + */ + cprbmem = kcalloc(2, cprbplusparamblen, GFP_KERNEL); + if (!cprbmem) + return -ENOMEM; + + preqcblk = (struct CPRBX *) cprbmem; + prepcblk = (struct CPRBX *) (cprbmem + cprbplusparamblen); + + /* fill request cprb struct */ + preqcblk->cprb_len = sizeof(struct CPRBX); + preqcblk->cprb_ver_id = 0x02; + memcpy(preqcblk->func_id, "T2", 2); + preqcblk->rpl_msgbl = cprbplusparamblen; + if (paramblen) { + preqcblk->req_parmb = + ((u8 *) preqcblk) + sizeof(struct CPRBX); + preqcblk->rpl_parmb = + ((u8 *) prepcblk) + sizeof(struct CPRBX); + } + + *pcprbmem = cprbmem; + *preqCPRB = preqcblk; + *prepCPRB = prepcblk; + + return 0; +} + +/* + * Free the cprb memory allocated with the function above. + * If the scrub value is not zero, the memory is filled + * with zeros before freeing (useful if there was some + * clear key material in there). + */ +static void free_cprbmem(void *mem, size_t paramblen, int scrub) +{ + if (scrub) + memzero_explicit(mem, 2 * (sizeof(struct CPRBX) + paramblen)); + kfree(mem); +} + +/* + * Helper function to prepare the xcrb struct + */ +static inline void prep_xcrb(struct ica_xcRB *pxcrb, + u16 cardnr, + struct CPRBX *preqcblk, + struct CPRBX *prepcblk) +{ + memset(pxcrb, 0, sizeof(*pxcrb)); + pxcrb->agent_ID = 0x4341; /* 'CA' */ + pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); + pxcrb->request_control_blk_length = + preqcblk->cprb_len + preqcblk->req_parml; + pxcrb->request_control_blk_addr = (void *) preqcblk; + pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; + pxcrb->reply_control_blk_addr = (void *) prepcblk; +} + +/* + * Helper function which calls zcrypt_send_cprb with + * memory management segment adjusted to kernel space + * so that the copy_from_user called within this + * function do in fact copy from kernel space. + */ +static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb) +{ + int rc; + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + rc = zcrypt_send_cprb(xcrb); + set_fs(old_fs); + + return rc; +} + +/* + * Generate (random) CCA AES DATA secure key. + */ +int cca_genseckey(u16 cardnr, u16 domain, + u32 keytype, u8 seckey[SECKEYBLOBSIZE]) +{ + int i, rc, keysize; + int seckeysize; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct kgreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv1 { + u16 len; + char key_form[8]; + char key_length[8]; + char key_type1[8]; + char key_type2[8]; + } lv1; + struct lv2 { + u16 len; + struct keyid { + u16 len; + u16 attr; + u8 data[SECKEYBLOBSIZE]; + } keyid[6]; + } lv2; + } __packed * preqparm; + struct kgrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv3 { + u16 len; + u16 keyblocklen; + struct { + u16 toklen; + u16 tokattr; + u8 tok[0]; + /* ... some more data ... */ + } keyblock; + } lv3; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with KG request */ + preqparm = (struct kgreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "KG", 2); + preqparm->rule_array_len = sizeof(preqparm->rule_array_len); + preqparm->lv1.len = sizeof(struct lv1); + memcpy(preqparm->lv1.key_form, "OP ", 8); + switch (keytype) { + case PKEY_KEYTYPE_AES_128: + keysize = 16; + memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); + break; + case PKEY_KEYTYPE_AES_192: + keysize = 24; + memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); + break; + case PKEY_KEYTYPE_AES_256: + keysize = 32; + memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); + break; + default: + DEBUG_ERR("%s unknown/unsupported keytype %d\n", + __func__, keytype); + rc = -EINVAL; + goto out; + } + memcpy(preqparm->lv1.key_type1, "AESDATA ", 8); + preqparm->lv2.len = sizeof(struct lv2); + for (i = 0; i < 6; i++) { + preqparm->lv2.keyid[i].len = sizeof(struct keyid); + preqparm->lv2.keyid[i].attr = (i == 2 ? 0x30 : 0x10); + } + preqcblk->req_parml = sizeof(struct kgreqparm); + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, errno %d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s secure key generate failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct kgrepparm *) prepcblk->rpl_parmb; + + /* check length of the returned secure key token */ + seckeysize = prepparm->lv3.keyblock.toklen + - sizeof(prepparm->lv3.keyblock.toklen) + - sizeof(prepparm->lv3.keyblock.tokattr); + if (seckeysize != SECKEYBLOBSIZE) { + DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); + rc = -EIO; + goto out; + } + + /* check secure key token */ + rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, + prepparm->lv3.keyblock.tok, 8*keysize); + if (rc) { + rc = -EIO; + goto out; + } + + /* copy the generated secure key token */ + memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_genseckey); + +/* + * Generate an CCA AES DATA secure key with given key value. + */ +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, + const u8 *clrkey, u8 seckey[SECKEYBLOBSIZE]) +{ + int rc, keysize, seckeysize; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct cmreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[8]; + struct lv1 { + u16 len; + u8 clrkey[0]; + } lv1; + struct lv2 { + u16 len; + struct keyid { + u16 len; + u16 attr; + u8 data[SECKEYBLOBSIZE]; + } keyid; + } lv2; + } __packed * preqparm; + struct lv2 *plv2; + struct cmrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv3 { + u16 len; + u16 keyblocklen; + struct { + u16 toklen; + u16 tokattr; + u8 tok[0]; + /* ... some more data ... */ + } keyblock; + } lv3; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with CM request */ + preqparm = (struct cmreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "CM", 2); + memcpy(preqparm->rule_array, "AES ", 8); + preqparm->rule_array_len = + sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); + 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); + rc = -EINVAL; + goto out; + } + preqparm->lv1.len = sizeof(struct lv1) + keysize; + memcpy(preqparm->lv1.clrkey, clrkey, keysize); + plv2 = (struct lv2 *) (((u8 *) &preqparm->lv2) + keysize); + plv2->len = sizeof(struct lv2); + plv2->keyid.len = sizeof(struct keyid); + plv2->keyid.attr = 0x30; + preqcblk->req_parml = sizeof(struct cmreqparm) + keysize; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s clear key import failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct cmrepparm *) prepcblk->rpl_parmb; + + /* check length of the returned secure key token */ + seckeysize = prepparm->lv3.keyblock.toklen + - sizeof(prepparm->lv3.keyblock.toklen) + - sizeof(prepparm->lv3.keyblock.tokattr); + if (seckeysize != SECKEYBLOBSIZE) { + DEBUG_ERR("%s secure token size mismatch %d != %d bytes\n", + __func__, seckeysize, SECKEYBLOBSIZE); + rc = -EIO; + goto out; + } + + /* check secure key token */ + rc = cca_check_secaeskeytoken(zcrypt_dbf_info, DBF_ERR, + prepparm->lv3.keyblock.tok, 8*keysize); + if (rc) { + rc = -EIO; + goto out; + } + + /* copy the generated secure key token */ + memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); + +out: + free_cprbmem(mem, PARMBSIZE, 1); + return rc; +} +EXPORT_SYMBOL(cca_clr2seckey); + +/* + * Derive proteced key from an CCA AES DATA secure key. + */ +int cca_sec2protkey(u16 cardnr, u16 domain, + const u8 seckey[SECKEYBLOBSIZE], + u8 *protkey, u32 *protkeylen, + u32 *keytype) +{ + int rc; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct uskreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv1 { + u16 len; + u16 attr_len; + u16 attr_flags; + } lv1; + struct lv2 { + u16 len; + u16 attr_len; + u16 attr_flags; + u8 token[0]; /* cca secure key token */ + } lv2; + } __packed * preqparm; + struct uskrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct lv3 { + u16 len; + u16 attr_len; + u16 attr_flags; + struct cpacfkeyblock { + u8 version; /* version of this struct */ + u8 flags[2]; + u8 algo; + u8 form; + u8 pad1[3]; + u16 len; + u8 key[64]; /* the key (len bytes) */ + u16 keyattrlen; + u8 keyattr[32]; + u8 pad2[1]; + u8 vptype; + u8 vp[32]; /* verification pattern */ + } keyblock; + } lv3; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with USK request */ + preqparm = (struct uskreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "US", 2); + preqparm->rule_array_len = sizeof(preqparm->rule_array_len); + preqparm->lv1.len = sizeof(struct lv1); + preqparm->lv1.attr_len = sizeof(struct lv1) - sizeof(preqparm->lv1.len); + preqparm->lv1.attr_flags = 0x0001; + preqparm->lv2.len = sizeof(struct lv2) + SECKEYBLOBSIZE; + preqparm->lv2.attr_len = sizeof(struct lv2) + - sizeof(preqparm->lv2.len) + SECKEYBLOBSIZE; + preqparm->lv2.attr_flags = 0x0000; + memcpy(preqparm->lv2.token, seckey, SECKEYBLOBSIZE); + preqcblk->req_parml = sizeof(struct uskreqparm) + SECKEYBLOBSIZE; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + if (prepcblk->ccp_rscode != 0) { + DEBUG_WARN("%s unwrap secure key warning, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct uskrepparm *) prepcblk->rpl_parmb; + + /* check the returned keyblock */ + if (prepparm->lv3.keyblock.version != 0x01) { + DEBUG_ERR("%s reply param keyblock version mismatch 0x%02x != 0x01\n", + __func__, (int) prepparm->lv3.keyblock.version); + rc = -EIO; + goto out; + } + + /* copy the tanslated protected key */ + switch (prepparm->lv3.keyblock.len) { + case 16+32: + /* AES 128 protected key */ + if (keytype) + *keytype = PKEY_KEYTYPE_AES_128; + break; + case 24+32: + /* AES 192 protected key */ + if (keytype) + *keytype = PKEY_KEYTYPE_AES_192; + break; + case 32+32: + /* AES 256 protected key */ + if (keytype) + *keytype = PKEY_KEYTYPE_AES_256; + break; + default: + DEBUG_ERR("%s unknown/unsupported keytype %d\n", + __func__, prepparm->lv3.keyblock.len); + rc = -EIO; + goto out; + } + memcpy(protkey, prepparm->lv3.keyblock.key, prepparm->lv3.keyblock.len); + if (protkeylen) + *protkeylen = prepparm->lv3.keyblock.len; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_sec2protkey); + +/* + * query cryptographic facility from CCA adapter + */ +int cca_query_crypto_facility(u16 cardnr, u16 domain, + const char *keyword, + u8 *rarray, size_t *rarraylen, + u8 *varray, size_t *varraylen) +{ + int rc; + u16 len; + u8 *mem, *ptr; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct fqreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[8]; + struct lv1 { + u16 len; + u8 data[VARDATASIZE]; + } lv1; + u16 dummylen; + } __packed * preqparm; + size_t parmbsize = sizeof(struct fqreqparm); + struct fqrepparm { + u8 subfunc_code[2]; + u8 lvdata[0]; + } __packed * prepparm; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(parmbsize, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with FQ request */ + preqparm = (struct fqreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "FQ", 2); + memcpy(preqparm->rule_array, keyword, sizeof(preqparm->rule_array)); + preqparm->rule_array_len = + sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); + preqparm->lv1.len = sizeof(preqparm->lv1); + preqparm->dummylen = sizeof(preqparm->dummylen); + preqcblk->req_parml = parmbsize; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR("%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR("%s unwrap secure key failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct fqrepparm *) prepcblk->rpl_parmb; + ptr = prepparm->lvdata; + + /* check and possibly copy reply rule array */ + len = *((u16 *) ptr); + if (len > sizeof(u16)) { + ptr += sizeof(u16); + len -= sizeof(u16); + if (rarray && rarraylen && *rarraylen > 0) { + *rarraylen = (len > *rarraylen ? *rarraylen : len); + memcpy(rarray, ptr, *rarraylen); + } + ptr += len; + } + /* check and possible copy reply var array */ + len = *((u16 *) ptr); + if (len > sizeof(u16)) { + ptr += sizeof(u16); + len -= sizeof(u16); + if (varray && varraylen && *varraylen > 0) { + *varraylen = (len > *varraylen ? *varraylen : len); + memcpy(varray, ptr, *varraylen); + } + ptr += len; + } + +out: + free_cprbmem(mem, parmbsize, 0); + return rc; +} +EXPORT_SYMBOL(cca_query_crypto_facility); + +static int mkvp_cache_fetch(u16 cardnr, u16 domain, u64 mkvp[2]) +{ + int rc = -ENOENT; + struct mkvp_info *ptr; + + spin_lock_bh(&mkvp_list_lock); + list_for_each_entry(ptr, &mkvp_list, list) { + if (ptr->cardnr == cardnr && + ptr->domain == domain) { + memcpy(mkvp, ptr->mkvp, 2 * sizeof(u64)); + rc = 0; + break; + } + } + spin_unlock_bh(&mkvp_list_lock); + + return rc; +} + +static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2]) +{ + int found = 0; + struct mkvp_info *ptr; + + spin_lock_bh(&mkvp_list_lock); + list_for_each_entry(ptr, &mkvp_list, list) { + if (ptr->cardnr == cardnr && + ptr->domain == domain) { + memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); + found = 1; + break; + } + } + if (!found) { + ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); + if (!ptr) { + spin_unlock_bh(&mkvp_list_lock); + return; + } + ptr->cardnr = cardnr; + ptr->domain = domain; + memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); + list_add(&ptr->list, &mkvp_list); + } + spin_unlock_bh(&mkvp_list_lock); +} + +static void mkvp_cache_scrub(u16 cardnr, u16 domain) +{ + struct mkvp_info *ptr; + + spin_lock_bh(&mkvp_list_lock); + list_for_each_entry(ptr, &mkvp_list, list) { + if (ptr->cardnr == cardnr && + ptr->domain == domain) { + list_del(&ptr->list); + kfree(ptr); + break; + } + } + spin_unlock_bh(&mkvp_list_lock); +} + +static void __exit mkvp_cache_free(void) +{ + struct mkvp_info *ptr, *pnext; + + spin_lock_bh(&mkvp_list_lock); + list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) { + list_del(&ptr->list); + kfree(ptr); + } + spin_unlock_bh(&mkvp_list_lock); +} + +/* + * Fetch the current and old mkvp values via + * query_crypto_facility from adapter. + */ +static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2]) +{ + int rc, found = 0; + size_t rlen, vlen; + u8 *rarray, *varray, *pg; + + pg = (u8 *) __get_free_page(GFP_KERNEL); + if (!pg) + return -ENOMEM; + rarray = pg; + varray = pg + PAGE_SIZE/2; + rlen = vlen = PAGE_SIZE/2; + + rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", + rarray, &rlen, varray, &vlen); + if (rc == 0 && rlen > 8*8 && vlen > 184+8) { + if (rarray[8*8] == '2') { + /* current master key state is valid */ + mkvp[0] = *((u64 *)(varray + 184)); + mkvp[1] = *((u64 *)(varray + 172)); + found = 1; + } + } + + free_page((unsigned long) pg); + + return found ? 0 : -ENOENT; +} + +/* + * Search for a matching crypto card based on the Master Key + * Verification Pattern provided inside a secure key. + * Returns < 0 on failure, 0 if CURRENT MKVP matches and + * 1 if OLD MKVP matches. + */ +int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) +{ + const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey; + struct zcrypt_device_status_ext *device_status; + u16 card, dom; + u64 mkvp[2]; + int i, rc, oi = -1; + + /* some simple checks of the given secure key token */ + if (t->type != TOKTYPE_CCA_INTERNAL || + t->version != TOKVER_CCA_AES || + t->mkvp == 0) + return -EINVAL; + + /* fetch status of all crypto cards */ + device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); + if (!device_status) + return -ENOMEM; + zcrypt_device_status_mask_ext(device_status); + + /* walk through all crypto cards */ + for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { + card = AP_QID_CARD(device_status[i].qid); + dom = AP_QID_QUEUE(device_status[i].qid); + if (device_status[i].online && + device_status[i].functions & 0x04) { + /* an enabled CCA Coprocessor card */ + /* try cached mkvp */ + if (mkvp_cache_fetch(card, dom, mkvp) == 0 && + t->mkvp == mkvp[0]) { + if (!verify) + break; + /* verify: fetch mkvp from adapter */ + if (fetch_mkvp(card, dom, mkvp) == 0) { + mkvp_cache_update(card, dom, mkvp); + if (t->mkvp == mkvp[0]) + break; + } + } + } else { + /* Card is offline and/or not a CCA card. */ + /* del mkvp entry from cache if it exists */ + mkvp_cache_scrub(card, dom); + } + } + if (i >= MAX_ZDEV_ENTRIES_EXT) { + /* nothing found, so this time without cache */ + for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { + if (!(device_status[i].online && + device_status[i].functions & 0x04)) + continue; + card = AP_QID_CARD(device_status[i].qid); + dom = AP_QID_QUEUE(device_status[i].qid); + /* fresh fetch mkvp from adapter */ + if (fetch_mkvp(card, dom, mkvp) == 0) { + mkvp_cache_update(card, dom, mkvp); + if (t->mkvp == mkvp[0]) + break; + if (t->mkvp == mkvp[1] && oi < 0) + oi = i; + } + } + if (i >= MAX_ZDEV_ENTRIES_EXT && oi >= 0) { + /* old mkvp matched, use this card then */ + card = AP_QID_CARD(device_status[oi].qid); + dom = AP_QID_QUEUE(device_status[oi].qid); + } + } + if (i < MAX_ZDEV_ENTRIES_EXT || oi >= 0) { + if (pcardnr) + *pcardnr = card; + if (pdomain) + *pdomain = dom; + rc = (i < MAX_ZDEV_ENTRIES_EXT ? 0 : 1); + } else + rc = -ENODEV; + + kfree(device_status); + return rc; +} +EXPORT_SYMBOL(cca_findcard); + +void __exit zcrypt_ccamisc_exit(void) +{ + mkvp_cache_free(); +} diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h new file mode 100644 index 000000000000..417427462493 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright IBM Corp. 2019 + * Author(s): Harald Freudenberger + * Ingo Franzki + * + * Collection of CCA misc functions used by zcrypt and pkey + */ + +#ifndef _ZCRYPT_CCAMISC_H_ +#define _ZCRYPT_CCAMISC_H_ + +#include +#include + +/* 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 CCA 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 CCA secure key token (only type 0x01 version 0x04) */ +struct secaeskeytoken { + u8 type; /* 0x01 for internal key token */ + u8 res0[3]; + u8 version; /* should be 0x04 */ + u8 res1[1]; + u8 flag; /* key flags */ + u8 res2[1]; + u64 mkvp; /* master key verification pattern */ + u8 key[32]; /* key value (encrypted) */ + u8 cv[8]; /* control vector */ + u16 bitsize; /* key bit size */ + u16 keysize; /* key byte size */ + u8 tvv[4]; /* token validation value */ +} __packed; + +/* + * Simple check if the token is a valid CCA secure AES data key + * token. If keybitsize is given, the bitsize of the key is + * also checked. Returns 0 on success or errno value on failure. + */ +int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize); + +/* + * Generate (random) CCA AES DATA secure key. + */ +int cca_genseckey(u16 cardnr, u16 domain, u32 keytype, u8 *seckey); + +/* + * Generate CCA AES DATA secure key with given clear key value. + */ +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, + const u8 *clrkey, u8 *seckey); + +/* + * Derive proteced key from an CCA AES DATA secure key. + */ +int cca_sec2protkey(u16 cardnr, u16 domain, + const u8 seckey[SECKEYBLOBSIZE], + u8 *protkey, u32 *protkeylen, + u32 *protkeytype); + +/* + * Query cryptographic facility from CCA adapter + */ +int cca_query_crypto_facility(u16 cardnr, u16 domain, + const char *keyword, + u8 *rarray, size_t *rarraylen, + u8 *varray, size_t *varraylen); + +/* + * Search for a matching crypto card based on the Master Key + * Verification Pattern provided inside a secure key. + * Returns < 0 on failure, 0 if CURRENT MKVP matches and + * 1 if OLD MKVP matches. + */ +int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify); + +void zcrypt_ccamisc_exit(void); + +#endif /* _ZCRYPT_CCAMISC_H_ */ -- cgit v1.2.3 From 94bbd34e51bc7809357e24e4011b169d321a8272 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 11 Jun 2019 14:10:47 +0200 Subject: s390/zcrypt: add base code for cca crypto card info support This patch widens the information held for cca crypto apqns. Currently the current and old master key verification pattern is used by the existing code. Now the new master key registers mkvp, the 8 byte serial number and state info about each master key register is part of the cca info cache. In a next step this information will be used to provide some additional attributes in sysfs for each CCA crypto adapter. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_ccamisc.c | 131 ++++++++++++++++++++--------------- 1 file changed, 75 insertions(+), 56 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 3a76c7b5e33c..b1f9332a0298 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -33,17 +33,27 @@ /* Size of vardata block used for some of the cca requests/replies */ #define VARDATASIZE 4096 -/* struct to hold cached mkvp info for each CCA card/domain */ -struct mkvp_info { +/* struct to hold cached info for each CCA card/domain */ +struct cca_info { + char new_mk_state; /* '1' Empty, '2' Partially full, '3' Full */ + char cur_mk_state; /* '1' Invalid, '2' Valid */ + char old_mk_state; /* '1' Invalid, '2' Valid */ + u64 new_mkvp; /* truncated sha256 hash of new master key */ + u64 cur_mkvp; /* truncated sha256 hash of current master key */ + u64 old_mkvp; /* truncated sha256 hash of old master key */ + char serial[9]; +}; + +struct cca_info_list_entry { struct list_head list; u16 cardnr; u16 domain; - u64 mkvp[2]; + struct cca_info info; }; -/* a list with mkvp_info entries */ -static LIST_HEAD(mkvp_list); -static DEFINE_SPINLOCK(mkvp_list_lock); +/* a list with cca_info_list_entry entries */ +static LIST_HEAD(cca_info_list); +static DEFINE_SPINLOCK(cca_info_list_lock); /* * Simple check if the token is a valid CCA secure AES key @@ -697,35 +707,35 @@ out: } EXPORT_SYMBOL(cca_query_crypto_facility); -static int mkvp_cache_fetch(u16 cardnr, u16 domain, u64 mkvp[2]) +static int cca_info_cache_fetch(u16 cardnr, u16 domain, struct cca_info *ci) { int rc = -ENOENT; - struct mkvp_info *ptr; + struct cca_info_list_entry *ptr; - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { - if (ptr->cardnr == cardnr && - ptr->domain == domain) { - memcpy(mkvp, ptr->mkvp, 2 * sizeof(u64)); + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry(ptr, &cca_info_list, list) { + if (ptr->cardnr == cardnr && ptr->domain == domain) { + memcpy(ci, &ptr->info, sizeof(*ci)); rc = 0; break; } } - spin_unlock_bh(&mkvp_list_lock); + spin_unlock_bh(&cca_info_list_lock); return rc; } -static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2]) +static void cca_info_cache_update(u16 cardnr, u16 domain, + const struct cca_info *ci) { int found = 0; - struct mkvp_info *ptr; + struct cca_info_list_entry *ptr; - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry(ptr, &cca_info_list, list) { if (ptr->cardnr == cardnr && ptr->domain == domain) { - memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); + memcpy(&ptr->info, ci, sizeof(*ci)); found = 1; break; } @@ -733,23 +743,23 @@ static void mkvp_cache_update(u16 cardnr, u16 domain, u64 mkvp[2]) if (!found) { ptr = kmalloc(sizeof(*ptr), GFP_ATOMIC); if (!ptr) { - spin_unlock_bh(&mkvp_list_lock); + spin_unlock_bh(&cca_info_list_lock); return; } ptr->cardnr = cardnr; ptr->domain = domain; - memcpy(ptr->mkvp, mkvp, 2 * sizeof(u64)); - list_add(&ptr->list, &mkvp_list); + memcpy(&ptr->info, ci, sizeof(*ci)); + list_add(&ptr->list, &cca_info_list); } - spin_unlock_bh(&mkvp_list_lock); + spin_unlock_bh(&cca_info_list_lock); } -static void mkvp_cache_scrub(u16 cardnr, u16 domain) +static void cca_info_cache_scrub(u16 cardnr, u16 domain) { - struct mkvp_info *ptr; + struct cca_info_list_entry *ptr; - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry(ptr, &mkvp_list, list) { + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry(ptr, &cca_info_list, list) { if (ptr->cardnr == cardnr && ptr->domain == domain) { list_del(&ptr->list); @@ -757,26 +767,25 @@ static void mkvp_cache_scrub(u16 cardnr, u16 domain) break; } } - spin_unlock_bh(&mkvp_list_lock); + spin_unlock_bh(&cca_info_list_lock); } static void __exit mkvp_cache_free(void) { - struct mkvp_info *ptr, *pnext; + struct cca_info_list_entry *ptr, *pnext; - spin_lock_bh(&mkvp_list_lock); - list_for_each_entry_safe(ptr, pnext, &mkvp_list, list) { + spin_lock_bh(&cca_info_list_lock); + list_for_each_entry_safe(ptr, pnext, &cca_info_list, list) { list_del(&ptr->list); kfree(ptr); } - spin_unlock_bh(&mkvp_list_lock); + spin_unlock_bh(&cca_info_list_lock); } /* - * Fetch the current and old mkvp values via - * query_crypto_facility from adapter. + * Fetch cca_info values via query_crypto_facility from adapter. */ -static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2]) +static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) { int rc, found = 0; size_t rlen, vlen; @@ -791,13 +800,19 @@ static int fetch_mkvp(u16 cardnr, u16 domain, u64 mkvp[2]) rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", rarray, &rlen, varray, &vlen); - if (rc == 0 && rlen > 8*8 && vlen > 184+8) { - if (rarray[8*8] == '2') { - /* current master key state is valid */ - mkvp[0] = *((u64 *)(varray + 184)); - mkvp[1] = *((u64 *)(varray + 172)); - found = 1; - } + if (rc == 0 && rlen >= 10*8 && vlen >= 204) { + memset(ci, 0, sizeof(*ci)); + memcpy(ci->serial, rarray, 8); + ci->new_mk_state = (char) rarray[7*8]; + ci->cur_mk_state = (char) rarray[8*8]; + ci->old_mk_state = (char) rarray[9*8]; + if (ci->old_mk_state == '2') + memcpy(&ci->old_mkvp, varray + 172, 8); + if (ci->cur_mk_state == '2') + memcpy(&ci->cur_mkvp, varray + 184, 8); + if (ci->new_mk_state == '3') + memcpy(&ci->new_mkvp, varray + 196, 8); + found = 1; } free_page((unsigned long) pg); @@ -816,7 +831,7 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey; struct zcrypt_device_status_ext *device_status; u16 card, dom; - u64 mkvp[2]; + struct cca_info ci; int i, rc, oi = -1; /* some simple checks of the given secure key token */ @@ -839,23 +854,24 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) dom = AP_QID_QUEUE(device_status[i].qid); if (device_status[i].online && device_status[i].functions & 0x04) { - /* an enabled CCA Coprocessor card */ - /* try cached mkvp */ - if (mkvp_cache_fetch(card, dom, mkvp) == 0 && - t->mkvp == mkvp[0]) { + /* enabled CCA card, check current mkvp from cache */ + if (cca_info_cache_fetch(card, dom, &ci) == 0 && + ci.cur_mk_state == '2' && + ci.cur_mkvp == t->mkvp) { if (!verify) break; - /* verify: fetch mkvp from adapter */ - if (fetch_mkvp(card, dom, mkvp) == 0) { - mkvp_cache_update(card, dom, mkvp); - if (t->mkvp == mkvp[0]) + /* verify: refresh card info */ + if (fetch_cca_info(card, dom, &ci) == 0) { + cca_info_cache_update(card, dom, &ci); + if (ci.cur_mk_state == '2' && + ci.cur_mkvp == t->mkvp) break; } } } else { /* Card is offline and/or not a CCA card. */ /* del mkvp entry from cache if it exists */ - mkvp_cache_scrub(card, dom); + cca_info_cache_scrub(card, dom); } } if (i >= MAX_ZDEV_ENTRIES_EXT) { @@ -867,11 +883,14 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) card = AP_QID_CARD(device_status[i].qid); dom = AP_QID_QUEUE(device_status[i].qid); /* fresh fetch mkvp from adapter */ - if (fetch_mkvp(card, dom, mkvp) == 0) { - mkvp_cache_update(card, dom, mkvp); - if (t->mkvp == mkvp[0]) + if (fetch_cca_info(card, dom, &ci) == 0) { + cca_info_cache_update(card, dom, &ci); + if (ci.cur_mk_state == '2' && + ci.cur_mkvp == t->mkvp) break; - if (t->mkvp == mkvp[1] && oi < 0) + if (ci.old_mk_state == '2' && + ci.old_mkvp == t->mkvp && + oi < 0) oi = i; } } -- cgit v1.2.3 From 7c4e91c0959bf42a86ba4887425fc944d0d28595 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 12 Jun 2019 15:05:34 +0200 Subject: s390/zcrypt: new sysfs attributes serialnr and mkvps This patch extends the sysfs interface with two new attributes for the CEX4, CEX5 and CEX6 crypto cards/queues in coprocessor ('CCA') mode: /sys/devices/ap/cardxx/serialnr /sys/devices/ap/cardxx/xx.yyyy/mkvps The serialnr attribute is card based and shows the 8 character ASCII serial number string which should unique identify the card. The mkvps is queue based and displays 3 lines of information about the new, current and old master key register: AES NEW: AES CUR: AES OLD: with : 'empty' or 'partial' or 'full' : 'valid' or 'invalid' : 'valid' or 'invalid' , , 8 byte hex string with leading 0x MKVP means Master Key Verification Pattern and is a folded hash over the key value. Only the states 'full' and 'valid' result in displaying a useful mkvp, otherwise a mkvp of all bytes zero is shown. If for any reason the FQ fails and the (cached) information is not available, the state '-' will be shown with the mkvp value also '-'. The values shown here are the very same as the cca panel tools displays. As of now only the AES master keys states and verification patterns are shown. A CCA APQN also has similar master key registers for DES, RSA and ECC. So the content of this attribute may get extended. Reading the sysfs attribute automatically triggers an FQ CPRB to be sent to the queue as long as the queue is (soft-) online. For the serialnr attribute the queue with the default domain id is addressed (if available and valid). This is reasonable as it is assumed that this sysfs interface is not performance critical and on the other side a master key change should be visiable as soon as possible. When a queue is (soft-) offline however, the cached values are displayed. If no cached values are available, the serial number string will be empty and the mkvp lines will show state '-' and mkvp value '-'. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_ccamisc.c | 33 ++++++----- drivers/s390/crypto/zcrypt_ccamisc.h | 16 ++++++ drivers/s390/crypto/zcrypt_cex4.c | 106 ++++++++++++++++++++++++++++++++++- 3 files changed, 141 insertions(+), 14 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index b1f9332a0298..9dd31577ce47 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -33,17 +33,6 @@ /* Size of vardata block used for some of the cca requests/replies */ #define VARDATASIZE 4096 -/* struct to hold cached info for each CCA card/domain */ -struct cca_info { - char new_mk_state; /* '1' Empty, '2' Partially full, '3' Full */ - char cur_mk_state; /* '1' Invalid, '2' Valid */ - char old_mk_state; /* '1' Invalid, '2' Valid */ - u64 new_mkvp; /* truncated sha256 hash of new master key */ - u64 cur_mkvp; /* truncated sha256 hash of current master key */ - u64 old_mkvp; /* truncated sha256 hash of old master key */ - char serial[9]; -}; - struct cca_info_list_entry { struct list_head list; u16 cardnr; @@ -164,9 +153,9 @@ static inline void prep_xcrb(struct ica_xcRB *pxcrb, pxcrb->user_defined = (cardnr == 0xFFFF ? AUTOSELECT : cardnr); pxcrb->request_control_blk_length = preqcblk->cprb_len + preqcblk->req_parml; - pxcrb->request_control_blk_addr = (void *) preqcblk; + pxcrb->request_control_blk_addr = (void __user *) preqcblk; pxcrb->reply_control_blk_length = preqcblk->rpl_msgbl; - pxcrb->reply_control_blk_addr = (void *) prepcblk; + pxcrb->reply_control_blk_addr = (void __user *) prepcblk; } /* @@ -820,6 +809,24 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) return found ? 0 : -ENOENT; } +/* + * Fetch cca information about a CCA queue. + */ +int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify) +{ + int rc; + + rc = cca_info_cache_fetch(card, dom, ci); + if (rc || verify) { + rc = fetch_cca_info(card, dom, ci); + if (rc == 0) + cca_info_cache_update(card, dom, ci); + } + + return rc; +} +EXPORT_SYMBOL(cca_get_info); + /* * Search for a matching crypto card based on the Master Key * Verification Pattern provided inside a secure key. diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index 417427462493..d92fb731602a 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -90,6 +90,22 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, */ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify); +/* struct to hold info for each CCA queue */ +struct cca_info { + char new_mk_state; /* '1' empty, '2' partially full, '3' full */ + char cur_mk_state; /* '1' invalid, '2' valid */ + char old_mk_state; /* '1' invalid, '2' valid */ + u64 new_mkvp; /* truncated sha256 hash of new master key */ + u64 cur_mkvp; /* truncated sha256 hash of current master key */ + u64 old_mkvp; /* truncated sha256 hash of old master key */ + char serial[9]; /* serial number string (8 ascii numbers + 0x00) */ +}; + +/* + * Fetch cca information about an CCA queue. + */ +int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify); + void zcrypt_ccamisc_exit(void); #endif /* _ZCRYPT_CCAMISC_H_ */ diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index 582ffa7e0f18..f58d8dec19dc 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -18,6 +18,7 @@ #include "zcrypt_msgtype50.h" #include "zcrypt_error.h" #include "zcrypt_cex4.h" +#include "zcrypt_ccamisc.h" #define CEX4A_MIN_MOD_SIZE 1 /* 8 bits */ #define CEX4A_MAX_MOD_SIZE_2K 256 /* 2048 bits */ @@ -65,6 +66,85 @@ static struct ap_device_id zcrypt_cex4_queue_ids[] = { MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids); +/* + * CCA card addditional device attributes + */ +static ssize_t serialnr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct cca_info ci; + struct ap_card *ac = to_ap_card(dev); + struct zcrypt_card *zc = ac->private; + + memset(&ci, 0, sizeof(ci)); + + if (ap_domain_index >= 0) + cca_get_info(ac->id, ap_domain_index, &ci, zc->online); + + return snprintf(buf, PAGE_SIZE, "%s\n", ci.serial); +} +static DEVICE_ATTR_RO(serialnr); + +static struct attribute *cca_card_attrs[] = { + &dev_attr_serialnr.attr, + NULL, +}; + +static const struct attribute_group cca_card_attr_group = { + .attrs = cca_card_attrs, +}; + +/* + * CCA queue addditional device attributes + */ +static ssize_t mkvps_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int n = 0; + struct cca_info ci; + struct zcrypt_queue *zq = to_ap_queue(dev)->private; + static const char * const cao_state[] = { "invalid", "valid" }; + static const char * const new_state[] = { "empty", "partial", "full" }; + + memset(&ci, 0, sizeof(ci)); + + cca_get_info(AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + &ci, zq->online); + + if (ci.new_mk_state >= '1' && ci.new_mk_state <= '3') + n = snprintf(buf, PAGE_SIZE, "AES NEW: %s 0x%016llx\n", + new_state[ci.new_mk_state - '1'], ci.new_mkvp); + else + n = snprintf(buf, PAGE_SIZE, "AES NEW: - -\n"); + + if (ci.cur_mk_state >= '1' && ci.cur_mk_state <= '2') + n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: %s 0x%016llx\n", + cao_state[ci.cur_mk_state - '1'], ci.cur_mkvp); + else + n += snprintf(buf + n, PAGE_SIZE - n, "AES CUR: - -\n"); + + if (ci.old_mk_state >= '1' && ci.old_mk_state <= '2') + n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: %s 0x%016llx\n", + cao_state[ci.old_mk_state - '1'], ci.old_mkvp); + else + n += snprintf(buf + n, PAGE_SIZE - n, "AES OLD: - -\n"); + + return n; +} +static DEVICE_ATTR_RO(mkvps); + +static struct attribute *cca_queue_attrs[] = { + &dev_attr_mkvps.attr, + NULL, +}; + +static const struct attribute_group cca_queue_attr_group = { + .attrs = cca_queue_attrs, +}; + /** * Probe function for CEX4/CEX5/CEX6 card device. It always * accepts the AP device since the bus_match already checked @@ -194,8 +274,17 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) if (rc) { ac->private = NULL; zcrypt_card_free(zc); + goto out; } + if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) { + rc = sysfs_create_group(&ap_dev->device.kobj, + &cca_card_attr_group); + if (rc) + zcrypt_card_unregister(zc); + } + +out: return rc; } @@ -205,8 +294,11 @@ static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) */ static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) { - struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc = ac->private; + if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) + sysfs_remove_group(&ap_dev->device.kobj, &cca_card_attr_group); if (zc) zcrypt_card_unregister(zc); } @@ -251,6 +343,7 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) } else { return -ENODEV; } + zq->queue = aq; zq->online = 1; atomic_set(&zq->load, 0); @@ -261,8 +354,17 @@ static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) if (rc) { aq->private = NULL; zcrypt_queue_free(zq); + goto out; + } + + if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) { + rc = sysfs_create_group(&ap_dev->device.kobj, + &cca_queue_attr_group); + if (rc) + zcrypt_queue_unregister(zq); } +out: return rc; } @@ -275,6 +377,8 @@ static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) struct ap_queue *aq = to_ap_queue(&ap_dev->device); struct zcrypt_queue *zq = aq->private; + if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) + sysfs_remove_group(&ap_dev->device.kobj, &cca_queue_attr_group); if (zq) zcrypt_queue_unregister(zq); } -- cgit v1.2.3 From 8c72e0c85212df4e7c77fca55556e423fe17e801 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 25 Jul 2019 09:21:47 +0200 Subject: Documentation/s390: remove outdated dasd documentation The contents of the file is completely outdated - just remove it. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- Documentation/s390/dasd.rst | 84 -------------------------------------------- Documentation/s390/index.rst | 1 - 2 files changed, 85 deletions(-) delete mode 100644 Documentation/s390/dasd.rst diff --git a/Documentation/s390/dasd.rst b/Documentation/s390/dasd.rst deleted file mode 100644 index 9e22247285c8..000000000000 --- a/Documentation/s390/dasd.rst +++ /dev/null @@ -1,84 +0,0 @@ -================== -DASD device driver -================== - -S/390's disk devices (DASDs) are managed by Linux via the DASD device -driver. It is valid for all types of DASDs and represents them to -Linux as block devices, namely "dd". Currently the DASD driver uses a -single major number (254) and 4 minor numbers per volume (1 for the -physical volume and 3 for partitions). With respect to partitions see -below. Thus you may have up to 64 DASD devices in your system. - -The kernel parameter 'dasd=from-to,...' may be issued arbitrary times -in the kernel's parameter line or not at all. The 'from' and 'to' -parameters are to be given in hexadecimal notation without a leading -0x. -If you supply kernel parameters the different instances are processed -in order of appearance and a minor number is reserved for any device -covered by the supplied range up to 64 volumes. Additional DASDs are -ignored. If you do not supply the 'dasd=' kernel parameter at all, the -DASD driver registers all supported DASDs of your system to a minor -number in ascending order of the subchannel number. - -The driver currently supports ECKD-devices and there are stubs for -support of the FBA and CKD architectures. For the FBA architecture -only some smart data structures are missing to make the support -complete. -We performed our testing on 3380 and 3390 type disks of different -sizes, under VM and on the bare hardware (LPAR), using internal disks -of the multiprise as well as a RAMAC virtual array. Disks exported by -an Enterprise Storage Server (Seascape) should work fine as well. - -We currently implement one partition per volume, which is the whole -volume, skipping the first blocks up to the volume label. These are -reserved for IPL records and IBM's volume label to assure -accessibility of the DASD from other OSs. In a later stage we will -provide support of partitions, maybe VTOC oriented or using a kind of -partition table in the label record. - -Usage -===== - --Low-level format (?CKD only) -For using an ECKD-DASD as a Linux harddisk you have to low-level -format the tracks by issuing the BLKDASDFORMAT-ioctl on that -device. This will erase any data on that volume including IBM volume -labels, VTOCs etc. The ioctl may take a `struct format_data *` or -'NULL' as an argument:: - - typedef struct { - int start_unit; - int stop_unit; - int blksize; - } format_data_t; - -When a NULL argument is passed to the BLKDASDFORMAT ioctl the whole -disk is formatted to a blocksize of 1024 bytes. Otherwise start_unit -and stop_unit are the first and last track to be formatted. If -stop_unit is -1 it implies that the DASD is formatted from start_unit -up to the last track. blksize can be any power of two between 512 and -4096. We recommend no blksize lower than 1024 because the ext2fs uses -1kB blocks anyway and you gain approx. 50% of capacity increasing your -blksize from 512 byte to 1kB. - -Make a filesystem -================= - -Then you can mk??fs the filesystem of your choice on that volume or -partition. For reasons of sanity you should build your filesystem on -the partition /dev/dd?1 instead of the whole volume. You only lose 3kB -but may be sure that you can reuse your data after introduction of a -real partition table. - -Bugs -==== - -- Performance sometimes is rather low because we don't fully exploit clustering - -TODO-List -========= - -- Add IBM'S Disk layout to genhd -- Enhance driver to use more than one major number -- Enable usage as a module -- Support Cache fast write and DASD fast write (ECKD) diff --git a/Documentation/s390/index.rst b/Documentation/s390/index.rst index 4602312909d3..f8c01cb7fa37 100644 --- a/Documentation/s390/index.rst +++ b/Documentation/s390/index.rst @@ -15,7 +15,6 @@ s390 Architecture vfio-ap vfio-ccw zfcpdump - dasd common_io text_files -- cgit v1.2.3 From f62f7dcbf023160ca47eb4bc7228ece8207f8a8e Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 25 Jul 2019 09:23:39 +0200 Subject: Documentation/s390: remove outdated debugging390 documentation This file would need a lot of work to make sense again. Thomas Huth started working on that four years ago, but that wasn't finished. Therefore remove this. Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- Documentation/s390/debugging390.rst | 2613 ----------------------------------- Documentation/s390/index.rst | 1 - 2 files changed, 2614 deletions(-) delete mode 100644 Documentation/s390/debugging390.rst diff --git a/Documentation/s390/debugging390.rst b/Documentation/s390/debugging390.rst deleted file mode 100644 index 73ad0b06c666..000000000000 --- a/Documentation/s390/debugging390.rst +++ /dev/null @@ -1,2613 +0,0 @@ -============================================= -Debugging on Linux for s/390 & z/Architecture -============================================= - -Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - -Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation - -.. Best viewed with fixed width fonts - -Overview of Document: -===================== -This document is intended to give a good overview of how to debug Linux for -s/390 and z/Architecture. It is not intended as a complete reference and not a -tutorial on the fundamentals of C & assembly. It doesn't go into -390 IO in any detail. It is intended to complement the documents in the -reference section below & any other worthwhile references you get. - -It is intended like the Enterprise Systems Architecture/390 Reference Summary -to be printed out & used as a quick cheat sheet self help style reference when -problems occur. - -.. Contents - ======== - Register Set - Address Spaces on Intel Linux - Address Spaces on Linux for s/390 & z/Architecture - The Linux for s/390 & z/Architecture Kernel Task Structure - Register Usage & Stackframes on Linux for s/390 & z/Architecture - A sample program with comments - Compiling programs for debugging on Linux for s/390 & z/Architecture - Debugging under VM - s/390 & z/Architecture IO Overview - Debugging IO on s/390 & z/Architecture under VM - GDB on s/390 & z/Architecture - Stack chaining in gdb by hand - Examining core dumps - ldd - Debugging modules - The proc file system - SysRq - References - Special Thanks - -Register Set -============ -The current architectures have the following registers. - -16 General propose registers, 32 bit on s/390 and 64 bit on z/Architecture, -r0-r15 (or gpr0-gpr15), used for arithmetic and addressing. - -16 Control registers, 32 bit on s/390 and 64 bit on z/Architecture, cr0-cr15, -kernel usage only, used for memory management, interrupt control, debugging -control etc. - -16 Access registers (ar0-ar15), 32 bit on both s/390 and z/Architecture, -normally not used by normal programs but potentially could be used as -temporary storage. These registers have a 1:1 association with general -purpose registers and are designed to be used in the so-called access -register mode to select different address spaces. -Access register 0 (and access register 1 on z/Architecture, which needs a -64 bit pointer) is currently used by the pthread library as a pointer to -the current running threads private area. - -16 64-bit floating point registers (fp0-fp15 ) IEEE & HFP floating -point format compliant on G5 upwards & a Floating point control reg (FPC) - -4 64-bit registers (fp0,fp2,fp4 & fp6) HFP only on older machines. - -Note: - Linux (currently) always uses IEEE & emulates G5 IEEE format on older - machines, ( provided the kernel is configured for this ). - - -The PSW is the most important register on the machine it -is 64 bit on s/390 & 128 bit on z/Architecture & serves the roles of -a program counter (pc), condition code register,memory space designator. -In IBM standard notation I am counting bit 0 as the MSB. -It has several advantages over a normal program counter -in that you can change address translation & program counter -in a single instruction. To change address translation, -e.g. switching address translation off requires that you -have a logical=physical mapping for the address you are -currently running at. - -+-------------------------+-------------------------------------------------+ -| Bit | | -+--------+----------------+ Value | -| s/390 | z/Architecture | | -+========+================+=================================================+ -| 0 | 0 | Reserved (must be 0) otherwise specification | -| | | exception occurs. | -+--------+----------------+-------------------------------------------------+ -| 1 | 1 | Program Event Recording 1 PER enabled, | -| | | PER is used to facilitate debugging e.g. | -| | | single stepping. | -+--------+----------------+-------------------------------------------------+ -| 2-4 | 2-4 | Reserved (must be 0). | -+--------+----------------+-------------------------------------------------+ -| 5 | 5 | Dynamic address translation 1=DAT on. | -+--------+----------------+-------------------------------------------------+ -| 6 | 6 | Input/Output interrupt Mask | -+--------+----------------+-------------------------------------------------+ -| 7 | 7 | External interrupt Mask used primarily for | -| | | interprocessor signalling and clock interrupts. | -+--------+----------------+-------------------------------------------------+ -| 8-11 | 8-11 | PSW Key used for complex memory protection | -| | | mechanism (not used under linux) | -+--------+----------------+-------------------------------------------------+ -| 12 | 12 | 1 on s/390 0 on z/Architecture | -+--------+----------------+-------------------------------------------------+ -| 13 | 13 | Machine Check Mask 1=enable machine check | -| | | interrupts | -+--------+----------------+-------------------------------------------------+ -| 14 | 14 | Wait State. Set this to 1 to stop the processor | -| | | except for interrupts and give time to other | -| | | LPARS. Used in CPU idle in the kernel to | -| | | increase overall usage of processor resources. | -+--------+----------------+-------------------------------------------------+ -| 15 | 15 | Problem state (if set to 1 certain instructions | -| | | are disabled). All linux user programs run with | -| | | this bit 1 (useful info for debugging under VM).| -+--------+----------------+-------------------------------------------------+ -| 16-17 | 16-17 | Address Space Control | -| | | | -| | | 00 Primary Space Mode: | -| | | | -| | | The register CR1 contains the primary | -| | | address-space control element (PASCE), which | -| | | points to the primary space region/segment | -| | | table origin. | -| | | | -| | | 01 Access register mode | -| | | | -| | | 10 Secondary Space Mode: | -| | | | -| | | The register CR7 contains the secondary | -| | | address-space control element (SASCE), which | -| | | points to the secondary space region or | -| | | segment table origin. | -| | | | -| | | 11 Home Space Mode: | -| | | | -| | | The register CR13 contains the home space | -| | | address-space control element (HASCE), which | -| | | points to the home space region/segment | -| | | table origin. | -| | | | -| | | See "Address Spaces on Linux for s/390 & | -| | | z/Architecture" below for more information | -| | | about address space usage in Linux. | -+--------+----------------+-------------------------------------------------+ -| 18-19 | 18-19 | Condition codes (CC) | -+--------+----------------+-------------------------------------------------+ -| 20 | 20 | Fixed point overflow mask if 1=FPU exceptions | -| | | for this event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 21 | 21 | Decimal overflow mask if 1=FPU exceptions for | -| | | this event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 22 | 22 | Exponent underflow mask if 1=FPU exceptions | -| | | for this event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 23 | 23 | Significance Mask if 1=FPU exceptions for this | -| | | event occur (normally 0) | -+--------+----------------+-------------------------------------------------+ -| 24-31 | 24-30 | Reserved Must be 0. | -| +----------------+-------------------------------------------------+ -| | 31 | Extended Addressing Mode | -| +----------------+-------------------------------------------------+ -| | 32 | Basic Addressing Mode | -| | | | -| | | Used to set addressing mode:: | -| | | | -| | | +---------+----------+----------+ | -| | | | PSW 31 | PSW 32 | | | -| | | +---------+----------+----------+ | -| | | | 0 | 0 | 24 bit | | -| | | +---------+----------+----------+ | -| | | | 0 | 1 | 31 bit | | -| | | +---------+----------+----------+ | -| | | | 1 | 1 | 64 bit | | -| | | +---------+----------+----------+ | -+--------+----------------+-------------------------------------------------+ -| 32 | | 1=31 bit addressing mode 0=24 bit addressing | -| | | mode (for backward compatibility), linux | -| | | always runs with this bit set to 1 | -+--------+----------------+-------------------------------------------------+ -| 33-64 | | Instruction address. | -| +----------------+-------------------------------------------------+ -| | 33-63 | Reserved must be 0 | -| +----------------+-------------------------------------------------+ -| | 64-127 | Address | -| | | | -| | | - In 24 bits mode bits 64-103=0 bits 104-127 | -| | | Address | -| | | - In 31 bits mode bits 64-96=0 bits 97-127 | -| | | Address | -| | | | -| | | Note: | -| | | unlike 31 bit mode on s/390 bit 96 must be | -| | | zero when loading the address with LPSWE | -| | | otherwise a specification exception occurs, | -| | | LPSW is fully backward compatible. | -+--------+----------------+-------------------------------------------------+ - -Prefix Page(s) --------------- -This per cpu memory area is too intimately tied to the processor not to mention. -It exists between the real addresses 0-4096 on s/390 and between 0-8192 on -z/Architecture and is exchanged with one page on s/390 or two pages on -z/Architecture in absolute storage by the set prefix instruction during Linux -startup. - -This page is mapped to a different prefix for each processor in an SMP -configuration (assuming the OS designer is sane of course). - -Bytes 0-512 (200 hex) on s/390 and 0-512, 4096-4544, 4604-5119 currently on -z/Architecture are used by the processor itself for holding such information -as exception indications and entry points for exceptions. - -Bytes after 0xc00 hex are used by linux for per processor globals on s/390 and -z/Architecture (there is a gap on z/Architecture currently between 0xc00 and -0x1000, too, which is used by Linux). - -The closest thing to this on traditional architectures is the interrupt -vector table. This is a good thing & does simplify some of the kernel coding -however it means that we now cannot catch stray NULL pointers in the -kernel without hard coded checks. - - - -Address Spaces on Intel Linux -============================= - -The traditional Intel Linux is approximately mapped as follows forgive -the ascii art:: - - 0xFFFFFFFF 4GB Himem ***************** - * * - * Kernel Space * - * * - ***************** **************** - User Space Himem * User Stack * * * - (typically 0xC0000000 3GB ) ***************** * * - * Shared Libs * * Next Process * - ***************** * to * - * * <== * Run * <== - * User Program * * * - * Data BSS * * * - * Text * * * - * Sections * * * - 0x00000000 ***************** **************** - -Now it is easy to see that on Intel it is quite easy to recognise a kernel -address as being one greater than user space himem (in this case 0xC0000000), -and addresses of less than this are the ones in the current running program on -this processor (if an smp box). - -If using the virtual machine ( VM ) as a debugger it is quite difficult to -know which user process is running as the address space you are looking at -could be from any process in the run queue. - -The limitation of Intels addressing technique is that the linux -kernel uses a very simple real address to virtual addressing technique -of Real Address=Virtual Address-User Space Himem. -This means that on Intel the kernel linux can typically only address -Himem=0xFFFFFFFF-0xC0000000=1GB & this is all the RAM these machines -can typically use. - -They can lower User Himem to 2GB or lower & thus be -able to use 2GB of RAM however this shrinks the maximum size -of User Space from 3GB to 2GB they have a no win limit of 4GB unless -they go to 64 Bit. - - -On 390 our limitations & strengths make us slightly different. -For backward compatibility we are only allowed use 31 bits (2GB) -of our 32 bit addresses, however, we use entirely separate address -spaces for the user & kernel. - -This means we can support 2GB of non Extended RAM on s/390, & more -with the Extended memory management swap device & -currently 4TB of physical memory currently on z/Architecture. - - -Address Spaces on Linux for s/390 & z/Architecture -================================================== - -Our addressing scheme is basically as follows:: - - Primary Space Home Space - Himem 0x7fffffff 2GB on s/390 ***************** **************** - currently 0x3ffffffffff (2^42)-1 * User Stack * * * - on z/Architecture. ***************** * * - * Shared Libs * * * - ***************** * * - * * * Kernel * - * User Program * * * - * Data BSS * * * - * Text * * * - * Sections * * * - 0x00000000 ***************** **************** - -This also means that we need to look at the PSW problem state bit and the -addressing mode to decide whether we are looking at user or kernel space. - -User space runs in primary address mode (or access register mode within -the vdso code). - -The kernel usually also runs in home space mode, however when accessing -user space the kernel switches to primary or secondary address mode if -the mvcos instruction is not available or if a compare-and-swap (futex) -instruction on a user space address is performed. - -When also looking at the ASCE control registers, this means: - -User space: - -- runs in primary or access register mode -- cr1 contains the user asce -- cr7 contains the user asce -- cr13 contains the kernel asce - -Kernel space: - -- runs in home space mode -- cr1 contains the user or kernel asce - - - the kernel asce is loaded when a uaccess requires primary or - secondary address mode - -- cr7 contains the user or kernel asce, (changed with set_fs()) -- cr13 contains the kernel asce - -In case of uaccess the kernel changes to: - -- primary space mode in case of a uaccess (copy_to_user) and uses - e.g. the mvcp instruction to access user space. However the kernel - will stay in home space mode if the mvcos instruction is available -- secondary space mode in case of futex atomic operations, so that the - instructions come from primary address space and data from secondary - space - -In case of KVM, the kernel runs in home space mode, but cr1 gets switched -to contain the gmap asce before the SIE instruction gets executed. When -the SIE instruction is finished, cr1 will be switched back to contain the -user asce. - - -Virtual Addresses on s/390 & z/Architecture -=========================================== - -A virtual address on s/390 is made up of 3 parts -The SX (segment index, roughly corresponding to the PGD & PMD in Linux -terminology) being bits 1-11. - -The PX (page index, corresponding to the page table entry (pte) in Linux -terminology) being bits 12-19. - -The remaining bits BX (the byte index are the offset in the page ) -i.e. bits 20 to 31. - -On z/Architecture in linux we currently make up an address from 4 parts. - -- The region index bits (RX) 0-32 we currently use bits 22-32 -- The segment index (SX) being bits 33-43 -- The page index (PX) being bits 44-51 -- The byte index (BX) being bits 52-63 - -Notes: - 1) s/390 has no PMD so the PMD is really the PGD also. - A lot of this stuff is defined in pgtable.h. - - 2) Also seeing as s/390's page indexes are only 1k in size - (bits 12-19 x 4 bytes per pte ) we use 1 ( page 4k ) - to make the best use of memory by updating 4 segment indices - entries each time we mess with a PMD & use offsets - 0,1024,2048 & 3072 in this page as for our segment indexes. - On z/Architecture our page indexes are now 2k in size - ( bits 12-19 x 8 bytes per pte ) we do a similar trick - but only mess with 2 segment indices each time we mess with - a PMD. - - 3) As z/Architecture supports up to a massive 5-level page table lookup we - can only use 3 currently on Linux ( as this is all the generic kernel - currently supports ) however this may change in future - this allows us to access ( according to my sums ) - 4TB of virtual storage per process i.e. - 4096*512(PTES)*1024(PMDS)*2048(PGD) = 4398046511104 bytes, - enough for another 2 or 3 of years I think :-). - to do this we use a region-third-table designation type in - our address space control registers. - - -The Linux for s/390 & z/Architecture Kernel Task Structure -========================================================== -Each process/thread under Linux for S390 has its own kernel task_struct -defined in linux/include/linux/sched.h -The S390 on initialisation & resuming of a process on a cpu sets -the __LC_KERNEL_STACK variable in the spare prefix area for this cpu -(which we use for per-processor globals). - -The kernel stack pointer is intimately tied with the task structure for -each processor as follows:: - - s/390 - ************************ - * 1 page kernel stack * - * ( 4K ) * - ************************ - * 1 page task_struct * - * ( 4K ) * - 8K aligned ************************ - - z/Architecture - ************************ - * 2 page kernel stack * - * ( 8K ) * - ************************ - * 2 page task_struct * - * ( 8K ) * - 16K aligned ************************ - -What this means is that we don't need to dedicate any register or global -variable to point to the current running process & can retrieve it with the -following very simple construct for s/390 & one very similar for -z/Architecture:: - - static inline struct task_struct * get_current(void) - { - struct task_struct *current; - __asm__("lhi %0,-8192\n\t" - "nr %0,15" - : "=r" (current) ); - return current; - } - -i.e. just anding the current kernel stack pointer with the mask -8192. -Thankfully because Linux doesn't have support for nested IO interrupts -& our devices have large buffers can survive interrupts being shut for -short amounts of time we don't need a separate stack for interrupts. - - - - -Register Usage & Stackframes on Linux for s/390 & z/Architecture -================================================================= -Overview: ---------- -This is the code that gcc produces at the top & the bottom of -each function. It usually is fairly consistent & similar from -function to function & if you know its layout you can probably -make some headway in finding the ultimate cause of a problem -after a crash without a source level debugger. - -Note: To follow stackframes requires a knowledge of C or Pascal & -limited knowledge of one assembly language. - -It should be noted that there are some differences between the -s/390 and z/Architecture stack layouts as the z/Architecture stack layout -didn't have to maintain compatibility with older linkage formats. - -Glossary: ---------- -alloca: - This is a built in compiler function for runtime allocation - of extra space on the callers stack which is obviously freed - up on function exit ( e.g. the caller may choose to allocate nothing - of a buffer of 4k if required for temporary purposes ), it generates - very efficient code ( a few cycles ) when compared to alternatives - like malloc. - -automatics: - These are local variables on the stack, i.e they aren't in registers & - they aren't static. - -back-chain: - This is a pointer to the stack pointer before entering a - framed functions ( see frameless function ) prologue got by - dereferencing the address of the current stack pointer, - i.e. got by accessing the 32 bit value at the stack pointers - current location. - -base-pointer: - This is a pointer to the back of the literal pool which - is an area just behind each procedure used to store constants - in each function. - -call-clobbered: - The caller probably needs to save these registers if there - is something of value in them, on the stack or elsewhere before making a - call to another procedure so that it can restore it later. - -epilogue: - The code generated by the compiler to return to the caller. - -frameless-function: - A frameless function in Linux for s390 & z/Architecture is one which doesn't - need more than the register save area (96 bytes on s/390, 160 on z/Architecture) - given to it by the caller. - - A frameless function never: - - 1) Sets up a back chain. - 2) Calls alloca. - 3) Calls other normal functions - 4) Has automatics. - -GOT-pointer: - This is a pointer to the global-offset-table in ELF - ( Executable Linkable Format, Linux'es most common executable format ), - all globals & shared library objects are found using this pointer. - -lazy-binding - ELF shared libraries are typically only loaded when routines in the shared - library are actually first called at runtime. This is lazy binding. - -procedure-linkage-table - This is a table found from the GOT which contains pointers to routines - in other shared libraries which can't be called to by easier means. - -prologue: - The code generated by the compiler to set up the stack frame. - -outgoing-args: - This is extra area allocated on the stack of the calling function if the - parameters for the callee's cannot all be put in registers, the same - area can be reused by each function the caller calls. - -routine-descriptor: - A COFF executable format based concept of a procedure reference - actually being 8 bytes or more as opposed to a simple pointer to the routine. - This is typically defined as follows: - - - Routine Descriptor offset 0=Pointer to Function - - Routine Descriptor offset 4=Pointer to Table of Contents - - The table of contents/TOC is roughly equivalent to a GOT pointer. - & it means that shared libraries etc. can be shared between several - environments each with their own TOC. - -static-chain: - This is used in nested functions a concept adopted from pascal - by gcc not used in ansi C or C++ ( although quite useful ), basically it - is a pointer used to reference local variables of enclosing functions. - You might come across this stuff once or twice in your lifetime. - - e.g. - - The function below should return 11 though gcc may get upset & toss warnings - about unused variables:: - - int FunctionA(int a) - { - int b; - FunctionC(int c) - { - b=c+1; - } - FunctionC(10); - return(b); - } - - -s/390 & z/Architecture Register usage -===================================== - -======== ========================================== =============== -r0 used by syscalls/assembly call-clobbered -r1 used by syscalls/assembly call-clobbered -r2 argument 0 / return value 0 call-clobbered -r3 argument 1 / return value 1 (if long long) call-clobbered -r4 argument 2 call-clobbered -r5 argument 3 call-clobbered -r6 argument 4 saved -r7 pointer-to arguments 5 to ... saved -r8 this & that saved -r9 this & that saved -r10 static-chain ( if nested function ) saved -r11 frame-pointer ( if function used alloca ) saved -r12 got-pointer saved -r13 base-pointer saved -r14 return-address saved -r15 stack-pointer saved - -f0 argument 0 / return value ( float/double ) call-clobbered -f2 argument 1 call-clobbered -f4 z/Architecture argument 2 saved -f6 z/Architecture argument 3 saved -======== ========================================== =============== - -The remaining floating points -f1,f3,f5 f7-f15 are call-clobbered. - -Notes: ------- -1) The only requirement is that registers which are used - by the callee are saved, e.g. the compiler is perfectly - capable of using r11 for purposes other than a frame a - frame pointer if a frame pointer is not needed. -2) In functions with variable arguments e.g. printf the calling procedure - is identical to one without variable arguments & the same number of - parameters. However, the prologue of this function is somewhat more - hairy owing to it having to move these parameters to the stack to - get va_start, va_arg & va_end to work. -3) Access registers are currently unused by gcc but are used in - the kernel. Possibilities exist to use them at the moment for - temporary storage but it isn't recommended. -4) Only 4 of the floating point registers are used for - parameter passing as older machines such as G3 only have only 4 - & it keeps the stack frame compatible with other compilers. - However with IEEE floating point emulation under linux on the - older machines you are free to use the other 12. -5) A long long or double parameter cannot be have the - first 4 bytes in a register & the second four bytes in the - outgoing args area. It must be purely in the outgoing args - area if crossing this boundary. -6) Floating point parameters are mixed with outgoing args - on the outgoing args area in the order the are passed in as parameters. -7) Floating point arguments 2 & 3 are saved in the outgoing args area for - z/Architecture - - -Stack Frame Layout ------------------- - -========= ============== ====================================================== -s/390 z/Architecture -========= ============== ====================================================== -0 0 back chain ( a 0 here signifies end of back chain ) -4 8 eos ( end of stack, not used on Linux for S390 used - in other linkage formats ) -8 16 glue used in other s/390 linkage formats for saved - routine descriptors etc. -12 24 glue used in other s/390 linkage formats for saved - routine descriptors etc. -16 32 scratch area -20 40 scratch area -24 48 saved r6 of caller function -28 56 saved r7 of caller function -32 64 saved r8 of caller function -36 72 saved r9 of caller function -40 80 saved r10 of caller function -44 88 saved r11 of caller function -48 96 saved r12 of caller function -52 104 saved r13 of caller function -56 112 saved r14 of caller function -60 120 saved r15 of caller function -64 128 saved f4 of caller function -72 132 saved f6 of caller function -80 undefined -96 160 outgoing args passed from caller to callee -96+x 160+x possible stack alignment ( 8 bytes desirable ) -96+x+y 160+x+y alloca space of caller ( if used ) -96+x+y+z 160+x+y+z automatics of caller ( if used ) -0 back-chain -========= ============== ====================================================== - -A sample program with comments. -=============================== - -Comments on the function test ------------------------------ -1) It didn't need to set up a pointer to the constant pool gpr13 as it is not - used ( :-( ). -2) This is a frameless function & no stack is bought. -3) The compiler was clever enough to recognise that it could return the - value in r2 as well as use it for the passed in parameter ( :-) ). -4) The basr ( branch relative & save ) trick works as follows the instruction - has a special case with r0,r0 with some instruction operands is understood as - the literal value 0, some risc architectures also do this ). So now - we are branching to the next address & the address new program counter is - in r13,so now we subtract the size of the function prologue we have executed - the size of the literal pool to get to the top of the literal pool:: - - - 0040037c int test(int b) - { # Function prologue below - 40037c: 90 de f0 34 stm %r13,%r14,52(%r15) # Save registers r13 & r14 - 400380: 0d d0 basr %r13,%r0 # Set up pointer to constant pool using - 400382: a7 da ff fa ahi %r13,-6 # basr trick - return(5+b); - # Huge main program - 400386: a7 2a 00 05 ahi %r2,5 # add 5 to r2 - - # Function epilogue below - 40038a: 98 de f0 34 lm %r13,%r14,52(%r15) # restore registers r13 & 14 - 40038e: 07 fe br %r14 # return - } - -Comments on the function main ------------------------------ -1) The compiler did this function optimally ( 8-) ):: - - Literal pool for main. - 400390: ff ff ff ec .long 0xffffffec - main(int argc,char *argv[]) - { # Function prologue below - 400394: 90 bf f0 2c stm %r11,%r15,44(%r15) # Save necessary registers - 400398: 18 0f lr %r0,%r15 # copy stack pointer to r0 - 40039a: a7 fa ff a0 ahi %r15,-96 # Make area for callee saving - 40039e: 0d d0 basr %r13,%r0 # Set up r13 to point to - 4003a0: a7 da ff f0 ahi %r13,-16 # literal pool - 4003a4: 50 00 f0 00 st %r0,0(%r15) # Save backchain - - return(test(5)); # Main Program Below - 4003a8: 58 e0 d0 00 l %r14,0(%r13) # load relative address of test from - # literal pool - 4003ac: a7 28 00 05 lhi %r2,5 # Set first parameter to 5 - 4003b0: 4d ee d0 00 bas %r14,0(%r14,%r13) # jump to test setting r14 as return - # address using branch & save instruction. - - # Function Epilogue below - 4003b4: 98 bf f0 8c lm %r11,%r15,140(%r15)# Restore necessary registers. - 4003b8: 07 fe br %r14 # return to do program exit - } - - -Compiler updates ----------------- - -:: - - main(int argc,char *argv[]) - { - 4004fc: 90 7f f0 1c stm %r7,%r15,28(%r15) - 400500: a7 d5 00 04 bras %r13,400508 - 400504: 00 40 04 f4 .long 0x004004f4 - # compiler now puts constant pool in code to so it saves an instruction - 400508: 18 0f lr %r0,%r15 - 40050a: a7 fa ff a0 ahi %r15,-96 - 40050e: 50 00 f0 00 st %r0,0(%r15) - return(test(5)); - 400512: 58 10 d0 00 l %r1,0(%r13) - 400516: a7 28 00 05 lhi %r2,5 - 40051a: 0d e1 basr %r14,%r1 - # compiler adds 1 extra instruction to epilogue this is done to - # avoid processor pipeline stalls owing to data dependencies on g5 & - # above as register 14 in the old code was needed directly after being loaded - # by the lm %r11,%r15,140(%r15) for the br %14. - 40051c: 58 40 f0 98 l %r4,152(%r15) - 400520: 98 7f f0 7c lm %r7,%r15,124(%r15) - 400524: 07 f4 br %r4 - } - - -Hartmut ( our compiler developer ) also has been threatening to take out the -stack backchain in optimised code as this also causes pipeline stalls, you -have been warned. - -64 bit z/Architecture code disassembly --------------------------------------- - -If you understand the stuff above you'll understand the stuff -below too so I'll avoid repeating myself & just say that -some of the instructions have g's on the end of them to indicate -they are 64 bit & the stack offsets are a bigger, -the only other difference you'll find between 32 & 64 bit is that -we now use f4 & f6 for floating point arguments on 64 bit:: - - 00000000800005b0 : - int test(int b) - { - return(5+b); - 800005b0: a7 2a 00 05 ahi %r2,5 - 800005b4: b9 14 00 22 lgfr %r2,%r2 # downcast to integer - 800005b8: 07 fe br %r14 - 800005ba: 07 07 bcr 0,%r7 - - - } - - 00000000800005bc
: - main(int argc,char *argv[]) - { - 800005bc: eb bf f0 58 00 24 stmg %r11,%r15,88(%r15) - 800005c2: b9 04 00 1f lgr %r1,%r15 - 800005c6: a7 fb ff 60 aghi %r15,-160 - 800005ca: e3 10 f0 00 00 24 stg %r1,0(%r15) - return(test(5)); - 800005d0: a7 29 00 05 lghi %r2,5 - # brasl allows jumps > 64k & is overkill here bras would do fune - 800005d4: c0 e5 ff ff ff ee brasl %r14,800005b0 - 800005da: e3 40 f1 10 00 04 lg %r4,272(%r15) - 800005e0: eb bf f0 f8 00 04 lmg %r11,%r15,248(%r15) - 800005e6: 07 f4 br %r4 - } - - - -Compiling programs for debugging on Linux for s/390 & z/Architecture -==================================================================== --gdwarf-2 now works it should be considered the default debugging -format for s/390 & z/Architecture as it is more reliable for debugging -shared libraries, normal -g debugging works much better now -Thanks to the IBM java compiler developers bug reports. - -This is typically done adding/appending the flags -g or -gdwarf-2 to the -CFLAGS & LDFLAGS variables Makefile of the program concerned. - -If using gdb & you would like accurate displays of registers & -stack traces compile without optimisation i.e make sure -that there is no -O2 or similar on the CFLAGS line of the Makefile & -the emitted gcc commands, obviously this will produce worse code -( not advisable for shipment ) but it is an aid to the debugging process. - -This aids debugging because the compiler will copy parameters passed in -in registers onto the stack so backtracing & looking at passed in -parameters will work, however some larger programs which use inline functions -will not compile without optimisation. - -Debugging with optimisation has since much improved after fixing -some bugs, please make sure you are using gdb-5.0 or later developed -after Nov'2000. - - - -Debugging under VM -================== - -Notes ------ -Addresses & values in the VM debugger are always hex never decimal -Address ranges are of the format - or -. -For example, the address range 0x2000 to 0x3000 can be described as 2000-3000 -or 2000.1000 - -The VM Debugger is case insensitive. - -VM's strengths are usually other debuggers weaknesses you can get at any -resource no matter how sensitive e.g. memory management resources, change -address translation in the PSW. For kernel hacking you will reap dividends if -you get good at it. - -The VM Debugger displays operators but not operands, and also the debugger -displays useful information on the same line as the author of the code probably -felt that it was a good idea not to go over the 80 columns on the screen. -This isn't as unintuitive as it may seem as the s/390 instructions are easy to -decode mentally and you can make a good guess at a lot of them as all the -operands are nibble (half byte aligned). -So if you have an objdump listing by hand, it is quite easy to follow, and if -you don't have an objdump listing keep a copy of the s/390 Reference Summary -or alternatively the s/390 principles of operation next to you. -e.g. even I can guess that -0001AFF8' LR 180F CC 0 -is a ( load register ) lr r0,r15 - -Also it is very easy to tell the length of a 390 instruction from the 2 most -significant bits in the instruction (not that this info is really useful except -if you are trying to make sense of a hexdump of code). -Here is a table - -======================= ================== -Bits Instruction Length -======================= ================== -00 2 Bytes -01 4 Bytes -10 4 Bytes -11 6 Bytes -======================= ================== - -The debugger also displays other useful info on the same line such as the -addresses being operated on destination addresses of branches & condition codes. -e.g.:: - - 00019736' AHI A7DAFF0E CC 1 - 000198BA' BRC A7840004 -> 000198C2' CC 0 - 000198CE' STM 900EF068 >> 0FA95E78 CC 2 - - - -Useful VM debugger commands ---------------------------- - -I suppose I'd better mention this before I start -to list the current active traces do:: - - Q TR - -there can be a maximum of 255 of these per set -( more about trace sets later ). - -To stop traces issue a:: - - TR END. - -To delete a particular breakpoint issue:: - - TR DEL - -The PA1 key drops to CP mode so you can issue debugger commands, -Doing alt c (on my 3270 console at least ) clears the screen. - -hitting b comes back to the running operating system -from cp mode ( in our case linux ). - -It is typically useful to add shortcuts to your profile.exec file -if you have one ( this is roughly equivalent to autoexec.bat in DOS ). -file here are a few from mine:: - - /* this gives me command history on issuing f12 */ - set pf12 retrieve - /* this continues */ - set pf8 imm b - /* goes to trace set a */ - set pf1 imm tr goto a - /* goes to trace set b */ - set pf2 imm tr goto b - /* goes to trace set c */ - set pf3 imm tr goto c - - - -Instruction Tracing -------------------- -Setting a simple breakpoint:: - - TR I PSWA
- -To debug a particular function try:: - - TR I R - TR I on its own will single step. - TR I DATA will trace for particular mnemonics - -e.g.:: - - TR I DATA 4D R 0197BC.4000 - -will trace for BAS'es ( opcode 4D ) in the range 0197BC.4000 - -if you were inclined you could add traces for all branch instructions & -suffix them with the run prefix so you would have a backtrace on screen -when a program crashes:: - - TR BR will trace branches into or out of an address. - -e.g.:: - - TR BR INTO 0 - -is often quite useful if a program is getting awkward & deciding -to branch to 0 & crashing as this will stop at the address before in jumps to 0. - -:: - - TR I R
RUN cmd d g - -single steps a range of addresses but stays running & -displays the gprs on each step. - - - -Displaying & modifying Registers --------------------------------- -D G - will display all the gprs - -Adding a extra G to all the commands is necessary to access the full 64 bit -content in VM on z/Architecture. Obviously this isn't required for access -registers as these are still 32 bit. - -e.g. - -DGG - instead of DG - -D X - will display all the control registers -D AR - will display all the access registers -D AR4-7 - will display access registers 4 to 7 -CPU ALL D G - will display the GRPS of all CPUS in the configuration -D PSW - will display the current PSW -st PSW 2000 - will put the value 2000 into the PSW & cause crash your machine. -D PREFIX - displays the prefix offset - - -Displaying Memory ------------------ -To display memory mapped using the current PSW's mapping try:: - - D - -To make VM display a message each time it hits a particular address and -continue try: - -D I - will disassemble/display a range of instructions. - -ST addr 32 bit word - will store a 32 bit aligned address -D T - will display the EBCDIC in an address (if you are that way inclined) -D R - will display real addresses ( without DAT ) but with prefixing. - -There are other complex options to display if you need to get at say home space -but are in primary space the easiest thing to do is to temporarily -modify the PSW to the other addressing mode, display the stuff & then -restore it. - - - -Hints ------ -If you want to issue a debugger command without halting your virtual machine -with the PA1 key try prefixing the command with #CP e.g.:: - - #cp tr i pswa 2000 - -also suffixing most debugger commands with RUN will cause them not -to stop just display the mnemonic at the current instruction on the console. - -If you have several breakpoints you want to put into your program & -you get fed up of cross referencing with System.map -you can do the following trick for several symbols. - -:: - - grep do_signal System.map - -which emits the following among other things:: - - 0001f4e0 T do_signal - -now you can do:: - - TR I PSWA 0001f4e0 cmd msg * do_signal - -This sends a message to your own console each time do_signal is entered. -( As an aside I wrote a perl script once which automatically generated a REXX -script with breakpoints on every kernel procedure, this isn't a good idea -because there are thousands of these routines & VM can only set 255 breakpoints -at a time so you nearly had to spend as long pruning the file down as you would -entering the msgs by hand), however, the trick might be useful for a single -object file. In the 3270 terminal emulator x3270 there is a very useful option -in the file menu called "Save Screen In File" - this is very good for keeping a -copy of traces. - -From CMS help will give you online help on a particular command. -e.g.:: - - HELP DISPLAY - -Also CP has a file called profile.exec which automatically gets called -on startup of CMS ( like autoexec.bat ), keeping on a DOS analogy session -CP has a feature similar to doskey, it may be useful for you to -use profile.exec to define some keystrokes. - -SET PF9 IMM B - This does a single step in VM on pressing F8. - -SET PF10 ^ - This sets up the ^ key. - which can be used for ^c (ctrl-c),^z (ctrl-z) which can't be typed - directly into some 3270 consoles. - -SET PF11 ^- - This types the starting keystrokes for a sysrq see SysRq below. -SET PF12 RETRIEVE - This retrieves command history on pressing F12. - - -Sometimes in VM the display is set up to scroll automatically this -can be very annoying if there are messages you wish to look at -to stop this do - -TERM MORE 255 255 - This will nearly stop automatic screen updates, however it will - cause a denial of service if lots of messages go to the 3270 console, - so it would be foolish to use this as the default on a production machine. - - -Tracing particular processes ----------------------------- -The kernel's text segment is intentionally at an address in memory that it will -very seldom collide with text segments of user programs ( thanks Martin ), -this simplifies debugging the kernel. -However it is quite common for user processes to have addresses which collide -this can make debugging a particular process under VM painful under normal -circumstances as the process may change when doing a:: - - TR I R
. - -Thankfully after reading VM's online help I figured out how to debug -I particular process. - -Your first problem is to find the STD ( segment table designation ) -of the program you wish to debug. -There are several ways you can do this here are a few - -Run:: - - objdump --syms | grep main - -To get the address of main in the program. Then:: - - tr i pswa
- -Start the program, if VM drops to CP on what looks like the entry -point of the main function this is most likely the process you wish to debug. -Now do a D X13 or D XG13 on z/Architecture. - -On 31 bit the STD is bits 1-19 ( the STO segment table origin ) -& 25-31 ( the STL segment table length ) of CR13. - -now type:: - - TR I R STD 0.7fffffff - -e.g.:: - - TR I R STD 8F32E1FF 0.7fffffff - -Another very useful variation is:: - - TR STORE INTO STD
- -for finding out when a particular variable changes. - -An alternative way of finding the STD of a currently running process -is to do the following, ( this method is more complex but -could be quite convenient if you aren't updating the kernel much & -so your kernel structures will stay constant for a reasonable period of -time ). - -:: - - grep task /proc//status - -from this you should see something like:: - - task: 0f160000 ksp: 0f161de8 pt_regs: 0f161f68 - -This now gives you a pointer to the task structure. - -Now make:: - - CC:="s390-gcc -g" kernel/sched.s - -To get the task_struct stabinfo. - -( task_struct is defined in include/linux/sched.h ). - -Now we want to look at -task->active_mm->pgd - -on my machine the active_mm in the task structure stab is -active_mm:(4,12),672,32 - -its offset is 672/8=84=0x54 - -the pgd member in the mm_struct stab is -pgd:(4,6)=*(29,5),96,32 -so its offset is 96/8=12=0xc - -so we'll:: - - hexdump -s 0xf160054 /dev/mem | more - -i.e. task_struct+active_mm offset -to look at the active_mm member:: - - f160054 0fee cc60 0019 e334 0000 0000 0000 0011 - -:: - - hexdump -s 0x0feecc6c /dev/mem | more - -i.e. active_mm+pgd offset:: - - feecc6c 0f2c 0000 0000 0001 0000 0001 0000 0010 - -we get something like -now do:: - - TR I R STD 0.7fffffff - -i.e. the 0x7f is added because the pgd only -gives the page table origin & we need to set the low bits -to the maximum possible segment table length. - -:: - - TR I R STD 0f2c007f 0.7fffffff - -on z/Architecture you'll probably need to do:: - - TR I R STD 0.ffffffffffffffff - -to set the TableType to 0x1 & the Table length to 3. - - - -Tracing Program Exceptions --------------------------- -If you get a crash which says something like -illegal operation or specification exception followed by a register dump -You can restart linux & trace these using the tr prog trace -option. - - -The most common ones you will normally be tracing for is: - -- 1=operation exception -- 2=privileged operation exception -- 4=protection exception -- 5=addressing exception -- 6=specification exception -- 10=segment translation exception -- 11=page translation exception - -The full list of these is on page 22 of the current s/390 Reference Summary. -e.g. - -tr prog 10 will trace segment translation exceptions. - -tr prog on its own will trace all program interruption codes. - -Trace Sets ----------- -On starting VM you are initially in the INITIAL trace set. -You can do a Q TR to verify this. -If you have a complex tracing situation where you wish to wait for instance -till a driver is open before you start tracing IO, but know in your -heart that you are going to have to make several runs through the code till you -have a clue whats going on. - -What you can do is:: - - TR I PSWA - -hit b to continue till breakpoint - -reach the breakpoint - -now do your:: - - TR GOTO B - TR IO 7c08-7c09 inst int run - -or whatever the IO channels you wish to trace are & hit b - -To got back to the initial trace set do:: - - TR GOTO INITIAL - -& the TR I PSWA will be the only active breakpoint again. - - -Tracing linux syscalls under VM -------------------------------- -Syscalls are implemented on Linux for S390 by the Supervisor call instruction -(SVC). There 256 possibilities of these as the instruction is made up of a 0xA -opcode and the second byte being the syscall number. They are traced using the -simple command:: - - TR SVC - -the syscalls are defined in linux/arch/s390/include/asm/unistd.h -e.g. to trace all file opens just do:: - - TR SVC 5 ( as this is the syscall number of open ) - - -SMP Specific commands ---------------------- -To find out how many cpus you have -Q CPUS displays all the CPU's available to your virtual machine -To find the cpu that the current cpu VM debugger commands are being directed at -do Q CPU to change the current cpu VM debugger commands are being directed at -do:: - - CPU - -On a SMP guest issue a command to all CPUs try prefixing the command with cpu -all. To issue a command to a particular cpu try cpu e.g.:: - - CPU 01 TR I R 2000.3000 - -If you are running on a guest with several cpus & you have a IO related problem -& cannot follow the flow of code but you know it isn't smp related. - -from the bash prompt issue:: - - shutdown -h now or halt. - -do a:: - - Q CPUS - -to find out how many cpus you have detach each one of them from cp except -cpu 0 by issuing a:: - - DETACH CPU 01-(number of cpus in configuration) - -& boot linux again. - -TR SIGP - will trace inter processor signal processor instructions. - -DEFINE CPU 01-(number in configuration) - will get your guests cpus back. - - -Help for displaying ascii textstrings -------------------------------------- -On the very latest VM Nucleus'es VM can now display ascii -( thanks Neale for the hint ) by doing:: - - D TX. - -e.g.:: - - D TX0.100 - -Alternatively -============= -Under older VM debuggers (I love EBDIC too) you can use following little -program which converts a command line of hex digits to ascii text. It can be -compiled under linux and you can copy the hex digits from your x3270 terminal -to your xterm if you are debugging from a linuxbox. - -This is quite useful when looking at a parameter passed in as a text string -under VM ( unless you are good at decoding ASCII in your head ). - -e.g. consider tracing an open syscall:: - - TR SVC 5 - -We have stopped at a breakpoint:: - - 000151B0' SVC 0A05 -> 0001909A' CC 0 - -D 20.8 to check the SVC old psw in the prefix area and see was it from userspace -(for the layout of the prefix area consult the "Fixed Storage Locations" -chapter of the s/390 Reference Summary if you have it available). - -:: - - V00000020 070C2000 800151B2 - -The problem state bit wasn't set & it's also too early in the boot sequence -for it to be a userspace SVC if it was we would have to temporarily switch the -psw to user space addressing so we could get at the first parameter of the open -in gpr2. - -Next do a:: - - D G2 - GPR 2 = 00014CB4 - -Now display what gpr2 is pointing to:: - - D 00014CB4.20 - V00014CB4 2F646576 2F636F6E 736F6C65 00001BF5 - V00014CC4 FC00014C B4001001 E0001000 B8070707 - -Now copy the text till the first 00 hex ( which is the end of the string -to an xterm & do hex2ascii on it:: - - hex2ascii 2F646576 2F636F6E 736F6C65 00 - -outputs:: - - Decoded Hex:=/ d e v / c o n s o l e 0x00 - -We were opening the console device, - -You can compile the code below yourself for practice :-), - -:: - - /* - * hex2ascii.c - * a useful little tool for converting a hexadecimal command line to ascii - * - * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation. - */ - #include - - int main(int argc,char *argv[]) - { - int cnt1,cnt2,len,toggle=0; - int startcnt=1; - unsigned char c,hex; - - if(argc>1&&(strcmp(argv[1],"-a")==0)) - startcnt=2; - printf("Decoded Hex:="); - for(cnt1=startcnt;cnt1='0'&&c<='9') - c=c-'0'; - if(c>='A'&&c<='F') - c=c-'A'+10; - if(c>='a'&&c<='f') - c=c-'a'+10; - switch(toggle) - { - case 0: - hex=c<<4; - toggle=1; - break; - case 1: - hex+=c; - if(hex<32||hex>127) - { - if(startcnt==1) - printf("0x%02X ",(int)hex); - else - printf("."); - } - else - { - printf("%c",hex); - if(startcnt==1) - printf(" "); - } - toggle=0; - break; - } - } - } - printf("\n"); - } - - - - -Stack tracing under VM ----------------------- -A basic backtrace ------------------ - -Here are the tricks I use 9 out of 10 times it works pretty well, - -When your backchain reaches a dead end --------------------------------------- -This can happen when an exception happens in the kernel and the kernel is -entered twice. If you reach the NULL pointer at the end of the back chain you -should be able to sniff further back if you follow the following tricks. -1) A kernel address should be easy to recognise since it is in -primary space & the problem state bit isn't set & also -The Hi bit of the address is set. -2) Another backchain should also be easy to recognise since it is an -address pointing to another address approximately 100 bytes or 0x70 hex -behind the current stackpointer. - - -Here is some practice. - -boot the kernel & hit PA1 at some random time - -d g to display the gprs, this should display something like:: - - GPR 0 = 00000001 00156018 0014359C 00000000 - GPR 4 = 00000001 001B8888 000003E0 00000000 - GPR 8 = 00100080 00100084 00000000 000FE000 - GPR 12 = 00010400 8001B2DC 8001B36A 000FFED8 - -Note that GPR14 is a return address but as we are real men we are going to -trace the stack. -display 0x40 bytes after the stack pointer:: - - V000FFED8 000FFF38 8001B838 80014C8E 000FFF38 - V000FFEE8 00000000 00000000 000003E0 00000000 - V000FFEF8 00100080 00100084 00000000 000FE000 - V000FFF08 00010400 8001B2DC 8001B36A 000FFED8 - - -Ah now look at whats in sp+56 (sp+0x38) this is 8001B36A our saved r14 if -you look above at our stackframe & also agrees with GPR14. - -now backchain:: - - d 000FFF38.40 - -we now are taking the contents of SP to get our first backchain:: - - V000FFF38 000FFFA0 00000000 00014995 00147094 - V000FFF48 00147090 001470A0 000003E0 00000000 - V000FFF58 00100080 00100084 00000000 001BF1D0 - V000FFF68 00010400 800149BA 80014CA6 000FFF38 - -This displays a 2nd return address of 80014CA6 - -now do:: - - d 000FFFA0.40 - -for our 3rd backchain:: - - V000FFFA0 04B52002 0001107F 00000000 00000000 - V000FFFB0 00000000 00000000 FF000000 0001107F - V000FFFC0 00000000 00000000 00000000 00000000 - V000FFFD0 00010400 80010802 8001085A 000FFFA0 - - -our 3rd return address is 8001085A - -as the 04B52002 looks suspiciously like rubbish it is fair to assume that the -kernel entry routines for the sake of optimisation don't set up a backchain. - -now look at System.map to see if the addresses make any sense:: - - grep -i 0001b3 System.map - -outputs among other things:: - - 0001b304 T cpu_idle - -so 8001B36A -is cpu_idle+0x66 ( quiet the cpu is asleep, don't wake it ) - -:: - - grep -i 00014 System.map - -produces among other things:: - - 00014a78 T start_kernel - -so 0014CA6 is start_kernel+some hex number I can't add in my head. - -:: - - grep -i 00108 System.map - -this produces:: - - 00010800 T _stext - -so 8001085A is _stext+0x5a - -Congrats you've done your first backchain. - - - -s/390 & z/Architecture IO Overview -================================== - -I am not going to give a course in 390 IO architecture as this would take me -quite a while and I'm no expert. Instead I'll give a 390 IO architecture -summary for Dummies. If you have the s/390 principles of operation available -read this instead. If nothing else you may find a few useful keywords in here -and be able to use them on a web search engine to find more useful information. - -Unlike other bus architectures modern 390 systems do their IO using mostly -fibre optics and devices such as tapes and disks can be shared between several -mainframes. Also S390 can support up to 65536 devices while a high end PC based -system might be choking with around 64. - -Here is some of the common IO terminology: - -Subchannel: - This is the logical number most IO commands use to talk to an IO device. There - can be up to 0x10000 (65536) of these in a configuration, typically there are a - few hundred. Under VM for simplicity they are allocated contiguously, however - on the native hardware they are not. They typically stay consistent between - boots provided no new hardware is inserted or removed. - - Under Linux for s390 we use these as IRQ's and also when issuing an IO command - (CLEAR SUBCHANNEL, HALT SUBCHANNEL, MODIFY SUBCHANNEL, RESUME SUBCHANNEL, - START SUBCHANNEL, STORE SUBCHANNEL and TEST SUBCHANNEL). We use this as the ID - of the device we wish to talk to. The most important of these instructions are - START SUBCHANNEL (to start IO), TEST SUBCHANNEL (to check whether the IO - completed successfully) and HALT SUBCHANNEL (to kill IO). A subchannel can have - up to 8 channel paths to a device, this offers redundancy if one is not - available. - -Device Number: - This number remains static and is closely tied to the hardware. There are 65536 - of these, made up of a CHPID (Channel Path ID, the most significant 8 bits) and - another lsb 8 bits. These remain static even if more devices are inserted or - removed from the hardware. There is a 1 to 1 mapping between subchannels and - device numbers, provided devices aren't inserted or removed. - -Channel Control Words: - CCWs are linked lists of instructions initially pointed to by an operation - request block (ORB), which is initially given to Start Subchannel (SSCH) - command along with the subchannel number for the IO subsystem to process - while the CPU continues executing normal code. - CCWs come in two flavours, Format 0 (24 bit for backward compatibility) and - Format 1 (31 bit). These are typically used to issue read and write (and many - other) instructions. They consist of a length field and an absolute address - field. - - Each IO typically gets 1 or 2 interrupts, one for channel end (primary status) - when the channel is idle, and the second for device end (secondary status). - Sometimes you get both concurrently. You check how the IO went on by issuing a - TEST SUBCHANNEL at each interrupt, from which you receive an Interruption - response block (IRB). If you get channel and device end status in the IRB - without channel checks etc. your IO probably went okay. If you didn't you - probably need to examine the IRB, extended status word etc. - If an error occurs, more sophisticated control units have a facility known as - concurrent sense. This means that if an error occurs Extended sense information - will be presented in the Extended status word in the IRB. If not you have to - issue a subsequent SENSE CCW command after the test subchannel. - - -TPI (Test pending interrupt) can also be used for polled IO, but in -multitasking multiprocessor systems it isn't recommended except for -checking special cases (i.e. non looping checks for pending IO etc.). - -Store Subchannel and Modify Subchannel can be used to examine and modify -operating characteristics of a subchannel (e.g. channel paths). - -Other IO related Terms: - -Sysplex: - S390's Clustering Technology -QDIO: - S390's new high speed IO architecture to support devices such as gigabit - ethernet, this architecture is also designed to be forward compatible with - upcoming 64 bit machines. - - -General Concepts ----------------- - -Input Output Processors (IOP's) are responsible for communicating between -the mainframe CPU's & the channel & relieve the mainframe CPU's from the -burden of communicating with IO devices directly, this allows the CPU's to -concentrate on data processing. - -IOP's can use one or more links ( known as channel paths ) to talk to each -IO device. It first checks for path availability & chooses an available one, -then starts ( & sometimes terminates IO ). -There are two types of channel path: ESCON & the Parallel IO interface. - -IO devices are attached to control units, control units provide the -logic to interface the channel paths & channel path IO protocols to -the IO devices, they can be integrated with the devices or housed separately -& often talk to several similar devices ( typical examples would be raid -controllers or a control unit which connects to 1000 3270 terminals ):: - - - +---------------------------------------------------------------+ - | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | - | | CPU | | CPU | | CPU | | CPU | | Main | | Expanded | | - | | | | | | | | | | Memory | | Storage | | - | +-----+ +-----+ +-----+ +-----+ +----------+ +----------+ | - |---------------------------------------------------------------+ - | IOP | IOP | IOP | - |--------------------------------------------------------------- - | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | C | - ---------------------------------------------------------------- - || || - || Bus & Tag Channel Path || ESCON - || ====================== || Channel - || || || || Path - +----------+ +----------+ +----------+ - | | | | | | - | CU | | CU | | CU | - | | | | | | - +----------+ +----------+ +----------+ - | | | | | - +----------+ +----------+ +----------+ +----------+ +----------+ - |I/O Device| |I/O Device| |I/O Device| |I/O Device| |I/O Device| - +----------+ +----------+ +----------+ +----------+ +----------+ - CPU = Central Processing Unit - C = Channel - IOP = IP Processor - CU = Control Unit - -The 390 IO systems come in 2 flavours the current 390 machines support both - -The Older 360 & 370 Interface,sometimes called the Parallel I/O interface, -sometimes called Bus-and Tag & sometimes Original Equipment Manufacturers -Interface (OEMI). - -This byte wide Parallel channel path/bus has parity & data on the "Bus" cable -and control lines on the "Tag" cable. These can operate in byte multiplex mode -for sharing between several slow devices or burst mode and monopolize the -channel for the whole burst. Up to 256 devices can be addressed on one of these -cables. These cables are about one inch in diameter. The maximum unextended -length supported by these cables is 125 Meters but this can be extended up to -2km with a fibre optic channel extended such as a 3044. The maximum burst speed -supported is 4.5 megabytes per second. However, some really old processors -support only transfer rates of 3.0, 2.0 & 1.0 MB/sec. -One of these paths can be daisy chained to up to 8 control units. - - -ESCON if fibre optic it is also called FICON -Was introduced by IBM in 1990. Has 2 fibre optic cables and uses either leds or -lasers for communication at a signaling rate of up to 200 megabits/sec. As -10bits are transferred for every 8 bits info this drops to 160 megabits/sec -and to 18.6 Megabytes/sec once control info and CRC are added. ESCON only -operates in burst mode. - -ESCONs typical max cable length is 3km for the led version and 20km for the -laser version known as XDF (extended distance facility). This can be further -extended by using an ESCON director which triples the above mentioned ranges. -Unlike Bus & Tag as ESCON is serial it uses a packet switching architecture, -the standard Bus & Tag control protocol is however present within the packets. -Up to 256 devices can be attached to each control unit that uses one of these -interfaces. - -Common 390 Devices include: -Network adapters typically OSA2,3172's,2116's & OSA-E gigabit ethernet adapters, -Consoles 3270 & 3215 (a teletype emulated under linux for a line mode console). -DASD's direct access storage devices ( otherwise known as hard disks ). -Tape Drives. -CTC ( Channel to Channel Adapters ), -ESCON or Parallel Cables used as a very high speed serial link -between 2 machines. - - -Debugging IO on s/390 & z/Architecture under VM -=============================================== - -Now we are ready to go on with IO tracing commands under VM - -A few self explanatory queries:: - - Q OSA - Q CTC - Q DISK ( This command is CMS specific ) - Q DASD - -Q OSA on my machine returns:: - - OSA 7C08 ON OSA 7C08 SUBCHANNEL = 0000 - OSA 7C09 ON OSA 7C09 SUBCHANNEL = 0001 - OSA 7C14 ON OSA 7C14 SUBCHANNEL = 0002 - OSA 7C15 ON OSA 7C15 SUBCHANNEL = 0003 - -If you have a guest with certain privileges you may be able to see devices -which don't belong to you. To avoid this, add the option V. -e.g.:: - - Q V OSA - -Now using the device numbers returned by this command we will -Trace the io starting up on the first device 7c08 & 7c09 -In our simplest case we can trace the -start subchannels -like TR SSCH 7C08-7C09 -or the halt subchannels -or TR HSCH 7C08-7C09 -MSCH's ,STSCH's I think you can guess the rest - -A good trick is tracing all the IO's and CCWS and spooling them into the reader -of another VM guest so he can ftp the logfile back to his own machine. I'll do -a small bit of this and give you a look at the output. - -1) Spool stdout to VM reader:: - - SP PRT TO (another vm guest ) or * for the local vm guest - -2) Fill the reader with the trace:: - - TR IO 7c08-7c09 INST INT CCW PRT RUN - -3) Start up linux:: - - i 00c -4) Finish the trace:: - - TR END - -5) close the reader:: - - C PRT - -6) list reader contents:: - - RDRLIST - -7) copy it to linux4's minidisk:: - - RECEIVE / LOG TXT A1 ( replace - -8) -filel & press F11 to look at it -You should see something like:: - - 00020942' SSCH B2334000 0048813C CC 0 SCH 0000 DEV 7C08 - CPA 000FFDF0 PARM 00E2C9C4 KEY 0 FPI C0 LPM 80 - CCW 000FFDF0 E4200100 00487FE8 0000 E4240100 ........ - IDAL 43D8AFE8 - IDAL 0FB76000 - 00020B0A' I/O DEV 7C08 -> 000197BC' SCH 0000 PARM 00E2C9C4 - 00021628' TSCH B2354000 >> 00488164 CC 0 SCH 0000 DEV 7C08 - CCWA 000FFDF8 DEV STS 0C SCH STS 00 CNT 00EC - KEY 0 FPI C0 CC 0 CTLS 4007 - 00022238' STSCH B2344000 >> 00488108 CC 0 SCH 0000 DEV 7C08 - -If you don't like messing up your readed ( because you possibly booted from it ) -you can alternatively spool it to another readers guest. - - -Other common VM device related commands ---------------------------------------------- -These commands are listed only because they have -been of use to me in the past & may be of use to -you too. For more complete info on each of the commands -use type HELP from CMS. - -detaching devices:: - - DET - ATT - -attach a device to guest * for your own guest - -READY - cause VM to issue a fake interrupt. - -The VARY command is normally only available to VM administrators:: - - VARY ON PATH TO - VARY OFF PATH FROM - -This is used to switch on or off channel paths to devices. - -Q CHPID - This displays state of devices using this channel path - -D SCHIB - This displays the subchannel information SCHIB block for the device. - this I believe is also only available to administrators. - -DEFINE CTC - defines a virtual CTC channel to channel connection - 2 need to be defined on each guest for the CTC driver to use. - -COUPLE devno userid remote devno - Joins a local virtual device to a remote virtual device - ( commonly used for the CTC driver ). - -Building a VM ramdisk under CMS which linux can use:: - - def vfb- - -blocksize is commonly 4096 for linux. - -Formatting it:: - - format (blksize - -Sharing a disk between multiple guests:: - - LINK userid devno1 devno2 mode password - - - -GDB on S390 -=========== -N.B. if compiling for debugging gdb works better without optimisation -( see Compiling programs for debugging ) - -invocation ----------- -gdb - -Online help ------------ -help: gives help on commands - -e.g.:: - - help - help display - -Note gdb's online help is very good use it. - - -Assembly --------- -info registers: - displays registers other than floating point. - -info all-registers: - displays floating points as well. - -disassemble: - disassembles - -e.g.:: - - disassemble without parameters will disassemble the current function - disassemble $pc $pc+10 - -Viewing & modifying variables ------------------------------ -print or p: - displays variable or register - -e.g. p/x $sp will display the stack pointer - -display: - prints variable or register each time program stops - -e.g.:: - - display/x $pc will display the program counter - display argc - -undisplay: - undo's display's - -info breakpoints: - shows all current breakpoints - -info stack: - shows stack back trace (if this doesn't work too well, I'll show - you the stacktrace by hand below). - -info locals: - displays local variables. - -info args: - display current procedure arguments. - -set args: - will set argc & argv each time the victim program is invoked - -e.g.:: - - set =value - set argc=100 - set $pc=0 - - - -Modifying execution -------------------- -step: - steps n lines of sourcecode - -step - steps 1 line. - -step 100 - steps 100 lines of code. - -next: - like step except this will not step into subroutines - -stepi: - steps a single machine code instruction. - -e.g.:: - - stepi 100 - -nexti: - steps a single machine code instruction but will not step into - subroutines. - -finish: - will run until exit of the current routine - -run: - (re)starts a program - -cont: - continues a program - -quit: - exits gdb. - - -breakpoints ------------- - -break - sets a breakpoint - -e.g.:: - - break main - break *$pc - break *0x400618 - -Here's a really useful one for large programs - -rbr - Set a breakpoint for all functions matching REGEXP - -e.g.:: - - rbr 390 - -will set a breakpoint with all functions with 390 in their name. - -info breakpoints - lists all breakpoints - -delete: - delete breakpoint by number or delete them all - -e.g. - -delete 1 - will delete the first breakpoint - - -delete - will delete them all - -watch: - This will set a watchpoint ( usually hardware assisted ), - -This will watch a variable till it changes - -e.g. - -watch cnt - will watch the variable cnt till it changes. - -As an aside unfortunately gdb's, architecture independent watchpoint code -is inconsistent & not very good, watchpoints usually work but not always. - -info watchpoints: - Display currently active watchpoints - -condition: ( another useful one ) - Specify breakpoint number N to break only if COND is true. - -Usage is `condition N COND`, where N is an integer and COND is an -expression to be evaluated whenever breakpoint N is reached. - - - -User defined functions/macros ------------------------------ -define: ( Note this is very very useful,simple & powerful ) - -usage define end - -examples which you should consider putting into .gdbinit in your home -directory:: - - define d - stepi - disassemble $pc $pc+10 - end - define e - nexti - disassemble $pc $pc+10 - end - - -Other hard to classify stuff ----------------------------- -signal n: - sends the victim program a signal. - -e.g. `signal 3` will send a SIGQUIT. - -info signals: - what gdb does when the victim receives certain signals. - -list: - -e.g.: - -list - lists current function source -list 1,10 - list first 10 lines of current file. - -list test.c:1,10 - - -directory: - Adds directories to be searched for source if gdb cannot find the source. - (note it is a bit sensitive about slashes) - -e.g. To add the root of the filesystem to the searchpath do:: - - directory // - - -call -This calls a function in the victim program, this is pretty powerful -e.g. -(gdb) call printf("hello world") -outputs: -$1 = 11 - -You might now be thinking that the line above didn't work, something extra had -to be done. -(gdb) call fflush(stdout) -hello world$2 = 0 -As an aside the debugger also calls malloc & free under the hood -to make space for the "hello world" string. - - - -hints ------ -1) command completion works just like bash - ( if you are a bad typist like me this really helps ) - -e.g. hit br & cursor up & down :-). - -2) if you have a debugging problem that takes a few steps to recreate -put the steps into a file called .gdbinit in your current working directory -if you have defined a few extra useful user defined commands put these in -your home directory & they will be read each time gdb is launched. - -A typical .gdbinit file might be.:: - - break main - run - break runtime_exception - cont - - -stack chaining in gdb by hand ------------------------------ -This is done using a the same trick described for VM:: - - p/x (*($sp+56))&0x7fffffff - -get the first backchain. - -For z/Architecture -Replace 56 with 112 & ignore the &0x7fffffff -in the macros below & do nasty casts to longs like the following -as gdb unfortunately deals with printed arguments as ints which -messes up everything. - -i.e. here is a 3rd backchain dereference:: - - p/x *(long *)(***(long ***)$sp+112) - - -this outputs:: - - $5 = 0x528f18 - -on my machine. - -Now you can use:: - - info symbol (*($sp+56))&0x7fffffff - -you might see something like:: - - rl_getc + 36 in section .text - -telling you what is located at address 0x528f18 -Now do:: - - p/x (*(*$sp+56))&0x7fffffff - -This outputs:: - - $6 = 0x528ed0 - -Now do:: - - info symbol (*(*$sp+56))&0x7fffffff - rl_read_key + 180 in section .text - -now do:: - - p/x (*(**$sp+56))&0x7fffffff - -& so on. - -Disassembling instructions without debug info ---------------------------------------------- -gdb typically complains if there is a lack of debugging -symbols in the disassemble command with -"No function contains specified address." To get around -this do:: - - x/xi
- -e.g.:: - - x/20xi 0x400730 - - - -Note: - Remember gdb has history just like bash you don't need to retype the - whole line just use the up & down arrows. - - - -For more info -------------- -From your linuxbox do:: - - man gdb - -or:: - - info gdb. - -core dumps ----------- - -What a core dump ? -^^^^^^^^^^^^^^^^^^ - -A core dump is a file generated by the kernel (if allowed) which contains the -registers and all active pages of the program which has crashed. - -From this file gdb will allow you to look at the registers, stack trace and -memory of the program as if it just crashed on your system. It is usually -called core and created in the current working directory. - -This is very useful in that a customer can mail a core dump to a technical -support department and the technical support department can reconstruct what -happened. Provided they have an identical copy of this program with debugging -symbols compiled in and the source base of this build is available. - -In short it is far more useful than something like a crash log could ever hope -to be. - -Why have I never seen one ? -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Probably because you haven't used the command:: - - ulimit -c unlimited in bash - -to allow core dumps, now do:: - - ulimit -a - -to verify that the limit was accepted. - -A sample core dump - To create this I'm going to do:: - - ulimit -c unlimited - gdb - -to launch gdb (my victim app. ) now be bad & do the following from another -telnet/xterm session to the same machine:: - - ps -aux | grep gdb - kill -SIGSEGV - -or alternatively use `killall -SIGSEGV gdb` if you have the killall command. - -Now look at the core dump:: - - ./gdb core - -Displays the following:: - - GNU gdb 4.18 - Copyright 1998 Free Software Foundation, Inc. - GDB is free software, covered by the GNU General Public License, and you are - welcome to change it and/or distribute copies of it under certain conditions. - Type "show copying" to see the conditions. - There is absolutely no warranty for GDB. Type "show warranty" for details. - This GDB was configured as "s390-ibm-linux"... - Core was generated by `./gdb'. - Program terminated with signal 11, Segmentation fault. - Reading symbols from /usr/lib/libncurses.so.4...done. - Reading symbols from /lib/libm.so.6...done. - Reading symbols from /lib/libc.so.6...done. - Reading symbols from /lib/ld-linux.so.2...done. - #0 0x40126d1a in read () from /lib/libc.so.6 - Setting up the environment for debugging gdb. - Breakpoint 1 at 0x4dc6f8: file utils.c, line 471. - Breakpoint 2 at 0x4d87a4: file top.c, line 2609. - (top-gdb) info stack - #0 0x40126d1a in read () from /lib/libc.so.6 - #1 0x528f26 in rl_getc (stream=0x7ffffde8) at input.c:402 - #2 0x528ed0 in rl_read_key () at input.c:381 - #3 0x5167e6 in readline_internal_char () at readline.c:454 - #4 0x5168ee in readline_internal_charloop () at readline.c:507 - #5 0x51692c in readline_internal () at readline.c:521 - #6 0x5164fe in readline (prompt=0x7ffff810) - at readline.c:349 - #7 0x4d7a8a in command_line_input (prompt=0x564420 "(gdb) ", repeat=1, - annotation_suffix=0x4d6b44 "prompt") at top.c:2091 - #8 0x4d6cf0 in command_loop () at top.c:1345 - #9 0x4e25bc in main (argc=1, argv=0x7ffffdf4) at main.c:635 - - -LDD -=== -This is a program which lists the shared libraries which a library needs, -Note you also get the relocations of the shared library text segments which -help when using objdump --source. - -e.g.:: - - ldd ./gdb - -outputs:: - - libncurses.so.4 => /usr/lib/libncurses.so.4 (0x40018000) - libm.so.6 => /lib/libm.so.6 (0x4005e000) - libc.so.6 => /lib/libc.so.6 (0x40084000) - /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) - - -Debugging shared libraries -========================== -Most programs use shared libraries, however it can be very painful -when you single step instruction into a function like printf for the -first time & you end up in functions like _dl_runtime_resolve this is -the ld.so doing lazy binding, lazy binding is a concept in ELF where -shared library functions are not loaded into memory unless they are -actually used, great for saving memory but a pain to debug. - -To get around this either relink the program -static or exit gdb type -export LD_BIND_NOW=true this will stop lazy binding & restart the gdb'ing -the program in question. - - - -Debugging modules -================= -As modules are dynamically loaded into the kernel their address can be -anywhere to get around this use the -m option with insmod to emit a load -map which can be piped into a file if required. - -The proc file system -==================== -What is it ?. -It is a filesystem created by the kernel with files which are created on demand -by the kernel if read, or can be used to modify kernel parameters, -it is a powerful concept. - -e.g.:: - - cat /proc/sys/net/ipv4/ip_forward - -On my machine outputs:: - - 0 - -telling me ip_forwarding is not on to switch it on I can do:: - - echo 1 > /proc/sys/net/ipv4/ip_forward - -cat it again:: - - cat /proc/sys/net/ipv4/ip_forward - -On my machine now outputs:: - - 1 - -IP forwarding is on. - -There is a lot of useful info in here best found by going in and having a look -around, so I'll take you through some entries I consider important. - -All the processes running on the machine have their own entry defined by -/proc/ - -So lets have a look at the init process:: - - cd /proc/1 - cat cmdline - -emits:: - - init [2] - -:: - - cd /proc/1/fd - -This contains numerical entries of all the open files, -some of these you can cat e.g. stdout (2):: - - cat /proc/29/maps - -on my machine emits:: - - 00400000-00478000 r-xp 00000000 5f:00 4103 /bin/bash - 00478000-0047e000 rw-p 00077000 5f:00 4103 /bin/bash - 0047e000-00492000 rwxp 00000000 00:00 0 - 40000000-40015000 r-xp 00000000 5f:00 14382 /lib/ld-2.1.2.so - 40015000-40016000 rw-p 00014000 5f:00 14382 /lib/ld-2.1.2.so - 40016000-40017000 rwxp 00000000 00:00 0 - 40017000-40018000 rw-p 00000000 00:00 0 - 40018000-4001b000 r-xp 00000000 5f:00 14435 /lib/libtermcap.so.2.0.8 - 4001b000-4001c000 rw-p 00002000 5f:00 14435 /lib/libtermcap.so.2.0.8 - 4001c000-4010d000 r-xp 00000000 5f:00 14387 /lib/libc-2.1.2.so - 4010d000-40111000 rw-p 000f0000 5f:00 14387 /lib/libc-2.1.2.so - 40111000-40114000 rw-p 00000000 00:00 0 - 40114000-4011e000 r-xp 00000000 5f:00 14408 /lib/libnss_files-2.1.2.so - 4011e000-4011f000 rw-p 00009000 5f:00 14408 /lib/libnss_files-2.1.2.so - 7fffd000-80000000 rwxp ffffe000 00:00 0 - - -Showing us the shared libraries init uses where they are in memory -& memory access permissions for each virtual memory area. - -/proc/1/cwd is a softlink to the current working directory. - -/proc/1/root is the root of the filesystem for this process. - -/proc/1/mem is the current running processes memory which you -can read & write to like a file. - -strace uses this sometimes as it is a bit faster than the -rather inefficient ptrace interface for peeking at DATA. - -:: - - cat status - - Name: init - State: S (sleeping) - Pid: 1 - PPid: 0 - Uid: 0 0 0 0 - Gid: 0 0 0 0 - Groups: - VmSize: 408 kB - VmLck: 0 kB - VmRSS: 208 kB - VmData: 24 kB - VmStk: 8 kB - VmExe: 368 kB - VmLib: 0 kB - SigPnd: 0000000000000000 - SigBlk: 0000000000000000 - SigIgn: 7fffffffd7f0d8fc - SigCgt: 00000000280b2603 - CapInh: 00000000fffffeff - CapPrm: 00000000ffffffff - CapEff: 00000000fffffeff - - User PSW: 070de000 80414146 - task: 004b6000 tss: 004b62d8 ksp: 004b7ca8 pt_regs: 004b7f68 - User GPRS: - 00000400 00000000 0000000b 7ffffa90 - 00000000 00000000 00000000 0045d9f4 - 0045cafc 7ffffa90 7fffff18 0045cb08 - 00010400 804039e8 80403af8 7ffff8b0 - User ACRS: - 00000000 00000000 00000000 00000000 - 00000001 00000000 00000000 00000000 - 00000000 00000000 00000000 00000000 - 00000000 00000000 00000000 00000000 - Kernel BackChain CallChain BackChain CallChain - 004b7ca8 8002bd0c 004b7d18 8002b92c - 004b7db8 8005cd50 004b7e38 8005d12a - 004b7f08 80019114 - -Showing among other things memory usage & status of some signals & -the processes'es registers from the kernel task_structure -as well as a backchain which may be useful if a process crashes -in the kernel for some unknown reason. - -Some driver debugging techniques -================================ -debug feature -------------- -Some of our drivers now support a "debug feature" in -/proc/s390dbf see s390dbf.txt in the linux/Documentation directory -for more info. - -e.g. -to switch on the lcs "debug feature":: - - echo 5 > /proc/s390dbf/lcs/level - -& then after the error occurred:: - - cat /proc/s390dbf/lcs/sprintf >/logfile - -the logfile now contains some information which may help -tech support resolve a problem in the field. - - - -high level debugging network drivers ------------------------------------- -ifconfig is a quite useful command -it gives the current state of network drivers. - -If you suspect your network device driver is dead -one way to check is type:: - - ifconfig - -e.g. tr0 - -You should see something like:: - - ifconfig tr0 - tr0 Link encap:16/4 Mbps Token Ring (New) HWaddr 00:04:AC:20:8E:48 - inet addr:9.164.185.132 Bcast:9.164.191.255 Mask:255.255.224.0 - UP BROADCAST RUNNING MULTICAST MTU:2000 Metric:1 - RX packets:246134 errors:0 dropped:0 overruns:0 frame:0 - TX packets:5 errors:0 dropped:0 overruns:0 carrier:0 - collisions:0 txqueuelen:100 - -if the device doesn't say up -try:: - - /etc/rc.d/init.d/network start - -( this starts the network stack & hopefully calls ifconfig tr0 up ). -ifconfig looks at the output of /proc/net/dev and presents it in a more -presentable form. - -Now ping the device from a machine in the same subnet. - -if the RX packets count & TX packets counts don't increment you probably -have problems. - -next:: - - cat /proc/net/arp - -Do you see any hardware addresses in the cache if not you may have problems. -Next try:: - - ping -c 5 - -i.e. the Bcast field above in the output of -ifconfig. Do you see any replies from machines other than the local machine -if not you may have problems. also if the TX packets count in ifconfig -hasn't incremented either you have serious problems in your driver -(e.g. the txbusy field of the network device being stuck on ) -or you may have multiple network devices connected. - - -chandev -------- -There is a new device layer for channel devices, some -drivers e.g. lcs are registered with this layer. - -If the device uses the channel device layer you'll be -able to find what interrupts it uses & the current state -of the device. - -See the manpage chandev.8 &type cat /proc/chandev for more info. - - -SysRq -===== -This is now supported by linux for s/390 & z/Architecture. - -To enable it do compile the kernel with:: - - Kernel Hacking -> Magic SysRq Key Enabled - -Then:: - - echo "1" > /proc/sys/kernel/sysrq - -also type:: - - echo "8" >/proc/sys/kernel/printk - -To make printk output go to console. - -On 390 all commands are prefixed with:: - - ^- - -e.g.:: - - ^-t will show tasks. - ^-? or some unknown command will display help. - -The sysrq key reading is very picky ( I have to type the keys in an -xterm session & paste them into the x3270 console ) -& it may be wise to predefine the keys as described in the VM hints above - -This is particularly useful for syncing disks unmounting & rebooting -if the machine gets partially hung. - -Read Documentation/admin-guide/sysrq.rst for more info - -References: -=========== -- Enterprise Systems Architecture Reference Summary -- Enterprise Systems Architecture Principles of Operation -- Hartmut Penners s390 stack frame sheet. -- IBM Mainframe Channel Attachment a technology brief from a CISCO webpage -- Various bits of man & info pages of Linux. -- Linux & GDB source. -- Various info & man pages. -- CMS Help on tracing commands. -- Linux for s/390 Elf Application Binary Interface -- Linux for z/Series Elf Application Binary Interface ( Both Highly Recommended ) -- z/Architecture Principles of Operation SA22-7832-00 -- Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the -- Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05 - -Special Thanks -============== -Special thanks to Neale Ferguson who maintains a much -prettier HTML version of this page at -http://linuxvm.org/penguinvm/ -Bob Grainger Stefan Bader & others for reporting bugs diff --git a/Documentation/s390/index.rst b/Documentation/s390/index.rst index f8c01cb7fa37..f7af2061e406 100644 --- a/Documentation/s390/index.rst +++ b/Documentation/s390/index.rst @@ -7,7 +7,6 @@ s390 Architecture cds 3270 - debugging390 driver-model monreader qeth -- cgit v1.2.3 From 59793c5ab93fed9661deaf6d8ba054af681c0a6a Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Fri, 2 Aug 2019 12:28:20 +0200 Subject: s390: move vmalloc option parsing to startup code Few other crucial memory setup options are already handled in the startup code. Those values are needed by kaslr and kasan implementations. "vmalloc" is the last piece required for future improvements such as early decision on kernel page levels depth required for actual memory setup, as well as vmalloc memory area access monitoring in kasan. Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/boot/ipl_parm.c | 5 +++++ arch/s390/include/asm/pgtable.h | 1 + arch/s390/include/asm/setup.h | 1 + arch/s390/kernel/setup.c | 13 ++----------- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 3c49bde8aa5e..449d26a42f3f 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "boot.h" @@ -14,6 +15,7 @@ char __bootdata(early_command_line)[COMMAND_LINE_SIZE]; struct ipl_parameter_block __bootdata_preserved(ipl_block); int __bootdata_preserved(ipl_block_valid); +unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE; unsigned long __bootdata(memory_end); int __bootdata(memory_end_set); int __bootdata(noexec_disabled); @@ -226,6 +228,9 @@ void parse_boot_command_line(void) memory_end_set = 1; } + if (!strcmp(param, "vmalloc")) + vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); + if (!strcmp(param, "noexec")) { rc = kstrtobool(val, &enabled); if (!rc && !enabled) diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h index 9b274fcaacb6..0c4600725fc2 100644 --- a/arch/s390/include/asm/pgtable.h +++ b/arch/s390/include/asm/pgtable.h @@ -86,6 +86,7 @@ extern unsigned long zero_page_mask; */ extern unsigned long VMALLOC_START; extern unsigned long VMALLOC_END; +#define VMALLOC_DEFAULT_SIZE ((128UL << 30) - MODULES_LEN) extern struct page *vmemmap; #define VMEM_MAX_PHYS ((unsigned long) vmemmap) diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index c5cfff7b1f91..a82d5a98428a 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h @@ -83,6 +83,7 @@ struct parmarea { extern int noexec_disabled; extern int memory_end_set; extern unsigned long memory_end; +extern unsigned long vmalloc_size; extern unsigned long max_physmem_end; #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2b94b0ad3588..0c3f1cd69ed1 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -99,6 +99,7 @@ int __bootdata_preserved(prot_virt_guest); int __bootdata(noexec_disabled); int __bootdata(memory_end_set); unsigned long __bootdata(memory_end); +unsigned long __bootdata(vmalloc_size); unsigned long __bootdata(max_physmem_end); struct mem_detect_info __bootdata(mem_detect); @@ -302,15 +303,6 @@ void machine_power_off(void) void (*pm_power_off)(void) = machine_power_off; EXPORT_SYMBOL_GPL(pm_power_off); -static int __init parse_vmalloc(char *arg) -{ - if (!arg) - return -EINVAL; - VMALLOC_END = (memparse(arg, &arg) + PAGE_SIZE - 1) & PAGE_MASK; - return 0; -} -early_param("vmalloc", parse_vmalloc); - void *restart_stack __section(.data); unsigned long stack_alloc(void) @@ -563,10 +555,9 @@ static void __init setup_resources(void) static void __init setup_memory_end(void) { - unsigned long vmax, vmalloc_size, tmp; + unsigned long vmax, tmp; /* Choose kernel address space layout: 3 or 4 levels. */ - vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN; if (IS_ENABLED(CONFIG_KASAN)) { vmax = IS_ENABLED(CONFIG_KASAN_S390_4_LEVEL_PAGING) ? _REGION1_SIZE -- cgit v1.2.3 From c4c3772384bc93e3d1eccd88bd7f5d74de74e0d7 Mon Sep 17 00:00:00 2001 From: Denis Efremov Date: Tue, 6 Aug 2019 19:01:37 +0300 Subject: s390/pci: PCI_IOV_RESOURCES loop refactoring in zpci_map_resources This patch alters the for loop iteration scheme in zpci_map_resources to make it more usual. Thus, the patch generalizes the style for PCI_IOV_RESOURCES iteration and improves readability. Link: http://lkml.kernel.org/r/20190806160137.29275-1-efremov@linux.com Signed-off-by: Denis Efremov Signed-off-by: Sebastian Ott Signed-off-by: Vasily Gorbik --- arch/s390/pci/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c index b0e3b9a0e488..c7fea9bea8cb 100644 --- a/arch/s390/pci/pci.c +++ b/arch/s390/pci/pci.c @@ -431,13 +431,13 @@ static void zpci_map_resources(struct pci_dev *pdev) } #ifdef CONFIG_PCI_IOV - i = PCI_IOV_RESOURCES; + for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { + int bar = i + PCI_IOV_RESOURCES; - for (; i < PCI_SRIOV_NUM_BARS + PCI_IOV_RESOURCES; i++) { - len = pci_resource_len(pdev, i); + len = pci_resource_len(pdev, bar); if (!len) continue; - pdev->resource[i].parent = &iov_res; + pdev->resource[bar].parent = &iov_res; } #endif } -- cgit v1.2.3 From 3434caec5b70519ead87e7b66dbdc18e8dbaa506 Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Thu, 8 Aug 2019 15:18:17 +0800 Subject: s390/extmem: use refcount_t for refcount Reference counters are preferred to use refcount_t instead of atomic_t. This is because the implementation of refcount_t can prevent overflows and detect possible use-after-free. So convert atomic_t ref counters to refcount_t. Link: http://lkml.kernel.org/r/20190808071817.6595-1-hslester96@gmail.com Signed-off-by: Chuhong Yuan Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/mm/extmem.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 0b5622714c12..fd0dae9d10f4 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,7 @@ struct dcss_segment { char res_name[16]; unsigned long start_addr; unsigned long end; - atomic_t ref_count; + refcount_t ref_count; int do_nonshared; unsigned int vm_segtype; struct qrange range[6]; @@ -362,7 +363,7 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long seg->start_addr = start_addr; seg->end = end_addr; seg->do_nonshared = do_nonshared; - atomic_set(&seg->ref_count, 1); + refcount_set(&seg->ref_count, 1); list_add(&seg->list, &dcss_list); *addr = seg->start_addr; *end = seg->end; @@ -422,7 +423,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, rc = __segment_load (name, do_nonshared, addr, end); else { if (do_nonshared == seg->do_nonshared) { - atomic_inc(&seg->ref_count); + refcount_inc(&seg->ref_count); *addr = seg->start_addr; *end = seg->end; rc = seg->vm_segtype; @@ -468,7 +469,7 @@ segment_modify_shared (char *name, int do_nonshared) rc = 0; goto out_unlock; } - if (atomic_read (&seg->ref_count) != 1) { + if (refcount_read(&seg->ref_count) != 1) { pr_warn("DCSS %s is in use and cannot be reloaded\n", name); rc = -EAGAIN; goto out_unlock; @@ -544,7 +545,7 @@ segment_unload(char *name) pr_err("Unloading unknown DCSS %s failed\n", name); goto out_unlock; } - if (atomic_dec_return(&seg->ref_count) != 0) + if (!refcount_dec_and_test(&seg->ref_count)) goto out_unlock; release_resource(seg->res); kfree(seg->res); -- cgit v1.2.3 From 40e90656c13587c0826e8afeef3cebe585db2d2c Mon Sep 17 00:00:00 2001 From: Chuhong Yuan Date: Thu, 8 Aug 2019 15:18:26 +0800 Subject: s390/mm: use refcount_t for refcount Reference counters are preferred to use refcount_t instead of atomic_t. This is because the implementation of refcount_t can prevent overflows and detect possible use-after-free. So convert atomic_t ref counters to refcount_t. Link: http://lkml.kernel.org/r/20190808071826.6649-1-hslester96@gmail.com Signed-off-by: Chuhong Yuan Reviewed-by: David Hildenbrand Reviewed-by: Cornelia Huck Signed-off-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/gmap.h | 4 +++- arch/s390/mm/gmap.c | 10 +++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/s390/include/asm/gmap.h b/arch/s390/include/asm/gmap.h index fcbd638fb9f4..37f96b6f0e61 100644 --- a/arch/s390/include/asm/gmap.h +++ b/arch/s390/include/asm/gmap.h @@ -9,6 +9,8 @@ #ifndef _ASM_S390_GMAP_H #define _ASM_S390_GMAP_H +#include + /* Generic bits for GMAP notification on DAT table entry changes. */ #define GMAP_NOTIFY_SHADOW 0x2 #define GMAP_NOTIFY_MPROT 0x1 @@ -46,7 +48,7 @@ struct gmap { struct radix_tree_root guest_to_host; struct radix_tree_root host_to_guest; spinlock_t guest_table_lock; - atomic_t ref_count; + refcount_t ref_count; unsigned long *table; unsigned long asce; unsigned long asce_end; diff --git a/arch/s390/mm/gmap.c b/arch/s390/mm/gmap.c index 1e668b95e0c6..3770f12d9252 100644 --- a/arch/s390/mm/gmap.c +++ b/arch/s390/mm/gmap.c @@ -67,7 +67,7 @@ static struct gmap *gmap_alloc(unsigned long limit) INIT_RADIX_TREE(&gmap->host_to_rmap, GFP_ATOMIC); spin_lock_init(&gmap->guest_table_lock); spin_lock_init(&gmap->shadow_lock); - atomic_set(&gmap->ref_count, 1); + refcount_set(&gmap->ref_count, 1); page = alloc_pages(GFP_KERNEL, CRST_ALLOC_ORDER); if (!page) goto out_free; @@ -214,7 +214,7 @@ static void gmap_free(struct gmap *gmap) */ struct gmap *gmap_get(struct gmap *gmap) { - atomic_inc(&gmap->ref_count); + refcount_inc(&gmap->ref_count); return gmap; } EXPORT_SYMBOL_GPL(gmap_get); @@ -227,7 +227,7 @@ EXPORT_SYMBOL_GPL(gmap_get); */ void gmap_put(struct gmap *gmap) { - if (atomic_dec_return(&gmap->ref_count) == 0) + if (refcount_dec_and_test(&gmap->ref_count)) gmap_free(gmap); } EXPORT_SYMBOL_GPL(gmap_put); @@ -1594,7 +1594,7 @@ static struct gmap *gmap_find_shadow(struct gmap *parent, unsigned long asce, continue; if (!sg->initialized) return ERR_PTR(-EAGAIN); - atomic_inc(&sg->ref_count); + refcount_inc(&sg->ref_count); return sg; } return NULL; @@ -1682,7 +1682,7 @@ struct gmap *gmap_shadow(struct gmap *parent, unsigned long asce, } } } - atomic_set(&new->ref_count, 2); + refcount_set(&new->ref_count, 2); list_add(&new->list, &parent->children); if (asce & _ASCE_REAL_SPACE) { /* nothing to protect, return right away */ -- cgit v1.2.3 From da9ed30d29c48233cec4a19e2bd794bcaa230341 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Thu, 8 Aug 2019 13:50:02 +0200 Subject: s390/startup: add initial pgm check handler The startup code is getting more complicated with features like kaslr and secure boot in place. In a potential unexpected startup code crash case the system would end up in a pgm check loop at address 0, overwriting pgm check old psw value and just making debugging more complicated. To avoid that introduce startup program check handler which is active immediately after kernel start and until early_pgm_check_handler is set in kernel/early.c. So it covers kernel relocation phase and transition to it. This pgm check handler simply saves general/control registers and psw in the save area which should guarantee that we still have something to look at when standalone dumper is called without saving registers. And it does disabled wait with a faulty address in the end. Acked-by: Ilya Leoshkevich Signed-off-by: Vasily Gorbik --- arch/s390/boot/head.S | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/arch/s390/boot/head.S b/arch/s390/boot/head.S index 2087bed6e60f..5b79ae7b44f3 100644 --- a/arch/s390/boot/head.S +++ b/arch/s390/boot/head.S @@ -60,8 +60,10 @@ __HEAD .long 0x02000690,0x60000050 .long 0x020006e0,0x20000050 - .org 0x1a0 + .org __LC_RST_NEW_PSW # 0x1a0 .quad 0,iplstart + .org __LC_PGM_NEW_PSW # 0x1d0 + .quad 0x0000000180000000,startup_pgm_check_handler .org 0x200 @@ -351,6 +353,26 @@ ENTRY(startup_kdump) #include "head_kdump.S" +# +# This program check is active immediately after kernel start +# and until early_pgm_check_handler is set in kernel/early.c +# It simply saves general/control registers and psw in +# the save area and does disabled wait with a faulty address. +# +ENTRY(startup_pgm_check_handler) + stmg %r0,%r15,__LC_SAVE_AREA_SYNC + la %r1,4095 + stctg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r1) + mvc __LC_GPREGS_SAVE_AREA-4095(128,%r1),__LC_SAVE_AREA_SYNC + mvc __LC_PSW_SAVE_AREA-4095(16,%r1),__LC_PGM_OLD_PSW + lg %r1,__LC_SAVE_AREA_SYNC+8 + mvc __LC_RETURN_PSW(16),__LC_PGM_OLD_PSW + ni __LC_RETURN_PSW,0xfc # remove IO and EX bits + ni __LC_RETURN_PSW+1,0xfb # remove MCHK bit + oi __LC_RETURN_PSW+1,0x2 # set wait state bit + lpswe __LC_RETURN_PSW # disabled wait +ENDPROC(startup_pgm_check_handler) + # # params at 10400 (setup.h) # Must be keept in sync with struct parmarea in setup.h -- cgit v1.2.3 From 19413fe04f49b32c63b470079afef8d1c7995cc1 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Sun, 11 Aug 2019 22:04:54 +0200 Subject: s390/startup: purge obsolete .gitignore patterns sizes.h and vmlinux.scr.lds are not generated since commit 369f91c37451 ("s390/decompressor: rework uncompressed image info collection"). vmlinux.bin.full is not generated since commit 183ab05ff285 ("s390: get rid of the first mb of uncompressed image"). Signed-off-by: Vasily Gorbik --- arch/s390/boot/compressed/.gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/arch/s390/boot/compressed/.gitignore b/arch/s390/boot/compressed/.gitignore index 45aeb4f08752..e72fcd7ecebb 100644 --- a/arch/s390/boot/compressed/.gitignore +++ b/arch/s390/boot/compressed/.gitignore @@ -1,5 +1,2 @@ -sizes.h vmlinux vmlinux.lds -vmlinux.scr.lds -vmlinux.bin.full -- cgit v1.2.3 From 2e83e0eb85ca62985406920f97ece36d822d421f Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Sun, 11 Aug 2019 20:55:18 +0200 Subject: s390: clean .bss before running uncompressed kernel Clean uncompressed kernel .bss section in the startup code before the uncompressed kernel is executed. At this point of time initrd and certificates have been already rescued. Uncompressed kernel .bss size is known from vmlinux_info. It is also taken into consideration during uncompressed kernel positioning by kaslr (so it is safe to clean it). With that uncompressed kernel is starting with .bss section zeroed and no .bss section usage restrictions apply. Which makes chkbss checks for uncompressed kernel objects obsolete and they can be removed. early_nobss.c is also not needed anymore. Parts of it which are still relevant are moved to early.c. Kasan initialization code is now called directly from head64 (early.c is instrumented and should not be executed before kasan shadow memory is set up). Reviewed-by: Philipp Rudo Signed-off-by: Vasily Gorbik --- arch/s390/boot/startup.c | 6 ++++++ arch/s390/kernel/Makefile | 13 +----------- arch/s390/kernel/early.c | 16 +++++++++++++++ arch/s390/kernel/early_nobss.c | 45 ------------------------------------------ arch/s390/kernel/head64.S | 8 +++----- arch/s390/lib/Makefile | 3 --- drivers/s390/char/Makefile | 3 --- 7 files changed, 26 insertions(+), 68 deletions(-) delete mode 100644 arch/s390/kernel/early_nobss.c diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 7b0d05414618..596ca7cc4d7b 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c @@ -112,6 +112,11 @@ static void handle_relocs(unsigned long offset) } } +static void clear_bss_section(void) +{ + memset((void *)vmlinux.default_lma + vmlinux.image_size, 0, vmlinux.bss_size); +} + void startup_kernel(void) { unsigned long random_lma; @@ -151,6 +156,7 @@ void startup_kernel(void) } else if (__kaslr_offset) memcpy((void *)vmlinux.default_lma, img, vmlinux.image_size); + clear_bss_section(); copy_bootdata(); if (IS_ENABLED(CONFIG_RELOCATABLE)) handle_relocs(__kaslr_offset); diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index 0f255b54b051..7edbbcd8228a 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile @@ -10,20 +10,12 @@ CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) # Do not trace early setup code CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_early_nobss.o = $(CC_FLAGS_FTRACE) endif GCOV_PROFILE_early.o := n -GCOV_PROFILE_early_nobss.o := n - KCOV_INSTRUMENT_early.o := n -KCOV_INSTRUMENT_early_nobss.o := n - UBSAN_SANITIZE_early.o := n -UBSAN_SANITIZE_early_nobss.o := n - -KASAN_SANITIZE_early_nobss.o := n KASAN_SANITIZE_ipl.o := n KASAN_SANITIZE_machine_kexec.o := n @@ -48,7 +40,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' obj-y := traps.o time.o process.o base.o early.o setup.o idle.o vtime.o obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o -obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o early_nobss.o +obj-y += debug.o irq.o ipl.o dis.o diag.o vdso.o obj-y += sysinfo.o lgr.o os_info.o machine_kexec.o pgm_check.o obj-y += runtime_instr.o cache.o fpu.o dumpstack.o guarded_storage.o sthyi.o obj-y += entry.o reipl.o relocate_kernel.o kdebugfs.o alternative.o @@ -90,6 +82,3 @@ obj-$(CONFIG_TRACEPOINTS) += trace.o # vdso obj-y += vdso64/ obj-$(CONFIG_COMPAT_VDSO) += vdso32/ - -chkbss := head64.o early_nobss.o -include $(srctree)/arch/s390/scripts/Makefile.chkbss diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c index 6312fed48530..b432d63d0b37 100644 --- a/arch/s390/kernel/early.c +++ b/arch/s390/kernel/early.c @@ -32,6 +32,21 @@ #include #include "entry.h" +static void __init reset_tod_clock(void) +{ + u64 time; + + if (store_tod_clock(&time) == 0) + return; + /* TOD clock not running. Set the clock to Unix Epoch. */ + if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0) + disabled_wait(); + + memset(tod_clock_base, 0, 16); + *(__u64 *) &tod_clock_base[1] = TOD_UNIX_EPOCH; + S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; +} + /* * Initialize storage key for kernel pages */ @@ -301,6 +316,7 @@ static void __init check_image_bootable(void) void __init startup_init(void) { + reset_tod_clock(); check_image_bootable(); time_early_init(); init_kernel_storage_key(); diff --git a/arch/s390/kernel/early_nobss.c b/arch/s390/kernel/early_nobss.c deleted file mode 100644 index 52a3ef959341..000000000000 --- a/arch/s390/kernel/early_nobss.c +++ /dev/null @@ -1,45 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright IBM Corp. 2007, 2018 - */ - -/* - * Early setup functions which may not rely on an initialized bss - * section. The last thing that is supposed to happen here is - * initialization of the bss section. - */ - -#include -#include -#include -#include -#include -#include -#include "entry.h" - -static void __init reset_tod_clock(void) -{ - u64 time; - - if (store_tod_clock(&time) == 0) - return; - /* TOD clock not running. Set the clock to Unix Epoch. */ - if (set_tod_clock(TOD_UNIX_EPOCH) != 0 || store_tod_clock(&time) != 0) - disabled_wait(); - - memset(tod_clock_base, 0, 16); - *(__u64 *) &tod_clock_base[1] = TOD_UNIX_EPOCH; - S390_lowcore.last_update_clock = TOD_UNIX_EPOCH; -} - -static void __init clear_bss_section(void) -{ - memset(__bss_start, 0, __bss_stop - __bss_start); -} - -void __init startup_init_nobss(void) -{ - reset_tod_clock(); - clear_bss_section(); - kasan_early_init(); -} diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 5aea1a527443..143ed71221fe 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S @@ -34,11 +34,9 @@ ENTRY(startup_continue) larl %r14,init_task stg %r14,__LC_CURRENT larl %r15,init_thread_union+THREAD_SIZE-STACK_FRAME_OVERHEAD -# -# Early setup functions that may not rely on an initialized bss section, -# like moving the initrd. Returns with an initialized bss section. -# - brasl %r14,startup_init_nobss +#ifdef CONFIG_KASAN + brasl %r14,kasan_early_init +#endif # # Early machine initialization and detection functions. # diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index a1ec63abfb95..d7c218e8b559 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile @@ -11,6 +11,3 @@ lib-$(CONFIG_UPROBES) += probes.o # Instrumenting memory accesses to __user data (in different address space) # produce false positives KASAN_SANITIZE_uaccess.o := n - -chkbss := mem.o -include $(srctree)/arch/s390/scripts/Makefile.chkbss diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile index b8a8816d94e7..845e12ac5954 100644 --- a/drivers/s390/char/Makefile +++ b/drivers/s390/char/Makefile @@ -49,6 +49,3 @@ obj-$(CONFIG_CRASH_DUMP) += sclp_sdias.o zcore.o hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o obj-$(CONFIG_HMC_DRV) += hmcdrv.o - -chkbss := sclp_early_core.o -include $(srctree)/arch/s390/scripts/Makefile.chkbss -- cgit v1.2.3 From f45f7b5bdaa4828ce871cf03f7c01599a0de57a5 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 12 Aug 2019 15:52:07 +0200 Subject: s390/kasan: provide uninstrumented __strlen s390 kasan code uses sclp_early_printk to report initialization failures. The code doing that should not be instrumented, because kasan shadow memory has not been set up yet. Even though sclp_early_core.c is compiled with instrumentation disabled it uses strlen function, which is instrumented and would produce shadow memory access if used. To avoid that, introduce uninstrumented __strlen function to be used instead. Before commit 7e0d92f00246 ("s390/kasan: improve string/memory functions checks") few string functions (including strlen) were escaping kasan instrumentation due to usage of platform specific versions which are implemented in inline assembly. Fixes: 7e0d92f00246 ("s390/kasan: improve string/memory functions checks") Acked-by: Ilya Leoshkevich Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/string.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/s390/include/asm/string.h b/arch/s390/include/asm/string.h index 70d87db54e62..4c0690fc5167 100644 --- a/arch/s390/include/asm/string.h +++ b/arch/s390/include/asm/string.h @@ -71,11 +71,16 @@ extern void *__memmove(void *dest, const void *src, size_t n); #define memcpy(dst, src, len) __memcpy(dst, src, len) #define memmove(dst, src, len) __memmove(dst, src, len) #define memset(s, c, n) __memset(s, c, n) +#define strlen(s) __strlen(s) + +#define __no_sanitize_prefix_strfunc(x) __##x #ifndef __NO_FORTIFY #define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */ #endif +#else +#define __no_sanitize_prefix_strfunc(x) x #endif /* defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__) */ void *__memset16(uint16_t *s, uint16_t v, size_t count); @@ -163,8 +168,8 @@ static inline char *strcpy(char *dst, const char *src) } #endif -#ifdef __HAVE_ARCH_STRLEN -static inline size_t strlen(const char *s) +#if defined(__HAVE_ARCH_STRLEN) || (defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)) +static inline size_t __no_sanitize_prefix_strfunc(strlen)(const char *s) { register unsigned long r0 asm("0") = 0; const char *tmp = s; -- cgit v1.2.3 From 8769f610fe6d473e5e8e221709c3ac402037da6c Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 13 Aug 2019 20:11:08 +0200 Subject: s390/process: avoid potential reading of freed stack With THREAD_INFO_IN_TASK (which is selected on s390) task's stack usage is refcounted and should always be protected by get/put when touching other task's stack to avoid race conditions with task's destruction code. Fixes: d5c352cdd022 ("s390: move thread_info into task_struct") Cc: stable@vger.kernel.org # v4.10+ Acked-by: Ilya Leoshkevich Signed-off-by: Vasily Gorbik --- arch/s390/kernel/process.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 63873aa6693f..9f2727bf3cbe 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -184,20 +184,30 @@ unsigned long get_wchan(struct task_struct *p) if (!p || p == current || p->state == TASK_RUNNING || !task_stack_page(p)) return 0; + + if (!try_get_task_stack(p)) + return 0; + low = task_stack_page(p); high = (struct stack_frame *) task_pt_regs(p); sf = (struct stack_frame *) p->thread.ksp; - if (sf <= low || sf > high) - return 0; + if (sf <= low || sf > high) { + return_address = 0; + goto out; + } for (count = 0; count < 16; count++) { sf = (struct stack_frame *) sf->back_chain; - if (sf <= low || sf > high) - return 0; + if (sf <= low || sf > high) { + return_address = 0; + goto out; + } return_address = sf->gprs[8]; if (!in_sched_functions(return_address)) - return return_address; + goto out; } - return 0; +out: + put_task_stack(p); + return return_address; } unsigned long arch_align_stack(unsigned long sp) -- cgit v1.2.3 From 2c7fa8a11cc528e49e88352fce8cf083104b3797 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 13 Aug 2019 19:23:51 +0200 Subject: s390/kasan: avoid report in get_wchan Reading other running task's stack can be a dangerous endeavor. Kasan stack memory access instrumentation includes special prologue and epilogue to mark/remove red zones in shadow memory between stack variables. For that reason there is always a race between a task reading value in other task's stack and that other task returning from a function and entering another one generating different red zones pattern. To avoid kasan reports simply perform uninstrumented memory reads. Acked-by: Ilya Leoshkevich Signed-off-by: Vasily Gorbik --- arch/s390/kernel/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c index 9f2727bf3cbe..b0afec673f77 100644 --- a/arch/s390/kernel/process.c +++ b/arch/s390/kernel/process.c @@ -196,12 +196,12 @@ unsigned long get_wchan(struct task_struct *p) goto out; } for (count = 0; count < 16; count++) { - sf = (struct stack_frame *) sf->back_chain; + sf = (struct stack_frame *)READ_ONCE_NOCHECK(sf->back_chain); if (sf <= low || sf > high) { return_address = 0; goto out; } - return_address = sf->gprs[8]; + return_address = READ_ONCE_NOCHECK(sf->gprs[8]); if (!in_sched_functions(return_address)) goto out; } -- cgit v1.2.3 From e991e5bb11d6eacf8a49867ff9d4ec6e1cde3718 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Wed, 14 Aug 2019 14:27:44 +0200 Subject: s390/stacktrace: use common arch_stack_walk infrastructure Use common arch_stack_walk infrastructure to avoid duplicated code and avoid taking care of the stack storage and filtering. Common code also uses try_get_task_stack/put_task_stack when needed which have been missing in our code, which also solves potential problem for us. Signed-off-by: Vasily Gorbik --- arch/s390/Kconfig | 1 + arch/s390/kernel/stacktrace.c | 50 ++++++------------------------------------- 2 files changed, 7 insertions(+), 44 deletions(-) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index a4ad2733eedf..3289cc243d92 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -105,6 +105,7 @@ config S390 select ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE select ARCH_KEEP_MEMBLOCK select ARCH_SAVE_PAGE_KEYS if HIBERNATION + select ARCH_STACKWALK select ARCH_SUPPORTS_ATOMIC_RMW select ARCH_SUPPORTS_NUMA_BALANCING select ARCH_USE_BUILTIN_BSWAP diff --git a/arch/s390/kernel/stacktrace.c b/arch/s390/kernel/stacktrace.c index f6a620f854e1..f8fc4f8aef9b 100644 --- a/arch/s390/kernel/stacktrace.c +++ b/arch/s390/kernel/stacktrace.c @@ -6,57 +6,19 @@ * Author(s): Heiko Carstens */ -#include -#include #include -#include -#include #include #include -void save_stack_trace(struct stack_trace *trace) +void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, + struct task_struct *task, struct pt_regs *regs) { struct unwind_state state; + unsigned long addr; - unwind_for_each_frame(&state, current, NULL, 0) { - if (trace->nr_entries >= trace->max_entries) + unwind_for_each_frame(&state, task, regs, 0) { + addr = unwind_get_return_address(&state); + if (!addr || !consume_entry(cookie, addr, false)) break; - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = state.ip; } } -EXPORT_SYMBOL_GPL(save_stack_trace); - -void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) -{ - struct unwind_state state; - - unwind_for_each_frame(&state, tsk, NULL, 0) { - if (trace->nr_entries >= trace->max_entries) - break; - if (in_sched_functions(state.ip)) - continue; - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = state.ip; - } -} -EXPORT_SYMBOL_GPL(save_stack_trace_tsk); - -void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) -{ - struct unwind_state state; - - unwind_for_each_frame(&state, current, regs, 0) { - if (trace->nr_entries >= trace->max_entries) - break; - if (trace->skip > 0) - trace->skip--; - else - trace->entries[trace->nr_entries++] = state.ip; - } -} -EXPORT_SYMBOL_GPL(save_stack_trace_regs); -- cgit v1.2.3 From 80ef517b018257220f14410004ede094c577c276 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Thu, 15 Aug 2019 14:49:02 +0200 Subject: s390/startup: adjust _sdma and _edma to page boundaries Move .dma.text section alignment out of section description, otherwise zeros used to align the section are included in the section itself (and section is not really aligned by itself). $ objdump -h arch/s390/boot/compressed/vmlinux 5 .dma.text 00001e38 000000000001b1c8 000000000001b1c8 0001c1c8 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 6 .dma.ex_table 00000018 000000000001d000 000000000001d000 0001e000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .dma.data 00000240 000000000001d080 000000000001d080 0001e080 2**7 CONTENTS, ALLOC, LOAD, DATA $ cat /sys/kernel/debug/memblock/reserved 0: 0x0000000000000000..0x0000000000011fff 1: 0x000000000001b1c8..0x000000000001d2bf ... Also add alignment before _edma linker symbol definition, so that entire .dma* region is rounded up to page boundaries. $ objdump -h arch/s390/boot/compressed/vmlinux 5 .dma.text 00001000 000000000001c000 000000000001c000 0001d000 2**2 CONTENTS, ALLOC, LOAD, READONLY, CODE 6 .dma.ex_table 00000018 000000000001d000 000000000001d000 0001e000 2**2 CONTENTS, ALLOC, LOAD, READONLY, DATA 7 .dma.data 00000240 000000000001d080 000000000001d080 0001e080 2**7 CONTENTS, ALLOC, LOAD, DATA $ cat /sys/kernel/debug/memblock/reserved 0: 0x0000000000000000..0x0000000000011fff 1: 0x000000000001c000..0x000000000001dfff ... $ cat /sys/kernel/debug/kernel_page_tables ---[ Identity Mapping ]--- 0x0000000000000000-0x000000000001c000 112K PTE RW NX 0x000000000001c000-0x000000000001d000 4K PTE RO X 0x000000000001d000-0x0000000000100000 908K PTE RW NX ... Reviewed-by: Gerald Schaefer Signed-off-by: Vasily Gorbik --- arch/s390/boot/compressed/vmlinux.lds.S | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/s390/boot/compressed/vmlinux.lds.S b/arch/s390/boot/compressed/vmlinux.lds.S index 635217eb3d91..44561b2c3712 100644 --- a/arch/s390/boot/compressed/vmlinux.lds.S +++ b/arch/s390/boot/compressed/vmlinux.lds.S @@ -37,9 +37,9 @@ SECTIONS * .dma section for code, data, ex_table that need to stay below 2 GB, * even when the kernel is relocate: above 2 GB. */ + . = ALIGN(PAGE_SIZE); _sdma = .; .dma.text : { - . = ALIGN(PAGE_SIZE); _stext_dma = .; *(.dma.text) . = ALIGN(PAGE_SIZE); @@ -52,6 +52,7 @@ SECTIONS _stop_dma_ex_table = .; } .dma.data : { *(.dma.data) } + . = ALIGN(PAGE_SIZE); _edma = .; BOOT_DATA -- cgit v1.2.3 From 22a33c7e4ed6aae8c47de72461162021dad87473 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Fri, 16 Aug 2019 10:43:55 +0200 Subject: s390/startup: round down "mem" option to page boundary Make a usable value out of "mem" option once and for all. Kasan memory allocator just takes memory_end or online memory size as allocation base. If memory_end is not aligned paging structures allocated in kasan end up unaligned as well. So this change fixes potential kasan crash as well. Fixes: 78333d1f908a ("s390/kasan: add support for mem= kernel parameter") Signed-off-by: Vasily Gorbik --- arch/s390/boot/ipl_parm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 449d26a42f3f..4a052a844f9b 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -224,7 +224,7 @@ void parse_boot_command_line(void) args = next_arg(args, ¶m, &val); if (!strcmp(param, "mem")) { - memory_end = memparse(val, NULL); + memory_end = round_down(memparse(val, NULL), PAGE_SIZE); memory_end_set = 1; } -- cgit v1.2.3 From 183cb46954dd204e3578a25ad1284aab3debec52 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 3 Jul 2019 13:09:03 +0200 Subject: s390/pkey: pkey cleanup: narrow in-kernel API, fix some variable types There are a lot of pkey functions exported as in-kernel callable API functions but not used at all. This patch narrows down the pkey in-kernel API to what is currently only used and exploited. Within the kernel just use u32 without any leading __u32. Also functions declared in a header file in arch/s390/include/asm don't need a comment 'In-kernel API', this is by definition, otherwise the header file would be in arch/s390/include/uapi/asm. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/pkey.h | 114 +---------------------------------------- drivers/s390/crypto/pkey_api.c | 37 ++++++------- 2 files changed, 18 insertions(+), 133 deletions(-) diff --git a/arch/s390/include/asm/pkey.h b/arch/s390/include/asm/pkey.h index 9b6e79077866..dd3d20c332ac 100644 --- a/arch/s390/include/asm/pkey.h +++ b/arch/s390/include/asm/pkey.h @@ -2,7 +2,7 @@ /* * Kernelspace interface to the pkey device driver * - * Copyright IBM Corp. 2016 + * Copyright IBM Corp. 2016,2019 * * Author: Harald Freudenberger * @@ -15,116 +15,6 @@ #include #include -/* - * Generate (AES) random secure key. - * @param cardnr may be -1 (use default card) - * @param domain may be -1 (use default domain) - * @param keytype one of the PKEY_KEYTYPE values - * @param seckey pointer to buffer receiving the secure key - * @return 0 on success, negative errno value on failure - */ -int pkey_genseckey(__u16 cardnr, __u16 domain, - __u32 keytype, struct pkey_seckey *seckey); - -/* - * Generate (AES) secure key with given key value. - * @param cardnr may be -1 (use default card) - * @param domain may be -1 (use default domain) - * @param keytype one of the PKEY_KEYTYPE values - * @param clrkey pointer to buffer with clear key data - * @param seckey pointer to buffer receiving the secure key - * @return 0 on success, negative errno value on failure - */ -int pkey_clr2seckey(__u16 cardnr, __u16 domain, __u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_seckey *seckey); - -/* - * Derive (AES) proteced key from the (AES) secure key blob. - * @param cardnr may be -1 (use default card) - * @param domain may be -1 (use default domain) - * @param seckey pointer to buffer with the input secure key - * @param protkey pointer to buffer receiving the protected key and - * additional info (type, length) - * @return 0 on success, negative errno value on failure - */ -int pkey_sec2protkey(__u16 cardnr, __u16 domain, - const struct pkey_seckey *seckey, - struct pkey_protkey *protkey); - -/* - * Derive (AES) protected key from a given clear key value. - * @param keytype one of the PKEY_KEYTYPE values - * @param clrkey pointer to buffer with clear key data - * @param protkey pointer to buffer receiving the protected key and - * additional info (type, length) - * @return 0 on success, negative errno value on failure - */ -int pkey_clr2protkey(__u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_protkey *protkey); - -/* - * Search for a matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. - * @param seckey pointer to buffer with the input secure key - * @param cardnr pointer to cardnr, receives the card number on success - * @param domain pointer to domain, receives the domain number on success - * @param verify if set, always verify by fetching verification pattern - * from card - * @return 0 on success, negative errno value on failure. If no card could be - * found, -ENODEV is returned. - */ -int pkey_findcard(const struct pkey_seckey *seckey, - __u16 *cardnr, __u16 *domain, int verify); - -/* - * Find card and transform secure key to protected key. - * @param seckey pointer to buffer with the input secure key - * @param protkey pointer to buffer receiving the protected key and - * additional info (type, length) - * @return 0 on success, negative errno value on failure - */ -int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *protkey); - -/* - * Verify the given secure key for being able to be useable with - * the pkey module. Check for correct key type and check for having at - * least one crypto card being able to handle this key (master key - * or old master key verification pattern matches). - * Return some info about the key: keysize in bits, keytype (currently - * only AES), flag if key is wrapped with an old MKVP. - * @param seckey pointer to buffer with the input secure key - * @param pcardnr pointer to cardnr, receives the card number on success - * @param pdomain pointer to domain, receives the domain number on success - * @param pkeysize pointer to keysize, receives the bitsize of the key - * @param pattributes pointer to attributes, receives additional info - * PKEY_VERIFY_ATTR_AES if the key is an AES key - * PKEY_VERIFY_ATTR_OLD_MKVP if key has old mkvp stored in - * @return 0 on success, negative errno value on failure. If no card could - * be found which is able to handle this key, -ENODEV is returned. - */ -int pkey_verifykey(const struct pkey_seckey *seckey, - u16 *pcardnr, u16 *pdomain, - u16 *pkeysize, u32 *pattributes); - -/* - * In-kernel API: Generate (AES) random protected key. - * @param keytype one of the PKEY_KEYTYPE values - * @param protkey pointer to buffer receiving the protected key - * @return 0 on success, negative errno value on failure - */ -int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey); - -/* - * In-kernel API: Verify an (AES) protected key. - * @param protkey pointer to buffer containing the protected key to verify - * @return 0 on success, negative errno value on failure. In case the protected - * key is not valid -EKEYREJECTED is returned - */ -int pkey_verifyprotkey(const struct pkey_protkey *protkey); - /* * In-kernel API: Transform an key blob (of any type) into a protected key. * @param key pointer to a buffer containing the key blob @@ -132,7 +22,7 @@ int pkey_verifyprotkey(const struct pkey_protkey *protkey); * @param protkey pointer to buffer receiving the protected key * @return 0 on success, negative errno value on failure */ -int pkey_keyblob2pkey(const __u8 *key, __u32 keylen, +int pkey_keyblob2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey); #endif /* _KAPI_PKEY_H */ diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index 9f7c26b6ca04..cd7e654bd18e 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -2,7 +2,7 @@ /* * pkey device driver * - * Copyright IBM Corp. 2017 + * Copyright IBM Corp. 2017,2019 * Author(s): Harald Freudenberger */ @@ -71,9 +71,9 @@ struct protaeskeytoken { /* * Create a protected key from a clear key value. */ -int pkey_clr2protkey(u32 keytype, - const struct pkey_clrkey *clrkey, - struct pkey_protkey *protkey) +static int pkey_clr2protkey(u32 keytype, + const struct pkey_clrkey *clrkey, + struct pkey_protkey *protkey) { long fc; int keysize; @@ -122,13 +122,12 @@ int pkey_clr2protkey(u32 keytype, return 0; } -EXPORT_SYMBOL(pkey_clr2protkey); /* * Find card and transform secure key into protected key. */ -int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *pkey) +static int pkey_skey2pkey(const struct pkey_seckey *seckey, + struct pkey_protkey *pkey) { u16 cardnr, domain; int rc, verify; @@ -157,14 +156,13 @@ int pkey_skey2pkey(const struct pkey_seckey *seckey, return rc; } -EXPORT_SYMBOL(pkey_skey2pkey); /* * Verify key and give back some info about the key. */ -int pkey_verifykey(const struct pkey_seckey *seckey, - u16 *pcardnr, u16 *pdomain, - u16 *pkeysize, u32 *pattributes) +static int pkey_verifykey(const struct pkey_seckey *seckey, + u16 *pcardnr, u16 *pdomain, + u16 *pkeysize, u32 *pattributes) { struct secaeskeytoken *t = (struct secaeskeytoken *) seckey; u16 cardnr, domain; @@ -201,12 +199,11 @@ out: DEBUG_DBG("%s rc=%d\n", __func__, rc); return rc; } -EXPORT_SYMBOL(pkey_verifykey); /* * Generate a random protected key */ -int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey) +static int pkey_genprotkey(u32 keytype, struct pkey_protkey *protkey) { struct pkey_clrkey clrkey; int keysize; @@ -241,12 +238,11 @@ int pkey_genprotkey(__u32 keytype, struct pkey_protkey *protkey) return 0; } -EXPORT_SYMBOL(pkey_genprotkey); /* * Verify if a protected key is still valid */ -int pkey_verifyprotkey(const struct pkey_protkey *protkey) +static int pkey_verifyprotkey(const struct pkey_protkey *protkey) { unsigned long fc; struct { @@ -287,12 +283,11 @@ int pkey_verifyprotkey(const struct pkey_protkey *protkey) 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, +static int pkey_nonccatok2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -320,7 +315,7 @@ static int pkey_nonccatok2pkey(const __u8 *key, __u32 keylen, /* * Transform a CCA internal key token into a protected key */ -static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen, +static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -342,7 +337,7 @@ static int pkey_ccainttok2pkey(const __u8 *key, __u32 keylen, /* * Transform a key blob (of any type) into a protected key */ -int pkey_keyblob2pkey(const __u8 *key, __u32 keylen, +int pkey_keyblob2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { struct keytoken_header *hdr = (struct keytoken_header *)key; @@ -507,8 +502,8 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, case PKEY_KBLOB2PROTK: { struct pkey_kblob2pkey __user *utp = (void __user *) arg; struct pkey_kblob2pkey ktp; - __u8 __user *ukey; - __u8 *kkey; + u8 __user *ukey; + u8 *kkey; if (copy_from_user(&ktp, utp, sizeof(ktp))) return -EFAULT; -- cgit v1.2.3 From 4da57a2fea064f662c29e77da043baebb8d6cdc8 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Tue, 18 Jun 2019 15:53:12 +0200 Subject: s390/zcrypt: extend cca_findcard function and helper Rework and extension of the cca_findcard function to be prepared for other types of secure key blobs. Split the function and extract an internal function which has no awareness of key blobs any more. Improve this function and the helper code around to be able to check for a minimal crypto card hardware level (Background: the newer AES cipher keys need to match to the master key verification pattern and need to have a crypto card CEX6 or higher). No API change, neither for the in-kernel API nor the ioctl interface. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_api.c | 28 +++++++++++++++ drivers/s390/crypto/zcrypt_api.h | 7 ++-- drivers/s390/crypto/zcrypt_ccamisc.c | 69 ++++++++++++++++++++++++++---------- drivers/s390/crypto/zcrypt_ccamisc.h | 3 +- 4 files changed, 83 insertions(+), 24 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 69ac7bf09a57..563801427fe4 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -1161,6 +1161,34 @@ void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus) } EXPORT_SYMBOL(zcrypt_device_status_mask_ext); +int zcrypt_device_status_ext(int card, int queue, + struct zcrypt_device_status_ext *devstat) +{ + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + + memset(devstat, 0, sizeof(*devstat)); + + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (card == AP_QID_CARD(zq->queue->qid) && + queue == AP_QID_QUEUE(zq->queue->qid)) { + devstat->hwtype = zc->card->ap_dev.device_type; + devstat->functions = zc->card->functions >> 26; + devstat->qid = zq->queue->qid; + devstat->online = zq->online ? 0x01 : 0x00; + spin_unlock(&zcrypt_list_lock); + return 0; + } + } + } + spin_unlock(&zcrypt_list_lock); + + return -ENODEV; +} +EXPORT_SYMBOL(zcrypt_device_status_ext); + static void zcrypt_status_mask(char status[], size_t max_adapters) { struct zcrypt_card *zc; diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index af67a768a3fc..2d3f2732344f 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -121,9 +121,6 @@ void zcrypt_card_get(struct zcrypt_card *); int zcrypt_card_put(struct zcrypt_card *); int zcrypt_card_register(struct zcrypt_card *); void zcrypt_card_unregister(struct zcrypt_card *); -struct zcrypt_card *zcrypt_card_get_best(unsigned int *, - unsigned int, unsigned int); -void zcrypt_card_put_best(struct zcrypt_card *, unsigned int); struct zcrypt_queue *zcrypt_queue_alloc(size_t); void zcrypt_queue_free(struct zcrypt_queue *); @@ -132,8 +129,6 @@ int zcrypt_queue_put(struct zcrypt_queue *); int zcrypt_queue_register(struct zcrypt_queue *); void zcrypt_queue_unregister(struct zcrypt_queue *); void zcrypt_queue_force_online(struct zcrypt_queue *, int); -struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int); -void zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int); int zcrypt_rng_device_add(void); void zcrypt_rng_device_remove(void); @@ -145,5 +140,7 @@ int zcrypt_api_init(void); void zcrypt_api_exit(void); long zcrypt_send_cprb(struct ica_xcRB *xcRB); void zcrypt_device_status_mask_ext(struct zcrypt_device_status_ext *devstatus); +int zcrypt_device_status_ext(int card, int queue, + struct zcrypt_device_status_ext *devstatus); #endif /* _ZCRYPT_API_H_ */ diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 9dd31577ce47..9b7a866141b8 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -779,7 +779,17 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) int rc, found = 0; size_t rlen, vlen; u8 *rarray, *varray, *pg; + struct zcrypt_device_status_ext devstat; + memset(ci, 0, sizeof(*ci)); + + /* get first info from zcrypt device driver about this apqn */ + rc = zcrypt_device_status_ext(cardnr, domain, &devstat); + if (rc) + return rc; + ci->hwtype = devstat.hwtype; + + /* prep page for rule array and var array use */ pg = (u8 *) __get_free_page(GFP_KERNEL); if (!pg) return -ENOMEM; @@ -787,10 +797,10 @@ static int fetch_cca_info(u16 cardnr, u16 domain, struct cca_info *ci) varray = pg + PAGE_SIZE/2; rlen = vlen = PAGE_SIZE/2; + /* QF for this card/domain */ rc = cca_query_crypto_facility(cardnr, domain, "STATICSA", rarray, &rlen, varray, &vlen); if (rc == 0 && rlen >= 10*8 && vlen >= 204) { - memset(ci, 0, sizeof(*ci)); memcpy(ci->serial, rarray, 8); ci->new_mk_state = (char) rarray[7*8]; ci->cur_mk_state = (char) rarray[8*8]; @@ -828,23 +838,19 @@ int cca_get_info(u16 card, u16 dom, struct cca_info *ci, int verify) EXPORT_SYMBOL(cca_get_info); /* - * Search for a matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. - * Returns < 0 on failure, 0 if CURRENT MKVP matches and - * 1 if OLD MKVP matches. + * Search for a matching crypto card based on the + * Master Key Verification Pattern given. */ -int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) +static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, + int verify, int minhwtype) { - const struct secaeskeytoken *t = (const struct secaeskeytoken *) seckey; struct zcrypt_device_status_ext *device_status; u16 card, dom; struct cca_info ci; int i, rc, oi = -1; - /* some simple checks of the given secure key token */ - if (t->type != TOKTYPE_CCA_INTERNAL || - t->version != TOKVER_CCA_AES || - t->mkvp == 0) + /* mkvp must not be zero, minhwtype needs to be >= 0 */ + if (mkvp == 0 || minhwtype < 0) return -EINVAL; /* fetch status of all crypto cards */ @@ -863,15 +869,17 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) device_status[i].functions & 0x04) { /* enabled CCA card, check current mkvp from cache */ if (cca_info_cache_fetch(card, dom, &ci) == 0 && + ci.hwtype >= minhwtype && ci.cur_mk_state == '2' && - ci.cur_mkvp == t->mkvp) { + ci.cur_mkvp == mkvp) { if (!verify) break; /* verify: refresh card info */ if (fetch_cca_info(card, dom, &ci) == 0) { cca_info_cache_update(card, dom, &ci); - if (ci.cur_mk_state == '2' && - ci.cur_mkvp == t->mkvp) + if (ci.hwtype >= minhwtype && + ci.cur_mk_state == '2' && + ci.cur_mkvp == mkvp) break; } } @@ -892,11 +900,13 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) /* fresh fetch mkvp from adapter */ if (fetch_cca_info(card, dom, &ci) == 0) { cca_info_cache_update(card, dom, &ci); - if (ci.cur_mk_state == '2' && - ci.cur_mkvp == t->mkvp) + if (ci.hwtype >= minhwtype && + ci.cur_mk_state == '2' && + ci.cur_mkvp == mkvp) break; - if (ci.old_mk_state == '2' && - ci.old_mkvp == t->mkvp && + if (ci.hwtype >= minhwtype && + ci.old_mk_state == '2' && + ci.old_mkvp == mkvp && oi < 0) oi = i; } @@ -919,6 +929,29 @@ int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify) kfree(device_status); return rc; } + +/* + * Search for a matching crypto card based on the Master Key + * Verification Pattern provided inside a secure key token. + */ +int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) +{ + u64 mkvp; + const struct keytoken_header *hdr = (struct keytoken_header *) key; + + if (hdr->type != TOKTYPE_CCA_INTERNAL) + return -EINVAL; + + switch (hdr->version) { + case TOKVER_CCA_AES: + mkvp = ((struct secaeskeytoken *)key)->mkvp; + break; + default: + return -EINVAL; + } + + return findcard(mkvp, pcardnr, pdomain, verify, 0); +} EXPORT_SYMBOL(cca_findcard); void __exit zcrypt_ccamisc_exit(void) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index d92fb731602a..e6f41e5baf18 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -88,10 +88,11 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, * Returns < 0 on failure, 0 if CURRENT MKVP matches and * 1 if OLD MKVP matches. */ -int cca_findcard(const u8 *seckey, u16 *pcardnr, u16 *pdomain, int verify); +int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify); /* struct to hold info for each CCA queue */ struct cca_info { + int hwtype; /* one of the defined AP_DEVICE_TYPE_* */ char new_mk_state; /* '1' empty, '2' partially full, '3' full */ char cur_mk_state; /* '1' invalid, '2' valid */ char old_mk_state; /* '1' invalid, '2' valid */ -- cgit v1.2.3 From 4bc123b18ce6ae6c42c69d0456b5acbd2f7bc8bd Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 3 Jul 2019 13:16:51 +0200 Subject: s390/zcrypt: Add low level functions for CCA AES cipher keys This patch adds low level functions, structs and defines to support CCA AES cipher keys: - struct cipherkeytoken can be used for an inside view of the CCA AES cipher key token blob. - function cca_cipher2protkey() derives an CPACF protected key from an CCA AES cipher key. - function cca_gencipherkey() generates an CCA AES cipher key with random value. - function cca_findcard2() constructs a list of apqns based on input constrains like min hardware type, mkvp values. - cca_check_secaescipherkey() does a check on the given CCA AES cipher key blob. - cca_clr2cipherkey() generates an CCA AES cipher key from a given clear key value. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_ccamisc.c | 800 ++++++++++++++++++++++++++++++++++- drivers/s390/crypto/zcrypt_ccamisc.h | 107 ++++- 2 files changed, 903 insertions(+), 4 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 9b7a866141b8..88c5f4a56be7 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -45,13 +46,12 @@ static LIST_HEAD(cca_info_list); static DEFINE_SPINLOCK(cca_info_list_lock); /* - * Simple check if the token is a valid CCA secure AES key + * Simple check if the token is a valid CCA secure AES data key * token. If keybitsize is given, the bitsize of the key is * also checked. Returns 0 on success or errno value on failure. */ int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, const u8 *token, int keybitsize) - { struct secaeskeytoken *t = (struct secaeskeytoken *) token; @@ -82,6 +82,96 @@ int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, } EXPORT_SYMBOL(cca_check_secaeskeytoken); +/* + * Simple check if the token is a valid CCA secure AES cipher key + * token. If keybitsize is given, the bitsize of the key is + * also checked. If checkcpacfexport is enabled, the key is also + * checked for the export flag to allow CPACF export. + * Returns 0 on success or errno value on failure. + */ +int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize, + int checkcpacfexport) +{ + struct cipherkeytoken *t = (struct cipherkeytoken *) token; + bool keybitsizeok = true; + +#define DBF(...) debug_sprintf_event(dbg, dbflvl, ##__VA_ARGS__) + + if (t->type != TOKTYPE_CCA_INTERNAL) { + if (dbg) + DBF("%s token check failed, type 0x%02x != 0x%02x\n", + __func__, (int) t->type, TOKTYPE_CCA_INTERNAL); + return -EINVAL; + } + if (t->version != TOKVER_CCA_VLSC) { + if (dbg) + DBF("%s token check failed, version 0x%02x != 0x%02x\n", + __func__, (int) t->version, TOKVER_CCA_VLSC); + return -EINVAL; + } + if (t->algtype != 0x02) { + if (dbg) + DBF("%s token check failed, algtype 0x%02x != 0x02\n", + __func__, (int) t->algtype); + return -EINVAL; + } + if (t->keytype != 0x0001) { + if (dbg) + DBF("%s token check failed, keytype 0x%04x != 0x0001\n", + __func__, (int) t->keytype); + return -EINVAL; + } + if (t->plfver != 0x00 && t->plfver != 0x01) { + if (dbg) + DBF("%s token check failed, unknown plfver 0x%02x\n", + __func__, (int) t->plfver); + return -EINVAL; + } + if (t->wpllen != 512 && t->wpllen != 576 && t->wpllen != 640) { + if (dbg) + DBF("%s token check failed, unknown wpllen %d\n", + __func__, (int) t->wpllen); + return -EINVAL; + } + if (keybitsize > 0) { + switch (keybitsize) { + case 128: + if (t->wpllen != (t->plfver ? 640 : 512)) + keybitsizeok = false; + break; + case 192: + if (t->wpllen != (t->plfver ? 640 : 576)) + keybitsizeok = false; + break; + case 256: + if (t->wpllen != 640) + keybitsizeok = false; + break; + default: + keybitsizeok = false; + break; + } + if (!keybitsizeok) { + if (dbg) + DBF("%s token check failed, bitsize %d\n", + __func__, keybitsize); + return -EINVAL; + } + } + if (checkcpacfexport && !(t->kmf1 & KMF1_XPRT_CPAC)) { + if (dbg) + DBF("%s token check failed, XPRT_CPAC bit is 0\n", + __func__); + return -EINVAL; + } + +#undef DBF + + return 0; +} +EXPORT_SYMBOL(cca_check_secaescipherkey); + /* * Allocate consecutive memory for request CPRB, request param * block, reply CPRB and reply param block and fill in values @@ -441,7 +531,8 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, } /* copy the generated secure key token */ - memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); + if (seckey) + memcpy(seckey, prepparm->lv3.keyblock.tok, SECKEYBLOBSIZE); out: free_cprbmem(mem, PARMBSIZE, 1); @@ -594,6 +685,623 @@ out: } EXPORT_SYMBOL(cca_sec2protkey); +/* + * AES cipher key skeleton created with CSNBKTB2 with these flags: + * INTERNAL, NO-KEY, AES, CIPHER, ANY-MODE, NOEX-SYM, NOEXAASY, + * NOEXUASY, XPRTCPAC, NOEX-RAW, NOEX-DES, NOEX-AES, NOEX-RSA + * used by cca_gencipherkey() and cca_clr2cipherkey(). + */ +static const u8 aes_cipher_key_skeleton[] = { + 0x01, 0x00, 0x00, 0x38, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x01, 0x02, 0xc0, 0x00, 0xff, + 0x00, 0x03, 0x08, 0xc8, 0x00, 0x00, 0x00, 0x00 }; +#define SIZEOF_SKELETON (sizeof(aes_cipher_key_skeleton)) + +/* + * Generate (random) CCA AES CIPHER secure key. + */ +int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, + u8 *keybuf, size_t *keybufsize) +{ + int rc; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct gkreqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[2*8]; + struct { + u16 len; + u8 key_type_1[8]; + u8 key_type_2[8]; + u16 clear_key_bit_len; + u16 key_name_1_len; + u16 key_name_2_len; + u16 user_data_1_len; + u16 user_data_2_len; + u8 key_name_1[0]; + u8 key_name_2[0]; + u8 user_data_1[0]; + u8 user_data_2[0]; + } vud; + struct { + u16 len; + struct { + u16 len; + u16 flag; + u8 kek_id_1[0]; + } tlv1; + struct { + u16 len; + u16 flag; + u8 kek_id_2[0]; + } tlv2; + struct { + u16 len; + u16 flag; + u8 gen_key_id_1[SIZEOF_SKELETON]; + } tlv3; + struct { + u16 len; + u16 flag; + u8 gen_key_id_1_label[0]; + } tlv4; + struct { + u16 len; + u16 flag; + u8 gen_key_id_2[0]; + } tlv5; + struct { + u16 len; + u16 flag; + u8 gen_key_id_2_label[0]; + } tlv6; + } kb; + } __packed * preqparm; + struct gkrepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct { + u16 len; + } vud; + struct { + u16 len; + struct { + u16 len; + u16 flag; + u8 gen_key[0]; /* 120-136 bytes */ + } tlv1; + } kb; + } __packed * prepparm; + struct cipherkeytoken *t; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + preqcblk->req_parml = sizeof(struct gkreqparm); + + /* prepare request param block with GK request */ + preqparm = (struct gkreqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "GK", 2); + preqparm->rule_array_len = sizeof(uint16_t) + 2 * 8; + memcpy(preqparm->rule_array, "AES OP ", 2*8); + + /* prepare vud block */ + preqparm->vud.len = sizeof(preqparm->vud); + switch (keybitsize) { + case 128: + case 192: + case 256: + break; + default: + DEBUG_ERR( + "%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); + rc = -EINVAL; + goto out; + } + preqparm->vud.clear_key_bit_len = keybitsize; + memcpy(preqparm->vud.key_type_1, "TOKEN ", 8); + memset(preqparm->vud.key_type_2, ' ', sizeof(preqparm->vud.key_type_2)); + + /* prepare kb block */ + preqparm->kb.len = sizeof(preqparm->kb); + preqparm->kb.tlv1.len = sizeof(preqparm->kb.tlv1); + preqparm->kb.tlv1.flag = 0x0030; + preqparm->kb.tlv2.len = sizeof(preqparm->kb.tlv2); + preqparm->kb.tlv2.flag = 0x0030; + preqparm->kb.tlv3.len = sizeof(preqparm->kb.tlv3); + preqparm->kb.tlv3.flag = 0x0030; + memcpy(preqparm->kb.tlv3.gen_key_id_1, + aes_cipher_key_skeleton, SIZEOF_SKELETON); + preqparm->kb.tlv4.len = sizeof(preqparm->kb.tlv4); + preqparm->kb.tlv4.flag = 0x0030; + preqparm->kb.tlv5.len = sizeof(preqparm->kb.tlv5); + preqparm->kb.tlv5.flag = 0x0030; + preqparm->kb.tlv6.len = sizeof(preqparm->kb.tlv6); + preqparm->kb.tlv6.flag = 0x0030; + + /* patch the skeleton key token export flags inside the kb block */ + if (keygenflags) { + t = (struct cipherkeytoken *) preqparm->kb.tlv3.gen_key_id_1; + t->kmf1 |= (u16) (keygenflags & 0x0000FFFF); + } + + /* prepare xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR( + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR( + "%s cipher key generate failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct gkrepparm *) prepcblk->rpl_parmb; + + /* do some plausibility checks on the key block */ + if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) || + prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) { + DEBUG_ERR("%s reply with invalid or unknown key block\n", + __func__); + rc = -EIO; + goto out; + } + + /* and some checks on the generated key */ + rc = cca_check_secaescipherkey(zcrypt_dbf_info, DBF_ERR, + prepparm->kb.tlv1.gen_key, + keybitsize, 1); + if (rc) { + rc = -EIO; + goto out; + } + + /* copy the generated vlsc key token */ + t = (struct cipherkeytoken *) prepparm->kb.tlv1.gen_key; + if (keybuf) { + if (*keybufsize >= t->len) + memcpy(keybuf, t, t->len); + else + rc = -EINVAL; + } + *keybufsize = t->len; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_gencipherkey); + +/* + * Helper function, does a the CSNBKPI2 CPRB. + */ +static int _ip_cprb_helper(u16 cardnr, u16 domain, + const char *rule_array_1, + const char *rule_array_2, + const char *rule_array_3, + const u8 *clr_key_value, + int clr_key_bit_size, + u8 *key_token, + int *key_token_size) +{ + int rc, n; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct rule_array_block { + u8 subfunc_code[2]; + u16 rule_array_len; + char rule_array[0]; + } __packed * preq_ra_block; + struct vud_block { + u16 len; + struct { + u16 len; + u16 flag; /* 0x0064 */ + u16 clr_key_bit_len; + } tlv1; + struct { + u16 len; + u16 flag; /* 0x0063 */ + u8 clr_key[0]; /* clear key value bytes */ + } tlv2; + } __packed * preq_vud_block; + struct key_block { + u16 len; + struct { + u16 len; + u16 flag; /* 0x0030 */ + u8 key_token[0]; /* key skeleton */ + } tlv1; + } __packed * preq_key_block; + struct iprepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct { + u16 len; + } vud; + struct { + u16 len; + struct { + u16 len; + u16 flag; /* 0x0030 */ + u8 key_token[0]; /* key token */ + } tlv1; + } kb; + } __packed * prepparm; + struct cipherkeytoken *t; + int complete = strncmp(rule_array_2, "COMPLETE", 8) ? 0 : 1; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + preqcblk->req_parml = 0; + + /* prepare request param block with IP request */ + preq_ra_block = (struct rule_array_block *) preqcblk->req_parmb; + memcpy(preq_ra_block->subfunc_code, "IP", 2); + preq_ra_block->rule_array_len = sizeof(uint16_t) + 2 * 8; + memcpy(preq_ra_block->rule_array, rule_array_1, 8); + memcpy(preq_ra_block->rule_array + 8, rule_array_2, 8); + preqcblk->req_parml = sizeof(struct rule_array_block) + 2 * 8; + if (rule_array_3) { + preq_ra_block->rule_array_len += 8; + memcpy(preq_ra_block->rule_array + 16, rule_array_3, 8); + preqcblk->req_parml += 8; + } + + /* prepare vud block */ + preq_vud_block = (struct vud_block *) + (preqcblk->req_parmb + preqcblk->req_parml); + n = complete ? 0 : (clr_key_bit_size + 7) / 8; + preq_vud_block->len = sizeof(struct vud_block) + n; + preq_vud_block->tlv1.len = sizeof(preq_vud_block->tlv1); + preq_vud_block->tlv1.flag = 0x0064; + preq_vud_block->tlv1.clr_key_bit_len = complete ? 0 : clr_key_bit_size; + preq_vud_block->tlv2.len = sizeof(preq_vud_block->tlv2) + n; + preq_vud_block->tlv2.flag = 0x0063; + if (!complete) + memcpy(preq_vud_block->tlv2.clr_key, clr_key_value, n); + preqcblk->req_parml += preq_vud_block->len; + + /* prepare key block */ + preq_key_block = (struct key_block *) + (preqcblk->req_parmb + preqcblk->req_parml); + n = *key_token_size; + preq_key_block->len = sizeof(struct key_block) + n; + preq_key_block->tlv1.len = sizeof(preq_key_block->tlv1) + n; + preq_key_block->tlv1.flag = 0x0030; + memcpy(preq_key_block->tlv1.key_token, key_token, *key_token_size); + preqcblk->req_parml += preq_key_block->len; + + /* prepare xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR( + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR( + "%s CSNBKPI2 failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct iprepparm *) prepcblk->rpl_parmb; + + /* do some plausibility checks on the key block */ + if (prepparm->kb.len < 120 + 5 * sizeof(uint16_t) || + prepparm->kb.len > 136 + 5 * sizeof(uint16_t)) { + DEBUG_ERR("%s reply with invalid or unknown key block\n", + __func__); + rc = -EIO; + goto out; + } + + /* do not check the key here, it may be incomplete */ + + /* copy the vlsc key token back */ + t = (struct cipherkeytoken *) prepparm->kb.tlv1.key_token; + memcpy(key_token, t, t->len); + *key_token_size = t->len; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} + +/* + * Build CCA AES CIPHER secure key with a given clear key value. + */ +int cca_clr2cipherkey(u16 card, u16 dom, u32 keybitsize, u32 keygenflags, + const u8 *clrkey, u8 *keybuf, size_t *keybufsize) +{ + int rc; + u8 *token; + int tokensize; + u8 exorbuf[32]; + struct cipherkeytoken *t; + + /* fill exorbuf with random data */ + get_random_bytes(exorbuf, sizeof(exorbuf)); + + /* allocate space for the key token to build */ + token = kmalloc(MAXCCAVLSCTOKENSIZE, GFP_KERNEL); + if (!token) + return -ENOMEM; + + /* prepare the token with the key skeleton */ + tokensize = SIZEOF_SKELETON; + memcpy(token, aes_cipher_key_skeleton, tokensize); + + /* patch the skeleton key token export flags */ + if (keygenflags) { + t = (struct cipherkeytoken *) token; + t->kmf1 |= (u16) (keygenflags & 0x0000FF00); + t->kmf1 &= (u16) ~(keygenflags & 0x000000FF); + } + + /* + * Do the key import with the clear key value in 4 steps: + * 1/4 FIRST import with only random data + * 2/4 EXOR the clear key + * 3/4 EXOR the very same random data again + * 4/4 COMPLETE the secure cipher key import + */ + rc = _ip_cprb_helper(card, dom, "AES ", "FIRST ", "MIN3PART", + exorbuf, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 1/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, + clrkey, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 2/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + rc = _ip_cprb_helper(card, dom, "AES ", "ADD-PART", NULL, + exorbuf, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 3/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + rc = _ip_cprb_helper(card, dom, "AES ", "COMPLETE", NULL, + NULL, keybitsize, token, &tokensize); + if (rc) { + DEBUG_ERR( + "%s clear key import 4/4 with CSNBKPI2 failed, rc=%d\n", + __func__, rc); + goto out; + } + + /* copy the generated key token */ + if (keybuf) { + if (tokensize > *keybufsize) + rc = -EINVAL; + else + memcpy(keybuf, token, tokensize); + } + *keybufsize = tokensize; + +out: + kfree(token); + return rc; +} +EXPORT_SYMBOL(cca_clr2cipherkey); + +/* + * Derive proteced key from CCA AES cipher secure key. + */ +int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, + u8 *protkey, u32 *protkeylen, u32 *protkeytype) +{ + int rc; + u8 *mem; + struct CPRBX *preqcblk, *prepcblk; + struct ica_xcRB xcrb; + struct aureqparm { + u8 subfunc_code[2]; + u16 rule_array_len; + u8 rule_array[8]; + struct { + u16 len; + u16 tk_blob_len; + u16 tk_blob_tag; + u8 tk_blob[66]; + } vud; + struct { + u16 len; + u16 cca_key_token_len; + u16 cca_key_token_flags; + u8 cca_key_token[0]; // 64 or more + } kb; + } __packed * preqparm; + struct aurepparm { + u8 subfunc_code[2]; + u16 rule_array_len; + struct { + u16 len; + u16 sublen; + u16 tag; + struct cpacfkeyblock { + u8 version; /* version of this struct */ + u8 flags[2]; + u8 algo; + u8 form; + u8 pad1[3]; + u16 keylen; + u8 key[64]; /* the key (keylen bytes) */ + u16 keyattrlen; + u8 keyattr[32]; + u8 pad2[1]; + u8 vptype; + u8 vp[32]; /* verification pattern */ + } ckb; + } vud; + struct { + u16 len; + } kb; + } __packed * prepparm; + int keytoklen = ((struct cipherkeytoken *)ckey)->len; + + /* get already prepared memory for 2 cprbs with param block each */ + rc = alloc_and_prep_cprbmem(PARMBSIZE, &mem, &preqcblk, &prepcblk); + if (rc) + return rc; + + /* fill request cprb struct */ + preqcblk->domain = domain; + + /* fill request cprb param block with AU request */ + preqparm = (struct aureqparm *) preqcblk->req_parmb; + memcpy(preqparm->subfunc_code, "AU", 2); + preqparm->rule_array_len = + sizeof(preqparm->rule_array_len) + + sizeof(preqparm->rule_array); + memcpy(preqparm->rule_array, "EXPT-SK ", 8); + /* vud, tk blob */ + preqparm->vud.len = sizeof(preqparm->vud); + preqparm->vud.tk_blob_len = sizeof(preqparm->vud.tk_blob) + + 2 * sizeof(uint16_t); + preqparm->vud.tk_blob_tag = 0x00C2; + /* kb, cca token */ + preqparm->kb.len = keytoklen + 3 * sizeof(uint16_t); + preqparm->kb.cca_key_token_len = keytoklen + 2 * sizeof(uint16_t); + memcpy(preqparm->kb.cca_key_token, ckey, keytoklen); + /* now fill length of param block into cprb */ + preqcblk->req_parml = sizeof(struct aureqparm) + keytoklen; + + /* fill xcrb struct */ + prep_xcrb(&xcrb, cardnr, preqcblk, prepcblk); + + /* forward xcrb with request CPRB and reply CPRB to zcrypt dd */ + rc = _zcrypt_send_cprb(&xcrb); + if (rc) { + DEBUG_ERR( + "%s zcrypt_send_cprb (cardnr=%d domain=%d) failed, rc=%d\n", + __func__, (int) cardnr, (int) domain, rc); + goto out; + } + + /* check response returncode and reasoncode */ + if (prepcblk->ccp_rtcode != 0) { + DEBUG_ERR( + "%s unwrap secure key failure, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + rc = -EIO; + goto out; + } + if (prepcblk->ccp_rscode != 0) { + DEBUG_WARN( + "%s unwrap secure key warning, card response %d/%d\n", + __func__, + (int) prepcblk->ccp_rtcode, + (int) prepcblk->ccp_rscode); + } + + /* process response cprb param block */ + prepcblk->rpl_parmb = ((u8 *) prepcblk) + sizeof(struct CPRBX); + prepparm = (struct aurepparm *) prepcblk->rpl_parmb; + + /* check the returned keyblock */ + if (prepparm->vud.ckb.version != 0x01) { + DEBUG_ERR( + "%s reply param keyblock version mismatch 0x%02x != 0x01\n", + __func__, (int) prepparm->vud.ckb.version); + rc = -EIO; + goto out; + } + if (prepparm->vud.ckb.algo != 0x02) { + DEBUG_ERR( + "%s reply param keyblock algo mismatch 0x%02x != 0x02\n", + __func__, (int) prepparm->vud.ckb.algo); + rc = -EIO; + goto out; + } + + /* copy the translated protected key */ + switch (prepparm->vud.ckb.keylen) { + case 16+32: + /* AES 128 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_128; + break; + case 24+32: + /* AES 192 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_192; + break; + case 32+32: + /* AES 256 protected key */ + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_256; + break; + default: + DEBUG_ERR("%s unknown/unsupported keylen %d\n", + __func__, prepparm->vud.ckb.keylen); + rc = -EIO; + goto out; + } + memcpy(protkey, prepparm->vud.ckb.key, prepparm->vud.ckb.keylen); + if (protkeylen) + *protkeylen = prepparm->vud.ckb.keylen; + +out: + free_cprbmem(mem, PARMBSIZE, 0); + return rc; +} +EXPORT_SYMBOL(cca_cipher2protkey); + /* * query cryptographic facility from CCA adapter */ @@ -954,6 +1662,92 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) } EXPORT_SYMBOL(cca_findcard); +int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, + int minhwtype, u64 cur_mkvp, u64 old_mkvp, int verify) +{ + struct zcrypt_device_status_ext *device_status; + int i, n, card, dom, curmatch, oldmatch, rc = 0; + struct cca_info ci; + + *apqns = NULL; + *nr_apqns = 0; + + /* fetch status of all crypto cards */ + device_status = kmalloc_array(MAX_ZDEV_ENTRIES_EXT, + sizeof(struct zcrypt_device_status_ext), + GFP_KERNEL); + if (!device_status) + return -ENOMEM; + zcrypt_device_status_mask_ext(device_status); + + /* loop two times: first gather eligible apqns, then store them */ + while (1) { + n = 0; + /* walk through all the crypto cards */ + for (i = 0; i < MAX_ZDEV_ENTRIES_EXT; i++) { + card = AP_QID_CARD(device_status[i].qid); + dom = AP_QID_QUEUE(device_status[i].qid); + /* check online state */ + if (!device_status[i].online) + continue; + /* check for cca functions */ + if (!(device_status[i].functions & 0x04)) + continue; + /* check cardnr */ + if (cardnr != 0xFFFF && card != cardnr) + continue; + /* check domain */ + if (domain != 0xFFFF && dom != domain) + continue; + /* get cca info on this apqn */ + if (cca_get_info(card, dom, &ci, verify)) + continue; + /* current master key needs to be valid */ + if (ci.cur_mk_state != '2') + continue; + /* check min hardware type */ + if (minhwtype > 0 && minhwtype > ci.hwtype) + continue; + if (cur_mkvp || old_mkvp) { + /* check mkvps */ + curmatch = oldmatch = 0; + if (cur_mkvp && cur_mkvp == ci.cur_mkvp) + curmatch = 1; + if (old_mkvp && ci.old_mk_state == '2' && + old_mkvp == ci.old_mkvp) + oldmatch = 1; + if ((cur_mkvp || old_mkvp) && + (curmatch + oldmatch < 1)) + continue; + } + /* apqn passed all filtering criterons */ + if (*apqns && n < *nr_apqns) + (*apqns)[n] = (((u16)card) << 16) | ((u16) dom); + n++; + } + /* loop 2nd time: array has been filled */ + if (*apqns) + break; + /* loop 1st time: have # of eligible apqns in n */ + if (!n) { + rc = -ENODEV; /* no eligible apqns found */ + break; + } + *nr_apqns = n; + /* allocate array to store n apqns into */ + *apqns = kmalloc_array(n, sizeof(u32), GFP_KERNEL); + if (!*apqns) { + rc = -ENOMEM; + break; + } + verify = 0; + } + + kfree(device_status); + return rc; +} +EXPORT_SYMBOL(cca_findcard2); + void __exit zcrypt_ccamisc_exit(void) { mkvp_cache_free(); diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index e6f41e5baf18..e97cda0f61e0 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -22,11 +22,16 @@ /* For TOKTYPE_CCA_INTERNAL: */ #define TOKVER_CCA_AES 0x04 /* CCA AES key token */ +#define TOKVER_CCA_VLSC 0x05 /* var length sym cipher key token */ + +/* Max size of a cca variable length cipher key token */ +#define MAXCCAVLSCTOKENSIZE 725 /* header part of a CCA key token */ struct keytoken_header { u8 type; /* one of the TOKTYPE values */ - u8 res0[3]; + u8 res0[1]; + u16 len; /* vlsc token: total length in bytes */ u8 version; /* one of the TOKVER values */ u8 res1[3]; } __packed; @@ -47,6 +52,56 @@ struct secaeskeytoken { u8 tvv[4]; /* token validation value */ } __packed; +/* inside view of a variable length symmetric cipher AES key token */ +struct cipherkeytoken { + u8 type; /* 0x01 for internal key token */ + u8 res0[1]; + u16 len; /* total key token length in bytes */ + u8 version; /* should be 0x05 */ + u8 res1[3]; + u8 kms; /* key material state, 0x03 means wrapped with MK */ + u8 kvpt; /* key verification pattern type, should be 0x01 */ + u64 mkvp0; /* master key verification pattern, lo part */ + u64 mkvp1; /* master key verification pattern, hi part (unused) */ + u8 eskwm; /* encrypted section key wrapping method */ + u8 hashalg; /* hash algorithmus used for wrapping key */ + u8 plfver; /* pay load format version */ + u8 res2[1]; + u8 adsver; /* associated data section version */ + u8 res3[1]; + u16 adslen; /* associated data section length */ + u8 kllen; /* optional key label length */ + u8 ieaslen; /* optional extended associated data length */ + u8 uadlen; /* optional user definable associated data length */ + u8 res4[1]; + u16 wpllen; /* wrapped payload length in bits: */ + /* plfver 0x00 0x01 */ + /* AES-128 512 640 */ + /* AES-192 576 640 */ + /* AES-256 640 640 */ + u8 res5[1]; + u8 algtype; /* 0x02 for AES cipher */ + u16 keytype; /* 0x0001 for 'cipher' */ + u8 kufc; /* key usage field count */ + u16 kuf1; /* key usage field 1 */ + u16 kuf2; /* key usage field 2 */ + u8 kmfc; /* key management field count */ + u16 kmf1; /* key management field 1 */ + u16 kmf2; /* key management field 2 */ + u16 kmf3; /* key management field 3 */ + u8 vdata[0]; /* variable part data follows */ +} __packed; + +/* Some defines for the CCA AES cipherkeytoken kmf1 field */ +#define KMF1_XPRT_SYM 0x8000 +#define KMF1_XPRT_UASY 0x4000 +#define KMF1_XPRT_AASY 0x2000 +#define KMF1_XPRT_RAW 0x1000 +#define KMF1_XPRT_CPAC 0x0800 +#define KMF1_XPRT_DES 0x0080 +#define KMF1_XPRT_AES 0x0040 +#define KMF1_XPRT_RSA 0x0008 + /* * Simple check if the token is a valid CCA secure AES data key * token. If keybitsize is given, the bitsize of the key is @@ -55,6 +110,17 @@ struct secaeskeytoken { int cca_check_secaeskeytoken(debug_info_t *dbg, int dbflvl, const u8 *token, int keybitsize); +/* + * Simple check if the token is a valid CCA secure AES cipher key + * token. If keybitsize is given, the bitsize of the key is + * also checked. If checkcpacfexport is enabled, the key is also + * checked for the export flag to allow CPACF export. + * Returns 0 on success or errno value on failure. + */ +int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, + const u8 *token, int keybitsize, + int checkcpacfexport); + /* * Generate (random) CCA AES DATA secure key. */ @@ -74,6 +140,24 @@ int cca_sec2protkey(u16 cardnr, u16 domain, u8 *protkey, u32 *protkeylen, u32 *protkeytype); +/* + * Generate (random) CCA AES CIPHER secure key. + */ +int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, + u8 *keybuf, size_t *keybufsize); + +/* + * Derive proteced key from CCA AES cipher secure key. + */ +int cca_cipher2protkey(u16 cardnr, u16 domain, const u8 *ckey, + u8 *protkey, u32 *protkeylen, u32 *protkeytype); + +/* + * Build CCA AES CIPHER secure key with a given clear key value. + */ +int cca_clr2cipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, + const u8 *clrkey, u8 *keybuf, size_t *keybufsize); + /* * Query cryptographic facility from CCA adapter */ @@ -90,6 +174,27 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, */ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify); +/* + * Build a list of cca apqns meeting the following constrains: + * - apqn is online and is in fact a CCA apqn + * - if cardnr is not FFFF only apqns with this cardnr + * - if domain is not FFFF only apqns with this domainnr + * - if minhwtype > 0 only apqns with hwtype >= minhwtype + * - if cur_mkvp != 0 only apqns where cur_mkvp == mkvp + * - if old_mkvp != 0 only apqns where old_mkvp == mkvp + * - if verify is enabled and a cur_mkvp and/or old_mkvp + * value is given, then refetch the cca_info and make sure the current + * cur_mkvp or old_mkvp values of the apqn are used. + * The array of apqn entries is allocated with kmalloc and returned in *apqns; + * the number of apqns stored into the list is returned in *nr_apqns. One apqn + * entry is simple a 32 bit value with 16 bit cardnr and 16 bit domain nr and + * may be casted to struct pkey_apqn. The return value is either 0 for success + * or a negative errno value. If no apqn meeting the criterias is found, + * -ENODEV is returned. + */ +int cca_findcard2(u32 **apqns, u32 *nr_apqns, u16 cardnr, u16 domain, + int minhwtype, u64 cur_mkvp, u64 old_mkvp, int verify); + /* struct to hold info for each CCA queue */ struct cca_info { int hwtype; /* one of the defined AP_DEVICE_TYPE_* */ -- cgit v1.2.3 From f2bbc96e7cfad3891b7bf9bd3e566b9b7ab4553d Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 19 Jun 2019 14:26:05 +0200 Subject: s390/pkey: add CCA AES cipher key support Introduce new ioctls and structs to be used with these new ioctls which are able to handle CCA AES secure keys and CCA AES cipher keys: PKEY_GENSECK2: Generate secure key, version 2. Generate either a CCA AES secure key or a CCA AES cipher key. PKEY_CLR2SECK2: Generate secure key from clear key value, version 2. Construct a CCA AES secure key or CCA AES cipher key from a given clear key value. PKEY_VERIFYKEY2: Verify the given secure key, version 2. Check for correct key type. If cardnr and domain are given, also check if this apqn is able to handle this type of key. If cardnr and domain are 0xFFFF, on return these values are filled with an apqn able to handle this key. The function also checks for the master key verification patterns of the key matching to the current or alternate mkvp of the apqn. CCA AES cipher keys are also checked for CPACF export allowed (CPRTCPAC flag). Currently CCA AES secure keys and CCA AES cipher keys are supported (may get extended in the future). PKEY_KBLOB2PROTK2: Transform a key blob (of any type) into a protected key, version 2. Difference to version 1 is only that this new ioctl has additional parameters to provide a list of apqns to be used for the transformation. PKEY_APQNS4K: Generate a list of APQNs based on the key blob given. Is able to find out which type of secure key is given (CCA AES secure key or CCA AES cipher key) and tries to find all matching crypto cards based on the MKVP and maybe other criterias (like CCA AES cipher keys need a CEX6C or higher). The list of APQNs is further filtered by the key's mkvp which needs to match to either the current mkvp or the alternate mkvp (which is the old mkvp on CCA adapters) of the apqns. The flags argument may be used to limit the matching apqns. If the PKEY_FLAGS_MATCH_CUR_MKVP is given, only the current mkvp of each apqn is compared. Likewise with the PKEY_FLAGS_MATCH_ALT_MKVP. If both are given it is assumed to return apqns where either the current or the alternate mkvp matches. If no matching APQN is found, the ioctl returns with 0 but the apqn_entries value is 0. PKEY_APQNS4KT: Generate a list of APQNs based on the key type given. Build a list of APQNs based on the given key type and maybe further restrict the list by given master key verification patterns. For different key types there may be different ways to match the master key verification patterns. For CCA keys (CCA data key and CCA cipher key) the first 8 bytes of cur_mkvp refer to the current mkvp value of the apqn and the first 8 bytes of the alt_mkvp refer to the old mkvp. The flags argument controls if the apqns current and/or alternate mkvp should match. If the PKEY_FLAGS_MATCH_CUR_MKVP is given, only the current mkvp of each apqn is compared. Likewise with the PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it is assumed to return apqns where either the current or the alternate mkvp matches. If no matching APQN is found, the ioctl returns with 0 but the apqn_entries value is 0. These new ioctls are now prepared for another new type of secure key blob which may come in the future. They all use a pointer to the key blob and a key blob length information instead of some hardcoded byte array. They all use the new enums pkey_key_type, pkey_key_size and pkey_key_info for getting/setting key type, key size and additional info about the key. All but the PKEY_VERIFY2 ioctl now work based on a list of apqns. This list is walked through trying to perform the operation on exactly this apqn without any further checking (like card type or online state). If the apqn fails, simple the next one in the list is tried until success (return 0) or the end of the list is reached (return -1 with errno ENODEV). All apqns in the list need to be exact apqns (0xFFFF as any card or domain is not allowed). There are two new ioctls which can be used to build a list of apqns based on a key or key type and maybe restricted by match to a current or alternate master key verifcation pattern. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- arch/s390/include/uapi/asm/pkey.h | 257 ++++++++++++-- drivers/s390/crypto/pkey_api.c | 652 +++++++++++++++++++++++++++++++++-- drivers/s390/crypto/zcrypt_ccamisc.c | 58 ++-- drivers/s390/crypto/zcrypt_ccamisc.h | 8 +- 4 files changed, 899 insertions(+), 76 deletions(-) diff --git a/arch/s390/include/uapi/asm/pkey.h b/arch/s390/include/uapi/asm/pkey.h index c0e86ce4a00b..e22f0720bbb8 100644 --- a/arch/s390/include/uapi/asm/pkey.h +++ b/arch/s390/include/uapi/asm/pkey.h @@ -2,7 +2,7 @@ /* * Userspace interface to the pkey device driver * - * Copyright IBM Corp. 2017 + * Copyright IBM Corp. 2017, 2019 * * Author: Harald Freudenberger * @@ -20,38 +20,74 @@ #define PKEY_IOCTL_MAGIC 'p' -#define SECKEYBLOBSIZE 64 /* secure key blob size is always 64 bytes */ -#define PROTKEYBLOBSIZE 80 /* protected key blob size is always 80 bytes */ -#define MAXPROTKEYSIZE 64 /* a protected key blob may be up to 64 bytes */ -#define MAXCLRKEYSIZE 32 /* a clear key value may be up to 32 bytes */ +#define SECKEYBLOBSIZE 64 /* secure key blob size is always 64 bytes */ +#define PROTKEYBLOBSIZE 80 /* protected key blob size is always 80 bytes */ +#define MAXPROTKEYSIZE 64 /* a protected key blob may be up to 64 bytes */ +#define MAXCLRKEYSIZE 32 /* a clear key value may be up to 32 bytes */ +#define MAXAESCIPHERKEYSIZE 136 /* our aes cipher keys have always 136 bytes */ -#define MINKEYBLOBSIZE SECKEYBLOBSIZE /* Minimum size of a key blob */ -#define MAXKEYBLOBSIZE PROTKEYBLOBSIZE /* Maximum size of a key blob */ +/* Minimum and maximum size of a key blob */ +#define MINKEYBLOBSIZE SECKEYBLOBSIZE +#define MAXKEYBLOBSIZE MAXAESCIPHERKEYSIZE /* defines for the type field within the pkey_protkey struct */ -#define PKEY_KEYTYPE_AES_128 1 -#define PKEY_KEYTYPE_AES_192 2 -#define PKEY_KEYTYPE_AES_256 3 +#define PKEY_KEYTYPE_AES_128 1 +#define PKEY_KEYTYPE_AES_192 2 +#define PKEY_KEYTYPE_AES_256 3 -/* Struct to hold a secure key blob */ +/* the newer ioctls use a pkey_key_type enum for type information */ +enum pkey_key_type { + PKEY_TYPE_CCA_DATA = (__u32) 1, + PKEY_TYPE_CCA_CIPHER = (__u32) 2, +}; + +/* the newer ioctls use a pkey_key_size enum for key size information */ +enum pkey_key_size { + PKEY_SIZE_AES_128 = (__u32) 128, + PKEY_SIZE_AES_192 = (__u32) 192, + PKEY_SIZE_AES_256 = (__u32) 256, + PKEY_SIZE_UNKNOWN = (__u32) 0xFFFFFFFF, +}; + +/* some of the newer ioctls use these flags */ +#define PKEY_FLAGS_MATCH_CUR_MKVP 0x00000002 +#define PKEY_FLAGS_MATCH_ALT_MKVP 0x00000004 + +/* keygenflags defines for CCA AES cipher keys */ +#define PKEY_KEYGEN_XPRT_SYM 0x00008000 +#define PKEY_KEYGEN_XPRT_UASY 0x00004000 +#define PKEY_KEYGEN_XPRT_AASY 0x00002000 +#define PKEY_KEYGEN_XPRT_RAW 0x00001000 +#define PKEY_KEYGEN_XPRT_CPAC 0x00000800 +#define PKEY_KEYGEN_XPRT_DES 0x00000080 +#define PKEY_KEYGEN_XPRT_AES 0x00000040 +#define PKEY_KEYGEN_XPRT_RSA 0x00000008 + +/* Struct to hold apqn target info (card/domain pair) */ +struct pkey_apqn { + __u16 card; + __u16 domain; +}; + +/* Struct to hold a CCA AES secure key blob */ struct pkey_seckey { __u8 seckey[SECKEYBLOBSIZE]; /* the secure key blob */ }; /* Struct to hold protected key and length info */ struct pkey_protkey { - __u32 type; /* key type, one of the PKEY_KEYTYPE values */ + __u32 type; /* key type, one of the PKEY_KEYTYPE_AES values */ __u32 len; /* bytes actually stored in protkey[] */ __u8 protkey[MAXPROTKEYSIZE]; /* the protected key blob */ }; -/* Struct to hold a clear key value */ +/* Struct to hold an AES clear key value */ struct pkey_clrkey { __u8 clrkey[MAXCLRKEYSIZE]; /* 16, 24, or 32 byte clear key value */ }; /* - * Generate secure key + * Generate CCA AES secure key. */ struct pkey_genseck { __u16 cardnr; /* in: card to use or FFFF for any */ @@ -62,7 +98,7 @@ struct pkey_genseck { #define PKEY_GENSECK _IOWR(PKEY_IOCTL_MAGIC, 0x01, struct pkey_genseck) /* - * Construct secure key from clear key value + * Construct CCA AES secure key from clear key value */ struct pkey_clr2seck { __u16 cardnr; /* in: card to use or FFFF for any */ @@ -74,7 +110,7 @@ struct pkey_clr2seck { #define PKEY_CLR2SECK _IOWR(PKEY_IOCTL_MAGIC, 0x02, struct pkey_clr2seck) /* - * Fabricate protected key from a secure key + * Fabricate AES protected key from a CCA AES secure key */ struct pkey_sec2protk { __u16 cardnr; /* in: card to use or FFFF for any */ @@ -85,7 +121,7 @@ struct pkey_sec2protk { #define PKEY_SEC2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x03, struct pkey_sec2protk) /* - * Fabricate protected key from an clear key value + * Fabricate AES protected key from clear key value */ struct pkey_clr2protk { __u32 keytype; /* in: key type to generate */ @@ -96,7 +132,7 @@ struct pkey_clr2protk { /* * Search for matching crypto card based on the Master Key - * Verification Pattern provided inside a secure key. + * Verification Pattern provided inside a CCA AES secure key. */ struct pkey_findcard { struct pkey_seckey seckey; /* in: the secure key blob */ @@ -115,7 +151,7 @@ struct pkey_skey2pkey { #define PKEY_SKEY2PKEY _IOWR(PKEY_IOCTL_MAGIC, 0x06, struct pkey_skey2pkey) /* - * Verify the given secure key for being able to be useable with + * Verify the given CCA AES secure key for being able to be useable with * the pkey module. Check for correct key type and check for having at * least one crypto card being able to handle this key (master key * or old master key verification pattern matches). @@ -134,7 +170,7 @@ struct pkey_verifykey { #define PKEY_VERIFY_ATTR_OLD_MKVP 0x00000100 /* key has old MKVP value */ /* - * Generate (AES) random protected key. + * Generate AES random protected key. */ struct pkey_genprotk { __u32 keytype; /* in: key type to generate */ @@ -144,7 +180,7 @@ struct pkey_genprotk { #define PKEY_GENPROTK _IOWR(PKEY_IOCTL_MAGIC, 0x08, struct pkey_genprotk) /* - * Verify an (AES) protected key. + * Verify an AES protected key. */ struct pkey_verifyprotk { struct pkey_protkey protkey; /* in: the protected key to verify */ @@ -160,7 +196,184 @@ struct pkey_kblob2pkey { __u32 keylen; /* in: the key blob length */ struct pkey_protkey protkey; /* out: the protected key */ }; - #define PKEY_KBLOB2PROTK _IOWR(PKEY_IOCTL_MAGIC, 0x0A, struct pkey_kblob2pkey) +/* + * Generate secure key, version 2. + * Generate either a CCA AES secure key or a CCA AES cipher key. + * There needs to be a list of apqns given with at least one entry in there. + * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain + * is not supported. The implementation walks through the list of apqns and + * tries to send the request to each apqn without any further checking (like + * card type or online state). If the apqn fails, simple the next one in the + * list is tried until success (return 0) or the end of the list is reached + * (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to + * generate a list of apqns based on the key type to generate. + * The keygenflags argument is passed to the low level generation functions + * individual for the key type and has a key type specific meaning. Currently + * only CCA AES cipher keys react to this parameter: Use one or more of the + * PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher + * key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC). + */ +struct pkey_genseck2 { + struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets*/ + __u32 apqn_entries; /* in: # of apqn target list entries */ + enum pkey_key_type type; /* in: key type to generate */ + enum pkey_key_size size; /* in: key size to generate */ + __u32 keygenflags; /* in: key generation flags */ + __u8 __user *key; /* in: pointer to key blob buffer */ + __u32 keylen; /* in: available key blob buffer size */ + /* out: actual key blob size */ +}; +#define PKEY_GENSECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x11, struct pkey_genseck2) + +/* + * Generate secure key from clear key value, version 2. + * Construct a CCA AES secure key or CCA AES cipher key from a given clear key + * value. + * There needs to be a list of apqns given with at least one entry in there. + * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain + * is not supported. The implementation walks through the list of apqns and + * tries to send the request to each apqn without any further checking (like + * card type or online state). If the apqn fails, simple the next one in the + * list is tried until success (return 0) or the end of the list is reached + * (return -1 with errno ENODEV). You may use the PKEY_APQNS4KT ioctl to + * generate a list of apqns based on the key type to generate. + * The keygenflags argument is passed to the low level generation functions + * individual for the key type and has a key type specific meaning. Currently + * only CCA AES cipher keys react to this parameter: Use one or more of the + * PKEY_KEYGEN_* flags to widen the export possibilities. By default a cipher + * key is only exportable for CPACF (PKEY_KEYGEN_XPRT_CPAC). + */ +struct pkey_clr2seck2 { + struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */ + __u32 apqn_entries; /* in: # of apqn target list entries */ + enum pkey_key_type type; /* in: key type to generate */ + enum pkey_key_size size; /* in: key size to generate */ + __u32 keygenflags; /* in: key generation flags */ + struct pkey_clrkey clrkey; /* in: the clear key value */ + __u8 __user *key; /* in: pointer to key blob buffer */ + __u32 keylen; /* in: available key blob buffer size */ + /* out: actual key blob size */ +}; +#define PKEY_CLR2SECK2 _IOWR(PKEY_IOCTL_MAGIC, 0x12, struct pkey_clr2seck2) + +/* + * Verify the given secure key, version 2. + * Check for correct key type. If cardnr and domain are given (are not + * 0xFFFF) also check if this apqn is able to handle this type of key. + * If cardnr and/or domain is 0xFFFF, on return these values are filled + * with one apqn able to handle this key. + * The function also checks for the master key verification patterns + * of the key matching to the current or alternate mkvp of the apqn. + * Currently CCA AES secure keys and CCA AES cipher keys are supported. + * The flags field is updated with some additional info about the apqn mkvp + * match: If the current mkvp matches to the key's mkvp then the + * PKEY_FLAGS_MATCH_CUR_MKVP bit is set, if the alternate mkvp matches to + * the key's mkvp the PKEY_FLAGS_MATCH_ALT_MKVP is set. For CCA keys the + * alternate mkvp is the old master key verification pattern. + * CCA AES secure keys are also checked to have the CPACF export allowed + * bit enabled (XPRTCPAC) in the kmf1 field. + * The ioctl returns 0 as long as the given or found apqn matches to + * matches with the current or alternate mkvp to the key's mkvp. If the given + * apqn does not match or there is no such apqn found, -1 with errno + * ENODEV is returned. + */ +struct pkey_verifykey2 { + __u8 __user *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + __u16 cardnr; /* in/out: card number */ + __u16 domain; /* in/out: domain number */ + enum pkey_key_type type; /* out: the key type */ + enum pkey_key_size size; /* out: the key size */ + __u32 flags; /* out: additional key info flags */ +}; +#define PKEY_VERIFYKEY2 _IOWR(PKEY_IOCTL_MAGIC, 0x17, struct pkey_verifykey2) + +/* + * Transform a key blob (of any type) into a protected key, version 2. + * There needs to be a list of apqns given with at least one entry in there. + * All apqns in the list need to be exact apqns, 0xFFFF as ANY card or domain + * is not supported. The implementation walks through the list of apqns and + * tries to send the request to each apqn without any further checking (like + * card type or online state). If the apqn fails, simple the next one in the + * list is tried until success (return 0) or the end of the list is reached + * (return -1 with errno ENODEV). You may use the PKEY_APQNS4K ioctl to + * generate a list of apqns based on the key. + */ +struct pkey_kblob2pkey2 { + __u8 __user *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + struct pkey_apqn __user *apqns; /* in: ptr to list of apqn targets */ + __u32 apqn_entries; /* in: # of apqn target list entries */ + struct pkey_protkey protkey; /* out: the protected key */ +}; +#define PKEY_KBLOB2PROTK2 _IOWR(PKEY_IOCTL_MAGIC, 0x1A, struct pkey_kblob2pkey2) + +/* + * Build a list of APQNs based on a key blob given. + * Is able to find out which type of secure key is given (CCA AES secure + * key or CCA AES cipher key) and tries to find all matching crypto cards + * based on the MKVP and maybe other criterias (like CCA AES cipher keys + * need a CEX5C or higher). The list of APQNs is further filtered by the key's + * mkvp which needs to match to either the current mkvp or the alternate mkvp + * (which is the old mkvp on CCA adapters) of the apqns. The flags argument may + * be used to limit the matching apqns. If the PKEY_FLAGS_MATCH_CUR_MKVP is + * given, only the current mkvp of each apqn is compared. Likewise with the + * PKEY_FLAGS_MATCH_ALT_MKVP. If both are given, it is assumed to + * return apqns where either the current or the alternate mkvp + * matches. At least one of the matching flags needs to be given. + * The list of matching apqns is stored into the space given by the apqns + * argument and the number of stored entries goes into apqn_entries. If the list + * is empty (apqn_entries is 0) the apqn_entries field is updated to the number + * of apqn targets found and the ioctl returns with 0. If apqn_entries is > 0 + * but the number of apqn targets does not fit into the list, the apqn_targets + * field is updatedd with the number of reqired entries but there are no apqn + * values stored in the list and the ioctl returns with ENOSPC. If no matching + * APQN is found, the ioctl returns with 0 but the apqn_entries value is 0. + */ +struct pkey_apqns4key { + __u8 __user *key; /* in: pointer to key blob */ + __u32 keylen; /* in: key blob size */ + __u32 flags; /* in: match controlling flags */ + struct pkey_apqn __user *apqns; /* in/out: ptr to list of apqn targets*/ + __u32 apqn_entries; /* in: max # of apqn entries in the list */ + /* out: # apqns stored into the list */ +}; +#define PKEY_APQNS4K _IOWR(PKEY_IOCTL_MAGIC, 0x1B, struct pkey_apqns4key) + +/* + * Build a list of APQNs based on a key type given. + * Build a list of APQNs based on a given key type and maybe further + * restrict the list by given master key verification patterns. + * For different key types there may be different ways to match the + * master key verification patterns. For CCA keys (CCA data key and CCA + * cipher key) the first 8 bytes of cur_mkvp refer to the current mkvp value + * of the apqn and the first 8 bytes of the alt_mkvp refer to the old mkvp. + * The flags argument controls if the apqns current and/or alternate mkvp + * should match. If the PKEY_FLAGS_MATCH_CUR_MKVP is given, only the current + * mkvp of each apqn is compared. Likewise with the PKEY_FLAGS_MATCH_ALT_MKVP. + * If both are given, it is assumed to return apqns where either the + * current or the alternate mkvp matches. If no match flag is given + * (flags is 0) the mkvp values are ignored for the match process. + * The list of matching apqns is stored into the space given by the apqns + * argument and the number of stored entries goes into apqn_entries. If the list + * is empty (apqn_entries is 0) the apqn_entries field is updated to the number + * of apqn targets found and the ioctl returns with 0. If apqn_entries is > 0 + * but the number of apqn targets does not fit into the list, the apqn_targets + * field is updatedd with the number of reqired entries but there are no apqn + * values stored in the list and the ioctl returns with ENOSPC. If no matching + * APQN is found, the ioctl returns with 0 but the apqn_entries value is 0. + */ +struct pkey_apqns4keytype { + enum pkey_key_type type; /* in: key type */ + __u8 cur_mkvp[32]; /* in: current mkvp */ + __u8 alt_mkvp[32]; /* in: alternate mkvp */ + __u32 flags; /* in: match controlling flags */ + struct pkey_apqn __user *apqns; /* in/out: ptr to list of apqn targets*/ + __u32 apqn_entries; /* in: max # of apqn entries in the list */ + /* out: # apqns stored into the list */ +}; +#define PKEY_APQNS4KT _IOWR(PKEY_IOCTL_MAGIC, 0x1C, struct pkey_apqns4keytype) + #endif /* _UAPI_PKEY_H */ diff --git a/drivers/s390/crypto/pkey_api.c b/drivers/s390/crypto/pkey_api.c index cd7e654bd18e..f76a1d0f54c4 100644 --- a/drivers/s390/crypto/pkey_api.c +++ b/drivers/s390/crypto/pkey_api.c @@ -30,6 +30,9 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("s390 protected key interface"); +#define KEYBLOBBUFSIZE 8192 /* key buffer size used for internal processing */ +#define MAXAPQNSINLIST 64 /* max 64 apqns within a apqn list */ + /* mask of available pckmo subfunctions, fetched once at module init */ static cpacf_mask_t pckmo_functions; @@ -126,27 +129,39 @@ static int pkey_clr2protkey(u32 keytype, /* * Find card and transform secure key into protected key. */ -static int pkey_skey2pkey(const struct pkey_seckey *seckey, - struct pkey_protkey *pkey) +static int pkey_skey2pkey(const u8 *key, struct pkey_protkey *pkey) { - u16 cardnr, domain; int rc, verify; + u16 cardnr, domain; + struct keytoken_header *hdr = (struct keytoken_header *)key; /* - * The cca_sec2protkey call may fail when a card has been + * The cca_xxx2protkey call may fail when a card has been * addressed where the master key was changed after last fetch * of the mkvp into the cache. Try 3 times: First witout verify * then with verify and last round with verify and old master * key verification pattern match not ignored. */ for (verify = 0; verify < 3; verify++) { - rc = cca_findcard(seckey->seckey, &cardnr, &domain, verify); + rc = cca_findcard(key, &cardnr, &domain, verify); if (rc < 0) continue; if (rc > 0 && verify < 2) continue; - rc = cca_sec2protkey(cardnr, domain, seckey->seckey, - pkey->protkey, &pkey->len, &pkey->type); + switch (hdr->version) { + case TOKVER_CCA_AES: + rc = cca_sec2protkey(cardnr, domain, + key, pkey->protkey, + &pkey->len, &pkey->type); + break; + case TOKVER_CCA_VLSC: + rc = cca_cipher2protkey(cardnr, domain, + key, pkey->protkey, + &pkey->len, &pkey->type); + break; + default: + return -EINVAL; + } if (rc == 0) break; } @@ -324,14 +339,18 @@ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, case TOKVER_CCA_AES: if (keylen != sizeof(struct secaeskeytoken)) return -EINVAL; - - return pkey_skey2pkey((struct pkey_seckey *)key, - protkey); + break; + case TOKVER_CCA_VLSC: + if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + return -EINVAL; + break; default: DEBUG_ERR("%s unknown/unsupported CCA internal token version %d\n", __func__, hdr->version); return -EINVAL; } + + return pkey_skey2pkey(key, protkey); } /* @@ -340,28 +359,394 @@ static int pkey_ccainttok2pkey(const u8 *key, u32 keylen, int pkey_keyblob2pkey(const u8 *key, u32 keylen, struct pkey_protkey *protkey) { + int rc; struct keytoken_header *hdr = (struct keytoken_header *)key; - if (keylen < sizeof(struct keytoken_header)) + if (keylen < sizeof(struct keytoken_header)) { + DEBUG_ERR("%s invalid keylen %d\n", __func__, keylen); return -EINVAL; + } switch (hdr->type) { case TOKTYPE_NON_CCA: - return pkey_nonccatok2pkey(key, keylen, protkey); + rc = pkey_nonccatok2pkey(key, keylen, protkey); + break; case TOKTYPE_CCA_INTERNAL: - return pkey_ccainttok2pkey(key, keylen, protkey); + rc = pkey_ccainttok2pkey(key, keylen, protkey); + break; default: - DEBUG_ERR("%s unknown/unsupported blob type %d\n", __func__, - hdr->type); + DEBUG_ERR("%s unknown/unsupported blob type %d\n", + __func__, hdr->type); return -EINVAL; } + + DEBUG_DBG("%s rc=%d\n", __func__, rc); + return rc; + } EXPORT_SYMBOL(pkey_keyblob2pkey); +static int pkey_genseckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + enum pkey_key_type ktype, enum pkey_key_size ksize, + u32 kflags, u8 *keybuf, size_t *keybufsize) +{ + int i, card, dom, rc; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + /* check key type and size */ + switch (ktype) { + case PKEY_TYPE_CCA_DATA: + case PKEY_TYPE_CCA_CIPHER: + if (*keybufsize < SECKEYBLOBSIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (ksize) { + case PKEY_SIZE_AES_128: + case PKEY_SIZE_AES_192: + case PKEY_SIZE_AES_256: + break; + default: + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_genseckey(card, dom, ksize, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); + } else /* TOKVER_CCA_VLSC */ + rc = cca_gencipherkey(card, dom, ksize, kflags, + keybuf, keybufsize); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_clr2seckey2(const struct pkey_apqn *apqns, size_t nr_apqns, + enum pkey_key_type ktype, enum pkey_key_size ksize, + u32 kflags, const u8 *clrkey, + u8 *keybuf, size_t *keybufsize) +{ + int i, card, dom, rc; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + /* check key type and size */ + switch (ktype) { + case PKEY_TYPE_CCA_DATA: + case PKEY_TYPE_CCA_CIPHER: + if (*keybufsize < SECKEYBLOBSIZE) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (ksize) { + case PKEY_SIZE_AES_128: + case PKEY_SIZE_AES_192: + case PKEY_SIZE_AES_256: + break; + default: + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (ktype == PKEY_TYPE_CCA_DATA) { + rc = cca_clr2seckey(card, dom, ksize, + clrkey, keybuf); + *keybufsize = (rc ? 0 : SECKEYBLOBSIZE); + } else /* TOKVER_CCA_VLSC */ + rc = cca_clr2cipherkey(card, dom, ksize, kflags, + clrkey, keybuf, keybufsize); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_verifykey2(const u8 *key, size_t keylen, + u16 *cardnr, u16 *domain, + enum pkey_key_type *ktype, + enum pkey_key_size *ksize, u32 *flags) +{ + int rc; + u32 _nr_apqns, *_apqns = NULL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header) || + hdr->type != TOKTYPE_CCA_INTERNAL) + return -EINVAL; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + rc = cca_check_secaeskeytoken(debug_info, 3, key, 0); + if (rc) + goto out; + if (ktype) + *ktype = PKEY_TYPE_CCA_DATA; + if (ksize) + *ksize = (enum pkey_key_size) t->bitsize; + + rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX3C, t->mkvp, 0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_CUR_MKVP; + if (rc == -ENODEV) { + rc = cca_findcard2(&_apqns, &_nr_apqns, + *cardnr, *domain, + ZCRYPT_CEX3C, 0, t->mkvp, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_ALT_MKVP; + } + if (rc) + goto out; + + *cardnr = ((struct pkey_apqn *)_apqns)->card; + *domain = ((struct pkey_apqn *)_apqns)->domain; + + } else if (hdr->version == TOKVER_CCA_VLSC) { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + rc = cca_check_secaescipherkey(debug_info, 3, key, 0, 1); + if (rc) + goto out; + if (ktype) + *ktype = PKEY_TYPE_CCA_CIPHER; + if (ksize) { + *ksize = PKEY_SIZE_UNKNOWN; + if (!t->plfver && t->wpllen == 512) + *ksize = PKEY_SIZE_AES_128; + else if (!t->plfver && t->wpllen == 576) + *ksize = PKEY_SIZE_AES_192; + else if (!t->plfver && t->wpllen == 640) + *ksize = PKEY_SIZE_AES_256; + } + + rc = cca_findcard2(&_apqns, &_nr_apqns, *cardnr, *domain, + ZCRYPT_CEX6, t->mkvp0, 0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_CUR_MKVP; + if (rc == -ENODEV) { + rc = cca_findcard2(&_apqns, &_nr_apqns, + *cardnr, *domain, + ZCRYPT_CEX6, 0, t->mkvp0, 1); + if (rc == 0 && flags) + *flags = PKEY_FLAGS_MATCH_ALT_MKVP; + } + if (rc) + goto out; + + *cardnr = ((struct pkey_apqn *)_apqns)->card; + *domain = ((struct pkey_apqn *)_apqns)->domain; + + } else + rc = -EINVAL; + +out: + kfree(_apqns); + return rc; +} + +static int pkey_keyblob2pkey2(const struct pkey_apqn *apqns, size_t nr_apqns, + const u8 *key, size_t keylen, + struct pkey_protkey *pkey) +{ + int i, card, dom, rc; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + /* check for at least one apqn given */ + if (!apqns || !nr_apqns) + return -EINVAL; + + if (keylen < sizeof(struct keytoken_header)) + return -EINVAL; + + switch (hdr->type) { + case TOKTYPE_NON_CCA: + return pkey_nonccatok2pkey(key, keylen, pkey); + case TOKTYPE_CCA_INTERNAL: + switch (hdr->version) { + case TOKVER_CCA_AES: + if (keylen != sizeof(struct secaeskeytoken)) + return -EINVAL; + if (cca_check_secaeskeytoken(debug_info, 3, key, 0)) + return -EINVAL; + break; + case TOKVER_CCA_VLSC: + if (keylen < hdr->len || keylen > MAXCCAVLSCTOKENSIZE) + return -EINVAL; + if (cca_check_secaescipherkey(debug_info, 3, key, 0, 1)) + return -EINVAL; + break; + default: + DEBUG_ERR("%s unknown CCA internal token version %d\n", + __func__, hdr->version); + return -EINVAL; + } + break; + default: + DEBUG_ERR("%s unknown/unsupported blob type %d\n", + __func__, hdr->type); + return -EINVAL; + } + + /* simple try all apqns from the list */ + for (i = 0, rc = -ENODEV; i < nr_apqns; i++) { + card = apqns[i].card; + dom = apqns[i].domain; + if (hdr->version == TOKVER_CCA_AES) + rc = cca_sec2protkey(card, dom, key, pkey->protkey, + &pkey->len, &pkey->type); + else /* TOKVER_CCA_VLSC */ + rc = cca_cipher2protkey(card, dom, key, pkey->protkey, + &pkey->len, &pkey->type); + if (rc == 0) + break; + } + + return rc; +} + +static int pkey_apqns4key(const u8 *key, size_t keylen, u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + int rc = EINVAL; + u32 _nr_apqns, *_apqns = NULL; + struct keytoken_header *hdr = (struct keytoken_header *)key; + + if (keylen < sizeof(struct keytoken_header) || + hdr->type != TOKTYPE_CCA_INTERNAL || + flags == 0) + return -EINVAL; + + if (hdr->version == TOKVER_CCA_AES || hdr->version == TOKVER_CCA_VLSC) { + int minhwtype = ZCRYPT_CEX3C; + u64 cur_mkvp = 0, old_mkvp = 0; + + if (hdr->version == TOKVER_CCA_AES) { + struct secaeskeytoken *t = (struct secaeskeytoken *)key; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp; + } else { + struct cipherkeytoken *t = (struct cipherkeytoken *)key; + + minhwtype = ZCRYPT_CEX6; + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = t->mkvp0; + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = t->mkvp0; + } + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + } + +out: + kfree(_apqns); + return rc; +} + +static int pkey_apqns4keytype(enum pkey_key_type ktype, + u8 cur_mkvp[32], u8 alt_mkvp[32], u32 flags, + struct pkey_apqn *apqns, size_t *nr_apqns) +{ + int rc = -EINVAL; + u32 _nr_apqns, *_apqns = NULL; + + if (ktype == PKEY_TYPE_CCA_DATA || ktype == PKEY_TYPE_CCA_CIPHER) { + u64 cur_mkvp = 0, old_mkvp = 0; + int minhwtype = ZCRYPT_CEX3C; + + if (flags & PKEY_FLAGS_MATCH_CUR_MKVP) + cur_mkvp = *((u64 *) cur_mkvp); + if (flags & PKEY_FLAGS_MATCH_ALT_MKVP) + old_mkvp = *((u64 *) alt_mkvp); + if (ktype == PKEY_TYPE_CCA_CIPHER) + minhwtype = ZCRYPT_CEX6; + rc = cca_findcard2(&_apqns, &_nr_apqns, 0xFFFF, 0xFFFF, + minhwtype, cur_mkvp, old_mkvp, 1); + if (rc) + goto out; + if (apqns) { + if (*nr_apqns < _nr_apqns) + rc = -ENOSPC; + else + memcpy(apqns, _apqns, _nr_apqns * sizeof(u32)); + } + *nr_apqns = _nr_apqns; + } + +out: + kfree(_apqns); + return rc; +} + /* * File io functions */ +static void *_copy_key_from_user(void __user *ukey, size_t keylen) +{ + void *kkey; + + if (!ukey || keylen < MINKEYBLOBSIZE || keylen > KEYBLOBBUFSIZE) + return ERR_PTR(-EINVAL); + kkey = kmalloc(keylen, GFP_KERNEL); + if (!kkey) + return ERR_PTR(-ENOMEM); + if (copy_from_user(kkey, ukey, keylen)) { + kfree(kkey); + return ERR_PTR(-EFAULT); + } + + return kkey; +} + +static void *_copy_apqns_from_user(void __user *uapqns, size_t nr_apqns) +{ + void *kapqns = NULL; + size_t nbytes; + + if (uapqns && nr_apqns > 0) { + nbytes = nr_apqns * sizeof(struct pkey_apqn); + kapqns = kmalloc(nbytes, GFP_KERNEL); + if (!kapqns) + return ERR_PTR(-ENOMEM); + if (copy_from_user(kapqns, uapqns, nbytes)) + return ERR_PTR(-EFAULT); + } + + return kapqns; +} + static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -452,7 +837,7 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, if (copy_from_user(&ksp, usp, sizeof(ksp))) return -EFAULT; - rc = pkey_skey2pkey(&ksp.seckey, &ksp.protkey); + rc = pkey_skey2pkey(ksp.seckey.seckey, &ksp.protkey); DEBUG_DBG("%s pkey_skey2pkey()=%d\n", __func__, rc); if (rc) break; @@ -502,24 +887,148 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, 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) + kkey = _copy_key_from_user(ktp.key, ktp.keylen); + if (IS_ERR(kkey)) + return PTR_ERR(kkey); + 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; + } + case PKEY_GENSECK2: { + struct pkey_genseck2 __user *ugs = (void __user *) arg; + struct pkey_genseck2 kgs; + struct pkey_apqn *apqns; + size_t klen = KEYBLOBBUFSIZE; + u8 *kkey; + + if (copy_from_user(&kgs, ugs, sizeof(kgs))) + return -EFAULT; + apqns = _copy_apqns_from_user(kgs.apqns, kgs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = kmalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); return -ENOMEM; - if (copy_from_user(kkey, ukey, ktp.keylen)) { + } + rc = pkey_genseckey2(apqns, kgs.apqn_entries, + kgs.type, kgs.size, kgs.keygenflags, + kkey, &klen); + DEBUG_DBG("%s pkey_genseckey2()=%d\n", __func__, rc); + kfree(apqns); + if (rc) { kfree(kkey); + break; + } + if (kgs.key) { + if (kgs.keylen < klen) { + kfree(kkey); + return -EINVAL; + } + if (copy_to_user(kgs.key, kkey, klen)) { + kfree(kkey); + return -EFAULT; + } + } + kgs.keylen = klen; + if (copy_to_user(ugs, &kgs, sizeof(kgs))) + rc = -EFAULT; + kfree(kkey); + break; + } + case PKEY_CLR2SECK2: { + struct pkey_clr2seck2 __user *ucs = (void __user *) arg; + struct pkey_clr2seck2 kcs; + struct pkey_apqn *apqns; + size_t klen = KEYBLOBBUFSIZE; + u8 *kkey; + + if (copy_from_user(&kcs, ucs, sizeof(kcs))) return -EFAULT; + apqns = _copy_apqns_from_user(kcs.apqns, kcs.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = kmalloc(klen, GFP_KERNEL); + if (!kkey) { + kfree(apqns); + return -ENOMEM; } - rc = pkey_keyblob2pkey(kkey, ktp.keylen, &ktp.protkey); - DEBUG_DBG("%s pkey_keyblob2pkey()=%d\n", __func__, rc); + rc = pkey_clr2seckey2(apqns, kcs.apqn_entries, + kcs.type, kcs.size, kcs.keygenflags, + kcs.clrkey.clrkey, kkey, &klen); + DEBUG_DBG("%s pkey_clr2seckey2()=%d\n", __func__, rc); + kfree(apqns); + if (rc) { + kfree(kkey); + break; + } + if (kcs.key) { + if (kcs.keylen < klen) { + kfree(kkey); + return -EINVAL; + } + if (copy_to_user(kcs.key, kkey, klen)) { + kfree(kkey); + return -EFAULT; + } + } + kcs.keylen = klen; + if (copy_to_user(ucs, &kcs, sizeof(kcs))) + rc = -EFAULT; + memzero_explicit(&kcs, sizeof(kcs)); + kfree(kkey); + break; + } + case PKEY_VERIFYKEY2: { + struct pkey_verifykey2 __user *uvk = (void __user *) arg; + struct pkey_verifykey2 kvk; + u8 *kkey; + + if (copy_from_user(&kvk, uvk, sizeof(kvk))) + return -EFAULT; + kkey = _copy_key_from_user(kvk.key, kvk.keylen); + if (IS_ERR(kkey)) + return PTR_ERR(kkey); + rc = pkey_verifykey2(kkey, kvk.keylen, + &kvk.cardnr, &kvk.domain, + &kvk.type, &kvk.size, &kvk.flags); + DEBUG_DBG("%s pkey_verifykey2()=%d\n", __func__, rc); + kfree(kkey); + if (rc) + break; + if (copy_to_user(uvk, &kvk, sizeof(kvk))) + return -EFAULT; + break; + } + case PKEY_KBLOB2PROTK2: { + struct pkey_kblob2pkey2 __user *utp = (void __user *) arg; + struct pkey_kblob2pkey2 ktp; + struct pkey_apqn *apqns = NULL; + u8 *kkey; + + if (copy_from_user(&ktp, utp, sizeof(ktp))) + return -EFAULT; + apqns = _copy_apqns_from_user(ktp.apqns, ktp.apqn_entries); + if (IS_ERR(apqns)) + return PTR_ERR(apqns); + kkey = _copy_key_from_user(ktp.key, ktp.keylen); + if (IS_ERR(kkey)) { + kfree(apqns); + return PTR_ERR(kkey); + } + rc = pkey_keyblob2pkey2(apqns, ktp.apqn_entries, + kkey, ktp.keylen, &ktp.protkey); + DEBUG_DBG("%s pkey_keyblob2pkey2()=%d\n", __func__, rc); + kfree(apqns); kfree(kkey); if (rc) break; @@ -527,6 +1036,97 @@ static long pkey_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; break; } + case PKEY_APQNS4K: { + struct pkey_apqns4key __user *uak = (void __user *) arg; + struct pkey_apqns4key kak; + struct pkey_apqn *apqns = NULL; + size_t nr_apqns, len; + u8 *kkey; + + if (copy_from_user(&kak, uak, sizeof(kak))) + return -EFAULT; + nr_apqns = kak.apqn_entries; + if (nr_apqns) { + apqns = kmalloc_array(nr_apqns, + sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!apqns) + return -ENOMEM; + } + kkey = _copy_key_from_user(kak.key, kak.keylen); + if (IS_ERR(kkey)) { + kfree(apqns); + return PTR_ERR(kkey); + } + rc = pkey_apqns4key(kkey, kak.keylen, kak.flags, + apqns, &nr_apqns); + DEBUG_DBG("%s pkey_apqns4key()=%d\n", __func__, rc); + kfree(kkey); + if (rc && rc != -ENOSPC) { + kfree(apqns); + break; + } + if (!rc && kak.apqns) { + if (nr_apqns > kak.apqn_entries) { + kfree(apqns); + return -EINVAL; + } + len = nr_apqns * sizeof(struct pkey_apqn); + if (len) { + if (copy_to_user(kak.apqns, apqns, len)) { + kfree(apqns); + return -EFAULT; + } + } + } + kak.apqn_entries = nr_apqns; + if (copy_to_user(uak, &kak, sizeof(kak))) + rc = -EFAULT; + kfree(apqns); + break; + } + case PKEY_APQNS4KT: { + struct pkey_apqns4keytype __user *uat = (void __user *) arg; + struct pkey_apqns4keytype kat; + struct pkey_apqn *apqns = NULL; + size_t nr_apqns, len; + + if (copy_from_user(&kat, uat, sizeof(kat))) + return -EFAULT; + nr_apqns = kat.apqn_entries; + if (nr_apqns) { + apqns = kmalloc_array(nr_apqns, + sizeof(struct pkey_apqn), + GFP_KERNEL); + if (!apqns) + return -ENOMEM; + } + rc = pkey_apqns4keytype(kat.type, kat.cur_mkvp, kat.alt_mkvp, + kat.flags, apqns, &nr_apqns); + DEBUG_DBG("%s pkey_apqns4keytype()=%d\n", __func__, rc); + if (rc && rc != -ENOSPC) { + kfree(apqns); + break; + } + if (!rc && kat.apqns) { + if (nr_apqns > kat.apqn_entries) { + kfree(apqns); + return -EINVAL; + } + len = nr_apqns * sizeof(struct pkey_apqn); + if (len) { + if (copy_to_user(kat.apqns, apqns, len)) { + kfree(apqns); + return -EFAULT; + } + } + } + kat.apqn_entries = nr_apqns; + if (copy_to_user(uat, &kat, sizeof(kat))) + rc = -EFAULT; + kfree(apqns); + break; + } default: /* unknown/unsupported ioctl cmd */ return -ENOTTY; diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 88c5f4a56be7..3b2d3705d2db 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -270,7 +270,7 @@ static inline int _zcrypt_send_cprb(struct ica_xcRB *xcrb) * Generate (random) CCA AES DATA secure key. */ int cca_genseckey(u16 cardnr, u16 domain, - u32 keytype, u8 seckey[SECKEYBLOBSIZE]) + u32 keybitsize, u8 seckey[SECKEYBLOBSIZE]) { int i, rc, keysize; int seckeysize; @@ -325,22 +325,25 @@ int cca_genseckey(u16 cardnr, u16 domain, preqparm->rule_array_len = sizeof(preqparm->rule_array_len); preqparm->lv1.len = sizeof(struct lv1); memcpy(preqparm->lv1.key_form, "OP ", 8); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: + switch (keybitsize) { + case PKEY_SIZE_AES_128: + case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ keysize = 16; memcpy(preqparm->lv1.key_length, "KEYLN16 ", 8); break; - case PKEY_KEYTYPE_AES_192: + case PKEY_SIZE_AES_192: + case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ keysize = 24; memcpy(preqparm->lv1.key_length, "KEYLN24 ", 8); break; - case PKEY_KEYTYPE_AES_256: + case PKEY_SIZE_AES_256: + case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ keysize = 32; memcpy(preqparm->lv1.key_length, "KEYLN32 ", 8); break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", - __func__, keytype); + DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); rc = -EINVAL; goto out; } @@ -408,7 +411,7 @@ EXPORT_SYMBOL(cca_genseckey); /* * Generate an CCA AES DATA secure key with given key value. */ -int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, const u8 *clrkey, u8 seckey[SECKEYBLOBSIZE]) { int rc, keysize, seckeysize; @@ -462,19 +465,22 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, memcpy(preqparm->rule_array, "AES ", 8); preqparm->rule_array_len = sizeof(preqparm->rule_array_len) + sizeof(preqparm->rule_array); - switch (keytype) { - case PKEY_KEYTYPE_AES_128: + switch (keybitsize) { + case PKEY_SIZE_AES_128: + case PKEY_KEYTYPE_AES_128: /* older ioctls used this */ keysize = 16; break; - case PKEY_KEYTYPE_AES_192: + case PKEY_SIZE_AES_192: + case PKEY_KEYTYPE_AES_192: /* older ioctls used this */ keysize = 24; break; - case PKEY_KEYTYPE_AES_256: + case PKEY_SIZE_AES_256: + case PKEY_KEYTYPE_AES_256: /* older ioctls used this */ keysize = 32; break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", - __func__, keytype); + DEBUG_ERR("%s unknown/unsupported keybitsize %d\n", + __func__, keybitsize); rc = -EINVAL; goto out; } @@ -545,8 +551,7 @@ EXPORT_SYMBOL(cca_clr2seckey); */ int cca_sec2protkey(u16 cardnr, u16 domain, const u8 seckey[SECKEYBLOBSIZE], - u8 *protkey, u32 *protkeylen, - u32 *keytype) + u8 *protkey, u32 *protkeylen, u32 *protkeytype) { int rc; u8 *mem; @@ -656,21 +661,21 @@ int cca_sec2protkey(u16 cardnr, u16 domain, switch (prepparm->lv3.keyblock.len) { case 16+32: /* AES 128 protected key */ - if (keytype) - *keytype = PKEY_KEYTYPE_AES_128; + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_128; break; case 24+32: /* AES 192 protected key */ - if (keytype) - *keytype = PKEY_KEYTYPE_AES_192; + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_192; break; case 32+32: /* AES 256 protected key */ - if (keytype) - *keytype = PKEY_KEYTYPE_AES_256; + if (protkeytype) + *protkeytype = PKEY_KEYTYPE_AES_256; break; default: - DEBUG_ERR("%s unknown/unsupported keytype %d\n", + DEBUG_ERR("%s unknown/unsupported keylen %d\n", __func__, prepparm->lv3.keyblock.len); rc = -EIO; goto out; @@ -1645,6 +1650,7 @@ static int findcard(u64 mkvp, u16 *pcardnr, u16 *pdomain, int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) { u64 mkvp; + int minhwtype = 0; const struct keytoken_header *hdr = (struct keytoken_header *) key; if (hdr->type != TOKTYPE_CCA_INTERNAL) @@ -1654,11 +1660,15 @@ int cca_findcard(const u8 *key, u16 *pcardnr, u16 *pdomain, int verify) case TOKVER_CCA_AES: mkvp = ((struct secaeskeytoken *)key)->mkvp; break; + case TOKVER_CCA_VLSC: + mkvp = ((struct cipherkeytoken *)key)->mkvp0; + minhwtype = AP_DEVICE_TYPE_CEX6; + break; default: return -EINVAL; } - return findcard(mkvp, pcardnr, pdomain, verify, 0); + return findcard(mkvp, pcardnr, pdomain, verify, minhwtype); } EXPORT_SYMBOL(cca_findcard); diff --git a/drivers/s390/crypto/zcrypt_ccamisc.h b/drivers/s390/crypto/zcrypt_ccamisc.h index e97cda0f61e0..77b6cc7b8f82 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.h +++ b/drivers/s390/crypto/zcrypt_ccamisc.h @@ -124,12 +124,12 @@ int cca_check_secaescipherkey(debug_info_t *dbg, int dbflvl, /* * Generate (random) CCA AES DATA secure key. */ -int cca_genseckey(u16 cardnr, u16 domain, u32 keytype, u8 *seckey); +int cca_genseckey(u16 cardnr, u16 domain, u32 keybitsize, u8 *seckey); /* * Generate CCA AES DATA secure key with given clear key value. */ -int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, +int cca_clr2seckey(u16 cardnr, u16 domain, u32 keybitsize, const u8 *clrkey, u8 *seckey); /* @@ -137,8 +137,7 @@ int cca_clr2seckey(u16 cardnr, u16 domain, u32 keytype, */ int cca_sec2protkey(u16 cardnr, u16 domain, const u8 seckey[SECKEYBLOBSIZE], - u8 *protkey, u32 *protkeylen, - u32 *protkeytype); + u8 *protkey, u32 *protkeylen, u32 *protkeytype); /* * Generate (random) CCA AES CIPHER secure key. @@ -169,6 +168,7 @@ int cca_query_crypto_facility(u16 cardnr, u16 domain, /* * Search for a matching crypto card based on the Master Key * Verification Pattern provided inside a secure key. + * Works with CCA AES data and cipher keys. * Returns < 0 on failure, 0 if CURRENT MKVP matches and * 1 if OLD MKVP matches. */ -- cgit v1.2.3 From 416f79c23dbe47e0e223efc06d3487e1d90a92ee Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 19 Jul 2019 15:22:26 +0200 Subject: s390/paes: Prepare paes functions for large key blobs The context used to store the key blob used a fixed 80 bytes buffer. And all the set_key functions did not even check the given key size. With CCA variable length AES cipher keys there come key blobs with about 136 bytes and maybe in the future there will arise the need to store even bigger key blobs. This patch reworks the paes set_key functions and the context buffers to work with small key blobs (<= 128 bytes) directly in the context buffer and larger blobs by allocating additional memory and storing the pointer in the context buffer. If there has been memory allocated for storing a key blob, it also needs to be freed on release of the tfm. So all the paes ciphers now have a init and exit function implemented for this job. Signed-off-by: Harald Freudenberger Reviewed-by: Ingo Franzki Signed-off-by: Vasily Gorbik --- arch/s390/crypto/paes_s390.c | 184 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 160 insertions(+), 24 deletions(-) diff --git a/arch/s390/crypto/paes_s390.c b/arch/s390/crypto/paes_s390.c index e8d9fa54569c..6184dceed340 100644 --- a/arch/s390/crypto/paes_s390.c +++ b/arch/s390/crypto/paes_s390.c @@ -5,7 +5,7 @@ * s390 implementation of the AES Cipher Algorithm with protected keys. * * s390 Version: - * Copyright IBM Corp. 2017 + * Copyright IBM Corp. 2017,2019 * Author(s): Martin Schwidefsky * Harald Freudenberger */ @@ -25,16 +25,59 @@ #include #include +/* + * Key blobs smaller/bigger than these defines are rejected + * by the common code even before the individual setkey function + * is called. As paes can handle different kinds of key blobs + * and padding is also possible, the limits need to be generous. + */ +#define PAES_MIN_KEYSIZE 64 +#define PAES_MAX_KEYSIZE 256 + static u8 *ctrblk; static DEFINE_SPINLOCK(ctrblk_lock); static cpacf_mask_t km_functions, kmc_functions, kmctr_functions; struct key_blob { - __u8 key[MAXKEYBLOBSIZE]; + /* + * Small keys will be stored in the keybuf. Larger keys are + * stored in extra allocated memory. In both cases does + * key point to the memory where the key is stored. + * The code distinguishes by checking keylen against + * sizeof(keybuf). See the two following helper functions. + */ + u8 *key; + u8 keybuf[128]; unsigned int keylen; }; +static inline int _copy_key_to_kb(struct key_blob *kb, + const u8 *key, + unsigned int keylen) +{ + if (keylen <= sizeof(kb->keybuf)) + kb->key = kb->keybuf; + else { + kb->key = kmalloc(keylen, GFP_KERNEL); + if (!kb->key) + return -ENOMEM; + } + memcpy(kb->key, key, keylen); + kb->keylen = keylen; + + return 0; +} + +static inline void _free_kb_keybuf(struct key_blob *kb) +{ + if (kb->key && kb->key != kb->keybuf + && kb->keylen > sizeof(kb->keybuf)) { + kfree(kb->key); + kb->key = NULL; + } +} + struct s390_paes_ctx { struct key_blob kb; struct pkey_protkey pk; @@ -80,13 +123,33 @@ static int __paes_set_key(struct s390_paes_ctx *ctx) return ctx->fc ? 0 : -EINVAL; } +static int ecb_paes_init(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb.key = NULL; + + return 0; +} + +static void ecb_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb); +} + static int ecb_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { + int rc; struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); - memcpy(ctx->kb.key, in_key, key_len); - ctx->kb.keylen = key_len; + _free_kb_keybuf(&ctx->kb); + rc = _copy_key_to_kb(&ctx->kb, in_key, key_len); + if (rc) + return rc; + if (__paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -148,10 +211,12 @@ static struct crypto_alg ecb_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ecb_paes_alg.cra_list), + .cra_init = ecb_paes_init, + .cra_exit = ecb_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = MINKEYBLOBSIZE, - .max_keysize = MAXKEYBLOBSIZE, + .min_keysize = PAES_MIN_KEYSIZE, + .max_keysize = PAES_MAX_KEYSIZE, .setkey = ecb_paes_set_key, .encrypt = ecb_paes_encrypt, .decrypt = ecb_paes_decrypt, @@ -159,6 +224,22 @@ static struct crypto_alg ecb_paes_alg = { } }; +static int cbc_paes_init(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb.key = NULL; + + return 0; +} + +static void cbc_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb); +} + static int __cbc_paes_set_key(struct s390_paes_ctx *ctx) { unsigned long fc; @@ -180,10 +261,14 @@ static int __cbc_paes_set_key(struct s390_paes_ctx *ctx) static int cbc_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { + int rc; struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); - memcpy(ctx->kb.key, in_key, key_len); - ctx->kb.keylen = key_len; + _free_kb_keybuf(&ctx->kb); + rc = _copy_key_to_kb(&ctx->kb, in_key, key_len); + if (rc) + return rc; + if (__cbc_paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -252,10 +337,12 @@ static struct crypto_alg cbc_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(cbc_paes_alg.cra_list), + .cra_init = cbc_paes_init, + .cra_exit = cbc_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = MINKEYBLOBSIZE, - .max_keysize = MAXKEYBLOBSIZE, + .min_keysize = PAES_MIN_KEYSIZE, + .max_keysize = PAES_MAX_KEYSIZE, .ivsize = AES_BLOCK_SIZE, .setkey = cbc_paes_set_key, .encrypt = cbc_paes_encrypt, @@ -264,6 +351,24 @@ static struct crypto_alg cbc_paes_alg = { } }; +static int xts_paes_init(struct crypto_tfm *tfm) +{ + struct s390_pxts_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb[0].key = NULL; + ctx->kb[1].key = NULL; + + return 0; +} + +static void xts_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_pxts_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb[0]); + _free_kb_keybuf(&ctx->kb[1]); +} + static int __xts_paes_set_key(struct s390_pxts_ctx *ctx) { unsigned long fc; @@ -287,20 +392,27 @@ static int __xts_paes_set_key(struct s390_pxts_ctx *ctx) } static int xts_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) + unsigned int xts_key_len) { + int rc; struct s390_pxts_ctx *ctx = crypto_tfm_ctx(tfm); u8 ckey[2 * AES_MAX_KEY_SIZE]; - unsigned int ckey_len, keytok_len; + unsigned int ckey_len, key_len; - if (key_len % 2) + if (xts_key_len % 2) return -EINVAL; - keytok_len = key_len / 2; - memcpy(ctx->kb[0].key, in_key, keytok_len); - ctx->kb[0].keylen = keytok_len; - memcpy(ctx->kb[1].key, in_key + keytok_len, keytok_len); - ctx->kb[1].keylen = keytok_len; + key_len = xts_key_len / 2; + + _free_kb_keybuf(&ctx->kb[0]); + _free_kb_keybuf(&ctx->kb[1]); + rc = _copy_key_to_kb(&ctx->kb[0], in_key, key_len); + if (rc) + return rc; + rc = _copy_key_to_kb(&ctx->kb[1], in_key + key_len, key_len); + if (rc) + return rc; + if (__xts_paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -394,10 +506,12 @@ static struct crypto_alg xts_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(xts_paes_alg.cra_list), + .cra_init = xts_paes_init, + .cra_exit = xts_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = 2 * MINKEYBLOBSIZE, - .max_keysize = 2 * MAXKEYBLOBSIZE, + .min_keysize = 2 * PAES_MIN_KEYSIZE, + .max_keysize = 2 * PAES_MAX_KEYSIZE, .ivsize = AES_BLOCK_SIZE, .setkey = xts_paes_set_key, .encrypt = xts_paes_encrypt, @@ -406,6 +520,22 @@ static struct crypto_alg xts_paes_alg = { } }; +static int ctr_paes_init(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + ctx->kb.key = NULL; + + return 0; +} + +static void ctr_paes_exit(struct crypto_tfm *tfm) +{ + struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); + + _free_kb_keybuf(&ctx->kb); +} + static int __ctr_paes_set_key(struct s390_paes_ctx *ctx) { unsigned long fc; @@ -428,10 +558,14 @@ static int __ctr_paes_set_key(struct s390_paes_ctx *ctx) static int ctr_paes_set_key(struct crypto_tfm *tfm, const u8 *in_key, unsigned int key_len) { + int rc; struct s390_paes_ctx *ctx = crypto_tfm_ctx(tfm); - memcpy(ctx->kb.key, in_key, key_len); - ctx->kb.keylen = key_len; + _free_kb_keybuf(&ctx->kb); + rc = _copy_key_to_kb(&ctx->kb, in_key, key_len); + if (rc) + return rc; + if (__ctr_paes_set_key(ctx)) { tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; return -EINVAL; @@ -541,10 +675,12 @@ static struct crypto_alg ctr_paes_alg = { .cra_type = &crypto_blkcipher_type, .cra_module = THIS_MODULE, .cra_list = LIST_HEAD_INIT(ctr_paes_alg.cra_list), + .cra_init = ctr_paes_init, + .cra_exit = ctr_paes_exit, .cra_u = { .blkcipher = { - .min_keysize = MINKEYBLOBSIZE, - .max_keysize = MAXKEYBLOBSIZE, + .min_keysize = PAES_MIN_KEYSIZE, + .max_keysize = PAES_MAX_KEYSIZE, .ivsize = AES_BLOCK_SIZE, .setkey = ctr_paes_set_key, .encrypt = ctr_paes_encrypt, -- cgit v1.2.3 From 60e05d1cf0875f0cf73472f7dff71d9933c5b697 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Thu, 15 Aug 2019 13:53:41 +0200 Subject: vfio-ccw: add some logging Usually, the common I/O layer logs various things into the s390 cio debug feature, which has been very helpful in the past when looking at crash dumps. As vfio-ccw devices unbind from the standard I/O subchannel driver, we lose some information there. Let's introduce some vfio-ccw debug features and log some things there. (Unfortunately we cannot reuse the cio debug feature from a module.) Message-Id: <20190816151505.9853-2-cohuck@redhat.com> Reviewed-by: Eric Farman Signed-off-by: Cornelia Huck --- drivers/s390/cio/vfio_ccw_drv.c | 50 +++++++++++++++++++++++++++++++++--- drivers/s390/cio/vfio_ccw_fsm.c | 51 ++++++++++++++++++++++++++++++++++++- drivers/s390/cio/vfio_ccw_ops.c | 10 ++++++++ drivers/s390/cio/vfio_ccw_private.h | 17 +++++++++++++ 4 files changed, 124 insertions(+), 4 deletions(-) diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 9208c0e56c33..45e792f6afd0 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -27,6 +27,9 @@ struct workqueue_struct *vfio_ccw_work_q; static struct kmem_cache *vfio_ccw_io_region; static struct kmem_cache *vfio_ccw_cmd_region; +debug_info_t *vfio_ccw_debug_msg_id; +debug_info_t *vfio_ccw_debug_trace_id; + /* * Helpers */ @@ -164,6 +167,9 @@ static int vfio_ccw_sch_probe(struct subchannel *sch) if (ret) goto out_disable; + VFIO_CCW_MSG_EVENT(4, "bound to subchannel %x.%x.%04x\n", + sch->schid.cssid, sch->schid.ssid, + sch->schid.sch_no); return 0; out_disable: @@ -194,6 +200,9 @@ static int vfio_ccw_sch_remove(struct subchannel *sch) kfree(private->cp.guest_cp); kfree(private); + VFIO_CCW_MSG_EVENT(4, "unbound from subchannel %x.%x.%04x\n", + sch->schid.cssid, sch->schid.ssid, + sch->schid.sch_no); return 0; } @@ -263,13 +272,46 @@ static struct css_driver vfio_ccw_sch_driver = { .sch_event = vfio_ccw_sch_event, }; +static int __init vfio_ccw_debug_init(void) +{ + vfio_ccw_debug_msg_id = debug_register("vfio_ccw_msg", 16, 1, + 11 * sizeof(long)); + if (!vfio_ccw_debug_msg_id) + goto out_unregister; + debug_register_view(vfio_ccw_debug_msg_id, &debug_sprintf_view); + debug_set_level(vfio_ccw_debug_msg_id, 2); + vfio_ccw_debug_trace_id = debug_register("vfio_ccw_trace", 16, 1, 16); + if (!vfio_ccw_debug_trace_id) + goto out_unregister; + debug_register_view(vfio_ccw_debug_trace_id, &debug_hex_ascii_view); + debug_set_level(vfio_ccw_debug_trace_id, 2); + return 0; + +out_unregister: + debug_unregister(vfio_ccw_debug_msg_id); + debug_unregister(vfio_ccw_debug_trace_id); + return -1; +} + +static void vfio_ccw_debug_exit(void) +{ + debug_unregister(vfio_ccw_debug_msg_id); + debug_unregister(vfio_ccw_debug_trace_id); +} + static int __init vfio_ccw_sch_init(void) { - int ret = -ENOMEM; + int ret; + + ret = vfio_ccw_debug_init(); + if (ret) + return ret; vfio_ccw_work_q = create_singlethread_workqueue("vfio-ccw"); - if (!vfio_ccw_work_q) - return -ENOMEM; + if (!vfio_ccw_work_q) { + ret = -ENOMEM; + goto out_err; + } vfio_ccw_io_region = kmem_cache_create_usercopy("vfio_ccw_io_region", sizeof(struct ccw_io_region), 0, @@ -298,6 +340,7 @@ out_err: kmem_cache_destroy(vfio_ccw_cmd_region); kmem_cache_destroy(vfio_ccw_io_region); destroy_workqueue(vfio_ccw_work_q); + vfio_ccw_debug_exit(); return ret; } @@ -308,6 +351,7 @@ static void __exit vfio_ccw_sch_exit(void) kmem_cache_destroy(vfio_ccw_io_region); kmem_cache_destroy(vfio_ccw_cmd_region); destroy_workqueue(vfio_ccw_work_q); + vfio_ccw_debug_exit(); } module_init(vfio_ccw_sch_init); module_exit(vfio_ccw_sch_exit); diff --git a/drivers/s390/cio/vfio_ccw_fsm.c b/drivers/s390/cio/vfio_ccw_fsm.c index 49d9d3da0282..4a1e727c62d9 100644 --- a/drivers/s390/cio/vfio_ccw_fsm.c +++ b/drivers/s390/cio/vfio_ccw_fsm.c @@ -37,9 +37,14 @@ static int fsm_io_helper(struct vfio_ccw_private *private) goto out; } + VFIO_CCW_TRACE_EVENT(5, "stIO"); + VFIO_CCW_TRACE_EVENT(5, dev_name(&sch->dev)); + /* Issue "Start Subchannel" */ ccode = ssch(sch->schid, orb); + VFIO_CCW_HEX_EVENT(5, &ccode, sizeof(ccode)); + switch (ccode) { case 0: /* @@ -86,9 +91,14 @@ static int fsm_do_halt(struct vfio_ccw_private *private) spin_lock_irqsave(sch->lock, flags); + VFIO_CCW_TRACE_EVENT(2, "haltIO"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); + /* Issue "Halt Subchannel" */ ccode = hsch(sch->schid); + VFIO_CCW_HEX_EVENT(2, &ccode, sizeof(ccode)); + switch (ccode) { case 0: /* @@ -122,9 +132,14 @@ static int fsm_do_clear(struct vfio_ccw_private *private) spin_lock_irqsave(sch->lock, flags); + VFIO_CCW_TRACE_EVENT(2, "clearIO"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); + /* Issue "Clear Subchannel" */ ccode = csch(sch->schid); + VFIO_CCW_HEX_EVENT(2, &ccode, sizeof(ccode)); + switch (ccode) { case 0: /* @@ -149,6 +164,9 @@ static void fsm_notoper(struct vfio_ccw_private *private, { struct subchannel *sch = private->sch; + VFIO_CCW_TRACE_EVENT(2, "notoper"); + VFIO_CCW_TRACE_EVENT(2, dev_name(&sch->dev)); + /* * TODO: * Probably we should send the machine check to the guest. @@ -229,6 +247,7 @@ static void fsm_io_request(struct vfio_ccw_private *private, struct ccw_io_region *io_region = private->io_region; struct mdev_device *mdev = private->mdev; char *errstr = "request"; + struct subchannel_id schid = get_schid(private); private->state = VFIO_CCW_STATE_CP_PROCESSING; memcpy(scsw, io_region->scsw_area, sizeof(*scsw)); @@ -239,18 +258,32 @@ static void fsm_io_request(struct vfio_ccw_private *private, /* Don't try to build a cp if transport mode is specified. */ if (orb->tm.b) { io_region->ret_code = -EOPNOTSUPP; + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): transport mode\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no); errstr = "transport mode"; goto err_out; } io_region->ret_code = cp_init(&private->cp, mdev_dev(mdev), orb); if (io_region->ret_code) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): cp_init=%d\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no, + io_region->ret_code); errstr = "cp init"; goto err_out; } io_region->ret_code = cp_prefetch(&private->cp); if (io_region->ret_code) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): cp_prefetch=%d\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no, + io_region->ret_code); errstr = "cp prefetch"; cp_free(&private->cp); goto err_out; @@ -259,23 +292,36 @@ static void fsm_io_request(struct vfio_ccw_private *private, /* Start channel program and wait for I/O interrupt. */ io_region->ret_code = fsm_io_helper(private); if (io_region->ret_code) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): fsm_io_helper=%d\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no, + io_region->ret_code); errstr = "cp fsm_io_helper"; cp_free(&private->cp); goto err_out; } return; } else if (scsw->cmd.fctl & SCSW_FCTL_HALT_FUNC) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): halt on io_region\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no); /* halt is handled via the async cmd region */ io_region->ret_code = -EOPNOTSUPP; goto err_out; } else if (scsw->cmd.fctl & SCSW_FCTL_CLEAR_FUNC) { + VFIO_CCW_MSG_EVENT(2, + "%pUl (%x.%x.%04x): clear on io_region\n", + mdev_uuid(mdev), schid.cssid, + schid.ssid, schid.sch_no); /* clear is handled via the async cmd region */ io_region->ret_code = -EOPNOTSUPP; goto err_out; } err_out: - trace_vfio_ccw_io_fctl(scsw->cmd.fctl, get_schid(private), + trace_vfio_ccw_io_fctl(scsw->cmd.fctl, schid, io_region->ret_code, errstr); } @@ -308,6 +354,9 @@ static void fsm_irq(struct vfio_ccw_private *private, { struct irb *irb = this_cpu_ptr(&cio_irb); + VFIO_CCW_TRACE_EVENT(6, "IRQ"); + VFIO_CCW_TRACE_EVENT(6, dev_name(&private->sch->dev)); + memcpy(&private->irb, irb, sizeof(*irb)); queue_work(vfio_ccw_work_q, &private->io_work); diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index 5eb61116ca6f..f0d71ab77c50 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c @@ -124,6 +124,11 @@ static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) private->mdev = mdev; private->state = VFIO_CCW_STATE_IDLE; + VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: create\n", + mdev_uuid(mdev), private->sch->schid.cssid, + private->sch->schid.ssid, + private->sch->schid.sch_no); + return 0; } @@ -132,6 +137,11 @@ static int vfio_ccw_mdev_remove(struct mdev_device *mdev) struct vfio_ccw_private *private = dev_get_drvdata(mdev_parent_dev(mdev)); + VFIO_CCW_MSG_EVENT(2, "mdev %pUl, sch %x.%x.%04x: remove\n", + mdev_uuid(mdev), private->sch->schid.cssid, + private->sch->schid.ssid, + private->sch->schid.sch_no); + if ((private->state != VFIO_CCW_STATE_NOT_OPER) && (private->state != VFIO_CCW_STATE_STANDBY)) { if (!vfio_ccw_sch_quiesce(private->sch)) diff --git a/drivers/s390/cio/vfio_ccw_private.h b/drivers/s390/cio/vfio_ccw_private.h index f1092c3dc1b1..bbe9babf767b 100644 --- a/drivers/s390/cio/vfio_ccw_private.h +++ b/drivers/s390/cio/vfio_ccw_private.h @@ -17,6 +17,7 @@ #include #include #include +#include #include "css.h" #include "vfio_ccw_cp.h" @@ -139,4 +140,20 @@ static inline void vfio_ccw_fsm_event(struct vfio_ccw_private *private, extern struct workqueue_struct *vfio_ccw_work_q; + +/* s390 debug feature, similar to base cio */ +extern debug_info_t *vfio_ccw_debug_msg_id; +extern debug_info_t *vfio_ccw_debug_trace_id; + +#define VFIO_CCW_TRACE_EVENT(imp, txt) \ + debug_text_event(vfio_ccw_debug_trace_id, imp, txt) + +#define VFIO_CCW_MSG_EVENT(imp, args...) \ + debug_sprintf_event(vfio_ccw_debug_msg_id, imp, ##args) + +static inline void VFIO_CCW_HEX_EVENT(int level, void *data, int length) +{ + debug_event(vfio_ccw_debug_trace_id, level, data, length); +} + #endif -- cgit v1.2.3 From 915ef7bda76466a5542a76694c08709895383f1c Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Fri, 16 Aug 2019 15:49:49 +0200 Subject: s390/numa: correct early_param handling When command line options are used without specifying values (e.g. "emu_size" instead of "emu_size="), the value is NULL. Check that before performing string operations and further processing. Signed-off-by: Vasily Gorbik --- arch/s390/numa/mode_emu.c | 7 +++---- arch/s390/numa/numa.c | 2 ++ 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/s390/numa/mode_emu.c b/arch/s390/numa/mode_emu.c index 71a12a4f4906..72d742bb2d17 100644 --- a/arch/s390/numa/mode_emu.c +++ b/arch/s390/numa/mode_emu.c @@ -558,9 +558,7 @@ static int __init early_parse_emu_nodes(char *p) { int count; - if (kstrtoint(p, 0, &count) != 0 || count <= 0) - return 0; - if (count <= 0) + if (!p || kstrtoint(p, 0, &count) != 0 || count <= 0) return 0; emu_nodes = min(count, MAX_NUMNODES); return 0; @@ -572,7 +570,8 @@ early_param("emu_nodes", early_parse_emu_nodes); */ static int __init early_parse_emu_size(char *p) { - emu_size = memparse(p, NULL); + if (p) + emu_size = memparse(p, NULL); return 0; } early_param("emu_size", early_parse_emu_size); diff --git a/arch/s390/numa/numa.c b/arch/s390/numa/numa.c index 8eb9e9743f5d..d2910fa834c8 100644 --- a/arch/s390/numa/numa.c +++ b/arch/s390/numa/numa.c @@ -158,6 +158,8 @@ early_param("numa_debug", parse_debug); static int __init parse_numa(char *parm) { + if (!parm) + return 1; if (strcmp(parm, numa_mode_plain.name) == 0) mode = &numa_mode_plain; #ifdef CONFIG_NUMA_EMU -- cgit v1.2.3 From a45425d8a5a672d3322164cfce10b7b6fb32fcc2 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 10:44:54 +0200 Subject: s390/vmcp: correct early_param handling Check "p" is not NULL before passing it to memparse, which doesn't handle that case explicitly. Signed-off-by: Vasily Gorbik --- drivers/s390/char/vmcp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 0fa1b6b1491a..9e066281e2d0 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -43,6 +43,8 @@ static struct cma *vmcp_cma; static int __init early_parse_vmcp_cma(char *p) { + if (!p) + return 1; vmcp_cma_size = ALIGN(memparse(p, NULL), PAGE_SIZE); return 0; } -- cgit v1.2.3 From 227f52a43a2fa0bb50f07faa2d5e31530a740499 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 10:49:53 +0200 Subject: s390/startup: correct command line options parsing Check val is not NULL before accessing it. This might happen if corresponding kernel command line options are used without specifying values. Signed-off-by: Vasily Gorbik --- arch/s390/boot/ipl_parm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/s390/boot/ipl_parm.c b/arch/s390/boot/ipl_parm.c index 4a052a844f9b..80b8d8712f08 100644 --- a/arch/s390/boot/ipl_parm.c +++ b/arch/s390/boot/ipl_parm.c @@ -223,12 +223,12 @@ void parse_boot_command_line(void) while (*args) { args = next_arg(args, ¶m, &val); - if (!strcmp(param, "mem")) { + if (!strcmp(param, "mem") && val) { memory_end = round_down(memparse(val, NULL), PAGE_SIZE); memory_end_set = 1; } - if (!strcmp(param, "vmalloc")) + if (!strcmp(param, "vmalloc") && val) vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE); if (!strcmp(param, "noexec")) { @@ -237,7 +237,7 @@ void parse_boot_command_line(void) noexec_disabled = 1; } - if (!strcmp(param, "facilities")) + if (!strcmp(param, "facilities") && val) modify_fac_list(val); if (!strcmp(param, "nokaslr")) -- cgit v1.2.3 From 3d644364533931df298dc4f026a74731c2f752cb Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 17:41:17 +0200 Subject: s390/vdso: reuse kstrtobool for option value parsing "vdso" option setup already recognises integer and textual values. Yet kstrtobool is a more common way to parse boolean values, reuse it to unify option value parsing behavior and simplify code a bit. While at it, __setup value parsing callbacks are expected to return 1 when an option is recognized, and returning any other value won't trigger any error message currently, so simply return 1. Also don't change default vdso_enabled value of 1 when "vdso" option value is invalid. Reviewed-by: Philipp Rudo Signed-off-by: Vasily Gorbik --- arch/s390/kernel/vdso.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c index 243d8b1185bf..1d98a9f23e2a 100644 --- a/arch/s390/kernel/vdso.c +++ b/arch/s390/kernel/vdso.c @@ -97,21 +97,13 @@ static const struct vm_special_mapping vdso_mapping = { .mremap = vdso_mremap, }; -static int __init vdso_setup(char *s) +static int __init vdso_setup(char *str) { - unsigned long val; - int rc; + bool enabled; - rc = 0; - if (strncmp(s, "on", 3) == 0) - vdso_enabled = 1; - else if (strncmp(s, "off", 4) == 0) - vdso_enabled = 0; - else { - rc = kstrtoul(s, 0, &val); - vdso_enabled = rc ? 0 : !!val; - } - return !rc; + if (!kstrtobool(str, &enabled)) + vdso_enabled = enabled; + return 1; } __setup("vdso=", vdso_setup); -- cgit v1.2.3 From 5f0917a281c66fb310988d4c38f3c55b7023b8ff Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 17:55:44 +0200 Subject: s390/cmma: reuse kstrtobool for option value parsing "cmma" option setup already recognises some textual values. Yet kstrtobool is a more common way to parse boolean values, reuse it to unify option value parsing behavior and simplify code a bit. While at it, __setup value parsing callbacks are expected to return 1 when an option is recognized, and returning any other value won't trigger any error message currently, so simply return 1. Reviewed-by: Philipp Rudo Signed-off-by: Vasily Gorbik --- arch/s390/mm/page-states.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c index dc3cede7f2ec..fc141893d028 100644 --- a/arch/s390/mm/page-states.c +++ b/arch/s390/mm/page-states.c @@ -21,17 +21,11 @@ static int cmma_flag = 1; static int __init cmma(char *str) { - char *parm; + bool enabled; - parm = strstrip(str); - if (strcmp(parm, "yes") == 0 || strcmp(parm, "on") == 0) { - cmma_flag = 1; - return 1; - } - cmma_flag = 0; - if (strcmp(parm, "no") == 0 || strcmp(parm, "off") == 0) - return 1; - return 0; + if (!kstrtobool(str, &enabled)) + cmma_flag = enabled; + return 1; } __setup("cmma=", cmma); -- cgit v1.2.3 From 9b692102d87d13d24c97461207cae259121ed44b Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 23:14:10 +0200 Subject: s390/mem_detect: provide single get_mem_detect_end get_mem_detect_end is already used in couple of places with potential to be utilized in more cases. Provide single get_mem_detect_end implementation in asm/mem_detect.h to be used by kasan and startup code. Signed-off-by: Vasily Gorbik --- arch/s390/boot/mem_detect.c | 7 ------- arch/s390/include/asm/mem_detect.h | 12 ++++++++++++ arch/s390/mm/kasan_init.c | 12 ------------ 3 files changed, 12 insertions(+), 19 deletions(-) diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c index 5d316fe40480..62e7c13ce85c 100644 --- a/arch/s390/boot/mem_detect.c +++ b/arch/s390/boot/mem_detect.c @@ -63,13 +63,6 @@ void add_mem_detect_block(u64 start, u64 end) mem_detect.count++; } -static unsigned long get_mem_detect_end(void) -{ - if (mem_detect.count) - return __get_mem_detect_block_ptr(mem_detect.count - 1)->end; - return 0; -} - static int __diag260(unsigned long rx1, unsigned long rx2) { register unsigned long _rx1 asm("2") = rx1; diff --git a/arch/s390/include/asm/mem_detect.h b/arch/s390/include/asm/mem_detect.h index 6114b92ab667..a7c922a69050 100644 --- a/arch/s390/include/asm/mem_detect.h +++ b/arch/s390/include/asm/mem_detect.h @@ -79,4 +79,16 @@ static inline void get_mem_detect_reserved(unsigned long *start, *size = 0; } +static inline unsigned long get_mem_detect_end(void) +{ + unsigned long start; + unsigned long end; + + if (mem_detect.count) { + __get_mem_detect_block(mem_detect.count - 1, &start, &end); + return end; + } + return 0; +} + #endif diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c index 0c1f257be422..4a61bc955388 100644 --- a/arch/s390/mm/kasan_init.c +++ b/arch/s390/mm/kasan_init.c @@ -236,18 +236,6 @@ static void __init kasan_early_detect_facilities(void) } } -static unsigned long __init get_mem_detect_end(void) -{ - unsigned long start; - unsigned long end; - - if (mem_detect.count) { - __get_mem_detect_block(mem_detect.count - 1, &start, &end); - return end; - } - return 0; -} - void __init kasan_early_init(void) { unsigned long untracked_mem_end; -- cgit v1.2.3 From 759d4899d905c2a491d34987366421aebca359de Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 23:19:00 +0200 Subject: s390/kaslr: reserve memory for kasan usage Sometimes the kernel fails to boot with: "The Linux kernel failed to boot with the KernelAddressSanitizer: out of memory during initialisation" even with big amounts of memory when both kaslr and kasan are enabled. The problem is that kasan initialization code requires 1/8 of physical memory plus some for page tables. To keep as much code instrumented as possible kasan avoids using memblock for memory allocations. Instead kasan uses trivial memory allocator which simply chops off the memory from the end of online physical memory. For that reason when kaslr is enabled together with kasan avoid positioning kernel into upper memory region which would be utilized during kasan initialization. Reviewed-by: Gerald Schaefer Signed-off-by: Vasily Gorbik --- arch/s390/boot/kaslr.c | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/arch/s390/boot/kaslr.c b/arch/s390/boot/kaslr.c index 3bdd8132e56b..b4bb4ad15c5b 100644 --- a/arch/s390/boot/kaslr.c +++ b/arch/s390/boot/kaslr.c @@ -3,6 +3,7 @@ * Copyright IBM Corp. 2019 */ #include +#include #include #include #include @@ -89,8 +90,10 @@ static unsigned long get_random(unsigned long limit) unsigned long get_random_base(unsigned long safe_addr) { + unsigned long memory_limit = memory_end_set ? memory_end : 0; unsigned long base, start, end, kernel_size; unsigned long block_sum, offset; + unsigned long kasan_needs; int i; if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE) { @@ -99,14 +102,36 @@ unsigned long get_random_base(unsigned long safe_addr) } safe_addr = ALIGN(safe_addr, THREAD_SIZE); + if ((IS_ENABLED(CONFIG_KASAN))) { + /* + * Estimate kasan memory requirements, which it will reserve + * at the very end of available physical memory. To estimate + * that, we take into account that kasan would require + * 1/8 of available physical memory (for shadow memory) + + * creating page tables for the whole memory + shadow memory + * region (1 + 1/8). To keep page tables estimates simple take + * the double of combined ptes size. + */ + memory_limit = get_mem_detect_end(); + if (memory_end_set && memory_limit > memory_end) + memory_limit = memory_end; + + /* for shadow memory */ + kasan_needs = memory_limit / 8; + /* for paging structures */ + kasan_needs += (memory_limit + kasan_needs) / PAGE_SIZE / + _PAGE_ENTRIES * _PAGE_TABLE_SIZE * 2; + memory_limit -= kasan_needs; + } + kernel_size = vmlinux.image_size + vmlinux.bss_size; block_sum = 0; for_each_mem_detect_block(i, &start, &end) { - if (memory_end_set) { - if (start >= memory_end) + if (memory_limit) { + if (start >= memory_limit) break; - if (end > memory_end) - end = memory_end; + if (end > memory_limit) + end = memory_limit; } if (end - start < kernel_size) continue; @@ -124,11 +149,11 @@ unsigned long get_random_base(unsigned long safe_addr) base = safe_addr; block_sum = offset = 0; for_each_mem_detect_block(i, &start, &end) { - if (memory_end_set) { - if (start >= memory_end) + if (memory_limit) { + if (start >= memory_limit) break; - if (end > memory_end) - end = memory_end; + if (end > memory_limit) + end = memory_limit; } if (end - start < kernel_size) continue; -- cgit v1.2.3 From 8dec6bd4ef327f48eb790a48cba0e833109d4e41 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 16:29:01 +0200 Subject: s390/pci: avoid using strncmp with hardcoded length Command line option values passed to __setup callbacks are always null-terminated and "s390_iommu=" may only accept "strict" as value. So replace strncmp with strcmp. While at it also make s390_iommu_setup return 1, which means this command line option is handled by this callback. Signed-off-by: Vasily Gorbik --- arch/s390/pci/pci_dma.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 9e52d1527f71..fb2c7db0164e 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c @@ -674,9 +674,9 @@ EXPORT_SYMBOL_GPL(s390_pci_dma_ops); static int __init s390_iommu_setup(char *str) { - if (!strncmp(str, "strict", 6)) + if (!strcmp(str, "strict")) s390_iommu_strict = 1; - return 0; + return 1; } __setup("s390_iommu=", s390_iommu_setup); -- cgit v1.2.3 From b29cd7c4c482d895f4b13ef1dfe85550529f38c9 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 17:05:44 +0200 Subject: s390/module: avoid using strncmp with hardcoded length Reuse str_has_prefix instead of strncmp with hardcoded length to make the intent of a comparison more obvious. Signed-off-by: Vasily Gorbik --- arch/s390/kernel/module.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c index 31889db609e9..ba8f19bb438b 100644 --- a/arch/s390/kernel/module.c +++ b/arch/s390/kernel/module.c @@ -472,11 +472,11 @@ int module_finalize(const Elf_Ehdr *hdr, apply_alternatives(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strncmp(".s390_indirect", secname, 14))) + (str_has_prefix(secname, ".s390_indirect"))) nospec_revert(aseg, aseg + s->sh_size); if (IS_ENABLED(CONFIG_EXPOLINE) && - (!strncmp(".s390_return", secname, 12))) + (str_has_prefix(secname, ".s390_return"))) nospec_revert(aseg, aseg + s->sh_size); } -- cgit v1.2.3 From 54fb07d030e1b2fa9d903a748f84398bbe6f213d Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 17:13:04 +0200 Subject: s390/sclp: avoid using strncmp with hardcoded length "earlyprintk" option documentation does not clearly state which platform supports which additional values (e.g. ",keep"). Preserve old option behaviour and reuse str_has_prefix instead of strncmp for prefix testing. Signed-off-by: Vasily Gorbik --- arch/s390/kernel/early_printk.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/kernel/early_printk.c b/arch/s390/kernel/early_printk.c index 40c1dfec944e..6f24d83bc5dc 100644 --- a/arch/s390/kernel/early_printk.c +++ b/arch/s390/kernel/early_printk.c @@ -25,7 +25,7 @@ static int __init setup_early_printk(char *buf) if (early_console) return 0; /* Accept only "earlyprintk" and "earlyprintk=sclp" */ - if (buf && strncmp(buf, "sclp", 4)) + if (buf && !str_has_prefix(buf, "sclp")) return 0; if (!sclp.has_linemode && !sclp.has_vt220) return 0; -- cgit v1.2.3 From d0b319843baddc1a224ccdc73729aed55ec7787a Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 19 Aug 2019 17:32:44 +0200 Subject: s390/setup: avoid using strncmp with hardcoded length Replace strncmp usage in console mode setup code with simple strcmp. Replace strncmp which is used for prefix comparison with str_has_prefix. Signed-off-by: Vasily Gorbik --- arch/s390/kernel/setup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 0c3f1cd69ed1..3e4b4a48a597 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -169,15 +169,15 @@ static void __init set_preferred_console(void) static int __init conmode_setup(char *str) { #if defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) - if (strncmp(str, "hwc", 4) == 0 || strncmp(str, "sclp", 5) == 0) + if (!strcmp(str, "hwc") || !strcmp(str, "sclp")) SET_CONSOLE_SCLP; #endif #if defined(CONFIG_TN3215_CONSOLE) - if (strncmp(str, "3215", 5) == 0) + if (!strcmp(str, "3215")) SET_CONSOLE_3215; #endif #if defined(CONFIG_TN3270_CONSOLE) - if (strncmp(str, "3270", 5) == 0) + if (!strcmp(str, "3270")) SET_CONSOLE_3270; #endif set_preferred_console(); @@ -212,7 +212,7 @@ static void __init conmode_default(void) #endif return; } - if (strncmp(ptr + 8, "3270", 4) == 0) { + if (str_has_prefix(ptr + 8, "3270")) { #if defined(CONFIG_TN3270_CONSOLE) SET_CONSOLE_3270; #elif defined(CONFIG_TN3215_CONSOLE) @@ -220,7 +220,7 @@ static void __init conmode_default(void) #elif defined(CONFIG_SCLP_CONSOLE) || defined(CONFIG_SCLP_VT220_CONSOLE) SET_CONSOLE_SCLP; #endif - } else if (strncmp(ptr + 8, "3215", 4) == 0) { + } else if (str_has_prefix(ptr + 8, "3215")) { #if defined(CONFIG_TN3215_CONSOLE) SET_CONSOLE_3215; #elif defined(CONFIG_TN3270_CONSOLE) -- cgit v1.2.3 From 042c1d29de8c0d4e4c9e77c64995b59be97aed33 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Tue, 20 Aug 2019 19:45:47 +0200 Subject: s390/kasan: add kdump support If kasan enabled kernel is used as crash kernel it crashes itself with program check loop during kdump execution. The reason for that is that kasan shadow memory backed by pages beyond OLDMEM_SIZE. Make kasan memory allocator respect physical memory limit imposed by kdump. Signed-off-by: Vasily Gorbik --- arch/s390/mm/kasan_init.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/s390/mm/kasan_init.c b/arch/s390/mm/kasan_init.c index 4a61bc955388..460f25572940 100644 --- a/arch/s390/mm/kasan_init.c +++ b/arch/s390/mm/kasan_init.c @@ -261,6 +261,8 @@ void __init kasan_early_init(void) /* respect mem= cmdline parameter */ if (memory_end_set && memsize > memory_end) memsize = memory_end; + if (IS_ENABLED(CONFIG_CRASH_DUMP) && OLDMEM_BASE) + memsize = min(memsize, OLDMEM_SIZE); memsize = min(memsize, KASAN_SHADOW_START); if (IS_ENABLED(CONFIG_KASAN_S390_4_LEVEL_PAGING)) { -- cgit v1.2.3 From deffa48fb014f06f7cf8c4b3ea3c96160be3c854 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 29 Aug 2019 15:16:35 +0200 Subject: s390/zcrypt: fix wrong handling of cca cipher keygenflags Tests showed that the keygenflags parameter is not handled correctly within the zcrypt ccamisc generate cca cipher key code. A similar code is used with cca cipher key value import and there the flags are handled correctly. For unknown reason these lines have not been updated for the generate function and so this patch now introduces these two lines of code. This affects only pkey with the use of CCA cipher keys and the use of additional key generate flags. Fixes: 4bc123b18ce6 ("s390/zcrypt: Add low level functions for CCA AES cipher keys") Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/zcrypt_ccamisc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/s390/crypto/zcrypt_ccamisc.c b/drivers/s390/crypto/zcrypt_ccamisc.c index 3b2d3705d2db..c1db64a2db21 100644 --- a/drivers/s390/crypto/zcrypt_ccamisc.c +++ b/drivers/s390/crypto/zcrypt_ccamisc.c @@ -838,7 +838,8 @@ int cca_gencipherkey(u16 cardnr, u16 domain, u32 keybitsize, u32 keygenflags, /* patch the skeleton key token export flags inside the kb block */ if (keygenflags) { t = (struct cipherkeytoken *) preqparm->kb.tlv3.gen_key_id_1; - t->kmf1 |= (u16) (keygenflags & 0x0000FFFF); + t->kmf1 |= (u16) (keygenflags & 0x0000FF00); + t->kmf1 &= (u16) ~(keygenflags & 0x000000FF); } /* prepare xcrb struct */ -- cgit v1.2.3 From 4df9a82549cfed5b52da21e7d007b79b2ea1769a Mon Sep 17 00:00:00 2001 From: Philipp Rudo Date: Thu, 29 Aug 2019 15:38:37 +0200 Subject: s390/sclp: Fix bit checked for has_sipl Fixes: c9896acc7851 ("s390/ipl: Provide has_secure sysfs attribute") Cc: stable@vger.kernel.org # 5.2+ Reviewed-by: Heiko Carstens Signed-off-by: Philipp Rudo Signed-off-by: Vasily Gorbik --- drivers/s390/char/sclp_early.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index e71992a3c55f..cc5e84b80c69 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -40,7 +40,7 @@ static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) sclp.has_gisaf = !!(sccb->fac118 & 0x08); sclp.has_hvs = !!(sccb->fac119 & 0x80); sclp.has_kss = !!(sccb->fac98 & 0x01); - sclp.has_sipl = !!(sccb->cbl & 0x02); + sclp.has_sipl = !!(sccb->cbl & 0x4000); if (sccb->fac85 & 0x02) S390_lowcore.machine_flags |= MACHINE_FLAG_ESOP; if (sccb->fac91 & 0x40) -- cgit v1.2.3 From 512222789ce8aba54295854c4641aa6f680c1897 Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Mon, 2 Sep 2019 16:59:32 +0200 Subject: s390/base: remove unused s390_base_mcck_handler s390_base_mcck_handler was used during system reset if diag308 set was not available. But after commit d485235b0054 ("s390: assume diag308 set always works") is a dead code and could be removed. Acked-by: Heiko Carstens Signed-off-by: Vasily Gorbik --- arch/s390/include/asm/processor.h | 2 -- arch/s390/kernel/base.S | 21 --------------------- 2 files changed, 23 deletions(-) diff --git a/arch/s390/include/asm/processor.h b/arch/s390/include/asm/processor.h index d56c519bc696..51a0e4a2dc96 100644 --- a/arch/s390/include/asm/processor.h +++ b/arch/s390/include/asm/processor.h @@ -324,11 +324,9 @@ static inline void __noreturn disabled_wait(void) * Basic Machine Check/Program Check Handler. */ -extern void s390_base_mcck_handler(void); extern void s390_base_pgm_handler(void); extern void s390_base_ext_handler(void); -extern void (*s390_base_mcck_handler_fn)(void); extern void (*s390_base_pgm_handler_fn)(void); extern void (*s390_base_ext_handler_fn)(void); diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S index 2f39ea57f358..b79e0fd571f8 100644 --- a/arch/s390/kernel/base.S +++ b/arch/s390/kernel/base.S @@ -16,27 +16,6 @@ GEN_BR_THUNK %r9 GEN_BR_THUNK %r14 -ENTRY(s390_base_mcck_handler) - basr %r13,0 -0: lg %r15,__LC_NODAT_STACK # load panic stack - aghi %r15,-STACK_FRAME_OVERHEAD - larl %r1,s390_base_mcck_handler_fn - lg %r9,0(%r1) - ltgr %r9,%r9 - jz 1f - BASR_EX %r14,%r9 -1: la %r1,4095 - lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) - lpswe __LC_MCK_OLD_PSW -ENDPROC(s390_base_mcck_handler) - - .section .bss - .align 8 - .globl s390_base_mcck_handler_fn -s390_base_mcck_handler_fn: - .quad 0 - .previous - ENTRY(s390_base_ext_handler) stmg %r0,%r15,__LC_SAVE_AREA_ASYNC basr %r13,0 -- cgit v1.2.3 From 024cdcdbf3cf9904465a7d5256d8594defa2758b Mon Sep 17 00:00:00 2001 From: Halil Pasic Date: Tue, 3 Sep 2019 15:36:18 +0200 Subject: s390: vfio-ap: fix warning reset not completed The intention seems to be to warn once when we don't wait enough for the reset to complete. Let's use the right retry counter to accomplish that semantic. Signed-off-by: Halil Pasic Link: https://lore.kernel.org/r/20190903133618.9122-1-pasic@linux.ibm.com Reviewed-by: Cornelia Huck Signed-off-by: Christian Borntraeger Signed-off-by: Vasily Gorbik --- drivers/s390/crypto/vfio_ap_ops.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/s390/crypto/vfio_ap_ops.c b/drivers/s390/crypto/vfio_ap_ops.c index 0604b49a4d32..5c0f53c6dde7 100644 --- a/drivers/s390/crypto/vfio_ap_ops.c +++ b/drivers/s390/crypto/vfio_ap_ops.c @@ -1143,7 +1143,7 @@ int vfio_ap_mdev_reset_queue(unsigned int apid, unsigned int apqi, msleep(20); status = ap_tapq(apqn, NULL); } - WARN_ON_ONCE(retry <= 0); + WARN_ON_ONCE(retry2 <= 0); return 0; case AP_RESPONSE_RESET_IN_PROGRESS: case AP_RESPONSE_BUSY: -- cgit v1.2.3 From 987ca7ca1fda0ac470179b2110716d62e107ab06 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 4 Sep 2019 08:33:15 +0000 Subject: vfio-ccw: fix error return code in vfio_ccw_sch_init() Fix to return negative error code -ENOMEM from the memory alloc failed error handling case instead of 0, as done elsewhere in this function. Fixes: 60e05d1cf087 ("vfio-ccw: add some logging") Signed-off-by: Wei Yongjun Reviewed-by: Cornelia Huck Link https://lore.kernel.org/kvm/20190904083315.105600-1-weiyongjun1@huawei.com/ Signed-off-by: Christian Borntraeger Signed-off-by: Vasily Gorbik --- drivers/s390/cio/vfio_ccw_drv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/s390/cio/vfio_ccw_drv.c b/drivers/s390/cio/vfio_ccw_drv.c index 45e792f6afd0..e401a3d0aa57 100644 --- a/drivers/s390/cio/vfio_ccw_drv.c +++ b/drivers/s390/cio/vfio_ccw_drv.c @@ -317,15 +317,19 @@ static int __init vfio_ccw_sch_init(void) sizeof(struct ccw_io_region), 0, SLAB_ACCOUNT, 0, sizeof(struct ccw_io_region), NULL); - if (!vfio_ccw_io_region) + if (!vfio_ccw_io_region) { + ret = -ENOMEM; goto out_err; + } vfio_ccw_cmd_region = kmem_cache_create_usercopy("vfio_ccw_cmd_region", sizeof(struct ccw_cmd_region), 0, SLAB_ACCOUNT, 0, sizeof(struct ccw_cmd_region), NULL); - if (!vfio_ccw_cmd_region) + if (!vfio_ccw_cmd_region) { + ret = -ENOMEM; goto out_err; + } isc_register(VFIO_CCW_ISC); ret = css_driver_register(&vfio_ccw_sch_driver); -- cgit v1.2.3 From 9e323d45ba94262620a073a3f9945ca927c07c71 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 5 Sep 2019 09:38:17 +0200 Subject: s390/crypto: xts-aes-s390 fix extra run-time crypto self tests finding With 'extra run-time crypto self tests' enabled, the selftest for s390-xts fails with alg: skcipher: xts-aes-s390 encryption unexpectedly succeeded on test vector "random: len=0 klen=64"; expected_error=-22, cfg="random: inplace use_digest nosimd src_divs=[2.61%@+4006, 84.44%@+21, 1.55%@+13, 4.50%@+344, 4.26%@+21, 2.64%@+27]" This special case with nbytes=0 is not handled correctly and this fix now makes sure that -EINVAL is returned when there is en/decrypt called with 0 bytes to en/decrypt. Signed-off-by: Harald Freudenberger Signed-off-by: Vasily Gorbik --- arch/s390/crypto/aes_s390.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/s390/crypto/aes_s390.c b/arch/s390/crypto/aes_s390.c index d00f84add5f4..6d2dbb5089d5 100644 --- a/arch/s390/crypto/aes_s390.c +++ b/arch/s390/crypto/aes_s390.c @@ -586,6 +586,9 @@ static int xts_aes_encrypt(struct blkcipher_desc *desc, struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; + if (!nbytes) + return -EINVAL; + if (unlikely(!xts_ctx->fc)) return xts_fallback_encrypt(desc, dst, src, nbytes); @@ -600,6 +603,9 @@ static int xts_aes_decrypt(struct blkcipher_desc *desc, struct s390_xts_ctx *xts_ctx = crypto_blkcipher_ctx(desc->tfm); struct blkcipher_walk walk; + if (!nbytes) + return -EINVAL; + if (unlikely(!xts_ctx->fc)) return xts_fallback_decrypt(desc, dst, src, nbytes); -- cgit v1.2.3 From 724dc336b79ff965bd5773257642685cf33ed9af Mon Sep 17 00:00:00 2001 From: Vasily Gorbik Date: Thu, 8 Aug 2019 20:09:08 +0200 Subject: s390/startup: add pgm check info printing Try to print out startup pgm check info including exact linux kernel version, pgm interruption code and ilc, psw and general registers. Like the following: Linux version 5.3.0-rc7-07282-ge7b4d41d61bd-dirty (gor@tuxmaker) #3 SMP PREEMPT Thu Sep 5 16:07:34 CEST 2019 Kernel fault: interruption code 0005 ilc:2 PSW : 0000000180000000 0000000000012e52 R:0 T:0 IO:0 EX:0 Key:0 M:0 W:0 P:0 AS:0 CC:0 PM:0 RI:0 EA:3 GPRS: 0000000000000000 00ffffffffffffff 0000000000000000 0000000000019a58 000000000000bf68 0000000000000000 0000000000000000 0000000000000000 0000000000000000 0000000000000000 000000000001a041 0000000000000000 0000000004c9c000 0000000000010070 0000000000012e42 000000000000beb0 This info makes it apparent that kernel startup failed and might help to understand what went wrong without actual standalone dump. Printing code runs on its own stack of 1 page (at unused 0x5000), which should be sufficient for sclp_early_printk usage (typical stack usage observed has been around 512 bytes). The code has pgm check recursion prevention, despite pgm check info printing failure (follow on pgm check) or success it restores original faulty psw and gprs and does disabled wait. Reviewed-by: Heiko Carstens Signed-off-by: Vasily Gorbik Signed-off-by: Heiko Carstens --- arch/s390/boot/Makefile | 2 +- arch/s390/boot/boot.h | 1 + arch/s390/boot/head.S | 10 ++++- arch/s390/boot/pgm_check_info.c | 90 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 arch/s390/boot/pgm_check_info.c diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index 4cf0bddb7d92..e2c47d3a1c89 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile @@ -36,7 +36,7 @@ CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o -obj-y += version.o ctype.o text_dma.o +obj-y += version.o pgm_check_info.o ctype.o text_dma.o obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o obj-$(CONFIG_RELOCATABLE) += machine_kexec_reloc.o obj-$(CONFIG_RANDOMIZE_BASE) += kaslr.o diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index 082905d97309..1f7a8d4aff28 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h @@ -9,6 +9,7 @@ void setup_boot_command_line(void); void parse_boot_command_line(void); void setup_memory_end(void); void print_missing_facilities(void); +void print_pgm_check_info(void); unsigned long get_random_base(unsigned long safe_addr); extern int kaslr_enabled; diff --git a/arch/s390/boot/head.S b/arch/s390/boot/head.S index 5b79ae7b44f3..4b86a8d3c121 100644 --- a/arch/s390/boot/head.S +++ b/arch/s390/boot/head.S @@ -365,12 +365,20 @@ ENTRY(startup_pgm_check_handler) stctg %c0,%c15,__LC_CREGS_SAVE_AREA-4095(%r1) mvc __LC_GPREGS_SAVE_AREA-4095(128,%r1),__LC_SAVE_AREA_SYNC mvc __LC_PSW_SAVE_AREA-4095(16,%r1),__LC_PGM_OLD_PSW - lg %r1,__LC_SAVE_AREA_SYNC+8 mvc __LC_RETURN_PSW(16),__LC_PGM_OLD_PSW ni __LC_RETURN_PSW,0xfc # remove IO and EX bits ni __LC_RETURN_PSW+1,0xfb # remove MCHK bit oi __LC_RETURN_PSW+1,0x2 # set wait state bit + larl %r2,.Lold_psw_disabled_wait + stg %r2,__LC_PGM_NEW_PSW+8 + l %r15,.Ldump_info_stack-.Lold_psw_disabled_wait(%r2) + brasl %r14,print_pgm_check_info +.Lold_psw_disabled_wait: + la %r1,4095 + lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) lpswe __LC_RETURN_PSW # disabled wait +.Ldump_info_stack: + .long 0x5000 + PAGE_SIZE - STACK_FRAME_OVERHEAD ENDPROC(startup_pgm_check_handler) # diff --git a/arch/s390/boot/pgm_check_info.c b/arch/s390/boot/pgm_check_info.c new file mode 100644 index 000000000000..83b5b7915c32 --- /dev/null +++ b/arch/s390/boot/pgm_check_info.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include "boot.h" + +const char hex_asc[] = "0123456789abcdef"; + +#define add_val_as_hex(dst, val) \ + __add_val_as_hex(dst, (const unsigned char *)&val, sizeof(val)) + +static char *__add_val_as_hex(char *dst, const unsigned char *src, size_t count) +{ + while (count--) + dst = hex_byte_pack(dst, *src++); + return dst; +} + +static char *add_str(char *dst, char *src) +{ + strcpy(dst, src); + return dst + strlen(dst); +} + +void print_pgm_check_info(void) +{ + struct psw_bits *psw = &psw_bits(S390_lowcore.psw_save_area); + unsigned short ilc = S390_lowcore.pgm_ilc >> 1; + char buf[256]; + int row, col; + char *p; + + add_str(buf, "Linux version "); + strlcat(buf, kernel_version, sizeof(buf)); + sclp_early_printk(buf); + + p = add_str(buf, "Kernel fault: interruption code "); + p = add_val_as_hex(buf + strlen(buf), S390_lowcore.pgm_code); + p = add_str(p, " ilc:"); + *p++ = hex_asc_lo(ilc); + add_str(p, "\n"); + sclp_early_printk(buf); + + p = add_str(buf, "PSW : "); + p = add_val_as_hex(p, S390_lowcore.psw_save_area.mask); + p = add_str(p, " "); + p = add_val_as_hex(p, S390_lowcore.psw_save_area.addr); + add_str(p, "\n"); + sclp_early_printk(buf); + + p = add_str(buf, " R:"); + *p++ = hex_asc_lo(psw->per); + p = add_str(p, " T:"); + *p++ = hex_asc_lo(psw->dat); + p = add_str(p, " IO:"); + *p++ = hex_asc_lo(psw->io); + p = add_str(p, " EX:"); + *p++ = hex_asc_lo(psw->ext); + p = add_str(p, " Key:"); + *p++ = hex_asc_lo(psw->key); + p = add_str(p, " M:"); + *p++ = hex_asc_lo(psw->mcheck); + p = add_str(p, " W:"); + *p++ = hex_asc_lo(psw->wait); + p = add_str(p, " P:"); + *p++ = hex_asc_lo(psw->pstate); + p = add_str(p, " AS:"); + *p++ = hex_asc_lo(psw->as); + p = add_str(p, " CC:"); + *p++ = hex_asc_lo(psw->cc); + p = add_str(p, " PM:"); + *p++ = hex_asc_lo(psw->pm); + p = add_str(p, " RI:"); + *p++ = hex_asc_lo(psw->ri); + p = add_str(p, " EA:"); + *p++ = hex_asc_lo(psw->eaba); + add_str(p, "\n"); + sclp_early_printk(buf); + + for (row = 0; row < 4; row++) { + p = add_str(buf, row == 0 ? "GPRS:" : " "); + for (col = 0; col < 4; col++) { + p = add_str(p, " "); + p = add_val_as_hex(p, S390_lowcore.gpregs_save_area[row * 4 + col]); + } + add_str(p, "\n"); + sclp_early_printk(buf); + } +} -- cgit v1.2.3 From 3c2eb6b76cabb7d90834798d6455f7f3431fc989 Mon Sep 17 00:00:00 2001 From: Joerg Schmidbauer Date: Wed, 14 Aug 2019 14:56:54 +0200 Subject: s390/crypto: Support for SHA3 via CPACF (MSA6) This patch introduces sha3 support for s390. - Rework the s390-specific SHA1 and SHA2 related code to provide the basis for SHA3. - Provide two new kernel modules sha3_256_s390 and sha3_512_s390 together with new kernel options. Signed-off-by: Joerg Schmidbauer Reviewed-by: Ingo Franzki Reviewed-by: Harald Freudenberger Signed-off-by: Heiko Carstens --- arch/s390/configs/debug_defconfig | 2 + arch/s390/configs/defconfig | 2 + arch/s390/crypto/Makefile | 2 + arch/s390/crypto/sha.h | 12 +-- arch/s390/crypto/sha3_256_s390.c | 147 ++++++++++++++++++++++++++++++++++++ arch/s390/crypto/sha3_512_s390.c | 155 ++++++++++++++++++++++++++++++++++++++ arch/s390/crypto/sha_common.c | 75 ++++++++++++------ arch/s390/include/asm/cpacf.h | 8 ++ drivers/crypto/Kconfig | 20 +++++ 9 files changed, 395 insertions(+), 28 deletions(-) create mode 100644 arch/s390/crypto/sha3_256_s390.c create mode 100644 arch/s390/crypto/sha3_512_s390.c diff --git a/arch/s390/configs/debug_defconfig b/arch/s390/configs/debug_defconfig index e26d4413d34c..a08e3dcd3e9d 100644 --- a/arch/s390/configs/debug_defconfig +++ b/arch/s390/configs/debug_defconfig @@ -723,6 +723,8 @@ CONFIG_CRYPTO_PAES_S390=m CONFIG_CRYPTO_SHA1_S390=m CONFIG_CRYPTO_SHA256_S390=m CONFIG_CRYPTO_SHA512_S390=m +CONFIG_CRYPTO_SHA3_256_S390=m +CONFIG_CRYPTO_SHA3_512_S390=m CONFIG_CRYPTO_DES_S390=m CONFIG_CRYPTO_AES_S390=m CONFIG_CRYPTO_GHASH_S390=m diff --git a/arch/s390/configs/defconfig b/arch/s390/configs/defconfig index e4bc40073003..3c3515d6be12 100644 --- a/arch/s390/configs/defconfig +++ b/arch/s390/configs/defconfig @@ -665,6 +665,8 @@ CONFIG_CRYPTO_PAES_S390=m CONFIG_CRYPTO_SHA1_S390=m CONFIG_CRYPTO_SHA256_S390=m CONFIG_CRYPTO_SHA512_S390=m +CONFIG_CRYPTO_SHA3_256_S390=m +CONFIG_CRYPTO_SHA3_512_S390=m CONFIG_CRYPTO_DES_S390=m CONFIG_CRYPTO_AES_S390=m CONFIG_CRYPTO_GHASH_S390=m diff --git a/arch/s390/crypto/Makefile b/arch/s390/crypto/Makefile index a51010ea62fa..12889d4652cc 100644 --- a/arch/s390/crypto/Makefile +++ b/arch/s390/crypto/Makefile @@ -6,6 +6,8 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o sha_common.o obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o sha_common.o obj-$(CONFIG_CRYPTO_SHA512_S390) += sha512_s390.o sha_common.o +obj-$(CONFIG_CRYPTO_SHA3_256_S390) += sha3_256_s390.o sha_common.o +obj-$(CONFIG_CRYPTO_SHA3_512_S390) += sha3_512_s390.o sha_common.o obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o obj-$(CONFIG_CRYPTO_PAES_S390) += paes_s390.o diff --git a/arch/s390/crypto/sha.h b/arch/s390/crypto/sha.h index d6f8258b44df..ada2f98c27b7 100644 --- a/arch/s390/crypto/sha.h +++ b/arch/s390/crypto/sha.h @@ -12,15 +12,17 @@ #include #include +#include /* must be big enough for the largest SHA variant */ -#define SHA_MAX_STATE_SIZE (SHA512_DIGEST_SIZE / 4) -#define SHA_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE +#define SHA3_STATE_SIZE 200 +#define CPACF_MAX_PARMBLOCK_SIZE SHA3_STATE_SIZE +#define SHA_MAX_BLOCK_SIZE SHA3_224_BLOCK_SIZE struct s390_sha_ctx { - u64 count; /* message length in bytes */ - u32 state[SHA_MAX_STATE_SIZE]; - u8 buf[2 * SHA_MAX_BLOCK_SIZE]; + u64 count; /* message length in bytes */ + u32 state[CPACF_MAX_PARMBLOCK_SIZE / sizeof(u32)]; + u8 buf[SHA_MAX_BLOCK_SIZE]; int func; /* KIMD function to use */ }; diff --git a/arch/s390/crypto/sha3_256_s390.c b/arch/s390/crypto/sha3_256_s390.c new file mode 100644 index 000000000000..460cbbbaa44a --- /dev/null +++ b/arch/s390/crypto/sha3_256_s390.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Cryptographic API. + * + * s390 implementation of the SHA256 and SHA224 Secure Hash Algorithm. + * + * s390 Version: + * Copyright IBM Corp. 2019 + * Author(s): Joerg Schmidbauer (jschmidb@de.ibm.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "sha.h" + +static int sha3_256_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_256; + + return 0; +} + +static int sha3_256_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha3_state *octx = out; + + octx->rsiz = sctx->count; + memcpy(octx->st, sctx->state, sizeof(octx->st)); + memcpy(octx->buf, sctx->buf, sizeof(octx->buf)); + + return 0; +} + +static int sha3_256_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + sctx->count = ictx->rsiz; + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_256; + + return 0; +} + +static int sha3_224_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + sctx->count = ictx->rsiz; + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_224; + + return 0; +} + +static struct shash_alg sha3_256_alg = { + .digestsize = SHA3_256_DIGEST_SIZE, /* = 32 */ + .init = sha3_256_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_256_export, + .import = sha3_256_import, + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-256", + .cra_driver_name = "sha3-256-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_256_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int sha3_224_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_224; + + return 0; +} + +static struct shash_alg sha3_224_alg = { + .digestsize = SHA3_224_DIGEST_SIZE, + .init = sha3_224_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_256_export, /* same as for 256 */ + .import = sha3_224_import, /* function code different! */ + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-224", + .cra_driver_name = "sha3-224-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_224_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +static int __init sha3_256_s390_init(void) +{ + int ret; + + if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_SHA3_256)) + return -ENODEV; + + ret = crypto_register_shash(&sha3_256_alg); + if (ret < 0) + goto out; + + ret = crypto_register_shash(&sha3_224_alg); + if (ret < 0) + crypto_unregister_shash(&sha3_256_alg); +out: + return ret; +} + +static void __exit sha3_256_s390_fini(void) +{ + crypto_unregister_shash(&sha3_224_alg); + crypto_unregister_shash(&sha3_256_alg); +} + +module_cpu_feature_match(MSA, sha3_256_s390_init); +module_exit(sha3_256_s390_fini); + +MODULE_ALIAS_CRYPTO("sha3-256"); +MODULE_ALIAS_CRYPTO("sha3-224"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA3-256 and SHA3-224 Secure Hash Algorithm"); diff --git a/arch/s390/crypto/sha3_512_s390.c b/arch/s390/crypto/sha3_512_s390.c new file mode 100644 index 000000000000..72cf460a53e5 --- /dev/null +++ b/arch/s390/crypto/sha3_512_s390.c @@ -0,0 +1,155 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Cryptographic API. + * + * s390 implementation of the SHA512 and SHA384 Secure Hash Algorithm. + * + * Copyright IBM Corp. 2019 + * Author(s): Joerg Schmidbauer (jschmidb@de.ibm.com) + */ +#include +#include +#include +#include +#include +#include +#include + +#include "sha.h" + +static int sha3_512_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_512; + + return 0; +} + +static int sha3_512_export(struct shash_desc *desc, void *out) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + struct sha3_state *octx = out; + + octx->rsiz = sctx->count; + octx->rsizw = sctx->count >> 32; + + memcpy(octx->st, sctx->state, sizeof(octx->st)); + memcpy(octx->buf, sctx->buf, sizeof(octx->buf)); + + return 0; +} + +static int sha3_512_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + if (unlikely(ictx->rsizw)) + return -ERANGE; + sctx->count = ictx->rsiz; + + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_512; + + return 0; +} + +static int sha3_384_import(struct shash_desc *desc, const void *in) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + const struct sha3_state *ictx = in; + + if (unlikely(ictx->rsizw)) + return -ERANGE; + sctx->count = ictx->rsiz; + + memcpy(sctx->state, ictx->st, sizeof(ictx->st)); + memcpy(sctx->buf, ictx->buf, sizeof(ictx->buf)); + sctx->func = CPACF_KIMD_SHA3_384; + + return 0; +} + +static struct shash_alg sha3_512_alg = { + .digestsize = SHA3_512_DIGEST_SIZE, + .init = sha3_512_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_512_export, + .import = sha3_512_import, + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-512", + .cra_driver_name = "sha3-512-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_512_BLOCK_SIZE, + .cra_module = THIS_MODULE, + } +}; + +MODULE_ALIAS_CRYPTO("sha3-512"); + +static int sha3_384_init(struct shash_desc *desc) +{ + struct s390_sha_ctx *sctx = shash_desc_ctx(desc); + + memset(sctx->state, 0, sizeof(sctx->state)); + sctx->count = 0; + sctx->func = CPACF_KIMD_SHA3_384; + + return 0; +} + +static struct shash_alg sha3_384_alg = { + .digestsize = SHA3_384_DIGEST_SIZE, + .init = sha3_384_init, + .update = s390_sha_update, + .final = s390_sha_final, + .export = sha3_512_export, /* same as for 512 */ + .import = sha3_384_import, /* function code different! */ + .descsize = sizeof(struct s390_sha_ctx), + .statesize = sizeof(struct sha3_state), + .base = { + .cra_name = "sha3-384", + .cra_driver_name = "sha3-384-s390", + .cra_priority = 300, + .cra_blocksize = SHA3_384_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct s390_sha_ctx), + .cra_module = THIS_MODULE, + } +}; + +MODULE_ALIAS_CRYPTO("sha3-384"); + +static int __init init(void) +{ + int ret; + + if (!cpacf_query_func(CPACF_KIMD, CPACF_KIMD_SHA3_512)) + return -ENODEV; + ret = crypto_register_shash(&sha3_512_alg); + if (ret < 0) + goto out; + ret = crypto_register_shash(&sha3_384_alg); + if (ret < 0) + crypto_unregister_shash(&sha3_512_alg); +out: + return ret; +} + +static void __exit fini(void) +{ + crypto_unregister_shash(&sha3_512_alg); + crypto_unregister_shash(&sha3_384_alg); +} + +module_cpu_feature_match(MSA, init); +module_exit(fini); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("SHA3-512 and SHA3-384 Secure Hash Algorithm"); diff --git a/arch/s390/crypto/sha_common.c b/arch/s390/crypto/sha_common.c index cf0718d121bc..d39e0f079217 100644 --- a/arch/s390/crypto/sha_common.c +++ b/arch/s390/crypto/sha_common.c @@ -20,7 +20,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) unsigned int index, n; /* how much is already in the buffer? */ - index = ctx->count & (bsize - 1); + index = ctx->count % bsize; ctx->count += len; if ((index + len) < bsize) @@ -37,7 +37,7 @@ int s390_sha_update(struct shash_desc *desc, const u8 *data, unsigned int len) /* process as many blocks as possible */ if (len >= bsize) { - n = len & ~(bsize - 1); + n = (len / bsize) * bsize; cpacf_kimd(ctx->func, ctx->state, data, n); data += n; len -= n; @@ -50,34 +50,63 @@ store: } EXPORT_SYMBOL_GPL(s390_sha_update); +static int s390_crypto_shash_parmsize(int func) +{ + switch (func) { + case CPACF_KLMD_SHA_1: + return 20; + case CPACF_KLMD_SHA_256: + return 32; + case CPACF_KLMD_SHA_512: + return 64; + case CPACF_KLMD_SHA3_224: + case CPACF_KLMD_SHA3_256: + case CPACF_KLMD_SHA3_384: + case CPACF_KLMD_SHA3_512: + return 200; + default: + return -EINVAL; + } +} + int s390_sha_final(struct shash_desc *desc, u8 *out) { struct s390_sha_ctx *ctx = shash_desc_ctx(desc); unsigned int bsize = crypto_shash_blocksize(desc->tfm); u64 bits; - unsigned int index, end, plen; - - /* SHA-512 uses 128 bit padding length */ - plen = (bsize > SHA256_BLOCK_SIZE) ? 16 : 8; + unsigned int n, mbl_offset; - /* must perform manual padding */ - index = ctx->count & (bsize - 1); - end = (index < bsize - plen) ? bsize : (2 * bsize); - - /* start pad with 1 */ - ctx->buf[index] = 0x80; - index++; - - /* pad with zeros */ - memset(ctx->buf + index, 0x00, end - index - 8); - - /* - * Append message length. Well, SHA-512 wants a 128 bit length value, - * nevertheless we use u64, should be enough for now... - */ + n = ctx->count % bsize; bits = ctx->count * 8; - memcpy(ctx->buf + end - 8, &bits, sizeof(bits)); - cpacf_kimd(ctx->func, ctx->state, ctx->buf, end); + mbl_offset = s390_crypto_shash_parmsize(ctx->func) / sizeof(u32); + if (mbl_offset < 0) + return -EINVAL; + + /* set total msg bit length (mbl) in CPACF parmblock */ + switch (ctx->func) { + case CPACF_KLMD_SHA_1: + case CPACF_KLMD_SHA_256: + memcpy(ctx->state + mbl_offset, &bits, sizeof(bits)); + break; + case CPACF_KLMD_SHA_512: + /* + * the SHA512 parmblock has a 128-bit mbl field, clear + * high-order u64 field, copy bits to low-order u64 field + */ + memset(ctx->state + mbl_offset, 0x00, sizeof(bits)); + mbl_offset += sizeof(u64) / sizeof(u32); + memcpy(ctx->state + mbl_offset, &bits, sizeof(bits)); + break; + case CPACF_KLMD_SHA3_224: + case CPACF_KLMD_SHA3_256: + case CPACF_KLMD_SHA3_384: + case CPACF_KLMD_SHA3_512: + break; + default: + return -EINVAL; + } + + cpacf_klmd(ctx->func, ctx->state, ctx->buf, n); /* copy digest to out */ memcpy(out, ctx->state, crypto_shash_digestsize(desc->tfm)); diff --git a/arch/s390/include/asm/cpacf.h b/arch/s390/include/asm/cpacf.h index e3d53eb6bcf5..a092f63aac6a 100644 --- a/arch/s390/include/asm/cpacf.h +++ b/arch/s390/include/asm/cpacf.h @@ -93,6 +93,10 @@ #define CPACF_KIMD_SHA_1 0x01 #define CPACF_KIMD_SHA_256 0x02 #define CPACF_KIMD_SHA_512 0x03 +#define CPACF_KIMD_SHA3_224 0x20 +#define CPACF_KIMD_SHA3_256 0x21 +#define CPACF_KIMD_SHA3_384 0x22 +#define CPACF_KIMD_SHA3_512 0x23 #define CPACF_KIMD_GHASH 0x41 /* @@ -103,6 +107,10 @@ #define CPACF_KLMD_SHA_1 0x01 #define CPACF_KLMD_SHA_256 0x02 #define CPACF_KLMD_SHA_512 0x03 +#define CPACF_KLMD_SHA3_224 0x20 +#define CPACF_KLMD_SHA3_256 0x21 +#define CPACF_KLMD_SHA3_384 0x22 +#define CPACF_KLMD_SHA3_512 0x23 /* * function codes for the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 603413f28fa3..d7c85c79094b 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -145,6 +145,26 @@ config CRYPTO_SHA512_S390 It is available as of z10. +config CRYPTO_SHA3_256_S390 + tristate "SHA3_224 and SHA3_256 digest algorithm" + depends on S390 + select CRYPTO_HASH + help + This is the s390 hardware accelerated implementation of the + SHA3_256 secure hash standard. + + It is available as of z14. + +config CRYPTO_SHA3_512_S390 + tristate "SHA3_384 and SHA3_512 digest algorithm" + depends on S390 + select CRYPTO_HASH + help + This is the s390 hardware accelerated implementation of the + SHA3_512 secure hash standard. + + It is available as of z14. + config CRYPTO_DES_S390 tristate "DES and Triple DES cipher algorithms" depends on S390 -- cgit v1.2.3 From a0e2251132995b962281aa80ab54a9288f9e0b6b Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 6 Feb 2019 08:22:11 +0100 Subject: s390: add support for IBM z15 machines Add detection for machine types 0x8562 and 8x8561 and set the ELF platform name to z15. Add the miscellaneous-instruction-extension 3 facility to the list of facilities for z15. And allow to generate code that only runs on a z15 machine. Reviewed-by: Christian Borntraeger Signed-off-by: Martin Schwidefsky Signed-off-by: Heiko Carstens --- arch/s390/Kconfig | 18 ++++++++++++++++++ arch/s390/Makefile | 2 ++ arch/s390/kernel/setup.c | 4 ++++ arch/s390/tools/gen_facilities.c | 3 +++ 4 files changed, 27 insertions(+) diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 3289cc243d92..8c5b05d91106 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -237,6 +237,10 @@ config HAVE_MARCH_Z14_FEATURES def_bool n select HAVE_MARCH_Z13_FEATURES +config HAVE_MARCH_Z15_FEATURES + def_bool n + select HAVE_MARCH_Z14_FEATURES + choice prompt "Processor type" default MARCH_Z196 @@ -308,6 +312,14 @@ config MARCH_Z14 and 3906 series). The kernel will be slightly faster but will not work on older machines. +config MARCH_Z15 + bool "IBM z15" + select HAVE_MARCH_Z15_FEATURES + help + Select this to enable optimizations for IBM z15 (8562 + and 8561 series). The kernel will be slightly faster but will not + work on older machines. + endchoice config MARCH_Z900_TUNE @@ -334,6 +346,9 @@ config MARCH_Z13_TUNE config MARCH_Z14_TUNE def_bool TUNE_Z14 || MARCH_Z14 && TUNE_DEFAULT +config MARCH_Z15_TUNE + def_bool TUNE_Z15 || MARCH_Z15 && TUNE_DEFAULT + choice prompt "Tune code generation" default TUNE_DEFAULT @@ -378,6 +393,9 @@ config TUNE_Z13 config TUNE_Z14 bool "IBM z14" +config TUNE_Z15 + bool "IBM z15" + endchoice config 64BIT diff --git a/arch/s390/Makefile b/arch/s390/Makefile index e0bab7ed4123..478b645b20dd 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile @@ -45,6 +45,7 @@ mflags-$(CONFIG_MARCH_Z196) := -march=z196 mflags-$(CONFIG_MARCH_ZEC12) := -march=zEC12 mflags-$(CONFIG_MARCH_Z13) := -march=z13 mflags-$(CONFIG_MARCH_Z14) := -march=z14 +mflags-$(CONFIG_MARCH_Z15) := -march=z15 export CC_FLAGS_MARCH := $(mflags-y) @@ -59,6 +60,7 @@ cflags-$(CONFIG_MARCH_Z196_TUNE) += -mtune=z196 cflags-$(CONFIG_MARCH_ZEC12_TUNE) += -mtune=zEC12 cflags-$(CONFIG_MARCH_Z13_TUNE) += -mtune=z13 cflags-$(CONFIG_MARCH_Z14_TUNE) += -mtune=z14 +cflags-$(CONFIG_MARCH_Z15_TUNE) += -mtune=z15 cflags-y += -Wa,-I$(srctree)/arch/$(ARCH)/include diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 3e4b4a48a597..f63a9f378b37 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -981,6 +981,10 @@ static int __init setup_hwcaps(void) case 0x3907: strcpy(elf_platform, "z14"); break; + case 0x8561: + case 0x8562: + strcpy(elf_platform, "z15"); + break; } /* diff --git a/arch/s390/tools/gen_facilities.c b/arch/s390/tools/gen_facilities.c index cead9e0dcffb..61ce5b59b828 100644 --- a/arch/s390/tools/gen_facilities.c +++ b/arch/s390/tools/gen_facilities.c @@ -57,6 +57,9 @@ static struct facility_def facility_defs[] = { #endif #ifdef CONFIG_HAVE_MARCH_Z14_FEATURES 58, /* miscellaneous-instruction-extension 2 */ +#endif +#ifdef CONFIG_HAVE_MARCH_Z15_FEATURES + 61, /* miscellaneous-instruction-extension 3 */ #endif -1 /* END */ } -- cgit v1.2.3 From cf2c4a3f35b75d38cebb4afbd578f1594f068d1e Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Tue, 10 Sep 2019 15:45:04 +0200 Subject: s390/pci: fix MSI message data After recent changes the MSI message data needs to specify the function-relative IRQ number. Reported-and-tested-by: Alexander Schmidt Signed-off-by: Sebastian Ott Signed-off-by: Vasily Gorbik --- arch/s390/pci/pci_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/s390/pci/pci_irq.c b/arch/s390/pci/pci_irq.c index d80616ae8dd8..fbe97ab2e228 100644 --- a/arch/s390/pci/pci_irq.c +++ b/arch/s390/pci/pci_irq.c @@ -284,7 +284,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) return rc; irq_set_chip_and_handler(irq, &zpci_irq_chip, handle_percpu_irq); - msg.data = hwirq; + msg.data = hwirq - bit; if (irq_delivery == DIRECTED) { msg.address_lo = zdev->msi_addr & 0xff0000ff; msg.address_lo |= msi->affinity ? -- cgit v1.2.3 From 03e9e42f7981b3ebc17b30e4c8ce19b40d143f94 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Tue, 16 Apr 2019 09:36:26 +0000 Subject: s390/cpum_sf: Fix line length and format string Rewrite some lines to match line length and replace format string 0x%x to %#x. Add and remove blank line. Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Signed-off-by: Vasily Gorbik --- arch/s390/kernel/perf_cpum_sf.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/arch/s390/kernel/perf_cpum_sf.c b/arch/s390/kernel/perf_cpum_sf.c index 1266194afb02..292a452cd1f3 100644 --- a/arch/s390/kernel/perf_cpum_sf.c +++ b/arch/s390/kernel/perf_cpum_sf.c @@ -514,7 +514,6 @@ static void extend_sampling_buffer(struct sf_buffer *sfb, sfb_pending_allocs(sfb, hwc)); } - /* Number of perf events counting hardware events */ static atomic_t num_events; /* Used to avoid races in calling reserve/release_cpumf_hardware */ @@ -923,9 +922,10 @@ static void cpumsf_pmu_enable(struct pmu *pmu) lpp(&S390_lowcore.lpp); debug_sprintf_event(sfdbg, 6, "pmu_enable: es=%i cs=%i ed=%i cd=%i " - "tear=%p dear=%p\n", cpuhw->lsctl.es, cpuhw->lsctl.cs, - cpuhw->lsctl.ed, cpuhw->lsctl.cd, - (void *) cpuhw->lsctl.tear, (void *) cpuhw->lsctl.dear); + "tear=%p dear=%p\n", cpuhw->lsctl.es, + cpuhw->lsctl.cs, cpuhw->lsctl.ed, cpuhw->lsctl.cd, + (void *) cpuhw->lsctl.tear, + (void *) cpuhw->lsctl.dear); } static void cpumsf_pmu_disable(struct pmu *pmu) @@ -1083,7 +1083,8 @@ static void debug_sample_entry(struct hws_basic_entry *sample, struct hws_trailer_entry *te) { debug_sprintf_event(sfdbg, 4, "hw_collect_samples: Found unknown " - "sampling data entry: te->f=%i basic.def=%04x (%p)\n", + "sampling data entry: te->f=%i basic.def=%04x " + "(%p)\n", te->f, sample->def, sample); } @@ -1216,7 +1217,7 @@ static void hw_perf_event_update(struct perf_event *event, int flush_all) /* Timestamps are valid for full sample-data-blocks only */ debug_sprintf_event(sfdbg, 6, "hw_perf_event_update: sdbt=%p " - "overflow=%llu timestamp=0x%llx\n", + "overflow=%llu timestamp=%#llx\n", sdbt, te->overflow, (te->f) ? trailer_timestamp(te) : 0ULL); @@ -1879,10 +1880,12 @@ static struct attribute_group cpumsf_pmu_events_group = { .name = "events", .attrs = cpumsf_pmu_events_attr, }; + static struct attribute_group cpumsf_pmu_format_group = { .name = "format", .attrs = cpumsf_pmu_format_attr, }; + static const struct attribute_group *cpumsf_pmu_attr_groups[] = { &cpumsf_pmu_events_group, &cpumsf_pmu_format_group, @@ -1938,7 +1941,8 @@ static void cpumf_measurement_alert(struct ext_code ext_code, /* Report measurement alerts only for non-PRA codes */ if (alert != CPU_MF_INT_SF_PRA) - debug_sprintf_event(sfdbg, 6, "measurement alert: 0x%x\n", alert); + debug_sprintf_event(sfdbg, 6, "measurement alert: %#x\n", + alert); /* Sampling authorization change request */ if (alert & CPU_MF_INT_SF_SACA) @@ -1959,6 +1963,7 @@ static void cpumf_measurement_alert(struct ext_code ext_code, sf_disable(); } } + static int cpusf_pmu_setup(unsigned int cpu, int flags) { /* Ignore the notification if no events are scheduled on the PMU. @@ -2096,5 +2101,6 @@ static int __init init_cpum_sampling_pmu(void) out: return err; } + arch_initcall(init_cpum_sampling_pmu); core_param(cpum_sfb_size, CPUM_SF_MAX_SDB, sfb_size, 0640); -- cgit v1.2.3 From 2735913c1079b7dd7ec1d746c13a84ec1b5ea276 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 12 Sep 2019 14:23:54 +0900 Subject: s390: remove pointless drivers-y in drivers/s390/Makefile This is unused. Signed-off-by: Masahiro Yamada Signed-off-by: Vasily Gorbik --- drivers/s390/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/s390/Makefile b/drivers/s390/Makefile index a863b0462b43..cde73b6a9afb 100644 --- a/drivers/s390/Makefile +++ b/drivers/s390/Makefile @@ -4,6 +4,3 @@ # obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/ - -drivers-y += drivers/s390/built-in.a - -- cgit v1.2.3