#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().
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 }
__thread struct spe_context_info* __spe_current_active_context |
Referenced by _base_spe_context_run().