1 /*
2     Copyright (c) 2014-2016 Intel Corporation.  All Rights Reserved.
3 
4     Redistribution and use in source and binary forms, with or without
5     modification, are permitted provided that the following conditions
6     are met:
7 
8       * Redistributions of source code must retain the above copyright
9         notice, this list of conditions and the following disclaimer.
10       * Redistributions in binary form must reproduce the above copyright
11         notice, this list of conditions and the following disclaimer in the
12         documentation and/or other materials provided with the distribution.
13       * Neither the name of Intel Corporation nor the names of its
14         contributors may be used to endorse or promote products derived
15         from this software without specific prior written permission.
16 
17     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20     A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21     HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23     LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27     OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include "coi_device.h"
31 
32 #include "coi_version_asm.h"
33 
34 #define CYCLE_FREQUENCY     1000000000
35 
36 
37 static uint32_t engine_index;
38 static char *engine_dir;
39 
40 
41 extern "C"
42 {
43 
44 COIRESULT
45 SYMBOL_VERSION (COIBufferAddRef, 1) (void *ptr)
46 {
47   COITRACE ("COIBufferAddRef");
48 
49   /* Looks like we have nothing to do here.  */
50 
51   return COI_SUCCESS;
52 }
53 
54 
55 COIRESULT
56 SYMBOL_VERSION (COIBufferReleaseRef, 1) (void *ptr)
57 {
58   COITRACE ("COIBufferReleaseRef");
59 
60   /* Looks like we have nothing to do here.  */
61 
62   return COI_SUCCESS;
63 }
64 
65 
66 COIRESULT
67 SYMBOL_VERSION (COIEngineGetIndex, 1) (COI_ISA_TYPE *type,
68 				       uint32_t *index)
69 {
70   COITRACE ("COIEngineGetIndex");
71 
72   /* type is not used in liboffloadmic.  */
73   *index = engine_index;
74 
75   return COI_SUCCESS;
76 }
77 
78 
79 COIRESULT
80 SYMBOL_VERSION (COIPipelineStartExecutingRunFunctions, 1) ()
81 {
82   COITRACE ("COIPipelineStartExecutingRunFunctions");
83 
84   /* Looks like we have nothing to do here.  */
85 
86   return COI_SUCCESS;
87 }
88 
89 
90 /* The start routine for the COI pipeline thread.  */
91 
92 static void *
pipeline_thread_routine(void * in_pipeline_num)93 pipeline_thread_routine (void *in_pipeline_num)
94 {
95   uint32_t pipeline_num = *(uint32_t *) in_pipeline_num;
96   free (in_pipeline_num);
97 
98   /* Open pipes.  */
99   char *pipe_host2tgt_path, *pipe_tgt2host_path;
100   MALLOCN (char *, pipe_host2tgt_path,
101 	  strlen (engine_dir) + sizeof (PIPE_HOST2TGT_NAME "0000000000"));
102   MALLOCN (char *, pipe_tgt2host_path,
103 	  strlen (engine_dir) + sizeof (PIPE_TGT2HOST_NAME "0000000000"));
104   sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "%010d", engine_dir,
105 	   pipeline_num);
106   sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "%010d", engine_dir,
107 	   pipeline_num);
108   int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_RDONLY);
109   if (pipe_host2tgt < 0)
110     COIERRORN ("Cannot open host-to-target pipe.");
111   int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_WRONLY);
112   if (pipe_tgt2host < 0)
113     COIERRORN ("Cannot open target-to-host pipe.");
114 
115   free (pipe_host2tgt_path);
116   free (pipe_tgt2host_path);
117 
118   while (1)
119     {
120       /* Read and execute command.  */
121       cmd_t cmd = CMD_PIPELINE_DESTROY;
122       int cmd_len = read (pipe_host2tgt, &cmd, sizeof (cmd_t));
123       if (cmd_len != sizeof (cmd_t) && cmd_len != 0)
124 	COIERRORN ("Cannot read from pipe.");
125 
126       if (cmd == CMD_PIPELINE_DESTROY)
127 	break;
128       else if (cmd == CMD_PIPELINE_RUN_FUNCTION)
129 	{
130 	  /* Receive data from host.  */
131 	  void (*func) (uint32_t, void **, uint64_t *, void *, uint16_t, void *,
132 			uint16_t);
133 	  uint32_t buffer_count;
134 	  READN (pipe_host2tgt, &func, sizeof (void *));
135 	  READN (pipe_host2tgt, &buffer_count, sizeof (uint32_t));
136 	  void **buffers;
137 	  uint64_t *buffers_len;
138 	  MALLOCN (void **, buffers, buffer_count * sizeof (void *));
139 	  MALLOCN (uint64_t *, buffers_len, buffer_count * sizeof (uint64_t));
140 	  for (uint32_t i = 0; i < buffer_count; i++)
141 	    {
142 	      READN (pipe_host2tgt, &buffers_len[i], sizeof (uint64_t));
143 	      READN (pipe_host2tgt, &buffers[i], sizeof (void *));
144 	    }
145 	  uint16_t misc_data_len;
146 	  READN (pipe_host2tgt, &misc_data_len, sizeof (uint16_t));
147 	  void *misc_data = NULL;
148 	  if (misc_data_len > 0)
149 	    {
150 	      MALLOCN (void *, misc_data, misc_data_len);
151 	      READN (pipe_host2tgt, misc_data, misc_data_len);
152 	    }
153 	  uint16_t return_data_len;
154 	  READN (pipe_host2tgt, &return_data_len, sizeof (uint16_t));
155 	  void *return_data;
156 	  if (return_data_len > 0)
157 	    MALLOCN (void *, return_data, return_data_len);
158 
159 	  /* Run function.  */
160 	  func (buffer_count, buffers, buffers_len, misc_data,
161 		misc_data_len, return_data, return_data_len);
162 
163 	  /* Send data to host if any or just send notification.  */
164 	  WRITEN (pipe_tgt2host, return_data_len > 0 ? return_data : &cmd,
165 		  return_data_len > 0 ? return_data_len : sizeof (cmd_t));
166 
167 	  /* Clean up.  */
168 	  free (buffers);
169 	  free (buffers_len);
170 	  if (misc_data_len > 0)
171 	    free (misc_data);
172 	  if (return_data_len > 0)
173 	    free (return_data);
174 	}
175       else
176 	COIERRORN ("Unrecognizable command from host.");
177     }
178 
179   /* Close pipes.  */
180   if (close (pipe_host2tgt) < 0)
181     COIERRORN ("Cannot close host-to-target pipe.");
182   if (close (pipe_tgt2host) < 0)
183     COIERRORN ("Cannot close target-to-host pipe.");
184 
185   return NULL;
186 }
187 
188 
189 COIRESULT
190 SYMBOL_VERSION (COIProcessWaitForShutdown, 1) ()
191 {
192   COITRACE ("COIProcessWaitForShutdown");
193 
194   engine_dir = getenv (MIC_DIR_ENV);
195   char *mic_index = getenv (MIC_INDEX_ENV);
196   assert (engine_dir != NULL && mic_index != NULL);
197 
198   /* Get engine index.  */
199   engine_index = atoi (mic_index);
200 
201   /* Open main pipes.  */
202   char *pipe_host2tgt_path, *pipe_tgt2host_path;
203   MALLOC (char *, pipe_host2tgt_path,
204 	  strlen (engine_dir) + sizeof (PIPE_HOST2TGT_NAME "mainpipe"));
205   MALLOC (char *, pipe_tgt2host_path,
206 	  strlen (engine_dir) + sizeof (PIPE_TGT2HOST_NAME "mainpipe"));
207   sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "mainpipe", engine_dir);
208   sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "mainpipe", engine_dir);
209   int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_RDONLY);
210   if (pipe_host2tgt < 0)
211     COIERROR ("Cannot open host-to-target main pipe.");
212   int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_WRONLY);
213   if (pipe_tgt2host < 0)
214     COIERROR ("Cannot open target-to-host main pipe.");
215 
216   /* Clean up.  */
217   free (pipe_host2tgt_path);
218   free (pipe_tgt2host_path);
219 
220   /* Handler.  */
221   while (1)
222     {
223       /* Read and execute command.  */
224       cmd_t cmd = CMD_SHUTDOWN;
225       int cmd_len = read (pipe_host2tgt, &cmd, sizeof (cmd_t));
226       if (cmd_len != sizeof (cmd_t) && cmd_len != 0)
227 	COIERROR ("Cannot read from main pipe.");
228 
229       switch (cmd)
230 	{
231 	case CMD_BUFFER_COPY:
232 	  {
233 	    uint64_t len;
234 	    void *dest, *source;
235 
236 	    /* Receive data from host.  */
237 	    READ (pipe_host2tgt, &dest, sizeof (void *));
238 	    READ (pipe_host2tgt, &source, sizeof (void *));
239 	    READ (pipe_host2tgt, &len, sizeof (uint64_t));
240 
241 	    /* Copy.  */
242 	    memcpy (dest, source, len);
243 
244 	    /* Notify host about completion.  */
245 	    WRITE (pipe_tgt2host, &cmd, sizeof (cmd_t));
246 
247 	    break;
248 	  }
249 	case CMD_BUFFER_MAP:
250 	  {
251 	    char *name;
252 	    size_t len;
253 	    uint64_t buffer_len;
254 	    void *buffer;
255 
256 	    /* Receive data from host.  */
257 	    READ (pipe_host2tgt, &len, sizeof (size_t));
258 	    MALLOC (char *, name, len);
259 	    READ (pipe_host2tgt, name, len);
260 	    READ (pipe_host2tgt, &buffer_len, sizeof (uint64_t));
261 
262 	    /* Open shared memory.  */
263 	    int fd = shm_open (name, O_CLOEXEC | O_RDWR, S_IRUSR | S_IWUSR);
264 	    if (fd < 0)
265 	      COIERROR ("Cannot open shared memory.");
266 
267 	    /* Map shared memory.  */
268 	    buffer = mmap (NULL, buffer_len, PROT_READ | PROT_WRITE,
269 			   MAP_SHARED, fd, 0);
270 	    if (buffer == NULL)
271 	      COIERROR ("Cannot map shared memory.");
272 
273 	    /* Send data to host.  */
274 	    WRITE (pipe_tgt2host, &fd, sizeof (int));
275 	    WRITE (pipe_tgt2host, &buffer, sizeof (void *));
276 
277 	    /* Clean up.  */
278 	    free (name);
279 
280 	    break;
281 	  }
282 	case CMD_BUFFER_UNMAP:
283 	  {
284 	    int fd;
285 	    uint64_t buffer_len;
286 	    void *buffer;
287 
288 	    /* Receive data from host.  */
289 	    READ (pipe_host2tgt, &fd, sizeof (int));
290 	    READ (pipe_host2tgt, &buffer, sizeof (void *));
291 	    READ (pipe_host2tgt, &buffer_len, sizeof (uint64_t));
292 
293 	    /* Unmap buffer.  */
294 	    if (munmap (buffer, buffer_len) < 0)
295 	      COIERROR ("Cannot unmap shared memory.");
296 
297 	    /* Close shared memory.  */
298 	    if (close (fd) < 0)
299 	      COIERROR ("Cannot close shared memory file.");
300 
301 	    /* Notify host about completion.  */
302 	    WRITE (pipe_tgt2host, &cmd, sizeof (cmd_t));
303 
304 	    break;
305 	  }
306 	case CMD_GET_FUNCTION_HANDLE:
307 	  {
308 	    char *name;
309 	    size_t len;
310 
311 	    /* Receive data from host.  */
312 	    READ (pipe_host2tgt, &len, sizeof (size_t));
313 	    MALLOC (char *, name, len);
314 	    READ (pipe_host2tgt, name, len);
315 
316 	    /* Find function.  */
317 	    void *ptr = dlsym (RTLD_DEFAULT, name);
318 	    if (ptr == NULL)
319 	      COIERROR ("Cannot find symbol %s.", name);
320 
321 	    /* Send data to host.  */
322 	    WRITE (pipe_tgt2host, &ptr, sizeof (void *));
323 
324 	    /* Clean up.  */
325 	    free (name);
326 
327 	    break;
328 	  }
329 	case CMD_OPEN_LIBRARY:
330 	  {
331 	    char *lib_path;
332 	    size_t len;
333 
334 	    /* Receive data from host.  */
335 	    READ (pipe_host2tgt, &len, sizeof (size_t));
336 	    MALLOC (char *, lib_path, len);
337 	    READ (pipe_host2tgt, lib_path, len);
338 
339 	    /* Open library.  */
340 	    void *handle = dlopen (lib_path, RTLD_LAZY | RTLD_GLOBAL);
341 	    if (handle == NULL)
342 	      COIERROR ("Cannot load %s: %s", lib_path, dlerror ());
343 
344 	    /* Send data to host.  */
345 	    WRITE (pipe_tgt2host, &handle, sizeof (void *));
346 
347 	    /* Clean up.  */
348 	    free (lib_path);
349 
350 	    break;
351 	  }
352 	case CMD_CLOSE_LIBRARY:
353 	  {
354 	    /* Receive data from host.  */
355 	    void *handle;
356 	    READ (pipe_host2tgt, &handle, sizeof (void *));
357 
358 	    dlclose (handle);
359 
360 	    break;
361 	  }
362 	case CMD_PIPELINE_CREATE:
363 	  {
364 	    /* Receive data from host.  */
365 	    uint32_t *pipeline_num;
366 	    MALLOC (uint32_t *, pipeline_num, sizeof (uint32_t));
367 	    READ (pipe_host2tgt, pipeline_num, sizeof (*pipeline_num));
368 
369 	    /* Create a new thread for the pipeline.  */
370 	    pthread_t thread;
371 	    if (pthread_create (&thread, NULL, pipeline_thread_routine,
372 				pipeline_num))
373 	      COIERROR ("Cannot create new thread.");
374 	    break;
375 	  }
376 	case CMD_SHUTDOWN:
377 	  if (close (pipe_host2tgt) < 0)
378 	    COIERROR ("Cannot close host-to-target main pipe.");
379 	  if (close (pipe_tgt2host) < 0)
380 	    COIERROR ("Cannot close target-to-host main pipe.");
381 	  return COI_SUCCESS;
382 	default:
383 	  COIERROR ("Unrecognizable command from host.");
384 	}
385     }
386 
387   return COI_ERROR;
388 }
389 
390 
391 
392 uint64_t
393 SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) ()
394 {
395   COITRACE ("COIPerfGetCycleFrequency");
396 
397   return (uint64_t) CYCLE_FREQUENCY;
398 }
399 
400 } // extern "C"
401 
402