diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2019-02-21 08:23:04 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2019-04-26 06:34:05 -0400 |
commit | 9641b8cc733f70a5400aa7e6831de4542c46a94c (patch) | |
tree | 446b0fc5c9e6875da888017debb971eff4d4d4b0 /arch/s390/boot | |
parent | d29af5b7a886033e6a4eb5f0a9a25cd00da63ae8 (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/Makefile | 5 | ||||
-rw-r--r-- | arch/s390/boot/boot.h | 2 | ||||
-rw-r--r-- | arch/s390/boot/ipl_report.c | 165 | ||||
-rw-r--r-- | arch/s390/boot/startup.c | 18 |
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 | ||
29 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char | 29 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char |
30 | 30 | ||
31 | obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o string.o ebcdic.o | 31 | obj-y := head.o als.o startup.o mem_detect.o ipl_parm.o ipl_report.o |
32 | obj-y += sclp_early_core.o mem.o ipl_vmparm.o cmdline.o ctype.o | 32 | obj-y += string.o ebcdic.o sclp_early_core.o mem.o ipl_vmparm.o cmdline.o |
33 | obj-y += ctype.o | ||
33 | obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o | 34 | obj-$(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) += uv.o |
34 | targets := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y) | 35 | targets := bzImage startup.a section_cmp.boot.data section_cmp.boot.preserved.data $(obj-y) |
35 | subdir- := compressed | 36 | subdir- := 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); | |||
10 | void setup_memory_end(void); | 10 | void setup_memory_end(void); |
11 | void print_missing_facilities(void); | 11 | void print_missing_facilities(void); |
12 | 12 | ||
13 | unsigned 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 | |||
11 | int __bootdata_preserved(ipl_secure_flag); | ||
12 | |||
13 | unsigned long __bootdata_preserved(ipl_cert_list_addr); | ||
14 | unsigned long __bootdata_preserved(ipl_cert_list_size); | ||
15 | |||
16 | unsigned long __bootdata(early_ipl_comp_list_addr); | ||
17 | unsigned 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 | |||
24 | static 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 | |||
30 | static 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 | */ | ||
56 | repeat: | ||
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 | |||
76 | static 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 | |||
85 | static 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 | |||
99 | unsigned 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 | ||
28 | static void rescue_initrd(void) | 28 | static 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 | ||
43 | static void copy_bootdata(void) | 40 | static void copy_bootdata(void) |
@@ -52,12 +49,15 @@ static void copy_bootdata(void) | |||
52 | 49 | ||
53 | void startup_kernel(void) | 50 | void 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(); |