Skip to content

Commit

Permalink
image: Properly implement empty/unformatted tracks beyond end of imag…
Browse files Browse the repository at this point in the history
…e-file track count.

These tracks read as garbage, and ignore writes.

This fixes a bug where writing beyond an image-file limit would trash the last
cylinder's track data. This was particularly an issue for HFE image files.

Refs #309
  • Loading branch information
keirf committed Jul 15, 2020
1 parent cfd3c51 commit b5e70de
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 63 deletions.
6 changes: 5 additions & 1 deletion inc/floppy.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ struct image_bufs {
};

struct image {
const struct image_handler *handler;
/* Handler for currently-selected type of disk image. */
const struct image_handler *disk_handler;

/* Handler for current track. May differ from the primary disk handler. */
const struct image_handler *track_handler;

/* FatFS. */
FIL fp;
Expand Down
10 changes: 6 additions & 4 deletions src/floppy.c
Original file line number Diff line number Diff line change
Expand Up @@ -450,10 +450,12 @@ static bool_t dma_rd_handle(struct drive *drv)
/* Seek to the new track. */
track = drive_calc_track(drv);
read_start_pos *= SYSCLK_MHZ/STK_MHZ;
if ((track >= (DA_FIRST_CYL*2)) && (drv->outp & m(outp_wrprot))
&& !volume_readonly()) {
/* Remove write-protect when driven into D-A mode. */
drive_change_output(drv, outp_wrprot, FALSE);
if (track >= (DA_FIRST_CYL*2)) {
/* Remove write-protect when driven into D-A mode.
* D-A mode ignores the HEAD signal. */
drv->nr_sides = 1;
if ((drv->outp & m(outp_wrprot)) && !volume_readonly())
drive_change_output(drv, outp_wrprot, FALSE);
}
if (image_setup_track(drv->image, track, &read_start_pos))
return TRUE;
Expand Down
5 changes: 3 additions & 2 deletions src/floppy_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ static void floppy_mount(struct slot *slot)

/* Mount the image file. */
image_open(im, slot, cltbl);
if (!im->handler->write_track || volume_readonly())
if (!im->disk_handler->write_track || volume_readonly())
slot->attributes |= AM_RDO;
if (slot->attributes & AM_RDO) {
printk("Image is R/O\n");
Expand All @@ -223,6 +223,8 @@ static void floppy_mount(struct slot *slot)

} while (f_size(&im->fp) != fastseek_sz);

drv->nr_sides = im->nr_sides;

/* After image is extended at mount time, we permit no further changes
* to the file metadata. Clear the dirent info to ensure this. */
im->fp.dir_ptr = NULL;
Expand Down Expand Up @@ -308,7 +310,6 @@ static void timer_dma_init(void)

static unsigned int drive_calc_track(struct drive *drv)
{
drv->nr_sides = (drv->cyl >= DA_FIRST_CYL) ? 1 : drv->image->nr_sides;
return drv->cyl*2 + (drv->head & (drv->nr_sides - 1));
}

Expand Down
6 changes: 0 additions & 6 deletions src/image/adf.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,6 @@ static void adf_setup_track(
struct image_buf *rd = &im->bufs.read_data;
struct image_buf *bc = &im->bufs.read_bc;
uint32_t decode_off, sector, sys_ticks = start_pos ? *start_pos : 0;
uint8_t cyl = track/2, side = track&1;

/* TODO: Fake out unformatted tracks. */
cyl = min_t(uint8_t, cyl, im->nr_cyls-1);
side = min_t(uint8_t, side, im->nr_sides-1);
track = cyl*2 + side;

im->adf.trk_len = im->adf.nr_secs * 512;
im->adf.trk_off = track * im->adf.trk_len;
Expand Down
54 changes: 23 additions & 31 deletions src/image/dummy.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,59 +12,51 @@
static bool_t dummy_open(struct image *im)
{
/* Check for dummy slot info (zero-sized, invalid start cluster). */
im->nr_sides = 1;
return (im->fp.obj.sclust == ~0u) && (f_size(&im->fp) == 0);
}

static void dummy_setup_track(
struct image *im, uint16_t track, uint32_t *start_pos)
{
struct image_buf *bc = &im->bufs.read_bc;
uint32_t sys_ticks = start_pos ? *start_pos : 0;

im->cur_track = track;

im->ticks_per_cell = im->write_bc_ticks * 16;
im->tracklen_bc = 100000;
im->stk_per_rev = stk_sysclk(im->tracklen_bc * im->write_bc_ticks);

im->cur_bc = (sys_ticks * 16) / im->ticks_per_cell;
im->cur_bc &= ~15;
if (im->cur_bc >= im->tracklen_bc)
im->cur_bc = 0;
im->cur_ticks = im->cur_bc * im->ticks_per_cell;
im->cur_ticks = (start_pos ? *start_pos : 0) * 16;
im->tracklen_ticks = sysclk_stk(im->stk_per_rev) * 16;
im->ticks_since_flux = 0;

bc->prod = bc->cons = 0;
}

static bool_t dummy_read_track(struct image *im)
{
struct image_buf *bc = &im->bufs.read_bc;
uint16_t *bc_b = bc->p;
uint32_t bc_len, bc_mask, bc_space, bc_p, bc_c;
return TRUE;
}

/* Generate some MFM if there is space in the raw-bitcell ring buffer. */
bc_p = bc->prod / 16; /* MFM words */
bc_c = bc->cons / 16; /* MFM words */
bc_len = bc->len / 2; /* MFM words */
bc_mask = bc_len - 1;
bc_space = bc_len - (uint16_t)(bc_p - bc_c);
if (bc_space == 0)
return FALSE;
static uint16_t dummy_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr)
{
uint32_t todo = nr, ticks, cur_ticks = im->cur_ticks;

while (bc_space--)
bc_b[bc_p++ & bc_mask] = 0xaaaa;
while (todo--) {
ticks = ((rand() >> 4) & 1023) + 100;
cur_ticks += ticks << 4;
*tbuf++ = ticks - 1;
}

bc->prod = bc_p * 16;
im->cur_ticks = cur_ticks % im->tracklen_ticks;

return TRUE;
return nr;
}

static bool_t dummy_write_track(struct image *im)
{
bool_t flush = (im->wr_cons != im->wr_bc);
return flush;
}

const struct image_handler dummy_image_handler = {
.open = dummy_open,
.setup_track = dummy_setup_track,
.read_track = dummy_read_track,
.rdata_flux = bc_rdata_flux,
.rdata_flux = dummy_rdata_flux,
.write_track = dummy_write_track,
};

/*
Expand Down
6 changes: 1 addition & 5 deletions src/image/hfe.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,9 @@ static void hfe_setup_track(
struct image_buf *bc = &im->bufs.read_bc;
uint32_t sys_ticks;
uint8_t cyl = track >> (im->hfe.double_step ? 2 : 1);
uint8_t side = track & 1;
uint8_t side = track & (im->nr_sides - 1);

/* TODO: Fake out unformatted tracks. */
cyl = min_t(uint8_t, cyl, im->nr_cyls-1);
side = min_t(uint8_t, side, im->nr_sides-1);
track = cyl*2 + side;

if (track != im->cur_track)
hfe_seek_track(im, track);

Expand Down
23 changes: 14 additions & 9 deletions src/image/image.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ static bool_t try_handler(struct image *im, struct slot *slot,
im->write_bc_ticks = sysclk_us(2);
im->stk_per_rev = stk_ms(200);

im->handler = handler;
im->disk_handler = im->track_handler = handler;

mode = FA_READ | FA_OPEN_EXISTING;
if (handler->write_track != NULL)
Expand Down Expand Up @@ -210,10 +210,10 @@ void image_extend(struct image *im)
{
FSIZE_t new_sz;

if (!(im->handler->extend && im->fp.dir_ptr && ff_cfg.extend_image))
if (!(im->disk_handler->extend && im->fp.dir_ptr && ff_cfg.extend_image))
return;

new_sz = im->handler->extend(im);
new_sz = im->disk_handler->extend(im);
if (f_size(&im->fp) >= new_sz)
return;

Expand Down Expand Up @@ -253,17 +253,22 @@ static void print_image_info(struct image *im)
bool_t image_setup_track(
struct image *im, uint16_t track, uint32_t *start_pos)
{
const struct image_handler *h = im->track_handler;

#if !defined(QUICKDISK)
if (track < (DA_FIRST_CYL*2)) {
/* If we are exiting D-A mode then need to re-read the config file. */
if (im->handler == &da_image_handler)
if (h == &da_image_handler)
return TRUE;
h = ((track>>1) >= im->nr_cyls) ? &dummy_image_handler
: im->disk_handler;
} else {
im->handler = &da_image_handler;
h = &da_image_handler;
}
#endif

im->handler->setup_track(im, track, start_pos);
im->track_handler = h;
h->setup_track(im, track, start_pos);

print_image_info(im);

Expand All @@ -272,17 +277,17 @@ bool_t image_setup_track(

bool_t image_read_track(struct image *im)
{
return im->handler->read_track(im);
return im->track_handler->read_track(im);
}

uint16_t image_rdata_flux(struct image *im, uint16_t *tbuf, uint16_t nr)
{
return im->handler->rdata_flux(im, tbuf, nr);
return im->track_handler->rdata_flux(im, tbuf, nr);
}

bool_t image_write_track(struct image *im)
{
return im->handler->write_track(im);
return im->track_handler->write_track(im);
}

uint32_t image_ticks_since_index(struct image *im)
Expand Down
6 changes: 1 addition & 5 deletions src/image/img.c
Original file line number Diff line number Diff line change
Expand Up @@ -1704,13 +1704,9 @@ static void raw_setup_track(
struct image_buf *rd = &im->bufs.read_data;
struct image_buf *bc = &im->bufs.read_bc;
uint32_t decode_off, sys_ticks = start_pos ? *start_pos : 0;
uint8_t cyl = track/2, side = track&1;
uint8_t cyl = track/2, side = track & (im->nr_sides - 1);

/* TODO: Fake out unformatted tracks. */
cyl = min_t(uint8_t, cyl, im->nr_cyls-1);
side = min_t(uint8_t, side, im->nr_sides-1);
track = cyl*2 + side;

if (track != im->cur_track)
raw_seek_track(im, track, cyl, side);

Expand Down

0 comments on commit b5e70de

Please sign in to comment.