| /* |
| * 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 <stddef.h> |
| #include <limits.h> |
| #include "os/mynewt.h" |
| #include "hal/hal_bsp.h" |
| #include "flash_map/flash_map.h" |
| #include "bootutil/image.h" |
| #include "imgmgr/imgmgr.h" |
| #include "coredump/coredump.h" |
| |
| uint8_t coredump_disabled; |
| |
| static void |
| dump_core_tlv(const struct flash_area *fa, uint32_t *off, |
| struct coredump_tlv *tlv, void *data) |
| { |
| flash_area_write(fa, *off, tlv, sizeof(*tlv)); |
| *off += sizeof(*tlv); |
| |
| flash_area_write(fa, *off, data, tlv->ct_len); |
| *off += tlv->ct_len; |
| } |
| |
| void |
| coredump_dump(void *regs, int regs_sz) |
| { |
| struct coredump_header hdr; |
| struct coredump_tlv tlv; |
| const struct flash_area *fa; |
| struct image_version ver; |
| const struct hal_bsp_mem_dump *mem, *cur; |
| int area_cnt, i; |
| uint8_t hash[IMGMGR_HASH_LEN]; |
| uint32_t off; |
| uint32_t area_off, area_end; |
| int slot; |
| |
| if (coredump_disabled) { |
| return; |
| } |
| if (flash_area_open(MYNEWT_VAL(COREDUMP_FLASH_AREA), &fa)) { |
| return; |
| } |
| |
| if (flash_area_read(fa, 0, &hdr, sizeof(hdr))) { |
| return; |
| } |
| if (hdr.ch_magic == COREDUMP_MAGIC) { |
| /* |
| * Don't override corefile. |
| */ |
| return; |
| } |
| |
| /* Don't overwrite an image that has any flags set (pending, active, or |
| * confirmed). |
| */ |
| slot = flash_area_id_to_image_slot(MYNEWT_VAL(COREDUMP_FLASH_AREA)); |
| if (slot != -1) { |
| if (imgmgr_state_slot_in_use(slot)) { |
| return; |
| } |
| } |
| |
| if (flash_area_erase(fa, 0, fa->fa_size)) { |
| return; |
| } |
| |
| /* |
| * First put in data, followed by the header. |
| */ |
| tlv.ct_type = COREDUMP_TLV_REGS; |
| tlv._pad = 0; |
| tlv.ct_len = regs_sz; |
| tlv.ct_off = 0; |
| |
| off = sizeof(hdr); |
| dump_core_tlv(fa, &off, &tlv, regs); |
| |
| if (imgr_read_info(boot_current_slot, &ver, hash, NULL) == 0) { |
| tlv.ct_type = COREDUMP_TLV_IMAGE; |
| tlv.ct_len = IMGMGR_HASH_LEN; |
| |
| dump_core_tlv(fa, &off, &tlv, hash); |
| } |
| |
| mem = hal_bsp_core_dump(&area_cnt); |
| for (i = 0; i < area_cnt; i++) { |
| cur = &mem[i]; |
| area_off = (uint32_t)cur->hbmd_start; |
| area_end = area_off + cur->hbmd_size; |
| while (area_off < area_end) { |
| tlv.ct_type = COREDUMP_TLV_MEM; |
| if (area_end - area_off > USHRT_MAX) { |
| tlv.ct_len = USHRT_MAX - 3; /* 0xfffc */ |
| } else { |
| tlv.ct_len = area_end - area_off; |
| } |
| if (off + tlv.ct_len + sizeof(tlv) > fa->fa_size) { |
| if (off + sizeof(tlv) >= fa->fa_size) { |
| break; |
| } |
| tlv.ct_len = fa->fa_size - (off + sizeof(tlv)); |
| } |
| tlv.ct_off = area_off; |
| dump_core_tlv(fa, &off, &tlv, (void *)area_off); |
| area_off += tlv.ct_len; |
| } |
| } |
| hdr.ch_magic = COREDUMP_MAGIC; |
| hdr.ch_size = off; |
| |
| flash_area_write(fa, 0, &hdr, sizeof(hdr)); |
| } |