root/arch/s390/boot/ipl_parm.c

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

DEFINITIONS

This source file includes following definitions.
  1. __diag308
  2. store_ipl_parmblock
  3. scpdata_length
  4. ipl_block_get_ascii_scpdata
  5. append_ipl_block_parm
  6. has_ebcdic_char
  7. setup_boot_command_line
  8. modify_facility
  9. check_cleared_facilities
  10. modify_fac_list
  11. parse_boot_command_line
  12. setup_memory_end

   1 // SPDX-License-Identifier: GPL-2.0
   2 #include <linux/kernel.h>
   3 #include <linux/init.h>
   4 #include <linux/ctype.h>
   5 #include <asm/ebcdic.h>
   6 #include <asm/sclp.h>
   7 #include <asm/sections.h>
   8 #include <asm/boot_data.h>
   9 #include <asm/facility.h>
  10 #include <asm/pgtable.h>
  11 #include <asm/uv.h>
  12 #include "boot.h"
  13 
  14 char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
  15 struct ipl_parameter_block __bootdata_preserved(ipl_block);
  16 int __bootdata_preserved(ipl_block_valid);
  17 
  18 unsigned long __bootdata(vmalloc_size) = VMALLOC_DEFAULT_SIZE;
  19 unsigned long __bootdata(memory_end);
  20 int __bootdata(memory_end_set);
  21 int __bootdata(noexec_disabled);
  22 
  23 int kaslr_enabled __section(.data);
  24 
  25 static inline int __diag308(unsigned long subcode, void *addr)
  26 {
  27         register unsigned long _addr asm("0") = (unsigned long)addr;
  28         register unsigned long _rc asm("1") = 0;
  29         unsigned long reg1, reg2;
  30         psw_t old = S390_lowcore.program_new_psw;
  31 
  32         asm volatile(
  33                 "       epsw    %0,%1\n"
  34                 "       st      %0,%[psw_pgm]\n"
  35                 "       st      %1,%[psw_pgm]+4\n"
  36                 "       larl    %0,1f\n"
  37                 "       stg     %0,%[psw_pgm]+8\n"
  38                 "       diag    %[addr],%[subcode],0x308\n"
  39                 "1:     nopr    %%r7\n"
  40                 : "=&d" (reg1), "=&a" (reg2),
  41                   [psw_pgm] "=Q" (S390_lowcore.program_new_psw),
  42                   [addr] "+d" (_addr), "+d" (_rc)
  43                 : [subcode] "d" (subcode)
  44                 : "cc", "memory");
  45         S390_lowcore.program_new_psw = old;
  46         return _rc;
  47 }
  48 
  49 void store_ipl_parmblock(void)
  50 {
  51         int rc;
  52 
  53         rc = __diag308(DIAG308_STORE, &ipl_block);
  54         if (rc == DIAG308_RC_OK &&
  55             ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION)
  56                 ipl_block_valid = 1;
  57 }
  58 
  59 static size_t scpdata_length(const u8 *buf, size_t count)
  60 {
  61         while (count) {
  62                 if (buf[count - 1] != '\0' && buf[count - 1] != ' ')
  63                         break;
  64                 count--;
  65         }
  66         return count;
  67 }
  68 
  69 static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
  70                                           const struct ipl_parameter_block *ipb)
  71 {
  72         size_t count;
  73         size_t i;
  74         int has_lowercase;
  75 
  76         count = min(size - 1, scpdata_length(ipb->fcp.scp_data,
  77                                              ipb->fcp.scp_data_len));
  78         if (!count)
  79                 goto out;
  80 
  81         has_lowercase = 0;
  82         for (i = 0; i < count; i++) {
  83                 if (!isascii(ipb->fcp.scp_data[i])) {
  84                         count = 0;
  85                         goto out;
  86                 }
  87                 if (!has_lowercase && islower(ipb->fcp.scp_data[i]))
  88                         has_lowercase = 1;
  89         }
  90 
  91         if (has_lowercase)
  92                 memcpy(dest, ipb->fcp.scp_data, count);
  93         else
  94                 for (i = 0; i < count; i++)
  95                         dest[i] = tolower(ipb->fcp.scp_data[i]);
  96 out:
  97         dest[count] = '\0';
  98         return count;
  99 }
 100 
 101 static void append_ipl_block_parm(void)
 102 {
 103         char *parm, *delim;
 104         size_t len, rc = 0;
 105 
 106         len = strlen(early_command_line);
 107 
 108         delim = early_command_line + len;    /* '\0' character position */
 109         parm = early_command_line + len + 1; /* append right after '\0' */
 110 
 111         switch (ipl_block.pb0_hdr.pbt) {
 112         case IPL_PBT_CCW:
 113                 rc = ipl_block_get_ascii_vmparm(
 114                         parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
 115                 break;
 116         case IPL_PBT_FCP:
 117                 rc = ipl_block_get_ascii_scpdata(
 118                         parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
 119                 break;
 120         }
 121         if (rc) {
 122                 if (*parm == '=')
 123                         memmove(early_command_line, parm + 1, rc);
 124                 else
 125                         *delim = ' '; /* replace '\0' with space */
 126         }
 127 }
 128 
 129 static inline int has_ebcdic_char(const char *str)
 130 {
 131         int i;
 132 
 133         for (i = 0; str[i]; i++)
 134                 if (str[i] & 0x80)
 135                         return 1;
 136         return 0;
 137 }
 138 
 139 void setup_boot_command_line(void)
 140 {
 141         COMMAND_LINE[ARCH_COMMAND_LINE_SIZE - 1] = 0;
 142         /* convert arch command line to ascii if necessary */
 143         if (has_ebcdic_char(COMMAND_LINE))
 144                 EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
 145         /* copy arch command line */
 146         strcpy(early_command_line, strim(COMMAND_LINE));
 147 
 148         /* append IPL PARM data to the boot command line */
 149         if (!is_prot_virt_guest() && ipl_block_valid)
 150                 append_ipl_block_parm();
 151 }
 152 
 153 static void modify_facility(unsigned long nr, bool clear)
 154 {
 155         if (clear)
 156                 __clear_facility(nr, S390_lowcore.stfle_fac_list);
 157         else
 158                 __set_facility(nr, S390_lowcore.stfle_fac_list);
 159 }
 160 
 161 static void check_cleared_facilities(void)
 162 {
 163         unsigned long als[] = { FACILITIES_ALS };
 164         int i;
 165 
 166         for (i = 0; i < ARRAY_SIZE(als); i++) {
 167                 if ((S390_lowcore.stfle_fac_list[i] & als[i]) != als[i]) {
 168                         sclp_early_printk("Warning: The Linux kernel requires facilities cleared via command line option\n");
 169                         print_missing_facilities();
 170                         break;
 171                 }
 172         }
 173 }
 174 
 175 static void modify_fac_list(char *str)
 176 {
 177         unsigned long val, endval;
 178         char *endp;
 179         bool clear;
 180 
 181         while (*str) {
 182                 clear = false;
 183                 if (*str == '!') {
 184                         clear = true;
 185                         str++;
 186                 }
 187                 val = simple_strtoull(str, &endp, 0);
 188                 if (str == endp)
 189                         break;
 190                 str = endp;
 191                 if (*str == '-') {
 192                         str++;
 193                         endval = simple_strtoull(str, &endp, 0);
 194                         if (str == endp)
 195                                 break;
 196                         str = endp;
 197                         while (val <= endval) {
 198                                 modify_facility(val, clear);
 199                                 val++;
 200                         }
 201                 } else {
 202                         modify_facility(val, clear);
 203                 }
 204                 if (*str != ',')
 205                         break;
 206                 str++;
 207         }
 208         check_cleared_facilities();
 209 }
 210 
 211 static char command_line_buf[COMMAND_LINE_SIZE] __section(.data);
 212 void parse_boot_command_line(void)
 213 {
 214         char *param, *val;
 215         bool enabled;
 216         char *args;
 217         int rc;
 218 
 219         kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE);
 220         args = strcpy(command_line_buf, early_command_line);
 221         while (*args) {
 222                 args = next_arg(args, &param, &val);
 223 
 224                 if (!strcmp(param, "mem") && val) {
 225                         memory_end = round_down(memparse(val, NULL), PAGE_SIZE);
 226                         memory_end_set = 1;
 227                 }
 228 
 229                 if (!strcmp(param, "vmalloc") && val)
 230                         vmalloc_size = round_up(memparse(val, NULL), PAGE_SIZE);
 231 
 232                 if (!strcmp(param, "noexec")) {
 233                         rc = kstrtobool(val, &enabled);
 234                         if (!rc && !enabled)
 235                                 noexec_disabled = 1;
 236                 }
 237 
 238                 if (!strcmp(param, "facilities") && val)
 239                         modify_fac_list(val);
 240 
 241                 if (!strcmp(param, "nokaslr"))
 242                         kaslr_enabled = 0;
 243         }
 244 }
 245 
 246 void setup_memory_end(void)
 247 {
 248 #ifdef CONFIG_CRASH_DUMP
 249         if (OLDMEM_BASE) {
 250                 kaslr_enabled = 0;
 251         } else if (ipl_block_valid &&
 252                    ipl_block.pb0_hdr.pbt == IPL_PBT_FCP &&
 253                    ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP) {
 254                 kaslr_enabled = 0;
 255                 if (!sclp_early_get_hsa_size(&memory_end) && memory_end)
 256                         memory_end_set = 1;
 257         }
 258 #endif
 259 }

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