]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
s390/ipl: add helper functions to create an IPL report
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 25 Feb 2019 16:23:39 +0000 (17:23 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 26 Apr 2019 10:34:05 +0000 (12:34 +0200)
PR: Adjusted to the use in kexec_file later.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/ipl.h
arch/s390/kernel/ipl.c

index 878f6fd5f2e74dc7c18b26fafbbee6b0b06fe017..bf62af49af063799cdfd56fb2dc2d0f925cbdc9c 100644 (file)
@@ -81,6 +81,33 @@ extern struct ipl_info ipl_info;
 extern void setup_ipl(void);
 extern void set_os_info_reipl_block(void);
 
+struct ipl_report {
+       struct ipl_parameter_block *ipib;
+       struct list_head components;
+       struct list_head certificates;
+       size_t size;
+};
+
+struct ipl_report_component {
+       struct list_head list;
+       struct ipl_rb_component_entry entry;
+};
+
+struct ipl_report_certificate {
+       struct list_head list;
+       struct ipl_rb_certificate_entry entry;
+       void *key;
+};
+
+struct kexec_buf;
+struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib);
+void *ipl_report_finish(struct ipl_report *report);
+int ipl_report_free(struct ipl_report *report);
+int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
+                            unsigned char flags, unsigned short cert);
+int ipl_report_add_certificate(struct ipl_report *report, void *key,
+                              unsigned long addr, unsigned long len);
+
 /*
  * DIAG 308 support
  */
index 0567de4005b4290f1911ac62418f9e6c6e8a6bd9..6f2bb64cf70ea888e58af1cdb63b5690a48c52f9 100644 (file)
@@ -1705,3 +1705,137 @@ void s390_reset_system(void)
        __ctl_clear_bit(0, 28);
        diag308_reset();
 }
+
+#ifdef CONFIG_KEXEC_FILE
+
+int ipl_report_add_component(struct ipl_report *report, struct kexec_buf *kbuf,
+                            unsigned char flags, unsigned short cert)
+{
+       struct ipl_report_component *comp;
+
+       comp = vzalloc(sizeof(*comp));
+       if (!comp)
+               return -ENOMEM;
+       list_add_tail(&comp->list, &report->components);
+
+       comp->entry.addr = kbuf->mem;
+       comp->entry.len = kbuf->memsz;
+       comp->entry.flags = flags;
+       comp->entry.certificate_index = cert;
+
+       report->size += sizeof(comp->entry);
+
+       return 0;
+}
+
+int ipl_report_add_certificate(struct ipl_report *report, void *key,
+                              unsigned long addr, unsigned long len)
+{
+       struct ipl_report_certificate *cert;
+
+       cert = vzalloc(sizeof(*cert));
+       if (!cert)
+               return -ENOMEM;
+       list_add_tail(&cert->list, &report->certificates);
+
+       cert->entry.addr = addr;
+       cert->entry.len = len;
+       cert->key = key;
+
+       report->size += sizeof(cert->entry);
+       report->size += cert->entry.len;
+
+       return 0;
+}
+
+struct ipl_report *ipl_report_init(struct ipl_parameter_block *ipib)
+{
+       struct ipl_report *report;
+
+       report = vzalloc(sizeof(*report));
+       if (!report)
+               return ERR_PTR(-ENOMEM);
+
+       report->ipib = ipib;
+       INIT_LIST_HEAD(&report->components);
+       INIT_LIST_HEAD(&report->certificates);
+
+       report->size = ALIGN(ipib->hdr.len, 8);
+       report->size += sizeof(struct ipl_rl_hdr);
+       report->size += sizeof(struct ipl_rb_components);
+       report->size += sizeof(struct ipl_rb_certificates);
+
+       return report;
+}
+
+void *ipl_report_finish(struct ipl_report *report)
+{
+       struct ipl_report_certificate *cert;
+       struct ipl_report_component *comp;
+       struct ipl_rb_certificates *certs;
+       struct ipl_parameter_block *ipib;
+       struct ipl_rb_components *comps;
+       struct ipl_rl_hdr *rl_hdr;
+       void *buf, *ptr;
+
+       buf = vzalloc(report->size);
+       if (!buf)
+               return ERR_PTR(-ENOMEM);
+       ptr = buf;
+
+       memcpy(ptr, report->ipib, report->ipib->hdr.len);
+       ipib = ptr;
+       if (ipl_secure_flag)
+               ipib->hdr.flags |= IPL_PL_FLAG_SIPL;
+       ipib->hdr.flags |= IPL_PL_FLAG_IPLSR;
+       ptr += report->ipib->hdr.len;
+       ptr = PTR_ALIGN(ptr, 8);
+
+       rl_hdr = ptr;
+       ptr += sizeof(*rl_hdr);
+
+       comps = ptr;
+       comps->rbt = IPL_RBT_COMPONENTS;
+       ptr += sizeof(*comps);
+       list_for_each_entry(comp, &report->components, list) {
+               memcpy(ptr, &comp->entry, sizeof(comp->entry));
+               ptr += sizeof(comp->entry);
+       }
+       comps->len = ptr - (void *)comps;
+
+       certs = ptr;
+       certs->rbt = IPL_RBT_CERTIFICATES;
+       ptr += sizeof(*certs);
+       list_for_each_entry(cert, &report->certificates, list) {
+               memcpy(ptr, &cert->entry, sizeof(cert->entry));
+               ptr += sizeof(cert->entry);
+       }
+       certs->len = ptr - (void *)certs;
+       rl_hdr->len = ptr - (void *)rl_hdr;
+
+       list_for_each_entry(cert, &report->certificates, list) {
+               memcpy(ptr, cert->key, cert->entry.len);
+               ptr += cert->entry.len;
+       }
+
+       BUG_ON(ptr > buf + report->size);
+       return buf;
+}
+
+int ipl_report_free(struct ipl_report *report)
+{
+       struct ipl_report_component *comp, *ncomp;
+       struct ipl_report_certificate *cert, *ncert;
+
+       list_for_each_entry_safe(comp, ncomp, &report->components, list)
+               vfree(comp);
+
+       list_for_each_entry_safe(cert, ncert, &report->certificates, list)
+               vfree(cert);
+
+       vfree(report);
+
+       return 0;
+}
+
+#endif