#include <stdarg.h>
#include "general.h"
#include "platform.h"
#include "remote.h"
#include "gdb_main.h"
#include "gdb_packet.h"
#include "gdb_if.h"
#include "jtagtap.h"
#include "swd.h"
#include "spi.h"
#include "sfdp.h"
#include "target.h"
#include "adiv5.h"
#include "version.h"
#include "exception.h"
#include "hex_utils.h"
#define HTON(x) (((x) <= '9') ? (x) - '0' : ((TOUPPER(x)) - 'A' + 10))
#define TOUPPER(x) ((((x) >= 'a') && ((x) <= 'z')) ? ((x) - ('a' - 'A')) : (x))
#define ISHEX(x) ((((x) >= '0') && ((x) <= '9')) || (((x) >= 'A') && ((x) <= 'F')) || (((x) >= 'a') && ((x) <= 'f')))
uint64_t remote_hex_string_to_num(const uint32_t max, const char *const str)
{
uint64_t ret = 0;
for (size_t i = 0; i < max; ++i) {
const char value = str[i];
if (!ISHEX(value))
return ret;
ret = (ret << 4U) | HTON(value);
}
return ret;
}
#if PC_HOSTED == 0
static void remote_send_buf(const void *const buffer, const size_t len)
{
char hex[2] = {0};
const uint8_t *const data = (const uint8_t *)buffer;
for (size_t offset = 0; offset < len; ++offset) {
hexify(hex, data + offset, 1U);
gdb_if_putchar(hex[0], 0);
gdb_if_putchar(hex[1], 0);
}
}
static void remote_respond_buf(const char response_code, const void *const buffer, const size_t len)
{
gdb_if_putchar(REMOTE_RESP, 0);
gdb_if_putchar(response_code, 0);
remote_send_buf(buffer, len);
gdb_if_putchar(REMOTE_EOM, 1);
}
static void remote_respond(const char response_code, uint64_t param)
{
gdb_if_putchar(REMOTE_RESP, false);
gdb_if_putchar(response_code, false);
char response[16];
size_t idx = 0;
for (; idx < 16U && param; ++idx) {
response[idx] = hex_digit(param & 0xfU);
param >>= 4U;
}
if (!idx)
response[idx++] = '0';
for (; idx; --idx)
gdb_if_putchar(response[idx - 1U], false);
gdb_if_putchar(REMOTE_EOM, true);
}
static void remote_respond_string(const char response_code, const char *const str)
{
gdb_if_putchar(REMOTE_RESP, 0);
gdb_if_putchar(response_code, 0);
const size_t str_length = strlen(str);
for (size_t idx = 0; idx < str_length; ++idx) {
const char chr = str[idx];
if (chr == '$' || chr == REMOTE_SOM || chr == REMOTE_EOM)
gdb_if_putchar(' ', 0);
else
gdb_if_putchar(chr, 0);
}
gdb_if_putchar(REMOTE_EOM, 1);
}
static adiv5_debug_port_s remote_dp = {
.ap_read = firmware_ap_read,
.ap_write = firmware_ap_write,
.mem_read = advi5_mem_read_bytes,
.mem_write = adiv5_mem_write_bytes,
};
static void remote_packet_process_swd(const char *const packet, const size_t packet_len)
{
switch (packet[1]) {
case REMOTE_INIT:
if (packet_len == 2) {
remote_dp.dp_read = firmware_swdp_read;
remote_dp.low_access = firmware_swdp_low_access;
remote_dp.abort = firmware_swdp_abort;
swdptap_init();
remote_respond(REMOTE_RESP_OK, 0);
} else
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_WRONGLEN);
break;
case REMOTE_IN_PAR: {
const size_t clock_cycles = remote_hex_string_to_num(2, packet + 2);
uint32_t result = 0;
const bool parity_error = swd_proc.seq_in_parity(&result, clock_cycles);
remote_respond(parity_error ? REMOTE_RESP_PARERR : REMOTE_RESP_OK, result);
break;
}
case REMOTE_IN: {
const size_t clock_cycles = remote_hex_string_to_num(2, packet + 2);
const uint32_t result = swd_proc.seq_in(clock_cycles);
remote_respond(REMOTE_RESP_OK, result);
break;
}
case REMOTE_OUT: {
const size_t clock_cycles = remote_hex_string_to_num(2, packet + 2);
const uint32_t data = remote_hex_string_to_num(-1, packet + 4);
swd_proc.seq_out(data, clock_cycles);
remote_respond(REMOTE_RESP_OK, 0);
break;
}
case REMOTE_OUT_PAR: {
const size_t clock_cycles = remote_hex_string_to_num(2, packet + 2);
const uint32_t data = remote_hex_string_to_num(-1, packet + 4);
swd_proc.seq_out_parity(data, clock_cycles);
remote_respond(REMOTE_RESP_OK, 0);
break;
}
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
}
static void remote_packet_process_jtag(const char *const packet, const size_t packet_len)
{
switch (packet[1]) {
case REMOTE_INIT:
remote_dp.dp_read = fw_adiv5_jtagdp_read;
remote_dp.low_access = fw_adiv5_jtagdp_low_access;
remote_dp.abort = adiv5_jtagdp_abort;
jtagtap_init();
remote_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_RESET:
jtag_proc.jtagtap_reset();
remote_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_TMS: {
const size_t clock_cycles = remote_hex_string_to_num(2, packet + 2);
const uint32_t tms_states = remote_hex_string_to_num(2, packet + 4);
if (packet_len < 4U)
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_WRONGLEN);
else {
jtag_proc.jtagtap_tms_seq(tms_states, clock_cycles);
remote_respond(REMOTE_RESP_OK, 0);
}
break;
}
case REMOTE_CYCLE: {
const size_t clock_cycles = remote_hex_string_to_num(8, packet + 4);
const bool tms = packet[2] != '0';
const bool tdi = packet[3] != '0';
jtag_proc.jtagtap_cycle(tms, tdi, clock_cycles);
remote_respond(REMOTE_RESP_OK, 0);
break;
}
case REMOTE_TDITDO_TMS:
case REMOTE_TDITDO_NOTMS: {
if (packet_len < 5U)
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_WRONGLEN);
else {
const size_t clock_cycles = remote_hex_string_to_num(2, packet + 2);
const uint64_t data_in = remote_hex_string_to_num(-1, packet + 4);
uint64_t data_out = 0;
jtag_proc.jtagtap_tdi_tdo_seq(
(uint8_t *)&data_out, packet[1] == REMOTE_TDITDO_TMS, (const uint8_t *)&data_in, clock_cycles);
remote_respond(REMOTE_RESP_OK, data_out);
}
break;
}
case REMOTE_NEXT: {
if (packet_len != 4U)
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_WRONGLEN);
else {
const bool tdo = jtag_proc.jtagtap_next(packet[2] == '1', packet[3] == '1');
remote_respond(REMOTE_RESP_OK, tdo ? 1U : 0U);
}
break;
}
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
}
#if !defined(BOARD_IDENT) && defined(BOARD_IDENT)
#define PLATFORM_IDENT BOARD_IDENT
#endif
static void remote_packet_process_general(char *packet, const size_t packet_len)
{
(void)packet_len;
switch (packet[1]) {
case REMOTE_VOLTAGE:
remote_respond_string(REMOTE_RESP_OK, platform_target_voltage());
break;
case REMOTE_NRST_SET:
platform_nrst_set_val(packet[2] == '1');
remote_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_NRST_GET:
remote_respond(REMOTE_RESP_OK, platform_nrst_get_val());
break;
case REMOTE_FREQ_SET:
platform_max_frequency_set(remote_hex_string_to_num(8, packet + 2));
remote_respond(REMOTE_RESP_OK, 0);
break;
case REMOTE_FREQ_GET: {
const uint32_t freq = platform_max_frequency_get();
remote_respond_buf(REMOTE_RESP_OK, (uint8_t *)&freq, 4);
break;
}
case REMOTE_PWR_SET:
#ifdef PLATFORM_HAS_POWER_SWITCH
if (packet[2] == '1' && !platform_target_get_power() &&
platform_target_voltage_sense() > POWER_CONFLICT_THRESHOLD) {
remote_respond(REMOTE_RESP_ERR, 0);
} else {
const bool result = platform_target_set_power(packet[2] == '1');
remote_respond(result ? REMOTE_RESP_OK : REMOTE_RESP_ERR, 0);
}
#else
remote_respond(REMOTE_RESP_NOTSUP, 0);
#endif
break;
case REMOTE_PWR_GET:
#ifdef PLATFORM_HAS_POWER_SWITCH
remote_respond(REMOTE_RESP_OK, platform_target_get_power());
#else
remote_respond(REMOTE_RESP_NOTSUP, 0);
#endif
break;
case REMOTE_START:
#if defined(ENABLE_DEBUG) && defined(PLATFORM_HAS_DEBUG)
debug_bmp = true;
#endif
remote_respond_string(REMOTE_RESP_OK, PLATFORM_IDENT "" FIRMWARE_VERSION);
break;
case REMOTE_TARGET_CLK_OE:
platform_target_clk_output_enable(packet[2] != '0');
remote_respond(REMOTE_RESP_OK, 0);
break;
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
}
static void remote_packet_process_high_level(const char *packet, const size_t packet_len)
{
SET_IDLE_STATE(0);
switch (packet[1]) {
case REMOTE_HL_CHECK:
remote_respond(REMOTE_RESP_OK, REMOTE_HL_VERSION);
break;
case REMOTE_ADD_JTAG_DEV: {
if (packet_len < 22U) {
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_WRONGLEN);
break;
}
jtag_dev_s jtag_dev = {0};
const uint8_t index = remote_hex_string_to_num(2, packet + 2);
jtag_dev.dr_prescan = remote_hex_string_to_num(2, packet + 4);
jtag_dev.dr_postscan = remote_hex_string_to_num(2, packet + 6);
jtag_dev.ir_len = remote_hex_string_to_num(2, packet + 8);
jtag_dev.ir_prescan = remote_hex_string_to_num(2, packet + 10);
jtag_dev.ir_postscan = remote_hex_string_to_num(2, packet + 12);
jtag_dev.current_ir = remote_hex_string_to_num(8, packet + 14);
jtag_add_device(index, &jtag_dev);
remote_respond(REMOTE_RESP_OK, 0);
break;
}
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
SET_IDLE_STATE(1);
}
static void remote_adiv5_respond(const void *const data, const size_t length)
{
if (remote_dp.fault)
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_FAULT | ((uint16_t)remote_dp.fault << 8U));
else {
if (data)
remote_respond_buf(REMOTE_RESP_OK, data, length);
else
remote_respond(REMOTE_RESP_OK, 0);
}
}
static void remote_packet_process_adiv5(const char *const packet, const size_t packet_len)
{
if (packet_len < 8U) {
remote_respond(REMOTE_RESP_PARERR, 0);
return;
}
remote_dp.dev_index = remote_hex_string_to_num(2, packet + 2);
adiv5_access_port_s remote_ap;
remote_ap.apsel = remote_hex_string_to_num(2, packet + 4);
remote_ap.dp = &remote_dp;
SET_IDLE_STATE(0);
switch (packet[1]) {
case REMOTE_DP_READ: {
const uint16_t addr = remote_hex_string_to_num(4, packet + 6);
const uint32_t data = adiv5_dp_read(&remote_dp, addr);
remote_adiv5_respond(&data, 4U);
break;
}
case REMOTE_ADIv5_RAW_ACCESS: {
const uint16_t addr = remote_hex_string_to_num(4, packet + 6);
const uint32_t value = remote_hex_string_to_num(8, packet + 10);
const uint32_t data = adiv5_dp_low_access(&remote_dp, remote_ap.apsel, addr, value);
remote_adiv5_respond(&data, 4U);
break;
}
case REMOTE_AP_READ: {
const uint16_t addr = remote_hex_string_to_num(4, packet + 6);
const uint32_t data = adiv5_ap_read(&remote_ap, addr);
remote_adiv5_respond(&data, 4U);
break;
}
case REMOTE_AP_WRITE: {
const uint16_t addr = remote_hex_string_to_num(4, packet + 6);
const uint32_t value = remote_hex_string_to_num(8, packet + 10);
adiv5_ap_write(&remote_ap, addr, value);
remote_adiv5_respond(NULL, 0U);
break;
}
case REMOTE_MEM_READ: {
remote_ap.csw = remote_hex_string_to_num(8, packet + 6);
const uint32_t address = remote_hex_string_to_num(8, packet + 14U);
const uint32_t length = remote_hex_string_to_num(8, packet + 22U);
if (length > 1024U) {
remote_respond(REMOTE_RESP_PARERR, 0);
break;
}
void *data = gdb_packet_buffer();
adiv5_mem_read(&remote_ap, data, address, length);
remote_adiv5_respond(data, length);
break;
}
case REMOTE_MEM_WRITE: {
remote_ap.csw = remote_hex_string_to_num(8, packet + 6);
const align_e align = remote_hex_string_to_num(2, packet + 14U);
const uint32_t dest = remote_hex_string_to_num(8, packet + 16U);
const size_t length = remote_hex_string_to_num(8, packet + 24U);
if (length > 1024U) {
remote_respond(REMOTE_RESP_PARERR, 0);
break;
}
if (length & ((1U << align) - 1U)) {
remote_respond(REMOTE_RESP_PARERR, 0);
break;
}
void *data = gdb_packet_buffer();
unhexify(data, packet + 32U, length);
adiv5_mem_write_sized(&remote_ap, dest, data, length, align);
remote_adiv5_respond(NULL, 0);
break;
}
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
SET_IDLE_STATE(1);
}
static void remote_spi_respond(const bool result)
{
if (result)
remote_respond(REMOTE_RESP_OK, 0);
else
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_FAULT);
}
void remote_packet_process_spi(const char *const packet, const size_t packet_len)
{
if (packet_len < 4U) {
remote_respond(REMOTE_RESP_PARERR, 0);
return;
}
const uint8_t spi_bus = remote_hex_string_to_num(2, packet + 2);
switch (packet[1]) {
case REMOTE_SPI_BEGIN:
remote_spi_respond(platform_spi_init(spi_bus));
break;
case REMOTE_SPI_END:
remote_spi_respond(platform_spi_deinit(spi_bus));
break;
case REMOTE_SPI_CHIP_SELECT:
remote_spi_respond(platform_spi_chip_select(spi_bus));
break;
case REMOTE_SPI_TRANSFER: {
const uint8_t data_in = remote_hex_string_to_num(2, packet + 4);
const uint8_t data_out = platform_spi_xfer(spi_bus, data_in);
remote_respond(REMOTE_RESP_OK, data_out);
break;
}
case REMOTE_SPI_READ: {
const uint8_t spi_device = remote_hex_string_to_num(2, packet + 4);
const uint16_t command = remote_hex_string_to_num(4, packet + 6);
const target_addr_t address = remote_hex_string_to_num(6, packet + 10);
const size_t length = remote_hex_string_to_num(4, packet + 16);
if (length > 256U) {
remote_respond(REMOTE_RESP_PARERR, 0);
break;
}
void *data = gdb_packet_buffer();
bmp_spi_read(spi_bus, spi_device, command, address, data, length);
remote_respond_buf(REMOTE_RESP_OK, data, length);
break;
}
case REMOTE_SPI_WRTIE: {
const uint8_t spi_device = remote_hex_string_to_num(2, packet + 4);
const uint16_t command = remote_hex_string_to_num(4, packet + 6);
const target_addr_t address = remote_hex_string_to_num(6, packet + 10);
const size_t length = remote_hex_string_to_num(4, packet + 16);
if (length > 256U) {
remote_respond(REMOTE_RESP_PARERR, 0);
break;
}
void *data = gdb_packet_buffer();
unhexify(data, packet + 20U, length);
bmp_spi_write(spi_bus, spi_device, command, address, data, length);
remote_respond(REMOTE_RESP_OK, 0);
break;
}
case REMOTE_SPI_CHIP_ID: {
const uint8_t spi_device = remote_hex_string_to_num(2, packet + 4);
spi_flash_id_s flash_id;
bmp_spi_read(spi_bus, spi_device, SPI_FLASH_CMD_READ_JEDEC_ID, 0, &flash_id, sizeof(flash_id));
remote_respond_buf(REMOTE_RESP_OK, &flash_id, sizeof(flash_id));
break;
}
case REMOTE_SPI_RUN_COMMAND: {
const uint8_t spi_device = remote_hex_string_to_num(2, packet + 4);
const uint16_t command = remote_hex_string_to_num(4, packet + 6);
const target_addr_t address = remote_hex_string_to_num(6, packet + 10);
bmp_spi_run_command(spi_bus, spi_device, command, address);
remote_respond(REMOTE_RESP_OK, 0);
break;
}
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
}
void remote_packet_process(unsigned i, char *packet)
{
switch (packet[0]) {
case REMOTE_SWDP_PACKET:
remote_packet_process_swd(packet, i);
break;
case REMOTE_JTAG_PACKET:
remote_packet_process_jtag(packet, i);
break;
case REMOTE_GEN_PACKET:
remote_packet_process_general(packet, i);
break;
case REMOTE_HL_PACKET:
remote_packet_process_high_level(packet, i);
break;
case REMOTE_ADIv5_PACKET: {
volatile exception_s error = {0};
TRY_CATCH (error, EXCEPTION_ALL) {
remote_packet_process_adiv5(packet, i);
}
if (error.type)
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_EXCEPTION | ((uint64_t)error.type << 8U));
break;
}
case REMOTE_SPI_PACKET:
remote_packet_process_spi(packet, i);
break;
default:
remote_respond(REMOTE_RESP_ERR, REMOTE_ERROR_UNRECOGNISED);
break;
}
}
#endif