blob: cc838374715377410e1589bf4d64ceca6d28343c [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 "hal/hal_flash.h"
#include "nffs/nffs.h"
#include "nffs_priv.h"
/** A buffer used for flash reads; shared across all of nffs. */
uint8_t nffs_flash_buf[NFFS_FLASH_BUF_SZ];
/**
* Reads a chunk of data from flash.
*
* @param area_idx The index of the area to read from.
* @param area_offset The offset within the area to read from.
* @param data On success, the flash contents are written
* here.
* @param len The number of bytes to read.
*
* @return 0 on success;
* FS_EOFFSET on an attempt to read an invalid
* address range;
* FS_EHW on flash error.
*/
int
nffs_flash_read(uint8_t area_idx, uint32_t area_offset, void *data,
uint32_t len)
{
const struct nffs_area *area;
int rc;
assert(area_idx < nffs_num_areas);
area = nffs_areas + area_idx;
if (area_offset + len > area->na_length) {
return FS_EOFFSET;
}
STATS_INC(nffs_stats, nffs_iocnt_read);
rc = hal_flash_read(area->na_flash_id, area->na_offset + area_offset, data,
len);
if (rc != 0) {
return FS_EHW;
}
return 0;
}
/**
* Writes a chunk of data to flash.
*
* @param area_idx The index of the area to write to.
* @param area_offset The offset within the area to write to.
* @param data The data to write to flash.
* @param len The number of bytes to write.
*
* @return 0 on success;
* FS_EOFFSET on an attempt to write to an
* invalid address range, or on an attempt to
* perform a non-strictly-sequential write;
* FS_EFLASH_ERROR on flash error.
*/
int
nffs_flash_write(uint8_t area_idx, uint32_t area_offset, const void *data,
uint32_t len)
{
struct nffs_area *area;
int rc;
assert(area_idx < nffs_num_areas);
area = nffs_areas + area_idx;
if (area_offset + len > area->na_length) {
return FS_EOFFSET;
}
if (area_offset < area->na_cur) {
return FS_EOFFSET;
}
STATS_INC(nffs_stats, nffs_iocnt_write);
rc = hal_flash_write(area->na_flash_id, area->na_offset + area_offset,
data, len);
if (rc != 0) {
return FS_EHW;
}
area->na_cur = area_offset + len;
return 0;
}
/**
* Copies a chunk of data from one region of flash to another.
*
* @param area_idx_from The index of the area to copy from.
* @param area_offset_from The offset within the area to copy from.
* @param area_idx_to The index of the area to copy to.
* @param area_offset_to The offset within the area to copy to.
* @param len The number of bytes to copy.
*
* @return 0 on success; nonzero on failure.
*/
int
nffs_flash_copy(uint8_t area_idx_from, uint32_t area_offset_from,
uint8_t area_idx_to, uint32_t area_offset_to,
uint32_t len)
{
uint32_t chunk_len;
int rc;
/* Copy data in chunks small enough to fit in the flash buffer. */
while (len > 0) {
if (len > sizeof nffs_flash_buf) {
chunk_len = sizeof nffs_flash_buf;
} else {
chunk_len = len;
}
STATS_INC(nffs_stats, nffs_readcnt_copy);
rc = nffs_flash_read(area_idx_from, area_offset_from, nffs_flash_buf,
chunk_len);
if (rc != 0) {
return rc;
}
rc = nffs_flash_write(area_idx_to, area_offset_to, nffs_flash_buf,
chunk_len);
if (rc != 0) {
return rc;
}
area_offset_from += chunk_len;
area_offset_to += chunk_len;
len -= chunk_len;
}
return 0;
}
/**
* Compresses a flash-area-index,flash-area-offset pair into a 32-bit flash
* location.
*/
uint32_t
nffs_flash_loc(uint8_t area_idx, uint32_t area_offset)
{
assert(area_offset <= 0x00ffffff);
return area_idx << 24 | area_offset;
}
/**
* Expands a compressed 32-bit flash location into a
* flash-area-index,flash-area-offset pair.
*/
void
nffs_flash_loc_expand(uint32_t flash_loc, uint8_t *out_area_idx,
uint32_t *out_area_offset)
{
*out_area_idx = flash_loc >> 24;
*out_area_offset = flash_loc & 0x00ffffff;
}