shithub: drawcpu

ref: 206fff9e92b75aa0e3151c2fd657e93bb458581c
dir: /kern/seg.c/

View raw version
#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);
}