oskit_uvm_pfault.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 242 行
C
242 行
/* * Copyright (c) 2001 The University of Utah and the Flux Group. * All rights reserved. * * This file is part of the Flux OSKit. The OSKit is free software, also known * as "open source;" you can redistribute it and/or modify it under the terms * of the GNU General Public License (GPL), version 2, as published by the Free * Software Foundation (FSF). To explore alternate licensing terms, contact * the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271. * * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have * received a copy of the GPL along with the OSKit; see the file COPYING. If * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. */#include <sys/param.h>#include <sys/systm.h>#include <sys/mman.h>#include <sys/proc.h>#include <sys/malloc.h>#include <sys/pool.h>#include <uvm/uvm.h>#include <sys/user.h>#include <machine/pcb.h>#include <machine/trap.h>#include "opt_cputype.h"#include <oskit/x86/trap.h>#include <oskit/x86/base_trap.h>#include <oskit/x86/gdb.h>#include <oskit/x86/eflags.h>#include "oskit_uvm_internal.h"static voidcall_handler(oskit_vmspace_t oskitvm, int signo, struct trap_state *frame){ if (oskitvm->vm_handler) { (*oskitvm->vm_handler)(oskitvm, signo, frame); } else { oskit_sendsig(signo, frame); }}/* * Page fault handler. Taken from sys/arch/i386/i386/trap.c * * Note that this handler runs under interrupt enabled. * %cr2 is saved/restored when a context switch occurs. */extern intoskit_uvm_pfault_handler(struct trap_state *frame){ register struct proc *p = curproc; oskit_vmspace_t oskitvm = oskit_uvm_curvm; struct pcb *pcb = NULL; extern char fusubail[]; int type; type = frame->trapno; if (!KERNELMODE(frame->cs, frame->eflags)) { type |= T_USER; p->p_md.md_regs = frame; } switch (type) { case T_PAGE_FAULT: if (p == 0) goto we_re_toast; pcb = &p->p_addr->u_pcb; /* * fusubail is used by [fs]uswintr() to prevent page faulting * from inside the profiling interrupt. */ if (pcb != DEFAULT_PCB && pcb->pcb_onfault == fusubail) goto copyfault;#if 0 /* XXX - check only applies to 386's and 486's with WP off */ if (frame->err & PGEX_P) goto we_re_toast;#endif /* FALLTHROUGH */ case T_PAGE_FAULT|T_USER: { /* page fault */ register vaddr_t va; register struct vmspace *vm; register vm_map_t map; int rv; vm_prot_t ftype; extern vm_map_t kernel_map; unsigned nss; va = trunc_page((vaddr_t)rcr2()); /* * It is only a kernel address space fault iff: * 1. (type & T_USER) == 0 and * 2. pcb_onfault not set or * 3. pcb_onfault set but supervisor space fault * The last can occur during an exec() copyin where the * argument space is lazy-allocated. */ if (type == T_PAGE_FAULT && va <= VM_MAX_KERNEL_ADDRESS) map = kernel_map; else { vm = p->p_vmspace; assert(vm); map = &vm->vm_map; } if (frame->err & PGEX_W) ftype = VM_PROT_READ | VM_PROT_WRITE; else ftype = VM_PROT_READ;#ifdef DIAGNOSTIC if (map == kernel_map && va == 0) { printf("trap: bad kernel access at %lx\n", va); goto we_re_toast; }#endif nss = 0;#if 0 if ((caddr_t)va >= vm->vm_maxsaddr /*&& (caddr_t)va < (caddr_t)VM_MAXUSER_ADDRESS*/ && map != kernel_map) { nss = btoc(USRSTACK-(unsigned)va); if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) { /* * We used to fail here. However, it may * just have been an mmap()ed page low * in the stack, which is legal. If it * wasn't, uvm_fault() will fail below. * * Set nss to 0, since this case is not * a "stack extension". */ nss = 0; } }#endif /* Fault the original page in. */ UVM_LOCK; XPRINTF(OSKIT_DEBUG_FAULT, "CALL uvm_fault, map %p, va 0x%lx, " "ftype %x, thread %d, type %d\n", map, (long)va, ftype, (int)pthread_self(), type); rv = uvm_fault(map, va, 0, ftype); XPRINTF(OSKIT_DEBUG_FAULT, "RETURN from uvm_fault, " "thread %d, rv %d\n", (int)pthread_self(), rv); UVM_UNLOCK; if (rv == KERN_SUCCESS) {#if 0 if (nss > vm->vm_ssize) vm->vm_ssize = nss;#endif if (type == T_PAGE_FAULT) return 0; goto out; } XPRINTF(OSKIT_DEBUG_FAULT, __FUNCTION__ ": uvm_fault failed (%d) accessing va 0x%lx from %s " "mode, thread %d\n", rv, (unsigned long)va, (type == T_PAGE_FAULT ? "kernel" : "user"), (int)pthread_self()); if (type == T_PAGE_FAULT) { if (pcb != DEFAULT_PCB && pcb->pcb_onfault != 0) goto copyfault; call_handler(oskitvm, SIGSEGV, frame); break; } if (rv == KERN_RESOURCE_SHORTAGE) { printf("UVM: proc %p killed: out of swap\n", p); if (oskitvm->vm_handler) { (*oskitvm->vm_handler)(oskitvm, SIGKILL, frame); } oskit_uvm_vmspace_set(&oskit_uvm_kvmspace); oskit_uvm_destroy(oskitvm); pthread_exit(0); } else { call_handler(oskitvm, SIGSEGV, frame); } break; } default: we_re_toast: panic(__FUNCTION__"\n"); } out: return 0; copyfault: frame->eip = (int)pcb->pcb_onfault; return 0;}#ifdef I386_CPU/* * Compensate for 386 brain damage (missing URKR) */inttrapwrite(addr) unsigned addr;{ vaddr_t va; unsigned nss; struct proc *p; struct vmspace *vm; va = trunc_page((vaddr_t)addr); if (va < VM_MIN_ADDRESS) return 1; nss = 0; p = curproc; vm = p->p_vmspace;#if 0 if ((caddr_t)va >= vm->vm_maxsaddr) { nss = btoc(USRSTACK-(unsigned)va); if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) nss = 0; }#endif if (uvm_fault(&vm->vm_map, va, 0, VM_PROT_READ | VM_PROT_WRITE) != KERN_SUCCESS) return 1;#if 0 if (nss > vm->vm_ssize) vm->vm_ssize = nss;#endif return 0;}#endif
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?