]> git.proxmox.com Git - qemu.git/blame - kqemu.c
new bochs BIOS - 16 bit APM support (initial patch by Struan Bartlett)
[qemu.git] / kqemu.c
CommitLineData
9df217a3
FB
1/*
2 * KQEMU support
3 *
4 * Copyright (c) 2005 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include "config.h"
21#ifdef _WIN32
22#include <windows.h>
23#else
24#include <sys/types.h>
25#include <sys/mman.h>
26#endif
27#include <stdlib.h>
28#include <stdio.h>
29#include <stdarg.h>
30#include <string.h>
31#include <errno.h>
32#include <unistd.h>
33#include <inttypes.h>
34
35#include "cpu.h"
36#include "exec-all.h"
37
38#ifdef USE_KQEMU
39
40#define DEBUG
41
42#include <unistd.h>
43#include <fcntl.h>
44#include <sys/ioctl.h>
45#include "kqemu/kqemu.h"
46
47#define KQEMU_DEVICE "/dev/kqemu"
48
49int kqemu_allowed = 1;
50int kqemu_fd = -1;
51unsigned long *pages_to_flush;
52unsigned int nb_pages_to_flush;
53extern uint32_t **l1_phys_map;
54
55#define cpuid(index, eax, ebx, ecx, edx) \
56 asm volatile ("cpuid" \
57 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
58 : "0" (index))
59
60static int is_cpuid_supported(void)
61{
62 int v0, v1;
63 asm volatile ("pushf\n"
64 "popl %0\n"
65 "movl %0, %1\n"
66 "xorl $0x00200000, %0\n"
67 "pushl %0\n"
68 "popf\n"
69 "pushf\n"
70 "popl %0\n"
71 : "=a" (v0), "=d" (v1)
72 :
73 : "cc");
74 return (v0 != v1);
75}
76
77static void kqemu_update_cpuid(CPUState *env)
78{
79 int critical_features_mask, features;
80 uint32_t eax, ebx, ecx, edx;
81
82 /* the following features are kept identical on the host and
83 target cpus because they are important for user code. Strictly
84 speaking, only SSE really matters because the OS must support
85 it if the user code uses it. */
86 critical_features_mask =
87 CPUID_CMOV | CPUID_CX8 |
88 CPUID_FXSR | CPUID_MMX | CPUID_SSE |
89 CPUID_SSE2;
90 if (!is_cpuid_supported()) {
91 features = 0;
92 } else {
93 cpuid(1, eax, ebx, ecx, edx);
94 features = edx;
95 }
96 env->cpuid_features = (env->cpuid_features & ~critical_features_mask) |
97 (features & critical_features_mask);
98 /* XXX: we could update more of the target CPUID state so that the
99 non accelerated code sees exactly the same CPU features as the
100 accelerated code */
101}
102
103int kqemu_init(CPUState *env)
104{
105 struct kqemu_init init;
106 int ret, version;
107
108 if (!kqemu_allowed)
109 return -1;
110
111 kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
112 if (kqemu_fd < 0) {
113 fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
114 return -1;
115 }
116 version = 0;
117 ioctl(kqemu_fd, KQEMU_GET_VERSION, &version);
118 if (version != KQEMU_VERSION) {
119 fprintf(stderr, "Version mismatch between kqemu module and qemu (%08x %08x) - disabling kqemu use\n",
120 version, KQEMU_VERSION);
121 goto fail;
122 }
123
124 pages_to_flush = qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH *
125 sizeof(unsigned long));
126 if (!pages_to_flush)
127 goto fail;
128
129 init.ram_base = phys_ram_base;
130 init.ram_size = phys_ram_size;
131 init.ram_dirty = phys_ram_dirty;
132 init.phys_to_ram_map = l1_phys_map;
133 init.pages_to_flush = pages_to_flush;
134 ret = ioctl(kqemu_fd, KQEMU_INIT, &init);
135 if (ret < 0) {
136 fprintf(stderr, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret);
137 fail:
138 close(kqemu_fd);
139 kqemu_fd = -1;
140 return -1;
141 }
142 kqemu_update_cpuid(env);
143 env->kqemu_enabled = 1;
144 nb_pages_to_flush = 0;
145 return 0;
146}
147
148void kqemu_flush_page(CPUState *env, target_ulong addr)
149{
150#ifdef DEBUG
151 if (loglevel & CPU_LOG_INT) {
152 fprintf(logfile, "kqemu_flush_page: addr=" TARGET_FMT_lx "\n", addr);
153 }
154#endif
155 if (nb_pages_to_flush >= KQEMU_MAX_PAGES_TO_FLUSH)
156 nb_pages_to_flush = KQEMU_FLUSH_ALL;
157 else
158 pages_to_flush[nb_pages_to_flush++] = addr;
159}
160
161void kqemu_flush(CPUState *env, int global)
162{
163#ifdef DEBUG
164 if (loglevel & CPU_LOG_INT) {
165 fprintf(logfile, "kqemu_flush:\n");
166 }
167#endif
168 nb_pages_to_flush = KQEMU_FLUSH_ALL;
169}
170
171struct fpstate {
172 uint16_t fpuc;
173 uint16_t dummy1;
174 uint16_t fpus;
175 uint16_t dummy2;
176 uint16_t fptag;
177 uint16_t dummy3;
178
179 uint32_t fpip;
180 uint32_t fpcs;
181 uint32_t fpoo;
182 uint32_t fpos;
183 uint8_t fpregs1[8 * 10];
184};
185
186struct fpxstate {
187 uint16_t fpuc;
188 uint16_t fpus;
189 uint16_t fptag;
190 uint16_t fop;
191 uint32_t fpuip;
192 uint16_t cs_sel;
193 uint16_t dummy0;
194 uint32_t fpudp;
195 uint16_t ds_sel;
196 uint16_t dummy1;
197 uint32_t mxcsr;
198 uint32_t mxcsr_mask;
199 uint8_t fpregs1[8 * 16];
200 uint8_t xmm_regs[8 * 16];
201 uint8_t dummy2[224];
202};
203
204static struct fpxstate fpx1 __attribute__((aligned(16)));
205
206static void restore_native_fp_frstor(CPUState *env)
207{
208 int fptag, i, j;
209 struct fpstate fp1, *fp = &fp1;
210
211 fp->fpuc = env->fpuc;
212 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
213 fptag = 0;
214 for (i=7; i>=0; i--) {
215 fptag <<= 2;
216 if (env->fptags[i]) {
217 fptag |= 3;
218 } else {
219 /* the FPU automatically computes it */
220 }
221 }
222 fp->fptag = fptag;
223 j = env->fpstt;
224 for(i = 0;i < 8; i++) {
225 memcpy(&fp->fpregs1[i * 10], &env->fpregs[j].d, 10);
226 j = (j + 1) & 7;
227 }
228 asm volatile ("frstor %0" : "=m" (*fp));
229}
230
231static void save_native_fp_fsave(CPUState *env)
232{
233 int fptag, i, j;
234 uint16_t fpuc;
235 struct fpstate fp1, *fp = &fp1;
236
237 asm volatile ("fsave %0" : : "m" (*fp));
238 env->fpuc = fp->fpuc;
239 env->fpstt = (fp->fpus >> 11) & 7;
240 env->fpus = fp->fpus & ~0x3800;
241 fptag = fp->fptag;
242 for(i = 0;i < 8; i++) {
243 env->fptags[i] = ((fptag & 3) == 3);
244 fptag >>= 2;
245 }
246 j = env->fpstt;
247 for(i = 0;i < 8; i++) {
248 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);
249 j = (j + 1) & 7;
250 }
251 /* we must restore the default rounding state */
252 fpuc = 0x037f | (env->fpuc & (3 << 10));
253 asm volatile("fldcw %0" : : "m" (fpuc));
254}
255
256static void restore_native_fp_fxrstor(CPUState *env)
257{
258 struct fpxstate *fp = &fpx1;
259 int i, j, fptag;
260
261 fp->fpuc = env->fpuc;
262 fp->fpus = (env->fpus & ~0x3800) | (env->fpstt & 0x7) << 11;
263 fptag = 0;
264 for(i = 0; i < 8; i++)
265 fptag |= (env->fptags[i] << i);
266 fp->fptag = fptag ^ 0xff;
267
268 j = env->fpstt;
269 for(i = 0;i < 8; i++) {
270 memcpy(&fp->fpregs1[i * 16], &env->fpregs[j].d, 10);
271 j = (j + 1) & 7;
272 }
273 if (env->cpuid_features & CPUID_SSE) {
274 fp->mxcsr = env->mxcsr;
275 /* XXX: check if DAZ is not available */
276 fp->mxcsr_mask = 0xffff;
277 memcpy(fp->xmm_regs, env->xmm_regs, 8 * 16);
278 }
279 asm volatile ("fxrstor %0" : "=m" (*fp));
280}
281
282static void save_native_fp_fxsave(CPUState *env)
283{
284 struct fpxstate *fp = &fpx1;
285 int fptag, i, j;
286 uint16_t fpuc;
287
288 asm volatile ("fxsave %0" : : "m" (*fp));
289 env->fpuc = fp->fpuc;
290 env->fpstt = (fp->fpus >> 11) & 7;
291 env->fpus = fp->fpus & ~0x3800;
292 fptag = fp->fptag ^ 0xff;
293 for(i = 0;i < 8; i++) {
294 env->fptags[i] = (fptag >> i) & 1;
295 }
296 j = env->fpstt;
297 for(i = 0;i < 8; i++) {
298 memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 16], 10);
299 j = (j + 1) & 7;
300 }
301 if (env->cpuid_features & CPUID_SSE) {
302 env->mxcsr = fp->mxcsr;
303 memcpy(env->xmm_regs, fp->xmm_regs, 8 * 16);
304 }
305
306 /* we must restore the default rounding state */
307 asm volatile ("fninit");
308 fpuc = 0x037f | (env->fpuc & (3 << 10));
309 asm volatile("fldcw %0" : : "m" (fpuc));
310}
311
312int kqemu_cpu_exec(CPUState *env)
313{
314 struct kqemu_cpu_state kcpu_state, *kenv = &kcpu_state;
315 int ret;
316
317#ifdef DEBUG
318 if (loglevel & CPU_LOG_INT) {
319 fprintf(logfile, "kqemu: cpu_exec: enter\n");
320 cpu_dump_state(env, logfile, fprintf, 0);
321 }
322#endif
323 memcpy(kenv->regs, env->regs, sizeof(kenv->regs));
324 kenv->eip = env->eip;
325 kenv->eflags = env->eflags;
326 memcpy(&kenv->segs, &env->segs, sizeof(env->segs));
327 memcpy(&kenv->ldt, &env->ldt, sizeof(env->ldt));
328 memcpy(&kenv->tr, &env->tr, sizeof(env->tr));
329 memcpy(&kenv->gdt, &env->gdt, sizeof(env->gdt));
330 memcpy(&kenv->idt, &env->idt, sizeof(env->idt));
331 kenv->cr0 = env->cr[0];
332 kenv->cr2 = env->cr[2];
333 kenv->cr3 = env->cr[3];
334 kenv->cr4 = env->cr[4];
335 kenv->a20_mask = env->a20_mask;
336 if (env->dr[7] & 0xff) {
337 kenv->dr7 = env->dr[7];
338 kenv->dr0 = env->dr[0];
339 kenv->dr1 = env->dr[1];
340 kenv->dr2 = env->dr[2];
341 kenv->dr3 = env->dr[3];
342 } else {
343 kenv->dr7 = 0;
344 }
345 kenv->dr6 = env->dr[6];
346 kenv->cpl = 3;
347 kenv->nb_pages_to_flush = nb_pages_to_flush;
348 nb_pages_to_flush = 0;
349
350 if (!(kenv->cr0 & CR0_TS_MASK)) {
351 if (env->cpuid_features & CPUID_FXSR)
352 restore_native_fp_fxrstor(env);
353 else
354 restore_native_fp_frstor(env);
355 }
356
357 ret = ioctl(kqemu_fd, KQEMU_EXEC, kenv);
358
359 if (!(kenv->cr0 & CR0_TS_MASK)) {
360 if (env->cpuid_features & CPUID_FXSR)
361 save_native_fp_fxsave(env);
362 else
363 save_native_fp_fsave(env);
364 }
365
366 memcpy(env->regs, kenv->regs, sizeof(env->regs));
367 env->eip = kenv->eip;
368 env->eflags = kenv->eflags;
369 memcpy(env->segs, kenv->segs, sizeof(env->segs));
370#if 0
371 /* no need to restore that */
372 memcpy(env->ldt, kenv->ldt, sizeof(env->ldt));
373 memcpy(env->tr, kenv->tr, sizeof(env->tr));
374 memcpy(env->gdt, kenv->gdt, sizeof(env->gdt));
375 memcpy(env->idt, kenv->idt, sizeof(env->idt));
376 env->cr[0] = kenv->cr0;
377 env->cr[3] = kenv->cr3;
378 env->cr[4] = kenv->cr4;
379 env->a20_mask = kenv->a20_mask;
380#endif
381 env->cr[2] = kenv->cr2;
382 env->dr[6] = kenv->dr6;
383
384#ifdef DEBUG
385 if (loglevel & CPU_LOG_INT) {
386 fprintf(logfile, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret);
387 }
388#endif
389 if ((ret & 0xff00) == KQEMU_RET_INT) {
390 env->exception_index = ret & 0xff;
391 env->error_code = 0;
392 env->exception_is_int = 1;
393 env->exception_next_eip = kenv->next_eip;
394#ifdef DEBUG
395 if (loglevel & CPU_LOG_INT) {
396 fprintf(logfile, "kqemu: interrupt v=%02x:\n",
397 env->exception_index);
398 cpu_dump_state(env, logfile, fprintf, 0);
399 }
400#endif
401 return 1;
402 } else if ((ret & 0xff00) == KQEMU_RET_EXCEPTION) {
403 env->exception_index = ret & 0xff;
404 env->error_code = kenv->error_code;
405 env->exception_is_int = 0;
406 env->exception_next_eip = 0;
407#ifdef DEBUG
408 if (loglevel & CPU_LOG_INT) {
409 fprintf(logfile, "kqemu: exception v=%02x e=%04x:\n",
410 env->exception_index, env->error_code);
411 cpu_dump_state(env, logfile, fprintf, 0);
412 }
413#endif
414 return 1;
415 } else if (ret == KQEMU_RET_INTR) {
416 return 0;
417 } else if (ret == KQEMU_RET_SOFTMMU) {
418 return 2;
419 } else {
420 cpu_dump_state(env, stderr, fprintf, 0);
421 fprintf(stderr, "Unsupported return value: 0x%x\n", ret);
422 exit(1);
423 }
424 return 0;
425}
426
427#endif