| /* | |
| Copyright (c) 2014-2016 Intel Corporation. All Rights Reserved. | |
| Redistribution and use in source and binary forms, with or without | |
| modification, are permitted provided that the following conditions | |
| are met: | |
| * Redistributions of source code must retain the above copyright | |
| notice, this list of conditions and the following disclaimer. | |
| * Redistributions in binary form must reproduce the above copyright | |
| notice, this list of conditions and the following disclaimer in the | |
| documentation and/or other materials provided with the distribution. | |
| * Neither the name of Intel Corporation nor the names of its | |
| contributors may be used to endorse or promote products derived | |
| from this software without specific prior written permission. | |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #include "coi_device.h" | |
| #include "coi_version_asm.h" | |
| #define CYCLE_FREQUENCY 1000000000 | |
| static uint32_t engine_index; | |
| static char *engine_dir; | |
| extern "C" | |
| { | |
| COIRESULT | |
| SYMBOL_VERSION (COIBufferAddRef, 1) (void *ptr) | |
| { | |
| COITRACE ("COIBufferAddRef"); | |
| /* Looks like we have nothing to do here. */ | |
| return COI_SUCCESS; | |
| } | |
| COIRESULT | |
| SYMBOL_VERSION (COIBufferReleaseRef, 1) (void *ptr) | |
| { | |
| COITRACE ("COIBufferReleaseRef"); | |
| /* Looks like we have nothing to do here. */ | |
| return COI_SUCCESS; | |
| } | |
| COIRESULT | |
| SYMBOL_VERSION (COIEngineGetIndex, 1) (COI_ISA_TYPE *type, | |
| uint32_t *index) | |
| { | |
| COITRACE ("COIEngineGetIndex"); | |
| /* type is not used in liboffloadmic. */ | |
| *index = engine_index; | |
| return COI_SUCCESS; | |
| } | |
| COIRESULT | |
| SYMBOL_VERSION (COIPipelineStartExecutingRunFunctions, 1) () | |
| { | |
| COITRACE ("COIPipelineStartExecutingRunFunctions"); | |
| /* Looks like we have nothing to do here. */ | |
| return COI_SUCCESS; | |
| } | |
| /* The start routine for the COI pipeline thread. */ | |
| static void * | |
| pipeline_thread_routine (void *in_pipeline_num) | |
| { | |
| uint32_t pipeline_num = *(uint32_t *) in_pipeline_num; | |
| free (in_pipeline_num); | |
| /* Open pipes. */ | |
| char *pipe_host2tgt_path, *pipe_tgt2host_path; | |
| MALLOCN (char *, pipe_host2tgt_path, | |
| strlen (engine_dir) + sizeof (PIPE_HOST2TGT_NAME "0000000000")); | |
| MALLOCN (char *, pipe_tgt2host_path, | |
| strlen (engine_dir) + sizeof (PIPE_TGT2HOST_NAME "0000000000")); | |
| sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "%010d", engine_dir, | |
| pipeline_num); | |
| sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "%010d", engine_dir, | |
| pipeline_num); | |
| int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_RDONLY); | |
| if (pipe_host2tgt < 0) | |
| COIERRORN ("Cannot open host-to-target pipe."); | |
| int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_WRONLY); | |
| if (pipe_tgt2host < 0) | |
| COIERRORN ("Cannot open target-to-host pipe."); | |
| free (pipe_host2tgt_path); | |
| free (pipe_tgt2host_path); | |
| while (1) | |
| { | |
| /* Read and execute command. */ | |
| cmd_t cmd = CMD_PIPELINE_DESTROY; | |
| int cmd_len = read (pipe_host2tgt, &cmd, sizeof (cmd_t)); | |
| if (cmd_len != sizeof (cmd_t) && cmd_len != 0) | |
| COIERRORN ("Cannot read from pipe."); | |
| if (cmd == CMD_PIPELINE_DESTROY) | |
| break; | |
| else if (cmd == CMD_PIPELINE_RUN_FUNCTION) | |
| { | |
| /* Receive data from host. */ | |
| void (*func) (uint32_t, void **, uint64_t *, void *, uint16_t, void *, | |
| uint16_t); | |
| uint32_t buffer_count; | |
| READN (pipe_host2tgt, &func, sizeof (void *)); | |
| READN (pipe_host2tgt, &buffer_count, sizeof (uint32_t)); | |
| void **buffers; | |
| uint64_t *buffers_len; | |
| MALLOCN (void **, buffers, buffer_count * sizeof (void *)); | |
| MALLOCN (uint64_t *, buffers_len, buffer_count * sizeof (uint64_t)); | |
| for (uint32_t i = 0; i < buffer_count; i++) | |
| { | |
| READN (pipe_host2tgt, &buffers_len[i], sizeof (uint64_t)); | |
| READN (pipe_host2tgt, &buffers[i], sizeof (void *)); | |
| } | |
| uint16_t misc_data_len; | |
| READN (pipe_host2tgt, &misc_data_len, sizeof (uint16_t)); | |
| void *misc_data = NULL; | |
| if (misc_data_len > 0) | |
| { | |
| MALLOCN (void *, misc_data, misc_data_len); | |
| READN (pipe_host2tgt, misc_data, misc_data_len); | |
| } | |
| uint16_t return_data_len; | |
| READN (pipe_host2tgt, &return_data_len, sizeof (uint16_t)); | |
| void *return_data; | |
| if (return_data_len > 0) | |
| MALLOCN (void *, return_data, return_data_len); | |
| /* Run function. */ | |
| func (buffer_count, buffers, buffers_len, misc_data, | |
| misc_data_len, return_data, return_data_len); | |
| /* Send data to host if any or just send notification. */ | |
| WRITEN (pipe_tgt2host, return_data_len > 0 ? return_data : &cmd, | |
| return_data_len > 0 ? return_data_len : sizeof (cmd_t)); | |
| /* Clean up. */ | |
| free (buffers); | |
| free (buffers_len); | |
| if (misc_data_len > 0) | |
| free (misc_data); | |
| if (return_data_len > 0) | |
| free (return_data); | |
| } | |
| else | |
| COIERRORN ("Unrecognizable command from host."); | |
| } | |
| /* Close pipes. */ | |
| if (close (pipe_host2tgt) < 0) | |
| COIERRORN ("Cannot close host-to-target pipe."); | |
| if (close (pipe_tgt2host) < 0) | |
| COIERRORN ("Cannot close target-to-host pipe."); | |
| return NULL; | |
| } | |
| COIRESULT | |
| SYMBOL_VERSION (COIProcessWaitForShutdown, 1) () | |
| { | |
| COITRACE ("COIProcessWaitForShutdown"); | |
| engine_dir = getenv (MIC_DIR_ENV); | |
| char *mic_index = getenv (MIC_INDEX_ENV); | |
| assert (engine_dir != NULL && mic_index != NULL); | |
| /* Get engine index. */ | |
| engine_index = atoi (mic_index); | |
| /* Open main pipes. */ | |
| char *pipe_host2tgt_path, *pipe_tgt2host_path; | |
| MALLOC (char *, pipe_host2tgt_path, | |
| strlen (engine_dir) + sizeof (PIPE_HOST2TGT_NAME "mainpipe")); | |
| MALLOC (char *, pipe_tgt2host_path, | |
| strlen (engine_dir) + sizeof (PIPE_TGT2HOST_NAME "mainpipe")); | |
| sprintf (pipe_host2tgt_path, "%s" PIPE_HOST2TGT_NAME "mainpipe", engine_dir); | |
| sprintf (pipe_tgt2host_path, "%s" PIPE_TGT2HOST_NAME "mainpipe", engine_dir); | |
| int pipe_host2tgt = open (pipe_host2tgt_path, O_CLOEXEC | O_RDONLY); | |
| if (pipe_host2tgt < 0) | |
| COIERROR ("Cannot open host-to-target main pipe."); | |
| int pipe_tgt2host = open (pipe_tgt2host_path, O_CLOEXEC | O_WRONLY); | |
| if (pipe_tgt2host < 0) | |
| COIERROR ("Cannot open target-to-host main pipe."); | |
| /* Clean up. */ | |
| free (pipe_host2tgt_path); | |
| free (pipe_tgt2host_path); | |
| /* Handler. */ | |
| while (1) | |
| { | |
| /* Read and execute command. */ | |
| cmd_t cmd = CMD_SHUTDOWN; | |
| int cmd_len = read (pipe_host2tgt, &cmd, sizeof (cmd_t)); | |
| if (cmd_len != sizeof (cmd_t) && cmd_len != 0) | |
| COIERROR ("Cannot read from main pipe."); | |
| switch (cmd) | |
| { | |
| case CMD_BUFFER_COPY: | |
| { | |
| uint64_t len; | |
| void *dest, *source; | |
| /* Receive data from host. */ | |
| READ (pipe_host2tgt, &dest, sizeof (void *)); | |
| READ (pipe_host2tgt, &source, sizeof (void *)); | |
| READ (pipe_host2tgt, &len, sizeof (uint64_t)); | |
| /* Copy. */ | |
| memcpy (dest, source, len); | |
| /* Notify host about completion. */ | |
| WRITE (pipe_tgt2host, &cmd, sizeof (cmd_t)); | |
| break; | |
| } | |
| case CMD_BUFFER_MAP: | |
| { | |
| char *name; | |
| size_t len; | |
| uint64_t buffer_len; | |
| void *buffer; | |
| /* Receive data from host. */ | |
| READ (pipe_host2tgt, &len, sizeof (size_t)); | |
| MALLOC (char *, name, len); | |
| READ (pipe_host2tgt, name, len); | |
| READ (pipe_host2tgt, &buffer_len, sizeof (uint64_t)); | |
| /* Open shared memory. */ | |
| int fd = shm_open (name, O_CLOEXEC | O_RDWR, S_IRUSR | S_IWUSR); | |
| if (fd < 0) | |
| COIERROR ("Cannot open shared memory."); | |
| /* Map shared memory. */ | |
| buffer = mmap (NULL, buffer_len, PROT_READ | PROT_WRITE, | |
| MAP_SHARED, fd, 0); | |
| if (buffer == NULL) | |
| COIERROR ("Cannot map shared memory."); | |
| /* Send data to host. */ | |
| WRITE (pipe_tgt2host, &fd, sizeof (int)); | |
| WRITE (pipe_tgt2host, &buffer, sizeof (void *)); | |
| /* Clean up. */ | |
| free (name); | |
| break; | |
| } | |
| case CMD_BUFFER_UNMAP: | |
| { | |
| int fd; | |
| uint64_t buffer_len; | |
| void *buffer; | |
| /* Receive data from host. */ | |
| READ (pipe_host2tgt, &fd, sizeof (int)); | |
| READ (pipe_host2tgt, &buffer, sizeof (void *)); | |
| READ (pipe_host2tgt, &buffer_len, sizeof (uint64_t)); | |
| /* Unmap buffer. */ | |
| if (munmap (buffer, buffer_len) < 0) | |
| COIERROR ("Cannot unmap shared memory."); | |
| /* Close shared memory. */ | |
| if (close (fd) < 0) | |
| COIERROR ("Cannot close shared memory file."); | |
| /* Notify host about completion. */ | |
| WRITE (pipe_tgt2host, &cmd, sizeof (cmd_t)); | |
| break; | |
| } | |
| case CMD_GET_FUNCTION_HANDLE: | |
| { | |
| char *name; | |
| size_t len; | |
| /* Receive data from host. */ | |
| READ (pipe_host2tgt, &len, sizeof (size_t)); | |
| MALLOC (char *, name, len); | |
| READ (pipe_host2tgt, name, len); | |
| /* Find function. */ | |
| void *ptr = dlsym (RTLD_DEFAULT, name); | |
| if (ptr == NULL) | |
| COIERROR ("Cannot find symbol %s.", name); | |
| /* Send data to host. */ | |
| WRITE (pipe_tgt2host, &ptr, sizeof (void *)); | |
| /* Clean up. */ | |
| free (name); | |
| break; | |
| } | |
| case CMD_OPEN_LIBRARY: | |
| { | |
| char *lib_path; | |
| size_t len; | |
| /* Receive data from host. */ | |
| READ (pipe_host2tgt, &len, sizeof (size_t)); | |
| MALLOC (char *, lib_path, len); | |
| READ (pipe_host2tgt, lib_path, len); | |
| /* Open library. */ | |
| void *handle = dlopen (lib_path, RTLD_LAZY | RTLD_GLOBAL); | |
| if (handle == NULL) | |
| COIERROR ("Cannot load %s: %s", lib_path, dlerror ()); | |
| /* Send data to host. */ | |
| WRITE (pipe_tgt2host, &handle, sizeof (void *)); | |
| /* Clean up. */ | |
| free (lib_path); | |
| break; | |
| } | |
| case CMD_CLOSE_LIBRARY: | |
| { | |
| /* Receive data from host. */ | |
| void *handle; | |
| READ (pipe_host2tgt, &handle, sizeof (void *)); | |
| dlclose (handle); | |
| break; | |
| } | |
| case CMD_PIPELINE_CREATE: | |
| { | |
| /* Receive data from host. */ | |
| uint32_t *pipeline_num; | |
| MALLOC (uint32_t *, pipeline_num, sizeof (uint32_t)); | |
| READ (pipe_host2tgt, pipeline_num, sizeof (*pipeline_num)); | |
| /* Create a new thread for the pipeline. */ | |
| pthread_t thread; | |
| if (pthread_create (&thread, NULL, pipeline_thread_routine, | |
| pipeline_num)) | |
| COIERROR ("Cannot create new thread."); | |
| break; | |
| } | |
| case CMD_SHUTDOWN: | |
| if (close (pipe_host2tgt) < 0) | |
| COIERROR ("Cannot close host-to-target main pipe."); | |
| if (close (pipe_tgt2host) < 0) | |
| COIERROR ("Cannot close target-to-host main pipe."); | |
| return COI_SUCCESS; | |
| default: | |
| COIERROR ("Unrecognizable command from host."); | |
| } | |
| } | |
| return COI_ERROR; | |
| } | |
| uint64_t | |
| SYMBOL_VERSION (COIPerfGetCycleFrequency, 1) () | |
| { | |
| COITRACE ("COIPerfGetCycleFrequency"); | |
| return (uint64_t) CYCLE_FREQUENCY; | |
| } | |
| } // extern "C" | |