blob: 63f36452b1005aa129b6f7c1750667ef4c1116ac [file] [log] [blame]
/**
* Copyright (c) 2015 Runtime Inc.
*
* 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 <stdio.h>
#include <assert.h>
#include <string.h>
#include <inttypes.h>
#include "hal/hal_flash.h"
static FILE *file;
static const struct flash_area_desc {
uint32_t fad_offset;
uint32_t fad_length;
uint32_t fad_sector_id;
} flash_area_descs[] = {
{ 0x00000000, 16 * 1024, 0 },
{ 0x00004000, 16 * 1024, 1 },
{ 0x00008000, 16 * 1024, 2 },
{ 0x0000c000, 16 * 1024, 3 },
{ 0x00010000, 64 * 1024, 4 },
{ 0x00020000, 128 * 1024, 5 },
{ 0x00040000, 128 * 1024, 6 },
{ 0x00060000, 128 * 1024, 7 },
{ 0x00080000, 128 * 1024, 8 },
{ 0x000a0000, 128 * 1024, 9 },
{ 0x000c0000, 128 * 1024, 10 },
{ 0x000e0000, 128 * 1024, 11 },
};
#define FLASH_NUM_AREAS (int)(sizeof flash_area_descs / \
sizeof flash_area_descs[0])
static void
flash_native_erase(uint32_t addr, uint32_t len)
{
static uint8_t buf[256];
uint32_t end;
int chunk_sz;
int rc;
end = addr + len;
memset(buf, 0xff, sizeof buf);
rc = fseek(file, addr, SEEK_SET);
assert(rc == 0);
while (addr < end) {
if (end - addr < sizeof buf) {
chunk_sz = end - addr;
} else {
chunk_sz = sizeof buf;
}
rc = fwrite(buf, chunk_sz, 1, file);
assert(rc == 1);
addr += chunk_sz;
}
fflush(file);
}
static void
flash_native_ensure_file_open(void)
{
int expected_sz;
int i;
if (file == NULL) {
expected_sz = 0;
for (i = 0; i < FLASH_NUM_AREAS; i++) {
expected_sz += flash_area_descs[i].fad_length;
}
file = tmpfile();
assert(file != NULL);
flash_native_erase(0, expected_sz);
}
}
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();
fseek(file, address, SEEK_SET);
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 = flash_read(cur, buf, chunk_sz);
assert(rc == 0);
for (i = 0; i < chunk_sz; i++) {
assert(buf[i] == 0xff);
}
}
cur += chunk_sz;
}
fseek(file, address, SEEK_SET);
rc = fwrite(src, length, 1, file);
assert(rc == 1);
fflush(file);
return 0;
}
int
flash_write(uint32_t address, const void *src, uint32_t length)
{
return flash_native_write_internal(address, src, length, 0);
}
int
flash_native_overwrite(uint32_t address, const void *src, uint32_t length)
{
return flash_native_write_internal(address, src, length, 1);
}
int
flash_native_memset(uint32_t offset, uint8_t c, uint32_t len)
{
uint8_t buf[256];
int chunk_sz;
int rc;
memset(buf, c, sizeof buf);
while (len > 0) {
if (len > sizeof buf) {
chunk_sz = sizeof buf;
} else {
chunk_sz = len;
}
rc = flash_native_overwrite(offset, buf, chunk_sz);
if (rc != 0) {
return rc;
}
offset += chunk_sz;
len -= chunk_sz;
}
return 0;
}
int
flash_read(uint32_t address, void *dst, uint32_t length)
{
flash_native_ensure_file_open();
fseek(file, address, SEEK_SET);
fread(dst, length, 1, file);
return 0;
}
static int
find_area(uint32_t address)
{
int i;
for (i = 0; i < FLASH_NUM_AREAS; i++) {
if (flash_area_descs[i].fad_offset == address) {
return i;
}
}
return -1;
}
int
flash_erase_sector(uint32_t sector_address)
{
int next_sector_id;
int sector_id;
int area_id;
flash_native_ensure_file_open();
area_id = find_area(sector_address);
if (area_id == -1) {
return -1;
}
sector_id = flash_area_descs[area_id].fad_sector_id;
while (1) {
flash_native_erase(sector_address,
flash_area_descs[area_id].fad_length);
area_id++;
if (area_id >= FLASH_NUM_AREAS) {
break;
}
next_sector_id = flash_area_descs[area_id].fad_sector_id;
if (next_sector_id != sector_id) {
break;
}
sector_id = next_sector_id;
}
return 0;
}
int
flash_erase(uint32_t address, uint32_t num_bytes)
{
const struct flash_area_desc *area;
uint32_t end;
int i;
flash_native_ensure_file_open();
end = address + num_bytes;
for (i = 0; i < FLASH_NUM_AREAS; i++) {
area = flash_area_descs + i;
if (area->fad_offset >= end) {
return 0;
}
if (address >= area->fad_offset &&
address < area->fad_offset + area->fad_length) {
flash_native_erase(area->fad_offset, area->fad_length);
}
}
return 0;
}
int
flash_init(void)
{
return 0;
}