/* * Copyright (c) 2013, Peter Rutenbar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include "../shoebill.h" #include "../coff.h" struct dbg_state_t dbg_state; void print_mmu_rp(uint64_t rp) { printf("lu=%u limit=0x%x sg=%u dt=%u addr=0x%08x\n", rp_lu(rp), rp_limit(rp), rp_sg(rp), rp_dt(rp), rp_addr(rp)); } void printregs() { printf("[d0]%08x [d1]%08x [d2]%08x [d3]%08x\n", shoe.d[0], shoe.d[1], shoe.d[2], shoe.d[3]); printf("[d4]%08x [d5]%08x [d6]%08x [d7]%08x\n", shoe.d[4], shoe.d[5], shoe.d[6], shoe.d[7]); printf("[a0]%08x [a1]%08x [a2]%08x [a3]%08x\n", shoe.a[0], shoe.a[1], shoe.a[2], shoe.a[3]); printf("[a4]%08x [a5]%08x [a6]%08x [a7]%08x\n", shoe.a[4], shoe.a[5], shoe.a[6], shoe.a[7]); printf("[pc]%08x [sr]%c%c%c%c%c%c%c [tc]%08x\n", shoe.pc, sr_s()?'S':'s', sr_m()?'M':'m', sr_x()?'X':'x', sr_n()?'N':'n', sr_z()?'Z':'z', sr_v()?'V':'v', sr_c()?'C':'c', shoe.tc ); printf("[vbr]%08x\n", shoe.vbr); printf("srp: "); print_mmu_rp(shoe.srp); printf("crp: "); print_mmu_rp(shoe.crp); printf("tc: e=%u sre=%u fcl=%u ps=%u is=%u (tia=%u tib=%u tic=%u tid=%u)\n", tc_enable(), tc_sre(), tc_fcl(), tc_ps(), tc_is(), tc_tia(), tc_tib(), tc_tic(), tc_tid()); printf("\n"); } void print_pc() { char str[1024]; uint8_t binary[32]; uint32_t i; uint32_t len; const char *name = NULL; if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) { uint32_t i, addr = shoe.pc % (shoe.physical_rom_size); for (i=0; macii_rom_symbols[i].name; i++) { if (macii_rom_symbols[i].addr > addr) { break; } name = macii_rom_symbols[i].name; } } else if (sr_s()) { // these symbols are only meaningful in supervisor mode coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); if (symb && strlen(symb->name)) name = symb->name; } else { if ((shoe.pc >= 0x10000000) && (shoe.pc < 0x20000000)) { uint32_t i, addr = shoe.pc % (shoe.physical_rom_size); for (i=0; macii_rom_symbols[i].name; i++) { if (macii_rom_symbols[i].addr > addr) { break; } name = macii_rom_symbols[i].name; } } else { coff_symbol *symb = coff_find_func(shoe.launch, shoe.pc); if (symb) name = symb->name; } } const uint16_t old_abort = shoe.abort; shoe.suppress_exceptions = 1; for (i=0; i<32; i++) { binary[i] = (uint8_t) lget(shoe.pc+i, 1); } disassemble_inst(binary, shoe.pc, str, &len); printf("*0x%08x %s [ ", shoe.pc, name ? name : ""); for (i=0; inext) { if (shoe.pc == cur->addr) { printf("Hit breakpoint %llu *0x%08x\n", cur->num, shoe.pc); dbg_state.running = 0; return ; } } if (shoe.dbg) { // printf("*0x1ff01074 = %llx\n", lget(0x1ff01074, 4)); print_pc(); printregs(); } // if ((shoe.pc >= 0x40000000) && (shoe.pc < 0x50000000)) { // //print_pc(); // //printregs(); // } // else { // coff_symbol *symb = coff_find_func(shoe.coff, shoe.pc); // if ((symb && (strcmp(symb->name, "scsitask")==0)) || // /*(symb && (strcmp(symb->name, "scsiget")==0)) || // (symb && (strcmp(symb->name, "scsi_out")==0)) || // (symb && (strcmp(symb->name, "scsireq")==0)) || // (symb && (strcmp(symb->name, "scsi_vio")==0)) || // (symb && (strcmp(symb->name, "binit")==0)) ||*/ // (symb && (strcmp(symb->name, "realvtopte")==0)) || // (symb && (strcmp(symb->name, "realvtop")==0)) || // (symb && (strcmp(symb->name, "realsvtop")==0)) || /* // (symb && (strcmp(symb->name, "sdcmd")==0)) || // (symb && (strcmp(symb->name, "sdread")==0)) || // (symb && (strcmp(symb->name, "gdpartinit")==0)) || // (symb && (strcmp(symb->name, "scsi_in")==0)) || // (symb && (strcmp(symb->name, "gddriveinit")==0)) || // (symb && (strcmp(symb->name, "vio_init")==0)) || // (symb && (strcmp(symb->name, "get_psr")==0)) || // (symb && (strcmp(symb->name, "scsisched")==0)) || // (symb && (strcmp(symb->name, "choosetask")==0)) || */ // (symb && (strcmp(symb->name, "scsiselect")==0))) { // print_pc(); // printregs(); // } // else if ((shoe.pc > (0x0014ea02-32)) && (shoe.pc < (0x0014ea02+32))) { // print_pc(); // printregs(); // } // } } char *cli_prompt_callback(EditLine *el) { return "~ "; } // Hack to clear line after ^C. el_reset() screws up tty when called from the signal handler. void ch_reset(EditLine *el, int mclear); void signal_callback(int sig) { EditLine *el = dbg_state.el; (void) signal(SIGINT, signal_callback); (void) signal(SIGWINCH, signal_callback); switch (sig) { case SIGWINCH: el_resize(el); break ; case SIGINT: if (dbg_state.running) { dbg_state.running = 0; } else { printf("\n"); ch_reset(el, 0); el_set(el, EL_REFRESH); } break ; } return ; } void verb_backtrace_handler (const char *line) { const uint32_t old_abort = shoe.abort; shoe.suppress_exceptions = 1; shoe.abort = 0; // link // push a6 to a7 // set a6 = a7 // set a7 = a7 - (some stack space) // jsr // push return pointer to a7 // call // set a7 = a7 - (some stack space) // push arguments to a7 // push return pointer to a7 // (jump to function) // push // bt algorithm // set a7 = a6 // pop a7 -> a6 // pop a7 -> return pointer uint32_t i, j, a7, a6 = shoe.a[6]; coff_symbol *symb; if (sr_s()) { symb = coff_find_func(shoe.coff, shoe.pc); printf("%u: *0x%08x %s+%u\n", 0, shoe.pc, (symb && strlen(symb->name))?symb->name:"?", shoe.pc - symb->value); } else printf("%u: *0x%08x\n", 0, shoe.pc); for (i=1; 1; i++) { a7 = a6; const uint32_t last_a6 = lget(a7, 4); const uint32_t last_pc = lget(a7+4, 4); if ((last_a6 - a6) <= 1000) { printf(" {"); for (j = a6+8; j < last_a6; j+=4) { uint32_t data = lget(j, 4); printf("%x, ", data); } printf("}\n"); } if (sr_s()) { symb = coff_find_func(shoe.coff, last_pc); printf("%u: *0x%08x %s+%u\n", i, last_pc, (symb && strlen(symb->name))?symb->name:"?", last_pc - symb->value); } else printf("%u: *0x%08x\n", i, last_pc); if ((last_a6 - a6) > 1000) { break; } a6 = last_a6; } shoe.suppress_exceptions = 0; shoe.abort = old_abort; } void verb_break_handler (const char *line) { errno = 0; const uint32_t addr = (uint32_t) strtoul(line, NULL, 0); if (errno) { printf("errno: %d\n", errno); return ; } dbg_breakpoint_t *brk = calloc(sizeof(dbg_breakpoint_t), 1); brk->next = NULL; brk->addr = addr; brk->num = dbg_state.breakpoint_counter++; dbg_breakpoint_t **cur = &dbg_state.breakpoints; while (*cur) cur = &(*cur)->next; *cur = brk; printf("Set breakpoint %llu = *0x%08x\n", brk->num, brk->addr); } void verb_delete_handler (const char *line) { errno = 0; uint64_t num = strtoull(line, NULL, 0); if (errno) { printf("errno: %d\n", errno); return ; } dbg_breakpoint_t **cur = &dbg_state.breakpoints; while (*cur) { if ((*cur)->num == num) { dbg_breakpoint_t *victim = *cur; *cur = (*cur)->next; free(victim); return ; } cur = &(*cur)->next; } printf("No such breakpoint (#%llu)\n", num); } void verb_help_handler (const char *line) { printf("Help help help\n"); } void verb_quit_handler (const char *line) { printf("Quitting\n"); fflush(stdout); exit(0); } void verb_continue_handler (const char *line) { dbg_state.running = 1; while (dbg_state.running) { stepper(); } print_pc(); } void verb_stepi_handler (const char *line) { shoe.stopped = 0; dbg_state.running = 1; cpu_step(); dbg_state.running = 0; print_pc(); } void verb_registers_handler (const char *line) { printregs(); } void verb_trace_toggle_handler (const char *line) { shoe.dbg = !shoe.dbg; } void verb_examine_handler (const char *line) { uint32_t addr = (uint32_t)strtoul(line, NULL, 0); uint32_t old_suppress = shoe.suppress_exceptions; shoe.suppress_exceptions = 1; printf("(uint32_t)*0x%08x = 0x%08x\n", addr, (uint32_t)lget(addr, 4)); shoe.suppress_exceptions = old_suppress; } void verb_lookup_handler (const char *line) { char *sym_name = malloc(strlen(line)+1); sscanf(line, "%s", sym_name); coff_symbol *symb = coff_find_symbol(shoe.coff, sym_name); free(sym_name); if (symb == NULL) { printf("Couldn't find \"%s\"\n", sym_name); return ; } printf("%s = *0x%08x\n", symb->name, symb->value); } struct verb_handler_table_t { const char *name; void (*func)(const char *); } verb_handler_table[] = { {"quit", verb_quit_handler}, {"help", verb_help_handler}, {"registers", verb_registers_handler}, {"continue", verb_continue_handler}, {"stepi", verb_stepi_handler}, {"backtrace", verb_backtrace_handler}, {"bt", verb_backtrace_handler}, {"break", verb_break_handler}, {"delete", verb_delete_handler}, {"lookup", verb_lookup_handler}, {"trace", verb_trace_toggle_handler}, {"x", verb_examine_handler} }; void execute_verb (const char *line) { char verb[128]; uint32_t max_len=0, max_i=0; const char *remainder; uint32_t i, matches = 0, match_i; if (sscanf(line, "%127s", verb) != 1) return ; // Skip past the verb for (remainder = line; *remainder && !isspace(*remainder); remainder++) ; // Skip past the space between the verb and the arguments for (; *remainder && isspace(*remainder); remainder++) ; const uint32_t verb_len = strlen(verb); for (i=0; i < (sizeof(verb_handler_table) / sizeof(struct verb_handler_table_t)); i++) { const uint32_t i_len = strlen(verb_handler_table[i].name); // If it's a perfect match, if (strcasecmp(verb, verb_handler_table[i].name)==0) { verb_handler_table[i].func(remainder); return ; } // Otherwise, see if it's a partial match if ((i_len >= verb_len) && strncasecmp(verb, verb_handler_table[i].name, verb_len)==0) { matches++; match_i = i; } } // Only execute the verb if it's an unambiguous match (matches == 1) if (matches == 1) { verb_handler_table[match_i].func(remainder); return ; } printf(" %s?\n", verb); } void *ui_thread (void *arg) { EditLine *el; History *hist; HistEvent histev; const char *buf; int num; hist = history_init(); history(hist, &histev, H_SETSIZE, 10000); // Remember 10000 previous user inputs el = el_init("Shoebill", stdin, stdout, stderr); dbg_state.el = el; el_set(el, EL_SIGNAL, 0); el_set(el, EL_PROMPT, cli_prompt_callback); el_set(el, EL_EDITOR, "emacs"); el_set(el, EL_HIST, history, hist); (void) signal(SIGINT, signal_callback); (void) signal(SIGWINCH, signal_callback); while ((buf = el_gets(el, &num)) != NULL) { if (strcmp(buf, "\n")!=0) { execute_verb(buf); history(hist, &histev, H_ENTER, buf); } } el_end(el); history_end(hist); return NULL; } uint8_t *loadrom (char *path, uint32_t *len) { FILE *f = fopen(path, "r"); uint8_t *buf = calloc(1024, 1024); uint32_t i, sz, expected, checksum; if (!f) { printf("Couldn't open %s\n", path); return NULL; } for (sz=0; sz < (1024*1024); sz += (64*1024)) { printf("sz = %u\n", sz); if (fread(buf + sz, 64*1024, 1, f) != 1) { break; } } printf("sz = %u (done)\n", sz); fclose(f); if (sz == 0) { printf("loadrom: empty rom file\n"); free(buf); return NULL; } for (i=0, expected=0; i<4; i++) expected = (expected << 8) + buf[i]; for (i=4, checksum=0; i < sz; i+=2) { uint16_t word = (buf[i]<<8) + buf[i+1]; checksum += word; } if (checksum != expected) { printf("Bad checksum (computed %08x, expected %08x)\n", checksum, expected); free(buf); return NULL; } *len = sz; return buf; } struct __attribute__ ((__packed__)) kernel_info { // Auto data uint32_t auto_magic; uint32_t auto_id[16]; uint32_t auto_version[16]; uint32_t auto_command; uint16_t root_ctrl; uint8_t root_drive; uint8_t root_cluster; struct __attribute__ ((__packed__)) sect_info { uint32_t vstart; uint32_t pstart; uint32_t size; } si[3]; uint16_t machine_type; // Gestalt, I think? The "machine_type" for a quadra 950 doesn't match its gestalt, though. uint32_t drive_queue_offset; uint16_t ki_flags; uint8_t ki_version; // always 1 uint8_t root_partition; uint16_t swap_ctrl; uint8_t swap_drive; uint8_t swap_partition; }; void init_kernel_info() { struct kernel_info ki, *p; uint32_t i; p = (struct kernel_info*)0x00003c00; shoe.d[0] = 0x536d7201; shoe.a[0] = (uint32_t)p; /* ----- Setup kernel info structure ----- */ ki.auto_magic = 0x50696773; // 'Pigs' (Pigs in space?) for (i=0; i<16; i++) { ki.auto_id[i] = 0x0000ffff; ki.auto_version[i] = 0; } ki.auto_id[0xa] = 0x50; // Macintosh II video card has an auto_id of 5 (I guess?) ki.auto_id[0xb] = 0x5; // Macintosh II video card has an auto_id of 5 (I guess?) ki.auto_command = 0; // AUTO_RUN ki.root_ctrl = 0; ki.root_drive = 0; ki.root_cluster = 0; for (i = 0; i < shoe.coff->num_sections; i++) { coff_section *s = &shoe.coff->sections[i]; uint8_t sect; if (strcmp(s->name, ".text") == 0) sect = 0; else if (strcmp(s->name, ".data") == 0) sect = 1; else if (strcmp(s->name, ".bss") == 0) sect = 2; else continue; ki.si[sect].vstart = s->v_addr; ki.si[sect].pstart = s->p_addr; ki.si[sect].size = s->sz; } ki.machine_type = 4; // Macintosh II? // +4 because the DrvQEl structure has a hidden "flags" field 4 bytes below the pointer ki.drive_queue_offset = sizeof(struct kernel_info) + 4; ki.ki_flags = 1; // KI_VERBOSE ki.ki_version = 1; ki.root_partition = 0; ki.swap_ctrl = 0; ki.swap_drive = 0; ki.swap_partition = 1; /* ----- Copy ki into memory ----- */ #define ki_pset(_f, _s) {pset((uint32_t)&p->_f, _s, ki._f); printf("Setting 0x%08x to %x\n", (uint32_t)&p->_f, ki._f);} ki_pset(auto_magic, 4); for (i=0; i<16; i++) { ki_pset(auto_id[i], 4); ki_pset(auto_version[i], 4); } ki_pset(auto_command, 4); ki_pset(root_ctrl, 2); ki_pset(root_drive, 1); ki_pset(root_cluster, 1); for (i=0; i<3; i++) { ki_pset(si[i].vstart, 4); ki_pset(si[i].pstart, 4); ki_pset(si[i].size, 4); } ki_pset(machine_type, 2); ki_pset(drive_queue_offset, 4); ki_pset(ki_flags, 2); ki_pset(ki_version, 1); ki_pset(root_partition, 1); ki_pset(swap_ctrl, 2); ki_pset(swap_drive, 1); ki_pset(swap_partition, 1); // Fake drive queue /*uint8_t dummy[0x14*2] = { // 00 08 01 00 00 00 00 14 00 01 00 08 FF D9 00 00 CE AD 00 2C 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x08, 0xFF, 0xD9, 0x00, 0x00, 0x0f, 0x71, 0x00, 0x01, 0x00, 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0xFF, 0xDF, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00 };*/ uint8_t dummy[0x14*2] = { // 00 08 01 00 00 00 00 14 00 01 00 08 FF D9 00 00 CE AD 00 2C 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x01, 0x00, 0x08, 0xFF, 0xD9, 0x00, 0x00, 0, 0, 0, 0, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x09, 0xFF, 0xDF, 0x00, 0x00, 0, 0, 0, 0 }; for (i=0; i<(0x14*2); i++) pset(((uint32_t)p) + sizeof(struct kernel_info) + i, 1, dummy[i]); // FIXME: *really* implement drive queue } void init_macintosh_globals() { uint8_t buf[0x1000]; memset(buf, 0xBB, 0x1000); uint32_t i; for (i=0; i<0x1000; i++) pset(i, 1, buf[i]); #define hwCbSCSI (1<<15) #define hwCbClock (1<<14) #define hwCbExPRAM (1<<13) #define hwCbFPU (1<<12) #define hwCbMMU (1<<11) #define hwCbADB (1<<10) #define hwCbAUX (1<<9) // uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB | hwCbAUX; uint16_t HWCfgFlags = hwCbSCSI | hwCbClock | hwCbFPU | hwCbMMU | hwCbADB; pset(0xb22, 2, HWCfgFlags); // HWCfgFlags pset(0x12f, 1, 0x02); // CPUFlag = 0x02 (MC68020) pset(0x31a, 4, 0x00ffffff); // Lo3Bytes (always 0x00ffffff) pset(0x28e, 2, 0x3fff); // ROM85 (always 0x3fff, I think?) pset(0xdd8, 4, 0); // universal info ptr. is allowed to be null on Mac II, (I THINK) pset(0x1d4, 4, 0x50000000); // VIA (via1 ptr) pset(0x1d8, 4, 0x50004000); // SCC /*pset(0x8ce, 1, 1); // CrsrNew (set to 1?) pset(0x8cd, 1, 0); // CrsrBusy (0 -> Not presently busy) pset(0x8d0, 2, 0); // CrsrState pset(0x8cf, 1, 0xff); // CrsrCouple ?? pset(0x8d6, 4, 0xffffffff); // MouseMask pset(0x8da, 4, 0); // MouseOffset pset(0x8d3, 1, 6); // CrsrScale */ // 21e -> KbdType // dd8 -> UnivInfoPtr // d00 -> TimeDBRA // d02 -> TimeSCCDB // FIXME: add 0x21e, 0xdd8, 0x28e, 0xd00, 0xd02 // Do this after setting lomem mac stuff, because this structure is more important. init_kernel_info(); } uint32_t init_state (coff_file *coff, uint8_t *rom, uint32_t romsize) { uint32_t i, j, pc = 0xffffffff; fpu_setup_jump_table(); shoe.coff = coff; shoe.launch = coff_parser("priv/launch"); shoe.physical_mem_size = 32 * 1024 * 1024; shoe.physical_rom_size = romsize; shoe.physical_mem_base = valloc(shoe.physical_mem_size); shoe.physical_rom_base = valloc(romsize); memset(shoe.physical_mem_base, 0, shoe.physical_mem_size); memcpy(shoe.physical_rom_base, rom, romsize); for (i=0; i<16; i++) { shoe.slots[i].slotnum = i; shoe.slots[i].connected = 0; shoe.slots[i].glut_window_id = -1; } // Install TFB at slot B /*{ shoe.slots[0xb].connected = 1; shoe.slots[0xb].read_func = nubus_tfb_read_func; shoe.slots[0xb].write_func = nubus_tfb_write_func; nubus_tfb_init(0xb); }*/ { shoe.slots[0xa].connected = 1; shoe.slots[0xa].read_func = nubus_video_read_func; shoe.slots[0xa].write_func = nubus_video_write_func; // nubus_video_init(0xa, 1440, 900); nubus_video_init(0xa, 800, 600); } // Initialize relevant Mac globals // (Do this before copying COFF segments, in case they overwrite these globals) init_macintosh_globals(); /* Copy COFF segments into memory */ for (i = 0; i < coff->num_sections; i++) { coff_section *s = &coff->sections[i]; // Don't load a "copy" segment if (s->flags & coff_copy) continue; if ((s->flags & coff_text) || (s->flags & coff_data)) { /* copy text or data section */ for (j = 0; j < s->sz; j++) pset(s->p_addr+j, 1, s->data[j]); if (strcmp(s->name, "pstart") == 0) pc = s->p_addr; } else if (s->flags & coff_bss) { /* Create an empty .bss segment */ for (j = 0; j < s->sz; j++) pset(s->p_addr+j, 1, 0); } } if (pc == 0xffffffff) { printf("init_state: this unix doesn't contain a pstart segment\n"); return 0; } set_sr(0x2000); shoe.pc = pc; // Start the VIA clocks gettimeofday(&shoe.start_time, NULL); shoe.total_ticks = 0; // Put the adb chip in state 3 (idle) shoe.adb.state = 3; pthread_mutex_init(&shoe.adb.lock, NULL); for (i=0; i<8; i++) { shoe.scsi_devices[i].scsi_id = i; shoe.scsi_devices[i].block_size = 0; shoe.scsi_devices[i].num_blocks = 0; shoe.scsi_devices[i].image_path = "dummy"; shoe.scsi_devices[i].f = NULL; } // Hacky load scsi disk at id 0 /*shoe.scsi_devices[0].scsi_id = 0; shoe.scsi_devices[0].block_size = 512; shoe.scsi_devices[0].num_blocks = 656544; shoe.scsi_devices[0].image_path = "priv/Apple_UNIX_3.iso"; shoe.scsi_devices[0].f = fopen(shoe.scsi_devices[0].image_path, "r+"); assert(shoe.scsi_devices[0].f);*/ shoe.scsi_devices[0].scsi_id = 0; shoe.scsi_devices[0].block_size = 512; shoe.scsi_devices[0].num_blocks = 195912; //205561; shoe.scsi_devices[0].image_path = "priv/aux2.img"; shoe.scsi_devices[0].f = fopen(shoe.scsi_devices[0].image_path, "r+"); assert(shoe.scsi_devices[0].f); shoe.scsi_devices[1].scsi_id = 1; shoe.scsi_devices[1].block_size = 512; shoe.scsi_devices[1].num_blocks = 1048576; shoe.scsi_devices[1].image_path = "priv/blank.img"; shoe.scsi_devices[1].f = fopen(shoe.scsi_devices[1].image_path, "r+"); assert(shoe.scsi_devices[1].f); /*shoe.scsi_devices[6].scsi_id = 6; shoe.scsi_devices[6].block_size = 512; shoe.scsi_devices[6].num_blocks = 1280032; //205561; shoe.scsi_devices[6].image_path = "priv/macii_fs.img"; shoe.scsi_devices[6].f = fopen(shoe.scsi_devices[6].image_path, "r+"); assert(shoe.scsi_devices[6].f);*/ /* In the future, we'll need to setup that booter struct for A/UX. */ // HACK HACK HACK // Not sure why, but it seems that on non-RBV systems, A/UX version >= 1.1.1 does memcpy(0x0, 0x50000, 0x4000), blowing away all the lomem stuff // So copy lomem stuff to 0x50000 for (i=0; i<0x4000; i++) { uint8_t c = pget(i, 1); pset(0x50000 + i, 1, c); } shoe.a[0] += 0x50000; // A/UX thinks kernel_info should live at 0x50000 + (normal kernel_info addr). return 1; } #define KEY_SHIFT 1 const struct { uint8_t code; char c; uint8_t modifiers; } key_codes[] = { {0x0, 'A', 0}, {0x1, 'S', 0}, {2, 'D', 0}, {3, 'F', 0}, {4, 'H', 0}, {5, 'G', 0}, {6, 'Z', 0}, {7, 'X', 0}, {8, 'C', 0}, {9, 'V', 0}, // {0xa ?? {0xb, 'B', 0}, {0xc, 'Q', 0}, {0xd, 'W', 0}, {0xe, 'E', 0}, {0xf, 'R', 0}, {0x10, 'Y', 0}, {0x11, 'T', 0}, {0x12, '1', 0}, {0x12, '!', KEY_SHIFT}, {0x13, '2', 0}, {0x13, '@', KEY_SHIFT}, {0x14, '3', 0}, {0x14, '#', KEY_SHIFT}, {0x15, '4', 0}, {0x15, '$', KEY_SHIFT}, {0x16, '6', 0}, {0x16, '^', KEY_SHIFT}, {0x17, '5', 0}, {0x17, '%', KEY_SHIFT}, {0x18, '=', 0}, {0x18, '+', KEY_SHIFT}, {0x19, '9', 0}, {0x19, '(', KEY_SHIFT}, {0x1a, '7', 0}, {0x1a, '&', KEY_SHIFT}, {0x1b, '-', 0}, {0x1b, '_', KEY_SHIFT}, {0x1c, '8', 0}, {0x1c, '*', KEY_SHIFT}, {0x1d, '0', 0}, {0x1d, ')', KEY_SHIFT}, {0x1e, ']', 0}, {0x1e, '}', KEY_SHIFT}, {0x1f, 'O', 0}, {0x20, 'U', 0}, {0x21, '[', 0}, {0x21, '{', KEY_SHIFT}, {0x22, 'I', 0}, {0x23, 'P', 0}, {0x24, '\n', 0}, {0x24, '\r', 0}, {0x25, 'L', 0}, {0x26, 'J', 0}, {0x27, '"', KEY_SHIFT}, {0x27, '\'', 0}, {0x28, 'K', 0}, {0x29, ';', 0}, {0x29, ':', KEY_SHIFT}, {0x2a, '\\', 0}, {0x2a, '|', KEY_SHIFT}, {0x2b, ',', 0}, {0x2b, '<', KEY_SHIFT}, {0x2c, '/', 0}, {0x2c, '?', 0}, {0x2d, 'N', 0}, {0x2e, 'M', 0}, {0x2f, '.', 0}, {0x2f, '>', KEY_SHIFT}, {0x30, '\t', 0}, {0x31, ' ', 0}, {0x32, '`', 0}, {0x32, '~', KEY_SHIFT}, {0x33, '\b', 0}, {0x33, 0x7f, 0}, // {0x34, ?? // {0x35 // escape char // 0x36 // ctrl // 0x37 // command // 0x38 // shift // 0x39 // caps lock // 0x3a // option // 0x3b // left arrow // 0x3c // right arrow // 0x3d // down arrow // 0x3e // up arrow {0, 0, 0}, }; static uint8_t lookup_key(char c) { uint32_t i; uint8_t upper=toupper(c); for (i=0; key_codes[i].c; i++) { if (key_codes[i].c == upper) return key_codes[i].code; } return 0xff; } static uint8_t lookup_special(int special) { switch (special) { case GLUT_KEY_UP: return 0x3e; case GLUT_KEY_DOWN: return 0x3d; case GLUT_KEY_LEFT: return 0x3b; case GLUT_KEY_RIGHT: return 0x3c; default: return 0xff; } } static void keyboard_add_entry(uint8_t code, uint8_t up) { uint8_t up_mask = up ? 0x80 : 0; uint32_t i; int modifiers = glutGetModifiers(); assert(pthread_mutex_lock(&shoe.adb.lock) == 0); if ((shoe.key.key_i+1) < KEYBOARD_STATE_MAX_KEYS) { if (modifiers & GLUT_ACTIVE_SHIFT) { shoe.key.keys[shoe.key.key_i].code_a = 0x38; shoe.key.keys[shoe.key.key_i].code_b = 0xff; shoe.key.key_i++; } else if (shoe.key.down_modifiers & GLUT_ACTIVE_SHIFT) { shoe.key.keys[shoe.key.key_i].code_a = 0x80 | 0x38; shoe.key.keys[shoe.key.key_i].code_b = 0xff; shoe.key.key_i++; } shoe.key.keys[shoe.key.key_i].code_a = code | up_mask; shoe.key.keys[shoe.key.key_i].code_b = 0xff; shoe.key.key_i++; } shoe.key.down_modifiers = modifiers; adb_request_service_request(2); pthread_mutex_unlock(&shoe.adb.lock); } void global_mouse_func (int button, int state, int x, int y) { //if (button != GLUT_LEFT_BUTTON) // return ; assert(pthread_mutex_lock(&shoe.adb.lock) == 0); shoe.mouse.button_down = (state == GLUT_DOWN); shoe.mouse.changed = 1; adb_request_service_request(3); pthread_mutex_unlock(&shoe.adb.lock); // printf("mouse_func: setting service request\n"); } static void move_mouse (int x, int y, uint8_t button_down) { printf("%s: lock\n", __func__); fflush(stdout); assert(pthread_mutex_lock(&shoe.adb.lock) == 0); int32_t delta_x = x - shoe.mouse.old_x; int32_t delta_y = y - shoe.mouse.old_y; shoe.mouse.old_x = x; shoe.mouse.old_y = y; shoe.mouse.delta_x += delta_x; shoe.mouse.delta_y += delta_y; shoe.mouse.button_down = button_down; shoe.mouse.changed = 1; adb_request_service_request(3); printf("%s: unlock\n", __func__); fflush(stdout); pthread_mutex_unlock(&shoe.adb.lock); // printf("move_mouse: setting service request\n"); } void global_motion_func (int x, int y) { move_mouse(x, y, 1); } void global_passive_motion_func (int x, int y) { move_mouse(x, y, 0); } void global_keyboard_up_func (unsigned char c, int x, int y) { uint8_t code = lookup_key(c); if (code != 0xff) keyboard_add_entry(code, 1); } void global_keyboard_down_func (unsigned char c, int x, int y) { uint8_t code = lookup_key(c); if (code != 0xff) keyboard_add_entry(code, 0); } void global_special_up_func (int special, int x, int y) { const uint8_t code = lookup_special(special); if (code != 0xff) keyboard_add_entry(code, 1); } void global_special_down_func (int special, int x, int y) { const uint8_t code = lookup_special(special); if (code != 0xff) keyboard_add_entry(code, 0); } void timer_func (int arg) { glutTimerFunc(15, timer_func, 0); // 66.67hz is the usual refresh interval (right?) uint32_t slotnum; for (slotnum = 0; slotnum < 16; slotnum++) { if (shoe.slots[slotnum].glut_window_id == -1) continue; glutSetWindow(shoe.slots[slotnum].glut_window_id); glutPostRedisplay(); } } //void _macii_load_video_rom(const char *path); int main (int argc, char **argv) { coff_file *coff; uint32_t romsize; uint8_t *rom; pthread_t pid; //_macii_load_video_rom("tfb_rom"); rom = loadrom("priv/macii.rom", &romsize); if (rom == NULL) return 0; //printf(") /*if (romsize != (256 * 1024)) { printf("Bogus rom size (%u bytes)\n", romsize); return 0; }*/ coff = coff_parser("priv/unix"); if (coff == NULL) { printf("main: coff_parser() failed to load \"unix\"\n"); return 0; } int dummyargc = 1; glutInit(&dummyargc, argv); if (!init_state(coff, rom, romsize)) return 0; free(rom); pthread_create(&pid, NULL, ui_thread, NULL); glutTimerFunc(15, timer_func, 0); glutMainLoop(); while (1) sleep(1); return 0; }