--- trunk/src/emul.c 2007/10/08 16:21:17 34 +++ trunk/src/emul.c 2007/10/08 16:21:34 36 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: emul.c,v 1.278 2007/02/10 14:37:38 debug Exp $ + * $Id: emul.c,v 1.279 2007/03/16 14:45:30 debug Exp $ * * Emulation startup and misc. routines. */ @@ -57,9 +57,6 @@ #include "x11.h" -/* #define ISO_DEBUG */ - - extern int extra_argc; extern char **extra_argv; @@ -75,8 +72,6 @@ extern struct emul *debugger_emul; extern struct diskimage *diskimages[]; -static char *diskimage_types[] = DISKIMAGE_TYPES; - static void print_separator(void) { @@ -153,635 +148,6 @@ } -/* - * iso_load_bootblock(): - * - * Try to load a kernel from an ISO 9660 disk image. iso_type is 1 for - * "CD001" (standard), 2 for "CDW01" (ECMA), and 3 for "CDROM" (Sierra). - * - * TODO: This function uses too many magic offsets and so on; it should be - * cleaned up some day. - * - * Returns 1 on success, 0 on failure. - */ -static int iso_load_bootblock(struct machine *m, struct cpu *cpu, - int disk_id, int disk_type, int iso_type, unsigned char *buf, - int *n_loadp, char ***load_namesp) -{ - char str[35]; - int filenr, i, ofs, dirlen, res = 0, res2, iadd = DEBUG_INDENTATION; - int found_dir; - uint64_t dirofs; - uint64_t fileofs, filelen; - unsigned char *dirbuf = NULL, *dp; - unsigned char *match_entry = NULL; - char *p, *filename_orig; - char *filename = strdup(cpu->machine->boot_kernel_filename); - unsigned char *filebuf = NULL; - char *tmpfname = NULL; - char **new_array; - int tmpfile_handle; - - if (filename == NULL) { - fatal("out of memory\n"); - exit(1); - } - filename_orig = filename; - - debug("ISO9660 boot:\n"); - debug_indentation(iadd); - - /* Volume ID: */ - ofs = iso_type == 3? 48 : 40; - memcpy(str, buf + ofs, sizeof(str)); - str[32] = '\0'; i = 31; - while (i >= 0 && str[i]==' ') - str[i--] = '\0'; - if (str[0]) - debug("\"%s\"", str); - else { - /* System ID: */ - ofs = iso_type == 3? 16 : 8; - memcpy(str, buf + ofs, sizeof(str)); - str[32] = '\0'; i = 31; - while (i >= 0 && str[i]==' ') - str[i--] = '\0'; - if (str[0]) - debug("\"%s\"", str); - else - debug("(no ID)"); - } - - debug(":%s\n", filename); - - - /* - * Traverse the directory structure to find the kernel. - */ - - dirlen = buf[0x84] + 256*buf[0x85] + 65536*buf[0x86]; - if (dirlen != buf[0x8b] + 256*buf[0x8a] + 65536*buf[0x89]) - fatal("WARNING: Root directory length mismatch?\n"); - - dirofs = (int64_t)(buf[0x8c] + (buf[0x8d] << 8) + (buf[0x8e] << 16) + - ((uint64_t)buf[0x8f] << 24)) * 2048; - -#ifdef ISO_DEBUG - debug("root = %i bytes at 0x%llx\n", dirlen, (long long)dirofs); -#endif - - dirbuf = malloc(dirlen); - if (dirbuf == NULL) { - fatal("out of memory in iso_load_bootblock()\n"); - exit(1); - } - - res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, dirbuf, - dirlen); - if (!res2) { - fatal("Couldn't read the disk image. Aborting.\n"); - goto ret; - } - - found_dir = 1; /* Assume root dir */ - dp = dirbuf; filenr = 1; - p = NULL; - while (dp < dirbuf + dirlen) { - size_t i, nlen = dp[0]; - int x = dp[2] + (dp[3] << 8) + (dp[4] << 16) + - ((uint64_t)dp[5] << 24); - int y = dp[6] + (dp[7] << 8); - char direntry[65]; - - dp += 8; - - /* - * As long as there is an \ or / in the filename, then we - * have not yet found the directory. - */ - p = strchr(filename, '/'); - if (p == NULL) - p = strchr(filename, '\\'); - -#ifdef ISO_DEBUG - debug("%i%s: %i, %i, \"", filenr, filenr == found_dir? - " [CURRENT]" : "", x, y); -#endif - for (i=0; i 2047) { - dirofs = (dirofs | 2047) + 1; - /* debug("realign dirofs = 0x%llx\n", dirofs); */ - } - - res2 = diskimage_access(m, disk_id, disk_type, 0, dirofs, - dirbuf, 256); - if (!res2) { - fatal("Couldn't read the disk image. Aborting.\n"); - goto ret; - } - - dp = dirbuf; - len = dp[0]; - if (len < 2) - break; - - /* - * TODO: Actually parse the directory entry! - * - * Haha, this must be rewritten. - */ - for (i=32; i= 2) { - fatal("Error: Too many HFS partitions found! TODO\n"); - return 0; - } - - return 0; -} - - -/* - * load_bootblock(): - * - * For some emulation modes, it is possible to boot from a harddisk image by - * loading a bootblock from a specific disk offset into memory, and executing - * that, instead of requiring a separate kernel file. It is then up to the - * bootblock to load a kernel. - * - * Returns 1 on success, 0 on failure. - */ -static int load_bootblock(struct machine *m, struct cpu *cpu, - int *n_loadp, char ***load_namesp) -{ - int boot_disk_id, boot_disk_type = 0, n_blocks, res, readofs, - iso_type, retval = 0; - unsigned char minibuf[0x20]; - unsigned char *bootblock_buf; - uint64_t bootblock_offset, base_offset; - uint64_t bootblock_loadaddr, bootblock_pc; - - boot_disk_id = diskimage_bootdev(m, &boot_disk_type); - if (boot_disk_id < 0) - return 0; - - base_offset = diskimage_get_baseoffset(m, boot_disk_id, boot_disk_type); - - switch (m->machine_type) { - - case MACHINE_DREAMCAST: - if (!diskimage_is_a_cdrom(cpu->machine, boot_disk_id, - boot_disk_type)) { - fatal("The Dreamcast emulation mode can only boot" - " from CD images, not from other disk types.\n"); - exit(1); - } - - bootblock_buf = malloc(32768); - if (bootblock_buf == NULL) { - fprintf(stderr, "Out of memory.\n"); - exit(1); - } - - debug("loading Dreamcast IP.BIN from %s id %i\n", - diskimage_types[boot_disk_type], boot_disk_id); - - res = diskimage_access(m, boot_disk_id, boot_disk_type, - 0, base_offset, bootblock_buf, 0x8000); - if (!res) { - fatal("Couldn't read the disk image. Aborting.\n"); - return 0; - } - - if (strncmp((char *)bootblock_buf, "SEGA ", 5) != 0) { - fatal("This is not a Dreamcast IP.BIN header.\n"); - free(bootblock_buf); - return 0; - } - - /* Store IP.BIN at 0x8c008000, and set entry point. */ - store_buf(cpu, 0x8c008000, (char *)bootblock_buf, 32768); - cpu->pc = 0x8c008300; - - /* Remember the name of the file to boot (1ST_READ.BIN): */ - if (cpu->machine->boot_kernel_filename == NULL || - cpu->machine->boot_kernel_filename[0] == '\0') { - int i = 0x60; - while (i < 0x70) { - if (bootblock_buf[i] == ' ') - bootblock_buf[i] = 0; - i ++; - } - cpu->machine->boot_kernel_filename = strdup( - (char *)bootblock_buf + 0x60); - } - - debug("boot filename: %s\n", - cpu->machine->boot_kernel_filename); - - free(bootblock_buf); - - break; - - case MACHINE_PMAX: - /* - * The first few bytes of a disk contains information about - * where the bootblock(s) are located. (These are all 32-bit - * little-endian words.) - * - * Offset 0x10 = load address - * 0x14 = initial PC value - * 0x18 = nr of 512-byte blocks to read - * 0x1c = offset on disk to where the bootblocks - * are (in 512-byte units) - * 0x20 = nr of blocks to read... - * 0x24 = offset... - * - * nr of blocks to read and offset are repeated until nr of - * blocks to read is zero. - */ - res = diskimage_access(m, boot_disk_id, boot_disk_type, 0, 0, - minibuf, sizeof(minibuf)); - - bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8) - + (minibuf[0x12] << 16) + ((uint64_t)minibuf[0x13] << 24); - - /* Convert loadaddr to uncached: */ - if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 && - (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000) { - fatal("\nWARNING! Weird load address 0x%08"PRIx32 - " for SCSI id %i.\n\n", - (uint32_t)bootblock_loadaddr, boot_disk_id); - if (bootblock_loadaddr == 0) { - fatal("I'm assuming that this is _not_ a " - "DEC bootblock.\nAre you sure you are" - " booting from the correct disk?\n"); - exit(1); - } - } - - bootblock_loadaddr &= 0x0fffffffULL; - bootblock_loadaddr |= 0xffffffffa0000000ULL; - - bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8) - + (minibuf[0x16] << 16) + ((uint64_t)minibuf[0x17] << 24); - - bootblock_pc &= 0x0fffffffULL; - bootblock_pc |= 0xffffffffa0000000ULL; - cpu->pc = bootblock_pc; - - debug("DEC boot: loadaddr=0x%08x, pc=0x%08x", - (int)bootblock_loadaddr, (int)bootblock_pc); - - readofs = 0x18; - - for (;;) { - res = diskimage_access(m, boot_disk_id, boot_disk_type, - 0, readofs, minibuf, sizeof(minibuf)); - if (!res) { - fatal("Couldn't read the disk image. " - "Aborting.\n"); - return 0; - } - - n_blocks = minibuf[0] + (minibuf[1] << 8) - + (minibuf[2] << 16) + ((uint64_t)minibuf[3] << 24); - - bootblock_offset = (minibuf[4] + (minibuf[5] << 8) + - (minibuf[6]<<16) + ((uint64_t)minibuf[7]<<24)) * 512; - - if (n_blocks < 1) - break; - - debug(readofs == 0x18? ": %i" : " + %i", n_blocks); - - if (n_blocks * 512 > 65536) - fatal("\nWARNING! Unusually large bootblock " - "(%i bytes)\n\n", n_blocks * 512); - - bootblock_buf = malloc(n_blocks * 512); - if (bootblock_buf == NULL) { - fprintf(stderr, "out of memory in " - "load_bootblock()\n"); - exit(1); - } - - res = diskimage_access(m, boot_disk_id, boot_disk_type, - 0, bootblock_offset, bootblock_buf, n_blocks * 512); - if (!res) { - fatal("WARNING: could not load bootblocks from" - " disk offset 0x%llx\n", - (long long)bootblock_offset); - } - - store_buf(cpu, bootblock_loadaddr, - (char *)bootblock_buf, n_blocks * 512); - - bootblock_loadaddr += 512*n_blocks; - free(bootblock_buf); - readofs += 8; - } - - debug(readofs == 0x18? ": no blocks?\n" : " blocks\n"); - return 1; - } - - - /* - * Try reading a kernel manually from the disk. The code here - * does not rely on machine-dependent boot blocks etc. - */ - /* ISO9660: (0x800 bytes at 0x8000 + base_offset) */ - bootblock_buf = malloc(0x800); - if (bootblock_buf == NULL) { - fprintf(stderr, "Out of memory.\n"); - exit(1); - } - - res = diskimage_access(m, boot_disk_id, boot_disk_type, - 0, base_offset + 0x8000, bootblock_buf, 0x800); - if (!res) { - fatal("Couldn't read the disk image. Aborting.\n"); - return 0; - } - - iso_type = 0; - if (strncmp((char *)bootblock_buf+1, "CD001", 5) == 0) - iso_type = 1; - if (strncmp((char *)bootblock_buf+1, "CDW01", 5) == 0) - iso_type = 2; - if (strncmp((char *)bootblock_buf+1, "CDROM", 5) == 0) - iso_type = 3; - - if (iso_type != 0) { - /* - * If the user specified a kernel name, then load it from - * disk. - */ - if (cpu->machine->boot_kernel_filename == NULL || - cpu->machine->boot_kernel_filename[0] == '\0') - fatal("\nISO9660 filesystem, but no kernel " - "specified? (Use the -j option.)\n"); - else - retval = iso_load_bootblock(m, cpu, boot_disk_id, - boot_disk_type, iso_type, bootblock_buf, - n_loadp, load_namesp); - } - - if (retval != 0) - goto ret_ok; - - /* Apple parition table: */ - res = diskimage_access(m, boot_disk_id, boot_disk_type, - 0, 0x0, bootblock_buf, 0x800); - if (!res) { - fatal("Couldn't read the disk image. Aborting.\n"); - return 0; - } - if (bootblock_buf[0x000] == 'E' && bootblock_buf[0x001] == 'R' && - bootblock_buf[0x200] == 'P' && bootblock_buf[0x201] == 'M') { - if (cpu->machine->boot_kernel_filename == NULL || - cpu->machine->boot_kernel_filename[0] == '\0') - fatal("\nApple partition table, but no kernel " - "specified? (Use the -j option.)\n"); - else - retval = apple_load_bootblock(m, cpu, boot_disk_id, - boot_disk_type, n_loadp, load_namesp); - } - -ret_ok: - free(bootblock_buf); - return retval; -} - - /* * emul_new(): *