jehanne/sys/src/kern/port/fault.c

130 lines
2.6 KiB
C

/* Copyright (C) Charles Forsyth
* See /doc/license/NOTICE.Plan9-9k.txt for details about the licensing.
*/
/* Portions of this file are Copyright (C) 2015-2018 Giacomo Tesio <giacomo@tesio.it>
* See /doc/license/gpl-2.0.txt for details about the licensing.
*/
#define _DBGC_ 'F'
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "../port/error.h"
int
fault(uintptr_t addr, uintptr_t pc, int ftype)
{
ProcSegment *s;
char *sps;
uintptr_t mmuphys, faddr;
if(up == nil)
panic("fault: nil up");
if(up->nlocks){
panic("fault: %#p %s pc %#p: %s: nlocks %d %#p\n", addr, up->text, pc, up->user, up->nlocks, up->lastlock? lockgetpc(up->lastlock): 0);
//dumpstack();
}
sps = up->psstate;
up->psstate = "Fault";
m->pfault++;
spllo();
s = proc_segment(up, addr);
if(s == nil)
return -1;
mmuphys = 0;
faddr = addr; /* remember original address for better errors */
if(segment_fault(&mmuphys, &addr, s, ftype))
{
if(DBGFLG)
proc_check_pages();
up->psstate = sps;
mmuput(addr, mmuphys);
if(ftype == FaultExecute)
peekAtExecFaults(addr);
return 0;
}
if(up->procctl == Proc_exitbig)
pexit("out of memory", 1);
pprint("%s fault fail %s(%c%c%c) pid %d (%s) addr 0x%p pc 0x%p\n",
fault_types[ftype],
segment_types[s->type],
(s->permissions & SgRead) != 0 ? 'r' : '-',
(s->permissions & SgWrite) != 0 ? 'w' : '-',
(s->permissions & SgExecute) != 0 ? 'x' : '-',
up->pid, up->text, faddr, pc);
splhi();
up->psstate = sps;
return -1;
}
/*
* Called only in a system call
*/
int
okaddr(uintptr_t addr, long len, int write)
{
ProcSegment *s;
if(len >= 0) {
for(;;) {
s = proc_segment(up, addr);
if(s == 0 || (write && !(s->permissions&SgWrite)))
break;
if(addr+len > s->top) {
len -= s->top - addr;
addr = s->top;
continue;
}
return 1;
}
}
return 0;
}
void*
validaddr(void* addr, long len, int write)
{
if(!okaddr(PTR2UINT(addr), len, write)){
pprint("trap: invalid address %#p/%ld in sys call pc=%#p\n", addr, len, userpc(nil));
postnote(up, 1, "sys: bad address in syscall", NDebug);
error(Ebadarg);
}
return UINT2PTR(addr);
}
/*
* &s[0] is known to be a valid address.
*/
void*
vmemchr(void *s, int c, int n)
{
int np;
uintptr_t a;
void *t;
a = PTR2UINT(s);
while(ROUNDUP(a, PGSZ) != ROUNDUP(a+n-1, PGSZ)){
/* spans pages; handle this page */
np = PGSZ - (a & (PGSZ-1));
t = jehanne_memchr(UINT2PTR(a), c, np);
if(t)
return t;
a += np;
n -= np;
if(!iskaddr(a))
validaddr(UINT2PTR(a), 1, 0);
}
/* fits in one page */
return jehanne_memchr(UINT2PTR(a), c, n);
}