Subversion Repositories planix.SVN

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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"

/*
 * Back the processor into real mode to run a BIOS call,
 * then return.  This must be used carefully, since it 
 * completely disables hardware interrupts (e.g., the i8259)
 * while running.  It is *not* using VM86 mode. 
 * Maybe that's really the right answer, but real mode
 * is fine for now.  We don't expect to use this very much --
 * just for BIOS INT 13 disk i/o.
 */

void realmode0(void);           /* in realmode0.s */
void realmodeintrinst(void);    /* in realmode0.s */
void realmodeend(void);         /* in realmode0.s */

extern ushort rmseg;            /* in realmode0.s */

static Ureg rmu;
static QLock rmlock;
static int beenhere;

void
realmode(Ureg *ureg)
{
        int s, sz;
        ulong cr3;
        uchar *ip;

        qlock(&rmlock);
        if (!beenhere)
                iprint("into bios in real mode...");
        *(Ureg *)RMUADDR = *ureg;

        /*
         * in pxe-loaded bootstraps, the l.s real-mode code is already
         * below 64K, but for pbs-loaded bootstraps, we need to copy it there.
         */
        ip = (void *)realmodeintrinst;          /* the INT instruction */
        ip[1] = ureg->trap;                     /* insert INT number */
        coherence();
        if ((uintptr)KTZERO == KZERO+PXEBASE)   /* pxe-loaded? */
                rmseg = 0;                      /* into JMPFAR instr. */
        else {
                /* copy l.s so that it can be run from 16-bit mode */
                sz = (char *)realmodeend - (char *)KTZERO;
                if (sz > RMSIZE)
                        panic("real mode code %d bytes > %d", sz, RMSIZE);
                rmseg = (RMCODE - KZERO) >> 4;  /* into JMPFAR instr. */
                memmove((void*)RMCODE, (void*)KTZERO, sz);
        }
        coherence();

        s = splhi();
        m->pdb[PDX(0)] = m->pdb[PDX(KZERO)];    /* identity map low */
        cr3 = getcr3();
        putcr3(PADDR(m->pdb));
        if (arch)
                arch->introff();
        else
                i8259off();

        realmode0();
        splhi();                                /* who knows what the bios did */

        if(m->tss){
                /*
                 * Called from memory.c before initialization of mmu.
                 * Don't turn interrupts on before the kernel is ready!
                 */
                if (arch)
                        arch->intron();
                else
                        i8259on();
        }
        m->pdb[PDX(0)] = 0;     /* remove low mapping */
        putcr3(cr3);
        splx(s);

        *ureg = *(Ureg *)RMUADDR;
        if (!beenhere) {
                beenhere = 1;
                iprint("and back\n");
        }
        qunlock(&rmlock);
}