blob: a21237d29d866b9f18a153cff03179a6ef8b2d1f [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 <assert.h>
#include <flash.h>
#include <flash_map.h>
#include <zephyr.h>
#include <soc.h>
#include <init.h>
#include <dfu/mcuboot.h>
#include <dfu/flash_img.h>
#include <mgmt/mgmt.h>
#include <img_mgmt/img_mgmt_impl.h>
#include <img_mgmt/img_mgmt.h>
#include "../../../src/img_mgmt_priv.h"
/**
* Determines if the specified area of flash is completely unwritten.
*/
static int
zephyr_img_mgmt_flash_check_empty(u8_t fa_id, bool *out_empty)
{
const struct flash_area *fa;
uint32_t data[16];
off_t addr;
off_t end;
int bytes_to_read;
int rc;
int i;
rc = flash_area_open(fa_id, &fa);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
assert(fa->fa_size % 4 == 0);
end = fa->fa_size;
for (addr = 0; addr < end; addr += sizeof data) {
if (end - addr < sizeof data) {
bytes_to_read = end - addr;
} else {
bytes_to_read = sizeof data;
}
rc = flash_area_read(fa, addr, data, bytes_to_read);
if (rc != 0) {
flash_area_close(fa);
return MGMT_ERR_EUNKNOWN;
}
for (i = 0; i < bytes_to_read / 4; i++) {
if (data[i] != 0xffffffff) {
*out_empty = false;
flash_area_close(fa);
return 0;
}
}
}
*out_empty = true;
flash_area_close(fa);
return 0;
}
/**
* Get flash_area ID for a image slot number.
*/
static u8_t
zephyr_img_mgmt_flash_area_id(int slot)
{
u8_t fa_id;
switch (slot) {
case 0:
fa_id = DT_FLASH_AREA_IMAGE_0_ID;
break;
case 1:
fa_id = DT_FLASH_AREA_IMAGE_1_ID;
break;
default:
assert(0);
fa_id = DT_FLASH_AREA_IMAGE_1_ID;
break;
}
return fa_id;
}
int
img_mgmt_impl_erase_slot(void)
{
bool empty;
int rc;
rc = zephyr_img_mgmt_flash_check_empty(DT_FLASH_AREA_IMAGE_1_ID,
&empty);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
if (!empty) {
rc = boot_erase_img_bank(DT_FLASH_AREA_IMAGE_1_ID);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
}
return 0;
}
int
img_mgmt_impl_write_pending(int slot, bool permanent)
{
int rc;
if (slot != 1) {
return MGMT_ERR_EINVAL;
}
rc = boot_request_upgrade(permanent);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
return 0;
}
int
img_mgmt_impl_write_confirmed(void)
{
int rc;
rc = boot_write_img_confirmed();
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
return 0;
}
int
img_mgmt_impl_read(int slot, unsigned int offset, void *dst,
unsigned int num_bytes)
{
const struct flash_area *fa;
int rc;
rc = flash_area_open(zephyr_img_mgmt_flash_area_id(slot), &fa);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
rc = flash_area_read(fa, offset, dst, num_bytes);
flash_area_close(fa);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
return 0;
}
int
img_mgmt_impl_write_image_data(unsigned int offset, const void *data,
unsigned int num_bytes, bool last)
{
int rc;
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
static struct flash_img_context *ctx = NULL;
#else
static struct flash_img_context ctx_data;
#define ctx (&ctx_data)
#endif
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
if (offset != 0 && ctx == NULL) {
return MGMT_ERR_EUNKNOWN;
}
#endif
if (offset == 0) {
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
if (ctx == NULL) {
ctx = k_malloc(sizeof(*ctx));
if (ctx == NULL) {
return MGMT_ERR_ENOMEM;
}
}
#endif
rc = flash_img_init(ctx);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
}
if (offset != ctx->bytes_written + ctx->buf_bytes) {
return MGMT_ERR_EUNKNOWN;
}
/* Cast away const. */
rc = flash_img_buffered_write(ctx, (void *)data, num_bytes, last);
if (rc != 0) {
return MGMT_ERR_EUNKNOWN;
}
#if (CONFIG_HEAP_MEM_POOL_SIZE > 0)
if (last) {
k_free(ctx);
ctx = NULL;
}
#endif
return 0;
}
int
img_mgmt_impl_swap_type(void)
{
switch (mcuboot_swap_type()) {
case BOOT_SWAP_TYPE_NONE:
return IMG_MGMT_SWAP_TYPE_NONE;
case BOOT_SWAP_TYPE_TEST:
return IMG_MGMT_SWAP_TYPE_TEST;
case BOOT_SWAP_TYPE_PERM:
return IMG_MGMT_SWAP_TYPE_PERM;
case BOOT_SWAP_TYPE_REVERT:
return IMG_MGMT_SWAP_TYPE_REVERT;
default:
assert(0);
return IMG_MGMT_SWAP_TYPE_NONE;
}
}