diff options
author | zilio nicolas <nicolas.zilio@kit.edu> | 2015-07-07 11:12:52 +0200 |
---|---|---|
committer | zilio nicolas <nicolas.zilio@kit.edu> | 2015-07-07 11:12:52 +0200 |
commit | f923add0a9b6bd17d43f72c21eec4e01e19240cf (patch) | |
tree | 8f737e8bd5faa360dfef5b33c52a0f58679c4b8d | |
parent | e2515f6e1a7b17addda4c558a0a6ca05b4ec6e55 (diff) | |
download | pcitool-f923add0a9b6bd17d43f72c21eec4e01e19240cf.tar.gz pcitool-f923add0a9b6bd17d43f72c21eec4e01e19240cf.tar.bz2 pcitool-f923add0a9b6bd17d43f72c21eec4e01e19240cf.tar.xz pcitool-f923add0a9b6bd17d43f72c21eec4e01e19240cf.zip |
clean version for locks
-rw-r--r-- | dma/ipe.h | 1 | ||||
-rw-r--r-- | pcilib/CMakeLists.txt | 4 | ||||
-rw-r--r-- | pcilib/kmem.h | 1 | ||||
-rw-r--r-- | pcilib/lock.c | 116 | ||||
-rw-r--r-- | pcilib/lock.h | 55 | ||||
-rw-r--r-- | pcilib/locking.c | 74 | ||||
-rw-r--r-- | pcilib/locking.h | 44 | ||||
-rw-r--r-- | pcilib/pci.c | 8 | ||||
-rw-r--r-- | pcilib/pci.h | 2 | ||||
-rw-r--r-- | pcitool/cli.c | 17 | ||||
-rw-r--r-- | protocols/software.c | 41 |
11 files changed, 346 insertions, 17 deletions
@@ -79,6 +79,7 @@ static const pcilib_register_description_t ipe_dma_registers[] = { {0x005C, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "desc_mem_addr", "Number of descriptors configured"}, {0x0060, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "update_thresh", "Update threshold of progress register"}, {0x0000, 0, 32, PCILIB_VERSION, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMACONF, "dma_version", "Version of DMA engine"}, + {0x005, 0, 32, PCILIB_VERSION, 0x00000040, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMACONF, "test", "testdesc"}, {0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL} }; #endif /* _PCILIB_EXPORT_C */ diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt index c9bf0fb..ebb5cec 100644 --- a/pcilib/CMakeLists.txt +++ b/pcilib/CMakeLists.txt @@ -3,8 +3,8 @@ include_directories( ${CMAKE_SOURCE_DIR}/pcilib ) -set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h kmem.h irq.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h) -add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c register.c kmem.c irq.c dma.c event.c plugin.c tools.c error.c debug.c env.c) +set(HEADERS pcilib.h pci.h export.h bar.h fifo.h model.h bank.h register.h kmem.h irq.h dma.h event.h plugin.h tools.h error.h debug.h env.h version.h config.h locking.h lock.h) +add_library(pcilib SHARED pci.c export.c bar.c fifo.c model.c bank.c register.c kmem.c irq.c dma.c event.c plugin.c tools.c error.c debug.c env.c locking.c lock.c) target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ${CMAKE_DL_LIBS}) add_dependencies(pcilib dma protocols) diff --git a/pcilib/kmem.h b/pcilib/kmem.h index 8299379..65bdf04 100644 --- a/pcilib/kmem.h +++ b/pcilib/kmem.h @@ -31,6 +31,7 @@ typedef enum { PCILIB_KMEM_USE_DMA_RING = 1, PCILIB_KMEM_USE_DMA_PAGES = 2, PCILIB_KMEM_USE_SOFTWARE_REGISTERS = 3, + PCILIB_KMEM_USE_MUTEXES = 4, PCILIB_KMEM_USE_USER = 0x10 } pcilib_kmem_use_t; diff --git a/pcilib/lock.c b/pcilib/lock.c new file mode 100644 index 0000000..8715d21 --- /dev/null +++ b/pcilib/lock.c @@ -0,0 +1,116 @@ +#define _GNU_SOURCE +#define _XOPEN_SOURCE 600 + +#include <string.h> +#include <stdint.h> +#include "error.h" +#include "lock.h" +#include "pci.h" + +/* + * this function will take the lock for the semaphore pointed by semId + */ +void pcilib_lock(pcilib_lock_t *lock_ctx, pcilib_lock_flags_t flags, ...){ + int err; + struct timespec *time; + va_list pa; + va_start(pa,flags); + + if(flags & MUTEX_LOCK){ + err=pthread_mutex_lock(lock_ctx);/**< we try to lock here*/ + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + /** if the lock haven't been acquired and errno==EOWNERDEAD, it means the previous application that got the lock crashed, we have to remake the lock "consistent" so*/ + else if(errno==EOWNERDEAD){ + pthread_mutex_consistent(lock_ctx); + pthread_mutex_lock(lock_ctx); + if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + } + } + else if(flags & MUTEX_TRYLOCK){ + err=pthread_mutex_trylock(lock_ctx);/**< we try to lock here*/ + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + else if(errno==EOWNERDEAD){ + pthread_mutex_consistent(lock_ctx); + pthread_mutex_lock(lock_ctx); + if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + } + } + else if(flags & MUTEX_TIMEDLOCK){ + time=va_arg(pa,struct timespec*); + va_end(pa); + err=pthread_mutex_timedlock(lock_ctx, time);/**< we try to lock here*/ + if(errno!=EOWNERDEAD && err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)),errno); + else if(errno==EOWNERDEAD){ + pthread_mutex_consistent(lock_ctx); + pthread_mutex_timedlock(lock_ctx, time); + if(err!=0) pcilib_error("can't acquire lock %s, error %i\n",(char*)(lock_ctx+sizeof(pcilib_lock_t)), errno); + } + } + else pcilib_error("wrong flag for pcilib_lock"); +} + +/** + * this function will unlock the semaphore pointed by lock_ctx. + */ +void pcilib_unlock(pcilib_lock_t* lock_ctx){ + int err; + if((err=pthread_mutex_unlock(lock_ctx))!=0) pcilib_error("can't unlock semaphore\n"); +} + +/** + * pcilib_init_lock + * this function initialize a new semaphore in the kernel if it's not already initialized given the key that permits to differentiate semaphores, and then return the integer that points to the semaphore that have been initialized or to a previously already initialized semaphore + * @param[out] lock_ctx the pointer that will points to the semaphore for other functions + * @param[in] keysem the integer that permits to define to what the semaphore is attached + */ +pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx, char* lock_id, ...){ + int err; + pthread_mutexattr_t attr; + int i,j; + void* addr,*locks_addr; + va_list pa; + va_start(pa,lock_id); + + pcilib_lock_init_flags_t flag; + flag=va_arg(pa,pcilib_lock_init_flags_t); + va_end(pa); + + if(strlen(lock_id)>PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)) pcilib_error("the entered protocol name is too long"); + if(((PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)%PCILIB_KMEM_PAGE_SIZE)!=0) pcilib_error("PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE should be a multiple of kmem page size"); + + addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,0); + if(flag & LOCK_INIT) pcilib_lock((pcilib_lock_t*)addr,MUTEX_LOCK); + /* we search for the given lock if it was already initialized*/ + for(j=0;j<PCILIB_NUMBER_OF_LOCK_PAGES;j++){ + i=0; + locks_addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,j); + while((*(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t))!=0) && (i<PCILIB_LOCKS_PER_PAGE)){ + if(strcmp(lock_id,(char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t)))==0){ + return (pcilib_lock_t*)(locks_addr+i*PCILIB_LOCK_SIZE);} + i++; + } + if(i<PCILIB_LOCKS_PER_PAGE) break; + } + if(i==PCILIB_LOCKS_PER_PAGE) pcilib_error("no more free space for a new lock\n"); + /* if not, we create a new one*/ + if((err= pthread_mutexattr_init(&attr))!=0) pcilib_error("can't initialize semaphore attribute\n"); + if((err = pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED))!=0) pcilib_error("can't set a shared mutex\n"); + if((err= pthread_mutexattr_setrobust(&attr,PTHREAD_MUTEX_ROBUST))!=0) pcilib_error("can't set a robust mutex\n"); + if((err=pthread_mutex_init((pcilib_lock_t*)(locks_addr+i*PCILIB_LOCK_SIZE),&attr))!=0) pcilib_error("can't set attributes to semaphore\n"); + pthread_mutexattr_destroy(&attr); + + strcpy((char*)(locks_addr+i*PCILIB_LOCK_SIZE+sizeof(pcilib_lock_t)),lock_id); + + if(flag & LOCK_INIT) pcilib_unlock((pcilib_lock_t*)addr); + return (pcilib_lock_t*)(locks_addr+i*PCILIB_LOCK_SIZE); + +} + +/* + * pcilib_lock_free does nothing for now, as we don't want to erase possible locks in the kernel memory (or at any erasing, we should rearrange the locks to have no free space between locks). A thing i think of would be to use chained lists in kernel memory, but how? + */ +void pcilib_free_lock(pcilib_lock_t *lock_ctx){ + int err; + if((err=pthread_mutex_destroy(lock_ctx))==-1) pcilib_warning("can't clean lock properly\n"); + memset((char*)(lock_ctx+sizeof(pcilib_lock_t)),0,PCILIB_LOCK_SIZE-sizeof(pcilib_lock_t)); + } diff --git a/pcilib/lock.h b/pcilib/lock.h new file mode 100644 index 0000000..53da543 --- /dev/null +++ b/pcilib/lock.h @@ -0,0 +1,55 @@ +/** + * @file lock.h + * @skip author zilio nicolas, nicolas.zilio@hotmail.fr + * @brief this file is the header file for the functions that implement a semaphore API for the pcitool program, using pthread robust mutexes. + * @details the use of pthread robust mutexes was chosen due to the fact we privilege security over fastness, and that pthread mutexes permits to recover semaphores even with crash ,and that it does not require access to resources that can be easily accessible from extern usage as flock file locking mechanism. A possible other locking mechanism could be the sysv semaphores, but we have a problem of how determine a perfect hash for the init function, and more, benchmarks proves that sysv semaphore aren't that stable and that with more than 10 locks/unlocks, pthread is better in performance, so that should suits more to the final pcitool program. + * We considered that mutex implmentation is enough compared to a reader/writer implementation. If it should change, please go to sysv semaphore. + * Basic explanation on how semaphores here work: a semaphore here is a positive integer, thus that can't go below zero, which is initiated with a value. when a process want access to the critical resource, it asks to decrement the value of the semaphore, and when it has finished, it reincrements it.basically, when the semaphore is equal to zero, any process must have to wait for it to be reincremented before decrementing it again. Here are defined two types of access to the semaphore corresponding to the reader/writer problem : an exclusive lock, which means that no other process than the one who have the resource can access it; a shared lock, which means that other processes who want to access to the resource with a shared lock can have the access, but a concurrent process who want to access the semaphore with an exclusive lock won't be able to. + */ + +#ifndef _LOCK_ +#define _LOCK_ + +#include "locking.h" + +typedef enum{ + MUTEX_LOCK=1, + MUTEX_TRYLOCK=2, + MUTEX_TIMEDLOCK=4 +} pcilib_lock_flags_t; + +typedef enum{ + LOCK_INIT=16 +}pcilib_lock_init_flags_t; + + + +/** + * this function initialize a new semaphore in the kernel given a name that corresponds to a specific processus if the semaphore is not already initialized given the name that permits to differentiate semaphores, and then return the integer that points to the semaphore that have been initialized or to a previously already initialized semaphore. + * @param[in] ctx the pcilib_t running + * @param[in] id_protocol_name the name of the protocol that permits to define to what the semaphore is attached. It suppose that there is one semaphore by protocol, but if it's not the case, create one semaphore by each sub-protocol name. + *@return a mutex for the given protocol name + */ +pcilib_lock_t* pcilib_init_lock(pcilib_t *ctx,char* lock_id, ...); + +/** + * this function does nothing for the moment, as we don't want to destroy the locks put in kernel memory. + * @param[in] lock_ctx the pointer that points to the semaphore set. + */ +void pcilib_free_lock(pcilib_lock_t *lock_ctx); + +/** + * this function will take a lock for the mutex pointed by lock_ctx + * @param[in] lock_ctx the pointer to the mutex + * @param[in] lock_flags define the type of lock wanted : MUTEX_LOCK (normal lock), MUTEX_TRYLOCK (will return if it can't acquire lock), MUTEX_TIMEDLOCK (will wait if it can't acquire lock for a given time, after it returns) + * + */ +void pcilib_lock(pcilib_lock_t* lock_ctx,pcilib_lock_flags_t flags, ...); + +/** + * this function will unlock the semaphore pointed by lock_ctx + * @param[in] lock_ctx the integer that points to the semaphore + */ +void pcilib_unlock(pcilib_lock_t* lock_ctx); + +#endif /*_LOCK_*/ diff --git a/pcilib/locking.c b/pcilib/locking.c new file mode 100644 index 0000000..93e6fdd --- /dev/null +++ b/pcilib/locking.c @@ -0,0 +1,74 @@ +#define _XOPEN_SOURCE 700 + +#include "error.h" +#include "pci.h" +#include <sys/file.h> +#include <string.h> +#include "lock.h" + +/* + * this function clean all locks created by the pcitool program + */ +void pcilib_clean_all_locks(pcilib_t* ctx){ +int i,j; +void* addr; + i=0; + while(i<PCILIB_NUMBER_OF_LOCK_PAGES){ +addr=pcilib_kmem_get_block_ua(ctx,ctx->locks_handle,i); +for(j=0;j<PCILIB_LOCKS_PER_PAGE;j++) + pcilib_free_lock((pcilib_lock_t*)(addr+i*PCILIB_LOCK_SIZE)); + i++; + } + +} + +void pcilib_free_locking(pcilib_t* ctx){ + pcilib_clean_all_locks(ctx); + pcilib_free_kernel_memory(ctx,ctx->locks_handle,PCILIB_KMEM_FLAG_REUSE); +} + +/* + * this function allocates the kernel memory for the locks for software registers + */ +int pcilib_init_locking(pcilib_t* ctx, ...){ +/*for future possible more args + va_list pa; + va_start(pa,ctx);*/ + pcilib_kmem_handle_t *handle; + int err; + pcilib_kmem_reuse_state_t reused; + + + if((err=flock(ctx->handle,LOCK_EX))==-1) pcilib_warning("can't get flock on /dev/fpga0"); + handle=pcilib_alloc_kernel_memory(ctx,PCILIB_KMEM_TYPE_PAGE,PCILIB_NUMBER_OF_LOCK_PAGES,PCILIB_KMEM_PAGE_SIZE,0,PCILIB_KMEM_USE(PCILIB_KMEM_USE_MUTEXES,0),PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); + + if (!handle) { + pcilib_error("Allocation of kernel memory for mutexes has failed"); + return 1; + } + + ctx->locks_handle=handle; + reused = pcilib_kmem_is_reused(ctx, handle); +//#define DEBUG_REUSE +#ifdef DEBUG_REUSE +reused=0; +#endif + if ((reused & PCILIB_KMEM_REUSE_REUSED) == 0) { + pcilib_register_t i; + + if (reused & PCILIB_KMEM_REUSE_PARTIAL) { + pcilib_error("Inconsistent software registers are found (only part of required buffers is available)"); + pcilib_clean_all_locks(ctx); + return 1; + } + for(i=0;i<PCILIB_NUMBER_OF_LOCK_PAGES;i++){ + memset(pcilib_kmem_get_block_ua(ctx,handle,i),0,PCILIB_KMEM_PAGE_SIZE); + } + pcilib_init_lock(ctx,"pcilib_locking",LOCK_INIT); + + } + + if((err=flock(ctx->handle,LOCK_UN))==-1) pcilib_warning("could not remove lock correctly on /dev/fpga0"); + + return 0; +} diff --git a/pcilib/locking.h b/pcilib/locking.h new file mode 100644 index 0000000..f7570f6 --- /dev/null +++ b/pcilib/locking.h @@ -0,0 +1,44 @@ +/** + * @file lock_global.h + * @brief this file is the header file for functions that touch all locks allocated for software registers. + * @details for more details about implementation choice, please read the file lock.h + */ +#define _XOPEN_SOURCE 700 + +#ifndef _LOCKING_ +#define _LOCKING_ + +#include <pthread.h> + +/** number of maximum locks*/ +#define PCILIB_MAX_NUMBER_LOCKS 64 + +/**size of one lock, determine so the size of the protocol_name in the way locks are registered. 40 bytes are necessary for the mutex structure, so we have a protocol name of length LOCK_SIZE-40*/ +#define PCILIB_LOCK_SIZE 128 + +#define PCILIB_LOCKS_PER_PAGE PCILIB_KMEM_PAGE_SIZE/PCILIB_LOCK_SIZE + +#define PCILIB_NUMBER_OF_LOCK_PAGES (PCILIB_MAX_NUMBER_LOCKS*PCILIB_LOCK_SIZE)/PCILIB_KMEM_PAGE_SIZE + + +/** +* new type to define a semaphore. It was made to differentiate from the library type. +*/ +typedef pthread_mutex_t pcilib_lock_t; + +/** + * this function destroy all locks created + *@param[in] ctx, the pcilib_t running + */ +void pcilib_clean_all_locks(pcilib_t* ctx); + +/** +* this function initialize the kmem pages containing locks +*@param[in] ctx the pcilib_t running +*/ +int pcilib_init_locking(pcilib_t* ctx, ...); + + +void pcilib_free_all_locks(pcilib_t* ctx); + +#endif /* _LOCK_GLOBAL_ */ diff --git a/pcilib/pci.c b/pcilib/pci.c index 3a18ccd..c7b86e8 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -1,4 +1,5 @@ //#define PCILIB_FILE_IO +#define _XOPEN_SOURCE 700 #define _BSD_SOURCE #define _POSIX_C_SOURCE 200809L @@ -24,6 +25,7 @@ #include "model.h" #include "plugin.h" #include "bar.h" +#include "locking.h" static int pcilib_detect_model(pcilib_t *ctx, const char *model) { int i, j; @@ -159,6 +161,12 @@ pcilib_t *pcilib_open(const char *device, const char *model) { ctx->model_info.protocols = ctx->protocols; ctx->model_info.ranges = ctx->ranges; + err=pcilib_init_locking(ctx); + if (err) { + pcilib_error("Error (%i) initializing locking\n", err); + pcilib_close(ctx); + return NULL; + } err = pcilib_init_register_banks(ctx); if (err) { diff --git a/pcilib/pci.h b/pcilib/pci.h index d176caf..a7b3d50 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -69,7 +69,7 @@ struct pcilib_s { pcilib_register_bank_context_t *bank_ctx[PCILIB_MAX_REGISTER_BANKS]; /**< Contexts for registers banks if required by register protocol */ pcilib_dma_context_t *dma_ctx; /**< DMA context */ pcilib_context_t *event_ctx; /**< Implmentation context */ - + void* locks_handle; /**< adress of the kernel memory use for locks from user space*/ #ifdef PCILIB_FILE_IO int file_io_handle; #endif /* PCILIB_FILE_IO */ diff --git a/pcitool/cli.c b/pcitool/cli.c index 9eeb046..a6224e3 100644 --- a/pcitool/cli.c +++ b/pcitool/cli.c @@ -1,3 +1,4 @@ +#define _XOPEN_SOURCE 700 #define _POSIX_C_SOURCE 200112L #define _BSD_SOURCE @@ -37,6 +38,7 @@ #include "error.h" #include "debug.h" #include "model.h" +#include "locking.h" /* defines */ #define MAX_KBUF 14 @@ -89,7 +91,8 @@ typedef enum { MODE_ALLOC_KMEM, MODE_LIST_KMEM, MODE_READ_KMEM, - MODE_FREE_KMEM + MODE_FREE_KMEM, + MODE_FREE_LOCKS } MODE; typedef enum { @@ -167,7 +170,8 @@ typedef enum { OPT_VERIFY, OPT_WAIT, OPT_MULTIPACKET, - OPT_VERBOSE + OPT_VERBOSE, + OPT_FREE_LOCKS } OPTIONS; static struct option long_options[] = { @@ -219,6 +223,7 @@ static struct option long_options[] = { {"multipacket", no_argument, 0, OPT_MULTIPACKET }, {"wait", no_argument, 0, OPT_WAIT }, {"help", no_argument, 0, OPT_HELP }, + {"free-locks", no_argument, 0, OPT_FREE_LOCKS}, { 0, 0, 0, 0 } }; @@ -272,6 +277,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { " block is specified as: use:block_number\n" " --alloc-kernel-memory <use> - Allocate kernel buffers (DANGEROUS)\n" " --free-kernel-memory <use> - Cleans lost kernel space buffers (DANGEROUS)\n" +" --free-locks - Cleans locks allocated during pcitool program use(dangerous in a concurrential model)\n" " dma - Remove all buffers allocated by DMA subsystem\n" " #number - Remove all buffers with the specified use id\n" "\n" @@ -2570,6 +2576,9 @@ int main(int argc, char **argv) { event = stmp; } break; + case OPT_FREE_LOCKS: + mode=MODE_FREE_LOCKS; + break; case OPT_TRIGGER: if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_TRIGGER))) Usage(argc, argv, "Multiple operations are not supported"); @@ -2949,7 +2958,6 @@ int main(int argc, char **argv) { model_info = pcilib_get_model_description(handle); dma_info = pcilib_get_dma_description(handle); - switch (mode) { case MODE_WRITE: if (((argc - optind) == 1)&&(*argv[optind] == '*')) { @@ -3137,6 +3145,9 @@ int main(int argc, char **argv) { } switch (mode) { + case MODE_FREE_LOCKS: + pcilib_clean_all_locks(handle); + break; case MODE_INFO: Info(handle, model_info); break; diff --git a/protocols/software.c b/protocols/software.c index 5534dc7..5170583 100644 --- a/protocols/software.c +++ b/protocols/software.c @@ -1,38 +1,44 @@ +#define _XOPEN_SOURCE 700 + #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/file.h> - #include "model.h" #include "error.h" #include "kmem.h" #include "pcilib.h" #include "pci.h" +#include "lock.h" typedef struct pcilib_software_register_bank_context_s pcilib_software_register_bank_context_t; +/** + * new context to save all needed informations for software registers + */ struct pcilib_software_register_bank_context_s { - pcilib_register_bank_context_t bank_ctx; + pcilib_register_bank_context_t bank_ctx; /**< the bank context associated with the software registers*/ - pcilib_kmem_handle_t *kmem; - void *addr; + pcilib_kmem_handle_t *kmem; /**< the kernel memory for software registers */ + void *addr; /**< the base adress of the allocated kernel memory*/ }; /** * pcilib_software_registers_close * this function clear the kernel memory space that could have been allocated for software registers + *@param[in] ctx the pcilib_t running * @param[in] bank_ctx the bank context running that we get from the initialisation function */ void pcilib_software_registers_close(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx) { if (((pcilib_software_register_bank_context_t*)bank_ctx)->kmem) - pcilib_free_kernel_memory(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, PCILIB_KMEM_FLAG_REUSE); + pcilib_free_kernel_memory(ctx, ((pcilib_software_register_bank_context_t*)bank_ctx)->kmem, PCILIB_KMEM_FLAG_REUSE); free(bank_ctx); } /** * pcilib_software_registers_open - * this function initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. It the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used + * this function initializes the kernel space memory and stores in it the default values of the registers of the given bank index, if it was not initialized by a concurrent process, and return a bank context containing the adress of this kernel space. If the kernel space memory was already initialized by a concurrent process, then this function just return the bank context with the adress of this kernel space already used. The initialization is protected by the locking mechanisms of lock files. * @param[in] ctx the pcilib_t structure running * @param[in] bank the bank index that will permits to get the bank we want registers from * @param[in] model not used @@ -43,6 +49,7 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc pcilib_software_register_bank_context_t *bank_ctx; pcilib_kmem_handle_t *handle; pcilib_kmem_reuse_state_t reused; + pcilib_lock_t* semId=NULL; const pcilib_register_bank_description_t *bank_desc = ctx->banks + bank; @@ -52,8 +59,12 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc } bank_ctx = calloc(1, sizeof(pcilib_software_register_bank_context_t)); + + /* prtoection against several kernel memory allocation*/ + semId=pcilib_init_lock(ctx,"thisatest2"); + pcilib_lock(semId,MUTEX_LOCK); - handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); + handle = pcilib_alloc_kernel_memory(ctx, PCILIB_KMEM_TYPE_PAGE, 1, PCILIB_KMEM_PAGE_SIZE, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_SOFTWARE_REGISTERS, bank), PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_PERSISTENT); /**< get the kernel memory*/ if (!handle) { pcilib_error("Allocation of kernel memory for software registers has failed"); pcilib_software_registers_close(ctx, (pcilib_register_bank_context_t*)bank_ctx); @@ -75,11 +86,18 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc for (i = 0; ctx->model_info.registers[i].name != NULL; i++) { if ((ctx->model_info.registers[i].bank == ctx->banks[bank].addr)&&(ctx->model_info.registers[i].type == PCILIB_REGISTER_STANDARD)) { - *(pcilib_register_value_t*)(bank_ctx->addr + ctx->model_info.registers[i].addr) = ctx->model_info.registers[i].defvalue; + + /*initialization here*/ + + *(pcilib_register_value_t*)(bank_ctx->addr + ctx->model_info.registers[i].addr) = ctx->model_info.registers[i].defvalue; + + + } } } - + pcilib_unlock(semId); + return (pcilib_register_bank_context_t*)bank_ctx; } @@ -93,11 +111,12 @@ pcilib_register_bank_context_t* pcilib_software_registers_open(pcilib_t *ctx, pc * @return 0 in case of success */ int pcilib_software_registers_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank_ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value){ + if ((addr + sizeof(pcilib_register_value_t)) > bank_ctx->bank->size) { pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); return PCILIB_ERROR_INVALID_ADDRESS; } - + /* the following reading is considered atomic operation, so not protected, may change*/ *value = *(pcilib_register_value_t*)(((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr); return 0; } @@ -116,7 +135,7 @@ int pcilib_software_registers_write(pcilib_t *ctx, pcilib_register_bank_context_ pcilib_error("Trying to access space outside of the define register bank (bank: %s, addr: 0x%lx)", bank_ctx->bank->name, addr); return PCILIB_ERROR_INVALID_ADDRESS; } - + /* the following writing is considered atomic operation, so not protected, may change*/ *(pcilib_register_value_t*)(((pcilib_software_register_bank_context_t*)bank_ctx)->addr + addr) = value; return 0; } |