├── CMakeLists.txt ├── Readme.md ├── SWD_SPI.c ├── component.mk ├── include └── libswd.h ├── libswd_bin.c ├── libswd_bitgen.c ├── libswd_bus.c ├── libswd_cli.c ├── libswd_cmd.c ├── libswd_cmdq.c ├── libswd_core.c ├── libswd_dap.c ├── libswd_debug.c ├── libswd_drv.c ├── libswd_error.c ├── libswd_log.c └── libswd_memap.c /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register( 2 | SRCS 3 | libswd_bin.c 4 | libswd_bitgen.c 5 | libswd_bus.c 6 | libswd_cmd.c 7 | libswd_cmdq.c 8 | libswd_core.c 9 | libswd_dap.c 10 | libswd_debug.c 11 | libswd_drv.c 12 | libswd_error.c 13 | libswd_log.c 14 | libswd_memap.c 15 | SWD_SPI.c 16 | INCLUDE_DIRS 17 | include 18 | ) 19 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # LibSWD for ESP32 IDF 2 | 3 | The basis for this component comes from https://github.com/cederom/LibSWD with an addition of a driver layer for the ESP32 IDF SPI master that is able to work in three wire mode. License is BSDv3, same as the libSWD library. 4 | 5 | Place the content of this repository in a folder libswd inside of the components folder of your project. 6 | 7 | # Example code 8 | 9 | The following example code is able to read out the ID code of a CPU and read 4 bytes from memory at a specific address. It works with three GPIO pins as intended because of the 3wire mode of the SPI master. With an unoptimized cable this code was able to read values with up to 40mHz closk speed from an Atmel SAM C20, after that edges began to deteriorate. 10 | 11 | ## Neccessary includes 12 | ```c 13 | #include 14 | #include 15 | #include // For ets_printf 16 | ``` 17 | 18 | ## Set up libSWD and the SPI device 19 | ```c 20 | spi_bus_config_t pinsSPI; 21 | pinsSPI.mosi_io_num = GPIO_NUM_13; // SWD I/O 22 | pinsSPI.miso_io_num = GPIO_NUM_12; // not connected 23 | pinsSPI.sclk_io_num = GPIO_NUM_14; // SWD CLK 24 | pinsSPI.quadwp_io_num = -1; 25 | pinsSPI.quadhd_io_num = -1; 26 | pinsSPI.max_transfer_sz = 0; 27 | 28 | ets_printf("[spi_bus_initialize]"); 29 | if(ESP_OK != spi_bus_initialize(HSPI_HOST, &pinsSPI, 0)) { // No DMA 30 | ets_printf("[spi_bus_initialize] fail"); 31 | return; // Warning, this example does not close handles correctly 32 | } 33 | 34 | spi_device_interface_config_t confSPI; 35 | confSPI.command_bits = 0; 36 | confSPI.address_bits = 0; 37 | confSPI.dummy_bits = 0; 38 | confSPI.mode = 0; 39 | confSPI.duty_cycle_pos = 0; 40 | confSPI.cs_ena_pretrans = 0; 41 | confSPI.cs_ena_posttrans = 0; 42 | confSPI.clock_speed_hz = 10000; 43 | confSPI.spics_io_num = -1; 44 | confSPI.flags = SPI_DEVICE_3WIRE | SPI_DEVICE_HALFDUPLEX | SPI_DEVICE_BIT_LSBFIRST; 45 | confSPI.queue_size = 24; 46 | confSPI.pre_cb = nullptr; 47 | confSPI.post_cb = nullptr; 48 | 49 | spi_device_handle_t deviceSPI 50 | ets_printf("[spi_bus_add_device]"); 51 | if(ESP_OK != spi_bus_add_device(HSPI_HOST, &confSPI, &deviceSPI)) { 52 | ets_printf("[spi_bus_add_device] fail"); 53 | return; // Warning, this example does not close handles correctly 54 | } 55 | 56 | ets_printf("[libswd_init]"); 57 | libswd_ctx_t* libswdctx = libswd_init(); 58 | if(libswdctx == nullptr) { 59 | ets_printf("[libswd_init] returned empty context"); 60 | return; // Warning, this example does not close handles correctly 61 | } 62 | 63 | libswd_log_level_set(libswdctx, LIBSWD_LOGLEVEL_DEBUG); 64 | libswdctx->driver->device = &deviceSPI; 65 | ``` 66 | 67 | ## Request ID code 68 | ```c 69 | int idcode = 0; 70 | int* idcode_ptr = &idcode; 71 | ets_printf("[libswd_dap_detect]"); 72 | auto dap_res = libswd_dap_detect(libswdctx, LIBSWD_OPERATION_EXECUTE, &idcode_ptr); 73 | if(LIBSWD_OK != dap_res) { 74 | ets_printf("[libswd_dap_detect] failed with code %d\n", dap_res); 75 | return; // Warning, this example does not close handles correctly 76 | } 77 | 78 | char buff[128]; 79 | sprintf(buff, "Detected IDCODE: 0x%08X\n", *idcode_ptr); 80 | ets_printf("%s", buff); 81 | ``` 82 | 83 | ## Read four bytes from memory address 84 | ```c 85 | uint32_t address = 0x20001000; // Example address 86 | ets_printf("[libswd_memap_init]"); 87 | auto memmap_res = libswd_memap_init(libswdctx, LIBSWD_OPERATION_EXECUTE); 88 | if(LIBSWD_OK != memmap_res) { 89 | ets_printf("[libswd_memap_init] failed"); 90 | return; // Warning, this example does not close handles correctly 91 | } 92 | 93 | const uint16_t buffCnt = 4; 94 | uint8_t buff[buffCnt] = {0}; 95 | int read_res = libswd_memap_read_char(libswdctx, LIBSWD_OPERATION_EXECUTE, address, buffCnt, (char*)&buff); 96 | if(read_res < LIBSWD_OK) { 97 | ets_printf("[libswd_memap_read_char] FAILED"); 98 | return; 99 | } 100 | 101 | char stringBuff[128]; 102 | sprintf(stringBuff, "MEMAP read at %08X: %02X %02X %02X %02X", address, buff[0], buff[1], buff[2], buff[3]); 103 | ets_printf("%s", stringBuff); 104 | ``` 105 | -------------------------------------------------------------------------------- /SWD_SPI.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * ESP32 SPI driver 4 | * 5 | * Copyright (C) 2018, Paul Freund 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2014; 32 | * 33 | */ 34 | 35 | #define DIRECTION_GPIO GPIO_NUM_4 36 | #define DIRECTION_MISO 0 37 | #define DIRECTION_MOSI 1 38 | 39 | #define direction_set(gpio, direction) gpio_set_level(gpio, direction) 40 | //#define direction_set(gpio, direction) 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | //#define spi_printf(...) ets_printf(__VA_ARGS__) 47 | #define spi_printf(...) 48 | 49 | inline void transmitSPI(spi_device_handle_t devSPI, spi_transaction_t* transSPI) { 50 | if(ESP_OK != spi_device_transmit(devSPI, transSPI)) { 51 | spi_printf(" - FAIL\n"); 52 | } 53 | } 54 | 55 | extern int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst) { 56 | spi_printf("[MOSI08][%02d] -> ", bits); 57 | 58 | spi_device_handle_t* devSPI = (spi_device_handle_t*)libswdctx->driver->device; 59 | 60 | spi_transaction_t transSPI; 61 | memset(&transSPI, 0, sizeof(spi_transaction_t)); 62 | 63 | transSPI.flags = SPI_TRANS_USE_TXDATA; 64 | transSPI.cmd = 0; // If want to set, change command_bits 65 | transSPI.addr = 0; // If want to set, change address_bits 66 | transSPI.length = bits; // Bits 67 | transSPI.rxlength = 0; 68 | transSPI.tx_data[0] = *data; 69 | 70 | direction_set(DIRECTION_GPIO, DIRECTION_MOSI); 71 | transmitSPI(*devSPI, &transSPI); 72 | direction_set(DIRECTION_GPIO, DIRECTION_MISO); 73 | 74 | spi_printf("%02x", transSPI.tx_data[0]); 75 | 76 | spi_printf(";\n"); 77 | return LIBSWD_OK; 78 | } 79 | 80 | extern int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst) { 81 | spi_printf("[MOSI32][%02d] -> ", bits); 82 | 83 | spi_device_handle_t* devSPI = (spi_device_handle_t*)libswdctx->driver->device; 84 | 85 | spi_transaction_t transSPI; 86 | memset(&transSPI, 0, sizeof(spi_transaction_t)); 87 | 88 | transSPI.flags = SPI_TRANS_USE_TXDATA; 89 | transSPI.cmd = 0; // If want to set, change command_bits 90 | transSPI.addr = 0; // If want to set, change address_bits 91 | transSPI.length = bits; // Bits 92 | transSPI.rxlength = 0; 93 | 94 | *((int*)(&transSPI.tx_data)) = (*data); 95 | 96 | direction_set(DIRECTION_GPIO, DIRECTION_MOSI); 97 | transmitSPI(*devSPI, &transSPI); 98 | direction_set(DIRECTION_GPIO, DIRECTION_MISO); 99 | 100 | spi_printf("%02x %02x %02x %02x", transSPI.tx_data[0], transSPI.tx_data[1], transSPI.tx_data[2], transSPI.tx_data[3]); 101 | 102 | spi_printf(";\n"); 103 | return LIBSWD_OK; 104 | } 105 | 106 | extern int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst) { 107 | spi_printf("[MISO08][%02d] <- ", bits); 108 | 109 | spi_device_handle_t* devSPI = (spi_device_handle_t*)libswdctx->driver->device; 110 | 111 | spi_transaction_t transSPI; 112 | memset(&transSPI, 0, sizeof(spi_transaction_t)); 113 | 114 | transSPI.flags = SPI_TRANS_USE_RXDATA; 115 | transSPI.cmd = 0; // If want to set, change command_bits 116 | transSPI.addr = 0; // If want to set, change address_bits 117 | transSPI.length = 0; // Bits 118 | transSPI.rxlength = bits; // Bits expected 119 | 120 | transmitSPI(*devSPI, &transSPI); 121 | 122 | spi_printf("%02x", transSPI.rx_data[0]); 123 | 124 | (*data) = transSPI.rx_data[0]; 125 | 126 | spi_printf(";\n"); 127 | return LIBSWD_OK; 128 | } 129 | 130 | extern int libswd_drv_miso_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst) { 131 | spi_printf("[MISO32][%02d] <- ", bits); 132 | 133 | spi_device_handle_t* devSPI = (spi_device_handle_t*)libswdctx->driver->device; 134 | 135 | spi_transaction_t transSPI; 136 | memset(&transSPI, 0, sizeof(spi_transaction_t)); 137 | 138 | transSPI.flags = SPI_TRANS_USE_RXDATA; 139 | transSPI.cmd = 0; // If want to set, change command_bits 140 | transSPI.addr = 0; // If want to set, change address_bits 141 | transSPI.length = 0; // Bits 142 | transSPI.rxlength = bits; // Bits expected 143 | 144 | transmitSPI(*devSPI, &transSPI); 145 | 146 | spi_printf("%02x %02x %02x %02x", transSPI.rx_data[0], transSPI.rx_data[1], transSPI.rx_data[2], transSPI.rx_data[3]); 147 | 148 | (*data) = *((int*)(&transSPI.rx_data)); 149 | 150 | spi_printf(";\n"); 151 | return LIBSWD_OK; 152 | } 153 | 154 | extern int libswd_drv_mosi_trn(libswd_ctx_t *libswdctx, int clks) { 155 | spi_printf("[MOSITN][%02d]", clks); 156 | 157 | if(clks == 0) { return LIBSWD_OK; } 158 | 159 | spi_device_handle_t* devSPI = (spi_device_handle_t*)libswdctx->driver->device; 160 | 161 | spi_transaction_t transSPI; 162 | memset(&transSPI, 0, sizeof(spi_transaction_t)); 163 | 164 | transSPI.flags = SPI_TRANS_USE_TXDATA; 165 | transSPI.cmd = 0; // If want to set, change command_bits 166 | transSPI.addr = 0; // If want to set, change address_bits 167 | transSPI.length = clks; // Bits 168 | transSPI.rxlength = 0; 169 | 170 | direction_set(DIRECTION_GPIO, DIRECTION_MOSI); 171 | transmitSPI(*devSPI, &transSPI); 172 | direction_set(DIRECTION_GPIO, DIRECTION_MISO); 173 | 174 | spi_printf(";\n"); 175 | return LIBSWD_OK; 176 | } 177 | 178 | extern int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int clks) { 179 | spi_printf("[MISOTN][%02d]", clks); 180 | 181 | if(clks == 0) { return LIBSWD_OK; } 182 | spi_device_handle_t* devSPI = (spi_device_handle_t*)libswdctx->driver->device; 183 | 184 | spi_transaction_t transSPI; 185 | memset(&transSPI, 0, sizeof(spi_transaction_t)); 186 | 187 | transSPI.flags = SPI_TRANS_USE_TXDATA; 188 | transSPI.cmd = 0; // If want to set, change command_bits 189 | transSPI.addr = 0; // If want to set, change address_bits 190 | transSPI.length = clks; 191 | transSPI.rxlength = 0; 192 | 193 | direction_set(DIRECTION_GPIO, DIRECTION_MOSI); 194 | transmitSPI(*devSPI, &transSPI); 195 | direction_set(DIRECTION_GPIO, DIRECTION_MISO); 196 | 197 | spi_printf(";\n"); 198 | 199 | return LIBSWD_OK; 200 | } 201 | 202 | #include "esp_log.h" 203 | extern int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...) { 204 | // va_list args; 205 | // va_start (args, msg); 206 | 207 | // char buffer[256]; 208 | // int length = 0; 209 | // length = vsnprintf (buffer, 255, msg, args); 210 | // buffer[length] = '\0'; 211 | // ESP_LOGE("SWD_SPI", "%s", buffer); 212 | // va_end (args); 213 | return LIBSWD_OK; 214 | } 215 | 216 | extern int libswd_log_level_inherit(libswd_ctx_t *libswdctx, int loglevel) { 217 | return LIBSWD_OK; 218 | } -------------------------------------------------------------------------------- /component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Component Makefile 3 | # 4 | COMPONENT_ADD_INCLUDEDIRS := include 5 | 6 | # COMPONENT_SRCDIRS := 7 | 8 | -------------------------------------------------------------------------------- /libswd_bin.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_bin.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_bin Binary operations helper functions. 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | /** 45 | * Data parity calculator, calculates even parity on char type. 46 | * \param *data source data pointer. 47 | * \param *parity resulting data pointer. 48 | * \return negative value on error, 0 or 1 as parity result. 49 | */ 50 | int libswd_bin8_parity_even(char *data, char *parity){ 51 | char i; 52 | unsigned char test=*data; 53 | *parity=0; 54 | for (i=0;i<=8;i++) *parity ^= ((test>>i)&1); 55 | if (*parity<0 || *parity>1) return LIBSWD_ERROR_PARITY; 56 | return (int)*parity; 57 | } 58 | 59 | /** 60 | * Data parity calculator, calculates even parity on integer type. 61 | * \param *data source data pointer. 62 | * \param *parity resulting data pointer. 63 | * \return negative value on error, 0 or 1 as parity result. 64 | */ 65 | int libswd_bin32_parity_even(int *data, char *parity){ 66 | int i; 67 | unsigned int test=*data; 68 | *parity=0; 69 | for (i=0;i<32;i++) *parity ^= ((test>>i)&1); 70 | if (*parity<0 || *parity>1) return LIBSWD_ERROR_PARITY; 71 | return (int)*parity; 72 | } 73 | 74 | /** 75 | * Prints binary data of a char value on the screen. 76 | * \param *data source data pointer. 77 | * \return number of characters printed. 78 | */ 79 | int libswd_bin8_print(char *data){ 80 | unsigned char i, bits=*data; 81 | for (i=0;i<8;i++) putchar(((bits<8) return LIBSWD_ERROR_PARAM; 131 | unsigned char bit, result=0; //res must be unsigned for proper shifting result 132 | #ifdef __SWDDEBUG__ 133 | printf("|LIBSWD_DEBUG: libswd_bin8_bitswap(%02X, %d);\n", *buffer, bitcount); 134 | #endif 135 | for (bit=0;bit>bit)&1)?1:0); 137 | #ifdef __SWDDEBUG__ 138 | printf("|LIBSWD_DEBUG: libswd_bin8_bitswap: in=%02X out=%02X bit=%d\n", *buffer, result, bit); 139 | #endif 140 | } 141 | *buffer=result; 142 | return bit; 143 | } 144 | 145 | /** 146 | * Bit swap helper function that reverse bit order in int *buffer. 147 | * Most Significant Bit becomes Least Significant Bit. 148 | * It is possible to swap only n-bits from int (32-bit) *buffer. 149 | * \param *buffer unsigned char (32-bit) data pointer. 150 | * \param bitcount how many bits to swap. 151 | * \return swapped bit count (positive) or error code (negative). 152 | */ 153 | int libswd_bin32_bitswap(unsigned int *buffer, unsigned int bitcount){ 154 | if (buffer==NULL) return LIBSWD_ERROR_NULLPOINTER; 155 | if (bitcount>32) return LIBSWD_ERROR_PARAM; 156 | unsigned int bit, result=0; //res must be unsigned for proper shifting result 157 | #ifdef __SWDDEBUG__ 158 | printf("|LIBSWD_DEBUG: libswd_bin32_bitswap(%08X, %d);\n", *buffer, bitcount); 159 | #endif 160 | for (bit=0;bit>bit)&1)?1:0); 162 | #ifdef __SWDDEBUG__ 163 | printf("|LIBSWD_DEBUG: libswd_bin32_bitswap: in=%08X out=%08X bit=%d\n", *buffer, result, bit); 164 | #endif 165 | } 166 | *buffer=result; 167 | return bit; 168 | } 169 | 170 | /** @} */ 171 | -------------------------------------------------------------------------------- /libswd_bitgen.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_bitgen.c */ 36 | 37 | #include 38 | 39 | 40 | /******************************************************************************* 41 | * \defgroup libswd_bitgen SWD Bitstream / Packet Payload generation routines. 42 | * @{ 43 | ******************************************************************************/ 44 | 45 | /** Generate 8-bit SWD-REQUEST packet contents with provided parameters. 46 | * Note that parity bit value is calculated automatically. 47 | * Note that Request is also sent LSB-First so diagrams are wrapped! 48 | * \param *libswdctx swd context pointer. 49 | * \param *APnDP AccessPort (high) or DebugPort (low) access type pointer. 50 | * \param *RnW Read (high) or Write (low) operation type pointer. 51 | * \param *addr target register address value pointer. 52 | * \param *request pointer where to store resulting packet. 53 | * \return number of generated packets (1), or LIBSWD_ERROR_CODE on failure. 54 | */ 55 | int libswd_bitgen8_request(libswd_ctx_t *libswdctx, char *APnDP, char *RnW, char *addr, char *request){ 56 | /* Verify function parameters.*/ 57 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 58 | if (*APnDP!=0 && *APnDP!=1) return LIBSWD_ERROR_APnDP; 59 | if (*RnW!=0 && *RnW!=1) return LIBSWD_ERROR_RnW; 60 | if (*addrLIBSWD_ADDR_MAXVAL) return LIBSWD_ERROR_ADDR; 61 | 62 | /* Build request header content. */ 63 | unsigned char reqhdr=0; 64 | char parity, req; 65 | int res; 66 | reqhdr|=(((*addr&(1<<2))?1:0)<1) return LIBSWD_ERROR_PARITY; 74 | reqhdr|=(res<, 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_bus.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_bus SWD Bus Primitives: Request, ACK, Data+Parity, Direction. 41 | * These functions generate payloads and queue up all elements/commands 42 | * necessary to perform requested operations on the SWD bus. Depending 43 | * on "operation" type, elements can be only enqueued on the queue (operation == 44 | * LIBSWD_OPERATION_ENQUEUE) or queued and then flushed into hardware driver 45 | * (operation == LIBSWD_OPERATION_EXECUTE) for immediate effect on the target. 46 | * Other operations are not allowed for these functions and will produce error. 47 | * This group of functions is intelligent, so they will react on errors, when 48 | * operation is LIBSWD_OPERATION_EXECUTE, otherwise simply queue up transaction. 49 | * These functions are primitives to use by high level functions operating 50 | * on the Debug Port (DP) or the Access Port (AP). 51 | * @{ 52 | ******************************************************************************/ 53 | 54 | /** Append command queue with TRN WRITE/MOSI, if previous command was READ/MISO. 55 | * \param *libswdctx swd context pointer. 56 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 57 | */ 58 | int libswd_bus_setdir_mosi(libswd_ctx_t *libswdctx){ 59 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 60 | int res, cmdcnt=0; 61 | libswd_cmd_t *cmdqtail=libswd_cmdq_find_tail(libswdctx->cmdq); 62 | if (cmdqtail==NULL) return LIBSWD_ERROR_QUEUE; 63 | if ( cmdqtail->prev==NULL || (cmdqtail->cmdtype*LIBSWD_CMDTYPE_MOSI<0) ) { 64 | res=libswd_cmd_enqueue_mosi_trn(libswdctx); 65 | if (res<1) return res; 66 | cmdcnt+=res; 67 | } 68 | return cmdcnt; 69 | } 70 | 71 | /** Append command queue with TRN READ/MISO, if previous command was WRITE/MOSI. 72 | * \param *libswdctx swd context pointer. 73 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 74 | */ 75 | int libswd_bus_setdir_miso(libswd_ctx_t *libswdctx){ 76 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 77 | int res, cmdcnt=0; 78 | libswd_cmd_t *cmdqtail=libswd_cmdq_find_tail(libswdctx->cmdq); 79 | if (cmdqtail==NULL) return LIBSWD_ERROR_QUEUE; 80 | if (cmdqtail->prev==NULL || (cmdqtail->cmdtype*LIBSWD_CMDTYPE_MISO<0) ) { 81 | res=libswd_cmd_enqueue_miso_trn(libswdctx); 82 | if (res<0) return res; 83 | cmdcnt+=res; 84 | } 85 | return cmdcnt; 86 | } 87 | 88 | /** Perform Request (write provided raw byte). 89 | * \param *libswdctx swd context pointer. 90 | * \param operation type of action to perform with generated request. 91 | * \param *request request packet raw data 92 | * \return number of commands processed, or LIBSWD_ERROR_CODE on failure. 93 | */ 94 | int libswd_bus_write_request_raw 95 | (libswd_ctx_t *libswdctx, libswd_operation_t operation, char *request){ 96 | /* Verify function parameters.*/ 97 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 98 | if (request==NULL) return LIBSWD_ERROR_NULLPOINTER; 99 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 100 | return LIBSWD_ERROR_BADOPCODE; 101 | 102 | int res, qcmdcnt=0, tcmdcnt=0; 103 | 104 | /* Bus direction must be MOSI. */ 105 | res=libswd_bus_setdir_mosi(libswdctx); 106 | if (res<0) return res; 107 | qcmdcnt+=res; 108 | 109 | /* Append request command to the queue. */ 110 | res=libswd_cmd_enqueue_mosi_request(libswdctx, request); 111 | if (res<0) return res; 112 | qcmdcnt+=res; 113 | 114 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 115 | return qcmdcnt; 116 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 117 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 118 | if (res<0) return res; 119 | tcmdcnt+=res; 120 | return qcmdcnt+tcmdcnt; 121 | } else return LIBSWD_ERROR_BADOPCODE; 122 | } 123 | 124 | /** Perform Request. 125 | * \param *libswdctx swd context pointer. 126 | * \param operation type of action to perform with generated request. 127 | * \param *APnDP AccessPort (high) or DebugPort (low) access value pointer. 128 | * \param *RnW Read (high) or Write (low) access value pointer. 129 | * \param *addr target register address value pointer. 130 | * \return number of commands processed, or LIBSWD_ERROR_CODE on failure. 131 | */ 132 | int libswd_bus_write_request 133 | (libswd_ctx_t *libswdctx, libswd_operation_t operation, char *APnDP, char *RnW, char *addr){ 134 | /* Verify function parameters.*/ 135 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 136 | if (*APnDP!=0 && *APnDP!=1) return LIBSWD_ERROR_APnDP; 137 | if (*RnW!=0 && *RnW!=1) return LIBSWD_ERROR_RnW; 138 | if (*addrLIBSWD_ADDR_MAXVAL) return LIBSWD_ERROR_ADDR; 139 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 140 | return LIBSWD_ERROR_BADOPCODE; 141 | 142 | int res, qcmdcnt=0, tcmdcnt=0; 143 | char request; 144 | 145 | /* Generate request bitstream. */ 146 | res=libswd_bitgen8_request(libswdctx, APnDP, RnW, addr, &request); 147 | if (res<0) return res; 148 | 149 | /* Bus direction must be MOSI. */ 150 | res=libswd_bus_setdir_mosi(libswdctx); 151 | if (res<0) return res; 152 | qcmdcnt+=res; 153 | 154 | /* Append request command to the queue. */ 155 | res=libswd_cmd_enqueue_mosi_request(libswdctx, &request); 156 | if (res<0) return res; 157 | qcmdcnt+=res; 158 | 159 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 160 | return qcmdcnt; 161 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 162 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 163 | if (res<0) return res; 164 | tcmdcnt+=res; 165 | return qcmdcnt+tcmdcnt; 166 | } else return LIBSWD_ERROR_BADOPCODE; 167 | } 168 | 169 | /** Perform ACK read into *ack and verify received data. 170 | * \param *libswdctx swd context pointer. 171 | * \param operation type of action to perform with generated request. 172 | * \param *ack pointer to the result location. 173 | * \return number of commands processed, or LIBSWD_ERROR_CODE on failure. 174 | */ 175 | int libswd_bus_read_ack(libswd_ctx_t *libswdctx, libswd_operation_t operation, char **ack){ 176 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 177 | if (ack==NULL) return LIBSWD_ERROR_NULLPOINTER; 178 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 179 | return LIBSWD_ERROR_BADOPCODE; 180 | 181 | int res, qcmdcnt=0, tcmdcnt=0; 182 | libswd_cmd_t *tmpcmdq, *cmdqtail; 183 | 184 | /* ACK can only show after REQ_MOSI,TRN_MISO sequence. */ 185 | cmdqtail=libswd_cmdq_find_tail(libswdctx->cmdq); 186 | if (cmdqtail==NULL) return LIBSWD_ERROR_QUEUE; 187 | if (cmdqtail->prev==NULL) return LIBSWD_ERROR_ACKORDER; 188 | /* Check if there is REQ->TRN sequence at the command queue tail. */ 189 | if (cmdqtail->prev->cmdtype!=LIBSWD_CMDTYPE_MOSI_REQUEST 190 | && cmdqtail->cmdtype!=LIBSWD_CMDTYPE_MISO_TRN){ 191 | /* If not, there should be at least REQ. */ 192 | if (cmdqtail->cmdtype!=LIBSWD_CMDTYPE_MOSI_REQUEST){ 193 | return LIBSWD_ERROR_ACKORDER; 194 | } else { 195 | /* TRN was found at queue tail, so we need to append TRN_MISO command. */ 196 | res=libswd_bus_setdir_miso(libswdctx); 197 | if (res<0) return res; 198 | qcmdcnt+=res; 199 | } 200 | } 201 | 202 | res=libswd_cmd_enqueue_miso_ack(libswdctx, ack); 203 | if (res<0) return res; 204 | qcmdcnt+=res; 205 | 206 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 207 | return qcmdcnt; 208 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 209 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 210 | if (res<0) return res; 211 | tcmdcnt+=res; 212 | } else return LIBSWD_ERROR_BADOPCODE; 213 | 214 | /* Now verify the read result and return/pass error code if necessary. */ 215 | 216 | /* Use temporary queue pointer for context queue operations.*/ 217 | tmpcmdq=libswdctx->cmdq; 218 | /* Search backward for ACK command on the queue (ack we have just appended). */ 219 | while (tmpcmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_ACK){ 220 | if (tmpcmdq->prev==NULL) return LIBSWD_ERROR_ACKMISSING; 221 | tmpcmdq=tmpcmdq->prev; 222 | } 223 | /* If command was found and executed, read received ACK code, or error code. */ 224 | if (tmpcmdq->cmdtype==LIBSWD_CMDTYPE_MISO_ACK && tmpcmdq->done){ 225 | /* Verify data address found on the queue, with pointer selected before run.*/ 226 | if (&tmpcmdq->ack!=*ack) return LIBSWD_ERROR_ACKMISMATCH; 227 | return qcmdcnt+tcmdcnt; 228 | } else return LIBSWD_ERROR_ACKNOTDONE; 229 | } 230 | 231 | /** Perform (MOSI) data write with provided parity value. 232 | * \param *libswdctx swd context pointer. 233 | * \param operation type of action to perform on generated command. 234 | * \param *data payload value pointer. 235 | * \param *parity payload parity value pointer. 236 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 237 | */ 238 | int libswd_bus_write_data_p 239 | (libswd_ctx_t *libswdctx, libswd_operation_t operation, int *data, char *parity){ 240 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 241 | if (data==NULL || parity==NULL) return LIBSWD_ERROR_NULLPOINTER; 242 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 243 | return LIBSWD_ERROR_BADOPCODE; 244 | 245 | int res, qcmdcnt=0, tcmdcnt=0; 246 | 247 | res=libswd_bus_setdir_mosi(libswdctx); 248 | if (res<0) return res; 249 | qcmdcnt+=res; 250 | 251 | res=libswd_cmd_enqueue_mosi_data_p(libswdctx, data, parity); 252 | if (res<0) return res; 253 | qcmdcnt+=res; 254 | 255 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 256 | return qcmdcnt; 257 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 258 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 259 | if (res<0) return res; 260 | tcmdcnt+=res; 261 | return qcmdcnt+tcmdcnt; 262 | } else return LIBSWD_ERROR_BADOPCODE; 263 | } 264 | 265 | 266 | /** Perform (MOSI) data write with automatic parity calculation. 267 | * \param *libswdctx swd context pointer. 268 | * \param operation type of action to perform on generated command. 269 | * \param *data payload value pointer. 270 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 271 | */ 272 | int libswd_bus_write_data_ap(libswd_ctx_t *libswdctx, libswd_operation_t operation, int *data){ 273 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 274 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 275 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 276 | return LIBSWD_ERROR_BADOPCODE; 277 | 278 | int res, qcmdcnt=0, tcmdcnt=0; 279 | 280 | res=libswd_bus_setdir_mosi(libswdctx); 281 | if (res<0) return res; 282 | qcmdcnt+=res; 283 | 284 | res=libswd_cmd_enqueue_mosi_data_ap(libswdctx, data); 285 | if (res<0) return res; 286 | qcmdcnt+=res; 287 | 288 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 289 | return qcmdcnt; 290 | } else if (operation==LIBSWD_OPERATION_EXECUTE) { 291 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 292 | if (res<0) return res; 293 | tcmdcnt+=res; 294 | return qcmdcnt+tcmdcnt; 295 | } else return LIBSWD_ERROR_BADOPCODE; 296 | } 297 | 298 | /** Perform (MISO) data read. 299 | * \param *libswdctx swd context pointer. 300 | * \param operation type of action to perform on generated command. 301 | * \param *data payload value pointer. 302 | * \param *parity payload parity value pointer. 303 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 304 | */ 305 | int libswd_bus_read_data_p(libswd_ctx_t *libswdctx, libswd_operation_t operation, int **data, char **parity){ 306 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 307 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 308 | return LIBSWD_ERROR_BADOPCODE; 309 | 310 | int res, qcmdcnt=0, tcmdcnt=0; 311 | libswd_cmd_t *tmpcmdq; 312 | 313 | res=libswd_bus_setdir_miso(libswdctx); 314 | if (res<0) return res; 315 | qcmdcnt+=res; 316 | 317 | res=libswd_cmd_enqueue_miso_data_p(libswdctx, data, parity); 318 | if (res<0) return res; 319 | qcmdcnt+=res; 320 | 321 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 322 | return qcmdcnt; 323 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 324 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 325 | if (res<2) return res; 326 | tcmdcnt+=res; 327 | } else return LIBSWD_ERROR_BADOPCODE; 328 | 329 | /* Now verify the read result and return error if necessary. 330 | * Maybe iterative approach should be applied, not only last elemnt found..? */ 331 | 332 | /* Use temporary queue pointer for context queue operations.*/ 333 | tmpcmdq=libswdctx->cmdq; 334 | /* Search backward for our MISO_DATA command on the queue. */ 335 | while (tmpcmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_DATA){ 336 | if (tmpcmdq->prev==NULL) return LIBSWD_ERROR_NODATACMD; 337 | tmpcmdq=tmpcmdq->prev; 338 | } 339 | /* There should be parity bit (command) just after data (command). */ 340 | if (tmpcmdq->next->cmdtype!=LIBSWD_CMDTYPE_MISO_PARITY) 341 | return LIBSWD_ERROR_NOPARITYCMD; 342 | /* If command found and executed, verify if data points to correct address. */ 343 | if (tmpcmdq->cmdtype==LIBSWD_CMDTYPE_MISO_DATA && tmpcmdq->done){ 344 | if (tmpcmdq->next->cmdtype==LIBSWD_CMDTYPE_MISO_PARITY && tmpcmdq->next->done){ 345 | if (*data!=&tmpcmdq->misodata) return LIBSWD_ERROR_DATAPTR; 346 | if (*parity!=&tmpcmdq->next->parity) return LIBSWD_ERROR_PARITYPTR; 347 | return qcmdcnt+tcmdcnt; 348 | } else return LIBSWD_ERROR_NOTDONE; 349 | } 350 | return LIBSWD_OK; 351 | } 352 | 353 | /** Write CONTROL byte to the Target's DAP. 354 | * \param *libswdctx swd context. 355 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 356 | * \param *ctlmsg byte/char array that contains control payload. 357 | * \param len number of bytes in the *ctlmsg to send. 358 | * \return number of bytes sent or LIBSWD_ERROR_CODE on failure. 359 | */ 360 | int libswd_bus_write_control(libswd_ctx_t *libswdctx, libswd_operation_t operation, char *ctlmsg, int len){ 361 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 362 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 363 | return LIBSWD_ERROR_BADOPCODE; 364 | if (ctlmsg==NULL) return LIBSWD_ERROR_NULLPOINTER; 365 | if (len<1 && len>libswdctx->config.maxcmdqlen) return LIBSWD_ERROR_PARAM; 366 | 367 | int res, qcmdcnt=0, tcmdcnt=0; 368 | 369 | /* Make sure that bus is in MOSI state. */ 370 | res=libswd_bus_setdir_mosi(libswdctx); 371 | if (res<0) return res; 372 | qcmdcnt+=res; 373 | 374 | res=libswd_cmd_enqueue_mosi_control(libswdctx, ctlmsg, len); 375 | if (res<0) return res; 376 | qcmdcnt+=res; 377 | 378 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 379 | return qcmdcnt; 380 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 381 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 382 | if (res<0) return res; 383 | tcmdcnt+=res; 384 | } else return LIBSWD_ERROR_BADOPCODE; 385 | return LIBSWD_OK; 386 | } 387 | 388 | /** @} */ 389 | -------------------------------------------------------------------------------- /libswd_cli.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Command Line Interface Body File. 4 | * 5 | * Copyright (C) 2010-2014, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2014; 32 | * 33 | */ 34 | 35 | /** \file libswd_cli.c */ 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | /******************************************************************************* 44 | * \defgroup libswd_cli Command Line Interface functions. 45 | * @{ 46 | ******************************************************************************/ 47 | 48 | int libswd_cli_print_usage(libswd_ctx_t *libswdctx) 49 | { 50 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 51 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: Available LibSWD CLI commands:\n"); 52 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [h]elp / [?]\n"); 53 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [i]nit [dap]|memap|debug\n"); 54 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [l]oglevel \n"); 55 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [r]ead [d]ap/[a]p 0xAddress\n"); 56 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [w]rite [d]ap/[a]p 0xAddress 0x32BitData\n"); 57 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [r]ead [m]emap 0xAddress <0xCount>|4 \n"); 58 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: [w]rite [m]emap 0xAddress 0xData[]|filename\n"); 59 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "\n"); 60 | return LIBSWD_OK; 61 | } 62 | 63 | /** Command Line Interface parse and execution engine. 64 | * Multiple commands invocation is possible, split by '\n' or ';' characters. 65 | * \param *libswdctx libswd context 66 | * \param *cmd command string pointer 67 | * \return LIBSWD_ERROR_OK on success or negative value error code otherwise. 68 | */ 69 | int libswd_cli(libswd_ctx_t *libswdctx, char *command) 70 | { 71 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 72 | "LIBSWD_D: libswd_cli(libswdctx=@%p, command=@%p/\"%s\"): Entring function...\n", 73 | (void*)libswdctx, (void*)command, command); 74 | 75 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 76 | if (command==NULL) return LIBSWD_ERROR_NULLPOINTER; 77 | 78 | int res, retval, addrstart, /*addrstop,*/ count, data, *data32, i, j; 79 | char *cmd, *thiscommand, ap, *filename, *endptr; 80 | 81 | while ( (thiscommand=strsep(&command,"\n;")) ) 82 | { 83 | while ( (cmd=strsep(&thiscommand," ")) ) 84 | { 85 | // Strip heading and trailing spaces. 86 | if (cmd && thiscommand) if (!cmd[0] && thiscommand[0]) continue; 87 | if (cmd && thiscommand) if (!cmd[0] && !thiscommand[0]) break; 88 | 89 | // Check for HELP invocation. 90 | if ( strncmp(cmd,"?",1)==0 || strncmp(cmd,"help",4)==0 || strncmp(cmd,"h",1)==0 ) 91 | { 92 | return libswd_cli_print_usage(libswdctx); 93 | } 94 | 95 | // Check for LOGLEVEL invocation. 96 | else if ( strncmp(cmd,"l",1)==0 || strncmp(cmd,"loglevel",8)==0 ) 97 | { 98 | int loglevel_new=LIBSWD_LOGLEVEL_DEFAULT; 99 | cmd=strsep(&thiscommand," "); 100 | if (cmd==NULL) 101 | { 102 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 103 | "LIBSWD_I: libswd_cli(): Current loglevel is: %d (%s)\n", 104 | (int)libswdctx->config.loglevel, 105 | libswd_log_level_string(libswdctx->config.loglevel) ); 106 | } 107 | else 108 | { 109 | errno=LIBSWD_OK; 110 | loglevel_new=atol(cmd); 111 | if (errno==LIBSWD_OK) 112 | { 113 | retval=libswd_log_level_set(libswdctx, (libswd_loglevel_t)loglevel_new ); 114 | if (retval<0) 115 | { 116 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 117 | "LIBSWD_E: libswd_cli(): Cannot set loglevel %d/%s): %s.\n", 118 | loglevel_new, 119 | libswd_log_level_string((libswd_loglevel_t)loglevel_new), 120 | libswd_error_string(retval) ); 121 | } 122 | } 123 | else if (errno!=LIBSWD_OK) 124 | { 125 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 126 | "LIBSWD_I: libswd_cli(): Current loglevel is: %d (%s)\n", 127 | (int)libswdctx->config.loglevel, 128 | libswd_log_level_string(libswdctx->config.loglevel) ); 129 | } 130 | } 131 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LOGLEVEL=%d/%s\n", 132 | (int)libswdctx->config.loglevel, 133 | libswd_log_level_string(libswdctx->config.loglevel)); 134 | continue; 135 | } 136 | 137 | // Initialize Target subsystems. 138 | // This will bring components into known state and remove any pending errors. 139 | else if ( strncmp(cmd,"i",1)==0 || strncmp(cmd,"init",4)==0 ) 140 | { 141 | cmd=strsep(&thiscommand," "); 142 | if (!cmd || strncmp(cmd,"da",2)==0 || strncmp(cmd,"dap",3)==0 ) 143 | { 144 | int *idcode; 145 | retval=libswd_dap_init(libswdctx, LIBSWD_OPERATION_EXECUTE, &idcode); 146 | if (retval<0) 147 | { 148 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 149 | "LIBSWD_E: libswd_cli(): Cannot Initialize DAP! (%s)\n", 150 | libswd_error_string(retval) ); 151 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 152 | "LIBSWD_N: libswd_cli(): DAP INIT ERROR!\n" ); 153 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 154 | "LIBSWD_N: DAP INIT OK! IDCODE=0x%08X/%s\n", 155 | *idcode, libswd_bin32_string(idcode) ); 156 | } 157 | else if ( strncmp(cmd,"m",1)==0 || strncmp(cmd,"memap",5)==0 ) 158 | { 159 | retval=libswd_memap_init(libswdctx, LIBSWD_OPERATION_EXECUTE); 160 | if (retval<0) 161 | { 162 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 163 | "LIBSWD_E: libswd_cli(): MEM-AP INIT ERROR!\n"); 164 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 165 | "LIBSWD_N: MEM-AP INIT OK!\n"); 166 | } 167 | else if ( strncmp(cmd,"de",2)==0 || strncmp(cmd,"debug",5)==0 ) 168 | { 169 | retval=libswd_debug_init(libswdctx, LIBSWD_OPERATION_EXECUTE); 170 | if (retval<0) 171 | { 172 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 173 | "LIBSWD_E: libswd_cli(): DEBUG INIT ERROR!\n" ); 174 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 175 | "LIBSWD_N: DEBUG INIT OK!\n"); 176 | } 177 | continue; 178 | } 179 | // Check for DEBUG invocation. 180 | else if ( strncmp(cmd,"d",1)==0 || strncmp(cmd,"debug",5)==0 ) 181 | { 182 | cmd=strsep(&thiscommand," "); 183 | if (!cmd) goto libswd_cli_syntaxerror; 184 | if ( strncmp(cmd,"h",1)==0 || strncmp(cmd,"halt",4)==0 ) 185 | { 186 | retval=libswd_debug_halt(libswdctx, LIBSWD_OPERATION_EXECUTE); 187 | if (retval<0) 188 | { 189 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 190 | "LIBSWD_E: libswd_cli(): DEBUG HALT ERROR! (%s).\n", 191 | libswd_error_string(retval) ); 192 | } 193 | } 194 | else if ( strncmp(cmd,"r",1)==0 || strncmp(cmd,"run",3)==0 ) 195 | { 196 | retval=libswd_debug_run(libswdctx, LIBSWD_OPERATION_EXECUTE); 197 | if (retval<0) 198 | { 199 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 200 | "LIBSWD_E: libswd_cli(); DEBUG RUN ERROR! (%s)\n", 201 | libswd_error_string(retval) ); 202 | } 203 | } 204 | } 205 | // Check for READ invocation. 206 | else if ( strncmp(cmd,"r",1)==0 || strncmp(cmd,"read",4)==0 ) 207 | { 208 | // Parse access port name parameter. 209 | cmd=strsep(&thiscommand," "); 210 | if (!cmd) goto libswd_cli_syntaxerror; 211 | if ( strncmp(cmd,"d",1)==0 || strncmp(cmd,"dap",3)==0 ) 212 | { 213 | ap='d'; 214 | } 215 | else if ( strncmp(cmd,"a",1)==0 || strncmp(cmd,"ap",2)==0 ) 216 | { 217 | ap='a'; 218 | } 219 | else if ( strncmp(cmd,"m",1)==0 || strncmp(cmd,"memap",5)==0 ) 220 | { 221 | ap='m'; 222 | } else goto libswd_cli_syntaxerror; 223 | // Parse address parameter. 224 | cmd=strsep(&thiscommand," "); 225 | if (!cmd) goto libswd_cli_syntaxerror; 226 | errno=LIBSWD_OK; 227 | addrstart=strtol(cmd, (char**)NULL, 0); 228 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 229 | // Perform operations on a given access port. 230 | switch (ap) 231 | { 232 | case 'd': 233 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, 234 | addrstart, &data32 ); 235 | if (retval<0) goto libswd_cli_error; 236 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 237 | "LIBSWD_N: DP[0x%08X]=0x%08X\n", 238 | addrstart, *data32 ); 239 | break; 240 | case 'a': 241 | retval=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, 242 | addrstart, &data32 ); 243 | if (retval<0) goto libswd_cli_error; 244 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 245 | "LIBSWD_N: AP[0x%08X]=0x%08X\n", 246 | addrstart, *data32 ); 247 | break; 248 | case 'm': 249 | // Parse count parameter for MEM-AP operation. 250 | if (thiscommand) 251 | { 252 | cmd=strsep(&thiscommand," "); 253 | errno=LIBSWD_OK; 254 | count=strtol(cmd, &endptr, 0); 255 | if (errno!=LIBSWD_OK || count<=0) goto libswd_cli_syntaxerror; 256 | } else count=4; 257 | // Make sure count is 32-bit boundary. 258 | if (count%4) count=count-(count%4); 259 | //addrstop=addrstart+count; 260 | // Parse filename parameter for MEM-AP operation. 261 | if (thiscommand) 262 | { 263 | cmd=strsep(&thiscommand," "); 264 | if (cmd && cmd!='\0' && !isspace((int)(*cmd))) 265 | { 266 | filename=cmd; 267 | } else filename=NULL; 268 | } else filename=NULL; 269 | // Take care of proper memory (re)allocation. 270 | if (libswdctx->membuf.sizemembuf.data) free(libswdctx->membuf.data); 273 | libswdctx->membuf.size=count*sizeof(char); 274 | libswdctx->membuf.data=(unsigned char*)malloc(libswdctx->membuf.size); 275 | if (!libswdctx->membuf.data) 276 | { 277 | libswdctx->membuf.size=0; 278 | libswd_log(libswdctx, LIBSWD_ERROR_OUTOFMEM, 279 | "LIBSWD_E: libswd_cli(): Cannot (re)allocate memory buffer!\n"); 280 | retval=LIBSWD_ERROR_OUTOFMEM; 281 | goto libswd_cli_error; 282 | } else memset((void*)libswdctx->membuf.data, 0xFF, libswdctx->membuf.size); 283 | } else libswdctx->membuf.size=count*sizeof(char); 284 | // Perform MEM-AP read. 285 | retval=libswd_memap_read_char_32(libswdctx, LIBSWD_OPERATION_EXECUTE, 286 | addrstart, count, 287 | (char*)libswdctx->membuf.data ); 288 | if (retval<0) goto libswd_cli_error; 289 | // Store result to a file if requested. 290 | if (filename) 291 | { 292 | FILE *fp; 293 | fp=fopen(filename,"w"); 294 | if (!fp) 295 | { 296 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 297 | "LIBSWD_W: libswd_cli(): Cannot open '%s' data file!\n", 298 | filename, strerror(errno) ); 299 | break; 300 | } 301 | retval=fwrite(libswdctx->membuf.data, sizeof(char), count, fp); 302 | if (!retval) 303 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 304 | "LIBSWD_W: libswd_cli(): Cannot write to data file '%s' (%s)!\n", 305 | filename, strerror(errno) ); 306 | retval=fclose(fp); 307 | if (retval) 308 | { 309 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 310 | "LIBSWD_W: libswd_cli(): Cannot close data file '%s' (%s)!\n", 311 | filename, strerror(errno) ); 312 | } 313 | } 314 | // Print out the result. 315 | for (i=0; imembuf.size;j++) printf("%02X ", (unsigned char)libswdctx->membuf.data[i+j]); 319 | if (j<16) for(;j<16;j++) printf(" "); 320 | printf(" "); 321 | for (j=0;j<16&&i+jmembuf.size;j++) printf("%c", isprint(libswdctx->membuf.data[i+j])?libswdctx->membuf.data[i+j]:'.'); 322 | if (j<16) for (;j<16;j++) printf("."); 323 | } 324 | printf("\n"); 325 | break; 326 | default: 327 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 328 | "LIBSWD_E: libswd_cli(): Unknown Access Port given!\n"); 329 | goto libswd_cli_syntaxerror; 330 | } 331 | continue; 332 | } 333 | 334 | // Check for WRITE invocation. 335 | else if ( strncmp(cmd,"w",1)==0 || strncmp(cmd,"write",5)==0 ) 336 | { 337 | // Parse access port name parameter. 338 | cmd=strsep(&thiscommand," "); 339 | if (!cmd) goto libswd_cli_syntaxerror; 340 | if ( strncmp(cmd,"d",1)==0 || strncmp(cmd,"dap",3)==0 ) 341 | { 342 | ap='d'; 343 | } 344 | else if ( strncmp(cmd,"a",1)==0 || strncmp(cmd,"ap",2)==0 ) 345 | { 346 | ap='a'; 347 | } 348 | else if ( strncmp(cmd,"m",1)==0 || strncmp(cmd,"memap",5)==0 ) 349 | { 350 | ap='m'; 351 | } else goto libswd_cli_syntaxerror; 352 | // Parse address parameter. 353 | cmd=strsep(&thiscommand," "); 354 | if (!cmd) goto libswd_cli_syntaxerror; 355 | errno=LIBSWD_OK; 356 | addrstart=strtol(cmd, (char**)NULL, 0); 357 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 358 | // At this point parse for DP/AP and MEM-AP will vary, so skip it here. 359 | // Perform operations on a given access port. 360 | switch (ap) 361 | { 362 | case 'd': 363 | // Parse data parameter. 364 | if (!thiscommand) goto libswd_cli_syntaxerror; 365 | cmd=strsep(&thiscommand," "); 366 | if (!cmd) goto libswd_cli_syntaxerror; 367 | errno=LIBSWD_OK; 368 | data=strtol(cmd, &endptr, 0); 369 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 370 | retval=libswd_dp_write(libswdctx, LIBSWD_OPERATION_EXECUTE, 371 | addrstart, &data ); 372 | if (retval<0) goto libswd_cli_error; 373 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 374 | "LIBSWD_N: DP[0x%08X]=0x%08X\n", 375 | addrstart, data ); 376 | break; 377 | case 'a': 378 | // Parse data parameter. 379 | if (!thiscommand) goto libswd_cli_syntaxerror; 380 | cmd=strsep(&thiscommand," "); 381 | if (!cmd) goto libswd_cli_syntaxerror; 382 | errno=LIBSWD_OK; 383 | data=strtol(cmd, &endptr, 0); 384 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 385 | retval=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, 386 | addrstart, &data ); 387 | if (retval<0) goto libswd_cli_error; 388 | // Read-back the register value as it may differ from original request. 389 | retval=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, addrstart, &data32); 390 | if (retval<0) goto libswd_cli_error; 391 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, 392 | "LIBSWD_N: AP[0x%08X]=0x%08X\n", 393 | addrstart, *data32 ); 394 | break; 395 | case 'm': 396 | // First data parameter can be a number or filename. 397 | // If number, it will also deretmine data type (char/int). 398 | // Parse data parameter. 399 | if (!thiscommand) goto libswd_cli_syntaxerror; 400 | errno=LIBSWD_OK; 401 | data=strtol(thiscommand, &endptr, 0); 402 | if (!*endptr || endptr==strstr(thiscommand," ")) 403 | { 404 | // 'thiscommand' variable holds the data list. 405 | // First element length determines data type (char or int). 406 | int elmcnt, elmlen, elmbytes; 407 | for (elmlen=0;thiscommand[elmlen]&&thiscommand[elmlen]!=' ';elmlen++); 408 | // Count the number of elements on the list. 409 | elmcnt=1; for (i=0;thiscommand[i];i++) if (thiscommand[i]==' ') elmcnt++; 410 | if (elmlen<1 || elmlen>10) goto libswd_cli_syntaxerror; 411 | // Calculate and allocate memory buffer. 412 | // Buffer is char based, round up size to match 32-bit align if necessary. 413 | if (libswdctx->membuf.data) free(libswdctx->membuf.data); 414 | libswdctx->membuf.size=0; 415 | elmbytes=elmcnt*((elmlen>4)?(4*sizeof(char)):(sizeof(char))); 416 | if (elmbytes%4) elmbytes+=elmbytes%4; 417 | libswdctx->membuf.size=elmbytes; 418 | libswdctx->membuf.data=(unsigned char*)malloc(libswdctx->membuf.size); 419 | if (!libswdctx->membuf.data) 420 | { 421 | libswdctx->membuf.size=0; 422 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 423 | "LIBSWD_E: libswd_cli(): Cannot allocate memory for data, aborting!\n" ); 424 | retval=LIBSWD_ERROR_OUTOFMEM; 425 | goto libswd_cli_syntaxerror; 426 | } else memset((void*)libswdctx->membuf.data, 0xFF, libswdctx->membuf.size); 427 | // Fill the memory buffer with provided data. 428 | // Load char type data. 429 | if (elmlen<=4) 430 | { 431 | for (i=0;(imembuf.size)&&thiscommand;i++) 432 | { 433 | cmd=strsep(&thiscommand," "); 434 | errno=LIBSWD_OK; 435 | data=strtol(cmd,(char**)NULL, 0); 436 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 437 | libswdctx->membuf.data[i]=(unsigned char)data; 438 | } 439 | } 440 | // Load int type data. 441 | else 442 | { 443 | for (i=0;(imembuf.size/4)&&thiscommand;i++) 444 | { 445 | cmd=strsep(&thiscommand," "); 446 | errno=LIBSWD_OK; 447 | data=strtol(cmd,(char**)NULL, 0); 448 | if (errno!=LIBSWD_OK) goto libswd_cli_syntaxerror; 449 | libswdctx->membuf.data[i*4+0]=(unsigned char)data; 450 | libswdctx->membuf.data[i*4+1]=(unsigned char)(data>>8); 451 | libswdctx->membuf.data[i*4+2]=(unsigned char)(data>>16); 452 | libswdctx->membuf.data[i*4+3]=(unsigned char)(data>>24); 453 | } 454 | } 455 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 456 | "LIBSWD_I: libswd_cli(): Parsed %d bytes of data into memory buffer!\n", 457 | libswdctx->membuf.size ); 458 | } 459 | // Given data parameter is a filename. Load file into memory. 460 | else 461 | { 462 | filename=thiscommand; 463 | res=LIBSWD_OK; 464 | FILE *fp; 465 | fp=fopen(filename,"r"); 466 | if (!fp) 467 | { 468 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 469 | "LIBSWD_E: libswd_cli(): Cannot open '%s' data file (%s), aborting!\n", 470 | filename, strerror(errno)); 471 | return LIBSWD_ERROR_FILE; 472 | } 473 | // Take care of (re)allocating memory for membuf based on a file size. 474 | if (libswdctx->membuf.size) free(libswdctx->membuf.data); 475 | fseek(fp, 0, SEEK_END); 476 | libswdctx->membuf.size=ftell(fp); 477 | libswdctx->membuf.data=(unsigned char*)malloc(libswdctx->membuf.size); 478 | fseek(fp, 0, SEEK_SET); 479 | if (!libswdctx->membuf.data) 480 | { 481 | libswdctx->membuf.size=0; 482 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 483 | "LIBSWD_E: libswd_cli(): Cannot allocate memory to load '%s' file, aborting!\n", 484 | filename ); 485 | res=LIBSWD_ERROR_OUTOFMEM; 486 | goto libswd_cli_write_memap_file_load_error; 487 | } else memset((void*)libswdctx->membuf.data, 0xFF, libswdctx->membuf.size); 488 | // Load file content into memory. 489 | retval=fread(libswdctx->membuf.data, sizeof(char), libswdctx->membuf.size, fp); 490 | if (!retval) 491 | { 492 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 493 | "LIBSWD_E: libswd_cli(): Cannot load data from '%s' file (%s), aborting!\n", 494 | filename, strerror(errno) ); 495 | res=LIBSWD_ERROR_FILE; 496 | goto libswd_cli_write_memap_file_load_error; 497 | } 498 | libswd_cli_write_memap_file_load_error: 499 | retval=fclose(fp); 500 | if (retval) 501 | { 502 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 503 | "LIBSWD_E: libswd_cli(): Cannot close data file '%s' (%s), aborting!\n", 504 | filename, strerror(errno) ); 505 | return LIBSWD_ERROR_FILE; 506 | } 507 | if (res!=LIBSWD_OK) return res; 508 | //libswd_cli_write_memap_file_load_ok: 509 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 510 | "LIBSWD_I: libswd_cli(): %d bytes of data from '%s' file loaded!\n", 511 | libswdctx->membuf.size, filename ); 512 | } 513 | // At this point data are in membuf, sent them to MEM-AP. 514 | retval=libswd_memap_write_char_32(libswdctx, LIBSWD_OPERATION_EXECUTE, 515 | addrstart, libswdctx->membuf.size, 516 | (char*)libswdctx->membuf.data ); 517 | if (retval<0) goto libswd_cli_error; 518 | // Print out the data. 519 | for (i=0; imembuf.size; i=i+16) 520 | { 521 | printf("\n%08X: ", i+addrstart); 522 | for (j=0;j<16&&i+jmembuf.size;j++) printf("%02X ", (unsigned char)libswdctx->membuf.data[i+j]); 523 | if (j<16) for(;j<16;j++) printf(" "); 524 | printf(" "); 525 | for (j=0;j<16&&i+jmembuf.size;j++) printf("%c", isprint(libswdctx->membuf.data[i+j])?libswdctx->membuf.data[i+j]:'.'); 526 | if (j<16) for (;j<16;j++) printf("."); 527 | } 528 | printf("\n"); 529 | break; 530 | default: 531 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 532 | "LIBSWD_E: libswd_cli(): Unknown Access Port given!\n"); 533 | goto libswd_cli_syntaxerror; 534 | } 535 | break; 536 | } 537 | // No known thiscommand was invoked, show usage message and return message. 538 | else 539 | { 540 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 541 | "LIBSWD_E: libswd_cli(): %s.\n", 542 | libswd_error_string(LIBSWD_ERROR_CLISYNTAX) ); 543 | libswd_cli_print_usage(libswdctx); 544 | return LIBSWD_ERROR_CLISYNTAX; 545 | } 546 | } 547 | } 548 | 549 | return LIBSWD_OK; 550 | 551 | libswd_cli_syntaxerror: 552 | retval=LIBSWD_ERROR_CLISYNTAX; 553 | libswd_cli_error: 554 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 555 | "LIBSWD_E: libswd_cli(): %s.\n", 556 | libswd_error_string(retval) ); 557 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 558 | "LIBSWD_D: libswd_cli(): CMD=%s COMMAND=%s.\n", 559 | cmd, command ); 560 | return retval; 561 | }; 562 | 563 | 564 | /** @} */ 565 | -------------------------------------------------------------------------------- /libswd_cmd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_cmd.c */ 36 | 37 | #include 38 | 39 | /** Payload for commands that will not change, transmitted MSBFirst */ 40 | /// SW-DP Reset sequence. 41 | static const char LIBSWD_CMD_SWDPRESET[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}; 42 | /// Switches DAP from JTAG to SWD. 43 | static const char LIBSWD_CMD_JTAG2SWD[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9e, 0xe7}; 44 | /// Switches DAP from SWD to JTAG. 45 | static const char LIBSWD_CMD_SWD2JTAG[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3c, 0xe7}; 46 | /// Inserts idle clocks for proper data processing. 47 | static const char LIBSWD_CMD_IDLE[] = {0x00}; 48 | 49 | /******************************************************************************* 50 | * \defgroup libswd_cmd_enqueue SWD Command Genration and Enqueueing routines. 51 | * Command quants are first generated/created in memory, then enqueued into 52 | * command queue for execution by libswd_cmd_flush(). Queue elements are created 53 | * in memory and filled with payload, then appended to the queue. If enqueue 54 | * fails, memory for newly created elements is set free before return. 55 | * All functions here start with "libswd_cmd_queue_append_" prefix. 56 | * Functions here are NOT intelligent, they only create payload in memory, 57 | * so treat them rather as blocks for high-level functions. 58 | * @{ 59 | ******************************************************************************/ 60 | 61 | /** Append selected command to a context's command queue (libswdctx->cmdq). 62 | * This function does not update the libswdctx->cmdq pointer (its updated on flush). 63 | * Limitation to CMD queue len is handled here. 64 | * \param *libswdctx swd context pointer containing the command queue. 65 | * \param *cmd command to be appended to the context's command queue. 66 | * \return number of elements appended or LIBSWD_ERROR_CODE on failure. 67 | */ 68 | int libswd_cmd_enqueue(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 69 | if (libswdctx==NULL || cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 70 | int res; 71 | if (libswdctx->config.maxcmdqlen!=0){ 72 | while (libswdctx->stats.cmdqlen >= libswdctx->config.maxcmdqlen){ 73 | libswd_cmd_t *cmd; 74 | cmd=libswd_cmdq_find_head(libswdctx->cmdq); 75 | if ((cmd->done!=1) || (cmd==libswdctx->cmdq)){ 76 | //Need to release memory, but this CMD in queue is not yet handled, so we can`t remove it 77 | return LIBSWD_ERROR_OUTOFMEM; 78 | } else { 79 | res=libswd_cmdq_free_one_element(libswdctx, cmd); 80 | if (res<1) return LIBSWD_ERROR_QUEUE; 81 | } 82 | } 83 | } 84 | res=libswd_cmdq_append(libswdctx, cmd); 85 | return res; 86 | } 87 | 88 | /** Appends command queue with SWD Request packet header. 89 | * Note that contents is not validated, so bad request can be sent as well. 90 | * \param *libswdctx swd context pointer. 91 | * \param *request pointer to the 8-bit request payload. 92 | * \return return number elements appended (1), or LIBSWD_ERROR_CODE on failure. 93 | */ 94 | int libswd_cmd_enqueue_mosi_request(libswd_ctx_t *libswdctx, char *request){ 95 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 96 | if (request==NULL) return LIBSWD_ERROR_NULLPOINTER; 97 | int res; 98 | libswd_cmd_t *cmd; 99 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 100 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 101 | cmd->request=*request; 102 | cmd->bits=LIBSWD_REQUEST_BITLEN; 103 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_REQUEST; 104 | res=libswd_cmd_enqueue(libswdctx, cmd); 105 | if (res<1) free(cmd); 106 | return res; 107 | } 108 | 109 | /** Append command queue with Turnaround activating MOSI mode. 110 | * \param *libswdctx swd context pointer. 111 | * \return return number elements appended (1), or LIBSWD_ERROR_CODE on failure. 112 | */ 113 | int libswd_cmd_enqueue_mosi_trn(libswd_ctx_t *libswdctx){ 114 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 115 | int res; 116 | libswd_cmd_t *cmd; 117 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 118 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 119 | cmd->TRNnMOSI=0; 120 | cmd->bits=libswdctx->config.trnlen; 121 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_TRN; 122 | res=libswd_cmd_enqueue(libswdctx, cmd); 123 | if (res<1) free(cmd); 124 | return res; 125 | } 126 | 127 | /** Append command queue with Turnaround activating MISO mode. 128 | * \param *libswdctx swd context pointer. 129 | * \return return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 130 | */ 131 | int libswd_cmd_enqueue_miso_trn(libswd_ctx_t *libswdctx){ 132 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 133 | int res; 134 | libswd_cmd_t *cmd; 135 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 136 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 137 | cmd->TRNnMOSI=1; 138 | cmd->bits=libswdctx->config.trnlen; 139 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_TRN; 140 | res=libswd_cmd_enqueue(libswdctx, cmd); 141 | if (res<1) free(cmd); 142 | return res; 143 | } 144 | 145 | /** Append command queue with bus binary read bit-by-bit operation. 146 | * This function will append command to the queue for each bit, and store 147 | * one bit into single char array element, so read is not constrained to 8 bits. 148 | * On error memory is released and apropriate error code is returned. 149 | * Important: Memory pointed by *data must be allocated prior call! 150 | * \param *libswdctx swd context pointer. 151 | * \param **data allocated data array to write result into. 152 | * \param count number of bits to read (also the **data size). 153 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 154 | */ 155 | int libswd_cmd_enqueue_miso_nbit(libswd_ctx_t *libswdctx, char **data, int count){ 156 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 157 | if (count<=0) return LIBSWD_ERROR_PARAM; 158 | int res = 0; 159 | int res2 = 0; 160 | libswd_cmd_t *cmd, *oldcmdq=libswdctx->cmdq; 161 | int i,cmdcnt=0; 162 | for (i=0;ibits=1; 169 | if (data!=NULL) *data=&cmd->misobit; 170 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_BITBANG; 171 | res=libswd_cmd_enqueue(libswdctx, cmd); 172 | if (res<1) break; 173 | cmdcnt+=res; 174 | } 175 | //If there was problem enqueueing elements, rollback changes on queue. 176 | if (res<1) { 177 | res2=libswd_cmdq_free_tail(libswdctx, oldcmdq); 178 | if (res2<0) return res2; 179 | return res; 180 | } else return cmdcnt; 181 | } 182 | 183 | /** Append command queue with bus binary write bit-by-bit operation. 184 | * This function will append command to the queue for each bit and store 185 | * one bit into single char array element, so read is not constrained to 8 bits. 186 | * On error memory is released and apropriate error code is returned. 187 | * Important: Memory pointed by *data must be allocated prior call! 188 | * \param *libswdctx swd context pointer. 189 | * \param **data allocated data array to write result into. 190 | * \param count number of bits to read (also the **data size). 191 | * \return number of elements processed, or LIBSWD_ERROR_CODE on failure. 192 | */ 193 | int libswd_cmd_enqueue_mosi_nbit(libswd_ctx_t *libswdctx, char *data, int count){ 194 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 195 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 196 | if (count<=0) return LIBSWD_ERROR_PARAM; 197 | int res = 0; 198 | int res2 = 0; 199 | int cmdcnt=0; 200 | libswd_cmd_t *cmd, *oldcmdq=libswdctx->cmdq; 201 | int i; 202 | for (i=0;imosibit=data[i]; 209 | cmd->bits=1; 210 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_BITBANG; 211 | res=libswd_cmd_enqueue(libswdctx, cmd); 212 | if (res<1) break; 213 | cmdcnt+=res; 214 | } 215 | //If there was problem enqueueing elements, rollback changes on queue. 216 | if (res<1){ 217 | res2=libswd_cmdq_free_tail(libswdctx, oldcmdq); 218 | if (res2<0) return res2; 219 | libswdctx->cmdq=oldcmdq; 220 | return res; 221 | } else return cmdcnt; 222 | } 223 | 224 | /** Append command queue with parity bit write. 225 | * \param *libswdctx swd context pointer. 226 | * \param *parity parity value pointer. 227 | * \return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 228 | */ 229 | int libswd_cmd_enqueue_mosi_parity(libswd_ctx_t *libswdctx, char *parity){ 230 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 231 | if (*parity!=0 && *parity!=1) return LIBSWD_ERROR_PARAM; 232 | int res; 233 | libswd_cmd_t *cmd; 234 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 235 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 236 | cmd->parity=*parity; 237 | cmd->bits=1; 238 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_PARITY; 239 | res=libswd_cmd_enqueue(libswdctx, cmd); 240 | if (res<1) free(cmd); 241 | return res; 242 | } 243 | 244 | /** Append command queue with parity bit read. 245 | * \param *libswdctx swd context pointer. 246 | * \param *parity parity value pointer. 247 | * \return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 248 | */ 249 | int libswd_cmd_enqueue_miso_parity(libswd_ctx_t *libswdctx, char **parity){ 250 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 251 | int res; 252 | libswd_cmd_t *cmd; 253 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 254 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 255 | if (parity!=NULL) *parity=&cmd->parity; 256 | cmd->bits=1; 257 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_PARITY; 258 | res=libswd_cmd_enqueue(libswdctx, cmd); 259 | if (res<1) free(cmd); 260 | return res; 261 | } 262 | 263 | /** Append command queue with data read. 264 | * \param *libswdctx swd context pointer. 265 | * \param *data data pointer. 266 | * \return of elements appended (1), or LIBSWD_ERROR_CODE on failure. 267 | */ 268 | int libswd_cmd_enqueue_miso_data(libswd_ctx_t *libswdctx, int **data){ 269 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 270 | int res; 271 | libswd_cmd_t *cmd; 272 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 273 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 274 | if (data!=NULL) *data=&cmd->misodata; 275 | cmd->bits=32; 276 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_DATA; 277 | res=libswd_cmd_enqueue(libswdctx, cmd); // should be 1 on success 278 | if (res<1) free(cmd); 279 | return res; 280 | } 281 | 282 | /** Append command queue with data and parity read. 283 | * \param *libswdctx swd context pointer. 284 | * \param *data data value pointer. 285 | * \param *parity parity value pointer. 286 | * \return number of elements appended (2), or LIBSWD_ERROR_CODE on failure. 287 | */ 288 | int libswd_cmd_enqueue_miso_data_p(libswd_ctx_t *libswdctx, int **data, char **parity){ 289 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 290 | int res, cmdcnt=0; 291 | res=libswd_cmd_enqueue_miso_data(libswdctx, data); 292 | if (res<1) return res; 293 | cmdcnt+=res; 294 | res=libswd_cmd_enqueue_miso_parity(libswdctx, parity); 295 | if (res<1) return res; 296 | cmdcnt+=res; 297 | return cmdcnt; // should be 2 or 3(+trn) on success 298 | } 299 | 300 | /** Append command queue with series of data and parity read. 301 | * \param *libswdctx swd context pointer. 302 | * \param **data data value array pointer. 303 | * \param **parity parity value array pointer. 304 | * \param count number of (data+parity) elements to read. 305 | * \return number of elements appended (2*count), or LIBSWD_ERROR_CODE on failure. 306 | */ 307 | int libswd_cmd_enqueue_miso_n_data_p(libswd_ctx_t *libswdctx, int **data, char **parity, int count){ 308 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 309 | if (count<=0) return LIBSWD_ERROR_PARAM; 310 | int i,res, cmdcnt=0; 311 | for (i=0;i<=count;i++){ 312 | res=libswd_cmd_enqueue_miso_data_p(libswdctx, &data[i], &parity[i]); 313 | if (res<2) return LIBSWD_ERROR_RESULT; 314 | cmdcnt+=res; 315 | } 316 | return cmdcnt; 317 | } 318 | 319 | /** Append command queue with data and parity write. 320 | * \param *libswdctx swd context pointer. 321 | * \param *data data value pointer. 322 | * \return number of elements appended (1), or LIBSWD_ERROR_CODE on failure. 323 | */ 324 | int libswd_cmd_enqueue_mosi_data(libswd_ctx_t *libswdctx, int *data){ 325 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 326 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 327 | int res; 328 | libswd_cmd_t *cmd; 329 | cmd=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 330 | if (cmd==NULL) return LIBSWD_ERROR_OUTOFMEM; 331 | cmd->mosidata=*data; 332 | cmd->bits=32; 333 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_DATA; 334 | res=libswd_cmd_enqueue(libswdctx, cmd); // should be 1 or 2 on success 335 | if (res<1) free(cmd); 336 | return res; 337 | } 338 | 339 | /** Append command queue with data and automatic parity write. 340 | * \param *libswdctx swd context pointer. 341 | * \param *data data value pointer. 342 | * \return number of elements appended (2), or LIBSWD_ERROR_CODE on failure. 343 | */ 344 | int libswd_cmd_enqueue_mosi_data_ap(libswd_ctx_t *libswdctx, int *data){ 345 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 346 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 347 | int res, cmdcnt=0; 348 | char parity; 349 | res=libswd_cmd_enqueue_mosi_data(libswdctx, data); 350 | if (res<1) return res; 351 | cmdcnt+=res; 352 | res=libswd_bin32_parity_even(data, &parity); 353 | if (res<0) return res; 354 | res=libswd_cmd_enqueue_mosi_parity(libswdctx, &parity); 355 | if (res<1) return res; 356 | cmdcnt+=res; 357 | return cmdcnt; // should be 2 or 3 on success 358 | } 359 | 360 | /** Append command queue with data and provided parity write. 361 | * \param *libswdctx swd context pointer. 362 | * \param *data data value pointer. 363 | * \param *parity parity value pointer. 364 | * \return number of elements appended (2), or LIBSWD_ERROR_CODE on failure. 365 | */ 366 | int libswd_cmd_enqueue_mosi_data_p(libswd_ctx_t *libswdctx, int *data, char *parity){ 367 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 368 | if (data==NULL || parity==NULL) return LIBSWD_ERROR_NULLPOINTER; 369 | int res, cmdcnt=0; 370 | res=libswd_cmd_enqueue_mosi_data(libswdctx, data); 371 | if (res<1) return res; 372 | cmdcnt+=res; 373 | res=libswd_cmd_enqueue_mosi_parity(libswdctx, parity); 374 | if (res<1) return res; 375 | cmdcnt+=res; 376 | return cmdcnt; // should be 2 or 3 on success 377 | } 378 | 379 | /** Append command queue with series of data and automatic parity writes. 380 | * \param *libswdctx swd context pointer. 381 | * \param **data data value array pointer. 382 | * \param count number of (data+parity) elements to read. 383 | * \return number of elements appended (2*count), or LIBSWD_ERROR_CODE on failure. 384 | */ 385 | int libswd_cmd_enqueue_mosi_n_data_ap(libswd_ctx_t *libswdctx, int **data, int count){ 386 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 387 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 388 | if (count<1) return LIBSWD_ERROR_PARAM; 389 | int i, res, cmdcnt=0; 390 | for (i=0;iack; 430 | cmd->bits=LIBSWD_ACK_BITLEN; 431 | cmd->cmdtype=LIBSWD_CMDTYPE_MISO_ACK; 432 | res=libswd_cmd_enqueue(libswdctx, cmd); //should be 1 on success 433 | if (res<1) free(cmd); 434 | return res; 435 | } 436 | 437 | /** Append command queue with len-octet size control seruence. 438 | * This control sequence can be used for instance to send payload of packets 439 | * switching DAP between JTAG and SWD mode. 440 | * \param *libswdctx swd context pointer. 441 | * \param *ctlmsg control message array pointer. 442 | * \param len number of elements to send from *ctlmsg. 443 | * \return number of elements appended (len), or LIBSWD_ERROR_CODE on failure. 444 | */ 445 | int libswd_cmd_enqueue_mosi_control(libswd_ctx_t *libswdctx, char *ctlmsg, int len){ 446 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 447 | if (ctlmsg==NULL) return LIBSWD_ERROR_NULLPOINTER; 448 | if (len<=0) return LIBSWD_ERROR_PARAM; 449 | int elm = 0; 450 | int res = 0; 451 | int res2 = 0; 452 | int cmdcnt = 0; 453 | libswd_cmd_t *cmd=NULL, *oldcmdq=libswdctx->cmdq; 454 | for (elm=0;elmcontrol=ctlmsg[elm]; 461 | cmd->cmdtype=LIBSWD_CMDTYPE_MOSI_CONTROL; 462 | cmd->bits=sizeof(ctlmsg[elm])*LIBSWD_DATA_BYTESIZE; 463 | res=libswd_cmd_enqueue(libswdctx, cmd); 464 | if (res<1) break; 465 | cmdcnt+=res; 466 | } 467 | //If there was problem enqueueing elements, rollback changes on queue. 468 | if (res<1){ 469 | res2=libswd_cmdq_free_tail(libswdctx, oldcmdq); 470 | if (res2<0) return res2; 471 | libswdctx->cmdq=oldcmdq; 472 | return res; 473 | } return cmdcnt; 474 | } 475 | 476 | /** Append command queue with SW-DP-RESET sequence. 477 | * \param *libswdctx swd context pointer. 478 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 479 | */ 480 | int libswd_cmd_enqueue_mosi_dap_reset(libswd_ctx_t *libswdctx){ 481 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_SWDPRESET, sizeof(LIBSWD_CMD_SWDPRESET)); 482 | } 483 | 484 | /** Append command queue with idle sequence. 485 | * \param *libswdctx swd context pointer. 486 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 487 | */ 488 | int libswd_cmd_enqueue_mosi_idle(libswd_ctx_t *libswdctx){ 489 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_IDLE, sizeof(LIBSWD_CMD_IDLE)); 490 | } 491 | 492 | /** Append command queue with JTAG-TO-SWD DAP-switch sequence. 493 | * \param *libswdctx swd context pointer. 494 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 495 | */ 496 | int libswd_cmd_enqueue_mosi_jtag2swd(libswd_ctx_t *libswdctx){ 497 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_JTAG2SWD, sizeof(LIBSWD_CMD_JTAG2SWD)); 498 | } 499 | 500 | /** Append command queue with SWD-TO-JTAG DAP-switch sequence. 501 | * \param *libswdctx swd context pointer. 502 | * \return number of elements appended, or LIBSWD_ERROR_CODE on failure. 503 | */ 504 | int libswd_cmd_enqueue_mosi_swd2jtag(libswd_ctx_t *libswdctx){ 505 | return libswd_cmd_enqueue_mosi_control(libswdctx, (char *)LIBSWD_CMD_SWD2JTAG, sizeof(LIBSWD_CMD_SWD2JTAG)); 506 | } 507 | 508 | /** Return human readable command type string of *cmd. 509 | * \param *cmd command the name is to be printed. 510 | * \return string containing human readable command name, or NULL on failure. 511 | */ 512 | char *libswd_cmd_string_cmdtype(libswd_cmd_t *cmd){ 513 | if (cmd==NULL) return NULL; 514 | switch (cmd->cmdtype){ 515 | case LIBSWD_CMDTYPE_MOSI_DATA: return "MOSI_DATA"; 516 | case LIBSWD_CMDTYPE_MOSI_REQUEST: return "MOSI_REQUEST"; 517 | case LIBSWD_CMDTYPE_MOSI_TRN: return "MOSI_TRN"; 518 | case LIBSWD_CMDTYPE_MOSI_PARITY: return "MOSI_PARITY"; 519 | case LIBSWD_CMDTYPE_MOSI_BITBANG: return "MOSI_BITBANG"; 520 | case LIBSWD_CMDTYPE_MOSI_CONTROL: return "MOSI_CONTROL"; 521 | case LIBSWD_CMDTYPE_MOSI: return "MOSI"; 522 | case LIBSWD_CMDTYPE_UNDEFINED: return "UNDEFINED"; 523 | case LIBSWD_CMDTYPE_MISO: return "MISO"; 524 | case LIBSWD_CMDTYPE_MISO_ACK: return "MISO_ACK"; 525 | case LIBSWD_CMDTYPE_MISO_BITBANG: return "MISO_BITBANG"; 526 | case LIBSWD_CMDTYPE_MISO_PARITY: return "MISO_PARITY"; 527 | case LIBSWD_CMDTYPE_MISO_TRN: return "MISO_TRN"; 528 | case LIBSWD_CMDTYPE_MISO_DATA: return "MISO_DATA"; 529 | default: return "Unknown command type!"; 530 | } 531 | } 532 | 533 | 534 | /** @} */ 535 | -------------------------------------------------------------------------------- /libswd_cmdq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_cmdq.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_cmdq Command Queue helper functions 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | /** Initialize new queue element in memory that becomes a queue root. 45 | * \param *libswdctx swd context pointer containing empty command queue. 46 | * \return LIBSWD_OK on success, LIBSWD_ERROR_CODE code on failure 47 | */ 48 | int libswd_cmdq_init(libswd_ctx_t *libswdctx){ 49 | libswd_cmd_t * new_cmdq=(libswd_cmd_t *)calloc(1,sizeof(libswd_cmd_t)); 50 | if (new_cmdq==NULL) return LIBSWD_ERROR_OUTOFMEM; 51 | new_cmdq->prev=NULL; 52 | new_cmdq->next=NULL; 53 | libswdctx->cmdq=new_cmdq; 54 | libswdctx->stats.cmdqlen=1; //One cmd element is always present in cmdq, until libswd_cmdq_free is called 55 | return LIBSWD_OK; 56 | } 57 | 58 | /** Find queue root (first element). 59 | * \param *cmdq pointer to any queue element 60 | * \return libswd_cmd_t* pointer to the first element (root), NULL on failure 61 | */ 62 | libswd_cmd_t* libswd_cmdq_find_head(libswd_cmd_t *cmdq){ 63 | if (cmdq==NULL) return NULL; 64 | libswd_cmd_t *cmd=cmdq; 65 | while (cmd->prev!=NULL) cmd=cmd->prev; 66 | return cmd; 67 | } 68 | 69 | /** Find queue tail (last element). 70 | * \param *cmdq pointer to any queue element 71 | * \return libswd_cmd_t* pointer to the last element (tail), NULL on failure 72 | */ 73 | libswd_cmd_t* libswd_cmdq_find_tail(libswd_cmd_t *cmdq){ 74 | if (cmdq==NULL) return NULL; 75 | libswd_cmd_t *cmd=cmdq; 76 | while (cmd->next!=NULL) cmd=cmd->next; 77 | return cmd; 78 | } 79 | 80 | /** Find last executed element from the *cmdq. 81 | * Start search at *cmdq head, return element pointer or NULL if not found. 82 | * \param *cmdq queue that contains elements. 83 | * \return libswd_cmd_t* pointer to the last executed element or NULL on error. 84 | */ 85 | libswd_cmd_t* libswd_cmdq_find_exectail(libswd_cmd_t *cmdq){ 86 | if (cmdq==NULL) return NULL; 87 | libswd_cmd_t *cmd=libswd_cmdq_find_head(cmdq); 88 | if (cmd==NULL) return NULL; 89 | for (cmd=libswd_cmdq_find_head(cmdq);cmd;cmd=cmd->next){ 90 | if (cmd->done) { 91 | if (cmd->next){ 92 | if (!cmd->next->done) return cmd; 93 | } else return cmd; 94 | } 95 | } 96 | return NULL; 97 | } 98 | 99 | /** Append element pointed by *cmd at the end of the quque pointed by *cmdq. 100 | * After this operation queue will be pointed by appended element (ie. last 101 | * element added becomes actual queue pointer to show what was added recently). 102 | * \param *libswdctx swd context pointer containing the command queue. 103 | * \param *cmd pointer to the command to be appended 104 | * \return number of appended elements (one), LIBSWD_ERROR_CODE on failure 105 | */ 106 | int libswd_cmdq_append(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 107 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 108 | if (libswdctx->cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; //XXX Create a start point automatically? 109 | if (cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 110 | if (libswdctx->cmdq->next != NULL){ 111 | libswd_cmd_t *lastcmd; 112 | lastcmd=libswd_cmdq_find_tail(libswdctx->cmdq); 113 | lastcmd->next=cmd; 114 | cmd->prev=lastcmd; 115 | } else { 116 | libswdctx->cmdq->next=cmd; 117 | cmd->prev=libswdctx->cmdq; 118 | } 119 | libswdctx->stats.cmdqlen++; 120 | return 1; 121 | } 122 | 123 | /** Free whole queue pointed by *cmdq element in libswdctx. 124 | * \param *libswdctx swd context pointer containing the command queue. 125 | * \return number of elements destroyed, LIBSWD_ERROR_CODE on failure 126 | */ 127 | int libswd_cmdq_free(libswd_ctx_t *libswdctx){ 128 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 129 | if (libswdctx->cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 130 | int cmdcnt=0; 131 | libswd_cmd_t *cmd, *nextcmd; 132 | cmd=libswd_cmdq_find_head(libswdctx->cmdq); 133 | while (cmd!=NULL) { 134 | nextcmd=cmd->next; 135 | free(cmd); 136 | cmd=nextcmd; 137 | cmdcnt++; 138 | } 139 | libswdctx->cmdq=NULL; 140 | libswdctx->stats.cmdqlen=0; 141 | return cmdcnt; 142 | } 143 | 144 | /** Free queue head up to *cmd element. 145 | * \param *libswdctx swd context pointer containing the command queue. 146 | * \param *cmd pointer to the element that becomes new queue root. 147 | * \return number of elements destroyed, or LIBSWD_ERROR_CODE on failure. 148 | */ 149 | int libswd_cmdq_free_head(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 150 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 151 | if (cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 152 | int cmdcnt=0; 153 | libswd_cmd_t *cmdqroot, *nextcmd; 154 | cmdqroot=libswd_cmdq_find_head(cmd); 155 | while(cmdqroot!=cmd){ 156 | nextcmd=cmdqroot->next; 157 | free(cmdqroot); 158 | cmdqroot=nextcmd; 159 | cmdcnt++; 160 | } 161 | cmdqroot->prev=NULL; 162 | libswdctx->cmdq=cmdqroot; 163 | libswdctx->stats.cmdqlen-=cmdcnt; 164 | return cmdcnt; 165 | } 166 | 167 | /** Free queue tail starting after *cmd element. 168 | * \param *libswdctx swd context pointer containing the command queue. 169 | * \param *cmd pointer to the last element on the new queue. 170 | * \return number of elements destroyed, or LIBSWD_ERROR_CODE on failure. 171 | */ 172 | int libswd_cmdq_free_tail(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 173 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 174 | if (cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 175 | int cmdcnt=0; 176 | libswd_cmd_t *cmdqend; 177 | if (cmd->next==NULL) return 0; 178 | cmdqend=libswd_cmdq_find_tail(cmd->next); 179 | if (cmdqend==NULL) return LIBSWD_ERROR_QUEUE; 180 | while(cmdqend!=cmd){ 181 | cmdqend=cmdqend->prev; 182 | free(cmdqend->next); 183 | cmdcnt++; 184 | } 185 | cmd->next=NULL; 186 | libswdctx->stats.cmdqlen-=cmdcnt; 187 | return cmdcnt; 188 | } 189 | 190 | /** Free one cmd element from cmdq. 191 | * \param *libswdctx swd context pointer containing the command queue. 192 | * \param *cmd pointer to any element on command queue 193 | * \return number of elements destroyed, LIBSWD_ERROR_CODE on failure 194 | */ 195 | int libswd_cmdq_free_one_element(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 196 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 197 | if (cmd==NULL) return LIBSWD_ERROR_NULLQUEUE; 198 | libswd_cmd_t *prevcmd,*nextcmd; 199 | prevcmd=cmd->prev; 200 | nextcmd=cmd->next; 201 | if ((prevcmd==NULL)&&(nextcmd==NULL)) return 0; //root cmd cannot be removed 202 | if (prevcmd!=NULL){ 203 | prevcmd->next=nextcmd; 204 | } 205 | if (nextcmd!=NULL){ 206 | nextcmd->prev=prevcmd; 207 | } 208 | free(cmd); 209 | libswdctx->stats.cmdqlen--; 210 | return 1; 211 | } 212 | 213 | /** Flush command queue contents into interface driver and update **cmdq. 214 | * Operation is specified by LIBSWD_OPERATION and can be used to select 215 | * how to flush the queue, ie. head-only, tail-only, one, all, etc. 216 | * This function is not only used to flush libswdctx->cmdq but also other 217 | * queues (i.e. error handling) so the parameter is **cmdq not libswdctx itself. 218 | * This is the only place where **cmdq is updated to the last executed element. 219 | * Double pointer is used because we update pointer element not its data. 220 | * \param *cmdq pointer to queue to be flushed. 221 | * \param operation tells how to flush the queue. 222 | * \return number of commands transmitted, or LIBSWD_ERROR_CODE on failure. 223 | * !TODO: HOW WE WANT TO UPDATE CMDQ ELEMENT AFTER PROCESSING WITHOUT DOUBLE POINTER? 224 | */ 225 | int libswd_cmdq_flush(libswd_ctx_t *libswdctx, libswd_cmd_t **cmdq, libswd_operation_t operation){ 226 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 227 | if (*cmdq==NULL||cmdq==NULL) return LIBSWD_ERROR_NULLQUEUE; 228 | if (operationLIBSWD_OPERATION_LAST) 229 | return LIBSWD_ERROR_BADOPCODE; 230 | 231 | int res, cmdcnt=0; 232 | libswd_cmd_t *cmd, *firstcmd, *lastcmd; 233 | 234 | switch (operation){ 235 | case LIBSWD_OPERATION_TRANSMIT_HEAD: 236 | firstcmd=libswd_cmdq_find_head(*cmdq); 237 | lastcmd=*cmdq; 238 | break; 239 | case LIBSWD_OPERATION_TRANSMIT_TAIL: 240 | firstcmd=*cmdq; 241 | lastcmd=libswd_cmdq_find_tail(*cmdq); 242 | break; 243 | case LIBSWD_OPERATION_EXECUTE: 244 | case LIBSWD_OPERATION_TRANSMIT_ALL: 245 | firstcmd=libswd_cmdq_find_head(*cmdq); 246 | lastcmd=libswd_cmdq_find_tail(*cmdq); 247 | break; 248 | case LIBSWD_OPERATION_TRANSMIT_ONE: 249 | firstcmd=*cmdq; 250 | lastcmd=*cmdq; 251 | break; 252 | case LIBSWD_OPERATION_TRANSMIT_LAST: 253 | firstcmd=libswd_cmdq_find_tail(*cmdq); 254 | lastcmd=firstcmd; 255 | break; 256 | default: 257 | return LIBSWD_ERROR_BADOPCODE; 258 | } 259 | 260 | if (firstcmd==NULL) return LIBSWD_ERROR_QUEUEROOT; 261 | if (lastcmd==NULL) return LIBSWD_ERROR_QUEUETAIL; 262 | 263 | if (firstcmd==lastcmd){ 264 | if (!firstcmd->done) { 265 | res=libswd_drv_transmit(libswdctx, firstcmd); 266 | if (res<0) return res; 267 | *cmdq=firstcmd; 268 | } 269 | return 1; 270 | } 271 | 272 | for (cmd=firstcmd;;cmd=cmd->next){ 273 | if (cmd->done){ 274 | if (cmd->next){ 275 | continue; 276 | } else break; 277 | } 278 | res=libswd_drv_transmit(libswdctx, cmd); 279 | if (res<0) return res; 280 | cmdcnt+=res; 281 | if (cmd==lastcmd) break; 282 | } 283 | *cmdq=cmd; 284 | return cmdcnt; 285 | } 286 | 287 | /** @} */ 288 | -------------------------------------------------------------------------------- /libswd_core.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_core.c */ 36 | 37 | #include 38 | #include 39 | 40 | /******************************************************************************* 41 | * \defgroup libswd_core Library and Context (de)initialization routines. 42 | * @{ 43 | ******************************************************************************/ 44 | 45 | /** LibSWD initialization routine. 46 | * It should be called prior any operation made with libswd. It initializes 47 | * command queue and basic parameters for context that is returned as pointer. 48 | * \return pointer to the initialized swd context. 49 | */ 50 | libswd_ctx_t *libswd_init(void){ 51 | int res; 52 | libswd_ctx_t *libswdctx; 53 | libswdctx=(libswd_ctx_t *)calloc(1,sizeof(libswd_ctx_t)); 54 | if (libswdctx==NULL) return NULL; 55 | libswdctx->driver=(libswd_driver_t *)calloc(1,sizeof(libswd_driver_t)); 56 | if (libswdctx->driver==NULL){ 57 | free(libswdctx); 58 | return NULL; 59 | } 60 | res=libswd_cmdq_init(libswdctx); 61 | if (res<0) { 62 | libswd_deinit_ctx(libswdctx); 63 | return NULL; 64 | } 65 | libswdctx->config.initialized=LIBSWD_TRUE; 66 | libswdctx->config.trnlen=LIBSWD_TURNROUND_DEFAULT_VAL; 67 | libswdctx->config.maxcmdqlen=LIBSWD_CMDQLEN_DEFAULT; 68 | libswdctx->config.loglevel=LIBSWD_LOGLEVEL_DEFAULT; 69 | libswdctx->config.autofixerrors=LIBSWD_AUTOFIX_DEFAULT; 70 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N\n"); 71 | return libswdctx; 72 | } 73 | 74 | /** De-initialize selected swd context and free its memory. 75 | * Note: This function will not free command queue for selected context! 76 | * \param *libswdctx swd context pointer. 77 | * \return LIBSWD_OK on success, LIBSWD_ERROR_CODE on failure. 78 | */ 79 | int libswd_deinit_ctx(libswd_ctx_t *libswdctx){ 80 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 81 | free(libswdctx); 82 | return LIBSWD_OK; 83 | } 84 | 85 | /** De-initialize command queue and free its memory on selected swd context. 86 | * OBSOLETE FUNCTION, please use libswd_cmdq_free directly 87 | * \param *libswdctx swd context pointer. 88 | * \return number of commands freed, or LIBSWD_ERROR_CODE on failure. 89 | */ 90 | int libswd_deinit_cmdq(libswd_ctx_t *libswdctx){ 91 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLPOINTER; 92 | int res; 93 | res=libswd_cmdq_free(libswdctx); 94 | if (res<0) return res; 95 | return res; 96 | } 97 | 98 | /** De-initialize selected swd context and its command queue. 99 | * \param *libswdctx swd context pointer. 100 | * \return number of elements freed, or LIBSWD_ERROR_CODE on failure. 101 | */ 102 | int libswd_deinit(libswd_ctx_t *libswdctx){ 103 | int res, cmdcnt=0; 104 | if (libswdctx->membuf.data) free(libswdctx->membuf.data); 105 | res=libswd_cmdq_free(libswdctx); 106 | if (res<0) return res; 107 | cmdcnt=res; 108 | //TODO what about libswdctx->driver? should be free-ed to! 109 | res=libswd_deinit_ctx(libswdctx); 110 | if (res<0) return res; 111 | return cmdcnt+res; 112 | } 113 | 114 | /** @} */ 115 | -------------------------------------------------------------------------------- /libswd_dap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2014, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2014; 32 | * 33 | */ 34 | 35 | /** \file libswd_dap.c DAP, DP, AP Operation Routines. */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_dap High-level SWD Debug Access Port operations. 41 | * High level functions in general call lower level functions that append 42 | * queue with specific commands and payload, but also react on received data. 43 | * They operate on data pointers where target data is being stored. 44 | * Operation can be LIBSWD_OPERATION_QUEUE_APPEND for queueing only the command 45 | * for later execution, or LIBSWD_OPERATION_EXECUTE to queue command, flush it 46 | * into the interface driver (target read/write) and react on its result before 47 | * function returns. 48 | * Return values: negative number on error, data on success. 49 | ******************************************************************************/ 50 | 51 | 52 | /** Macro: DAP INIT (Reset DAP, select SW-DP, read out IDCODE, Setup DAP). 53 | * This is the full initialization and setup of the SW-DP. 54 | * It will bring DAP to a known state on error/stall etc and zero DP SELECT. 55 | * \param *libswdctx swd context pointer. 56 | * \param operation type (LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE). 57 | * \return Target's IDCODE, or LIBSWD_ERROR_CODE on failure. 58 | */ 59 | int libswd_dap_init(libswd_ctx_t *libswdctx, libswd_operation_t operation, int **idcode){ 60 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 61 | "LIBSWD_D: libswd_dap_init(*libswdctx=@%p, operation=%s, **idcode=@%p) entring function...\n", 62 | (void*)libswdctx, libswd_operation_string(operation), (void**)idcode ); 63 | if (!libswdctx) return LIBSWD_ERROR_NULLCONTEXT; 64 | if (!idcode) return LIBSWD_ERROR_NULLPOINTER; 65 | int res, dpselect=0, dpabort=~0, dpctrlstat=0; 66 | dpctrlstat|=LIBSWD_DP_CTRLSTAT_ORUNDETECT; 67 | dpctrlstat|=LIBSWD_DP_CTRLSTAT_CSYSPWRUPREQ; 68 | dpctrlstat|=LIBSWD_DP_CTRLSTAT_CDBGPWRUPREQ; 69 | libswdctx->log.dp.initialized=0; 70 | res=libswd_dap_detect(libswdctx, operation, idcode); 71 | if (res<0) return res; 72 | res=libswd_dap_setup(libswdctx, operation, &dpabort, &dpctrlstat); 73 | if (res<0) return res; 74 | res=libswd_dp_write(libswdctx, operation, LIBSWD_DP_SELECT_ADDR, &dpselect); 75 | if (res<0) return res; 76 | libswdctx->log.dp.initialized=1; 77 | return LIBSWD_OK; 78 | } 79 | 80 | 81 | /** Setup the DAP. Terget CTRL/STAT 82 | * This function will: 83 | * 1. Clear errors by writing to DP ABORT, 2. Power up the System and Debug 84 | * by writing to DP CTRL/STAT, 3. Set the desired DP CTRL/STAT value. 85 | * When dpabort or dpctrlstat are NULL then leave this register untouched. 86 | * \param *libswdctx swd context to work on. 87 | * \param *dpabort write only value to store in DP ABORT if not NULL. 88 | * \param *dpctrlstat desired DP CTRL/STAT value if not NULL. 89 | * \return LIBSWD_OK on success or LIBSWD_ERROR code on failure. 90 | */ 91 | int libswd_dap_setup(libswd_ctx_t *libswdctx, libswd_operation_t operation, int *abort, int *ctrlstat){ 92 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 93 | "LIBSWD_D: libswd_dap_setup(*libswdctx=@%p, operation=%s, *abort=0x%X@%p, *ctrlstat=0x%X@%p) entring function...\n", 94 | (void*)libswdctx, libswd_operation_string(operation), abort?*abort:0, (void*)abort, ctrlstat?*ctrlstat:0, (void*)ctrlstat ); 95 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 96 | int i, res; 97 | if (abort) 98 | { 99 | res=libswd_dp_write(libswdctx, operation, LIBSWD_DP_ABORT_ADDR, abort); 100 | if (res<0) goto libswd_dap_setup_error; 101 | } 102 | if (ctrlstat) 103 | { 104 | // Do not lock-out the debug unit. 105 | *ctrlstat|=LIBSWD_DP_CTRLSTAT_CDBGPWRUPREQ|LIBSWD_DP_CTRLSTAT_CSYSPWRUPREQ; 106 | // Write to CTRL/STAT register. 107 | res=libswd_dp_write(libswdctx, operation, LIBSWD_DP_CTRLSTAT_ADDR, ctrlstat); 108 | if (res<0) goto libswd_dap_setup_error; 109 | // Wait for System and Debug Unit powerup. 110 | for (i=LIBSWD_RETRY_COUNT_DEFAULT;i;i--) 111 | { 112 | res=libswd_dp_read(libswdctx, operation, LIBSWD_DP_CTRLSTAT_ADDR, &ctrlstat); 113 | if (res<0) goto libswd_dap_setup_error; 114 | if (*ctrlstat&(LIBSWD_DP_CTRLSTAT_CDBGPWRUPACK|LIBSWD_DP_CTRLSTAT_CSYSPWRUPACK)) break; 115 | usleep(LIBSWD_RETRY_DELAY_DEFAULT); 116 | } 117 | libswdctx->log.dp.ctrlstat=*ctrlstat; 118 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 119 | "LIBSWD_I: libswd_dap_setup(): DP CTRL/STAT=0x%08X\n", 120 | libswdctx->log.dp.ctrlstat ); 121 | // Return error if CDBGPWRUPACK and CSYSPWRUPACK flags are not set in CTRL/STAT. 122 | if (!i) 123 | { 124 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 125 | "LIBSWD_W: libswd_dap_setup(): CDBGPWRUPACK/CSYSPWRUPACK not set in DP CTRL/STAT!\n", 126 | libswdctx->log.dp.ctrlstat ); 127 | res=LIBSWD_ERROR_MAXRETRY; 128 | goto libswd_dap_setup_error; 129 | } 130 | } 131 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 132 | "LIBSWD_D: libswd_dap_setup(*libswdctx=%p) execution OK.\n", 133 | (void*)libswdctx ); 134 | return LIBSWD_OK; 135 | libswd_dap_setup_error: 136 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 137 | "LIBSWD_E: libswd_dap_setup(): Cannot setup SW-DAP (%s)!\n", 138 | libswd_error_string(res) ); 139 | return res; 140 | } 141 | 142 | 143 | /** Debug Access Port Reset sends 50 CLK with TMS high that brings both 144 | * SW-DP and JTAG-DP into reset state. 145 | * \param *libswdctx swd context pointer. 146 | * \param operation type (LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE). 147 | * \return number of elements processed or LIBSWD_ERROR_CODE code on failure. 148 | */ 149 | int libswd_dap_reset(libswd_ctx_t *libswdctx, libswd_operation_t operation){ 150 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 151 | "LIBSWD_D: Executing libswd_dap_reset(*libswdctx=@%p, operation=%s)\n", 152 | (void*)libswdctx, libswd_operation_string(operation) ); 153 | 154 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 155 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 156 | return LIBSWD_ERROR_BADOPCODE; 157 | 158 | int res, qcmdcnt=0, tcmdcnt=0; 159 | libswdctx->log.memap.initialized=0; 160 | res=libswd_bus_setdir_mosi(libswdctx); 161 | if (res<0) return res; 162 | res=libswd_cmd_enqueue_mosi_dap_reset(libswdctx); 163 | if (res<1) return res; 164 | qcmdcnt+=res; 165 | 166 | if (operation==LIBSWD_OPERATION_ENQUEUE) 167 | { 168 | return qcmdcnt; 169 | } 170 | else if (operation==LIBSWD_OPERATION_EXECUTE) 171 | { 172 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 173 | if (res<0) return res; 174 | tcmdcnt+=res; 175 | return qcmdcnt+tcmdcnt; 176 | } 177 | else return LIBSWD_ERROR_BADOPCODE; 178 | } 179 | 180 | 181 | /** Activate SW-DP by sending out RESET and JTAG-TO-SWD sequence on SWDIOTMS line. 182 | * \param *libswdctx swd context. 183 | * \return number of control bytes executed, or error code on failre. 184 | */ 185 | int libswd_dap_select(libswd_ctx_t *libswdctx, libswd_operation_t operation){ 186 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 187 | "LIBSWD_D: Executing libswd_dap_activate(*libswdctx=@%p, operation=%s)\n", 188 | (void*)libswdctx, libswd_operation_string(operation)); 189 | 190 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 191 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 192 | return LIBSWD_ERROR_BADOPCODE; 193 | 194 | int res, qcmdcnt=0, tcmdcnt=0; 195 | res=libswd_bus_setdir_mosi(libswdctx); 196 | if (res<0) return res; 197 | res=libswd_cmd_enqueue_mosi_jtag2swd(libswdctx); 198 | if (res<0) return res; 199 | qcmdcnt=res; 200 | 201 | if (operation==LIBSWD_OPERATION_ENQUEUE) 202 | { 203 | return qcmdcnt; 204 | } 205 | else if (operation==LIBSWD_OPERATION_EXECUTE) 206 | { 207 | res=libswd_cmdq_flush(libswdctx, &libswdctx->cmdq, operation); 208 | if (res<0) return res; 209 | tcmdcnt+=res; 210 | return qcmdcnt +tcmdcnt; 211 | } else return LIBSWD_ERROR_BADOPCODE; 212 | } 213 | 214 | 215 | /** Read out the CTRL/STAT and clear apropriate flags by writing the ABORT register. 216 | * This function is helpful for clearing sticky errors. 217 | * ABORT register flags are additionally bitmasked by a function parameter, 218 | * so called can control which bits can be set (0xFFFFFFFF allows all). 219 | * \param *libswdctx swd context pointer. 220 | * \param operation operation type. 221 | * \param *ctrlstat will hold the CTRL/STAT register value. 222 | * \param *abort bitmask of which ABORT flags can be set, also will hold the ABORT write. 223 | */ 224 | int libswd_dap_errors_handle(libswd_ctx_t *libswdctx, libswd_operation_t operation, int *abort, int *ctrlstat){ 225 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 226 | "LIBSWD_D: Executing libswd_dap_errors_handle(*libswdctx=@%p, operation=%s, *abort=0x%X@%p, *ctrlstat=0x%X@%p)\n", 227 | (void*)libswdctx, libswd_operation_string(operation), 228 | (void*)abort, abort?*abort:0, ctrlstat?*ctrlstat:0, 229 | (void*)ctrlstat ); 230 | 231 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 232 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_BADOPCODE; 233 | 234 | int res; 235 | char APnDP=0, R=1, W=0, ctrlstat_addr=LIBSWD_DP_CTRLSTAT_ADDR, abort_addr=LIBSWD_DP_ABORT_ADDR, *ack, *parity, cparity; 236 | if (abort) { 237 | *abort=*abort&(LIBSWD_DP_ABORT_STKCMPCLR|LIBSWD_DP_ABORT_STKERRCLR|LIBSWD_DP_ABORT_WDERRCLR|LIBSWD_DP_ABORT_ORUNERRCLR); 238 | res=libswd_bus_write_request(libswdctx, operation, &APnDP, &W, &abort_addr); 239 | if (res<0) return res; 240 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 241 | if (res<0) return res; 242 | res=libswd_bus_write_data_ap(libswdctx, operation, abort); 243 | if (res<0) return res; 244 | } 245 | if (ctrlstat){ 246 | res=libswd_bus_write_request(libswdctx, operation, &APnDP, &R, &ctrlstat_addr); 247 | if (res<0) return res; 248 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 249 | if (res<0) return res; 250 | res=libswd_bus_read_data_p(libswdctx, operation, &ctrlstat, &parity); 251 | if (res<0) return res; 252 | res=libswd_bin32_parity_even(ctrlstat, &cparity); 253 | if (res<0) return res; 254 | if (*parity!=cparity) return LIBSWD_ERROR_PARITY; 255 | libswdctx->log.dp.ctrlstat=*ctrlstat; 256 | } 257 | return LIBSWD_OK; 258 | } 259 | 260 | 261 | /** Macro: Read out IDCODE register and return its value on function return. 262 | * \param *libswdctx swd context pointer. 263 | * \param operation operation type. 264 | * \return Number of elements processed or LIBSWD_ERROR code error on failure. 265 | */ 266 | int libswd_dp_read_idcode(libswd_ctx_t *libswdctx, libswd_operation_t operation, int **idcode){ 267 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_dp_read_idcode(*libswdctx=%p, operation=%s): entering function...\n", (void*)libswdctx, libswd_operation_string(operation)); 268 | 269 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 270 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 271 | return LIBSWD_ERROR_BADOPCODE; 272 | 273 | int res, cmdcnt=0; 274 | char APnDP, RnW, addr, cparity, *ack, *parity; 275 | 276 | APnDP=0; 277 | RnW=1; 278 | addr=LIBSWD_DP_IDCODE_ADDR; 279 | 280 | res=libswd_bus_write_request(libswdctx, LIBSWD_OPERATION_ENQUEUE, &APnDP, &RnW, &addr); 281 | if (res<1) return res; 282 | cmdcnt+=res; 283 | 284 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 285 | res=libswd_bus_read_ack(libswdctx, operation, (char**)&libswdctx->qlog.read.ack); 286 | if (res<1) return res; 287 | cmdcnt+=res; 288 | res=libswd_bus_read_data_p(libswdctx, operation, (int**)&libswdctx->qlog.read.data, (char**)&libswdctx->qlog.read.parity); 289 | if (res<1) return res; 290 | cmdcnt+=res; 291 | return cmdcnt; 292 | 293 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 294 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 295 | if (res<1) return res; 296 | cmdcnt+=res; 297 | res=libswd_bus_read_data_p(libswdctx, operation, idcode, &parity); 298 | if (res<0) return res; 299 | cmdcnt+=res; 300 | libswdctx->log.dp.idcode=**idcode; 301 | libswdctx->log.dp.parity=*parity; 302 | libswdctx->log.dp.ack =*ack; 303 | res=libswd_bin32_parity_even(*idcode, &cparity); 304 | if (res<0) return res; 305 | if (cparity!=*parity) return LIBSWD_ERROR_PARITY; 306 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "LIBSWD_I: libswd_dp_read_idcode(libswdctx=@%p, operation=%s, **idcode=0x%X/%s).\n", (void*)libswdctx, libswd_operation_string(operation), **idcode, libswd_bin32_string(*idcode)); 307 | return cmdcnt; 308 | } else return LIBSWD_ERROR_BADOPCODE; 309 | } 310 | 311 | /** Macro: Reset target DAP, select SW-DP, read out IDCODE. 312 | * This is the proper SW-DP initialization as stated by ARM Information Center. 313 | * \param *libswdctx swd context pointer. 314 | * \param operation type (LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE). 315 | * \return Target's IDCODE, or LIBSWD_ERROR_CODE on failure. 316 | */ 317 | int libswd_dap_detect(libswd_ctx_t *libswdctx, libswd_operation_t operation, int **idcode){ 318 | int res; 319 | res=libswd_dap_select(libswdctx, operation); 320 | if (res<1) return res; 321 | res=libswd_dap_reset(libswdctx, operation); 322 | if (res<1) return res; 323 | res=libswd_dp_read_idcode(libswdctx, operation, idcode); 324 | if (res<0) return res; 325 | return LIBSWD_OK; 326 | } 327 | 328 | 329 | /** Macro: Generic read of the DP register. 330 | * When operation is LIBSWD_OPERATION_EXECUTE it also caches register values. 331 | * \param *libswdctx swd context to work on. 332 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 333 | * \param addr is the address of the DP register to read. 334 | * \param **data is the pointer to data where result will be stored. 335 | * \return number of elements processed or LIBSWD_ERROR_CODE on failure. 336 | */ 337 | int libswd_dp_read(libswd_ctx_t *libswdctx, libswd_operation_t operation, char addr, int **data){ 338 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_dp_read(libswdctx=@%p, operation=%s, addr=0x%X, **data=%p) entering function...\n", (void*)libswdctx, libswd_operation_string(operation), addr, (void**)&data); 339 | 340 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 341 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 342 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 343 | return LIBSWD_ERROR_BADOPCODE; 344 | 345 | int res, cmdcnt=0; 346 | char APnDP, RnW, cparity, *ack, *parity, request; 347 | 348 | APnDP=0; 349 | RnW=1; 350 | 351 | res=libswd_bitgen8_request(libswdctx, &APnDP, &RnW, &addr, &request); 352 | if (res<0) return res; 353 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 354 | if (res<1) return res; 355 | cmdcnt+=res; 356 | 357 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 358 | res=libswd_bus_read_ack(libswdctx, operation, (char**)&libswdctx->qlog.read.ack); 359 | if (res<1) return res; 360 | cmdcnt+=res; 361 | res=libswd_bus_read_data_p(libswdctx, operation, (int**)&data, (char**)&libswdctx->qlog.read.parity); 362 | if (res<1) return res; 363 | cmdcnt+=res; 364 | return cmdcnt; 365 | 366 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 367 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 368 | if (res>=0) { 369 | res=libswd_bus_read_data_p(libswdctx, operation, data, &parity); 370 | if (res<0) return res; 371 | res=libswd_bin32_parity_even(*data, &cparity); 372 | if (res<0) return res; 373 | if (cparity!=*parity) return LIBSWD_ERROR_PARITY; 374 | cmdcnt+=res; 375 | } else if (res==LIBSWD_ERROR_ACK_WAIT) { 376 | //We got ACK==WAIT, retry last transfer until success or failure. 377 | int retry, ctrlstat, abort; 378 | for (retry=LIBSWD_RETRY_COUNT_DEFAULT; retry>0; retry--){ 379 | abort=0xFFFFFFFE; 380 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, &ctrlstat); 381 | if (res<0) continue; 382 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 383 | if (res<0) continue; 384 | res=libswd_bus_read_ack(libswdctx, LIBSWD_OPERATION_EXECUTE, &ack); 385 | if (res<0) continue; 386 | res=libswd_bus_read_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, data, &parity); 387 | if (res<0) continue; 388 | res=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_RDBUFF_ADDR, data); 389 | if (res<0) continue; 390 | break; 391 | } 392 | if (retry==0) return LIBSWD_ERROR_MAXRETRY; 393 | } 394 | if (res<0) { 395 | //libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_dp_read(libswdctx=@%p, operation=%s, addr=0x%X, **data=0x%X/%s) failed: %s.\n", (void*)libswdctx, libswd_operation_string(operation), addr, **data, libswd_bin32_string(*data), libswd_error_string(res)); 396 | return res; 397 | } 398 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_dp_read(libswdctx=@%p, operation=%s, addr=0x%X, **data=0x%X/%s) execution OK.\n", (void*)libswdctx, libswd_operation_string(operation), addr, **data, libswd_bin32_string(*data)); 399 | // Here we also can cache DP register values into libswdctx log. 400 | switch(addr){ 401 | case LIBSWD_DP_IDCODE_ADDR: libswdctx->log.dp.idcode=**data; break; 402 | case LIBSWD_DP_RDBUFF_ADDR: libswdctx->log.dp.rdbuff=**data; break; 403 | case LIBSWD_DP_RESEND_ADDR: libswdctx->log.dp.resend=**data; break; 404 | case LIBSWD_DP_CTRLSTAT_ADDR: // which is also LIBSWD_DP_WCR_ADDR 405 | if (libswdctx->log.dp.select&LIBSWD_DP_SELECT_CTRLSEL){ 406 | libswdctx->log.dp.wcr=**data; 407 | } else libswdctx->log.dp.ctrlstat=**data; 408 | break; 409 | } 410 | return cmdcnt; 411 | } else return LIBSWD_ERROR_BADOPCODE; 412 | } 413 | 414 | /** Macro function: Generic write of the DP register. 415 | * When operation is LIBSWD_OPERATION_EXECUTE it also caches register values. 416 | * \param *libswdctx swd context to work on. 417 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 418 | * \param addr is the address of the DP register to write. 419 | * \param *data is the pointer to data to be written. 420 | * \return number of elements processed or LIBSWD_ERROR code on failure. 421 | */ 422 | int libswd_dp_write(libswd_ctx_t *libswdctx, libswd_operation_t operation, char addr, int *data){ 423 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_dp_write(*libswdctx=%p, operation=%s, addr=0x%X, *data=%p) entering function...\n", (void*)libswdctx, libswd_operation_string(operation), addr, (void*)data); 424 | 425 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 426 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 427 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 428 | return LIBSWD_ERROR_BADOPCODE; 429 | 430 | int res, cmdcnt=0; 431 | char APnDP, RnW, *ack, request; 432 | 433 | APnDP=0; 434 | RnW=0; 435 | 436 | res=libswd_bitgen8_request(libswdctx, &APnDP, &RnW, &addr, &request); 437 | if (res<0) return res; 438 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 439 | if (res<1) return res; 440 | cmdcnt+=res; 441 | 442 | libswd_bin32_parity_even(data, (char *)&libswdctx->qlog.write.parity); 443 | 444 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 445 | res=libswd_bus_read_ack(libswdctx, operation, (char**)&libswdctx->qlog.write.ack); 446 | if (res<1) return res; 447 | cmdcnt+=res; 448 | res=libswd_bus_write_data_ap(libswdctx, operation, data); 449 | if (res<1) return res; 450 | cmdcnt+=res; 451 | return cmdcnt; 452 | 453 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 454 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 455 | if (res>=0) { 456 | res=libswd_bus_write_data_ap(libswdctx, operation, data); 457 | } else if (res==LIBSWD_ERROR_ACK_WAIT) { 458 | //We got ACK==WAIT, retry last transfer until success or failure. 459 | int retry, ctrlstat, abort; 460 | for (retry=LIBSWD_RETRY_COUNT_DEFAULT; retry>0; retry--){ 461 | abort=0xFFFFFFFF; 462 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, &ctrlstat); 463 | if (res<0) continue; 464 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 465 | if (res<0) continue; 466 | res=libswd_bus_read_ack(libswdctx, LIBSWD_OPERATION_EXECUTE, &ack); 467 | if (res<0) continue; 468 | res=libswd_bus_write_data_ap(libswdctx, LIBSWD_OPERATION_EXECUTE, data); 469 | if (res<0) continue; 470 | break; 471 | } 472 | if (retry==0) return LIBSWD_ERROR_MAXRETRY; 473 | } 474 | if (res<0) { 475 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_dp_write(libswdctx=@%p, operation=%s, addr=0x%X, *data=0x%X/%s) failed: %s.\n", (void*)libswdctx, libswd_operation_string(operation), addr, *data, libswd_bin32_string(data), libswd_error_string(res)); 476 | return res; 477 | } 478 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_dp_write(libswdctx=@%p, operation=%s, addr=0x%X, *data=0x%X/%s) execution OK.\n", (void*)libswdctx, libswd_operation_string(operation), addr, *data, libswd_bin32_string(data)); 479 | // Here we also can cache DP register values into libswdctx log. 480 | switch(addr){ 481 | case LIBSWD_DP_ABORT_ADDR: libswdctx->log.dp.abort=*data; break; 482 | case LIBSWD_DP_SELECT_ADDR: libswdctx->log.dp.select=*data; break; 483 | case LIBSWD_DP_ROUTESEL_ADDR: libswdctx->log.dp.routesel=*data; break; 484 | case LIBSWD_DP_CTRLSTAT_ADDR: // which is also LIBSWD_DP_WCR_ADDR 485 | if (libswdctx->log.dp.select&LIBSWD_DP_SELECT_CTRLSEL){ 486 | libswdctx->log.dp.wcr=*data; 487 | } else libswdctx->log.dp.ctrlstat=*data; 488 | break; 489 | } 490 | return cmdcnt; 491 | } else return LIBSWD_ERROR_BADOPCODE; 492 | } 493 | 494 | /** Macro function: Selects APBANK based on provided address value. 495 | * Bank number is calculated from [7..4] bits of the address. 496 | * It is also possible to provide direct value of APBANKSEL register on bits [7..4]. 497 | * Remember not to enqueue any other SELECT writes after this function and before queue flush. 498 | * \param *libswdctx swd context to work on. 499 | * \param addr is the target AP register address, bank will be calculated based on this value. 500 | * \return number of cmdq operations on success, or LIBSWD_ERROR code on failure. 501 | */ 502 | int libswd_ap_bank_select(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr){ 503 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_bank_select(*libswdctx=%p, operation=%s, addr=0x%02X) entering function...\n", (void*)libswdctx, libswd_operation_string(operation), addr); 504 | // If the correct AP bank is already selected no need to change it. 505 | // Verify against cached DP SELECT register value. 506 | // Unfortunately SELECT register is read only so we need to work on cached values... 507 | if ( (libswdctx->log.dp.select&LIBSWD_DP_SELECT_APBANKSEL)==(addr&LIBSWD_DP_SELECT_APBANKSEL) ) return LIBSWD_OK; 508 | // If the cached value of APBANKSEL is different from addr, set it up. 509 | int retval; 510 | int new_select=libswdctx->log.dp.select; 511 | new_select&=~LIBSWD_DP_SELECT_APBANKSEL; 512 | new_select|=addr&LIBSWD_DP_SELECT_APBANKSEL; 513 | retval=libswd_dp_write(libswdctx, operation, LIBSWD_DP_SELECT_ADDR, &new_select); 514 | if (retval<0){ 515 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "libswd_ap_bank_select(%p, %0x02X): cannot update DP SELECT register (%s)\n", (void*)libswdctx, addr, libswd_error_string(retval)); 516 | return retval; 517 | } 518 | libswdctx->log.dp.select=new_select; 519 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_bank_select(*libswdctx=%p, operation=%s, addr=0x%02X) execution OK.\n", (void*)libswdctx, libswd_operation_string(operation), addr); 520 | return retval; 521 | } 522 | 523 | 524 | /** Macro function: Select Access Port (updates APSEL field in DP SELECT register). 525 | * Remember not to enqueue any other SELECT writes after this function and before queue flush. 526 | * \param *libswdctx swd context to work on. 527 | * \param addr is the target AP register address, bank will be calculated based on this value. 528 | * \return number of cmdq operations on success, or LIBSWD_ERROR code on failure. 529 | */ 530 | int libswd_ap_select(libswd_ctx_t *libswdctx, libswd_operation_t operation, int ap){ 531 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_select(*libswdctx=%p, operation=%s, ap=0x%02X) entering function...\n", (void*)libswdctx, libswd_operation_string(operation), ap); 532 | 533 | // If the correct AP is already selected no need to change it. 534 | // Verify against cached DP SELECT register value. 535 | // Unfortunately SELECT register is write only so we need to work on cached values... 536 | int retval; 537 | int new_select=libswdctx->log.dp.select; 538 | new_select&= ~LIBSWD_DP_SELECT_APSEL; 539 | new_select|= ap<log.dp.select=new_select; 544 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_select(*libswdctx=%p, operation=%s, ap=0x%02X) execution OK.\n", (void*)libswdctx, libswd_operation_string(operation), ap); 545 | return retval; 546 | } 547 | 548 | 549 | /** Macro function: Generic read of the AP register. 550 | * Address field should contain AP BANK on bits [4..7]. 551 | * \param *libswdctx swd context to work on. 552 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 553 | * \param addr is the address of the AP register to read plus AP BANK on bits [4..7]. 554 | * \param **data is the pointer to data where result will be stored. 555 | * \return number of elements processed or LIBSWD_ERROR code on failure. 556 | */ 557 | int libswd_ap_read(libswd_ctx_t *libswdctx, libswd_operation_t operation, char addr, int **data){ 558 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_read(*libswdctx=%p, command=%s, addr=0x%X, *data=%p) entering function...\n", (void*)libswdctx, libswd_operation_string(operation), (unsigned char)addr, (void**)data); 559 | 560 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 561 | if (data==NULL) return LIBSWD_ERROR_NULLPOINTER; 562 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 563 | return LIBSWD_ERROR_BADOPCODE; 564 | 565 | int res, cmdcnt=0, retry, ctrlstat, abort; 566 | char APnDP, RnW, *ack, *parity, request; 567 | 568 | res=libswd_ap_bank_select(libswdctx, LIBSWD_OPERATION_ENQUEUE, addr); 569 | if (res<0) return res; 570 | 571 | APnDP=1; 572 | RnW=1; 573 | 574 | res=libswd_bitgen8_request(libswdctx, &APnDP, &RnW, &addr, &request); 575 | if (res<0) return res; 576 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 577 | if (res<1) return res; 578 | cmdcnt+=res; 579 | 580 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 581 | res=libswd_bus_read_ack(libswdctx, operation, (char**)&libswdctx->qlog.read.ack); 582 | if (res<1) return res; 583 | cmdcnt+=res; 584 | res=libswd_bus_read_data_p(libswdctx, operation, (int**)&libswdctx->qlog.read.data, (char**)&libswdctx->qlog.read.parity); 585 | if (res<1) return res; 586 | cmdcnt+=res; 587 | return cmdcnt; 588 | 589 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 590 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 591 | if (res>=0) { 592 | res=libswd_bus_read_data_p(libswdctx, operation, data, &parity); 593 | if (res<0) return res; 594 | } else if (res==LIBSWD_ERROR_ACK_WAIT) { 595 | //We got ACK==WAIT, retry last transfer until success or failure. 596 | for (retry=LIBSWD_RETRY_COUNT_DEFAULT; retry>0; retry--){ 597 | abort=0xFFFFFFFE; 598 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, NULL); 599 | if (res<0) continue; 600 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 601 | if (res<0) continue; 602 | res=libswd_bus_read_ack(libswdctx, LIBSWD_OPERATION_EXECUTE, &ack); 603 | if (res<0) continue; 604 | res=libswd_bus_read_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, data, &parity); 605 | if (res<0) continue; 606 | break; 607 | } 608 | if (retry==0) return LIBSWD_ERROR_MAXRETRY; 609 | } 610 | else if (LIBSWD_ERROR_ACK_FAULT == res) 611 | { 612 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 613 | "LIBSWD_E: libswd_ap_read(libswdctx=@%p, operation=%s, addr=0x%X) failed: %s.\n", 614 | (void*)libswdctx, libswd_operation_string(operation), addr, libswd_error_string(res)); 615 | return res; 616 | } 617 | else 618 | { 619 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 620 | "LIBSWD_E: libswd_ap_read(libswdctx=@%p, operation=%s, addr=0x%X) failed: %s.\n", 621 | (void*)libswdctx, libswd_operation_string(operation), addr, libswd_error_string(res)); 622 | abort=0xFFFFFFFE; 623 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, &ctrlstat); 624 | return res; 625 | } 626 | res=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_RDBUFF_ADDR, data); 627 | if (res<0) { 628 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_ap_read(libswdctx=@%p, operation=%s, addr=0x%X, **data=0x%X/%s) failed: %s.\n", (void*)libswdctx, libswd_operation_string(operation), addr, **data, libswd_bin32_string(*data), libswd_error_string(res)); 629 | return res; 630 | } 631 | // Clear all possible error flags that may remain, but don't abort transaction. 632 | abort=0xFFFFFFFE; 633 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, &ctrlstat); 634 | if (res<0) return res; 635 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_read(libswdctx=@%p, command=%s, addr=0x%X, **data=0x%X/%s) execution OK.\n", (void*)libswdctx, libswd_operation_string(operation), addr, **data, libswd_bin32_string(*data)); 636 | return cmdcnt; 637 | } else return LIBSWD_ERROR_BADOPCODE; 638 | } 639 | 640 | /** Macro function: Generic write of the AP register. 641 | * Address field should contain AP BANK on bits [4..7]. 642 | * \param *libswdctx swd context to work on. 643 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 644 | * \param addr is the address of the AP register to write plus AP BANK on bits[4..7]. 645 | * \param *data is the pointer to data to be written. 646 | * \return number of elements processed or LIBSWD_ERROR code on failure. 647 | */ 648 | int libswd_ap_write(libswd_ctx_t *libswdctx, libswd_operation_t operation, char addr, int *data){ 649 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_write(libswdctx=@%p, operation=%s, addr=0x%X, *data=0x%X).\n", (void*)libswdctx, libswd_operation_string(operation), addr, (void**)data); 650 | 651 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 652 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 653 | return LIBSWD_ERROR_BADOPCODE; 654 | 655 | int res, cmdcnt=0, retry, ctrlstat, abort; 656 | char APnDP, RnW, *ack, request; 657 | 658 | res=libswd_ap_bank_select(libswdctx, LIBSWD_OPERATION_ENQUEUE, addr); 659 | if (res<0) return res; 660 | 661 | APnDP=1; 662 | RnW=0; 663 | 664 | res=libswd_bitgen8_request(libswdctx, &APnDP, &RnW, &addr, &request); 665 | if (res<0) return res; 666 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 667 | if (res<1) return res; 668 | cmdcnt+=res; 669 | libswd_bin32_parity_even(data, (char *)&libswdctx->qlog.write.parity); 670 | 671 | if (operation==LIBSWD_OPERATION_ENQUEUE){ 672 | res=libswd_bus_read_ack(libswdctx, operation, (char**)&libswdctx->qlog.write.ack); 673 | if (res<1) return res; 674 | cmdcnt+=res; 675 | libswdctx->qlog.write.data=*data; 676 | res=libswd_bus_write_data_ap(libswdctx, operation, &libswdctx->qlog.write.data); 677 | if (res<1) return res; 678 | cmdcnt+=res; 679 | return cmdcnt; 680 | 681 | } else if (operation==LIBSWD_OPERATION_EXECUTE){ 682 | res=libswd_bus_read_ack(libswdctx, operation, &ack); 683 | if (res>=0) { 684 | res=libswd_bus_write_data_ap(libswdctx, operation, data); 685 | if (res<0) return res; 686 | cmdcnt+=res; 687 | } else if (res==LIBSWD_ERROR_ACK_WAIT) { 688 | //We got ACK==WAIT, retry last transfer until success or failure. 689 | for (retry=LIBSWD_RETRY_COUNT_DEFAULT; retry>0; retry--){ 690 | abort=0xFFFFFFFE; 691 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, NULL); 692 | if (res<0) continue; 693 | res=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 694 | if (res<0) continue; 695 | res=libswd_bus_read_ack(libswdctx, LIBSWD_OPERATION_EXECUTE, &ack); 696 | if (res<0) continue; 697 | res=libswd_bus_write_data_ap(libswdctx, LIBSWD_OPERATION_EXECUTE, data); 698 | if (res<0) continue; 699 | break; 700 | } 701 | if (retry==0) return LIBSWD_ERROR_MAXRETRY; 702 | } 703 | if (res<0) { 704 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_ap_write(libswdctx=@%p, operation=%s, addr=0x%X, *data=0x%X/%s) failed: %s.\n", (void*)libswdctx, libswd_operation_string(operation), addr, *data, libswd_bin32_string(data), libswd_error_string(res)); 705 | abort=0xFFFFFFFE; 706 | res=libswd_dap_errors_handle(libswdctx, LIBSWD_OPERATION_EXECUTE, &abort, &ctrlstat); 707 | return res; 708 | } 709 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_ap_write(libswdctx=@%p, operation=%s, addr=0x%X, *data=0x%X/%s) execution OK.\n", (void*)libswdctx, libswd_operation_string(operation), addr, *data, libswd_bin32_string(data)); 710 | return cmdcnt; 711 | } else return LIBSWD_ERROR_BADOPCODE; 712 | return LIBSWD_OK; 713 | } 714 | 715 | 716 | 717 | /** @} */ 718 | -------------------------------------------------------------------------------- /libswd_debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Debug Functionalities Body File. 4 | * 5 | * Copyright (C) 2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_debug.c Debug Related Routines. */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_debug High-level Debug operations using SWD DAP. 41 | ******************************************************************************/ 42 | 43 | /** Detect Debug Unit. 44 | * This is the full initialization and setup of the SW-DP. 45 | * It may come handy to bring DAP to a known state on error/stall etc. 46 | * \param *libswdctx swd context pointer. 47 | * \param operation type (LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE). 48 | * \return LIBSWD_OK if Debug Unit is supported, LIBSWD_ERROR_UNSUPPORTED otherwise. 49 | */ 50 | int libswd_debug_detect(libswd_ctx_t *libswdctx, libswd_operation_t operation) 51 | { 52 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_I: Executing libswd_debug_detect(*libswdctx=%p, operation=%s)\n", (void*)libswdctx, libswd_operation_string(operation)); 53 | 54 | if (!libswdctx) return LIBSWD_ERROR_NULLCONTEXT; 55 | int retval=0, cpuid; 56 | unsigned int i; 57 | 58 | if (!libswdctx->log.memap.initialized) 59 | { 60 | retval=libswd_memap_init(libswdctx, operation); 61 | if (retval<0) return retval; 62 | } 63 | 64 | retval=libswd_memap_read_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_CPUID_ADDR, 1, &cpuid); 65 | if (retval<0) return retval; 66 | 67 | for (i=0;ilog.debug.cpuid=libswd_arm_debug_CPUID[i]; 72 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 73 | "LIBSWD_I: libswd_debug_detect(): Found supported CPUID=0x%08X (%s).\n", 74 | libswd_arm_debug_CPUID[i].default_value, libswd_arm_debug_CPUID[i].name ); 75 | break; 76 | } 77 | } 78 | if (i==LIBSWD_NUM_SUPPORTED_CPUIDS) { 79 | libswdctx->log.debug.cpuid.default_value=cpuid; 80 | return LIBSWD_ERROR_UNSUPPORTED; 81 | } 82 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_I: libswd_debug_detect(*libswdctx=%p, operation=%s) execution OK...\n", (void*)libswdctx, libswd_operation_string(operation)); 83 | return LIBSWD_OK; 84 | } 85 | 86 | 87 | int libswd_debug_init(libswd_ctx_t *libswdctx, libswd_operation_t operation) 88 | { 89 | if (!libswdctx) return LIBSWD_ERROR_NULLCONTEXT; 90 | if ( operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_BADOPCODE; 91 | 92 | int retval; 93 | retval=libswd_debug_detect(libswdctx, operation); 94 | if (retval<0) return retval; 95 | libswdctx->log.debug.initialized=1; 96 | return LIBSWD_OK; 97 | } 98 | 99 | 100 | int libswd_debug_halt(libswd_ctx_t *libswdctx, libswd_operation_t operation) 101 | { 102 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 103 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 104 | 105 | int retval, i, dbgdhcsr; 106 | 107 | if (!libswdctx->log.debug.initialized) 108 | { 109 | retval=libswd_debug_init(libswdctx, operation); 110 | if (retval<0) return retval; 111 | } 112 | // Halt the CPU. 113 | retval=libswd_memap_read_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 114 | if (retval<0) return retval; 115 | for (i=LIBSWD_RETRY_COUNT_DEFAULT;i;i--) 116 | { 117 | dbgdhcsr=LIBSWD_ARM_DEBUG_DHCSR_DBGKEY; 118 | dbgdhcsr|=LIBSWD_ARM_DEBUG_DHCSR_CDEBUGEN; 119 | dbgdhcsr|=LIBSWD_ARM_DEBUG_DHCSR_CHALT; 120 | dbgdhcsr&=~LIBSWD_ARM_DEBUG_DHCSR_CMASKINTS; 121 | retval=libswd_memap_write_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 122 | if (retval<0) return retval; 123 | retval=libswd_memap_read_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 124 | if (retval<0) return retval; 125 | if (dbgdhcsr&LIBSWD_ARM_DEBUG_DHCSR_SHALT) 126 | { 127 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "LIBSWD_I: libswd_debug_halt(): DHCSR=0x%08X\n", dbgdhcsr); 128 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: libswd_debug_halt(): TARGET HALT OK!\n"); 129 | libswdctx->log.debug.dhcsr=dbgdhcsr; 130 | return LIBSWD_OK; 131 | } 132 | } 133 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_debug_halt(): TARGET HALT ERROR!\n"); 134 | return LIBSWD_ERROR_MAXRETRY; 135 | } 136 | 137 | int libswd_debug_enable_reset_vector_catch(libswd_ctx_t *libswdctx, libswd_operation_t operation) 138 | { 139 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 140 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 141 | 142 | int retval; 143 | 144 | if (!libswdctx->log.debug.initialized) 145 | { 146 | retval=libswd_debug_init(libswdctx, operation); 147 | if (retval<0) return retval; 148 | } 149 | int demcr_val=0x00000001; 150 | retval=libswd_memap_write_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_DEMCR_ADDR, 1, &demcr_val); 151 | if (retval<0) return retval; 152 | return LIBSWD_OK; 153 | } 154 | 155 | int libswd_debug_reset(libswd_ctx_t *libswdctx, libswd_operation_t operation) 156 | { 157 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 158 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 159 | 160 | int retval; 161 | 162 | if (!libswdctx->log.debug.initialized) 163 | { 164 | retval=libswd_debug_init(libswdctx, operation); 165 | if (retval<0) return retval; 166 | } 167 | // Reset the CPU. 168 | int aircr_val=0x05FA0004; 169 | retval=libswd_memap_write_int_32(libswdctx, operation, LIBSWD_ARM_DEBUG_AIRCR_ADDR, 1, &aircr_val); 170 | if (retval<0) return retval; 171 | return LIBSWD_OK; 172 | } 173 | 174 | int libswd_debug_run(libswd_ctx_t *libswdctx, libswd_operation_t operation) 175 | { 176 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 177 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 178 | 179 | int retval, i, dbgdhcsr; 180 | 181 | if (!libswdctx->log.debug.initialized) 182 | { 183 | retval=libswd_debug_init(libswdctx, operation); 184 | if (retval<0) return retval; 185 | } 186 | // UnHalt the CPU. 187 | retval=libswd_memap_read_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 188 | if (retval<0) return retval; 189 | for (i=LIBSWD_RETRY_COUNT_DEFAULT;i;i--) 190 | { 191 | dbgdhcsr=LIBSWD_ARM_DEBUG_DHCSR_DBGKEY; 192 | dbgdhcsr|=LIBSWD_ARM_DEBUG_DHCSR_CDEBUGEN; 193 | dbgdhcsr&=~LIBSWD_ARM_DEBUG_DHCSR_CHALT; 194 | retval=libswd_memap_write_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 195 | if (retval<0) return retval; 196 | retval=libswd_memap_read_int_32(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_ARM_DEBUG_DHCSR_ADDR, 1, &dbgdhcsr); 197 | if (retval<0) return retval; 198 | if (!(dbgdhcsr&LIBSWD_ARM_DEBUG_DHCSR_SHALT)) 199 | { 200 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_NORMAL, "LIBSWD_N: libswd_debug_run(): TARGET RUN OK!\n"); 201 | libswdctx->log.debug.dhcsr=dbgdhcsr; 202 | return LIBSWD_OK; 203 | } 204 | 205 | } 206 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_debug_run(): TARGET RUN ERROR!\n"); 207 | return LIBSWD_ERROR_MAXRETRY; 208 | } 209 | 210 | int libswd_debug_is_halted(libswd_ctx_t *libswdctx, libswd_operation_t operation) 211 | { 212 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 213 | if (operation!=LIBSWD_OPERATION_EXECUTE && operation!=LIBSWD_OPERATION_ENQUEUE) return LIBSWD_ERROR_PARAM; 214 | 215 | return (libswdctx->log.debug.dhcsr&LIBSWD_ARM_DEBUG_DHCSR_SHALT)?1:0; 216 | } 217 | 218 | 219 | /** @} */ 220 | -------------------------------------------------------------------------------- /libswd_drv.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2014, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2014; 32 | * 33 | */ 34 | 35 | /** \file libswd_drv.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_drv SWD Bus and Interface Driver Transfer Functions that 41 | * executes command queue. 42 | * @{ 43 | ******************************************************************************/ 44 | 45 | extern int libswd_drv_mosi_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 46 | extern int libswd_drv_mosi_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 47 | extern int libswd_drv_miso_8(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, char *data, int bits, int nLSBfirst); 48 | extern int libswd_drv_miso_32(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd, int *data, int bits, int nLSBfirst); 49 | extern int libswd_drv_mosi_trn(libswd_ctx_t *libswdctx, int bits); 50 | extern int libswd_drv_miso_trn(libswd_ctx_t *libswdctx, int bits); 51 | 52 | /** Transmit selected command from the *cmdq to the interface driver. 53 | * Also update the libswdctx->log structure (this should be done only here!). 54 | * Because commands that were queued does not get ack/parity data anymore, 55 | * we need to verify ACK/PARITY that was just read and return error if necesary. 56 | * When ACK/PARITY error is detected queue tail is removed as it is invalid. 57 | * When CTRL/STAT:STICKYORUN=1 ACK={WAIT,FAULT] requires additional data phase. 58 | * \param *libswdctx swd context pointer. 59 | * \param *cmd pointer to the command to be sent. 60 | * \return number of commands transmitted (1), or LIBSWD_ERROR_CODE on failure. 61 | */ 62 | int libswd_drv_transmit(libswd_ctx_t *libswdctx, libswd_cmd_t *cmd){ 63 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 64 | if (cmd==NULL) return LIBSWD_ERROR_NULLPOINTER; 65 | 66 | int res=LIBSWD_ERROR_BADCMDTYPE, errcode=LIBSWD_ERROR_RESULT; 67 | 68 | switch (cmd->cmdtype){ 69 | case LIBSWD_CMDTYPE_MOSI: 70 | case LIBSWD_CMDTYPE_MISO: 71 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_drv_transmit(): This command does not contain payload."); 72 | break; 73 | 74 | case LIBSWD_CMDTYPE_MOSI_CONTROL: 75 | // 8 clock cycles. 76 | if (cmd->bits!=8) return LIBSWD_ERROR_BADCMDDATA; 77 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->control, 8, LIBSWD_DIR_LSBFIRST); 78 | if (res>=0) libswdctx->log.write.control=cmd->control; 79 | break; 80 | 81 | case LIBSWD_CMDTYPE_MOSI_BITBANG: 82 | // 1 clock cycle. 83 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 84 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->mosibit, 1, LIBSWD_DIR_LSBFIRST); 85 | if (res>=0) libswdctx->log.write.bitbang=cmd->mosibit; 86 | break; 87 | 88 | case LIBSWD_CMDTYPE_MOSI_PARITY: 89 | // 1 clock cycle. 90 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 91 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->parity, 1, LIBSWD_DIR_LSBFIRST); 92 | if (res>=0) libswdctx->log.write.parity=cmd->parity; 93 | break; 94 | 95 | case LIBSWD_CMDTYPE_MOSI_TRN: 96 | // 1..4-bit clock cycle. 97 | if (cmd->bitsbits>LIBSWD_TURNROUND_MAX_VAL) 98 | return LIBSWD_ERROR_BADCMDDATA; 99 | res=libswd_drv_mosi_trn(libswdctx, cmd->bits); 100 | break; 101 | 102 | case LIBSWD_CMDTYPE_MOSI_REQUEST: 103 | // 8 clock cycles. 104 | if (cmd->bits!=LIBSWD_REQUEST_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 105 | res=libswd_drv_mosi_8(libswdctx, cmd, &cmd->request, 8, LIBSWD_DIR_LSBFIRST); 106 | if (res>=0){ 107 | libswdctx->log.write.request=cmd->request; 108 | // Log human-readable request fields for easier transmission debug. 109 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: Sending Request: %s\n", \ 110 | libswd_request_string(libswdctx, cmd->request)); 111 | } 112 | break; 113 | 114 | case LIBSWD_CMDTYPE_MOSI_DATA: 115 | // 32 clock cycles. 116 | if (cmd->bits!=LIBSWD_DATA_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 117 | res=libswd_drv_mosi_32(libswdctx, cmd, &cmd->mosidata, 32, LIBSWD_DIR_LSBFIRST); 118 | if (res>=0) libswdctx->log.write.data=cmd->mosidata; 119 | break; 120 | 121 | case LIBSWD_CMDTYPE_MISO_ACK: 122 | // 3 clock cycles. 123 | if (cmd->bits!=LIBSWD_ACK_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 124 | res=libswd_drv_miso_8(libswdctx, cmd, &cmd->ack, cmd->bits, LIBSWD_DIR_LSBFIRST); 125 | if (res>=0) libswdctx->log.read.ack=cmd->ack; 126 | break; 127 | 128 | case LIBSWD_CMDTYPE_MISO_BITBANG: 129 | // 1 clock cycle. 130 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 131 | res=libswd_drv_miso_8(libswdctx, cmd, &cmd->misobit, 1, LIBSWD_DIR_LSBFIRST); 132 | if (res>=0) libswdctx->log.read.bitbang=cmd->misobit; 133 | break; 134 | 135 | case LIBSWD_CMDTYPE_MISO_PARITY: 136 | // 1 clock cycle. 137 | if (cmd->bits!=1) return LIBSWD_ERROR_BADCMDDATA; 138 | res=libswd_drv_miso_8(libswdctx, cmd, &cmd->parity, 1, LIBSWD_DIR_LSBFIRST); 139 | if (res>=0) libswdctx->log.read.parity=cmd->parity; 140 | break; 141 | 142 | case LIBSWD_CMDTYPE_MISO_TRN: 143 | // 1..4 clock cycles 144 | if (cmd->bitsbits>LIBSWD_TURNROUND_MAX_VAL) 145 | return LIBSWD_ERROR_BADCMDDATA; 146 | res=libswd_drv_miso_trn(libswdctx, cmd->bits); 147 | break; 148 | 149 | case LIBSWD_CMDTYPE_MISO_DATA: 150 | // 32 clock cycles 151 | if (cmd->bits!=LIBSWD_DATA_BITLEN) return LIBSWD_ERROR_BADCMDDATA; 152 | res=libswd_drv_miso_32(libswdctx, cmd, &cmd->misodata, cmd->bits, LIBSWD_DIR_LSBFIRST); 153 | if (res>=0) libswdctx->log.read.data=cmd->misodata; 154 | break; 155 | 156 | case LIBSWD_CMDTYPE_UNDEFINED: 157 | res=0; 158 | break; 159 | 160 | default: 161 | return LIBSWD_ERROR_BADCMDTYPE; 162 | } 163 | 164 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_PAYLOAD, 165 | "LIBSWD_P: libswd_drv_transmit(libswdctx=@%p, cmd=@%p) bits=%-2d cmdtype=%-12s returns=%-3d payload=0x%08x (%s)\n", 166 | libswdctx, cmd, cmd->bits, libswd_cmd_string_cmdtype(cmd), res, 167 | (cmd->bits>8)?cmd->data32:cmd->data8, 168 | (cmd->bits<=8)?libswd_bin8_string(&cmd->data8):libswd_bin32_string(&cmd->data32)); 169 | 170 | if (res<0) return res; 171 | cmd->done=1; 172 | 173 | /* Now verify the ACK value, notify caller about possible errors, truncate cmdq if libswdctx.config.autofixerrors is not set. 174 | * Accodring to ADIv5.0 specification (ARM IHI 0031A, section 5.4.5) data phase is required when STICKYORUN=1. 175 | * Unfortunately at this point we cannot read the CTRL/STAT flag, so we will write zeros to avoid random Request. 176 | */ 177 | if (cmd->cmdtype==LIBSWD_CMDTYPE_MISO_ACK){ 178 | switch(cmd->ack){ 179 | // If the ACK was OK then simply return to the caller. 180 | case LIBSWD_ACK_OK_VAL: return res; 181 | // For other ACK codes produce a warning and remember the code. 182 | case LIBSWD_ACK_FAULT_VAL: 183 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 184 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): LIBSWD_ACK_FAULT detected!\n", 185 | (void*)libswdctx, (void*)cmd ); 186 | errcode=LIBSWD_ERROR_ACK_FAULT; 187 | break; 188 | case LIBSWD_ACK_WAIT_VAL: 189 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 190 | "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): LIBSWD_ACK_WAIT detectd!\n", 191 | (void*)libswdctx, (void*)cmd ); 192 | errcode=LIBSWD_ERROR_ACK_WAIT; 193 | break; 194 | default: 195 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 196 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): UnknownACK/ProtocolErrorSequence! Target Powered Off?\n", 197 | (void*)libswdctx, (void*)cmd ); 198 | errcode=LIBSWD_ERROR_ACKUNKNOWN; 199 | } 200 | // If libswdctx.config.autofixerrors is not set, on error truncate cmdq, append+execute dummy data phase, then let caller handle situation. 201 | // The reason for clearing out the queue is to preserve synchronization with Target. 202 | // As data phase is required in some situations and data are already enqueued use data pointers not to crash applications that rely on that poiters... 203 | if (!libswdctx->config.autofixerrors){ 204 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 205 | "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): ACK!=OK, clearing cmdq tail to preserve synchronization...\n", 206 | (void*)libswdctx, (void*)cmd ); 207 | // Save DATA and PARITY queue elements for ACK={WAIT,FAULT} as they may be referenced by application. 208 | if (errcode==LIBSWD_ERROR_ACK_WAIT || errcode==LIBSWD_ERROR_ACK_FAULT) 209 | if (cmd->next) if(cmd->next->next) cmd=cmd->next->next; 210 | // Now free the queue tail. 211 | if (libswd_cmdq_free_tail(libswdctx, cmd)<0) { 212 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 213 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot free cmdq tail in ACK error handling routine, Protocol Error Sequence imminent...\n", 214 | (void*)libswdctx, (void*)cmd ); 215 | return LIBSWD_ERROR_QUEUENOTFREE; 216 | } 217 | // TODO: MOVE THIS INTO SEPARATE ERROR HANDLING ROUTINE 218 | // If ACK={WAIT,FAULT} then append data phase and again flush the queue to maintain sync. 219 | // MOSI_TRN + 33 zero data cycles should be universal for STICKYORUN={0,1} ??? 220 | if (errcode==LIBSWD_ERROR_ACK_WAIT || errcode==LIBSWD_ERROR_ACK_FAULT){ 221 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Performing data phase after ACK={WAIT,FAULT}...\n", (void*)libswdctx, (void*)cmd); 222 | int data=0; 223 | char parity=0; 224 | res=libswd_bus_write_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, &data, &parity); 225 | if (res<0){ 226 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 227 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot perform data phase after ACK=WAIT/FAIL, Protocol Error Sequence imminent...\n", 228 | (void*)libswdctx, (void*)cmd ); 229 | } 230 | // Caller now should read CTRL/STAT and clear STICKY Error Flags at this point. 231 | } 232 | } else { 233 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 234 | "LIBSWD_D: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): libswdctx->config.autofixerrors is set, applying error handling...\n", (void*)libswdctx, (void*)cmd ); 235 | res=libswd_error_handle(libswdctx); 236 | if (res<0){ 237 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "libswd_drv_transmit(libswdctx=@%p, @%p): error handling failed, %s\n", (void*)libswdctx, (void*)cmd, libswd_error_string(res)); 238 | return res; 239 | } 240 | errcode=LIBSWD_OK; 241 | } 242 | return errcode; 243 | } 244 | 245 | 246 | /* Verify the PARITY value and notify caller about possible errors. 247 | * If error was detected, delete trailing queue elements. 248 | */ 249 | if (cmd->cmdtype==LIBSWD_CMDTYPE_MISO_PARITY){ 250 | // Parity must be preceded with data, look for that data and verify parity. 251 | if (cmd->prev->cmdtype==LIBSWD_CMDTYPE_MISO_DATA){ 252 | char testparity; 253 | // Calculate parity based on data value or give warning it cannot be performed. 254 | if (libswd_bin32_parity_even(&cmd->prev->misodata, &testparity)<0) 255 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 256 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot perform parity check (calculation error).\n", 257 | (void*)libswdctx, (void*)cmd ); 258 | // Verify calculated data parity with value received from target. 259 | if (cmd->parity!=testparity){ 260 | // Give error message. 261 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 262 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Parity mismatch detected (%s/%d)!\n", 263 | (void*)libswdctx, (void*)cmd, libswd_bin32_string(&cmd->prev->misodata), cmd->parity ); 264 | // Clean the cmdq tail (as it contains invalid operations). 265 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 266 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Bad PARITY, clearing cmdq tail to preserve synchronization...\n", 267 | (void*)libswdctx, (void*)cmd ); 268 | if (libswd_cmdq_free_tail(libswdctx, cmd)<0) { 269 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 270 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot free cmdq tail in PARITY error hanlig routine!\n", 271 | (void*)libswdctx, (void*)cmd); 272 | return LIBSWD_ERROR_QUEUENOTFREE; 273 | } 274 | // Return parity error. 275 | return LIBSWD_ERROR_PARITY; 276 | } 277 | } else { 278 | // If data element was not found then parity cannot be calculated. 279 | // Give warning about that but does not return an error, as queue might be cleaned just before. 280 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, 281 | "LIBSWD_W: libswd_drv_transmit(libswdctx=@%p, cmd=@%p): Cannot perform parity check (data missing).\n", 282 | (void*)libswdctx, (void*)cmd ); 283 | return res; 284 | } 285 | } 286 | 287 | /* Everyting went fine, return number of elements processed. */ 288 | return res; 289 | } 290 | 291 | /** @} */ 292 | -------------------------------------------------------------------------------- /libswd_error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_error.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_error Error handling and information routines. 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | char *libswd_error_string(libswd_error_code_t error){ 45 | switch (error){ 46 | case LIBSWD_OK: return "[LIBSWD_OK] hmm, there was no error"; 47 | case LIBSWD_ERROR_GENERAL: return "[LIBSWD_ERROR_GENERAL] general error"; 48 | case LIBSWD_ERROR_NULLPOINTER: return "[LIBSWD_ERROR_NULLPOINTER] null pointer"; 49 | case LIBSWD_ERROR_NULLQUEUE: return "[LIBSWD_ERROR_NULLQUEUE] null queue"; 50 | case LIBSWD_ERROR_NULLTRN: return "[LIBSWD_ERROR_NULLTRN] null turnaround"; 51 | case LIBSWD_ERROR_PARAM: return "[LIBSWD_ERROR_PARAM] bad parameter"; 52 | case LIBSWD_ERROR_OUTOFMEM: return "[LIBSWD_ERROR_OUTOFMEM] out of memory"; 53 | case LIBSWD_ERROR_RESULT: return "[LIBSWD_ERROR_RESULT] bad result"; 54 | case LIBSWD_ERROR_RANGE: return "[LIBSWD_ERROR_RANGE] out of range"; 55 | case LIBSWD_ERROR_DEFINITION: return "[LIBSWD_ERROR_DEFINITION] definition error"; 56 | case LIBSWD_ERROR_NULLCONTEXT: return "[LIBSWD_ERROR_NULLCONTEXT] null context"; 57 | case LIBSWD_ERROR_QUEUE: return "[LIBSWD_ERROR_QUEUE] queue error"; 58 | case LIBSWD_ERROR_ADDR: return "[LIBSWD_ERROR_ADDR] addressing error"; 59 | case LIBSWD_ERROR_APnDP: return "[LIBSWD_ERROR_APnDP] bad APnDP value"; 60 | case LIBSWD_ERROR_RnW: return "[LIBSWD_ERROR_RnW] bad RnW value"; 61 | case LIBSWD_ERROR_PARITY: return "[LIBSWD_ERROR_PARITY] parity error"; 62 | case LIBSWD_ERROR_ACK: return "[LIBSWD_ERROR_ACK] acknowledge error"; 63 | case LIBSWD_ERROR_ACKUNKNOWN: return "[LIBSWD_ERROR_ACKUNKNOWN] got unknown acknowledge"; 64 | case LIBSWD_ERROR_ACKNOTDONE: return "[LIBSWD_ERROR_ACKNOTDONE] not yet executed on target"; 65 | case LIBSWD_ERROR_ACKMISSING: return "[LIBSWD_ERROR_ACKMISSING] command not found on the queue"; 66 | case LIBSWD_ERROR_ACKMISMATCH: return "[LIBSWD_ERROR_ACKMISMATCH] different result address/value expected"; 67 | case LIBSWD_ERROR_ACKORDER: return "[LIBSWD_ERROR_ACKORDER] cmdq not in sequence REQ->TRN->ACK"; 68 | case LIBSWD_ERROR_BADOPCODE: return "[LIBSWD_ERROR_BADOPCODE] unsupported operation requested"; 69 | case LIBSWD_ERROR_NODATACMD: return "[LIBSWD_ERROR_NODATACMD] command not found on the queue"; 70 | case LIBSWD_ERROR_DATAPTR: return "[LIBSWD_ERROR_DATAPTR] bad data pointer address"; 71 | case LIBSWD_ERROR_NOPARITYCMD: return "[LIBSWD_ERROR_NOPARITYCMD] parity command missing or misplaced"; 72 | case LIBSWD_ERROR_PARITYPTR: return "[LIBSWD_ERROR_PARITYPTR] bad parity pointer address"; 73 | case LIBSWD_ERROR_NOTDONE: return "[LIBSWD_ERROR_NOTDONE] could not end selected task"; 74 | case LIBSWD_ERROR_QUEUEROOT: return "[LIBSWD_ERROR_QUEUEROOT] queue root not found or null"; 75 | case LIBSWD_ERROR_QUEUETAIL: return "[LIBSWD_ERROR_QUEUETAIL] queue tail not found or null"; 76 | case LIBSWD_ERROR_BADCMDTYPE: return "[LIBSWD_ERROR_BADCMDTYPE] unknown command detected"; 77 | case LIBSWD_ERROR_BADCMDDATA: return "[LIBSWD_ERROR_BADCMDDATA] command contains bad data (out of range, etc)"; 78 | case LIBSWD_ERROR_ACK_WAIT: return "[LIBSWD_ERROR_ACK_WAIT] got ACK_WAIT response"; 79 | case LIBSWD_ERROR_ACK_FAULT: return "[LIBSWD_ERROR_ACK_FAULT] got ACK_FAULT response"; 80 | case LIBSWD_ERROR_QUEUENOTFREE: return "[LIBSWD_ERROR_QUEUENOTFREE] cannot free resources, queue not empty"; 81 | case LIBSWD_ERROR_TRANSPORT: return "[LIBSWD_ERROR_TRANSPORT] transport error or undefined"; 82 | case LIBSWD_ERROR_DIRECTION: return "[LIBSWD_ERROR_DIRECTION] MSb/LSb direction error"; 83 | case LIBSWD_ERROR_LOGLEVEL: return "[LIBSWD_ERROR_LOGLEVEL] invalid loglevel value"; 84 | case LIBSWD_ERROR_UNHANDLED: return "[LIBSWD_ERROR_UNHANDLED] cannot handle that error automatically"; 85 | case LIBSWD_ERROR_MAXRETRY: return "[LIBSWD_ERROR_MAXRETRY] maximum retry count exceeded"; 86 | case LIBSWD_ERROR_CLISYNTAX: return "[LIBSWD_ERROR_CLISYNTAX] CLI syntax error, see '?' for help"; 87 | case LIBSWD_ERROR_FILE: return "[LIBSWD_ERROR_FILE] file I/O related problem"; 88 | case LIBSWD_ERROR_UNSUPPORTED: return "[LIBSWD_ERROR_UNSUPPORTED] Target not supported"; 89 | case LIBSWD_ERROR_MEMAPACCSIZE: return "[LIBSWD_ERROR_MEMAPACCSIZE] Invalid MEM-AP access size"; 90 | case LIBSWD_ERROR_MEMAPALIGN: return "[LIBSWD_ERROR_MEMAPALIGN] Invalid address alignment for access size"; 91 | default: return "undefined error"; 92 | } 93 | return "undefined error"; 94 | } 95 | 96 | 97 | int libswd_error_handle(libswd_ctx_t *libswdctx){ 98 | // At this point we got negative return code from libswd_cmd_flush() so we need to handle errors accordingly here. 99 | // libswdctx->cmdq should point to the last element executed that produced error. 100 | int retval; 101 | libswd_cmd_t *exectail; 102 | 103 | // Verify if libswdctx->cmdq contains last executed element, correct if necessary. 104 | exectail=libswd_cmdq_find_exectail(libswdctx->cmdq); 105 | if (exectail==NULL) { 106 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_error_handle(libswdctx=@%p): Cannot find last executed element on the queue!\n", (void*)libswdctx); 107 | return LIBSWD_ERROR_QUEUE; 108 | } 109 | if (exectail!=libswdctx->cmdq){ 110 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "LIBSWD_I: libswd_error_handle(libswdctx=@%p): Correcting libswdctx->cmdq to match last executed element...\n", (void*)libswdctx); 111 | libswdctx->cmdq=exectail; 112 | } 113 | 114 | switch (libswdctx->cmdq->cmdtype){ 115 | case LIBSWD_CMDTYPE_MISO_ACK: 116 | retval=libswd_error_handle_ack(libswdctx); 117 | break; 118 | default: 119 | return LIBSWD_ERROR_UNHANDLED; 120 | } 121 | 122 | if (retval<0){ 123 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle(@%p) failed! on cmdq=@%p", (void*)libswdctx, (void*)libswdctx->cmdq); 124 | } 125 | return retval; 126 | } 127 | 128 | int libswd_error_handle_ack(libswd_ctx_t *libswdctx){ 129 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 130 | // Make sure we are working on the ACK cmdq element. 131 | if (libswdctx->cmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_ACK){ 132 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_error_handle_ack(@%p):libswdctx->cmdq does not point to ACK!", (void*)libswdctx); 133 | return LIBSWD_ERROR_UNHANDLED; //do we want to handle this kind of error here? 134 | } 135 | 136 | switch (libswdctx->cmdq->ack) { 137 | case LIBSWD_ACK_OK_VAL: 138 | // Uhm, there was no error. 139 | // Should we return OK or search for next ACK recursively? 140 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle_ack(libswdctx=@%p): ACK=OK, handling wrong element?\n", (void*)libswdctx); 141 | return LIBSWD_OK; 142 | case LIBSWD_ACK_WAIT_VAL: 143 | return libswd_error_handle_ack_wait(libswdctx); 144 | case LIBSWD_ACK_FAULT_VAL: 145 | // TODO: Handle ACK=FAULT accordingly. 146 | return LIBSWD_ERROR_UNHANDLED; 147 | default: 148 | // TODO: By default we assume lost synchronization, handle accordingly. 149 | return LIBSWD_ERROR_UNHANDLED; 150 | } 151 | } 152 | 153 | int libswd_error_handle_ack_wait(libswd_ctx_t *libswdctx){ 154 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 155 | // Make sure we are working on the ACK cmdq element. 156 | if (libswdctx->cmdq->cmdtype!=LIBSWD_CMDTYPE_MISO_ACK){ 157 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle_ack_wait(libswdctx=@%p):libswdctx->cmdq does not point to ACK!", (void*)libswdctx); 158 | return LIBSWD_ERROR_UNHANDLED; //do we want to handle this kind of error here? 159 | } 160 | // Make sure the ACK contains WAIT response. 161 | if (libswdctx->cmdq->ack!=LIBSWD_ACK_WAIT_VAL){ 162 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_WARNING, "LIBSWD_W: libswd_error_handle_ack_wait(libswdctx=@%p):libswdctx->cmdq->ack does not contain WAIT response!", (void*)libswdctx); 163 | return LIBSWD_ERROR_ACKMISMATCH; 164 | } 165 | 166 | //TODO: NOW DECIDE IF AN OPERATION WAS READ OR WRITE AND PERFORM RETRY ACCORDINGLY 167 | // READ AND WRITE WILL HAVE DIFFERENT RETRY SEQUENCES 168 | 169 | char request = libswdctx->cmdq->prev->prev->request; 170 | char *ack, *rparity; 171 | char parity=0; 172 | 173 | // Remember original cmdq and cmdqlen, restore on return. 174 | libswd_cmd_t *mastercmdq = libswdctx->cmdq; 175 | unsigned int mastercmdqlen = libswdctx->stats.cmdqlen; 176 | 177 | 178 | // Append dummy data phase, fix sticky flags and retry operation. 179 | int retval=0, *ctrlstat, *rdata, abort, retrycnt=50; 180 | // retval=libswd_cmdq_init(errors); 181 | libswdctx->cmdq->errors=(libswd_cmd_t*)calloc(1,sizeof(libswd_cmd_t)); 182 | //retval = LIBSWD_ERROR_OUTOFMEM; 183 | if (libswdctx->cmdq->errors==NULL) goto libswd_error_handle_ack_wait_end; 184 | libswdctx->cmdq=libswdctx->cmdq->errors; // From now, this becomes out main cmdq for use with standard functions. 185 | libswdctx->stats.cmdqlen=1; //Do not forget about memory management 186 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_error_handle_ack_wait(libswdctx=@%p): Performing data phase after ACK={WAIT,FAULT}...\n", (void*)libswdctx); 187 | int data=0; 188 | retval=libswd_bus_write_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, &data, &parity); 189 | if (retval<0) goto libswd_error_handle_ack_wait_end; 190 | 191 | // NOW WE CAN HANDLE MEM-AP READ RETRY: 192 | // 1. READ STICKY FLAGS FROM CTRL/STAT 193 | // 2. CLEAR STICKY FLAGS IN ABORT - this will discard AP transaction 194 | // 3. RETRY MEM-AP DRW READ - now it must be ACK=OK (it will return last mem-ap read result). 195 | // 4. READ DP RDBUFF TO OBTAIN READ DATA 196 | 197 | for (retrycnt=50/*LIBSWD_RETRY_COUNT_DEFAULT*/; retrycnt>0; retrycnt--){ 198 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_CTRLSTAT_ADDR, &ctrlstat); 199 | if (retval<0) goto libswd_error_handle_ack_wait_end; 200 | abort=0x00000014; 201 | retval=libswd_dp_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_ABORT_ADDR, &abort); 202 | if (retval<0) goto libswd_error_handle_ack_wait_end; 203 | retval=libswd_bus_write_request_raw(libswdctx, LIBSWD_OPERATION_ENQUEUE, &request); 204 | retval=libswd_bus_read_ack(libswdctx, LIBSWD_OPERATION_EXECUTE, &ack); 205 | if (retval<0 || *ack!=LIBSWD_ACK_OK_VAL) goto libswd_error_handle_ack_wait_end; 206 | retval=libswd_bus_read_data_p(libswdctx, LIBSWD_OPERATION_EXECUTE, &rdata, &rparity); 207 | if (retval<0) goto libswd_error_handle_ack_wait_end; 208 | 209 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_CTRLSTAT_ADDR, &ctrlstat); 210 | if (retval<0) goto libswd_error_handle_ack_wait_end; 211 | 212 | 213 | if (*ctrlstat&LIBSWD_DP_CTRLSTAT_READOK){ 214 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "=========================GOT RESPONSE===========================\n\n\n"); 215 | retval=libswd_dp_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_DP_RDBUFF_ADDR, &rdata); 216 | if (retval<0) goto libswd_error_handle_ack_wait_end; 217 | break; 218 | } 219 | } 220 | if (retrycnt==0){ 221 | retval=LIBSWD_ERROR_MAXRETRY; 222 | goto libswd_error_handle_ack_wait_end; 223 | } 224 | 225 | //Make sure we have RDATA and PARITY elements after libswdctx->cmdq. 226 | //Should we check for this at the procedure start??? 227 | libswd_cmdq_free(libswdctx); //Well, as a first thing, release the memory 228 | libswdctx->cmdq=mastercmdq; //Revert origal cmdq 229 | libswdctx->cmdq->errors=NULL; //Delete a pointer which is probably no more valid 230 | libswdctx->stats.cmdqlen=mastercmdqlen; //Do not forget about original cmdqlen 231 | if (libswdctx->cmdq->cmdtype==LIBSWD_CMDTYPE_MISO_ACK && libswdctx->cmdq->next->cmdtype==LIBSWD_CMDTYPE_MISO_DATA && libswdctx->cmdq->next->next->cmdtype==LIBSWD_CMDTYPE_MISO_PARITY){ 232 | libswdctx->cmdq->ack=LIBSWD_ACK_OK_VAL; 233 | libswdctx->cmdq=libswdctx->cmdq->next; 234 | libswdctx->cmdq->misodata=*rdata; 235 | libswdctx->cmdq->done=1; 236 | libswdctx->cmdq=libswdctx->cmdq->next; 237 | //libswd_bin8_parity_even(rdata, &parity); 238 | libswdctx->cmdq->parity=*rparity; 239 | libswdctx->cmdq->done=1; 240 | return LIBSWD_OK; 241 | } else libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: UNSUPPORTED COMMAND SEQUENCE ON CMDQ (NOT ACK->RDATA->PARITY)\n"); 242 | 243 | 244 | // At this point we should have the read result from RDBUFF ready for MEM-AP read fix. 245 | return LIBSWD_ERROR_BADOPCODE; 246 | 247 | 248 | libswd_error_handle_ack_wait_end: 249 | // Exit ACK WAIT handling routine, verify retval before return. 250 | if (retval<0||retrycnt==0){ 251 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, "LIBSWD_E: libswd_error_handle_ack_wait(libswdctx=@%p) ejecting: %s\n", (void*)libswdctx, libswd_error_string(retval)); 252 | } 253 | 254 | libswd_cmdq_free(libswdctx); //Well, as a first thing, release the memory 255 | libswdctx->cmdq=mastercmdq; //Revert origal cmdq 256 | libswdctx->cmdq->errors=NULL; //Delete a pointer which is probably no more valid 257 | libswdctx->stats.cmdqlen=mastercmdqlen; //Do not forget about original cmdqlen 258 | while (1) {printf("ACK WAIT HANDLER\n");usleep(1000);} //TODO this is unacceptable! 259 | return retval; 260 | } 261 | /** @} */ 262 | -------------------------------------------------------------------------------- /libswd_log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Serial Wire Debug Open Library. 3 | * Library Body File. 4 | * 5 | * Copyright (C) 2010-2013, Tomasz Boleslaw CEDRO (http://www.tomek.cedro.info) 6 | * All rights reserved. 7 | * 8 | * Redistribution and use in source and binary forms, with or without 9 | * modification, are permitted provided that the following conditions are met: 10 | * 1. Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 2. Redistributions in binary form must reproduce the above copyright notice, 13 | * this list of conditions and the following disclaimer in the documentation 14 | * and/or other materials provided with the distribution. 15 | * 3. Neither the name of the Tomasz Boleslaw CEDRO nor the names of its 16 | * contributors may be used to endorse or promote products derived from this 17 | * software without specific prior written permission. 18 | * 19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS 23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 24 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 27 | * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 29 | * OF THE POSSIBILITY OF SUCH DAMAGE.* 30 | * 31 | * Written by Tomasz Boleslaw CEDRO , 2010-2013; 32 | * 33 | */ 34 | 35 | /** \file libswd_log.c */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_log Miscelanous logging functionalities. 41 | * @{ 42 | ******************************************************************************/ 43 | 44 | /** Logging functionality can be external or internal, by default external 45 | * function can be defined to use target program logging mechanism. 46 | * To use internal logging mechanism simply wrap libswd_log_internal() around 47 | * this function in application specific driver bridge file, 48 | * see liblibswd_externs.c for examples. When you want to use variable argument 49 | * (printf style) invocation you can use libswd_log_internal_va() as vprintf(). 50 | */ 51 | extern int libswd_log(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...); 52 | 53 | /** Put a message into swd context log at specified verbosity level. 54 | * If specified message's log level is lower than actual context configuration, 55 | * message will be omitted. Verbosity level increases from 0 (silent) to 6 (bitstream). 56 | * This function does not put '\n' at the end of line so you need to put them by hand. 57 | * \param *libswdctx swd context. 58 | * \param loglevel at which to put selected message. 59 | * \param *msg message body with variable arguments as in "printf". 60 | * \return number of characters written or error code on failure. 61 | */ 62 | int libswd_log_internal(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *msg, ...){ 63 | if (loglevelLIBSWD_LOGLEVEL_MAX) 64 | return LIBSWD_ERROR_LOGLEVEL; 65 | if (loglevel > libswdctx->config.loglevel) return LIBSWD_OK; 66 | int res; 67 | va_list ap; 68 | va_start(ap, msg); 69 | res=vprintf(msg, ap); 70 | va_end(ap); 71 | return res; 72 | } 73 | 74 | /** Put a fmt+va_list message into swd context log at specified verbosity level. 75 | * It works just as libswd_log_internal() but is intended for use instead 76 | * vprintf() between va_start() and va_end()... 77 | * \param *libswdctx swd context. 78 | * \param loglevel at which to put selected message. 79 | * \param *msg message body with variable arguments as in "printf". 80 | * \return number of characters written or error code on failure. 81 | */ 82 | int libswd_log_internal_va(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel, char *fmt, va_list ap){ 83 | if (loglevelLIBSWD_LOGLEVEL_MAX) 84 | return LIBSWD_ERROR_LOGLEVEL; 85 | if (loglevel > libswdctx->config.loglevel) return LIBSWD_OK; 86 | int res; 87 | res=vprintf(fmt, ap); 88 | return res; 89 | } 90 | 91 | /** Change log level to increase or decrease verbosity level. 92 | * \param *libswdctx swd context. 93 | * \param loglevel is the target verbosity level to be set. 94 | * \return LIBSWD_OK on success or error code. 95 | */ 96 | int libswd_log_level_set(libswd_ctx_t *libswdctx, libswd_loglevel_t loglevel){ 97 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 98 | if (loglevelLIBSWD_LOGLEVEL_MAX) 99 | return LIBSWD_ERROR_LOGLEVEL; 100 | 101 | libswdctx->config.loglevel=loglevel; 102 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, "LIBSWD_D: libswd_log_level_set(libswdctx=0x%p, loglevel[%d..%d]=%d/%s)\n", (void*)libswdctx, LIBSWD_LOGLEVEL_MIN, LIBSWD_LOGLEVEL_MAX, loglevel, libswd_log_level_string(loglevel)); 103 | return LIBSWD_OK; 104 | } 105 | 106 | /** Return integer log level value. 107 | * \param *libswdctx swd context. 108 | * \return integer log level value or LIBSWD_ERROR code on failure. 109 | */ 110 | int libswd_log_level_get(libswd_ctx_t *libswdctx){ 111 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 112 | return libswdctx->config.loglevel; 113 | } 114 | 115 | /** Helper function that returns loglevel name string for logging purposes. 116 | * \param loglevel is the libswd_loglevel_t code to produce a string. 117 | * \return char* loglevel name sring array. 118 | */ 119 | const char *libswd_log_level_string(libswd_loglevel_t loglevel){ 120 | switch (loglevel){ 121 | case LIBSWD_LOGLEVEL_SILENT: return "LIBSWD_LOGLEVEL_SILENT"; 122 | case LIBSWD_LOGLEVEL_ERROR: return "LIBSWD_LOGLEVEL_ERROR"; 123 | case LIBSWD_LOGLEVEL_WARNING: return "LIBSWD_LOGLEVEL_WARNING"; 124 | case LIBSWD_LOGLEVEL_NORMAL: return "LIBSWD_LOGLEVEL_NORMAL"; 125 | case LIBSWD_LOGLEVEL_INFO: return "LIBSWD_LOGLEVEL_INFO"; 126 | case LIBSWD_LOGLEVEL_DEBUG: return "LIBSWD_LOGLEVEL_DEBUG"; 127 | case LIBSWD_LOGLEVEL_PAYLOAD: return "LIBSWD_LOGLEVEL_PAYLOAD"; 128 | } 129 | return "UNKNOWN_LOGLEVEL"; 130 | }; 131 | 132 | /** Helper function to produce operation name string for logging purposes. 133 | * \param operation is the libswd_operation_t code to return as string. 134 | * \return char* array with operation name string. 135 | */ 136 | const char *libswd_operation_string(libswd_operation_t operation){ 137 | switch(operation){ 138 | case LIBSWD_OPERATION_ENQUEUE: return "LIBSWD_OPERATION_ENQUEUE"; 139 | case LIBSWD_OPERATION_EXECUTE: return "LIBSWD_OPERATION_EXECUTE"; 140 | case LIBSWD_OPERATION_TRANSMIT_HEAD: return "LIBSWD_OPERATION_TRANSMIT_HEAD"; 141 | case LIBSWD_OPERATION_TRANSMIT_TAIL: return "LIBSWD_OPERATION_TRANSMIT_TAIL"; 142 | case LIBSWD_OPERATION_TRANSMIT_ALL: return "LIBSWD_OPERATION_TRANSMIT_ALL"; 143 | case LIBSWD_OPERATION_TRANSMIT_ONE: return "LIBSWD_OPERATION_TRANSMIT_ONE"; 144 | case LIBSWD_OPERATION_TRANSMIT_LAST: return "LIBSWD_OPERATION_TRANSMIT_LAST"; 145 | } 146 | return "UNKNOWN_LIBSWD_OPERATION"; 147 | } 148 | 149 | /** Helper function that can print name of the request fields. 150 | * DP SELECT APBANKSEL fields are also taken into account here for APACC. 151 | * \param libswdctx points to the swd context and its necessary to know 152 | DP SELECT register value as it determines CTRL/STAT or WCR access. 153 | * \param RnW is the read/write bit of the request packet. 154 | * \param addr is the address of the register. 155 | * \return char* array with the register name string. 156 | */ 157 | const char *libswd_request_string(libswd_ctx_t *libswdctx, char request){ 158 | static char string[100], tmp[8]; string[0]=0; 159 | int apndp=request&LIBSWD_REQUEST_APnDP; 160 | int addr=0; 161 | addr|=((request&LIBSWD_REQUEST_A3)?1<<3:0); 162 | addr|=((request&LIBSWD_REQUEST_A2)?1<<2:0); 163 | if (apndp) addr|=(libswdctx->log.dp.select&LIBSWD_DP_SELECT_APBANKSEL); 164 | int rnw=request&LIBSWD_REQUEST_RnW; 165 | int parity=request&LIBSWD_REQUEST_PARITY; 166 | 167 | strcat(string, apndp?"AccessPort ":"DebugPort "); 168 | strcat(string, rnw?"Read ":"Write "); 169 | strcat(string, "Addr="); sprintf(tmp, "0x%02X", addr); strcat(string, tmp); 170 | 171 | if (apndp){ 172 | // APnDP=1 so we print out the AHB-AP registers 173 | addr|=libswdctx->log.dp.select&LIBSWD_DP_SELECT_APBANKSEL; 174 | switch (addr){ 175 | case 0x00: strcat(string, "(R/W: Control/Status Word, CSW (reset value: 0x43800042)) "); break; 176 | case 0x04: strcat(string, "(R/W: Transfer Address, TAR (reset value: 0x00000000)) "); break; 177 | case 0x08: strcat(string, "(Reserved SBZ) "); break; 178 | case 0x0c: strcat(string, "(R/W, Data Read/Write, DRW) "); break; 179 | case 0x10: strcat(string, "(R/W, Banked Data 0, BD0) "); break; 180 | case 0x14: strcat(string, "(R/W, Banked Data 1, BD1) "); break; 181 | case 0x18: strcat(string, "(R/W, Banked Data 2, BD2 )"); break; 182 | case 0x1c: strcat(string, "(R/W, Banked Data 3, BD3) "); break; 183 | case 0xf8: strcat(string, "(RO, Debug ROM table (reset value: 0xE00FF000)) "); break; 184 | case 0xfc: strcat(string, "(RO, Identification Register, IDR (reset value: 0x24770001)) "); break; 185 | default: strcat(string, "(UNKNOWN) "); 186 | } 187 | } else { 188 | // APnDP=0 so we print out the SW-DP registers 189 | if (rnw) { 190 | switch (addr){ 191 | case LIBSWD_DP_IDCODE_ADDR: strcat(string, "(IDCODE)"); break; 192 | case LIBSWD_DP_CTRLSTAT_ADDR: strcat(string, (libswdctx->log.dp.select&1<log.dp.select&1<, 2010-2014; 32 | * 33 | */ 34 | 35 | /** \file libswd_memap.c MEM-AP related routines. */ 36 | 37 | #include 38 | 39 | /******************************************************************************* 40 | * \defgroup libswd_memap High-level MEM-AP (Memory Access Port) operations. 41 | * These routines are based on DAP operations. 42 | * Return values: negative number on error, LIBSWD_OK on success. 43 | ******************************************************************************/ 44 | 45 | /** Initialize the MEM-AP. 46 | * This function will set DbgSwEnable, DeviceEn, 32-bit Size in CSW. 47 | * This function will disable Tar Auto Increment. 48 | * Use libswd_memap_setup() to set specific CSW and TAR values. 49 | * \param *libswdctx swd context to work on. 50 | * \return LIBSWD_OK on success or LIBSWD_ERROR code on failure. 51 | */ 52 | int libswd_memap_init(libswd_ctx_t *libswdctx, libswd_operation_t operation){ 53 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 54 | "LIBSWD_D: Executing libswd_memap_init(*libswdctx=%p, operation=%s)...\n", 55 | (void*)libswdctx, libswd_operation_string(operation) ); 56 | 57 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 58 | 59 | int res=0, *memapidr, *memapbase, *memapcswp, memapcsw; 60 | 61 | // Verify if DAP is already initialized, do so in necessary. 62 | if (!libswdctx->log.dp.initialized) 63 | { 64 | int *idcode; 65 | res=libswd_dap_init(libswdctx, operation, &idcode); 66 | if (res<0) goto libswd_memap_init_error; 67 | } 68 | 69 | // Select MEM-AP. 70 | //res=libswd_ap_select(libswdctx, operation, LIBSWD_MEMAP_APSEL_VAL); 71 | //if (res<0) goto libswd_memap_init_error; 72 | // TODO: DO WE NEED LIBSWD_AP_SELECT ??? 73 | 74 | // Check IDentification Register, use cached value if possible. 75 | if (!libswdctx->log.memap.idr) 76 | { 77 | res=libswd_ap_read(libswdctx, operation, LIBSWD_MEMAP_IDR_ADDR, &memapidr); 78 | if (res<0) goto libswd_memap_init_error; 79 | libswdctx->log.memap.idr=*memapidr; 80 | } 81 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 82 | "LIBSWD_I: libswd_memap_init(): MEM-AP IDR=0x%08X\n", 83 | libswdctx->log.memap.idr ); 84 | 85 | // Check Debug BASE Address Register, use cached value if possible. 86 | if (!libswdctx->log.memap.base) 87 | { 88 | res=libswd_ap_read(libswdctx, operation, LIBSWD_MEMAP_BASE_ADDR, &memapbase); 89 | if (res<0) goto libswd_memap_init_error; 90 | libswdctx->log.memap.base=*memapbase; 91 | } 92 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 93 | "LIBSWD_I: libswd_memap_init(): MEM-AP BASE=0x%08X\n", 94 | libswdctx->log.memap.base ); 95 | 96 | // Setup the CSW (MEM-AP Control and Status) register. 97 | memapcsw=0; 98 | // Check if DbgSwEnable bit is set, set if necessary. 99 | memapcsw|=LIBSWD_MEMAP_CSW_DBGSWENABLE; 100 | memapcsw&=~LIBSWD_MEMAP_CSW_ADDRINC; 101 | memapcsw&=~LIBSWD_MEMAP_CSW_SIZE; 102 | memapcsw|=LIBSWD_MEMAP_CSW_SIZE_32BIT; 103 | // Write new CSW value. 104 | res=libswd_ap_write(libswdctx, operation, LIBSWD_MEMAP_CSW_ADDR, &memapcsw); 105 | if (res<0) goto libswd_memap_init_error; 106 | // Read back and cache CSW value. 107 | res=libswd_ap_read(libswdctx, operation, LIBSWD_MEMAP_CSW_ADDR, &memapcswp); 108 | if (res<0) goto libswd_memap_init_error; 109 | libswdctx->log.memap.csw=(*memapcswp); 110 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 111 | "LIBSWD_I: libswd_memap_init(): MEM-AP CSW=0x%08X\n", 112 | libswdctx->log.memap.csw); 113 | 114 | // Mark MEM-AP as configured. 115 | libswdctx->log.memap.initialized=1; 116 | 117 | return LIBSWD_OK; 118 | 119 | libswd_memap_init_error: 120 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 121 | "LIBSWD_E: libswd_memap_init(): Cannot initialize MEM-AP (%s)!\n", 122 | libswd_error_string(res) ); 123 | return res; 124 | } 125 | 126 | /** Setup the MEM-AP. 127 | * Use this function to setup CSW and TAR values for given MEM-AP operations. 128 | * This setup needs to be done before MEM-AP with different access size. 129 | * Function will try to compare agains chahed values to save bus traffic. 130 | * This function will set DBGSWENABLE and PROT bits in CSW by default. 131 | * \param *libswd LibSWD context to work on. 132 | * \param operation is the LIBSWD_OPERATION type. 133 | * \param csw is the CSW register value to be set. 134 | * \param tar is the TAR register value to be set. 135 | * \return LIBSWD_OK on success, LIBSWD_ERROR otherwise. 136 | */ 137 | int libswd_memap_setup(libswd_ctx_t *libswdctx, libswd_operation_t operation, int csw, int tar){ 138 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 139 | "LIBSWD_D: Entering libswd_memap_setup(*libswdctx=%p, operation=%s, csw=0x%08X, tar=0x%08X)...\n", 140 | (void*)libswdctx, libswd_operation_string(operation), csw, tar ); 141 | 142 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 143 | 144 | int res, *memapcswp, memapcsw, *memaptarp; 145 | 146 | // Verify if MEM-AP is already initialized, do so in necessary. 147 | if (!libswdctx->log.memap.initialized) 148 | { 149 | res=libswd_memap_init(libswdctx, operation); 150 | if (res<0) goto libswd_memap_setup_error; 151 | } 152 | 153 | // Remember to set these bits not to lock-out the Debug... 154 | memapcsw=csw|LIBSWD_MEMAP_CSW_DBGSWENABLE; 155 | memapcsw|=LIBSWD_MEMAP_CSW_PROT; // PROT ENABLES DEBUG!! 156 | 157 | // Update MEM-AP CSW register if necessary. 158 | if (memapcsw!=libswdctx->log.memap.csw) 159 | { 160 | // Write register value. 161 | res=libswd_ap_write(libswdctx, operation, LIBSWD_MEMAP_CSW_ADDR, &memapcsw); 162 | if (res<0) goto libswd_memap_setup_error; 163 | // Read-back and cache CSW value. 164 | res=libswd_ap_read(libswdctx, operation, LIBSWD_MEMAP_CSW_ADDR, &memapcswp); 165 | if (res<0) goto libswd_memap_setup_error; 166 | libswdctx->log.memap.csw=(*memapcswp); 167 | } 168 | 169 | // Update MEM-AP TAR register if necessary. 170 | if (tar!=libswdctx->log.memap.tar) 171 | { 172 | // Write register value. 173 | res=libswd_ap_write(libswdctx, operation, LIBSWD_MEMAP_TAR_ADDR, &tar); 174 | if (res<0) goto libswd_memap_setup_error; 175 | // Read-back and cache TAR value. 176 | res=libswd_ap_read(libswdctx, operation, LIBSWD_MEMAP_TAR_ADDR, &memaptarp); 177 | if (res<0) goto libswd_memap_setup_error; 178 | libswdctx->log.memap.tar=(*memaptarp); 179 | } 180 | 181 | return LIBSWD_OK; 182 | 183 | libswd_memap_setup_error: 184 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 185 | "LIBSWD_E: libswd_memap_setup(): Cannot setup MEM-AP (%s)!\n", 186 | libswd_error_string(res) ); 187 | return res; 188 | } 189 | 190 | 191 | /** Generic read using MEM-AP into char array. 192 | * Data are stored into char array. Count shows CHAR elements. 193 | * Remember to setup MEM-AP first for valid access! 194 | * \param *libswdctx swd context to work on. 195 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 196 | * \param addr is the start address of the data to read with MEM-AP. 197 | * \param count is the number of bytes to read. 198 | * \param *data is the pointer to char array where result will be stored. 199 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 200 | */ 201 | int libswd_memap_read_char(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, char *data){ 202 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 203 | "LIBSWD_D: Entering libswd_memap_read_char(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, *data=%p)...\n", 204 | (void*)libswdctx, libswd_operation_string(operation), 205 | addr, count, (void*)data ); 206 | 207 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 208 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 209 | return LIBSWD_ERROR_BADOPCODE; 210 | 211 | int i, loc, res=0, accsize=0, *memapdrw; 212 | float tdeltam; 213 | struct timeval tstart, tstop; 214 | 215 | // Initialize MEM-AP if necessary. 216 | if (!libswdctx->log.memap.initialized) 217 | { 218 | res=libswd_memap_init(libswdctx, operation); 219 | if (res<0) goto libswd_memap_read_char_error; 220 | } 221 | 222 | // Verify the count parameter to be access boundary. 223 | switch (libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_SIZE) 224 | { 225 | case LIBSWD_MEMAP_CSW_SIZE_8BIT: 226 | accsize=1; 227 | break; 228 | case LIBSWD_MEMAP_CSW_SIZE_16BIT: 229 | accsize=2; 230 | break; 231 | case LIBSWD_MEMAP_CSW_SIZE_32BIT: 232 | accsize=4; 233 | break; 234 | default: 235 | res=LIBSWD_ERROR_MEMAPACCSIZE; 236 | goto libswd_memap_read_char_error; 237 | } 238 | if (count%accsize) count=count-(count%accsize); 239 | 240 | // Check for alignment issues. 241 | if ((addr%accsize)!=0) 242 | { 243 | res=LIBSWD_ERROR_MEMAPALIGN; 244 | goto libswd_memap_read_char_error; 245 | } 246 | 247 | // Mark start time for transfer speed measurement. 248 | gettimeofday(&tstart, NULL); 249 | 250 | // Perform word-by-word read operation and implode result into char array. 251 | if (!(libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_ADDRINC)) 252 | { 253 | // Use manual TAR incrementation (slower). 254 | for (i=0;ilog.memap.tar=loc; 274 | // Read data from DRW register. 275 | res=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &memapdrw); 276 | if (res<0) goto libswd_memap_read_char_error; 277 | libswdctx->log.memap.drw=*memapdrw; 278 | // apply the data byte-laning shift 279 | tmp=*memapdrw >>= drw_shift; 280 | memcpy((void*)data+i, &tmp, accsize); 281 | } 282 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 283 | } 284 | else 285 | { 286 | // Use TAR Auto Increment (faster). 287 | // TAR auto increment is only guaranteed to work on the bottom 10 bits 288 | // of the TAR register. Above that it is implementation defined. 289 | // We use 1024 byte chunks as it will work on every platform 290 | // and one TAR write every 1024 bytes is not adding too much overhead. 291 | const unsigned int BOUNDARY = 1024; 292 | unsigned int i; 293 | 294 | // Check if packed transfer, if so use word access. 295 | if (libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_ADDRINC_PACKED) accsize=4; 296 | 297 | for (loc = addr, i = 0; loc < (addr + count); loc += accsize, i+= accsize) 298 | { 299 | int tmp; 300 | int drw_shift; 301 | 302 | // Calculate the offset in DRW where the data should be 303 | // see Data byte-laning in the ARM debug interface v5 documentation 304 | // note: this only works for little endian systems. 305 | drw_shift=8*(loc%4); 306 | 307 | // only write the TAR register, if this is the first time through the loop. 308 | // or if we've passed over the boundary where TAR auto inc isn't guaranteed 309 | // to work anymore. 310 | if (loc == addr || 311 | (loc % BOUNDARY) == 0) 312 | { 313 | // Pass address to TAR register. 314 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_TAR_ADDR, &loc); 315 | if (res<0) goto libswd_memap_read_char_error; 316 | libswdctx->log.memap.tar=loc; 317 | } 318 | 319 | // Measure transfer speed. 320 | gettimeofday(&tstop, NULL); 321 | tdeltam=fabsf((tstop.tv_sec-tstart.tv_sec)*1000+(tstop.tv_usec-tstart.tv_usec)/1000); 322 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 323 | "LIBSWD_I: libswd_memap_read_char() reading address 0x%08X (speed %fKB/s)\r", 324 | loc, count/tdeltam); 325 | fflush(0); 326 | 327 | // Read data from the DRW register. 328 | res=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &memapdrw); 329 | if (res<0) goto libswd_memap_read_char_error; 330 | libswdctx->log.memap.drw=*memapdrw; 331 | 332 | // apply the data byte-laning shift 333 | tmp=*memapdrw >>= drw_shift; 334 | memcpy((void*)data + i, &tmp, accsize); 335 | } 336 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 337 | } 338 | 339 | return LIBSWD_OK; 340 | 341 | libswd_memap_read_char_error: 342 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 343 | "\nLIBSWD_E: libswd_memap_read_char(): %s\n", 344 | libswd_error_string(res) ); 345 | return res; 346 | } 347 | 348 | 349 | /** Generic read using MEM-AP to char array, with prior CSW setup. 350 | * Data are stored into char array. 351 | * Remember to setup CSW first for valid bus access! 352 | * \param *libswdctx swd context to work on. 353 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 354 | * \param addr is the start address of the data to read with MEM-AP. 355 | * \param count is the number of bytes to read. 356 | * \param *data is the pointer to char array where result will be stored. 357 | * \param csw is the value of csw register to write prior data write. 358 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 359 | */ 360 | int libswd_memap_read_char_csw(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, char *data, int csw){ 361 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 362 | "LIBSWD_D: Entering libswd_memap_read_char_csw(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, *data=%p, csw=0x%X)...\n", 363 | (void*)libswdctx, libswd_operation_string(operation), 364 | addr, count, (void**)data, csw); 365 | 366 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 367 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 368 | return LIBSWD_ERROR_BADOPCODE; 369 | 370 | int res=0, accsize=0; 371 | 372 | // Calculate required access size based on CSW value. 373 | switch (csw&LIBSWD_MEMAP_CSW_SIZE) 374 | { 375 | case LIBSWD_MEMAP_CSW_SIZE_8BIT: 376 | accsize=1; 377 | break; 378 | case LIBSWD_MEMAP_CSW_SIZE_16BIT: 379 | accsize=2; 380 | break; 381 | case LIBSWD_MEMAP_CSW_SIZE_32BIT: 382 | accsize=4; 383 | break; 384 | default: 385 | res=LIBSWD_ERROR_MEMAPACCSIZE; 386 | goto libswd_memap_read_char_csw_error; 387 | } 388 | // Verify the count parameter to be access boundary. 389 | if (count%accsize) count=count-(count%accsize); 390 | 391 | // Initialize MEM-AP if necessary. 392 | if (!libswdctx->log.memap.initialized) 393 | { 394 | res=libswd_memap_init(libswdctx, operation); 395 | if (res<0) goto libswd_memap_read_char_csw_error; 396 | } 397 | 398 | // Setup MEM-AP CSW and TAR. 399 | res=libswd_memap_setup(libswdctx, operation, csw, addr); 400 | if (res<0) goto libswd_memap_read_char_csw_error; 401 | 402 | // Perform the read operation. 403 | res=libswd_memap_read_char(libswdctx, operation, addr, count, data); 404 | if (res<0) goto libswd_memap_read_char_csw_error; 405 | 406 | return LIBSWD_OK; 407 | 408 | libswd_memap_read_char_csw_error: 409 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 410 | "\nLIBSWD_E: libswd_memap_read_char_csw(): %s\n", 411 | libswd_error_string(res) ); 412 | return res; 413 | } 414 | 415 | 416 | /** Generic read using MEM-AP to char array, using 32-bit data access. 417 | * Data are stored into char array. 418 | * Remember to setup CSW first for valid bus width! 419 | * \param *libswdctx swd context to work on. 420 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 421 | * \param addr is the start address of the data to read with MEM-AP. 422 | * \param count is the number of bytes to read. 423 | * \param *data is the pointer to char array where result will be stored. 424 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 425 | */ 426 | int libswd_memap_read_char_32(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, char *data){ 427 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 428 | "LIBSWD_D: Entering libswd_memap_read_char_32(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, *data=%p)...\n", 429 | (void*)libswdctx, libswd_operation_string(operation), 430 | addr, count, (void**)data ); 431 | 432 | return libswd_memap_read_char_csw(libswdctx, operation, addr, count, data, LIBSWD_MEMAP_CSW_SIZE_32BIT|LIBSWD_MEMAP_CSW_ADDRINC_SINGLE); 433 | } 434 | 435 | /** Generic read using MEM-AP into int array. 436 | * Data are stored into int array. Count shows INT elements. 437 | * \param *libswdctx swd context to work on. 438 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 439 | * \param addr is the start address of the data to read with MEM-AP. 440 | * \param count is the number of words to read. 441 | * \param *data is the pointer to int array where result will be stored. 442 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 443 | */ 444 | int libswd_memap_read_int(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, int *data){ 445 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 446 | "LIBSWD_D: Entering libswd_memap_read_int(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, *data=%p)...\n", 447 | (void*)libswdctx, libswd_operation_string(operation), 448 | addr, count, (void**)data); 449 | 450 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 451 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 452 | return LIBSWD_ERROR_BADOPCODE; 453 | 454 | int i, loc, res, *memapdrw; 455 | float tdeltam; 456 | struct timeval tstart, tstop; 457 | 458 | // Initialize MEM-AP if necessary. 459 | if (!libswdctx->log.memap.initialized) 460 | { 461 | res=libswd_memap_init(libswdctx, operation); 462 | if (res<0) goto libswd_memap_read_int_error; 463 | } 464 | 465 | // Mark start time for transfer speed measurement. 466 | gettimeofday(&tstart, NULL); 467 | 468 | // Perform word-by-word read operation and store result into int array. 469 | if (!(libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_ADDRINC)) 470 | { 471 | // Use manual TAR incrementation (slower). 472 | for (i=0;ilog.memap.tar=loc; 486 | // Read data from DRW register. 487 | res=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &memapdrw); 488 | if (res<0) goto libswd_memap_read_int_error; 489 | libswdctx->log.memap.drw=*memapdrw; 490 | data[i]=*memapdrw; 491 | } 492 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 493 | } 494 | else 495 | { 496 | // Use TAR Auto Increment (faster). 497 | // TAR auto increment is only guaranteed to work on the bottom 10 bits 498 | // of the TAR register. Above that it is implementation defined. 499 | // We use 1024 byte chunks as it will work on every platform 500 | // and one TAR write every 1024 bytes is not adding too much overhead. 501 | const unsigned int BOUNDARY = 1024; 502 | unsigned int i; 503 | 504 | for (loc = addr, i = 0; loc < (addr + (count * 4)); loc += 4, i++) 505 | { 506 | // only write the TAR register, if this is the first time through the loop. 507 | // or if we've passed over the boundary where TAR auto inc isn't guaranteed 508 | // to work anymore. 509 | if (loc == addr || 510 | (loc % BOUNDARY) == 0) 511 | { 512 | // Pass address to TAR register. 513 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_TAR_ADDR, &loc); 514 | if (res<0) goto libswd_memap_read_int_error; 515 | libswdctx->log.memap.tar=loc; 516 | } 517 | 518 | // Measure transfer speed. 519 | gettimeofday(&tstop, NULL); 520 | tdeltam=fabsf((tstop.tv_sec-tstart.tv_sec)*1000+(tstop.tv_usec-tstart.tv_usec)/1000); 521 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 522 | "LIBSWD_I: libswd_memap_read_int() reading address 0x%08X (speed %fKB/s)\r", 523 | loc, count*4/tdeltam ); 524 | fflush(0); 525 | 526 | // Read data from the DRW register. 527 | res=libswd_ap_read(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &memapdrw); 528 | if (res<0) goto libswd_memap_read_int_error; 529 | libswdctx->log.memap.drw=*memapdrw; 530 | data[i]=*memapdrw; 531 | } 532 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 533 | } 534 | 535 | return LIBSWD_OK; 536 | 537 | libswd_memap_read_int_error: 538 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 539 | "\nLIBSWD_E: libswd_memap_read_int(): %s\n", 540 | libswd_error_string(res) ); 541 | return res; 542 | } 543 | 544 | 545 | /** Generic read using MEM-AP, with prior CSW MEM-AP access setup. 546 | * Data are stored into int array. 547 | * \param *libswdctx swd context to work on. 548 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 549 | * \param addr is the start address of the data to read with MEM-AP. 550 | * \param count is the number of words to read. 551 | * \param *data is the pointer to int array where result will be stored. 552 | * \param csw is the value of csw register to write prior data write. 553 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 554 | */ 555 | int libswd_memap_read_int_csw(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, int *data, int csw){ 556 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 557 | "LIBSWD_D: Entering libswd_memap_read_int_csw(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, *data=%p, csw=0x%X)...\n", 558 | (void*)libswdctx, libswd_operation_string(operation), 559 | addr, count, (void**)data, csw ); 560 | 561 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 562 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 563 | return LIBSWD_ERROR_BADOPCODE; 564 | 565 | int res=0; 566 | 567 | // Calculate required access size based on CSW value. 568 | switch (csw&LIBSWD_MEMAP_CSW_SIZE) 569 | { 570 | case LIBSWD_MEMAP_CSW_SIZE_8BIT: 571 | case LIBSWD_MEMAP_CSW_SIZE_16BIT: 572 | case LIBSWD_MEMAP_CSW_SIZE_32BIT: 573 | break; 574 | default: 575 | res=LIBSWD_ERROR_MEMAPACCSIZE; 576 | goto libswd_memap_read_int_csw_error; 577 | } 578 | 579 | // Initialize MEM-AP if necessary. 580 | if (!libswdctx->log.memap.initialized) 581 | { 582 | res=libswd_memap_init(libswdctx, operation); 583 | if (res<0) goto libswd_memap_read_int_csw_error; 584 | } 585 | 586 | // Setup MEM-AP CSW and TAR. 587 | res=libswd_memap_setup(libswdctx, operation, csw, addr); 588 | if (res<0) goto libswd_memap_read_int_csw_error; 589 | 590 | // Perform the read operation. 591 | res=libswd_memap_read_int(libswdctx, operation, addr, count, data); 592 | if (res<0) goto libswd_memap_read_int_csw_error; 593 | 594 | return LIBSWD_OK; 595 | 596 | libswd_memap_read_int_csw_error: 597 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 598 | "\nLIBSWD_E: libswd_memap_read_int_csw(): %s\n", 599 | libswd_error_string(res) ); 600 | return res; 601 | } 602 | 603 | 604 | /** Generic read using MEM-AP, with prior 32-bit MEM-AP access setup. 605 | * Data are stored into int array. 606 | * \param *libswdctx swd context to work on. 607 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 608 | * \param addr is the start address of the data to read with MEM-AP. 609 | * \param count is the number of words to read. 610 | * \param *data is the pointer to int array where result will be stored. 611 | * \param csw is the value of csw register to write prior data write. 612 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 613 | */ 614 | int libswd_memap_read_int_32(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, int *data){ 615 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 616 | "LIBSWD_D: Entering libswd_memap_read_int_32(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, *data=%p)...\n", 617 | (void*)libswdctx, libswd_operation_string(operation), 618 | addr, count, (void**)data); 619 | 620 | return libswd_memap_read_int_csw(libswdctx, operation, addr, count, data, LIBSWD_MEMAP_CSW_SIZE_32BIT|LIBSWD_MEMAP_CSW_ADDRINC_SINGLE); 621 | } 622 | 623 | 624 | /** Generic write using MEM-AP from char array. 625 | * Data are read from char array. Count shows CHAR elements. 626 | * \param *libswdctx swd context to work on. 627 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 628 | * \param addr is the start address of the data to write with MEM-AP. 629 | * \param count is the number of bytes to write. 630 | * \param *data is the pointer to data to be written. 631 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 632 | */ 633 | int libswd_memap_write_char(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, char *data){ 634 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 635 | "LIBSWD_D: Entering libswd_memap_write_char(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, **data=%p)...\n", 636 | (void*)libswdctx, libswd_operation_string(operation), 637 | addr, count, (void*)data ); 638 | 639 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 640 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 641 | return LIBSWD_ERROR_BADOPCODE; 642 | 643 | int i, loc, res=0, accsize=0; 644 | float tdeltam; 645 | struct timeval tstart, tstop; 646 | 647 | // Initialize MEM-AP if neessary. 648 | if (!libswdctx->log.memap.initialized) 649 | { 650 | res=libswd_memap_init(libswdctx, operation); 651 | if (res<0) goto libswd_memap_write_char_error; 652 | } 653 | 654 | // Verify the count parameter to be access boundary. 655 | switch (libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_SIZE) 656 | { 657 | case LIBSWD_MEMAP_CSW_SIZE_8BIT: 658 | accsize=1; 659 | break; 660 | case LIBSWD_MEMAP_CSW_SIZE_16BIT: 661 | accsize=2; 662 | break; 663 | case LIBSWD_MEMAP_CSW_SIZE_32BIT: 664 | accsize=4; 665 | break; 666 | default: 667 | res=LIBSWD_ERROR_MEMAPACCSIZE; 668 | goto libswd_memap_write_char_error; 669 | } 670 | if (count%accsize) count=count-(count%accsize); 671 | 672 | // check for alignment issues. 673 | if ((addr%accsize)!=0) 674 | { 675 | res=LIBSWD_ERROR_MEMAPALIGN; 676 | goto libswd_memap_write_char_error; 677 | } 678 | 679 | // Mark start time for transfer speed measurement. 680 | gettimeofday(&tstart, NULL); 681 | 682 | // Perform word-by-word write operation from char array. 683 | // Use write method that match the CSW AddrInc configuration. 684 | if (!(libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_ADDRINC)) 685 | { 686 | // Use manual TAR incrementation (slower). 687 | for (i=0;ilog.memap.tar=loc; 706 | // Implode and Write data to DRW register. 707 | memcpy((void*)&libswdctx->log.memap.drw, data+i, accsize); 708 | // apply the data byte-laning shift 709 | libswdctx->log.memap.drw <<= drw_shift; 710 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &libswdctx->log.memap.drw); 711 | if (res<0) goto libswd_memap_write_char_error; 712 | } 713 | } 714 | else 715 | { 716 | // Use TAR Auto Increment (faster). 717 | // TAR auto increment is only guaranteed to work on the bottom 10 bits 718 | // of the TAR register. Above that it is implementation defined. 719 | // We use 1024 byte chunks as it will work on every platform 720 | // and one TAR write every 1024 bytes is not adding too much overhead. 721 | const unsigned int BOUNDARY = 1024; 722 | unsigned int i; 723 | 724 | // Check if packed transfer, if so use word access. 725 | if (libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_ADDRINC_PACKED) accsize=4; 726 | 727 | for (loc = addr, i = 0; loc < (addr + count); loc += accsize, i+= accsize) 728 | { 729 | int drw_shift; 730 | 731 | // Calculate the offset in DRW where the data should go 732 | // see Data byte-laning in the ARM debug interface v5 documentation 733 | // note: this only works for little endian systems. 734 | drw_shift=8*(loc%4); 735 | 736 | // only write the TAR register, if this is the first time through the loop. 737 | // or if we've passed over the boundary where TAR auto inc isn't guaranteed 738 | // to work anymore. 739 | if (loc == addr || 740 | (loc % BOUNDARY) == 0) 741 | { 742 | // Pass address to TAR register. 743 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_TAR_ADDR, &loc); 744 | if (res<0) goto libswd_memap_write_char_error; 745 | libswdctx->log.memap.tar=loc; 746 | } 747 | 748 | // Measure transfer speed. 749 | gettimeofday(&tstop, NULL); 750 | tdeltam=fabsf((tstop.tv_sec-tstart.tv_sec)*1000+(tstop.tv_usec-tstart.tv_usec)/1000); 751 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 752 | "LIBSWD_I: libswd_memap_write_char() writing address 0x%08X (speed %fKB/s)\r", 753 | loc, count/tdeltam ); 754 | fflush(0); 755 | 756 | // apply the data byte-laning shift and write to the DRW register 757 | memcpy((void*)&libswdctx->log.memap.drw, data + i, accsize); 758 | libswdctx->log.memap.drw <<= drw_shift; 759 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &libswdctx->log.memap.drw); 760 | if (res<0) goto libswd_memap_write_char_error; 761 | } 762 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 763 | } 764 | 765 | return LIBSWD_OK; 766 | 767 | libswd_memap_write_char_error: 768 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 769 | "LIBSWD_E: libswd_memap_write_char(): %s\n", 770 | libswd_error_string(res) ); 771 | return res; 772 | } 773 | 774 | 775 | /** Generic write using MEM-AP from char array, with prior CSW setup. 776 | * \param *libswdctx swd context to work on. 777 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 778 | * \param addr is the start address of the data to write with MEM-AP. 779 | * \param count is the number of bytes to write. 780 | * \param *data is the pointer to data to be written. 781 | * \param csw is the value of csw register to write prior data write. 782 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 783 | */ 784 | int libswd_memap_write_char_csw(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, char *data, int csw){ 785 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 786 | "LIBSWD_D: Entring libswd_memap_write_char_csw(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, **data=%p, csw=0x%X)...\n", 787 | (void*)libswdctx, libswd_operation_string(operation), 788 | addr, count, (void**)data, csw ); 789 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 790 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 791 | return LIBSWD_ERROR_BADOPCODE; 792 | 793 | int res=0, accsize=0; 794 | 795 | // Calculate required access size based on CSW value. 796 | switch (csw&LIBSWD_MEMAP_CSW_SIZE) 797 | { 798 | case LIBSWD_MEMAP_CSW_SIZE_8BIT: 799 | accsize=1; 800 | break; 801 | case LIBSWD_MEMAP_CSW_SIZE_16BIT: 802 | accsize=2; 803 | break; 804 | case LIBSWD_MEMAP_CSW_SIZE_32BIT: 805 | accsize=4; 806 | break; 807 | default: 808 | res=LIBSWD_ERROR_MEMAPACCSIZE; 809 | goto libswd_memap_write_char_csw_error; 810 | } 811 | // Verify the count parameter to be access boundary. 812 | if (count%accsize) count=count-(count%accsize); 813 | 814 | // Initialize MEM-AP if necessary. 815 | if (!libswdctx->log.memap.initialized) 816 | { 817 | res=libswd_memap_init(libswdctx, operation); 818 | if (res<0) goto libswd_memap_write_char_csw_error; 819 | } 820 | 821 | // Setup MEM-AP CSW and TAR. 822 | res=libswd_memap_setup(libswdctx, operation, csw, addr); 823 | if (res<0) goto libswd_memap_write_char_csw_error; 824 | 825 | res=libswd_memap_write_char(libswdctx, operation, addr, count, data); 826 | if (res<0) goto libswd_memap_write_char_csw_error; 827 | 828 | return LIBSWD_OK; 829 | 830 | libswd_memap_write_char_csw_error: 831 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 832 | "LIBSWD_E: libswd_memap_write_char_csw(): %s\n", 833 | libswd_error_string(res) ); 834 | return res; 835 | } 836 | 837 | 838 | /** Generic write using MEM-AP from char array, using 32-bit access. 839 | * \param *libswdctx swd context to work on. 840 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 841 | * \param addr is the start address of the data to write with MEM-AP. 842 | * \param count is the number of bytes to write. 843 | * \param *data is the pointer to data to be written. 844 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 845 | */ 846 | int libswd_memap_write_char_32(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, char *data){ 847 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 848 | "LIBSWD_D: Entering libswd_memap_write_char_32(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, **data=%p)...\n", 849 | (void*)libswdctx, libswd_operation_string(operation), 850 | addr, count, (void**)data); 851 | 852 | return libswd_memap_write_char_csw(libswdctx, operation, addr, count, data, LIBSWD_MEMAP_CSW_SIZE_32BIT|LIBSWD_MEMAP_CSW_ADDRINC_SINGLE); 853 | } 854 | 855 | 856 | /** Generic write using MEM-AP from int array. 857 | * Data are stored into char array. 858 | * Remember to setup CSW first for valid bus access! 859 | * \param *libswdctx swd context to work on. 860 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 861 | * \param addr is the start address of the data to write with MEM-AP. 862 | * \param count is the number of words to write. 863 | * \param *data is the pointer to int data array to be written. 864 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 865 | */ 866 | int libswd_memap_write_int(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, int *data){ 867 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 868 | "LIBSWD_D: Entering libswd_memap_write_int(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, **data=%p)...\n", 869 | (void*)libswdctx, libswd_operation_string(operation), 870 | addr, count, (void*)data); 871 | 872 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 873 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 874 | return LIBSWD_ERROR_BADOPCODE; 875 | 876 | int i, loc, res=0; 877 | float tdeltam; 878 | struct timeval tstart, tstop; 879 | 880 | // Initialize MEM-AP if necessary. 881 | if (!libswdctx->log.memap.initialized) 882 | { 883 | res=libswd_memap_init(libswdctx, operation); 884 | if (res<0) goto libswd_memap_write_int_error; 885 | } 886 | 887 | // Mark start time for transfer speed measurement. 888 | gettimeofday(&tstart, NULL); 889 | 890 | // Perform word-by-word write operation from int array. 891 | if (!(libswdctx->log.memap.csw&LIBSWD_MEMAP_CSW_ADDRINC)) 892 | { 893 | // Use manual TAR incrementation (slower). 894 | for (i=0;ilog.memap.tar=loc; 908 | // Implode and Write data to DRW register. 909 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, data+i); 910 | if (res<0) goto libswd_memap_write_int_error; 911 | libswdctx->log.memap.drw=data[i]; 912 | } 913 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 914 | } 915 | else 916 | { 917 | // Use TAR Auto Increment (faster). 918 | // TAR auto increment is only guaranteed to work on the bottom 10 bits 919 | // of the TAR register. Above that it is implementation defined. 920 | // We use 1024 byte chunks as it will work on every platform 921 | // and one TAR write every 1024 bytes is not adding too much overhead. 922 | const unsigned int BOUNDARY = 1024; 923 | unsigned int i; 924 | 925 | for (loc = addr, i = 0; loc < (addr + (count * 4)); loc += 4, i++) 926 | { 927 | // only write the TAR register, if this is the first time through the loop. 928 | // or if we've passed over the boundary where TAR auto inc isn't guaranteed 929 | // to work anymore. 930 | if (loc == addr || 931 | (loc % BOUNDARY) == 0) 932 | { 933 | // Pass address to TAR register. 934 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_TAR_ADDR, &loc); 935 | if (res<0) goto libswd_memap_write_int_error; 936 | libswdctx->log.memap.tar=loc; 937 | } 938 | 939 | // Measure transfer speed. 940 | gettimeofday(&tstop, NULL); 941 | tdeltam=fabsf((tstop.tv_sec-tstart.tv_sec)*1000+(tstop.tv_usec-tstart.tv_usec)/1000); 942 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, 943 | "LIBSWD_I: libswd_memap_write_int() writing address 0x%08X (speed %fKB/s)\r", 944 | loc, count*4/tdeltam ); 945 | fflush(0); 946 | 947 | // Write data to DRW register. 948 | libswdctx->log.memap.drw=data[i]; 949 | res=libswd_ap_write(libswdctx, LIBSWD_OPERATION_EXECUTE, LIBSWD_MEMAP_DRW_ADDR, &libswdctx->log.memap.drw); 950 | if (res<0) goto libswd_memap_write_int_error; 951 | } 952 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_INFO, "\n"); 953 | } 954 | 955 | return LIBSWD_OK; 956 | 957 | libswd_memap_write_int_error: 958 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 959 | "\nLIBSWD_E: libswd_memap_write_int(): %s\n", 960 | libswd_error_string(res) ); 961 | return res; 962 | } 963 | 964 | /** Generic write using MEM-AP from int array, with prior CSW MEM-AP setup. 965 | * \param *libswdctx swd context to work on. 966 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 967 | * \param addr is the start address of the data to write with MEM-AP. 968 | * \param count is the number of words to write. 969 | * \param *data is the pointer to int data array to be written. 970 | * \param csw is the value of csw register to write prior data write. 971 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 972 | */ 973 | int libswd_memap_write_int_csw(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, int *data, int csw){ 974 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 975 | "LIBSWD_D: Entering libswd_memap_write_int_csw(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, **data=%p, csw=0x%X)...\n", 976 | (void*)libswdctx, libswd_operation_string(operation), 977 | addr, count, (void**)data, csw ); 978 | 979 | if (libswdctx==NULL) return LIBSWD_ERROR_NULLCONTEXT; 980 | if (operation!=LIBSWD_OPERATION_ENQUEUE && operation!=LIBSWD_OPERATION_EXECUTE) 981 | return LIBSWD_ERROR_BADOPCODE; 982 | 983 | int res=0; 984 | 985 | // Calculate required access size based on CSW value. 986 | switch (csw&LIBSWD_MEMAP_CSW_SIZE) 987 | { 988 | case LIBSWD_MEMAP_CSW_SIZE_8BIT: 989 | case LIBSWD_MEMAP_CSW_SIZE_16BIT: 990 | case LIBSWD_MEMAP_CSW_SIZE_32BIT: 991 | break; 992 | default: 993 | res=LIBSWD_ERROR_MEMAPACCSIZE; 994 | goto libswd_memap_write_int_csw_error; 995 | } 996 | 997 | // Initialize MEM-AP if necessary. 998 | if (!libswdctx->log.memap.initialized) 999 | { 1000 | res=libswd_memap_init(libswdctx, operation); 1001 | if (res<0) goto libswd_memap_write_int_csw_error; 1002 | } 1003 | 1004 | // Setup MEM-AP CSW and TAR. 1005 | res=libswd_memap_setup(libswdctx, operation, csw, addr); 1006 | if (res<0) goto libswd_memap_write_int_csw_error; 1007 | 1008 | // Perform the write operation. 1009 | res=libswd_memap_write_int(libswdctx, operation, addr, count, data); 1010 | if (res<0) goto libswd_memap_write_int_csw_error; 1011 | 1012 | return LIBSWD_OK; 1013 | 1014 | libswd_memap_write_int_csw_error: 1015 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_ERROR, 1016 | "\nLIBSWD_E: libswd_memap_write_int_csw(): %s\n", 1017 | libswd_error_string(res) ); 1018 | return res; 1019 | } 1020 | 1021 | /** Generic write using MEM-AP from int array, with prior 32-bit MEM-AP access setup. 1022 | * \param *libswdctx swd context to work on. 1023 | * \param operation can be LIBSWD_OPERATION_ENQUEUE or LIBSWD_OPERATION_EXECUTE. 1024 | * \param addr is the start address of the data to write with MEM-AP. 1025 | * \param count is the number of words to write. 1026 | * \param *data is the pointer to int data array to be written. 1027 | * \return number of elements/words processed or LIBSWD_ERROR code on failure. 1028 | */ 1029 | int libswd_memap_write_int_32(libswd_ctx_t *libswdctx, libswd_operation_t operation, int addr, int count, int *data){ 1030 | libswd_log(libswdctx, LIBSWD_LOGLEVEL_DEBUG, 1031 | "LIBSWD_D: Entering libswd_memap_write_int_32(*libswdctx=%p, operation=%s, addr=0x%08X, count=0x%08X, **data=%p)...\n", 1032 | (void*)libswdctx, libswd_operation_string(operation), 1033 | addr, count, (void**)data); 1034 | 1035 | return libswd_memap_write_int_csw(libswdctx, operation, addr, count, data, LIBSWD_MEMAP_CSW_SIZE_32BIT|LIBSWD_MEMAP_CSW_ADDRINC_SINGLE); 1036 | } 1037 | 1038 | 1039 | /** @} */ 1040 | --------------------------------------------------------------------------------