@da9000
static __inline u_int32_t rl(const u_int8_t *p)
{
return (u_int32_t) ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
}
static __inline int romptr(u_int32_t p)
{
return p >= ROMSTART && p < ROMEND;
}
for (i = 8; i < 512; i += 2)
{
static const u_int8_t header[] =
"\xff\xff\xff\xff\x0d\x0a\x0a" "AMIGA ROM Operating System";
u_int8_t * const p = (u_int8_t *) rom + i;
if (!memcmp(p, header, sizeof(header) - 1))
{
newtdread = p;
if (verbose > 1)
{
fprintf(stderr, "0x%06x: Patch position\n",
(u_int8_t *) newtdread - (u_int8_t *) rom + ROMSTART);
}
break;
}
}
for (i = 8; i < ROMSIZE - 40; i += 2)
{
u_int8_t * const p = (u_int8_t *) rom + i;
u_int32_t p1, p2;
p1 = rl(p);
p2 = rl(p + 8);
if (romptr(p1) && romptr(p2) &&
rl(p + 4) == p1 && rl(p + 12) == p2 &&
romptr(rl(p + 16)) && romptr(rl(p + 20)) &&
rl(p + 24) == p1 && rl(p + 28) == p1 && rl(p + 32) == p1)
{
const u_int8_t *func = (u_int8_t *) rom + p2 - ROMSTART;
if (rl(func) == 0x48E70038 && rl(func + 4) == 0x26690018)
{
oldtdreadptr = p + 8;
if (verbose > 1)
{
fprintf(stderr, "0x%06x: trackdisk.device CMD_READ function ptr\n",
(u_int8_t *) oldtdreadptr - (u_int8_t *) rom + ROMSTART);
}
break;
}
}
}
Efficiency does not matter here. The code is executed once when creating the disk.
The first loop finds the strings at the beginning of the ROM (it's quite pointless since in fact I think the strings are always at the same offset for all pre-2.0 ROMs). This is where the patch code will be placed.
The second loop is more magic, it locates the jumptable entry for the trackdisk.device CMD_READ command. There it looks for certain combination of pointers, and also has some code matching for the beginning of the actual cmd_read routine. The magical pattern is:
ptr1 ; CMD_INVALID
ptr1 ; CMD_RESET
ptr2 ; CMD_READ
ptr2 ; CMD_WRITE
ptr3 ; CMD_UPDATE
ptr4 ; CMD_CLEAR
ptr1 ; CMD_STOP
ptr1 ; CMD_START
ptr1 ; CMD_FLUSH
Once the code finds this pattern of pointers it then checks the code pointed by ptr2. It checks for:
ptr2:
movem.l a2-a4,-(sp)
move.l (IO_UNIT,a1),a3
Those are the first two instructions of the cmd_read routine (actually read/write.. as you can see both CMD_READ and CMD_WRITE point to the same routine, the routines are so similar it helped to reduce the codesize to combine them).
Once this jumptable entry is located it is changed to point to the first pointer (where we've copied the patch code to). The patch code is adjusted to jsr to the original cmd_read(write) routine.
Obviously this isn't the only way to patch the trackdisk.device, there are several other ways to do it aswell. One would been by patching the trackdisk.device BEGINIO vector for example. However, in my case I had very little storage left for my patch so to simplify the patchcode I had to locate the patch to as close to actual read operation as possible. Patching BEGINIO would have required for the patch routine to perform further checking to make sure it is a CMD_READ operation.