Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/init.h>
  3#include <linux/ctype.h>
  4#include <asm/ebcdic.h>
  5#include <asm/sclp.h>
  6#include <asm/sections.h>
  7#include <asm/boot_data.h>
  8#include <asm/physmem_info.h>
  9#include <uapi/asm/ipl.h>
 10#include "boot.h"
 11
 12int __bootdata_preserved(ipl_secure_flag);
 13
 14unsigned long __bootdata_preserved(ipl_cert_list_addr);
 15unsigned long __bootdata_preserved(ipl_cert_list_size);
 16
 17unsigned long __bootdata(early_ipl_comp_list_addr);
 18unsigned long __bootdata(early_ipl_comp_list_size);
 19
 20static struct ipl_rb_certificates *certs;
 21static struct ipl_rb_components *comps;
 22static bool ipl_report_needs_saving;
 23
 24#define for_each_rb_entry(entry, rb) \
 25	for (entry = rb->entries; \
 26	     (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \
 27	     entry++)
 28
 29static unsigned long get_cert_comp_list_size(void)
 30{
 31	struct ipl_rb_certificate_entry *cert;
 32	struct ipl_rb_component_entry *comp;
 33	size_t size;
 34
 35	/*
 36	 * Find the length for the IPL report boot data
 37	 */
 38	early_ipl_comp_list_size = 0;
 39	for_each_rb_entry(comp, comps)
 40		early_ipl_comp_list_size += sizeof(*comp);
 41	ipl_cert_list_size = 0;
 42	for_each_rb_entry(cert, certs)
 43		ipl_cert_list_size += sizeof(unsigned int) + cert->len;
 44	return ipl_cert_list_size + early_ipl_comp_list_size;
 45}
 46
 47bool ipl_report_certs_intersects(unsigned long addr, unsigned long size,
 48				 unsigned long *intersection_start)
 49{
 50	struct ipl_rb_certificate_entry *cert;
 51
 52	if (!ipl_report_needs_saving)
 53		return false;
 54
 55	for_each_rb_entry(cert, certs) {
 56		if (intersects(addr, size, cert->addr, cert->len)) {
 57			*intersection_start = cert->addr;
 58			return true;
 59		}
 60	}
 61	return false;
 62}
 63
 64static void copy_components_bootdata(void)
 65{
 66	struct ipl_rb_component_entry *comp, *ptr;
 67
 68	ptr = (struct ipl_rb_component_entry *) early_ipl_comp_list_addr;
 69	for_each_rb_entry(comp, comps)
 70		memcpy(ptr++, comp, sizeof(*ptr));
 71}
 72
 73static void copy_certificates_bootdata(void)
 74{
 75	struct ipl_rb_certificate_entry *cert;
 76	void *ptr;
 77
 78	ptr = (void *) ipl_cert_list_addr;
 79	for_each_rb_entry(cert, certs) {
 80		*(unsigned int *) ptr = cert->len;
 81		ptr += sizeof(unsigned int);
 82		memcpy(ptr, (void *) cert->addr, cert->len);
 83		ptr += cert->len;
 84	}
 85}
 86
 87int read_ipl_report(void)
 88{
 89	struct ipl_pl_hdr *pl_hdr;
 90	struct ipl_rl_hdr *rl_hdr;
 91	struct ipl_rb_hdr *rb_hdr;
 92	unsigned long tmp;
 93	void *rl_end;
 94
 95	/*
 96	 * Check if there is a IPL report by looking at the copy
 97	 * of the IPL parameter information block.
 98	 */
 99	if (!ipl_block_valid ||
100	    !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR))
101		return -1;
102	ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL);
103	/*
104	 * There is an IPL report, to find it load the pointer to the
105	 * IPL parameter information block from lowcore and skip past
106	 * the IPL parameter list, then align the address to a double
107	 * word boundary.
108	 */
109	tmp = (unsigned long)get_lowcore()->ipl_parmblock_ptr;
110	pl_hdr = (struct ipl_pl_hdr *) tmp;
111	tmp = (tmp + pl_hdr->len + 7) & -8UL;
112	rl_hdr = (struct ipl_rl_hdr *) tmp;
113	/* Walk through the IPL report blocks in the IPL Report list */
114	certs = NULL;
115	comps = NULL;
116	rl_end = (void *) rl_hdr + rl_hdr->len;
117	rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr);
118	while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end &&
119	       (void *) rb_hdr + rb_hdr->len <= rl_end) {
120
121		switch (rb_hdr->rbt) {
122		case IPL_RBT_CERTIFICATES:
123			certs = (struct ipl_rb_certificates *) rb_hdr;
124			break;
125		case IPL_RBT_COMPONENTS:
126			comps = (struct ipl_rb_components *) rb_hdr;
127			break;
128		default:
129			break;
130		}
131
132		rb_hdr = (void *) rb_hdr + rb_hdr->len;
133	}
134
135	/*
136	 * With either the component list or the certificate list
137	 * missing the kernel will stay ignorant of secure IPL.
138	 */
139	if (!comps || !certs) {
140		certs = NULL;
141		return -1;
142	}
143
144	ipl_report_needs_saving = true;
145	physmem_reserve(RR_IPLREPORT, (unsigned long)pl_hdr,
146			(unsigned long)rl_end - (unsigned long)pl_hdr);
147	return 0;
148}
149
150void save_ipl_cert_comp_list(void)
151{
152	unsigned long size;
153
154	if (!ipl_report_needs_saving)
155		return;
156
157	size = get_cert_comp_list_size();
158	early_ipl_comp_list_addr = physmem_alloc_top_down(RR_CERT_COMP_LIST, size, sizeof(int));
159	ipl_cert_list_addr = early_ipl_comp_list_addr + early_ipl_comp_list_size;
160
161	copy_components_bootdata();
162	copy_certificates_bootdata();
163	physmem_free(RR_IPLREPORT);
164	ipl_report_needs_saving = false;
165}
v6.8
  1// SPDX-License-Identifier: GPL-2.0
  2#include <linux/init.h>
  3#include <linux/ctype.h>
  4#include <asm/ebcdic.h>
  5#include <asm/sclp.h>
  6#include <asm/sections.h>
  7#include <asm/boot_data.h>
  8#include <asm/physmem_info.h>
  9#include <uapi/asm/ipl.h>
 10#include "boot.h"
 11
 12int __bootdata_preserved(ipl_secure_flag);
 13
 14unsigned long __bootdata_preserved(ipl_cert_list_addr);
 15unsigned long __bootdata_preserved(ipl_cert_list_size);
 16
 17unsigned long __bootdata(early_ipl_comp_list_addr);
 18unsigned long __bootdata(early_ipl_comp_list_size);
 19
 20static struct ipl_rb_certificates *certs;
 21static struct ipl_rb_components *comps;
 22static bool ipl_report_needs_saving;
 23
 24#define for_each_rb_entry(entry, rb) \
 25	for (entry = rb->entries; \
 26	     (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \
 27	     entry++)
 28
 29static unsigned long get_cert_comp_list_size(void)
 30{
 31	struct ipl_rb_certificate_entry *cert;
 32	struct ipl_rb_component_entry *comp;
 33	size_t size;
 34
 35	/*
 36	 * Find the length for the IPL report boot data
 37	 */
 38	early_ipl_comp_list_size = 0;
 39	for_each_rb_entry(comp, comps)
 40		early_ipl_comp_list_size += sizeof(*comp);
 41	ipl_cert_list_size = 0;
 42	for_each_rb_entry(cert, certs)
 43		ipl_cert_list_size += sizeof(unsigned int) + cert->len;
 44	return ipl_cert_list_size + early_ipl_comp_list_size;
 45}
 46
 47bool ipl_report_certs_intersects(unsigned long addr, unsigned long size,
 48				 unsigned long *intersection_start)
 49{
 50	struct ipl_rb_certificate_entry *cert;
 51
 52	if (!ipl_report_needs_saving)
 53		return false;
 54
 55	for_each_rb_entry(cert, certs) {
 56		if (intersects(addr, size, cert->addr, cert->len)) {
 57			*intersection_start = cert->addr;
 58			return true;
 59		}
 60	}
 61	return false;
 62}
 63
 64static void copy_components_bootdata(void)
 65{
 66	struct ipl_rb_component_entry *comp, *ptr;
 67
 68	ptr = (struct ipl_rb_component_entry *) early_ipl_comp_list_addr;
 69	for_each_rb_entry(comp, comps)
 70		memcpy(ptr++, comp, sizeof(*ptr));
 71}
 72
 73static void copy_certificates_bootdata(void)
 74{
 75	struct ipl_rb_certificate_entry *cert;
 76	void *ptr;
 77
 78	ptr = (void *) ipl_cert_list_addr;
 79	for_each_rb_entry(cert, certs) {
 80		*(unsigned int *) ptr = cert->len;
 81		ptr += sizeof(unsigned int);
 82		memcpy(ptr, (void *) cert->addr, cert->len);
 83		ptr += cert->len;
 84	}
 85}
 86
 87int read_ipl_report(void)
 88{
 89	struct ipl_pl_hdr *pl_hdr;
 90	struct ipl_rl_hdr *rl_hdr;
 91	struct ipl_rb_hdr *rb_hdr;
 92	unsigned long tmp;
 93	void *rl_end;
 94
 95	/*
 96	 * Check if there is a IPL report by looking at the copy
 97	 * of the IPL parameter information block.
 98	 */
 99	if (!ipl_block_valid ||
100	    !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR))
101		return -1;
102	ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL);
103	/*
104	 * There is an IPL report, to find it load the pointer to the
105	 * IPL parameter information block from lowcore and skip past
106	 * the IPL parameter list, then align the address to a double
107	 * word boundary.
108	 */
109	tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr;
110	pl_hdr = (struct ipl_pl_hdr *) tmp;
111	tmp = (tmp + pl_hdr->len + 7) & -8UL;
112	rl_hdr = (struct ipl_rl_hdr *) tmp;
113	/* Walk through the IPL report blocks in the IPL Report list */
114	certs = NULL;
115	comps = NULL;
116	rl_end = (void *) rl_hdr + rl_hdr->len;
117	rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr);
118	while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end &&
119	       (void *) rb_hdr + rb_hdr->len <= rl_end) {
120
121		switch (rb_hdr->rbt) {
122		case IPL_RBT_CERTIFICATES:
123			certs = (struct ipl_rb_certificates *) rb_hdr;
124			break;
125		case IPL_RBT_COMPONENTS:
126			comps = (struct ipl_rb_components *) rb_hdr;
127			break;
128		default:
129			break;
130		}
131
132		rb_hdr = (void *) rb_hdr + rb_hdr->len;
133	}
134
135	/*
136	 * With either the component list or the certificate list
137	 * missing the kernel will stay ignorant of secure IPL.
138	 */
139	if (!comps || !certs) {
140		certs = NULL;
141		return -1;
142	}
143
144	ipl_report_needs_saving = true;
145	physmem_reserve(RR_IPLREPORT, (unsigned long)pl_hdr,
146			(unsigned long)rl_end - (unsigned long)pl_hdr);
147	return 0;
148}
149
150void save_ipl_cert_comp_list(void)
151{
152	unsigned long size;
153
154	if (!ipl_report_needs_saving)
155		return;
156
157	size = get_cert_comp_list_size();
158	early_ipl_comp_list_addr = physmem_alloc_top_down(RR_CERT_COMP_LIST, size, sizeof(int));
159	ipl_cert_list_addr = early_ipl_comp_list_addr + early_ipl_comp_list_size;
160
161	copy_components_bootdata();
162	copy_certificates_bootdata();
163	physmem_free(RR_IPLREPORT);
164	ipl_report_needs_saving = false;
165}