/*1* This file is subject to the terms and conditions of the GNU General Public2* License. See the file "COPYING" in the main directory of this archive3* for more details.4*5*6* Copyright (C) 1995, 1996, 1997, 1998 by Ralf Baechle7* Copyright 1999 SuSE GmbH (Philipp Rumpf, [email protected])8* Copyright 1999 Hewlett Packard Co.9*10*/1112#include <linux/mm.h>13#include <linux/ptrace.h>14#include <linux/sched.h>15#include <linux/interrupt.h>16#include <linux/module.h>1718#include <asm/uaccess.h>19#include <asm/traps.h>2021#define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */22/* dumped to the console via printk) */232425/* Various important other fields */26#define bit22set(x) (x & 0x00000200)27#define bits23_25set(x) (x & 0x000001c0)28#define isGraphicsFlushRead(x) ((x & 0xfc003fdf) == 0x04001a80)29/* extended opcode is 0x6a */3031#define BITSSET 0x1c0 /* for identifying LDCW */323334DEFINE_PER_CPU(struct exception_data, exception_data);3536/*37* parisc_acctyp(unsigned int inst) --38* Given a PA-RISC memory access instruction, determine if the39* the instruction would perform a memory read or memory write40* operation.41*42* This function assumes that the given instruction is a memory access43* instruction (i.e. you should really only call it if you know that44* the instruction has generated some sort of a memory access fault).45*46* Returns:47* VM_READ if read operation48* VM_WRITE if write operation49* VM_EXEC if execute operation50*/51static unsigned long52parisc_acctyp(unsigned long code, unsigned int inst)53{54if (code == 6 || code == 16)55return VM_EXEC;5657switch (inst & 0xf0000000) {58case 0x40000000: /* load */59case 0x50000000: /* new load */60return VM_READ;6162case 0x60000000: /* store */63case 0x70000000: /* new store */64return VM_WRITE;6566case 0x20000000: /* coproc */67case 0x30000000: /* coproc2 */68if (bit22set(inst))69return VM_WRITE;7071case 0x0: /* indexed/memory management */72if (bit22set(inst)) {73/*74* Check for the 'Graphics Flush Read' instruction.75* It resembles an FDC instruction, except for bits76* 20 and 21. Any combination other than zero will77* utilize the block mover functionality on some78* older PA-RISC platforms. The case where a block79* move is performed from VM to graphics IO space80* should be treated as a READ.81*82* The significance of bits 20,21 in the FDC83* instruction is:84*85* 00 Flush data cache (normal instruction behavior)86* 01 Graphics flush write (IO space -> VM)87* 10 Graphics flush read (VM -> IO space)88* 11 Graphics flush read/write (VM <-> IO space)89*/90if (isGraphicsFlushRead(inst))91return VM_READ;92return VM_WRITE;93} else {94/*95* Check for LDCWX and LDCWS (semaphore instructions).96* If bits 23 through 25 are all 1's it is one of97* the above two instructions and is a write.98*99* Note: With the limited bits we are looking at,100* this will also catch PROBEW and PROBEWI. However,101* these should never get in here because they don't102* generate exceptions of the type:103* Data TLB miss fault/data page fault104* Data memory protection trap105*/106if (bits23_25set(inst) == BITSSET)107return VM_WRITE;108}109return VM_READ; /* Default */110}111return VM_READ; /* Default */112}113114#undef bit22set115#undef bits23_25set116#undef isGraphicsFlushRead117#undef BITSSET118119120#if 0121/* This is the treewalk to find a vma which is the highest that has122* a start < addr. We're using find_vma_prev instead right now, but123* we might want to use this at some point in the future. Probably124* not, but I want it committed to CVS so I don't lose it :-)125*/126while (tree != vm_avl_empty) {127if (tree->vm_start > addr) {128tree = tree->vm_avl_left;129} else {130prev = tree;131if (prev->vm_next == NULL)132break;133if (prev->vm_next->vm_start > addr)134break;135tree = tree->vm_avl_right;136}137}138#endif139140int fixup_exception(struct pt_regs *regs)141{142const struct exception_table_entry *fix;143144fix = search_exception_tables(regs->iaoq[0]);145if (fix) {146struct exception_data *d;147d = &__get_cpu_var(exception_data);148d->fault_ip = regs->iaoq[0];149d->fault_space = regs->isr;150d->fault_addr = regs->ior;151152regs->iaoq[0] = ((fix->fixup) & ~3);153/*154* NOTE: In some cases the faulting instruction155* may be in the delay slot of a branch. We156* don't want to take the branch, so we don't157* increment iaoq[1], instead we set it to be158* iaoq[0]+4, and clear the B bit in the PSW159*/160regs->iaoq[1] = regs->iaoq[0] + 4;161regs->gr[0] &= ~PSW_B; /* IPSW in gr[0] */162163return 1;164}165166return 0;167}168169void do_page_fault(struct pt_regs *regs, unsigned long code,170unsigned long address)171{172struct vm_area_struct *vma, *prev_vma;173struct task_struct *tsk = current;174struct mm_struct *mm = tsk->mm;175unsigned long acc_type;176int fault;177178if (in_atomic() || !mm)179goto no_context;180181down_read(&mm->mmap_sem);182vma = find_vma_prev(mm, address, &prev_vma);183if (!vma || address < vma->vm_start)184goto check_expansion;185/*186* Ok, we have a good vm_area for this memory access. We still need to187* check the access permissions.188*/189190good_area:191192acc_type = parisc_acctyp(code,regs->iir);193194if ((vma->vm_flags & acc_type) != acc_type)195goto bad_area;196197/*198* If for any reason at all we couldn't handle the fault, make199* sure we exit gracefully rather than endlessly redo the200* fault.201*/202203fault = handle_mm_fault(mm, vma, address, (acc_type & VM_WRITE) ? FAULT_FLAG_WRITE : 0);204if (unlikely(fault & VM_FAULT_ERROR)) {205/*206* We hit a shared mapping outside of the file, or some207* other thing happened to us that made us unable to208* handle the page fault gracefully.209*/210if (fault & VM_FAULT_OOM)211goto out_of_memory;212else if (fault & VM_FAULT_SIGBUS)213goto bad_area;214BUG();215}216if (fault & VM_FAULT_MAJOR)217current->maj_flt++;218else219current->min_flt++;220up_read(&mm->mmap_sem);221return;222223check_expansion:224vma = prev_vma;225if (vma && (expand_stack(vma, address) == 0))226goto good_area;227228/*229* Something tried to access memory that isn't in our memory map..230*/231bad_area:232up_read(&mm->mmap_sem);233234if (user_mode(regs)) {235struct siginfo si;236237#ifdef PRINT_USER_FAULTS238printk(KERN_DEBUG "\n");239printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n",240task_pid_nr(tsk), tsk->comm, code, address);241if (vma) {242printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n",243vma->vm_start, vma->vm_end);244}245show_regs(regs);246#endif247/* FIXME: actually we need to get the signo and code correct */248si.si_signo = SIGSEGV;249si.si_errno = 0;250si.si_code = SEGV_MAPERR;251si.si_addr = (void __user *) address;252force_sig_info(SIGSEGV, &si, current);253return;254}255256no_context:257258if (!user_mode(regs) && fixup_exception(regs)) {259return;260}261262parisc_terminate("Bad Address (null pointer deref?)", regs, code, address);263264out_of_memory:265up_read(&mm->mmap_sem);266if (!user_mode(regs))267goto no_context;268pagefault_out_of_memory();269}270271272