kqemu-kmod port

Norikatsu Shigemura nork at FreeBSD.org
Tue Oct 25 05:58:03 PDT 2005


Hi qemu maintainer and users!

	I want kqemu only port to make buildkernel with PORTS_MODULES.

	I tested that make buildworld PORTS_MODULES=emulators/qemu,
	but no good.  So I decided to make kqemu-kmod port.

	If I commit following port, I'll remove kqemu related code
	from emulators/qemu/Makefile and add dependency on kqemu-kmod.

	http://people.freebsd.org/~nork/kqemu-kmod.shar
		or
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	kqemu-kmod/Makefile
#	kqemu-kmod/distinfo
#	kqemu-kmod/files
#	kqemu-kmod/files/patch-Makefile.freebsd
#	kqemu-kmod/files/patch-kqemu-freebsd.c
#	kqemu-kmod/pkg-descr
#
echo x - kqemu-kmod/Makefile
sed 's/^X//' >kqemu-kmod/Makefile << 'END-of-kqemu-kmod/Makefile'
X# New ports collection makefile for:	kqemu-kmod
X# Date created:				2005/10/25
X# Whom:					nork at FreeBSD.org
X#
X# $FreeBSD$
X#
X
XPORTNAME=	kqemu
XPORTVERSION=	0.7.2
XCATEGORIES=	emulators
XMASTER_SITES=	http://fabrice.bellard.free.fr/qemu/
XPKGNAMESUFFIX=	-kmod
XDIST_SUBDIR=	kqemu
X
XMAINTAINER=	nork at FreeBSD.org
XCOMMENT=	Kernel Acceralator for QEMU CPU Emulator
X
XONLY_FOR_ARCHS=	i386 amd64
XNO_PACKAGE=	"Depends on kernel, and module not redistributable"
X
XPLIST_FILES=	"@cwd /"
XPLIST_FILES+=	${KMODDIR:C,^/,,}/kqemu.ko
X
XWRKSRC=		${WRKDIR}/${PORTNAME}
XMAKEFILE=	BSDmakefile
X
X.include <bsd.port.pre.mk>
X
X.if !exists(${SRC_BASE}/sys/Makefile)
XIGNORE=		kqemu requires kernel source to be installed
X.endif
X
Xpost-extract:
X	@${LN} -s Makefile.freebsd ${WRKSRC}/BSDmakefile
X
Xpost-install:
X	if mount |${GREP} ^devfs >/dev/null ; then \
X		: ; \
X	else \
X		if [ ! -e /dev/kqemu ]; then\
X			mknod /dev/kqemu c 250 0 ; \
X		fi ; \
X		${CHMOD} 666 /dev/kqemu ; \
X	fi
X
X.include <bsd.port.post.mk>
END-of-kqemu-kmod/Makefile
echo x - kqemu-kmod/distinfo
sed 's/^X//' >kqemu-kmod/distinfo << 'END-of-kqemu-kmod/distinfo'
XMD5 (kqemu/kqemu-0.7.2.tar.gz) = 02cfdecda90458d6393781496ec6b48b
XSIZE (kqemu/kqemu-0.7.2.tar.gz) = 79314
END-of-kqemu-kmod/distinfo
echo c - kqemu-kmod/files
mkdir -p kqemu-kmod/files > /dev/null 2>&1
echo x - kqemu-kmod/files/patch-Makefile.freebsd
sed 's/^X//' >kqemu-kmod/files/patch-Makefile.freebsd << 'END-of-kqemu-kmod/files/patch-Makefile.freebsd'
X--- Makefile.freebsd.orig	Fri Jul 29 06:37:06 2005
X+++ Makefile.freebsd	Tue Oct 25 21:08:43 2005
X@@ -5,6 +5,7 @@
X .elif ${MACHINE_ARCH} == "amd64"
X OBJS=	kqemu-mod-x86_64.o
X .endif
X+CC=	cc
X WERROR=
X 
X .include <bsd.kmod.mk>
END-of-kqemu-kmod/files/patch-Makefile.freebsd
echo x - kqemu-kmod/files/patch-kqemu-freebsd.c
sed 's/^X//' >kqemu-kmod/files/patch-kqemu-freebsd.c << 'END-of-kqemu-kmod/files/patch-kqemu-freebsd.c'
X--- kqemu-freebsd.c.orig	Mon Aug 15 01:34:06 2005
X+++ kqemu-freebsd.c	Tue Oct 25 21:08:43 2005
X@@ -3,32 +3,55 @@
X #include <sys/param.h>
X #include <sys/systm.h>
X #include <sys/conf.h>
X+#include <sys/ctype.h>
X+#include <sys/fcntl.h>
X #include <sys/ioccom.h>
X #include <sys/malloc.h>
X #include <sys/module.h>
X+#if __FreeBSD_version >= 500000
X #include <sys/mutex.h>
X+#endif
X #include <sys/proc.h>
X+#include <sys/resourcevar.h>
X+#if __FreeBSD_version >= 500000
X #include <sys/sched.h>
X+#endif
X #include <sys/signalvar.h>
X #include <sys/kernel.h>
X+#include <sys/sysctl.h>
X+#include <sys/uio.h>
X+#if __FreeBSD_version < 500000
X+#include <sys/buf.h>
X+#endif
X+
X #include <vm/vm.h>
X #include <vm/vm_param.h>
X #include <vm/vm_extern.h>
X #include <vm/pmap.h>
X #include <vm/vm_map.h>
X #include <vm/vm_kern.h>
X+#include <vm/vm_page.h>
X+
X #include <machine/vmparam.h>
X #include <machine/stdarg.h>
X 
X #include "kqemu-kernel.h"
X 
X+#ifndef KQEMU_MAJOR
X+#define KQEMU_MAJOR 250
X+#endif
X+
X MALLOC_DECLARE(M_KQEMU);
X MALLOC_DEFINE(M_KQEMU, "kqemu", "kqemu buffers");
X 
X+int kqemu_debug;
X+SYSCTL_INT(_debug, OID_AUTO, kqemu_debug, CTLFLAG_RW, &kqemu_debug, 0,
X+        "kqemu debug flag");
X+
X #define	USER_BASE	0x1000
X 
X /* lock the page at virtual address 'user_addr' and return its
X-   physical page index. Return -1 if error */
X+   physical page index. Return NULL if error */
X struct kqemu_user_page *CDECL kqemu_lock_user_page(unsigned long *ppage_index,
X                                                    unsigned long user_addr)
X {
X@@ -37,14 +60,18 @@
X     vm_paddr_t pa = 0;
X     int ret;
X     pmap_t pmap;
X+#if __FreeBSD_version >= 500000
X     ret = vm_map_wire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
X+#else
X+    ret = vm_map_user_pageable(&vm->vm_map, va, va+PAGE_SIZE, FALSE);
X+#endif
X     if (ret != KERN_SUCCESS) {
X-	printf("kqemu_lock_user_page(%08lx) failed, ret=%d\n", user_addr, ret);
X+	kqemu_log("kqemu_lock_user_page(%08lx) failed, ret=%d\n", user_addr, ret);
X 	return NULL;
X     }
X     pmap = vm_map_pmap(&vm->vm_map);
X     pa = pmap_extract(pmap, va);
X-    // printf("kqemu_lock_user_page(%08lx) va=%08x pa=%08x\n", user_addr, va, pa);
X+    /* kqemu_log("kqemu_lock_user_page(%08lx) va=%08x pa=%08x\n", user_addr, va, pa); */
X     *ppage_index = pa >> PAGE_SHIFT;
X     return (struct kqemu_user_page *)va;
X }
X@@ -54,12 +81,16 @@
X     struct vmspace *vm = curproc->p_vmspace;
X     vm_offset_t va;
X     int ret;
X-    // printf("kqemu_unlock_user_page(%08lx)\n", page_index);
X+    /* kqemu_log("kqemu_unlock_user_page(%08lx)\n", page_index); */
X     va = (vm_offset_t)page;
X+#if __FreeBSD_version >= 500000
X     ret = vm_map_unwire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
X+#else
X+    ret = vm_map_user_pageable(&vm->vm_map, va, va+PAGE_SIZE, TRUE);
X+#endif
X #if 0
X     if (ret != KERN_SUCCESS) {
X-	printf("kqemu_unlock_user_page(%08lx) failed, ret=%d\n", page_index, ret);
X+	kqemu_log("kqemu_unlock_user_page(%08lx) failed, ret=%d\n", page_index, ret);
X     }
X #endif
X }
X@@ -76,20 +107,21 @@
X 
X     va = kmem_alloc(kernel_map, PAGE_SIZE);
X     if (va == 0) {
X-	printf("kqemu_alloc_zeroed_page: NULL\n");
X-	return -1;
X+	kqemu_log("kqemu_alloc_zeroed_page: NULL\n");
X+	return NULL;
X     }
X     pmap = vm_map_pmap(kernel_map);
X     pa = pmap_extract(pmap, va);
X-    // printf("kqemu_alloc_zeroed_page: %08x\n", pa);
X+    /* kqemu_log("kqemu_alloc_zeroed_page: %08x\n", pa); */
X     *ppage_index = pa >> PAGE_SHIFT;
X     return (struct kqemu_page *)va;
X }
X 
X void CDECL kqemu_free_page(struct kqemu_page *page)
X {
X-    //    printf("kqemu_free_page(%08lx)\n", page_index);
X-    /* XXX: do it */
X+    if (kqemu_debug > 0)
X+    	kqemu_log("kqemu_free_page(%p)\n", page);
X+    kmem_free(kernel_map, (vm_offset_t) page, PAGE_SIZE);
X }
X 
X /* return kernel address of the physical page page_index */
X@@ -103,42 +135,29 @@
X    GB of physical memory */
X void * CDECL kqemu_vmalloc(unsigned int size)
X {
X-    struct vmspace *vm = curproc->p_vmspace;
X-    vm_offset_t va = USER_BASE;
X-    int rv;
X-    if (size % PAGE_SIZE != 0) {
X-	printf("kqemu_vmalloc(%d) not a multiple of page size\n", size);
X-	return NULL;
X-    }
X-    rv = vm_map_find(&vm->vm_map, NULL, 0, &va, size, 1,
X-		     VM_PROT_ALL, VM_PROT_ALL, 0);
X-    if (rv != KERN_SUCCESS) {
X-	printf("kqemu_vmalloc(%d) failed rv=%d\n", size, rv);
X-	return NULL;
X-    }
X-    printf("kqemu_vmalloc(%d): %08x\n", size, va);
X-    return (void *)va;
X+    void *ptr = malloc(size, M_KQEMU, M_WAITOK);
X+    if (kqemu_debug > 0)
X+	kqemu_log("kqemu_vmalloc(%d): %p\n", size, ptr);
X+    return ptr;
X }
X 
X void CDECL kqemu_vfree(void *ptr)
X {
X-    printf("kqemu_vfree(%p)\n", ptr);
X+    if (kqemu_debug > 0)
X+	kqemu_log("kqemu_vfree(%p)\n", ptr);
X+    free(ptr, M_KQEMU);
X }
X 
X /* return the physical page index for a given virtual page */
X unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr)
X {
X-    struct vmspace *vm = curproc->p_vmspace;
X-    vm_paddr_t pa;
X-    pmap_t pmap;
X-
X-    pmap = vm_map_pmap(&vm->vm_map);
X-    pa = pmap_extract(pmap, (vm_offset_t)vaddr);
X+    vm_paddr_t pa = vtophys(vaddr);
X     if (pa == 0) {
X-	printf("kqemu_vmalloc_to_phys(%p)->error\n", vaddr);
X+	kqemu_log("kqemu_vmalloc_to_phys(%p)->error\n", vaddr);
X 	return -1;
X     }
X-    printf("kqemu_vmalloc_to_phys(%p)->%08x\n", vaddr, pa);
X+    if (kqemu_debug > 0)
X+	kqemu_log("kqemu_vmalloc_to_phys(%p)->%08x\n", vaddr, pa);
X     return pa >> PAGE_SHIFT;
X }
X 
X@@ -154,16 +173,48 @@
X {
X }
X 
X+#if __FreeBSD_version < 500000
X+static int
X+curpriority_cmp(struct proc *p)
X+{
X+    int c_class, p_class;
X+
X+    c_class = RTP_PRIO_BASE(curproc->p_rtprio.type);
X+    p_class = RTP_PRIO_BASE(p->p_rtprio.type);
X+    if (p_class != c_class)
X+	return (p_class - c_class);
X+    if (p_class == RTP_PRIO_NORMAL)
X+	return (((int)p->p_priority - (int)curpriority) / PPQ);
X+    return ((int)p->p_rtprio.prio - (int)curproc->p_rtprio.prio);
X+}
X+
X+/* return TRUE if a signal is pending (i.e. the guest must stop
X+   execution) */
X+int CDECL kqemu_schedule(void)
X+{
X+    struct proc *p = curproc;
X+    if (curpriority_cmp(p) > 0) {
X+	int s = splhigh();
X+	p->p_priority = MAXPRI;
X+	setrunqueue(p);
X+	p->p_stats->p_ru.ru_nvcsw++;
X+	mi_switch();
X+	splx(s);
X+    }
X+    return issignal(curproc) != 0;
X+}
X+#else
X /* return TRUE if a signal is pending (i.e. the guest must stop
X    execution) */
X int CDECL kqemu_schedule(void)
X {
X-    // printf("kqemu_schedule\n");
X+    /* kqemu_log("kqemu_schedule\n"); */
X     mtx_lock_spin(&sched_lock);
X     mi_switch(SW_VOL, NULL);
X     mtx_unlock_spin(&sched_lock);
X     return SIGPENDING(curthread);
X }
X+#endif
X 
X static char log_buf[4096];
X 
X@@ -176,47 +227,159 @@
X     va_end(ap);
X }
X 
X+#define KQEMU_MAX_INSTANCES 4
X+
X struct kqemu_instance { 
X-    //    struct semaphore sem;  
X+#if __FreeBSD_version >= 500000
X+    TAILQ_ENTRY(kqemu_instance) kqemu_ent;
X+    struct cdev *kqemu_dev;
X+#endif
X+    /*    struct semaphore sem;  */
X     struct kqemu_state *state;
X };
X 
X+static int kqemu_ref_count = 0;
X+static int max_locked_pages;
X+
X+#if __FreeBSD_version < 500000
X+static dev_t kqemu_dev;
X+#else
X+static struct clonedevs *kqemuclones;
X+static TAILQ_HEAD(,kqemu_instance) kqemuhead = TAILQ_HEAD_INITIALIZER(kqemuhead);
X+static eventhandler_tag clonetag;
X+#endif
X+
X static d_close_t kqemu_close;
X static d_open_t kqemu_open;
X static d_ioctl_t kqemu_ioctl;
X 
X static struct cdevsw kqemu_cdevsw = {
X+#if __FreeBSD_version < 500000
X+	/* open */	kqemu_open,
X+	/* close */	kqemu_close,
X+	/* read */	noread,
X+	/* write */	nowrite,
X+	/* ioctl */	kqemu_ioctl,
X+	/* poll */	nopoll,
X+	/* mmap */	nommap,
X+	/* strategy */	nostrategy,
X+	/* name */	"kqemu",
X+	/* maj */	KQEMU_MAJOR,
X+	/* dump */	nodump,
X+	/* psize */	nopsize,
X+	/* flags */	0,
X+	/* bmaj */	-1
X+#else
X 	.d_version =	D_VERSION,
X 	.d_flags =	D_NEEDGIANT,
X 	.d_open =	kqemu_open,
X 	.d_ioctl =	kqemu_ioctl,
X 	.d_close =	kqemu_close,
X 	.d_name =	"kqemu"
X+#endif
X };
X 
X-/* For use with make_dev(9)/destroy_dev(9). */
X-static struct cdev *kqemu_dev;
X+#if __FreeBSD_version >= 500000
X+static void
X+#if __FreeBSD_version >= 600034
X+kqemu_clone(void *arg, struct ucred *cred, char *name, int namelen,
X+struct cdev **dev)
X+#else
X+kqemu_clone(void *arg, char *name, int namelen, struct cdev **dev)
X+#endif
X+{
X+    int unit, r;
X+    if (*dev != NULL)
X+	return;
X+
X+    if (strcmp(name, "kqemu") == 0)
X+	unit = -1;
X+    else if (dev_stdclone(name, NULL, "kqemu", &unit) != 1)
X+	return;         /* Bad name */
X+    if (unit != -1 && unit > KQEMU_MAX_INSTANCES)
X+	return;
X+
X+    r = clone_create(&kqemuclones, &kqemu_cdevsw, &unit, dev, 0);
X+    if (r) {
X+	*dev = make_dev(&kqemu_cdevsw, unit2minor(unit),
X+	    UID_ROOT, GID_WHEEL, 0660, "kqemu%d", unit);
X+	if (*dev != NULL) {
X+	    (*dev)->si_flags |= SI_CHEAPCLONE;
X+	}
X+    }
X+}
X+#endif
X+
X+static void kqemu_destroy(struct kqemu_instance *ks)
X+{
X+#if __FreeBSD_version >= 500000
X+    struct cdev *dev = ks->kqemu_dev;
X+#endif
X+
X+    if (ks->state) {
X+        kqemu_delete(ks->state);
X+        ks->state = NULL;
X+    }
X+
X+#if __FreeBSD_version >= 500000
X+    dev->si_drv1 = NULL;
X+    TAILQ_REMOVE(&kqemuhead, ks, kqemu_ent);
X+    destroy_dev(dev);
X+#endif
X+    free(ks, M_KQEMU);
X+    --kqemu_ref_count;
X+}
X 
X /* ARGSUSED */
X static int
X+#if __FreeBSD_version < 500000
X+kqemu_open(dev_t dev, int flags, int fmt __unused, struct proc *p)
X+{
X+#else
X kqemu_open(struct cdev *dev, int flags, int fmt __unused,
X     struct thread *td)
X {
X+    struct proc	*p = td->td_proc;
X+#endif
X     struct kqemu_instance *ks;
X+
X+#if __FreeBSD_version >= 500000
X+    if (kqemu_ref_count >= KQEMU_MAX_INSTANCES)
X+#else
X+    if (dev->si_drv1 || kqemu_ref_count >= KQEMU_MAX_INSTANCES)
X+#endif
X+	return(EBUSY);
X+
X+    if ((flags & (FREAD|FWRITE)) == FREAD)
X+	return(EPERM);
X+
X     ks = malloc(sizeof(struct kqemu_instance), M_KQEMU, M_WAITOK);
X     if (ks == NULL) {
X-	printf("malloc failed\n");
X+	kqemu_log("malloc failed\n");
X 	return ENOMEM;
X     }
X-    ks->state = NULL;
X+    memset(ks, 0, sizeof *ks);
X+#if __FreeBSD_version >= 500000
X+    ks->kqemu_dev = dev;
X+    TAILQ_INSERT_TAIL(&kqemuhead, ks, kqemu_ent);
X+#endif
X+    kqemu_ref_count++;
X+
X     dev->si_drv1 = ks;
X+    if (kqemu_debug > 0)
X+	kqemu_log("opened by pid=%d\n", p->p_pid);
X     return 0;
X }
X 
X /* ARGSUSED */
X static int
X+#if __FreeBSD_version < 500000
X+kqemu_ioctl(dev_t dev, u_long cmd, caddr_t addr,
X+    int flags __unused, struct proc *p)
X+#else
X kqemu_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, 
X     int flags __unused, struct thread *td)
X+#endif
X {
X     int error = 0;
X     int ret;
X@@ -231,8 +394,9 @@
X 	    break;
X 	}
X 	d1 = *(struct kqemu_init *)addr;
X-	printf("ram_base=%p ram_size=%ld\n", d1.ram_base, d1.ram_size);
X-	s = kqemu_init(d, 16000);
X+	if (kqemu_debug > 0)
X+	    kqemu_log("ram_base=%p ram_size=%ld\n", d1.ram_base, d1.ram_size);
X+	s = kqemu_init(d, max_locked_pages);
X 	if (s == NULL) {
X 	    error = ENOMEM;
X 	    break;
X@@ -248,9 +412,16 @@
X 	}
X 	ctx = kqemu_get_cpu_state(s);
X 	*ctx = *(struct kqemu_cpu_state *)addr;
X+#if __FreeBSD_version >= 500000
X 	DROP_GIANT();
X+#endif
X 	ret = kqemu_exec(s);
X+#if __FreeBSD_version >= 500000
X 	PICKUP_GIANT();
X+	td->td_retval[0] = ret;
X+#else
X+	p->p_retval[0] = ret;
X+#endif
X 	*(struct kqemu_cpu_state *)addr = *ctx;
X 	break;
X     }
X@@ -265,10 +436,22 @@
X 
X /* ARGSUSED */
X static int
X+#if __FreeBSD_version < 500000
X+kqemu_close(dev_t dev, int flags, int fmt __unused, struct proc *p)
X+{
X+#else
X kqemu_close(struct cdev *dev __unused, int flags, int fmt __unused,
X     struct thread *td)
X {
X-	return 0;
X+    struct proc     *p = td->td_proc;
X+#endif
X+    struct kqemu_instance *ks = (struct kqemu_instance *) dev->si_drv1;
X+
X+    kqemu_destroy(ks);
X+
X+    if (kqemu_debug > 0)
X+	kqemu_log("closed by pid=%d\n", p->p_pid);
X+    return 0;
X }
X 
X /* ARGSUSED */
X@@ -276,15 +459,55 @@
X kqemu_modevent(module_t mod __unused, int type, void *data __unused)
X {
X     int error = 0;
X+#if __FreeBSD_version < 500000
X+    int rc;
X+#else
X+    struct kqemu_instance *ks;
X+#endif
X 
X     switch (type) {
X     case MOD_LOAD:
X 	printf("kqemu version 0x%08x\n", KQEMU_VERSION);
X+	max_locked_pages = physmem / (2 * KQEMU_MAX_INSTANCES);
X+	if (max_locked_pages > 32768)
X+	    max_locked_pages = 32768;
X+#if __FreeBSD_version < 500000
X+	if ((rc = cdevsw_add(&kqemu_cdevsw))) {
X+	    kqemu_log("error registering cdevsw, rc=%d\n", rc);
X+            error = ENOENT;
X+            break;
X+	}
X 	kqemu_dev = make_dev(&kqemu_cdevsw, 0,
X-			     UID_ROOT, GID_WHEEL, 0666, "kqemu");
X+			     UID_ROOT, GID_WHEEL, 0660, "kqemu");
X+#else
X+	clone_setup(&kqemuclones);
X+	clonetag = EVENTHANDLER_REGISTER(dev_clone, kqemu_clone, 0, 1000);
X+	if (!clonetag) {
X+            error = ENOMEM;
X+	    break;
X+	}
X+#endif
X+	kqemu_log("KQEMU installed, max_instances=%d max_locked_mem=%dkB.\n",
X+		  KQEMU_MAX_INSTANCES, max_locked_pages * 4);
X+
X+	kqemu_ref_count = 0;
X 	break;
X     case MOD_UNLOAD:
X+	if (kqemu_ref_count > 0) {
X+            error = EBUSY;
X+            break;
X+        }
X+#if __FreeBSD_version < 500000
X 	destroy_dev(kqemu_dev);
X+	if ((rc = cdevsw_remove(&kqemu_cdevsw)))
X+	    kqemu_log("error unregistering, rc=%d\n", rc);
X+#else
X+	EVENTHANDLER_DEREGISTER(dev_clone, clonetag);
X+	while ((ks = TAILQ_FIRST(&kqemuhead)) != NULL) {
X+	    kqemu_destroy(ks);
X+	}
X+	clone_cleanup(&kqemuclones);
X+#endif
X 	break;
X     case MOD_SHUTDOWN:
X 	break;
END-of-kqemu-kmod/files/patch-kqemu-freebsd.c
echo x - kqemu-kmod/pkg-descr
sed 's/^X//' >kqemu-kmod/pkg-descr << 'END-of-kqemu-kmod/pkg-descr'
XKQEMU is a qemu accelerator kernel module on x86/amd64.
X
XWWW: http://fabrice.bellard.free.fr/qemu/qemu-accel.html
END-of-kqemu-kmod/pkg-descr
exit


More information about the freebsd-emulation mailing list