s390/ipl: add helper functions to create an IPL report

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>
This commit is contained in:
Martin Schwidefsky 2019-02-25 17:23:39 +01:00
parent 9641b8cc73
commit 937347ac56
2 changed files with 161 additions and 0 deletions

View 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
*/

View 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