xref: /plan9-contrib/sys/src/9/pc/realmode.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
1 #include	"u.h"
2 #include	"tos.h"
3 #include	"../port/lib.h"
4 #include	"mem.h"
5 #include	"dat.h"
6 #include	"fns.h"
7 #include	"io.h"
8 #include	"ureg.h"
9 #include	"../port/error.h"
10 
11 /*
12  * Back the processor into real mode to run a BIOS call,
13  * then return.  This must be used carefully, since it
14  * completely disables hardware interrupts (e.g., the i8259)
15  * while running.  It is *not* using VM86 mode.
16  * Maybe that's really the right answer, but real mode
17  * is fine for now.  We don't expect to use this very much --
18  * just for VGA and APM.
19  */
20 #define realmoderegs (*(Ureg*)RMUADDR)
21 
22 #define LORMBUF (RMBUF-KZERO)
23 
24 static Ureg rmu;
25 static Lock rmlock;
26 
27 void
realmode(Ureg * ureg)28 realmode(Ureg *ureg)
29 {
30 	int s;
31 	ulong cr3;
32 	extern void realmode0(void);	/* in l.s */
33 
34 	if(getconf("*norealmode"))
35 		return;
36 
37 	lock(&rmlock);
38 	realmoderegs = *ureg;
39 
40 	/* copy l.s so that it can be run from 16-bit mode */
41 	memmove((void*)RMCODE, (void*)KTZERO, 0x1000);
42 
43 	s = splhi();
44 	m->pdb[PDX(0)] = m->pdb[PDX(KZERO)];	/* identity map low */
45 	cr3 = getcr3();
46 	putcr3(PADDR(m->pdb));
47 	if (arch)
48 		arch->introff();
49 	else
50 		i8259off();
51 	realmode0();
52 	if(m->tss){
53 		/*
54 		 * Called from memory.c before initialization of mmu.
55 		 * Don't turn interrupts on before the kernel is ready!
56 		 */
57 		if (arch)
58 			arch->intron();
59 		else
60 			i8259on();
61 	}
62 	m->pdb[PDX(0)] = 0;	/* remove low mapping */
63 	putcr3(cr3);
64 	splx(s);
65 	*ureg = realmoderegs;
66 	unlock(&rmlock);
67 }
68 
69 static long
rtrapread(Chan *,void * a,long n,vlong off)70 rtrapread(Chan*, void *a, long n, vlong off)
71 {
72 	if(off < 0)
73 		error("badarg");
74 	if(n+off > sizeof rmu)
75 		n = sizeof rmu - off;
76 	if(n <= 0)
77 		return 0;
78 	memmove(a, (char*)&rmu+off, n);
79 	return n;
80 }
81 
82 static long
rtrapwrite(Chan *,void * a,long n,vlong off)83 rtrapwrite(Chan*, void *a, long n, vlong off)
84 {
85 	if(off || n != sizeof rmu)
86 		error("write a Ureg");
87 	memmove(&rmu, a, sizeof rmu);
88 	/*
89 	 * Sanity check
90 	 */
91 	if(rmu.trap == 0x10){	/* VBE */
92 		rmu.es = (LORMBUF>>4)&0xF000;
93 		rmu.di = LORMBUF&0xFFFF;
94 	}else
95 		error("invalid trap arguments");
96 	realmode(&rmu);
97 	return n;
98 }
99 
100 static long
rmemrw(int isr,void * a,long n,vlong off)101 rmemrw(int isr, void *a, long n, vlong off)
102 {
103 	if(off < 0 || n < 0)
104 		error("bad offset/count");
105 	if(isr){
106 		if(off >= MB)
107 			return 0;
108 		if(off+n >= MB)
109 			n = MB - off;
110 		memmove(a, KADDR((ulong)off), n);
111 	}else{
112 		/* realmode buf page ok, allow vga framebuf's access */
113 		if(off >= MB || off+n > MB ||
114 		    (off < LORMBUF || off+n > LORMBUF+BY2PG) &&
115 		    (off < 0xA0000 || off+n > 0xB0000+0x10000))
116 			error("bad offset/count in write");
117 		memmove(KADDR((ulong)off), a, n);
118 	}
119 	return n;
120 }
121 
122 static long
rmemread(Chan *,void * a,long n,vlong off)123 rmemread(Chan*, void *a, long n, vlong off)
124 {
125 	return rmemrw(1, a, n, off);
126 }
127 
128 static long
rmemwrite(Chan *,void * a,long n,vlong off)129 rmemwrite(Chan*, void *a, long n, vlong off)
130 {
131 	return rmemrw(0, a, n, off);
132 }
133 
134 void
realmodelink(void)135 realmodelink(void)
136 {
137 	addarchfile("realmode", 0660, rtrapread, rtrapwrite);
138 	addarchfile("realmodemem", 0660, rmemread, rmemwrite);
139 }
140 
141