Merge tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Vasily Gorbik: - Add support for IBM z15 machines. - Add SHA3 and CCA AES cipher key support in zcrypt and pkey refactoring. - Move to arch_stack_walk infrastructure for the stack unwinder. - Various kasan fixes and improvements. - Various command line parsing fixes. - Improve decompressor phase debuggability. - Lift no bss usage restriction for the early code. - Use refcount_t for reference counters for couple of places in mm code. - Logging improvements and return code fix in vfio-ccw code. - Couple of zpci fixes and minor refactoring. - Remove some outdated documentation. - Fix secure boot detection. - Other various minor code clean ups. * tag 's390-5.4-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (48 commits) s390: remove pointless drivers-y in drivers/s390/Makefile s390/cpum_sf: Fix line length and format string s390/pci: fix MSI message data s390: add support for IBM z15 machines s390/crypto: Support for SHA3 via CPACF (MSA6) s390/startup: add pgm check info printing s390/crypto: xts-aes-s390 fix extra run-time crypto self tests finding vfio-ccw: fix error return code in vfio_ccw_sch_init() s390: vfio-ap: fix warning reset not completed s390/base: remove unused s390_base_mcck_handler s390/sclp: Fix bit checked for has_sipl s390/zcrypt: fix wrong handling of cca cipher keygenflags s390/kasan: add kdump support s390/setup: avoid using strncmp with hardcoded length s390/sclp: avoid using strncmp with hardcoded length s390/module: avoid using strncmp with hardcoded length s390/pci: avoid using strncmp with hardcoded length s390/kaslr: reserve memory for kasan usage s390/mem_detect: provide single get_mem_detect_end s390/cmma: reuse kstrtobool for option value parsing ...
This commit is contained in:
@@ -4,6 +4,3 @@
|
||||
#
|
||||
|
||||
obj-y += cio/ block/ char/ crypto/ net/ scsi/ virtio/
|
||||
|
||||
drivers-y += drivers/s390/built-in.a
|
||||
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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,27 +272,64 @@ 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,
|
||||
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);
|
||||
@@ -298,6 +344,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 +355,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);
|
||||
|
@@ -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);
|
||||
|
@@ -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))
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <linux/eventfd.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/vfio_ccw.h>
|
||||
#include <asm/debug.h>
|
||||
|
||||
#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
|
||||
|
@@ -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
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -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:
|
||||
|
@@ -35,6 +35,7 @@
|
||||
|
||||
#include "zcrypt_msgtype6.h"
|
||||
#include "zcrypt_msgtype50.h"
|
||||
#include "zcrypt_ccamisc.h"
|
||||
|
||||
/*
|
||||
* Module description.
|
||||
@@ -1160,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;
|
||||
@@ -1874,6 +1903,7 @@ void __exit zcrypt_api_exit(void)
|
||||
misc_deregister(&zcrypt_misc_device);
|
||||
zcrypt_msgtype6_exit();
|
||||
zcrypt_msgtype50_exit();
|
||||
zcrypt_ccamisc_exit();
|
||||
zcrypt_debug_exit();
|
||||
}
|
||||
|
||||
|
@@ -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_ */
|
||||
|
1765
drivers/s390/crypto/zcrypt_ccamisc.c
Normal file
1765
drivers/s390/crypto/zcrypt_ccamisc.c
Normal file
File diff suppressed because it is too large
Load Diff
217
drivers/s390/crypto/zcrypt_ccamisc.h
Normal file
217
drivers/s390/crypto/zcrypt_ccamisc.h
Normal file
@@ -0,0 +1,217 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright IBM Corp. 2019
|
||||
* Author(s): Harald Freudenberger <freude@linux.ibm.com>
|
||||
* Ingo Franzki <ifranzki@linux.ibm.com>
|
||||
*
|
||||
* Collection of CCA misc functions used by zcrypt and pkey
|
||||
*/
|
||||
|
||||
#ifndef _ZCRYPT_CCAMISC_H_
|
||||
#define _ZCRYPT_CCAMISC_H_
|
||||
|
||||
#include <asm/zcrypt.h>
|
||||
#include <asm/pkey.h>
|
||||
|
||||
/* 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 */
|
||||
#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[1];
|
||||
u16 len; /* vlsc token: total length in bytes */
|
||||
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;
|
||||
|
||||
/* 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
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
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 keybitsize,
|
||||
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);
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
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.
|
||||
* Works with CCA AES data and cipher keys.
|
||||
* Returns < 0 on failure, 0 if CURRENT MKVP matches and
|
||||
* 1 if OLD MKVP matches.
|
||||
*/
|
||||
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_* */
|
||||
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_ */
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user