~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/s390/boot/ipl_parm.c

Version: ~ [ linux-5.8-rc4 ] ~ [ linux-5.7.7 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.50 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.131 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.187 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.229 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.229 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.85 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp