diff --git a/arch/s390/include/asm/ipl.h b/arch/s390/include/asm/ipl.h index bf62af49af06..420d39ebdc46 100644 --- a/arch/s390/include/asm/ipl.h +++ b/arch/s390/include/asm/ipl.h @@ -36,6 +36,8 @@ struct ipl_parameter_block { #define IPL_MAX_SUPPORTED_VERSION (0) +#define IPL_RB_CERT_UNKNOWN ((unsigned short)-1) + #define DIAG308_VMPARM_SIZE (64) #define DIAG308_SCPDATA_OFFSET offsetof(struct ipl_parameter_block, \ fcp.scp_data) diff --git a/arch/s390/include/asm/kexec.h b/arch/s390/include/asm/kexec.h index 59026899e766..305d3465574f 100644 --- a/arch/s390/include/asm/kexec.h +++ b/arch/s390/include/asm/kexec.h @@ -63,6 +63,8 @@ struct s390_load_data { /* Total size of loaded segments in memory. Used as an offset. */ size_t memsz; + + struct ipl_report *report; }; int s390_verify_sig(const char *kernel, unsigned long kernel_len); diff --git a/arch/s390/kernel/kexec_elf.c b/arch/s390/kernel/kexec_elf.c index 01e45d89b636..6d0635ceddd0 100644 --- a/arch/s390/kernel/kexec_elf.c +++ b/arch/s390/kernel/kexec_elf.c @@ -10,6 +10,7 @@ #include #include #include +#include #include static int kexec_file_add_kernel_elf(struct kimage *image, @@ -50,6 +51,10 @@ static int kexec_file_add_kernel_elf(struct kimage *image, data->parm = buf.buffer + PARMAREA; } + ipl_report_add_component(data->report, &buf, + IPL_RB_COMPONENT_FLAG_SIGNED | + IPL_RB_COMPONENT_FLAG_VERIFIED, + IPL_RB_CERT_UNKNOWN); ret = kexec_add_buffer(&buf); if (ret) return ret; diff --git a/arch/s390/kernel/kexec_image.c b/arch/s390/kernel/kexec_image.c index c378bbac5b35..58318bf89fd9 100644 --- a/arch/s390/kernel/kexec_image.c +++ b/arch/s390/kernel/kexec_image.c @@ -10,6 +10,7 @@ #include #include #include +#include #include static int kexec_file_add_kernel_image(struct kimage *image, @@ -32,6 +33,10 @@ static int kexec_file_add_kernel_image(struct kimage *image, data->parm = image->kernel_buf + PARMAREA; data->memsz += buf.memsz; + ipl_report_add_component(data->report, &buf, + IPL_RB_COMPONENT_FLAG_SIGNED | + IPL_RB_COMPONENT_FLAG_VERIFIED, + IPL_RB_CERT_UNKNOWN); return kexec_add_buffer(&buf); } diff --git a/arch/s390/kernel/machine_kexec_file.c b/arch/s390/kernel/machine_kexec_file.c index e0f6e618e1bf..48cab9600ed9 100644 --- a/arch/s390/kernel/machine_kexec_file.c +++ b/arch/s390/kernel/machine_kexec_file.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -150,9 +151,9 @@ static int kexec_file_add_purgatory(struct kimage *image, ret = kexec_load_purgatory(image, &buf); if (ret) return ret; + data->memsz += buf.memsz; - ret = kexec_file_update_purgatory(image, data); - return ret; + return kexec_file_update_purgatory(image, data); } static int kexec_file_add_initrd(struct kimage *image, @@ -177,7 +178,60 @@ static int kexec_file_add_initrd(struct kimage *image, data->memsz += buf.memsz; ret = kexec_add_buffer(&buf); - return ret; + if (ret) + return ret; + + return ipl_report_add_component(data->report, &buf, 0, 0); +} + +static int kexec_file_add_ipl_report(struct kimage *image, + struct s390_load_data *data) +{ + __u32 *lc_ipl_parmblock_ptr; + unsigned int len, ncerts; + struct kexec_buf buf; + unsigned long addr; + void *ptr, *end; + + buf.image = image; + + data->memsz = ALIGN(data->memsz, PAGE_SIZE); + buf.mem = data->memsz; + if (image->type == KEXEC_TYPE_CRASH) + buf.mem += crashk_res.start; + + ptr = (void *)ipl_cert_list_addr; + end = ptr + ipl_cert_list_size; + ncerts = 0; + while (ptr < end) { + ncerts++; + len = *(unsigned int *)ptr; + ptr += sizeof(len); + ptr += len; + } + + addr = data->memsz + data->report->size; + addr += ncerts * sizeof(struct ipl_rb_certificate_entry); + ptr = (void *)ipl_cert_list_addr; + while (ptr < end) { + len = *(unsigned int *)ptr; + ptr += sizeof(len); + ipl_report_add_certificate(data->report, ptr, addr, len); + addr += len; + ptr += len; + } + + buf.buffer = ipl_report_finish(data->report); + buf.bufsz = data->report->size; + buf.memsz = buf.bufsz; + + data->memsz += buf.memsz; + + lc_ipl_parmblock_ptr = + data->kernel_buf + offsetof(struct lowcore, ipl_parmblock_ptr); + *lc_ipl_parmblock_ptr = (__u32)buf.mem; + + return kexec_add_buffer(&buf); } void *kexec_file_add_components(struct kimage *image, @@ -187,12 +241,18 @@ void *kexec_file_add_components(struct kimage *image, struct s390_load_data data = {0}; int ret; + data.report = ipl_report_init(&ipl_block); + if (IS_ERR(data.report)) + return data.report; + ret = add_kernel(image, &data); if (ret) - return ERR_PTR(ret); + goto out; - if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) - return ERR_PTR(-EINVAL); + if (image->cmdline_buf_len >= ARCH_COMMAND_LINE_SIZE) { + ret = -EINVAL; + goto out; + } memcpy(data.parm->command_line, image->cmdline_buf, image->cmdline_buf_len); @@ -204,12 +264,12 @@ void *kexec_file_add_components(struct kimage *image, if (image->initrd_buf) { ret = kexec_file_add_initrd(image, &data); if (ret) - return ERR_PTR(ret); + goto out; } ret = kexec_file_add_purgatory(image, &data); if (ret) - return ERR_PTR(ret); + goto out; if (data.kernel_mem == 0) { unsigned long restart_psw = 0x0008000080000000UL; @@ -218,7 +278,10 @@ void *kexec_file_add_components(struct kimage *image, image->start = 0; } - return NULL; + ret = kexec_file_add_ipl_report(image, &data); +out: + ipl_report_free(data.report); + return ERR_PTR(ret); } int arch_kexec_apply_relocations_add(struct purgatory_info *pi,