libspe2  0.9a
create.c
Go to the documentation of this file.
1 /*
2  * libspe2 - A wrapper library to adapt the JSRE SPU usage model to SPUFS
3  * Copyright (C) 2005 IBM Corp.
4  *
5  * This library is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation; either version 2.1 of the License,
8  * or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19 
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <pthread.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include <sys/mman.h>
28 #include <sys/types.h>
29 #include <sys/spu.h>
30 #include <sys/stat.h>
31 #include <unistd.h>
32 
33 #include "create.h"
34 #include "spebase.h"
35 
36 
37 struct fd_attr {
38  const char *name;
39  int mode;
40 };
41 
42 static const struct fd_attr spe_fd_attr[NUM_MBOX_FDS] = {
43  [FD_MBOX] = { .name = "mbox", .mode = O_RDONLY },
44  [FD_MBOX_STAT] = { .name = "mbox_stat", .mode = O_RDONLY },
45  [FD_IBOX] = { .name = "ibox", .mode = O_RDONLY },
46  [FD_IBOX_NB] = { .name = "ibox", .mode = O_RDONLY |O_NONBLOCK },
47  [FD_IBOX_STAT] = { .name = "ibox_stat", .mode = O_RDONLY },
48  [FD_WBOX] = { .name = "wbox", .mode = O_WRONLY },
49  [FD_WBOX_NB] = { .name = "wbox", .mode = O_WRONLY|O_NONBLOCK },
50  [FD_WBOX_STAT] = { .name = "wbox_stat", .mode = O_RDONLY },
51  [FD_SIG1] = { .name = "signal1", .mode = O_WRONLY },
52  [FD_SIG2] = { .name = "signal2", .mode = O_WRONLY },
53  [FD_MFC] = { .name = "mfc", .mode = O_RDWR },
54  [FD_MSS] = { .name = "mss", .mode = O_RDWR },
55 };
56 
57 static void *mapfileat(int dir, const char *filename, int size)
58 {
59  int fd_temp;
60  void *ret;
61 
62  fd_temp = openat(dir, filename, O_RDWR);
63  if (fd_temp < 0) {
64  DEBUG_PRINTF("ERROR: Could not open SPE %s file.\n", filename);
65  errno = EFAULT;
66  return MAP_FAILED;
67  }
68  ret = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_temp, 0);
69  close(fd_temp);
70 
71  return ret;
72 }
73 
74 static int setsignotify(int dir, const char *filename)
75 {
76  int fd_sig, rc = 0;
77  char one = '1';
78 
79  fd_sig = openat(dir, filename, O_RDWR);
80  if (fd_sig < 0)
81  return -1;
82 
83  if (write(fd_sig, &one, sizeof(one)) != sizeof(one))
84  rc = -1;
85 
86  close(fd_sig);
87 
88  return 0;
89 }
90 
92 {
93  pthread_mutex_lock(&spe->base_private->fd_lock[fdesc]);
94 }
95 
97 {
98  pthread_mutex_unlock(&spe->base_private->fd_lock[fdesc]);
99 }
100 
101 int _base_spe_open_if_closed(struct spe_context *spe, enum fd_name fdesc, int locked)
102 {
103  if (!locked)
104  _base_spe_context_lock(spe, fdesc);
105 
106  /* already open? */
107  if (spe->base_private->spe_fds_array[fdesc] != -1) {
108  spe->base_private->spe_fds_refcount[fdesc]++;
109  } else {
110  spe->base_private->spe_fds_array[fdesc] =
111  openat(spe->base_private->fd_spe_dir,
112  spe_fd_attr[fdesc].name,
113  spe_fd_attr[fdesc].mode);
114 
115  if (spe->base_private->spe_fds_array[(int)fdesc] > 0)
116  spe->base_private->spe_fds_refcount[(int)fdesc]++;
117  }
118 
119  if (!locked)
120  _base_spe_context_unlock(spe, fdesc);
121 
122  return spe->base_private->spe_fds_array[(int)fdesc];
123 }
124 
125 void _base_spe_close_if_open(struct spe_context *spe, enum fd_name fdesc)
126 {
127  _base_spe_context_lock(spe, fdesc);
128 
129  if (spe->base_private->spe_fds_array[(int)fdesc] != -1 &&
130  spe->base_private->spe_fds_refcount[(int)fdesc] == 1) {
131 
132  spe->base_private->spe_fds_refcount[(int)fdesc]--;
133  close(spe->base_private->spe_fds_array[(int)fdesc]);
134 
135  spe->base_private->spe_fds_array[(int)fdesc] = -1;
136  } else if (spe->base_private->spe_fds_refcount[(int)fdesc] > 0) {
137  spe->base_private->spe_fds_refcount[(int)fdesc]--;
138  }
139 
140  _base_spe_context_unlock(spe, fdesc);
141 }
142 
143 static int free_spe_context(struct spe_context *spe)
144 {
145  int i;
146 
147  if (spe->base_private->psmap_mmap_base != MAP_FAILED) {
148  munmap(spe->base_private->psmap_mmap_base, PSMAP_SIZE);
149 
150  } else {
151  if (spe->base_private->mfc_mmap_base != MAP_FAILED)
152  munmap(spe->base_private->mfc_mmap_base, MFC_SIZE);
153  if (spe->base_private->mssync_mmap_base != MAP_FAILED)
154  munmap(spe->base_private->mssync_mmap_base, MSS_SIZE);
155  if (spe->base_private->cntl_mmap_base != MAP_FAILED)
156  munmap(spe->base_private->cntl_mmap_base, CNTL_SIZE);
157  if (spe->base_private->signal1_mmap_base != MAP_FAILED)
158  munmap(spe->base_private->signal1_mmap_base,
159  SIGNAL_SIZE);
160  if (spe->base_private->signal2_mmap_base != MAP_FAILED)
161  munmap(spe->base_private->signal2_mmap_base,
162  SIGNAL_SIZE);
163  }
164 
165  if (spe->base_private->mem_mmap_base != MAP_FAILED)
166  munmap(spe->base_private->mem_mmap_base, LS_SIZE);
167 
168  for (i = 0; i < NUM_MBOX_FDS; i++) {
169  if (spe->base_private->spe_fds_array[i] >= 0)
170  close(spe->base_private->spe_fds_array[i]);
171  pthread_mutex_destroy(&spe->base_private->fd_lock[i]);
172  }
173 
174  if (spe->base_private->fd_spe_dir >= 0)
175  close(spe->base_private->fd_spe_dir);
176 
177  free(spe->base_private);
178  free(spe);
179 
180  return 0;
181 }
182 
185 {
186  char pathname[256];
187  int i, aff_spe_fd = 0;
188  unsigned int spu_createflags = 0;
189  struct spe_context *spe = NULL;
190  struct spe_context_base_priv *priv;
191 
192  /* We need a loader present to run in emulated isolated mode */
193  if (flags & SPE_ISOLATE_EMULATE
195  errno = EINVAL;
196  return NULL;
197  }
198 
199  /* Put some sane defaults into the SPE context */
200  spe = malloc(sizeof(*spe));
201  if (!spe) {
202  DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
203  return NULL;
204  }
205  memset(spe, 0, sizeof(*spe));
206 
207  spe->base_private = malloc(sizeof(*spe->base_private));
208  if (!spe->base_private) {
209  DEBUG_PRINTF("ERROR: Could not allocate "
210  "spe->base_private context.\n");
211  free(spe);
212  return NULL;
213  }
214 
215  /* just a convenience variable */
216  priv = spe->base_private;
217 
218  priv->fd_spe_dir = -1;
219  priv->mem_mmap_base = MAP_FAILED;
220  priv->psmap_mmap_base = MAP_FAILED;
221  priv->mssync_mmap_base = MAP_FAILED;
222  priv->mfc_mmap_base = MAP_FAILED;
223  priv->cntl_mmap_base = MAP_FAILED;
224  priv->signal1_mmap_base = MAP_FAILED;
225  priv->signal2_mmap_base = MAP_FAILED;
226  priv->loaded_program = NULL;
227 
228  for (i = 0; i < NUM_MBOX_FDS; i++) {
229  priv->spe_fds_array[i] = -1;
230  pthread_mutex_init(&priv->fd_lock[i], NULL);
231  }
232 
233  /* initialise spu_createflags */
234  if (flags & SPE_ISOLATE) {
235  flags |= SPE_MAP_PS;
236  spu_createflags |= SPU_CREATE_ISOLATE | SPU_CREATE_NOSCHED;
237  }
238 
239  if (flags & SPE_EVENTS_ENABLE)
240  spu_createflags |= SPU_CREATE_EVENTS_ENABLED;
241 
242  if (aff_spe)
243  spu_createflags |= SPU_CREATE_AFFINITY_SPU;
244 
245  if (flags & SPE_AFFINITY_MEMORY)
246  spu_createflags |= SPU_CREATE_AFFINITY_MEM;
247 
248  /* Make the SPUFS directory for the SPE */
249  if (gctx == NULL)
250  sprintf(pathname, "/spu/spethread-%i-%lu",
251  getpid(), (unsigned long)spe);
252  else
253  sprintf(pathname, "/spu/%s/spethread-%i-%lu",
254  gctx->base_private->gangname, getpid(),
255  (unsigned long)spe);
256 
257  if (aff_spe)
258  aff_spe_fd = aff_spe->base_private->fd_spe_dir;
259 
260  priv->fd_spe_dir = spu_create(pathname, spu_createflags,
261  S_IRUSR | S_IWUSR | S_IXUSR, aff_spe_fd);
262 
263  if (priv->fd_spe_dir < 0) {
264  int errno_saved = errno; /* save errno to prevent being overwritten */
265  DEBUG_PRINTF("ERROR: Could not create SPE %s\n", pathname);
266  perror("spu_create()");
267  free_spe_context(spe);
268  /* we mask most errors, but leave ENODEV, etc */
269  switch (errno_saved) {
270  case ENOTSUP:
271  case EEXIST:
272  case EINVAL:
273  case EBUSY:
274  case EPERM:
275  case ENODEV:
276  errno = errno_saved; /* restore errno */
277  break;
278  default:
279  errno = EFAULT;
280  break;
281  }
282  return NULL;
283  }
284 
285  priv->flags = flags;
286 
287  /* Map the required areas into process memory */
288  priv->mem_mmap_base = mapfileat(priv->fd_spe_dir, "mem", LS_SIZE);
289  if (priv->mem_mmap_base == MAP_FAILED) {
290  DEBUG_PRINTF("ERROR: Could not map SPE memory.\n");
291  free_spe_context(spe);
292  errno = ENOMEM;
293  return NULL;
294  }
295 
296  if (flags & SPE_MAP_PS) {
297  /* It's possible to map the entire problem state area with
298  * one mmap - try this first */
299  priv->psmap_mmap_base = mapfileat(priv->fd_spe_dir,
300  "psmap", PSMAP_SIZE);
301 
302  if (priv->psmap_mmap_base != MAP_FAILED) {
303  priv->mssync_mmap_base =
305  priv->mfc_mmap_base =
306  priv->psmap_mmap_base + MFC_OFFSET;
307  priv->cntl_mmap_base =
309  priv->signal1_mmap_base =
311  priv->signal2_mmap_base =
313 
314  } else {
315  /* map each region separately */
316  priv->mfc_mmap_base =
317  mapfileat(priv->fd_spe_dir, "mfc", MFC_SIZE);
318  priv->mssync_mmap_base =
319  mapfileat(priv->fd_spe_dir, "mss", MSS_SIZE);
320  priv->cntl_mmap_base =
321  mapfileat(priv->fd_spe_dir, "cntl", CNTL_SIZE);
322  priv->signal1_mmap_base =
323  mapfileat(priv->fd_spe_dir, "signal1",
324  SIGNAL_SIZE);
325  priv->signal2_mmap_base =
326  mapfileat(priv->fd_spe_dir, "signal2",
327  SIGNAL_SIZE);
328 
329  if (priv->mfc_mmap_base == MAP_FAILED ||
330  priv->cntl_mmap_base == MAP_FAILED ||
331  priv->signal1_mmap_base == MAP_FAILED ||
332  priv->signal2_mmap_base == MAP_FAILED) {
333  DEBUG_PRINTF("ERROR: Could not map SPE "
334  "PS memory.\n");
335  free_spe_context(spe);
336  errno = ENOMEM;
337  return NULL;
338  }
339  }
340  }
341 
342  if (flags & SPE_CFG_SIGNOTIFY1_OR) {
343  if (setsignotify(priv->fd_spe_dir, "signal1_type")) {
344  DEBUG_PRINTF("ERROR: Could not open SPE "
345  "signal1_type file.\n");
346  free_spe_context(spe);
347  errno = EFAULT;
348  return NULL;
349  }
350  }
351 
352  if (flags & SPE_CFG_SIGNOTIFY2_OR) {
353  if (setsignotify(priv->fd_spe_dir, "signal2_type")) {
354  DEBUG_PRINTF("ERROR: Could not open SPE "
355  "signal2_type file.\n");
356  free_spe_context(spe);
357  errno = EFAULT;
358  return NULL;
359  }
360  }
361 
362  return spe;
363 }
364 
365 static int free_spe_gang_context(struct spe_gang_context *gctx)
366 {
367  if (gctx->base_private->fd_gang_dir >= 0)
368  close(gctx->base_private->fd_gang_dir);
369 
370  free(gctx->base_private);
371  free(gctx);
372 
373  return 0;
374 }
375 
377 {
378  char pathname[256];
379  struct spe_gang_context_base_priv *pgctx = NULL;
380  struct spe_gang_context *gctx = NULL;
381 
382  gctx = malloc(sizeof(*gctx));
383  if (!gctx) {
384  DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
385  return NULL;
386  }
387  memset(gctx, 0, sizeof(*gctx));
388 
389  pgctx = malloc(sizeof(*pgctx));
390  if (!pgctx) {
391  DEBUG_PRINTF("ERROR: Could not allocate spe context.\n");
392  free(gctx);
393  return NULL;
394  }
395  memset(pgctx, 0, sizeof(*pgctx));
396 
397  gctx->base_private = pgctx;
398 
399  sprintf(gctx->base_private->gangname, "gang-%i-%lu", getpid(),
400  (unsigned long)gctx);
401  sprintf(pathname, "/spu/%s", gctx->base_private->gangname);
402 
403  gctx->base_private->fd_gang_dir = spu_create(pathname, SPU_CREATE_GANG,
404  S_IRUSR | S_IWUSR | S_IXUSR);
405 
406  if (gctx->base_private->fd_gang_dir < 0) {
407  DEBUG_PRINTF("ERROR: Could not create Gang %s\n", pathname);
408  free_spe_gang_context(gctx);
409  errno = EFAULT;
410  return NULL;
411  }
412 
413  gctx->base_private->flags = flags;
414 
415  return gctx;
416 }
417 
419 {
420  int ret = free_spe_context(spe);
421 
423 
424  return ret;
425 }
426 
428 {
429  return free_spe_gang_context(gctx);
430 }
431 
void _base_spe_close_if_open(struct spe_context *spe, enum fd_name fdesc)
Definition: create.c:125
#define SIGNAL1_OFFSET
Definition: spebase.h:125
void * signal2_mmap_base
Definition: spebase.h:90
#define MFC_SIZE
Definition: spebase.h:117
spe_gang_context_ptr_t _base_spe_gang_context_create(unsigned int flags)
Definition: create.c:376
#define SPE_CFG_SIGNOTIFY1_OR
#define CNTL_OFFSET
Definition: spebase.h:124
#define DEBUG_PRINTF(fmt, args...)
Definition: elf_loader.c:45
int _base_spe_gang_context_destroy(spe_gang_context_ptr_t gctx)
Definition: create.c:427
int _base_spe_emulated_loader_present(void)
Definition: load.c:159
void * psmap_mmap_base
Definition: spebase.h:84
spe_program_handle_t * loaded_program
Definition: spebase.h:99
void * mssync_mmap_base
Definition: spebase.h:87
#define PSMAP_SIZE
Definition: spebase.h:116
#define CNTL_SIZE
Definition: spebase.h:119
#define SPE_EVENTS_ENABLE
const char * name
Definition: create.c:38
int _base_spe_open_if_closed(struct spe_context *spe, enum fd_name fdesc, int locked)
Definition: create.c:101
void * cntl_mmap_base
Definition: spebase.h:88
void * mfc_mmap_base
Definition: spebase.h:86
void * signal1_mmap_base
Definition: spebase.h:89
void _base_spe_context_unlock(spe_context_ptr_t spe, enum fd_name fdesc)
Definition: create.c:96
#define SPE_CFG_SIGNOTIFY2_OR
#define SPE_MAP_PS
int spe_fds_array[NUM_MBOX_FDS]
Definition: spebase.h:77
Definition: spebase.h:53
#define MFC_OFFSET
Definition: spebase.h:123
int spe_fds_refcount[NUM_MBOX_FDS]
Definition: spebase.h:78
#define SIGNAL2_OFFSET
Definition: spebase.h:126
int mode
Definition: create.c:39
#define MSSYNC_OFFSET
Definition: spebase.h:122
Definition: spebase.h:54
void __spe_context_update_event(void)
struct spe_context_base_priv * base_private
Definition: libspe2-types.h:76
#define SPE_AFFINITY_MEMORY
#define MSS_SIZE
Definition: spebase.h:118
fd_name
Definition: spebase.h:42
#define SPE_ISOLATE_EMULATE
unsigned int flags
Definition: spebase.h:74
Definition: create.c:37
#define LS_SIZE
Definition: elf_loader.h:23
spe_context_ptr_t _base_spe_context_create(unsigned int flags, spe_gang_context_ptr_t gctx, spe_context_ptr_t aff_spe)
Definition: create.c:183
int _base_spe_context_destroy(spe_context_ptr_t spe)
Definition: create.c:418
#define SPE_ISOLATE
void * mem_mmap_base
Definition: spebase.h:85
void _base_spe_context_lock(spe_context_ptr_t spe, enum fd_name fdesc)
Definition: create.c:91
struct spe_gang_context_base_priv * base_private
Definition: libspe2-types.h:99
#define SIGNAL_SIZE
Definition: spebase.h:120
pthread_mutex_t fd_lock[NUM_MBOX_FDS]
Definition: spebase.h:65