Fix typo in comment
[kqemu.git] / kqemu-freebsd.c
blob3d3b114842372923628c6f9cd3b6bf23e1060d76
1 /* $Id: kqemu-freebsd.c,v 1.6 2006/04/25 22:16:42 bellard Exp $ */
2 #include <sys/param.h>
3 #include <sys/systm.h>
4 #include <sys/conf.h>
5 #include <sys/ctype.h>
6 #include <sys/fcntl.h>
7 #include <sys/ioccom.h>
8 #include <sys/malloc.h>
9 #include <sys/module.h>
10 #if __FreeBSD_version >= 500000
11 #include <sys/mutex.h>
12 #endif
13 #include <sys/proc.h>
14 #include <sys/resourcevar.h>
15 #if __FreeBSD_version >= 500000
16 #include <sys/sched.h>
17 #endif
18 #include <sys/signalvar.h>
19 #include <sys/kernel.h>
20 #include <sys/sysctl.h>
21 #include <sys/uio.h>
22 #if __FreeBSD_version < 500000
23 #include <sys/buf.h>
24 #endif
26 #include <vm/vm.h>
27 #include <vm/vm_param.h>
28 #include <vm/vm_extern.h>
29 #include <vm/pmap.h>
30 #include <vm/vm_map.h>
31 #include <vm/vm_kern.h>
32 #include <vm/vm_page.h>
34 #include <machine/vmparam.h>
35 #include <machine/stdarg.h>
37 #include "kqemu-kernel.h"
39 #ifndef KQEMU_MAJOR
40 #define KQEMU_MAJOR 250
41 #endif
43 MALLOC_DECLARE(M_KQEMU);
44 MALLOC_DEFINE(M_KQEMU, "kqemu", "kqemu buffers");
46 int kqemu_debug;
47 SYSCTL_INT(_debug, OID_AUTO, kqemu_debug, CTLFLAG_RW, &kqemu_debug, 0,
48 "kqemu debug flag");
50 #define USER_BASE 0x1000
52 /* lock the page at virtual address 'user_addr' and return its
53 physical page index. Return NULL if error */
54 struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
55 unsigned long user_addr)
57 struct vmspace *vm = curproc->p_vmspace;
58 vm_offset_t va = user_addr;
59 vm_paddr_t pa = 0;
60 int ret;
61 pmap_t pmap;
62 #if __FreeBSD_version >= 500000
63 ret = vm_map_wire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
64 #else
65 ret = vm_map_user_pageable(&vm->vm_map, va, va+PAGE_SIZE, FALSE);
66 #endif
67 if (ret != KERN_SUCCESS) {
68 kqemu_log("kqemu_lock_user_page(%08lx) failed, ret=%d\n", user_addr, ret);
69 return NULL;
71 pmap = vm_map_pmap(&vm->vm_map);
72 pa = pmap_extract(pmap, va);
73 /* kqemu_log("kqemu_lock_user_page(%08lx) va=%08x pa=%08x\n", user_addr, va, pa); */
74 *ppage_index = pa >> PAGE_SHIFT;
75 return (struct kqemu_user_page *)va;
78 void CDECL kqemu_unlock_user_page(struct kqemu_user_page *page)
80 struct vmspace *vm = curproc->p_vmspace;
81 vm_offset_t va;
82 int ret;
83 /* kqemu_log("kqemu_unlock_user_page(%08lx)\n", page_index); */
84 va = (vm_offset_t)page;
85 #if __FreeBSD_version >= 500000
86 ret = vm_map_unwire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
87 #else
88 ret = vm_map_user_pageable(&vm->vm_map, va, va+PAGE_SIZE, TRUE);
89 #endif
90 #if 0
91 if (ret != KERN_SUCCESS) {
92 kqemu_log("kqemu_unlock_user_page(%08lx) failed, ret=%d\n", page_index, ret);
94 #endif
98 * Allocate a new page. The page must be mapped in the kernel space.
99 * Return the page_index or -1 if error.
101 struct kqemu_page *CDECL kqemu_alloc_zeroed_page(unsigned long *ppage_index)
103 pmap_t pmap;
104 vm_offset_t va;
105 vm_paddr_t pa;
107 va = kmem_alloc(kernel_map, PAGE_SIZE);
108 if (va == 0) {
109 kqemu_log("kqemu_alloc_zeroed_page: NULL\n");
110 return NULL;
112 pmap = vm_map_pmap(kernel_map);
113 pa = pmap_extract(pmap, va);
114 /* kqemu_log("kqemu_alloc_zeroed_page: %08x\n", pa); */
115 *ppage_index = pa >> PAGE_SHIFT;
116 return (struct kqemu_page *)va;
119 void CDECL kqemu_free_page(struct kqemu_page *page)
121 if (kqemu_debug > 0)
122 kqemu_log("kqemu_free_page(%p)\n", page);
123 kmem_free(kernel_map, (vm_offset_t) page, PAGE_SIZE);
126 /* return kernel address of the physical page page_index */
127 void * CDECL kqemu_page_kaddr(struct kqemu_page *page)
129 vm_offset_t va = (vm_offset_t)page;
130 return (void *)va;
133 /* contraint: each page of the vmalloced area must be in the first 4
134 GB of physical memory */
135 void * CDECL kqemu_vmalloc(unsigned int size)
137 void *ptr = malloc(size, M_KQEMU, M_WAITOK);
138 if (kqemu_debug > 0)
139 kqemu_log("kqemu_vmalloc(%d): %p\n", size, ptr);
140 return ptr;
143 void CDECL kqemu_vfree(void *ptr)
145 if (kqemu_debug > 0)
146 kqemu_log("kqemu_vfree(%p)\n", ptr);
147 free(ptr, M_KQEMU);
150 /* return the physical page index for a given virtual page */
151 unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr)
153 vm_paddr_t pa = vtophys(vaddr);
154 if (pa == 0) {
155 kqemu_log("kqemu_vmalloc_to_phys(%p)->error\n", vaddr);
156 return -1;
158 if (kqemu_debug > 0)
159 kqemu_log("kqemu_vmalloc_to_phys(%p)->%08x\n", vaddr, pa);
160 return pa >> PAGE_SHIFT;
163 /* Map a IO area in the kernel address space and return its
164 address. Return NULL if error or not implemented. */
165 void * CDECL kqemu_io_map(unsigned long page_index, unsigned int size)
167 return NULL;
170 /* Unmap the IO area */
171 void CDECL kqemu_io_unmap(void *ptr, unsigned int size)
175 #if __FreeBSD_version < 500000
176 static int
177 curpriority_cmp(struct proc *p)
179 int c_class, p_class;
181 c_class = RTP_PRIO_BASE(curproc->p_rtprio.type);
182 p_class = RTP_PRIO_BASE(p->p_rtprio.type);
183 if (p_class != c_class)
184 return (p_class - c_class);
185 if (p_class == RTP_PRIO_NORMAL)
186 return (((int)p->p_priority - (int)curpriority) / PPQ);
187 return ((int)p->p_rtprio.prio - (int)curproc->p_rtprio.prio);
190 /* return TRUE if a signal is pending (i.e. the guest must stop
191 execution) */
192 int CDECL kqemu_schedule(void)
194 struct proc *p = curproc;
195 if (curpriority_cmp(p) > 0) {
196 int s = splhigh();
197 p->p_priority = MAXPRI;
198 setrunqueue(p);
199 p->p_stats->p_ru.ru_nvcsw++;
200 mi_switch();
201 splx(s);
203 return issignal(curproc) != 0;
205 #else
206 /* return TRUE if a signal is pending (i.e. the guest must stop
207 execution) */
208 int CDECL kqemu_schedule(void)
210 /* kqemu_log("kqemu_schedule\n"); */
211 mtx_lock_spin(&sched_lock);
212 mi_switch(SW_VOL, NULL);
213 mtx_unlock_spin(&sched_lock);
214 return SIGPENDING(curthread);
216 #endif
218 static char log_buf[4096];
220 void CDECL kqemu_log(const char *fmt, ...)
222 va_list ap;
223 va_start(ap, fmt);
224 vsnprintf(log_buf, sizeof(log_buf), fmt, ap);
225 printf("kqemu: %s", log_buf);
226 va_end(ap);
229 struct kqemu_instance {
230 #if __FreeBSD_version >= 500000
231 TAILQ_ENTRY(kqemu_instance) kqemu_ent;
232 struct cdev *kqemu_dev;
233 #endif
234 /* struct semaphore sem; */
235 struct kqemu_state *state;
238 static int kqemu_ref_count = 0;
239 static struct kqemu_global_state *kqemu_gs = NULL;
241 #if __FreeBSD_version < 500000
242 static dev_t kqemu_dev;
243 #else
244 static struct clonedevs *kqemuclones;
245 static TAILQ_HEAD(,kqemu_instance) kqemuhead = TAILQ_HEAD_INITIALIZER(kqemuhead);
246 static eventhandler_tag clonetag;
247 #endif
249 static d_close_t kqemu_close;
250 static d_open_t kqemu_open;
251 static d_ioctl_t kqemu_ioctl;
253 static struct cdevsw kqemu_cdevsw = {
254 #if __FreeBSD_version < 500000
255 /* open */ kqemu_open,
256 /* close */ kqemu_close,
257 /* read */ noread,
258 /* write */ nowrite,
259 /* ioctl */ kqemu_ioctl,
260 /* poll */ nopoll,
261 /* mmap */ nommap,
262 /* strategy */ nostrategy,
263 /* name */ "kqemu",
264 /* maj */ KQEMU_MAJOR,
265 /* dump */ nodump,
266 /* psize */ nopsize,
267 /* flags */ 0,
268 /* bmaj */ -1
269 #else
270 .d_version = D_VERSION,
271 .d_flags = D_NEEDGIANT,
272 .d_open = kqemu_open,
273 .d_ioctl = kqemu_ioctl,
274 .d_close = kqemu_close,
275 .d_name = "kqemu"
276 #endif
279 #if __FreeBSD_version >= 500000
280 static void
281 #if __FreeBSD_version >= 600034
282 kqemu_clone(void *arg, struct ucred *cred, char *name, int namelen,
283 struct cdev **dev)
284 #else
285 kqemu_clone(void *arg, char *name, int namelen, struct cdev **dev)
286 #endif
288 int unit, r;
289 if (*dev != NULL)
290 return;
292 if (strcmp(name, "kqemu") == 0)
293 unit = -1;
294 else if (dev_stdclone(name, NULL, "kqemu", &unit) != 1)
295 return; /* Bad name */
297 r = clone_create(&kqemuclones, &kqemu_cdevsw, &unit, dev, 0);
298 if (r) {
299 *dev = make_dev(&kqemu_cdevsw, unit2minor(unit),
300 UID_ROOT, GID_WHEEL, 0660, "kqemu%d", unit);
301 if (*dev != NULL) {
302 dev_ref(*dev);
303 (*dev)->si_flags |= SI_CHEAPCLONE;
307 #endif
309 static void kqemu_destroy(struct kqemu_instance *ks)
311 #if __FreeBSD_version >= 500000
312 struct cdev *dev = ks->kqemu_dev;
313 #endif
315 if (ks->state) {
316 kqemu_delete(ks->state);
317 ks->state = NULL;
320 #if __FreeBSD_version >= 500000
321 dev->si_drv1 = NULL;
322 TAILQ_REMOVE(&kqemuhead, ks, kqemu_ent);
323 destroy_dev(dev);
324 #endif
325 free(ks, M_KQEMU);
326 --kqemu_ref_count;
329 /* ARGSUSED */
330 static int
331 #if __FreeBSD_version < 500000
332 kqemu_open(dev_t dev, int flags, int fmt __unused, struct proc *p)
334 #else
335 kqemu_open(struct cdev *dev, int flags, int fmt __unused,
336 struct thread *td)
338 struct proc *p = td->td_proc;
339 #endif
340 struct kqemu_instance *ks;
342 #if __FreeBSD_version < 500000
343 if (dev->si_drv1)
344 return(EBUSY);
345 #endif
347 if ((flags & (FREAD|FWRITE)) == FREAD)
348 return(EPERM);
350 ks = malloc(sizeof(struct kqemu_instance), M_KQEMU, M_WAITOK);
351 if (ks == NULL) {
352 kqemu_log("malloc failed\n");
353 return ENOMEM;
355 memset(ks, 0, sizeof *ks);
356 #if __FreeBSD_version >= 500000
357 ks->kqemu_dev = dev;
358 TAILQ_INSERT_TAIL(&kqemuhead, ks, kqemu_ent);
359 #endif
360 kqemu_ref_count++;
362 dev->si_drv1 = ks;
363 if (kqemu_debug > 0)
364 kqemu_log("opened by pid=%d\n", p->p_pid);
365 return 0;
368 /* ARGSUSED */
369 static int
370 #if __FreeBSD_version < 500000
371 kqemu_ioctl(dev_t dev, u_long cmd, caddr_t addr,
372 int flags __unused, struct proc *p)
373 #else
374 kqemu_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
375 int flags __unused, struct thread *td)
376 #endif
378 int error = 0;
379 int ret;
380 struct kqemu_instance *ks = dev->si_drv1;
381 struct kqemu_state *s = ks->state;
383 switch(cmd) {
384 case KQEMU_INIT: {
385 struct kqemu_init d1, *d = &d1;
386 if (s != NULL) {
387 error = EIO;
388 break;
390 d1 = *(struct kqemu_init *)addr;
391 if (kqemu_debug > 0)
392 kqemu_log("ram_base=%p ram_size=%ld\n", d1.ram_base, d1.ram_size);
393 s = kqemu_init(d, kqemu_gs);
394 if (s == NULL) {
395 error = ENOMEM;
396 break;
398 ks->state = s;
399 break;
401 case KQEMU_EXEC: {
402 struct kqemu_cpu_state *ctx;
403 if (s == NULL) {
404 error = EIO;
405 break;
407 ctx = kqemu_get_cpu_state(s);
408 *ctx = *(struct kqemu_cpu_state *)addr;
409 #if __FreeBSD_version >= 500000
410 DROP_GIANT();
411 #endif
412 ret = kqemu_exec(s);
413 #if __FreeBSD_version >= 500000
414 PICKUP_GIANT();
415 td->td_retval[0] = ret;
416 #else
417 p->p_retval[0] = ret;
418 #endif
419 *(struct kqemu_cpu_state *)addr = *ctx;
420 break;
422 case KQEMU_GET_VERSION:
423 *(int *)addr = KQEMU_VERSION;
424 break;
425 default:
426 error = EINVAL;
428 return error;
431 /* ARGSUSED */
432 static int
433 #if __FreeBSD_version < 500000
434 kqemu_close(dev_t dev, int flags, int fmt __unused, struct proc *p)
436 #else
437 kqemu_close(struct cdev *dev __unused, int flags, int fmt __unused,
438 struct thread *td)
440 struct proc *p = td->td_proc;
441 #endif
442 struct kqemu_instance *ks = (struct kqemu_instance *) dev->si_drv1;
444 kqemu_destroy(ks);
446 if (kqemu_debug > 0)
447 kqemu_log("closed by pid=%d\n", p->p_pid);
448 return 0;
451 /* ARGSUSED */
452 static int
453 kqemu_modevent(module_t mod __unused, int type, void *data __unused)
455 int error = 0;
456 int max_locked_pages;
457 #if __FreeBSD_version < 500000
458 int rc;
459 #else
460 struct kqemu_instance *ks;
461 #endif
463 switch (type) {
464 case MOD_LOAD:
465 printf("kqemu version 0x%08x\n", KQEMU_VERSION);
466 max_locked_pages = physmem / 2;
467 kqemu_gs = kqemu_global_init(max_locked_pages);
468 #if __FreeBSD_version < 500000
469 if ((rc = cdevsw_add(&kqemu_cdevsw))) {
470 kqemu_log("error registering cdevsw, rc=%d\n", rc);
471 error = ENOENT;
472 break;
474 kqemu_dev = make_dev(&kqemu_cdevsw, 0,
475 UID_ROOT, GID_WHEEL, 0660, "kqemu");
476 #else
477 clone_setup(&kqemuclones);
478 clonetag = EVENTHANDLER_REGISTER(dev_clone, kqemu_clone, 0, 1000);
479 if (!clonetag) {
480 error = ENOMEM;
481 break;
483 #endif
484 kqemu_log("KQEMU installed, max_locked_mem=%dkB.\n",
485 max_locked_pages * 4);
487 kqemu_ref_count = 0;
488 break;
489 case MOD_UNLOAD:
490 if (kqemu_ref_count > 0) {
491 error = EBUSY;
492 break;
494 #if __FreeBSD_version < 500000
495 destroy_dev(kqemu_dev);
496 if ((rc = cdevsw_remove(&kqemu_cdevsw)))
497 kqemu_log("error unregistering, rc=%d\n", rc);
498 #else
499 EVENTHANDLER_DEREGISTER(dev_clone, clonetag);
500 while ((ks = TAILQ_FIRST(&kqemuhead)) != NULL) {
501 kqemu_destroy(ks);
503 clone_cleanup(&kqemuclones);
504 #endif
505 kqemu_global_delete(kqemu_gs);
506 kqemu_gs = NULL;
507 break;
508 case MOD_SHUTDOWN:
509 break;
510 default:
511 error = EOPNOTSUPP;
512 break;
514 return (error);
517 DEV_MODULE(kqemu, kqemu_modevent, NULL);
518 MODULE_VERSION(kqemu, 1);