CD-i: Buffer overflow fix + Initial default NvRAM (#1106)

* CD-i: Fixed buffer overflow

Fixed reintroduction of the buffer overflow by
commit 1addb89ff

Originally was fixed with c0171c9 but not yet
well understood.

* CD-i: Mount root folder NvRAM after core load

Instead of starting with an empty NvRAM,
"saves/CD-i/CD-i.sav" will be loaded instead.

Avoids machine reset by NvRAM change in case
a root folder CD image shall be used
This commit is contained in:
Andre Zeps
2026-02-26 06:16:21 +01:00
committed by GitHub
parent 7b570422ff
commit d0cf945ae2
4 changed files with 43 additions and 27 deletions

View File

@@ -3,6 +3,7 @@
#include <stdlib.h>
#include <string.h>
#include <array>
#include <assert.h>
#include <inttypes.h>
#include <memory>
@@ -40,7 +41,7 @@ struct subcode
uint16_t mode1_crc0;
uint16_t mode1_crc1;
};
static_assert(sizeof(struct subcode) == 24);
static_assert(sizeof(struct subcode) == CDI_SUBCHANNEL_LEN);
struct toc_entry
{
@@ -51,8 +52,6 @@ struct toc_entry
uint8_t f;
};
#define CD_SECTOR_LEN 2352
#define CDIC_BUFFER_SIZE (CD_SECTOR_LEN + sizeof(subcode))
static std::array<struct toc_entry, 200> toc_buffer;
uint32_t toc_entry_count = 0;
static enum DiscType disc_type = DT_CDDA;
@@ -233,7 +232,7 @@ static int load_cue(const char *filename, toc_t *table)
bool modecdi{strstr(lptr, "CDI/2352") != nullptr};
bool audio{strstr(lptr, "AUDIO") != nullptr};
table->tracks[table->last].sector_size = CD_SECTOR_LEN;
table->tracks[table->last].sector_size = CDI_SECTOR_LEN;
if (!table->last)
table->end = 150; // implicit 2 seconds pregap for track 1
@@ -315,7 +314,7 @@ static int load_cd_image(const char *filename, toc_t *table)
// The real source and how this is calculated is yet unknown
// We use sector 00:02:16 as reference as it contains the boot block.
// If this is a suitable MODE2 header, we assume it is a CD-i disc
auto buffer = std::make_unique<uint8_t[]>(CDIC_BUFFER_SIZE);
auto buffer = std::make_unique<uint8_t[]>(CDI_CDIC_BUFFER_SIZE);
if (buffer)
{
cdi_read_cd(buffer.get(), 166, 1);
@@ -631,7 +630,7 @@ const uint8_t s_sector_scramble[] =
void descramble_sector(uint8_t *buffer)
{
for (uint32_t i = 12; i < CD_SECTOR_LEN; i++)
for (uint32_t i = 12; i < CDI_SECTOR_LEN; i++)
{
buffer[i] ^= s_sector_scramble[i - 12];
}
@@ -790,11 +789,15 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt)
{
if (lba < 0 || !toc.last)
{
memset(buffer, 0, CD_SECTOR_LEN);
// Probably TOC area
memset(buffer, 0, CDI_SECTOR_LEN);
buffer += CDI_SECTOR_LEN;
subcode_data(lba, *reinterpret_cast<struct subcode *>(buffer));
buffer += sizeof(struct subcode);
}
else
{
memset(buffer, 0xAA, CD_SECTOR_LEN);
memset(buffer, 0xAA, CDI_SECTOR_LEN);
for (int i = 0; i < toc.last; i++)
{
@@ -804,11 +807,11 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt)
{
if (toc.tracks[i].offset)
{
FileSeek(&toc.tracks[0].f, toc.tracks[i].offset + ((lba - toc.tracks[i].start + toc.tracks[i].pregap) * CD_SECTOR_LEN), SEEK_SET);
FileSeek(&toc.tracks[0].f, toc.tracks[i].offset + ((lba - toc.tracks[i].start + toc.tracks[i].pregap) * CDI_SECTOR_LEN), SEEK_SET);
}
else
{
FileSeek(&toc.tracks[i].f, (lba - toc.tracks[i].start + toc.tracks[i].pregap) * CD_SECTOR_LEN, SEEK_SET);
FileSeek(&toc.tracks[i].f, (lba - toc.tracks[i].start + toc.tracks[i].pregap) * CDI_SECTOR_LEN, SEEK_SET);
}
}
@@ -818,11 +821,11 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt)
{
// The "fake" 150 sector pregap moves all the LBAs up by 150, so adjust here to read where the core actually wants data from
int read_lba = lba - 150;
if (mister_chd_read_sector(toc.chd_f, (read_lba + toc.tracks[i].offset), 0, 0, CD_SECTOR_LEN, buffer, chd_hunkbuf, &chd_hunknum) == CHDERR_NONE)
if (mister_chd_read_sector(toc.chd_f, (read_lba + toc.tracks[i].offset), 0, 0, CDI_SECTOR_LEN, buffer, chd_hunkbuf, &chd_hunknum) == CHDERR_NONE)
{
if (!toc.tracks[i].type) // CHD requires byteswap of audio data
{
for (int swapidx = 0; swapidx < CD_SECTOR_LEN; swapidx += 2)
for (int swapidx = 0; swapidx < CDI_SECTOR_LEN; swapidx += 2)
{
uint8_t temp = buffer[swapidx];
buffer[swapidx] = buffer[swapidx + 1];
@@ -838,15 +841,15 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt)
else
{
if (toc.tracks[i].offset)
FileReadAdv(&toc.tracks[0].f, buffer, CD_SECTOR_LEN);
FileReadAdv(&toc.tracks[0].f, buffer, CDI_SECTOR_LEN);
else
FileReadAdv(&toc.tracks[i].f, buffer, CD_SECTOR_LEN);
FileReadAdv(&toc.tracks[i].f, buffer, CDI_SECTOR_LEN);
}
if ((lba + 1) > toc.tracks[i].end)
break;
check_scramble(lba, buffer);
buffer += CD_SECTOR_LEN;
buffer += CDI_SECTOR_LEN;
subcode_data(lba, *reinterpret_cast<struct subcode *>(buffer));
buffer += sizeof(struct subcode);
cnt--;
@@ -857,8 +860,7 @@ void cdi_read_cd(uint8_t *buffer, int lba, int cnt)
}
}
buffer += CD_SECTOR_LEN;
subcode_data(lba, *reinterpret_cast<struct subcode *>(buffer));
buffer += CDI_SECTOR_LEN;
buffer += sizeof(struct subcode);
cnt--;
lba++;
@@ -875,14 +877,14 @@ static void mount_cd(int size, int index)
user_io_bufferinvalidate(0);
}
/// Last used directory for save file management
/// Must be static to keep the value between mount calls
static char last_dir[1024] = "";
void cdi_mount_cd(int s_index, const char *filename)
{
int loaded = 0;
/// Last used directory for save file management
/// Must be static to keep the value between mount calls
static char last_dir[1024] = {};
if (strlen(filename))
{
if (load_cd_image(filename, &toc) && toc.last)
@@ -911,7 +913,7 @@ void cdi_mount_cd(int s_index, const char *filename)
prepare_toc_buffer(&toc);
user_io_set_index(0);
mount_cd(toc.end * CD_SECTOR_LEN, s_index);
mount_cd(toc.end * CDI_SECTOR_LEN, s_index);
loaded = 1;
}
}
@@ -928,3 +930,9 @@ void cdi_mount_cd(int s_index, const char *filename)
void cdi_poll()
{
}
void cdi_load_root_nvram()
{
strcpy(last_dir, "games/CD-i");
cdi_mount_save(last_dir);
}

View File

@@ -1,11 +1,16 @@
#ifndef CDI_H
#define CDI_H
#define CDI_SECTOR_LEN 2352
#define CDI_SUBCHANNEL_LEN 24
#define CDI_CDIC_BUFFER_SIZE (CDI_SECTOR_LEN + CDI_SUBCHANNEL_LEN)
void cdi_mount_cd(int s_index, const char *filename);
void cdi_fill_blanksave(uint8_t *buffer, uint32_t lba, int cnt);
void cdi_read_cd(uint8_t *buffer, int lba, int cnt);
int cdi_chd_hunksize();
const char* cdi_get_game_id();
void cdi_poll();
void cdi_load_root_nvram();
#endif

View File

@@ -1552,6 +1552,7 @@ void user_io_init(const char *path, const char *xml)
const char *home = HomeDir();
if (is_uneon()) x86_ide_set();
if (is_cdi()) cdi_load_root_nvram();
if (!strlen(path) || !user_io_file_tx(path, 0, 0, 0, 1))
{
@@ -3107,7 +3108,7 @@ void user_io_poll()
int disk = -1;
int ack = 0;
int op = 0;
static uint8_t buffer[16][16384];
static uint8_t buffer[16][UIO_BUFFER_SIZE];
uint64_t lba = 0;
uint32_t blksz, blks, sz;
@@ -3130,7 +3131,7 @@ void user_io_poll()
if (disk == 1 && is_psx())
blksz = 2352;
else if (disk == 0 && is_cdi())
blksz = (2352 + 24);
blksz = CDI_CDIC_BUFFER_SIZE;
else
blksz = 128 << ((c >> 6) & 7);
@@ -3265,11 +3266,11 @@ void user_io_poll()
unsigned int psx_blksz = psx_chd_hunksize();
if (psx_blksz && psx_blksz <= sizeof(buffer[0])) buf_n = psx_blksz / blksz;
}
else if (is_cdi() && blksz == (2352 + 24))
else if (is_cdi() && blksz == CDI_CDIC_BUFFER_SIZE)
{
//returns 0 if the mounted disk is not a chd, otherwise returns the chd hunksize in bytes
unsigned int psx_blksz = cdi_chd_hunksize();
if (psx_blksz && psx_blksz <= sizeof(buffer[0])) buf_n = psx_blksz / blksz;
unsigned int cdi_blksz = cdi_chd_hunksize();
if (cdi_blksz && cdi_blksz <= sizeof(buffer[0])) buf_n = cdi_blksz / blksz;
}
//printf("SD RD (%llu,%d) on %d, WIDE=%d\n", lba, blksz, disk, fio_size);

View File

@@ -163,6 +163,8 @@
#define EMU_JOY0 2
#define EMU_JOY1 3
#define UIO_BUFFER_SIZE 16384
void user_io_init(const char *path, const char *xml);
unsigned char user_io_core_type();
void user_io_read_core_name();