static int str9x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t words_remaining = (count / 2); uint32_t bytes_remaining = (count & 0x00000001); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint8_t status; int retval; uint32_t check_address = offset; uint32_t bank_adr; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x1) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; /* multiple half words (2-byte) to be programmed? */ if (words_remaining > 0) { /* try using a block write */ retval = str9x_write_block(bank, buffer, offset, words_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else if (retval == ERROR_FLASH_OPERATION_FAILED) { LOG_ERROR("flash writing failed"); return ERROR_FLASH_OPERATION_FAILED; } } else { buffer += words_remaining * 2; address += words_remaining * 2; words_remaining = 0; } } while (words_remaining > 0) { bank_adr = address & ~0x03; /* write data command */ target_write_u16(target, bank_adr, 0x40); target_write_memory(target, address, 2, 1, buffer + bytes_written); /* get status command */ target_write_u16(target, bank_adr, 0x70); int timeout; for (timeout = 0; timeout < 1000; timeout++) { target_read_u8(target, bank_adr, &status); if (status & 0x80) break; alive_sleep(1); } if (timeout == 1000) { LOG_ERROR("write timed out"); return ERROR_FAIL; } /* clear status reg and read array */ target_write_u16(target, bank_adr, 0x50); target_write_u16(target, bank_adr, 0xFF); if (status & 0x10) return ERROR_FLASH_OPERATION_FAILED; else if (status & 0x02) return ERROR_FLASH_OPERATION_FAILED; bytes_written += 2; words_remaining--; address += 2; } if (bytes_remaining) { uint8_t last_halfword[2] = {0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_halfword, buffer+bytes_written, bytes_remaining); bank_adr = address & ~0x03; /* write data command */ target_write_u16(target, bank_adr, 0x40); target_write_memory(target, address, 2, 1, last_halfword); /* query status command */ target_write_u16(target, bank_adr, 0x70); int timeout; for (timeout = 0; timeout < 1000; timeout++) { target_read_u8(target, bank_adr, &status); if (status & 0x80) break; alive_sleep(1); } if (timeout == 1000) { LOG_ERROR("write timed out"); return ERROR_FAIL; } /* clear status reg and read array */ target_write_u16(target, bank_adr, 0x50); target_write_u16(target, bank_adr, 0xFF); if (status & 0x10) return ERROR_FLASH_OPERATION_FAILED; else if (status & 0x02) return ERROR_FLASH_OPERATION_FAILED; } return ERROR_OK; }
int agent_run_command (int pid, const char *cmd, int len) { int fd; int tid = agent_get_helper_thread_id (); ptid_t ptid = ptid_build (pid, tid, 0); int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, len); if (ret != 0) { warning (_("unable to write")); return -1; } DEBUG_AGENT ("agent: resumed helper thread\n"); /* Resume helper thread. */ target_continue_no_signal (ptid); fd = gdb_connect_sync_socket (pid); if (fd >= 0) { char buf[1] = ""; int ret; DEBUG_AGENT ("agent: signalling helper thread\n"); do { ret = write (fd, buf, 1); } while (ret == -1 && errno == EINTR); DEBUG_AGENT ("agent: waiting for helper thread's response\n"); do { ret = read (fd, buf, 1); } while (ret == -1 && errno == EINTR); close (fd); DEBUG_AGENT ("agent: helper thread's response received\n"); } else return -1; /* Need to read response with the inferior stopped. */ if (!ptid_equal (ptid, null_ptid)) { /* Stop thread PTID. */ DEBUG_AGENT ("agent: stop helper thread\n"); target_stop_and_wait (ptid); } if (fd >= 0) { if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, IPA_CMD_BUF_SIZE)) { warning (_("Error reading command response")); return -1; } } return 0; }
static void copy_sections (bfd *abfd, asection *sect, void *data) { asymbol **symbol_table = data; bfd_byte *sect_data, *sect_data_got; struct cleanup *cleanups; struct bfd_link_info link_info; struct bfd_link_order link_order; CORE_ADDR inferior_addr; struct link_hash_table_cleanup_data cleanup_data; if ((bfd_get_section_flags (abfd, sect) & (SEC_ALLOC | SEC_LOAD)) != (SEC_ALLOC | SEC_LOAD)) return; if (bfd_get_section_size (sect) == 0) return; /* Mostly a copy of bfd_simple_get_relocated_section_contents which GDB cannot use as it does not report relocations to undefined symbols. */ memset (&link_info, 0, sizeof (link_info)); link_info.output_bfd = abfd; link_info.input_bfds = abfd; link_info.input_bfds_tail = &abfd->link.next; cleanup_data.abfd = abfd; cleanup_data.link_next = abfd->link.next; abfd->link.next = NULL; link_info.hash = bfd_link_hash_table_create (abfd); cleanups = make_cleanup (link_hash_table_free, &cleanup_data); link_info.callbacks = &link_callbacks; memset (&link_order, 0, sizeof (link_order)); link_order.next = NULL; link_order.type = bfd_indirect_link_order; link_order.offset = 0; link_order.size = bfd_get_section_size (sect); link_order.u.indirect.section = sect; sect_data = xmalloc (bfd_get_section_size (sect)); make_cleanup (xfree, sect_data); sect_data_got = bfd_get_relocated_section_contents (abfd, &link_info, &link_order, sect_data, FALSE, symbol_table); if (sect_data_got == NULL) error (_("Cannot map compiled module \"%s\" section \"%s\": %s"), bfd_get_filename (abfd), bfd_get_section_name (abfd, sect), bfd_errmsg (bfd_get_error ())); gdb_assert (sect_data_got == sect_data); inferior_addr = bfd_get_section_vma (abfd, sect); if (0 != target_write_memory (inferior_addr, sect_data, bfd_get_section_size (sect))) error (_("Cannot write compiled module \"%s\" section \"%s\" " "to inferior memory range %s-%s."), bfd_get_filename (abfd), bfd_get_section_name (abfd, sect), paddress (target_gdbarch (), inferior_addr), paddress (target_gdbarch (), inferior_addr + bfd_get_section_size (sect))); do_cleanups (cleanups); }
static LONGEST ld_so_xfer_auxv (gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { struct minimal_symbol *msym; CORE_ADDR data_address, pointer_address; struct type *ptr_type = builtin_type (target_gdbarch)->builtin_data_ptr; size_t ptr_size = TYPE_LENGTH (ptr_type); size_t auxv_pair_size = 2 * ptr_size; gdb_byte *ptr_buf = alloca (ptr_size); LONGEST retval; size_t block; msym = lookup_minimal_symbol ("_dl_auxv", NULL, NULL); if (msym == NULL) return -1; if (MSYMBOL_SIZE (msym) != ptr_size) return -1; /* POINTER_ADDRESS is a location where the `_dl_auxv' variable resides. DATA_ADDRESS is the inferior value present in `_dl_auxv', therefore the real inferior AUXV address. */ pointer_address = SYMBOL_VALUE_ADDRESS (msym); /* The location of the _dl_auxv symbol may no longer be correct if ld.so runs at a different address than the one present in the file. This is very common case - for unprelinked ld.so or with a PIE executable. PIE executable forces random address even for libraries already being prelinked to some address. PIE executables themselves are never prelinked even on prelinked systems. Prelinking of a PIE executable would block their purpose of randomizing load of everything including the executable. If the memory read fails, return -1 to fallback on another mechanism for retrieving the AUXV. In most cases of a PIE running under valgrind there is no way to find out the base addresses of any of ld.so, executable or AUXV as everything is randomized and /proc information is not relevant for the virtual executable running under valgrind. We think that we might need a valgrind extension to make it work. This is PR 11440. */ if (target_read_memory (pointer_address, ptr_buf, ptr_size) != 0) return -1; data_address = extract_typed_address (ptr_buf, ptr_type); /* Possibly still not initialized such as during an inferior startup. */ if (data_address == 0) return -1; data_address += offset; if (writebuf != NULL) { if (target_write_memory (data_address, writebuf, len) == 0) return len; else return -1; } /* Stop if trying to read past the existing AUXV block. The final AT_NULL was already returned before. */ if (offset >= auxv_pair_size) { if (target_read_memory (data_address - auxv_pair_size, ptr_buf, ptr_size) != 0) return -1; if (extract_typed_address (ptr_buf, ptr_type) == AT_NULL) return 0; } retval = 0; block = 0x400; gdb_assert (block % auxv_pair_size == 0); while (len > 0) { if (block > len) block = len; /* Reading sizes smaller than AUXV_PAIR_SIZE is not supported. Tails unaligned to AUXV_PAIR_SIZE will not be read during a call (they should be completed during next read with new/extended buffer). */ block &= -auxv_pair_size; if (block == 0) return retval; if (target_read_memory (data_address, readbuf, block) != 0) { if (block <= auxv_pair_size) return retval; block = auxv_pair_size; continue; } data_address += block; len -= block; /* Check terminal AT_NULL. This function is being called indefinitely being extended its READBUF until it returns EOF (0). */ while (block >= auxv_pair_size) { retval += auxv_pair_size; if (extract_typed_address (readbuf, ptr_type) == AT_NULL) return retval; readbuf += auxv_pair_size; block -= auxv_pair_size; } } return retval; }
static int str7x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t dwords_remaining = (count / 8); uint32_t bytes_remaining = (count & 0x00000007); uint32_t address = bank->base + offset; uint32_t bytes_written = 0; uint32_t cmd; int retval; uint32_t check_address = offset; int i; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x7) { LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { uint32_t sec_start = bank->sectors[i].offset; uint32_t sec_end = sec_start + bank->sectors[i].size; /* check if destination falls within the current sector */ if ((check_address >= sec_start) && (check_address < sec_end)) { /* check if destination ends in the current sector */ if (offset + count < sec_end) check_address = offset + count; else check_address = sec_end; } } if (check_address != offset + count) return ERROR_FLASH_DST_OUT_OF_BANK; /* clear FLASH_ER register */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_ER), 0x0); /* multiple dwords (8-byte) to be programmed? */ if (dwords_remaining > 0) { /* try using a block write */ retval = str7x_write_block(bank, buffer, offset, dwords_remaining); if (retval != ERROR_OK) { if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* if block write failed (no sufficient working area), * we use normal (slow) single dword accesses */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); } else { return retval; } } else { buffer += dwords_remaining * 8; address += dwords_remaining * 8; dwords_remaining = 0; } } while (dwords_remaining > 0) { /* command */ cmd = FLASH_DWPG; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); /* address */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address); /* data word 1 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, buffer + bytes_written); bytes_written += 4; /* data word 2 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, buffer + bytes_written); bytes_written += 4; /* start programming cycle */ cmd = FLASH_DWPG | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); int err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; dwords_remaining--; address += 8; } if (bytes_remaining) { uint8_t last_dword[8] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; /* copy the last remaining bytes into the write buffer */ memcpy(last_dword, buffer+bytes_written, bytes_remaining); /* command */ cmd = FLASH_DWPG; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); /* address */ target_write_u32(target, str7x_get_flash_adr(bank, FLASH_AR), address); /* data word 1 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR0), 4, 1, last_dword); /* data word 2 */ target_write_memory(target, str7x_get_flash_adr(bank, FLASH_DR1), 4, 1, last_dword + 4); /* start programming cycle */ cmd = FLASH_DWPG | FLASH_WMS; target_write_u32(target, str7x_get_flash_adr(bank, FLASH_CR0), cmd); int err; err = str7x_waitbusy(bank); if (err != ERROR_OK) return err; err = str7x_result(bank); if (err != ERROR_OK) return err; } return ERROR_OK; }
static int do_semihosting(struct target *target) { struct arm *arm = target_to_arm(target); struct gdb_fileio_info *fileio_info = target->fileio_info; uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); uint8_t params[16]; int retval; /* * TODO: lots of security issues are not considered yet, such as: * - no validation on target provided file descriptors * - no safety checks on opened/deleted/renamed file paths * Beware the target app you use this support with. * * TODO: unsupported semihosting fileio operations could be * implemented if we had a small working area at our disposal. */ switch ((arm->semihosting_op = r0)) { case 0x01: /* SYS_OPEN */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t m = target_buffer_get_u32(target, params+4); uint32_t l = target_buffer_get_u32(target, params+8); uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; if (arm->is_semihosting_fileio) { if (strcmp((char *)fn, ":tt") == 0) arm->semihosting_result = 0; else { arm->semihosting_hit_fileio = true; fileio_info->identifier = "open"; fileio_info->param_1 = a; fileio_info->param_2 = l; fileio_info->param_3 = open_modeflags[m]; fileio_info->param_4 = 0644; } } else { if (l <= 255 && m <= 11) { if (strcmp((char *)fn, ":tt") == 0) { if (m < 4) arm->semihosting_result = dup(STDIN_FILENO); else arm->semihosting_result = dup(STDOUT_FILENO); } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ arm->semihosting_result = open((char *)fn, open_modeflags[m], 0644); } arm->semihosting_errno = errno; } else { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } } } break; case 0x02: /* SYS_CLOSE */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "close"; fileio_info->param_1 = fd; } else { arm->semihosting_result = close(fd); arm->semihosting_errno = errno; } } break; case 0x03: /* SYS_WRITEC */ if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = 1; fileio_info->param_2 = r1; fileio_info->param_3 = 1; } else { unsigned char c; retval = target_read_memory(target, r1, 1, 1, &c); if (retval != ERROR_OK) return retval; putchar(c); arm->semihosting_result = 0; } break; case 0x04: /* SYS_WRITE0 */ if (arm->is_semihosting_fileio) { size_t count = 0; for (uint32_t a = r1;; a++) { unsigned char c; retval = target_read_memory(target, a, 1, 1, &c); if (retval != ERROR_OK) return retval; if (c == '\0') break; count++; } arm->semihosting_hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = 1; fileio_info->param_2 = r1; fileio_info->param_3 = count; } else { do { unsigned char c; retval = target_read_memory(target, r1++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; putchar(c); } while (1); arm->semihosting_result = 0; } break; case 0x05: /* SYS_WRITE */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); size_t l = target_buffer_get_u32(target, params+8); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "write"; fileio_info->param_1 = fd; fileio_info->param_2 = a; fileio_info->param_3 = l; } else { uint8_t *buf = malloc(l); if (!buf) { arm->semihosting_result = -1; arm->semihosting_errno = ENOMEM; } else { retval = target_read_buffer(target, a, l, buf); if (retval != ERROR_OK) { free(buf); return retval; } arm->semihosting_result = write(fd, buf, l); arm->semihosting_errno = errno; if (arm->semihosting_result >= 0) arm->semihosting_result = l - arm->semihosting_result; free(buf); } } } break; case 0x06: /* SYS_READ */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); ssize_t l = target_buffer_get_u32(target, params+8); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "read"; fileio_info->param_1 = fd; fileio_info->param_2 = a; fileio_info->param_3 = l; } else { uint8_t *buf = malloc(l); if (!buf) { arm->semihosting_result = -1; arm->semihosting_errno = ENOMEM; } else { arm->semihosting_result = read(fd, buf, l); arm->semihosting_errno = errno; if (arm->semihosting_result >= 0) { retval = target_write_buffer(target, a, arm->semihosting_result, buf); if (retval != ERROR_OK) { free(buf); return retval; } arm->semihosting_result = l - arm->semihosting_result; } free(buf); } } } break; case 0x07: /* SYS_READC */ if (arm->is_semihosting_fileio) { LOG_ERROR("SYS_READC not supported by semihosting fileio"); return ERROR_FAIL; } arm->semihosting_result = getchar(); break; case 0x08: /* SYS_ISERROR */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; arm->semihosting_result = (target_buffer_get_u32(target, params+0) != 0); break; case 0x09: /* SYS_ISTTY */ if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "isatty"; fileio_info->param_1 = r1; } else { retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; arm->semihosting_result = isatty(target_buffer_get_u32(target, params+0)); } break; case 0x0a: /* SYS_SEEK */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); off_t pos = target_buffer_get_u32(target, params+4); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "lseek"; fileio_info->param_1 = fd; fileio_info->param_2 = pos; fileio_info->param_3 = SEEK_SET; } else { arm->semihosting_result = lseek(fd, pos, SEEK_SET); arm->semihosting_errno = errno; if (arm->semihosting_result == pos) arm->semihosting_result = 0; } } break; case 0x0c: /* SYS_FLEN */ if (arm->is_semihosting_fileio) { LOG_ERROR("SYS_FLEN not supported by semihosting fileio"); return ERROR_FAIL; } retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); struct stat buf; arm->semihosting_result = fstat(fd, &buf); if (arm->semihosting_result == -1) { arm->semihosting_errno = errno; arm->semihosting_result = -1; break; } arm->semihosting_result = buf.st_size; } break; case 0x0e: /* SYS_REMOVE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "unlink"; fileio_info->param_1 = a; fileio_info->param_2 = l; } else { if (l <= 255) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; arm->semihosting_result = remove((char *)fn); arm->semihosting_errno = errno; } else { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } } } break; case 0x0f: /* SYS_RENAME */ retval = target_read_memory(target, r1, 4, 4, params); if (retval != ERROR_OK) return retval; else { uint32_t a1 = target_buffer_get_u32(target, params+0); uint32_t l1 = target_buffer_get_u32(target, params+4); uint32_t a2 = target_buffer_get_u32(target, params+8); uint32_t l2 = target_buffer_get_u32(target, params+12); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "rename"; fileio_info->param_1 = a1; fileio_info->param_2 = l1; fileio_info->param_3 = a2; fileio_info->param_4 = l2; } else { if (l1 <= 255 && l2 <= 255) { uint8_t fn1[256], fn2[256]; retval = target_read_memory(target, a1, 1, l1, fn1); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, a2, 1, l2, fn2); if (retval != ERROR_OK) return retval; fn1[l1] = 0; fn2[l2] = 0; arm->semihosting_result = rename((char *)fn1, (char *)fn2); arm->semihosting_errno = errno; } else { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } } } break; case 0x11: /* SYS_TIME */ arm->semihosting_result = time(NULL); break; case 0x13: /* SYS_ERRNO */ arm->semihosting_result = arm->semihosting_errno; break; case 0x15: /* SYS_GET_CMDLINE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : ""; uint32_t s = strlen(arg) + 1; if (l < s) arm->semihosting_result = -1; else { retval = target_write_buffer(target, a, s, (uint8_t *)arg); if (retval != ERROR_OK) return retval; arm->semihosting_result = 0; } } break; case 0x16: /* SYS_HEAPINFO */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); /* tell the remote we have no idea */ memset(params, 0, 4*4); retval = target_write_memory(target, a, 4, 4, params); if (retval != ERROR_OK) return retval; arm->semihosting_result = 0; } break; case 0x18: /* angel_SWIreason_ReportException */ switch (r1) { case 0x20026: /* ADP_Stopped_ApplicationExit */ fprintf(stderr, "semihosting: *** application exited ***\n"); break; case 0x20000: /* ADP_Stopped_BranchThroughZero */ case 0x20001: /* ADP_Stopped_UndefinedInstr */ case 0x20002: /* ADP_Stopped_SoftwareInterrupt */ case 0x20003: /* ADP_Stopped_PrefetchAbort */ case 0x20004: /* ADP_Stopped_DataAbort */ case 0x20005: /* ADP_Stopped_AddressException */ case 0x20006: /* ADP_Stopped_IRQ */ case 0x20007: /* ADP_Stopped_FIQ */ case 0x20020: /* ADP_Stopped_BreakPoint */ case 0x20021: /* ADP_Stopped_WatchPoint */ case 0x20022: /* ADP_Stopped_StepComplete */ case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */ case 0x20024: /* ADP_Stopped_InternalError */ case 0x20025: /* ADP_Stopped_UserInterruption */ case 0x20027: /* ADP_Stopped_StackOverflow */ case 0x20028: /* ADP_Stopped_DivisionByZero */ case 0x20029: /* ADP_Stopped_OSSpecific */ default: fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1); } return target_call_event_callbacks(target, TARGET_EVENT_HALTED); case 0x12: /* SYS_SYSTEM */ /* Provide SYS_SYSTEM functionality. Uses the * libc system command, there may be a reason *NOT* * to use this, but as I can't think of one, I * implemented it this way. */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t len = target_buffer_get_u32(target, params+4); uint32_t c_ptr = target_buffer_get_u32(target, params); if (arm->is_semihosting_fileio) { arm->semihosting_hit_fileio = true; fileio_info->identifier = "system"; fileio_info->param_1 = c_ptr; fileio_info->param_2 = len; } else { uint8_t cmd[256]; if (len > 255) { arm->semihosting_result = -1; arm->semihosting_errno = EINVAL; } else { memset(cmd, 0x0, 256); retval = target_read_memory(target, c_ptr, 1, len, cmd); if (retval != ERROR_OK) return retval; else arm->semihosting_result = system((const char *)cmd); } } } break; case 0x0d: /* SYS_TMPNAM */ case 0x10: /* SYS_CLOCK */ case 0x17: /* angel_SWIreason_EnterSVC */ case 0x30: /* SYS_ELAPSED */ case 0x31: /* SYS_TICKFREQ */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) r0); arm->semihosting_result = -1; arm->semihosting_errno = ENOTSUP; } return ERROR_OK; }
int default_memory_remove_breakpoint (struct bp_target_info *bp_tgt) { return target_write_memory (bp_tgt->placed_address, bp_tgt->shadow_contents, bp_tgt->placed_size); }
static void remote_fileio_func_fstat (char *buf) { CORE_ADDR ptrval; int fd, ret; long target_fd; LONGEST lnum; struct stat st; struct fio_stat fst; struct timeval tv; /* 1. Parameter: file descriptor */ if (remote_fileio_extract_int (&buf, &target_fd)) { remote_fileio_ioerror (); return; } fd = remote_fileio_map_fd ((int) target_fd); if (fd == FIO_FD_INVALID) { remote_fileio_badfd (); return; } /* 2. Parameter: Ptr to struct stat */ if (remote_fileio_extract_long (&buf, &lnum)) { remote_fileio_ioerror (); return; } ptrval = (CORE_ADDR) lnum; remote_fio_no_longjmp = 1; if (fd == FIO_FD_CONSOLE_IN || fd == FIO_FD_CONSOLE_OUT) { host_to_fileio_uint (1, fst.fst_dev); memset (&st, 0, sizeof (st)); st.st_mode = S_IFCHR | (fd == FIO_FD_CONSOLE_IN ? S_IRUSR : S_IWUSR); st.st_nlink = 1; #ifdef HAVE_GETUID st.st_uid = getuid (); #endif #ifdef HAVE_GETGID st.st_gid = getgid (); #endif #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE st.st_blksize = 512; #endif #if HAVE_STRUCT_STAT_ST_BLOCKS st.st_blocks = 0; #endif if (!gettimeofday (&tv, NULL)) st.st_atime = st.st_mtime = st.st_ctime = tv.tv_sec; else st.st_atime = st.st_mtime = st.st_ctime = (time_t) 0; ret = 0; } else ret = fstat (fd, &st); if (ret == -1) { remote_fileio_return_errno (-1); return; } if (ptrval) { host_to_fileio_stat (&st, &fst); errno = target_write_memory (ptrval, (gdb_byte *) &fst, sizeof fst); if (errno != 0) { remote_fileio_return_errno (-1); return; } } remote_fileio_return_success (ret); }
static void restore_section_callback(bfd *ibfd, asection *isec, void *args) { struct callback_data *data = (struct callback_data *)args; bfd_vma sec_start = bfd_section_vma(ibfd, isec); bfd_size_type size = bfd_section_size(ibfd, isec); bfd_vma sec_end = (sec_start + size); bfd_size_type sec_offset = 0UL; bfd_size_type sec_load_count = size; struct cleanup *old_chain; gdb_byte *buf; int ret; /* Ignore non-loadable sections, eg. from elf files: */ if (!(bfd_get_section_flags(ibfd, isec) & SEC_LOAD)) return; /* Does the section overlap with the desired restore range? */ if ((sec_end <= data->load_start) || ((data->load_end > 0) && (sec_start >= data->load_end))) { /* No, no useable data in this section. */ printf_filtered(_("skipping section %s...\n"), bfd_section_name(ibfd, isec)); return; } /* Compare section address range with user-requested address range (if any). Compute where the actual transfer should start and end. */ if (sec_start < data->load_start) sec_offset = (data->load_start - sec_start); /* Size of a partial transfer: */ sec_load_count -= sec_offset; if ((data->load_end > 0) && (sec_end > data->load_end)) sec_load_count -= (sec_end - data->load_end); /* Get the data. */ buf = (gdb_byte *)xmalloc((size_t)size); old_chain = make_cleanup(xfree, buf); if (!bfd_get_section_contents(ibfd, isec, buf, 0, size)) error(_("Failed to read bfd file %s: '%s'."), bfd_get_filename(ibfd), bfd_errmsg(bfd_get_error())); printf_filtered("Restoring section %s (0x%lx to 0x%lx)", bfd_section_name(ibfd, isec), (unsigned long)sec_start, (unsigned long)sec_end); if ((data->load_offset != 0) || (data->load_start != 0) || (data->load_end != 0)) printf_filtered(" into memory (0x%s to 0x%s)\n", paddr_nz((unsigned long)sec_start + sec_offset + data->load_offset), paddr_nz((unsigned long)sec_start + sec_offset + data->load_offset + sec_load_count)); else puts_filtered("\n"); /* Write the data: */ ret = target_write_memory((sec_start + sec_offset + data->load_offset), (buf + sec_offset), (int)sec_load_count); if (ret != 0) warning(_("restore: memory write failed (%s)."), safe_strerror(ret)); do_cleanups(old_chain); return; }
/* APPLE LOCAL BEGIN: segment binary file download: */ static void restore_binary_file(char *filename, struct callback_data *data) { FILE *file = fopen_with_cleanup(filename, FOPEN_RB); gdb_byte *buf; long len; long total_file_bytes; long bytes_to_read_from_file; CORE_ADDR addrp; /* Get the file size for reading: */ if (fseek(file, 0L, SEEK_END) == 0) total_file_bytes = ftell(file); else perror_with_name(filename); if (total_file_bytes <= (int)data->load_start) error(_("Start address is greater than length of binary file %s."), filename); bytes_to_read_from_file = (int)data->load_end; if (bytes_to_read_from_file == 0) bytes_to_read_from_file = total_file_bytes; if (data->load_start > 0) bytes_to_read_from_file -= (int)data->load_start; if (bytes_to_read_from_file > total_file_bytes) bytes_to_read_from_file = total_file_bytes; printf_filtered("Restoring binary file %s into memory (0x%s to 0x%s)\n", filename, paddr_nz(data->load_start + data->load_offset), paddr_nz(data->load_start + data->load_offset + bytes_to_read_from_file)); /* Now set the file pos to the requested load start pos: */ if (fseek(file, (long)data->load_start, SEEK_SET) != 0) perror_with_name(filename); if (bytes_to_read_from_file > g_max_binary_file_chunk) len = g_max_binary_file_chunk; else len = bytes_to_read_from_file; buf = (gdb_byte *)xmalloc(len); make_cleanup(xfree, buf); addrp = (data->load_start + data->load_offset); /* BYTES_TO_READ_FROM_FILE decreases each time through this loop; we read g_max_binary_file_chunk or less bytes at each iteration. */ while (bytes_to_read_from_file > 0) { int max_errors; /* The last chunk we shall be reading -- at this point our LEN buffer is larger than the remaining number of bytes to be read; cap it so we do NOT read off the end of the file. */ if (len > bytes_to_read_from_file) len = bytes_to_read_from_file; if (fread(buf, 1, len, file) != (size_t)len) perror_with_name(filename); max_errors = 2; while (max_errors > 0) { printf_unfiltered(_("Writing 0x%s bytes to 0x%s\n"), paddr_nz(len), paddr_nz(addrp)); gdb_flush (gdb_stdout); if (target_write_memory(addrp, buf, (int)len) == 0) { addrp += len; break; } else { warning(_("restore: memory write failed - retrying.")); max_errors--; } } if (max_errors == 0) error ("restore: memory write failed."); bytes_to_read_from_file -= len; } }
static void gdbscm_memory_port_write (SCM port, const void *void_data, size_t size) { scm_t_port *pt = SCM_PTAB_ENTRY (port); ioscm_memory_port *iomem = (ioscm_memory_port *) SCM_STREAM (port); const gdb_byte *data = (const gdb_byte *) void_data; /* There's no way to indicate a short write, so if the request goes past the end of the port's memory range, flag an error. */ if (size > iomem->size - iomem->current) { gdbscm_out_of_range_error (FUNC_NAME, 0, gdbscm_scm_from_ulongest (size), _("writing beyond end of memory range")); } if (pt->write_buf == &pt->shortbuf) { /* Unbuffered port. */ if (target_write_memory (iomem->start + iomem->current, data, size) != 0) gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL); iomem->current += size; return; } /* Note: The edge case of what to do when the buffer exactly fills is debatable. Guile flushes when the buffer exactly fills up, so we do too. It's counter-intuitive to my mind, but in case there's a subtlety somewhere that depends on this, we do the same. */ { size_t space = pt->write_end - pt->write_pos; if (size < space) { /* Data fits in buffer, and does not fill it. */ memcpy (pt->write_pos, data, size); pt->write_pos += size; } else { memcpy (pt->write_pos, data, space); pt->write_pos = pt->write_end; gdbscm_memory_port_flush (port); { const gdb_byte *ptr = data + space; size_t remaining = size - space; if (remaining >= pt->write_buf_size) { if (target_write_memory (iomem->start + iomem->current, ptr, remaining) != 0) gdbscm_memory_error (FUNC_NAME, _("error writing memory"), SCM_EOL); iomem->current += remaining; } else { memcpy (pt->write_pos, ptr, remaining); pt->write_pos += remaining; } } } } }
/* Start a low level flash write for the specified region */ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; uint32_t address = NRF5_FLASH_BASE + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes); assert(bytes % 4 == 0); /* allocate working area with flash programming code */ if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); for (; bytes > 0; bytes -= 4) { retval = target_write_memory(chip->target, offset, 4, 1, buffer); if (retval != ERROR_OK) return retval; retval = nrf5_wait_for_nvmc(chip); if (retval != ERROR_OK) return retval; offset += 4; buffer += 4; } return ERROR_OK; } LOG_WARNING("using fast async flash loader. This is currently supported"); LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add"); LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it"); retval = target_write_buffer(target, write_algorithm->address, sizeof(nrf5_flash_write_code), nrf5_flash_write_code); if (retval != ERROR_OK) return retval; /* memory buffer */ while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) { buffer_size /= 2; buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */ if (buffer_size <= 256) { /* free working area, write algorithm already allocated */ target_free_working_area(target, write_algorithm); LOG_WARNING("No large enough working area available, can't do block memory writes"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* byte count */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer start */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); /* target address */ buf_set_u32(reg_params[0].value, 0, 32, bytes); buf_set_u32(reg_params[1].value, 0, 32, source->address); buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size); buf_set_u32(reg_params[3].value, 0, 32, address); retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4, 0, NULL, 4, reg_params, source->address, source->size, write_algorithm->address, 0, &armv7m_info); target_free_working_area(target, source); target_free_working_area(target, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
static int do_semihosting(struct target *target) { struct arm *arm = target_to_arm(target); uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); uint8_t params[16]; int retval, result; /* * TODO: lots of security issues are not considered yet, such as: * - no validation on target provided file descriptors * - no safety checks on opened/deleted/renamed file paths * Beware the target app you use this support with. * * TODO: explore mapping requests to GDB's "File-I/O Remote * Protocol Extension" ... when GDB is active. */ switch (r0) { case 0x01: /* SYS_OPEN */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t m = target_buffer_get_u32(target, params+4); uint32_t l = target_buffer_get_u32(target, params+8); if (l <= 255 && m <= 11) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; if (strcmp((char *)fn, ":tt") == 0) { if (m < 4) result = dup(STDIN_FILENO); else result = dup(STDOUT_FILENO); } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ result = open((char *)fn, open_modeflags[m], 0644); } arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x02: /* SYS_CLOSE */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); result = close(fd); arm->semihosting_errno = errno; } break; case 0x03: /* SYS_WRITEC */ { unsigned char c; retval = target_read_memory(target, r1, 1, 1, &c); if (retval != ERROR_OK) return retval; putchar(c); result = 0; } break; case 0x04: /* SYS_WRITE0 */ do { unsigned char c; retval = target_read_memory(target, r1++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; putchar(c); } while (1); result = 0; break; case 0x05: /* SYS_WRITE */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); size_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { retval = target_read_buffer(target, a, l, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = write(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) result = l - result; free(buf); } } break; case 0x06: /* SYS_READ */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); ssize_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { result = read(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) { retval = target_write_buffer(target, a, result, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = l - result; } free(buf); } } break; case 0x07: /* SYS_READC */ result = getchar(); break; case 0x08: /* SYS_ISERROR */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = (target_buffer_get_u32(target, params+0) != 0); break; case 0x09: /* SYS_ISTTY */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = isatty(target_buffer_get_u32(target, params+0)); break; case 0x0a: /* SYS_SEEK */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); off_t pos = target_buffer_get_u32(target, params+4); result = lseek(fd, pos, SEEK_SET); arm->semihosting_errno = errno; if (result == pos) result = 0; } break; case 0x0c: /* SYS_FLEN */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); struct stat buf; result = fstat(fd, &buf); if (result == -1) { arm->semihosting_errno = errno; result = -1; break; } result = buf.st_size; } break; case 0x0e: /* SYS_REMOVE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); if (l <= 255) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; result = remove((char *)fn); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x0f: /* SYS_RENAME */ retval = target_read_memory(target, r1, 4, 4, params); if (retval != ERROR_OK) return retval; else { uint32_t a1 = target_buffer_get_u32(target, params+0); uint32_t l1 = target_buffer_get_u32(target, params+4); uint32_t a2 = target_buffer_get_u32(target, params+8); uint32_t l2 = target_buffer_get_u32(target, params+12); if (l1 <= 255 && l2 <= 255) { uint8_t fn1[256], fn2[256]; retval = target_read_memory(target, a1, 1, l1, fn1); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, a2, 1, l2, fn2); if (retval != ERROR_OK) return retval; fn1[l1] = 0; fn2[l2] = 0; result = rename((char *)fn1, (char *)fn2); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x11: /* SYS_TIME */ result = time(NULL); break; case 0x13: /* SYS_ERRNO */ result = arm->semihosting_errno; break; case 0x15: /* SYS_GET_CMDLINE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); char *arg = "foobar"; uint32_t s = strlen(arg) + 1; if (l < s) result = -1; else { retval = target_write_buffer(target, a, s, (uint8_t *)arg); if (retval != ERROR_OK) return retval; result = 0; } } break; case 0x16: /* SYS_HEAPINFO */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); /* tell the remote we have no idea */ memset(params, 0, 4*4); retval = target_write_memory(target, a, 4, 4, params); if (retval != ERROR_OK) return retval; result = 0; } break; case 0x18: /* angel_SWIreason_ReportException */ switch (r1) { case 0x20026: /* ADP_Stopped_ApplicationExit */ fprintf(stderr, "semihosting: *** application exited ***\n"); break; case 0x20000: /* ADP_Stopped_BranchThroughZero */ case 0x20001: /* ADP_Stopped_UndefinedInstr */ case 0x20002: /* ADP_Stopped_SoftwareInterrupt */ case 0x20003: /* ADP_Stopped_PrefetchAbort */ case 0x20004: /* ADP_Stopped_DataAbort */ case 0x20005: /* ADP_Stopped_AddressException */ case 0x20006: /* ADP_Stopped_IRQ */ case 0x20007: /* ADP_Stopped_FIQ */ case 0x20020: /* ADP_Stopped_BreakPoint */ case 0x20021: /* ADP_Stopped_WatchPoint */ case 0x20022: /* ADP_Stopped_StepComplete */ case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */ case 0x20024: /* ADP_Stopped_InternalError */ case 0x20025: /* ADP_Stopped_UserInterruption */ case 0x20027: /* ADP_Stopped_StackOverflow */ case 0x20028: /* ADP_Stopped_DivisionByZero */ case 0x20029: /* ADP_Stopped_OSSpecific */ default: fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1); } return target_call_event_callbacks(target, TARGET_EVENT_HALTED); case 0x12: /* SYS_SYSTEM */ /* Provide SYS_SYSTEM functionality. Uses the * libc system command, there may be a reason *NOT* * to use this, but as I can't think of one, I * implemented it this way. */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t len = target_buffer_get_u32(target, params+4); uint32_t c_ptr = target_buffer_get_u32(target, params); uint8_t cmd[256]; if (len > 255) { result = -1; arm->semihosting_errno = EINVAL; } else { memset(cmd, 0x0, 256); retval = target_read_memory(target, c_ptr, 1, len, cmd); if (retval != ERROR_OK) return retval; else result = system((const char *)cmd); } } break; case 0x0d: /* SYS_TMPNAM */ case 0x10: /* SYS_CLOCK */ case 0x17: /* angel_SWIreason_EnterSVC */ case 0x30: /* SYS_ELAPSED */ case 0x31: /* SYS_TICKFREQ */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) r0); result = -1; arm->semihosting_errno = ENOTSUP; } /* resume execution to the original mode */ /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ if (is_arm7_9(target_to_arm7_9(target))) { uint32_t spsr; /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; /* LR --> PC */ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32)); arm->core_cache->reg_list[15].dirty = 1; /* saved PSR --> current PSR */ spsr = buf_get_u32(arm->spsr->value, 0, 32); /* REVISIT should this be arm_set_cpsr(arm, spsr) * instead of a partially unrolled version? */ buf_set_u32(arm->cpsr->value, 0, 32, spsr); arm->cpsr->dirty = 1; arm->core_mode = spsr & 0x1f; if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ /* return result in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; } return target_resume(target, 1, 0, 0, 0); }
static void remote_fileio_func_read (char *buf) { long target_fd, num; LONGEST lnum; CORE_ADDR ptrval; int fd, ret; gdb_byte *buffer; size_t length; off_t old_offset, new_offset; /* 1. Parameter: file descriptor */ if (remote_fileio_extract_int (&buf, &target_fd)) { remote_fileio_ioerror (); return; } fd = remote_fileio_map_fd ((int) target_fd); if (fd == FIO_FD_INVALID) { remote_fileio_badfd (); return; } /* 2. Parameter: buffer pointer */ if (remote_fileio_extract_long (&buf, &lnum)) { remote_fileio_ioerror (); return; } ptrval = (CORE_ADDR) lnum; /* 3. Parameter: buffer length */ if (remote_fileio_extract_int (&buf, &num)) { remote_fileio_ioerror (); return; } length = (size_t) num; switch (fd) { case FIO_FD_CONSOLE_OUT: remote_fileio_badfd (); return; case FIO_FD_CONSOLE_IN: { static char *remaining_buf = NULL; static int remaining_length = 0; buffer = (gdb_byte *) xmalloc (16384); if (remaining_buf) { remote_fio_no_longjmp = 1; if (remaining_length > length) { memcpy (buffer, remaining_buf, length); memmove (remaining_buf, remaining_buf + length, remaining_length - length); remaining_length -= length; ret = length; } else { memcpy (buffer, remaining_buf, remaining_length); xfree (remaining_buf); remaining_buf = NULL; ret = remaining_length; } } else { /* Windows (at least XP and Server 2003) has difficulty with large reads from consoles. If a handle is backed by a real console device, overly large reads from the handle will fail and set errno == ENOMEM. On a Windows Server 2003 system where I tested, reading 26608 bytes from the console was OK, but anything above 26609 bytes would fail. The limit has been observed to vary on different systems. So, we limit this read to something smaller than that - by a safe margin, in case the limit depends on system resources or version. */ ret = ui_file_read (gdb_stdtargin, (char *) buffer, 16383); remote_fio_no_longjmp = 1; if (ret > 0 && (size_t)ret > length) { remaining_buf = (char *) xmalloc (ret - length); remaining_length = ret - length; memcpy (remaining_buf, buffer + length, remaining_length); ret = length; } } } break; default: buffer = (gdb_byte *) xmalloc (length); /* POSIX defines EINTR behaviour of read in a weird way. It's allowed for read() to return -1 even if "some" bytes have been read. It has been corrected in SUSv2 but that doesn't help us much... Therefore a complete solution must check how many bytes have been read on EINTR to return a more reliable value to the target */ old_offset = lseek (fd, 0, SEEK_CUR); remote_fio_no_longjmp = 1; ret = read (fd, buffer, length); if (ret < 0 && errno == EINTR) { new_offset = lseek (fd, 0, SEEK_CUR); /* If some data has been read, return the number of bytes read. The Ctrl-C flag is set in remote_fileio_reply() anyway. */ if (old_offset != new_offset) ret = new_offset - old_offset; } break; } if (ret > 0) { errno = target_write_memory (ptrval, buffer, ret); if (errno != 0) ret = -1; } if (ret < 0) remote_fileio_return_errno (-1); else remote_fileio_return_success (ret); xfree (buffer); }
void store_inferior_registers (int regno) { struct regs inferior_registers; struct fp_status inferior_fp_registers; int wanna_store = INT_REGS + STACK_REGS + FP_REGS; int store_pid; /* NOTE: cagney/2002-12-02: See comment in fetch_inferior_registers about threaded assumptions. */ store_pid = TIDGET (inferior_ptid); if (store_pid == 0) store_pid = PIDGET (inferior_ptid); /* First decide which pieces of machine-state we need to modify. Default for regno == -1 case is all pieces. */ if (regno >= 0) { if (FP0_REGNUM <= regno && regno < FP0_REGNUM + 32) { wanna_store = FP_REGS; } else { if (regno == SP_REGNUM) wanna_store = INT_REGS + STACK_REGS; else if (regno < L0_REGNUM || regno > I7_REGNUM) wanna_store = INT_REGS; else if (regno == FPS_REGNUM) wanna_store = FP_REGS; else wanna_store = STACK_REGS; } } /* See if we're forcing the stores to happen now, or deferring. */ if (regno == -2) { wanna_store = deferred_stores; deferred_stores = 0; } else { if (wanna_store == STACK_REGS) { /* Fall through and just store one stack reg. If we deferred it, we'd have to store them all, or remember more info. */ } else { deferred_stores |= wanna_store; return; } } if (wanna_store & STACK_REGS) { CORE_ADDR sp = *(unsigned int *) & registers[REGISTER_BYTE (SP_REGNUM)]; if (regno < 0 || regno == SP_REGNUM) { if (!register_valid[L0_REGNUM + 5]) internal_error (__FILE__, __LINE__, "failed internal consistency check"); target_write_memory (sp, ®isters[REGISTER_BYTE (L0_REGNUM)], 16 * REGISTER_RAW_SIZE (L0_REGNUM)); } else { if (!register_valid[regno]) internal_error (__FILE__, __LINE__, "failed internal consistency check"); target_write_memory (sp + REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM), ®isters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno)); } } if (wanna_store & INT_REGS) { if (!register_valid[G1_REGNUM]) internal_error (__FILE__, __LINE__, "failed internal consistency check"); memcpy (&inferior_registers.r_g1, ®isters[REGISTER_BYTE (G1_REGNUM)], 15 * REGISTER_RAW_SIZE (G1_REGNUM)); inferior_registers.r_ps = *(int *) ®isters[REGISTER_BYTE (PS_REGNUM)]; inferior_registers.r_pc = *(int *) ®isters[REGISTER_BYTE (PC_REGNUM)]; inferior_registers.r_npc = *(int *) ®isters[REGISTER_BYTE (NPC_REGNUM)]; inferior_registers.r_y = *(int *) ®isters[REGISTER_BYTE (Y_REGNUM)]; if (0 != ptrace (PTRACE_SETREGS, store_pid, (PTRACE_ARG3_TYPE) & inferior_registers, 0)) perror ("ptrace_setregs"); } if (wanna_store & FP_REGS) { if (!register_valid[FP0_REGNUM + 9]) internal_error (__FILE__, __LINE__, "failed internal consistency check"); memcpy (&inferior_fp_registers, ®isters[REGISTER_BYTE (FP0_REGNUM)], sizeof inferior_fp_registers.fpu_fr); memcpy (&inferior_fp_registers.Fpu_fsr, ®isters[REGISTER_BYTE (FPS_REGNUM)], sizeof (FPU_FSR_TYPE)); if (0 != ptrace (PTRACE_SETFPREGS, store_pid, (PTRACE_ARG3_TYPE) & inferior_fp_registers, 0)) perror ("ptrace_setfpregs"); } }
static void remote_fileio_func_stat (char *buf) { CORE_ADDR statptr, nameptr; int ret, namelength; char *pathname; LONGEST lnum; struct stat st; struct fio_stat fst; /* 1. Parameter: Ptr to pathname / length incl. trailing zero */ if (remote_fileio_extract_ptr_w_len (&buf, &nameptr, &namelength)) { remote_fileio_ioerror (); return; } /* 2. Parameter: Ptr to struct stat */ if (remote_fileio_extract_long (&buf, &lnum)) { remote_fileio_ioerror (); return; } statptr = (CORE_ADDR) lnum; /* Request pathname using 'm' packet */ pathname = alloca (namelength); if (target_read_memory (nameptr, (gdb_byte *) pathname, namelength) != 0) { remote_fileio_ioerror (); return; } remote_fio_no_longjmp = 1; ret = stat (pathname, &st); if (ret == -1) { remote_fileio_return_errno (-1); return; } /* Only operate on regular files and directories. */ if (!ret && !S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode)) { remote_fileio_reply (-1, FILEIO_EACCES); return; } if (statptr) { host_to_fileio_stat (&st, &fst); host_to_fileio_uint (0, fst.fst_dev); errno = target_write_memory (statptr, (gdb_byte *) &fst, sizeof fst); if (errno != 0) { remote_fileio_return_errno (-1); return; } } remote_fileio_return_success (ret); }
int agent_run_command (int pid, const char *cmd, int len) { int fd; int tid = agent_get_helper_thread_id (); ptid_t ptid = ptid_build (pid, tid, 0); #ifdef GDBSERVER int ret = write_inferior_memory (ipa_sym_addrs.addr_cmd_buf, (const unsigned char *) cmd, len); #else int ret = target_write_memory (ipa_sym_addrs.addr_cmd_buf, cmd, len); #endif if (ret != 0) { warning (_("unable to write")); return -1; } DEBUG_AGENT ("agent: resumed helper thread\n"); /* Resume helper thread. */ #ifdef GDBSERVER { struct thread_resume resume_info; resume_info.thread = ptid; resume_info.kind = resume_continue; resume_info.sig = GDB_SIGNAL_0; (*the_target->resume) (&resume_info, 1); } #else target_resume (ptid, 0, GDB_SIGNAL_0); #endif fd = gdb_connect_sync_socket (pid); if (fd >= 0) { char buf[1] = ""; int ret; DEBUG_AGENT ("agent: signalling helper thread\n"); do { ret = write (fd, buf, 1); } while (ret == -1 && errno == EINTR); DEBUG_AGENT ("agent: waiting for helper thread's response\n"); do { ret = read (fd, buf, 1); } while (ret == -1 && errno == EINTR); close (fd); DEBUG_AGENT ("agent: helper thread's response received\n"); } else return -1; /* Need to read response with the inferior stopped. */ if (!ptid_equal (ptid, null_ptid)) { struct target_waitstatus status; int was_non_stop = non_stop; /* Stop thread PTID. */ DEBUG_AGENT ("agent: stop helper thread\n"); #ifdef GDBSERVER { struct thread_resume resume_info; resume_info.thread = ptid; resume_info.kind = resume_stop; resume_info.sig = GDB_SIGNAL_0; (*the_target->resume) (&resume_info, 1); } non_stop = 1; mywait (ptid, &status, 0, 0); #else non_stop = 1; target_stop (ptid); memset (&status, 0, sizeof (status)); target_wait (ptid, &status, 0); #endif non_stop = was_non_stop; } if (fd >= 0) { #ifdef GDBSERVER if (read_inferior_memory (ipa_sym_addrs.addr_cmd_buf, (unsigned char *) cmd, IPA_CMD_BUF_SIZE)) #else if (target_read_memory (ipa_sym_addrs.addr_cmd_buf, (gdb_byte *) cmd, IPA_CMD_BUF_SIZE)) #endif { warning (_("Error reading command response")); return -1; } } return 0; }
void store_inferior_registers (int regno) { int whatregs = 0; if (regno == -1) whatregs = WHATREGS_FLOAT | WHATREGS_GEN | WHATREGS_STACK; else if (regno >= L0_REGNUM && regno <= I7_REGNUM) whatregs = WHATREGS_STACK; else if (regno >= FP0_REGNUM && regno < FP0_REGNUM + 32) whatregs = WHATREGS_FLOAT; else if (regno == SP_REGNUM) whatregs = WHATREGS_STACK | WHATREGS_GEN; else whatregs = WHATREGS_GEN; if (whatregs & WHATREGS_GEN) { struct econtext ec; /* general regs */ int retval; ec.tbr = read_register (TBR_REGNUM); memcpy (&ec.g1, ®isters[REGISTER_BYTE (G1_REGNUM)], 4 * REGISTER_RAW_SIZE (G1_REGNUM)); ec.psr = read_register (PS_REGNUM); ec.y = read_register (Y_REGNUM); ec.pc = read_register (PC_REGNUM); ec.npc = read_register (NPC_REGNUM); ec.wim = read_register (WIM_REGNUM); memcpy (ec.o, ®isters[REGISTER_BYTE (O0_REGNUM)], 8 * REGISTER_RAW_SIZE (O0_REGNUM)); errno = 0; retval = ptrace (PTRACE_SETREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) & ec, 0); if (errno) perror_with_name ("ptrace(PTRACE_SETREGS)"); } if (whatregs & WHATREGS_STACK) { int regoffset; CORE_ADDR sp; sp = read_register (SP_REGNUM); if (regno == -1 || regno == SP_REGNUM) { if (!register_valid[L0_REGNUM + 5]) internal_error (__FILE__, __LINE__, "failed internal consistency check"); target_write_memory (sp + FRAME_SAVED_I0, ®isters[REGISTER_BYTE (I0_REGNUM)], 8 * REGISTER_RAW_SIZE (I0_REGNUM)); target_write_memory (sp + FRAME_SAVED_L0, ®isters[REGISTER_BYTE (L0_REGNUM)], 8 * REGISTER_RAW_SIZE (L0_REGNUM)); } else if (regno >= L0_REGNUM && regno <= I7_REGNUM) { if (!register_valid[regno]) internal_error (__FILE__, __LINE__, "failed internal consistency check"); if (regno >= L0_REGNUM && regno <= L0_REGNUM + 7) regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (L0_REGNUM) + FRAME_SAVED_L0; else regoffset = REGISTER_BYTE (regno) - REGISTER_BYTE (I0_REGNUM) + FRAME_SAVED_I0; target_write_memory (sp + regoffset, ®isters[REGISTER_BYTE (regno)], REGISTER_RAW_SIZE (regno)); } } if (whatregs & WHATREGS_FLOAT) { struct fcontext fc; /* fp regs */ int retval; /* We read fcontext first so that we can get good values for fq_t... */ errno = 0; retval = ptrace (PTRACE_GETFPREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) & fc, 0); if (errno) perror_with_name ("ptrace(PTRACE_GETFPREGS)"); memcpy (fc.f.fregs, ®isters[REGISTER_BYTE (FP0_REGNUM)], 32 * REGISTER_RAW_SIZE (FP0_REGNUM)); fc.fsr = read_register (FPS_REGNUM); errno = 0; retval = ptrace (PTRACE_SETFPREGS, PIDGET (inferior_ptid), (PTRACE_ARG3_TYPE) & fc, 0); if (errno) perror_with_name ("ptrace(PTRACE_SETFPREGS)"); } }
/* call LPC1700/LPC2000 IAP function * uses 180 bytes working area * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait) * 0x8 to 0x1f: command parameter table (1+5 words) * 0x20 to 0x33: command result table (1+4 words) * 0x34 to 0xb3: stack (only 128b needed) */ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4]) { int retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; struct mem_param mem_params[2]; struct reg_param reg_params[5]; struct arm_algorithm arm_algo; /* for LPC2000 */ struct armv7m_algorithm armv7m_info; /* for LPC1700 */ uint32_t status_code; uint32_t iap_entry_point = 0; /* to make compiler happier */ /* regrab previously allocated working_area, or allocate a new one */ if (!lpc2000_info->iap_working_area) { uint8_t jump_gate[8]; /* make sure we have a working area */ if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } /* write IAP code to working area */ switch (lpc2000_info->variant) { case lpc1700: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; case lpc2000_v1: case lpc2000_v2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; default: LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate); if (retval != ERROR_OK) { LOG_ERROR( "Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address); return retval; } } switch (lpc2000_info->variant) { case lpc1700: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; iap_entry_point = 0x1fff1ff1; break; case lpc2000_v1: case lpc2000_v2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } /* command parameter table */ init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT); target_buffer_set_u32(target, mem_params[0].value, code); target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]); target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]); target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]); target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]); target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]); init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08); /* command result table */ init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20); /* IAP entry point */ init_reg_param(®_params[2], "r12", 32, PARAM_OUT); buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { case lpc1700: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4); /* return address */ init_reg_param(®_params[4], "lr", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */ target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info); break; case lpc2000_v1: case lpc2000_v2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4); /* return address */ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04); target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &arm_algo); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } status_code = target_buffer_get_u32(target, mem_params[1].value); result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04); result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08); result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c); result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10); LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ") completed with result = %8.8" PRIx32, code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return status_code; }
void sparc_collect_rwindow (const struct regcache *regcache, CORE_ADDR sp, int regnum) { int offset = 0; gdb_byte buf[8]; int i; if (sp & 1) { /* Registers are 64-bit. */ sp += BIAS; for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++) { if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i) { regcache_raw_collect (regcache, i, buf); /* Handle StackGhost. */ if (i == SPARC_I7_REGNUM) { ULONGEST wcookie = sparc_fetch_wcookie (); ULONGEST i7 = extract_unsigned_integer (buf + offset, 8); store_unsigned_integer (buf, 8, i7 ^ wcookie); } target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 8), buf, 8); } } } else { /* Registers are 32-bit. Toss any sign-extension of the stack pointer. */ sp &= 0xffffffffUL; /* Only use the bottom half if we're in 64-bit mode. */ if (gdbarch_ptr_bit (current_gdbarch) == 64) offset = 4; for (i = SPARC_L0_REGNUM; i <= SPARC_I7_REGNUM; i++) { if (regnum == -1 || regnum == SPARC_SP_REGNUM || regnum == i) { regcache_raw_collect (regcache, i, buf); /* Handle StackGhost. */ if (i == SPARC_I7_REGNUM) { ULONGEST wcookie = sparc_fetch_wcookie (); ULONGEST i7 = extract_unsigned_integer (buf + offset, 4); store_unsigned_integer (buf + offset, 4, i7 ^ wcookie); } target_write_memory (sp + ((i - SPARC_L0_REGNUM) * 4), buf + offset, 4); } } } }
/* The write routine stub. */ static int nuc1x_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t i, timeout, status; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } LOG_INFO("Novoton NUC: FLASH Write ..."); int retval = nuc1x_reset2lprom(bank); if (retval != ERROR_OK) return retval; retval = nuc1x_init_iap(bank); if (retval != ERROR_OK) return retval; retval = nuc1x_unlock(bank); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUC1X_FLASH_ISPCMD, ISPCMD_WRITE); if (retval != ERROR_OK) return retval; /* program command */ for (i = 0; i < count; i += 4) { LOG_DEBUG("write longword @ %08" PRIX32, (uint32_t)(offset + i)); uint8_t padding[4] = {0xff, 0xff, 0xff, 0xff}; memcpy(padding, buffer + i, MIN(4, count-i)); retval = target_write_u32(target, NUC1X_FLASH_ISPADR, bank->base + offset + i); if (retval != ERROR_OK) return retval; retval = target_write_memory(target, NUC1X_FLASH_ISPDAT, 4, 1, padding); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, NUC1X_FLASH_ISPTRG, ISPTRG_ISPGO); if (retval != ERROR_OK) return retval; /* wait for busy to clear - check the GO flag */ timeout = 100; for (;;) { retval = target_read_u32(target, NUC1X_FLASH_ISPTRG, &status); if (retval != ERROR_OK) return retval; LOG_DEBUG("status: 0x%" PRIx32 "", status); if (status == 0) break; if (timeout-- <= 0) { LOG_DEBUG("timed out waiting for flash"); return ERROR_FAIL; } busy_sleep(1); /* can use busy sleep for short times. */ } /* check for failure */ retval = target_read_u32(target, NUC1X_FLASH_ISPCON, &status); if (retval != ERROR_OK) return retval; if ((status & ISPCON_ISPFF) != 0) { LOG_DEBUG("failure: 0x%" PRIx32 "", status); /* if bit is set, then must write to it to clear it. */ retval = target_write_u32(target, NUC1X_FLASH_ISPCON, ISPCON_ISPFF); if (retval != ERROR_OK) return retval; } else { LOG_DEBUG("writed OK"); } } retval = nuc1x_reset(bank); if (retval != ERROR_OK) return retval; /* done, */ LOG_DEBUG("Write done."); return ERROR_OK; }