fs: buffer Fugue writes through RAM

Writing from ROM causes occasional crashes, which are fairly hard to
produce when the buffers are small.
This commit is contained in:
Lephe 2022-01-10 14:45:01 +01:00
parent d6ada7f11f
commit 227c06631b
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
3 changed files with 88 additions and 6 deletions

View file

@ -10,6 +10,7 @@ extern "C" {
#endif
#include <gint/mpu/mmu.h>
#include <stdbool.h>
//---
// Unified interface
@ -40,6 +41,17 @@ void *mmu_uram(void);
fx-9860G, and 512k on fx-CG 50. */
uint32_t mmu_uram_size(void);
/* mmu_is_rom(): Determine if an address points to ROM
Checks whether the supplied pointer points to ROM or to a virtualized
portion of ROM. For the sake of efficiency, this function uses heuristics
about the structure of P0 rather than actually checking the TLB.
This is useful during filesystem accesses because only data outside of ROM
can be written to files. Pointers for which this function returns true
cannot be used as a source for BFile_Write(). */
bool mmu_is_rom(void const *ptr);
//---
// SH7705 TLB
//---

View file

@ -1,7 +1,9 @@
#include <gint/fs.h>
#include <gint/hardware.h>
#include <gint/bfile.h>
#include <gint/mmu.h>
#include <gint/defs/util.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include "fugue.h"
@ -26,18 +28,71 @@ ssize_t fugue_read(void *data0, void *buf, size_t size)
return size;
}
static void *temp_ram(size_t total_size, size_t *block_size)
{
for(size_t candidate = 16384; candidate >= 64; candidate >>= 1) {
if(candidate > 64 && candidate >= 2 * total_size)
continue;
size_t size = min(candidate, total_size);
void *ram = malloc(size);
if(ram) {
*block_size = size;
return ram;
}
}
return NULL;
}
ssize_t fugue_write(void *data0, const void *buf, size_t size)
{
fugue_fd_t *data = data0;
int fugue_fd = data->fd;
int rc = BFile_Write(fugue_fd, buf, size);
if(rc < 0) {
errno = bfile_error_to_errno(rc);
return -1;
/* The main concern of this function is that we cannot write from ROM.
If [buf] is in ROM then we have to copy it to RAM, preferably within
the limits of available heap memory. */
if(mmu_is_rom(buf)) {
size_t alloc_size, written=0;
void *ram = temp_ram(size, &alloc_size);
if(!ram) {
errno = ENOMEM;
return -1;
}
while(written < size) {
size_t block_size = min(size - written, alloc_size);
memcpy(ram, buf + written, block_size);
int rc = BFile_Write(fugue_fd, ram, block_size);
if(rc < 0) {
errno = bfile_error_to_errno(rc);
written = -1;
break;
}
written += rc;
data->pos += rc;
/* Partial write */
if(rc < (int)block_size) break;
}
free(ram);
return written;
}
/* Otherwise, we can write normally */
else {
int rc = BFile_Write(fugue_fd, buf, size);
if(rc < 0) {
errno = bfile_error_to_errno(rc);
return -1;
}
data->pos += rc;
return rc;
}
data->pos += rc;
return rc;
}
off_t fugue_lseek(void *data0, off_t offset, int whence)

View file

@ -38,6 +38,21 @@ uint32_t mmu_uram_size(void)
return size;
}
/* mmu_is_rom(): Determine if an address points to ROM */
bool mmu_is_rom(void const *ptr)
{
uint32_t a = (uint32_t)ptr;
if(a >= 0x80000000 && a < 0x88000000)
return true;
if(a >= 0xa0000000 && a < 0xa8000000)
return true;
if(a >= 0x00300000 && a < 0x00800000)
return true;
return false;
}
//---
// SH7705 TLB
//---