00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <errno.h>
00020 #define GNU_SOURCE 1
00021
00022 #include <fcntl.h>
00023 #include <stdio.h>
00024 #include <stdint.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <syscall.h>
00028 #include <unistd.h>
00029
00030 #include <sys/types.h>
00031 #include <sys/mman.h>
00032
00033 #include <sys/spu.h>
00034
00035 #include "elf_loader.h"
00036 #include "lib_builtin.h"
00037 #include "spebase.h"
00038
00039
00040 __thread struct spe_context_info {
00041 int spe_id;
00042 unsigned int npc;
00043 unsigned int status;
00044 struct spe_context_info *prev;
00045 }*__spe_current_active_context;
00046
00047
00048 static void cleanupspeinfo(struct spe_context_info *ctxinfo)
00049 {
00050 struct spe_context_info *tmp = ctxinfo->prev;
00051 __spe_current_active_context = tmp;
00052 }
00053
00054 static int set_regs(struct spe_context *spe, void *regs)
00055 {
00056 int fd_regs, rc;
00057
00058 fd_regs = openat(spe->base_private->fd_spe_dir, "regs", O_RDWR);
00059 if (fd_regs < 0) {
00060 DEBUG_PRINTF("Could not open SPE regs file.\n");
00061 errno = EFAULT;
00062 return -1;
00063 }
00064
00065 rc = write(fd_regs, regs, 2048);
00066
00067 close(fd_regs);
00068
00069 if (rc < 0)
00070 return -1;
00071
00072 return 0;
00073 }
00074
00075 static int issue_isolated_exit(struct spe_context *spe)
00076 {
00077 struct spe_spu_control_area *cntl_area =
00078 spe->base_private->cntl_mmap_base;
00079
00080 if (cntl_area == MAP_FAILED) {
00081 DEBUG_PRINTF("%s: could not access SPE control area\n",
00082 __FUNCTION__);
00083 return -1;
00084 }
00085
00086
00087 cntl_area->SPU_RunCntl = 0x2;
00088
00089 return 0;
00090 }
00091
00092 static inline void freespeinfo()
00093 {
00094
00095 struct spe_context_info *tmp = __spe_current_active_context->prev;
00096 __spe_current_active_context = tmp;
00097 }
00098
00099 int _base_spe_context_run(spe_context_ptr_t spe, unsigned int *entry,
00100 unsigned int runflags, void *argp, void *envp,
00101 spe_stop_info_t *stopinfo)
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
00109
00110 if (!stopinfo)
00111 stopinfo = &stopinfo_buf;
00112
00113
00114
00115
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
00125
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
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
00139 memset(regs, 0, sizeof(regs));
00140
00141
00142 regs[1][0] = (unsigned int) LS_SIZE - 16;
00143 regs[2][0] = 0;
00144
00145 if (runflags & SPE_RUN_USER_REGS) {
00146
00147
00148
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
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
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
00186 __spe_current_active_context->spe_id = spe->base_private->fd_spe_dir;
00187
00188 do_run:
00189
00190 __spe_current_active_context->npc = tmp_entry;
00191
00192
00193 run_rc = spu_run(spe->base_private->fd_spe_dir,
00194 &tmp_entry, &run_status);
00195
00196
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
00204
00205
00206 stopinfo->spu_status = run_rc;
00207
00208 if (spe->base_private->flags & SPE_ISOLATE_EMULATE) {
00209
00210 spe->base_private->emulated_entry = tmp_entry;
00211 *entry = 0;
00212 } else {
00213 *entry = tmp_entry;
00214 }
00215
00216
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
00225
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
00241
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
00251
00252
00253
00254
00255
00256
00257 int stopcode = (run_rc >> 16) & 0x3fff;
00258
00259
00260
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
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
00274
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
00284
00285 tmp_entry += 4;
00286 goto do_run;
00287 }
00288
00289 } else if ((stopcode & 0xff00) == SPE_PROGRAM_NORMAL_END) {
00290
00291 stopinfo->stop_reason = SPE_EXIT;
00292 stopinfo->result.spe_exit_code = stopcode & 0xff;
00293
00294 if (spe->base_private->flags & SPE_ISOLATE) {
00295
00296
00297
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
00306
00307
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
00321 retval = 0;
00322
00323 } else {
00324
00325
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 }