From: Pierre Beyssac <pb@freebsd.org>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] kqemu port to FreeBSD 5.x + qemu patch
Date: Wed, 23 Mar 2005 20:29:36 +0100 [thread overview]
Message-ID: <20050323192936.GA80428@bofh.enst.fr> (raw)
[-- Attachment #1: Type: text/plain, Size: 872 bytes --]
Hello,
I have written a kqemu wrapper for FreeBSD 5.x (attached). It seems
to work (I've had no crash at all) but it's alpha quality and it
currently lacks working kqemu_free_page() and kqemu_vfree() hooks
(which were never called by kqemu-mid-i386.o in my tests).
I would be interested in any comments. It's substantially different
from the code posted here by Antony T Curtis.
I have also attached a patch to qemu/osdep.c to replace the mmaped
"swap" file with a MAP_ANON area; using a file is unnecessary under
FreeBSD; perhaps it's been done this way due to Linux peculiarities,
but I don't see why. The patch doesn't help performance noticeably
but it saves some precious disk or ramdisk space.
--
A: Yes. Pierre Beyssac pb@freebsd.org
>Q: Are you sure?
>>A: Because it reverses the logical flow of conversation.
>>>Q: Why is top posting annoying in email?
[-- Attachment #2: kmod-freebsd.c --]
[-- Type: text/plain, Size: 7367 bytes --]
/* $Id: kmod-freebsd.c,v 1.3 2005/03/23 17:53:24 pb Exp $ */
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/conf.h>
#include <sys/ioccom.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/mutex.h>
#include <sys/proc.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
#include <sys/kernel.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/vm_extern.h>
#include <vm/pmap.h>
#include <vm/vm_map.h>
#include <vm/vm_kern.h>
#include <machine/vmparam.h>
#include <machine/stdarg.h>
#define __KERNEL__
#include "kqemu.h"
MALLOC_DECLARE(M_KQEMU);
MALLOC_DEFINE(M_KQEMU, "kqemu", "kqemu buffers");
#define USER_BASE 0x1000
/* quick and dirty convert a physical address to a virtual address */
static vm_offset_t pa_to_va(vm_paddr_t pa, vm_offset_t beg, vm_offset_t end)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t va;
pmap_t pmap;
pmap = vm_map_pmap(&vm->vm_map);
for (va = beg; va != end; va += PAGE_SIZE)
if (pa == pmap_extract(pmap, va))
return va;
printf("pa_to_va failed: pa=%08x\n", pa);
return -1;
}
/* lock the page at virtual address 'user_addr' and return its
physical page index. Return -1 if error */
unsigned long CDECL kqemu_lock_user_page(unsigned long user_addr)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t va = user_addr;
vm_paddr_t pa = 0;
int ret;
pmap_t pmap;
ret = vm_map_wire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
if (ret != KERN_SUCCESS) {
printf("kqemu_lock_user_page(%08lx) failed, ret=%d\n", user_addr, ret);
return -1;
}
pmap = vm_map_pmap(&vm->vm_map);
pa = pmap_extract(pmap, va);
// printf("kqemu_lock_user_page(%08lx) va=%08x pa=%08x\n", user_addr, va, pa);
return pa >> PAGE_SHIFT;
}
void CDECL kqemu_unlock_user_page(unsigned long page_index)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t va;
int ret;
// printf("kqemu_unlock_user_page(%08lx)\n", page_index);
va = pa_to_va(page_index << PAGE_SHIFT, USER_BASE, KERNBASE);
ret = vm_map_unwire(&vm->vm_map, va, va+PAGE_SIZE, VM_MAP_WIRE_USER);
if (ret != KERN_SUCCESS) {
printf("kqemu_unlock_user_page(%08lx) failed, ret=%d\n", page_index, ret);
}
}
/*
* Allocate a new page. The page must be mapped in the kernel space.
* Return the page_index or -1 if error.
*/
unsigned long CDECL kqemu_alloc_zeroed_page(void)
{
pmap_t pmap;
vm_offset_t va;
vm_paddr_t pa;
va = kmem_alloc(kernel_map, PAGE_SIZE);
if (va == 0) {
printf("kqemu_alloc_zeroed_page: NULL\n");
return -1;
}
pmap = vm_map_pmap(kernel_map);
pa = pmap_extract(pmap, va);
// printf("kqemu_alloc_zeroed_page: %08x\n", pa);
return pa >> PAGE_SHIFT;
}
void CDECL kqemu_free_page(unsigned long page_index)
{
printf("kqemu_free_page(%08lx)\n", page_index);
}
/* return kernel address of the physical page page_index */
void *CDECL kqemu_page_kaddr(unsigned long page_index)
{
vm_offset_t va;
va = pa_to_va(page_index << PAGE_SHIFT, KERNBASE, 0);
if (va != -1) {
printf("kqemu_page_kaddr(%08lx)=%08x\n", page_index, va);
return (void *)va;
}
printf("kqemu_page_kaddr(%08lx)=NOT FOUND\n", page_index);
return NULL;
}
/* contraint: each page of the vmalloced area must be in the first 4
GB of physical memory */
void * CDECL kqemu_vmalloc(unsigned int size)
{
struct vmspace *vm = curproc->p_vmspace;
vm_offset_t va = USER_BASE;
int rv;
if (size % PAGE_SIZE != 0) {
printf("kqemu_vmalloc(%d) not a multiple of page size\n", size);
return NULL;
}
rv = vm_map_find(&vm->vm_map, NULL, 0, &va, size, 1,
VM_PROT_ALL, VM_PROT_ALL, 0);
if (rv != KERN_SUCCESS) {
printf("kqemu_vmalloc(%d) failed rv=%d\n", size, rv);
return NULL;
}
printf("kqemu_vmalloc(%d): %08x\n", size, va);
return (void *)va;
}
void CDECL kqemu_vfree(void *ptr)
{
printf("kqemu_vfree(%p)\n", ptr);
}
/* return the physical page index for a given virtual page */
unsigned long CDECL kqemu_vmalloc_to_phys(const void *vaddr)
{
struct vmspace *vm = curproc->p_vmspace;
vm_paddr_t pa;
pmap_t pmap;
pmap = vm_map_pmap(&vm->vm_map);
pa = pmap_extract(pmap, (vm_offset_t)vaddr);
if (pa == 0) {
printf("kqemu_vmalloc_to_phys(%p)->error\n", vaddr);
return -1;
}
printf("kqemu_vmalloc_to_phys(%p)->%08x\n", vaddr, pa);
return pa >> PAGE_SHIFT;
}
/* return TRUE if a signal is pending (i.e. the guest must stop
execution) */
int CDECL kqemu_schedule(void)
{
// printf("kqemu_schedule\n");
mtx_lock_spin(&sched_lock);
mi_switch(SW_VOL, NULL);
mtx_unlock_spin(&sched_lock);
return SIGPENDING(curthread);
}
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);
}
struct kqemu_instance {
// struct semaphore sem;
struct kqemu_state *state;
};
static d_close_t kqemu_close;
static d_open_t kqemu_open;
static d_ioctl_t kqemu_ioctl;
static struct cdevsw kqemu_cdevsw = {
.d_version = D_VERSION,
.d_flags = D_NEEDGIANT,
.d_open = kqemu_open,
.d_ioctl = kqemu_ioctl,
.d_close = kqemu_close,
.d_name = "kqemu"
};
/* For use with make_dev(9)/destroy_dev(9). */
static struct cdev *kqemu_dev;
/* ARGSUSED */
static int
kqemu_open(struct cdev *dev, int flags, int fmt __unused,
struct thread *td)
{
struct kqemu_instance *ks;
ks = malloc(sizeof(struct kqemu_instance), M_KQEMU, M_WAITOK);
if (ks == NULL) {
printf("malloc failed\n");
return ENOMEM;
}
ks->state = NULL;
dev->si_drv1 = ks;
return 0;
}
/* ARGSUSED */
static int
kqemu_ioctl(struct cdev *dev, u_long cmd, caddr_t addr,
int flags __unused, struct thread *td)
{
int error = 0;
int ret;
struct kqemu_instance *ks = dev->si_drv1;
struct kqemu_state *s = ks->state;
switch(cmd) {
case KQEMU_INIT: {
struct kqemu_init d1, *d = &d1;
if (s != NULL) {
error = EIO;
break;
}
d1 = *(struct kqemu_init *)addr;
printf("ram_base=%p ram_size=%ld\n", d1.ram_base, d1.ram_size);
s = kqemu_init(d, 16000);
if (s == NULL) {
error = ENOMEM;
break;
}
ks->state = s;
break;
}
case KQEMU_EXEC: {
struct kqemu_cpu_state *ctx;
if (s == NULL) {
error = EIO;
break;
}
ctx = kqemu_get_cpu_state(s);
*ctx = *(struct kqemu_cpu_state *)addr;
DROP_GIANT();
ret = kqemu_exec(s);
PICKUP_GIANT();
td->td_retval[0] = ret;
*(struct kqemu_cpu_state *)addr = *ctx;
break;
}
case KQEMU_GET_VERSION:
*(int *)addr = KQEMU_VERSION;
break;
default:
error = EINVAL;
}
return error;
}
/* ARGSUSED */
static int
kqemu_close(struct cdev *dev __unused, int flags, int fmt __unused,
struct thread *td)
{
return 0;
}
/* ARGSUSED */
static int
kqemu_modevent(module_t mod __unused, int type, void *data __unused)
{
int error = 0;
switch (type) {
case MOD_LOAD:
printf("kqemu version 0x%08x\n", KQEMU_VERSION);
kqemu_dev = make_dev(&kqemu_cdevsw, 0,
UID_ROOT, GID_WHEEL, 0666, "kqemu");
break;
case MOD_UNLOAD:
destroy_dev(kqemu_dev);
break;
case MOD_SHUTDOWN:
break;
default:
error = EOPNOTSUPP;
break;
}
return (error);
}
DEV_MODULE(kqemu, kqemu_modevent, NULL);
MODULE_VERSION(kqemu, 1);
[-- Attachment #3: Makefile --]
[-- Type: text/plain, Size: 135 bytes --]
# $Id: Makefile,v 1.1.1.1 2005/03/23 12:29:35 pb Exp $
KMOD= kqemu
SRCS= kmod-freebsd.c
OBJS= kqemu-mod-i386.o
.include <bsd.kmod.mk>
[-- Attachment #4: patch-osdep.c --]
[-- Type: text/plain, Size: 820 bytes --]
--- osdep.c.orig Mon Feb 21 21:10:36 2005
+++ osdep.c Wed Mar 23 18:10:33 2005
@@ -321,6 +321,7 @@
char phys_ram_file[1024];
void *ptr;
+#if 0
if (phys_ram_fd < 0) {
tmpdir = getenv("QEMU_TMPDIR");
if (!tmpdir)
@@ -349,12 +350,20 @@
}
unlink(phys_ram_file);
}
+#endif
size = (size + 4095) & ~4095;
+#if 0
ftruncate(phys_ram_fd, phys_ram_size + size);
ptr = mmap(NULL,
size,
PROT_WRITE | PROT_READ, MAP_SHARED,
phys_ram_fd, phys_ram_size);
+#else
+ ptr = mmap(NULL,
+ size,
+ PROT_WRITE | PROT_READ, MAP_PRIVATE|MAP_ANON,
+ -1, 0);
+#endif
if (ptr == MAP_FAILED) {
fprintf(stderr, "Could not map physical memory\n");
exit(1);
next reply other threads:[~2005-03-23 19:55 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-23 19:29 Pierre Beyssac [this message]
2005-03-24 1:35 ` [Qemu-devel] kqemu port to FreeBSD 5.x + qemu patch Antony T Curtis
2005-03-24 1:51 ` Antony T Curtis
-- strict thread matches above, loose matches on Subject: below --
2005-03-25 9:15 ecs user
2005-03-25 9:49 ` Antony T Curtis
2005-03-25 11:48 ` Hetz Ben Hamo
2005-03-25 13:50 ecs user
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=20050323192936.GA80428@bofh.enst.fr \
--to=pb@freebsd.org \
--cc=qemu-devel@nongnu.org \
/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).