This source file includes following definitions.
- kvm86_init
- kvm86_prepare
- kvm86_map
- kvm86_mapbios
- kvm86_bios_addpage
- kvm86_bios_delpage
- kvm86_bios_read
- kvm86_bioscall
- kvm86_simplecall
- kvm86_gpfault
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 #include <sys/cdefs.h>
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/proc.h>
33 #include <sys/user.h>
34 #include <sys/malloc.h>
35 #include <sys/mutex.h>
36 #include <sys/simplelock.h>
37 #include <uvm/uvm_extern.h>
38 #include <uvm/uvm.h>
39 #include <machine/pcb.h>
40 #include <machine/pte.h>
41 #include <machine/pmap.h>
42 #include <machine/kvm86.h>
43 #include <machine/cpu.h>
44
45
46 extern int kvm86_call(struct trapframe *);
47 extern void kvm86_ret(struct trapframe *, int);
48
49 #define PGTABLE_SIZE ((1024 + 64) * 1024 / PAGE_SIZE)
50
51 struct kvm86_data {
52 pt_entry_t pgtbl[PGTABLE_SIZE];
53
54 struct segment_descriptor sd;
55
56 struct pcb pcb;
57 u_long iomap[0x10000/32];
58 };
59
60 void kvm86_map(struct kvm86_data *, paddr_t, uint32_t);
61 void kvm86_mapbios(struct kvm86_data *);
62 void kvm86_prepare(struct kvm86_data *vmd);
63
64
65
66 struct kvm86_data *bioscallvmd;
67
68 void *bioscallscratchpage;
69
70 #define BIOSCALLSCRATCHPAGE_VMVA 0x1000
71
72 vaddr_t bioscalltmpva;
73
74 struct mutex kvm86_mp_mutex;
75
76 #define KVM86_IOPL3
77
78 void
79 kvm86_init()
80 {
81 size_t vmdsize;
82 char *buf;
83 struct kvm86_data *vmd;
84 struct pcb *pcb;
85 paddr_t pa;
86 int i;
87
88 vmdsize = round_page(sizeof(struct kvm86_data)) + PAGE_SIZE;
89
90 if ((buf = (char *)uvm_km_zalloc(kernel_map, vmdsize)) == NULL)
91 return;
92
93
94 vmd = (struct kvm86_data *)(buf + PAGE_SIZE);
95 pcb = &vmd->pcb;
96
97
98
99
100
101
102
103 memcpy(pcb, &proc0.p_addr->u_pcb, sizeof(struct pcb));
104 pcb->pcb_tss.tss_esp0 = (int)vmd;
105 pcb->pcb_tss.tss_ss0 = GSEL(GDATA_SEL, SEL_KPL);
106 for (i = 0; i < sizeof(vmd->iomap) / 4; i++)
107 vmd->iomap[i] = 0;
108 pcb->pcb_tss.tss_ioopt =
109 ((caddr_t)vmd->iomap - (caddr_t)&pcb->pcb_tss) << 16;
110
111
112 setsegment(&vmd->sd, &pcb->pcb_tss,
113 sizeof(struct pcb) + sizeof(vmd->iomap) - 1,
114 SDT_SYS386TSS, SEL_KPL, 0, 0);
115
116
117 kvm86_mapbios(vmd);
118 if ((bioscallscratchpage = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE))
119 == 0)
120 return;
121
122 pmap_extract(pmap_kernel(), (vaddr_t)bioscallscratchpage, &pa);
123 kvm86_map(vmd, pa, BIOSCALLSCRATCHPAGE_VMVA);
124 bioscallvmd = vmd;
125 bioscalltmpva = uvm_km_alloc(kernel_map, PAGE_SIZE);
126 mtx_init(&kvm86_mp_mutex, IPL_IPI);
127 }
128
129
130
131
132
133
134 volatile struct pcb *vm86pcb;
135 volatile int vm86tssd0, vm86tssd1;
136 volatile paddr_t vm86newptd;
137 volatile struct trapframe *vm86frame;
138 volatile pt_entry_t *vm86pgtableva;
139
140 void
141 kvm86_prepare(struct kvm86_data *vmd)
142 {
143 vm86newptd = vtophys((vaddr_t)vmd) | PG_V | PG_RW | PG_U | PG_u;
144 vm86pgtableva = vmd->pgtbl;
145 vm86frame = (struct trapframe *)vmd - 1;
146 vm86pcb = &vmd->pcb;
147 vm86tssd0 = *(int*)&vmd->sd;
148 vm86tssd1 = *((int*)&vmd->sd + 1);
149 }
150
151 void
152 kvm86_map(struct kvm86_data *vmd, paddr_t pa, uint32_t vmva)
153 {
154
155 vmd->pgtbl[vmva >> 12] = pa | PG_V | PG_RW | PG_U | PG_u;
156 }
157
158 void
159 kvm86_mapbios(struct kvm86_data *vmd)
160 {
161 paddr_t pa;
162
163
164 kvm86_map(vmd, 0, 0);
165
166
167 for (pa = 0xa0000; pa < 0x100000; pa += PAGE_SIZE)
168 kvm86_map(vmd, pa, pa);
169 }
170
171 void *
172 kvm86_bios_addpage(uint32_t vmva)
173 {
174 void *mem;
175 paddr_t pa;
176
177 if (bioscallvmd->pgtbl[vmva >> 12])
178 return (NULL);
179
180 if ((mem = (void *)uvm_km_alloc(kernel_map, PAGE_SIZE)) == NULL)
181 return (NULL);
182
183 pmap_extract(pmap_kernel(), (vaddr_t)mem, &pa);
184 kvm86_map(bioscallvmd, pa, vmva);
185
186 return (mem);
187 }
188
189 void
190 kvm86_bios_delpage(uint32_t vmva, void *kva)
191 {
192
193 bioscallvmd->pgtbl[vmva >> 12] = 0;
194 uvm_km_free(kernel_map, (vaddr_t)kva, PAGE_SIZE);
195 }
196
197 size_t
198 kvm86_bios_read(u_int32_t vmva, char *buf, size_t len)
199 {
200 size_t todo, now;
201 paddr_t vmpa;
202
203 todo = len;
204 while (todo > 0) {
205 now = min(todo, PAGE_SIZE - (vmva & (PAGE_SIZE - 1)));
206
207 if (!bioscallvmd->pgtbl[vmva >> 12])
208 break;
209 vmpa = bioscallvmd->pgtbl[vmva >> 12] & ~(PAGE_SIZE - 1);
210 pmap_kenter_pa(bioscalltmpva, vmpa, VM_PROT_READ);
211 pmap_update(pmap_kernel());
212
213 memcpy(buf, (void *)(bioscalltmpva + (vmva & (PAGE_SIZE - 1))),
214 now);
215 buf += now;
216 todo -= now;
217 vmva += now;
218 }
219 return (len - todo);
220 }
221
222 int
223 kvm86_bioscall(int intno, struct trapframe *tf)
224 {
225 static const unsigned char call[] = {
226 0xfa,
227 0xcd,
228 0,
229 0xfb,
230 0xf4
231 };
232
233 memcpy(bioscallscratchpage, call, sizeof(call));
234 *((unsigned char *)bioscallscratchpage + 2) = intno;
235
236 tf->tf_eip = BIOSCALLSCRATCHPAGE_VMVA;
237 tf->tf_cs = 0;
238 tf->tf_esp = BIOSCALLSCRATCHPAGE_VMVA + PAGE_SIZE - 2;
239 tf->tf_ss = 0;
240 tf->tf_eflags = PSL_USERSET | PSL_VM;
241 #ifdef KVM86_IOPL3
242 tf->tf_eflags |= PSL_IOPL;
243 #endif
244 tf->tf_ds = tf->tf_es = tf->tf_fs = tf->tf_gs = 0;
245
246 kvm86_prepare(bioscallvmd);
247 return (kvm86_call(tf));
248 }
249
250 int
251 kvm86_simplecall(int no, struct kvm86regs *regs)
252 {
253 struct trapframe tf;
254 int res;
255
256 memset(&tf, 0, sizeof(struct trapframe));
257 tf.tf_eax = regs->eax;
258 tf.tf_ebx = regs->ebx;
259 tf.tf_ecx = regs->ecx;
260 tf.tf_edx = regs->edx;
261 tf.tf_esi = regs->esi;
262 tf.tf_edi = regs->edi;
263 tf.tf_vm86_es = regs->es;
264
265 mtx_enter(&kvm86_mp_mutex);
266 res = kvm86_bioscall(no, &tf);
267 mtx_leave(&kvm86_mp_mutex);
268
269 regs->eax = tf.tf_eax;
270 regs->ebx = tf.tf_ebx;
271 regs->ecx = tf.tf_ecx;
272 regs->edx = tf.tf_edx;
273 regs->esi = tf.tf_esi;
274 regs->edi = tf.tf_edi;
275 regs->es = tf.tf_vm86_es;
276 regs->eflags = tf.tf_eflags;
277
278 return (res);
279 }
280
281 void
282 kvm86_gpfault(struct trapframe *tf)
283 {
284 unsigned char *kva, insn, trapno;
285 uint16_t *sp;
286
287 kva = (unsigned char *)((tf->tf_cs << 4) + tf->tf_eip);
288 insn = *kva;
289 #ifdef KVM86DEBUG
290 printf("kvm86_gpfault: cs=%x, eip=%x, insn=%x, eflags=%x\n",
291 tf->tf_cs, tf->tf_eip, insn, tf->tf_eflags);
292 #endif
293
294 KASSERT(tf->tf_eflags & PSL_VM);
295
296 switch (insn) {
297 case 0xf4:
298 kvm86_ret(tf, 0);
299 break;
300 case 0xcd:
301
302 trapno = *(kva + 1);
303 sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
304 *(--sp) = tf->tf_eflags;
305 *(--sp) = tf->tf_cs;
306 *(--sp) = tf->tf_eip + 2;
307 tf->tf_esp -= 6;
308 tf->tf_cs = *(uint16_t *)(trapno * 4 + 2);
309 tf->tf_eip = *(uint16_t *)(trapno * 4);
310 break;
311 case 0xcf:
312 sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
313 tf->tf_eip = *(sp++);
314 tf->tf_cs = *(sp++);
315 tf->tf_eflags = *(sp++);
316 tf->tf_esp += 6;
317 tf->tf_eflags |= PSL_VM;
318 break;
319 #ifndef KVM86_IOPL3
320 case 0xfa:
321 case 0xfb:
322
323 tf->tf_eip++;
324 break;
325 case 0x9c:
326 sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
327 *(--sp) = tf->tf_eflags;
328 tf->tf_esp -= 2;
329 tf->tf_eip++;
330 break;
331 case 0x9d:
332 sp = (uint16_t *)((tf->tf_ss << 4) + tf->tf_esp);
333 tf->tf_eflags = *(sp++);
334 tf->tf_esp += 2;
335 tf->tf_eip++;
336 tf->tf_eflags |= PSL_VM;
337 break;
338 #endif
339 default:
340 #ifdef KVM86DEBUG
341 printf("kvm86_gpfault: unhandled\n");
342 #else
343 printf("kvm86_gpfault: cs=%x, eip=%x, insn=%x, eflags=%x\n",
344 tf->tf_cs, tf->tf_eip, insn, tf->tf_eflags);
345 #endif
346
347
348
349 kvm86_ret(tf, -1);
350 break;
351 }
352 }