4 * Copyright (c) 2005 Fabrice Bellard
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.
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.
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
24 #include <sys/types.h>
44 #include <sys/ioctl.h>
45 #include "kqemu/kqemu.h"
47 #define KQEMU_DEVICE "/dev/kqemu"
49 int kqemu_allowed
= 1;
51 unsigned long *pages_to_flush
;
52 unsigned int nb_pages_to_flush
;
53 extern uint32_t **l1_phys_map
;
55 #define cpuid(index, eax, ebx, ecx, edx) \
56 asm volatile ("cpuid" \
57 : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) \
60 static int is_cpuid_supported(void)
63 asm volatile ("pushf\n"
66 "xorl $0x00200000, %0\n"
71 : "=a" (v0
), "=d" (v1
)
77 static void kqemu_update_cpuid(CPUState
*env
)
79 int critical_features_mask
, features
;
80 uint32_t eax
, ebx
, ecx
, edx
;
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
|
90 if (!is_cpuid_supported()) {
93 cpuid(1, eax
, ebx
, ecx
, edx
);
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
103 int kqemu_init(CPUState
*env
)
105 struct kqemu_init init
;
111 kqemu_fd
= open(KQEMU_DEVICE
, O_RDWR
);
113 fprintf(stderr
, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE
);
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
);
124 pages_to_flush
= qemu_vmalloc(KQEMU_MAX_PAGES_TO_FLUSH
*
125 sizeof(unsigned long));
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
);
136 fprintf(stderr
, "Error %d while initializing QEMU acceleration layer - disabling it for now\n", ret
);
142 kqemu_update_cpuid(env
);
143 env
->kqemu_enabled
= 1;
144 nb_pages_to_flush
= 0;
148 void kqemu_flush_page(CPUState
*env
, target_ulong addr
)
151 if (loglevel
& CPU_LOG_INT
) {
152 fprintf(logfile
, "kqemu_flush_page: addr=" TARGET_FMT_lx
"\n", addr
);
155 if (nb_pages_to_flush
>= KQEMU_MAX_PAGES_TO_FLUSH
)
156 nb_pages_to_flush
= KQEMU_FLUSH_ALL
;
158 pages_to_flush
[nb_pages_to_flush
++] = addr
;
161 void kqemu_flush(CPUState
*env
, int global
)
164 if (loglevel
& CPU_LOG_INT
) {
165 fprintf(logfile
, "kqemu_flush:\n");
168 nb_pages_to_flush
= KQEMU_FLUSH_ALL
;
183 uint8_t fpregs1
[8 * 10];
199 uint8_t fpregs1
[8 * 16];
200 uint8_t xmm_regs
[8 * 16];
204 static struct fpxstate fpx1
__attribute__((aligned(16)));
206 static void restore_native_fp_frstor(CPUState
*env
)
209 struct fpstate fp1
, *fp
= &fp1
;
211 fp
->fpuc
= env
->fpuc
;
212 fp
->fpus
= (env
->fpus
& ~0x3800) | (env
->fpstt
& 0x7) << 11;
214 for (i
=7; i
>=0; i
--) {
216 if (env
->fptags
[i
]) {
219 /* the FPU automatically computes it */
224 for(i
= 0;i
< 8; i
++) {
225 memcpy(&fp
->fpregs1
[i
* 10], &env
->fpregs
[j
].d
, 10);
228 asm volatile ("frstor %0" : "=m" (*fp
));
231 static void save_native_fp_fsave(CPUState
*env
)
235 struct fpstate fp1
, *fp
= &fp1
;
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;
242 for(i
= 0;i
< 8; i
++) {
243 env
->fptags
[i
] = ((fptag
& 3) == 3);
247 for(i
= 0;i
< 8; i
++) {
248 memcpy(&env
->fpregs
[j
].d
, &fp
->fpregs1
[i
* 10], 10);
251 /* we must restore the default rounding state */
252 fpuc
= 0x037f | (env
->fpuc
& (3 << 10));
253 asm volatile("fldcw %0" : : "m" (fpuc
));
256 static void restore_native_fp_fxrstor(CPUState
*env
)
258 struct fpxstate
*fp
= &fpx1
;
261 fp
->fpuc
= env
->fpuc
;
262 fp
->fpus
= (env
->fpus
& ~0x3800) | (env
->fpstt
& 0x7) << 11;
264 for(i
= 0; i
< 8; i
++)
265 fptag
|= (env
->fptags
[i
] << i
);
266 fp
->fptag
= fptag
^ 0xff;
269 for(i
= 0;i
< 8; i
++) {
270 memcpy(&fp
->fpregs1
[i
* 16], &env
->fpregs
[j
].d
, 10);
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);
279 asm volatile ("fxrstor %0" : "=m" (*fp
));
282 static void save_native_fp_fxsave(CPUState
*env
)
284 struct fpxstate
*fp
= &fpx1
;
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;
297 for(i
= 0;i
< 8; i
++) {
298 memcpy(&env
->fpregs
[j
].d
, &fp
->fpregs1
[i
* 16], 10);
301 if (env
->cpuid_features
& CPUID_SSE
) {
302 env
->mxcsr
= fp
->mxcsr
;
303 memcpy(env
->xmm_regs
, fp
->xmm_regs
, 8 * 16);
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
));
312 int kqemu_cpu_exec(CPUState
*env
)
314 struct kqemu_cpu_state kcpu_state
, *kenv
= &kcpu_state
;
318 if (loglevel
& CPU_LOG_INT
) {
319 fprintf(logfile
, "kqemu: cpu_exec: enter\n");
320 cpu_dump_state(env
, logfile
, fprintf
, 0);
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];
345 kenv
->dr6
= env
->dr
[6];
347 kenv
->nb_pages_to_flush
= nb_pages_to_flush
;
348 nb_pages_to_flush
= 0;
350 if (!(kenv
->cr0
& CR0_TS_MASK
)) {
351 if (env
->cpuid_features
& CPUID_FXSR
)
352 restore_native_fp_fxrstor(env
);
354 restore_native_fp_frstor(env
);
357 ret
= ioctl(kqemu_fd
, KQEMU_EXEC
, kenv
);
359 if (!(kenv
->cr0
& CR0_TS_MASK
)) {
360 if (env
->cpuid_features
& CPUID_FXSR
)
361 save_native_fp_fxsave(env
);
363 save_native_fp_fsave(env
);
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
));
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
;
381 env
->cr
[2] = kenv
->cr2
;
382 env
->dr
[6] = kenv
->dr6
;
385 if (loglevel
& CPU_LOG_INT
) {
386 fprintf(logfile
, "kqemu: kqemu_cpu_exec: ret=0x%x\n", ret
);
389 if ((ret
& 0xff00) == KQEMU_RET_INT
) {
390 env
->exception_index
= ret
& 0xff;
392 env
->exception_is_int
= 1;
393 env
->exception_next_eip
= kenv
->next_eip
;
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);
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;
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);
415 } else if (ret
== KQEMU_RET_INTR
) {
417 } else if (ret
== KQEMU_RET_SOFTMMU
) {
420 cpu_dump_state(env
, stderr
, fprintf
, 0);
421 fprintf(stderr
, "Unsupported return value: 0x%x\n", ret
);