Home | History | Annotate | Download | only in tf_daemon
      1 /**
      2  * Copyright(c) 2011 Trusted Logic.   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
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *  * Neither the name Trusted Logic nor the names of its
     15  *    contributors may be used to endorse or promote products derived
     16  *    from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #if defined(__ANDROID32__)
     32 #include <stddef.h>
     33 #endif
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 
     38 /*
     39  * When porting to a new OS, insert here the appropriate include files
     40  */
     41 #include <sys/stat.h>
     42 #include <errno.h>
     43 #include <sys/types.h>
     44 #include <fcntl.h>
     45 
     46 #if defined(LINUX) || defined(__ANDROID32__)
     47 #include <unistd.h>
     48 #include <sys/resource.h>
     49 
     50 
     51 #if defined(__ANDROID32__)
     52 /* fdatasync does not exist on Android */
     53 #define fdatasync fsync
     54 #else
     55 /*
     56  * http://linux.die.net/man/2/fsync
     57  * The function fdatasync seems to be absent of the header file
     58  * in some distributions
     59  */
     60 int fdatasync(int fd);
     61 #endif /* __ANDROID32__ */
     62 #include <syslog.h>
     63 #include <sys/types.h>
     64 #include <sys/stat.h>
     65 #include <pthread.h>
     66 #include <semaphore.h>
     67 #define PATH_SEPARATOR '/'
     68 #endif /* LINUX || __ANDROID32__ */
     69 
     70 #ifdef WIN32
     71 #include <windows.h>
     72 #include <io.h>
     73 #define PATH_SEPARATOR '\\'
     74 #endif
     75 
     76 #ifdef __SYMBIAN32__
     77 #include <unistd.h>
     78 #include "os_symbian.h"
     79 #define PATH_SEPARATOR '\\'
     80 #endif
     81 
     82 #include <stdarg.h>
     83 #include <assert.h>
     84 
     85 #include "service_delegation_protocol.h"
     86 
     87 #include "s_version.h"
     88 #include "s_error.h"
     89 #include "tee_client_api.h"
     90 
     91 /* You can define the preprocessor constant SUPPORT_DELEGATION_EXTENSION
     92    if you want to pass extended options in a configuration file (option '-c').
     93    It is up to you to define the format of this configuration file and the
     94    extended option in the source file delegation_client_extension.c. You can
     95    use extended options, e.g., to control the name of each partition file. */
     96 #ifdef SUPPORT_DELEGATION_EXTENSION
     97 #include "delegation_client_extension.h"
     98 #endif
     99 
    100 /*----------------------------------------------------------------------------
    101  * Design notes
    102  * ============
    103  *
    104  * This implementation of the delegation daemon supports the protocol
    105  * specified in the Product Reference Manual ("Built-in Services Protocols Specification")
    106  *
    107  *----------------------------------------------------------------------------*/
    108 
    109 /*----------------------------------------------------------------------------
    110  * Defines and structures
    111  *----------------------------------------------------------------------------*/
    112 #define ECHANGE_BUFFER_INSTRUCTIONS_NB 100
    113 
    114 #define DEFAULT_WORKSPACE_SIZE (128*1024)
    115 
    116 /* A single shared memory block is used to contain the administrative data, the
    117    instruction buffer and the workspace. The size of the instruction buffer is
    118    fixed, but the size of workspace can be configured using the "-workspaceSize"
    119    command-line option. */
    120 typedef struct
    121 {
    122    DELEGATION_ADMINISTRATIVE_DATA sAdministrativeData;
    123    uint32_t                       sInstructions[ECHANGE_BUFFER_INSTRUCTIONS_NB];
    124    uint8_t                        sWorkspace[1/*g_nWorkspaceSize*/];
    125 } DELEGATION_EXCHANGE_BUFFER;
    126 
    127 #define MD_VAR_NOT_USED(variable)  do{(void)(variable);}while(0);
    128 
    129 #define MD_INLINE __inline
    130 
    131 /* ----------------------------------------------
    132    Traces and logs
    133 
    134    On Linux, traces and logs go either to the console (stderr) or to the syslog.
    135    When the daemon is started, the logs go to the console. Once and if the daemon
    136    is detached, the logs go to syslog.
    137 
    138    On other systems, traces and logs go systematically to stderr
    139 
    140    The difference between traces and logs is that traces are compiled out
    141    in release builds whereas logs are visible to the customer.
    142 
    143    -----------------------------------------------*/
    144 #if defined(LINUX) || (defined __ANDROID32__)
    145 
    146 static bool bDetached = false;
    147 
    148 static MD_INLINE void LogError(const char* format, ...)
    149 {
    150    va_list ap;
    151    va_start(ap, format);
    152    if (bDetached)
    153    {
    154       vsyslog(LOG_ERR, format, ap);
    155    }
    156    else
    157    {
    158       fprintf(stderr, "ERROR: ");
    159       vfprintf(stderr, format, ap);
    160       fprintf(stderr, "\n");
    161    }
    162    va_end(ap);
    163 }
    164 
    165 static MD_INLINE void LogWarning(const char* format, ...)
    166 {
    167    va_list ap;
    168    va_start(ap, format);
    169    if (bDetached)
    170    {
    171       vsyslog(LOG_WARNING, format, ap);
    172    }
    173    else
    174    {
    175       fprintf(stderr, "WARNING: ");
    176       vfprintf(stderr, format, ap);
    177       fprintf(stderr, "\n");
    178    }
    179    va_end(ap);
    180 }
    181 static MD_INLINE void LogInfo(const char* format, ...)
    182 {
    183    va_list ap;
    184    va_start(ap, format);
    185    if (bDetached)
    186    {
    187       vsyslog(LOG_INFO, format, ap);
    188    }
    189    else
    190    {
    191       vfprintf(stderr, format, ap);
    192       fprintf(stderr, "\n");
    193    }
    194    va_end(ap);
    195 }
    196 
    197 static MD_INLINE void TRACE_ERROR(const char* format, ...)
    198 {
    199 #ifndef NDEBUG
    200    va_list ap;
    201    va_start(ap, format);
    202    if (bDetached)
    203    {
    204       vsyslog(LOG_ERR, format, ap);
    205    }
    206    else
    207    {
    208       fprintf(stderr, "TRACE: ERROR: ");
    209       vfprintf(stderr, format, ap);
    210       fprintf(stderr, "\n");
    211    }
    212    va_end(ap);
    213 #else
    214    MD_VAR_NOT_USED(format);
    215 #endif /* NDEBUG */
    216 }
    217 
    218 static MD_INLINE void TRACE_WARNING(const char* format, ...)
    219 {
    220 #ifndef NDEBUG
    221    va_list ap;
    222    va_start(ap, format);
    223    if (bDetached)
    224    {
    225       vsyslog(LOG_WARNING, format, ap);
    226    }
    227    else
    228    {
    229       fprintf(stderr, "TRACE: WARNING: ");
    230       vfprintf(stderr, format, ap);
    231       fprintf(stderr, "\n");
    232    }
    233    va_end(ap);
    234 #else
    235    MD_VAR_NOT_USED(format);
    236 #endif /* NDEBUG */
    237 }
    238 
    239 static MD_INLINE void TRACE_INFO(const char* format, ...)
    240 {
    241 #ifndef NDEBUG
    242    va_list ap;
    243    va_start(ap, format);
    244    if (bDetached)
    245    {
    246       vsyslog(LOG_DEBUG, format, ap);
    247    }
    248    else
    249    {
    250       fprintf(stderr, "TRACE: ");
    251       vfprintf(stderr, format, ap);
    252       fprintf(stderr, "\n");
    253    }
    254    va_end(ap);
    255 #else
    256    MD_VAR_NOT_USED(format);
    257 #endif /* NDEBUG */
    258 }
    259 #elif defined __SYMBIAN32__
    260 /* defined in os_symbian.h */
    261 
    262 #elif defined NO_LOG_NO_TRACE
    263 static MD_INLINE void LogError(const char* format, ...)
    264 {
    265    MD_VAR_NOT_USED(format);
    266 }
    267 static MD_INLINE void LogWarning(const char* format, ...)
    268 {
    269    MD_VAR_NOT_USED(format);
    270 }
    271 static MD_INLINE void LogInfo(const char* format, ...)
    272 {
    273    MD_VAR_NOT_USED(format);
    274 }
    275 
    276 static MD_INLINE void TRACE_ERROR(const char* format, ...)
    277 {
    278    MD_VAR_NOT_USED(format);
    279 }
    280 
    281 static MD_INLINE void TRACE_WARNING(const char* format, ...)
    282 {
    283    MD_VAR_NOT_USED(format);
    284 }
    285 
    286 static MD_INLINE void TRACE_INFO(const char* format, ...)
    287 {
    288    MD_VAR_NOT_USED(format);
    289 }
    290 
    291 #else
    292 /* !defined(LINUX) || !defined(__ANDROID32__) */
    293 
    294 static MD_INLINE void LogError(const char* format, ...)
    295 {
    296    va_list ap;
    297    va_start(ap, format);
    298    fprintf(stderr, "ERROR: ");
    299    vfprintf(stderr, format, ap);
    300    fprintf(stderr, "\n");
    301    va_end(ap);
    302 }
    303 static MD_INLINE void LogWarning(const char* format, ...)
    304 {
    305    va_list ap;
    306    va_start(ap, format);
    307    fprintf(stderr, "WARNING: ");
    308    vfprintf(stderr, format, ap);
    309    fprintf(stderr, "\n");
    310    va_end(ap);
    311 }
    312 static MD_INLINE void LogInfo(const char* format, ...)
    313 {
    314    va_list ap;
    315    va_start(ap, format);
    316    vfprintf(stderr, format, ap);
    317    fprintf(stderr, "\n");
    318    va_end(ap);
    319 }
    320 
    321 static MD_INLINE void TRACE_ERROR(const char* format, ...)
    322 {
    323 #ifndef NDEBUG
    324    va_list ap;
    325    va_start(ap, format);
    326    fprintf(stderr, "TRACE: ERROR: ");
    327    vfprintf(stderr, format, ap);
    328    fprintf(stderr, "\n");
    329    va_end(ap);
    330 #else
    331    MD_VAR_NOT_USED(format);
    332 #endif /* NDEBUG */
    333 }
    334 
    335 static MD_INLINE void TRACE_WARNING(const char* format, ...)
    336 {
    337 #ifndef NDEBUG
    338    va_list ap;
    339    va_start(ap, format);
    340    fprintf(stderr, "TRACE: WARNING: ");
    341    vfprintf(stderr, format, ap);
    342    fprintf(stderr, "\n");
    343    va_end(ap);
    344 #else
    345    MD_VAR_NOT_USED(format);
    346 #endif /* NDEBUG */
    347 }
    348 
    349 static MD_INLINE void TRACE_INFO(const char* format, ...)
    350 {
    351 #ifndef NDEBUG
    352    va_list ap;
    353    va_start(ap, format);
    354    fprintf(stderr, "TRACE: ");
    355    vfprintf(stderr, format, ap);
    356    fprintf(stderr, "\n");
    357    va_end(ap);
    358 #else
    359    MD_VAR_NOT_USED(format);
    360 #endif /* NDEBUG */
    361 }
    362 #endif /* defined(LINUX) || defined(__ANDROID32__) */
    363 
    364 /*----------------------------------------------------------------------------
    365  * Globals
    366  *----------------------------------------------------------------------------*/
    367 /* The sector size */
    368 static uint32_t g_nSectorSize;
    369 
    370 /* The workspace size */
    371 static uint32_t g_nWorkspaceSize = DEFAULT_WORKSPACE_SIZE;
    372 
    373 /* UUID of the delegation service */
    374 static const TEEC_UUID g_sServiceId = SERVICE_DELEGATION_UUID;
    375 
    376 /* pWorkspaceBuffer points to the workspace buffer shared with the secure
    377    world to transfer the sectors in the READ and WRITE instructions  */
    378 static uint8_t* g_pWorkspaceBuffer;
    379 static DELEGATION_EXCHANGE_BUFFER * g_pExchangeBuffer;
    380 TEEC_SharedMemory sExchangeSharedMem;
    381 /*
    382    The absolute path name for each of the 16 possible partitions.
    383  */
    384 static char* g_pPartitionNames[16];
    385 
    386 /* The file context for each of the 16 possible partitions. An entry
    387    in this array is NULL if the corresponding partition is currently not opened
    388  */
    389 static FILE* g_pPartitionFiles[16];
    390 
    391 /*----------------------------------------------------------------------------
    392  * Utilities functions
    393  *----------------------------------------------------------------------------*/
    394 static void printUsage(void)
    395 {
    396    LogInfo("usage : tf_daemon [options]");
    397    LogInfo("where [options] are:");
    398    LogInfo("-h --help  Display help.");
    399 #ifdef SUPPORT_DELEGATION_EXTENSION
    400    LogInfo("-c <conf>  Configuration file path.");
    401 #else
    402    /* If the compilation parameter SUPPORT_DELEGATION_EXTENSION is not set, each
    403       partition is stored as a file within the base dir */
    404    LogInfo("-storageDir <baseDir>  Set the directory where the data will be stored; this directory");
    405    LogInfo("           must be writable and executable (this parameter is mandatory)");
    406 #endif
    407    LogInfo("-d         Turns on debug mode.  If not specified, the daemon will fork itself");
    408    LogInfo("           and get detached from the console.");
    409 #ifndef SUPPORT_DELEGATION_EXTENSION
    410    LogInfo("-workspaceSize <integer>  Set the size in bytes of the workspace. Must be greater or equal to 8 sectors.");
    411    LogInfo("           (default is 128KB)");
    412 #endif
    413 }
    414 
    415 static TEEC_Result errno2serror(void)
    416 {
    417    switch (errno)
    418    {
    419    case EINVAL:
    420       return S_ERROR_BAD_PARAMETERS;
    421    case EMFILE:
    422       return S_ERROR_NO_MORE_HANDLES;
    423    case ENOENT:
    424       return S_ERROR_ITEM_NOT_FOUND;
    425    case EEXIST:
    426       return S_ERROR_ITEM_EXISTS;
    427    case ENOSPC:
    428       return S_ERROR_STORAGE_NO_SPACE;
    429    case ENOMEM:
    430       return S_ERROR_OUT_OF_MEMORY;
    431    case EBADF:
    432    case EACCES:
    433    default:
    434       return S_ERROR_STORAGE_UNREACHABLE;
    435    }
    436 }
    437 
    438 /*
    439  * Check if the directory in parameter exists with Read/Write access
    440  * Return 0 in case of success and 1 otherwise.
    441  */
    442 int static_checkStorageDirAndAccessRights(char * directoryName)
    443 {
    444 #ifdef __SYMBIAN32__
    445    /* it looks like stat is not working properly on Symbian
    446       Create and remove dummy file to check access rights */
    447    FILE *stream;
    448    char *checkAccess = NULL;
    449 
    450    if (directoryName == NULL)
    451    {
    452       LogError("Directory Name is NULL");
    453       return 1;
    454    }
    455 
    456    checkAccess = malloc(strlen(directoryName)+1/* \ */ +1 /* a */ + 1 /* 0 */);
    457    if (!checkAccess)
    458    {
    459       LogError("storageDir '%s' allocation error", directoryName);
    460       return 1;
    461    }
    462    sprintf(checkAccess,"%s\\a",directoryName);
    463    stream = fopen(checkAccess, "w+b");
    464    if (!stream)
    465    {
    466       LogError("storageDir '%s' is incorrect or cannot be reached", directoryName);
    467       return 1;
    468    }
    469    fclose(stream);
    470    unlink(checkAccess);
    471 #else
    472    /* Non-Symbian OS: use stat */
    473    struct stat buf;
    474    int result = 0;
    475 
    476    if (directoryName == NULL)
    477    {
    478       LogError("Directory Name is NULL");
    479       return 1;
    480    }
    481 
    482    result = stat(directoryName, &buf);
    483    if (result == 0)
    484    {
    485       /* Storage dir exists. Check access rights */
    486 #if defined(LINUX) || (defined __ANDROID32__)
    487       if ((buf.st_mode & (S_IXUSR | S_IWUSR)) != (S_IXUSR | S_IWUSR))
    488       {
    489          LogError("storageDir '%s' does not have read-write access", directoryName);
    490          return 1;
    491       }
    492 #endif
    493    }
    494    else if (errno == ENOENT)
    495    {
    496       LogError("storageDir '%s' does not exist", directoryName);
    497       return 1;
    498    }
    499    else
    500    {
    501       /* Another error */
    502       LogError("storageDir '%s' is incorrect or cannot be reached", directoryName);
    503       return 1;
    504    }
    505 #endif
    506    return 0;
    507 }
    508 
    509 
    510 
    511 /*----------------------------------------------------------------------------
    512  * Instructions
    513  *----------------------------------------------------------------------------*/
    514 
    515 /**
    516  * This function executes the DESTROY_PARTITION instruction
    517  *
    518  * @param nPartitionID: the partition identifier
    519  **/
    520 static TEEC_Result partitionDestroy(uint32_t nPartitionID)
    521 {
    522    TEEC_Result  nError = S_SUCCESS;
    523 
    524    if (g_pPartitionFiles[nPartitionID] != NULL)
    525    {
    526       /* The partition must not be currently opened */
    527       LogError("g_pPartitionFiles not NULL");
    528       return S_ERROR_BAD_STATE;
    529    }
    530 
    531    /* Try to erase the file */
    532 #if defined(LINUX) || (defined __ANDROID32__) || defined (__SYMBIAN32__)
    533    if (unlink(g_pPartitionNames[nPartitionID]) != 0)
    534 #endif
    535 #ifdef WIN32
    536    if (_unlink(g_pPartitionNames[nPartitionID]) != 0)
    537 #endif
    538    {
    539       /* File in use or OS didn't allow the operation */
    540       nError = errno2serror();
    541    }
    542 
    543    return nError;
    544 }
    545 
    546 /**
    547  * This function executes the CREATE_PARTITION instruction. When successful,
    548  * it fills the g_pPartitionFiles[nPartitionID] slot.
    549  *
    550  * @param nPartitionID: the partition identifier
    551  **/
    552 static TEEC_Result partitionCreate(uint32_t nPartitionID)
    553 {
    554    uint32_t nError = S_SUCCESS;
    555 
    556    if (g_pPartitionFiles[nPartitionID] != NULL)
    557    {
    558       /* The partition is already opened */
    559       LogError("g_pPartitionFiles not NULL");
    560       return S_ERROR_BAD_STATE;
    561    }
    562 
    563    /* Create the file unconditionnally */
    564    LogInfo("Create storage file \"%s\"", g_pPartitionNames[nPartitionID]);
    565    g_pPartitionFiles[nPartitionID] = fopen(g_pPartitionNames[nPartitionID], "w+b");
    566 
    567    if (g_pPartitionFiles[nPartitionID] == NULL)
    568    {
    569       LogError("Cannot create storage file \"%s\"", g_pPartitionNames[nPartitionID]);
    570       nError = errno2serror();
    571       return nError;
    572    }
    573 
    574    return nError;
    575 }
    576 
    577 /**
    578  * This function executes the OPEN_PARTITION instruction. When successful,
    579  * it fills the g_pPartitionFiles[nPartitionID] slot and writes the partition
    580  * size in hResultEncoder
    581  *
    582  * @param nPartitionID: the partition identifier
    583  * @param pnPartitionSize: filled with the number of sectors in the partition
    584  **/
    585 static TEEC_Result partitionOpen(uint32_t nPartitionID, uint32_t* pnPartitionSize)
    586 {
    587    uint32_t nError = S_SUCCESS;
    588 
    589    if (g_pPartitionFiles[nPartitionID] != NULL)
    590    {
    591       /* No partition must be currently opened in the session */
    592       LogError("g_pPartitionFiles not NULL");
    593       return S_ERROR_BAD_STATE;
    594    }
    595 
    596    /* Open the file */
    597    g_pPartitionFiles[nPartitionID] = fopen(g_pPartitionNames[nPartitionID], "r+b");
    598    if (g_pPartitionFiles[nPartitionID] == NULL)
    599    {
    600       if (errno == ENOENT)
    601       {
    602          /* File does not exist */
    603          LogError("Storage file \"%s\" does not exist", g_pPartitionNames[nPartitionID]);
    604          nError = S_ERROR_ITEM_NOT_FOUND;
    605          return nError;
    606       }
    607       else
    608       {
    609          LogError("cannot open storage file \"%s\"", g_pPartitionNames[nPartitionID]);
    610          nError = errno2serror();
    611          return nError;
    612       }
    613    }
    614    /* Determine the current number of sectors */
    615    fseek(g_pPartitionFiles[nPartitionID], 0L, SEEK_END);
    616    *pnPartitionSize = ftell(g_pPartitionFiles[nPartitionID]) / g_nSectorSize;
    617 
    618    LogInfo("storage file \"%s\" successfully opened (size = %d KB (%d bytes))",
    619       g_pPartitionNames[nPartitionID],
    620       ((*pnPartitionSize) * g_nSectorSize) / 1024,
    621       ((*pnPartitionSize) * g_nSectorSize));
    622 
    623    return nError;
    624 }
    625 
    626 
    627 /**
    628  * This function executes the CLOSE_PARTITION instruction.
    629  * It closes the partition file.
    630  *
    631  * @param nPartitionID: the partition identifier
    632  **/
    633 static TEEC_Result partitionClose(uint32_t nPartitionID)
    634 {
    635    if (g_pPartitionFiles[nPartitionID] == NULL)
    636    {
    637       /* The partition is currently not opened */
    638       return S_ERROR_BAD_STATE;
    639    }
    640    fclose(g_pPartitionFiles[nPartitionID]);
    641    g_pPartitionFiles[nPartitionID] = NULL;
    642    return S_SUCCESS;
    643 }
    644 
    645 /**
    646  * This function executes the READ instruction.
    647  *
    648  * @param nPartitionID: the partition identifier
    649  * @param nSectorIndex: the index of the sector to read
    650  * @param nWorkspaceOffset: the offset in the workspace where the sector must be written
    651  **/
    652 static TEEC_Result partitionRead(uint32_t nPartitionID, uint32_t nSectorIndex, uint32_t nWorkspaceOffset)
    653 {
    654    FILE* pFile;
    655 
    656    TRACE_INFO(">Partition %1X: read sector 0x%08X into workspace at offset 0x%08X",
    657       nPartitionID, nSectorIndex, nWorkspaceOffset);
    658 
    659    pFile = g_pPartitionFiles[nPartitionID];
    660 
    661    if (pFile == NULL)
    662    {
    663       /* The partition is not opened */
    664       return S_ERROR_BAD_STATE;
    665    }
    666 
    667    if (fseek(pFile, nSectorIndex*g_nSectorSize, SEEK_SET) != 0)
    668    {
    669       LogError("fseek error: %s", strerror(errno));
    670       return errno2serror();
    671    }
    672 
    673    if (fread(g_pWorkspaceBuffer + nWorkspaceOffset,
    674              g_nSectorSize, 1,
    675              pFile) != 1)
    676    {
    677       if (feof(pFile))
    678       {
    679          LogError("fread error: End-Of-File detected");
    680          return S_ERROR_ITEM_NOT_FOUND;
    681       }
    682       LogError("fread error: %s", strerror(errno));
    683       return errno2serror();
    684    }
    685 
    686    return S_SUCCESS;
    687 }
    688 
    689 /**
    690  * This function executes the WRITE instruction.
    691  *
    692  * @param nPartitionID: the partition identifier
    693  * @param nSectorIndex: the index of the sector to read
    694  * @param nWorkspaceOffset: the offset in the workspace where the sector must be read
    695  **/
    696 static TEEC_Result partitionWrite(uint32_t nPartitionID, uint32_t nSectorIndex, uint32_t nWorkspaceOffset)
    697 {
    698    FILE* pFile;
    699 
    700    TRACE_INFO(">Partition %1X: write sector 0x%X from workspace at offset 0x%X",
    701       nPartitionID, nSectorIndex, nWorkspaceOffset);
    702 
    703    pFile = g_pPartitionFiles[nPartitionID];
    704 
    705    if (pFile == NULL)
    706    {
    707       /* The partition is not opened */
    708       return S_ERROR_BAD_STATE;
    709    }
    710 
    711    if (fseek(pFile, nSectorIndex*g_nSectorSize, SEEK_SET) != 0)
    712    {
    713       LogError("fseek error: %s", strerror(errno));
    714       return errno2serror();
    715    }
    716 
    717    if (fwrite(g_pWorkspaceBuffer + nWorkspaceOffset,
    718               g_nSectorSize, 1,
    719               pFile) != 1)
    720    {
    721       LogError("fread error: %s", strerror(errno));
    722       return errno2serror();
    723    }
    724    return S_SUCCESS;
    725 }
    726 
    727 
    728 /**
    729  * This function executes the SET_SIZE instruction.
    730  *
    731  * @param nPartitionID: the partition identifier
    732  * @param nNewSectorCount: the new sector count
    733  **/
    734 static TEEC_Result partitionSetSize(uint32_t nPartitionID, uint32_t nNewSectorCount)
    735 {
    736    FILE* pFile;
    737    uint32_t nCurrentSectorCount;
    738 
    739    pFile = g_pPartitionFiles[nPartitionID];
    740 
    741    if (pFile==NULL)
    742    {
    743       /* The partition is not opened */
    744       return S_ERROR_BAD_STATE;
    745    }
    746 
    747    /* Determine the current size of the partition */
    748    if (fseek(pFile, 0, SEEK_END) != 0)
    749    {
    750       LogError("fseek error: %s", strerror(errno));
    751       return errno2serror();
    752    }
    753    nCurrentSectorCount = ftell(pFile) / g_nSectorSize;
    754 
    755    if (nNewSectorCount > nCurrentSectorCount)
    756    {
    757       uint32_t nAddedBytesCount;
    758       /* Enlarge the partition file. Make sure we actually write
    759          some non-zero data into the new sectors. Otherwise, some file-system
    760          might not really reserve the storage space but use a
    761          sparse representation. In this case, a subsequent write instruction
    762          could fail due to out-of-space, which we want to avoid. */
    763       nAddedBytesCount = (nNewSectorCount-nCurrentSectorCount)*g_nSectorSize;
    764       while (nAddedBytesCount)
    765       {
    766          if (fputc(0xA5, pFile)!=0xA5)
    767          {
    768             return errno2serror();
    769          }
    770          nAddedBytesCount--;
    771       }
    772    }
    773    else if (nNewSectorCount < nCurrentSectorCount)
    774    {
    775       int result = 0;
    776       /* Truncate the partition file */
    777 #if defined(LINUX) || (defined __ANDROID32__)
    778       result = ftruncate(fileno(pFile),nNewSectorCount * g_nSectorSize);
    779 #endif
    780 #if defined (__SYMBIAN32__)
    781 	  LogError("No truncate available in Symbian C API");
    782 #endif
    783 #ifdef WIN32
    784       result = _chsize(_fileno(pFile),nNewSectorCount * g_nSectorSize);
    785 #endif
    786       if (result)
    787       {
    788          return errno2serror();
    789       }
    790    }
    791    return S_SUCCESS;
    792 }
    793 
    794 /**
    795  * This function executes the SYNC instruction.
    796  *
    797  * @param pPartitionID: the partition identifier
    798  **/
    799 static TEEC_Result partitionSync(uint32_t nPartitionID)
    800 {
    801    TEEC_Result nError = S_SUCCESS;
    802    int result;
    803 
    804    FILE* pFile = g_pPartitionFiles[nPartitionID];
    805 
    806    if (pFile == NULL)
    807    {
    808       /* The partition is not currently opened */
    809       return S_ERROR_BAD_STATE;
    810    }
    811 
    812    /* First make sure that the data in the stdio buffers
    813       is flushed to the file descriptor */
    814    result=fflush(pFile);
    815    if (result)
    816    {
    817       nError=errno2serror();
    818       goto end;
    819    }
    820    /* Then synchronize the file descriptor with the file-system */
    821 
    822 #if defined(LINUX) || (defined __ANDROID32__)
    823    result=fdatasync(fileno(pFile));
    824 #endif
    825 #if defined (__SYMBIAN32__)
    826    result=fsync(fileno(pFile));
    827 #endif
    828 #ifdef WIN32
    829    result=_commit(_fileno(pFile));
    830 #endif
    831    if (result)
    832    {
    833       nError=errno2serror();
    834    }
    835 
    836 end:
    837    return nError;
    838 }
    839 
    840 /**
    841  * This function executes the NOTIFY instruction.
    842  *
    843  * @param pMessage the message string
    844  * @param nMessageType the type of messages
    845  **/
    846 static void notify(const wchar_t* pMessage, uint32_t nMessageType)
    847 {
    848    switch (nMessageType)
    849    {
    850    case DELEGATION_NOTIFY_TYPE_ERROR:
    851       LogError("%ls", pMessage);
    852       break;
    853    case DELEGATION_NOTIFY_TYPE_WARNING:
    854       LogWarning("%ls", pMessage);
    855       break;
    856    case DELEGATION_NOTIFY_TYPE_DEBUG:
    857       LogInfo("DEBUG: %ls", pMessage);
    858       break;
    859    case DELEGATION_NOTIFY_TYPE_INFO:
    860    default:
    861       LogInfo("%ls", pMessage);
    862       break;
    863    }
    864 }
    865 
    866 /*----------------------------------------------------------------------------
    867  * Session main function
    868  *----------------------------------------------------------------------------*/
    869 
    870 /*
    871  * This function runs a session opened on the delegation service. It fetches
    872  * instructions and execute them in a loop. It never returns, but may call
    873  * exit when instructed to shutdown by the service
    874  */
    875 static int runSession(TEEC_Context* pContext, TEEC_Session* pSession, TEEC_Operation* pOperation)
    876 {
    877    memset(&g_pExchangeBuffer->sAdministrativeData, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData));
    878 
    879    while (true)
    880    {
    881       S_RESULT    nError;
    882       TEEC_Result                      nTeeError;
    883       uint32_t                         nInstructionsIndex;
    884       uint32_t                         nInstructionsBufferSize = sizeof(g_pExchangeBuffer->sInstructions);
    885 
    886       pOperation->paramTypes = TEEC_PARAM_TYPES(
    887          TEEC_MEMREF_PARTIAL_INPUT,
    888          TEEC_MEMREF_PARTIAL_OUTPUT,
    889          TEEC_MEMREF_PARTIAL_INOUT,
    890          TEEC_NONE);
    891       pOperation->params[0].memref.parent = &sExchangeSharedMem;
    892       pOperation->params[0].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sAdministrativeData);
    893       pOperation->params[0].memref.size   = sizeof(g_pExchangeBuffer->sAdministrativeData);
    894 
    895       pOperation->params[1].memref.parent = &sExchangeSharedMem;
    896       pOperation->params[1].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sInstructions);
    897       pOperation->params[1].memref.size   = sizeof(g_pExchangeBuffer->sInstructions);
    898 
    899       pOperation->params[2].memref.parent = &sExchangeSharedMem;
    900       pOperation->params[2].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sWorkspace);
    901       pOperation->params[2].memref.size   = g_nWorkspaceSize;
    902 
    903       nTeeError = TEEC_InvokeCommand(pSession,
    904                                   SERVICE_DELEGATION_GET_INSTRUCTIONS,   /* commandID */
    905                                   pOperation,     /* IN OUT operation */
    906                                   NULL             /* OUT errorOrigin, optional */
    907                                  );
    908 
    909       if (nTeeError != TEEC_SUCCESS)
    910       {
    911          LogError("TEEC_InvokeCommand error: 0x%08X", nTeeError);
    912          LogError("Daemon exits");
    913          exit(2);
    914       }
    915 
    916       if (pOperation->params[1].tmpref.size >  nInstructionsBufferSize)
    917       {
    918          /* Should not happen, probably an error from the service */
    919          pOperation->params[1].tmpref.size = 0;
    920       }
    921 
    922       /* Reset the operation results */
    923       nError = TEEC_SUCCESS;
    924       g_pExchangeBuffer->sAdministrativeData.nSyncExecuted = 0;
    925       memset(g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates));
    926       memset(g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes));
    927 
    928       /* Execute the instructions */
    929       nInstructionsIndex = 0;
    930       nInstructionsBufferSize = pOperation->params[1].tmpref.size;
    931       while (true)
    932       {
    933          DELEGATION_INSTRUCTION * pInstruction;
    934          uint32_t nInstructionID;
    935          pInstruction = (DELEGATION_INSTRUCTION *)(&g_pExchangeBuffer->sInstructions[nInstructionsIndex/4]);
    936          if (nInstructionsIndex + 4 <= nInstructionsBufferSize)
    937          {
    938             nInstructionID = pInstruction->sGeneric.nInstructionID;
    939             nInstructionsIndex+=4;
    940          }
    941          else
    942          {
    943             goto instruction_parse_end;
    944          }
    945          if ((nInstructionID & 0x0F) == 0)
    946          {
    947             /* Partition-independent instruction */
    948             switch (nInstructionID)
    949             {
    950             case DELEGATION_INSTRUCTION_SHUTDOWN:
    951                {
    952                   exit(0);
    953                   /* The implementation of the TF Client API will automatically
    954                      destroy the context and release any associated resource */
    955                }
    956             case DELEGATION_INSTRUCTION_NOTIFY:
    957                {
    958                   /* Parse the instruction parameters */
    959                   wchar_t  pMessage[100];
    960                   uint32_t nMessageType;
    961                   uint32_t nMessageSize;
    962                   memset(pMessage, 0, 100*sizeof(wchar_t));
    963 
    964                   if (nInstructionsIndex + 8 <= nInstructionsBufferSize)
    965                   {
    966                      nMessageType = pInstruction->sNotify.nMessageType;
    967                      nMessageSize = pInstruction->sNotify.nMessageSize;
    968                      nInstructionsIndex+=8;
    969                   }
    970                   else
    971                   {
    972                      goto instruction_parse_end;
    973                   }
    974                   if (nMessageSize > (99)*sizeof(wchar_t))
    975                   {
    976                      /* How to handle the error correctly in this case ? */
    977                      goto instruction_parse_end;
    978                   }
    979                   if (nInstructionsIndex + nMessageSize <= nInstructionsBufferSize)
    980                   {
    981                      memcpy(pMessage, &pInstruction->sNotify.nMessage[0], nMessageSize);
    982                      nInstructionsIndex+=nMessageSize;
    983                   }
    984                   else
    985                   {
    986                      goto instruction_parse_end;
    987                   }
    988                   /* Align the pInstructionsIndex on 4 bytes */
    989                   nInstructionsIndex = (nInstructionsIndex+3)&~3;
    990                   notify(pMessage, nMessageType);
    991                   break;
    992                }
    993             default:
    994                LogError("Unknown instruction identifier: %02X", nInstructionID);
    995                nError = S_ERROR_BAD_PARAMETERS;
    996                break;
    997             }
    998          }
    999          else
   1000          {
   1001             /* Partition-specific instruction */
   1002             uint32_t nPartitionID = (nInstructionID & 0xF0) >> 4;
   1003             if (g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates[nPartitionID] == S_SUCCESS)
   1004             {
   1005                /* Execute the instruction only if there is currently no
   1006                   error on the partition */
   1007                switch (nInstructionID & 0x0F)
   1008                {
   1009                case DELEGATION_INSTRUCTION_PARTITION_CREATE:
   1010                   nError = partitionCreate(nPartitionID);
   1011                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
   1012                   break;
   1013                case DELEGATION_INSTRUCTION_PARTITION_OPEN:
   1014                   {
   1015                      uint32_t nPartitionSize = 0;
   1016                      nError = partitionOpen(nPartitionID, &nPartitionSize);
   1017                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d pSize=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nPartitionSize, nError);
   1018                      if (nError == S_SUCCESS)
   1019                      {
   1020                         g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes[nPartitionID] = nPartitionSize;
   1021                      }
   1022                      break;
   1023                   }
   1024                case DELEGATION_INSTRUCTION_PARTITION_READ:
   1025                   {
   1026                      /* Parse parameters */
   1027                      uint32_t nSectorID;
   1028                      uint32_t nWorkspaceOffset;
   1029                      if (nInstructionsIndex + 8 <= nInstructionsBufferSize)
   1030                      {
   1031                         nSectorID        = pInstruction->sReadWrite.nSectorID;
   1032                         nWorkspaceOffset = pInstruction->sReadWrite.nWorkspaceOffset;
   1033                         nInstructionsIndex+=8;
   1034                      }
   1035                      else
   1036                      {
   1037                         goto instruction_parse_end;
   1038                      }
   1039                      nError = partitionRead(nPartitionID, nSectorID, nWorkspaceOffset);
   1040                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d sid=%d woff=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nSectorID, nWorkspaceOffset, nError);
   1041                      break;
   1042                   }
   1043                case DELEGATION_INSTRUCTION_PARTITION_WRITE:
   1044                   {
   1045                      /* Parse parameters */
   1046                      uint32_t nSectorID;
   1047                      uint32_t nWorkspaceOffset;
   1048                      if (nInstructionsIndex + 8 <= nInstructionsBufferSize)
   1049                      {
   1050                         nSectorID        = pInstruction->sReadWrite.nSectorID;
   1051                         nWorkspaceOffset = pInstruction->sReadWrite.nWorkspaceOffset;
   1052                         nInstructionsIndex+=8;
   1053                      }
   1054                      else
   1055                      {
   1056                         goto instruction_parse_end;
   1057                      }
   1058                      nError = partitionWrite(nPartitionID, nSectorID, nWorkspaceOffset);
   1059                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d sid=%d woff=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nSectorID, nWorkspaceOffset, nError);
   1060                      break;
   1061                   }
   1062                case DELEGATION_INSTRUCTION_PARTITION_SYNC:
   1063                   nError = partitionSync(nPartitionID);
   1064                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
   1065                   if (nError == S_SUCCESS)
   1066                   {
   1067                      g_pExchangeBuffer->sAdministrativeData.nSyncExecuted++;
   1068                   }
   1069                   break;
   1070                case DELEGATION_INSTRUCTION_PARTITION_SET_SIZE:
   1071                   {
   1072                      uint32_t nNewSize;
   1073                      if (nInstructionsIndex + 4 <= nInstructionsBufferSize)
   1074                      {
   1075                         nNewSize = pInstruction->sSetSize.nNewSize;
   1076                         nInstructionsIndex+=4;
   1077                      }
   1078                      else
   1079                      {
   1080                         goto instruction_parse_end;
   1081                      }
   1082                      nError = partitionSetSize(nPartitionID, nNewSize);
   1083                      TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d nNewSize=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nNewSize, nError);
   1084                      break;
   1085                   }
   1086                case DELEGATION_INSTRUCTION_PARTITION_CLOSE:
   1087                   nError = partitionClose(nPartitionID);
   1088                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
   1089                   break;
   1090                case DELEGATION_INSTRUCTION_PARTITION_DESTROY:
   1091                   nError = partitionDestroy(nPartitionID);
   1092                   TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError);
   1093                   break;
   1094                }
   1095                g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates[nPartitionID] = nError;
   1096             }
   1097          }
   1098       }
   1099 instruction_parse_end:
   1100       memset(pOperation, 0, sizeof(TEEC_Operation));
   1101    }
   1102 }
   1103 
   1104 /**
   1105  * This function opens a new session to the delegation service.
   1106  **/
   1107 static int createSession(TEEC_Context* pContext, TEEC_Session* pSession, TEEC_Operation* pOperation)
   1108 {
   1109    TEEC_Result nError;
   1110    uint32_t nExchangeBufferSize;
   1111 
   1112    memset(pOperation, 0, sizeof(TEEC_Operation));
   1113    pOperation->paramTypes = TEEC_PARAM_TYPES(
   1114       TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE);
   1115    nError = TEEC_OpenSession(pContext,
   1116                              pSession,                /* OUT session */
   1117                              &g_sServiceId,           /* destination UUID */
   1118                              TEEC_LOGIN_PRIVILEGED,   /* connectionMethod */
   1119                              NULL,                    /* connectionData */
   1120                              pOperation,              /* IN OUT operation */
   1121                              NULL                     /* OUT errorOrigin, optional */
   1122                              );
   1123    if (nError != TEEC_SUCCESS)
   1124    {
   1125       LogError("Error on TEEC_OpenSession : 0x%x", nError);
   1126       exit(2);
   1127    }
   1128    /* Read sector size */
   1129    g_nSectorSize = pOperation->params[0].value.a;
   1130    LogInfo("Sector Size: %d bytes", g_nSectorSize);
   1131 
   1132    /* Check sector size */
   1133    if (!(g_nSectorSize == 512 || g_nSectorSize == 1024 || g_nSectorSize == 2048 || g_nSectorSize == 4096))
   1134    {
   1135       LogError("Incorrect sector size: terminating...");
   1136       exit(2);
   1137    }
   1138 
   1139    /* Check workspace size */
   1140    if (g_nWorkspaceSize < 8 * g_nSectorSize)
   1141    {
   1142       g_nWorkspaceSize = 8 * g_nSectorSize;
   1143       LogWarning("Workspace size too small, automatically set to %d bytes", g_nWorkspaceSize);
   1144    }
   1145    /* Compute the size of the exchange buffer */
   1146    nExchangeBufferSize = sizeof(DELEGATION_EXCHANGE_BUFFER)-1+g_nWorkspaceSize;
   1147    g_pExchangeBuffer  = (DELEGATION_EXCHANGE_BUFFER*)malloc(nExchangeBufferSize);
   1148 	 if (g_pExchangeBuffer == NULL)
   1149    {
   1150       LogError("Cannot allocate exchange buffer of %d bytes", nExchangeBufferSize);
   1151       LogError("Now exiting...");
   1152       exit(2);
   1153    }
   1154    g_pWorkspaceBuffer = (uint8_t*)g_pExchangeBuffer->sWorkspace;
   1155    memset(g_pExchangeBuffer, 0x00, nExchangeBufferSize);
   1156    memset(g_pPartitionFiles,0,16*sizeof(FILE*));
   1157 
   1158    /* Register the exchange buffer as a shared memory block */
   1159    sExchangeSharedMem.buffer = g_pExchangeBuffer;
   1160    sExchangeSharedMem.size   = nExchangeBufferSize;
   1161    sExchangeSharedMem.flags  = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT;
   1162    nError = TEEC_RegisterSharedMemory(pContext, &sExchangeSharedMem);
   1163    if (nError != TEEC_SUCCESS)
   1164    {
   1165       LogError("Error on TEEC_RegisterSharedMemory : 0x%x", nError);
   1166       free(g_pExchangeBuffer);
   1167       exit(2);
   1168    }
   1169    LogInfo("Daemon now connected");
   1170    return 0;
   1171 }
   1172 
   1173 
   1174 /*----------------------------------------------------------------------------
   1175  * Main
   1176  *----------------------------------------------------------------------------*/
   1177 
   1178 #ifdef INCLUDE_CLIENT_DELEGATION
   1179 int delegation_main(int argc, char* argv[])
   1180 #else
   1181 int main(int argc, char* argv[])
   1182 #endif
   1183 {
   1184    TEEC_Result    nError;
   1185    TEEC_Context   sContext;
   1186    TEEC_Session   sSession;
   1187    TEEC_Operation sOperation;
   1188    bool        debug = false;
   1189 
   1190 #ifndef SUPPORT_DELEGATION_EXTENSION
   1191    char * baseDir = NULL;
   1192 
   1193    LogInfo("TFSW Normal-World Daemon");
   1194 #else
   1195    LogInfo("TFSW Normal-World Ext Daemon");
   1196 #endif
   1197    LogInfo(S_VERSION_STRING);
   1198    LogInfo("");
   1199 
   1200    /* Skip program name */
   1201    argv++;
   1202    argc--;
   1203 
   1204    while (argc != 0)
   1205    {
   1206       if (strcmp(argv[0], "-d") == 0)
   1207       {
   1208          debug = true;
   1209       }
   1210 #ifdef SUPPORT_DELEGATION_EXTENSION
   1211       else if (strcmp(argv[0], "-c") == 0)
   1212       {
   1213          int error;
   1214          argc--;
   1215          argv++;
   1216          if (argc == 0)
   1217          {
   1218             printUsage();
   1219             return 1;
   1220          }
   1221          /* Note that the function parseCommandLineExtension can modify the
   1222             content of the g_partitionNames array */
   1223          error = parseCommandLineExtension(argv[0], g_pPartitionNames);
   1224          if ( error != 0 )
   1225          {
   1226             printUsage();
   1227             return error;
   1228          }
   1229       }
   1230 #else
   1231       else if (strcmp(argv[0], "-storageDir") == 0)
   1232       {
   1233          uint32_t i = 0;
   1234          argc--;
   1235          argv++;
   1236          if (argc == 0)
   1237          {
   1238             printUsage();
   1239             return 1;
   1240          }
   1241          if (baseDir != NULL)
   1242          {
   1243             LogError("Only one storage directory may be specified");
   1244             return 1;
   1245          }
   1246          baseDir = malloc(strlen(argv[0])+1); /* Zero-terminated string */
   1247          if (baseDir == NULL)
   1248          {
   1249              LogError("Out of memory");
   1250              return 2;
   1251          }
   1252 
   1253          strcpy(baseDir, argv[0]);
   1254 
   1255          /* Set default names to the partitions */
   1256          for ( i=0; i<16 ;i++ )
   1257          {
   1258             g_pPartitionNames[i] = NULL;
   1259             g_pPartitionNames[i] = malloc(strlen(baseDir) + 1 /* separator */ + sizeof("Store_X.tf"));
   1260             if (g_pPartitionNames[i] != NULL)
   1261             {
   1262                sprintf(g_pPartitionNames[i], "%s%cStore_%1X.tf", baseDir, PATH_SEPARATOR, i);
   1263             }
   1264             else
   1265             {
   1266                free(baseDir);
   1267                i=0;
   1268                while(g_pPartitionNames[i] != NULL) free(g_pPartitionNames[i++]);
   1269                LogError("Out of memory");
   1270                return 2;
   1271             }
   1272          }
   1273       }
   1274       else if (strcmp(argv[0], "-workspaceSize") == 0)
   1275       {
   1276          argc--;
   1277          argv++;
   1278          if (argc == 0)
   1279          {
   1280             printUsage();
   1281             return 1;
   1282          }
   1283          g_nWorkspaceSize=atol(argv[0]);
   1284       }
   1285 #endif /* ! SUPPORT_DELEGATION_EXTENSION */
   1286       /*****************************************/
   1287       else if (strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0)
   1288       {
   1289          printUsage();
   1290          return 0;
   1291       }
   1292       else
   1293       {
   1294          printUsage();
   1295          return 1;
   1296       }
   1297       argc--;
   1298       argv++;
   1299    }
   1300 
   1301 #ifndef SUPPORT_DELEGATION_EXTENSION
   1302    if (baseDir == NULL)
   1303    {
   1304       LogError("-storageDir option is mandatory");
   1305       return 1;
   1306    }
   1307    else
   1308    {
   1309       if (static_checkStorageDirAndAccessRights(baseDir) != 0)
   1310       {
   1311          return 1;
   1312       }
   1313    }
   1314 #endif /* #ifndef SUPPORT_DELEGATION_EXTENSION */
   1315 
   1316    /*
   1317     * Detach the daemon from the console
   1318     */
   1319 
   1320 #if defined(LINUX) || (defined __ANDROID32__)
   1321    {
   1322       /*
   1323        * Turns this application into a daemon => fork off parent process, setup logging, ...
   1324        */
   1325 
   1326       /* Our process ID and Session ID */
   1327       pid_t pid, sid;
   1328 
   1329       if (!debug)
   1330       {
   1331          LogInfo("tf_daemon is detaching from console... Further traces go to syslog");
   1332          /* Fork off the parent process */
   1333          pid = fork();
   1334          if (pid < 0)
   1335          {
   1336             LogError("daemon forking failed");
   1337             return 1;
   1338          }
   1339 
   1340          if (pid > 0)
   1341          {
   1342             /* parent */
   1343             return 0;
   1344          }
   1345          bDetached = true;
   1346       }
   1347 
   1348       /* Change the file mode mask */
   1349       umask(0077);
   1350 
   1351       if (!debug)
   1352       {
   1353          /* Open any logs here */
   1354          openlog("tf_daemon", 0, LOG_DAEMON);
   1355 
   1356          /* Detach from the console */
   1357          sid = setsid();
   1358          if (sid < 0)
   1359          {
   1360             /* Log the failure */
   1361             LogError("daemon group creation failed");
   1362             return 1;
   1363          }
   1364          /* Close out the standard file descriptors */
   1365          close(STDIN_FILENO);
   1366          close(STDOUT_FILENO);
   1367          close(STDERR_FILENO);
   1368       }
   1369    }
   1370    /* Change priority so that tf_driver.ko with no polling thread is faster */
   1371    if (setpriority(PRIO_PROCESS, 0, 19)!=0)
   1372    {
   1373       LogError("Daemon cannot change priority");
   1374       return 1;
   1375    }
   1376 
   1377 #endif
   1378 
   1379    TRACE_INFO("Sector size is %d", g_nSectorSize);
   1380 
   1381    LogInfo("tf_daemon - started");
   1382 
   1383    nError = TEEC_InitializeContext(NULL,  /* const char * name */
   1384                                    &sContext);   /* TEEC_Context* context */
   1385    if (nError != TEEC_SUCCESS)
   1386    {
   1387       LogError("TEEC_InitializeContext error: 0x%08X", nError);
   1388       LogError("Now exiting...");
   1389       exit(2);
   1390    }
   1391 
   1392    /* Open a session */
   1393    if(createSession(&sContext, &sSession, &sOperation) == 0)
   1394    {
   1395       /* Run the session. This should never return */
   1396       runSession(&sContext, &sSession, &sOperation);
   1397    }
   1398    TEEC_FinalizeContext(&sContext);
   1399 
   1400    return 3;
   1401 }
   1402