arch/tile: add Tilera's <arch/sim.h> header as an open-source header

This change adds one of the Tilera standard <arch> headers to the set
of headers shipped with Linux.  The <arch/sim.h> header provides
methods for programmatically interacting with the Tilera simulator.

The current <arch/sim.h> provides inline assembly for the _sim_syscall
function, so the declaration and definition previously provided
manually in Linux are no longer needed.  We now use the standard
sim_validate_lines_evicted() method from <arch/sim.h> rather than
rolling our own direct call to sim_syscall().

Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
This commit is contained in:
Chris Metcalf 2010-10-14 16:00:11 -04:00
parent 4fe938c513
commit bf65e440e8
4 changed files with 622 additions and 37 deletions

View File

@ -0,0 +1,619 @@
/*
* Copyright 2010 Tilera Corporation. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation, version 2.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
* NON INFRINGEMENT. See the GNU General Public License for
* more details.
*/
/**
* @file
*
* Provides an API for controlling the simulator at runtime.
*/
/**
* @addtogroup arch_sim
* @{
*
* An API for controlling the simulator at runtime.
*
* The simulator's behavior can be modified while it is running.
* For example, human-readable trace output can be enabled and disabled
* around code of interest.
*
* There are two ways to modify simulator behavior:
* programmatically, by calling various sim_* functions, and
* interactively, by entering commands like "sim set functional true"
* at the tile-monitor prompt. Typing "sim help" at that prompt provides
* a list of interactive commands.
*
* All interactive commands can also be executed programmatically by
* passing a string to the sim_command function.
*/
#ifndef __ARCH_SIM_H__
#define __ARCH_SIM_H__
#include <arch/sim_def.h>
#include <arch/abi.h>
#ifndef __ASSEMBLER__
#include <arch/spr_def.h>
/**
* Return true if the current program is running under a simulator,
* rather than on real hardware. If running on hardware, other "sim_xxx()"
* calls have no useful effect.
*/
static inline int
sim_is_simulator(void)
{
return __insn_mfspr(SPR_SIM_CONTROL) != 0;
}
/**
* Checkpoint the simulator state to a checkpoint file.
*
* The checkpoint file name is either the default or the name specified
* on the command line with "--checkpoint-file".
*/
static __inline void
sim_checkpoint(void)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_CHECKPOINT);
}
/**
* Report whether or not various kinds of simulator tracing are enabled.
*
* @return The bitwise OR of these values:
*
* SIM_TRACE_CYCLES (--trace-cycles),
* SIM_TRACE_ROUTER (--trace-router),
* SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
* SIM_TRACE_DISASM (--trace-disasm),
* SIM_TRACE_STALL_INFO (--trace-stall-info)
* SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
* SIM_TRACE_L2_CACHE (--trace-l2)
* SIM_TRACE_LINES (--trace-lines)
*/
static __inline unsigned int
sim_get_tracing(void)
{
return __insn_mfspr(SPR_SIM_CONTROL) & SIM_TRACE_FLAG_MASK;
}
/**
* Turn on or off different kinds of simulator tracing.
*
* @param mask Either one of these special values:
*
* SIM_TRACE_NONE (turns off tracing),
* SIM_TRACE_ALL (turns on all possible tracing).
*
* or the bitwise OR of these values:
*
* SIM_TRACE_CYCLES (--trace-cycles),
* SIM_TRACE_ROUTER (--trace-router),
* SIM_TRACE_REGISTER_WRITES (--trace-register-writes),
* SIM_TRACE_DISASM (--trace-disasm),
* SIM_TRACE_STALL_INFO (--trace-stall-info)
* SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller)
* SIM_TRACE_L2_CACHE (--trace-l2)
* SIM_TRACE_LINES (--trace-lines)
*/
static __inline void
sim_set_tracing(unsigned int mask)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_TRACE_SPR_ARG(mask));
}
/**
* Request dumping of different kinds of simulator state.
*
* @param mask Either this special value:
*
* SIM_DUMP_ALL (dump all known state)
*
* or the bitwise OR of these values:
*
* SIM_DUMP_REGS (the register file),
* SIM_DUMP_SPRS (the SPRs),
* SIM_DUMP_ITLB (the iTLB),
* SIM_DUMP_DTLB (the dTLB),
* SIM_DUMP_L1I (the L1 I-cache),
* SIM_DUMP_L1D (the L1 D-cache),
* SIM_DUMP_L2 (the L2 cache),
* SIM_DUMP_SNREGS (the switch register file),
* SIM_DUMP_SNITLB (the switch iTLB),
* SIM_DUMP_SNL1I (the switch L1 I-cache),
* SIM_DUMP_BACKTRACE (the current backtrace)
*/
static __inline void
sim_dump(unsigned int mask)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_DUMP_SPR_ARG(mask));
}
/**
* Print a string to the simulator stdout.
*
* @param str The string to be written; a newline is automatically added.
*/
static __inline void
sim_print_string(const char* str)
{
int i;
for (i = 0; str[i] != 0; i++)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
(str[i] << _SIM_CONTROL_OPERATOR_BITS));
}
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC |
(SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS));
}
/**
* Execute a simulator command string.
*
* Type 'sim help' at the tile-monitor prompt to learn what commands
* are available. Note the use of the tile-monitor "sim" command to
* pass commands to the simulator.
*
* The argument to sim_command() does not include the leading "sim"
* prefix used at the tile-monitor prompt; for example, you might call
* sim_command("trace disasm").
*/
static __inline void
sim_command(const char* str)
{
int c;
do
{
c = *str++;
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_COMMAND |
(c << _SIM_CONTROL_OPERATOR_BITS));
}
while (c);
}
#ifndef __DOXYGEN__
/**
* The underlying implementation of "_sim_syscall()".
*
* We use extra "and" instructions to ensure that all the values
* we are passing to the simulator are actually valid in the registers
* (i.e. returned from memory) prior to the SIM_CONTROL spr.
*/
static __inline int _sim_syscall0(int val)
{
long result;
__asm__ __volatile__ ("mtspr SIM_CONTROL, r0"
: "=R00" (result) : "R00" (val));
return result;
}
static __inline int _sim_syscall1(int val, long arg1)
{
long result;
__asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
: "=R00" (result) : "R00" (val), "R01" (arg1));
return result;
}
static __inline int _sim_syscall2(int val, long arg1, long arg2)
{
long result;
__asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
: "=R00" (result)
: "R00" (val), "R01" (arg1), "R02" (arg2));
return result;
}
/* Note that _sim_syscall3() and higher are technically at risk of
receiving an interrupt right before the mtspr bundle, in which case
the register values for arguments 3 and up may still be in flight
to the core from a stack frame reload. */
static __inline int _sim_syscall3(int val, long arg1, long arg2, long arg3)
{
long result;
__asm__ __volatile__ ("{ and zero, r3, r3 };"
"{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
: "=R00" (result)
: "R00" (val), "R01" (arg1), "R02" (arg2),
"R03" (arg3));
return result;
}
static __inline int _sim_syscall4(int val, long arg1, long arg2, long arg3,
long arg4)
{
long result;
__asm__ __volatile__ ("{ and zero, r3, r4 };"
"{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
: "=R00" (result)
: "R00" (val), "R01" (arg1), "R02" (arg2),
"R03" (arg3), "R04" (arg4));
return result;
}
static __inline int _sim_syscall5(int val, long arg1, long arg2, long arg3,
long arg4, long arg5)
{
long result;
__asm__ __volatile__ ("{ and zero, r3, r4; and zero, r5, r5 };"
"{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }"
: "=R00" (result)
: "R00" (val), "R01" (arg1), "R02" (arg2),
"R03" (arg3), "R04" (arg4), "R05" (arg5));
return result;
}
/**
* Make a special syscall to the simulator itself, if running under
* simulation. This is used as the implementation of other functions
* and should not be used outside this file.
*
* @param syscall_num The simulator syscall number.
* @param nr The number of additional arguments provided.
*
* @return Varies by syscall.
*/
#define _sim_syscall(syscall_num, nr, args...) \
_sim_syscall##nr( \
((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, args)
/* Values for the "access_mask" parameters below. */
#define SIM_WATCHPOINT_READ 1
#define SIM_WATCHPOINT_WRITE 2
#define SIM_WATCHPOINT_EXECUTE 4
static __inline int
sim_add_watchpoint(unsigned int process_id,
unsigned long address,
unsigned long size,
unsigned int access_mask,
unsigned long user_data)
{
return _sim_syscall(SIM_SYSCALL_ADD_WATCHPOINT, 5, process_id,
address, size, access_mask, user_data);
}
static __inline int
sim_remove_watchpoint(unsigned int process_id,
unsigned long address,
unsigned long size,
unsigned int access_mask,
unsigned long user_data)
{
return _sim_syscall(SIM_SYSCALL_REMOVE_WATCHPOINT, 5, process_id,
address, size, access_mask, user_data);
}
/**
* Return value from sim_query_watchpoint.
*/
struct SimQueryWatchpointStatus
{
/**
* 0 if a watchpoint fired, 1 if no watchpoint fired, or -1 for
* error (meaning a bad process_id).
*/
int syscall_status;
/**
* The address of the watchpoint that fired (this is the address
* passed to sim_add_watchpoint, not an address within that range
* that actually triggered the watchpoint).
*/
unsigned long address;
/** The arbitrary user_data installed by sim_add_watchpoint. */
unsigned long user_data;
};
static __inline struct SimQueryWatchpointStatus
sim_query_watchpoint(unsigned int process_id)
{
struct SimQueryWatchpointStatus status;
long val = SIM_CONTROL_SYSCALL |
(SIM_SYSCALL_QUERY_WATCHPOINT << _SIM_CONTROL_OPERATOR_BITS);
__asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }"
: "=R00" (status.syscall_status),
"=R01" (status.address),
"=R02" (status.user_data)
: "R00" (val), "R01" (process_id));
return status;
}
/* On the simulator, confirm lines have been evicted everywhere. */
static __inline void
sim_validate_lines_evicted(unsigned long long pa, unsigned long length)
{
#ifdef __LP64__
_sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 2, pa, length);
#else
_sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 4,
0 /* dummy */, (long)(pa), (long)(pa >> 32), length);
#endif
}
#endif /* !__DOXYGEN__ */
/**
* Modify the shaping parameters of a shim.
*
* @param shim The shim to modify. One of:
* SIM_CONTROL_SHAPING_GBE_0
* SIM_CONTROL_SHAPING_GBE_1
* SIM_CONTROL_SHAPING_GBE_2
* SIM_CONTROL_SHAPING_GBE_3
* SIM_CONTROL_SHAPING_XGBE_0
* SIM_CONTROL_SHAPING_XGBE_1
*
* @param type The type of shaping. This should be the same type of
* shaping that is already in place on the shim. One of:
* SIM_CONTROL_SHAPING_MULTIPLIER
* SIM_CONTROL_SHAPING_PPS
* SIM_CONTROL_SHAPING_BPS
*
* @param units The magnitude of the rate. One of:
* SIM_CONTROL_SHAPING_UNITS_SINGLE
* SIM_CONTROL_SHAPING_UNITS_KILO
* SIM_CONTROL_SHAPING_UNITS_MEGA
* SIM_CONTROL_SHAPING_UNITS_GIGA
*
* @param rate The rate to which to change it. This must fit in
* SIM_CONTROL_SHAPING_RATE_BITS bits or a warning is issued and
* the shaping is not changed.
*
* @return 0 if no problems were detected in the arguments to sim_set_shaping
* or 1 if problems were detected (for example, rate does not fit in 17 bits).
*/
static __inline int
sim_set_shaping(unsigned shim,
unsigned type,
unsigned units,
unsigned rate)
{
if ((rate & ~((1 << SIM_CONTROL_SHAPING_RATE_BITS) - 1)) != 0)
return 1;
__insn_mtspr(SPR_SIM_CONTROL, SIM_SHAPING_SPR_ARG(shim, type, units, rate));
return 0;
}
#ifdef __tilegx__
/** Enable a set of mPIPE links. Pass a -1 link_mask to enable all links. */
static __inline void
sim_enable_mpipe_links(unsigned mpipe, unsigned long link_mask)
{
__insn_mtspr(SPR_SIM_CONTROL,
(SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
(mpipe << 8) | (1 << 16) | ((uint_reg_t)link_mask << 32)));
}
/** Disable a set of mPIPE links. Pass a -1 link_mask to disable all links. */
static __inline void
sim_disable_mpipe_links(unsigned mpipe, unsigned long link_mask)
{
__insn_mtspr(SPR_SIM_CONTROL,
(SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE |
(mpipe << 8) | (0 << 16) | ((uint_reg_t)link_mask << 32)));
}
#endif /* __tilegx__ */
/*
* An API for changing "functional" mode.
*/
#ifndef __DOXYGEN__
#define sim_enable_functional() \
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_ENABLE_FUNCTIONAL)
#define sim_disable_functional() \
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_DISABLE_FUNCTIONAL)
#endif /* __DOXYGEN__ */
/*
* Profiler support.
*/
/**
* Turn profiling on for the current task.
*
* Note that this has no effect if run in an environment without
* profiling support (thus, the proper flags to the simulator must
* be supplied).
*/
static __inline void
sim_profiler_enable(void)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_ENABLE);
}
/** Turn profiling off for the current task. */
static __inline void
sim_profiler_disable(void)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_DISABLE);
}
/**
* Turn profiling on or off for the current task.
*
* @param enabled If true, turns on profiling. If false, turns it off.
*
* Note that this has no effect if run in an environment without
* profiling support (thus, the proper flags to the simulator must
* be supplied).
*/
static __inline void
sim_profiler_set_enabled(int enabled)
{
int val =
enabled ? SIM_CONTROL_PROFILER_ENABLE : SIM_CONTROL_PROFILER_DISABLE;
__insn_mtspr(SPR_SIM_CONTROL, val);
}
/**
* Return true if and only if profiling is currently enabled
* for the current task.
*
* This returns false even if sim_profiler_enable() was called
* if the current execution environment does not support profiling.
*/
static __inline int
sim_profiler_is_enabled(void)
{
return ((__insn_mfspr(SPR_SIM_CONTROL) & SIM_PROFILER_ENABLED_MASK) != 0);
}
/**
* Reset profiling counters to zero for the current task.
*
* Resetting can be done while profiling is enabled. It does not affect
* the chip-wide profiling counters.
*/
static __inline void
sim_profiler_clear(void)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_CLEAR);
}
/**
* Enable specified chip-level profiling counters.
*
* Does not affect the per-task profiling counters.
*
* @param mask Either this special value:
*
* SIM_CHIP_ALL (enables all chip-level components).
*
* or the bitwise OR of these values:
*
* SIM_CHIP_MEMCTL (enable all memory controllers)
* SIM_CHIP_XAUI (enable all XAUI controllers)
* SIM_CHIP_MPIPE (enable all MPIPE controllers)
*/
static __inline void
sim_profiler_chip_enable(unsigned int mask)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask));
}
/**
* Disable specified chip-level profiling counters.
*
* Does not affect the per-task profiling counters.
*
* @param mask Either this special value:
*
* SIM_CHIP_ALL (disables all chip-level components).
*
* or the bitwise OR of these values:
*
* SIM_CHIP_MEMCTL (disable all memory controllers)
* SIM_CHIP_XAUI (disable all XAUI controllers)
* SIM_CHIP_MPIPE (disable all MPIPE controllers)
*/
static __inline void
sim_profiler_chip_disable(unsigned int mask)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask));
}
/**
* Reset specified chip-level profiling counters to zero.
*
* Does not affect the per-task profiling counters.
*
* @param mask Either this special value:
*
* SIM_CHIP_ALL (clears all chip-level components).
*
* or the bitwise OR of these values:
*
* SIM_CHIP_MEMCTL (clear all memory controllers)
* SIM_CHIP_XAUI (clear all XAUI controllers)
* SIM_CHIP_MPIPE (clear all MPIPE controllers)
*/
static __inline void
sim_profiler_chip_clear(unsigned int mask)
{
__insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask));
}
/*
* Event support.
*/
#ifndef __DOXYGEN__
static __inline void
sim_event_begin(unsigned int x)
{
#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
__insn_mtspr(SPR_EVENT_BEGIN, x);
#endif
}
static __inline void
sim_event_end(unsigned int x)
{
#if defined(__tile__) && !defined(__NO_EVENT_SPR__)
__insn_mtspr(SPR_EVENT_END, x);
#endif
}
#endif /* !__DOXYGEN__ */
#endif /* !__ASSEMBLER__ */
#endif /* !__ARCH_SIM_H__ */
/** @} */

View File

@ -217,13 +217,6 @@ int hardwall_deactivate(struct task_struct *task);
} while (0)
#endif
/* Invoke the simulator "syscall" mechanism (see arch/tile/kernel/entry.S). */
extern int _sim_syscall(int syscall_num, ...);
#define sim_syscall(syscall_num, ...) \
_sim_syscall(SIM_CONTROL_SYSCALL + \
((syscall_num) << _SIM_CONTROL_OPERATOR_BITS), \
## __VA_ARGS__)
/*
* Kernel threads can check to see if they need to migrate their
* stack whenever they return from a context switch; for user

View File

@ -25,28 +25,6 @@ STD_ENTRY(current_text_addr)
{ move r0, lr; jrp lr }
STD_ENDPROC(current_text_addr)
STD_ENTRY(_sim_syscall)
/*
* Wait for r0-r9 to be ready (and lr on the off chance we
* want the syscall to locate its caller), then make a magic
* simulator syscall.
*
* We carefully stall until the registers are readable in case they
* are the target of a slow load, etc. so that tile-sim will
* definitely be able to read all of them inside the magic syscall.
*
* Technically this is wrong for r3-r9 and lr, since an interrupt
* could come in and restore the registers with a slow load right
* before executing the mtspr. We may need to modify tile-sim to
* explicitly stall for this case, but we do not yet have
* a way to implement such a stall.
*/
{ and zero, lr, r9 ; and zero, r8, r7 }
{ and zero, r6, r5 ; and zero, r4, r3 }
{ and zero, r2, r1 ; mtspr SIM_CONTROL, r0 }
{ jrp lr }
STD_ENDPROC(_sim_syscall)
/*
* Implement execve(). The i386 code has a note that forking from kernel
* space results in no copy on write until the execve, so we should be

View File

@ -37,6 +37,8 @@
#include <asm/pgalloc.h>
#include <asm/homecache.h>
#include <arch/sim.h>
#include "migrate.h"
@ -217,13 +219,6 @@ static unsigned long cache_flush_length(unsigned long length)
return (length >= CHIP_L2_CACHE_SIZE()) ? HV_FLUSH_EVICT_L2 : length;
}
/* On the simulator, confirm lines have been evicted everywhere. */
static void validate_lines_evicted(unsigned long pfn, size_t length)
{
sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED,
(HV_PhysAddr)pfn << PAGE_SHIFT, length);
}
/* Flush a page out of whatever cache(s) it is in. */
void homecache_flush_cache(struct page *page, int order)
{
@ -234,7 +229,7 @@ void homecache_flush_cache(struct page *page, int order)
homecache_mask(page, pages, &home_mask);
flush_remote(pfn, length, &home_mask, 0, 0, 0, NULL, NULL, 0);
validate_lines_evicted(pfn, pages * PAGE_SIZE);
sim_validate_lines_evicted(PFN_PHYS(pfn), pages * PAGE_SIZE);
}