286 lines
4.2 KiB
C
286 lines
4.2 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <mach.h>
|
|
#include "arm.h"
|
|
|
|
extern ulong textbase;
|
|
|
|
ulong
|
|
ifetch(ulong addr)
|
|
{
|
|
uchar *va;
|
|
|
|
if(addr&3) {
|
|
Bprint(bioout, "Address error (I-fetch) vaddr %.8lux\n", addr);
|
|
longjmp(errjmp, 0);
|
|
}
|
|
|
|
if(icache.on)
|
|
updateicache(addr);
|
|
iprof[(addr-textbase)/PROFGRAN]++;
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
|
|
return va[3]<<24 | va[2]<<16 | va[1]<<8 | va[0];
|
|
}
|
|
|
|
ulong
|
|
getmem_4(ulong addr)
|
|
{
|
|
ulong val;
|
|
int i;
|
|
|
|
val = 0;
|
|
for(i = 0; i < 4; i++)
|
|
val = (val>>8) | (getmem_b(addr++)<<24);
|
|
return val;
|
|
}
|
|
|
|
ulong
|
|
getmem_2(ulong addr)
|
|
{
|
|
ulong val;
|
|
int i;
|
|
|
|
val = 0;
|
|
for(i = 0; i < 2; i++)
|
|
val = (val>>8) | (getmem_b(addr++)<<16);
|
|
return val;
|
|
}
|
|
|
|
ulong
|
|
getmem_w(ulong addr)
|
|
{
|
|
uchar *va;
|
|
ulong w;
|
|
|
|
if(addr&3) {
|
|
w = getmem_w(addr & ~3);
|
|
while(addr & 3) {
|
|
w = (w>>8) | (w<<24);
|
|
addr--;
|
|
}
|
|
return w;
|
|
}
|
|
if(membpt)
|
|
brkchk(addr, Read);
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
|
|
return va[3]<<24 | va[2]<<16 | va[1]<<8 | va[0];
|
|
}
|
|
|
|
ushort
|
|
getmem_h(ulong addr)
|
|
{
|
|
uchar *va;
|
|
ulong w;
|
|
|
|
if(addr&1) {
|
|
w = getmem_h(addr & ~1);
|
|
while(addr & 1) {
|
|
w = (w>>8) | (w<<8);
|
|
addr--;
|
|
}
|
|
return w;
|
|
}
|
|
if(membpt)
|
|
brkchk(addr, Read);
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
|
|
return va[1]<<8 | va[0];
|
|
}
|
|
|
|
uchar
|
|
getmem_b(ulong addr)
|
|
{
|
|
uchar *va;
|
|
|
|
if(membpt)
|
|
brkchk(addr, Read);
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
return va[0];
|
|
}
|
|
|
|
uvlong
|
|
getmem_v(ulong addr)
|
|
{
|
|
return ((uvlong)getmem_w(addr+4) << 32) | getmem_w(addr);
|
|
}
|
|
|
|
void
|
|
putmem_h(ulong addr, ushort data)
|
|
{
|
|
uchar *va;
|
|
|
|
if(addr&1) {
|
|
Bprint(bioout, "Address error (Store) vaddr %.8lux\n", addr);
|
|
longjmp(errjmp, 0);
|
|
}
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
|
|
va[1] = data>>8;
|
|
va[0] = data;
|
|
if(membpt)
|
|
brkchk(addr, Write);
|
|
}
|
|
|
|
void
|
|
putmem_w(ulong addr, ulong data)
|
|
{
|
|
uchar *va;
|
|
|
|
if(addr&3) {
|
|
Bprint(bioout, "Address error (Store) vaddr %.8lux\n", addr);
|
|
longjmp(errjmp, 0);
|
|
}
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
|
|
va[3] = data>>24;
|
|
va[2] = data>>16;
|
|
va[1] = data>>8;
|
|
va[0] = data;
|
|
if(membpt)
|
|
brkchk(addr, Write);
|
|
}
|
|
|
|
void
|
|
putmem_b(ulong addr, uchar data)
|
|
{
|
|
uchar *va;
|
|
|
|
va = vaddr(addr);
|
|
va += addr&(BY2PG-1);
|
|
va[0] = data;
|
|
if(membpt)
|
|
brkchk(addr, Write);
|
|
}
|
|
|
|
void
|
|
putmem_v(ulong addr, uvlong data)
|
|
{
|
|
putmem_w(addr, data); /* two stages, to catch brkchk */
|
|
putmem_w(addr+4, data>>32);
|
|
}
|
|
|
|
char *
|
|
memio(char *mb, ulong mem, int size, int dir)
|
|
{
|
|
int i;
|
|
char *buf, c;
|
|
|
|
if(mb == 0)
|
|
mb = emalloc(size);
|
|
|
|
buf = mb;
|
|
switch(dir) {
|
|
default:
|
|
fatal(0, "memio");
|
|
case MemRead:
|
|
while(size--)
|
|
*mb++ = getmem_b(mem++);
|
|
break;
|
|
case MemReadstring:
|
|
for(;;) {
|
|
if(size-- == 0) {
|
|
Bprint(bioout, "memio: user/kernel copy too long for arm\n");
|
|
longjmp(errjmp, 0);
|
|
}
|
|
c = getmem_b(mem++);
|
|
*mb++ = c;
|
|
if(c == '\0')
|
|
break;
|
|
}
|
|
break;
|
|
case MemWrite:
|
|
for(i = 0; i < size; i++)
|
|
putmem_b(mem++, *mb++);
|
|
break;
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
void
|
|
dotlb(ulong vaddr)
|
|
{
|
|
ulong *l, *e;
|
|
|
|
vaddr &= ~(BY2PG-1);
|
|
|
|
e = &tlb.tlbent[tlb.tlbsize];
|
|
for(l = tlb.tlbent; l < e; l++)
|
|
if(*l == vaddr) {
|
|
tlb.hit++;
|
|
return;
|
|
}
|
|
|
|
tlb.miss++;
|
|
tlb.tlbent[lnrand(tlb.tlbsize)] = vaddr;
|
|
}
|
|
|
|
void *
|
|
vaddr(ulong addr)
|
|
{
|
|
Segment *s, *es;
|
|
int off, foff, l, n;
|
|
uchar **p, *a;
|
|
|
|
if(tlb.on)
|
|
dotlb(addr);
|
|
|
|
es = &memory.seg[Nseg];
|
|
for(s = memory.seg; s < es; s++) {
|
|
if(addr >= s->base && addr < s->end) {
|
|
s->refs++;
|
|
off = (addr-s->base)/BY2PG;
|
|
p = &s->table[off];
|
|
if(*p)
|
|
return *p;
|
|
s->rss++;
|
|
switch(s->type) {
|
|
default:
|
|
fatal(0, "vaddr");
|
|
case Text:
|
|
*p = emalloc(BY2PG);
|
|
if(seek(text, s->fileoff+(off*BY2PG), 0) < 0)
|
|
fatal(1, "vaddr text seek");
|
|
if(read(text, *p, BY2PG) < 0)
|
|
fatal(1, "vaddr text read");
|
|
return *p;
|
|
case Data:
|
|
*p = emalloc(BY2PG);
|
|
foff = s->fileoff+(off*BY2PG);
|
|
if(seek(text, foff, 0) < 0)
|
|
fatal(1, "vaddr text seek");
|
|
n = read(text, *p, BY2PG);
|
|
if(n < 0)
|
|
fatal(1, "vaddr text read");
|
|
if(foff + n > s->fileend) {
|
|
l = BY2PG - (s->fileend-foff);
|
|
a = *p+(s->fileend-foff);
|
|
memset(a, 0, l);
|
|
}
|
|
return *p;
|
|
case Bss:
|
|
case Stack:
|
|
*p = emalloc(BY2PG);
|
|
return *p;
|
|
}
|
|
}
|
|
}
|
|
Bprint(bioout, "User TLB miss vaddr 0x%.8lux\n", addr);
|
|
longjmp(errjmp, 0);
|
|
return 0; /*to stop compiler whining*/
|
|
}
|