From: Andreas Sandberg Date: Mon, 30 Sep 2013 10:20:53 +0000 (+0200) Subject: x86: Add support for m5ops through a memory mapped interface X-Git-Tag: stable_2014_02_15~105 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=fec2dea5c35d830ab4f4dc5295e6dba0e152f18e;p=gem5.git x86: Add support for m5ops through a memory mapped interface 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. --- diff --git a/configs/common/FSConfig.py b/configs/common/FSConfig.py index c971ba4cf..742aaca2d 100644 --- a/configs/common/FSConfig.py +++ b/configs/common/FSConfig.py @@ -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 diff --git a/src/arch/x86/tlb.cc b/src/arch/x86/tlb.cc index 087cfbadf..e6ca166b3 100644 --- a/src/arch/x86/tlb.cc +++ b/src/arch/x86/tlb.cc @@ -39,6 +39,7 @@ #include +#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)); } } diff --git a/util/m5/Makefile.x86 b/util/m5/Makefile.x86 index e2d5d3722..326120298 100644 --- a/util/m5/Makefile.x86 +++ b/util/m5/Makefile.x86 @@ -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 diff --git a/util/m5/m5.c b/util/m5/m5.c index 021816ce3..1ddaaf66d 100644 --- a/util/m5/m5.c +++ b/util/m5/m5.c @@ -51,10 +51,15 @@ #include #include #include +#include +#include +#include #include #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; diff --git a/util/m5/m5op_x86.S b/util/m5/m5op_x86.S index 2c25785e6..2e950c10f 100644 --- a/util/m5/m5op_x86.S +++ b/util/m5/m5op_x86.S @@ -32,6 +32,24 @@ #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)