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