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