00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <pthread.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026
00027 #include <sys/mman.h>
00028 #include <sys/types.h>
00029 #include <sys/spu.h>
00030 #include <sys/stat.h>
00031 #include <unistd.h>
00032
00033 #include "create.h"
00034 #include "spebase.h"
00035
00036
00037 struct fd_attr {
00038 const char *name;
00039 int mode;
00040 };
00041
00042 static const struct fd_attr spe_fd_attr[NUM_MBOX_FDS] = {
00043 [FD_MBOX] = { .name = "mbox", .mode = O_RDONLY },
00044 [FD_MBOX_STAT] = { .name = "mbox_stat", .mode = O_RDONLY },
00045 [FD_IBOX] = { .name = "ibox", .mode = O_RDONLY },
00046 [FD_IBOX_NB] = { .name = "ibox", .mode = O_RDONLY |O_NONBLOCK },
00047 [FD_IBOX_STAT] = { .name = "ibox_stat", .mode = O_RDONLY },
00048 [FD_WBOX] = { .name = "wbox", .mode = O_WRONLY },
00049 [FD_WBOX_NB] = { .name = "wbox", .mode = O_WRONLY|O_NONBLOCK },
00050 [FD_WBOX_STAT] = { .name = "wbox_stat", .mode = O_RDONLY },
00051 [FD_SIG1] = { .name = "signal1", .mode = O_WRONLY },
00052 [FD_SIG2] = { .name = "signal2", .mode = O_WRONLY },
00053 [FD_MFC] = { .name = "mfc", .mode = O_RDWR },
00054 [FD_MSS] = { .name = "mss", .mode = O_RDWR },
00055 };
00056
00057 static void *mapfileat(int dir, const char *filename, int size)
00058 {
00059 int fd_temp;
00060 void *ret;
00061
00062 fd_temp = openat(dir, filename, O_RDWR);
00063 if (fd_temp < 0) {
00064 DEBUG_PRINTF("ERROR: Could not open SPE %s file.\n", filename);
00065 errno = EFAULT;
00066 return MAP_FAILED;
00067 }
00068 ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_temp, 0);
00069 close(fd_temp);
00070
00071 return ret;
00072 }
00073
00074 static int setsignotify(int dir, const char *filename)
00075 {
00076 int fd_sig, rc = 0;
00077 char one = '1';
00078
00079 fd_sig = openat(dir, filename, O_RDWR);
00080 if (fd_sig < 0)
00081 return -1;
00082
00083 if (write(fd_sig, &one, sizeof(one)) != sizeof(one))
00084 rc = -1;
00085
00086 close(fd_sig);
00087
00088 return 0;
00089 }
00090
00091 void _base_spe_context_lock(spe_context_ptr_t spe, enum fd_name fdesc)
00092 {
00093 pthread_mutex_lock(&spe->base_private->fd_lock[fdesc]);
00094 }
00095
00096 void _base_spe_context_unlock(spe_context_ptr_t spe, enum fd_name fdesc)
00097 {
00098 pthread_mutex_unlock(&spe->base_private->fd_lock[fdesc]);
00099 }
00100
00101 int _base_spe_open_if_closed(struct spe_context *spe, enum fd_name fdesc, int locked)
00102 {
00103 if (!locked)
00104 _base_spe_context_lock(spe, fdesc);
00105
00106
00107 if (spe->base_private->spe_fds_array[fdesc] != -1) {
00108 spe->base_private->spe_fds_refcount[fdesc]++;
00109 } else {
00110 spe->base_private->spe_fds_array[fdesc] =
00111 openat(spe->base_private->fd_spe_dir,
00112 spe_fd_attr[fdesc].name,
00113 spe_fd_attr[fdesc].mode);
00114
00115 if (spe->base_private->spe_fds_array[(int)fdesc] > 0)
00116 spe->base_private->spe_fds_refcount[(int)fdesc]++;
00117 }
00118
00119 if (!locked)
00120 _base_spe_context_unlock(spe, fdesc);
00121
00122 return spe->base_private->spe_fds_array[(int)fdesc];
00123 }
00124
00125 void _base_spe_close_if_open(struct spe_context *spe, enum fd_name fdesc)
00126 {
00127 _base_spe_context_lock(spe, fdesc);
00128
00129 if (spe->base_private->spe_fds_array[(int)fdesc] != -1 &&
00130 spe->base_private->spe_fds_refcount[(int)fdesc] == 1) {
00131
00132 spe->base_private->spe_fds_refcount[(int)fdesc]--;
00133 close(spe->base_private->spe_fds_array[(int)fdesc]);
00134
00135 spe->base_private->spe_fds_array[(int)fdesc] = -1;
00136 } else if (spe->base_private->spe_fds_refcount[(int)fdesc] > 0) {
00137 spe->base_private->spe_fds_refcount[(int)fdesc]--;
00138 }
00139
00140 _base_spe_context_unlock(spe, fdesc);
00141 }
00142
00143 static int free_spe_context(struct spe_context *spe)
00144 {
00145 int i;
00146
00147 if (spe->base_private->psmap_mmap_base != MAP_FAILED) {
00148 munmap(spe->base_private->psmap_mmap_base, PSMAP_SIZE);
00149
00150 } else {
00151 if (spe->base_private->mfc_mmap_base != MAP_FAILED)
00152 munmap(spe->base_private->mfc_mmap_base, MFC_SIZE);
00153 if (spe->base_private->mssync_mmap_base != MAP_FAILED)
00154 munmap(spe->base_private->mssync_mmap_base, MSS_SIZE);
00155 if (spe->base_private->cntl_mmap_base != MAP_FAILED)
00156 munmap(spe->base_private->cntl_mmap_base, CNTL_SIZE);
00157 if (spe->base_private->signal1_mmap_base != MAP_FAILED)
00158 munmap(spe->base_private->signal1_mmap_base,
00159 SIGNAL_SIZE);
00160 if (spe->base_private->signal2_mmap_base != MAP_FAILED)
00161 munmap(spe->base_private->signal2_mmap_base,
00162 SIGNAL_SIZE);
00163 }
00164
00165 if (spe->base_private->mem_mmap_base != MAP_FAILED)
00166 munmap(spe->base_private->mem_mmap_base, LS_SIZE);
00167
00168 for (i = 0; i < NUM_MBOX_FDS; i++) {
00169 if (spe->base_private->spe_fds_array[i] >= 0)
00170 close(spe->base_private->spe_fds_array[i]);
00171 pthread_mutex_destroy(&spe->base_private->fd_lock[i]);
00172 }
00173
00174 if (spe->base_private->fd_spe_dir >= 0)
00175 close(spe->base_private->fd_spe_dir);
00176
00177 free(spe->base_private);
00178 free(spe);
00179
00180 return 0;
00181 }
00182
00183 spe_context_ptr_t _base_spe_context_create(unsigned int flags,
00184 spe_gang_context_ptr_t gctx, spe_context_ptr_t aff_spe)
00185 {
00186 char pathname[256];
00187 int i, aff_spe_fd = 0;
00188 unsigned int spu_createflags = 0;
00189 struct spe_context *spe = NULL;
00190 struct spe_context_base_priv *priv;
00191
00192
00193 if (flags & SPE_ISOLATE_EMULATE
00194 && !_base_spe_emulated_loader_present()) {
00195 errno = EINVAL;
00196 return NULL;
00197 }
00198
00199
00200 spe = malloc(sizeof(*spe));
00201 if (!spe) {
00202 DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
00203 return NULL;
00204 }
00205 memset(spe, 0, sizeof(*spe));
00206
00207 spe->base_private = malloc(sizeof(*spe->base_private));
00208 if (!spe->base_private) {
00209 DEBUG_PRINTF("ERROR: Could not allocate "
00210 "spe->base_private context.\n");
00211 free(spe);
00212 return NULL;
00213 }
00214
00215
00216 priv = spe->base_private;
00217
00218 priv->fd_spe_dir = -1;
00219 priv->mem_mmap_base = MAP_FAILED;
00220 priv->psmap_mmap_base = MAP_FAILED;
00221 priv->mssync_mmap_base = MAP_FAILED;
00222 priv->mfc_mmap_base = MAP_FAILED;
00223 priv->cntl_mmap_base = MAP_FAILED;
00224 priv->signal1_mmap_base = MAP_FAILED;
00225 priv->signal2_mmap_base = MAP_FAILED;
00226 priv->loaded_program = NULL;
00227
00228 for (i = 0; i < NUM_MBOX_FDS; i++) {
00229 priv->spe_fds_array[i] = -1;
00230 pthread_mutex_init(&priv->fd_lock[i], NULL);
00231 }
00232
00233
00234 if (flags & SPE_ISOLATE) {
00235 flags |= SPE_MAP_PS;
00236 spu_createflags |= SPU_CREATE_ISOLATE | SPU_CREATE_NOSCHED;
00237 }
00238
00239 if (flags & SPE_EVENTS_ENABLE)
00240 spu_createflags |= SPU_CREATE_EVENTS_ENABLED;
00241
00242 if (aff_spe)
00243 spu_createflags |= SPU_CREATE_AFFINITY_SPU;
00244
00245 if (flags & SPE_AFFINITY_MEMORY)
00246 spu_createflags |= SPU_CREATE_AFFINITY_MEM;
00247
00248
00249 if (gctx == NULL)
00250 sprintf(pathname, "/spu/spethread-%i-%lu",
00251 getpid(), (unsigned long)spe);
00252 else
00253 sprintf(pathname, "/spu/%s/spethread-%i-%lu",
00254 gctx->base_private->gangname, getpid(),
00255 (unsigned long)spe);
00256
00257 if (aff_spe)
00258 aff_spe_fd = aff_spe->base_private->fd_spe_dir;
00259
00260 priv->fd_spe_dir = spu_create(pathname, spu_createflags,
00261 S_IRUSR | S_IWUSR | S_IXUSR, aff_spe_fd);
00262
00263 if (priv->fd_spe_dir < 0) {
00264 int errno_saved = errno;
00265 DEBUG_PRINTF("ERROR: Could not create SPE %s\n", pathname);
00266 perror("spu_create()");
00267 free_spe_context(spe);
00268
00269 switch (errno_saved) {
00270 case ENOTSUP:
00271 case EEXIST:
00272 case EINVAL:
00273 case EBUSY:
00274 case EPERM:
00275 case ENODEV:
00276 errno = errno_saved;
00277 break;
00278 default:
00279 errno = EFAULT;
00280 break;
00281 }
00282 return NULL;
00283 }
00284
00285 priv->flags = flags;
00286
00287
00288 priv->mem_mmap_base = mapfileat(priv->fd_spe_dir, "mem", LS_SIZE);
00289 if (priv->mem_mmap_base == MAP_FAILED) {
00290 DEBUG_PRINTF("ERROR: Could not map SPE memory.\n");
00291 free_spe_context(spe);
00292 errno = ENOMEM;
00293 return NULL;
00294 }
00295
00296 if (flags & SPE_MAP_PS) {
00297
00298
00299 priv->psmap_mmap_base = mapfileat(priv->fd_spe_dir,
00300 "psmap", PSMAP_SIZE);
00301
00302 if (priv->psmap_mmap_base != MAP_FAILED) {
00303 priv->mssync_mmap_base =
00304 priv->psmap_mmap_base + MSSYNC_OFFSET;
00305 priv->mfc_mmap_base =
00306 priv->psmap_mmap_base + MFC_OFFSET;
00307 priv->cntl_mmap_base =
00308 priv->psmap_mmap_base + CNTL_OFFSET;
00309 priv->signal1_mmap_base =
00310 priv->psmap_mmap_base + SIGNAL1_OFFSET;
00311 priv->signal2_mmap_base =
00312 priv->psmap_mmap_base + SIGNAL2_OFFSET;
00313
00314 } else {
00315
00316 priv->mfc_mmap_base =
00317 mapfileat(priv->fd_spe_dir, "mfc", MFC_SIZE);
00318 priv->mssync_mmap_base =
00319 mapfileat(priv->fd_spe_dir, "mss", MSS_SIZE);
00320 priv->cntl_mmap_base =
00321 mapfileat(priv->fd_spe_dir, "cntl", CNTL_SIZE);
00322 priv->signal1_mmap_base =
00323 mapfileat(priv->fd_spe_dir, "signal1",
00324 SIGNAL_SIZE);
00325 priv->signal2_mmap_base =
00326 mapfileat(priv->fd_spe_dir, "signal2",
00327 SIGNAL_SIZE);
00328
00329 if (priv->mfc_mmap_base == MAP_FAILED ||
00330 priv->cntl_mmap_base == MAP_FAILED ||
00331 priv->signal1_mmap_base == MAP_FAILED ||
00332 priv->signal2_mmap_base == MAP_FAILED) {
00333 DEBUG_PRINTF("ERROR: Could not map SPE "
00334 "PS memory.\n");
00335 free_spe_context(spe);
00336 errno = ENOMEM;
00337 return NULL;
00338 }
00339 }
00340 }
00341
00342 if (flags & SPE_CFG_SIGNOTIFY1_OR) {
00343 if (setsignotify(priv->fd_spe_dir, "signal1_type")) {
00344 DEBUG_PRINTF("ERROR: Could not open SPE "
00345 "signal1_type file.\n");
00346 free_spe_context(spe);
00347 errno = EFAULT;
00348 return NULL;
00349 }
00350 }
00351
00352 if (flags & SPE_CFG_SIGNOTIFY2_OR) {
00353 if (setsignotify(priv->fd_spe_dir, "signal2_type")) {
00354 DEBUG_PRINTF("ERROR: Could not open SPE "
00355 "signal2_type file.\n");
00356 free_spe_context(spe);
00357 errno = EFAULT;
00358 return NULL;
00359 }
00360 }
00361
00362 return spe;
00363 }
00364
00365 static int free_spe_gang_context(struct spe_gang_context *gctx)
00366 {
00367 if (gctx->base_private->fd_gang_dir >= 0)
00368 close(gctx->base_private->fd_gang_dir);
00369
00370 free(gctx->base_private);
00371 free(gctx);
00372
00373 return 0;
00374 }
00375
00376 spe_gang_context_ptr_t _base_spe_gang_context_create(unsigned int flags)
00377 {
00378 char pathname[256];
00379 struct spe_gang_context_base_priv *pgctx = NULL;
00380 struct spe_gang_context *gctx = NULL;
00381
00382 gctx = malloc(sizeof(*gctx));
00383 if (!gctx) {
00384 DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
00385 return NULL;
00386 }
00387 memset(gctx, 0, sizeof(*gctx));
00388
00389 pgctx = malloc(sizeof(*pgctx));
00390 if (!pgctx) {
00391 DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
00392 free(gctx);
00393 return NULL;
00394 }
00395 memset(pgctx, 0, sizeof(*pgctx));
00396
00397 gctx->base_private = pgctx;
00398
00399 sprintf(gctx->base_private->gangname, "gang-%i-%lu", getpid(),
00400 (unsigned long)gctx);
00401 sprintf(pathname, "/spu/%s", gctx->base_private->gangname);
00402
00403 gctx->base_private->fd_gang_dir = spu_create(pathname, SPU_CREATE_GANG,
00404 S_IRUSR | S_IWUSR | S_IXUSR);
00405
00406 if (gctx->base_private->fd_gang_dir < 0) {
00407 DEBUG_PRINTF("ERROR: Could not create Gang %s\n", pathname);
00408 free_spe_gang_context(gctx);
00409 errno = EFAULT;
00410 return NULL;
00411 }
00412
00413 gctx->base_private->flags = flags;
00414
00415 return gctx;
00416 }
00417
00418 int _base_spe_context_destroy(spe_context_ptr_t spe)
00419 {
00420 int ret = free_spe_context(spe);
00421
00422 __spe_context_update_event();
00423
00424 return ret;
00425 }
00426
00427 int _base_spe_gang_context_destroy(spe_gang_context_ptr_t gctx)
00428 {
00429 return free_spe_gang_context(gctx);
00430 }
00431