libspe2 0.9a
|
#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"
Go to the source code of this file.
Data Structures | |
struct | spe_context_info |
Defines | |
#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 |
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
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; }
__thread struct spe_context_info* __spe_current_active_context |
Referenced by _base_spe_context_run().