xref: /plan9-contrib/sys/src/9/pc/realmode.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
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