root/arch/s390/boot/ipl_report.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intersects
  2. find_bootdata_space
  3. copy_components_bootdata
  4. copy_certificates_bootdata
  5. read_ipl_report

   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 }

/* [<][>][^][v][top][bottom][index][help] */