0001
0002 #include <linux/init.h>
0003 #include <linux/ctype.h>
0004 #include <asm/ebcdic.h>
0005 #include <asm/sclp.h>
0006 #include <asm/sections.h>
0007 #include <asm/boot_data.h>
0008 #include <uapi/asm/ipl.h>
0009 #include "boot.h"
0010
0011 int __bootdata_preserved(ipl_secure_flag);
0012
0013 unsigned long __bootdata_preserved(ipl_cert_list_addr);
0014 unsigned long __bootdata_preserved(ipl_cert_list_size);
0015
0016 unsigned long __bootdata(early_ipl_comp_list_addr);
0017 unsigned long __bootdata(early_ipl_comp_list_size);
0018
0019 #define for_each_rb_entry(entry, rb) \
0020 for (entry = rb->entries; \
0021 (void *) entry + sizeof(*entry) <= (void *) rb + rb->len; \
0022 entry++)
0023
0024 static inline bool intersects(unsigned long addr0, unsigned long size0,
0025 unsigned long addr1, unsigned long size1)
0026 {
0027 return addr0 + size0 > addr1 && addr1 + size1 > addr0;
0028 }
0029
0030 static unsigned long find_bootdata_space(struct ipl_rb_components *comps,
0031 struct ipl_rb_certificates *certs,
0032 unsigned long safe_addr)
0033 {
0034 struct ipl_rb_certificate_entry *cert;
0035 struct ipl_rb_component_entry *comp;
0036 size_t size;
0037
0038
0039
0040
0041 early_ipl_comp_list_size = 0;
0042 for_each_rb_entry(comp, comps)
0043 early_ipl_comp_list_size += sizeof(*comp);
0044 ipl_cert_list_size = 0;
0045 for_each_rb_entry(cert, certs)
0046 ipl_cert_list_size += sizeof(unsigned int) + cert->len;
0047 size = ipl_cert_list_size + early_ipl_comp_list_size;
0048
0049
0050
0051
0052
0053
0054
0055
0056 repeat:
0057 if (IS_ENABLED(CONFIG_BLK_DEV_INITRD) && initrd_data.start && initrd_data.size &&
0058 intersects(initrd_data.start, initrd_data.size, safe_addr, size))
0059 safe_addr = initrd_data.start + initrd_data.size;
0060 for_each_rb_entry(comp, comps)
0061 if (intersects(safe_addr, size, comp->addr, comp->len)) {
0062 safe_addr = comp->addr + comp->len;
0063 goto repeat;
0064 }
0065 for_each_rb_entry(cert, certs)
0066 if (intersects(safe_addr, size, cert->addr, cert->len)) {
0067 safe_addr = cert->addr + cert->len;
0068 goto repeat;
0069 }
0070 early_ipl_comp_list_addr = safe_addr;
0071 ipl_cert_list_addr = safe_addr + early_ipl_comp_list_size;
0072
0073 return safe_addr + size;
0074 }
0075
0076 static void copy_components_bootdata(struct ipl_rb_components *comps)
0077 {
0078 struct ipl_rb_component_entry *comp, *ptr;
0079
0080 ptr = (struct ipl_rb_component_entry *) early_ipl_comp_list_addr;
0081 for_each_rb_entry(comp, comps)
0082 memcpy(ptr++, comp, sizeof(*ptr));
0083 }
0084
0085 static void copy_certificates_bootdata(struct ipl_rb_certificates *certs)
0086 {
0087 struct ipl_rb_certificate_entry *cert;
0088 void *ptr;
0089
0090 ptr = (void *) ipl_cert_list_addr;
0091 for_each_rb_entry(cert, certs) {
0092 *(unsigned int *) ptr = cert->len;
0093 ptr += sizeof(unsigned int);
0094 memcpy(ptr, (void *) cert->addr, cert->len);
0095 ptr += cert->len;
0096 }
0097 }
0098
0099 unsigned long read_ipl_report(unsigned long safe_addr)
0100 {
0101 struct ipl_rb_certificates *certs;
0102 struct ipl_rb_components *comps;
0103 struct ipl_pl_hdr *pl_hdr;
0104 struct ipl_rl_hdr *rl_hdr;
0105 struct ipl_rb_hdr *rb_hdr;
0106 unsigned long tmp;
0107 void *rl_end;
0108
0109
0110
0111
0112
0113 if (!ipl_block_valid ||
0114 !(ipl_block.hdr.flags & IPL_PL_FLAG_IPLSR))
0115 return safe_addr;
0116 ipl_secure_flag = !!(ipl_block.hdr.flags & IPL_PL_FLAG_SIPL);
0117
0118
0119
0120
0121
0122
0123 tmp = (unsigned long) S390_lowcore.ipl_parmblock_ptr;
0124 pl_hdr = (struct ipl_pl_hdr *) tmp;
0125 tmp = (tmp + pl_hdr->len + 7) & -8UL;
0126 rl_hdr = (struct ipl_rl_hdr *) tmp;
0127
0128 certs = NULL;
0129 comps = NULL;
0130 rl_end = (void *) rl_hdr + rl_hdr->len;
0131 rb_hdr = (void *) rl_hdr + sizeof(*rl_hdr);
0132 while ((void *) rb_hdr + sizeof(*rb_hdr) < rl_end &&
0133 (void *) rb_hdr + rb_hdr->len <= rl_end) {
0134
0135 switch (rb_hdr->rbt) {
0136 case IPL_RBT_CERTIFICATES:
0137 certs = (struct ipl_rb_certificates *) rb_hdr;
0138 break;
0139 case IPL_RBT_COMPONENTS:
0140 comps = (struct ipl_rb_components *) rb_hdr;
0141 break;
0142 default:
0143 break;
0144 }
0145
0146 rb_hdr = (void *) rb_hdr + rb_hdr->len;
0147 }
0148
0149
0150
0151
0152
0153 if (!comps || !certs)
0154 return safe_addr;
0155
0156
0157
0158
0159
0160 safe_addr = find_bootdata_space(comps, certs, safe_addr);
0161 copy_components_bootdata(comps);
0162 copy_certificates_bootdata(certs);
0163
0164 return safe_addr;
0165 }