14de34a7eSDavid du Colombier #include "u.h"
24de34a7eSDavid du Colombier #include "tos.h"
34de34a7eSDavid du Colombier #include "../port/lib.h"
44de34a7eSDavid du Colombier #include "mem.h"
54de34a7eSDavid du Colombier #include "dat.h"
64de34a7eSDavid du Colombier #include "fns.h"
74de34a7eSDavid du Colombier #include "io.h"
84de34a7eSDavid du Colombier #include "ureg.h"
94de34a7eSDavid du Colombier #include "../port/error.h"
104de34a7eSDavid du Colombier
114de34a7eSDavid du Colombier /*
124de34a7eSDavid du Colombier * Back the processor into real mode to run a BIOS call,
134de34a7eSDavid du Colombier * then return. This must be used carefully, since it
144de34a7eSDavid du Colombier * completely disables hardware interrupts (e.g., the i8259)
154de34a7eSDavid du Colombier * while running. It is *not* using VM86 mode.
164de34a7eSDavid du Colombier * Maybe that's really the right answer, but real mode
174de34a7eSDavid du Colombier * is fine for now. We don't expect to use this very much --
184de34a7eSDavid du Colombier * just for VGA and APM.
194de34a7eSDavid du Colombier */
204de34a7eSDavid du Colombier #define realmoderegs (*(Ureg*)RMUADDR)
214de34a7eSDavid du Colombier
224de34a7eSDavid du Colombier #define LORMBUF (RMBUF-KZERO)
234de34a7eSDavid du Colombier
244de34a7eSDavid du Colombier static Ureg rmu;
254de34a7eSDavid du Colombier static Lock rmlock;
264de34a7eSDavid du Colombier
274de34a7eSDavid du Colombier void
realmode(Ureg * ureg)284de34a7eSDavid du Colombier realmode(Ureg *ureg)
294de34a7eSDavid du Colombier {
304de34a7eSDavid du Colombier int s;
310b9a5132SDavid du Colombier ulong cr3;
324de34a7eSDavid du Colombier extern void realmode0(void); /* in l.s */
334de34a7eSDavid du Colombier
344de34a7eSDavid du Colombier if(getconf("*norealmode"))
354de34a7eSDavid du Colombier return;
364de34a7eSDavid du Colombier
374de34a7eSDavid du Colombier lock(&rmlock);
384de34a7eSDavid du Colombier realmoderegs = *ureg;
394de34a7eSDavid du Colombier
404de34a7eSDavid du Colombier /* copy l.s so that it can be run from 16-bit mode */
414de34a7eSDavid du Colombier memmove((void*)RMCODE, (void*)KTZERO, 0x1000);
424de34a7eSDavid du Colombier
434de34a7eSDavid du Colombier s = splhi();
444de34a7eSDavid du Colombier m->pdb[PDX(0)] = m->pdb[PDX(KZERO)]; /* identity map low */
450b9a5132SDavid du Colombier cr3 = getcr3();
464de34a7eSDavid du Colombier putcr3(PADDR(m->pdb));
4787af424aSDavid du Colombier if (arch)
4887af424aSDavid du Colombier arch->introff();
4987af424aSDavid du Colombier else
504de34a7eSDavid du Colombier i8259off();
514de34a7eSDavid du Colombier realmode0();
524de34a7eSDavid du Colombier if(m->tss){
534de34a7eSDavid du Colombier /*
544de34a7eSDavid du Colombier * Called from memory.c before initialization of mmu.
554de34a7eSDavid du Colombier * Don't turn interrupts on before the kernel is ready!
564de34a7eSDavid du Colombier */
5787af424aSDavid du Colombier if (arch)
5887af424aSDavid du Colombier arch->intron();
5987af424aSDavid du Colombier else
604de34a7eSDavid du Colombier i8259on();
614de34a7eSDavid du Colombier }
624de34a7eSDavid du Colombier m->pdb[PDX(0)] = 0; /* remove low mapping */
630b9a5132SDavid du Colombier putcr3(cr3);
644de34a7eSDavid du Colombier splx(s);
654de34a7eSDavid du Colombier *ureg = realmoderegs;
664de34a7eSDavid du Colombier unlock(&rmlock);
674de34a7eSDavid du Colombier }
684de34a7eSDavid du Colombier
694de34a7eSDavid du Colombier static long
rtrapread(Chan *,void * a,long n,vlong off)704de34a7eSDavid du Colombier rtrapread(Chan*, void *a, long n, vlong off)
714de34a7eSDavid du Colombier {
724de34a7eSDavid du Colombier if(off < 0)
734de34a7eSDavid du Colombier error("badarg");
744de34a7eSDavid du Colombier if(n+off > sizeof rmu)
754de34a7eSDavid du Colombier n = sizeof rmu - off;
764de34a7eSDavid du Colombier if(n <= 0)
774de34a7eSDavid du Colombier return 0;
784de34a7eSDavid du Colombier memmove(a, (char*)&rmu+off, n);
794de34a7eSDavid du Colombier return n;
804de34a7eSDavid du Colombier }
814de34a7eSDavid du Colombier
824de34a7eSDavid du Colombier static long
rtrapwrite(Chan *,void * a,long n,vlong off)834de34a7eSDavid du Colombier rtrapwrite(Chan*, void *a, long n, vlong off)
844de34a7eSDavid du Colombier {
854de34a7eSDavid du Colombier if(off || n != sizeof rmu)
864de34a7eSDavid du Colombier error("write a Ureg");
874de34a7eSDavid du Colombier memmove(&rmu, a, sizeof rmu);
884de34a7eSDavid du Colombier /*
894de34a7eSDavid du Colombier * Sanity check
904de34a7eSDavid du Colombier */
914de34a7eSDavid du Colombier if(rmu.trap == 0x10){ /* VBE */
924de34a7eSDavid du Colombier rmu.es = (LORMBUF>>4)&0xF000;
934de34a7eSDavid du Colombier rmu.di = LORMBUF&0xFFFF;
944de34a7eSDavid du Colombier }else
954de34a7eSDavid du Colombier error("invalid trap arguments");
964de34a7eSDavid du Colombier realmode(&rmu);
974de34a7eSDavid du Colombier return n;
984de34a7eSDavid du Colombier }
994de34a7eSDavid du Colombier
1004de34a7eSDavid du Colombier static long
rmemrw(int isr,void * a,long n,vlong off)1014de34a7eSDavid du Colombier rmemrw(int isr, void *a, long n, vlong off)
1024de34a7eSDavid du Colombier {
1034de34a7eSDavid du Colombier if(off < 0 || n < 0)
1044de34a7eSDavid du Colombier error("bad offset/count");
105*cb8c047aSDavid du Colombier if(isr){
106*cb8c047aSDavid du Colombier if(off >= MB)
107*cb8c047aSDavid du Colombier return 0;
108*cb8c047aSDavid du Colombier if(off+n >= MB)
109*cb8c047aSDavid du Colombier n = MB - off;
1104de34a7eSDavid du Colombier memmove(a, KADDR((ulong)off), n);
111*cb8c047aSDavid du Colombier }else{
112*cb8c047aSDavid du Colombier /* realmode buf page ok, allow vga framebuf's access */
113*cb8c047aSDavid du Colombier if(off >= MB || off+n > MB ||
114*cb8c047aSDavid du Colombier (off < LORMBUF || off+n > LORMBUF+BY2PG) &&
115*cb8c047aSDavid du Colombier (off < 0xA0000 || off+n > 0xB0000+0x10000))
1164de34a7eSDavid du Colombier error("bad offset/count in write");
1174de34a7eSDavid du Colombier memmove(KADDR((ulong)off), a, n);
1184de34a7eSDavid du Colombier }
1194de34a7eSDavid du Colombier return n;
1204de34a7eSDavid du Colombier }
1214de34a7eSDavid du Colombier
1224de34a7eSDavid du Colombier static long
rmemread(Chan *,void * a,long n,vlong off)1234de34a7eSDavid du Colombier rmemread(Chan*, void *a, long n, vlong off)
1244de34a7eSDavid du Colombier {
1254de34a7eSDavid du Colombier return rmemrw(1, a, n, off);
1264de34a7eSDavid du Colombier }
1274de34a7eSDavid du Colombier
1284de34a7eSDavid du Colombier static long
rmemwrite(Chan *,void * a,long n,vlong off)1294de34a7eSDavid du Colombier rmemwrite(Chan*, void *a, long n, vlong off)
1304de34a7eSDavid du Colombier {
1314de34a7eSDavid du Colombier return rmemrw(0, a, n, off);
1324de34a7eSDavid du Colombier }
1334de34a7eSDavid du Colombier
1344de34a7eSDavid du Colombier void
realmodelink(void)1354de34a7eSDavid du Colombier realmodelink(void)
1364de34a7eSDavid du Colombier {
1374de34a7eSDavid du Colombier addarchfile("realmode", 0660, rtrapread, rtrapwrite);
1384de34a7eSDavid du Colombier addarchfile("realmodemem", 0660, rmemread, rmemwrite);
1394de34a7eSDavid du Colombier }
1404de34a7eSDavid du Colombier
141