From 40b79073f0031337cea10624b0ebd73ed9f884cf Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Fri, 27 Mar 2020 01:57:13 -0700 Subject: [PATCH] util: Add support for multiple call types in the m5 utility. 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 Reviewed-by: Pouya Fotouhi Maintainer: Gabe Black Tested-by: kokoro --- util/m5/SConstruct | 24 +++++++++++ util/m5/src/SConscript | 30 +++++++++++--- util/m5/src/aarch64/SConsopts | 3 ++ util/m5/src/aarch64/m5op.S | 21 ---------- util/m5/src/aarch64/m5op_addr.S | 65 +++++++++++++++++++++++++++++ util/m5/src/addr_call_type.c | 1 + util/m5/src/arm/SConsopts | 2 + util/m5/src/m5.c | 73 ++++++++++++++++++++++++--------- util/m5/src/semi_call_type.c | 4 ++ util/m5/src/sparc/SConsopts | 2 + util/m5/src/thumb/SConsopts | 2 + util/m5/src/x86/SConsopts | 4 +- util/m5/src/x86/m5op.S | 65 ++++++----------------------- util/m5/src/x86/m5op_addr.S | 57 +++++++++++++++++++++++++ 14 files changed, 253 insertions(+), 100 deletions(-) create mode 100644 util/m5/src/aarch64/m5op_addr.S create mode 100644 util/m5/src/x86/m5op_addr.S diff --git a/util/m5/SConstruct b/util/m5/SConstruct index 83d46aa44..48073d24f 100644 --- a/util/m5/SConstruct +++ b/util/m5/SConstruct @@ -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 diff --git a/util/m5/src/SConscript b/util/m5/src/SConscript index 392ac9e33..c2a3eded7 100644 --- a/util/m5/src/SConscript +++ b/util/m5/src/SConscript @@ -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) diff --git a/util/m5/src/aarch64/SConsopts b/util/m5/src/aarch64/SConsopts index 12059f81f..343247c02 100644 --- a/util/m5/src/aarch64/SConsopts +++ b/util/m5/src/aarch64/SConsopts @@ -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') diff --git a/util/m5/src/aarch64/m5op.S b/util/m5/src/aarch64/m5op.S index 1cc222a95..6529dcf0b 100644 --- a/util/m5/src/aarch64/m5op.S +++ b/util/m5/src/aarch64/m5op.S @@ -40,33 +40,12 @@ #include -#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 index 000000000..0368754b3 --- /dev/null +++ b/util/m5/src/aarch64/m5op_addr.S @@ -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 + +.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 diff --git a/util/m5/src/addr_call_type.c b/util/m5/src/addr_call_type.c index d91d2ec66..cb269dc5f 100644 --- a/util/m5/src/addr_call_type.c +++ b/util/m5/src/addr_call_type.c @@ -53,5 +53,6 @@ addr_call_type_detect(int *argc, char **argv[]) DispatchTable * addr_call_type_init() { + map_m5_mem(); return &addr_dispatch; } diff --git a/util/m5/src/arm/SConsopts b/util/m5/src/arm/SConsopts index fb46668fc..e2517580f 100644 --- a/util/m5/src/arm/SConsopts +++ b/util/m5/src/arm/SConsopts @@ -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) diff --git a/util/m5/src/m5.c b/util/m5/src/m5.c index 9fe82213c..cda6bf6dd 100644 --- a/util/m5/src/m5.c +++ b/util/m5/src/m5.c @@ -51,6 +51,7 @@ #include #include +#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] [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); } diff --git a/util/m5/src/semi_call_type.c b/util/m5/src/semi_call_type.c index 012d63755..f3d563083 100644 --- a/util/m5/src/semi_call_type.c +++ b/util/m5/src/semi_call_type.c @@ -29,6 +29,10 @@ #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 diff --git a/util/m5/src/sparc/SConsopts b/util/m5/src/sparc/SConsopts index 89b2db981..aa6f4be21 100644 --- a/util/m5/src/sparc/SConsopts +++ b/util/m5/src/sparc/SConsopts @@ -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) diff --git a/util/m5/src/thumb/SConsopts b/util/m5/src/thumb/SConsopts index ffa6c3730..e0b0245eb 100644 --- a/util/m5/src/thumb/SConsopts +++ b/util/m5/src/thumb/SConsopts @@ -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) diff --git a/util/m5/src/x86/SConsopts b/util/m5/src/x86/SConsopts index 8bfbe0a4f..8763f293b 100644 --- a/util/m5/src/x86/SConsopts +++ b/util/m5/src/x86/SConsopts @@ -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) diff --git a/util/m5/src/x86/m5op.S b/util/m5/src/x86/m5op.S index cd83a9412..9a425b6c2 100644 --- a/util/m5/src/x86/m5op.S +++ b/util/m5/src/x86/m5op.S @@ -28,57 +28,18 @@ #include -/* - 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 index 000000000..d6e6cf531 --- /dev/null +++ b/util/m5/src/x86/m5op_addr.S @@ -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 + +/* + * 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 -- 2.30.2