Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 937347ac authored by Martin Schwidefsky's avatar Martin Schwidefsky
Browse files

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



PR: Adjusted to the use in kexec_file later.

Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarPhilipp Rudo <prudo@linux.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 9641b8cc
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -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
 */
+134 −0
Original line number Diff line number Diff line
@@ -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