ref: dd193a6e22c0911760aa56bbf0df06b4b75772ca
dir: /kern/seg.c/
#include <u.h>
#include <lib.h>
#include "dat.h"
#include "fns.h"
Segment *
newseg(u32int start, u32int size, int idx)
{
Segment *s;
if(debug)
print("newseg: size=%.8ux start=%.8ux idx=%d\n", size, start, idx);
s = malloc(sizeof *s);
if(s == nil)
panic("%r");
memset(s, 0, sizeof *s);
incref(&s->ref);
s->start = start;
s->size = size;
s->dref = malloc(size + sizeof(Ref));
if(s->dref == nil)
panic("%r");
memset(s->dref, 0, sizeof(Ref));
incref(s->dref);
s->data = s->dref + 1;
if(idx == SEGBSS)
s->flags = SEGFLLOCK;
up->S[idx] = s;
return s;
}
void
freesegs(void)
{
Segment **s, *ss;
for(s = up->S; s < up->S + SEGNUM; s++) {
if(*s == nil)
continue;
ss = *s;
if(decref((*s)->dref) == 0)
free((*s)->dref);
if(decref(&ss->ref) == 0)
free(*s);
*s = nil;
}
}
void *
vaddr(u32int addr, u32int len, Segment **seg)
{
Segment **ss, *s;
for (ss = up->S; ss < up->S + SEGNUM; ss++) {
if (*ss == nil)
continue;
s = *ss;
if (addr >= s->start && addr < s->start + s->size) {
if (addr + len > s->start + s->size)
break;
if (s->flags & SEGFLLOCK)
rlock(&s->rw);
*seg = s;
// if(debug)
// print("vaddr addr=%.8ux, (%d), PC=%.8ux index=%.8ux\n", addr, len, up->R[15], s->start);
return (char *)s->data + (addr - s->start);
}
}
panic("fault addr=%.8ux, (%d), PC=%.8ux", addr, len, up->R[15]);
return nil;
}
void*
vaddrnol(u32int addr, u32int len)
{
Segment *seg;
void *ret;
ret = vaddr(addr, len, &seg);
segunlock(seg);
return ret;
}
/* might be made a macro for hurr durr performance */
void
segunlock(Segment *s)
{
if(s->flags & SEGFLLOCK)
runlock(&s->rw);
}
void *
copyifnec(u32int addr, int len, int *copied)
{
void *targ, *ret;
Segment *seg;
targ = vaddr(addr, len > 0 ? len : 0, &seg);
if((seg->flags & SEGFLLOCK) == 0) {
*copied = 0;
return targ;
}
if(len < 0)
len = strlen(targ) + 1;
ret = malloc(len);
if (ret == nil)
panic("%r");
setmalloctag(ret, getcallerpc(&addr));
memcpy(ret, targ, len);
segunlock(seg);
*copied = 1;
return ret;
}
void *
bufifnec(u32int addr, int len, int *buffered)
{
void *targ, *v;
Segment *seg;
targ = vaddr(addr, len, &seg);
if((seg->flags & SEGFLLOCK) == 0) {
*buffered = 0;
return targ;
}
segunlock(seg);
*buffered = 1;
v = malloc(len);
if (v == nil)
panic("%r");
setmalloctag(v, getcallerpc(&addr));
return v;
}
void
copyback(u32int addr, int len, void *data)
{
void *targ;
Segment *seg;
if(len <= 0) {
free(data);
return;
}
targ = vaddr(addr, len, &seg);
memmove(targ, data, len);
segunlock(seg);
free(data);
}