fygue: rework flash abstraction + support FAT12 (untested) + support G35PE2 device + support Math+ device (untested)

This commit is contained in:
Yann MAGNIN 2025-04-08 11:21:04 +02:00
parent fc358c2fb1
commit f1bf037a18
No known key found for this signature in database
GPG key ID: D82629D933EADC59
7 changed files with 323 additions and 118 deletions

View file

@ -4,6 +4,88 @@
#include "fat.h"
#include "../flash/flash.h"
//---
// Internals
//---
/* _fygue_fat16_cluster_get_next(): FAT16 cluster handling */
static int _fygue_fat16_cluster_get_next(
struct fygue_fat *fat,
int *cluster
) {
uint16_t *fat0;
int nb_entry_per_sector;
int cluster_sector;
int cluster_real;
int rc;
nb_entry_per_sector = fat->SectorSize / 2;
cluster_sector = *cluster / nb_entry_per_sector;
cluster_real = *cluster - (cluster_sector * nb_entry_per_sector);
rc = fygue_fat_sector_get_addr(
fat,
(void*)&fat0,
fat->FAT0SectorID + cluster_sector
);
if (rc < 0)
return -1;
*cluster = FAT_WORD(fat0[cluster_real]);
return 0;
}
/* _fygue_fat12_cluster_get_next(): FAT12 cluster handling */
// TODO: assume fixed sector size to 512
// TODO: better calculus
static int _fygue_fat12_cluster_get_next(
struct fygue_fat *fat,
int *cluster
) {
int fat_index0;
int fat_index1;
int fat_offset0;
int fat_offset1;
int fat_sector0;
int fat_sector1;
uintptr_t fat_data0;
uintptr_t fat_data1;
fat_index0 = *cluster + (*cluster / 2);
fat_index1 = fat_index0 + 1;
fat_sector0 = fat->FAT0SectorID + (fat_index0 / fat->SectorSize);
fat_sector1 = fat->FAT0SectorID + (fat_index1 / fat->SectorSize);
if (fat_sector0 == fat_sector1) {
if (fygue_fat_sector_get_addr(fat, &fat_data0, fat_sector0) != 0)
return -1;
fat_data1 = fat_data0;
fat_offset0 = fat_index0 - (fat_sector0 * fat->SectorSize);
fat_offset1 = fat_offset0 + 1;
} else {
if (fygue_fat_sector_get_addr(fat, &fat_data0, fat_sector0) != 0)
return -1;
if (fygue_fat_sector_get_addr(fat, &fat_data1, fat_sector1) != 0)
return -1;
fat_offset0 = fat_index0 - (fat_sector0 * fat->SectorSize);
fat_offset1 = fat_index1 - (fat_sector1 * fat->SectorSize);
}
if (*cluster & 1) {
*cluster = (
((((uint8_t*)fat_data0)[fat_offset0] & 0xf0) >> 4) |
((((uint8_t*)fat_data1)[fat_offset1] & 0xff) << 4)
);
} else {
*cluster = (
((((uint8_t*)fat_data0)[fat_offset0] & 0xff) >> 0) |
((((uint8_t*)fat_data1)[fat_offset1] & 0xf0) << 8)
);
}
if (*cluster == 0x0fff)
*cluster = 0xffff;
return -1;
}
//---
// Public
//---
@ -24,10 +106,6 @@
* - ensure FAT1 information is the same ? */
int fygue_fat_cluster_get_next(struct fygue_fat *fat, int *cluster_current)
{
uint16_t *fat0;
int nb_entry_per_sector;
int cluster_sector;
int cluster_real;
int cluster;
int rc;
@ -42,18 +120,12 @@ int fygue_fat_cluster_get_next(struct fygue_fat *fat, int *cluster_current)
return -2;
if (cluster >= fat->ClusterCount)
return -2;
nb_entry_per_sector = fat->SectorSize / 2;
cluster_sector = cluster / nb_entry_per_sector;
cluster_real = cluster - (cluster_sector * nb_entry_per_sector);
rc = fygue_fat_sector_get_addr(
fat,
(void*)&fat0,
fat->FAT0SectorID + cluster_sector
);
if (rc < 0)
if (fat->Type == FYGUE_FAT_TYPE_FAT12)
rc = _fygue_fat12_cluster_get_next(fat, &cluster);
if (fat->Type == FYGUE_FAT_TYPE_FAT16)
rc = _fygue_fat16_cluster_get_next(fat, &cluster);
if (rc != 0)
return -5;
rc = 0;
cluster = FAT_WORD(fat0[cluster_real]);
if (cluster == 0xffff)
rc = -6;
if (cluster == 0x0000)

View file

@ -100,7 +100,6 @@ static int _fygue_fat_configure(struct fygue_fat *fat)
struct _fat_bpb *bpb;
int RootDirSectors;
int DataSec;
int CountofClusters;
bpb = (void *)fat->BPB;
@ -111,13 +110,13 @@ static int _fygue_fat_configure(struct fygue_fat *fat)
DataSec += FAT_WORD(bpb->BPB_FATSz16) * bpb->BPB_NumFATs;
DataSec += RootDirSectors;
DataSec = FAT_WORD(bpb->BPB_TotSec16) - DataSec;
CountofClusters = DataSec / bpb->BPB_SecPerClus;
if (CountofClusters < 4085) {
fat->ClusterCount = DataSec / bpb->BPB_SecPerClus;
if (fat->ClusterCount < 4085) {
fat->Type = FYGUE_FAT_TYPE_FAT12;
} else if (CountofClusters < 65525) {
} else if (fat->ClusterCount < 65525) {
fat->Type = FYGUE_FAT_TYPE_FAT16;
} else {
// TODO: maybe gint panic ?
// TODO: (FAT32) maybe gint panic ?
return -2;
}
@ -126,11 +125,6 @@ static int _fygue_fat_configure(struct fygue_fat *fat)
fat->SectorSize = FAT_WORD(bpb->BPB_BytsPerSec);
fat->SectorPerClus = bpb->BPB_SecPerClus;
// todo : FAT12-specific operation
fat->ClusterCount = FAT_WORD(bpb->BPB_FATSz16);
fat->ClusterCount *= FAT_WORD(bpb->BPB_BytsPerSec);
fat->ClusterCount /= 2;
fat->FAT0SectorID = fat->SectorHiddenCount;
fat->FAT0SectorID += FAT_WORD(bpb->BPB_RsvdSecCnt);
fat->FAT1SectorID = fat->FAT0SectorID;
@ -167,13 +161,12 @@ int fygue_fat_init_cold(struct fygue_fat *fat)
memset(fat, 0x00, sizeof(struct fygue_fat));
if (fygue_flash_initialize(&(fat->_flash)) != 0)
return -2;
if (
_fygue_fat_sector0(fat) != 0 ||
_fygue_fat_configure(fat) != 0 ||
_fygue_fat_prepare(fat) != 0
) {
if (_fygue_fat_sector0(fat) != 0)
return -3;
}
if (_fygue_fat_configure(fat) != 0)
return -4;
if (_fygue_fat_prepare(fat) != 0)
return -5;
return 0;
}

View file

@ -4,6 +4,8 @@
#include <string.h>
#include <gint/defs/attributes.h>
#include <gint/defs/util.h>
#include <gint/hardware.h>
#include "flash.h"
@ -23,6 +25,8 @@ struct _bfile_cluster_metadata
uint8_t ecc_bitmask_position[3];
} GPACKED(1);
uintptr_t debug_meta = 0;
/* _fygue_flash_cluster_convert - ensure that the provided meta is valid
*
* notes
@ -66,6 +70,7 @@ static int _fygue_flash_cluster_convert(
if (fcluster == NULL)
return -1;
debug_meta = bfile_meta;
meta = (void*)(bfile_meta | 0xa0000000);
if (
meta->signature[0] != 0x5a ||
@ -102,10 +107,172 @@ static int _fygue_flash_cluster_convert(
return 0;
}
/* _fygue_flash_cluster_meta(): special metadata cluster handling
*
* notes:
* metadata cluster are the last flash cluster of a flash sector it does
* not have Bfile information. Generate a fake flash cluster with a
* special custom kind to allow quick identification */
static int _fygue_flash_cluster_meta(
struct fygue_flash *flash,
struct fygue_flash_cluster *fcluster,
int fsector_id
) {
GAUTOTYPE geometry = &(flash->geometry);
memset(fcluster, 0x00, sizeof(struct fygue_flash_cluster));
fcluster->kind = FYGUE_FCLUSTER_KIND_METADATA;
fcluster->lcluster_id = 0xffff;
fcluster->fcluster_id = 0xffff;
fcluster->fcluster_id_bfile = 0xffff;
fcluster->version = 0xffffffff;
fcluster->meta_addr = 0xffffffff;
fcluster->data_addr = (
(geometry->phy_start | 0xa0000000) +
((fsector_id + 1) * geometry->fsector_size) -
(8 * 512)
);
return 0;
}
/* _fygue_flash_cluster_details(): special flash sector details handling
*
* notes:
* flash sector details is a particular flash cluster that contains
* critical versioning information needed to rebuild Casio's flash
* mapping.
* However, this particular flash cluster are not represented in the
* same way between machines. For example, the G35EII that use flash
* sector of 64ko merge the details sector inside the metadata cluster to
* keep some space which is not the case with the FXCP400 or CG50 that
* use 128ko flash sector and which the first cluster should be a details
* one type. */
//TODO: remove device-specific code
static int _fygue_flash_cluster_details(
struct fygue_flash *flash,
struct fygue_flash_cluster *fcluster,
int fsector_id
) {
GAUTOTYPE geometry = &(flash->geometry);
volatile uint32_t *data32;
uintptr_t meta;
uintptr_t data;
memset(fcluster, 0x00, sizeof(struct fygue_flash_cluster));
if (gint[HWCALC] == HWCALC_G35PE2) {
data = (
(geometry->phy_start | 0xa0000000) +
(fsector_id * geometry->fsector_size) +
(geometry->fsector_size - (8*512)) +
((geometry->fcluster_per_fsector - 1) * 0x40)
);
meta = data + 512;
} else {
data = (
(geometry->phy_start | 0xa0000000) +
(fsector_id * geometry->fsector_size)
);
meta = data + (geometry->fsector_size) - (8*512);
}
if (_fygue_flash_cluster_convert(flash, fcluster, meta) != 0)
return -1;
if (fcluster->version != 0xffffffff)
return -2;
data32 = (void*)data;
if (
((data32[0] ^ data32[1]) != 0xffffffff) ||
((data32[2] ^ data32[3]) != 0xffffffff) ||
((data32[4] ^ data32[5]) != 0xffffffff)
) {
return -1;
}
fcluster->data_addr = data;
fcluster->meta_addr = meta;
fcluster->version = data32[0];
return 0;
}
/* _fygue_flash_cluster_data(): handle generic data flash cluster
*
* notes
* flash cluster data (0x11 or 0x88) are handled in the same way between
* all device */
static int _fygue_flash_cluster_data(
struct fygue_flash *flash,
struct fygue_flash_cluster *fcluster,
int fcluster_id,
int fsector_id,
int fcluster_off
) {
GAUTOTYPE geometry = &(flash->geometry);
uintptr_t meta;
uintptr_t data;
data = (
(geometry->phy_start | 0xa0000000) +
(fsector_id * geometry->fsector_size) +
(fcluster_off * (8 * 512))
);
meta = (
(geometry->phy_start | 0xa0000000) +
(fsector_id * geometry->fsector_size) +
(geometry->fsector_size - (8 * 512)) +
(fcluster_off * 0x40)
);
int rc = _fygue_flash_cluster_convert(flash, fcluster, meta);
if (rc != 0)
return rc;
fcluster->data_addr = data;
fcluster->meta_addr = meta;
fcluster->fcluster_id = fcluster_id;
fcluster->fcluster_id_bfile = (
(fsector_id * (geometry->fcluster_per_fsector - 1)) +
(fcluster_off)
);
return 0;
}
//---
// Public
//---
/* fygue_flash_cluster_get() - get flash cluster information
*
* return
* -1 if the provided `fline` is not valid
* -2 if the provided `fline` have invalid Bfile metadata
* 0 if the meta information has been generated */
int fygue_flash_cluster_get(
struct fygue_flash *flash,
struct fygue_flash_cluster *fcluster,
int fcluster_id
) {
int fsector_id;
int fcluster_off;
int nb_entry;
if (flash == NULL || fcluster == NULL)
return -1;
if (fcluster_id >= flash->geometry.fcluster_count)
return -1;
nb_entry = flash->geometry.fcluster_per_fsector;
fsector_id = fcluster_id / nb_entry;
fcluster_off = fcluster_id % nb_entry;
if (fcluster_off == (nb_entry - 1))
return _fygue_flash_cluster_meta(flash, fcluster, fsector_id);
if (fcluster_off == 0)
return _fygue_flash_cluster_details(flash, fcluster, fsector_id);
return _fygue_flash_cluster_data(
flash,
fcluster,
fcluster_id,
fsector_id,
fcluster_off
);
}
/* fygue_flash_cluster_geometry() - get geometry information
*
* notes
@ -123,72 +290,19 @@ int fygue_flash_cluster_geometry(
uint16_t *fsector_id,
uint16_t *fcluster_off
) {
int nb_cluster;
if ((addr & 0x0fffffff) < flash->geometry.phy_start)
return -1;
nb_cluster = flash->geometry.fcluster_per_fsector;
addr = (addr & 0x0fffffff) - flash->geometry.phy_start;
if (fcluster_id != NULL) {
*fcluster_id = ((addr & 0xfffe0000) >> 17) * 32;
*fcluster_id = ((addr & 0xfffe0000) >> 17) * nb_cluster;
*fcluster_id += ((addr & 0x0001ffff) >> 12);
}
if (fsector_id != NULL)
*fsector_id = ((addr & 0xfffe0000) >> 17) * 32;
*fsector_id = ((addr & 0xfffe0000) >> 17) * nb_cluster;
if (fcluster_off != NULL)
*fcluster_off = ((addr & 0x0001ffff) >> 12);
return 0;
}
/* fygue_flash_cluster_get() - get flash cluster information
*
* return
* -1 if the provided `fline` is not valid
* -2 if the provided `fline` have invalid Bfile metadata
* 0 if the meta information has been generated */
int fygue_flash_cluster_get(
struct fygue_flash *flash,
uint16_t fcluster_id,
struct fygue_flash_cluster *fcluster
) {
uintptr_t bfile_meta;
uintptr_t bfile_data;
int fsector_id;
int fcluster_off;
if (flash == NULL || fcluster == NULL)
return -1;
if (fcluster_id >= flash->geometry.fcluster_count)
return -1;
fsector_id = fcluster_id / 32;
fcluster_off = fcluster_id % 32;
if (fcluster_off == 31)
{
fcluster->kind = 0x667;
fcluster->lcluster_id = 0xffff;
fcluster->version = 0xffffffff;
} else {
bfile_meta = flash->geometry.phy_start;
bfile_meta += (fsector_id * 0x20000) + 0x1f000;
bfile_meta += (fcluster_off * 0x40);
if (_fygue_flash_cluster_convert(flash, fcluster, bfile_meta) != 0)
return -2;
}
bfile_data = flash->geometry.phy_start;
bfile_data += (fsector_id * 0x20000);
bfile_data += (fcluster_off * 0x1000);
fcluster->data_p1 = bfile_data | 0xa0000000;
fcluster->data_p2 = bfile_data | 0xa0000000;
fcluster->fcluster_id_bfile = (fsector_id * 31) + fcluster_off;
fcluster->fcluster_id = fcluster_id;
if (fcluster->kind == 0x22)
{
uint32_t *data = (void*)fcluster->data_p1;
if (
((data[0] ^ data[1]) != 0xffffffff) ||
((data[2] ^ data[3]) != 0xffffffff) ||
((data[4] ^ data[5]) != 0xffffffff)
) {
return -2;
}
fcluster->version = data[0];
}
return 0;
}

View file

@ -61,8 +61,7 @@ static int fygue_flash_cmap_update(
) {
cmap->lcluster[i].fcluster_id = 0xffff;
cmap->lcluster[i].fcluster_id_bfile = 0xffff;
cmap->lcluster[i].fcluster_data_p1 = 0xffffffff;
cmap->lcluster[i].fcluster_data_p2 = 0xffffffff;
cmap->lcluster[i].fcluster_addr = 0xffffffff;
cmap->lcluster[i].version = 0xffffffff;
}
cmap->lcluster_id_max = fcluster->lcluster_id + 1;
@ -70,8 +69,7 @@ static int fygue_flash_cmap_update(
entry = &(cmap->lcluster[fcluster->lcluster_id]);
entry->fcluster_id = fcluster->fcluster_id;
entry->fcluster_id_bfile = fcluster->fcluster_id_bfile;
entry->fcluster_data_p1 = fcluster->data_p1;
entry->fcluster_data_p2 = fcluster->data_p2;
entry->fcluster_addr = fcluster->data_addr;
entry->version = fcluster->version;
return 0;
}
@ -80,6 +78,8 @@ static int fygue_flash_cmap_update(
// Public
//---
int debug_count = 0;
/* fygue_flash_cmap_init() - initialize fcluster translation
*
* notes:
@ -102,28 +102,30 @@ int fygue_flash_cmap_init(
struct fygue_flash_cmap *cmap
) {
struct fygue_flash_cluster fcluster;
int fsector_id;
int fsector;
int rc;
int j;
if (flash == NULL || cmap == NULL)
return -1;
fsector_id = 0;
memset(cmap, 0x00, sizeof(struct fygue_flash_cmap));
for (
fsector = 0 ;
fsector < flash->geometry.fsector_count ;
fsector++
) {
if (fygue_flash_cluster_get(flash, fsector * 32, &fcluster) != 0)
if (fsector != 0)
fsector_id += flash->geometry.fcluster_per_fsector;
if (fygue_flash_cluster_get(flash, &fcluster, fsector_id) != 0)
continue;
if (fcluster.kind != 0x22)
continue;
for (int j = 0 ; j < 31 ; j++)
debug_count += 1;
for (j = 1 ; j < (flash->geometry.fcluster_per_fsector - 1) ; j++)
{
rc = fygue_flash_cluster_get(
flash,
(fsector * 32) + j,
&fcluster
);
rc = fygue_flash_cluster_get(flash, &fcluster, fsector_id + j);
if (rc != 0)
continue;
if (fcluster.kind != 0x11)
@ -159,7 +161,7 @@ int fygue_flash_cmap_lsector_get_addr(
) {
return -2;
}
fsector_addr = cmap->lcluster[lcluster_id].fcluster_data_p1;
fsector_addr = cmap->lcluster[lcluster_id].fcluster_addr;
fsector_addr += (lsector_id % 8) * 512;
*sector = fsector_addr;
return 0;

View file

@ -15,33 +15,50 @@
* hardcoded information */
// TODO: support CRC check and try each flash sector until one work ?
// TODO: cluster integrity check seems change between device (?)
static int _fygue_flash_hw_detect(struct fygue_flash *flash)
int _fygue_flash_hw_detect(struct fygue_flash *flash)
{
switch (gint[HWCALC])
{
case HWCALC_FXCP400:
flash->geometry.phy_start = 0x01a20000;
flash->geometry.fsector_count = 0xf2;
flash->geometry.fcluster_per_fsector = 32;
flash->integrity = FYGUE_FLASH_INTEGRITY_PARTIAL;
break;
case HWCALC_G35PE2:
flash->geometry.phy_start = 0x003f0000;
flash->geometry.fsector_count = 0x00;
flash->integrity = FYGUE_FLASH_INTEGRITY_FULL;
flash->geometry.fsector_count = 0x41;
flash->geometry.fcluster_per_fsector = 16;
flash->integrity = FYGUE_FLASH_INTEGRITY_PARTIAL;
break;
case HWCALC_FXCG50:
flash->geometry.phy_start = 0x00c80000;
flash->geometry.fsector_count = 0x9c;
flash->geometry.fcluster_per_fsector = 32;
flash->integrity = FYGUE_FLASH_INTEGRITY_FULL;
break;
case HWCALC_FXCG100:
flash->geometry.phy_start = 0x00bc0000;
flash->geometry.fsector_count = 0x26;
flash->geometry.fcluster_per_fsector = 32;
flash->integrity = FYGUE_FLASH_INTEGRITY_PARTIAL;
break;
default:
errno = ENOTSUP;
return -1;
}
flash->geometry.fcluster_count = flash->geometry.fsector_count * 32;
flash->geometry.size = flash->geometry.fsector_count * 0x20000;
flash->geometry.phy_end = flash->geometry.phy_start;
flash->geometry.phy_end += flash->geometry.size;
flash->geometry.fcluster_count = (
flash->geometry.fsector_count * flash->geometry.fcluster_per_fsector
);
flash->geometry.fsector_size = (
flash->geometry.fcluster_per_fsector * (8 * 512)
);
flash->geometry.size = (
flash->geometry.fsector_count * flash->geometry.fsector_size
);
flash->geometry.phy_end = (
flash->geometry.phy_start + flash->geometry.size
);
return 0;
}
@ -57,7 +74,8 @@ int fygue_flash_initialize(struct fygue_flash *flash)
memset(flash, 0x00, sizeof(struct fygue_flash));
if (_fygue_flash_hw_detect(flash) != 0)
return -2;
if (fygue_flash_cmap_init(flash, &(flash->cmap)) != 0)
return -3;
int rc = fygue_flash_cmap_init(flash, &(flash->cmap));
if (rc != 0)
return rc;
return 0;
}

View file

@ -7,13 +7,18 @@
/* fygue_fcluster - generic flash cluster information */
struct fygue_flash_cluster
{
uint32_t kind;
enum {
FYGUE_FCLUSTER_KIND_DATA = 0x11,
FYGUE_FCLUSTER_KIND_FINFO = 0x22,
FYGUE_FCLUSTER_KIND_DETAILS = 0x88,
FYGUE_FCLUSTER_KIND_METADATA = 0x667,
} kind;
uint16_t fcluster_id;
uint16_t fcluster_id_bfile;
uint16_t lcluster_id;
uint32_t version;
uintptr_t data_p1;
uintptr_t data_p2;
uintptr_t data_addr;
uintptr_t meta_addr;
};
/* fygue_fcluster_map_entry - cmap list entry */
@ -21,8 +26,7 @@ struct fygue_flash_cmap_entry
{
uint16_t fcluster_id;
uint16_t fcluster_id_bfile;
uintptr_t fcluster_data_p1;
uintptr_t fcluster_data_p2;
uintptr_t fcluster_addr;
uint32_t version;
};
@ -33,6 +37,7 @@ struct fygue_flash_cmap
int lcluster_id_max;
};
/* fygue_flash - flash information */
struct fygue_flash
{
struct {
@ -40,6 +45,8 @@ struct fygue_flash
uintptr_t phy_end;
size_t size;
int fsector_count;
size_t fsector_size;
int fcluster_per_fsector;
int fcluster_count;
} geometry;
enum {
@ -97,8 +104,8 @@ extern int fygue_flash_cluster_geometry(
/* fygue_flash_cluster_get() - get cluster information */
extern int fygue_flash_cluster_get(
struct fygue_flash *flash,
uint16_t fcluster_id,
struct fygue_flash_cluster *fcluster
struct fygue_flash_cluster *fcluster,
int fcluster_id
);
#endif /* FS_FYGUE_FLASH_H */

View file

@ -13,7 +13,6 @@ static struct fygue_fsinfo *__fygue_fsinfo = NULL;
// Primitives
//---
/* fygue_mount() - mount (if needed) and return the filesystem information
*
* notes