aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/kernel/traps.c29
-rw-r--r--arch/s390/mm/fault.c113
2 files changed, 5 insertions, 137 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index 6b8703ec2ae6..c5bd36fae56b 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -57,7 +57,6 @@ int sysctl_userprocess_debug = 0;
57 57
58extern pgm_check_handler_t do_protection_exception; 58extern pgm_check_handler_t do_protection_exception;
59extern pgm_check_handler_t do_dat_exception; 59extern pgm_check_handler_t do_dat_exception;
60extern pgm_check_handler_t do_pseudo_page_fault;
61#ifdef CONFIG_PFAULT 60#ifdef CONFIG_PFAULT
62extern int pfault_init(void); 61extern int pfault_init(void);
63extern void pfault_fini(void); 62extern void pfault_fini(void);
@@ -676,20 +675,6 @@ asmlinkage void kernel_stack_overflow(struct pt_regs * regs)
676 panic("Corrupt kernel stack, can't continue."); 675 panic("Corrupt kernel stack, can't continue.");
677} 676}
678 677
679#ifndef CONFIG_ARCH_S390X
680static int
681pagex_reboot_event(struct notifier_block *this, unsigned long event, void *ptr)
682{
683 if (MACHINE_IS_VM)
684 cpcmd("SET PAGEX OFF", NULL, 0, NULL);
685 return NOTIFY_DONE;
686}
687
688static struct notifier_block pagex_reboot_notifier = {
689 .notifier_call = &pagex_reboot_event,
690};
691#endif
692
693/* init is done in lowcore.S and head.S */ 678/* init is done in lowcore.S and head.S */
694 679
695void __init trap_init(void) 680void __init trap_init(void)
@@ -717,9 +702,7 @@ void __init trap_init(void)
717 pgm_check_table[0x11] = &do_dat_exception; 702 pgm_check_table[0x11] = &do_dat_exception;
718 pgm_check_table[0x12] = &translation_exception; 703 pgm_check_table[0x12] = &translation_exception;
719 pgm_check_table[0x13] = &special_op_exception; 704 pgm_check_table[0x13] = &special_op_exception;
720#ifndef CONFIG_ARCH_S390X 705#ifdef CONFIG_ARCH_S390X
721 pgm_check_table[0x14] = &do_pseudo_page_fault;
722#else /* CONFIG_ARCH_S390X */
723 pgm_check_table[0x38] = &do_dat_exception; 706 pgm_check_table[0x38] = &do_dat_exception;
724 pgm_check_table[0x39] = &do_dat_exception; 707 pgm_check_table[0x39] = &do_dat_exception;
725 pgm_check_table[0x3A] = &do_dat_exception; 708 pgm_check_table[0x3A] = &do_dat_exception;
@@ -731,12 +714,10 @@ void __init trap_init(void)
731 pgm_check_table[0x40] = &do_monitor_call; 714 pgm_check_table[0x40] = &do_monitor_call;
732 715
733 if (MACHINE_IS_VM) { 716 if (MACHINE_IS_VM) {
717#ifdef CONFIG_PFAULT
734 /* 718 /*
735 * First try to get pfault pseudo page faults going. 719 * Try to get pfault pseudo page faults going.
736 * If this isn't available turn on pagex page faults.
737 */ 720 */
738#ifdef CONFIG_PFAULT
739 /* request the 0x2603 external interrupt */
740 if (register_early_external_interrupt(0x2603, pfault_interrupt, 721 if (register_early_external_interrupt(0x2603, pfault_interrupt,
741 &ext_int_pfault) != 0) 722 &ext_int_pfault) != 0)
742 panic("Couldn't request external interrupt 0x2603"); 723 panic("Couldn't request external interrupt 0x2603");
@@ -748,9 +729,5 @@ void __init trap_init(void)
748 unregister_early_external_interrupt(0x2603, pfault_interrupt, 729 unregister_early_external_interrupt(0x2603, pfault_interrupt,
749 &ext_int_pfault); 730 &ext_int_pfault);
750#endif 731#endif
751#ifndef CONFIG_ARCH_S390X
752 register_reboot_notifier(&pagex_reboot_notifier);
753 cpcmd("SET PAGEX ON", NULL, 0, NULL);
754#endif
755 } 732 }
756} 733}
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index 856a971759b1..64e32da77754 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -352,115 +352,6 @@ void do_dat_exception(struct pt_regs *regs, unsigned long error_code)
352 do_exception(regs, error_code & 0xff, 0); 352 do_exception(regs, error_code & 0xff, 0);
353} 353}
354 354
355#ifndef CONFIG_ARCH_S390X
356
357typedef struct _pseudo_wait_t {
358 struct _pseudo_wait_t *next;
359 wait_queue_head_t queue;
360 unsigned long address;
361 int resolved;
362} pseudo_wait_t;
363
364static pseudo_wait_t *pseudo_lock_queue = NULL;
365static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
366
367/*
368 * This routine handles 'pagex' pseudo page faults.
369 */
370asmlinkage void
371do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
372{
373 pseudo_wait_t wait_struct;
374 pseudo_wait_t *ptr, *last, *next;
375 unsigned long address;
376
377 /*
378 * get the failing address
379 * more specific the segment and page table portion of
380 * the address
381 */
382 address = S390_lowcore.trans_exc_code & 0xfffff000;
383
384 if (address & 0x80000000) {
385 /* high bit set -> a page has been swapped in by VM */
386 address &= 0x7fffffff;
387 spin_lock(&pseudo_wait_spinlock);
388 last = NULL;
389 ptr = pseudo_lock_queue;
390 while (ptr != NULL) {
391 next = ptr->next;
392 if (address == ptr->address) {
393 /*
394 * This is one of the processes waiting
395 * for the page. Unchain from the queue.
396 * There can be more than one process
397 * waiting for the same page. VM presents
398 * an initial and a completion interrupt for
399 * every process that tries to access a
400 * page swapped out by VM.
401 */
402 if (last == NULL)
403 pseudo_lock_queue = next;
404 else
405 last->next = next;
406 /* now wake up the process */
407 ptr->resolved = 1;
408 wake_up(&ptr->queue);
409 } else
410 last = ptr;
411 ptr = next;
412 }
413 spin_unlock(&pseudo_wait_spinlock);
414 } else {
415 /* Pseudo page faults in kernel mode is a bad idea */
416 if (!(regs->psw.mask & PSW_MASK_PSTATE)) {
417 /*
418 * VM presents pseudo page faults if the interrupted
419 * state was not disabled for interrupts. So we can
420 * get pseudo page fault interrupts while running
421 * in kernel mode. We simply access the page here
422 * while we are running disabled. VM will then swap
423 * in the page synchronously.
424 */
425 if (check_user_space(regs, error_code) == 0)
426 /* dereference a virtual kernel address */
427 __asm__ __volatile__ (
428 " ic 0,0(%0)"
429 : : "a" (address) : "0");
430 else
431 /* dereference a virtual user address */
432 __asm__ __volatile__ (
433 " la 2,0(%0)\n"
434 " sacf 512\n"
435 " ic 2,0(2)\n"
436 "0:sacf 0\n"
437 ".section __ex_table,\"a\"\n"
438 " .align 4\n"
439 " .long 0b,0b\n"
440 ".previous"
441 : : "a" (address) : "2" );
442
443 return;
444 }
445 /* initialize and add element to pseudo_lock_queue */
446 init_waitqueue_head (&wait_struct.queue);
447 wait_struct.address = address;
448 wait_struct.resolved = 0;
449 spin_lock(&pseudo_wait_spinlock);
450 wait_struct.next = pseudo_lock_queue;
451 pseudo_lock_queue = &wait_struct;
452 spin_unlock(&pseudo_wait_spinlock);
453 /*
454 * The instruction that caused the program check will
455 * be repeated. Don't signal single step via SIGTRAP.
456 */
457 clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
458 /* go to sleep */
459 wait_event(wait_struct.queue, wait_struct.resolved);
460 }
461}
462#endif /* CONFIG_ARCH_S390X */
463
464#ifdef CONFIG_PFAULT 355#ifdef CONFIG_PFAULT
465/* 356/*
466 * 'pfault' pseudo page faults routines. 357 * 'pfault' pseudo page faults routines.
@@ -508,7 +399,7 @@ int pfault_init(void)
508 " .quad 0b,1b\n" 399 " .quad 0b,1b\n"
509#endif /* CONFIG_ARCH_S390X */ 400#endif /* CONFIG_ARCH_S390X */
510 ".previous" 401 ".previous"
511 : "=d" (rc) : "a" (&refbk) : "cc" ); 402 : "=d" (rc) : "a" (&refbk), "m" (refbk) : "cc" );
512 __ctl_set_bit(0, 9); 403 __ctl_set_bit(0, 9);
513 return rc; 404 return rc;
514} 405}
@@ -532,7 +423,7 @@ void pfault_fini(void)
532 " .quad 0b,0b\n" 423 " .quad 0b,0b\n"
533#endif /* CONFIG_ARCH_S390X */ 424#endif /* CONFIG_ARCH_S390X */
534 ".previous" 425 ".previous"
535 : : "a" (&refbk) : "cc" ); 426 : : "a" (&refbk), "m" (refbk) : "cc" );
536} 427}
537 428
538asmlinkage void 429asmlinkage void