/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include "u.h"#include "tos.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 VGA and APM. */#define realmoderegs (*(Ureg*)RMUADDR) #define LORMBUF (RMBUF-KZERO) static Ureg rmu;static Lock rmlock; voidrealmode(Ureg *ureg){ int s; ulong cr3; extern void realmode0(void); /* in l.s */ if(getconf("*norealmode")) return; lock(&rmlock); realmoderegs = *ureg; /* copy l.s so that it can be run from 16-bit mode */ memmove((void*)RMCODE, (void*)KTZERO, 0x1000); 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(); 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 = realmoderegs; unlock(&rmlock);} static longrtrapread(Chan*, void *a, long n, vlong off){ if(off < 0) error("badarg"); if(n+off > sizeof rmu) n = sizeof rmu - off; if(n <= 0) return 0; memmove(a, (char*)&rmu+off, n); return n;} static longrtrapwrite(Chan*, void *a, long n, vlong off){ if(off || n != sizeof rmu) error("write a Ureg"); memmove(&rmu, a, sizeof rmu); /* * Sanity check */ if(rmu.trap == 0x10){ /* VBE */ rmu.es = (LORMBUF>>4)&0xF000; rmu.di = LORMBUF&0xFFFF; }else error("invalid trap arguments"); realmode(&rmu); return n;} static longrmemrw(int isr, void *a, long n, vlong off){ if(off < 0 || n < 0) error("bad offset/count"); if(isr){ if(off >= MB) return 0; if(off+n >= MB) n = MB - off; memmove(a, KADDR((ulong)off), n); }else{ /* realmode buf page ok, allow vga framebuf's access */ if(off >= MB || off+n > MB || (off < LORMBUF || off+n > LORMBUF+BY2PG) && (off < 0xA0000 || off+n > 0xB0000+0x10000)) error("bad offset/count in write"); memmove(KADDR((ulong)off), a, n); } return n;} static longrmemread(Chan*, void *a, long n, vlong off){ return rmemrw(1, a, n, off);} static longrmemwrite(Chan*, void *a, long n, vlong off){ return rmemrw(0, a, n, off);} voidrealmodelink(void){ addarchfile("realmode", 0660, rtrapread, rtrapwrite); addarchfile("realmodemem", 0660, rmemread, rmemwrite);}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#include "u.h"
#include "tos.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 VGA and APM.
*/
#define realmoderegs (*(Ureg*)RMUADDR)
#define LORMBUF (RMBUF-KZERO)
static Ureg rmu;
static Lock rmlock;
void
realmode(Ureg *ureg)
{
int s;
ulong cr3;
extern void realmode0(void); /* in l.s */
if(getconf("*norealmode"))
return;
lock(&rmlock);
realmoderegs = *ureg;
/* copy l.s so that it can be run from 16-bit mode */
memmove((void*)RMCODE, (void*)KTZERO, 0x1000);
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();
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 = realmoderegs;
unlock(&rmlock);
}
static long
rtrapread(Chan*, void *a, long n, vlong off)
{
if(off < 0)
error("badarg");
if(n+off > sizeof rmu)
n = sizeof rmu - off;
if(n <= 0)
return 0;
memmove(a, (char*)&rmu+off, n);
return n;
}
static long
rtrapwrite(Chan*, void *a, long n, vlong off)
{
if(off || n != sizeof rmu)
error("write a Ureg");
memmove(&rmu, a, sizeof rmu);
/*
* Sanity check
*/
if(rmu.trap == 0x10){ /* VBE */
rmu.es = (LORMBUF>>4)&0xF000;
rmu.di = LORMBUF&0xFFFF;
}else
error("invalid trap arguments");
realmode(&rmu);
return n;
}
static long
rmemrw(int isr, void *a, long n, vlong off)
{
if(off < 0 || n < 0)
error("bad offset/count");
if(isr){
if(off >= MB)
return 0;
if(off+n >= MB)
n = MB - off;
memmove(a, KADDR((ulong)off), n);
}else{
/* realmode buf page ok, allow vga framebuf's access */
if(off >= MB || off+n > MB ||
(off < LORMBUF || off+n > LORMBUF+BY2PG) &&
(off < 0xA0000 || off+n > 0xB0000+0x10000))
error("bad offset/count in write");
memmove(KADDR((ulong)off), a, n);
}
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("realmode", 0660, rtrapread, rtrapwrite);
addarchfile("realmodemem", 0660, rmemread, rmemwrite);
}