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/gc.c

134 lines
3.7 KiB

#include <flash.h>
#include <ftl.h>
#include <macros.h>
#include "gc.h"
int read_page_desc(struct ftl_map *map,
struct ftl_page_desc *page_desc, uint32_t upage);
int trace_path(struct ftl_map *map,
struct ftl_page_desc *new_page_desc, uint32_t *loc, uint32_t va);
int write_upage(struct ftl_map *map, const uint8_t *page,
const struct ftl_page_desc *page_desc);
/* For a given user page, attempt to claim more free space by checking if no
* recent mapping has obsoleted the older mapping. If a more recent mapping
* exists, the page can be safely ignored and erased. Otherwise, we preserve
* the page by copying the page to create a new mapping such that the old page
* can be ignored and erased.
*/
static int free_page(struct ftl_map *map, uint32_t upage)
{
struct ftl_page_desc page_desc;
uint32_t found_upage, va;
if (read_page_desc(map, &page_desc, upage) < 0)
return -1;
va = page_desc.va;
if (trace_path(map, &page_desc, &found_upage, va) < 0)
return -1;
if (upage != found_upage)
return 0;
page_desc.nused_pages = map->nused_pages;
if (flash_copy(map->dev, map->head << map->log2_page_size,
upage << map->log2_page_size, 1 << map->log2_page_size) == 0)
return -1;
return write_upage(map, NULL, &page_desc);
}
/* Claim more free space by checking which user pages in a page group are
* mapped and for which the mappings have been obsoleted by a more recent
* mapping. The mapped user pages are preserved by copying.
*/
static int free_group(struct ftl_map *map, uint32_t group)
{
uint32_t npages = UINT32_C(1) << map->log2_pages_per_group;
uint32_t page = group << map->log2_pages_per_group;
uint32_t i;
for (i = 0; i < npages; ++i) {
if (free_page(map, page + i) < 0)
return -1;
}
return 0;
}
/* Claim more free space by checking which user pages in a block are mapped and
* for which the mappings have been obsoleted by a more recent mapping. The
* mapped user pages are preserved by copying.
*/
static int free_block(struct ftl_map *map, uint32_t block)
{
uint32_t ngroups = UINT32_C(1) << map->log2_groups_per_block;
uint32_t group = block << map->log2_groups_per_block;
uint32_t i;
for (i = 0; i < ngroups; ++i) {
if (free_group(map, group + i) < 0)
return -1;
}
return 0;
}
/* Checks if there are sufficient pages available for writing. Otherwise this
* function attempts to claim more free space from unmapped pages for which
* newer pages have obsoleted the mapping. Further, we move the user pages that
* are still mapped as these should be preserved.
*/
static int free_tail(struct ftl_map *map)
{
size_t log2_pages_per_block = map->log2_pages_per_group +
map->log2_groups_per_block;
size_t npages = map->nblocks << log2_pages_per_block;
size_t dist;
if (map->head < map->tail)
dist = map->tail - map->head;
else
dist = npages - map->head + map->tail;
if (dist > (UINT32_C(1) << log2_pages_per_block))
return 0;
if (free_block(map, map->tail >> log2_pages_per_block) < 0)
return -1;
map->tail += 1 << log2_pages_per_block;
if (map->tail >= npages)
map->tail -= npages;
return 0;
}
/* Prepare the head for writing. If the user page to be written to is not
* aligned on a block boundary, the block must already be erased and there is
* nothing to be done. Otherwise, we free the tail if necessary and erase the
* block for writing.
*/
#ifdef prepare_head
#undef prepare_head
#define prepare_head __real_prepare_head
#endif
int prepare_head(struct ftl_map *map)
{
size_t log2_pages_per_block = map->log2_pages_per_group +
map->log2_groups_per_block;
if (!is_aligned(map->head, log2_pages_per_block))
return 0;
if (free_tail(map) < 0)
return -1;
return flash_erase(map->dev, map->head, 1 << log2_pages_per_block);
}