summaryrefslogtreecommitdiffstats
path: root/arch/s390/boot
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2019-02-21 08:23:04 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2019-04-26 06:34:05 -0400
commit9641b8cc733f70a5400aa7e6831de4542c46a94c (patch)
tree446b0fc5c9e6875da888017debb971eff4d4d4b0 /arch/s390/boot
parentd29af5b7a886033e6a4eb5f0a9a25cd00da63ae8 (diff)
s390/ipl: read IPL report at early boot
Read the IPL Report block provided by secure-boot, add the entries of the certificate list to the system key ring and print the list of components. PR: Adjust to Vasilys bootdata_preserved patch set. Preserve ipl_cert_list for later use in kexec_file. 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>
Diffstat (limited to 'arch/s390/boot')
-rw-r--r--arch/s390/boot/Makefile5
-rw-r--r--arch/s390/boot/boot.h2
-rw-r--r--arch/s390/boot/ipl_report.c165
-rw-r--r--arch/s390/boot/startup.c18
4 files changed, 179 insertions, 11 deletions
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile
index a5ae68b2aa84..1f8fd68beae3 100644
--- a/arch/s390/boot/Makefile
+++ b/arch/s390/boot/Makefile
@@ -28,8 +28,9 @@ endif
28 28
29CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char 29CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
30 30
31obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o string.o ebcdic.o 31obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o
32obj-y += sclp_early_core.o mem.o ipl_vmparm.o cmdline.o ctype.o 32obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o
33obj-y += ctype.o
33obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o 34obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o
34targets := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y) 35targets := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y)
35subdir- := compressed 36subdir- := compressed
diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h
index 82bc06346e05..ca395fcff15e 100644
--- a/arch/s390/boot/boot.h
+++ b/arch/s390/boot/boot.h
@@ -10,4 +10,6 @@ void parse_boot_command_line(void);
10void setup_memory_end(void); 10void setup_memory_end(void);
11void print_missing_facilities(void); 11void print_missing_facilities(void);
12 12
13unsigned long read_ipl_report(unsigned long safe_offset);
14
13#endif /* BOOT_BOOT_H */ 15#endif /* BOOT_BOOT_H */
diff --git a/arch/s390/boot/ipl_report.c b/arch/s390/boot/ipl_report.c
new file mode 100644
index 000000000000..0b4965573656
--- /dev/null
+++ b/arch/s390/boot/ipl_report.c
@@ -0,0 +1,165 @@
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 <uapi/asm/ipl.h>
9#include "boot.h"
10
11int __bootdata_preserved(ipl_secure_flag);
12
13unsigned long __bootdata_preserved(ipl_cert_list_addr);
14unsigned long __bootdata_preserved(ipl_cert_list_size);
15
16unsigned long __bootdata(early_ipl_comp_list_addr);
17unsigned long __bootdata(early_ipl_comp_list_size);
18
19#define for_each_rb_entry(entry, rb) \
20 for (entry = rb->entries; \
21 (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \
22 entry++)
23
24static inline bool intersects(unsigned long addr0, unsigned long size0,
25 unsigned long addr1, unsigned long size1)
26{
27 return addr0 + size0 > addr1 && addr1 + size1 > addr0;
28}
29
30static unsigned long find_bootdata_space(struct ipl_rb_components *comps,
31 struct ipl_rb_certificates *certs,
32 unsigned long safe_addr)
33{
34 struct ipl_rb_certificate_entry *cert;
35 struct ipl_rb_component_entry *comp;
36 size_t size;
37
38 /*
39 * Find the length for the IPL report boot data
40 */
41 early_ipl_comp_list_size = 0;
42 for_each_rb_entry(comp, comps)
43 early_ipl_comp_list_size += sizeof(*comp);
44 ipl_cert_list_size = 0;
45 for_each_rb_entry(cert, certs)
46 ipl_cert_list_size += sizeof(unsigned int) + cert->len;
47 size = ipl_cert_list_size + early_ipl_comp_list_size;
48
49 /*
50 * Start from safe_addr to find a free memory area large
51 * enough for the IPL report boot data. This area is used
52 * for ipl_cert_list_addr/ipl_cert_list_size and
53 * early_ipl_comp_list_addr/early_ipl_comp_list_size. It must
54 * not overlap with any component or any certificate.
55 */
56repeat:
57 if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE &&
58 intersects(INITRD_START, INITRD_SIZE, safe_addr, size))
59 safe_addr = INITRD_START + INITRD_SIZE;
60 for_each_rb_entry(comp, comps)
61 if (intersects(safe_addr, size, comp->addr, comp->len)) {
62 safe_addr = comp->addr + comp->len;
63 goto repeat;
64 }
65 for_each_rb_entry(cert, certs)
66 if (intersects(safe_addr, size, cert->addr, cert->len)) {
67 safe_addr = cert->addr + cert->len;
68 goto repeat;
69 }
70 early_ipl_comp_list_addr = safe_addr;
71 ipl_cert_list_addr = safe_addr + early_ipl_comp_list_size;
72
73 return safe_addr + size;
74}
75
76static void copy_components_bootdata(struct ipl_rb_components *comps)
77{
78 struct ipl_rb_component_entry *comp, *ptr;
79
80 ptr = (struct ipl_rb_component_entry *) early_ipl_comp_list_addr;
81 for_each_rb_entry(comp, comps)
82 memcpy(ptr++, comp, sizeof(*ptr));
83}
84
85static void copy_certificates_bootdata(struct ipl_rb_certificates *certs)
86{
87 struct ipl_rb_certificate_entry *cert;
88 void *ptr;
89
90 ptr = (void *) ipl_cert_list_addr;
91 for_each_rb_entry(cert, certs) {
92 *(unsigned int *) ptr = cert->len;
93 ptr += sizeof(unsigned int);
94 memcpy(ptr, (void *) cert->addr, cert->len);
95 ptr += cert->len;
96 }
97}
98
99unsigned long read_ipl_report(unsigned long safe_addr)
100{
101 struct ipl_rb_certificates *certs;
102 struct ipl_rb_components *comps;
103 struct ipl_pl_hdr *pl_hdr;
104 struct ipl_rl_hdr *rl_hdr;
105 struct ipl_rb_hdr *rb_hdr;
106 unsigned long tmp;
107 void *rl_end;
108
109 /*
110 * Check if there is a IPL report by looking at the copy
111 * of the IPL parameter information block.
112 */
113 if (!ipl_block_valid ||
114 !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR))
115 return safe_addr;
116 ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL);
117 /*
118 * There is an IPL report, to find it load the pointer to the
119 * IPL parameter information block from lowcore and skip past
120 * the IPL parameter list, then align the address to a double
121 * word boundary.
122 */
123 tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr;
124 pl_hdr = (struct ipl_pl_hdr *) tmp;
125 tmp = (tmp + pl_hdr->len + 7) & -8UL;
126 rl_hdr = (struct ipl_rl_hdr *) tmp;
127 /* Walk through the IPL report blocks in the IPL Report list */
128 certs = NULL;
129 comps = NULL;
130 rl_end = (void *) rl_hdr + rl_hdr->len;
131 rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr);
132 while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end &&
133 (void *) rb_hdr + rb_hdr->len <= rl_end) {
134
135 switch (rb_hdr->rbt) {
136 case IPL_RBT_CERTIFICATES:
137 certs = (struct ipl_rb_certificates *) rb_hdr;
138 break;
139 case IPL_RBT_COMPONENTS:
140 comps = (struct ipl_rb_components *) rb_hdr;
141 break;
142 default:
143 break;
144 }
145
146 rb_hdr = (void *) rb_hdr + rb_hdr->len;
147 }
148
149 /*
150 * With either the component list or the certificate list
151 * missing the kernel will stay ignorant of secure IPL.
152 */
153 if (!comps || !certs)
154 return safe_addr;
155
156 /*
157 * Copy component and certificate list to a safe area
158 * where the decompressed kernel can find them.
159 */
160 safe_addr = find_bootdata_space(comps, certs, safe_addr);
161 copy_components_bootdata(comps);
162 copy_certificates_bootdata(certs);
163
164 return safe_addr;
165}
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c
index 2bd4a62d436c..90898976a941 100644
--- a/arch/s390/boot/startup.c
+++ b/arch/s390/boot/startup.c
@@ -25,19 +25,16 @@ unsigned long mem_safe_offset(void)
25} 25}
26#endif 26#endif
27 27
28static void rescue_initrd(void) 28static void rescue_initrd(unsigned long addr)
29{ 29{
30 unsigned long min_initrd_addr;
31
32 if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD)) 30 if (!IS_ENABLED(CONFIG_BLK_DEV_INITRD))
33 return; 31 return;
34 if (!INITRD_START || !INITRD_SIZE) 32 if (!INITRD_START || !INITRD_SIZE)
35 return; 33 return;
36 min_initrd_addr = mem_safe_offset(); 34 if (addr <= INITRD_START)
37 if (min_initrd_addr <= INITRD_START)
38 return; 35 return;
39 memmove((void *)min_initrd_addr, (void *)INITRD_START, INITRD_SIZE); 36 memmove((void *)addr, (void *)INITRD_START, INITRD_SIZE);
40 INITRD_START = min_initrd_addr; 37 INITRD_START = addr;
41} 38}
42 39
43static void copy_bootdata(void) 40static void copy_bootdata(void)
@@ -52,12 +49,15 @@ static void copy_bootdata(void)
52 49
53void startup_kernel(void) 50void startup_kernel(void)
54{ 51{
52 unsigned long safe_addr;
55 void *img; 53 void *img;
56 54
55 store_ipl_parmblock();
56 safe_addr = mem_safe_offset();
57 safe_addr = read_ipl_report(safe_addr);
57 uv_query_info(); 58 uv_query_info();
58 rescue_initrd(); 59 rescue_initrd(safe_addr);
59 sclp_early_read_info(); 60 sclp_early_read_info();
60 store_ipl_parmblock();
61 setup_boot_command_line(); 61 setup_boot_command_line();
62 parse_boot_command_line(); 62 parse_boot_command_line();
63 setup_memory_end(); 63 setup_memory_end();