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