FreeBSD/Linux Kernel Cross Reference
sys/pc/realmode.c
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
28 realmode(Ureg *ureg)
29 {
30 int s;
31 ulong cr3;
32 extern void realmode0(void); /* in l.s */
33 extern void i8259off(void), i8259on(void);
34
35 if(getconf("*norealmode"))
36 return;
37
38 lock(&rmlock);
39 realmoderegs = *ureg;
40
41 /* copy l.s so that it can be run from 16-bit mode */
42 memmove((void*)RMCODE, (void*)KTZERO, 0x1000);
43
44 s = splhi();
45 m->pdb[PDX(0)] = m->pdb[PDX(KZERO)]; /* identity map low */
46 cr3 = getcr3();
47 putcr3(PADDR(m->pdb));
48 i8259off();
49 realmode0();
50 if(m->tss){
51 /*
52 * Called from memory.c before initialization of mmu.
53 * Don't turn interrupts on before the kernel is ready!
54 */
55 i8259on();
56 }
57 m->pdb[PDX(0)] = 0; /* remove low mapping */
58 putcr3(cr3);
59 splx(s);
60 *ureg = realmoderegs;
61 unlock(&rmlock);
62 }
63
64 static long
65 rtrapread(Chan*, void *a, long n, vlong off)
66 {
67 if(off < 0)
68 error("badarg");
69 if(n+off > sizeof rmu)
70 n = sizeof rmu - off;
71 if(n <= 0)
72 return 0;
73 memmove(a, (char*)&rmu+off, n);
74 return n;
75 }
76
77 static long
78 rtrapwrite(Chan*, void *a, long n, vlong off)
79 {
80 if(off || n != sizeof rmu)
81 error("write a Ureg");
82 memmove(&rmu, a, sizeof rmu);
83 /*
84 * Sanity check
85 */
86 if(rmu.trap == 0x10){ /* VBE */
87 rmu.es = (LORMBUF>>4)&0xF000;
88 rmu.di = LORMBUF&0xFFFF;
89 }else
90 error("invalid trap arguments");
91 realmode(&rmu);
92 return n;
93 }
94
95 static long
96 rmemrw(int isr, void *a, long n, vlong off)
97 {
98 if(off >= 1024*1024 || off+n >= 1024*1024)
99 return 0;
100 if(off < 0 || n < 0)
101 error("bad offset/count");
102 if(isr)
103 memmove(a, KADDR((ulong)off), n);
104 else{
105 /* writes are more restricted */
106 if(LORMBUF <= off && off < LORMBUF+BY2PG
107 && off+n <= LORMBUF+BY2PG)
108 {}
109 else
110 error("bad offset/count in write");
111 memmove(KADDR((ulong)off), a, n);
112 }
113 return n;
114 }
115
116 static long
117 rmemread(Chan*, void *a, long n, vlong off)
118 {
119 return rmemrw(1, a, n, off);
120 }
121
122 static long
123 rmemwrite(Chan*, void *a, long n, vlong off)
124 {
125 return rmemrw(0, a, n, off);
126 }
127
128 void
129 realmodelink(void)
130 {
131 addarchfile("realmode", 0660, rtrapread, rtrapwrite);
132 addarchfile("realmodemem", 0660, rmemread, rmemwrite);
133 }
134
Cache object: ecde8f442c617d152b52b16c706eba5b
|