int mc_fseek(MC_FILE *fp, long offset, int whence) { #if !mxMC if (fp->aux != NULL) fseek(fp->aux, offset, whence); #endif if (fp->ffs != NULL) { long pos; switch (whence) { case SEEK_SET: break; case SEEK_CUR: if ((pos = mc_ffs_position(fp->ffs, -1L, 0)) < 0L) return -1; offset += pos; break; case SEEK_END: if ((pos = mc_ffs_position(fp->ffs, 1L << 30, 0)) < 0L) return -1; offset += pos; break; } offset = mc_ffs_position(fp->ffs, offset, 1); if (offset >= 0L) { fp->pos = offset; fp->bp = fp->bufend = fp->buf; } return offset < 0L ? -1 : 0; } else if (fp->mmapped != NULL) { uint8_t *p; switch (whence) { default: case SEEK_SET: p = fp->buf + offset; break; case SEEK_CUR: p = fp->bp + offset; break; case SEEK_END: p = fp->bufend + offset; break; } if (p < fp->buf || p > fp->bufend) { mc_log_error("mc_fseek: range error\n"); errno = ENXIO; return -1; } fp->bp = p; return 0; } #if FTFS else if (fp->aux != NULL) { return mc_ft_fseek(fp->aux, offset, whence); } #endif return 0; }
int mc_event_main(xsMachine *the, mc_event_shutdown_callback_t *cb) { struct timeval tv; fd_set rs, ws; int n = -1, i; unsigned int flags; uint64_t timeInterval; struct sockaddr_in sin; int localevent_sock; mc_shutdown_callback = cb; g_status = -1; /* not ready yet */ if ((localevent_sock = lwip_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) return -1; sin.sin_family = AF_INET; sin.sin_port = htons(MC_LOCAL_EVENT_PORT); sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); lwip_bind(localevent_sock, (struct sockaddr *)&sin, sizeof(sin)); mc_event_register(localevent_sock, MC_SOCK_READ, mc_event_local_callback, the); mc_event_delegation_init(); g_status = 0; /* running */ while (!g_status) { timeInterval = mc_event_process_timeout(the); if (timeInterval != 0) { tv.tv_sec = timeInterval / 1000; tv.tv_usec = (timeInterval % 1000) * 1000; } if (maxfd < 0) { /* @@ what if only timer is running?? */ mc_log_debug("event: no one is waiting!\n"); break; /* no one is waiting for anything! will be blocked forever unless break */ } rs = reads; ws = writes; n = lwip_select(maxfd + 1, &rs, &ws, NULL, timeInterval > 0 ? &tv : NULL); if (mc_event_callback_any.callback != NULL) (*mc_event_callback_any.callback)(mc_event_callback_any.fd, (unsigned int)n, mc_event_callback_any.closure); if (n > 0) { for (i = 0; i <= maxfd; i++) { flags = 0; if (FD_ISSET(i, &rs)) flags |= MC_SOCK_READ; if (FD_ISSET(i, &ws)) flags |= MC_SOCK_WRITE; if (flags) { if (mc_event_callbacks[i].callback == NULL) { mc_log_error("event: %s ready for closed socket(%d)!?\n", flags & MC_SOCK_WRITE ? "write" : "read", i); continue; } (*mc_event_callbacks[i].callback)(i, flags, mc_event_callbacks[i].closure); } } } } mc_event_delegation_fin(); lwip_close(localevent_sock); return g_exit_status; }
int mc_erase_volume(const char *volname) { mc_partition_entry_t pe; void *mdev; int ret; if ((strlen(volname) > 0) && (volname[0] == '/')) volname++; if (mc_get_partition_by_name(volname, &pe, 0) != 0) { if (mc_get_partition_by_name(volname, &pe, -1) != 0) { mc_log_error("mc_erase_volume: no partition! %s\n", volname); return -1; } } if ((mdev = mc_flash_drv_open(pe.pe_dev)) == NULL) { mc_log_error("mc_erase_volume: mc_flash_drv_open failed\n"); return -1; } ret = mc_flash_drv_erase(mdev, pe.pe_start, pe.pe_size); mc_flash_drv_close(mdev); return ret; }
struct mc_timeout * mc_interval_set(unsigned long interval, mc_timeout_callback_f callback, void *closure) { int i; for (i = 0; i < MC_MAX_TIMEOUTS; i++) { if (mc_timeout_callbacks[i].status == MC_TIMEOUT_UNUSED) { struct mc_timeout *tc = &mc_timeout_callbacks[i]; tc->interval = interval; tc->status = MC_TIMEOUT_STOP; tc->callback = callback; tc->closure = closure; return tc; } } mc_log_error("# Error: timeout: no slot!\n"); return NULL; }
int mc_ftruncate(MC_FILE *fp, long length) { #if !mxMC if (fp->aux != NULL) ftruncate(fileno(fp->aux), length); #endif if (fp->ffs == NULL) { mc_log_error("mc_ftruncate: fp->ffs is NULL\n"); errno = ENXIO; return -1; } if (mc_ffs_position(fp->ffs, length, 1) >= 0 && mc_ffs_truncate(fp->ffs) == 0) { fp->pos = length; fp->length = length; fp->bp = fp->bufend = fp->buf; return 0; } else return -1; }
int mc_check_volume(const char *volname, int recovery) { mc_partition_entry_t pe; int err; if ((strlen(volname) > 0) && (volname[0] == '/')) volname++; if (mc_get_partition_by_name(volname, &pe, 1) != 0) { mc_log_error("mc_check_volume: partition not found: %s\n", volname); return -1; } switch (pe.pe_type) { case MC_PTYPE_USER_APP: err = mc_ffs_check(&pe, recovery, volname); break; default: err = 0; break; } return err; }
size_t mc_fwrite(const void *ptr, size_t size, size_t nmemb, MC_FILE *fp) { size_t n; if (fp->ffs == NULL) { mc_log_error("mc_fwrite: fp->ffs is NULL\n"); errno = EPERM; return 0; } #if !mxMC if (fp->aux != NULL) fwrite(ptr, size, nmemb, fp->aux); #endif n = mc_ffs_write(ptr, size, nmemb, fp->ffs); if (n == 0) return 0; fp->pos += n * size; if (fp->pos > (long)fp->length) fp->length = fp->pos; return n; }
MC_FILE * mc_fopen(const char *fullpath, const char *mode) { MC_FILE *fp; errno = 0; if ((fp = mc_malloc(sizeof(MC_FILE))) == NULL) { errno = ENOMEM; mc_log_error("mc_fopen: mc_malloc failed\n"); return NULL; } fp->ffs = NULL; fp->mmapped = NULL; fp->buf = NULL; fp->bp = fp->bufend = fp->buf; fp->length = 0; fp->pos = 0; #if FTFS || !mxMC fp->aux = NULL; #endif if ((mode[0] == 'r' && mode[1] != '+') && fullpath[0] != '/') { size_t sz; const void *p = mc_mmap(fullpath, &sz); if (p != NULL) { fp->mmapped = p; fp->length = sz; fp->bp = fp->buf = (uint8_t *)p; fp->bufend = fp->buf + sz; fp->pos = (long)sz; } else { #if FTFS if ((fp->aux = mc_ft_fopen(fullpath, mode)) != NULL) { fp->length = mc_ft_fseek(fp->aux, 0L, SEEK_END); mc_ft_fseek(fp->aux, 0L, SEEK_SET); } else errno = ENOENT; #else errno = ENOENT; #endif } } else { uint32_t flags = 0; #if !mxMC if (sync_with_native_path(fullpath)) { const char *path = mc_resolve_path(fullpath, *mode == 'r' ? 0 : 1); fp->aux = fopen(path, mode); errno = 0; } #endif if (strlen(mode) > 1) { switch (mode[1]) { case '+': flags |= FFS_ORDWR; break; case 'p': flags |= FFS_OPASSIVE; break; case 'a': flags |= FFS_OACTIVE; break; } } if (mode[0] == 'w') flags |= FFS_OTRUNC | FFS_OCREAT; if ((fp->ffs = mc_ffs_open(fullpath, flags)) != NULL) fp->length = mc_ffs_position(fp->ffs, 1L << 30, mode[0] == 'a'); else { /* errno must've been set */ if (errno != ENOENT) mc_log_error("mc_fopen: ffs_open failed: %d\n", errno); } } if (errno == 0) { if (fp->mmapped == NULL) { if ((fp->buf = mc_malloc(MC_STREAM_BUFSIZ)) != NULL) fp->bufend = fp->bp = fp->buf; else { mc_log_error("mc_fopen: mc_malloc failed\n"); errno = ENOMEM; } } } if (errno != 0) { if (fp != NULL) mc_fclose(fp); fp = NULL; } return fp; }
static int load_elf(const char *path, void **basep, struct mc_module **modp) { struct mc_elf elf; unsigned int i; uint32_t psize = 0, sz; uint8_t *base = NULL; uint8_t *paddr = NULL, *adr; struct mc_module *mod = NULL; int err = -1; mc_log_debug("ELF: loading %s...\n", path); if (mc_elf_open(path, &elf) != 0) { mc_log_error("ELF: cannot open %s\n", path); return -1; } /* calculate the entire program size in VM */ for (i = 0; i < NUM_EXT_SECTIONS; i++) { if (mc_elf_get_section_addr_and_size(&elf, ext_sections[i], &adr, &sz) != 0) continue; if (adr >= paddr) { paddr = adr; psize = (uint32_t)paddr + sz; } } mc_log_debug("ELF: allocating %d bytes...\n", (unsigned int)psize); if ((base = mc_malloc(psize)) == NULL) goto bail; /* load each section */ for (i = 0; i < NUM_EXT_SECTIONS; i++) { if (mc_elf_load_section(&elf, ext_sections[i], base) != 0) mc_log_error("cannot load %s (%d)\n", ext_sections[i], err); } #if 0 /* adjust function(?) addresses */ if (mc_elf_get_section_addr_and_size(&elf, ".got", &adr, &sz) == 0) { uint32_t *gadr = (uint32_t *)(adr + (uint32_t)base), *eadr = (uint32_t *)(adr + (uint32_t)base + sz); for (; gadr < eadr; gadr++) { /* if (*gadr & 0xf0000000) { *gadr = (*gadr & ~0xf0000000) + (uint32_t)base; mc_log_debug("adjusted: 0x%lx\n", *gadr); } */ *gadr += (uint32_t)base; } } #endif /* relocate variables */ if (mc_elf_set_position(&elf, ".rel.dyn") == 0) { struct elf_rel rel; while (mc_elf_read(&elf, &rel, sizeof(rel)) == 0) { switch (ELF32_R_TYPE(rel.info)) { case 0x17: /* R_ARM_RELATIVE */ *(uint32_t *)(rel.offset + (uint32_t)base) += (uint32_t)base; // mc_log_debug("RELOC (rel): %x: %x\n", rel.offset, *(uint32_t *)(rel.offset + (uint32_t)base)); break; case 0x02: { /* R_ARM_ABS32 */ struct elf_sym sym; if (mc_elf_get(&elf, ".dynsym", &sym, sizeof(sym), ELF32_R_SYM(rel.info)) != 0) { mc_log_error("cannot read .dynsym %ld\n", ELF32_R_SYM(rel.info)); goto bail; } *(uint32_t *)(rel.offset + (uint32_t)base) = sym.value + (uint32_t)base; // mc_log_debug("RELOC (abs): %x: %x\n", rel.offset, *(uint32_t *)(rel.offset + (uint32_t)base)); break; } default: /* no-op */ mc_log_error("RELOC unknown type: 0x%x\n", ELF32_R_TYPE(rel.info)); break; } } } paddr = mc_elf_get_entry(&elf); // mc_log_debug("ELF: entry = 0x%lx, base = 0x%lx\n", (uint32_t)paddr, (uint32_t)base); paddr += (uint32_t)base; mod = (struct mc_module *)paddr; *mod->stubs = (const void **)ext_stubs; *mod->num_stubs = num_ext_stubs; *basep = base; *modp = mod; err = 0; bail: mc_elf_close(&elf); if (err != 0 && base != NULL) mc_free(base); return err; }