/*
 *  killinitrd-s2.c
 *
 *  This will patch the panic("No bootable RAMdisk") call on v3.1.0,
 *  v3.2 and v4.0 kernels. It will also nuke the gzip magic.
 *  i.e. it will disable initrd on a Series2 unit.  Of course, you will
 *  need a patched PROM in order to take advantage of this.
 *
 *  Created by Steve White on Tue Feb 11 2003.
 *  Copyright (c) 2003 Steve White. All rights reserved.
 *
 */

#include <stdio.h>
#include <fcntl.h>

struct patch {
	unsigned long int offset;
	unsigned long int originalValue;
	unsigned long int patchedValue;
};

int main(int argc, char *argv[]) {
//	Uncomment for a v2.4.4 kernel (TiVo v3.1.0 & TiVo v3.2) 
/*
	struct patch patches[] = { {0x2e68, 0x1040004a, 0x1040003a},
  				   {0x2e84, 0x10620043, 0x10620033},
				   {0x2e90, 0x14620040, 0x14620030},
				   {0x2e98, 0x1440003e, 0x1440002e},
				   {0} };
*/

//	Uncomment for a v2.4.18 Kernel (TiVo v4.0)
	struct patch patches[] = { {0x1523c, 0x10400054, 0x1040003f},
				   {0x15254, 0x1082004e, 0x10820039},
				   {0x15260, 0x1462004b, 0x14620036},
				   {0x15268, 0x14400049, 0x14400034},
				   {0} };
	unsigned long int data;
	unsigned long cmp;
	unsigned char readdata;
	long offset;
	int fd,i=0;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s <kernel image>\n", argv[0]);
		exit(1);
	}

	if ( (fd=open(argv[1], O_RDWR)) < 0) {
		perror(argv[1]);
		exit(1);
	}

	// sanity test. make sure the values we are looking for exist
	while (patches[i].offset != 0) {
		lseek(fd, patches[i].offset, SEEK_SET);
		read(fd, &data, 4);
		if (htonl(data) != patches[i].originalValue) {
			fprintf(stderr, "0x%08x: Expected 0x%08x but instead got 0x%08x!\n",
				 patches[i].offset, patches[i].originalValue, htonl(data));
			close(fd);
			exit(1);
		}
		i++;
	}

	// if we made it here, everything is as we expected. now patch.
	i=0;
	while (patches[i].offset != 0) {
		data = htonl(patches[i].patchedValue);
		lseek(fd, patches[i].offset, SEEK_SET);
		write(fd, &data, sizeof(patches[i].patchedValue));
		i++;
	}

	// now look for the gzip magic. when found, disable it too.
	while (read(fd, &readdata, 1) == 1) {
		offset = lseek(fd, 0, SEEK_CUR);
		cmp = cmp << 8 | readdata;
		if (cmp == 0x1f8b0800) {
			lseek(fd, offset-4, SEEK_SET);
			data = 0x00;
			write(fd, &data, 1);
			break;
		}
	}

	close(fd);
	printf("Successfully patched %s!\n", argv[1]);
}
