diff options
Diffstat (limited to 'arch/s390/mm/fault.c')
-rw-r--r-- | arch/s390/mm/fault.c | 113 |
1 files changed, 2 insertions, 111 deletions
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 | |||
357 | typedef 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 | |||
364 | static pseudo_wait_t *pseudo_lock_queue = NULL; | ||
365 | static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */ | ||
366 | |||
367 | /* | ||
368 | * This routine handles 'pagex' pseudo page faults. | ||
369 | */ | ||
370 | asmlinkage void | ||
371 | do_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 | ||
538 | asmlinkage void | 429 | asmlinkage void |