run.c File Reference
`#include <errno.h>`
`#include <fcntl.h>`
`#include <stdio.h>`
`#include <stdint.h>`
`#include <stdlib.h>`
`#include <string.h>`
`#include <syscall.h>`
`#include <unistd.h>`
`#include <sys/types.h>`
`#include <sys/mman.h>`
`#include <sys/spu.h>`
`#include "elf_loader.h"`
`#include "lib_builtin.h"`
`#include "spebase.h"`
Include dependency graph for run.c:

Go to the source code of this file.

## Data Structures

struct | spe_context_info

## Macros

#define | GNU_SOURCE 1

## Functions

int | _base_spe_context_run (spe_context_ptr_t spe, unsigned int *entry, unsigned int runflags, void *argp, void *envp, spe_stop_info_t *stopinfo)

## Variables

__thread struct spe_context_info * | __spe_current_active_context

## Macro Definition Documentation

#define GNU_SOURCE 1

Definition at line 20 of file run.c.

## Function Documentation

int _base_spe_context_run | ( | spe_context_ptr_t | spe,
|  | unsigned int * | entry,
|  | unsigned int | runflags,
|  | void * | argp,
|  | void * | envp,
|  | spe_stop_info_t * | stopinfo
| ) |  |

_base_spe_context_run starts execution of an SPE context with a loaded image

Parameters

  spectx | Specifies the SPE context
  entry | entry point for the SPE programm. If set to 0, entry point is determined by the ELF loader.
  runflags | valid values are: SPE_RUN_USER_REGS Specifies that the SPE setup registers r3, r4, and r5 are initialized with the 48 bytes pointed to by argp. SPE_NO_CALLBACKS do not use built in library functions.
  argp | An (optional) pointer to application specific data, and is passed as the second parameter to the SPE program.
  envp | An (optional) pointer to environment specific data, and is passed as the third parameter to the SPE program.

Definition at line 99 of file run.c.

References __spe_current_active_context, _base_spe_handle_library_callback(), _base_spe_program_load_complete(), spe_context::base_private, DEBUG_PRINTF, spe_context_base_priv::emulated_entry, spe_context_base_priv::entry, spe_context_base_priv::fd_spe_dir, spe_context_base_priv::flags, LS_SIZE, spe_context_base_priv::mem_mmap_base, spe_context_info::npc, spe_context_info::prev, spe_stop_info::result, spe_stop_info::spe_callback_error, SPE_CALLBACK_ERROR, SPE_DEFAULT_ENTRY, SPE_EVENTS_ENABLE, SPE_EXIT, spe_stop_info::spe_exit_code, spe_context_info::spe_id, SPE_ISOLATE, SPE_ISOLATE_EMULATE, spe_stop_info::spe_isolation_error, SPE_ISOLATION_ERROR, SPE_NO_CALLBACKS, SPE_PROGRAM_ISO_LOAD_COMPLETE, SPE_PROGRAM_ISOLATED_STOP, SPE_PROGRAM_LIBRARY_CALL, SPE_PROGRAM_NORMAL_END, SPE_RUN_USER_REGS, spe_stop_info::spe_runtime_error, SPE_RUNTIME_ERROR, spe_stop_info::spe_runtime_exception, SPE_RUNTIME_EXCEPTION, spe_stop_info::spe_runtime_fatal, SPE_RUNTIME_FATAL, spe_stop_info::spe_signal_code, SPE_SPU_HALT, SPE_SPU_INVALID_CHANNEL, SPE_SPU_INVALID_INSTR, SPE_SPU_STOPPED_BY_STOP, SPE_SPU_WAITING_ON_CHANNEL, SPE_STOP_AND_SIGNAL, spe_stop_info::spu_status, spe_context_info::status, spe_stop_info::stop_reason, addr64::ui, and addr64::ull.

Referenced by _event_spe_context_run().

{
int retval = 0, run_rc;
unsigned int run_status, tmp_entry;
spe_stop_info_t stopinfo_buf;
struct spe_context_info this_context_info __attribute__((cleanup(cleanupspeinfo)));
/* If the caller hasn't set a stopinfo buffer, provide a buffer on the
* stack instead. */
if (!stopinfo)
stopinfo = &stopinfo_buf;
/* In emulated isolated mode, the npc will always return as zero.
* use our private entry point instead */
if (spe->base_private->flags & SPE_ISOLATE_EMULATE)
tmp_entry = spe->base_private->emulated_entry;
else if (*entry == SPE_DEFAULT_ENTRY)
tmp_entry = spe->base_private->entry;
else
tmp_entry = *entry;
/* If we're starting the SPE binary from its original entry point,
* setup the arguments to main() */
if (tmp_entry == spe->base_private->entry &&
!(spe->base_private->flags &
(SPE_ISOLATE | SPE_ISOLATE_EMULATE))) {
addr64 argp64, envp64, tid64, ls64;
unsigned int regs[128][4];
/* setup parameters */
argp64.ull = (uint64_t)(unsigned long)argp;
envp64.ull = (uint64_t)(unsigned long)envp;
tid64.ull = (uint64_t)(unsigned long)spe;
/* make sure the register values are 0 */
memset(regs, 0, sizeof(regs));
/* set sensible values for stack_ptr and stack_size */
regs[1][0] = (unsigned int) LS_SIZE - 16; /* stack_ptr */
regs[2][0] = 0; /* stack_size ( 0 = default ) */
if (runflags & SPE_RUN_USER_REGS) {
/* When SPE_USER_REGS is set, argp points to an array
* of 3x128b registers to be passed directly to the SPE
* program.
*/
memcpy(regs[3], argp, sizeof(unsigned int) * 12);
} else {
regs[3][0] = tid64.ui[0];
regs[3][1] = tid64.ui[1];
regs[4][0] = argp64.ui[0];
regs[4][1] = argp64.ui[1];
regs[5][0] = envp64.ui[0];
regs[5][1] = envp64.ui[1];
}
/* Store the LS base address in R6 */
ls64.ull = (uint64_t)(unsigned long)spe->base_private->mem_mmap_base;
regs[6][0] = ls64.ui[0];
regs[6][1] = ls64.ui[1];
if (set_regs(spe, regs))
return -1;
}
/*Leave a trail of breadcrumbs for the debugger to follow */
if (!__spe_current_active_context) {
__spe_current_active_context = &this_context_info;
if (!__spe_current_active_context)
return -1;
__spe_current_active_context->prev = NULL;
} else {
struct spe_context_info *newinfo;
newinfo = &this_context_info;
if (!newinfo)
return -1;
newinfo->prev = __spe_current_active_context;
__spe_current_active_context = newinfo;
}
/*remember the ls-addr*/
__spe_current_active_context->spe_id = spe->base_private->fd_spe_dir;
do_run:
/*Remember the npc value*/
__spe_current_active_context->npc = tmp_entry;
/* run SPE context */
run_rc = spu_run(spe->base_private->fd_spe_dir,
&tmp_entry, &run_status);
/*Remember the npc value*/
__spe_current_active_context->npc = tmp_entry;
__spe_current_active_context->status = run_status;
DEBUG_PRINTF("spu_run returned run_rc=0x%08x, entry=0x%04x, "
"ext_status=0x%04x.\n", run_rc, tmp_entry, run_status);
/* set up return values and stopinfo according to spu_run exit
* conditions. This is overwritten on error.
*/
stopinfo->spu_status = run_rc;
if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
/* save the entry point, and pretend that the npc is zero */
spe->base_private->emulated_entry = tmp_entry;
*entry = 0;
} else {
*entry = tmp_entry;
}
/* Return with stopinfo set on syscall error paths */
if (run_rc == -1) {
DEBUG_PRINTF("spu_run returned error %d, errno=%d\n",
run_rc, errno);
stopinfo->stop_reason = SPE_RUNTIME_FATAL;
stopinfo->result.spe_runtime_fatal = errno;
retval = -1;
/* For isolated contexts, pass EPERM up to the
* caller.
*/
if (!(spe->base_private->flags & SPE_ISOLATE
&& errno == EPERM))
errno = EFAULT;
} else if (run_rc & SPE_SPU_INVALID_INSTR) {
DEBUG_PRINTF("SPU has tried to execute an invalid "
"instruction. %d\n", run_rc);
stopinfo->stop_reason = SPE_RUNTIME_ERROR;
stopinfo->result.spe_runtime_error = SPE_SPU_INVALID_INSTR;
errno = EFAULT;
retval = -1;
} else if ((spe->base_private->flags & SPE_EVENTS_ENABLE) && run_status) {
/* Report asynchronous error if return val are set and
* SPU events are enabled.
*/
stopinfo->stop_reason = SPE_RUNTIME_EXCEPTION;
stopinfo->result.spe_runtime_exception = run_status;
stopinfo->spu_status = -1;
errno = EIO;
retval = -1;
} else if (run_rc & SPE_SPU_STOPPED_BY_STOP) {
/* Stop & signals are broken down into three groups
* 1. SPE library call
* 2. SPE user defined stop & signal
* 3. SPE program end.
*
* These groups are signified by the 14-bit stop code:
*/
int stopcode = (run_rc >> 16) & 0x3fff;
/* Check if this is a library callback, and callbacks are
* allowed (ie, running without SPE_NO_CALLBACKS)
*/
if ((stopcode & 0xff00) == SPE_PROGRAM_LIBRARY_CALL
&& !(runflags & SPE_NO_CALLBACKS)) {
int callback_rc, callback_number = stopcode & 0xff;
/* execute library callback */
DEBUG_PRINTF("SPE library call: %d\n", callback_number);
callback_rc = _base_spe_handle_library_callback(spe,
callback_number, *entry);
if (callback_rc) {
/* library callback failed; set errno and
* return immediately */
DEBUG_PRINTF("SPE library call failed: %d\n",
callback_rc);
stopinfo->stop_reason = SPE_CALLBACK_ERROR;
stopinfo->result.spe_callback_error =
callback_rc;
errno = EFAULT;
retval = -1;
} else {
/* successful library callback - restart the SPE
* program at the next instruction */
tmp_entry += 4;
goto do_run;
}
} else if ((stopcode & 0xff00) == SPE_PROGRAM_NORMAL_END) {
/* The SPE program has exited by exit(X) */
stopinfo->stop_reason = SPE_EXIT;
stopinfo->result.spe_exit_code = stopcode & 0xff;
if (spe->base_private->flags & SPE_ISOLATE) {
/* Issue an isolated exit, and re-run the SPE.
* We should see a return value without the
* 0x80 bit set. */
if (!issue_isolated_exit(spe))
goto do_run;
retval = -1;
}
} else if ((stopcode & 0xfff0) == SPE_PROGRAM_ISOLATED_STOP) {
/* 0x2206: isolated app has been loaded by loader;
* provide a hook for the debugger to catch this,
* and restart
*/
if (stopcode == SPE_PROGRAM_ISO_LOAD_COMPLETE) {
_base_spe_program_load_complete(spe);
goto do_run;
} else {
stopinfo->stop_reason = SPE_ISOLATION_ERROR;
stopinfo->result.spe_isolation_error =
stopcode & 0xf;
}
} else if (spe->base_private->flags & SPE_ISOLATE &&
!(run_rc & 0x80)) {
/* We've successfully exited isolated mode */
retval = 0;
} else {
/* User defined stop & signal, including
* callbacks when disabled */
stopinfo->stop_reason = SPE_STOP_AND_SIGNAL;
stopinfo->result.spe_signal_code = stopcode;
retval = stopcode;
}
} else if (run_rc & SPE_SPU_HALT) {
DEBUG_PRINTF("SPU was stopped by halt. %d\n", run_rc);
stopinfo->stop_reason = SPE_RUNTIME_ERROR;
stopinfo->result.spe_runtime_error = SPE_SPU_HALT;
errno = EFAULT;
retval = -1;
} else if (run_rc & SPE_SPU_WAITING_ON_CHANNEL) {
DEBUG_PRINTF("SPU is waiting on channel. %d\n", run_rc);
stopinfo->stop_reason = SPE_RUNTIME_EXCEPTION;
stopinfo->result.spe_runtime_exception = run_status;
stopinfo->spu_status = -1;
errno = EIO;
retval = -1;
} else if (run_rc & SPE_SPU_INVALID_CHANNEL) {
DEBUG_PRINTF("SPU has tried to access an invalid "
"channel. %d\n", run_rc);
stopinfo->stop_reason = SPE_RUNTIME_ERROR;
stopinfo->result.spe_runtime_error = SPE_SPU_INVALID_CHANNEL;
errno = EFAULT;
retval = -1;
} else {
DEBUG_PRINTF("spu_run returned invalid data: 0x%04x\n", run_rc);
stopinfo->stop_reason = SPE_RUNTIME_FATAL;
stopinfo->result.spe_runtime_fatal = -1;
stopinfo->spu_status = -1;
errno = EFAULT;
retval = -1;
}
freespeinfo();
return retval;
}

Here is the call graph for this function:

## Variable Documentation

__thread struct spe_context_info* __spe_current_active_context

Referenced by _base_spe_context_run().