| /* |
| * 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 <sys/mman.h> |
| #include <fcntl.h> |
| #include <assert.h> |
| #include <string.h> |
| #include <inttypes.h> |
| #include <stdlib.h> |
| |
| #include "os/mynewt.h" |
| |
| #include "hal/hal_flash_int.h" |
| #include "mcu/mcu_sim.h" |
| |
| char *native_flash_file; |
| static int file; |
| static void *file_loc; |
| |
| static int native_flash_init(const struct hal_flash *dev); |
| static int native_flash_read(const struct hal_flash *dev, uint32_t address, |
| void *dst, uint32_t length); |
| static int native_flash_write(const struct hal_flash *dev, uint32_t address, |
| const void *src, uint32_t length); |
| static int native_flash_erase_sector(const struct hal_flash *dev, |
| uint32_t sector_address); |
| static int native_flash_sector_info(const struct hal_flash *dev, int idx, |
| uint32_t *address, uint32_t *size); |
| |
| static const struct hal_flash_funcs native_flash_funcs = { |
| .hff_read = native_flash_read, |
| .hff_write = native_flash_write, |
| .hff_erase_sector = native_flash_erase_sector, |
| .hff_sector_info = native_flash_sector_info, |
| .hff_init = native_flash_init |
| }; |
| |
| #if MYNEWT_VAL(MCU_FLASH_STYLE_ST) |
| static const uint32_t native_flash_sectors[] = { |
| 0x00000000, /* 16 * 1024 */ |
| 0x00004000, /* 16 * 1024 */ |
| 0x00008000, /* 16 * 1024 */ |
| 0x0000c000, /* 16 * 1024 */ |
| 0x00010000, /* 64 * 1024 */ |
| 0x00020000, /* 128 * 1024 */ |
| 0x00040000, /* 128 * 1024 */ |
| 0x00060000, /* 128 * 1024 */ |
| 0x00080000, /* 128 * 1024 */ |
| 0x000a0000, /* 128 * 1024 */ |
| 0x000c0000, /* 128 * 1024 */ |
| 0x000e0000, /* 128 * 1024 */ |
| }; |
| #elif MYNEWT_VAL(MCU_FLASH_STYLE_NORDIC) |
| static uint32_t native_flash_sectors[1024 * 1024 / 2048]; |
| #else |
| #error "Need to specify either MCU_FLASH_STYLE_NORDIC or MCU_FLASH_STYLE_ST" |
| #endif |
| |
| #define FLASH_NUM_AREAS (int)(sizeof native_flash_sectors / \ |
| sizeof native_flash_sectors[0]) |
| |
| const struct hal_flash native_flash_dev = { |
| .hf_itf = &native_flash_funcs, |
| .hf_base_addr = 0, |
| .hf_size = 1024 * 1024, |
| .hf_sector_cnt = FLASH_NUM_AREAS, |
| .hf_align = MYNEWT_VAL(MCU_FLASH_MIN_WRITE_SIZE), |
| .hf_erased_val = 0xff, |
| }; |
| |
| static void |
| flash_native_erase(uint32_t addr, uint32_t len) |
| { |
| memset(file_loc + addr, 0xff, len); |
| } |
| |
| static void |
| flash_native_file_open(char *name) |
| { |
| int created = 0; |
| extern int ftruncate(int fd, off_t length); |
| |
| if (name) { |
| file = open(name, O_RDWR); |
| if (file < 0) { |
| file = open(name, O_RDWR | O_CREAT, 0660); |
| assert(file > 0); |
| created = 1; |
| } |
| } else { |
| char tmpl[] = "/tmp/native_flash.XXXXXX"; |
| file = mkstemp(tmpl); |
| assert(file > 0); |
| created = 1; |
| } |
| |
| if (created) { |
| if (ftruncate(file, native_flash_dev.hf_size) < 0) { |
| assert(0); |
| } |
| } |
| |
| file_loc = mmap(0, native_flash_dev.hf_size, |
| PROT_READ | PROT_WRITE, MAP_SHARED, file, 0); |
| assert(file_loc != MAP_FAILED); |
| if (created) { |
| flash_native_erase(0, native_flash_dev.hf_size); |
| } |
| } |
| |
| static void |
| flash_native_ensure_file_open(void) |
| { |
| if (file == 0) { |
| flash_native_file_open(NULL); |
| } |
| } |
| |
| static int |
| flash_native_write_internal(uint32_t address, const void *src, uint32_t length, |
| int allow_overwrite) |
| { |
| static uint8_t buf[256]; |
| uint32_t cur; |
| uint32_t end; |
| int chunk_sz; |
| int rc; |
| int i; |
| |
| if (length == 0) { |
| return 0; |
| } |
| |
| end = address + length; |
| |
| flash_native_ensure_file_open(); |
| |
| cur = address; |
| while (cur < end) { |
| if (end - cur < sizeof buf) { |
| chunk_sz = end - cur; |
| } else { |
| chunk_sz = sizeof buf; |
| } |
| |
| /* Ensure data is not being overwritten. */ |
| if (!allow_overwrite) { |
| rc = native_flash_read(NULL, cur, buf, chunk_sz); |
| assert(rc == 0); |
| for (i = 0; i < chunk_sz; i++) { |
| assert(buf[i] == 0xff); |
| } |
| } |
| |
| cur += chunk_sz; |
| } |
| |
| memcpy((char *)file_loc + address, src, length); |
| |
| return 0; |
| } |
| |
| static int |
| native_flash_write(const struct hal_flash *dev, uint32_t address, |
| const void *src, uint32_t length) |
| { |
| assert(address % native_flash_dev.hf_align == 0); |
| return flash_native_write_internal(address, src, length, 0); |
| } |
| |
| int |
| flash_native_memset(uint32_t offset, uint8_t c, uint32_t len) |
| { |
| memset(file_loc + offset, c, len); |
| return 0; |
| } |
| |
| static int |
| native_flash_read(const struct hal_flash *dev, uint32_t address, void *dst, |
| uint32_t length) |
| { |
| flash_native_ensure_file_open(); |
| memcpy(dst, (char *)file_loc + address, length); |
| |
| return 0; |
| } |
| |
| static int |
| find_area(uint32_t address) |
| { |
| int i; |
| |
| for (i = 0; i < FLASH_NUM_AREAS; i++) { |
| if (native_flash_sectors[i] == address) { |
| return i; |
| } |
| } |
| |
| return -1; |
| } |
| |
| static int |
| flash_sector_len(int sector) |
| { |
| uint32_t end; |
| |
| if (sector == FLASH_NUM_AREAS - 1) { |
| end = native_flash_dev.hf_size + native_flash_sectors[0]; |
| } else { |
| end = native_flash_sectors[sector + 1]; |
| } |
| return end - native_flash_sectors[sector]; |
| } |
| |
| static int |
| native_flash_erase_sector(const struct hal_flash *dev, uint32_t sector_address) |
| { |
| int area_id; |
| uint32_t len; |
| |
| flash_native_ensure_file_open(); |
| |
| area_id = find_area(sector_address); |
| if (area_id == -1) { |
| return -1; |
| } |
| len = flash_sector_len(area_id); |
| flash_native_erase(sector_address, len); |
| return 0; |
| } |
| |
| static int |
| native_flash_sector_info(const struct hal_flash *dev, int idx, |
| uint32_t *address, uint32_t *size) |
| { |
| assert(idx < FLASH_NUM_AREAS); |
| |
| *address = native_flash_sectors[idx]; |
| *size = flash_sector_len(idx); |
| return 0; |
| } |
| |
| static int |
| native_flash_init(const struct hal_flash *dev) |
| { |
| if (native_flash_file) { |
| flash_native_file_open(native_flash_file); |
| } |
| #if MYNEWT_VAL(MCU_FLASH_STYLE_NORDIC) |
| int i; |
| |
| for (i = 0; i < FLASH_NUM_AREAS; i++) { |
| native_flash_sectors[i] = i * 2048; |
| } |
| #endif |
| return 0; |
| } |