Here is an updated diff.

It includes some fixes to the lkm wrapper code, and more importantly,
a hack to the common/monitor.c file, which should allow you to run
OpenBSD itself inside kqemu, with user-only virtualization.
(-kernel-kqemu doesn't work yet).

I included some instructions in the README.openbsd file.

If you try to use a recent linux (2.6.x) or freebsd kernel on
qemu (with the accelerator or not) you should expect it to be
unbearably slow and/or jerky, loosing interrupts and keeping a
funny clock that runs much faster than real.

That happens because those systems are tuned to higher frequency than
the host (250 or 1000 Hz), and there's currently no way to get a
timer with a resolution higher than the 10ms tick on OpenBSD.

Thanks to everybody who tested it,
Adi

diff -Nrup xx/kqemu-1.3.0pre11/Makefile.openbsd 
kqemu-1.3.0pre11/Makefile.openbsd
--- xx/kqemu-1.3.0pre11/Makefile.openbsd        Thu Jan  1 02:00:00 1970
+++ kqemu-1.3.0pre11/Makefile.openbsd   Mon Nov 12 04:33:48 2007
@@ -0,0 +1,26 @@
+CFLAGS += -Wall
+NOMAN = noman
+
+POSTINSTALL = kqemu-openbsd.sh
+COMMON = kqemu-mod-i386.o
+SRCS = kqemu-openbsd.c
+OBJS = $(COMMON)
+LKM = kqemu
+COMBINED = kqemu.o
+
+.include <bsd.lkm.mk>
+
+$(COMMON): .PHONY config-host.mak
+       gmake -C common all
+config-host.mak: configure
+       ./configure
+tests:
+       gmake -C tests all
+       tests/kqemutest
+
+clean: common.clean
+common.clean: .PHONY
+       rm -f $(COMMON)
+       gmake -C common clean
+       gmake -C tests clean
+       rm -f config-host.mak
diff -Nrup xx/kqemu-1.3.0pre11/README.openbsd kqemu-1.3.0pre11/README.openbsd
--- xx/kqemu-1.3.0pre11/README.openbsd  Thu Jan  1 02:00:00 1970
+++ kqemu-1.3.0pre11/README.openbsd     Mon Nov 12 07:46:26 2007
@@ -0,0 +1,34 @@
+To build the module:
+
+$ make -f Makefile.openbsd
+
+To load it, make the kqemu-openbsd.sh script executable,
+and do the following command as root, at security level = 0:
+
+$ make -f Makefile.openbsd load
+
+The kqemu-openbsd.sh script, when called by modload(8) via the
+'-p' switch, will create a /dev/kqemu character device with the
+correct major number and a 'kqemu' group to own it (if that user
+doesn't already exist). When called without arguments (as by
+modunload) it will remove /dev/kqemu.
+
+To use the accelerator, you have to add yourself to the 'kqemu'
+group.
+
+It is ESSENTIAL to create the device every time the module is
+loaded, and to remove it after the module is unloaded; otherwise
+you may end up accessing other devices via /dev/kqemu, with
+catastrophic consequences.
+
+If you plan to install the module permanently, one way to do it
+is to call 'make install' as root, rename /usr/lkm/kqemu-openbsd.sh
+to /usr/lkm/kqemu.sh, and add to following to
+
+/etc/rc.securelevel:
+for m in $lkm_modules; do
+        modload -e $m -o $m -p /usr/lkm/$m.sh /usr/lkm/$m.o
+done
+
+/etc/rc.conf.local:
+lkm_modules="kqemu"
diff -Nrup xx/kqemu-1.3.0pre11/common/Makefile kqemu-1.3.0pre11/common/Makefile
--- xx/kqemu-1.3.0pre11/common/Makefile Tue Feb  6 23:02:00 2007
+++ kqemu-1.3.0pre11/common/Makefile    Mon Nov 12 07:59:31 2007
@@ -41,7 +41,13 @@ LD=ld
 endif
 
 DEFINES=-D__KERNEL__
-INCLUDES=-nostdinc -iwithprefix include -I. -I..
+
+ifdef CONFIG_OPENBSD
+  INCLUDES=-I. -I..
+else
+  INCLUDES=-nostdinc -iwithprefix include -I. -I..
+endif
+
 TOOLS_CFLAGS=-Wall -O2 -Werror -g
 COMMON_CFLAGS=-Wall -O2 -fomit-frame-pointer -fno-strict-aliasing -Werror 
 ifeq ($(ARCH), x86_64)
diff -Nrup xx/kqemu-1.3.0pre11/common/monitor.c 
kqemu-1.3.0pre11/common/monitor.c
--- xx/kqemu-1.3.0pre11/common/monitor.c        Tue Feb  6 23:02:00 2007
+++ kqemu-1.3.0pre11/common/monitor.c   Mon Nov 12 04:35:43 2007
@@ -990,7 +990,8 @@ static void *map_vaddr(struct kqemu_state *s, unsigned
     e = &s->soft_tlb[(addr >> PAGE_SHIFT) & (SOFT_TLB_SIZE - 1)];
  redo:
     if (e->vaddr[(is_user << 1) + is_write] != (addr & PAGE_MASK)) {
-        soft_tlb_fill(s, addr, is_write, is_user);
+        if(cpu_x86_handle_mmu_fault(s, addr, is_write, is_user, 1))
+                return NULL;
         goto redo;
     } else {
         taddr = e->addend + addr;
@@ -1802,6 +1803,11 @@ static void update_dt_cache(struct kqemu_state *s, int
             page_end = dt_end;
         sel2 = sel + (page_end - dt_ptr);
         ptr = map_vaddr(s, dt_ptr, 0, 0);
+        if(!ptr)
+                /* Open/NetBSD have a 'dynamic' GDT, but they load the gdt
+                   register with LGDT only once and with a limit far beyond
+                   the end of the memory actually mapped for the table */
+                goto skip_the_rest;
         ram_addr = ram_ptr_to_ram_addr(s, ptr);
         if (dt_changed || 
             s->dt_ram_addr[dt_type][pindex] != ram_addr ||
@@ -1818,7 +1824,7 @@ static void update_dt_cache(struct kqemu_state *s, int
     sel_end = (s->dt_limit[dt_type] + 1) & ~7;
     if (sel < sel_end)
         reset_dt_entries(s, dt_type, sel, sel_end);
-
+skip_the_rest:
     s->dt_base[dt_type] = base;
     s->dt_limit[dt_type] = limit;
 }
diff -Nrup xx/kqemu-1.3.0pre11/configure kqemu-1.3.0pre11/configure
--- xx/kqemu-1.3.0pre11/configure       Tue Feb  6 23:02:00 2007
+++ kqemu-1.3.0pre11/configure  Mon Nov 12 07:57:27 2007
@@ -112,6 +112,10 @@ oss="yes"
 OpenBSD)
 bsd="yes"
 oss="yes"
+openbsd="yes"
+if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+    kqemu="yes"
+fi
 ;;
 Darwin)
 bsd="yes"
@@ -344,6 +348,9 @@ if test $linux = "yes" ; then
   if test $kbuild26 = "yes" ; then
     echo "CONFIG_KBUILD26=yes" >> $config_mak
   fi
+fi
+if test $openbsd = "yes"; then
+  echo "CONFIG_OPENBSD=yes" >> $config_mak
 fi
 echo "SRC_PATH=$source_path" >> $config_mak
 
diff -Nrup xx/kqemu-1.3.0pre11/kqemu-openbsd.c kqemu-1.3.0pre11/kqemu-openbsd.c
--- xx/kqemu-1.3.0pre11/kqemu-openbsd.c Thu Jan  1 02:00:00 1970
+++ kqemu-1.3.0pre11/kqemu-openbsd.c    Wed Nov  7 06:41:49 2007
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 2007 Enache Adrian <[EMAIL PROTECTED]>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/exec.h>
+#include <sys/fcntl.h>
+#include <sys/ioccom.h>
+#include <sys/lkm.h>
+#include <sys/malloc.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/stdarg.h>
+#include <uvm/uvm.h>
+#include "kqemu-kernel.h"
+
+struct kqemu_page* CDECL
+kqemu_alloc_zeroed_page(unsigned long *ppage_index)
+{
+       vaddr_t va;
+       paddr_t pa;
+       if(!(va = uvm_km_zalloc(kernel_map, PAGE_SIZE)))
+               return 0;
+       pmap_extract(pmap_kernel(), va, &pa);
+       *ppage_index = pa >> PAGE_SHIFT;
+       return (struct kqemu_page*)va;
+}
+
+void CDECL
+kqemu_free_page(struct kqemu_page *page)
+{
+       uvm_km_free(kernel_map, (vaddr_t)page, PAGE_SIZE);
+}
+
+void* CDECL
+kqemu_io_map(unsigned long page_index, unsigned int size)
+{
+       return 0; /*XXX*/
+}
+
+void CDECL
+kqemu_io_unmap(void *ptr, unsigned int size)
+{
+       /*XXX*/
+}
+
+struct kqemu_user_page *CDECL
+kqemu_lock_user_page(unsigned long *ppage_index, unsigned long user_addr)
+{
+       vaddr_t va = (vaddr_t)user_addr;
+       vm_map_t map = &curproc->p_vmspace->vm_map;
+       paddr_t pa;
+       if(uvm_map_pageable(map, va, va + PAGE_SIZE, FALSE, 0))
+               return 0;
+       pmap_extract(vm_map_pmap(map), va, &pa);
+       *ppage_index = pa >> PAGE_SHIFT;
+       return (struct kqemu_user_page*)va;
+}
+
+void CDECL
+kqemu_log(const char *fmt, ...)
+{
+       va_list va;
+       printf("kqemu: ");
+       va_start(va, fmt); vprintf(fmt, va); va_end(va);
+}
+
+void* CDECL
+kqemu_page_kaddr(struct kqemu_page *page)
+{
+       return page; /*XXX*/
+}
+
+int CDECL
+kqemu_schedule(void)
+{
+       if(want_resched)
+               yield();
+       return CURSIG(curproc);
+}
+
+void CDECL
+kqemu_unlock_user_page(struct kqemu_user_page *page)
+{
+       vaddr_t va = (vaddr_t)page;
+       vm_map_t map = &curproc->p_vmspace->vm_map;
+       if(uvm_map_pageable(map, va, va + PAGE_SIZE, TRUE, 0))
+               printf("kqemu: failed to unwire page at 0x%08lx\n", va);
+}
+
+void CDECL kqemu_vfree(void *ptr)
+{
+       free(ptr, M_TEMP);
+}
+
+void* CDECL
+kqemu_vmalloc(unsigned int size)
+{
+       return malloc(size, M_TEMP, M_WAITOK);
+}
+
+unsigned long CDECL
+kqemu_vmalloc_to_phys(const void *vaddr)
+{
+       paddr_t pa = vtophys((vaddr_t)vaddr);
+       if(!pa)
+               return -1;
+       return pa >> PAGE_SHIFT;
+}
+
+/* /dev/kqemu device operations */
+
+#define        QEMU_MAGIC      0x554d4551
+struct kqemu_instance {
+       int magic;
+       struct kqemu_state *state;
+};
+
+static struct kqemu_global_state *kqemu_gs;
+
+static int
+kqemuopen(dev_t dev, int flag, int devtype, struct proc* p)
+{
+       struct kqemu_instance *ks;
+       if ((flag & (FREAD|FWRITE)) == FREAD)
+               return EPERM;
+       if(p->p_emuldata)
+               return EBUSY;
+       if(!(ks = malloc(sizeof *ks, M_EMULDATA, M_WAITOK)))
+               return ENOMEM;
+       ks->magic = QEMU_MAGIC;
+       ks->state = 0;
+       p->p_emuldata = ks;
+       return 0;
+}
+
+static int
+kqemuclose(dev_t dev, int flag, int devtype, struct proc* p)
+{
+       struct kqemu_instance *ks = p->p_emuldata;
+       if(!ks || ks->magic != QEMU_MAGIC){
+               printf("kqemu: the kqemu instance was lost\n");
+               return EIO;
+       }
+       if(ks->state) kqemu_delete(ks->state);
+       free(ks, M_EMULDATA);
+       p->p_emuldata = 0;
+       return 0;
+}
+
+static int
+kqemuioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
+{
+       struct kqemu_cpu_state *ctx;
+       struct kqemu_instance *ks = p->p_emuldata;
+       if(!ks || ks->magic != QEMU_MAGIC){
+               printf("kqemu: the kqemu instance was lost\n");
+               return EIO;
+       }
+       switch(cmd){
+       case KQEMU_INIT:
+               if(ks->state) return EIO;
+               ks->state = kqemu_init((struct kqemu_init*)data, kqemu_gs);
+               if(!ks->state) return ENOMEM;
+               break;
+       case KQEMU_EXEC:
+               if(!ks->state) return EIO;
+               ctx = kqemu_get_cpu_state(ks->state);
+               *ctx = *(struct kqemu_cpu_state*)data;
+               KERNEL_PROC_UNLOCK(p);
+               kqemu_exec(ks->state);
+               KERNEL_PROC_LOCK(p);
+               *(struct kqemu_cpu_state*)data = *ctx;
+               break;
+       case KQEMU_GET_VERSION:
+               *(int*)data = KQEMU_VERSION;
+               break;
+       default:
+               return ENOTTY;
+       }
+       return 0;
+}
+
+static struct cdevsw kqemu_cdevsw = {
+       kqemuopen,
+       kqemuclose,
+       (dev_type_read((*)))enodev,
+       (dev_type_write((*)))enodev,
+       kqemuioctl,
+       (dev_type_stop((*)))enodev,
+       0,
+       seltrue,
+       (dev_type_mmap((*)))enodev,
+};
+
+MOD_DEV("kqemu", LM_DT_CHAR, -1, &kqemu_cdevsw);
+int lkmexists(struct lkm_table *);
+
+static int
+kqemu_mod(struct lkm_table *lkmtp, int cmd)
+{
+       int max_locked_pages = physmem / 2;
+       switch(cmd){
+       case LKM_E_LOAD:
+               if(lkmexists(lkmtp))
+                       return EEXIST;
+               if(!(kqemu_gs = kqemu_global_init(max_locked_pages)))
+                       return ENOMEM;
+               printf("kqemu: kqemu version 0x%08x loaded,"
+                       " max locked mem=%dkB\n",
+                       KQEMU_VERSION, max_locked_pages << (PAGE_SHIFT - 10));
+               break;
+       case LKM_E_UNLOAD:
+               /* kqemu_global_delete() should return an
+                  error if kqemu_gs->nb_kqemu_states > 0.
+                  then this could be changed to:
+                  if(kqemu_global_delete(kqemu_gs)) return EBUSY; */
+               kqemu_global_delete(kqemu_gs);
+               break;
+       }
+       return 0;
+}
+
+int
+kqemu(struct lkm_table *lkmtp, int cmd, int ver)
+{
+        DISPATCH(lkmtp, cmd, ver, kqemu_mod, kqemu_mod, lkm_nofunc);
+}
diff -Nrup xx/kqemu-1.3.0pre11/kqemu-openbsd.sh 
kqemu-1.3.0pre11/kqemu-openbsd.sh
--- xx/kqemu-1.3.0pre11/kqemu-openbsd.sh        Thu Jan  1 02:00:00 1970
+++ kqemu-1.3.0pre11/kqemu-openbsd.sh   Mon Nov 12 07:14:00 2007
@@ -0,0 +1,17 @@
+#! /bin/sh
+# script to be run as the -p argument to modload and modunload
+# BEWARE: it adds users, and creates and removes special files in /dev
+
+set -e
+
+if [ $# -gt 0 ]; then
+       # called by modload
+       maj="$3"
+       rm -f /dev/kqemu
+       mknod -m 660 /dev/kqemu c "$maj" 0
+       groupinfo -e kqemu || groupadd kqemu
+       chgrp kqemu /dev/kqemu
+else
+       # called by modunload
+       rm -f /dev/kqemu
+fi
diff -Nrup xx/kqemu-1.3.0pre11/tests/Makefile kqemu-1.3.0pre11/tests/Makefile
--- xx/kqemu-1.3.0pre11/tests/Makefile  Tue Feb  6 23:02:00 2007
+++ kqemu-1.3.0pre11/tests/Makefile     Mon Nov 12 08:05:40 2007
@@ -3,9 +3,17 @@ include ../config-host.mak
 #CC=gcc34
 LD=ld
 CC_32=$(CC) -m32
-LD_32=$(LD) -m elf_i386
+
 CFLAGS=-O2 -Wall -Werror -fno-optimize-sibling-calls -fno-common \
        -fno-strict-aliasing -fno-builtin -g -I..
+
+ifdef CONFIG_OPENBSD
+  LD_32=$(LD) -m elf_i386_obsd
+  CFLAGS+=-fno-stack-protector
+else
+  LD_32=$(LD) -m elf_i386
+endif
+
 KERNEL_CFLAGS_32=$(CFLAGS)
 KERNEL_CFLAGS_64=$(CFLAGS) -mno-red-zone -mcmodel=kernel
 
diff -Nrup xx/kqemu-1.3.0pre11/tests/kqemutest.c 
kqemu-1.3.0pre11/tests/kqemutest.c
--- xx/kqemu-1.3.0pre11/tests/kqemutest.c       Tue Feb  6 23:02:00 2007
+++ kqemu-1.3.0pre11/tests/kqemutest.c  Mon Nov  5 18:59:58 2007
@@ -10,7 +10,12 @@
 #include <inttypes.h>
 #include <unistd.h>
 #include <string.h>
+
+#if __OpenBSD__
+#include <elf_abi.h>
+#else
 #include <elf.h>
+#endif
 
 #include "kqemu.h"
 #include "kqemutest.h"

Reply via email to