ipl_parm.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. // SPDX-License-Identifier: GPL-2.0
  2. #include <linux/kernel.h>
  3. #include <linux/init.h>
  4. #include <linux/ctype.h>
  5. #include <linux/pgtable.h>
  6. #include <asm/arch-stackprotector.h>
  7. #include <asm/abs_lowcore.h>
  8. #include <asm/page-states.h>
  9. #include <asm/machine.h>
  10. #include <asm/ebcdic.h>
  11. #include <asm/sclp.h>
  12. #include <asm/sections.h>
  13. #include <asm/boot_data.h>
  14. #include <asm/facility.h>
  15. #include <asm/setup.h>
  16. #include <asm/uv.h>
  17. #include "boot.h"
  18. struct parmarea parmarea __section(".parmarea") = {
  19. .kernel_version = (unsigned long)kernel_version,
  20. .max_command_line_size = COMMAND_LINE_SIZE,
  21. .command_line = "root=/dev/ram0 ro",
  22. };
  23. char __bootdata(early_command_line)[COMMAND_LINE_SIZE];
  24. unsigned int __bootdata_preserved(zlib_dfltcc_support) = ZLIB_DFLTCC_FULL;
  25. struct ipl_parameter_block __bootdata_preserved(ipl_block);
  26. int __bootdata_preserved(ipl_block_valid);
  27. int __bootdata_preserved(__kaslr_enabled);
  28. int __bootdata_preserved(cmma_flag) = 1;
  29. unsigned long vmalloc_size = VMALLOC_DEFAULT_SIZE;
  30. unsigned long memory_limit;
  31. int vmalloc_size_set;
  32. static inline int __diag308(unsigned long subcode, void *addr)
  33. {
  34. union register_pair r1 = { .even = (unsigned long)addr, .odd = 0 };
  35. asm_inline volatile(
  36. " diag %[r1],%[subcode],0x308\n"
  37. "0:\n"
  38. EX_TABLE(0b, 0b)
  39. : [r1] "+d" (r1.pair)
  40. : [subcode] "d" (subcode)
  41. : "cc", "memory");
  42. return r1.odd;
  43. }
  44. void store_ipl_parmblock(void)
  45. {
  46. int rc;
  47. rc = __diag308(DIAG308_STORE, &ipl_block);
  48. if (rc == DIAG308_RC_OK &&
  49. ipl_block.hdr.version <= IPL_MAX_SUPPORTED_VERSION)
  50. ipl_block_valid = 1;
  51. }
  52. bool is_ipl_block_dump(void)
  53. {
  54. if (ipl_block.pb0_hdr.pbt == IPL_PBT_FCP &&
  55. ipl_block.fcp.opt == IPL_PB0_FCP_OPT_DUMP)
  56. return true;
  57. if (ipl_block.pb0_hdr.pbt == IPL_PBT_NVME &&
  58. ipl_block.nvme.opt == IPL_PB0_NVME_OPT_DUMP)
  59. return true;
  60. if (ipl_block.pb0_hdr.pbt == IPL_PBT_ECKD &&
  61. ipl_block.eckd.opt == IPL_PB0_ECKD_OPT_DUMP)
  62. return true;
  63. return false;
  64. }
  65. static size_t scpdata_length(const u8 *buf, size_t count)
  66. {
  67. while (count) {
  68. if (buf[count - 1] != '\0' && buf[count - 1] != ' ')
  69. break;
  70. count--;
  71. }
  72. return count;
  73. }
  74. static size_t ipl_block_get_ascii_scpdata(char *dest, size_t size,
  75. const struct ipl_parameter_block *ipb)
  76. {
  77. const __u8 *scp_data;
  78. __u32 scp_data_len;
  79. int has_lowercase;
  80. size_t count = 0;
  81. size_t i;
  82. switch (ipb->pb0_hdr.pbt) {
  83. case IPL_PBT_FCP:
  84. scp_data_len = ipb->fcp.scp_data_len;
  85. scp_data = ipb->fcp.scp_data;
  86. break;
  87. case IPL_PBT_NVME:
  88. scp_data_len = ipb->nvme.scp_data_len;
  89. scp_data = ipb->nvme.scp_data;
  90. break;
  91. case IPL_PBT_ECKD:
  92. scp_data_len = ipb->eckd.scp_data_len;
  93. scp_data = ipb->eckd.scp_data;
  94. break;
  95. default:
  96. goto out;
  97. }
  98. count = min(size - 1, scpdata_length(scp_data, scp_data_len));
  99. if (!count)
  100. goto out;
  101. has_lowercase = 0;
  102. for (i = 0; i < count; i++) {
  103. if (!isascii(scp_data[i])) {
  104. count = 0;
  105. goto out;
  106. }
  107. if (!has_lowercase && islower(scp_data[i]))
  108. has_lowercase = 1;
  109. }
  110. if (has_lowercase)
  111. memcpy(dest, scp_data, count);
  112. else
  113. for (i = 0; i < count; i++)
  114. dest[i] = tolower(scp_data[i]);
  115. out:
  116. dest[count] = '\0';
  117. return count;
  118. }
  119. static void append_ipl_block_parm(void)
  120. {
  121. char *parm, *delim;
  122. size_t len, rc = 0;
  123. len = strlen(early_command_line);
  124. delim = early_command_line + len; /* '\0' character position */
  125. parm = early_command_line + len + 1; /* append right after '\0' */
  126. switch (ipl_block.pb0_hdr.pbt) {
  127. case IPL_PBT_CCW:
  128. rc = ipl_block_get_ascii_vmparm(
  129. parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
  130. break;
  131. case IPL_PBT_FCP:
  132. case IPL_PBT_NVME:
  133. case IPL_PBT_ECKD:
  134. rc = ipl_block_get_ascii_scpdata(
  135. parm, COMMAND_LINE_SIZE - len - 1, &ipl_block);
  136. break;
  137. }
  138. if (rc) {
  139. if (*parm == '=')
  140. memmove(early_command_line, parm + 1, rc);
  141. else
  142. *delim = ' '; /* replace '\0' with space */
  143. }
  144. }
  145. static inline int has_ebcdic_char(const char *str)
  146. {
  147. int i;
  148. for (i = 0; str[i]; i++)
  149. if (str[i] & 0x80)
  150. return 1;
  151. return 0;
  152. }
  153. void setup_boot_command_line(void)
  154. {
  155. parmarea.command_line[COMMAND_LINE_SIZE - 1] = 0;
  156. /* convert arch command line to ascii if necessary */
  157. if (has_ebcdic_char(parmarea.command_line))
  158. EBCASC(parmarea.command_line, COMMAND_LINE_SIZE);
  159. /* copy arch command line */
  160. strscpy(early_command_line, strim(parmarea.command_line));
  161. /* append IPL PARM data to the boot command line */
  162. if (!is_prot_virt_guest() && ipl_block_valid)
  163. append_ipl_block_parm();
  164. }
  165. static void modify_facility(unsigned long nr, bool clear)
  166. {
  167. if (clear)
  168. __clear_facility(nr, stfle_fac_list);
  169. else
  170. __set_facility(nr, stfle_fac_list);
  171. }
  172. static void check_cleared_facilities(void)
  173. {
  174. unsigned long als[] = { FACILITIES_ALS };
  175. int i;
  176. for (i = 0; i < ARRAY_SIZE(als); i++) {
  177. if ((stfle_fac_list[i] & als[i]) != als[i]) {
  178. boot_emerg("The Linux kernel requires facilities cleared via command line option\n");
  179. print_missing_facilities();
  180. break;
  181. }
  182. }
  183. }
  184. static void modify_fac_list(char *str)
  185. {
  186. unsigned long val, endval;
  187. char *endp;
  188. bool clear;
  189. while (*str) {
  190. clear = false;
  191. if (*str == '!') {
  192. clear = true;
  193. str++;
  194. }
  195. val = simple_strtoull(str, &endp, 0);
  196. if (str == endp)
  197. break;
  198. str = endp;
  199. if (*str == '-') {
  200. str++;
  201. endval = simple_strtoull(str, &endp, 0);
  202. if (str == endp)
  203. break;
  204. str = endp;
  205. while (val <= endval) {
  206. modify_facility(val, clear);
  207. val++;
  208. }
  209. } else {
  210. modify_facility(val, clear);
  211. }
  212. if (*str != ',')
  213. break;
  214. str++;
  215. }
  216. check_cleared_facilities();
  217. }
  218. static char command_line_buf[COMMAND_LINE_SIZE];
  219. void parse_boot_command_line(void)
  220. {
  221. char *param, *val;
  222. bool enabled;
  223. char *args;
  224. int rc;
  225. __kaslr_enabled = IS_ENABLED(CONFIG_RANDOMIZE_BASE);
  226. strscpy(command_line_buf, early_command_line);
  227. args = command_line_buf;
  228. while (*args) {
  229. args = next_arg(args, &param, &val);
  230. if (!strcmp(param, "mem") && val)
  231. memory_limit = round_down(memparse(val, NULL), PAGE_SIZE);
  232. if (!strcmp(param, "vmalloc") && val) {
  233. vmalloc_size = round_up(memparse(val, NULL), _SEGMENT_SIZE);
  234. vmalloc_size_set = 1;
  235. }
  236. if (!strcmp(param, "dfltcc") && val) {
  237. if (!strcmp(val, "off"))
  238. zlib_dfltcc_support = ZLIB_DFLTCC_DISABLED;
  239. else if (!strcmp(val, "on"))
  240. zlib_dfltcc_support = ZLIB_DFLTCC_FULL;
  241. else if (!strcmp(val, "def_only"))
  242. zlib_dfltcc_support = ZLIB_DFLTCC_DEFLATE_ONLY;
  243. else if (!strcmp(val, "inf_only"))
  244. zlib_dfltcc_support = ZLIB_DFLTCC_INFLATE_ONLY;
  245. else if (!strcmp(val, "always"))
  246. zlib_dfltcc_support = ZLIB_DFLTCC_FULL_DEBUG;
  247. }
  248. if (!strcmp(param, "facilities") && val)
  249. modify_fac_list(val);
  250. if (!strcmp(param, "debug-alternative"))
  251. alt_debug_setup(val);
  252. if (!strcmp(param, "nokaslr"))
  253. __kaslr_enabled = 0;
  254. if (!strcmp(param, "cmma")) {
  255. rc = kstrtobool(val, &enabled);
  256. if (!rc && !enabled)
  257. cmma_flag = 0;
  258. }
  259. #ifdef CONFIG_STACKPROTECTOR
  260. if (!strcmp(param, "debug_stackprotector"))
  261. stack_protector_debug = 1;
  262. #endif
  263. #if IS_ENABLED(CONFIG_KVM)
  264. if (!strcmp(param, "prot_virt")) {
  265. rc = kstrtobool(val, &enabled);
  266. if (!rc && enabled)
  267. prot_virt_host = 1;
  268. }
  269. #endif
  270. if (!strcmp(param, "relocate_lowcore") && test_facility(193))
  271. set_machine_feature(MFEATURE_LOWCORE);
  272. if (!strcmp(param, "earlyprintk"))
  273. boot_earlyprintk = true;
  274. if (!strcmp(param, "debug"))
  275. boot_console_loglevel = CONSOLE_LOGLEVEL_DEBUG;
  276. if (!strcmp(param, "bootdebug")) {
  277. bootdebug = true;
  278. if (val)
  279. strscpy(bootdebug_filter, val);
  280. }
  281. if (!strcmp(param, "quiet"))
  282. boot_console_loglevel = CONSOLE_LOGLEVEL_QUIET;
  283. if (!strcmp(param, "ignore_loglevel"))
  284. boot_ignore_loglevel = true;
  285. if (!strcmp(param, "loglevel")) {
  286. boot_console_loglevel = simple_strtoull(val, NULL, 10);
  287. if (boot_console_loglevel < CONSOLE_LOGLEVEL_MIN)
  288. boot_console_loglevel = CONSOLE_LOGLEVEL_MIN;
  289. }
  290. }
  291. }