diff --git a/targets/os/mbed-os/nanoBooter/.gitignore b/targets/os/mbed-os/nanoBooter/.gitignore new file mode 100644 index 0000000000..2e4be499d2 --- /dev/null +++ b/targets/os/mbed-os/nanoBooter/.gitignore @@ -0,0 +1,3 @@ +Build/ +mbed-os/ +mbed* \ No newline at end of file diff --git a/targets/os/mbed-os/nanoBooter/README.md b/targets/os/mbed-os/nanoBooter/README.md new file mode 100644 index 0000000000..5b140d7eb5 --- /dev/null +++ b/targets/os/mbed-os/nanoBooter/README.md @@ -0,0 +1,58 @@ +## nanoBooter mbed-os Example + +This is the nanoBooter example implementation for mbed-os. + +### Prerequisites + +1. ARM mbed Command Line Interface [mbed-cli](https://github.com/ARMmbed/mbed-cli) + * Requires Python 2.7.x and git +2. Command-line compiler or IDE toolchain + * GCC ARM, IAR, Keil uVision + +### Building nanoBooter + +1. Switch to `nanoBooter` directory and open command line window, +2. Make sure Python scripts and git executable are in the PATH, + otherwise execute + ``` + PATH=C:\Apps\Python27\Scripts;C:\Program Files\Git\bin;%PATH% + ``` +3. Create a new mbed-os progam in the current directory + ``` + mbed new . + ``` + It will take a moment for mbed-cli to download mbed-os git repository. + +4. Configure toolchain path + ``` + mbed config --global GCC_ARM_PATH C:\Apps\GCC\5.4-2016q3\bin + ``` + +5. Optional: Configure default toolchain and target + ``` + mbed toolchain GCC_ARM + mbed target NUCLEO_F072RB + ``` + To list supported targets launch + ``` + mbed target -S + ``` + +6. Compile nanoBooter + ``` + mbed compile + ``` + If toolchain and target were not set in step 5, use command line parameters + ``` + mbed compile -t -m + ``` + +7. Deploy binary image `BUILD\\\nanoBooter.bin` + +### Important notes and limitations + +* nanoBooter recognizes and responds only to Ping request, +* The reply is not correctly received in MFDeploy due to invalid CRC, +* WireProtocol implementation is duplicated at the moment (the source code will be added as proper mbed-os library), +* Used serial (USART) transport, +* nanoBooter code is in the main.cpp (will be moved to completely separated library/component). \ No newline at end of file diff --git a/targets/os/mbed-os/nanoBooter/TinyCLR_Messaging.h b/targets/os/mbed-os/nanoBooter/TinyCLR_Messaging.h new file mode 100644 index 0000000000..9ac8085261 --- /dev/null +++ b/targets/os/mbed-os/nanoBooter/TinyCLR_Messaging.h @@ -0,0 +1,194 @@ +//--------------------------------------------------------------------------- +// Copyright (c) 2016 The nano Framework Interpreter project contributors +// Copyright (c) Microsoft Corporation. All rights reserved. +//--------------------------------------------------------------------------- + +#ifndef _TINYCLR_MESSAGING_H_ +#define _TINYCLR_MESSAGING_H_ + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#include + +#include + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#if NUM_MESSAGING > 1 + #define TINYCLR_FOREACH_MESSAGING(ptr) \ + for(int iMessageT = 0; iMessageT < NUM_MESSAGING; iMessageT++) \ + { \ + CLR_Messaging& ptr = g_CLR_Messaging[ iMessageT ]; + +#define TINYCLR_FOREACH_MESSAGING_NO_TEMP() \ + for(int iMessageT = 0; iMessageT < NUM_MESSAGING; iMessageT++) \ + { +#else + #define TINYCLR_FOREACH_MESSAGING(ptr) \ + { \ + CLR_Messaging& ptr = g_CLR_Messaging[ 0 ]; + + #define TINYCLR_FOREACH_MESSAGING_NO_TEMP() \ + { +#endif + +#define TINYCLR_FOREACH_MESSAGING_END() \ + } + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef bool (*CLR_Messaging_CommandHandler)( WP_Message* msg, void* owner ); + +struct CLR_Messaging_CommandHandlerLookup +{ + CLR_Messaging_CommandHandler hnd; + UINT32 cmd; +}; + +struct CLR_Messaging_CommandHandlerLookups +{ + const CLR_Messaging_CommandHandlerLookup* table; + void* owner; + CLR_UINT32 size; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +struct CLR_Messaging_Commands +{ + static const UINT32 c_Messaging_Query = 0x00020090; // Checks the presence of an EndPoint. + static const UINT32 c_Messaging_Send = 0x00020091; // Sends a message to an EndPoint. + static const UINT32 c_Messaging_Reply = 0x00020092; // Response from an EndPoint. + + struct Messaging_Query + { + CLR_RT_HeapBlock_EndPoint::Address m_addr; + + struct Reply + { + CLR_UINT32 m_found; + CLR_RT_HeapBlock_EndPoint::Address m_addr; + }; + }; + + struct Messaging_Send + { + CLR_RT_HeapBlock_EndPoint::Address m_addr; + UINT8 m_data[ 1 ]; + + struct Reply + { + CLR_UINT32 m_found; + CLR_RT_HeapBlock_EndPoint::Address m_addr; + }; + }; + + struct Messaging_Reply + { + CLR_RT_HeapBlock_EndPoint::Address m_addr; + UINT8 m_data[ 1 ]; + + struct Reply + { + CLR_UINT32 m_found; + CLR_RT_HeapBlock_EndPoint::Address m_addr; + }; + }; + +}; + + +struct CLR_Messaging +{ + struct CachedMessage : public CLR_RT_HeapBlock_Node + { + static const CLR_UINT32 c_Processed = 0x00000001; + + CLR_UINT32 m_flags; + + CLR_UINT32 m_size; + CLR_INT64 m_lastSeen; + WP_Message m_message; + }; + + //--// + + CLR_Messaging_CommandHandlerLookups m_Lookup_Requests[ 2 ]; + CLR_Messaging_CommandHandlerLookups m_Lookup_Replies[ 2 ]; + + static const CLR_UINT32 c_MaxCacheSize = 5 * 1024; + + WP_Controller m_controller; + + CLR_RT_DblLinkedList m_cacheSubordinate; + CLR_RT_DblLinkedList m_cacheMaster; + CLR_UINT32 m_cacheTotalSize; + + COM_HANDLE m_port; + + //--// + + static HRESULT CreateInstance(); + + void Initialize(COM_HANDLE port, const CLR_Messaging_CommandHandlerLookup* requestLookup, const CLR_UINT32 requestLookupCount, const CLR_Messaging_CommandHandlerLookup* replyLookup, const CLR_UINT32 replyLookupCount, void* owner ); + void Cleanup(); + + static HRESULT DeleteInstance(); + + void ProcessCommands(); + void PurgeCache (); + + bool SendEvent ( UINT32 cmd, UINT32 payloadSize, UINT8* payload, UINT32 flags ); + static void BroadcastEvent( UINT32 cmd, UINT32 payloadSize, UINT8* payload, UINT32 flags ); + + void ReplyToCommand( WP_Message* msg, bool fSuccess, bool fCritical, void* ptr, int size ); + void ReplyToCommand( WP_Message* msg, bool fSuccess, bool fCritical ); + + static bool Phy_ReceiveBytes ( void* state, UINT8*& ptr, UINT32 & size ); + static bool Phy_TransmitMessage( void* state, const WP_Message* msg ); + + static bool App_ProcessHeader ( void* state, WP_Message* msg ); + static bool App_ProcessPayload( void* state, WP_Message* msg ); + static bool App_Release ( void* state, WP_Message* msg ); + + bool IsDebuggerInitialized() { return m_fDebuggerInitialized; } + void InitializeDebugger() { m_fDebuggerInitialized = (DebuggerPort_Initialize( m_port ) == TRUE); } + +private: + + bool m_fInitialized; + bool m_fDebuggerInitialized; + + bool AllocateAndQueueMessage( CLR_UINT32 cmd, UINT32 length, UINT8* data, CLR_RT_HeapBlock_EndPoint::Port port, CLR_RT_HeapBlock_EndPoint::Address addr, CLR_UINT32 found ); + + bool ProcessHeader ( WP_Message* msg ); + bool ProcessPayload( WP_Message* msg ); + + + void PurgeCache( CLR_RT_DblLinkedList& lst, CLR_INT64 oldest ); + + bool TransmitMessage( const WP_Message* msg, bool fQueue ); + +public: + static bool Messaging_Query ( WP_Message* msg, void* owner ); + static bool Messaging_Query__Reply ( WP_Message* msg, void* owner ); + static bool Messaging_Send ( WP_Message* msg, void* owner ); + static bool Messaging_Send__Reply ( WP_Message* msg, void* owner ); + static bool Messaging_Reply ( WP_Message* msg, void* owner ); + static bool Messaging_Reply__Reply ( WP_Message* msg, void* owner ); +#if defined(NETMF_TARGET_BIG_ENDIAN) +public: + static void SwapDebuggingValue ( UINT8* &msg, UINT32 size ); + static void SwapEndian ( WP_Message* msg, void* ptr, int size, bool fReply ); + static UINT32 SwapEndianPattern ( UINT8* &buffer, UINT32 size, UINT32 count=1 ); +#endif +}; + +//--// + +extern CLR_UINT32 g_scratchMessaging[]; +extern CLR_Messaging *g_CLR_Messaging; + +//--// + +#endif // _TINYCLR_MESSAGING_H_ diff --git a/targets/os/mbed-os/nanoBooter/WireProtocol.cpp b/targets/os/mbed-os/nanoBooter/WireProtocol.cpp new file mode 100644 index 0000000000..c7b31e4fac --- /dev/null +++ b/targets/os/mbed-os/nanoBooter/WireProtocol.cpp @@ -0,0 +1,397 @@ +//--------------------------------------------------------------------------- +// Copyright (c) 2016 The nano Framework Interpreter project contributors +// Copyright (c) Microsoft Corporation. All rights reserved. +//--------------------------------------------------------------------------- + +#include + +#define TRACE0(f, msg, ...) +#define TRACE(f, msg, ...) + + +UINT32 SUPPORT_ComputeCRC(const void* rgBlock, int nLength, UINT32 crc); + + +///////////////////////////////////////////////////////////////////////////// +// +// WP_Message +// + +void WP_Message::Initialize(WP_Controller* parent) +{ + m_parent = parent; + + memset(&m_header, 0, sizeof(m_header)); + m_payload = NULL; + m_pos = NULL; + m_size = 0; + m_payloadTicks = 0; + m_rxState = ReceiveState::Idle; +} + +void WP_Message::PrepareReception() +{ + m_rxState = ReceiveState::Initialize; +} + +void WP_Message::PrepareRequest(UINT32 cmd, UINT32 flags, UINT32 payloadSize, UINT8* payload) +{ + memcpy(m_header.m_signature, m_parent->m_szMarker ? m_parent->m_szMarker : MARKER_PACKET_V1, sizeof(m_header.m_signature)); + + m_header.m_crcData = SUPPORT_ComputeCRC(payload, payloadSize, 0); + m_header.m_cmd = cmd; + m_header.m_seq = m_parent->m_lastOutboundMessage++; + m_header.m_seqReply = 0; + m_header.m_flags = flags; + m_header.m_size = payloadSize; + m_payload = payload; + + // + // The CRC for the header is computed setting the CRC field to zero and then running the CRC algorithm. + // + m_header.m_crcHeader = 0; + m_header.m_crcHeader = SUPPORT_ComputeCRC((UINT8*)&m_header, sizeof(m_header), 0); +} + +void WP_Message::PrepareReply(const WP_Packet& req, UINT32 flags, UINT32 payloadSize, UINT8* payload) +{ + memcpy(m_header.m_signature, m_parent->m_szMarker ? m_parent->m_szMarker : MARKER_PACKET_V1, sizeof(m_header.m_signature)); + + m_header.m_crcData = SUPPORT_ComputeCRC(payload, payloadSize, 0); + m_header.m_cmd = req.m_cmd; + m_header.m_seq = m_parent->m_lastOutboundMessage++; + m_header.m_seqReply = req.m_seq; + m_header.m_flags = flags | WP_Flags::c_Reply; + m_header.m_size = payloadSize; + m_payload = payload; + + // + // The CRC for the header is computed setting the CRC field to zero and then running the CRC algorithm. + // + m_header.m_crcHeader = 0; + m_header.m_crcHeader = SUPPORT_ComputeCRC((UINT8*)&m_header, sizeof(m_header), 0); +} + +void WP_Message::SetPayload(UINT8* payload) +{ + m_payload = payload; +} + +void WP_Message::Release() +{ + if(m_payload) + { + m_parent->m_app->Release(m_parent->m_state, this); + m_payload = NULL; + } +} + +bool WP_Message::VerifyHeader() +{ + UINT32 crc = m_header.m_crcHeader; + m_header.m_crcHeader = 0; + UINT32 computedCrc = SUPPORT_ComputeCRC((UINT8*)&m_header, sizeof(m_header), 0); + m_header.m_crcHeader = crc; + + if(computedCrc != crc) + { + TRACE(TRACE_ERRORS, "Header CRC check failed: computed: 0x%08X; got: 0x%08X\n", computedCrc, m_header.m_crcHeader); + return false; + } + return true; +} + +bool WP_Message::VerifyPayload() +{ + if(m_payload == NULL && m_header.m_size) + { + return false; + } + + UINT32 computedCrc = SUPPORT_ComputeCRC(m_payload, m_header.m_size, 0); + if(computedCrc != m_header.m_crcData) + { + TRACE(TRACE_ERRORS, "Payload CRC check failed: computed: 0x%08X; got: 0x%08X\n", computedCrc, m_header.m_crcData); + return false; + } + return true; +} + +void WP_Message::ReplyBadPacket(UINT32 flags) +{ + WP_Message msg; + msg.Initialize(m_parent); + msg.PrepareRequest(0, WP_Flags::c_NonCritical | WP_Flags::c_NACK | flags, 0, NULL); + + m_parent->SendProtocolMessage(msg); +} + +bool WP_Message::Process() +{ + UINT8* buf = (UINT8*)&m_header; + int len; + + while(true) + { + switch(m_rxState) + { + case ReceiveState::Idle: + TRACE0(TRACE_STATE, "RxState==IDLE\n"); + return true; + + case ReceiveState::Initialize: + TRACE0(TRACE_STATE, "RxState==INIT\n"); + Release(); + + m_rxState = ReceiveState::WaitingForHeader; + m_pos = (UINT8*)&m_header; + m_size = sizeof(m_header); + break; + + case ReceiveState::WaitingForHeader: + TRACE0(TRACE_STATE, "RxState==WaitForHeader\n"); + if(m_parent->m_phy->ReceiveBytes(m_parent->m_state, m_pos, m_size) == false) + { + TRACE0(TRACE_NODATA, "ReceiveBytes returned false - bailing out\n"); + return true; + } + + // + // Synch to the start of a message. + // + while(true) + { + len = sizeof(m_header) - m_size; + if(len <= 0) + { + break; + } + + size_t lenCmp = min(len, sizeof(m_header.m_signature)); + + if(memcmp(&m_header, MARKER_DEBUGGER_V1, lenCmp) == 0) + { + break; + } + if(memcmp(&m_header, MARKER_PACKET_V1, lenCmp) == 0) + { + break; + } + + memmove(&buf[0], &buf[1], len-1); + + m_pos--; + m_size++; + } + + if(len >= sizeof(m_header.m_signature)) + { + m_rxState = ReceiveState::ReadingHeader; + } + break; + + case ReceiveState::ReadingHeader: + TRACE0(TRACE_STATE, "RxState==ReadingHeader\n"); + if(m_parent->m_phy->ReceiveBytes(m_parent->m_state, m_pos, m_size) == false) + { + TRACE0(TRACE_NODATA, "ReceiveBytes returned false - bailing out\n"); + return true; + } + + if(m_size == 0) + { + m_rxState = ReceiveState::CompleteHeader; + } + break; + + case ReceiveState::CompleteHeader: + { + TRACE0(TRACE_STATE, "RxState=CompleteHeader\n"); + + bool fBadPacket = true; + + if(VerifyHeader()) + { + TRACE(TRACE_HEADERS, "RXMSG: 0x%08X, 0x%08X, 0x%08X\n", m_header.m_cmd, m_header.m_flags, m_header.m_size); + if(m_parent->m_app->ProcessHeader(m_parent->m_state, this)) + { + fBadPacket = false; + + if(m_header.m_size) + { + if(m_payload == NULL) // Bad, no buffer... + { + m_rxState = ReceiveState::Initialize; + } + else + { + // FIXME: m_payloadTicks = HAL_Time_CurrentTicks(); + m_rxState = ReceiveState::ReadingPayload; + m_pos = (UINT8*)m_payload; + m_size = m_header.m_size; + } + } + else + { + m_rxState = ReceiveState::CompletePayload; + } + } + } + + if(fBadPacket) + { + if((m_header.m_flags & WP_Flags::c_NonCritical) == 0) + { + ReplyBadPacket(WP_Flags::c_BadHeader); + } + + m_rxState = ReceiveState::Initialize; + } + } + break; + + case ReceiveState::ReadingPayload: + { + TRACE0(TRACE_STATE, "RxState=ReadingPayload\n"); + + // FIXME: UINT64 curTicks = HAL_Time_CurrentTicks(); + + // If the time between consecutive payload bytes exceeds the timeout threshold then assume that + // the rest of the payload is not coming. Reinitialize to synch on the next header. + + // FIXME: if(HAL_Time_TicksToTime(curTicks - m_payloadTicks) < (UINT64)c_PayloadTimeout) + { + // FIXME: m_payloadTicks = curTicks; + + if(m_parent->m_phy->ReceiveBytes(m_parent->m_state, m_pos, m_size) == false) + { + TRACE0(TRACE_NODATA, "ReceiveBytes returned false - bailing out\n"); + return true; + } + + if(m_size == 0) + { + m_rxState = ReceiveState::CompletePayload; + } + } + // FIXME: else + //{ + // TRACE0(TRACE_ERRORS, "RxError: Payload InterCharacterTimeout exceeded\n"); + // m_rxState = ReceiveState::Initialize; + //} + } + break; + + case ReceiveState::CompletePayload: + TRACE0(TRACE_STATE, "RxState=CompletePayload\n"); + if(VerifyPayload() == true) + { + m_parent->m_app->ProcessPayload(m_parent->m_state, this); + } + else + { + ReplyBadPacket(WP_Flags::c_BadPayload); + } + + m_rxState = ReceiveState::Initialize; + break; + + + default: + TRACE0(TRACE_ERRORS, "RxState=UNKNOWN!!\n"); + return false; + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// +// WP_Controller +// + +void WP_Controller::Initialize(LPCSTR szMarker, const WP_PhysicalLayer* phy, const WP_ApplicationLayer* app, void* state) +{ + m_szMarker = szMarker; + m_phy = phy; + m_app = app; + m_state = state; + m_lastOutboundMessage = 0; + + memset(&m_inboundMessage, 0, sizeof(m_inboundMessage)); + + m_inboundMessage.Initialize(this); + m_inboundMessage.PrepareReception(); +} + +bool WP_Controller::AdvanceState() +{ + return m_inboundMessage.Process(); +} + +bool WP_Controller::SendProtocolMessage(const WP_Message& msg) +{ + TRACE(TRACE_HEADERS, "TXMSG: 0x%08X, 0x%08X, 0x%08X\n", msg.m_header.m_cmd, msg.m_header.m_flags, msg.m_header.m_size); + return m_phy->TransmitMessage(m_state, &msg); +} + +bool WP_Controller::SendProtocolMessage(UINT32 cmd, UINT32 flags, UINT32 payloadSize, UINT8* payload) +{ + WP_Message msg; + msg.Initialize(this); + msg.PrepareRequest(cmd, flags, payloadSize, payload); + + return SendProtocolMessage(msg); +} + +///////////////////////////////////////////////////////////////////////////// +// +// CRC 32 table for use under ZModem protocol, IEEE 802 +// G(x) = x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1 +// +static const UINT32 c_CRCTable[256] = +{ + 0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, + 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, + 0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, + 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, + 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, + 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, + 0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, + 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, + 0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, + 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, + 0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, + 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, + 0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, + 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, + 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, + 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, + 0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, + 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, + 0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, + 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, + 0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, + 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, + 0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, + 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, + 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, + 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, + 0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, + 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, + 0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, + 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, + 0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, + 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4 +}; + +UINT32 SUPPORT_ComputeCRC(const void* rgBlock, int nLength, UINT32 crc) +{ + const UINT8* ptr = (const UINT8*)rgBlock; + + while(nLength-- > 0) + { + crc = c_CRCTable[((crc >> 24) ^ (*ptr++)) & 0xFF] ^ (crc << 8); + } + + return crc; +} diff --git a/targets/os/mbed-os/nanoBooter/WireProtocol.h b/targets/os/mbed-os/nanoBooter/WireProtocol.h new file mode 100644 index 0000000000..10955a6302 --- /dev/null +++ b/targets/os/mbed-os/nanoBooter/WireProtocol.h @@ -0,0 +1,183 @@ +//--------------------------------------------------------------------------- +// Copyright (c) 2016 The nano Framework Interpreter project contributors +// Copyright (c) Microsoft Corporation. All rights reserved. +//--------------------------------------------------------------------------- + +#ifndef _SUPPORT_WIREPROTOCOL_H_ +#define _SUPPORT_WIREPROTOCOL_H_ + +///////////////////////////////////////////////////////////////////////////// + +#if defined(_MSC_VER) +#pragma pack(push, SUPPORT_WIREPROTOCOL_H_, 4) +#endif + +// FIXME: xxx_Types.h + +//#include +// TinyHAL_Types.h + +#include + +typedef unsigned char UINT8; +typedef unsigned short int UINT16; +typedef unsigned int UINT32; +typedef uint64_t UINT64; + +typedef const char* LPCSTR; + +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif + +#include +#include + +///////////////////////////////////////////////////////////////////////////// + +// +// Keep these strings less than 7-characters long!! +// They are stuffed into an 8-byte structure (\0 terminated). +// +#define MARKER_DEBUGGER_V1 "MSdbgV1" // Used to identify the debugger at boot time. +#define MARKER_PACKET_V1 "MSpktV1" // Used to identify the start of a packet. + +//--// + +struct WP_Packet; +struct WP_PhysicalLayer; +struct WP_ApplicationLayer; +struct WP_Message; +struct WP_Controller; + +//--// + +struct WP_Flags +{ + static const UINT16 c_NonCritical = 0x0001; // This doesn't need an acknowledge. + static const UINT16 c_Reply = 0x0002; // This is the result of a command. + static const UINT16 c_BadHeader = 0x0004; + static const UINT16 c_BadPayload = 0x0008; + static const UINT16 c_Spare0010 = 0x0010; + static const UINT16 c_Spare0020 = 0x0020; + static const UINT16 c_Spare0040 = 0x0040; + static const UINT16 c_Spare0080 = 0x0080; + static const UINT16 c_Spare0100 = 0x0100; + static const UINT16 c_Spare0200 = 0x0200; + static const UINT16 c_Spare0400 = 0x0400; + static const UINT16 c_Spare0800 = 0x0800; + static const UINT16 c_Spare1000 = 0x1000; + static const UINT16 c_NoCaching = 0x2000; + static const UINT16 c_NACK = 0x4000; + static const UINT16 c_ACK = 0x8000; +}; + +struct WP_Packet +{ + UINT8 m_signature[8]; + UINT32 m_crcHeader; + UINT32 m_crcData; + + UINT32 m_cmd; + UINT16 m_seq; + UINT16 m_seqReply; + UINT32 m_flags; + UINT32 m_size; +}; + +//--// + +struct WP_PhysicalLayer +{ + // + // TransmitMessage has to be fully buffered, in the sense it should accept all the input and return. + // Blocking behavior has to be hidden in the driver. + // + bool (*ReceiveBytes)(void* state, UINT8*& ptr, UINT32 & size); + bool (*TransmitMessage)(void* state, const WP_Message* msg); +}; + +struct WP_ApplicationLayer +{ + bool (*ProcessHeader)(void* state, WP_Message* msg); + bool (*ProcessPayload)(void* state, WP_Message* msg); + bool (*Release)(void* state, WP_Message* msg); +}; + +//--// + +struct WP_Message +{ + struct ReceiveState + { + static const int Idle = 0; + static const int Initialize = 1; + static const int WaitingForHeader = 2; + static const int ReadingHeader = 3; + static const int CompleteHeader = 4; + static const int ReadingPayload = 5; + static const int CompletePayload = 6; + }; + + static const UINT32 c_PayloadTimeout = 60000000; // 6 secs (100 nsecs units) + + WP_Controller* m_parent; + WP_Packet m_header; + UINT8* m_payload; + +// UNDONE: FIXME: private: + UINT8* m_pos; + UINT32 m_size; + UINT64 m_payloadTicks; + int m_rxState; + +public: + void Initialize(WP_Controller* parent); + void PrepareReception(); + void PrepareRequest(UINT32 cmd, UINT32 flags, UINT32 payloadSize, UINT8* payload); + void PrepareReply(const WP_Packet& req, UINT32 flags, UINT32 payloadSize, UINT8* payload); + void SetPayload(UINT8* payload); + void Release(); + bool Process(); + +private: + bool VerifyHeader (); + bool VerifyPayload(); + void ReplyBadPacket(UINT32 flags); +}; + +struct WP_Controller +{ + LPCSTR m_szMarker; + const WP_PhysicalLayer* m_phy; + const WP_ApplicationLayer* m_app; + void* m_state; + + WP_Message m_inboundMessage; + UINT16 m_lastOutboundMessage; + + + void Initialize(LPCSTR szMarker, const WP_PhysicalLayer* phy, const WP_ApplicationLayer* app, void* state); + bool AdvanceState(); + bool SendProtocolMessage(const WP_Message& msg); + bool SendProtocolMessage(UINT32 cmd, UINT32 flags = 0, UINT32 payloadSize = 0, UINT8* payload = NULL); +}; + +//--// + +// +// This structure is never used, its purpose is to generate +// a compiler error in case the size of any structure changes. +// +struct WP_CompileCheck +{ + char buf1[sizeof(WP_Packet) == 8*4 ? 1 : -1]; +}; + +//--// + +#if defined(_MSC_VER) +#pragma pack(pop, SUPPORT_WIREPROTOCOL_H_) +#endif + +#endif // _SUPPORT_WIREPROTOCOL_H_ diff --git a/targets/os/mbed-os/nanoBooter/main.cpp b/targets/os/mbed-os/nanoBooter/main.cpp new file mode 100644 index 0000000000..780bd22522 --- /dev/null +++ b/targets/os/mbed-os/nanoBooter/main.cpp @@ -0,0 +1,300 @@ +//--------------------------------------------------------------------------- +// Copyright (c) 2016 The nano Framework Interpreter project contributors +//--------------------------------------------------------------------------- + +#include "mbed.h" +#include +#include + + +DigitalOut led1(LED1, 0); // Initially OFF + + +// +// Serial that does not implement locking, so it can be used from within interrupt handler. +// +class MySerial : public SerialBase +{ +public: + MySerial(PinName tx, PinName rx, int baud) : SerialBase(tx, rx, baud) + { + } + + int getc() + { + return _base_getc(); + } + + int putc(int c) + { + return _base_putc(c); + } + + int readable() + { + int ret = serial_readable(&_serial); + return ret; + } + + void lock() { } + + void unlock() { } +}; + + +MySerial serial(USBTX, USBRX, 115200); + +const int32_t signalDataIn = 0x10; + +const int BufferSize = 255; + +uint8_t rxBuffer[BufferSize + 1]; + +volatile int rxIn = 0; +volatile int rxOut = 0; + +WP_Message wpMessage; + +Thread rt; + +extern UINT32 SUPPORT_ComputeCRC(const void* rgBlock, int nLength, UINT32 crc); + +class Receiver +{ +public: + Receiver(WP_Message* msg) + { + this->msg = msg; + this->msg->Initialize(NULL); + + m_lastOutboundMessage = 0; + } + +public: + void receive() + { + msg->PrepareReception(); + + while(true) + { + // Note: For reason unknown, the signal is always set during startup (?) + Thread::signal_wait(signalDataIn); + + process(); + } + } + +private: + bool process() + { + // + // UNDONE: FIXME: Copy of WireProtocol.cpp code + // + while(true) + { + switch(msg->m_rxState) + { + case WP_Message::ReceiveState::Idle: + return true; + + case WP_Message::ReceiveState::Initialize: + msg->m_rxState = WP_Message::ReceiveState::WaitingForHeader; + msg->m_pos = (UINT8*)&msg->m_header; + msg->m_size = sizeof(msg->m_header); + break; + + case WP_Message::ReceiveState::WaitingForHeader: + if(!readData()) + { + return true; + } + if(syncToMessageStart()) + { + msg->m_rxState = WP_Message::ReceiveState::ReadingHeader; + } + break; + + case WP_Message::ReceiveState::ReadingHeader: + if(readData()) + { + msg->m_rxState = WP_Message::ReceiveState::CompleteHeader; + } + break; + + case WP_Message::ReceiveState::CompleteHeader: + // UNDONE: VerifyHeader + //if(processHeader()) + { + if(msg->m_header.m_size) + { + // UNDONE: Receive payload + } + else + { + msg->m_rxState = WP_Message::ReceiveState::CompletePayload; + } + } + // UNDONE: fBadPacket + break; + + case WP_Message::ReceiveState::CompletePayload: + // UNDONE: VerifyPayload + + processPayload(); + // else ReplyBadPacket + + msg->m_rxState = WP_Message::ReceiveState::Initialize; + break; + + default: + // Unknown state + return false; + } + } + } + + bool syncToMessageStart() + { + int len; + while(true) + { + len = sizeof(msg->m_header) - msg->m_size; + if(len <= 0) + { + break; + } + + size_t lenCmp = min(len, sizeof(msg->m_header.m_signature)); + + if(memcmp(&msg->m_header, MARKER_DEBUGGER_V1, lenCmp) == 0) + { + break; + } + if(memcmp(&msg->m_header, MARKER_PACKET_V1, lenCmp) == 0) + { + break; + } + + UINT8* buff = (UINT8*)&msg->m_header; + + memmove(buff, &buff[1], len - 1); + + msg->m_pos--; + msg->m_size++; + } + return (len >= sizeof(msg->m_header.m_signature)); + } + + + bool readData() + { + // TODO: Disable interrupts + while(msg->m_size > 0) + { + if(rxIn == rxOut) // Buffer is empty + { + break; + } + *msg->m_pos++ = rxBuffer[rxOut]; + msg->m_size--; + + rxOut = (rxOut + 1) % BufferSize; + } + return msg->m_size == 0; + } + + + void processPayload() + { + WP_Message reply; + + reply.Initialize(NULL); + reply.m_header.m_flags |= WP_Flags::c_ACK; + reply.m_header.m_flags |= WP_Flags::c_NonCritical; + + uint32_t pingReplyPayload[2] = + { + //public const uint c_Ping_Source_TinyCLR = 0x00000000; + //public const uint c_Ping_Source_TinyBooter = 0x00000001; + //public const uint c_Ping_Source_Host = 0x00000002; + + 1, // Source TinyBooter + + //public const uint c_Ping_DbgFlag_Stop = 0x00000001; + //public const uint c_Ping_DbgFlag_BigEndian = 0x02000002; + //public const uint c_Ping_DbgFlag_AppExit = 0x00000004; + 0, // Flags + }; + + + // UNDONE: PrepareReply() - m_parent is NULL + memcpy(reply.m_header.m_signature, MARKER_PACKET_V1, sizeof(reply.m_header.m_signature)); + reply.m_header.m_cmd = msg->m_header.m_cmd; + reply.m_header.m_seq = m_lastOutboundMessage++; + reply.m_header.m_seqReply = msg->m_header.m_seq; + reply.m_header.m_flags |= WP_Flags::c_Reply; + reply.m_header.m_size = sizeof(pingReplyPayload); + reply.m_payload = (UINT8*)pingReplyPayload; + + reply.m_header.m_crcData = SUPPORT_ComputeCRC(reply.m_payload, reply.m_header.m_size, 0); + + // + // The CRC for the header is computed setting the CRC field to zero and then running the CRC algorithm. + // + reply.m_header.m_crcHeader = 0; + reply.m_header.m_crcHeader = SUPPORT_ComputeCRC((UINT8*)&reply.m_header, sizeof(reply.m_header), 0); + + + uint8_t* p = (uint8_t*)&reply.m_header; + for(int i = 0; i < sizeof(reply.m_header); i++) + { + serial.putc(p[i]); + } + for(int i = 0; i < reply.m_header.m_size; i++) + { + serial.putc(reply.m_payload[i]); + } + p=p; + } + + WP_Message* msg; + uint8_t m_buffer[256]; + int m_lastOutboundMessage; +}; + +Receiver rec(&wpMessage); + + + +void rxInterrupt() +{ + // Note: you need to actually read from the serial to clear the RX interrupt + while(serial.readable() && (((rxIn + 1) % BufferSize) != rxOut)) + { + rxBuffer[rxIn] = serial.getc(); + rxIn = (rxIn + 1) % BufferSize; + } + + rt.signal_set(signalDataIn); +} + +///////////////////////////////////////////////////////////////////////////// +// +// Application entry point +// + +int main() +{ + // TODO: if(isBootloaderRequired(timeout) + + // TODO: Configure transport (USART, USB, TCP/IP) + serial.attach(callback(rxInterrupt), Serial::RxIrq); + + // TODO: Replace with nanoBooter.Start() + rt.start(callback(&rec, &Receiver::receive)); + + while(true) + { + Thread::wait(10000); + } +}