libspe2  0.9a
Data Structures | Macros | Functions | Variables
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
spectxSpecifies the SPE context
entryentry point for the SPE programm. If set to 0, entry point is determined by the ELF loader.
runflagsvalid 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.
argpAn (optional) pointer to application specific data, and is passed as the second parameter to the SPE program.
envpAn (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().

102 {
103  int retval = 0, run_rc;
104  unsigned int run_status, tmp_entry;
105  spe_stop_info_t stopinfo_buf;
106  struct spe_context_info this_context_info __attribute__((cleanup(cleanupspeinfo)));
107 
108  /* If the caller hasn't set a stopinfo buffer, provide a buffer on the
109  * stack instead. */
110  if (!stopinfo)
111  stopinfo = &stopinfo_buf;
112 
113 
114  /* In emulated isolated mode, the npc will always return as zero.
115  * use our private entry point instead */
117  tmp_entry = spe->base_private->emulated_entry;
118 
119  else if (*entry == SPE_DEFAULT_ENTRY)
120  tmp_entry = spe->base_private->entry;
121  else
122  tmp_entry = *entry;
123 
124  /* If we're starting the SPE binary from its original entry point,
125  * setup the arguments to main() */
126  if (tmp_entry == spe->base_private->entry &&
127  !(spe->base_private->flags &
129 
130  addr64 argp64, envp64, tid64, ls64;
131  unsigned int regs[128][4];
132 
133  /* setup parameters */
134  argp64.ull = (uint64_t)(unsigned long)argp;
135  envp64.ull = (uint64_t)(unsigned long)envp;
136  tid64.ull = (uint64_t)(unsigned long)spe;
137 
138  /* make sure the register values are 0 */
139  memset(regs, 0, sizeof(regs));
140 
141  /* set sensible values for stack_ptr and stack_size */
142  regs[1][0] = (unsigned int) LS_SIZE - 16; /* stack_ptr */
143  regs[2][0] = 0; /* stack_size ( 0 = default ) */
144 
145  if (runflags & SPE_RUN_USER_REGS) {
146  /* When SPE_USER_REGS is set, argp points to an array
147  * of 3x128b registers to be passed directly to the SPE
148  * program.
149  */
150  memcpy(regs[3], argp, sizeof(unsigned int) * 12);
151  } else {
152  regs[3][0] = tid64.ui[0];
153  regs[3][1] = tid64.ui[1];
154 
155  regs[4][0] = argp64.ui[0];
156  regs[4][1] = argp64.ui[1];
157 
158  regs[5][0] = envp64.ui[0];
159  regs[5][1] = envp64.ui[1];
160  }
161 
162  /* Store the LS base address in R6 */
163  ls64.ull = (uint64_t)(unsigned long)spe->base_private->mem_mmap_base;
164  regs[6][0] = ls64.ui[0];
165  regs[6][1] = ls64.ui[1];
166 
167  if (set_regs(spe, regs))
168  return -1;
169  }
170 
171  /*Leave a trail of breadcrumbs for the debugger to follow */
173  __spe_current_active_context = &this_context_info;
175  return -1;
177  } else {
178  struct spe_context_info *newinfo;
179  newinfo = &this_context_info;
180  if (!newinfo)
181  return -1;
184  }
185  /*remember the ls-addr*/
187 
188 do_run:
189  /*Remember the npc value*/
190  __spe_current_active_context->npc = tmp_entry;
191 
192  /* run SPE context */
193  run_rc = spu_run(spe->base_private->fd_spe_dir,
194  &tmp_entry, &run_status);
195 
196  /*Remember the npc value*/
197  __spe_current_active_context->npc = tmp_entry;
198  __spe_current_active_context->status = run_status;
199 
200  DEBUG_PRINTF("spu_run returned run_rc=0x%08x, entry=0x%04x, "
201  "ext_status=0x%04x.\n", run_rc, tmp_entry, run_status);
202 
203  /* set up return values and stopinfo according to spu_run exit
204  * conditions. This is overwritten on error.
205  */
206  stopinfo->spu_status = run_rc;
207 
208  if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
209  /* save the entry point, and pretend that the npc is zero */
210  spe->base_private->emulated_entry = tmp_entry;
211  *entry = 0;
212  } else {
213  *entry = tmp_entry;
214  }
215 
216  /* Return with stopinfo set on syscall error paths */
217  if (run_rc == -1) {
218  DEBUG_PRINTF("spu_run returned error %d, errno=%d\n",
219  run_rc, errno);
220  stopinfo->stop_reason = SPE_RUNTIME_FATAL;
221  stopinfo->result.spe_runtime_fatal = errno;
222  retval = -1;
223 
224  /* For isolated contexts, pass EPERM up to the
225  * caller.
226  */
227  if (!(spe->base_private->flags & SPE_ISOLATE
228  && errno == EPERM))
229  errno = EFAULT;
230 
231  } else if (run_rc & SPE_SPU_INVALID_INSTR) {
232  DEBUG_PRINTF("SPU has tried to execute an invalid "
233  "instruction. %d\n", run_rc);
234  stopinfo->stop_reason = SPE_RUNTIME_ERROR;
236  errno = EFAULT;
237  retval = -1;
238 
239  } else if ((spe->base_private->flags & SPE_EVENTS_ENABLE) && run_status) {
240  /* Report asynchronous error if return val are set and
241  * SPU events are enabled.
242  */
244  stopinfo->result.spe_runtime_exception = run_status;
245  stopinfo->spu_status = -1;
246  errno = EIO;
247  retval = -1;
248 
249  } else if (run_rc & SPE_SPU_STOPPED_BY_STOP) {
250  /* Stop & signals are broken down into three groups
251  * 1. SPE library call
252  * 2. SPE user defined stop & signal
253  * 3. SPE program end.
254  *
255  * These groups are signified by the 14-bit stop code:
256  */
257  int stopcode = (run_rc >> 16) & 0x3fff;
258 
259  /* Check if this is a library callback, and callbacks are
260  * allowed (ie, running without SPE_NO_CALLBACKS)
261  */
262  if ((stopcode & 0xff00) == SPE_PROGRAM_LIBRARY_CALL
263  && !(runflags & SPE_NO_CALLBACKS)) {
264 
265  int callback_rc, callback_number = stopcode & 0xff;
266 
267  /* execute library callback */
268  DEBUG_PRINTF("SPE library call: %d\n", callback_number);
269  callback_rc = _base_spe_handle_library_callback(spe,
270  callback_number, *entry);
271 
272  if (callback_rc) {
273  /* library callback failed; set errno and
274  * return immediately */
275  DEBUG_PRINTF("SPE library call failed: %d\n",
276  callback_rc);
277  stopinfo->stop_reason = SPE_CALLBACK_ERROR;
278  stopinfo->result.spe_callback_error =
279  callback_rc;
280  errno = EFAULT;
281  retval = -1;
282  } else {
283  /* successful library callback - restart the SPE
284  * program at the next instruction */
285  tmp_entry += 4;
286  goto do_run;
287  }
288 
289  } else if ((stopcode & 0xff00) == SPE_PROGRAM_NORMAL_END) {
290  /* The SPE program has exited by exit(X) */
291  stopinfo->stop_reason = SPE_EXIT;
292  stopinfo->result.spe_exit_code = stopcode & 0xff;
293 
294  if (spe->base_private->flags & SPE_ISOLATE) {
295  /* Issue an isolated exit, and re-run the SPE.
296  * We should see a return value without the
297  * 0x80 bit set. */
298  if (!issue_isolated_exit(spe))
299  goto do_run;
300  retval = -1;
301  }
302 
303  } else if ((stopcode & 0xfff0) == SPE_PROGRAM_ISOLATED_STOP) {
304 
305  /* 0x2206: isolated app has been loaded by loader;
306  * provide a hook for the debugger to catch this,
307  * and restart
308  */
309  if (stopcode == SPE_PROGRAM_ISO_LOAD_COMPLETE) {
311  goto do_run;
312  } else {
313  stopinfo->stop_reason = SPE_ISOLATION_ERROR;
314  stopinfo->result.spe_isolation_error =
315  stopcode & 0xf;
316  }
317 
318  } else if (spe->base_private->flags & SPE_ISOLATE &&
319  !(run_rc & 0x80)) {
320  /* We've successfully exited isolated mode */
321  retval = 0;
322 
323  } else {
324  /* User defined stop & signal, including
325  * callbacks when disabled */
326  stopinfo->stop_reason = SPE_STOP_AND_SIGNAL;
327  stopinfo->result.spe_signal_code = stopcode;
328  retval = stopcode;
329  }
330 
331  } else if (run_rc & SPE_SPU_HALT) {
332  DEBUG_PRINTF("SPU was stopped by halt. %d\n", run_rc);
333  stopinfo->stop_reason = SPE_RUNTIME_ERROR;
335  errno = EFAULT;
336  retval = -1;
337 
338  } else if (run_rc & SPE_SPU_WAITING_ON_CHANNEL) {
339  DEBUG_PRINTF("SPU is waiting on channel. %d\n", run_rc);
341  stopinfo->result.spe_runtime_exception = run_status;
342  stopinfo->spu_status = -1;
343  errno = EIO;
344  retval = -1;
345 
346  } else if (run_rc & SPE_SPU_INVALID_CHANNEL) {
347  DEBUG_PRINTF("SPU has tried to access an invalid "
348  "channel. %d\n", run_rc);
349  stopinfo->stop_reason = SPE_RUNTIME_ERROR;
351  errno = EFAULT;
352  retval = -1;
353 
354  } else {
355  DEBUG_PRINTF("spu_run returned invalid data: 0x%04x\n", run_rc);
356  stopinfo->stop_reason = SPE_RUNTIME_FATAL;
357  stopinfo->result.spe_runtime_fatal = -1;
358  stopinfo->spu_status = -1;
359  errno = EFAULT;
360  retval = -1;
361 
362  }
363 
364  freespeinfo();
365  return retval;
366 }

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