PageRenderTime 35ms CodeModel.GetById 16ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/arch/um/kernel/trap_kern.c

https://bitbucket.org/evzijst/gittest
C | 251 lines | 206 code | 27 blank | 18 comment | 49 complexity | 4f76b16707c31ea9fa59cee994688d3d MD5 | raw file
  1/* 
  2 * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com)
  3 * Licensed under the GPL
  4 */
  5
  6#include "linux/kernel.h"
  7#include "asm/errno.h"
  8#include "linux/sched.h"
  9#include "linux/mm.h"
 10#include "linux/spinlock.h"
 11#include "linux/config.h"
 12#include "linux/init.h"
 13#include "linux/ptrace.h"
 14#include "asm/semaphore.h"
 15#include "asm/pgtable.h"
 16#include "asm/pgalloc.h"
 17#include "asm/tlbflush.h"
 18#include "asm/a.out.h"
 19#include "asm/current.h"
 20#include "asm/irq.h"
 21#include "user_util.h"
 22#include "kern_util.h"
 23#include "kern.h"
 24#include "chan_kern.h"
 25#include "mconsole_kern.h"
 26#include "2_5compat.h"
 27#include "mem.h"
 28#include "mem_kern.h"
 29
 30int handle_page_fault(unsigned long address, unsigned long ip, 
 31		      int is_write, int is_user, int *code_out)
 32{
 33	struct mm_struct *mm = current->mm;
 34	struct vm_area_struct *vma;
 35	pgd_t *pgd;
 36	pud_t *pud;
 37	pmd_t *pmd;
 38	pte_t *pte;
 39	unsigned long page;
 40	int err = -EFAULT;
 41
 42	*code_out = SEGV_MAPERR;
 43	down_read(&mm->mmap_sem);
 44	vma = find_vma(mm, address);
 45	if(!vma) 
 46		goto out;
 47	else if(vma->vm_start <= address) 
 48		goto good_area;
 49	else if(!(vma->vm_flags & VM_GROWSDOWN)) 
 50		goto out;
 51	else if(!ARCH_IS_STACKGROW(address))
 52		goto out;
 53	else if(expand_stack(vma, address)) 
 54		goto out;
 55
 56 good_area:
 57	*code_out = SEGV_ACCERR;
 58	if(is_write && !(vma->vm_flags & VM_WRITE)) 
 59		goto out;
 60	page = address & PAGE_MASK;
 61	pgd = pgd_offset(mm, page);
 62	pud = pud_offset(pgd, page);
 63	pmd = pmd_offset(pud, page);
 64	do {
 65 survive:
 66		switch (handle_mm_fault(mm, vma, address, is_write)){
 67		case VM_FAULT_MINOR:
 68			current->min_flt++;
 69			break;
 70		case VM_FAULT_MAJOR:
 71			current->maj_flt++;
 72			break;
 73		case VM_FAULT_SIGBUS:
 74			err = -EACCES;
 75			goto out;
 76		case VM_FAULT_OOM:
 77			err = -ENOMEM;
 78			goto out_of_memory;
 79		default:
 80			BUG();
 81		}
 82		pgd = pgd_offset(mm, page);
 83		pud = pud_offset(pgd, page);
 84		pmd = pmd_offset(pud, page);
 85		pte = pte_offset_kernel(pmd, page);
 86	} while(!pte_present(*pte));
 87	err = 0;
 88	*pte = pte_mkyoung(*pte);
 89	if(pte_write(*pte)) *pte = pte_mkdirty(*pte);
 90	flush_tlb_page(vma, page);
 91 out:
 92	up_read(&mm->mmap_sem);
 93	return(err);
 94
 95/*
 96 * We ran out of memory, or some other thing happened to us that made
 97 * us unable to handle the page fault gracefully.
 98 */
 99out_of_memory:
100	if (current->pid == 1) {
101		up_read(&mm->mmap_sem);
102		yield();
103		down_read(&mm->mmap_sem);
104		goto survive;
105	}
106	goto out;
107}
108
109LIST_HEAD(physmem_remappers);
110
111void register_remapper(struct remapper *info)
112{
113	list_add(&info->list, &physmem_remappers);
114}
115
116static int check_remapped_addr(unsigned long address, int is_write)
117{
118	struct remapper *remapper;
119	struct list_head *ele;
120	__u64 offset;
121	int fd;
122
123	fd = phys_mapping(__pa(address), &offset);
124	if(fd == -1)
125		return(0);
126
127	list_for_each(ele, &physmem_remappers){
128		remapper = list_entry(ele, struct remapper, list);
129		if((*remapper->proc)(fd, address, is_write, offset))
130			return(1);
131	}
132
133	return(0);
134}
135
136unsigned long segv(unsigned long address, unsigned long ip, int is_write, 
137		   int is_user, void *sc)
138{
139	struct siginfo si;
140	void *catcher;
141	int err;
142
143        if(!is_user && (address >= start_vm) && (address < end_vm)){
144                flush_tlb_kernel_vm();
145                return(0);
146        }
147	else if(check_remapped_addr(address & PAGE_MASK, is_write))
148		return(0);
149	else if(current->mm == NULL)
150		panic("Segfault with no mm");
151	err = handle_page_fault(address, ip, is_write, is_user, &si.si_code);
152
153	catcher = current->thread.fault_catcher;
154	if(!err)
155		return(0);
156	else if(catcher != NULL){
157		current->thread.fault_addr = (void *) address;
158		do_longjmp(catcher, 1);
159	} 
160	else if(current->thread.fault_addr != NULL)
161		panic("fault_addr set but no fault catcher");
162	else if(arch_fixup(ip, sc))
163		return(0);
164
165 	if(!is_user) 
166		panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", 
167		      address, ip);
168
169	if(err == -EACCES){
170		si.si_signo = SIGBUS;
171		si.si_errno = 0;
172		si.si_code = BUS_ADRERR;
173		si.si_addr = (void *)address;
174		force_sig_info(SIGBUS, &si, current);
175	}
176	else if(err == -ENOMEM){
177		printk("VM: killing process %s\n", current->comm);
178		do_exit(SIGKILL);
179	}
180	else {
181		si.si_signo = SIGSEGV;
182		si.si_addr = (void *) address;
183		current->thread.cr2 = address;
184		current->thread.err = is_write;
185		force_sig_info(SIGSEGV, &si, current);
186	}
187	return(0);
188}
189
190void bad_segv(unsigned long address, unsigned long ip, int is_write)
191{
192	struct siginfo si;
193
194	si.si_signo = SIGSEGV;
195	si.si_code = SEGV_ACCERR;
196	si.si_addr = (void *) address;
197	current->thread.cr2 = address;
198	current->thread.err = is_write;
199	force_sig_info(SIGSEGV, &si, current);
200}
201
202void relay_signal(int sig, union uml_pt_regs *regs)
203{
204	if(arch_handle_signal(sig, regs)) return;
205	if(!UPT_IS_USER(regs))
206		panic("Kernel mode signal %d", sig);
207	force_sig(sig, current);
208}
209
210void bus_handler(int sig, union uml_pt_regs *regs)
211{
212	if(current->thread.fault_catcher != NULL)
213		do_longjmp(current->thread.fault_catcher, 1);
214	else relay_signal(sig, regs);
215}
216
217void winch(int sig, union uml_pt_regs *regs)
218{
219	do_IRQ(WINCH_IRQ, regs);
220}
221
222void trap_init(void)
223{
224}
225
226DEFINE_SPINLOCK(trap_lock);
227
228static int trap_index = 0;
229
230int next_trap_index(int limit)
231{
232	int ret;
233
234	spin_lock(&trap_lock);
235	ret = trap_index;
236	if(++trap_index == limit)
237		trap_index = 0;
238	spin_unlock(&trap_lock);
239	return(ret);
240}
241
242/*
243 * Overrides for Emacs so that we follow Linus's tabbing style.
244 * Emacs will notice this stuff at the end of the file and automatically
245 * adjust the settings for this buffer only.  This must remain at the end
246 * of the file.
247 * ---------------------------------------------------------------------------
248 * Local variables:
249 * c-file-style: "linux"
250 * End:
251 */