146 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			146 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include <stdlib.h>
 | |
| #include <stdio.h>
 | |
| #include <stdint.h>
 | |
| #include <stdarg.h>
 | |
| #include <errno.h>
 | |
| #include <string.h>
 | |
| #include <sys/types.h>
 | |
| #include <sys/stat.h>
 | |
| #include <fcntl.h>
 | |
| #include <unistd.h>
 | |
| #include "x86emu.h"
 | |
| 
 | |
| static uint8_t ram[1025*1024];
 | |
| static int floppy_fd;
 | |
| static X86EMU_intrFuncs intr_funcs[256];
 | |
| 
 | |
| void printk(const char* format, ...)
 | |
| {
 | |
| 	va_list ap;
 | |
| 	va_start(ap, format);
 | |
| 	vfprintf(stderr, format, ap);
 | |
| 	va_end(ap);
 | |
| }
 | |
| 
 | |
| static void unknown_interrupt_cb(int num)
 | |
| {
 | |
| 	printk("unknown interrupt 0x%02x\n", num);
 | |
| 	exit(1);
 | |
| }
 | |
| 
 | |
| static void ignored_interrupt_cb(int num)
 | |
| {
 | |
| 	M.x86.R_AX = 0;
 | |
| }
 | |
| 
 | |
| static void int10_cb(int num)
 | |
| {
 | |
| 	switch (M.x86.R_AH)
 | |
| 	{
 | |
| 		case 0x0e: /* print char al */
 | |
| 			putchar(M.x86.R_AL);
 | |
| 			fflush(stdout);
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			printk("unknown int10 service 0x%02x\n", M.x86.R_AH);
 | |
| 			exit(1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void int13_cb(int num)
 | |
| {
 | |
| 	if (M.x86.R_DL != 0)
 | |
| 	{
 | |
| 		/* unknown disk */
 | |
| 		M.x86.R_AX = 1;
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	switch (M.x86.R_AH)
 | |
| 	{
 | |
| 		case 0x02: /* read sector */
 | |
| 		{
 | |
| 			/* On entry:
 | |
| 			 *   al: number of sectors
 | |
| 			 *   bx: address
 | |
| 			 *   ch: track
 | |
| 			 *   cl: sector
 | |
| 			 *   dh: head number
 | |
| 			 *   dl: disk
 | |
| 			 */
 | |
| 			uint8_t count = M.x86.R_AL;
 | |
| 			uint32_t address = (M.x86.R_DS << 4) + M.x86.R_BX;
 | |
| 			uint8_t sector = M.x86.R_CL;
 | |
| 			uint8_t track = M.x86.R_CH;
 | |
| 			uint8_t head = M.x86.R_DH;
 | |
| 			uint32_t lba = track*18*2 + head*18 + (sector-1);
 | |
| 			//printf("CHS %d.%d.%d -> lba 0x%x\n", track, head, sector, lba);
 | |
| 			pread(floppy_fd, &ram[address], count*512, lba*512);
 | |
| 			M.x86.R_AX = 0;
 | |
| 			CLEAR_FLAG(F_CF);
 | |
| 		}
 | |
| 
 | |
| 		case 0x08: /* probe disk al */
 | |
| 			M.x86.R_AX = 0;
 | |
| 			M.x86.R_CL = 18; /* maximum sector number */
 | |
| 			M.x86.R_DH = 1; /* maximum head number */
 | |
| 			/* there's other stuff we should set as well */
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			printk("unknown int13 service 0x%02x\n", M.x86.R_AH);
 | |
| 			exit(1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int main(int argc, const char* argv[])
 | |
| {
 | |
| 	int i;
 | |
| 
 | |
| 	if (argc != 2)
 | |
| 	{
 | |
| 		printk("syntax: pc86emu <fdimage.img>\n");
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| 	floppy_fd = open(argv[1], O_RDONLY);
 | |
| 	if (floppy_fd == -1)
 | |
| 	{
 | |
| 		printk("could not open disk image: %s\n", strerror(errno));
 | |
| 		exit(1);
 | |
| 	}
 | |
| 
 | |
| 	/* Initialise the processor. */
 | |
| 
 | |
| 	M.mem_base = (uintptr_t) ram;
 | |
|     M.mem_size = sizeof(ram);
 | |
| 
 | |
| 	/* Load the boot sector at 0x07c0:0000. */
 | |
| 
 | |
| 	for (i=0; i<512; i++)
 | |
| 	{
 | |
| 		uint8_t b;
 | |
| 		read(floppy_fd, &b, 1);
 | |
| 		wrb(0x7c00 + i, b);
 | |
| 	}
 | |
| 
 | |
| 	/* Initialise. */
 | |
| 
 | |
| 	for (i=0; i<256; i++)
 | |
| 		intr_funcs[i] = unknown_interrupt_cb;
 | |
| 	intr_funcs[0x10] = int10_cb;
 | |
| 	intr_funcs[0x13] = int13_cb;
 | |
| 	intr_funcs[0x14] = ignored_interrupt_cb; /* serial port stuff */
 | |
| 
 | |
| 	//M.x86.debug = DEBUG_TRACE_F|DEBUG_STEP_F|DEBUG_DECODE_F;
 | |
| 	M.x86.debug = 0;
 | |
| 	M.x86.R_CS = 0x07c0;
 | |
| 	M.x86.R_IP = 0x0000;
 | |
| 	M.x86.R_DL = 0; /* boot drive */
 | |
| 	X86EMU_setupIntrFuncs(intr_funcs);
 | |
| 	X86EMU_exec();
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 |