No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

355 líneas
13 KiB

  1. /*******************************************************************************
  2. File Name:
  3. m2m_flash.c
  4. Summary:
  5. This module contains the WINC flash interface.
  6. Description:
  7. This module contains the WINC flash interface.
  8. *******************************************************************************/
  9. //DOM-IGNORE-BEGIN
  10. /*******************************************************************************
  11. * Copyright (C) 2021 Microchip Technology Inc. and its subsidiaries.
  12. *
  13. * Subject to your compliance with these terms, you may use Microchip software
  14. * and any derivatives exclusively with Microchip products. It is your
  15. * responsibility to comply with third party license terms applicable to your
  16. * use of third party software (including open source software) that may
  17. * accompany Microchip software.
  18. *
  19. * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
  20. * EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
  21. * WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
  22. * PARTICULAR PURPOSE.
  23. *
  24. * IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
  25. * INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
  26. * WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
  27. * BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
  28. * FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
  29. * ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  30. * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  31. *******************************************************************************/
  32. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
  33. INCLUDES
  34. *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  35. #include "m2m_flash.h"
  36. #include "spi_flash.h"
  37. #include "spi_flash_map.h"
  38. #include "nmdrv.h"
  39. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
  40. TYPEDEFS
  41. *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  42. typedef struct
  43. {
  44. uint32_t address;
  45. uint32_t size;
  46. } tstrFlashMapEntry;
  47. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
  48. GLOBALS
  49. *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  50. static const tstrFlashMapEntry flashMap[] =
  51. {
  52. {0 , 0 }, // WINC_FLASH_REGION_RAW,
  53. {0 , OTA_IMAGE_SIZE }, // WINC_FLASH_REGION_FIRMWARE_ACTIVE,
  54. {0 , OTA_IMAGE_SIZE }, // WINC_FLASH_REGION_FIRMWARE_INACTIVE,
  55. {M2M_PLL_FLASH_OFFSET , M2M_PLL_FLASH_SZ }, // WINC_FLASH_REGION_PLL_TABLE,
  56. {M2M_GAIN_FLASH_OFFSET , M2M_GAIN_FLASH_SZ }, // WINC_FLASH_REGION_GAIN_TABLE,
  57. {M2M_PLL_FLASH_OFFSET , M2M_PLL_FLASH_SZ+M2M_GAIN_FLASH_SZ}, // WINC_FLASH_REGION_PLL_AND_GAIN_TABLES,
  58. {M2M_TLS_ROOTCER_FLASH_OFFSET , M2M_TLS_ROOTCER_FLASH_SZ }, // WINC_FLASH_REGION_ROOT_CERTS,
  59. {M2M_TLS_SERVER_FLASH_OFFSET , M2M_TLS_SERVER_FLASH_SZ }, // WINC_FLASH_REGION_LOCAL_CERTS,
  60. {M2M_CACHED_CONNS_FLASH_OFFSET , M2M_CACHED_CONNS_FLASH_SZ }, // WINC_FLASH_REGION_CONN_PARAM,
  61. {0 , M2M_HTTP_MEM_FLASH_SZ }, // WINC_FLASH_REGION_HTTP_FILES,
  62. };
  63. /*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*
  64. FUNCTIONS
  65. *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/
  66. static int8_t winc_flash_compare(uint8_t *pu8Buf, uint32_t u32Offset, uint32_t u32Size)
  67. {
  68. int8_t ret = M2M_SUCCESS;
  69. uint8_t buf[128];
  70. uint32_t offset = 0;
  71. while(offset < u32Size)
  72. {
  73. uint32_t chunk_sz = sizeof(buf);
  74. if(chunk_sz > u32Size - offset)
  75. chunk_sz = u32Size - offset;
  76. ret = spi_flash_read(buf, u32Offset + offset, chunk_sz);
  77. if(ret != M2M_SUCCESS)
  78. break;
  79. ret = memcmp(buf, pu8Buf + offset, chunk_sz);
  80. if(ret != 0)
  81. break;
  82. offset += chunk_sz;
  83. }
  84. return ret;
  85. }
  86. static int8_t winc_flash_write_verify(uint8_t *pu8Buf, uint32_t u32Offset, uint32_t u32Size)
  87. {
  88. int8_t ret = M2M_ERR_FAIL;
  89. uint8_t count = 20;
  90. while((ret != M2M_SUCCESS) && (count-- > 0))
  91. {
  92. ret = spi_flash_write(pu8Buf, u32Offset, u32Size);
  93. if(ret == M2M_SUCCESS)
  94. ret = winc_flash_compare(pu8Buf, u32Offset, u32Size);
  95. }
  96. return ret;
  97. }
  98. /* Some internal functions for accessing the control structure. */
  99. static uint8_t crc7(uint8_t crc, const uint8_t *buff, uint16_t len)
  100. {
  101. uint8_t reg = crc;
  102. uint16_t i;
  103. for(i = 0; i < len; i++)
  104. {
  105. uint16_t g;
  106. for(g = 0; g < 8; g++)
  107. {
  108. uint8_t inv = (((buff[i] << g) & 0x80) >> 7) ^ ((reg >> 6) & 1);
  109. reg = ((reg << 1) & 0x7f) ^ (9 * inv);
  110. }
  111. }
  112. return reg;
  113. }
  114. static int8_t verify_control_structure(tstrOtaControlSec *pstrControlSec)
  115. {
  116. int8_t s8Ret = M2M_SUCCESS;
  117. if(pstrControlSec->u32OtaMagicValue != OTA_MAGIC_VALUE)
  118. s8Ret = M2M_ERR_FAIL;
  119. if(pstrControlSec->u32OtaControlSecCrc != crc7(0x7f, (uint8_t *)pstrControlSec, sizeof(tstrOtaControlSec) - 4))
  120. s8Ret = M2M_ERR_FAIL;
  121. return s8Ret;
  122. }
  123. static int8_t read_control_structure(tstrOtaControlSec *pstrControlSec)
  124. {
  125. int8_t s8Ret;
  126. s8Ret = spi_flash_read((uint8_t *)pstrControlSec, M2M_CONTROL_FLASH_OFFSET, sizeof(tstrOtaControlSec));
  127. if(s8Ret == M2M_SUCCESS)
  128. s8Ret = verify_control_structure(pstrControlSec);
  129. if(s8Ret != M2M_SUCCESS)
  130. {
  131. s8Ret = spi_flash_read((uint8_t *)pstrControlSec, M2M_BACKUP_FLASH_OFFSET, sizeof(tstrOtaControlSec));
  132. if(s8Ret == M2M_SUCCESS)
  133. s8Ret = verify_control_structure(pstrControlSec);
  134. }
  135. return s8Ret;
  136. }
  137. static int8_t update_control_structure(tstrOtaControlSec *pstrControlSec)
  138. {
  139. int8_t ret = M2M_ERR_FAIL;
  140. ret = spi_flash_erase(M2M_BACKUP_FLASH_OFFSET, M2M_BACKUP_FLASH_SZ);
  141. if(ret == M2M_SUCCESS)
  142. {
  143. pstrControlSec->u32OtaSequenceNumber++;
  144. pstrControlSec->u32OtaControlSecCrc = crc7(0x7f, (uint8_t *)pstrControlSec, sizeof(tstrOtaControlSec) - 4);
  145. ret = winc_flash_write_verify((uint8_t *)pstrControlSec, M2M_BACKUP_FLASH_OFFSET, sizeof(tstrOtaControlSec));
  146. if(ret == M2M_SUCCESS)
  147. {
  148. ret = spi_flash_erase(M2M_CONTROL_FLASH_OFFSET, M2M_CONTROL_FLASH_SZ);
  149. if(ret == M2M_SUCCESS)
  150. {
  151. pstrControlSec->u32OtaSequenceNumber++;
  152. pstrControlSec->u32OtaControlSecCrc = crc7(0x7f, (uint8_t *)pstrControlSec, sizeof(tstrOtaControlSec) - 4);
  153. ret = winc_flash_write_verify((uint8_t *)pstrControlSec, M2M_CONTROL_FLASH_OFFSET, sizeof(tstrOtaControlSec));
  154. }
  155. }
  156. }
  157. return ret;
  158. }
  159. static bool find_flash_section(tenuWincFlashRegion enuRegion, uint32_t *pu32StartAddr, uint32_t *pu32Size)
  160. {
  161. /* Ensure the pointers and region are valid. */
  162. if((NULL == pu32StartAddr) || (NULL == pu32Size) || (enuRegion >= WINC_FLASH_NUM_REGIONS))
  163. return false;
  164. /* For the raw region resolve the full flash space, otherwise lookup
  165. the region location and size from the flexible flash map. */
  166. switch(enuRegion)
  167. {
  168. case WINC_FLASH_REGION_RAW:
  169. *pu32StartAddr = 0;
  170. *pu32Size = spi_flash_get_size() << 17;
  171. break;
  172. case WINC_FLASH_REGION_FIRMWARE_ACTIVE:
  173. case WINC_FLASH_REGION_FIRMWARE_INACTIVE:
  174. case WINC_FLASH_REGION_HTTP_FILES:
  175. {
  176. /* In these cases we need to read the control structure to find the appropriate flash address. */
  177. tstrOtaControlSec strControl;
  178. /* Check the WINC is initialised and not running. */
  179. if (NM_STATE_INIT != nm_get_state())
  180. return false;
  181. /* Read control structure from flash. */
  182. if (M2M_SUCCESS != read_control_structure(&strControl))
  183. return false;
  184. if (WINC_FLASH_REGION_FIRMWARE_INACTIVE == enuRegion)
  185. *pu32StartAddr = strControl.u32OtaRollbackImageOffset;
  186. else if (WINC_FLASH_REGION_FIRMWARE_ACTIVE == enuRegion)
  187. *pu32StartAddr = strControl.u32OtaCurrentWorkingImagOffset;
  188. else if (WINC_FLASH_REGION_HTTP_FILES == enuRegion)
  189. *pu32StartAddr = strControl.u32OtaCurrentWorkingImagOffset + (M2M_HTTP_MEM_FLASH_OFFSET - M2M_OTA_IMAGE1_OFFSET);
  190. *pu32Size = flashMap[enuRegion].size;
  191. break;
  192. }
  193. default:
  194. *pu32StartAddr = flashMap[enuRegion].address;
  195. *pu32Size = flashMap[enuRegion].size;
  196. break;
  197. }
  198. M2M_INFO("Flash lookup %2d: 0x%06" PRIx32 " %0" PRId32 "\r\n", enuRegion, *pu32StartAddr, *pu32Size);
  199. return true;
  200. }
  201. int8_t m2m_flash_erase_sector(tenuWincFlashRegion enuRegion, uint8_t u8StartSector, uint8_t u8NumSectors)
  202. {
  203. uint32_t flashAddress;
  204. uint32_t flashRegionSize;
  205. /* Check the WINC is initialised and not running. */
  206. if(NM_STATE_INIT != nm_get_state())
  207. return M2M_ERR_FAIL;
  208. /* Check the region is valid. */
  209. if(enuRegion >= WINC_FLASH_NUM_REGIONS)
  210. return M2M_ERR_INVALID_ARG;
  211. /* Find region address and size. */
  212. if(false == find_flash_section(enuRegion, &flashAddress, &flashRegionSize))
  213. return M2M_ERR_FAIL;
  214. /* Erase is only supported for regions which begin on a sector boundary. */
  215. if(flashAddress & (FLASH_SECTOR_SZ-1))
  216. return M2M_ERR_INVALID_ARG;
  217. /* Check requested size fits within region size. */
  218. if((((uint32_t)u8StartSector + u8NumSectors) * FLASH_SECTOR_SZ) > flashRegionSize)
  219. return M2M_ERR_FAIL;
  220. /* Find start address of area within requested region. */
  221. flashAddress += (u8StartSector * FLASH_SECTOR_SZ);
  222. /* Erase the requested sectors. */
  223. if(M2M_SUCCESS != spi_flash_erase(flashAddress, u8NumSectors * FLASH_SECTOR_SZ))
  224. return M2M_ERR_FAIL;
  225. return M2M_SUCCESS;
  226. }
  227. int8_t m2m_flash_write(tenuWincFlashRegion enuRegion, void *pvBuffer, uint32_t u32Offset, uint32_t u32Size)
  228. {
  229. uint32_t flashAddress;
  230. uint32_t flashRegionSize;
  231. /* Check the WINC is initialised and not running. */
  232. if(NM_STATE_INIT != nm_get_state())
  233. return M2M_ERR_FAIL;
  234. /* Check the buffer pointer and region are valid. */
  235. if((NULL == pvBuffer) || (enuRegion >= WINC_FLASH_NUM_REGIONS))
  236. return M2M_ERR_INVALID_ARG;
  237. /* Find region address and size. */
  238. if(false == find_flash_section(enuRegion, &flashAddress, &flashRegionSize))
  239. return M2M_ERR_FAIL;
  240. /* Check requested size fits within region size. Also check for wraparound. */
  241. if(((u32Offset + u32Size) > flashRegionSize) || ((uint32_t)(u32Offset + u32Size) < u32Offset))
  242. return M2M_ERR_FAIL;
  243. /* Find start address of area within requested region. */
  244. flashAddress += u32Offset;
  245. /* Write data to flash. */
  246. if(M2M_SUCCESS != spi_flash_write(pvBuffer, flashAddress, u32Size))
  247. return M2M_ERR_FAIL;
  248. return M2M_SUCCESS;
  249. }
  250. int8_t m2m_flash_read(tenuWincFlashRegion enuRegion, void *pvBuffer, uint32_t u32Offset, uint32_t u32Size)
  251. {
  252. uint32_t flashAddress;
  253. uint32_t flashRegionSize;
  254. /* Check the WINC is initialised and not running. */
  255. if(NM_STATE_INIT != nm_get_state())
  256. return M2M_ERR_FAIL;
  257. /* Check the buffer pointer and region are valid. */
  258. if((NULL == pvBuffer) || (enuRegion >= WINC_FLASH_NUM_REGIONS))
  259. return M2M_ERR_INVALID_ARG;
  260. /* Find region address and size. */
  261. if(false == find_flash_section(enuRegion, &flashAddress, &flashRegionSize))
  262. return M2M_ERR_FAIL;
  263. /* Check requested size fits within region size. Also check for wraparound. */
  264. if(((u32Offset + u32Size) > flashRegionSize) || ((uint32_t)(u32Offset + u32Size) < u32Offset))
  265. return M2M_ERR_FAIL;
  266. /* Find start address of area within requested region. */
  267. flashAddress += u32Offset;
  268. /* Read data from flash. */
  269. if(M2M_SUCCESS != spi_flash_read(pvBuffer, flashAddress, u32Size))
  270. return M2M_ERR_FAIL;
  271. return M2M_SUCCESS;
  272. }
  273. int8_t m2m_flash_switch_firmware(void)
  274. {
  275. tstrOtaControlSec strControl;
  276. uint32_t u32Tmp;
  277. /* Check the WINC is initialised and not running. */
  278. if(NM_STATE_INIT != nm_get_state())
  279. return M2M_ERR_FAIL;
  280. /* Read control structure from flash. */
  281. if(M2M_SUCCESS != read_control_structure(&strControl))
  282. return M2M_ERR_FAIL;
  283. /* Switch active and inactive. */
  284. u32Tmp = strControl.u32OtaRollbackImageOffset;
  285. strControl.u32OtaRollbackImageOffset = strControl.u32OtaCurrentWorkingImagOffset;
  286. strControl.u32OtaCurrentWorkingImagOffset = u32Tmp;
  287. /* Ensure the inactive image is marked as invalid. This protects m2m_ota_switch_firmware from
  288. switching to an image whose validity is unknown. Switching remains possible via this API. */
  289. strControl.u32OtaRollbackImageValidStatus = OTA_STATUS_INVALID;
  290. if(M2M_SUCCESS != update_control_structure(&strControl))
  291. return M2M_ERR_FAIL;
  292. return M2M_SUCCESS;
  293. }
  294. //DOM-IGNORE-END