void trap_put_bytes(TrapContext *ctx, const void *haddrp, uaecptr addr, int cnt) { if (cnt <= 0) return; uae_u8 *haddr = (uae_u8*)haddrp; if (trap_is_indirect_null(ctx)) { while (cnt > 0) { int max = cnt > RTAREA_TRAP_DATA_EXTRA_SIZE ? RTAREA_TRAP_DATA_EXTRA_SIZE : cnt; memcpy(ctx->host_trap_data + RTAREA_TRAP_DATA_EXTRA, haddr, max); call_hardware_trap_back(ctx, TRAPCMD_PUT_BYTES, ctx->amiga_trap_data + RTAREA_TRAP_DATA_EXTRA, addr, max, 0); haddr += max; addr += max; cnt -= max; } } else { if (real_address_allowed() && valid_address(addr, cnt)) { memcpy(get_real_address(addr), haddr, cnt); } else { for (int i = 0; i < cnt; i++) { put_byte(addr, *haddr++); addr++; } } } }
static void uade_put_long(int addr, int val) { uae_u32 *p; if (!valid_address(addr, 4)) { fprintf(stderr, "uadecore: Invalid uade_put_long (0x%x).\n", addr); return; } p = (uae_u32 *) get_real_address(addr); *p = htonl(val); }
/* check if string is on a safe zone */ static int uade_valid_string(uae_u32 address) { while (valid_address(address, 1)) { if (* ((uae_u8 *) get_real_address(address)) == 0) return 1; address++; } fprintf(stderr, "uadecore: Invalid string at 0x%x.\n", address); return 0; }
static int uade_get_u32(int addr) { uae_u32 *ptr; int x; if (!valid_address(addr, 4)) { fprintf(stderr, "uadecore: Invalid uade_get_u32 (0x%x).\n", addr); return 0; } ptr = (uae_u32 *) get_real_address(addr); return ntohl(*ptr); }
bool UAECALL uae_ppc_io_mem_write(uint32_t addr, uint32_t data, int size) { bool locked = false; while (ppc_thread_running && ppc_cpu_lock_state < 0 && ppc_state); #if PPC_ACCESS_LOG > 0 && PPC_ACCESS_LOG < 2 if (!valid_address(addr, size)) { if (addr >= PPC_DEBUG_ADDR_FROM && addr < PPC_DEBUG_ADDR_TO) write_log(_T("PPC io write %08x = %08x %d\n"), addr, data, size); } #endif locked = spinlock_pre(addr); switch (size) { case 4: put_long(addr, data); break; case 2: put_word(addr, data); break; case 1: put_byte(addr, data); break; } if (addr >= 0xdff000 && addr < 0xe00000) { int reg = addr & 0x1fe; switch (reg) { case 0x09c: // INTREQ case 0x09a: // INTENA if (data & 0x8000) { // possible interrupt change: // make sure M68K thread reacts to it ASAP. uae_int_requested |= 0x010000; } break; } } spinlock_post(locked); #if PPC_ACCESS_LOG >= 2 write_log(_T("PPC write %08x = %08x %d\n"), addr, data, size); #endif return true; }
/* Return a pt_regs pointer for a valid signal handler frame */ static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt) { BacktraceIterator *b = &kbt->it; if (b->pc == VDSO_BASE) { struct rt_sigframe *frame; unsigned long sigframe_top = b->sp + sizeof(struct rt_sigframe) - 1; if (!valid_address(kbt, b->sp) || !valid_address(kbt, sigframe_top)) { if (kbt->verbose) pr_err(" (odd signal: sp %#lx?)\n", (unsigned long)(b->sp)); return NULL; } frame = (struct rt_sigframe *)b->sp; if (kbt->verbose) { pr_err(" <received signal %d>\n", frame->info.si_signo); } return (struct pt_regs *)&frame->uc.uc_mcontext; } return NULL; }
bool UAECALL uae_ppc_io_mem_read(uint32_t addr, uint32_t *data, int size) { uint32_t v; bool locked = false; while (ppc_thread_running && ppc_cpu_lock_state < 0 && ppc_state); if (addr >= 0xdff000 && addr < 0xe00000) { int reg = addr & 0x1fe; // shortcuts for common registers switch (reg) { case 0x01c: // INTENAR *data = intena; return true; case 0x01e: // INTREQR *data = intreq; return true; } } locked = spinlock_pre(addr); switch (size) { case 4: v = get_long(addr); break; case 2: v = get_word(addr); break; case 1: v = get_byte(addr); break; } *data = v; spinlock_post(locked); #if PPC_ACCESS_LOG > 0 && PPC_ACCESS_LOG < 2 if (!valid_address(addr, size)) { if (addr >= PPC_DEBUG_ADDR_FROM && addr < PPC_DEBUG_ADDR_TO && addr != 0xdff006) write_log(_T("PPC io read %08x=%08x %d\n"), addr, v, size); } #endif #if PPC_ACCESS_LOG >= 2 if (addr < 0xb00000 || addr > 0xc00000) write_log(_T("PPC read %08x=%08x %d\n"), addr, v, size); #endif return true; }
/* Callback for backtracer; basically a glorified memcpy */ static bool read_memory_func(void *result, unsigned long address, unsigned int size, void *vkbt) { int retval; struct KBacktraceIterator *kbt = (struct KBacktraceIterator *)vkbt; if (__kernel_text_address(address)) { /* OK to read kernel code. */ } else if (address >= PAGE_OFFSET) { /* We only tolerate kernel-space reads of this task's stack */ if (!in_kernel_stack(kbt, address)) return 0; } else if (!valid_address(kbt, address)) { return 0; /* invalid user-space address */ } pagefault_disable(); retval = __copy_from_user_inatomic(result, (void __user __force *)address, size); pagefault_enable(); return (retval == 0); }
static int uade_safe_load(int dst, FILE *file, int maxlen) { #define UADE_SAFE_BUFSIZE 4096 char buf[UADE_SAFE_BUFSIZE]; int nbytes, len, off; len = UADE_SAFE_BUFSIZE; off = 0; if (maxlen <= 0) return 0; while (maxlen > 0) { if (maxlen < UADE_SAFE_BUFSIZE) len = maxlen; nbytes = fread(buf, 1, len, file); if (!nbytes) break; if (!valid_address(dst + off, nbytes)) { fprintf(stderr, "uadecore: Invalid load range [%x,%x).\n", dst + off, dst + off + nbytes); break; } memcpy(get_real_address(dst + off), buf, nbytes); off += nbytes; maxlen -= nbytes; } /* find out how much would have been read even if maxlen was violated */ while ((nbytes = fread(buf, 1, UADE_SAFE_BUFSIZE, file))) off += nbytes; return off; }
static void uade_safe_get_string(char *dst, int src, int maxlen) { int i = 0; while (1) { if (i >= maxlen) break; if (!valid_address(src + i, 1)) { fprintf(stderr, "uadecore: Invalid memory range in safe_get_string.\n"); break; } dst[i] = * (char *) get_real_address(src + i); i++; } if (maxlen > 0) { if (i < maxlen) { dst[i] = 0; } else { fprintf(stderr, "uadecore: Warning: string truncated.\n"); dst[maxlen - 1] = 0; } } }
// // Process a set of S-records, loading the contents into memory. // Note: if a "base" value is provided, the data will be relocated // relative to that location. Of course, this can only work for // the first section of the data, so if there are non-contiguous // pieces of data, they will end up relocated in the same fashion. // Because of this, "base" probably only makes sense for a set of // data which has only one section, e.g. a ROM image. // static unsigned long load_srec_image(getc_t getc, unsigned long base) { int c; long offset = 0, count, sum, val, cksum; unsigned char *addr, *base_addr; char type; bool first_addr = true; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; while ((c = (*getc)()) > 0) { // Start of line if (c != 'S') { redboot_getc_terminate(true); err_printf("Invalid S-record at offset %p, input: %c\n", (void *)offset, c); return 0; } type = (*getc)(); offset += 2; sum = 0; if ((count = _hex2(getc, 1, &sum)) < 0) { redboot_getc_terminate(true); err_printf("Bad S-record count at offset %p\n", (void *)offset); return 0; } offset += 1; switch (type) { case '0': break; case '1': case '2': case '3': base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum); offset += (type-'1'+2); if (first_addr) { if (base) { addr_offset = (unsigned long)base - (unsigned long)addr; } else { addr_offset = 0; } first_addr = false; } addr += addr_offset; if ((unsigned long)(addr-addr_offset) < lowest_address) { lowest_address = (unsigned long)(addr - addr_offset); } #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!(valid_address(addr) #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH || (flash_verify_addr(addr) == FLASH_ERR_OK) #endif )) { // Only if there is no need to stop the download before printing // output can we ask confirmation questions. redboot_getc_terminate(true); err_printf("*** Abort! Attempt to load S-record to address: %p, which is not valid\n",(void*)addr); return 0; } #endif count -= ((type-'1'+2)+1); offset += count; while (count-- > 0) { val = _hex2(getc, 1, &sum); if (valid_address(addr)) { *addr++ = val; } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH else { flash_load_write(addr, val); addr++; } #endif } cksum = _hex2(getc, 1, 0); offset += 1; sum = sum & 0xFF; cksum = (~cksum & 0xFF); if (cksum != sum) { redboot_getc_terminate(true); err_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", (unsigned long)base_addr, sum, cksum); return 0; } if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } break; case '7': case '8': case '9': addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum); offset += ('9'-type+2); // Save load base/top, entry address if (base) { load_address = base; load_address_end = base + (highest_address - lowest_address); entry_address = (unsigned long)(base + (addr - lowest_address)); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = (unsigned long)addr; } redboot_getc_terminate(false); if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset); diag_printf("Entry point: %p, address range: %p-%p\n", (void*)entry_address, (void *)load_address, (void *)load_address_end); return load_address_end; default: redboot_getc_terminate(true); err_printf("Invalid S-record at offset 0x%lx, type: %x\n", (unsigned long)offset, type); return 0; } while ((c = (*getc)()) != '\n') offset++; } return 0; }
// // Load an ELF [binary] image // static unsigned long load_elf_image(getc_t getc, unsigned long base) { #ifdef CYGSEM_REDBOOT_ELF Elf32_Ehdr ehdr; #define MAX_PHDR 8 Elf32_Phdr phdr[MAX_PHDR]; unsigned long offset = 0; int phx, len, ch; unsigned char *addr; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; unsigned char *SHORT_DATA = "Short data reading ELF file\n"; // Read the header if (_read(getc, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) { err_printf("Can't read ELF header\n"); redboot_getc_terminate(true); return 0; } offset += sizeof(ehdr); #if 0 // DEBUG diag_printf("Type: %d, Machine: %d, Version: %d, Entry: %p, PHoff: %p/%d/%d, SHoff: %p/%d/%d\n", ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry, ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum); #endif if (ehdr.e_type != ET_EXEC) { err_printf("Only absolute ELF images supported\n"); redboot_getc_terminate(true); return 0; } if (ehdr.e_phnum > MAX_PHDR) { err_printf("Too many program headers\n"); redboot_getc_terminate(true); return 0; } while (offset < ehdr.e_phoff) { if ((*getc)() < 0) { err_printf(SHORT_DATA); redboot_getc_terminate(true); return 0; } offset++; } for (phx = 0; phx < ehdr.e_phnum; phx++) { if (_read(getc, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) { err_printf("Can't read ELF program header\n"); redboot_getc_terminate(true); return 0; } #if 0 // DEBUG diag_printf("Program header: type: %d, off: %p, va: %p, pa: %p, len: %d/%d, flags: %d\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags); #endif offset += sizeof(phdr[0]); } if (base) { // Set address offset based on lowest address in file. addr_offset = 0xFFFFFFFF; for (phx = 0; phx < ehdr.e_phnum; phx++) { #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) { addr_offset = phdr[phx].p_vaddr; #else if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) { addr_offset = phdr[phx].p_paddr; #endif } } addr_offset = (unsigned long)base - addr_offset; } else { addr_offset = 0; } for (phx = 0; phx < ehdr.e_phnum; phx++) { if (phdr[phx].p_type == PT_LOAD) { // Loadable segment #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS addr = (unsigned char *)phdr[phx].p_vaddr; #else addr = (unsigned char *)phdr[phx].p_paddr; #endif len = phdr[phx].p_filesz; if ((unsigned long)addr < lowest_address) { lowest_address = (unsigned long)addr; } addr += addr_offset; if (offset > phdr[phx].p_offset) { if ((phdr[phx].p_offset + len) < offset) { err_printf("Can't load ELF file - program headers out of order\n"); redboot_getc_terminate(true); return 0; } addr += offset - phdr[phx].p_offset; } else { while (offset < phdr[phx].p_offset) { if ((*getc)() < 0) { err_printf(SHORT_DATA); redboot_getc_terminate(true); return 0; } offset++; } } // Copy data into memory while (len-- > 0) { #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!(valid_address(addr) #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH || (flash_verify_addr(addr) == FLASH_ERR_OK) #endif )) { redboot_getc_terminate(true); err_printf("*** Abort! Attempt to load ELF data to address: %p which is not valid\n", (void*)addr); return 0; } #endif if ((ch = (*getc)()) < 0) { err_printf(SHORT_DATA); redboot_getc_terminate(true); return 0; } if (valid_address(addr)) { *addr++ = ch; } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH else { flash_load_write(addr, ch); addr++; } #endif offset++; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } } } // Save load base/top and entry if (base) { load_address = base; load_address_end = base + (highest_address - lowest_address); entry_address = base + (ehdr.e_entry - lowest_address); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = ehdr.e_entry; } // nak everything to stop the transfer, since redboot // usually doesn't read all the way to the end of the // elf files. redboot_getc_terminate(true); if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset); diag_printf("Entry point: %p, address range: %p-%p\n", (void*)entry_address, (void *)load_address, (void *)load_address_end); return 1; #else // CYGSEM_REDBOOT_ELF err_printf("Loading ELF images not supported\n"); return 0; #endif // CYGSEM_REDBOOT_ELF }
// // Process a set of S-records, loading the contents into memory. // Note: if a "base" value is provided, the data will be relocated // relative to that location. Of course, this can only work for // the first section of the data, so if there are non-contiguous // pieces of data, they will end up relocated in the same fashion. // Because of this, "base" probably only makes sense for a set of // data which has only one section, e.g. a ROM image. // // Note that in case of multicore and the core we wanna load the // image for is not in the same endianness that the core we run // redboot from, have to invert bytes on 16-bit boundary // (16-bit memory) // static unsigned long load_srec_image(getc_t getc, unsigned long base, bool swap16bit) { int c; long offset = 0, count, sum, val, cksum; unsigned char *addr, *base_addr, *addr_swap; char type; bool first_addr = true; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; while ((c = (*getc)()) > 0) { // Start of line if (c != 'S') { redboot_getc_terminate(true); diag_printf("Invalid S-record at offset %p, input: %c\n", (void *)offset, c); return 0; } type = (*getc)(); offset += 2; sum = 0; if ((count = _hex2(getc, 1, &sum)) < 0) { redboot_getc_terminate(true); diag_printf("Bad S-record count at offset %p\n", (void *)offset); return 0; } offset += 1; switch (type) { case '0': break; case '1': case '2': case '3': base_addr = addr = (unsigned char *)_hex2(getc, (type-'1'+2), &sum); offset += (type-'1'+2); if (first_addr) { if (base) { addr_offset = (unsigned long)base - (unsigned long)addr; } else { addr_offset = 0; } first_addr = false; } addr += addr_offset; if ((unsigned long)(addr-addr_offset) < lowest_address) { lowest_address = (unsigned long)(addr - addr_offset); } #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!valid_address(addr)) { // Only if there is no need to stop the download before printing // output can we ask confirmation questions. redboot_getc_terminate(true); diag_printf("*** Abort! Attempt to load S-record to address: %p, which is not in RAM\n",(void*)addr); return 0; } #endif count -= ((type-'1'+2)+1); offset += count; while (count-- > 0) { val = _hex2(getc, 1, &sum); /* In case of multicore and the core we wanna load the image for is not in the same endianness that the core we run redboot from, have to invert bytes on 16-bit boundary (16-bit memory)*/ if(swap16bit){ // addr is even, have to write char data to the last address if(((unsigned long)addr)%2){ addr_swap=addr-1; *addr_swap = val; } // addr is odd, have to write char data to the next address else{ addr_swap=addr+1; *addr_swap = val; } addr++; } else { *addr++ = val; } } cksum = _hex2(getc, 1, 0); offset += 1; sum = sum & 0xFF; cksum = (~cksum & 0xFF); if (cksum != sum) { redboot_getc_terminate(true); diag_printf("*** Warning! Checksum failure - Addr: %lx, %02lX <> %02lX\n", (unsigned long)base_addr, sum, cksum); return 0; } if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } break; case '7': case '8': case '9': addr = (unsigned char *)_hex2(getc, ('9'-type+2), &sum); offset += ('9'-type+2); // Save load base/top, entry address if (base) { load_address = base; load_address_end = base + (highest_address - lowest_address); entry_address = (unsigned long)(base + (addr - lowest_address)); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = (unsigned long)addr; } redboot_getc_terminate(false); if (addr_offset) diag_printf("Address offset = %p\n", (void *)addr_offset); diag_printf("Entry point: %p, address range: %p-%p\n", (void*)entry_address, (void *)load_address, (void *)load_address_end); return load_address_end; default: redboot_getc_terminate(true); diag_printf("Invalid S-record at offset 0x%lx, type: %x\n", (unsigned long)offset, type); return 0; } while ((c = (*getc)()) != '\n') offset++; } return 0; }
/* this is called for each played song from newcpu.c/m68k_reset() */ void uade_reset(void) { /* don't load anything under 0x1000 (execbase top at $1000) */ const int modnameaddr = 0x00400; const int scoreaddr = 0x01000; const int userstack = 0x08500; const int superstack = 0x08f00; const int playeraddr = 0x09000; int relocaddr; int modaddr; int len; FILE *file; int bytesread; uint8_t command[UADE_MAX_MESSAGE_SIZE]; struct uade_msg *um = (struct uade_msg *) command; int ret; nextsong: /* IMPORTANT: It seems that certain players don't work totally reliably if memory contains trash from previous songs. To be certain that each song is played from the same initial state of emulator we clear the memory from 0x400 to 'uade_highmem' each time a new song is played */ uade_highmem = 0; while (uade_highmem < 0x800000) { if (!valid_address(0, uade_highmem + 0x10000)) break; uade_highmem += 0x10000; } if (uade_highmem < 0x80000) { fprintf(stderr, "uadecore: There must be at least 512 KiB of amiga memory (%d bytes found).\n", uade_highmem); exit(-1); } if (uade_highmem < 0x200000) { fprintf(stderr, "uadecore: Warning: highmem == 0x%x (< 0x200000)!\n", uade_highmem); } memset(get_real_address(0), 0, uade_highmem); song.cur_subsong = song.min_subsong = song.max_subsong = 0; ret = uade_receive_string(song.scorename, UADE_COMMAND_SCORE, sizeof(song.scorename), &uadeipc); if (ret == 0) { fprintf(stderr, "uadecore: No more songs to play.\n"); exit(0); } else if (ret < 0) { fprintf(stderr, "uadecore: Invalid input. Expected score name.\n"); exit(-1); } // printf("got scorename %s\n",song.scorename); ret = uade_receive_string(song.playername, UADE_COMMAND_PLAYER, sizeof(song.playername), &uadeipc); if (ret == 0) { printf("uadecore: Expected player name. Got nothing.\n"); exit(-1); } else if (ret < 0) { printf( "uadecore: Invalid input. Expected player name.\n"); exit(-1); } // printf("got playername %s\n",song.playername); if (uade_dirname(uade_player_dir, song.playername, sizeof(uade_player_dir)) == NULL) { printf( "uadecore: Invalid dirname with player: %s\n", song.playername); exit(-1); } ret = uade_receive_message(um, sizeof command, &uadeipc); if (ret == 0) { printf("uadecore: Expected module name. Got nothing.\n"); exit(-1); } else if (ret < 0) { printf( "uadecore: Invalid input. Expected module name.\n"); exit(-1); } assert(um->msgtype == UADE_COMMAND_MODULE); if (um->size == 0) { song.modulename[0] = 0; } else { assert(um->size == (strlen((char *) um->data) + 1)); strlcpy(song.modulename, (char *) um->data, sizeof(song.modulename)); } // printf("got modulename %s\n",song.modulename); uade_set_automatic_song_end(1); uade_put_long(SCORE_EXEC_DEBUG, uade_execdebugboolean ? 0x12345678 : 0); uade_put_long(SCORE_VOLUME_TEST, voltestboolean); uade_put_long(SCORE_DMA_WAIT, uade_dmawait); uade_put_long(SCORE_MODULECHANGE, disable_modulechange); bytesread = uade_safe_load_name(playeraddr, song.playername, "player", uade_highmem - playeraddr); if (bytesread > (uade_highmem - playeraddr)) { fprintf (stderr, "uadecore: Player %s too big a file (%d bytes).\n", song.playername, bytesread); goto skiptonextsong; } if (bytesread == 0) { goto skiptonextsong; } /* fprintf(stderr, "uadecore: player '%s' (%d bytes)\n", song.playername, bytesread); */ /* set player executable address for relocator */ uade_put_long(SCORE_PLAYER_ADDR, playeraddr); len = uade_calc_reloc_size((uae_u32 *) get_real_address(playeraddr), (uae_u32 *) get_real_address(playeraddr + bytesread)); if (!len) { fprintf(stderr, "uadecore: Problem with reloc calculation.\n"); goto skiptonextsong; } relocaddr = ((playeraddr + bytesread) & 0x7FFFF000) + 0x4000; /* + 0x4000 for hippel coso (wasseremu) */ modaddr = ((relocaddr + len) & 0x7FFFF000) + 0x2000; if (modaddr <= relocaddr) { /* this is very bad because sound core memory allocation will fail */ fprintf(stderr, "uadecore: Warning: modaddr <= relocaddr: 0x%x <= 0x%x\n", modaddr, relocaddr); } uade_put_long(SCORE_RELOC_ADDR, relocaddr); /*address for relocated player*/ uade_put_long(SCORE_MODULE_ADDR, modaddr); /* set module address */ uade_put_long(SCORE_MODULE_LEN, 0); /* set module size to zero */ uade_put_long(SCORE_MODULE_NAME_ADDR, 0); /* mod name address pointer */ /* load the module if available */ if (song.modulename[0]) { bytesread = uade_safe_load_name(modaddr, song.modulename, "module", uade_highmem - modaddr); if (bytesread > (uade_highmem - playeraddr)) { fprintf (stderr, "uadecore: Module %s too big a file (%d bytes).\n", song.modulename, bytesread); goto skiptonextsong; } if (bytesread == 0) { goto skiptonextsong; } uade_put_long(SCORE_MODULE_LEN, bytesread); if (!valid_address(modnameaddr, strlen(song.modulename) + 1)) { fprintf(stderr, "uadecore: Invalid address for modulename.\n"); goto skiptonextsong; } strlcpy((char *) get_real_address(modnameaddr), song.modulename, 1024); uade_put_long(SCORE_MODULE_NAME_ADDR, modnameaddr); } else { if (!valid_address(modnameaddr, strlen(song.playername) + 1)) { fprintf(stderr, "uadecore: Invalid address for playername.\n"); goto skiptonextsong; } strlcpy((char *) get_real_address(modnameaddr), song.playername, 1024); uade_put_long(SCORE_MODULE_NAME_ADDR, modnameaddr); bytesread = 0; } /* load sound core (score) */ if ((file = fopen(song.scorename, "rb"))) { bytesread = uade_safe_load(scoreaddr, file, uade_highmem - scoreaddr); fclose(file); } else { fprintf (stderr, "uadecore: Can not load score (%s).\n", song.scorename); goto skiptonextsong; } m68k_areg(regs,7) = scoreaddr; m68k_setpc(scoreaddr); /* obey player format checking */ uade_put_long(SCORE_FORCE, 0); /* set default subsong */ uade_put_long(SCORE_SET_SUBSONG, 0); uade_put_long(SCORE_SUBSONG, 0); /* set PAL mode */ uade_set_ntsc(0); /* pause bits (don't care!), for debugging purposes only */ uade_put_long(SCORE_PREPAUSE, 0); uade_put_long(SCORE_POSTPAUSE, 0); /* set user and supervisor stack pointers */ uade_put_long(SCORE_USER_STACK, userstack); uade_put_long(SCORE_SUPER_STACK, superstack); /* no message for score */ uade_put_long(SCORE_OUTPUT_MSG, 0); if ((userstack - (scoreaddr + bytesread)) < 0x1000) fprintf(stderr, "uadecore: Amiga stack overrun warning.\n"); flush_sound(); /* note that uade_speed_hack can be negative (meaning that uade never uses speed hack, even if it's requested by the amiga player)! */ uade_time_critical = 0; if (uade_speed_hack > 0) { uade_time_critical = 1; } uade_reboot = 0; uade_audio_output = 0; uade_audio_skip = 0; old_ledstate = gui_ledstate; if (uade_receive_short_message(UADE_COMMAND_TOKEN, &uadeipc)) { fprintf(stderr, "uadecore: Can not receive token in uade_reset().\n"); exit(-1); } if (uade_send_short_message(UADE_REPLY_CAN_PLAY, &uadeipc)) { fprintf(stderr, "uadecore: Can not send 'CAN_PLAY' reply.\n"); exit(-1); } if (uade_send_short_message(UADE_COMMAND_TOKEN, &uadeipc)) { fprintf(stderr, "uadecore: Can not send token from uade_reset().\n"); exit(-1); } set_sound_freq(UADE_DEFAULT_FREQUENCY); epoptionsize = 0; return; skiptonextsong: fprintf(stderr, "uadecore: Can not play. Reboot.\n"); if (uade_receive_short_message(UADE_COMMAND_TOKEN, &uadeipc)) { fprintf(stderr, "uadecore: Can not receive token in uade_reset().\n"); exit(-1); } if (uade_send_short_message(UADE_REPLY_CANT_PLAY, &uadeipc)) { fprintf(stderr, "uadecore: Can not send 'CANT_PLAY' reply.\n"); exit(-1); } if (uade_send_short_message(UADE_COMMAND_TOKEN, &uadeipc)) { fprintf(stderr, "uadecore: Can not send token from uade_reset().\n"); exit(-1); } goto nextsong; }
void uade_get_amiga_message(void) { uae_u8 *ptr; uae_u8 *nameptr; FILE *file; int x; unsigned int mins, maxs, curs; int status; int src, dst, off, len; char tmpstr[256]; char *srcstr, *dststr; uint32_t *u32ptr; uint8_t space[256]; struct uade_msg *um = (struct uade_msg *) space; x = uade_get_u32(SCORE_INPUT_MSG); /* message type from amiga */ switch (x) { case AMIGAMSG_SONG_END: uade_song_end("player", 0); break; case AMIGAMSG_SUBSINFO: mins = uade_get_u32(SCORE_MIN_SUBSONG); maxs = uade_get_u32(SCORE_MAX_SUBSONG); curs = uade_get_u32(SCORE_CUR_SUBSONG); /* Brain damage in TFMX BC Kid Despair */ if (maxs < mins) { uade_send_debug("Odd subsongs. Eagleplayer reported (min, cur, max) == (%u, %u, %u)", mins, curs, maxs); maxs = mins; } /* Brain damage in Bubble bobble custom */ if (curs > maxs) { uade_send_debug("Odd subsongs. Eagleplayer reported (min, cur, max) == (%u, %u, %u)", mins, curs, maxs); maxs = curs; } um->msgtype = UADE_REPLY_SUBSONG_INFO; um->size = 12; u32ptr = (uint32_t *) um->data; u32ptr[0] = htonl(mins); u32ptr[1] = htonl(maxs); u32ptr[2] = htonl(curs); if (uade_send_message(um, &uadeipc)) { fprintf(stderr, "uadecore: Could not send subsong info message.\n"); exit(-1); } break; case AMIGAMSG_PLAYERNAME: strlcpy(tmpstr, (char *) get_real_address(0x204), sizeof tmpstr); uade_send_string(UADE_REPLY_PLAYERNAME, tmpstr, &uadeipc); break; case AMIGAMSG_MODULENAME: strlcpy(tmpstr, (char *) get_real_address(0x204), sizeof tmpstr); uade_send_string(UADE_REPLY_MODULENAME, tmpstr, &uadeipc); break; case AMIGAMSG_FORMATNAME: strlcpy(tmpstr, (char *) get_real_address(0x204), sizeof tmpstr); uade_send_string(UADE_REPLY_FORMATNAME, tmpstr, &uadeipc); break; case AMIGAMSG_GENERALMSG: uade_send_debug((char *) get_real_address(0x204)); break; case AMIGAMSG_CHECKERROR: uade_song_end("module check failed", 1); break; case AMIGAMSG_SCORECRASH: if (uade_debug) { fprintf(stderr, "uadecore: Score crashed.\n"); activate_debugger(); break; } uade_song_end("score crashed", 1); break; case AMIGAMSG_SCOREDEAD: if (uade_debug) { fprintf(stderr, "uadecore: Score is dead.\n"); activate_debugger(); break; } uade_song_end("score died", 1); break; case AMIGAMSG_LOADFILE: /* load a file named at 0x204 (name pointer) to address pointed by 0x208 and insert the length to 0x20C */ src = uade_get_u32(0x204); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: Load name in invalid address range.\n"); break; } nameptr = get_real_address(src); if ((file = uade_open_amiga_file((char *) nameptr, uade_player_dir))) { dst = uade_get_u32(0x208); len = uade_safe_load(dst, file, uade_highmem - dst); fclose(file); file = NULL; uade_put_long(0x20C, len); uade_send_debug("load success: %s ptr 0x%x size 0x%x", nameptr, dst, len); } else { uade_send_debug("load: file not found: %s", nameptr); } break; case AMIGAMSG_READ: src = uade_get_u32(0x204); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: Read name in invalid address range.\n"); break; } nameptr = get_real_address(src); dst = uade_get_u32(0x208); off = uade_get_u32(0x20C); len = uade_get_u32(0x210); if ((file = uade_open_amiga_file((char *) nameptr, uade_player_dir))) { if (fseek(file, off, SEEK_SET)) { perror("can not fseek to position"); x = 0; } else { x = uade_safe_load(dst, file, len); if (x > len) x = len; } fclose(file); uade_send_debug("read %s dst 0x%x off 0x%x len 0x%x res 0x%x", nameptr, dst, off, len, x); uade_put_long(0x214, x); } else { uade_send_debug("read: file not found: %s", nameptr); uade_put_long(0x214, 0); } break; case AMIGAMSG_FILESIZE: src = uade_get_u32(0x204); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: Filesize name in invalid address range.\n"); break; } nameptr = get_real_address(src); if ((file = uade_open_amiga_file((char *) nameptr, uade_player_dir))) { fseek(file, 0, SEEK_END); len = ftell(file); fclose(file); uade_put_long(0x208, len); uade_put_long(0x20C, -1); uade_send_debug("filesize: file %s res 0x%x", nameptr, len); } else { uade_put_long(0x208, 0); uade_put_long(0x20C, 0); uade_send_debug("filesize: file not found: %s", nameptr); } break; case AMIGAMSG_TIME_CRITICAL: uade_time_critical = uade_get_u32(0x204) ? 1 : 0; if (uade_speed_hack < 0) { /* a negative value forbids use of speed hack */ uade_time_critical = 0; } break; case AMIGAMSG_GET_INFO: src = uade_get_u32(0x204); dst = uade_get_u32(0x208); len = uade_get_u32(0x20C); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: get info: Invalid src: 0x%x\n", src); break; } if (len <= 0) { fprintf(stderr, "uadecore: get info: len = %d\n", len); break; } if (!valid_address(dst, len)) { fprintf(stderr, "uadecore: get info: Invalid dst: 0x%x\n", dst); break; } srcstr = (char *) get_real_address(src); dststr = (char *) get_real_address(dst); uade_send_debug("score issued an info request: %s (maxlen %d)\n", srcstr, len); len = get_info_for_ep(dststr, srcstr, len); /* Send printable debug */ do { size_t i; size_t maxspace = sizeof space; if (len <= 0) { maxspace = 1; } else { if (len < maxspace) maxspace = len; } for (i = 0; i < maxspace; i++) { space[i] = dststr[i]; if (space[i] == 0) space[i] = ' '; } if (i < maxspace) { space[i] = 0; } else { space[maxspace - 1] = 0; } uade_send_debug("reply to score: %s (total len %d)\n", space, len); } while (0); uade_put_long(0x20C, len); break; case AMIGAMSG_START_OUTPUT: uade_audio_output = 1; uade_send_debug("Starting audio output at %d", uade_audio_skip); break; default: fprintf(stderr,"uadecore: Unknown message from score (%d)\n", x); break; } }
/*-------------------------------------------- | Name: _tiny_elfloader | Description: | Parameters: none | Return Type: none | Comments: | See: ----------------------------------------------*/ unsigned long _tiny_elfloader(unsigned long flash_base, unsigned long base) { Elf32_Ehdr ehdr; Elf32_Phdr phdr[MAX_PHDR]; unsigned long offset = 0; int phx=0; int len=0; unsigned char ch; unsigned char *addr; unsigned long addr_offset = 0; unsigned long highest_address = 0; unsigned long lowest_address = 0xFFFFFFFF; unsigned char *SHORT_DATA = "error: short data reading elf file\r\n"; // int cb=0; boot_handler_t boot_handler = (boot_handler_t)0x00000000; #ifdef DEBUG _elf_printf("read elf file at 0x%x\r\n", (unsigned int)flash_base); #endif //ALREADY DONE //_at91sam9261_remap_internal_ram(); // Read the header _elf_printf("read elf header informations:\r\n" ); if (_elf_read(flash_base, (unsigned char *)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) { #ifdef DEBUG _elf_printf("error: can't read elf header\r\n"); #endif return 0; } offset += sizeof(ehdr); // #ifdef DEBUG _elf_printf( "type: %d, machine: %d, version: %d\r\nentry: 0x%x, PHoff: 0x%x/%d/%d, SHoff: 0x%x/%d/%d\r\n\r\n", ehdr.e_type, ehdr.e_machine, ehdr.e_version, ehdr.e_entry, ehdr.e_phoff, ehdr.e_phentsize, ehdr.e_phnum, ehdr.e_shoff, ehdr.e_shentsize, ehdr.e_shnum); #endif // if (ehdr.e_type != ET_EXEC) { #ifdef DEBUG _elf_printf("error: only absolute elf images supported\r\n"); #endif return 0; } // if (ehdr.e_phnum > MAX_PHDR) { #ifdef DEBUG _elf_printf("error: too many firmware headers\r\n"); #endif return 0; } #ifdef DEBUG _elf_printf("jump to offset 0x%x wait some seconds... ",ehdr.e_phoff); #endif //jump to offset #ifdef USE_OPTIMIZED_READELF //optimized code #if !defined(__GNUC__) _elf_lseek(flash_base,ehdr.e_phoff,0); offset+=ehdr.e_phoff; #endif #else //not optimized original code from reboot while (offset < ehdr.e_phoff) { if (_elf_getc(flash_base) < 0) { #ifdef DEBUG printf(SHORT_DATA); #endif return 0; } offset++; } #endif // #ifdef DEBUG _elf_printf("done\r\n"); #endif #ifdef DEBUG _elf_printf("read elf section header\r\n"); #endif // for (phx = 0; phx < ehdr.e_phnum; phx++) { if (_elf_read(flash_base, (unsigned char *)&phdr[phx], sizeof(phdr[0])) != sizeof(phdr[0])) { #ifdef DEBUG _elf_printf("error: can't read ELF program header\r\n"); #endif return 0; } #ifdef DEBUG _elf_printf( "section header: type: %d, off: 0x%x\r\nva: 0x%x, pa: 0x%x, len: %d/%d, flags: %d\r\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags); #endif offset += sizeof(phdr[0]); } if (base) { // Set address offset based on lowest address in file. addr_offset = 0xFFFFFFFF; for (phx = 0; phx < ehdr.e_phnum; phx++) { #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_vaddr < addr_offset)) { addr_offset = phdr[phx].p_vaddr; #else if ((phdr[phx].p_type == PT_LOAD) && (phdr[phx].p_paddr < addr_offset)) { addr_offset = phdr[phx].p_paddr; #endif } } addr_offset = (unsigned long)base - addr_offset; }else{ addr_offset = 0; } //phlb modif #if !defined(__GNUC__) _elf_lseek(flash_base,sizeof(ehdr),0); #endif #ifdef DEBUG _elf_printf("copy firmware in ram started:\r\n"); #endif for (phx = 0; phx < ehdr.e_phnum; phx++) { // if (phdr[phx].p_type == PT_LOAD) { // Loadable segment #ifdef CYGOPT_REDBOOT_ELF_VIRTUAL_ADDRESS addr = (unsigned char *)phdr[phx].p_vaddr; #else addr = (unsigned char *)phdr[phx].p_paddr; #endif // len = phdr[phx].p_filesz; if ((unsigned long)addr < lowest_address) { lowest_address = (unsigned long)addr; } // addr += addr_offset; if (offset > phdr[phx].p_offset) { /* if ((phdr[phx].p_offset + len) < offset) { printf("Can't load ELF file - program headers out of order\r\n"); return 0; } */ /*addr += offset - phdr[phx].p_offset;*/ } else { while (offset < phdr[phx].p_offset) { if (_elf_getc(flash_base) < 0) { #ifdef DEBUG printf(SHORT_DATA); #endif return 0; } offset++; } } #ifdef DEBUG _elf_printf( "program header: type: %d, off: 0x%x, va: 0x%x, pa:0x%x, len: %d/%d, flags: %d\r\n", phdr[phx].p_type, phdr[phx].p_offset, phdr[phx].p_vaddr, phdr[phx].p_paddr, phdr[phx].p_filesz, phdr[phx].p_memsz, phdr[phx].p_flags); #endif // Copy data into memory #ifndef USE_OPTIMIZED_READELF while (len-- > 0) { if ((ch = _elf_getc(flash_base)) < 0) { #ifdef DEBUG printf(SHORT_DATA); #endif return 0; } #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (valid_address(addr)) #endif *addr = ch; //original code #ifdef DEBUG if(!(((unsigned long)offset)%(80*1*1024))) _elf_printf("."); #endif addr++; offset++; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } #endif #ifdef USE_OPTIMIZED_READELF // #if defined(__GNUC__) _elf_lseek(flash_base,phdr[phx].p_offset,0); _elf_printf("offset:%d addr:0x%x fl_offset:%d\r\n", offset, addr, elf_flash_offset); #endif cb=0; while((len-cb)) { unsigned char elf_buffer[4096]={0}; int sz=0; if((len-cb)>=sizeof(elf_buffer)) sz=sizeof(elf_buffer); else sz=(len-cb); //cb += read(fd,elf_buffer,sz); cb+=_elf_read(flash_base, addr, sz); /* #ifdef DEBUG lseek(fd_bin,(unsigned long)addr,SEEK_SET); write(fd_bin,elf_buffer,sz); #endif */ #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (valid_address(addr)) #endif //memcpy(addr,elf_buffer,sz); // addr+=sz; offset+=sz; if ((unsigned long)(addr-addr_offset) > highest_address) { highest_address = (unsigned long)(addr - addr_offset); } } #endif } } // Save load base/top and entry if (base) { load_address = base; load_address_end = base + (highest_address - lowest_address); entry_address = base + (ehdr.e_entry - lowest_address); } else { load_address = lowest_address; load_address_end = highest_address; entry_address = ehdr.e_entry; } // nak everything to stop the transfer, since redboot // usually doesn't read all the way to the end of the // elf files. #ifdef DEBUG _elf_printf("\r\ncopy firmware in ram done\r\n"); if (addr_offset) _elf_printf("address offset = 0x%x\n", addr_offset); _elf_printf("firmware entry point: 0x%x, address range: 0x%x-0x%x\r\n",entry_address, load_address, load_address_end); _elf_printf("ready to rumble? ;)\r\nboot on firmware\r\n"); #endif boot_handler = (boot_handler_t)entry_address; //boot!!!! boot_handler(); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); __asm__("nop"); for(;; ) ; return 1; }
int main (int argc, char ** argv) { std::string filename; std::ifstream trace_file; uint64_t memory_size = 8*1024*1024; // default is 8GB // Check if all arguments are given in command line if (argc != 3) { std::cout << "Please supply two arguements: <trace file> <physical memory size (B)>." << std::endl; return -1; } // Get the filename filename.assign(argv[1]); // Assign the memory size memory_size = std::stol(argv[2], nullptr, 10); // allocate array uint64_t array_size = memory_size / page_size; array_size--; // assume 1st level page table ALWAYS in memory MEME * in_memory = new MEME[array_size]; // in_memory [array_size]; uint64_t array_index = 0; //std::cout << argv[2] << " " << memory_size << " " << array_size << std::endl; // Open the file trace_file.open(filename); char operation; std::string virtual_address; std::string this_key; int byte_size; std::string file_line; std::vector<std::string> line_input; std::string token; while (std::getline(trace_file, file_line)) { // tokenize string std::istringstream ss(file_line); while(std::getline(ss, token, ' ')) { line_input.push_back(token); //std::cout << token << std::endl; } if (line_input.size() != 3) { line_input.clear(); continue; } operation = line_input[0].at(0); if (operation != 'R' && operation != 'W') { line_input.clear(); continue; } line_input[1] = line_input[1].substr(0, line_input[1].size() - 3); if (!valid_address(line_input[1])) { line_input.clear(); continue; } virtual_address = line_input[1]; this_key = line_input[1];//virtual_address;//get_VPN(virtual_address); if (!valid_size(line_input[2])) { line_input.clear(); continue; } byte_size = std::stoi(line_input[2]); if (operation == 'R') total_bytes_read += byte_size; else total_bytes_write += byte_size; auto search = vpn_tracker.find(this_key); if (search != vpn_tracker.end()) { // check if 2nd level not in memory if (!vpn_tracker[this_key].lvl_2_mem) { // find page to eject array_index = get_next_index(in_memory, array_size, array_index); eject_from_memory (in_memory[array_index].vpn, in_memory[array_index].level); // insert new page insert_into_memory (in_memory, array_index, this_key, 2); } else if (vpn_tracker[this_key].lvl_2_mem) { total_accessed++; vpn_tracker[this_key].lvl_2_clock = 1; } // check if 3rd level not in memory if (!vpn_tracker[this_key].lvl_3_mem) { // find page to eject array_index = get_next_index(in_memory, array_size, array_index); eject_from_memory (in_memory[array_index].vpn, in_memory[array_index].level); // insert new page insert_into_memory (in_memory, array_index, this_key, 3); } else if (vpn_tracker[this_key].lvl_3_mem) { total_accessed++; vpn_tracker[this_key].lvl_3_clock = 1; } // check if 4th level not in memory if (!vpn_tracker[this_key].lvl_4_mem) { // find page to eject array_index = get_next_index(in_memory, array_size, array_index); eject_from_memory (in_memory[array_index].vpn, in_memory[array_index].level); // insert new page insert_into_memory (in_memory, array_index, this_key, 4); } else if (vpn_tracker[this_key].lvl_4_mem) { total_accessed++; vpn_tracker[this_key].lvl_4_clock = 1; } vpn_tracker[this_key].num_accessed += 1; } else { PTE new_elem = {this_key, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; vpn_tracker.insert(std::pair<std::string, PTE>(this_key, new_elem)); for (int i = 2; i < 5; ++i) { array_index = get_next_index(in_memory, array_size, array_index); eject_from_memory (in_memory[array_index].vpn, in_memory[array_index].level); insert_into_memory (in_memory, array_index, this_key, i); } } // std::cout << "num tokens: " << line_input.size() << std::endl; // { // virtual_address // } //std::cout << operation << " " << std::hex << virtual_address << " " << std::hex << get_VPN(virtual_address) << std::endl; line_input.clear(); } std::string most_accessed_vpn = ""; uint64_t num_access_vpn = 0; for (auto& x: vpn_tracker) { if (x.second.num_accessed > num_access_vpn) { num_access_vpn = x.second.num_accessed; most_accessed_vpn = x.first; } } long double page_fault_rate = (long double) total_faults / (long double) total_accessed; std::cout << "Number of pages accessed: " << vpn_tracker.size() << std::endl; //std::cout << "faults " << total_faults << " accessed " << total_accessed << std::endl; std::cout << "Page fault rate: " << page_fault_rate << std::endl; std::cout << "Most accessed VPN: " << most_accessed_vpn << std::endl; std::cout << "Number of bytes read: " << total_bytes_read << std::endl; std::cout << "Number of bytes written: " << total_bytes_write << std::endl; std::cout << "Memory footprint: " << (page_size * (1 + vpn_tracker.size())) << std::endl; delete [] in_memory; // uint64_t hex_value = 0; // std::cin >> std::hex >> hex_value; // std::cout << std::hex << get_VPN(hex_value) << std::endl; return 0; }
static void fis_load(int argc, char *argv[]) { char *name; struct fis_image_desc *img; CYG_ADDRESS mem_addr; bool mem_addr_set = false; bool show_cksum = false; struct option_info opts[3]; #if defined(CYGSEM_REDBOOT_FIS_CRC_CHECK) unsigned long cksum; #endif int num_options; #if defined(CYGPRI_REDBOOT_ZLIB_FLASH) || defined(CYGSEM_REDBOOT_FIS_CRC_CHECK) bool decompress = false; #endif void *err_addr; init_opts(&opts[0], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&mem_addr, (bool *)&mem_addr_set, "memory [load] base address"); init_opts(&opts[1], 'c', false, OPTION_ARG_TYPE_FLG, (void *)&show_cksum, (bool *)0, "display checksum"); num_options = 2; #ifdef CYGPRI_REDBOOT_ZLIB_FLASH init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, (void *)&decompress, 0, "decompress"); num_options++; #endif CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options"); if (!scan_opts(argc, argv, 2, opts, num_options, (void *)&name, OPTION_ARG_TYPE_STR, "image name")) { fis_usage("invalid arguments"); return; } if ((img = fis_lookup(name, NULL)) == (struct fis_image_desc *)0) { diag_printf("No image '%s' found\n", name); return; } if (!mem_addr_set) { mem_addr = img->mem_base; } // Load image from FLASH into RAM #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS if (!valid_address((void *)mem_addr)) { diag_printf("Not a loadable image - try using -b ADDRESS option\n"); return; } #endif #ifdef CYGPRI_REDBOOT_ZLIB_FLASH if (decompress) { int err; _pipe_t fis_load_pipe; _pipe_t* p = &fis_load_pipe; p->out_buf = (unsigned char*) mem_addr; p->out_max = p->out_size = -1; p->in_buf = (unsigned char*) img->flash_base; p->in_avail = img->data_length; err = (*_dc_init)(p); if (0 == err) err = (*_dc_inflate)(p); // Free used resources, do final translation of // error value. err = (*_dc_close)(p, err); if (0 != err && p->msg) { diag_printf("decompression error: %s\n", p->msg); } else { diag_printf("Image loaded from %p-%p\n", (unsigned char *)mem_addr, p->out_buf); } // Set load address/top load_address = mem_addr; load_address_end = (unsigned long)p->out_buf; // Reload fis directory fis_read_directory(); } else // dangling block #endif { flash_read((void *)img->flash_base, (void *)mem_addr, img->size, (void **)&err_addr); // Set load address/top load_address = mem_addr; load_address_end = mem_addr + img->size; diag_printf("load address 0x%08lx end 0x%08lx, image length 0x%08lx\n",load_address,load_address_end,img->data_length); } entry_address = (unsigned long)img->entry_point; #ifdef CYGSEM_REDBOOT_FIS_CRC_CHECK cksum = cyg_crc32((unsigned char *)mem_addr, img->data_length); if (show_cksum) { diag_printf("Checksum: 0x%08lx\n", cksum); } // When decompressing, leave CRC checking to decompressor if (!decompress && img->file_cksum) { if (cksum != img->file_cksum) { diag_printf("** Warning - checksum failure. stored: 0x%08lx, computed: 0x%08lx\n", img->file_cksum, cksum); entry_address = (unsigned long)NO_MEMORY; } } #endif }
void do_load(int argc, char *argv[]) { int res, num_options; int i, err; bool verbose, raw; bool base_addr_set, mode_str_set; char *mode_str; #ifdef CYGPKG_REDBOOT_NETWORKING struct sockaddr_in host; bool hostname_set, port_set; unsigned int port; // int because it's an OPTION_ARG_TYPE_NUM, // but will be cast to short char *hostname; #endif #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH bool flash_addr_set = false; #endif bool decompress = false; int chan = -1; #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 bool chan_set; #endif unsigned long base = 0; unsigned long end = 0; char type[4]; char *filename = 0; struct option_info opts[9]; connection_info_t info; getc_io_funcs_t *io = NULL; struct load_io_entry *io_tab; #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS bool spillover_ok = false; #endif #ifdef CYGPKG_REDBOOT_NETWORKING memset((char *)&host, 0, sizeof(host)); host.sin_len = sizeof(host); host.sin_family = AF_INET; host.sin_addr = my_bootp_info.bp_siaddr; host.sin_port = 0; #endif init_opts(&opts[0], 'v', false, OPTION_ARG_TYPE_FLG, (void *)&verbose, 0, "verbose"); init_opts(&opts[1], 'r', false, OPTION_ARG_TYPE_FLG, (void *)&raw, 0, "load raw data"); init_opts(&opts[2], 'b', true, OPTION_ARG_TYPE_NUM, (void *)&base, (bool *)&base_addr_set, "load address"); init_opts(&opts[3], 'm', true, OPTION_ARG_TYPE_STR, (void *)&mode_str, (bool *)&mode_str_set, "download mode (TFTP, xyzMODEM, or disk)"); num_options = 4; #if CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS > 1 init_opts(&opts[num_options], 'c', true, OPTION_ARG_TYPE_NUM, (void *)&chan, (bool *)&chan_set, "I/O channel"); num_options++; #endif #ifdef CYGPKG_REDBOOT_NETWORKING init_opts(&opts[num_options], 'h', true, OPTION_ARG_TYPE_STR, (void *)&hostname, (bool *)&hostname_set, "host name or IP address"); num_options++; init_opts(&opts[num_options], 'p', true, OPTION_ARG_TYPE_NUM, (void *)&port, (bool *)&port_set, "TCP port"); num_options++; #endif #ifdef CYGBLD_BUILD_REDBOOT_WITH_ZLIB init_opts(&opts[num_options], 'd', false, OPTION_ARG_TYPE_FLG, (void *)&decompress, 0, "decompress"); num_options++; #endif #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH init_opts(&opts[num_options], 'f', true, OPTION_ARG_TYPE_NUM, (void *)&base, (bool *)&flash_addr_set, "flash address"); num_options++; #endif CYG_ASSERT(num_options <= NUM_ELEMS(opts), "Too many options"); if (!scan_opts(argc, argv, 1, opts, num_options, (void *)&filename, OPTION_ARG_TYPE_STR, "file name")) { return; } #ifdef CYGPKG_REDBOOT_NETWORKING if (hostname_set) { ip_route_t rt; if (!_gethostbyname(hostname, (in_addr_t *)&host)) { err_printf("Invalid host: %s\n", hostname); return; } /* check that the host can be accessed */ if (__arp_lookup((ip_addr_t *)&host.sin_addr, &rt) < 0) { err_printf("Unable to reach host %s (%s)\n", hostname, inet_ntoa((in_addr_t *)&host)); return; } } if (port_set) host.sin_port = port; #endif if (chan >= CYGNUM_HAL_VIRTUAL_VECTOR_NUM_CHANNELS) { err_printf("Invalid I/O channel: %d\n", chan); return; } if (mode_str_set) { for (io_tab = __RedBoot_LOAD_TAB__; io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) { if (strncasecmp(&mode_str[0], io_tab->name, strlen(&mode_str[0])) == 0) { io = io_tab->funcs; break; } } if (!io) { diag_printf("Invalid 'mode': %s. Valid modes are:", mode_str); for (io_tab = __RedBoot_LOAD_TAB__; io_tab != &__RedBoot_LOAD_TAB_END__; io_tab++) { diag_printf(" %s", io_tab->name); } err_printf("\n"); } if (!io) { return; } verbose &= io_tab->can_verbose; if (io_tab->need_filename && !filename) { diag_printf("File name required\n"); err_printf("usage: load %s\n", usage); return; } } else { char *which = ""; io_tab = (struct load_io_entry *)NULL; // Default #ifdef CYGPKG_REDBOOT_NETWORKING #ifdef CYGSEM_REDBOOT_NET_TFTP_DOWNLOAD which = "TFTP"; io = &tftp_io; #elif defined(CYGSEM_REDBOOT_NET_HTTP_DOWNLOAD) which = "HTTP"; io = &http_io; #endif #endif #if 0 //def CYGPKG_REDBOOT_FILEIO // Make file I/O default if mounted if (fileio_mounted) { which = "file"; io = &fileio_io; } #endif if (!io) { #ifdef CYGBLD_BUILD_REDBOOT_WITH_XYZMODEM which = "Xmodem"; io = &xyzModem_io; verbose = false; #else err_printf("No default protocol!\n"); return; #endif } diag_printf("Using default protocol (%s)\n", which); } #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH if (flash_addr_set && flash_verify_addr((unsigned char *)base)) { if (!verify_action("Specified address (%p) is not believed to be in FLASH", (void*)base)) return; spillover_ok = true; } #endif if (base_addr_set && !valid_address((unsigned char *)base)) { if (!verify_action("Specified address (%p) is not believed to be in RAM", (void*)base)) return; spillover_ok = true; } #endif if (raw && !(base_addr_set #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH || flash_addr_set #endif )) { err_printf("Raw load requires a memory address\n"); return; } info.filename = filename; info.chan = chan; info.mode = io_tab ? io_tab->mode : 0; #ifdef CYGPKG_REDBOOT_NETWORKING info.server = &host; #endif res = redboot_getc_init(&info, io, verbose, decompress); if (res < 0) { return; } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH flash_load_start(); #endif // Stream open, process the data if (raw) { unsigned char *mp = (unsigned char *)base; err = 0; while ((res = redboot_getc()) >= 0) { #ifdef CYGSEM_REDBOOT_VALIDATE_USER_RAM_LOADS #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH if (flash_addr_set && flash_verify_addr(mp) && !spillover_ok) { // Only if there is no need to stop the download // before printing output can we ask confirmation // questions. redboot_getc_terminate(true); err_printf("*** Abort! RAW data spills over limit of FLASH at %p\n",(void*)mp); err = -1; break; } #endif if (base_addr_set && !valid_address(mp) && !spillover_ok) { // Only if there is no need to stop the download // before printing output can we ask confirmation // questions. redboot_getc_terminate(true); err_printf("*** Abort! RAW data spills over limit of user RAM at %p\n",(void*)mp); err = -1; break; } #endif #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH if (flash_addr_set) { flash_load_write(mp, res); mp++; res++; } else #endif *mp++ = res; } end = (unsigned long) mp; // Save load base/top load_address = base; load_address_end = end; entry_address = base; // best guess redboot_getc_terminate(false); if (0 == err) diag_printf("Raw file loaded %p-%p, assumed entry at %p\n", (void *)base, (void *)(end - 1), (void*)base); } else { // Read initial header - to determine file [image] type for (i = 0; i < sizeof(type); i++) { if ((res = redboot_getc()) < 0) { err = getc_info.err; break; } type[i] = res; } if (res >= 0) { redboot_getc_rewind(); // Restore header to stream // Treat data as some sort of executable image if (strncmp(&type[1], "ELF", 3) == 0) { end = load_elf_image(redboot_getc, base); } else if ((type[0] == 'S') && ((type[1] >= '0') && (type[1] <= '9'))) { end = load_srec_image(redboot_getc, base); } else { redboot_getc_terminate(true); err_printf("Unrecognized image type: 0x%lx\n", *(unsigned long *)type); } } } #ifdef CYGBLD_REDBOOT_LOAD_INTO_FLASH flash_load_finish(); #endif redboot_getc_close(); // Clean up return; }
/************************************************************* Display the enforcer hit *************************************************************/ static void enforcer_display_hit (const TCHAR *addressmode, uae_u32 pc, uaecptr addr) { uae_u32 a7; uae_u32 sysbase; uae_u32 this_task; uae_u32 task_name; TCHAR *native_task_name = NULL; int i, j; static TCHAR buf[256],instrcode[256]; static TCHAR lines[INSTRUCTIONLINES/2][256]; static uaecptr bestpc_array[INSTRUCTIONLINES/2][5]; static int bestpc_idxs[INSTRUCTIONLINES/2]; TCHAR *enforcer_buf_ptr = enforcer_buf; uaecptr bestpc, pospc, nextpc, temppc; if (enforcer_hit) return; /* our function itself generated a hit ;), avoid endless loop */ if (regs.vbr < 0x100 && addr >= 0x0c && addr < 0x80) return; enforcer_hit = 1; sysbase = get_long (4); if (sysbase < 0x100 || !valid_address (sysbase, 1000)) goto end; this_task = get_long (sysbase + 276); if (this_task < 0x100 || !valid_address (this_task, 1000)) goto end; task_name = get_long (this_task + 10); /* ln_Name */ native_task_name = au ((char*)amiga2native (task_name, 100)); /*if (strcmp(native_task_name,"c:MCP")!=0) { Exception (0x2d,0); }*/ _tcscpy (enforcer_buf_ptr, _T("Enforcer Hit! Bad program\n")); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); _stprintf (buf, _T("Illegal %s: %08x"), addressmode, addr); _stprintf (enforcer_buf_ptr, _T("%-48sPC: %08x\n"), buf, pc); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); /* Data registers */ _stprintf (enforcer_buf_ptr, _T("Data: %08x %08x %08x %08x %08x %08x %08x %08x\n"), m68k_dreg (regs, 0), m68k_dreg (regs, 1), m68k_dreg (regs, 2), m68k_dreg (regs, 3), m68k_dreg (regs, 4), m68k_dreg (regs, 5), m68k_dreg (regs, 6), m68k_dreg (regs, 7)); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); /* Address registers */ _stprintf (enforcer_buf_ptr, _T("Addr: %08x %08x %08x %08x %08x %08x %08x %08x\n"), m68k_areg (regs, 0), m68k_areg (regs, 1), m68k_areg (regs, 2), m68k_areg (regs, 3), m68k_areg (regs, 4), m68k_areg (regs, 5), m68k_areg (regs, 6), m68k_areg (regs, 7)); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); /* Stack */ a7 = m68k_areg (regs, 7); for (i = 0; i < 8 * STACKLINES; i++) { a7 += 4; if (!(i % 8)) { _tcscpy (enforcer_buf_ptr, _T("Stck:")); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); } _stprintf (enforcer_buf_ptr, _T(" %08x"),get_long (a7)); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); if (i%8 == 7) *enforcer_buf_ptr++ = '\n'; } /* Segtracker output */ if (enforcer_decode_hunk_and_offset (buf, pc)) { _tcscpy (enforcer_buf_ptr, buf); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); } uae_u32 oldaddrs[BACKTRACELONGS]; a7 = m68k_areg (regs, 7); for (i = 0; i < BACKTRACELONGS; i++) { uae_u32 addr; a7 += 4; addr = get_long (a7); for (j = 0; j < i; j++) { if (oldaddrs[j] == addr) break; } oldaddrs[i] = addr; if (j == i && addr != pc) { if (enforcer_decode_hunk_and_offset (buf, addr)) { int l = _tcslen (buf); if (ENFORCER_BUF_SIZE - (enforcer_buf_ptr - enforcer_buf) > l + 256) { _tcscpy (enforcer_buf_ptr, buf); enforcer_buf_ptr += l; } } } } /* Decode the instructions around the pc where the enforcer hit was caused. * * At first, the area before the pc, this not always done correctly because * it's done backwards */ temppc = pc; memset (bestpc_array, 0, sizeof (bestpc_array)); for (i = 0; i < INSTRUCTIONLINES / 2; i++) bestpc_idxs[i] = -1; for (i = 0; i < INSTRUCTIONLINES / 2; i++) { pospc = temppc; bestpc = 0; if (bestpc_idxs[i] == -1) { for (j = 0; j < 5; j++) { pospc -= 2; sm68k_disasm (buf, NULL, pospc, &nextpc); if (nextpc == temppc) { bestpc_idxs[i] = j; bestpc_array[i][j] = bestpc = pospc; } } } else { bestpc = bestpc_array[i][bestpc_idxs[i]]; } if (!bestpc) { /* there was no best pc found, so it is high probable that * a former used best pc was wrong. * * We trace back and use the former best pc instead */ int former_idx; int leave = 0; do { if (!i) { leave = 1; break; } i--; former_idx = bestpc_idxs[i]; bestpc_idxs[i] = -1; bestpc_array[i][former_idx] = 0; for (j = former_idx - 1; j >= 0; j--) { if (bestpc_array[i][j]) { bestpc_idxs[i] = j; break; } } } while (bestpc_idxs[i] == -1); if (leave) break; if (i) temppc = bestpc_array[i-1][bestpc_idxs[i-1]]; else temppc = pc; i--; /* will be increased in after continue */ continue; } sm68k_disasm (buf, instrcode, bestpc, NULL); _stprintf (lines[i], _T("%08x : %-20s %s\n"), bestpc, instrcode, buf); temppc = bestpc; } i--; for (; i >= 0; i--) { _tcscpy (enforcer_buf_ptr, lines[i]); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); } /* Now the instruction after the pc including the pc */ temppc = pc; for (i = 0; i < (INSTRUCTIONLINES + 1) / 2; i++) { sm68k_disasm (buf, instrcode, temppc, &nextpc); _stprintf (enforcer_buf_ptr, _T("%08x : %s %-20s %s\n"), temppc, (i == 0 ? _T("*") : _T(" ")), instrcode, buf); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); temppc = nextpc; } if (!native_task_name) native_task_name = my_strdup(_T("Unknown")); _stprintf (enforcer_buf_ptr, _T("Name: \"%s\"\n\n"), native_task_name); enforcer_buf_ptr += _tcslen (enforcer_buf_ptr); console_out (enforcer_buf); write_log (_T("%s"), enforcer_buf); if (!debug_enforcer()) { sleep_millis (5); doflashscreen (); } end: xfree (native_task_name); enforcer_hit = 0; }
void uadecore_get_amiga_message(void) { uae_u8 *ptr; uae_u8 *nameptr; int x; unsigned int mins, maxs, curs; int status; int src, dst, len; size_t off; char tmpstr[256]; char *srcstr, *dststr; struct uade_file *f; uint32_t *u32ptr; uint8_t space[256]; struct uade_msg *um = (struct uade_msg *) space; x = amiga_get_u32(SCORE_INPUT_MSG); /* message type from amiga */ switch (x) { case AMIGAMSG_SONG_END: uadecore_song_end("player", 0); break; case AMIGAMSG_SUBSINFO: mins = amiga_get_u32(SCORE_MIN_SUBSONG); maxs = amiga_get_u32(SCORE_MAX_SUBSONG); curs = amiga_get_u32(SCORE_CUR_SUBSONG); /* Brain damage in TFMX BC Kid Despair */ if (maxs < mins) { uadecore_send_debug("Odd subsongs. Eagleplayer reported (min, cur, max) == (%u, %u, %u)", mins, curs, maxs); maxs = mins; } /* Brain damage in Bubble bobble custom */ if (curs > maxs) { uadecore_send_debug("Odd subsongs. Eagleplayer reported (min, cur, max) == (%u, %u, %u)", mins, curs, maxs); maxs = curs; } um->msgtype = UADE_REPLY_SUBSONG_INFO; um->size = 12; u32ptr = (uint32_t *) um->data; u32ptr[0] = htonl(mins); u32ptr[1] = htonl(maxs); u32ptr[2] = htonl(curs); if (uade_send_message(um, &uadecore_ipc)) { fprintf(stderr, "uadecore: Could not send subsong info message.\n"); exit(1); } break; case AMIGAMSG_PLAYERNAME: strlcpy(tmpstr, (char *) get_real_address(0x204), sizeof tmpstr); uade_send_string(UADE_REPLY_PLAYERNAME, tmpstr, &uadecore_ipc); break; case AMIGAMSG_MODULENAME: strlcpy(tmpstr, (char *) get_real_address(0x204), sizeof tmpstr); uade_send_string(UADE_REPLY_MODULENAME, tmpstr, &uadecore_ipc); break; case AMIGAMSG_FORMATNAME: strlcpy(tmpstr, (char *) get_real_address(0x204), sizeof tmpstr); uade_send_string(UADE_REPLY_FORMATNAME, tmpstr, &uadecore_ipc); break; case AMIGAMSG_GENERALMSG: uadecore_send_debug((char *) get_real_address(0x204)); break; case AMIGAMSG_CHECKERROR: uadecore_song_end("module check failed", 1); break; case AMIGAMSG_SCORECRASH: if (uadecore_debug) { fprintf(stderr, "uadecore: Score crashed.\n"); activate_debugger(); break; } uadecore_song_end("score crashed", 1); break; case AMIGAMSG_SCOREDEAD: if (uadecore_debug) { fprintf(stderr, "uadecore: Score is dead.\n"); activate_debugger(); break; } uadecore_song_end("score died", 1); break; case AMIGAMSG_LOADFILE: /* * Load a file named at 0x204 (name pointer) to address pointed by * 0x208 and insert the length to 0x20C. * For example, R-Type (TFMX format) uses this. */ src = amiga_get_u32(0x204); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: Load name in invalid address range.\n"); break; } nameptr = get_real_address(src); f = lookup_amiga_file_cache((const char *) nameptr); if (f == NULL) { uadecore_send_debug("load: request error: %s", nameptr); exit(1); } if (f->data == NULL) { /* File not found */ uadecore_send_debug("load: file not found: %s", nameptr); break; } dst = amiga_get_u32(0x208); len = uade_safe_copy(dst, f->data, f->size); if (len == 0 && f->size > 0) uadecore_send_debug("load: too long a file to copy"); uade_put_long(0x20C, len); uadecore_send_debug("load: %s ptr 0x%x size 0x%x", nameptr, dst, len); break; case AMIGAMSG_READ: /* Used by "mdat.Crystal_Palace-1", for example */ src = amiga_get_u32(0x204); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: Read name in invalid address range.\n"); break; } nameptr = get_real_address(src); f = lookup_amiga_file_cache((const char *) nameptr); if (f == NULL) { uadecore_send_debug("read: request error: %s", nameptr); exit(1); } x = 0; if (f->data != NULL) { dst = amiga_get_u32(0x208); off = amiga_get_u32(0x20C); len = amiga_get_u32(0x210); if (off >= f->size) { uadecore_send_debug("read: file offset over the file end"); } else { size_t endpos = off + ((size_t) len); size_t tocopy = len; if (endpos > f->size) tocopy = f->size - off; x = uade_safe_copy(dst, f->data + off, tocopy); } uadecore_send_debug("read: %s dst 0x%x off 0x%x len 0x%x bytesread 0x%x", nameptr, dst, off, len, x); } else { uadecore_send_debug("read: file not found: %s", nameptr); } uade_put_long(0x214, x); break; case AMIGAMSG_FILESIZE: /* Used by "mdat.Crystal_Palace-1", for example */ src = amiga_get_u32(0x204); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: Filesize name in invalid address range.\n"); break; } nameptr = get_real_address(src); f = lookup_amiga_file_cache((const char *) nameptr); if (f == NULL) { uadecore_send_debug("filesize: request error: %s", nameptr); exit(1); } len = 0; x = 0; if (f->data != NULL) { len = f->size; x = -1; uadecore_send_debug("filesize: file %s res 0x%x", nameptr, len); } else { /* Note, f->size == -1 if file does not exist */ uadecore_send_debug("filesize: file not found: %s", nameptr); } uade_put_long(0x208, len); uade_put_long(0x20C, x); break; case AMIGAMSG_TIME_CRITICAL: uadecore_time_critical = amiga_get_u32(0x204) ? 1 : 0; if (speed_hack < 0) { /* a negative value forbids use of speed hack */ uadecore_time_critical = 0; } break; case AMIGAMSG_GET_INFO: src = amiga_get_u32(0x204); dst = amiga_get_u32(0x208); len = amiga_get_u32(0x20C); if (!uade_valid_string(src)) { fprintf(stderr, "uadecore: get info: Invalid src: 0x%x\n", src); break; } if (len <= 0) { fprintf(stderr, "uadecore: get info: len = %d\n", len); break; } if (!valid_address(dst, len)) { fprintf(stderr, "uadecore: get info: Invalid dst: 0x%x\n", dst); break; } srcstr = (char *) get_real_address(src); dststr = (char *) get_real_address(dst); uadecore_send_debug("score issued an info request: %s (maxlen %d)", srcstr, len); len = get_info_for_ep(dststr, srcstr, len); /* Send printable debug */ do { size_t i; size_t maxspace = sizeof space; if (len <= 0) { maxspace = 1; } else { if (len < maxspace) maxspace = len; } for (i = 0; i < maxspace; i++) { space[i] = dststr[i]; if (space[i] == 0) space[i] = ' '; } if (i < maxspace) { space[i] = 0; } else { space[maxspace - 1] = 0; } uadecore_send_debug("reply to score: %s (total len %d)", space, len); } while (0); uade_put_long(0x20C, len); break; case AMIGAMSG_START_OUTPUT: uadecore_audio_output = 1; break; default: fprintf(stderr,"uadecore: Unknown message from score (%d)\n", x); break; } }