util: Add support for multiple call types in the m5 utility.
authorGabe Black <gabeblack@google.com>
Fri, 27 Mar 2020 08:57:13 +0000 (01:57 -0700)
committerGabe Black <gabeblack@google.com>
Sat, 2 May 2020 06:11:26 +0000 (06:11 +0000)
Using mechanisms added in previous CLs, this change modifies the m5
utility so that it can use any of the back ends enabled and implemented
by each variant, defaulting to one particular implementation if not is
selected explicitly.

On x86, the default mechanism is the magic address. All other variants
default to the magic instruction since they don't have a well
established address to use or even in most cases an implementation to
use.

The ability to override the particular magic address the utility wants
to use (necessary on variants such as aarch64) will be added in a future
CL.

Change-Id: I5fc414740e30759e7dde719cddcc8d5d41f8cc74
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27242
Reviewed-by: Jason Lowe-Power <power.jg@gmail.com>
Reviewed-by: Pouya Fotouhi <pfotouhi@ucdavis.edu>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
14 files changed:
util/m5/SConstruct
util/m5/src/SConscript
util/m5/src/aarch64/SConsopts
util/m5/src/aarch64/m5op.S
util/m5/src/aarch64/m5op_addr.S [new file with mode: 0644]
util/m5/src/addr_call_type.c
util/m5/src/arm/SConsopts
util/m5/src/m5.c
util/m5/src/semi_call_type.c
util/m5/src/sparc/SConsopts
util/m5/src/thumb/SConsopts
util/m5/src/x86/SConsopts
util/m5/src/x86/m5op.S
util/m5/src/x86/m5op_addr.S [new file with mode: 0644]

index 83d46aa4429f03e3f8991b0b88d24f36ba3caaeb..48073d24f8741af082501b007050edf3d0f9c72f 100644 (file)
@@ -23,6 +23,7 @@
 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+import copy
 import os
 
 main = Environment()
@@ -59,11 +60,34 @@ main.SConsignFile(os.path.join(abspath(build_dir), 'sconsign'))
 # Use soft links instead of hard links when setting up a build directory.
 main.SetOption('duplicate', 'soft-copy')
 
+class CallType(object):
+    def __init__(self, name):
+        self.name = name
+        self.impl_file = None
+        self.enabled = False
+        self.default = False
+
+    def impl(self, impl, default=False):
+        self.impl_file = impl
+        self.enabled = True
+        self.default = default
+
+call_types = {
+    # Magic instruction.
+    'inst': CallType('inst'),
+    # Magic address.
+    'addr': CallType('addr'),
+    # Semihosting extension.
+    'semi': CallType('semi'),
+}
+
 for root, dirs, files in os.walk(abspath(src_dir)):
     # Each SConsopts file describes a variant of the m5 utility.
     if 'SConsopts' in files:
         env = main.Clone()
 
+        env['CALL_TYPE'] = copy.deepcopy(call_types)
+
         # The user may override variant settings by setting environment
         # variables of the form ${VARIANT}.${OPTION}. For instance, to set the
         # CROSS_COMPILE prefix for variant foo to bar-, the user would set an
index 392ac9e33b75b592460a1c81ae66ba34dc684bbf..c2a3eded799ca1099824aa07904c9e0b7d17189d 100644 (file)
@@ -29,30 +29,47 @@ Import('*')
 
 # Raw source files.
 m5_mmap = 'm5_mmap.c'
-m5op = '${VARIANT}/m5op.S'
 m5 = 'm5.c'
 jni = 'jni_gem5Op.c'
 lua = 'lua_gem5Op.c'
 
+all_call_types = list(env['CALL_TYPE'].values())
+call_types = list([ ct for ct in all_call_types if ct.enabled ])
+m5ops = list([ '${VARIANT}/%s' % ct.impl_file for ct in call_types ])
+
+default_call_type = list([ ct for ct in call_types if ct.default ])
+assert len(default_call_type) == 1, \
+        'There should be exactly one default call type for %s, found %d' % \
+        (env['VARIANT'], len(default_call_type))
+default_call_type = default_call_type[0]
+
 static_env = env.Clone()
 static_env.Append(LINKFLAGS=[ '-no-pie', '-static' ])
 
+for ct in all_call_types:
+    static_env.Append(CFLAGS='-DENABLE_CT_%s=%d' %
+                (ct.name, 1 if ct.enabled else 0))
+    static_env.Append(CFLAGS='-DDEFAULT_CT_%s=%d' %
+                (ct.name, 1 if ct.default else 0))
+static_env.Append(CFLAGS='-DDEFAULT_CALL_TYPE=%s' % default_call_type.name)
+
 #
 # The m5 library for use in other C/C++ programs.
 #
-libm5 = static_env.StaticLibrary('out/m5', [ m5op, m5_mmap ])
+libm5 = static_env.StaticLibrary('out/m5', [ m5_mmap ] + m5ops)
 
 
 #
 # The m5 stand alone command line utility.
 #
-m5_bin = static_env.Program('out/m5', [ m5, m5_mmap, libm5 ])
+ct_support = list([ File('%s_call_type.c' % ct.name) for ct in call_types ])
+m5_bin = static_env.Program('out/m5', ct_support + [ m5, m5_mmap, libm5 ])
 
 
 # The shared version of the m5 op call sights, used by mutliple targets below.
 shared_env = env.Clone()
 shared_env.Append(ASFLAGS='-DM5OP_PIC')
-m5op_shared = shared_env.SharedObject(m5op)
+m5op_shared = shared_env.SharedObject(m5ops)
 
 if env['HAVE_JAVA']:
     #
@@ -71,7 +88,7 @@ if env['HAVE_JAVA']:
                      OUT=Dir('out'), CWD=Dir('.'))
     # Set include paths to the C headers from the JDK which scons found for us.
     java_env.Append(CPPPATH='${JAVAINCLUDES}')
-    java_env.SharedLibrary('out/gem5OpJni', [ jni, m5op_shared ])
+    java_env.SharedLibrary('out/gem5OpJni', [ jni ] + m5op_shared)
 
 
 if env['HAVE_LUA51']:
@@ -81,4 +98,5 @@ if env['HAVE_LUA51']:
     lua_env = shared_env.Clone()
     # Extract the include paths needed for lua51 using pkg-config.
     lua_env.ParseConfig('pkg-config --cflags lua51')
-    lib = lua_env.SharedLibrary('out/gem5OpLua', [ lua, m5op_shared, m5_mmap ])
+    lib = lua_env.SharedLibrary('out/gem5OpLua',
+                                [ lua, m5_mmap ] + m5op_shared)
index 12059f81f7d7f4408014f094a06695a3480abc3b..343247c0288984b6fe06baf9d82cd794826b247b 100644 (file)
@@ -27,3 +27,6 @@ Import('*')
 
 env['VARIANT'] = 'aarch64'
 get_variant_opt('CROSS_COMPILE', 'aarch64-linux-gnu-')
+
+env['CALL_TYPE']['inst'].impl('m5op.S', default=True)
+env['CALL_TYPE']['addr'].impl('m5op_addr.S')
index 1cc222a9529c24fd4365d5ddd267630012ee3d29..6529dcf0b087c6d6747e979204b876c4ef6a13f1 100644 (file)
 
 #include <gem5/asm/generic/m5ops.h>
 
-#ifdef M5OP_ADDR
-.macro m5op_func, name, func
-        .globl \name
-        \name:
-        // Load the value of m5_mem into x9...
-#if defined(M5OP_PIC)
-        // using the global offset table.
-        adrp x9, :got:m5_mem
-        ldr x9, [ x9, #:got_lo12:m5_mem ]
-        ldr x9, [ x9 ]
-#else
-        // normally.
-        adrp x9, m5_mem
-        ldr x9, [ x9, #:lo12:m5_mem ]
-#endif
-        movz x10, #(\func << 8)
-        ldr x0, [ x9, x10 ]
-        ret
-.endm
-#else
 .macro m5op_func, name, func
         .globl \name
         \name:
         .long 0xff000110 | (\func << 16)
         ret
 .endm
-#endif
 
 .text
 #define M5OP(name, func) m5op_func name, func;
diff --git a/util/m5/src/aarch64/m5op_addr.S b/util/m5/src/aarch64/m5op_addr.S
new file mode 100644 (file)
index 0000000..0368754
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2010-2013, 2016-2017 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder.  You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gem5/asm/generic/m5ops.h>
+
+.macro m5op_func, name, func
+        .globl \name
+        \name:
+        // Load the value of m5_mem into x9...
+#if defined(M5OP_PIC)
+        // using the global offset table.
+        adrp x9, :got:m5_mem
+        ldr x9, [ x9, #:got_lo12:m5_mem ]
+        ldr x9, [ x9 ]
+#else
+        // normally.
+        adrp x9, m5_mem
+        ldr x9, [ x9, #:lo12:m5_mem ]
+#endif
+        movz x10, #(\func << 8)
+        ldr x0, [ x9, x10 ]
+        ret
+.endm
+
+.text
+#define M5OP(name, func) m5op_func M5OP_MERGE_TOKENS(name, _addr), func;
+        M5OP_FOREACH
+#undef M5OP
index d91d2ec665a4066af53ec5eb0cbab81ad0c1fb8b..cb269dc5fa5133b3f32856d00aca83f32d77fd75 100644 (file)
@@ -53,5 +53,6 @@ addr_call_type_detect(int *argc, char **argv[])
 DispatchTable *
 addr_call_type_init()
 {
+    map_m5_mem();
     return &addr_dispatch;
 }
index fb46668fc22dc40783207c55ad270b29f554fc64..e2517580f7c1859a4698a9f0bc599c25502e28d3 100644 (file)
@@ -28,3 +28,5 @@ Import('*')
 env['VARIANT'] = 'arm'
 get_variant_opt('CROSS_COMPILE', 'arm-linux-gnueabihf-')
 env.Append(CFLAGS='-march=armv7-a')
+
+env['CALL_TYPE']['inst'].impl('m5op.S', default=True)
index 9fe82213c1c7579009ce70764aee54e797de3a6d..cda6bf6ddda24cce3fe17382e92608eba2ceb09e 100644 (file)
@@ -51,6 +51,7 @@
 
 #include <gem5/asm/generic/m5ops.h>
 #include <gem5/m5ops.h>
+#include "call_type.h"
 #include "dispatch_table.h"
 #include "m5_mmap.h"
 
@@ -58,12 +59,6 @@ char *progname;
 char *command = "unspecified";
 void usage();
 
-DispatchTable default_dispatch = {
-#define M5OP(name, func) .name = &name,
-M5OP_FOREACH
-#undef M5OP
-};
-
 void
 parse_int_args(int argc, char *argv[], uint64_t ints[], int len)
 {
@@ -323,13 +318,29 @@ int numfuncs = sizeof(mainfuncs) / sizeof(mainfuncs[0]);
 void
 usage()
 {
-    int i;
-
-    for (i = 0; i < numfuncs; ++i) {
-        char *header = i ? "" : "usage:";
-        fprintf(stderr, "%-6s %s %s %s\n",
-                header, progname, mainfuncs[i].name, mainfuncs[i].usage);
-    }
+    fprintf(stderr, "Usage: %s [call type] <command> [arguments]\n", progname);
+    fprintf(stderr, "\n");
+    fprintf(stderr, "Call types:\n");
+#   if ENABLE_CT_addr
+    fprintf(stderr, "    --addr%s\n", DEFAULT_CT_addr ? " (default)" : "");
+    fprintf(stderr, "        Use the address based invocation method.\n");
+#   if defined(M5OP_ADDR)
+    fprintf(stderr, "        The address is %#"PRIx64".\n",
+            (uint64_t)M5OP_ADDR);
+#   endif
+#   endif
+#   if ENABLE_CT_inst
+    fprintf(stderr, "    --inst%s\n", DEFAULT_CT_inst ? " (default)" : "");
+    fprintf(stderr, "        Use the instruction based invocation method.\n");
+#   endif
+#   if ENABLE_CT_semi
+    fprintf(stderr, "    --semi%s\n", DEFAULT_CT_semi ? " (default)" : "");
+    fprintf(stderr, "        Use the semi-hosting based invocation method.\n");
+#   endif
+    fprintf(stderr, "\n");
+    fprintf(stderr, "Commands:\n");
+    for (int i = 0; i < numfuncs; ++i)
+        fprintf(stderr, "    %s %s\n", mainfuncs[i].name, mainfuncs[i].usage);
     fprintf(stderr, "\n");
     fprintf(stderr, "All times in nanoseconds!\n");
 
@@ -340,22 +351,44 @@ int
 main(int argc, char *argv[])
 {
     progname = argv[0];
-    if (argc < 2)
-        usage(1);
 
-    map_m5_mem();
+    argv++;
+    argc--;
+
+    DispatchTable *dt = NULL;
+
+#   if ENABLE_CT_inst
+    if (!dt && inst_call_type_detect(&argc, &argv)) {
+        dt = inst_call_type_init();
+    }
+#   endif
+#   if ENABLE_CT_addr
+    if (!dt && addr_call_type_detect(&argc, &argv)) {
+        dt = addr_call_type_init();
+    }
+#   endif
+#   if ENABLE_CT_semi
+    if (!dt && semi_call_type_detect(&argc, &argv)) {
+        dt = semi_call_type_init();
+    }
+#   endif
+    if (!dt)
+        dt = default_call_type_init();
+
+    if (!argc)
+        usage(1);
 
-    command = argv[1];
+    command = argv[0];
 
-    argv += 2;
-    argc -= 2;
+    argv++;
+    argc--;
 
     int i;
     for (i = 0; i < numfuncs; ++i) {
         if (strcmp(command, mainfuncs[i].name) != 0)
             continue;
 
-        mainfuncs[i].func(&default_dispatch, argc, argv);
+        mainfuncs[i].func(dt, argc, argv);
         exit(0);
     }
 
index 012d63755a3d6f16d001e91e0fa939e52eb86a82..f3d563083cd99db8e2ecbc921b49a9e4978d6505 100644 (file)
 
 #include "semi_call_type.h"
 
+#define M5OP(name, func) __typeof__(name) M5OP_MERGE_TOKENS(name, _semi);
+M5OP_FOREACH
+#undef M5OP
+
 static DispatchTable semi_dispatch = {
 #define M5OP(name, func) .name = &M5OP_MERGE_TOKENS(name, _semi),
 M5OP_FOREACH
index 89b2db9812eb9c5bab0475af290e5f6c3f247184..aa6f4be21d43d114b1c806f5104e617a14c44e63 100644 (file)
@@ -28,3 +28,5 @@ Import('*')
 env['VARIANT'] = 'sparc'
 get_variant_opt('CROSS_COMPILE', 'sparc64-linux-gnu-')
 env.Append(CFLAGS='-m64')
+
+env['CALL_TYPE']['inst'].impl('m5op.S', default=True)
index ffa6c37308661e29416c374f5ad63fa5c0d95f94..e0b0245eb0c94ca39bd89300bcc538a87e41e662 100644 (file)
@@ -28,3 +28,5 @@ Import('*')
 env['VARIANT'] = 'thumb'
 get_variant_opt('CROSS_COMPILE', 'arm-linux-gnueabihf-')
 env.Append(CFLAGS=[ '-mthumb', '-march=armv7' ])
+
+env['CALL_TYPE']['inst'].impl('m5op.S', default=True)
index 8bfbe0a4fc70e95e69e0ddd8c24f94a3e8b53801..8763f293b25ef06b28cd9adfabf7a97d9611bdba 100644 (file)
@@ -28,4 +28,6 @@ Import('*')
 env['VARIANT'] = 'x86'
 get_variant_opt('CROSS_COMPILE', '')
 env.Append(CFLAGS='-DM5OP_ADDR=0xFFFF0000')
-env.Append(ASFLAGS='-DM5OP_ADDR=0xFFFF0000')
+
+env['CALL_TYPE']['inst'].impl('m5op.S')
+env['CALL_TYPE']['addr'].impl('m5op_addr.S', default=True)
index cd83a941226ed2172aadaf1b44771f338ce13809..9a425b6c267370288fefc3bd84b2172d09be2ff0 100644 (file)
 
 #include <gem5/asm/generic/m5ops.h>
 
-/*
-  Note: The ABI for pseudo ops using the M5OP_ADDR is defined in
-  src/arch/x86/pseudo_inst_abi.hh. If the ABI is changed below, it's likely
-  that the ABI in the arch directory will also need to be updated.
-
-  The ABI for the magic instruction-based pseudo ops is not affected by this.
-*/
-
-#if defined(M5OP_ADDR) && defined(M5OP_PIC)
-/* Use the memory mapped m5op interface */
-#define TWO_BYTE_OP(name, number)         \
-        .globl name;                      \
-        .func name;                       \
-name:                                     \
-        mov m5_mem@gotpcrel(%rip), %r11;  \
-        mov (%r11), %r11;                 \
-        mov $number, %rax;                \
-        shl $8, %rax;                     \
-        mov 0(%r11, %rax, 1), %rax;       \
-        ret;                              \
-        .endfunc;
-
-#elif defined(M5OP_ADDR) && !defined(M5OP_PIC)
-/* 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;                       \
-name:                                     \
-        .byte 0x0F, 0x04;                 \
-        .word number;                     \
-        ret;                              \
-        .endfunc;
-
-#endif
-
-#define M5OP(name, number) TWO_BYTE_OP(name, number)
+.macro m5op_func, name, func
+        .globl \name
+        .func \name
+\name:
+        .byte 0x0F, 0x04
+        .word \func
+        ret
+        .endfunc
+.endm
+
+.text
+
+#define M5OP(name, func) m5op_func name, func;
         M5OP_FOREACH
 #undef M5OP
diff --git a/util/m5/src/x86/m5op_addr.S b/util/m5/src/x86/m5op_addr.S
new file mode 100644 (file)
index 0000000..d6e6cf5
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2003-2006 The Regents of The University of Michigan
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <gem5/asm/generic/m5ops.h>
+
+/*
+ * Note: The ABI for pseudo ops using the M5OP_ADDR is defined in
+ * src/arch/x86/pseudo_inst_abi.hh. If the ABI is changed below, it's likely
+ * that the ABI in the arch directory will also need to be updated.
+ */
+
+.macro  m5op_func, name, func
+        .globl \name
+        .func \name
+\name:
+#if defined(M5OP_PIC)
+        mov m5_mem@gotpcrel(%rip), %r11
+        mov (%r11), %r11
+#else
+        mov m5_mem, %r11
+#endif
+        mov $\func, %rax
+        shl $8, %rax
+        mov 0(%r11, %rax, 1), %rax
+        ret
+        .endfunc
+.endm
+
+.text
+#define M5OP(name, func) m5op_func M5OP_MERGE_TOKENS(name, _addr), func;
+        M5OP_FOREACH
+#undef M5OP