x86: Add support for m5ops through a memory mapped interface
authorAndreas Sandberg <andreas@sandberg.pp.se>
Mon, 30 Sep 2013 10:20:53 +0000 (12:20 +0200)
committerAndreas Sandberg <andreas@sandberg.pp.se>
Mon, 30 Sep 2013 10:20:53 +0000 (12:20 +0200)
In order to support m5ops in virtualized environments, we need to use
a memory mapped interface. This changeset adds support for that by
reserving 0xFFFF0000-0xFFFFFFFF and mapping those to the generic IPR
interface for m5ops. The mapping is done in the
X86ISA::TLB::finalizePhysical() which means that it just works for all
of the CPU models, including virtualized ones.

configs/common/FSConfig.py
src/arch/x86/tlb.cc
util/m5/Makefile.x86
util/m5/m5.c
util/m5/m5op_x86.S

index c971ba4cf201dbf1b6f620a1da5d9b2d9fc0cdb9..742aaca2dccb78cc13408950a793fa59ff75040e 100644 (file)
@@ -509,7 +509,10 @@ def makeLinuxX86System(mem_mode, numCPUs = 1, mdesc = None,
         # Mark the rest as available
         X86E820Entry(addr = 0x100000,
                 size = '%dB' % (phys_mem_size - 0x100000),
-                range_type = 1)
+                range_type = 1),
+        # Reserve the last 16kB of the 32-bit address space for the
+        # m5op interface
+        X86E820Entry(addr=0xFFFF0000, size='64kB', range_type=2),
         ]
 
     # Command line
index 087cfbadf0ef8a87edd38cdb5f0019e5f2ec9fcb..e6ca166b364804fd72deaf87644525216b44b638 100644 (file)
@@ -39,6 +39,7 @@
 
 #include <cstring>
 
+#include "arch/generic/mmapped_ipr.hh"
 #include "arch/x86/insts/microldstop.hh"
 #include "arch/x86/regs/misc.hh"
 #include "arch/x86/regs/msr.hh"
@@ -237,6 +238,8 @@ TLB::finalizePhysical(RequestPtr req, ThreadContext *tc, Mode mode) const
         AddrRange apicRange(localApicBase.base * PageBytes,
                             (localApicBase.base + 1) * PageBytes - 1);
 
+        AddrRange m5opRange(0xFFFF0000, 0xFFFFFFFF);
+
         if (apicRange.contains(paddr)) {
             // The Intel developer's manuals say the below restrictions apply,
             // but the linux kernel, because of a compiler optimization, breaks
@@ -253,6 +256,11 @@ TLB::finalizePhysical(RequestPtr req, ThreadContext *tc, Mode mode) const
             req->setFlags(Request::UNCACHEABLE);
             req->setPaddr(x86LocalAPICAddress(tc->contextId(),
                                               paddr - apicRange.start()));
+        } else if (m5opRange.contains(paddr)) {
+            req->setFlags(Request::MMAPPED_IPR);
+            req->setPaddr(GenericISA::iprAddressPseudoInst(
+                              (paddr >> 8) & 0xFF,
+                              paddr & 0xFF));
         }
     }
 
index e2d5d372214ea3a8b2ce719660c3d9d541210fef..326120298f45bca7cefd0b98e084a287922b477d 100644 (file)
@@ -31,7 +31,7 @@ CC=gcc
 AS=as
 LD=ld
 
-CFLAGS=-O2 
+CFLAGS=-O2 -DM5OP_ADDR=0xFFFF0000
 OBJS=m5.o m5op_x86.o
 
 all: m5
index 021816ce37d7767e5f0018cdbc6280b707aab2cd..1ddaaf66ddd327e8f3e0e33b658d53d2d0559382 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "m5op.h"
 
+void *m5_mem = NULL;
+
 char *progname;
 char *command = "unspecified";
 void usage();
@@ -315,6 +320,26 @@ usage()
     exit(1);
 }
 
+static void
+map_m5_mem()
+{
+#ifdef M5OP_ADDR
+    int fd;
+
+    fd = open("/dev/mem", O_RDWR | O_SYNC);
+    if (fd == -1) {
+        perror("Can't open /dev/mem");
+        exit(1);
+    }
+
+    m5_mem = mmap(NULL, 0x10000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, M5OP_ADDR);
+    if (!m5_mem) {
+        perror("Can't mmap /dev/mem");
+        exit(1);
+    }
+#endif
+}
+
 int
 main(int argc, char *argv[])
 {
@@ -322,6 +347,8 @@ main(int argc, char *argv[])
     if (argc < 2)
         usage(1);
 
+    map_m5_mem();
+
     command = argv[1];
 
     argv += 2;
index 2c25785e60bc2ff91fabcb0e5baccb4b6f3575c3..2e950c10fdcd1d2c9a62b95ca236018bdfb8ae65 100644 (file)
 
 #include "m5ops.h"
 
+#ifdef M5OP_ADDR
+/* Use the memory mapped m5op interface */
+#define TWO_BYTE_OP(name, number)         \
+        .globl name;                      \
+        .func name;                       \
+name:                                     \
+        mov m5_mem, %r11;                 \
+        mov $number, %rax;                \
+        shl $8, %rax;                     \
+        mov 0(%r11, %rax, 1), %rax;       \
+        ret;                              \
+        .endfunc;
+
+#else
+/* Use the magic instruction based m5op interface. This does not work
+ * in virtualized environments.
+ */
+
 #define TWO_BYTE_OP(name, number)         \
         .globl name;                      \
         .func name;                       \
@@ -41,6 +59,8 @@ name:                                     \
         ret;                              \
         .endfunc;
 
+#endif
+
 TWO_BYTE_OP(arm, arm_func)
 TWO_BYTE_OP(quiesce, quiesce_func)
 TWO_BYTE_OP(quiesceNs, quiescens_func)