diff options
author | Hongjie Yang <hongjie@us.ibm.com> | 2007-02-05 15:18:24 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-02-05 15:18:24 -0500 |
commit | fe355b7f1c7400cbb71762a1237461be03f88265 (patch) | |
tree | 8ef581c8ff0889a200bae88a4961395bcb80aec4 /arch/s390/kernel/setup.c | |
parent | 1b2782948997cf5a0d1747de13d43ba7dfa7c543 (diff) |
[S390] boot from NSS support
Add support to boot from a named saved segment (NSS).
Signed-off-by: Hongjie Yang <hongjie@us.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/setup.c')
-rw-r--r-- | arch/s390/kernel/setup.c | 178 |
1 files changed, 170 insertions, 8 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index b1b9a931237d..2569aafcc543 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <linux/device.h> | 38 | #include <linux/device.h> |
39 | #include <linux/notifier.h> | 39 | #include <linux/notifier.h> |
40 | #include <linux/pfn.h> | 40 | #include <linux/pfn.h> |
41 | #include <linux/ctype.h> | ||
41 | #include <linux/reboot.h> | 42 | #include <linux/reboot.h> |
42 | 43 | ||
43 | #include <asm/uaccess.h> | 44 | #include <asm/uaccess.h> |
@@ -50,6 +51,7 @@ | |||
50 | #include <asm/page.h> | 51 | #include <asm/page.h> |
51 | #include <asm/ptrace.h> | 52 | #include <asm/ptrace.h> |
52 | #include <asm/sections.h> | 53 | #include <asm/sections.h> |
54 | #include <asm/ebcdic.h> | ||
53 | #include <asm/compat.h> | 55 | #include <asm/compat.h> |
54 | 56 | ||
55 | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | | 57 | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | |
@@ -282,6 +284,140 @@ static void __init conmode_default(void) | |||
282 | } | 284 | } |
283 | } | 285 | } |
284 | 286 | ||
287 | /* | ||
288 | * Create a Kernel NSS if the SAVESYS= parameter is defined | ||
289 | */ | ||
290 | #define DEFSYS_CMD_SIZE 96 | ||
291 | #define SAVESYS_CMD_SIZE 32 | ||
292 | |||
293 | extern int _eshared; | ||
294 | char kernel_nss_name[NSS_NAME_SIZE + 1]; | ||
295 | |||
296 | #ifdef CONFIG_SHARED_KERNEL | ||
297 | static __init void create_kernel_nss(void) | ||
298 | { | ||
299 | unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size; | ||
300 | #ifdef CONFIG_BLK_DEV_INITRD | ||
301 | unsigned int sinitrd_pfn, einitrd_pfn; | ||
302 | #endif | ||
303 | int response; | ||
304 | char *savesys_ptr; | ||
305 | char upper_command_line[COMMAND_LINE_SIZE]; | ||
306 | char defsys_cmd[DEFSYS_CMD_SIZE]; | ||
307 | char savesys_cmd[SAVESYS_CMD_SIZE]; | ||
308 | |||
309 | /* Do nothing if we are not running under VM */ | ||
310 | if (!MACHINE_IS_VM) | ||
311 | return; | ||
312 | |||
313 | /* Convert COMMAND_LINE to upper case */ | ||
314 | for (i = 0; i < strlen(COMMAND_LINE); i++) | ||
315 | upper_command_line[i] = toupper(COMMAND_LINE[i]); | ||
316 | |||
317 | savesys_ptr = strstr(upper_command_line, "SAVESYS="); | ||
318 | |||
319 | if (!savesys_ptr) | ||
320 | return; | ||
321 | |||
322 | savesys_ptr += 8; /* Point to the beginning of the NSS name */ | ||
323 | for (i = 0; i < NSS_NAME_SIZE; i++) { | ||
324 | if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0') | ||
325 | break; | ||
326 | kernel_nss_name[i] = savesys_ptr[i]; | ||
327 | } | ||
328 | |||
329 | stext_pfn = PFN_DOWN(__pa(&_stext)); | ||
330 | eshared_pfn = PFN_DOWN(__pa(&_eshared)); | ||
331 | end_pfn = PFN_UP(__pa(&_end)); | ||
332 | min_size = end_pfn << 2; | ||
333 | |||
334 | sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X", | ||
335 | kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1, | ||
336 | eshared_pfn, end_pfn); | ||
337 | |||
338 | #ifdef CONFIG_BLK_DEV_INITRD | ||
339 | if (INITRD_START && INITRD_SIZE) { | ||
340 | sinitrd_pfn = PFN_DOWN(__pa(INITRD_START)); | ||
341 | einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE)); | ||
342 | min_size = einitrd_pfn << 2; | ||
343 | sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd, | ||
344 | sinitrd_pfn, einitrd_pfn); | ||
345 | } | ||
346 | #endif | ||
347 | |||
348 | sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size); | ||
349 | sprintf(savesys_cmd, "SAVESYS %s \n IPL %s", | ||
350 | kernel_nss_name, kernel_nss_name); | ||
351 | |||
352 | __cpcmd(defsys_cmd, NULL, 0, &response); | ||
353 | |||
354 | if (response != 0) | ||
355 | return; | ||
356 | |||
357 | __cpcmd(savesys_cmd, NULL, 0, &response); | ||
358 | |||
359 | if (response != strlen(savesys_cmd)) | ||
360 | return; | ||
361 | |||
362 | ipl_flags = IPL_NSS_VALID; | ||
363 | } | ||
364 | |||
365 | #else /* CONFIG_SHARED_KERNEL */ | ||
366 | |||
367 | static inline void create_kernel_nss(void) { } | ||
368 | |||
369 | #endif /* CONFIG_SHARED_KERNEL */ | ||
370 | |||
371 | /* | ||
372 | * Clear bss memory | ||
373 | */ | ||
374 | static __init void clear_bss_section(void) | ||
375 | { | ||
376 | memset(__bss_start, 0, _end - __bss_start); | ||
377 | } | ||
378 | |||
379 | /* | ||
380 | * Initialize storage key for kernel pages | ||
381 | */ | ||
382 | static __init void init_kernel_storage_key(void) | ||
383 | { | ||
384 | unsigned long end_pfn, init_pfn; | ||
385 | |||
386 | end_pfn = PFN_UP(__pa(&_end)); | ||
387 | |||
388 | for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++) | ||
389 | page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); | ||
390 | } | ||
391 | |||
392 | static __init void detect_machine_type(void) | ||
393 | { | ||
394 | struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data; | ||
395 | |||
396 | asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id)); | ||
397 | |||
398 | /* Running under z/VM ? */ | ||
399 | if (cpuinfo->cpu_id.version == 0xff) | ||
400 | machine_flags |= 1; | ||
401 | |||
402 | /* Running on a P/390 ? */ | ||
403 | if (cpuinfo->cpu_id.machine == 0x7490) | ||
404 | machine_flags |= 4; | ||
405 | } | ||
406 | |||
407 | /* | ||
408 | * Save ipl parameters, clear bss memory, initialize storage keys | ||
409 | * and create a kernel NSS at startup if the SAVESYS= parm is defined | ||
410 | */ | ||
411 | void __init startup_init(void) | ||
412 | { | ||
413 | ipl_save_parameters(); | ||
414 | clear_bss_section(); | ||
415 | init_kernel_storage_key(); | ||
416 | lockdep_init(); | ||
417 | detect_machine_type(); | ||
418 | create_kernel_nss(); | ||
419 | } | ||
420 | |||
285 | #ifdef CONFIG_SMP | 421 | #ifdef CONFIG_SMP |
286 | void (*_machine_restart)(char *command) = machine_restart_smp; | 422 | void (*_machine_restart)(char *command) = machine_restart_smp; |
287 | void (*_machine_halt)(void) = machine_halt_smp; | 423 | void (*_machine_halt)(void) = machine_halt_smp; |
@@ -523,7 +659,7 @@ setup_lowcore(void) | |||
523 | static void __init | 659 | static void __init |
524 | setup_resources(void) | 660 | setup_resources(void) |
525 | { | 661 | { |
526 | struct resource *res; | 662 | struct resource *res, *sub_res; |
527 | int i; | 663 | int i; |
528 | 664 | ||
529 | code_resource.start = (unsigned long) &_text; | 665 | code_resource.start = (unsigned long) &_text; |
@@ -548,8 +684,38 @@ setup_resources(void) | |||
548 | res->start = memory_chunk[i].addr; | 684 | res->start = memory_chunk[i].addr; |
549 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; | 685 | res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; |
550 | request_resource(&iomem_resource, res); | 686 | request_resource(&iomem_resource, res); |
551 | request_resource(res, &code_resource); | 687 | |
552 | request_resource(res, &data_resource); | 688 | if (code_resource.start >= res->start && |
689 | code_resource.start <= res->end && | ||
690 | code_resource.end > res->end) { | ||
691 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
692 | memcpy(sub_res, &code_resource, | ||
693 | sizeof(struct resource)); | ||
694 | sub_res->end = res->end; | ||
695 | code_resource.start = res->end + 1; | ||
696 | request_resource(res, sub_res); | ||
697 | } | ||
698 | |||
699 | if (code_resource.start >= res->start && | ||
700 | code_resource.start <= res->end && | ||
701 | code_resource.end <= res->end) | ||
702 | request_resource(res, &code_resource); | ||
703 | |||
704 | if (data_resource.start >= res->start && | ||
705 | data_resource.start <= res->end && | ||
706 | data_resource.end > res->end) { | ||
707 | sub_res = alloc_bootmem_low(sizeof(struct resource)); | ||
708 | memcpy(sub_res, &data_resource, | ||
709 | sizeof(struct resource)); | ||
710 | sub_res->end = res->end; | ||
711 | data_resource.start = res->end + 1; | ||
712 | request_resource(res, sub_res); | ||
713 | } | ||
714 | |||
715 | if (data_resource.start >= res->start && | ||
716 | data_resource.start <= res->end && | ||
717 | data_resource.end <= res->end) | ||
718 | request_resource(res, &data_resource); | ||
553 | } | 719 | } |
554 | } | 720 | } |
555 | 721 | ||
@@ -585,7 +751,7 @@ static void __init | |||
585 | setup_memory(void) | 751 | setup_memory(void) |
586 | { | 752 | { |
587 | unsigned long bootmap_size; | 753 | unsigned long bootmap_size; |
588 | unsigned long start_pfn, end_pfn, init_pfn; | 754 | unsigned long start_pfn, end_pfn; |
589 | int i; | 755 | int i; |
590 | 756 | ||
591 | /* | 757 | /* |
@@ -595,10 +761,6 @@ setup_memory(void) | |||
595 | start_pfn = PFN_UP(__pa(&_end)); | 761 | start_pfn = PFN_UP(__pa(&_end)); |
596 | end_pfn = max_pfn = PFN_DOWN(memory_end); | 762 | end_pfn = max_pfn = PFN_DOWN(memory_end); |
597 | 763 | ||
598 | /* Initialize storage key for kernel pages */ | ||
599 | for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++) | ||
600 | page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY); | ||
601 | |||
602 | #ifdef CONFIG_BLK_DEV_INITRD | 764 | #ifdef CONFIG_BLK_DEV_INITRD |
603 | /* | 765 | /* |
604 | * Move the initrd in case the bitmap of the bootmem allocater | 766 | * Move the initrd in case the bitmap of the bootmem allocater |