Repostiory containing DAPLink source code with Reset Pin workaround for HANI_IOT board.

Upstream: https://github.com/ARMmbed/DAPLink

Revision:
0:01f31e923fe2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/source/daplink/drag-n-drop/iap_flash_intf.c	Tue Apr 07 12:55:42 2020 +0200
@@ -0,0 +1,504 @@
+/**
+ * @file    iap_flash_intf.c
+ * @brief   Implementation of flash_intf.h
+ *
+ * DAPLink Interface Firmware
+ * Copyright (c) 2009-2019, ARM Limited, All Rights Reserved
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+
+#include "daplink.h"
+#include "flash_intf.h"
+#include "util.h"
+#include "flash_hal.h"
+#include "FlashPrg.h"
+#include "compiler.h"
+#include "crc.h"
+#include "info.h"
+
+// Application start must be aligned to page write
+COMPILER_ASSERT(DAPLINK_ROM_APP_START % DAPLINK_MIN_WRITE_SIZE == 0);
+// Application size must be a multiple of write size
+COMPILER_ASSERT(DAPLINK_ROM_APP_SIZE % DAPLINK_MIN_WRITE_SIZE == 0);
+// Sector size must be a multiple of write size
+COMPILER_ASSERT(DAPLINK_SECTOR_SIZE % DAPLINK_MIN_WRITE_SIZE == 0);
+// Application start must be aligned to a sector erase
+COMPILER_ASSERT(DAPLINK_ROM_APP_START % DAPLINK_SECTOR_SIZE == 0);
+// Update start must be aligned to sector write
+COMPILER_ASSERT(DAPLINK_ROM_UPDATE_START % DAPLINK_SECTOR_SIZE == 0);
+// Update size must be a multiple of sector size
+COMPILER_ASSERT(DAPLINK_ROM_UPDATE_SIZE % DAPLINK_SECTOR_SIZE == 0);
+
+typedef enum {
+    STATE_CLOSED,
+    STATE_OPEN,
+    STATE_ERROR
+} state_t;
+
+static error_t init(void);
+static error_t uninit(void);
+static error_t program_page(uint32_t addr, const uint8_t *buf, uint32_t size);
+static error_t erase_sector(uint32_t addr);
+static error_t erase_chip(void);
+static uint32_t program_page_min_size(uint32_t addr);
+static uint32_t erase_sector_size(uint32_t addr);
+
+static bool page_program_allowed(uint32_t addr, uint32_t size);
+static bool sector_erase_allowed(uint32_t addr);
+static error_t intercept_page_write(uint32_t addr, const uint8_t *buf, uint32_t size);
+static error_t intercept_sector_erase(uint32_t addr);
+static error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size);
+static uint8_t target_flash_busy(void);
+
+static const flash_intf_t flash_intf = {
+    init,
+    uninit,
+    program_page,
+    erase_sector,
+    erase_chip,
+    program_page_min_size,
+    erase_sector_size,
+    target_flash_busy,
+};
+
+const flash_intf_t *const flash_intf_iap_protected = &flash_intf;
+
+static state_t state = STATE_CLOSED;
+static bool update_complete;
+static bool mass_erase_performed;
+static bool current_sector_set;
+static uint32_t current_sector;
+static uint32_t current_sector_size;
+static bool current_page_set;
+static uint32_t current_page;
+static uint32_t current_page_write_size;
+static uint32_t crc;
+static uint8_t sector_buf[DAPLINK_SECTOR_SIZE];
+
+static error_t init()
+{
+    int iap_status;
+    bool update_supported = DAPLINK_ROM_UPDATE_SIZE != 0;
+
+    if (state != STATE_CLOSED) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    if (!update_supported) {
+        return ERROR_IAP_UPDT_NOT_SUPPORTED;
+    }
+
+    iap_status = Init(0, 0, 0);
+
+    if (iap_status != 0) {
+        return ERROR_IAP_INIT;
+    }
+
+    update_complete = false;
+    mass_erase_performed = false;
+    current_sector_set = false;
+    current_sector = 0;
+    current_sector_size = 0;
+    current_page_set = false;
+    current_page = 0;
+    current_page_write_size = 0;
+    crc = 0;
+    memset(sector_buf, 0, sizeof(sector_buf));
+    state = STATE_OPEN;
+    return ERROR_SUCCESS;
+}
+
+static error_t uninit(void)
+{
+    int iap_status;
+
+    if (STATE_CLOSED == state) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    state = STATE_CLOSED;
+    iap_status = UnInit(0);
+
+    if (iap_status != 0) {
+        return ERROR_IAP_UNINIT;
+    }
+
+    if (!update_complete && !daplink_is_bootloader()) {
+        // Interface - Error if the bootloader update is not complete
+        // Bootloader - For 3rd party applications the end of the update
+        //              is unknown so it is not an error if the transfer
+        //              ends early.
+        return ERROR_IAP_UPDT_INCOMPLETE;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static error_t program_page(uint32_t addr, const uint8_t *buf, uint32_t size)
+{
+    uint32_t iap_status;
+    error_t status;
+    uint32_t min_prog_size;
+    uint32_t sector_size;
+    uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
+
+    if (state != STATE_OPEN) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    min_prog_size = program_page_min_size(addr);
+    sector_size = erase_sector_size(addr);
+
+    // Address must be on a write size boundary
+    if (addr % min_prog_size != 0) {
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    // Programming size must be a non-zero multiple of the minimum write size
+    if ((size < min_prog_size) || (size % min_prog_size != 0)) {
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    // Write must not cross a sector boundary
+    if ((addr % sector_size) + size > sector_size) {
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    // Write must be in an erased sector (current_sector is always erased if it is set)
+    if (!mass_erase_performed) {
+        if (!current_sector_set) {
+            util_assert(0);
+            state = STATE_ERROR;
+            return ERROR_INTERNAL;
+        }
+
+        if ((addr < current_sector) || (addr >= current_sector + current_sector_size)) {
+            util_assert(0);
+            state = STATE_ERROR;
+            return ERROR_INTERNAL;
+        }
+    }
+
+    // Address must be sequential - no gaps
+    if (current_page_set && (addr != current_page + current_page_write_size)) {
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    if (!page_program_allowed(addr, size)) {
+        state = STATE_ERROR;
+        return ERROR_IAP_WRITE;
+    }
+
+    current_page_set = true;
+    current_page = addr;
+    current_page_write_size = size;
+    status = intercept_page_write(addr, buf, size);
+
+    if (status != ERROR_IAP_NO_INTERCEPT) {
+        // The operation has been intercepted so
+        // return the result
+        if (ERROR_SUCCESS != status) {
+            state = STATE_ERROR;
+        }
+
+        return status;
+    }
+
+    iap_status = flash_program_page(addr, size, (uint8_t *)buf);
+
+    if (iap_status != 0) {
+        state = STATE_ERROR;
+        return ERROR_IAP_WRITE;
+    }
+
+    if (addr + size >= updt_end) {
+        // Something has been updated so recompute the crc
+        info_crc_compute();
+        update_complete = true;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static error_t erase_sector(uint32_t addr)
+{
+    uint32_t iap_status;
+    error_t status;
+    uint32_t sector_size;
+
+    if (state != STATE_OPEN) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    // Address must be on a sector boundary
+    sector_size = erase_sector_size(addr);
+
+    if (addr % sector_size != 0) {
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    // Address must be sequential - no gaps
+    if (current_sector_set && (addr != current_sector + current_sector_size)) {
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    if (!sector_erase_allowed(addr)) {
+        state = STATE_ERROR;
+        return ERROR_IAP_ERASE_SECTOR;
+    }
+
+    current_sector_set = true;
+    current_sector = addr;
+    current_sector_size = sector_size;
+    status = intercept_sector_erase(addr);
+
+    if (status != ERROR_IAP_NO_INTERCEPT) {
+        // The operation has been intercepted so
+        // return the result
+        if (ERROR_SUCCESS != status) {
+            state = STATE_ERROR;
+        }
+
+        return status;
+    }
+
+    iap_status = flash_erase_sector(addr);
+
+    if (iap_status != 0) {
+        state = STATE_ERROR;
+        return ERROR_IAP_ERASE_SECTOR;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static error_t erase_chip(void)
+{
+    uint32_t updt_start = DAPLINK_ROM_UPDATE_START;
+    uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
+
+    if (state != STATE_OPEN) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    if (mass_erase_performed) {
+        // Mass erase only allowed once
+        util_assert(0);
+        state = STATE_ERROR;
+        return ERROR_INTERNAL;
+    }
+
+    for (uint32_t addr = updt_start; addr < updt_end; addr += DAPLINK_SECTOR_SIZE) {
+        error_t status;
+        status = erase_sector(addr);
+
+        if (status != ERROR_SUCCESS) {
+            state = STATE_ERROR;
+            return ERROR_IAP_ERASE_ALL;
+        }
+    }
+
+    mass_erase_performed = true;
+    return ERROR_SUCCESS;
+}
+
+static uint32_t program_page_min_size(uint32_t addr)
+{
+    return DAPLINK_MIN_WRITE_SIZE;
+}
+
+static uint32_t erase_sector_size(uint32_t addr)
+{
+    return DAPLINK_SECTOR_SIZE;
+}
+
+static bool page_program_allowed(uint32_t addr, uint32_t size)
+{
+    // Check if any data would overlap with the application region
+    if ((addr < DAPLINK_ROM_APP_START + DAPLINK_ROM_APP_SIZE) && (addr + size > DAPLINK_ROM_APP_START)) {
+        return false;
+    }
+
+    return true;
+}
+
+static bool sector_erase_allowed(uint32_t addr)
+{
+    uint32_t app_start = DAPLINK_ROM_APP_START;
+    uint32_t app_end = DAPLINK_ROM_APP_START + DAPLINK_ROM_APP_SIZE;
+
+    // Check if the sector is part of the application
+    if ((addr >= app_start) && (addr < app_end)) {
+        return false;
+    }
+
+    return true;
+}
+
+static error_t intercept_page_write(uint32_t addr, const uint8_t *buf, uint32_t size)
+{
+    error_t status;
+    uint32_t crc_size;
+    uint32_t updt_start = DAPLINK_ROM_UPDATE_START;
+    uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
+
+    if (state != STATE_OPEN) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    if ((addr < updt_start) || (addr >= updt_end)) {
+        return ERROR_IAP_OUT_OF_BOUNDS;
+    }
+
+    if (!daplink_is_interface()) {
+        return ERROR_IAP_NO_INTERCEPT;
+    }
+
+    /* Everything below here is interface specific */
+    crc_size = MIN(size, updt_end - addr - 4);
+    crc = crc32_continue(crc, buf, crc_size);
+
+    // Intercept the data if it is in the first sector
+    if ((addr >= updt_start) && (addr < updt_start + DAPLINK_SECTOR_SIZE)) {
+        uint32_t buf_offset = addr - updt_start;
+        memcpy(sector_buf + buf_offset, buf, size);
+        // Intercept was successful
+        return ERROR_SUCCESS;
+    }
+
+    // Finalize update if this is the last sector
+    if (updt_end == addr + size) {
+        uint32_t iap_status;
+        uint32_t size_left = updt_end - addr;
+        uint32_t crc_in_image = (buf[size_left - 4] << 0) |
+                                (buf[size_left - 3] << 8) |
+                                (buf[size_left - 2] << 16) |
+                                (buf[size_left - 1] << 24);
+
+        if (crc != crc_in_image) {
+            return ERROR_BL_UPDT_BAD_CRC;
+        }
+
+        // Program the current buffer
+        iap_status = flash_program_page(addr, size, (uint8_t *)buf);
+
+        if (iap_status != 0) {
+            return ERROR_IAP_WRITE;
+        }
+
+        status = critical_erase_and_program(DAPLINK_ROM_UPDATE_START, sector_buf, DAPLINK_SECTOR_SIZE);
+
+        if (ERROR_SUCCESS == status) {
+            status = ERROR_SUCCESS;
+        }
+
+        // The bootloader has been updated so recompute the crc
+        info_crc_compute();
+        update_complete = true;
+        return status;
+    }
+
+    return ERROR_IAP_NO_INTERCEPT;
+}
+
+static error_t intercept_sector_erase(uint32_t addr)
+{
+    error_t status;
+    uint32_t updt_start = DAPLINK_ROM_UPDATE_START;
+    uint32_t updt_end = DAPLINK_ROM_UPDATE_START + DAPLINK_ROM_UPDATE_SIZE;
+
+    if (state != STATE_OPEN) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    if ((addr < updt_start) || (addr >= updt_end)) {
+        return ERROR_IAP_OUT_OF_BOUNDS;
+    }
+
+    if (!daplink_is_interface()) {
+        return ERROR_IAP_NO_INTERCEPT;
+    }
+
+    /* Everything below here is interface specific */
+
+    if (DAPLINK_ROM_UPDATE_START == addr) {
+        uint32_t addr = DAPLINK_ROM_UPDATE_START;
+        status = critical_erase_and_program(addr, (uint8_t *)DAPLINK_ROM_IF_START, DAPLINK_MIN_WRITE_SIZE);
+
+        if (ERROR_SUCCESS == status) {
+            // Intercept was successful
+            status = ERROR_SUCCESS;
+        }
+
+        return status;
+    }
+
+    return ERROR_IAP_NO_INTERCEPT;
+}
+
+static error_t critical_erase_and_program(uint32_t addr, const uint8_t *data, uint32_t size)
+{
+    uint32_t iap_status;
+
+    if (size < DAPLINK_MIN_WRITE_SIZE) {
+        util_assert(0);
+        return ERROR_INTERNAL;
+    }
+
+    // CRITICAL SECTION BELOW HERE!
+    // If something goes wrong with either
+    // the erase or write then the device
+    // will no longer be bootable.
+    // Erase the first sector
+    iap_status = flash_erase_sector(addr);
+
+    if (iap_status != 0) {
+        return ERROR_ERASE_ALL;
+    }
+
+    // Program the interface's vector table
+    iap_status = flash_program_page(addr, size, (uint8_t *)data);
+
+    if (iap_status != 0) {
+        return ERROR_IAP_WRITE;
+    }
+
+    return ERROR_SUCCESS;
+}
+
+static uint8_t target_flash_busy(void){
+    return (state == STATE_OPEN);
+}