diff options
Diffstat (limited to 'source/LCDriverMethods.cpp')
-rw-r--r-- | source/LCDriverMethods.cpp | 2574 |
1 files changed, 2574 insertions, 0 deletions
diff --git a/source/LCDriverMethods.cpp b/source/LCDriverMethods.cpp new file mode 100644 index 0000000..fd07664 --- /dev/null +++ b/source/LCDriverMethods.cpp @@ -0,0 +1,2574 @@ +/********************************************************************************************* +* +* File name: LCDriverMethods.cpp +* Project: LoaderCommunicationDriver +* Language: Visual C++ +* Description: Implementation of all exported methods. +* +* +* Copyright (C) ST-Ericsson SA 2011 +* License terms: 3-clause BSD license +* +*********************************************************************************************/ + +#include "LCDriverMethods.h" +#include "lcdriver_error_codes.h" +#include "LCDriverThread.h" +#include "Error.h" +#include "LcmInterface.h" +#include "ZRpcInterface.h" +#include "ProtromRpcInterface.h" +#include "commands_impl.h" +#include "a2_commands_impl.h" +#include "Event.h" +#ifdef _WIN32 +#include "WinApiWrappers.h" +#else +#include "LinuxApiWrappers.h" +#include <cstdlib> +#endif +#include <sys/stat.h> +#include <sys/types.h> + +const char *const CLCDriverMethods::BULK_PATH = "/COMM"; + +// LCM timeouts structure to avoid LCD interface changes after removing bulk session end timeout +struct LcmR15Timeouts { + uint32 TCACK; + uint32 TBCR; + uint32 TBDR; +}; + +extern ListDevice_t Devices[]; +extern uint32 DevicesNumber; +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +/// <summary> +/// Constructor. +/// </summary> +/// <param name="pchInterfaceId">A zero terminated string containing the InterfaceId.</param> +CLCDriverMethods::CLCDriverMethods(const char *pchInterfaceId): + m_EventQueue(256) +{ + m_pchId = new char[strlen(pchInterfaceId)+1]; + strcpy_s(m_pchId, strlen(pchInterfaceId) + 1, pchInterfaceId); + + m_pCommunicationDevice = new CommunicationDevice_t; + m_pCmdResult = new CmdResult(); + m_pLcmInterface = new LcmInterface(); + m_pZRpcFunctions = new ZRpcInterface(m_pCmdResult, m_pLcmInterface); + m_pProtromRpcFunctions = new ProtromRpcInterface(m_pCmdResult, m_pLcmInterface); + m_pLoaderRpcFunctions = new LoaderRpcInterfaceImpl(this, m_pCmdResult, m_pLcmInterface); + m_pA2LoaderRpcFunctions = new A2LoaderRpcInterfaceImpl(this, m_pCmdResult, m_pLcmInterface); + + m_pTimer = new Timer(); + m_pHash = new Hash(); + m_pQueue = new Queue(); + m_pBuffers = new Buffers(); + m_pSerialization = new Serialization(); + m_pLogger = new Logger(m_pLcmInterface->getLCMContext()); + m_pBulkHandler = new BulkHandler(this, m_pBuffers, m_pLcmInterface, m_pLogger); + + // default values for timeouts + m_Timeouts.uiRTO = 0xFFFFFFFF; // Typically 5000 + m_Timeouts.uiSTO = 0xFFFFFFFF; // Typically 30000 i.e. 30 secs + + m_CurrentProtocolFamily = R15_FAMILY; + m_iBulkProtocolMode = BULK_INACTIVE; + + m_ProgressBarUpdate = 0; + m_uiBulkLength = 0; + m_uiBulkTransferred = 0; + m_pMainThread = 0; + m_pHashDevice = 0; + m_CurrentCEHCallback = 0; +} + +/// <summary> +/// Destructor. +/// </summary> +CLCDriverMethods::~CLCDriverMethods() +{ + m_EventQueue.SignalEvent(); + OS::Sleep(200); + + if (0 != m_pMainThread) { + m_pMainThread->EndCaptiveThread(); + } + + delete m_pMainThread; + + if (0 != m_pLcmInterface) { + m_pLcmInterface->CommunicationShutdown(); + } + + delete m_pLcmInterface; + delete m_pCmdResult; + delete m_pZRpcFunctions; + delete m_pProtromRpcFunctions; + delete m_pLoaderRpcFunctions; + delete m_pA2LoaderRpcFunctions; + + delete m_pCommunicationDevice; + delete m_pTimer; + delete m_pBuffers; + delete m_pHash; + delete m_pQueue; + delete m_pSerialization; + + delete m_pLogger; + delete m_pBulkHandler; + delete[] m_pchId; +} +//---------------------------------------- +// Static callback functions for intercept only +//---------------------------------------- + +//---------------------------------------- +// Static methods +//---------------------------------------- + +ErrorCode_e CLCDriverMethods::TimerInit(void *pObject, uint32 uiTimers) +{ + Timer *pTimer = static_cast<Timer *>(pObject); + return pTimer->Init(uiTimers); +} + +uint32 CLCDriverMethods::TimerGet(void *pObject, Timer_t *pTimer) +{ + Timer *pTimerLocal = static_cast<Timer *>(pObject); + return pTimerLocal->Get(pTimer); +} + +ErrorCode_e CLCDriverMethods::TimerRelease(void *pObject, uint32 uiTimerKey) +{ + Timer *pTimer = static_cast<Timer *>(pObject); + return pTimer->Release(uiTimerKey); +} + +uint32 CLCDriverMethods::TimerReadTime(void *pObject, uint32 uiTimerKey) +{ + Timer *pTimer = static_cast<Timer *>(pObject); + return pTimer->ReadTime(uiTimerKey); +} + +uint32 CLCDriverMethods::TimerGetSystemTime(void *pObject) +{ + Timer *pTimer = static_cast<Timer *>(pObject); + return pTimer->GetSystemTime(); +} + +//-------------------------------------------- +void CLCDriverMethods::HashCancel(void *pObject, void **ppHashDevice) +{ + Hash *pHashObject = static_cast<Hash *>(pObject); + pHashObject->Cancel((HashDevice_t **)ppHashDevice); +} + +void CLCDriverMethods::HashCalculate(void *pObject, HashType_e Type, void *pData, const uint32 uiLength, uint8 *pHash, HashCallback_fn fnCallback, void *pParam) +{ + Hash *pHashObject = static_cast<Hash *>(pObject); + pHashObject->Calculate(Type, pData, uiLength, pHash, fnCallback, pParam); +} + +//---------------------------------------- + +ErrorCode_e CLCDriverMethods::BuffersInit(void *pObject) +{ + Buffers *pBufferObject = static_cast<Buffers *>(pObject); + return pBufferObject->Init(); +} + +void *CLCDriverMethods::BufferAllocate(void *pObject, int iBufferSize) +{ + Buffers *pBufferObject = static_cast<Buffers *>(pObject); + return pBufferObject->Allocate(iBufferSize); +} + +ErrorCode_e CLCDriverMethods::BufferRelease(void *pObject, void *pBuffer, int iBufferSize) +{ + Buffers *pBufferObject = static_cast<Buffers *>(pObject); + return pBufferObject->Release(pBuffer, iBufferSize); +} + +uint32 CLCDriverMethods::BuffersAvailable(void *pObject, int iBufferSize) +{ + Buffers *pBufferObject = static_cast<Buffers *>(pObject); + return pBufferObject->Available(iBufferSize); +} + +void CLCDriverMethods::BuffersDeinit(void *pObject) +{ + Buffers *pBufferObject = static_cast<Buffers *>(pObject); + pBufferObject->Deinit(); +} + +//---------------------------------------- + +void CLCDriverMethods::QueueCreate(void *pObject, void **const ppQueue, const uint32 uiMaxLength, void (*pDestroyElement)(void *pElement)) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + pQueueLocal->RCreate(ppQueue, uiMaxLength, pDestroyElement); +} +void CLCDriverMethods::QueueDestroy(void *pObject, void **const ppQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + pQueueLocal->RDestroy(ppQueue); +} + +ErrorCode_e CLCDriverMethods::QueueEnqueue(void *pObject, void *const ppQueue, void *const pValue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->REnqueue(ppQueue, pValue); +} + +void *CLCDriverMethods::QueueDequeue(void *pObject, void *const ppQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RDequeue(ppQueue); +} + +QueueCallback_fn CLCDriverMethods::QueueSetCallback(void *pObject, void *const pQueue, const QueueCallbackType_e Type, const QueueCallback_fn fnCallback, void *const pParam) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RSetCallback(pQueue, Type, fnCallback, pParam); +} + +boolean CLCDriverMethods::QueueIsEmpty(void *pObject, const void *const pQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RIsEmpty(pQueue); +} + +boolean CLCDriverMethods::QueueIsMember(void *pObject, const void *const pQueue, void *pValue, boolean(*Match)(void *pValue1, void *pValue2)) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RIsMember(pQueue, pValue, Match); +} + +int CLCDriverMethods::QueueGetNrOfElements(void *pObject, const void *const pQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RGetNrOfElements(pQueue); +} + +void CLCDriverMethods::RQueueCreate(void *pObject, void **const ppQueue, const uint32 uiMaxLength, void (*pDestroyElement)(void *pElement)) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + pQueueLocal->RCreate(ppQueue, uiMaxLength, pDestroyElement); +} + +void CLCDriverMethods::RQueueDestroy(void *pObject, void **const ppQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + pQueueLocal->RDestroy(ppQueue); +} + +ErrorCode_e CLCDriverMethods::RQueueEnqueue(void *pObject, void *const pQueue, void *const pValue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->REnqueue(pQueue, pValue); +} + +void *CLCDriverMethods::RQueueDequeue(void *pObject, void *const pQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RDequeue(pQueue); +} + +QueueCallback_fn CLCDriverMethods::RQueueSetCallback(void *pObject, void *const pQueue, const QueueCallbackType_e Type, const QueueCallback_fn fnCallback, void *const pParam) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RSetCallback(pQueue, Type, fnCallback, pParam); +} + +boolean CLCDriverMethods::RQueueIsEmpty(void *pObject, const void *const pQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RIsEmpty(pQueue); +} + +boolean CLCDriverMethods::RQueueIsMember(void *pObject, const void *const pQueue, void *pValue, boolean(*Match)(void *pValue1, void *pValue2)) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RIsMember(pQueue, pValue, Match); +} + +int CLCDriverMethods::RQueueGetNrOfElements(void *pObject, const void *const pQueue) +{ + Queue *pQueueLocal = static_cast<Queue *>(pObject); + return pQueueLocal->RGetNrOfElements(pQueue); +} + +//---------------------------------------- + +ErrorCode_e CLCDriverMethods::CEHCallbackFunction(void *pObject, CommandData_t *pCmdData) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->m_pLoaderRpcFunctions->Do_CEH_Callback(pCmdData); +} + +ErrorCode_e CLCDriverMethods::CEH_Z_CallbackFunction(void *pObject, CommandData_t *pCmdData) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->m_pZRpcFunctions->Do_CEH_Callback(pCmdData); +} + +ErrorCode_e CLCDriverMethods::CEH_PROTROM_CallbackFunction(void *pObject, CommandData_t *pCmdData) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->m_pProtromRpcFunctions->Do_CEH_Callback(pCmdData); +} + +ErrorCode_e CLCDriverMethods::CEH_A2_CallbackFunction(void *pObject, CommandData_t *pCmdData) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->m_pA2LoaderRpcFunctions->Do_CEH_Callback(pCmdData); +} + +//---------------------------------------- + +void CLCDriverMethods::BulkCommandReqCallback(void *pObject, uint16 *puiSession, uint32 *puiChunkSize, uint64 *puiOffset, uint32 *puiLength, boolean bAckRead) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->m_pBulkHandler->HandleCommandRequest(*puiSession, *puiChunkSize, *puiOffset, *puiLength, bAckRead ? true : false); +} + +void CLCDriverMethods::BulkDataReqCallback(void *pObject, uint16 *puiSession, uint32 *puiChunkSize, uint64 *puiOffset, uint32 *puiLength, uint64 *puiTotalLength, uint32 *puiTransferedLength) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->Do_BulkDataReqCallback(puiSession, puiChunkSize, puiOffset, puiLength, puiTotalLength, puiTransferedLength); +} + +void CLCDriverMethods::BulkDataEndOfDumpCallback(void *pObject) +{ + CLCDriverMethods *pLcdMethods = static_cast<CLCDriverMethods *>(pObject); + return pLcdMethods->Do_BulkDataEndOfDumpCallback(); +} + +//////////////////////////////////////////////////////////////////////// +/// +/// Exported methods +/// + +/// <summary> +/// Initializes LCDriver. +/// </summary> +/// <param name="pfnRead">Callback to external Read function.</param> +/// <param name="pfnWrite">Callback to external Write function.</param> +/// <param name="pfnCancel">Callback to external Cancel function.</param> +/// <param name="ppInstance">Method modifies value to point to this instance of m_pGlobalCommunicationLCDriver object.</param> +/// <param name="pfnMessage">Callback to external Message function for outputting text.</param> +/// <param name="pchLCMLibPath">Path to LCM module.</param> +/// <param name="pfnProgressBarCallback">Callback to external ProgressBar function.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Initialize(void **ppInstance) +{ +#ifdef _MESSAGES + m_pBuffers->SetLogger(m_pLogger); + m_pQueue->SetLogger(m_pLogger); + m_pTimer->SetLogger(m_pLogger); + m_pSerialization->SetLogger(m_pLogger); +#endif + int ReturnValue = E_SUCCESS; + + // Setup Command Protocol buffer + m_pBuffers->Init(); + + BuffersInterface_t BufferFunctions; + TimersInterface_t TimerFunctions; + QueueInterface_t QueueFunctions; + + // Setup timer struct + VERIFY_SUCCESS(SetupTimers(&TimerFunctions)); + + // Setup buffer struct + VERIFY_SUCCESS(SetupBuffers(&BufferFunctions)); + + // Setup queue struct + VERIFY_SUCCESS(SetupQueues(&QueueFunctions)); + + // Setup hash struct + VERIFY_SUCCESS(SetupHash()); + + if (NULL == m_pCommunicationDevice->Read || NULL == m_pCommunicationDevice->Write || NULL == m_pCommunicationDevice->Cancel) { + VERIFY_SUCCESS(CALLBACKS_NOT_CONFIGURED_CORRECTLY); + } + + VERIFY_SUCCESS(m_pLcmInterface->CommunicationInitialize(this, m_CurrentProtocolFamily, m_pHashDevice, m_pCommunicationDevice, m_CurrentCEHCallback, &BufferFunctions, &TimerFunctions, &QueueFunctions)); + *ppInstance = m_pLcmInterface->getLCMContext(); + + // Create main thread + if (m_pTimer) { + m_pMainThread = new CLCDriverThread(this); + } else { + VERIFY_SUCCESS(LCDRIVER_THREAD_NOT_STARTED); + } + + // Initialize 32 timers for the moment (timer memory only allocated once for all instances) + TimerInit(m_pTimer, 32); + + if (R15_FAMILY == m_CurrentProtocolFamily) { + m_pMainThread->TimerOn(); + } + + //Now start LCDriver thread + m_pMainThread->ResumeThread(); + + m_pLogger->log("LCDriver/LCM started ok!"); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Set up Timers utility class required by LCM. +/// </summary> +/// <returns> Status of the command.</returns> +ErrorCode_e CLCDriverMethods::SetupTimers(TimersInterface_t *pTimerFunctions) +{ + ErrorCode_e Result = E_SUCCESS; + pTimerFunctions->GetSystemTime_Fn = static_cast<GetSystemTime_t>(TimerGetSystemTime); + pTimerFunctions->ReadTime_Fn = static_cast<ReadTime_t>(TimerReadTime); + pTimerFunctions->TimerGet_Fn = static_cast<TimerGet_t>(TimerGet); + pTimerFunctions->TimerRelease_Fn = static_cast<TimerRelease_t>(TimerRelease); + pTimerFunctions->TimersInit_Fn = static_cast<TimersInit_t>(TimerInit); + pTimerFunctions->Object_p = m_pTimer; + return Result; +} + +/// <summary> +/// Set up Buffer utility class required by LCM. +/// </summary> +/// <returns> Status of the command.</returns> +ErrorCode_e CLCDriverMethods::SetupBuffers(BuffersInterface_t *pBufferFunctions) +{ + ErrorCode_e Result = E_SUCCESS; + pBufferFunctions->BufferAllocate_Fn = static_cast<BufferAllocate_t>(BufferAllocate); + pBufferFunctions->BufferRelease_Fn = static_cast<BufferRelease_t>(BufferRelease); + pBufferFunctions->BuffersAvailable_Fn = static_cast<BuffersAvailable_t>(BuffersAvailable); + pBufferFunctions->BuffersDeinit_Fn = static_cast<BuffersDeinit_t>(BuffersDeinit); + pBufferFunctions->BuffersInit_Fn = static_cast<BuffersInit_t>(BuffersInit); + pBufferFunctions->Object_p = m_pBuffers; + return Result; +} + +/// <summary> +/// Set up Queue utility class required by LCM. +/// </summary> +/// <returns> Status of the command.</returns> +ErrorCode_e CLCDriverMethods::SetupQueues(QueueInterface_t *pQueueFunctions) +{ + ErrorCode_e Result = E_SUCCESS; + pQueueFunctions->Fifo_GetNrOfElements_Fn = QueueGetNrOfElements; + pQueueFunctions->Fifo_IsEmpty_Fn = QueueIsEmpty; + pQueueFunctions->Fifo_IsMember_Fn = QueueIsMember; + pQueueFunctions->Fifo_SetCallback_Fn = QueueSetCallback; + pQueueFunctions->FifoCreate_Fn = QueueCreate; + pQueueFunctions->FifoDequeue_Fn = QueueDequeue; + pQueueFunctions->FifoDestroy_Fn = QueueDestroy; + pQueueFunctions->FifoEnqueue_Fn = QueueEnqueue; + pQueueFunctions->RFifo_GetNrOfElements_Fn = RQueueGetNrOfElements; + pQueueFunctions->RFifo_IsEmpty_Fn = RQueueIsEmpty; + pQueueFunctions->RFifo_IsMember_Fn = RQueueIsMember; + pQueueFunctions->RFifo_SetCallback_Fn = RQueueSetCallback; + pQueueFunctions->RFifoCreate_Fn = RQueueCreate; + pQueueFunctions->RFifoDequeue_Fn = RQueueDequeue; + pQueueFunctions->RFifoDestroy_Fn = RQueueDestroy; + pQueueFunctions->RFifoEnqueue_Fn = RQueueEnqueue; + pQueueFunctions->Object_p = m_pQueue; + return Result; +} + +/// <summary> +/// Set up Hash utility class required by LCM. +/// </summary> +/// <returns> Status of the command.</returns> +ErrorCode_e CLCDriverMethods::SetupHash() +{ + m_pHashDevice = new HashDevice_t; + + if (0 == m_pHashDevice) { + return E_ALLOCATE_FAILED; + } + + m_pHashDevice->Calculate = HashCalculate; + m_pHashDevice->Cancel = HashCancel; + m_pHashDevice->Object_p = m_pHash; + return E_SUCCESS; +} + +void CLCDriverMethods::CancelCurrentLoaderCommand() +{ + m_EventQueue.SignalEvent(); +} + +/// <summary> +/// The Loader Start-up Status command is sent by the ME to notify the host that it has started. The Status parameter indicates in what mode the loader started. +/// </summary> +/// <param name="pchVersion">Loader version identifier.</param> +/// <param name="piVersionSize">Number of allocated bytes for version string.</param> +/// <param name="pchProtocol">Protocol version identifier.</param> +/// <param name="piProtocolSize">Number of allocated bytes for protocol string.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Done_System_LoaderStartupStatus(char *pchVersion, int *piVersionSize, char *pchProtocol, int *piProtocolSize) +{ + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(WaitForEvent(EVENT_CMD_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_LOADERSTARTUPSTATUS)); + VERIFY_SUCCESS(m_pCmdResult->System_LoaderStartupStatus_Status); + + //Copy output parameter from RPC class. + CopyStringToArray(m_pCmdResult->System_LoaderStartupStatus_LoaderVersion, pchVersion, piVersionSize); + CopyStringToArray(m_pCmdResult->System_LoaderStartupStatus_ProtocolVersion, pchProtocol, piProtocolSize); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piVersionSize = 0; + *piProtocolSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// The Reboot command is used to instruct the loader to reset the ME. Upon receiving this command, +/// the loader shuts down in a controlled fashion and restarts the ME. The Mode parameter is used to +/// select the mode of reset. The ME does not accept any further communication after a successful +/// response from this command has been returned. +/// </summary> +/// <param name="iMode">Indicates the mode of reset: +/// 0: indicates normal restart. +/// 1: indicates restart in service mode. +/// 2: indicates restart with JTAG debugging enabled. +/// 3: indicates restart in service mode and with JTAG debugging enabled. +/// </param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_System_Reboot(int iMode) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_Reboot(uiSessionOut, iMode)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// The loader returns a list of implemented commands and whether they are permitted to +/// execute in the current loader state. +/// </summary> +/// <param name="pCmdList">A list with supported commands.</param> +/// <param name="piCmdListSize">Number of commands in CmdList.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_System_SupportedCommands(TSupportedCmd *pCmdList, int *piCmdListSize) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_SupportedCommands(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_SUPPORTEDCOMMANDS)); + + //Copy output parameter from RPC class. + *piCmdListSize = static_cast<int>(m_pCmdResult->System_SupportedCommands_CmdList.size()); + CopyVectorToArray(m_pCmdResult->System_SupportedCommands_CmdList, pCmdList, piCmdListSize); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piCmdListSize = 0; + } + + return ReturnValue; +} + +int CLCDriverMethods::Do_System_CollectData(int iType, int *piSize, char *pData) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_CollectData(uiSessionOut, iType)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_COLLECTDATA)); + + //Copy output parameter from RPC class. + if (m_pCmdResult->System_CollectedData.length() > static_cast<size_t>(*piSize)) { + m_pCmdResult->System_CollectedData.erase(*piSize - 1); + } + + strcpy_s(pData, *piSize, m_pCmdResult->System_CollectedData.c_str()); + *piSize = m_pCmdResult->System_CollectedData.length(); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piSize = 0; + *pData = '\0'; + } + + return ReturnValue; +} + +/// <summary> +/// Receive, verify and execute software, which can be a signed loader. +/// After having sent this command, the ME attempts to read the software +/// payload data from the host using the Bulk protocol or from the flash +/// file system depending on the selected path. The current loader does not +/// respond to communication after this command has been successfully executed. +/// If the executed software is another loader, communication can be resumed once the +/// Loader Started command has been received. A response of E_OPERATION_CANCELLED +/// indicates the operation was canceled. +/// </summary> +/// <param name="pchDevicePath">Target path. If use bulk the path is on PC, else on ME.</param> +/// <param name="iUseBulk">If value = 1 -> source on PC, else source on ME.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_System_ExecuteSoftware(const uint32 ExecuteMode, const char *pchDevicePath, int iUseBulk) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + if (1 == ExecuteMode) { + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_ExecuteSoftware(uiSessionOut, ExecuteMode, pchDevicePath, 0)); + + } else if (2 == ExecuteMode) { + if (iUseBulk) { + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(m_pBuffers->AllocateBulkFile(pchDevicePath)); + uint64 uiLength = m_pBuffers->GetBulkFileLength(); + m_uiBulkLength = uiLength; + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Send(pchDevicePath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_ExecuteSoftware(uiSessionOut, ExecuteMode, BULK_PATH, uiLength)); + //VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_EXECUTESOFTWARE)); + } else { + // TEMPORARY ONLY - QSJOMIK: CURRENTLY WE CANNOT KNOW THE SIZE OF FILE ON AN ME MEMORY CARD IF USEBULK=0 - DO WE NEED A PARAMETER?? + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_ExecuteSoftware(uiSessionOut, ExecuteMode, pchDevicePath, 0)); + //VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_EXECUTESOFTWARE)); + } + + // reset session counters for this instance of the lcm + m_pLcmInterface->CommandResetSessionCounters(); + } else { + ReturnValue = INVALID_EXECUTION_MODE; + } + //} + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + m_pBuffers->ReleaseBulkFile(); + } + + return ReturnValue; +} + +/// <summary> +/// This command is used to escalate the privileges of the operator. Two ways of +/// authentication are available by default; control key authentication and certificate based +/// authentication. The authentication command sets the loader in a specific +/// authentication context when it takes control over the command flow. After +/// receiving the authentication command, the loader sends the appropriate request for information to the PC. +/// </summary> +/// <param name="iType">Authentication type:0 = control key authentication,1 = certificate authentication.</param> +/// <param name="piSize">Size of puchData.</param> +/// <param name="puchdata">Data challange. </param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_System_Authenticate(int iType, int *piSize, unsigned char *puchdata) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_Authenticate(uiSessionOut, iType)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED | EVENT_CMD_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_AUTHENTICATE)); + + if (0 != iType) { + CopyVectorToArray(m_pCmdResult->System_AuthenticationChallenge_Buffer, puchdata, piSize); + } + +ErrorExit: + + if (0 != iType && E_SUCCESS != ReturnValue) { + *piSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// This command is used by the loader to retrieve the SimLock control keys from the host to authenticate a user. +/// The command is used in the authentication context. +/// </summary> +/// <param name="pSIMLockKeys">A struct with all lock/unlock keys.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Done_System_GetControlKeys(TSIMLockKeys *pSIMLockKeys) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoneRPC_System_GetControlKeys(uiSessionOut, E_SUCCESS, + pSIMLockKeys->pchNLCKLock, pSIMLockKeys->pchNSLCKLock, + pSIMLockKeys->pchSPLCKLock, pSIMLockKeys->pchCLCKLock, + pSIMLockKeys->pchPCKLock, pSIMLockKeys->pchESLCKLock, + pSIMLockKeys->pchNLCKUnLock, pSIMLockKeys->pchNSLCKUnLock, + pSIMLockKeys->pchSPLCKUnLock, pSIMLockKeys->pchCLCKUnLock, + pSIMLockKeys->pchPCKLock, pSIMLockKeys->pchESLCKUnLock)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_AUTHENTICATE)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used by the loader to retrieve the SimLock control keys data buffer from the host to authenticate a user. +/// The command is used in the authentication context. +/// </summary> +/// <param name="SIMLockKeysData">SIMLockKeyData buffer that contain all SIMLock keys.</param> +/// <param name="iDataSize">SIMLockKeyData buffer size.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Done_System_GetControlKeysData(int iDataSize, unsigned char *pSIMLockKeysData) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoneRPC_System_GetControlKeysData(uiSessionOut, E_SUCCESS, + iDataSize, pSIMLockKeysData)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_AUTHENTICATE)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used by the loader to perform a certificate authentication. +/// The command is only used in the authentication context. +/// </summary> +/// <param name="puchChallengeData">Authentication challenge. This challenge must be signed +/// using the correct certificate and returned to the loader.</param> +/// <param name="iDataSize">Authentication challenge buffer length.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Done_System_AuthenticationChallenge(int iDataSize, unsigned char *puchChallengeData) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoneRPC_System_AuthenticationChallenge(uiSessionOut, E_SUCCESS, iDataSize, puchChallengeData)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_AUTHENTICATE)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// The Set System Time command is used to set the current epoch time for loader +/// to configure the real time clock and use it for file system operations. +/// </summary> +/// <param name="EpochTime"> +/// Number of seconds that have elapsed since January 1, 1970 +/// </param> +/// <returns>Status of the command.</returns> +int CLCDriverMethods::Do_System_SetSystemTime(uint32 EpochTime) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_SetSystemTime(uiSessionOut, EpochTime)); + + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_SETSYSTEMTIME)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to instruct the Loader to switch to a new communication device. +/// </summary> +/// <param name="Device"> +/// Device ID of the communication device to switch to. +/// </param> +/// <param name="DeviceParam"> +/// Communication device parameters. +/// </param> +/// <returns>Status of the command.</returns> +int CLCDriverMethods::Do_System_SwitchCommunicationDevice(uint32 Device, uint32 DeviceParam) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_SwitchCommunicationDevice(uiSessionOut, Device, DeviceParam)); + + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SYSTEM, COMMAND_SYSTEM_SWITCHCOMMUNICATIONDEVICE)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// The loader shuts down in a controlled fashion and proceeds to shut down the ME itself. +/// The ME does not accept any further communication after a successful response from this +/// command has been returned. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_System_Shutdown() +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_System_ShutDown(uiSessionOut)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to initiate a flashing session. The type argument is +/// used to select the type of file to process and Length parameter +/// defines the total size of the file. +/// </summary> +/// <param name="pchPath">Target path. If iUseBulk = 1, path is on PC.</param> +/// <param name="pchType">Type of the opened file.</param> +/// <param name="iUseBulk">If to use bulk protocol. If target is on PC iUseBulk shall be 1.</param> +/// <param name="iDeleteBuffers">Specify whether to delete bulk buffers when finished. 1 -> delete buffers. 0 -> don't delete buffers.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Flash_ProcessFile(const char *pchPath, const char *pchType, int iUseBulk, int iDeleteBuffers) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + +#ifdef _BULKDEBUG + m_pLogger->log("BULK: Do_Flash_ProcessFile - DeleteBuffers = %d", iDeleteBuffers); +#endif + + if (iUseBulk) { + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(m_pBuffers->AllocateBulkFile(pchPath)); + uint64 uiLength = m_pBuffers->GetBulkFileLength(); + m_uiBulkLength = uiLength; + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Send(pchPath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_ProcessFile(uiSessionOut, uiLength, pchType, BULK_PATH)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_PROCESSFILE)); + } else { + // QSJOMIK: CURRENTLY WE CANNOT KNOW THE SIZE OF FILE ON AN ME MEMORY CARD IF USEBULK=0 - SEND 0 FOR NOW + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_ProcessFile(uiSessionOut, 0, pchType, pchPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_PROCESSFILE)); + } + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + + if (0 != iDeleteBuffers) { + m_pBuffers->ReleaseBulkFile(); + } + } + + return ReturnValue; +} + +/// <summary> +/// This command is used by the client application program to obtain the device tree. +/// </summary> +/// <param name="pDevices">A struct with information about one flash device.</param> +/// <param name="piDeviceSize">Number of flash devices, size of pDevices array.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Flash_ListDevices(TDevices *pDevices, int *piDeviceSize) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_ListDevices(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_LISTDEVICES)); + + *piDeviceSize = DevicesNumber; + + for (int i = 0; i < *piDeviceSize; ++i) { + pDevices[i].pchPath = Devices[i].Path_p; + pDevices[i].pchType = Devices[i].Type_p; + + pDevices[i].iTypeSize = strlen(Devices[i].Type_p); + pDevices[i].iPathSize = strlen(Devices[i].Path_p); + + pDevices[i].uiBlockSize = Devices[i].BlockSize; + pDevices[i].uiStart = Devices[i].Start; + pDevices[i].uiLength = Devices[i].Length; + } + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piDeviceSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// This command is used to initiate a dump session. +/// </summary> +/// <param name="pchPathToDump">Path to the device to dump.</param> +/// <param name="uiStart">Start of the dump relative to the start of the device indicated by Path [Byte].</param> +/// <param name="uiLength">Length of the dump [Byte]. Actual length is determined by the device block size.</param> +/// <param name="pchFilePath">File path on PC to store dump data to.</param> +/// <param name="uiRedundantArea">Include redundant area in the dump.</param> +/// <param name="iUseBulk">1-> save dump data on PC, 0-> save dump data on ME.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Flash_DumpArea(const char *pchPathToDump, uint64 uiStart, uint64 uiLength, const char *pchFilePath, uint32 uiRedundantArea, int iUseBulk) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + if (iUseBulk) { + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + m_uiBulkLength = uiLength; + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Receive(pchFilePath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_DumpArea(uiSessionOut, pchPathToDump, uiStart, uiLength, BULK_PATH, uiRedundantArea)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_DUMPAREA)); + } else { + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_DumpArea(uiSessionOut, pchPathToDump, uiStart, uiLength, pchFilePath, uiRedundantArea)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_DUMPAREA)); + } + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + } + + return ReturnValue; +} + +/// <summary> +/// This command is used to erase a flash device or part of a flash device. +/// </summary> +/// <param name="pchPath">Path to the device to erase.</param> +/// <param name="uiStart">Start of the erase relative to the start of the device +/// indicated by path [Byte]. This must be a multiple of the block size of the device.</param> +/// <param name="uiLength">Length of the dump [Byte]. This must be a multiple of the block size of the device.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Flash_EraseArea(const char *pchPath, uint64 uiStart, uint64 uiLength) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_EraseArea(uiSessionOut, pchPath, uiStart, uiLength)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_ERASEAREA)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to initiate a flashing of raw data. The type argument is +/// used to select the type of file to process and Length parameter +/// defines the total size of the file. +/// </summary> +/// <param name="Context">LCD context on which to execute the operation.</param> +/// <param name="pchPath">Target path. If iUseBulk = 1, path is on PC.</param> +/// <param name="uiStart">Address where flashing should start.</param> +/// <param name="uiLength">Length of data to be flashed.</param> +/// <param name="uiDevice">Device ID number.</param> +/// <param name="iUseBulk">If to use bulk protocol. If target is on PC iUseBulk shall be 1.</param> +/// <param name="iDeleteBuffers">Specify if to delete bulk buffers after finish. 1 -> delete buffers. 0 -> don't delete buffers.</param> +/// <returns>Status of the command.</returns> +int CLCDriverMethods::Do_Flash_FlashRaw(const char *pchPath, uint64 uiStart, uint64 uiLength, uint32 uiDevice, int iUseBulk, int iDeleteBuffers) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + +#ifdef _BULKDEBUG + m_pLogger->log("BULK: Do_Flash_FlashRaw - DeleteBuffers = %d", iDeleteBuffers); +#endif + + if (iUseBulk) { + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(m_pBuffers->AllocateBulkFile(pchPath)); + + uint64 uiFileLength = m_pBuffers->GetBulkFileLength(); + VERIFY((uiLength <= uiFileLength), E_INVALID_INPUT_PARAMETERS); + + m_uiBulkLength = uiLength; + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Send(pchPath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_FlashRaw(uiSessionOut, uiStart, uiLength, uiDevice, BULK_PATH)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_FLASHRAW)); + } else { + // CURRENTLY WE CANNOT KNOW THE SIZE OF FILE ON AN ME MEMORY CARD IF USEBULK=0 - SEND 0 FOR NOW + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Flash_FlashRaw(uiSessionOut, uiStart, 0, uiDevice, pchPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FLASH, COMMAND_FLASH_FLASHRAW)); + } + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + + if (0 != iDeleteBuffers) { + m_pBuffers->ReleaseBulkFile(); + } + } + + return ReturnValue; +} + +/// <summary> +/// This command retrieves the properties of the specified file system volume. It is issued by the PC application. +/// </summary> +/// <param name="pchDevicePath">Path of file system volume.</param> +/// <param name="pchFSType">File system type.</param> +/// <param name="piFSTypeSize">Size of pchFSType array.</param> +/// <param name="puiSize">Total size of the file system [Byte].</param> +/// <param name="puiFree">Available space [Byte].</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_VolumeProperties(const char *pchDevicePath, char *pchFSType, int *piFSTypeSize, uint64 *puiSize, uint64 *puiFree) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_VolumeProperties(uiSessionOut, pchDevicePath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_VOLUMEPROPERTIES)); + + //Copy output parameter from RPC class. + if (m_pCmdResult->FileSystem_VolumeProperties_FSType.length() > static_cast<size_t>(*piFSTypeSize)) { + m_pCmdResult->FileSystem_VolumeProperties_FSType.erase(*piFSTypeSize - 1); + } + + strcpy_s(pchFSType, *piFSTypeSize, m_pCmdResult->FileSystem_VolumeProperties_FSType.c_str()); + *piFSTypeSize = m_pCmdResult->FileSystem_VolumeProperties_FSType.length(); + *puiSize = m_pCmdResult->FileSystem_VolumeProperties_Size; + *puiFree = m_pCmdResult->FileSystem_VolumeProperties_Free; + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *pchFSType = '\0'; + *piFSTypeSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// Formats unused file system volume specified in device path. This operation fails if the volume is currently in use. +/// </summary> +/// <param name="pchDevicePath">Device path of the file system volume.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_FormatVolume(const char *pchDevicePath) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_FormatVolume(uiSessionOut, pchDevicePath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_FORMATVOLUME)); + +ErrorExit: + return ReturnValue; +} + + +/// <summary> +/// List files and directories residing in specified path. +/// </summary> +/// <param name="pchPath">File system path.</param> +/// <param name="pEntries">Struct with file and directory information.</param> +/// <param name="piDeviceSize">Number of files or directories, number of element in pEntries array.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_ListDirectory(const char *pchPath, TEntries *pEntries, int *piDeviceSize) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_ListDirectory(uiSessionOut, pchPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_LISTDIRECTORY)); + + //Copy output parameter from RPC class. + *piDeviceSize = static_cast<int>(m_pCmdResult->FileSystem_ListDirectory_Entries.size()); + CopyVectorToArray(m_pCmdResult->FileSystem_ListDirectory_Entries, pEntries, piDeviceSize); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piDeviceSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// This command moves a file from the source path to the destination path if the source and destination differ. +/// It also renames a file if the source path and the destination path are the same. +/// </summary> +/// <param name="pchSourcePath">File system path in ME to source.</param> +/// <param name="pchDestinationPath">File system path in ME to destination.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_MoveFile(const char *pchSourcePath, const char *pchDestinationPath) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_MoveFile(uiSessionOut, pchSourcePath, pchDestinationPath)); // DoRPC_FileSystem_MoveFile(&uiSessionOut, pchSourcePath, pchDestinationPath); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_MOVEFILE)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Delete the specified file or directory. The loader only deletes empty directories. +/// </summary> +/// <param name="pchTargetPath">File system path in ME.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_DeleteFile(const char *pchTargetPath) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_DeleteFile(uiSessionOut, pchTargetPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_DELETEFILE)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to do the following: Copy a file from the PC to the ME. Copy a file between two directories or file systems on the ME. +/// Copy a file from the ME to the PC. +/// </summary> +/// <param name="pchSourcePath">If iSourceUseBulk = 1 -> path on PC, else path on ME.</param> +/// <param name="iSourceUseBulk">If = 1 -> source on PC, else source on ME.</param> +/// <param name="pchDestinationPath">If iDestinationUseBulk = 1 -> path on PC, else path on ME.</param> +/// <param name="iDestinationUseBulk">If = 1 -> destination on PC, else destination on ME.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_CopyFile(const char *pchSourcePath, int iSourceUseBulk, const char *pchDestinationPath, int iDestinationUseBulk) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + if (iSourceUseBulk) { // PC -> ME + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(m_pBuffers->AllocateBulkFile(pchSourcePath)); + m_uiBulkLength = m_pBuffers->GetBulkFileLength(); + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Send(pchSourcePath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_CopyFile(uiSessionOut, BULK_PATH, pchDestinationPath)); + + //Wait for stat command + VERIFY_SUCCESS(WaitForEvent(EVENT_CMD_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_PROPERTIES)); + + struct stat fileInfo; + stat(pchSourcePath, &fileInfo); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoneRPC_File_System_Operations_Properties(uiSessionOut, E_SUCCESS, fileInfo.st_mode, fileInfo.st_size, (uint32)fileInfo.st_mtime, (uint32)fileInfo.st_atime, (uint32)fileInfo.st_ctime)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_COPYFILE)); + } else if (iDestinationUseBulk) { // ME -> PC + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(m_pBulkHandler->Receive(pchDestinationPath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_CopyFile(uiSessionOut, pchSourcePath, BULK_PATH)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_COPYFILE)); + } else { + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_CopyFile(uiSessionOut, pchSourcePath, pchDestinationPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_COPYFILE)); + } + +ErrorExit: + + if (iSourceUseBulk || iDestinationUseBulk) { + m_pBulkHandler->Finish(); + + if (iSourceUseBulk) { + m_pBuffers->ReleaseBulkFile(); + } + } + + return ReturnValue; +} + +/// <summary> +/// This command is used to create a directory. It is issued by the PC application. +/// </summary> +/// <param name="pchTargetPath">File system path to target.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_CreateDirectory(const char *pchTargetPath) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_CreateDirectory(uiSessionOut, pchTargetPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_CREATEDIRECTORY)); + +ErrorExit: + return ReturnValue; +} +/// <summary> +/// This command is used to retrieve the properties of a file or directory. +/// </summary> +/// <param name="pchTargetPath">File system path to target.</param> +/// <param name="puiMode">File type and access restrictions descriptor.</param> +/// <param name="puiSize">File size [Byte].</param> +/// <param name="piMTime">Last modification timestamp.</param> +/// <param name="piATime">Last access timestamp.</param> +/// <param name="piCTime">Creation timestamp.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_Properties(const char *pchTargetPath, uint32 *puiMode, uint64 *puiSize, int *piMTime, int *piATime, int *piCTime) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_Properties(uiSessionOut, pchTargetPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_PROPERTIES)); + + //Copy output parameter from RPC class. + *puiMode = m_pCmdResult->FileSystem_Properties_Mode; + *puiSize = m_pCmdResult->FileSystem_Properties_Size; + *piMTime = m_pCmdResult->FileSystem_Properties_MTime; + *piATime = m_pCmdResult->FileSystem_Properties_ATime; + *piCTime = m_pCmdResult->FileSystem_Properties_CTime; + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to change the access permissions of a specified path. +/// </summary> +/// <param name="pchTargetPath">File system path to target.</param> +/// <param name="iAccess">New access permissions.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_ChangeAccess(const char *pchTargetPath, int iAccess) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_ChangeAccess(uiSessionOut, pchTargetPath, iAccess)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_CHANGEACCESS)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to read manifests contained in load modules at the specified path and send the data back over bulk protocol. +/// </summary> +/// <param name="pchTargetPath">Path on PC to save manifest.</param> +/// <param name="pchSourcePath">Load module(s) file system path.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_FileSystem_ReadLoadModuleManifests(const char *pchTargetPath, const char *pchSourcePath) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pBulkHandler->Receive(pchTargetPath)); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_File_System_Operations_ReadLoadModulesManifests(uiSessionOut, pchSourcePath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_FILE_SYSTEM_OPERATIONS, COMMAND_FILE_SYSTEM_OPERATIONS_READLOADMODULESMANIFESTS)); + +ErrorExit: + m_pBulkHandler->Finish(); + return ReturnValue; +} + +/// <summary> +/// This command is used to read the specified bits from the OTP. +/// </summary> +/// <param name="iOtpId">OTP area ID.</param> +/// <param name="iBitStart">Starting offset [bit].</param> +/// <param name="iBitLength">Length of read [bit].</param> +/// <param name="puchDataBuffer">Received OTP data.</param> +/// <param name="piDataBufferSize">Size of puchDataBuffer.</param> +/// <param name="puchStatusBuffer">Lock status for each read bit.</param> +/// <param name="piStatusBufferSize">Size of puchStatusBuffer.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_OTP_ReadBits(int iOtpId, int iBitStart, int iBitLength, unsigned char *puchDataBuffer, int *piDataBufferSize , unsigned char *puchStatusBuffer, int *piStatusBufferSize) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_OTP_ReadBits(uiSessionOut, iOtpId, iBitStart, iBitLength)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_OTP, COMMAND_OTP_READBITS)); + + //Copy output parameter from RPC class. + CopyVectorToArray(m_pCmdResult->OTP_ReadBits_DataBuffer, puchDataBuffer, piDataBufferSize); + CopyVectorToArray(m_pCmdResult->OTP_ReadBits_StatusBuffer, puchStatusBuffer, piStatusBufferSize); + + //clean up + m_pCmdResult->OTP_ReadBits_DataBuffer.clear(); + m_pCmdResult->OTP_ReadBits_StatusBuffer.clear(); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piDataBufferSize = 0; + *piStatusBufferSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// This command stores the specified bits in the loader internal OTP structures in RAM, it does not write to OTP. +/// </summary> +/// <param name="iOtpId">OTP area ID.</param> +/// <param name="iBitStart">Starting offset [bit].</param> +/// <param name="iBitLength">Length of write [bit].</param> +/// <param name="puchDataBuffer">OTP data to write.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_OTP_SetBits(int iOtpId, int iBitStart, int iBitLength, unsigned char *puchDataBuffer) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + uint32 Bytes = 0; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + Bytes = (iBitLength + 7) / 8; + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_OTP_SetBits(uiSessionOut, iOtpId, iBitStart, iBitLength, Bytes, puchDataBuffer)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_OTP, COMMAND_OTP_SETBITS)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command writes (burns) all data from loader internal OTP structures in RAM into the OTP fuse box. +/// </summary> +/// <param name="iOtpId">OTP area ID.</param> +/// <param name="iForceWrite">If true: write and lock all lockable areas even if not all bits are received in cache.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_OTP_WriteAndLock(int iOtpId, int iForceWrite) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_OTP_WriteAndLock(uiSessionOut, iOtpId, iForceWrite)); + + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_OTP, COMMAND_OTP_WRITEANDLOCK)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command installs a secure object to the Boot record or OTP area. +/// </summary> +/// <param name="pchSourcePath">If iUseBulk = 1 -> path on PC, else path on ME.</param> +/// <param name="iDestination">Secure object destination address on ME.</param> +/// <param name="iUseBulk">Source on PC -> iUseBulk= 1. Source on ME -> iUseBulk= 0.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_OTP_StoreSecureObject(const char *pchSourcePath, int iDestination, int iUseBulk) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + if (iUseBulk) { + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + + VERIFY_SUCCESS(m_pBuffers->AllocateBulkFile(pchSourcePath)); + m_uiBulkLength = m_pBuffers->GetBulkFileLength(); + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Send(pchSourcePath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_OTP_StoreSecureObject(uiSessionOut, BULK_PATH, iDestination)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_OTP, COMMAND_OTP_STORESECUREOBJECT)); + } else { + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_OTP_StoreSecureObject(uiSessionOut, pchSourcePath, iDestination)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_OTP, COMMAND_OTP_STORESECUREOBJECT)); + } + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + m_pBuffers->ReleaseBulkFile(); + } + + return ReturnValue; +} + +/// <summary> +/// Reads a specified unit from the global data storage area/partition specified by the DevicePath parameter. +/// </summary> +/// <param name="iGdfsId">GDFS ID.</param> +/// <param name="iUnit">Unit ID to read.</param> +/// <param name="puchDataBuffer">Received global data.</param> +/// <param name="piSize">Size of puchDataBuffer.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_ParameterStorage_ReadGlobalDataUnit(const char *pchGdfsId, int iUnit, unsigned char *puchDataBuffer, int *piSize) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_ReadGlobalDataUnit(uiSessionOut, pchGdfsId, iUnit)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_READGLOBALDATAUNIT)); + + //Copy output parameter from RPC class. + CopyVectorToArray(m_pCmdResult->ParameterStorage_ReadGlobalDataUnit_DataBuffer, puchDataBuffer, piSize); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// Writes a specified unit to the global data storage area/partition specified by the DevicePath parameter. +/// </summary> +/// <param name="iGdfsId">GDFS ID.</param> +/// <param name="iUnit">Unit ID to write.</param> +/// <param name="puchDataBuffer">Global data to write.</param> +/// <param name="iSize">Size of puchDataBuffer.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_ParameterStorage_WriteGlobalDataUnit(const char *pchGdfsId, int iUnit, const unsigned char *puchDataBuffer, int iSize) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_WriteGlobalDataUnit(uiSessionOut, pchGdfsId, iUnit, iSize, (void *)puchDataBuffer)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_WRITEGLOBALDATAUNIT)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Reads the complete global data storage area/partition specified by the DevicePath parameter (reads all units at once). +/// </summary> +/// <param name="iGdfsId">GDFS ID.</param> +/// <param name="pchPath">If iUseBulk=1 -> path on PC to save data set to. Else path on ME.</param> +/// <param name="iUseBulk">1-> save global data on PC, 0-> save global data on ME.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_ParameterStorage_ReadGlobalDataSet(const char *pchGdfsId, const char *pchPath, int iUseBulk) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + if (iUseBulk) { + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + VERIFY_SUCCESS(m_pBulkHandler->Receive(pchPath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_ReadGlobalDataSet(uiSessionOut, pchGdfsId, BULK_PATH)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_READGLOBALDATASET)); + } else { + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_ReadGlobalDataSet(uiSessionOut, pchGdfsId, pchPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_READGLOBALDATASET)); + } + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + } + + return ReturnValue; +} + +/// <summary> +/// Writes the complete global data storage area/partition specified by the DevicePath parameter (writes all units at once). +/// </summary> +/// <param name="iGdfsId">GDFS ID.</param> +/// <param name="pchPath">f iUseBulk=1 -> path on PC. Else path on ME</param> +/// <param name="iUseBulk">1-> Global data source on PC, 0-> global data source on ME.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_ParameterStorage_WriteGlobalDataSet(const char *pchGdfsId, const char *pchPath, int iUseBulk) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + if (iUseBulk) { + VERIFY_SUCCESS(m_pBuffers->AllocateBulkFile(pchPath)); + uint64 uiLength = m_pBuffers->GetBulkFileLength(); + m_pLcmInterface->BulkSetCallbacks((void *)BulkCommandReqCallback, (void *)BulkDataReqCallback, (void *)BulkDataEndOfDumpCallback); + m_uiBulkLength = uiLength; + m_uiBulkTransferred = 0; + VERIFY_SUCCESS(m_pBulkHandler->Send(pchPath)); + + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_WriteGlobalDataSet(uiSessionOut, pchGdfsId, uiLength, BULK_PATH)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_WRITEGLOBALDATASET)); + } else { + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_WriteGlobalDataSet(uiSessionOut, pchGdfsId, 0, pchPath)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_WRITEGLOBALDATASET)); + } + +ErrorExit: + + if (iUseBulk) { + m_pBulkHandler->Finish(); + m_pBuffers->ReleaseBulkFile(); + } + + return ReturnValue; +} + +/// <summary> +/// Erases the complete global data storage area/partition specified by the DevicePath parameter. +/// </summary> +/// <param name="iGdfsId">GDFS ID.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_ParameterStorage_EraseGlobalDataSet(const char *pchGdfsId) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_ParameterStorage_EraseGlobalDataSet(uiSessionOut, pchGdfsId)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_PARAMETERSTORAGE, COMMAND_PARAMETERSTORAGE_ERASEGLOBALDATASET)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to set the ME domain. +/// </summary> +/// <param name="iDomain">Target domain.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Security_SetDomain(int iDomain) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Security_SetDomain(uiSessionOut, iDomain)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SECURITY, COMMAND_SECURITY_SETDOMAIN)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to get the ME domain. +/// </summary> +/// <param name="piWrittenDomain">The ME current domain.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Security_GetDomain(int *piWrittenDomain) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Security_GetDomain(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SECURITY, COMMAND_SECURITY_GETDOMAIN)); + + //Copy output parameter from RPC class. + *piWrittenDomain = m_pCmdResult->Security_GetDomain_WrittenDomain; + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command is used to read a security data unit (such as a secure static or dynamic data unit). +/// </summary> +/// <param name="iUnitId">Unit ID to read.</param> +/// <param name="piSize">Size of puchDataBuffer.</param> +/// <param name="puchDataBuffer">The unit data.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Security_GetProperties(int iUnitId, int *piSize, unsigned char *puchDataBuffer) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Security_GetProperties(uiSessionOut, iUnitId)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SECURITY, COMMAND_SECURITY_GETPROPERTIES)); + + //Copy output parameter from RPC class. + CopyVectorToArray(m_pCmdResult->Security_GetProperties_DataBuffer, puchDataBuffer, piSize); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// This command is used to write a security data unit (such as a secure static or dynamic data unit). +/// </summary> +/// <param name="iUnitId">Unit ID to write.</param> +/// <param name="iSize">Size of puchDataBuffer.</param> +/// <param name="puchDataBuffer">The data to write.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Security_SetProperties(int iUnitId, int iSize, const unsigned char *puchDataBuffer) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Security_SetProperties(uiSessionOut, iUnitId, iSize, (void *)puchDataBuffer)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SECURITY, COMMAND_SECURITY_SETPROPERTIES)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// This command associates all security data units with the current ME. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Security_BindProperties() +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pLoaderRpcFunctions->DoRPC_Security_BindProperties(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_SECURITY, COMMAND_SECURITY_BINDPROPERTIES)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// The A2 loader shuts down in a controlled fashion and proceeds to shut down the ME itself. +/// The ME does not accept any further communication after a successful response from this +/// command has been returned. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_A2_System_Shutdown() +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + m_pA2LoaderRpcFunctions->setTargetCpu(1); + + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_System_Shutdown(uiSessionOut)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// The PC uses the Loader version command to request version information from the loader +/// The response holds the loader version information coded as ASCII characters in the data field +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_A2_System_LoaderVersion(char *pchLoaderVersion, int *piSize, int iTargetCPU) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + m_pA2LoaderRpcFunctions->setTargetCpu(iTargetCPU); + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_System_LoaderVersion(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_SYSTEM, COMMAND_A2_SYSTEM_LOADERVERSION)); + + CopyStringToArray(m_pCmdResult->A2_LoaderVersion, pchLoaderVersion, piSize); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piSize = 0; + } + + return ReturnValue; +} + +/// <summary> +/// The Protocol version command is sent by the PC to request application protocol version from the loader. +/// The loader responds with a GR with the protocol version in the response field. +/// The version is coded as: 1 byte Major version + 1 byte Minor version. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_A2_System_Reset(int iTimeout) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + m_pA2LoaderRpcFunctions->setTargetCpu(1); + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_System_Reset(uiSessionOut, iTimeout)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// The Loader on loader command is used to transfer a new loader to the ME +/// When the header or payload has been sent, the loader responds with a GR using status codes. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_A2_System_LoaderOnLoader(const char *pchPath, int iPLOffset, int iHLOffset, int iTargetCPU) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + MemMappedFile loaderFile; + uint32 loaderSize; + uint8 *loaderData = NULL; + uint32 LeftToSend; + size_t NumberOfPackets; + const uint32 PacketSize = m_pCmdResult->A2_MaxLoaderPacketSize - 17; + uint32 PayloadOffset; + const void *temp; + uint32 HL; + uint32 HL_Real; + uint32 PL; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(loaderFile.LoadFileData(pchPath)); + loaderSize = static_cast<uint32>(loaderFile.GetFileSize()); + loaderData = loaderFile.AllocateFileData(0, loaderSize); + VERIFY(0 != loaderData, loaderFile.GetError()); + + m_pA2LoaderRpcFunctions->setTargetCpu(iTargetCPU); + + // get header length. + temp = loaderData + iHLOffset; + HL = m_pSerialization->get_uint32_le(&temp); + // pad to 8 byte (64 bit) alignments + HL_Real = (HL + 7) & ~7; + + // calculate payload length + PL = loaderSize - HL_Real; + + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_System_LoaderOnLoader(uiSessionOut, HL_Real, loaderData)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_SYSTEM, COMMAND_A2_SYSTEM_LOADERONLOADER)); + + NumberOfPackets = PL / PacketSize; + + if (NumberOfPackets *PacketSize == PL) { + NumberOfPackets--; + } + + PayloadOffset = HL_Real; + + if (NumberOfPackets > 0) { + m_pA2LoaderRpcFunctions->setMorePackets(1); + + for (size_t i = 0; i < NumberOfPackets; ++i) { + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_System_LoaderOnLoader(uiSessionOut, PacketSize, loaderData + PayloadOffset)); + PayloadOffset += PacketSize; + } + + m_pA2LoaderRpcFunctions->setMorePackets(0); + } + + // send last payload package + LeftToSend = PL - PayloadOffset + HL_Real; + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_System_LoaderOnLoader(uiSessionOut, LeftToSend, loaderData + PayloadOffset)); + + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_SYSTEM, COMMAND_A2_SYSTEM_LOADERONLOADER)); + +ErrorExit: + + if (0 != loaderData) { + loaderFile.ReleaseFileData(loaderData, 0, loaderSize); + } + + return ReturnValue; +} + +/// <summary> +/// The Program flash command is sent by the PC to write a block of data into the flash memory. +/// The block data is sent in the data field. +/// When a complete block has been transmitted the loader verifies the data and responds with a GR using status codes +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_A2_Flash_ProgramFlash(const char *pchPath, int iUseSpeedFlash) +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + MemMappedFile softwareFile; + uint32 softwareSize; + uint8 *softwareData = 0; + const void *temp; + uint32 headerSize; + uint8 *payloadData; + uint32 leftToSend; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + softwareFile.LoadFileData(pchPath); + softwareSize = static_cast<uint32>(softwareFile.GetFileSize()); + softwareData = softwareFile.AllocateFileData(0, softwareSize); + VERIFY(0 != softwareData, softwareFile.GetError()); + + // A2 header length offset = 80 + temp = softwareData + 80; + headerSize = Serialization::get_uint32_le(&temp); + headerSize = (headerSize + 7) & ~7; + + payloadData = softwareData + headerSize; + + m_pA2LoaderRpcFunctions->setTargetCpu(2); + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_Flash_VerifySignedHeader(uiSessionOut, headerSize, softwareData)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_FLASH, COMMAND_A2_FLASH_VERIFYSIGNEDHEADER)); + + leftToSend = softwareSize - headerSize; + + if (iUseSpeedFlash) { + temp = softwareData + 60; // start address is located at byte 60 + uint32 startAddress = Serialization::get_uint32_le(&temp); + + temp = softwareData + 28; // maximum block size is located at byte 28 + uint32 subBlockSize = Serialization::get_uint32_le(&temp); + + temp = softwareData + 64; // the software length (end address) is located at byte 64 + uint32 endAddress = Serialization::get_uint32_le(&temp); + + // speedflash command should be sent to ACC CPU + m_pA2LoaderRpcFunctions->setTargetCpu(1); + + // start LCM speedflash mode + m_pLcmInterface->A2SpeedflashStart(); + + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_Flash_Speedflash(uiSessionOut, startAddress, endAddress, subBlockSize)); + + while (leftToSend) { + Serialization::skip_uint32((const void **)&payloadData); //skip start address + Serialization::skip_uint32((const void **)&payloadData); //skip block size + leftToSend -= 8; // skip start address and block size in the image + + subBlockSize = min(subBlockSize, leftToSend); + + VERIFY_SUCCESS(WaitForEvent(EVENT_SPEEDFLASH, GROUP_A2_FLASH, COMMAND_A2_FLASH_SPEEDFLASH)); + + if (0 == leftToSend - subBlockSize) { + m_pLcmInterface->A2SpeedflashSetLastBlock(); + } + + VERIFY_SUCCESS(m_pLcmInterface->A2SpeedflashWriteBlock(payloadData, subBlockSize)); // send sub-block + + payloadData += subBlockSize; + leftToSend -= subBlockSize; + } + + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_FLASH, COMMAND_A2_FLASH_SPEEDFLASH)); + } else { + while (leftToSend) { + uint32 startAddress = Serialization::get_uint32_le((const void **)&payloadData); + uint32 blockSize = Serialization::get_uint32_le((const void **)&payloadData); + leftToSend -= 8; // skip start address and block size in the image + blockSize = min(blockSize, leftToSend); + + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_Flash_SoftwareBlockAddress(uiSessionOut, startAddress, blockSize)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_FLASH, COMMAND_A2_FLASH_SOFTWAREBLOCKADDRESS)); + + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_Flash_ProgramFlash(uiSessionOut, blockSize, payloadData)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_FLASH, COMMAND_A2_FLASH_PROGRAMFLASH)); + + payloadData += blockSize; + leftToSend -= blockSize; + } + } + + // verify flash command should be sent to APP CPU + m_pA2LoaderRpcFunctions->setTargetCpu(2); + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_Flash_VerifySoftwareFlash(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_FLASH, COMMAND_A2_FLASH_VERIFYSOFTWAREFLASH)); + +ErrorExit: + + if (0 != softwareData) { + softwareFile.ReleaseFileData(softwareData, 0, softwareSize); + } + + return ReturnValue; +} + +/// <summary> +/// The Erase flash command is used to erase the complete flash memory. +/// It checks what type of memory is used in the ME and erases the complete memory including the first memory block. +/// If more than one flash is attached, all of them will be erased +/// The loader responds with a GR using status codes +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_A2_Flash_EraseFlash() +{ + uint16 uiSessionOut = 0; + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + m_pA2LoaderRpcFunctions->setTargetCpu(2); + VERIFY_SUCCESS(m_pA2LoaderRpcFunctions->DoRPC_A2_Flash_EraseFlash(uiSessionOut)); + VERIFY_SUCCESS(WaitForEvent(EVENT_GR_RECEIVED, GROUP_A2_FLASH, COMMAND_A2_FLASH_ERASEFLASH)); + +ErrorExit: + return ReturnValue; +} + +int CLCDriverMethods::Done_A2_Control_LoaderStarted() +{ + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + VERIFY_SUCCESS(WaitForEvent(EVENT_CMD_RECEIVED, GROUP_A2_CONTROL, COMMAND_A2_CONTROL_LOADERSTARTED)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Switch protocol family. +/// </summary> +/// <param name="family">New protocol family to use.</param> +/// <returns>Status of the command.</returns> +int CLCDriverMethods::Do_SwitchProtocolFamily(TFamily family) +{ + int ReturnValue = E_SUCCESS; + char strMessage[100] = {0}; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + m_pMainThread->TimerOff(); + + switch (family) { + case R15_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = R15_FAMILY; + m_CurrentCEHCallback = static_cast<Do_CEH_Call_t>(CEHCallbackFunction); + strcat_s(strMessage, "Do_SetProtocolFamily(R15_FAMILY)"); + m_pMainThread->TimerOn(); + break; + case PROTROM_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = PROTROM_FAMILY; + m_CurrentCEHCallback = static_cast<Do_CEH_Call_t>(CEH_PROTROM_CallbackFunction); + strcat_s(strMessage, "Do_SwitchProtocolFamily(PROTROM_FAMILY)"); + break; + case Z_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = Z_FAMILY; + m_CurrentCEHCallback = static_cast<Do_CEH_Call_t>(CEH_Z_CallbackFunction); + strcat_s(strMessage, "Do_SwitchProtocolFamily(Z_FAMILY)"); + m_pZRpcFunctions->Z_IndataBuffer->Clear(); + break; + case A2_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = A2_FAMILY; + m_CurrentCEHCallback = static_cast<Do_CEH_Call_t>(CEH_A2_CallbackFunction); + strcat_s(strMessage, "Do_SwitchProtocolFamily(A2_FAMILY)"); + //m_pMainThread->TimerOn(); + break; + default: + return INVALID_INPUT_PARAMETERS; + } + +#ifdef _MESSAGES + m_pLogger->log(strMessage); +#endif + + VERIFY_SUCCESS(m_pMainThread->SetLcmFamily(m_CurrentProtocolFamily, m_CurrentCEHCallback)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Set ME in service mode and receive chip id. +/// </summary> +/// <param name="puiChipId">Received chip id.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Z_SetInServiceMode(unsigned int *puiChipId) +{ + int ReturnValue = E_SUCCESS; + + time_t Start = 0; + time_t End = 0; + time_t ElapsedTime = 0; + bool bEmptyBuffer = false; + unsigned char uchReceivedByte; + unsigned char rguchReceivedChipId[8]; + int iCount = 0; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + //Receive a 'z' character. + time(&Start); + time(&End); + ElapsedTime = End - Start; + + while (ElapsedTime < 30) { + uchReceivedByte = m_pZRpcFunctions->Z_IndataBuffer->Pop(&bEmptyBuffer); + + if ((bEmptyBuffer == false) && (uchReceivedByte == 'z')) { + break; + } + + time(&End); + ElapsedTime = End - Start; + OS::Sleep(2); + } + + if (ElapsedTime >= 30) { + VERIFY_SUCCESS(TIMEOUT_NO_Z_DETECTED); + } + + //Send version request. + VERIFY_SUCCESS(m_pZRpcFunctions->DoRPC_Z_VersionRequest()); + + //Receive chip id. + time(&Start); + time(&End); + ElapsedTime = End - Start; + + while (ElapsedTime < 30) { + uchReceivedByte = m_pZRpcFunctions->Z_IndataBuffer->Pop(&bEmptyBuffer); + + if (bEmptyBuffer == false) { + rguchReceivedChipId[iCount++] = uchReceivedByte; + + if (iCount == 8) { + break; + } + } + + time(&End); + ElapsedTime = End - Start; + + OS::Sleep(2); + } + + if (ElapsedTime >= 30) { + VERIFY_SUCCESS(TIMEOUT_NO_CHIP_ID_DETECTED); + } + + //Copy chip ID byte 1 and 2 + *puiChipId = rguchReceivedChipId[0] << 8; //Major byte + *puiChipId += rguchReceivedChipId[1]; //Minor byte + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Set communication baudrate when communicating via UART. +/// </summary> +/// <param name="iBaudrate">Baudrate to use. Valid values: 9600, 19200, 38400, 57600, 115200, +/// 230400, 460800, 921600, 1625000.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Z_SetBaudrate(int iBaudrate) +{ + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + VERIFY_SUCCESS(m_pZRpcFunctions->DoRPC_Z_SetBaudrate(iBaudrate)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Exit Z-protocol and start uing PROTROM-protocol. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_Z_Exit_Z_Protocol() +{ + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + m_pCommunicationDevice->Cancel(m_pLcmInterface->getLCMContext()); + + //Send exit z-protocol command. + VERIFY_SUCCESS(m_pZRpcFunctions->DoRPC_Z_Exit_Z_Protocol()); + + //Change protocol family to PROTROM + VERIFY_SUCCESS(Do_SwitchProtocolFamily(PROTROM_PROTOCOL_FAMILY)); + + //Receive PROTROM command PDU: PROTROM_PDU_READY_TO_RECEIVE. + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_READY_TO_RECEIVE)); + + //Send PROTROOM command PDU:PROTROM_PDU_RESULT. + VERIFY_SUCCESS(m_pProtromRpcFunctions->DoRPC_PROTROM_ResultPdu(0)); + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Download loader using PROTROM-protocol. +/// </summary> +/// <param name="pchPath">Path to loader on PC.</param> +/// <param name="iPLOffset">Offset in header to payload length.</param> +/// <param name="iHLOffset">Offset in header to header length.</param> +/// <param name="iContinueProtRom">1 -> continue use PROTROM-protocol after download the loader. O -> not use PROTROM-protocol after download the loader.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::Do_PROTROM_DownloadLoader(const char *pchPath, int iPLOffset, int iHLOffset, int iContinueProtRom) +{ + int ReturnValue = E_SUCCESS; + + MemMappedFile loaderFile; + uint8 *loaderData; + const void *temp; + uint32 HL; //Header length. + uint32 HL_Real; //Header length + 32 bit alignment padding + uint32 PL; //Payload length. + const uint32 PacketSize = 64000; + size_t NumberOfPackets; + uint32 PayloadOffset; + uint32 LeftToSend; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + VERIFY_SUCCESS(loaderFile.LoadFileData(pchPath)); + /* coverity[tainted_data_return] */ + loaderData = loaderFile.AllocateFileData(0, loaderFile.GetFileSize()); + VERIFY(0 != loaderData, loaderFile.GetError()); + + //Get header length. + temp = loaderData + iHLOffset; + HL = m_pSerialization->get_uint32_le(&temp); + HL_Real = (HL + 3) & ~3; //Pad to 4 byte (32 bit) alignments + + //Get payload length. + temp = loaderData + iPLOffset; + PL = m_pSerialization->get_uint32_le(&temp); + + VERIFY_SUCCESS(m_pProtromRpcFunctions->DoRPC_PROTROM_SendLoaderHeader(loaderData, HL_Real)); + + //Receive PROTROM command PDU: PROTROM_PDU_RESULT. + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_RESULT)); + + //Download all packet beside one + NumberOfPackets = PL / PacketSize; + + if (NumberOfPackets *PacketSize == PL) { + NumberOfPackets--; + } + + PayloadOffset = HL_Real; + + if (NumberOfPackets > 0) { + for (size_t i = 0; i < NumberOfPackets; ++i) { + VERIFY_SUCCESS(m_pProtromRpcFunctions->DoRPC_PROTROM_SendLoaderPayload(loaderData + PayloadOffset, PacketSize)); + PayloadOffset += PacketSize; + + //Receive PROTROM command PDU: PROTROM_PDU_RESULT. + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_RESULT)); + } + } + + if (!iContinueProtRom) { + m_pProtromRpcFunctions->CancelDeviceOnResult(m_pCommunicationDevice); + m_pLcmInterface->CommunicationCancelReceiver(2); + } + + //Send last payload package + LeftToSend = PL - PayloadOffset + HL_Real; + + VERIFY_SUCCESS(m_pProtromRpcFunctions->DoRPC_PROTROM_SendLoaderFinalPayload(loaderData + PayloadOffset, LeftToSend)); + + loaderFile.ReleaseFileData(loaderData, 0, loaderFile.GetFileSize()); + + //If downloaded loader continues to use PROTROM protocol. + if (0 != iContinueProtRom) { + //Receive PROTROM command PDU: PROTROM_PDU_RESULT. + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_RESULT)); + + //Receive PROTROM command PDU: PROTROM_PDU_READY_TO_RECEIVE. + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_READY_TO_RECEIVE)); + + //Send result pdu. + VERIFY_SUCCESS(m_pProtromRpcFunctions->DoRPC_PROTROM_ResultPdu(0)); + } else { + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_RESULT)); + } + +ErrorExit: + return ReturnValue; +} + +/// <summary> +/// Send intrinsic request to read security data using PROTROM-protocol. +/// </summary> +/// <param name="uiSecDataId">ID of the security data to be read with the intrinsic request.</param> +/// <param name="puchDataBuffer">Buffer where the read data will be stored.</param> +/// <param name="piDataLength">IN: Length of DataBuffer; OUT: Read data length.</param> +/// <returns>Status of the command.</returns> +int CLCDriverMethods::Do_PROTROM_ReadSecurityData(uint8 uiSecDataId, unsigned char *puchDataBuffer, int *piDataLength) +{ + int ReturnValue = E_SUCCESS; + + VERIFY_SUCCESS(IsMainThreadAlive()); + + VERIFY_SUCCESS(m_pProtromRpcFunctions->DoRPC_PROTROM_ReadSecurityData(uiSecDataId)); + + //Receive PROTROM command PDU: PROTROM_PDU_RESULT. + VERIFY_SUCCESS(WaitForPROTROMResponseOrCancelOrTimeout(PROTROM_PDU_SECURITY_DATA_RES)); + + CopyVectorToArray(m_pCmdResult->ProtromPayloadData, puchDataBuffer, piDataLength); + +ErrorExit: + + if (E_SUCCESS != ReturnValue) { + *piDataLength = 0; + } + + return ReturnValue; +} + +int CLCDriverMethods::SetInitialProtocolFamily(TFamily family) +{ + switch (family) { + case R15_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = R15_FAMILY; + m_CurrentCEHCallback = CEHCallbackFunction; + break; + case PROTROM_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = PROTROM_FAMILY; + m_CurrentCEHCallback = CEH_PROTROM_CallbackFunction; + break; + case Z_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = Z_FAMILY; + m_CurrentCEHCallback = CEH_Z_CallbackFunction; + break; + case A2_PROTOCOL_FAMILY: + m_CurrentProtocolFamily = A2_FAMILY; + m_CurrentCEHCallback = CEH_A2_CallbackFunction; + break; + default: + return INVALID_INPUT_PARAMETERS; + } + + return 0; +} + +void CLCDriverMethods::ConfigureCommunicationDevice(void *Read_fn, void *Write_fn, void *Cancel_fn) +{ + m_pCommunicationDevice->Read = reinterpret_cast<DeviceRead_fn>(Read_fn); + m_pCommunicationDevice->Write = reinterpret_cast<DeviceWrite_fn>(Write_fn); + m_pCommunicationDevice->Cancel = reinterpret_cast<DeviceCancel_fn>(Cancel_fn); + m_pCommunicationDevice->Context_p = NULL; +} + +void CLCDriverMethods::SetMessageCallback(void *Callback_fn) +{ + m_pLogger->setMessageCallback(reinterpret_cast<MessageCallback_t>(Callback_fn)); +} + +void CLCDriverMethods::SetProgressCallback(void *Callback_fn) +{ + m_ProgressBarUpdate = reinterpret_cast<ProgressBarCallback_t>(Callback_fn); +} + +/// <summary> +/// Set timeouts used by LCM and LCDriver. +/// </summary> +/// <param name="R15_TOs">LCM timeout data.</param> +/// <param name="LCD_TOs">LCDriver timeout data.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::SetPcTimeouts(TR15Timeouts *R15_TOs, TLCDriverTimeouts *LCD_TOs) +{ + CLockCS TimeoutLock(m_SetTimeoutCS); + + // if null, default values are used + if (LCD_TOs != NULL) { + m_Timeouts.uiRTO = LCD_TOs->uiRTO; + m_Timeouts.uiSTO = LCD_TOs->uiSTO; + } + + if (m_CurrentProtocolFamily == R15_FAMILY) { + LcmR15Timeouts timeouts; + timeouts.TCACK = R15_TOs->TCACK; + timeouts.TBCR = R15_TOs->TBCR; + timeouts.TBDR = R15_TOs->TBDR; + return m_pLcmInterface->CommunicationSetProtocolTimeouts(static_cast<void *>(&timeouts)); + } else { + return E_SUCCESS; + } +} + +/// <summary> +/// Get timeouts used by LCM and LCDriver. +/// </summary> +/// <param name="R15_TOs">LCM timeout data.</param> +/// <param name="LCD_TOs">LCDriver timeout data.</param> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::GetPcTimeouts(TR15Timeouts *R15_TOs, TLCDriverTimeouts *LCD_TOs) +{ + int ReturnValue = E_SUCCESS; + LCD_TOs->uiRTO = m_Timeouts.uiRTO; + LCD_TOs->uiSTO = m_Timeouts.uiSTO; + + if (m_CurrentProtocolFamily == R15_FAMILY) { + LcmR15Timeouts timeouts; + ReturnValue = m_pLcmInterface->CommunicationGetProtocolTimeouts(static_cast<void *>(&timeouts)); + + if (E_SUCCESS == ReturnValue) { + R15_TOs->TCACK = timeouts.TCACK; + R15_TOs->TBCR = timeouts.TBCR; + R15_TOs->TBDR = timeouts.TBDR; + R15_TOs->TBES = 0xFFFFFFFF; + } + } else { + R15_TOs->TBCR = 0; + R15_TOs->TBDR = 0; + R15_TOs->TBES = 0; + R15_TOs->TCACK = 0; + } + + return ReturnValue; +} + +/// <summary> +/// Copies a vector to an array. +/// </summary> +/// <param name="Source">Source data.</param> +/// <param name="pDestination">The destination to write data to.</param> +/// <param name="piSize">Size of data to write.</param> +/// <returns> Void.</returns> +template <class T, class U> +void CLCDriverMethods::CopyVectorToArray(const vector<T>& Source, U *pDestination, int *piSize) +{ + size_t copyLength = *piSize; + + if (Source.size() < copyLength) { + copyLength = Source.size(); + } + + for (size_t i = 0; i < copyLength; i++) { + pDestination[i] = Source[i]; + } + + *piSize = static_cast<int>(copyLength); +} + +void CLCDriverMethods::CopyStringToArray(string &Source, char *pDestination, int *piSize) +{ + if (Source.size() > static_cast<size_t>(*piSize)) { + // erase part of the string that won't fit in the buffer + Source.erase(*piSize - 1); + } + + strcpy_s(pDestination, *piSize, Source.c_str()); + *piSize = Source.size(); +} + +/// <summary> +/// Check whether main thread is alive and perform other checks. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::IsMainThreadAlive() +{ + if (0 != m_pMainThread->ThreadIsDying()) { + if (m_pMainThread->ThreadIsDying() == 2) { + return LCDRIVER_THREAD_KILLED_WITH_SIGNAL_DEATH; + } else if (m_pMainThread->ThreadIsDying() == 3) { + return LCDRIVER_THREAD_KILLED_WITH_CANCEL; + } else { + return LCDRIVER_THREAD_KILLED; + } + } + + return 0; +} + +/// <summary> +/// Wait for General Response from ME. +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::WaitForEvent(uint32 event, int Group, int Command) +{ + int iResult; + Event *receivedEvent; + CLockCS TimeoutLock(m_SetTimeoutCS); + + m_pLogger->log("WaitForEvent: Entering method. Event = 0x%08x, Timeout = %d", event, m_Timeouts.uiRTO); + RemoveResult result = m_EventQueue.RemoveHead(reinterpret_cast<void **>(&receivedEvent), m_Timeouts.uiRTO); + + // always wait for error event + event |= EVENT_ERROR; + + if (REMOVE_SUCCESS == result) { + switch (receivedEvent->event & event) { + case EVENT_GR_RECEIVED: + if (receivedEvent->group == Group && + receivedEvent->command == Command) { + m_pLogger->log("WaitForEvent: General Response received. Number = %d", receivedEvent->command); + iResult = receivedEvent->error; + } else { + m_pLogger->log("Expected GR command # %d", Command); + m_pLogger->log("Expected GR application (group) # %d", Group); + m_pLogger->log("Received GR command # %d", receivedEvent->command); + m_pLogger->log("Received GR application (group) # %d", receivedEvent->group); + iResult = GENERAL_RESPONSE_COMMAND_NUMBER_ERROR; + } + + break; + case EVENT_CMD_RECEIVED: + if ((receivedEvent->group == Group && receivedEvent->command == Command) || + (Group == GROUP_SYSTEM && Command == COMMAND_SYSTEM_AUTHENTICATE)) { + m_pLogger->log("WaitForEvent: Expected command received"); + iResult = 0; + } else { + m_pLogger->log("WaitForEvent: ERROR Unexpected command received"); + iResult = COMMAND_NUMBER_ERROR; + } + + break; + case EVENT_SPEEDFLASH: + m_pLogger->log("WaitForEvent: Speedflash request received."); + iResult = 0; + break; + case EVENT_ERROR: + iResult = receivedEvent->error; + break; + default: + iResult = UNEXPECTED_EVENT_RECEIVED; + break; + } + } else if (REMOVE_CANCEL == result) { + m_pLogger->log("WaitForEvent: Cancel received"); + iResult = CANCEL_EVENT_RECEIVED; + } else if (REMOVE_TIMEOUT == result) { + m_pLogger->log("WaitForEvent: Timeout"); + iResult = TIMEOUT; + } else { + m_pLogger->log("WaitForEvent: Unknown return value"); + iResult = UNKNOWN_WAIT_RETURN_VALUE; + } + + return iResult; +} + +/// <summary> +/// Wait for specific Protrom response. +/// <param name="iReceivePdu">Which PDU to wait for.</param> +/// </summary> +/// <returns> Status of the command.</returns> +int CLCDriverMethods::WaitForPROTROMResponseOrCancelOrTimeout(int iReceivePdu) +{ + int iResult; + bool Continue = false; + TProtromInfo *pInfo = 0; + CLockCS TimeoutLock(m_SetTimeoutCS); + + do { + Continue = false; + m_pLogger->log("WaitForPROTROMResponseOrCancelOrTimeout: WAIT - expected PDU = %d", iReceivePdu); + + RemoveResult result = m_pProtromRpcFunctions->ProtromQueue.RemoveRequest(reinterpret_cast<void **>(&pInfo), m_Timeouts.uiRTO); + + if (REMOVE_SUCCESS == result) { + iResult = 0; + + if (pInfo->ReceivedPdu != iReceivePdu) { + m_pLogger->log("WaitForPROTROMResponseOrCancelOrTimeout: RECEIVE - unexpected PDU %d", pInfo->ReceivedPdu); + Continue = true; + } else if (iReceivePdu == PROTROM_PDU_RESULT) { + //Check result from PDU_RESULT + if (pInfo->Status != 0) { + iResult = PROTROM_STATUS_NOT_OK; + } + } + + delete[](uint8 *)pInfo->DataP; + delete pInfo; + } else if (REMOVE_CANCEL == result) { + m_pLogger->log("WaitForPROTROMResponseOrCancelOrTimeout: CANCEL"); + iResult = CANCEL_EVENT_RECEIVED; + } else if (REMOVE_TIMEOUT == result) { + m_pLogger->log("WaitForPROTROMResponseOrCancelOrTimeout: TIMEOUT"); + iResult = TIMEOUT; + } else { + m_pLogger->log("WaitForPROTROMResponseOrCancelOrTimeout: UNKNOWN"); + iResult = UNKNOWN_WAIT_RETURN_VALUE; + } + } while (Continue); + + return iResult; +} + +void CLCDriverMethods::Do_BulkDataReqCallback(uint16 *Session_p, uint32 *ChunkSize_p, uint64 *Offset_p, uint32 *Length_p, uint64 *TotalLength_p, uint32 *TransferredLength_p) +{ + m_uiBulkTransferred += *ChunkSize_p; +} + +void CLCDriverMethods::UpdateBulkProgress() +{ + if (NULL != m_ProgressBarUpdate) { + m_ProgressBarUpdate(m_pLcmInterface->getLCMContext(), m_uiBulkLength, m_uiBulkTransferred); + } +} + +void CLCDriverMethods::Do_BulkDataEndOfDumpCallback() +{ +#ifdef _BULKDEBUG + m_pLogger->log("BULK: END OF DUMP CALLBACK RECEIVED!"); +#endif +} + +int CLCDriverMethods::MapLcmError(int error) +{ + switch (error) { + case E_RETRANSMITION_FAILED: + return LCM_RETRANSMISSION_ERROR; + case E_GENERAL_COMMUNICATION_ERROR: + return LCM_DEVICE_WRITE_ERROR; + default: + return error; + } +} + +void CLCDriverMethods::SignalError(int error) +{ + Event *event = new Event(EVENT_ERROR, error); + m_EventQueue.AddTail(event); +} + +void CLCDriverMethods::AddEvent(Event *newEvent) +{ + m_EventQueue.AddTail(newEvent); +} |