Patchwork Get bsd-user host page protection code working on FreeBSD hosts

login
register
mail settings
Submitter Juergen Lock
Date March 25, 2010, 9:32 p.m.
Message ID <20100325213216.GA52727@triton8.kn-bremen.de>
Download mbox | patch
Permalink /patch/48605/
State New
Headers show

Comments

Juergen Lock - March 25, 2010, 9:32 p.m.
Use kinfo_getvmmap(3) on FeeBSD >= 7.x and /compat/linux/proc on older
FreeBSD.  (kinfo_getvmmap is preferred since /compat/linux/proc is
usually only mounted on hosts also using the Linuxolator.)

This patch is a bit hacky because the includes needed for kinfo_getvmmap
conflict with other definitions in exec.c by default so I had to `trick
around' a little, but I built the result in FreeBSD 6.4-stable and
7.2-stable tbs and on 8-stable on the host so the hacks at least
should be stable.  (If this is a problem maybe we could also move the
kinfo_getvmmap invocations into a seperate source file but that would
be more work...)

Signed-off-by: Juergen Lock <nox@jelal.kn-bremen.de>

Patch

--- a/configure
+++ b/configure
@@ -335,6 +335,8 @@  FreeBSD)
   make="gmake"
   audio_drv_list="oss"
   audio_possible_drivers="oss sdl esd pa"
+  # needed for kinfo_getvmmap(3) in libutil.h
+  LIBS="-lutil $LIBS"
 ;;
 DragonFly)
   bsd="yes"
--- a/exec.c
+++ b/exec.c
@@ -41,6 +41,21 @@ 
 #if defined(CONFIG_USER_ONLY)
 #include <qemu.h>
 #include <signal.h>
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <sys/param.h>
+#if __FreeBSD_version >= 700104
+#define HAVE_KINFO_GETVMMAP
+#define sigqueue sigqueue_freebsd  /* avoid redefinition */
+#include <sys/time.h>
+#include <sys/proc.h>
+#include <machine/profile.h>
+#define _KERNEL
+#include <sys/user.h>
+#undef _KERNEL
+#undef sigqueue
+#include <libutil.h>
+#endif
+#endif
 #endif
 
 //#define DEBUG_TB_INVALIDATE
@@ -274,11 +289,45 @@  static void page_init(void)
 
 #if !defined(_WIN32) && defined(CONFIG_USER_ONLY)
     {
+#ifdef HAVE_KINFO_GETVMMAP
+        struct kinfo_vmentry *freep;
+        int i, cnt;
+
+        freep = kinfo_getvmmap(getpid(), &cnt);
+        if (freep) {
+            mmap_lock();
+            for (i = 0; i < cnt; i++) {
+                unsigned long startaddr, endaddr;
+
+                startaddr = freep[i].kve_start;
+                endaddr = freep[i].kve_end;
+                if (h2g_valid(startaddr)) {
+                    startaddr = h2g(startaddr) & TARGET_PAGE_MASK;
+
+                    if (h2g_valid(endaddr)) {
+                        endaddr = h2g(endaddr);
+                        page_set_flags(startaddr, endaddr, PAGE_RESERVED);
+                    } else {
+#if TARGET_ABI_BITS <= L1_MAP_ADDR_SPACE_BITS
+                        endaddr = ~0ul;
+                        page_set_flags(startaddr, endaddr, PAGE_RESERVED);
+#endif
+                    }
+                }
+            }
+            free(freep);
+            mmap_unlock();
+        }
+#else
         FILE *f;
 
         last_brk = (unsigned long)sbrk(0);
 
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__DragonFly__)
+        f = fopen("/compat/linux/proc/self/maps", "r");
+#else
         f = fopen("/proc/self/maps", "r");
+#endif
         if (f) {
             mmap_lock();
 
@@ -303,6 +352,7 @@  static void page_init(void)
             fclose(f);
             mmap_unlock();
         }
+#endif
     }
 #endif
 }