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