| /* |
| * 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 <limits.h> |
| #include <assert.h> |
| #include <string.h> |
| |
| #include "os/mynewt.h" |
| #include "hal/hal_bsp.h" |
| #include "flash_map/flash_map.h" |
| #include "cborattr/cborattr.h" |
| #include "bootutil/image.h" |
| #include "bootutil/bootutil.h" |
| #include "imgmgr/imgmgr.h" |
| #include "mgmt/mgmt.h" |
| #include "img_mgmt/img_mgmt.h" |
| #include "imgmgr_priv.h" |
| |
| static imgr_upload_fn *imgr_upload_cb; |
| static void *imgr_upload_arg; |
| |
| void |
| imgr_set_upload_cb(imgr_upload_fn *cb, void *arg) |
| { |
| imgr_upload_cb = cb; |
| imgr_upload_arg = arg; |
| } |
| |
| |
| void imgmgr_dfu_stopped(void) |
| { |
| img_mgmt_dfu_stopped(); |
| } |
| |
| void imgmgr_dfu_started(void) |
| { |
| img_mgmt_dfu_started(); |
| } |
| |
| void imgmgr_dfu_pending(void) |
| { |
| img_mgmt_dfu_pending(); |
| } |
| |
| void imgmgr_dfu_confirmed(void) |
| { |
| img_mgmt_dfu_confirmed(); |
| } |
| |
| void |
| imgmgr_register_callbacks(const imgmgr_dfu_callbacks_t *cb_struct) |
| { |
| img_mgmt_register_callbacks((const img_mgmt_dfu_callbacks_t *)cb_struct); |
| } |
| |
| uint8_t |
| imgmgr_state_flags(int query_slot) |
| { |
| return img_mgmt_state_flags(query_slot); |
| } |
| |
| int |
| imgr_read_info(int image_slot, struct image_version *ver, uint8_t *hash, |
| uint32_t *flags) |
| { |
| return img_mgmt_read_info(image_slot, ver, hash, flags); |
| } |
| |
| static int |
| imgr_erase_state(struct mgmt_ctxt *ctxt); |
| |
| static const struct mgmt_handler imgr_mgmt_handlers[] = { |
| [IMGMGR_NMGR_ID_CORELIST] = { |
| #if MYNEWT_VAL(IMGMGR_COREDUMP) |
| .mh_read = imgr_core_list, |
| .mh_write = NULL |
| #else |
| .mh_read = NULL, |
| .mh_write = NULL |
| #endif |
| }, |
| [IMGMGR_NMGR_ID_CORELOAD] = { |
| #if MYNEWT_VAL(IMGMGR_COREDUMP) |
| .mh_read = imgr_core_load, |
| .mh_write = imgr_core_erase, |
| #else |
| .mh_read = NULL, |
| .mh_write = NULL |
| #endif |
| }, |
| [IMGMGR_NMGR_ID_ERASE_STATE] = { |
| .mh_read = NULL, |
| .mh_write = imgr_erase_state, |
| }, |
| }; |
| |
| #define IMGR_HANDLER_CNT \ |
| sizeof(imgr_mgmt_handlers) / sizeof(imgr_mgmt_handlers[0]) |
| |
| static struct mgmt_group imgr_mgmt_group = { |
| .mg_handlers = (struct mgmt_handler *)imgr_mgmt_handlers, |
| .mg_handlers_count = IMGR_HANDLER_CNT, |
| .mg_group_id = MGMT_GROUP_ID_IMAGE, |
| }; |
| |
| /* |
| * Read the current running image's build hash |
| * |
| * @param hash Ptr to hash to be filled up |
| * @param hashlen Length of hash to return |
| * |
| * Returns -2 if either of the argument is 0 or NULL |
| * Returns -1 if area is not readable |
| * Returns 0 if image in slot is ok |
| * Returns 1 if there is not a full image |
| * Returns 2 if slot is empty |
| */ |
| int |
| imgr_get_current_hash(uint8_t *hash, uint16_t hashlen) |
| { |
| uint8_t imghash[IMGMGR_HASH_LEN]; |
| int rc; |
| |
| if (!hashlen || !hash) { |
| return -2; |
| } |
| |
| rc = img_mgmt_read_info(0, NULL, imghash, NULL); |
| if (rc) { |
| return rc; |
| } |
| |
| memcpy(hash, imghash, hashlen); |
| |
| return 0; |
| } |
| |
| int |
| imgr_my_version(struct image_version *ver) |
| { |
| return img_mgmt_read_info(boot_current_slot, ver, NULL, NULL); |
| } |
| |
| /* |
| * Finds image given version number. Returns the slot number image is in, |
| * or -1 if not found. |
| */ |
| int |
| imgr_find_by_ver(struct image_version *find, uint8_t *hash) |
| { |
| int i; |
| struct image_version ver; |
| |
| for (i = 0; i < 2; i++) { |
| if (img_mgmt_read_info(i, &ver, hash, NULL) != 0) { |
| continue; |
| } |
| if (!memcmp(find, &ver, sizeof(ver))) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| /* |
| * Finds image given hash of the image. Returns the slot number image is in, |
| * or -1 if not found. |
| */ |
| int |
| imgr_find_by_hash(uint8_t *find, struct image_version *ver) |
| { |
| int i; |
| uint8_t hash[IMGMGR_HASH_LEN]; |
| |
| for (i = 0; i < 2; i++) { |
| if (img_mgmt_read_info(i, ver, hash, NULL) != 0) { |
| continue; |
| } |
| if (!memcmp(hash, find, IMGMGR_HASH_LEN)) { |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| int |
| imgmgr_find_best_area_id(void) |
| { |
| struct image_version ver; |
| int best = -1; |
| int i; |
| int rc; |
| |
| for (i = 0; i < 2; i++) { |
| rc = img_mgmt_read_info(i, &ver, NULL, NULL); |
| if (rc < 0) { |
| continue; |
| } |
| if (rc == 0) { |
| /* Image in slot is ok. */ |
| if (img_mgmt_slot_in_use(i)) { |
| /* Slot is in use; can't use this. */ |
| continue; |
| } else { |
| /* |
| * Not active slot, but image is ok. Use it if there are |
| * no better candidates. |
| */ |
| best = i; |
| } |
| continue; |
| } |
| best = i; |
| break; |
| } |
| if (best >= 0) { |
| best = flash_area_id_from_image_slot(best); |
| } |
| return best; |
| } |
| |
| static int |
| imgr_erase_state(struct mgmt_ctxt *ctxt) |
| { |
| const struct flash_area *fa; |
| int area_id; |
| int rc; |
| CborError g_err = CborNoError; |
| |
| area_id = imgmgr_find_best_area_id(); |
| if (area_id >= 0) { |
| rc = flash_area_open(area_id, &fa); |
| if (rc) { |
| return img_mgmt_error_rsp(ctxt, MGMT_ERR_EINVAL, |
| img_mgmt_err_str_flash_open_failed); |
| } |
| |
| rc = flash_area_erase(fa, 0, sizeof(struct image_header)); |
| if (rc) { |
| return img_mgmt_error_rsp(ctxt, MGMT_ERR_EINVAL, |
| img_mgmt_err_str_flash_erase_failed); |
| } |
| |
| flash_area_close(fa); |
| |
| } else { |
| return img_mgmt_error_rsp(ctxt, MGMT_ERR_ENOMEM, img_mgmt_err_str_no_slot); |
| } |
| |
| g_err |= cbor_encode_text_stringz(&ctxt->encoder, "rc"); |
| g_err |= cbor_encode_int(&ctxt->encoder, MGMT_ERR_EOK); |
| |
| if (g_err) { |
| return MGMT_ERR_ENOMEM; |
| } |
| |
| return 0; |
| } |
| |
| void |
| imgmgr_module_init(void) |
| { |
| int rc; |
| /* Ensure this function only gets called by sysinit. */ |
| SYSINIT_ASSERT_ACTIVE(); |
| |
| mgmt_register_group(&imgr_mgmt_group); |
| |
| #if MYNEWT_VAL(IMGMGR_CLI) |
| rc = imgr_cli_register(); |
| SYSINIT_PANIC_ASSERT(rc == 0); |
| #else |
| (void) rc; |
| #endif |
| } |