Source code for the Trusted Boot Module.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
tbm-mcu/source/ftl/ftl.c

149 lines
3.2 KiB

#include <limits.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <bitops.h>
#include <flash.h>
#include <ftl.h>
#include <macros.h>
#include "gc.h"
#include "map.h"
int ftl_is_mapped(struct ftl_map *map, uint32_t va)
{
if (trace_path(map, NULL, NULL, va) < 0)
return 0;
return 1;
}
size_t ftl_read(struct ftl_map *map, void *data, size_t len, uint32_t va)
{
int ret;
uint32_t mask, offset, page;
if (!data)
return 0;
mask = ((1 << map->log2_page_size) - 1);
offset = va & mask;
va >>= map->log2_page_size;
len = min(len, (1 << map->log2_page_size) - offset);
if ((ret = trace_path(map, NULL, &page, va)) < 0) {
memset(data, 0, len);
return len;
}
return flash_read(map->dev, (page << map->log2_page_size) + offset, data,
len);
}
size_t ftl_write(struct ftl_map *map, uint32_t va, const void *udata,
size_t len)
{
char data[1 << map->log2_page_size];
struct ftl_page_desc page_desc;
int ret;
uint32_t mask, offset, page;
if (va >= ftl_get_capacity(map) &&
!is_aligned(va, 1 << map->log2_page_size))
return 0;
mask = ((1 << map->log2_page_size) - 1);
offset = va & mask;
va >>= map->log2_page_size;
if ((ret = trace_path(map, &page_desc, &page, va)) < 0 &&
ret != -ERR_NOT_FOUND)
return 0;
if (ret == -ERR_NOT_FOUND) {
memset(data, 0, 1 << map->log2_page_size);
++map->nused_pages;
} else if (flash_read(map->dev, page << map->log2_page_size, data,
1 << map->log2_page_size) == 0) {
return 0;
}
page_desc.nused_pages = map->nused_pages;
len = min(len, (1 << map->log2_page_size) - offset);
memcpy(data + offset, udata, len);
if (write_upage(map, data, &page_desc) < 0)
return 0;
return len;
}
int ftl_trim(struct ftl_map *map, uint32_t va)
{
struct ftl_page_desc page_desc, alt_page_desc;
size_t level, i;
uint32_t alt_va, page;
int ret;
if ((ret = trace_path(map, &page_desc, &page, va)) < 0) {
if (ret == -ERR_NOT_FOUND)
return 0;
return ret;
}
--map->nused_pages;
for (i = 0; i < 32; ++i) {
level = 32 - i - 1;
if ((alt_va = page_desc.subtrees[level]) != UINT32_MAX)
break;
}
if (i == 32) {
map->root = UINT32_MAX;
memset(&page_desc, 0xff, sizeof page_desc);
page_desc.nused_pages = 0;
return write_upage(map, NULL, &page_desc);
}
if (read_page_desc(map, &alt_page_desc, alt_va) < 0)
return -1;
page_desc.va = alt_page_desc.va;
page_desc.nused_pages = map->nused_pages;
page_desc.subtrees[level] = UINT32_MAX;
for (i = level + 1; i < 32; ++i) {
page_desc.subtrees[i] = alt_page_desc.subtrees[i];
}
if (flash_copy(map->dev, map->head << map->log2_page_size,
page << map->log2_page_size, 1 << map->log2_page_size) < 0)
return -1;
return write_upage(map, NULL, &page_desc);
}
/* Returns the amount of used pages with a unique virtual address multiplied by
* the page size as the size of used space on the device.
*/
uint32_t ftl_get_size(const struct ftl_map *map)
{
return map->nused_pages << map->log2_page_size;
}
/* The capacity of the device is the total amount of user pages minus a block
* worth of user pages for garbage collection.
*/
uint32_t ftl_get_capacity(const struct ftl_map *map)
{
return ((map->nblocks - 1) << map->log2_block_size) -
((map->nblocks - 1) << map->log2_page_size);
}