qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Antony T Curtis <antony.t.curtis@ntlworld.com>
To: Ryan Rempel <rgrempel@gmail.com>
Cc: qemu-devel@nongnu.org
Subject: Re: KQEMU on FreeBSD partially works. (Was: [Qemu-devel] Accelerator for FreeBSD?)
Date: Wed, 23 Mar 2005 13:58:38 +0000	[thread overview]
Message-ID: <1111586318.2588.29.camel@pcgem.xiphis.org> (raw)
In-Reply-To: <fb5ec42305032217272e019959@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1028 bytes --]

On Tue, 2005-03-22 at 19:27 -0600, Ryan Rempel wrote:
> On Mon, 21 Mar 2005 14:57:33 +0000, Antony T Curtis
> <antony.t.curtis@ntlworld.com> wrote:
> 
> > On Sun, 2005-03-20 at 19:42 -0600, Ryan Rempel wrote:
> > > There is a reference here [1] to the possibility of porting the
> > > Accelerator to *BSD by porting a small "C stub".
> > >
> > > Is anyone working on this at the moment? 
>  
> > I have made some headway... The attached stub appears to work but in my
> > limited testing so far, it may be a bit unstable. The driver stub is for
> > FreeBSD 4 (tested on 4.9) and I may work on a 5.3+ one soon.
> 
> Thanks! I would need one that works with 5.3 -- I'll take a look when
> I get a chance and see what I can figure out.

Okay - the new files compile on both 4.9 and 5.3, currently untested on
5.3. YMMV.

Enjoy!


-- 
Antony T Curtis, BSc.                   UNIX, Linux, *BSD, Networking
antony.t.curtis@ntlworld.com            C++, J2EE, Perl, MySQL, Apache
                                        IT Consultancy.

[-- Attachment #2: Makefile.bsd --]
[-- Type: text/plain, Size: 89 bytes --]

# 

KMOD=	kqemu
SRCS=	kqemu.h kmod_bsd.c kqemu-mod-i386.o
NOMAN=

.include <bsd.kmod.mk>

[-- Attachment #3: kmod_bsd.c --]
[-- Type: text/x-csrc, Size: 9898 bytes --]

/*
 * FreeBSD kernel wrapper for KQEMU
 * Copyright (c) 2005 Antony T Curtis
 *
 * Based upon the Linux wrapper by Fabrice Bellard
 */

#include <sys/param.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#if __FreeBSD_version < 500000
#include <sys/buf.h>
#endif
#include <sys/uio.h>
#include <sys/conf.h>
#include <sys/ctype.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/ioccom.h>
#include <sys/signalvar.h>
#include <sys/resourcevar.h>
#include <sys/module.h>

#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_page.h>
#include <vm/vm_kern.h>
#include <vm/vm_extern.h>

#include <machine/stdarg.h>

#define __KERNEL__

#include "kqemu.h"

static MALLOC_DEFINE(M_KQEMU, "KQEMU", "KQEMU Resources");

/* lock the page at virtual address 'user_addr' and return its
   page index. Return -1 if error */
unsigned long CDECL kqemu_lock_user_page(unsigned long user_addr)
{
    int rc;
    caddr_t addr = (caddr_t) user_addr;
    vm_page_t m;
    vm_offset_t paddr;
    
    /*kqemu_log("kqemu_lock_user_page(0x%08x)\n", addr);*/
    
    rc = vm_fault_quick(addr, VM_PROT_READ|VM_PROT_WRITE);
    if (rc < 0) {    
	/*kqemu_log("vm_fault_quick failed rc=%d\n",rc);*/
	return -1;	
    }
    paddr = vtophys(addr);
    m = PHYS_TO_VM_PAGE(paddr);
    vm_page_wire(m);
    
    return (long)(paddr >> PAGE_SHIFT);
}

void CDECL kqemu_unlock_user_page(unsigned long page_index)
{
    vm_page_t m;
    vm_offset_t paddr;
    /*kqemu_log("kqemu_unlock_user_page(0x%08x)\n",page_index);*/

    paddr = (vm_offset_t)(page_index << PAGE_SHIFT);
    m = PHYS_TO_VM_PAGE(paddr);
    vm_page_unwire(m, 1);
}

unsigned long CDECL kqemu_alloc_zeroed_page(void)
{
    void *addr;
    /*kqemu_log("kqemu_alloc_zeroed_page()\n");*/
    addr = contigmalloc(PAGE_SIZE, M_KQEMU, M_WAITOK, 0, ~0ul, PAGE_SIZE, 0);
    if (!addr) {
	/*kqemu_log("contigmalloc failed\n");*/
        return -1;
    }
    memset(addr, 0, PAGE_SIZE);
    return ((long) addr) >> PAGE_SHIFT;
}

void CDECL kqemu_free_page(unsigned long page_index)
{
    /*kqemu_log("kqemu_free_page(0x%08x)\n", page_index);*/
    contigfree((void *)(page_index << PAGE_SHIFT), PAGE_SIZE, M_KQEMU);
}

void * CDECL kqemu_page_kaddr(unsigned long page_index)
{
    caddr_t addr;
    /*kqemu_log("kqemu_page_kaddr(0x%08x)\n", page_index);*/
    addr = (caddr_t)(page_index << PAGE_SHIFT);
    return (void *)addr;
}

/* contraint: each page of the vmalloced area must be in the first 4
   GB of physical memory */
void * CDECL kqemu_vmalloc(unsigned int size)
{
    /*kqemu_log("kqemu_vmalloc(0x%08x)\n", size);*/
    return malloc(size, M_KQEMU, M_WAITOK);
}

void CDECL kqemu_vfree(void *ptr)
{
    /*kqemu_log("kqemu_vfree(0x%08x)\n", ptr);*/
    return free(ptr, M_KQEMU);
}

unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr)
{
    vm_offset_t paddr = (vm_offset_t)vaddr;
    return (long)(paddr >> PAGE_SHIFT);
}

#if __FreeBSD_version < 500000
static int
curpriority_cmp(struct proc *p)
{
        int c_class, p_class;

        c_class = RTP_PRIO_BASE(curproc->p_rtprio.type);
        p_class = RTP_PRIO_BASE(p->p_rtprio.type);
        if (p_class != c_class)
                return (p_class - c_class);
        if (p_class == RTP_PRIO_NORMAL)
                return (((int)p->p_priority - (int)curpriority) / PPQ);
        return ((int)p->p_rtprio.prio - (int)curproc->p_rtprio.prio);
}

/* return TRUE if a signal is pending (i.e. the guest must stop
   execution) */
int CDECL kqemu_schedule(void)
{
    struct proc *p = curproc;
    if (curpriority_cmp(p) > 0) {
        int s = splhigh();
	p->p_priority = MAXPRI;
        setrunqueue(p);
        p->p_stats->p_ru.ru_nvcsw++;
        mi_switch();
        splx(s);
    }
    return issignal(curproc) != 0;
}

#else

/* return TRUE if a signal is pending (i.e. the guest must stop
   execution) */
int CDECL kqemu_schedule(void)
{
    struct thread *td = curthread;
    struct proc *p = td->td_proc;
    int rc = 0, sig;

    PROC_LOCK(p);
    mtx_lock(&p->p_sigacts->ps_mtx);
    if ((rc = ((sig= cursig(td)) != 0))) {
	do {
	    postsig(sig);
	} while ((sig= cursig(td)));
    }
    mtx_unlock(&p->p_sigacts->ps_mtx);
    PROC_UNLOCK(p);
    return rc;
}

#endif


static char log_buf[4096];

void CDECL kqemu_log(const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    vsnprintf(log_buf, sizeof(log_buf), fmt, ap);
    printf("kqemu: %s", log_buf);
    va_end(ap);
}

/*********************************************************/


#define KQEMU_MAX_INSTANCES 4

struct kqemu_instance {
    struct kqemu_state *state;
};

static int kqemu_ref_count = 0;
static int max_locked_pages;
#if __FreeBSD_version < 500000
static dev_t kqemu_dev;
#else
static struct cdev *kqemu_dev;
#endif


static	d_open_t	kqemu_open;
static	d_close_t	kqemu_close;
static	d_ioctl_t	kqemu_ioctl;

static struct cdevsw kqemu_cdevsw = {
#if __FreeBSD_version < 500000
	/* open */	kqemu_open,
	/* close */	kqemu_close,
	/* read */	noread,
	/* write */	nowrite,
	/* ioctl */	kqemu_ioctl,
	/* poll */	nopoll,
	/* mmap */	nommap,
	/* strategy */	nostrategy,
	/* name */	"kqemu",
	/* maj */	KQEMU_MAJOR,
	/* dump */	nodump,
	/* psize */	nopsize,
	/* flags */	0,
	/* bmaj */	-1
#else
	.d_version =	D_VERSION,
	.d_open =	kqemu_open,
	.d_close =	kqemu_close,
	.d_ioctl =	kqemu_ioctl,
	.d_name =	"kqemu",
#endif
};

int
#if __FreeBSD_version < 500000
kqemu_open(dev, flags, fmt, p)
	dev_t		dev;
	int		flags, fmt;
	struct proc	*p;
{
#else
kqemu_open(dev, flags, fmt, td)
	struct cdev	*dev;
	int		flags, fmt;
	struct thread	*td;
{
	struct proc	*p = td->td_proc;
#endif
    struct kqemu_instance *ks;
    
    if (dev->si_drv1 || kqemu_ref_count >= KQEMU_MAX_INSTANCES)
    	return(EBUSY);

    if ((flags & (FREAD|FWRITE)) == FREAD)
    	return(EPERM);

    ks = (struct kqemu_instance *) malloc(sizeof(*ks), M_KQEMU, M_WAITOK);
    if (ks == NULL)
        return(ENOMEM);
    memset(ks, 0, sizeof *ks);
    
    dev->si_drv1 = ks;
    kqemu_ref_count++;
    kqemu_log("opened by pid=%d\n", p->p_pid);
    return(0);
}

int
#if __FreeBSD_version < 500000
kqemu_close(dev, flags, fmt, p)
	dev_t		dev;
	int		flags, fmt;
	struct proc	*p;
{
#else
kqemu_close(dev, flags, fmt, td)
	struct cdev	*dev;
	int		flags, fmt;
	struct thread	*td;
{
	struct proc	*p = td->td_proc;
#endif
    struct kqemu_instance *ks = (struct kqemu_instance *) dev->si_drv1;

    if (ks->state) {
	kqemu_delete(ks->state);
	ks->state = NULL;
    }
    
    free(ks, M_KQEMU);
    dev->si_drv1 = NULL;
    kqemu_ref_count--;
    kqemu_log("closed by pid=%d\n", p->p_pid);
    return(0);
}

int
#if __FreeBSD_version < 500000
kqemu_ioctl(dev, cmd, cmdarg, flags, p)
	dev_t		dev;
	unsigned long	cmd;
	caddr_t		cmdarg;
	int		flags;
	struct proc	*p;
{
#else
kqemu_ioctl(dev, cmd, cmdarg, flags, td)
	struct cdev	*dev;
	unsigned long	cmd;
	caddr_t		cmdarg;
	int		flags;
	struct thread	*td;
{
#endif
    struct kqemu_instance *ks = (struct kqemu_instance *) dev->si_drv1;
    struct kqemu_state *s = ks->state;
    long ret;
    /*int error;*/

    switch (cmd) {
    case KQEMU_INIT:
    	/*kqemu_log("KQEMU_INIT data=0x%08x\n",cmdarg);*/
    {
        if (s)
	    return(EIO);

        if (!(s = kqemu_init((struct kqemu_init *)cmdarg, max_locked_pages)))
	    return(ENOMEM);

        ks->state = s;
	ret = 0;
	break;
    }
    case KQEMU_EXEC:
    	/*kqemu_log("KQEMU_EXEC data=0x%08x\n",cmdarg);*/
    {
        struct kqemu_cpu_state *ctx;
	
        if (!s)
	    return(EIO);
            
        ctx = kqemu_get_cpu_state(s);
	memcpy((void *)ctx, (void *)cmdarg, sizeof(struct kqemu_cpu_state));

        ret = kqemu_exec(s);

	memcpy((void *)cmdarg, (void *)ctx, sizeof(struct kqemu_cpu_state));

        break;
    }
    case KQEMU_GET_VERSION:
    	/*kqemu_log("KQEMU_GET_VERSION data=0x%08x\n",cmdarg);*/
    {
    	*(int *)cmdarg = KQEMU_VERSION;
	ret = 0;
	break;
    }
    default:
    	/*kqemu_log("ioctl unknown 0x%08x\n",cmd);*/
        return(ENXIO);
    }
    return(ret);
}

static int
init_module(void)
{
#if __FreeBSD_version < 500000
    int rc;
#endif
    
    printf("QEMU Accelerator Module version %d.%d.%d, Copyright (c) 2005 Fabrice Bellard\n"
	   "FreeBSD wrapper port, Copyright (c) 2005  Antony T Curtis\n"
           "This is a proprietary product. Read the LICENSE file for more information\n"
           "Redistribution of this module is prohibited without authorization\n",
           (KQEMU_VERSION >> 16),
           (KQEMU_VERSION >> 8) & 0xff,
           (KQEMU_VERSION) & 0xff);

    max_locked_pages = physmem / (2 * KQEMU_MAX_INSTANCES);
    if (max_locked_pages > 32768)
        max_locked_pages = 32768;

#if __FreeBSD_version < 500000
    if ((rc = cdevsw_add(&kqemu_cdevsw))) {
    	kqemu_log("error registering cdevsw, rc=%d\n", rc);
	return(ENOENT);
    }
#endif
	
    kqemu_dev = make_dev(&kqemu_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "kqemu");

    kqemu_log("KQEMU installed, max_instances=%d max_locked_mem=%dkB.\n",
              KQEMU_MAX_INSTANCES, max_locked_pages * 4);

    kqemu_ref_count = 0;
    return 0;
}

static void
cleanup_module(void)
{
#if __FreeBSD_version < 500000
    int rc;
#endif
    
    destroy_dev(kqemu_dev);
#if __FreeBSD_version < 500000
    if ((rc = cdevsw_remove(&kqemu_cdevsw)))
	kqemu_log("error unregistering, rc=%d\n", rc);
#endif
}

static int
kqemu_modevent(module_t mod, int type, void *data)
{
    int err = 0;
    switch (type) {
    case MOD_LOAD:
    	err = init_module();
	break;
    case MOD_UNLOAD:
    	if (kqemu_ref_count > 0) {
	    err = EBUSY;
	    break;
	}
	/* fall through */
    case MOD_SHUTDOWN:
        cleanup_module();
    	break;
    default:
        err = EINVAL;
    	break;
    }
    return(err);
}

static moduledata_t kqemu_mod = {
	"kqemu_driver",
	kqemu_modevent,
	NULL
};

DECLARE_MODULE(kqemu, kqemu_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);


      parent reply	other threads:[~2005-03-23 14:19 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-03-21  1:42 [Qemu-devel] Accelerator for FreeBSD? Ryan Rempel
2005-03-21  4:22 ` Mikko Työläjärvi
2005-03-21 14:57 ` KQEMU on FreeBSD partially works. (Was: [Qemu-devel] Accelerator for FreeBSD?) Antony T Curtis
2005-03-23  1:27   ` Ryan Rempel
2005-03-23 12:15     ` Antony T Curtis
2005-03-23 13:58     ` Antony T Curtis [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1111586318.2588.29.camel@pcgem.xiphis.org \
    --to=antony.t.curtis@ntlworld.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rgrempel@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).