Skip to content

Commit

Permalink
dragonfs: remove open file limit and local sector cache from open files
Browse files Browse the repository at this point in the history
  • Loading branch information
rasky committed Oct 23, 2023
1 parent c5c62ea commit 6963df1
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 137 deletions.
15 changes: 2 additions & 13 deletions include/dfsinternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,26 +42,15 @@ _Static_assert(sizeof(struct directory_entry) == SECTOR_SIZE, "invalid directory
typedef struct directory_entry directory_entry_t;

/** @brief Open file handle structure */
typedef struct open_file
typedef struct dfs_open_file_s
{
/** @brief Cached data to speed up small reads.
*
* We want this buffer to be 8-byte aligned for DMA, but also
* 16-byte aligned so that it doesn't share cachelines with other
* members of the structure, so it's easier to handle coherency.
* */
uint8_t cached_data[512] __attribute__((aligned(16)));
/** @brief location of the cached data */
uint32_t cached_loc;
/** @brief The unique file handle to refer to this file by */
uint32_t handle;
/** @brief The size in bytes of this file */
uint32_t size;
/** @brief The offset of the current location in the file */
uint32_t loc;
/** @brief The offset within the filesystem where the file is stored */
uint32_t cart_start_loc;
} open_file_t;
} dfs_open_file_t;

/** @} */ /* dfs */

Expand Down
5 changes: 0 additions & 5 deletions include/dragonfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,6 @@
*/
#define DFS_DEFAULT_LOCATION 0

/**
* @brief Maximum open files in DragonFS
*/
#define MAX_OPEN_FILES 4

/**
* @brief Maximum filename length
*
Expand Down
173 changes: 54 additions & 119 deletions src/dragonfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "system.h"
#include "dfsinternal.h"
#include "rompak_internal.h"
#include "utils.h"

/**
* @defgroup dfs DragonFS
Expand Down Expand Up @@ -78,14 +79,16 @@ enum

/** @brief Base filesystem pointer */
static uint32_t base_ptr = 0;
/** @brief Open file tracking */
static open_file_t open_files[MAX_OPEN_FILES];
/** @brief Directory pointer stack */
static uint32_t directories[MAX_DIRECTORY_DEPTH];
/** @brief Depth into directory pointer stack */
static uint32_t directory_top = 0;
/** @brief Pointer to next directory entry set when doing a directory walk */
static directory_entry_t *next_entry = 0;
/** @brief Convert an open file pointer to a handle */
#define OPENFILE_TO_HANDLE(file) ((int)PhysicalAddr(file))
/** @brief Convert a handle to an open file pointer */
#define HANDLE_TO_OPENFILE(handle) ((dfs_open_file_t*)((uint32_t)(handle) | 0x80000000))

/**
* @brief Read a sector from cartspace
Expand All @@ -106,51 +109,6 @@ static inline void grab_sector(void *cart_loc, void *ram_loc)
dma_read((void *)(((uint32_t)ram_loc) & 0x1FFFFFFF), (uint32_t)cart_loc, SECTOR_SIZE);
}

/**
* @brief Find a free open file structure
*
* @return A pointer to an open file structure or NULL if no more open file structures.
*/
static open_file_t *find_free_file()
{
for(int i = 0; i < MAX_OPEN_FILES; i++)
{
if(!open_files[i].handle)
{
/* Found one! */
return &open_files[i];
}
}

/* No free files */
return 0;
}

/**
* @brief Find an open file structure based on a handle
*
* @param[in] x
* The file handle given to the open file
*
* @return A pointer to an open file structure or NULL if no file matches the handle
*/
static open_file_t *find_open_file(uint32_t x)
{
if(x == 0) { return 0; }

for(int i = 0; i < MAX_OPEN_FILES; i++)
{
if(open_files[i].handle == x)
{
/* Found it! */
return &open_files[i];
}
}

/* Couldn't find handle */
return 0;
}

/**
* @brief Look up a sector number based on offset
*
Expand Down Expand Up @@ -643,8 +601,6 @@ static int __dfs_init(uint32_t base_fs_loc)
base_ptr = base_fs_loc;
clear_directory();

memset(open_files, 0, sizeof(open_files));

/* Good FS */
return DFS_ESUCCESS;
}
Expand Down Expand Up @@ -766,17 +722,6 @@ int dfs_dir_findnext(char *buf)
*/
int dfs_open(const char * const path)
{
/* Ensure we always open with a unique handle */
static uint32_t next_handle = 1;

/* Try to find a free slot */
open_file_t *file = find_free_file();

if(!file)
{
return DFS_ENFILE;
}

/* Try to find file */
directory_entry_t *dirent;
int ret = recurse_path(path, WALK_OPEN, &dirent, TYPE_FILE);
Expand All @@ -787,18 +732,24 @@ int dfs_open(const char * const path)
return ret;
}

/* Try to find a free slot */
dfs_open_file_t *file = malloc(sizeof(dfs_open_file_t));

if(!file)
{
return DFS_ENOMEM;
}

/* We now have the pointer to the file entry */
directory_entry_t t_node;
grab_sector(dirent, &t_node);

/* Set up file handle */
file->handle = next_handle++;
file->size = get_size(&t_node);
file->loc = 0;
file->cart_start_loc = get_start_location(&t_node);
file->cached_loc = 0xFFFFFFFF;

return file->handle;
return OPENFILE_TO_HANDLE(file);
}

/**
Expand All @@ -811,15 +762,15 @@ int dfs_open(const char * const path)
*/
int dfs_close(uint32_t handle)
{
open_file_t *file = find_open_file(handle);
dfs_open_file_t *file = HANDLE_TO_OPENFILE(handle);

if(!file)
{
return DFS_EBADHANDLE;
}

/* Closing the handle is easy as zeroing out the file */
memset(file, 0, sizeof(open_file_t));
/* Free the open file */
free(file);

return DFS_ESUCCESS;
}
Expand All @@ -838,7 +789,7 @@ int dfs_close(uint32_t handle)
*/
int dfs_seek(uint32_t handle, int offset, int origin)
{
open_file_t *file = find_open_file(handle);
dfs_open_file_t *file = HANDLE_TO_OPENFILE(handle);

if(!file)
{
Expand Down Expand Up @@ -912,7 +863,7 @@ int dfs_seek(uint32_t handle, int offset, int origin)
int dfs_tell(uint32_t handle)
{
/* The good thing is that the location is always in the file structure */
open_file_t *file = find_open_file(handle);
dfs_open_file_t *file = HANDLE_TO_OPENFILE(handle);

if(!file)
{
Expand All @@ -924,7 +875,11 @@ int dfs_tell(uint32_t handle)

/**
* @brief Read data from a file
*
*
* Note that no caching is performed: if you need to read small amounts
* (eg: one byte at a time), consider using standard C API instead (fopen())
* which performs internal buffering to avoid too much overhead.
*
* @param[out] buf
* Buffer to read into
* @param[in] size
Expand All @@ -939,7 +894,7 @@ int dfs_tell(uint32_t handle)
int dfs_read(void * const buf, int size, int count, uint32_t handle)
{
/* This is where we do all the work */
open_file_t *file = find_open_file(handle);
dfs_open_file_t *file = HANDLE_TO_OPENFILE(handle);

if(!file)
{
Expand All @@ -953,7 +908,6 @@ int dfs_read(void * const buf, int size, int count, uint32_t handle)
}

int to_read = size * count;
int did_read = 0;

/* Bounds check to make sure we don't read past the end */
if(file->loc + to_read > file->size)
Expand All @@ -966,72 +920,53 @@ int dfs_read(void * const buf, int size, int count, uint32_t handle)
return 0;

/* Fast-path. If possibly, we want to DMA directly into the destination
* buffer, without using any intermediate buffers. The rules are convoluted
* because we try to squeeze maximum performance here and thus we rely also
* on undocumented behaviors of PI DMA.
* The rules we follow are:
*
* * The RDRAM destination pointer must be 8-bytes aligned.
* * The ROM location must be 2-bytes aligned.
* * The length must be either less than 0x7F (all values accepted),
* or even.
* buffer, without using any intermediate buffers. We can do that only if
* the buffer and the ROM location have the same 2-byte phase.
*/
bool rom_aligned = (file->loc & 1) == 0;
bool ram_aligned = ((uint32_t)buf & 7) == 0;
bool len_aligned = (to_read < 0x7F) || ((to_read & 1) == 0);
if (rom_aligned && ram_aligned && len_aligned)
if (LIKELY(!(((uint32_t)buf ^ (uint32_t)file->loc) & 1)))
{
/* 16-byte alignment: we can simply invalidate the buffer.
* 8-byte alignment: we need to also writeback in case the partial
* cachelines have hot data to write back. */
/* 16-byte alignment: we can simply invalidate the buffer. */
if ((((uint32_t)buf | to_read) & 15) == 0)
data_cache_hit_invalidate(buf, to_read);
else
data_cache_hit_writeback_invalidate(buf, to_read);

dma_read((void *)(((uint32_t)buf) & 0x1FFFFFFF),
file->cart_start_loc + file->loc, to_read);
dma_read(buf, file->cart_start_loc + file->loc, to_read);

file->loc += to_read;
return to_read;
}

/* Something we can actually increment! */
/* It was not possible to perform a direct DMA read into the destination
* buffer. Use an intermediate buffer on the stack to perform the read. */
uint8_t *data = buf;
const int CACHED_SIZE = sizeof(file->cached_data);

/* Loop in, reading data in the cached buffer */
while(to_read)
{
/* Check if we need to read into the cached buffer */
if (file->loc < file->cached_loc || file->loc >= file->cached_loc+CACHED_SIZE)
{
/* We need to read from a 8-byte aligned location, so calculate it */
file->cached_loc = file->loc & ~7;
const int CHUNK_SIZE = 512;

/* Invalidate the cached data. No need to writeback here because
CACHE_SIZE is a multiple of 16 bytes and the data is aligned,
so the cachelines are not shared with other variables. */
data_cache_hit_invalidate(file->cached_data, CACHED_SIZE);
/* Allocate the buffer, aligned to 16 bytes */
uint8_t chunk_base[CHUNK_SIZE+16] __attribute__((aligned(16)));
data_cache_hit_invalidate(chunk_base, CHUNK_SIZE+16);

dma_read((void *)(((uint32_t)file->cached_data) & 0x1FFFFFFF),
file->cart_start_loc + file->cached_loc, CACHED_SIZE);
}
/* Get a pointer to it with the same 2-byte phase of the file current location.
* This guarantees that we can actually DMA into it directly. */
uint8_t *chunk = UncachedAddr(chunk_base);
if (file->loc & 1)
chunk++;

/* Pull as much data as we can from the current buffer */
int copy = file->cached_loc+CACHED_SIZE - file->loc;
if (copy > to_read)
copy = to_read;
while(to_read)
{
int n = MIN(to_read, CHUNK_SIZE);

memcpy(data, file->cached_data + (file->loc - file->cached_loc), copy);
/* Read the data from ROM into the stack buffer, and then and
* copy it to the destination buffer. */
dma_read(chunk, file->cart_start_loc + file->loc, n);
memcpy(data, chunk, n);

file->loc += copy;
data += copy;
to_read -= copy;
did_read += copy;
file->loc += n;
data += n;
to_read -= n;
}

return did_read;
return (void*)data - buf;
}

/**
Expand All @@ -1044,7 +979,7 @@ int dfs_read(void * const buf, int size, int count, uint32_t handle)
*/
int dfs_size(uint32_t handle)
{
open_file_t *file = find_open_file(handle);
dfs_open_file_t *file = HANDLE_TO_OPENFILE(handle);

if(!file)
{
Expand Down Expand Up @@ -1103,7 +1038,7 @@ uint32_t dfs_rom_addr(const char *path)
*/
int dfs_eof(uint32_t handle)
{
open_file_t *file = find_open_file(handle);
dfs_open_file_t *file = HANDLE_TO_OPENFILE(handle);

if(!file)
{
Expand Down

0 comments on commit 6963df1

Please sign in to comment.