libspe2 0.9a
|
00001 /* 00002 * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS 00003 * Copyright (C) 2005 IBM Corp. 00004 * 00005 * This library is free software; you can redistribute it and/or modify it 00006 * under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation; either version 2.1 of the License, 00008 * or (at your option) any later version. 00009 * 00010 * This library is distributed in the hope that it will be useful, but 00011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 00012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 00013 * License for more details. 00014 * 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this library; if not, write to the Free Software Foundation, 00017 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 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 /* already open? */ 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 /* We need a loader present to run in emulated isolated mode */ 00193 if (flags & SPE_ISOLATE_EMULATE 00194 && !_base_spe_emulated_loader_present()) { 00195 errno = EINVAL; 00196 return NULL; 00197 } 00198 00199 /* Put some sane defaults into the SPE context */ 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 /* just a convenience variable */ 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 /* initialise spu_createflags */ 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 /* Make the SPUFS directory for the SPE */ 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; /* save errno to prevent being overwritten */ 00265 DEBUG_PRINTF("ERROR: Could not create SPE %s\n", pathname); 00266 perror("spu_create()"); 00267 free_spe_context(spe); 00268 /* we mask most errors, but leave ENODEV, etc */ 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; /* restore errno */ 00277 break; 00278 default: 00279 errno = EFAULT; 00280 break; 00281 } 00282 return NULL; 00283 } 00284 00285 priv->flags = flags; 00286 00287 /* Map the required areas into process memory */ 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 /* It's possible to map the entire problem state area with 00298 * one mmap - try this first */ 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 /* map each region separately */ 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