here's my copy.  it probablly won't work if *ncpu>1 on the standard
system because vmap's no up to the task.

i didn't re-verify that all the vmap() wiggles are necessary with
nix; they are with the pae kernel.

- erik
#include        "u.h"
#include        "../port/lib.h"
#include        "mem.h"
#include        "dat.h"
#include        "fns.h"
#include        "io.h"
#include        "ureg.h"
#include        "../port/error.h"
#include        "amd64.h"

/*
 * we depend on aux/realemu to emulate realmode calls.
 */

enum {
        LORMBUF = 0x9000,
};

static ulong wtab[] = {
        LORMBUF,        LORMBUF+PGSZ,           /* realmode buffer page */
        0xA0000,        0xC0000,                                /* mda/vga 
range */
};

static void*
lomap(uint off)
{
        static uintptr va;
#define O PGSZ

        if(va == 0){
                va = PTR2UINT(vmappat(O, 0x100000 - O, PATWB));
                if(va == 0)
                        error("can't map lo memory");
        }
        return UINT2PTR(va+off - O);
}

static long
rmemrw(int isr, void *va, long n, vlong off)
{
        uchar *a;
        int i;

        a = va;
        if(off >= 0x100000)
                return 0;
        if(off < 0 || n < 0)
                error("bad offset/count");
        if(off+n > 0x100000)
                n = 0x100000 - off;

        if(isr){
                if(off == 0){
                        if(n >= PGSZ)
                                memmove(a, KADDR(0), PGSZ);
                        else
                                memmove(a, KADDR(0), n);
                        n -= PGSZ;
                        off += PGSZ;
                        a += PGSZ;
                }
                if(n > 0)
                        memmove(a, lomap((ulong)off), n);
        }else{
                /* writes are more restricted */
                for(i = 0;; i += 2)
                        if(i == nelem(wtab))
                                error("bad offset/count in write");
                        else if(off >= wtab[i] && off+n <= wtab[i+1]){
                                memmove(lomap((ulong)off), a, n);
                                break;
                        }
        }

        return n;
}

static long
rmemread(Chan*, void *a, long n, vlong off)
{
        return rmemrw(1, a, n, off);
}

static long
rmemwrite(Chan*, void *a, long n, vlong off)
{
        return rmemrw(0, a, n, off);
}

void
realmodelink(void)
{
        addarchfile("realmodemem", 0660, rmemread, rmemwrite);
}

Reply via email to