Skip to content

Commit

Permalink
s390/ipl: add helper functions to create an IPL report
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Martin Schwidefsky committed Apr 26, 2019
1 parent 9641b8c commit 937347a
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 0 deletions.
27 changes: 27 additions & 0 deletions arch/s390/include/asm/ipl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down
134 changes: 134 additions & 0 deletions arch/s390/kernel/ipl.c
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 937347a

Please sign in to comment.