/************************************************************************************************** * @fn sbCmnd * * @brief Act on the SB command and received buffer. * * input parameters * * @param sbCmd - Received SBL command. * @param payload_len - Length of command payload * * output parameters * * None. * * @return TRUE to indicate that the SB_ENABLE_CMD command was successful; FALSE otherwise. ************************************************************************************************** */ static uint8 sbCmnd(uint8 sbCmd, uint32 payload_len) { uint32 firstAddr; uint32 lastAddr; uint32 operationLength; uint32 writeLength; uint32 respPayloadLen = 0; uint32 pageNumber; uint32 i; uint32 actual_number_of_data_bytes_to_send; uint8 paddingLength; uint8 rsp = SB_SUCCESS; uint8 imageEnabledSuccessfully = FALSE; uint8 *pBuf; pBuf = sbBuf; switch (sbCmd) { case SB_HANDSHAKE_CMD: /* Mark all pages as not-deleted-yet */ memset(pageDeleted, 0, sizeof(pageDeleted)); UINT32_TO_BUF_LITTLE_ENDIAN(pBuf, SB_BOOTLOADER_REVISION); *pBuf++ = SB_DEVICE_TYPE_2538; UINT32_TO_BUF_LITTLE_ENDIAN(pBuf, SB_RW_BUF_LEN ); UINT32_TO_BUF_LITTLE_ENDIAN(pBuf, SB_DEVICE_PAGE_SIZE); respPayloadLen = pBuf - sbBuf; break; case SB_WRITE_CMD: firstAddr = BUF_TO_UINT32_LITTLE_ENDIAN(pBuf); operationLength = BUF_TO_UINT32_LITTLE_ENDIAN(pBuf); /* The payload_len includes the addr_offset * and the operationLength fields. The value * (pBuf - sbBuf) gives the number of bytes * used by those firelds. The remaining bytes * are the actual data bytes to be written. */ writeLength = payload_len - (pBuf - sbBuf); lastAddr = firstAddr + operationLength - 1; if ((firstAddr < FLASH_BASE) || (lastAddr > CC2538_CODE_FLASH_END_ADDRESS) || (writeLength > operationLength)) { rsp = SB_FAILURE; break; } /* Before writing to a flash page for the first time during a bootloading session, the * page must be erased. The following section makes sure that every page being written * to have already been erased, otherwise, it erases it (before writing to it). * Note that the write command may span over more than a single page. */ for (pageNumber = GET_PAGE_NUMBER(firstAddr); pageNumber <= GET_PAGE_NUMBER(lastAddr); pageNumber++) { if (!IS_PAGE_ERASED(pageNumber)) { if (FlashMainPageErase(GET_PAGE_ADDRESS(pageNumber)) != 0) { rsp = SB_FAILURE; break; } MARK_PAGE_ERASED(pageNumber); } } /* Note that the start address (firstAddr) and the byte count (writeLength) must be * word aligned. The start address is expected to be already aligned (by the SBL server), * since aligning it here would require padding the buffer's start, which would require * shifting the buffer content (as the buffer is passesd as (uint32_t *pui32Data) so it * should be aligned by itself. The byte count is aligned below. */ paddingLength = ((4 - (writeLength & 0x00000003)) % 4); for (i = 0; i < paddingLength; i++) { pBuf[writeLength + i] = 0xFF; } writeLength += paddingLength; /* If the page was successfully erased (or was previously erased), perform the write action. * Note that pBuf must point to a uint32-aligned address, as required by FlashMainPageProgram(). * This is the case now (the prefixing field are total of 8 bytes), and _sbBuf is 32bit aligned. */ if ((rsp == SB_SUCCESS) && (writeLength > 0) && (FlashMainPageProgram((uint32_t *)(pBuf), firstAddr, writeLength) != 0)) { rsp = SB_FAILURE; } break; case SB_READ_CMD: firstAddr = BUF_TO_UINT32_LITTLE_ENDIAN(pBuf); operationLength = BUF_TO_UINT32_LITTLE_ENDIAN(pBuf); lastAddr = firstAddr + operationLength - 1; if ((firstAddr < FLASH_BASE) || (lastAddr > CC2538_CODE_FLASH_END_ADDRESS) || (operationLength > sizeof(_sbBuf))) { rsp = SB_FAILURE; break; } #if !MT_SYS_OSAL_NV_READ_CERTIFICATE_DATA #if (HAL_IMG_A_BEG > HAL_NV_START_ADDR) #warning This check assumes NV PAGES located at the end of the program flash memory #endif if (GET_PAGE_NUMBER(lastAddr) >= HAL_NV_PAGE_BEG) { rsp = SB_FAILURE; break; } #endif /* If the end of the buffer is made only of 0xFF characters, no need to * send them. Find out the number of bytes that needs to be sent: */ for (actual_number_of_data_bytes_to_send = operationLength; (actual_number_of_data_bytes_to_send > 0) && ((*(uint8 *)(firstAddr + actual_number_of_data_bytes_to_send - 1)) == 0xFF); actual_number_of_data_bytes_to_send--); /* As a future upgrade, memcopy can be avoided. Instead, * may pass a pointer to the actual flash address */ (void)memcpy(pBuf, (const void *)firstAddr, actual_number_of_data_bytes_to_send); respPayloadLen = (pBuf - sbBuf) + actual_number_of_data_bytes_to_send; break; case SB_ENABLE_CMD: if (enableImg()) { imageEnabledSuccessfully = TRUE; } else { rsp = SB_VALIDATE_FAILED; } break; default: break; } sbResp(sbCmd, rsp, respPayloadLen); return imageEnabledSuccessfully; }
/************************************************************************************************** * @fn sbCmnd * * @brief Act on the SB command and received buffer. * * input parameters * * None. * * output parameters * * None. * * @return TRUE to indicate that the SB_ENABLE_CMD command was successful; FALSE otherwise. ************************************************************************************************** */ static uint8 sbCmnd(void) { uint16 tmp = BUILD_UINT16(sbBuf[SB_DATA_STATE], sbBuf[SB_DATA_STATE+1]) + SB_IMG_OSET; uint16 crc[2]; uint8 len = 1; uint8 rsp = SB_SUCCESS; uint8 rtrn = FALSE; switch (sbCmd2) { case SB_HANDSHAKE_CMD: break; case SB_WRITE_CMD: if ((tmp % SB_WPG_SIZE) == 0) { HalFlashErase(tmp / SB_WPG_SIZE); } HalFlashWrite(tmp, sbBuf+SB_DATA_STATE+2, SB_RW_BUF_LEN / HAL_FLASH_WORD_SIZE); break; case SB_READ_CMD: #if !MT_SYS_OSAL_NV_READ_CERTIFICATE_DATA if ((tmp / (HAL_FLASH_PAGE_SIZE / 4)) >= HAL_NV_PAGE_BEG) { rsp = SB_FAILURE; break; } #endif HalFlashRead(tmp / (HAL_FLASH_PAGE_SIZE / 4), (tmp % (HAL_FLASH_PAGE_SIZE / 4)) << 2, sbBuf + SB_DATA_STATE + 3, SB_RW_BUF_LEN); sbBuf[SB_DATA_STATE+2] = sbBuf[SB_DATA_STATE+1]; sbBuf[SB_DATA_STATE+1] = sbBuf[SB_DATA_STATE]; len = SB_RW_BUF_LEN + 3; break; case SB_ENABLE_CMD: HalFlashRead(HAL_SB_CRC_ADDR / HAL_FLASH_PAGE_SIZE, HAL_SB_CRC_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)crc, sizeof(crc)); // Bootload master must have verified extra checks to be issuing the SB_ENABLE_CMD. //if ((crc[0] != crc[1]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000)) if (crc[1] != crc[0]) { crc[1] = crc[0]; HalFlashWrite((HAL_SB_CRC_ADDR / HAL_FLASH_WORD_SIZE), (uint8 *)crc, 1); HalFlashRead( HAL_SB_CRC_ADDR / HAL_FLASH_PAGE_SIZE, HAL_SB_CRC_ADDR % HAL_FLASH_PAGE_SIZE, (uint8 *)crc, sizeof(crc)); } // Bootload master must have verified extra checks to be issuing the SB_ENABLE_CMD. //if ((crc[0] == crc[1]) && (crc[0] != 0xFFFF) && (crc[0] != 0x0000)) if (crc[0] == crc[1]) { rtrn = TRUE; } else { rsp = SB_VALIDATE_FAILED; } break; default: break; } sbResp(rsp, len); return rtrn; }