early.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  1. /*
  2. * arch/s390/kernel/early.c
  3. *
  4. * Copyright IBM Corp. 2007
  5. * Author(s): Hongjie Yang <hongjie@us.ibm.com>,
  6. * Heiko Carstens <heiko.carstens@de.ibm.com>
  7. */
  8. #include <linux/compiler.h>
  9. #include <linux/init.h>
  10. #include <linux/errno.h>
  11. #include <linux/string.h>
  12. #include <linux/ctype.h>
  13. #include <linux/lockdep.h>
  14. #include <linux/module.h>
  15. #include <linux/pfn.h>
  16. #include <linux/uaccess.h>
  17. #include <asm/ebcdic.h>
  18. #include <asm/ipl.h>
  19. #include <asm/lowcore.h>
  20. #include <asm/processor.h>
  21. #include <asm/sections.h>
  22. #include <asm/setup.h>
  23. #include <asm/sysinfo.h>
  24. #include <asm/cpcmd.h>
  25. #include <asm/sclp.h>
  26. #include "entry.h"
  27. /*
  28. * Create a Kernel NSS if the SAVESYS= parameter is defined
  29. */
  30. #define DEFSYS_CMD_SIZE 128
  31. #define SAVESYS_CMD_SIZE 32
  32. char kernel_nss_name[NSS_NAME_SIZE + 1];
  33. static void __init setup_boot_command_line(void);
  34. #ifdef CONFIG_SHARED_KERNEL
  35. int __init savesys_ipl_nss(char *cmd, const int cmdlen);
  36. asm(
  37. " .section .init.text,\"ax\",@progbits\n"
  38. " .align 4\n"
  39. " .type savesys_ipl_nss, @function\n"
  40. "savesys_ipl_nss:\n"
  41. #ifdef CONFIG_64BIT
  42. " stmg 6,15,48(15)\n"
  43. " lgr 14,3\n"
  44. " sam31\n"
  45. " diag 2,14,0x8\n"
  46. " sam64\n"
  47. " lgr 2,14\n"
  48. " lmg 6,15,48(15)\n"
  49. #else
  50. " stm 6,15,24(15)\n"
  51. " lr 14,3\n"
  52. " diag 2,14,0x8\n"
  53. " lr 2,14\n"
  54. " lm 6,15,24(15)\n"
  55. #endif
  56. " br 14\n"
  57. " .size savesys_ipl_nss, .-savesys_ipl_nss\n");
  58. static noinline __init void create_kernel_nss(void)
  59. {
  60. unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
  61. #ifdef CONFIG_BLK_DEV_INITRD
  62. unsigned int sinitrd_pfn, einitrd_pfn;
  63. #endif
  64. int response;
  65. size_t len;
  66. char *savesys_ptr;
  67. char upper_command_line[COMMAND_LINE_SIZE];
  68. char defsys_cmd[DEFSYS_CMD_SIZE];
  69. char savesys_cmd[SAVESYS_CMD_SIZE];
  70. /* Do nothing if we are not running under VM */
  71. if (!MACHINE_IS_VM)
  72. return;
  73. /* Convert COMMAND_LINE to upper case */
  74. for (i = 0; i < strlen(boot_command_line); i++)
  75. upper_command_line[i] = toupper(boot_command_line[i]);
  76. savesys_ptr = strstr(upper_command_line, "SAVESYS=");
  77. if (!savesys_ptr)
  78. return;
  79. savesys_ptr += 8; /* Point to the beginning of the NSS name */
  80. for (i = 0; i < NSS_NAME_SIZE; i++) {
  81. if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
  82. break;
  83. kernel_nss_name[i] = savesys_ptr[i];
  84. }
  85. stext_pfn = PFN_DOWN(__pa(&_stext));
  86. eshared_pfn = PFN_DOWN(__pa(&_eshared));
  87. end_pfn = PFN_UP(__pa(&_end));
  88. min_size = end_pfn << 2;
  89. sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
  90. kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
  91. eshared_pfn, end_pfn);
  92. #ifdef CONFIG_BLK_DEV_INITRD
  93. if (INITRD_START && INITRD_SIZE) {
  94. sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
  95. einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
  96. min_size = einitrd_pfn << 2;
  97. sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
  98. sinitrd_pfn, einitrd_pfn);
  99. }
  100. #endif
  101. sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
  102. defsys_cmd, min_size);
  103. sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
  104. kernel_nss_name, kernel_nss_name);
  105. __cpcmd(defsys_cmd, NULL, 0, &response);
  106. if (response != 0) {
  107. kernel_nss_name[0] = '\0';
  108. return;
  109. }
  110. len = strlen(savesys_cmd);
  111. ASCEBC(savesys_cmd, len);
  112. response = savesys_ipl_nss(savesys_cmd, len);
  113. /* On success: response is equal to the command size,
  114. * max SAVESYS_CMD_SIZE
  115. * On error: response contains the numeric portion of cp error message.
  116. * for SAVESYS it will be >= 263
  117. */
  118. if (response > SAVESYS_CMD_SIZE) {
  119. kernel_nss_name[0] = '\0';
  120. return;
  121. }
  122. /* re-setup boot command line with new ipl vm parms */
  123. ipl_update_parameters();
  124. setup_boot_command_line();
  125. ipl_flags = IPL_NSS_VALID;
  126. }
  127. #else /* CONFIG_SHARED_KERNEL */
  128. static inline void create_kernel_nss(void) { }
  129. #endif /* CONFIG_SHARED_KERNEL */
  130. /*
  131. * Clear bss memory
  132. */
  133. static noinline __init void clear_bss_section(void)
  134. {
  135. memset(__bss_start, 0, __bss_stop - __bss_start);
  136. }
  137. /*
  138. * Initialize storage key for kernel pages
  139. */
  140. static noinline __init void init_kernel_storage_key(void)
  141. {
  142. unsigned long end_pfn, init_pfn;
  143. end_pfn = PFN_UP(__pa(&_end));
  144. for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
  145. page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
  146. }
  147. static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
  148. static noinline __init void detect_machine_type(void)
  149. {
  150. /* No VM information? Looks like LPAR */
  151. if (stsi(&vmms, 3, 2, 2) == -ENOSYS)
  152. return;
  153. if (!vmms.count)
  154. return;
  155. /* Running under KVM? If not we assume z/VM */
  156. if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3))
  157. machine_flags |= MACHINE_FLAG_KVM;
  158. else
  159. machine_flags |= MACHINE_FLAG_VM;
  160. }
  161. static __init void early_pgm_check_handler(void)
  162. {
  163. unsigned long addr;
  164. const struct exception_table_entry *fixup;
  165. addr = S390_lowcore.program_old_psw.addr;
  166. fixup = search_exception_tables(addr & PSW_ADDR_INSN);
  167. if (!fixup)
  168. disabled_wait(0);
  169. S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
  170. }
  171. static noinline __init void setup_lowcore_early(void)
  172. {
  173. psw_t psw;
  174. psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
  175. psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
  176. S390_lowcore.external_new_psw = psw;
  177. psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
  178. S390_lowcore.program_new_psw = psw;
  179. s390_base_pgm_handler_fn = early_pgm_check_handler;
  180. }
  181. static noinline __init void setup_hpage(void)
  182. {
  183. #ifndef CONFIG_DEBUG_PAGEALLOC
  184. unsigned int facilities;
  185. facilities = stfl();
  186. if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
  187. return;
  188. machine_flags |= MACHINE_FLAG_HPAGE;
  189. __ctl_set_bit(0, 23);
  190. #endif
  191. }
  192. static __init void detect_mvpg(void)
  193. {
  194. #ifndef CONFIG_64BIT
  195. int rc;
  196. asm volatile(
  197. " la 0,0\n"
  198. " mvpg %2,%2\n"
  199. "0: la %0,0\n"
  200. "1:\n"
  201. EX_TABLE(0b,1b)
  202. : "=d" (rc) : "0" (-EOPNOTSUPP), "a" (0) : "memory", "cc", "0");
  203. if (!rc)
  204. machine_flags |= MACHINE_FLAG_MVPG;
  205. #endif
  206. }
  207. static __init void detect_ieee(void)
  208. {
  209. #ifndef CONFIG_64BIT
  210. int rc, tmp;
  211. asm volatile(
  212. " efpc %1,0\n"
  213. "0: la %0,0\n"
  214. "1:\n"
  215. EX_TABLE(0b,1b)
  216. : "=d" (rc), "=d" (tmp): "0" (-EOPNOTSUPP) : "cc");
  217. if (!rc)
  218. machine_flags |= MACHINE_FLAG_IEEE;
  219. #endif
  220. }
  221. static __init void detect_csp(void)
  222. {
  223. #ifndef CONFIG_64BIT
  224. int rc;
  225. asm volatile(
  226. " la 0,0\n"
  227. " la 1,0\n"
  228. " la 2,4\n"
  229. " csp 0,2\n"
  230. "0: la %0,0\n"
  231. "1:\n"
  232. EX_TABLE(0b,1b)
  233. : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc", "0", "1", "2");
  234. if (!rc)
  235. machine_flags |= MACHINE_FLAG_CSP;
  236. #endif
  237. }
  238. static __init void detect_diag9c(void)
  239. {
  240. unsigned int cpu_address;
  241. int rc;
  242. cpu_address = stap();
  243. asm volatile(
  244. " diag %2,0,0x9c\n"
  245. "0: la %0,0\n"
  246. "1:\n"
  247. EX_TABLE(0b,1b)
  248. : "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc");
  249. if (!rc)
  250. machine_flags |= MACHINE_FLAG_DIAG9C;
  251. }
  252. static __init void detect_diag44(void)
  253. {
  254. #ifdef CONFIG_64BIT
  255. int rc;
  256. asm volatile(
  257. " diag 0,0,0x44\n"
  258. "0: la %0,0\n"
  259. "1:\n"
  260. EX_TABLE(0b,1b)
  261. : "=d" (rc) : "0" (-EOPNOTSUPP) : "cc");
  262. if (!rc)
  263. machine_flags |= MACHINE_FLAG_DIAG44;
  264. #endif
  265. }
  266. static __init void detect_machine_facilities(void)
  267. {
  268. #ifdef CONFIG_64BIT
  269. unsigned int facilities;
  270. facilities = stfl();
  271. if (facilities & (1 << 28))
  272. machine_flags |= MACHINE_FLAG_IDTE;
  273. if (facilities & (1 << 23))
  274. machine_flags |= MACHINE_FLAG_PFMF;
  275. if (facilities & (1 << 4))
  276. machine_flags |= MACHINE_FLAG_MVCOS;
  277. #endif
  278. }
  279. static __init void rescue_initrd(void)
  280. {
  281. #ifdef CONFIG_BLK_DEV_INITRD
  282. /*
  283. * Move the initrd right behind the bss section in case it starts
  284. * within the bss section. So we don't overwrite it when the bss
  285. * section gets cleared.
  286. */
  287. if (!INITRD_START || !INITRD_SIZE)
  288. return;
  289. if (INITRD_START >= (unsigned long) __bss_stop)
  290. return;
  291. memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE);
  292. INITRD_START = (unsigned long) __bss_stop;
  293. #endif
  294. }
  295. /* Set up boot command line */
  296. static void __init setup_boot_command_line(void)
  297. {
  298. char *parm = NULL;
  299. /* copy arch command line */
  300. strlcpy(boot_command_line, COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
  301. /* append IPL PARM data to the boot command line */
  302. if (MACHINE_IS_VM) {
  303. parm = boot_command_line + strlen(boot_command_line);
  304. *parm++ = ' ';
  305. get_ipl_vmparm(parm);
  306. if (parm[0] == '=')
  307. memmove(boot_command_line, parm + 1, strlen(parm));
  308. }
  309. }
  310. /*
  311. * Save ipl parameters, clear bss memory, initialize storage keys
  312. * and create a kernel NSS at startup if the SAVESYS= parm is defined
  313. */
  314. void __init startup_init(void)
  315. {
  316. ipl_save_parameters();
  317. rescue_initrd();
  318. clear_bss_section();
  319. init_kernel_storage_key();
  320. lockdep_init();
  321. lockdep_off();
  322. sort_main_extable();
  323. setup_lowcore_early();
  324. detect_machine_type();
  325. ipl_update_parameters();
  326. setup_boot_command_line();
  327. create_kernel_nss();
  328. detect_mvpg();
  329. detect_ieee();
  330. detect_csp();
  331. detect_diag9c();
  332. detect_diag44();
  333. detect_machine_facilities();
  334. setup_hpage();
  335. sclp_facilities_detect();
  336. detect_memory_layout(memory_chunk);
  337. lockdep_on();
  338. }