• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/s390/kernel/
1/*
2 *  arch/s390/kernel/early.c
3 *
4 *    Copyright IBM Corp. 2007, 2009
5 *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
6 *		 Heiko Carstens <heiko.carstens@de.ibm.com>
7 */
8
9#define KMSG_COMPONENT "setup"
10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11
12#include <linux/compiler.h>
13#include <linux/init.h>
14#include <linux/errno.h>
15#include <linux/string.h>
16#include <linux/ctype.h>
17#include <linux/ftrace.h>
18#include <linux/lockdep.h>
19#include <linux/module.h>
20#include <linux/pfn.h>
21#include <linux/uaccess.h>
22#include <linux/kernel.h>
23#include <asm/ebcdic.h>
24#include <asm/ipl.h>
25#include <asm/lowcore.h>
26#include <asm/processor.h>
27#include <asm/sections.h>
28#include <asm/setup.h>
29#include <asm/sysinfo.h>
30#include <asm/cpcmd.h>
31#include <asm/sclp.h>
32#include "entry.h"
33
34/*
35 * Create a Kernel NSS if the SAVESYS= parameter is defined
36 */
37#define DEFSYS_CMD_SIZE		128
38#define SAVESYS_CMD_SIZE	32
39
40char kernel_nss_name[NSS_NAME_SIZE + 1];
41
42static void __init setup_boot_command_line(void);
43
44/*
45 * Get the TOD clock running.
46 */
47static void __init reset_tod_clock(void)
48{
49	u64 time;
50
51	if (store_clock(&time) == 0)
52		return;
53	/* TOD clock not running. Set the clock to Unix Epoch. */
54	if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
55		disabled_wait(0);
56
57	sched_clock_base_cc = TOD_UNIX_EPOCH;
58	S390_lowcore.last_update_clock = sched_clock_base_cc;
59}
60
61#ifdef CONFIG_SHARED_KERNEL
62int __init savesys_ipl_nss(char *cmd, const int cmdlen);
63
64asm(
65	"	.section .init.text,\"ax\",@progbits\n"
66	"	.align	4\n"
67	"	.type	savesys_ipl_nss, @function\n"
68	"savesys_ipl_nss:\n"
69#ifdef CONFIG_64BIT
70	"	stmg	6,15,48(15)\n"
71	"	lgr	14,3\n"
72	"	sam31\n"
73	"	diag	2,14,0x8\n"
74	"	sam64\n"
75	"	lgr	2,14\n"
76	"	lmg	6,15,48(15)\n"
77#else
78	"	stm	6,15,24(15)\n"
79	"	lr	14,3\n"
80	"	diag	2,14,0x8\n"
81	"	lr	2,14\n"
82	"	lm	6,15,24(15)\n"
83#endif
84	"	br	14\n"
85	"	.size	savesys_ipl_nss, .-savesys_ipl_nss\n"
86	"	.previous\n");
87
88static __initdata char upper_command_line[COMMAND_LINE_SIZE];
89
90static noinline __init void create_kernel_nss(void)
91{
92	unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
93#ifdef CONFIG_BLK_DEV_INITRD
94	unsigned int sinitrd_pfn, einitrd_pfn;
95#endif
96	int response;
97	size_t len;
98	char *savesys_ptr;
99	char defsys_cmd[DEFSYS_CMD_SIZE];
100	char savesys_cmd[SAVESYS_CMD_SIZE];
101
102	/* Do nothing if we are not running under VM */
103	if (!MACHINE_IS_VM)
104		return;
105
106	/* Convert COMMAND_LINE to upper case */
107	for (i = 0; i < strlen(boot_command_line); i++)
108		upper_command_line[i] = toupper(boot_command_line[i]);
109
110	savesys_ptr = strstr(upper_command_line, "SAVESYS=");
111
112	if (!savesys_ptr)
113		return;
114
115	savesys_ptr += 8;    /* Point to the beginning of the NSS name */
116	for (i = 0; i < NSS_NAME_SIZE; i++) {
117		if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
118			break;
119		kernel_nss_name[i] = savesys_ptr[i];
120	}
121
122	stext_pfn = PFN_DOWN(__pa(&_stext));
123	eshared_pfn = PFN_DOWN(__pa(&_eshared));
124	end_pfn = PFN_UP(__pa(&_end));
125	min_size = end_pfn << 2;
126
127	sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
128		kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
129		eshared_pfn, end_pfn);
130
131#ifdef CONFIG_BLK_DEV_INITRD
132	if (INITRD_START && INITRD_SIZE) {
133		sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
134		einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
135		min_size = einitrd_pfn << 2;
136		sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
137		sinitrd_pfn, einitrd_pfn);
138	}
139#endif
140
141	sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK PARMREGS=0-13",
142		defsys_cmd, min_size);
143	sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
144		kernel_nss_name, kernel_nss_name);
145
146	__cpcmd(defsys_cmd, NULL, 0, &response);
147
148	if (response != 0) {
149		pr_err("Defining the Linux kernel NSS failed with rc=%d\n",
150			response);
151		kernel_nss_name[0] = '\0';
152		return;
153	}
154
155	len = strlen(savesys_cmd);
156	ASCEBC(savesys_cmd, len);
157	response = savesys_ipl_nss(savesys_cmd, len);
158
159	/* On success: response is equal to the command size,
160	 *	       max SAVESYS_CMD_SIZE
161	 * On error: response contains the numeric portion of cp error message.
162	 *	     for SAVESYS it will be >= 263
163	 *	     for missing privilege class, it will be 1
164	 */
165	if (response > SAVESYS_CMD_SIZE || response == 1) {
166		pr_err("Saving the Linux kernel NSS failed with rc=%d\n",
167			response);
168		kernel_nss_name[0] = '\0';
169		return;
170	}
171
172	/* re-initialize cputime accounting. */
173	sched_clock_base_cc = get_clock();
174	S390_lowcore.last_update_clock = sched_clock_base_cc;
175	S390_lowcore.last_update_timer = 0x7fffffffffffffffULL;
176	S390_lowcore.user_timer = 0;
177	S390_lowcore.system_timer = 0;
178	asm volatile("SPT 0(%0)" : : "a" (&S390_lowcore.last_update_timer));
179
180	/* re-setup boot command line with new ipl vm parms */
181	ipl_update_parameters();
182	setup_boot_command_line();
183
184	ipl_flags = IPL_NSS_VALID;
185}
186
187#else /* CONFIG_SHARED_KERNEL */
188
189static inline void create_kernel_nss(void) { }
190
191#endif /* CONFIG_SHARED_KERNEL */
192
193/*
194 * Clear bss memory
195 */
196static noinline __init void clear_bss_section(void)
197{
198	memset(__bss_start, 0, __bss_stop - __bss_start);
199}
200
201/*
202 * Initialize storage key for kernel pages
203 */
204static noinline __init void init_kernel_storage_key(void)
205{
206	unsigned long end_pfn, init_pfn;
207
208	end_pfn = PFN_UP(__pa(&_end));
209
210	for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
211		page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
212}
213
214static __initdata struct sysinfo_3_2_2 vmms __aligned(PAGE_SIZE);
215
216static noinline __init void detect_machine_type(void)
217{
218	/* Check current-configuration-level */
219	if ((stsi(NULL, 0, 0, 0) >> 28) <= 2) {
220		S390_lowcore.machine_flags |= MACHINE_FLAG_LPAR;
221		return;
222	}
223	/* Get virtual-machine cpu information. */
224	if (stsi(&vmms, 3, 2, 2) == -ENOSYS || !vmms.count)
225		return;
226
227	/* Running under KVM? If not we assume z/VM */
228	if (!memcmp(vmms.vm[0].cpi, "\xd2\xe5\xd4", 3))
229		S390_lowcore.machine_flags |= MACHINE_FLAG_KVM;
230	else
231		S390_lowcore.machine_flags |= MACHINE_FLAG_VM;
232}
233
234static __init void early_pgm_check_handler(void)
235{
236	unsigned long addr;
237	const struct exception_table_entry *fixup;
238
239	addr = S390_lowcore.program_old_psw.addr;
240	fixup = search_exception_tables(addr & PSW_ADDR_INSN);
241	if (!fixup)
242		disabled_wait(0);
243	S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
244}
245
246static noinline __init void setup_lowcore_early(void)
247{
248	psw_t psw;
249
250	psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
251	psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
252	S390_lowcore.external_new_psw = psw;
253	psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
254	S390_lowcore.program_new_psw = psw;
255	s390_base_pgm_handler_fn = early_pgm_check_handler;
256}
257
258static noinline __init void setup_hpage(void)
259{
260#ifndef CONFIG_DEBUG_PAGEALLOC
261	unsigned int facilities;
262
263	facilities = stfl();
264	if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
265		return;
266	S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
267	__ctl_set_bit(0, 23);
268#endif
269}
270
271static __init void detect_mvpg(void)
272{
273#ifndef CONFIG_64BIT
274	int rc;
275
276	asm volatile(
277		"	la	0,0\n"
278		"	mvpg	%2,%2\n"
279		"0:	la	%0,0\n"
280		"1:\n"
281		EX_TABLE(0b,1b)
282		: "=d" (rc) : "0" (-EOPNOTSUPP), "a" (0) : "memory", "cc", "0");
283	if (!rc)
284		S390_lowcore.machine_flags |= MACHINE_FLAG_MVPG;
285#endif
286}
287
288static __init void detect_ieee(void)
289{
290#ifndef CONFIG_64BIT
291	int rc, tmp;
292
293	asm volatile(
294		"	efpc	%1,0\n"
295		"0:	la	%0,0\n"
296		"1:\n"
297		EX_TABLE(0b,1b)
298		: "=d" (rc), "=d" (tmp): "0" (-EOPNOTSUPP) : "cc");
299	if (!rc)
300		S390_lowcore.machine_flags |= MACHINE_FLAG_IEEE;
301#endif
302}
303
304static __init void detect_csp(void)
305{
306#ifndef CONFIG_64BIT
307	int rc;
308
309	asm volatile(
310		"	la	0,0\n"
311		"	la	1,0\n"
312		"	la	2,4\n"
313		"	csp	0,2\n"
314		"0:	la	%0,0\n"
315		"1:\n"
316		EX_TABLE(0b,1b)
317		: "=d" (rc) : "0" (-EOPNOTSUPP) : "cc", "0", "1", "2");
318	if (!rc)
319		S390_lowcore.machine_flags |= MACHINE_FLAG_CSP;
320#endif
321}
322
323static __init void detect_diag9c(void)
324{
325	unsigned int cpu_address;
326	int rc;
327
328	cpu_address = stap();
329	asm volatile(
330		"	diag	%2,0,0x9c\n"
331		"0:	la	%0,0\n"
332		"1:\n"
333		EX_TABLE(0b,1b)
334		: "=d" (rc) : "0" (-EOPNOTSUPP), "d" (cpu_address) : "cc");
335	if (!rc)
336		S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG9C;
337}
338
339static __init void detect_diag44(void)
340{
341#ifdef CONFIG_64BIT
342	int rc;
343
344	asm volatile(
345		"	diag	0,0,0x44\n"
346		"0:	la	%0,0\n"
347		"1:\n"
348		EX_TABLE(0b,1b)
349		: "=d" (rc) : "0" (-EOPNOTSUPP) : "cc");
350	if (!rc)
351		S390_lowcore.machine_flags |= MACHINE_FLAG_DIAG44;
352#endif
353}
354
355static __init void detect_machine_facilities(void)
356{
357#ifdef CONFIG_64BIT
358	unsigned int facilities;
359	unsigned long long facility_bits;
360
361	facilities = stfl();
362	if (facilities & (1 << 28))
363		S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
364	if (facilities & (1 << 23))
365		S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
366	if (facilities & (1 << 4))
367		S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
368	if ((stfle(&facility_bits, 1) > 0) &&
369	    (facility_bits & (1ULL << (63 - 40))))
370		S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
371#endif
372}
373
374static __init void rescue_initrd(void)
375{
376#ifdef CONFIG_BLK_DEV_INITRD
377	/*
378	 * Move the initrd right behind the bss section in case it starts
379	 * within the bss section. So we don't overwrite it when the bss
380	 * section gets cleared.
381	 */
382	if (!INITRD_START || !INITRD_SIZE)
383		return;
384	if (INITRD_START >= (unsigned long) __bss_stop)
385		return;
386	memmove(__bss_stop, (void *) INITRD_START, INITRD_SIZE);
387	INITRD_START = (unsigned long) __bss_stop;
388#endif
389}
390
391/* Set up boot command line */
392static void __init append_to_cmdline(size_t (*ipl_data)(char *, size_t))
393{
394	char *parm, *delim;
395	size_t rc, len;
396
397	len = strlen(boot_command_line);
398
399	delim = boot_command_line + len;	/* '\0' character position */
400	parm  = boot_command_line + len + 1;	/* append right after '\0' */
401
402	rc = ipl_data(parm, COMMAND_LINE_SIZE - len - 1);
403	if (rc) {
404		if (*parm == '=')
405			memmove(boot_command_line, parm + 1, rc);
406		else
407			*delim = ' ';		/* replace '\0' with space */
408	}
409}
410
411static void __init setup_boot_command_line(void)
412{
413	int i;
414
415	/* convert arch command line to ascii */
416	for (i = 0; i < ARCH_COMMAND_LINE_SIZE; i++)
417		if (COMMAND_LINE[i] & 0x80)
418			break;
419	if (i < ARCH_COMMAND_LINE_SIZE)
420		EBCASC(COMMAND_LINE, ARCH_COMMAND_LINE_SIZE);
421	COMMAND_LINE[ARCH_COMMAND_LINE_SIZE-1] = 0;
422
423	/* copy arch command line */
424	strlcpy(boot_command_line, strstrip(COMMAND_LINE),
425		ARCH_COMMAND_LINE_SIZE);
426
427	/* append IPL PARM data to the boot command line */
428	if (MACHINE_IS_VM)
429		append_to_cmdline(append_ipl_vmparm);
430
431	append_to_cmdline(append_ipl_scpdata);
432}
433
434
435/*
436 * Save ipl parameters, clear bss memory, initialize storage keys
437 * and create a kernel NSS at startup if the SAVESYS= parm is defined
438 */
439void __init startup_init(void)
440{
441	reset_tod_clock();
442	ipl_save_parameters();
443	rescue_initrd();
444	clear_bss_section();
445	init_kernel_storage_key();
446	lockdep_init();
447	lockdep_off();
448	sort_main_extable();
449	setup_lowcore_early();
450	detect_machine_type();
451	ipl_update_parameters();
452	setup_boot_command_line();
453	create_kernel_nss();
454	detect_mvpg();
455	detect_ieee();
456	detect_csp();
457	detect_diag9c();
458	detect_diag44();
459	detect_machine_facilities();
460	setup_hpage();
461	sclp_facilities_detect();
462	detect_memory_layout(memory_chunk);
463#ifdef CONFIG_DYNAMIC_FTRACE
464	S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
465#endif
466	lockdep_on();
467}
468