166 lines
4.2 KiB
C
166 lines
4.2 KiB
C
/* CPQPATCH 1.0 by John Elliott.
|
|
*
|
|
* Patches the BIOS ROM of the Compaq Portable (revision C) to support
|
|
* booting from a hard drive.
|
|
*
|
|
* This program is public domain.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
unsigned char rom[8192];
|
|
|
|
#ifdef __PACIFIC__
|
|
#define AV0 "CPQPATCH"
|
|
#define EXIT_FAILURE -1
|
|
#define EXIT_SUCCESS 0
|
|
#else
|
|
#define AV0 argv[0]
|
|
#endif
|
|
|
|
/* First patch: New INT19 vector */
|
|
static unsigned char p0[] = { 0x20, 0xf8 }; /* DW 0xF820 */
|
|
|
|
/* Second patch: Convert old INT19 into a subroutine */
|
|
static unsigned char p1[] = { /* Enter with DH = 0 DL = drive */
|
|
0xbb, 0x40, 0x00, /* P1: MOV BX, 0x40 ;BIOS dseg */
|
|
0x8E, 0xDB, /* MOV DS, BX */
|
|
0xB9, 0x03, 0x00, /* MOV CX, 0x0003 ;Try 3 times */
|
|
0x51, /* TRY: PUSH CX ;Save count */
|
|
0x52, /* PUSH DX ;Save drive */
|
|
0xBB, 0x00, 0x00, /* MOV BX, 0x0000 ;Load to */
|
|
0x8E, 0xC3, /* MOV ES, BX ;segment 0 */
|
|
0xB4, 0x00, /* MOV AH, 0x00 ;Reset FDC */
|
|
0xCD, 0x13, /* INT 0x13 ;BIOS disk */
|
|
0x5A, /* POP DX ;Get drive */
|
|
0x52, /* PUSH DX ;Save again */
|
|
0xBB, 0x00, 0x7C, /* MOV BX, 0x7C00 ;Load addr */
|
|
0xB9, 0x01, 0x00, /* MOV CX, 0x0001 ;Cyl 0 sec 1 */
|
|
0xB8, 0x01, 0x02, /* MOV AX, 0x0201 ;Read sector */
|
|
0xCD, 0x13, /* INT 0x13 ;BIOS disk */
|
|
0x5A, /* POP DX ;drive */
|
|
0x59, /* POP CX ;count */
|
|
0x73, 0x03, /* JNC OK ;It worked */
|
|
0xE2, 0xE2, /* LOOP TRY ;Retry */
|
|
0xF9, /* STC ;It failed */
|
|
0xC3, /* RET */
|
|
0x00, 0x00, 0x00, 0x00, /* ;Unused */
|
|
};
|
|
|
|
/* Third patch: New INT19 entry point. This replaces an unused area. */
|
|
static unsigned char p2[] = {
|
|
0xfb, /* STI */
|
|
0xBA, 0x00, 0x00, /* TR2: MOV DX, 0x0000 ;Floppy */
|
|
0xE8, 0xCB, 0xEE, /* CALL P1 ;Try it */
|
|
0x73, 0x0B, /* JNC GO ;It worked! */
|
|
0xB2, 0x80, /* MOV DL, 0x80 ;Hard drive */
|
|
0xE8, 0xC4, 0xEE, /* CALL P1 ;Try it */
|
|
0x73, 0x04, /* JNC GO ;It worked! */
|
|
0xCD, 0x20, /* INT 0x20 ;See below */
|
|
0xEB, 0xED, /* JMPS TR2 ;Loop forever*/
|
|
|
|
0xEA, 0x00, 0x7C, /* GO: JMPF 0x0000:0x7C00 ;Go to sector*/
|
|
0x00, 0x00,
|
|
0x00, /* DB 0 ;word align */
|
|
0xEC, 0x7E, /* DW 07EECh ;checksum */
|
|
0x00, 0x00, 0x00, 0x00, /* ;Unused */
|
|
/* Note on the INT 0x20: This is not 'program termination' at boot time. The
|
|
* Compaq BIOS hooks it and uses it to display the message:
|
|
*
|
|
* Diskette error
|
|
* Replace and strike any key when ready
|
|
*
|
|
*/
|
|
};
|
|
|
|
|
|
void patch()
|
|
{
|
|
memcpy(rom + 0x0376, p0, sizeof(p0));
|
|
memcpy(rom + 0x06f2, p1, sizeof(p1));
|
|
memcpy(rom + 0x1820, p2, sizeof(p2));
|
|
}
|
|
|
|
unsigned short checksum()
|
|
{
|
|
unsigned short total, cur;
|
|
int n;
|
|
|
|
total = 0;
|
|
for (n = 0; n < 8192; n++)
|
|
{
|
|
cur = rom[n];
|
|
++n;
|
|
cur |= (((unsigned short)rom[n]) << 8);
|
|
total += cur;
|
|
}
|
|
return total;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
FILE *fp;
|
|
unsigned short sum;
|
|
|
|
if (argc < 3)
|
|
{
|
|
fprintf(stderr, "Syntax: %s old_rom new_rom\n\n"
|
|
/* 1...5...10...15...20...25...30...35...40*/
|
|
"Patches the BIOS ROM of the Compaq\n"
|
|
"Portable (revision C) to support booting\n"
|
|
"from a hard drive.\n\n"
|
|
"This program is public domain.", AV0);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
fp = fopen(argv[1], "rb");
|
|
if (!fp)
|
|
{
|
|
perror(argv[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (fread(rom, 1, sizeof(rom), fp) < (int)sizeof(rom))
|
|
{
|
|
fprintf(stderr, "Could not read 8k from %s\n", argv[1]);
|
|
fclose(fp);
|
|
return EXIT_FAILURE;
|
|
}
|
|
fclose(fp);
|
|
if (memcmp(rom + 0x1FEA, "COMPAQ", 6))
|
|
{
|
|
fprintf(stderr, "COMPAQ signature not found in %s\n", argv[1]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (rom[0x1FE6] != 'C')
|
|
{
|
|
fprintf(stderr, "ROM revision is not C. This may not work.\n");
|
|
}
|
|
sum = checksum();
|
|
if (sum != 0)
|
|
{
|
|
fprintf(stderr, "ROM checksum is 0x%04x (should be 0). This "
|
|
"may not work.\n", sum);
|
|
}
|
|
patch();
|
|
sum = checksum();
|
|
if (sum != 0)
|
|
{
|
|
fprintf(stderr, "New checksum is 0x%04x (should be 0). This "
|
|
"may not work.\n", sum);
|
|
}
|
|
fp = fopen(argv[2], "wb");
|
|
if (!fp)
|
|
{
|
|
perror(argv[2]);
|
|
return EXIT_FAILURE;
|
|
}
|
|
if (fwrite(rom, 1, sizeof(rom), fp) < (int)sizeof(rom))
|
|
{
|
|
fprintf(stderr, "Could not write 8k to %s\n", argv[2]);
|
|
fclose(fp);
|
|
return EXIT_FAILURE;
|
|
}
|
|
fclose(fp);
|
|
return EXIT_SUCCESS;
|
|
}
|