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

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


Define 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().

00102 {
00103         int retval = 0, run_rc;
00104         unsigned int run_status, tmp_entry;
00105         spe_stop_info_t stopinfo_buf;
00106         struct spe_context_info this_context_info __attribute__((cleanup(cleanupspeinfo)));
00107 
00108         /* If the caller hasn't set a stopinfo buffer, provide a buffer on the
00109          * stack instead. */
00110         if (!stopinfo)
00111                 stopinfo = &stopinfo_buf;
00112 
00113 
00114         /* In emulated isolated mode, the npc will always return as zero.
00115          * use our private entry point instead */
00116         if (spe->base_private->flags & SPE_ISOLATE_EMULATE)
00117                 tmp_entry = spe->base_private->emulated_entry;
00118 
00119         else if (*entry == SPE_DEFAULT_ENTRY)
00120                 tmp_entry = spe->base_private->entry;
00121         else 
00122                 tmp_entry = *entry;
00123 
00124         /* If we're starting the SPE binary from its original entry point,
00125          * setup the arguments to main() */
00126         if (tmp_entry == spe->base_private->entry &&
00127                         !(spe->base_private->flags &
00128                                 (SPE_ISOLATE | SPE_ISOLATE_EMULATE))) {
00129 
00130                 addr64 argp64, envp64, tid64, ls64;
00131                 unsigned int regs[128][4];
00132 
00133                 /* setup parameters */
00134                 argp64.ull = (uint64_t)(unsigned long)argp;
00135                 envp64.ull = (uint64_t)(unsigned long)envp;
00136                 tid64.ull = (uint64_t)(unsigned long)spe;
00137 
00138                 /* make sure the register values are 0 */
00139                 memset(regs, 0, sizeof(regs));
00140 
00141                 /* set sensible values for stack_ptr and stack_size */
00142                 regs[1][0] = (unsigned int) LS_SIZE - 16;       /* stack_ptr */
00143                 regs[2][0] = 0;                                                         /* stack_size ( 0 = default ) */
00144 
00145                 if (runflags & SPE_RUN_USER_REGS) {
00146                         /* When SPE_USER_REGS is set, argp points to an array
00147                          * of 3x128b registers to be passed directly to the SPE
00148                          * program.
00149                          */
00150                         memcpy(regs[3], argp, sizeof(unsigned int) * 12);
00151                 } else {
00152                         regs[3][0] = tid64.ui[0];
00153                         regs[3][1] = tid64.ui[1];
00154 
00155                         regs[4][0] = argp64.ui[0];
00156                         regs[4][1] = argp64.ui[1];
00157 
00158                         regs[5][0] = envp64.ui[0];
00159                         regs[5][1] = envp64.ui[1];
00160                 }
00161                 
00162                 /* Store the LS base address in R6 */
00163                 ls64.ull = (uint64_t)(unsigned long)spe->base_private->mem_mmap_base;
00164                 regs[6][0] = ls64.ui[0];
00165                 regs[6][1] = ls64.ui[1];
00166 
00167                 if (set_regs(spe, regs))
00168                         return -1;
00169         }
00170 
00171         /*Leave a trail of breadcrumbs for the debugger to follow */
00172         if (!__spe_current_active_context) {
00173                 __spe_current_active_context = &this_context_info;
00174                 if (!__spe_current_active_context)
00175                         return -1;
00176                 __spe_current_active_context->prev = NULL;
00177         } else {
00178                 struct spe_context_info *newinfo;
00179                 newinfo = &this_context_info;
00180                 if (!newinfo)
00181                         return -1;
00182                 newinfo->prev = __spe_current_active_context;
00183                 __spe_current_active_context = newinfo;
00184         }
00185         /*remember the ls-addr*/
00186         __spe_current_active_context->spe_id = spe->base_private->fd_spe_dir;
00187 
00188 do_run:
00189         /*Remember the npc value*/
00190         __spe_current_active_context->npc = tmp_entry;
00191 
00192         /* run SPE context */
00193         run_rc = spu_run(spe->base_private->fd_spe_dir,
00194                         &tmp_entry, &run_status);
00195 
00196         /*Remember the npc value*/
00197         __spe_current_active_context->npc = tmp_entry;
00198         __spe_current_active_context->status = run_status;
00199 
00200         DEBUG_PRINTF("spu_run returned run_rc=0x%08x, entry=0x%04x, "
00201                         "ext_status=0x%04x.\n", run_rc, tmp_entry, run_status);
00202 
00203         /* set up return values and stopinfo according to spu_run exit
00204          * conditions. This is overwritten on error.
00205          */
00206         stopinfo->spu_status = run_rc;
00207 
00208         if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
00209                 /* save the entry point, and pretend that the npc is zero */
00210                 spe->base_private->emulated_entry = tmp_entry;
00211                 *entry = 0;
00212         } else {
00213                 *entry = tmp_entry;
00214         }
00215 
00216         /* Return with stopinfo set on syscall error paths */
00217         if (run_rc == -1) {
00218                 DEBUG_PRINTF("spu_run returned error %d, errno=%d\n",
00219                                 run_rc, errno);
00220                 stopinfo->stop_reason = SPE_RUNTIME_FATAL;
00221                 stopinfo->result.spe_runtime_fatal = errno;
00222                 retval = -1;
00223 
00224                 /* For isolated contexts, pass EPERM up to the
00225                  * caller.
00226                  */
00227                 if (!(spe->base_private->flags & SPE_ISOLATE
00228                                 && errno == EPERM))
00229                         errno = EFAULT;
00230 
00231         } else if (run_rc & SPE_SPU_INVALID_INSTR) {
00232                 DEBUG_PRINTF("SPU has tried to execute an invalid "
00233                                 "instruction. %d\n", run_rc);
00234                 stopinfo->stop_reason = SPE_RUNTIME_ERROR;
00235                 stopinfo->result.spe_runtime_error = SPE_SPU_INVALID_INSTR;
00236                 errno = EFAULT;
00237                 retval = -1;
00238 
00239         } else if ((spe->base_private->flags & SPE_EVENTS_ENABLE) && run_status) {
00240                 /* Report asynchronous error if return val are set and
00241                  * SPU events are enabled.
00242                  */
00243                 stopinfo->stop_reason = SPE_RUNTIME_EXCEPTION;
00244                 stopinfo->result.spe_runtime_exception = run_status;
00245                 stopinfo->spu_status = -1;
00246                 errno = EIO;
00247                 retval = -1;
00248 
00249         } else if (run_rc & SPE_SPU_STOPPED_BY_STOP) {
00250                 /* Stop & signals are broken down into three groups
00251                  *  1. SPE library call
00252                  *  2. SPE user defined stop & signal
00253                  *  3. SPE program end.
00254                  *
00255                  * These groups are signified by the 14-bit stop code:
00256                  */
00257                 int stopcode = (run_rc >> 16) & 0x3fff;
00258 
00259                 /* Check if this is a library callback, and callbacks are
00260                  * allowed (ie, running without SPE_NO_CALLBACKS)
00261                  */
00262                 if ((stopcode & 0xff00) == SPE_PROGRAM_LIBRARY_CALL
00263                                 && !(runflags & SPE_NO_CALLBACKS)) {
00264 
00265                         int callback_rc, callback_number = stopcode & 0xff;
00266 
00267                         /* execute library callback */
00268                         DEBUG_PRINTF("SPE library call: %d\n", callback_number);
00269                         callback_rc = _base_spe_handle_library_callback(spe,
00270                                                                         callback_number, *entry);
00271 
00272                         if (callback_rc) {
00273                                 /* library callback failed; set errno and
00274                                  * return immediately */
00275                                 DEBUG_PRINTF("SPE library call failed: %d\n",
00276                                                 callback_rc);
00277                                 stopinfo->stop_reason = SPE_CALLBACK_ERROR;
00278                                 stopinfo->result.spe_callback_error =
00279                                         callback_rc;
00280                                 errno = EFAULT;
00281                                 retval = -1;
00282                         } else {
00283                                 /* successful library callback - restart the SPE
00284                                  * program at the next instruction */
00285                                 tmp_entry += 4;
00286                                 goto do_run;
00287                         }
00288 
00289                 } else if ((stopcode & 0xff00) == SPE_PROGRAM_NORMAL_END) {
00290                         /* The SPE program has exited by exit(X) */
00291                         stopinfo->stop_reason = SPE_EXIT;
00292                         stopinfo->result.spe_exit_code = stopcode & 0xff;
00293 
00294                         if (spe->base_private->flags & SPE_ISOLATE) {
00295                                 /* Issue an isolated exit, and re-run the SPE.
00296                                  * We should see a return value without the
00297                                  * 0x80 bit set. */
00298                                 if (!issue_isolated_exit(spe))
00299                                         goto do_run;
00300                                 retval = -1;
00301                         }
00302 
00303                 } else if ((stopcode & 0xfff0) == SPE_PROGRAM_ISOLATED_STOP) {
00304 
00305                         /* 0x2206: isolated app has been loaded by loader;
00306                          * provide a hook for the debugger to catch this,
00307                          * and restart
00308                          */
00309                         if (stopcode == SPE_PROGRAM_ISO_LOAD_COMPLETE) {
00310                                 _base_spe_program_load_complete(spe);
00311                                 goto do_run;
00312                         } else {
00313                                 stopinfo->stop_reason = SPE_ISOLATION_ERROR;
00314                                 stopinfo->result.spe_isolation_error =
00315                                         stopcode & 0xf;
00316                         }
00317 
00318                 } else if (spe->base_private->flags & SPE_ISOLATE &&
00319                                 !(run_rc & 0x80)) {
00320                         /* We've successfully exited isolated mode */
00321                         retval = 0;
00322 
00323                 } else {
00324                         /* User defined stop & signal, including
00325                          * callbacks when disabled */
00326                         stopinfo->stop_reason = SPE_STOP_AND_SIGNAL;
00327                         stopinfo->result.spe_signal_code = stopcode;
00328                         retval = stopcode;
00329                 }
00330 
00331         } else if (run_rc & SPE_SPU_HALT) {
00332                 DEBUG_PRINTF("SPU was stopped by halt. %d\n", run_rc);
00333                 stopinfo->stop_reason = SPE_RUNTIME_ERROR;
00334                 stopinfo->result.spe_runtime_error = SPE_SPU_HALT;
00335                 errno = EFAULT;
00336                 retval = -1;
00337 
00338         } else if (run_rc & SPE_SPU_WAITING_ON_CHANNEL) {
00339                 DEBUG_PRINTF("SPU is waiting on channel. %d\n", run_rc);
00340                 stopinfo->stop_reason = SPE_RUNTIME_EXCEPTION;
00341                 stopinfo->result.spe_runtime_exception = run_status;
00342                 stopinfo->spu_status = -1;
00343                 errno = EIO;
00344                 retval = -1;
00345 
00346         } else if (run_rc & SPE_SPU_INVALID_CHANNEL) {
00347                 DEBUG_PRINTF("SPU has tried to access an invalid "
00348                                 "channel. %d\n", run_rc);
00349                 stopinfo->stop_reason = SPE_RUNTIME_ERROR;
00350                 stopinfo->result.spe_runtime_error = SPE_SPU_INVALID_CHANNEL;
00351                 errno = EFAULT;
00352                 retval = -1;
00353 
00354         } else {
00355                 DEBUG_PRINTF("spu_run returned invalid data: 0x%04x\n", run_rc);
00356                 stopinfo->stop_reason = SPE_RUNTIME_FATAL;
00357                 stopinfo->result.spe_runtime_fatal = -1;
00358                 stopinfo->spu_status = -1;
00359                 errno = EFAULT;
00360                 retval = -1;
00361 
00362         }
00363 
00364         freespeinfo();
00365         return retval;
00366 }

Here is the call graph for this function:


Variable Documentation

Referenced by _base_spe_context_run().


Generated on Tue Dec 16 10:15:35 2008 for libspe2 by  doxygen 1.5.7.1