diff --git a/LICENSES/preferred/CC0-1.0 b/LICENSES/preferred/CC0-1.0 new file mode 100644 index 000000000..ba3c8c795 --- /dev/null +++ b/LICENSES/preferred/CC0-1.0 @@ -0,0 +1,130 @@ +Valid-License-Identifier: CC0-1.0 +SPDX-URL: https://spdx.org/licenses/CC0-1.0.html +Usage-Guide: + To use the Creative Commons Zero v1.0 Universal License put the following + SPDX tag/value pair into a comment according to the placement guidelines in + the licensing rules documentation: + SPDX-License-Identifier: CC0-1.0 +License-Text: + +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/Makefile.am b/Makefile.am index ac08e4133..bf839d687 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,6 +66,7 @@ EXTRA_DIST += \ LICENSES/preferred/BSD-2-Clause-Views \ LICENSES/preferred/BSD-3-Clause \ LICENSES/preferred/BSD-Source-Code \ + LICENSES/preferred/CC0-1.0 \ LICENSES/preferred/GFDL-1.2 \ LICENSES/preferred/gfdl-1.2.texi.readme \ LICENSES/preferred/GPL-2.0 \ diff --git a/contrib/rtos-helpers/FreeRTOS-openocd.c b/contrib/rtos-helpers/FreeRTOS-openocd.c index 000453d5d..5f82ac7a2 100644 --- a/contrib/rtos-helpers/FreeRTOS-openocd.c +++ b/contrib/rtos-helpers/FreeRTOS-openocd.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: CC0-1.0 /* * Since at least FreeRTOS V7.5.3 uxTopUsedPriority is no longer diff --git a/doc/openocd.texi b/doc/openocd.texi index 7a880873c..1312c5f77 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5325,6 +5325,18 @@ Displays the current target state: (Also, @pxref{eventpolling,,Event Polling}.) @end deffn +@deffn {Command} {$target_name debug_reason} +Displays the current debug reason: +@code{debug-request}, +@code{breakpoint}, +@code{watchpoint}, +@code{watchpoint-and-breakpoint}, +@code{single-step}, +@code{target-not-halted}, +@code{program-exit}, +@code{exception-catch} or @code{undefined}. +@end deffn + @deffn {Command} {$target_name eventlist} Displays a table listing all event handlers currently associated with this target. @@ -9387,8 +9399,8 @@ for similar mechanisms that do not consume hardware breakpoints.) Remove the breakpoint at @var{address} or all breakpoints. @end deffn -@deffn {Command} {rwp} address -Remove data watchpoint on @var{address} +@deffn {Command} {rwp} @option{all} | address +Remove data watchpoint on @var{address} or all watchpoints. @end deffn @deffn {Command} {wp} [address len [(@option{r}|@option{w}|@option{a}) [value [mask]]]] @@ -12709,7 +12721,7 @@ Return information about the flash banks @item @b{capture} <@var{command}> Run <@var{command}> and return full log output that was produced during -its execution. Example: +its execution together with the command output. Example: @example > capture "reset init" diff --git a/src/flash/nor/rsl10.c b/src/flash/nor/rsl10.c index 5f0ac9b8f..c286e9ac8 100644 --- a/src/flash/nor/rsl10.c +++ b/src/flash/nor/rsl10.c @@ -815,7 +815,8 @@ static const struct command_registration rsl10_exec_command_handlers[] = { .help = "Mass erase all unprotected flash areas", .usage = "", }, - COMMAND_REGISTRATION_DONE}; + COMMAND_REGISTRATION_DONE +}; static const struct command_registration rsl10_command_handlers[] = { { @@ -825,7 +826,8 @@ static const struct command_registration rsl10_command_handlers[] = { .usage = "", .chain = rsl10_exec_command_handlers, }, - COMMAND_REGISTRATION_DONE}; + COMMAND_REGISTRATION_DONE +}; const struct flash_driver rsl10_flash = { .name = "rsl10", diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index ace274f3d..bf654f9f6 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -22,10 +22,22 @@ /* Shared table of known SPI flash devices for SPI-based flash drivers. Taken * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { - /* name, read_cmd, qread_cmd, pprog_cmd, erase_cmd, chip_erase_cmd, device_id, - * pagesize, sectorsize, size_in_bytes - * note: device id is usually 3 bytes long, however the unused highest byte counts - * continuation codes for manufacturer id as per JEP106xx */ + /* Note: device_id is usually 3 bytes long, however the unused highest byte counts + * continuation codes for manufacturer id as per JEP106xx. + * + * All sizes (page, sector/block and flash) are in bytes. + * + * Guide to select a proper erase command (if both sector and block erase cmds are available): + * Use 4kbit sector erase cmd and set erase size to the size of sector for small devices + * (4Mbit and less, size <= 0x80000) to prevent too raw erase granularity. + * Use 64kbit block erase cmd and set erase size to the size of block for bigger devices + * (8Mbit and more, size >= 0x100000) to keep erase speed reasonable. + * If the device implements also 32kbit block erase, use it for 8Mbit, size == 0x100000. + */ + /* name read qread page erase chip device_id page erase flash + * _cmd _cmd _prog _cmd* _erase size size* size + * _cmd _cmd + */ FLASH_ID("st m25pe10", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00118020, 0x100, 0x10000, 0x20000), FLASH_ID("st m25pe20", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00128020, 0x100, 0x10000, 0x40000), FLASH_ID("st m25pe40", 0x03, 0x00, 0x02, 0xd8, 0x00, 0x00138020, 0x100, 0x10000, 0x80000), @@ -174,6 +186,11 @@ const struct flash_device flash_devices[] = { FLASH_ID("zetta zd25q16", 0x03, 0x00, 0x02, 0xd8, 0xc7, 0x001560ba, 0x100, 0x10000, 0x200000), /* FRAM, no erase commands, no write page or sectors */ + + /* name read qread page device_id total + * _cmd _cmd _prog size + * _cmd + */ FRAM_ID("fu mb85rs16n", 0x03, 0, 0x02, 0x00010104, 0x800), FRAM_ID("fu mb85rs32v", 0x03, 0, 0x02, 0x00010204, 0x1000), /* exists ? */ FRAM_ID("fu mb85rs64v", 0x03, 0, 0x02, 0x00020304, 0x2000), diff --git a/src/helper/command.c b/src/helper/command.c index 945b890b3..ef50ab5bd 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -99,8 +99,7 @@ static struct log_capture_state *command_log_capture_start(Jim_Interp *interp) * The tcl return value is empty for openocd commands that provide * progress output. * - * Therefore we set the tcl return value only if we actually - * captured output. + * For other commands, we prepend the logs to the tcl return value. */ static void command_log_capture_finish(struct log_capture_state *state) { @@ -109,15 +108,18 @@ static void command_log_capture_finish(struct log_capture_state *state) log_remove_callback(tcl_output, state); - int length; - Jim_GetString(state->output, &length); + int loglen; + const char *log_result = Jim_GetString(state->output, &loglen); + int reslen; + const char *cmd_result = Jim_GetString(Jim_GetResult(state->interp), &reslen); - if (length > 0) - Jim_SetResult(state->interp, state->output); - else { - /* No output captured, use tcl return value (which could - * be empty too). */ - } + // Just in case the log doesn't end with a newline, we add it + if (loglen != 0 && reslen != 0 && log_result[loglen - 1] != '\n') + Jim_AppendString(state->interp, state->output, "\n", 1); + + Jim_AppendString(state->interp, state->output, cmd_result, reslen); + + Jim_SetResult(state->interp, state->output); Jim_DecrRefCount(state->interp, state->output); free(state); @@ -691,8 +693,8 @@ COMMAND_HANDLER(handle_echo) return ERROR_OK; } -/* Capture progress output and return as tcl return value. If the - * progress output was empty, return tcl return value. +/* Return both the progress output (LOG_INFO and higher) + * and the tcl return value of a command. */ static int jim_capture(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { diff --git a/src/helper/jep106.inc b/src/helper/jep106.inc index 6c8196765..bcf354c91 100644 --- a/src/helper/jep106.inc +++ b/src/helper/jep106.inc @@ -2,15 +2,15 @@ /* * The manufacturer's standard identification code list appears in JEP106. - * Copyright (c) 2022 JEDEC. All rights reserved. + * Copyright (c) 2023 JEDEC. All rights reserved. * * JEP106 is regularly updated. For the current manufacturer's standard * identification code list, please visit the JEDEC website at www.jedec.org . */ -/* This file is aligned to revision JEP106BG May 2023. */ +/* This file is aligned to revision JEP106BH September 2023. */ -/* "NXP (Philips)" is reported below, while missing in JEP106BG */ +/* "NXP (Philips)" is reported below, while missing since JEP106BG */ [0][0x01 - 1] = "AMD", [0][0x02 - 1] = "AMI", @@ -1375,7 +1375,7 @@ [10][0x65 - 1] = "Esperanto Technologies", [10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", [10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", -[10][0x68 - 1] = "Shanghai Rei Zuan Information Tech", +[10][0x68 - 1] = "Shanghai Rui Zuan Information Tech", [10][0x69 - 1] = "Fraunhofer IIS", [10][0x6a - 1] = "Kandou Bus SA", [10][0x6b - 1] = "Acer", @@ -1841,4 +1841,51 @@ [14][0x3f - 1] = "Shenzhen Dingsheng Technology Co Ltd", [14][0x40 - 1] = "EVAS Intelligence Co Ltd", [14][0x41 - 1] = "Kaibright Electronic Technologies", +[14][0x42 - 1] = "Fraunhofer IMS", +[14][0x43 - 1] = "Shenzhen Xinrui Renhe Technology", +[14][0x44 - 1] = "Beijing Vcore Technology Co Ltd", +[14][0x45 - 1] = "Silicon Innovation Technologies Co Ltd", +[14][0x46 - 1] = "Shenzhen Zhengxinda Technology Co Ltd", +[14][0x47 - 1] = "Shenzhen Remai Electronics Co Lttd", +[14][0x48 - 1] = "Shenzhen Xinruiyan Electronics Co Ltd", +[14][0x49 - 1] = "CEC Huada Electronic Design Co Ltd", +[14][0x4a - 1] = "Westberry Technology Inc", +[14][0x4b - 1] = "Tongxin Microelectronics Co Ltd", +[14][0x4c - 1] = "UNIM Semiconductor (Shang Hai) Co Ltd", +[14][0x4d - 1] = "Shenzhen Qiaowenxingyu Industrial Co Ltd", +[14][0x4e - 1] = "ICC", +[14][0x4f - 1] = "Enfabrica Corporation", +[14][0x50 - 1] = "Niobium Microsystems Inc", +[14][0x51 - 1] = "Xiaoli AI Electronics (Shenzhen) Co Ltd", +[14][0x52 - 1] = "Silicon Mitus", +[14][0x53 - 1] = "Ajiatek Inc", +[14][0x54 - 1] = "HomeNet", +[14][0x55 - 1] = "Shenzhen Shubang Technology Co Ltd", +[14][0x56 - 1] = "Exacta Technologies Ltd", +[14][0x57 - 1] = "Synology", +[14][0x58 - 1] = "Trium Elektronik Bilgi Islem San Ve Dis", +[14][0x59 - 1] = "Shenzhen Hippstor Technology Co Ltd", +[14][0x5a - 1] = "SSCT", +[14][0x5b - 1] = "Sichuan Heentai Semiconductor Co Ltd", +[14][0x5c - 1] = "Zhejiang University", +[14][0x5d - 1] = "www.shingroup.cn", +[14][0x5e - 1] = "Suzhou Nano Mchip Technology Company", +[14][0x5f - 1] = "Feature Integration Technology Inc", +[14][0x60 - 1] = "d-Matrix", +[14][0x61 - 1] = "Golden Memory", +[14][0x62 - 1] = "Qingdao Thunderobot Technology Co Ltd", +[14][0x63 - 1] = "Shenzhen Tianxiang Chuangxin Technology", +[14][0x64 - 1] = "HYPHY USA", +[14][0x65 - 1] = "Valkyrie", +[14][0x66 - 1] = "Suzhou Hesetc Electronic Technology Co", +[14][0x67 - 1] = "Hainan Zhongyuncun Technology Co Ltd", +[14][0x68 - 1] = "Shenzhen Yousheng Bona Technology Co", +[14][0x69 - 1] = "Shenzhen Xinle Chuang Technology Co", +[14][0x6a - 1] = "DEEPX", +[14][0x6b - 1] = "iStarChip CA LLC", +[14][0x6c - 1] = "Shenzhen Vinreada Technology Co Ltd", +[14][0x6d - 1] = "Novatek Microelectronics Corp", +[14][0x6e - 1] = "Chemgdu EG Technology Co Ltd", +[14][0x6f - 1] = "AGI Technology", +[14][0x70 - 1] = "Syntiant", /* EOF */ diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c index 9cc086599..b6bde5b3b 100644 --- a/src/jtag/drivers/angie.c +++ b/src/jtag/drivers/angie.c @@ -257,7 +257,7 @@ static int angie_usb_open(struct angie *device) const uint16_t vids[] = {ANGIE_VID, ANGIE_VID, ANGIE_VID, ANGIE_VID, 0}; const uint16_t pids[] = {ANGIE_PID, ANGIE_PID_2, ANGIE_PID_3, ANGIE_PID_4, 0}; - int ret = jtag_libusb_open(vids, pids, &usb_device_handle, NULL); + int ret = jtag_libusb_open(vids, pids, NULL, &usb_device_handle, NULL); if (ret != ERROR_OK) return ret; diff --git a/src/jtag/drivers/arm-jtag-ew.c b/src/jtag/drivers/arm-jtag-ew.c index a37272084..eada67f45 100644 --- a/src/jtag/drivers/arm-jtag-ew.c +++ b/src/jtag/drivers/arm-jtag-ew.c @@ -677,7 +677,7 @@ static struct armjtagew *armjtagew_usb_open(void) const uint16_t pids[] = { USB_PID, 0 }; struct libusb_device_handle *dev; - if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct armjtagew *result = malloc(sizeof(struct armjtagew)); diff --git a/src/jtag/drivers/bcm2835gpio.c b/src/jtag/drivers/bcm2835gpio.c index f41f7b51e..7fd7f3894 100644 --- a/src/jtag/drivers/bcm2835gpio.c +++ b/src/jtag/drivers/bcm2835gpio.c @@ -331,7 +331,7 @@ COMMAND_HANDLER(bcm2835gpio_handle_peripheral_base) } tmp_base = bcm2835_peri_base; - command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIu64, + command_print(CMD, "BCM2835 GPIO: peripheral_base = 0x%08" PRIx64, tmp_base); return ERROR_OK; } diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index 2ed0f58fd..950405954 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -487,7 +487,7 @@ static int esp_usb_jtag_init(void) bitq_interface->in_rdy = esp_usb_jtag_in_rdy; bitq_interface->in = esp_usb_jtag_in; - int r = jtag_libusb_open(vids, pids, &priv->usb_device, NULL); + int r = jtag_libusb_open(vids, pids, NULL, &priv->usb_device, NULL); if (r != ERROR_OK) { LOG_ERROR("esp_usb_jtag: could not find or open device!"); goto out; diff --git a/src/jtag/drivers/ft232r.c b/src/jtag/drivers/ft232r.c index c2ec78ad8..2d9d9ef34 100644 --- a/src/jtag/drivers/ft232r.c +++ b/src/jtag/drivers/ft232r.c @@ -246,7 +246,7 @@ static int ft232r_init(void) { uint16_t avids[] = {ft232r_vid, 0}; uint16_t apids[] = {ft232r_pid, 0}; - if (jtag_libusb_open(avids, apids, &adapter, NULL)) { + if (jtag_libusb_open(avids, apids, NULL, &adapter, NULL)) { const char *ft232r_serial_desc = adapter_get_required_serial(); LOG_ERROR("ft232r not found: vid=%04x, pid=%04x, serial=%s\n", ft232r_vid, ft232r_pid, (!ft232r_serial_desc) ? "[any]" : ft232r_serial_desc); diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index b953218b8..e126a9c22 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -275,7 +275,7 @@ static int kitprog_usb_open(void) const uint16_t vids[] = { VID, 0 }; const uint16_t pids[] = { PID, 0 }; - if (jtag_libusb_open(vids, pids, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &kitprog_handle->usb_handle, NULL) != ERROR_OK) { LOG_ERROR("Failed to open or find the device"); return ERROR_FAIL; } diff --git a/src/jtag/drivers/libusb_helper.c b/src/jtag/drivers/libusb_helper.c index c77fe78c2..9d788ee39 100644 --- a/src/jtag/drivers/libusb_helper.c +++ b/src/jtag/drivers/libusb_helper.c @@ -146,12 +146,13 @@ static bool jtag_libusb_match_serial(struct libusb_device_handle *device, } int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - struct libusb_device_handle **out, + const char *product, struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial) { int cnt, idx, err_code; int retval = ERROR_FAIL; bool serial_mismatch = false; + bool product_mismatch = false; struct libusb_device_handle *libusb_handle = NULL; const char *serial = adapter_get_required_serial(); @@ -188,10 +189,18 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], continue; } + if (product && + !string_descriptor_equal(libusb_handle, dev_desc.iProduct, product)) { + product_mismatch = true; + libusb_close(libusb_handle); + continue; + } + /* Success. */ *out = libusb_handle; retval = ERROR_OK; serial_mismatch = false; + product_mismatch = false; break; } if (cnt >= 0) @@ -200,6 +209,9 @@ int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], if (serial_mismatch) LOG_INFO("No device matches the serial string"); + if (product_mismatch) + LOG_INFO("No device matches the product string"); + if (retval != ERROR_OK) libusb_exit(jtag_libusb_context); diff --git a/src/jtag/drivers/libusb_helper.h b/src/jtag/drivers/libusb_helper.h index 75f133519..09309b40c 100644 --- a/src/jtag/drivers/libusb_helper.h +++ b/src/jtag/drivers/libusb_helper.h @@ -33,7 +33,7 @@ typedef char * (*adapter_get_alternate_serial_fn)(struct libusb_device_handle *d bool jtag_libusb_match_ids(struct libusb_device_descriptor *dev_desc, const uint16_t vids[], const uint16_t pids[]); int jtag_libusb_open(const uint16_t vids[], const uint16_t pids[], - struct libusb_device_handle **out, + const char *product, struct libusb_device_handle **out, adapter_get_alternate_serial_fn adapter_get_alternate_serial); void jtag_libusb_close(struct libusb_device_handle *dev); int jtag_libusb_control_transfer(struct libusb_device_handle *dev, diff --git a/src/jtag/drivers/opendous.c b/src/jtag/drivers/opendous.c index 2e1d64814..4d9fd998a 100644 --- a/src/jtag/drivers/opendous.c +++ b/src/jtag/drivers/opendous.c @@ -695,7 +695,7 @@ struct opendous_jtag *opendous_usb_open(void) struct opendous_jtag *result; struct libusb_device_handle *devh; - if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, &devh, NULL) != ERROR_OK) + if (jtag_libusb_open(opendous_probe->VID, opendous_probe->PID, NULL, &devh, NULL) != ERROR_OK) return NULL; jtag_libusb_set_configuration(devh, 0); diff --git a/src/jtag/drivers/openjtag.c b/src/jtag/drivers/openjtag.c index fe3a8ff7f..dca27b0a6 100644 --- a/src/jtag/drivers/openjtag.c +++ b/src/jtag/drivers/openjtag.c @@ -438,7 +438,7 @@ static int openjtag_init_cy7c65215(void) int ret; usbh = NULL; - ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, &usbh, NULL); + ret = jtag_libusb_open(cy7c65215_vids, cy7c65215_pids, NULL, &usbh, NULL); if (ret != ERROR_OK) { LOG_ERROR("unable to open cy7c65215 device"); goto err; diff --git a/src/jtag/drivers/osbdm.c b/src/jtag/drivers/osbdm.c index d8fe7135e..84f2fd66a 100644 --- a/src/jtag/drivers/osbdm.c +++ b/src/jtag/drivers/osbdm.c @@ -363,7 +363,7 @@ static int osbdm_flush(struct osbdm *osbdm, struct queue *queue) static int osbdm_open(struct osbdm *osbdm) { (void)memset(osbdm, 0, sizeof(*osbdm)); - if (jtag_libusb_open(osbdm_vid, osbdm_pid, &osbdm->devh, NULL) != ERROR_OK) + if (jtag_libusb_open(osbdm_vid, osbdm_pid, NULL, &osbdm->devh, NULL) != ERROR_OK) return ERROR_FAIL; if (libusb_claim_interface(osbdm->devh, 0) != ERROR_OK) diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c index 65f7494bd..a28e76e01 100644 --- a/src/jtag/drivers/rlink.c +++ b/src/jtag/drivers/rlink.c @@ -1448,7 +1448,7 @@ static int rlink_init(void) const uint16_t vids[] = { USB_IDVENDOR, 0 }; const uint16_t pids[] = { USB_IDPRODUCT, 0 }; - if (jtag_libusb_open(vids, pids, &hdev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &hdev, NULL) != ERROR_OK) return ERROR_FAIL; struct libusb_device_descriptor descriptor; diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index c5326a206..b14fbf1f3 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -3406,7 +3406,7 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param) in order to become operational. */ do { - if (jtag_libusb_open(param->vid, param->pid, + if (jtag_libusb_open(param->vid, param->pid, NULL, &h->usb_backend_priv.fd, stlink_usb_get_alternate_serial) != ERROR_OK) { LOG_ERROR("open failed"); return ERROR_FAIL; diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 3e3621873..4260e2d39 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -675,7 +675,7 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) /* TI (Stellaris) ICDI provides its serial number in the USB descriptor; no need to provide a callback here. */ - jtag_libusb_open(param->vid, param->pid, &h->usb_dev, NULL); + jtag_libusb_open(param->vid, param->pid, NULL, &h->usb_dev, NULL); if (!h->usb_dev) { LOG_ERROR("open failed"); diff --git a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c index f5e0026a7..de0d2d847 100644 --- a/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c +++ b/src/jtag/drivers/usb_blaster/ublast2_access_libusb.c @@ -202,7 +202,7 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) bool renumeration = false; int ret; - if (jtag_libusb_open(vids, pids, &temp, NULL) == ERROR_OK) { + if (jtag_libusb_open(vids, pids, NULL, &temp, NULL) == ERROR_OK) { LOG_INFO("Altera USB-Blaster II (uninitialized) found"); LOG_INFO("Loading firmware..."); ret = load_usb_blaster_firmware(temp, low); @@ -216,13 +216,13 @@ static int ublast2_libusb_init(struct ublast_lowlevel *low) const uint16_t pids_renum[] = { low->ublast_pid, 0 }; if (renumeration == false) { - if (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK) { + if (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev, NULL) != ERROR_OK) { LOG_ERROR("Altera USB-Blaster II not found"); return ERROR_FAIL; } } else { int retry = 10; - while (jtag_libusb_open(vids_renum, pids_renum, &low->libusb_dev, NULL) != ERROR_OK && retry--) { + while (jtag_libusb_open(vids_renum, pids_renum, NULL, &low->libusb_dev, NULL) != ERROR_OK && retry--) { usleep(1000000); LOG_INFO("Waiting for reenumerate..."); } diff --git a/src/jtag/drivers/usbprog.c b/src/jtag/drivers/usbprog.c index 5d41656b4..aa655ed7e 100644 --- a/src/jtag/drivers/usbprog.c +++ b/src/jtag/drivers/usbprog.c @@ -341,7 +341,7 @@ struct usbprog_jtag *usbprog_jtag_open(void) const uint16_t pids[] = { PID, 0 }; struct libusb_device_handle *dev; - if (jtag_libusb_open(vids, pids, &dev, NULL) != ERROR_OK) + if (jtag_libusb_open(vids, pids, NULL, &dev, NULL) != ERROR_OK) return NULL; struct usbprog_jtag *tmp = malloc(sizeof(struct usbprog_jtag)); diff --git a/src/pld/certus.c b/src/pld/certus.c index a49501f54..ccb3feb90 100644 --- a/src/pld/certus.c +++ b/src/pld/certus.c @@ -121,6 +121,7 @@ static int lattice_certus_enable_programming(struct jtag_tap *tap) uint8_t buffer = 0; field.num_bits = 8; field.out_value = &buffer; + field.in_value = NULL; jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); jtag_add_runtest(2, TAP_IDLE); return jtag_execute_queue(); diff --git a/src/rtos/rtos.c b/src/rtos/rtos.c index faf30bd6b..b5e8e9add 100644 --- a/src/rtos/rtos.c +++ b/src/rtos/rtos.c @@ -83,6 +83,7 @@ static void os_free(struct target *target) return; free(target->rtos->symbols); + rtos_free_threadlist(target->rtos); free(target->rtos); target->rtos = NULL; } diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 6f181b9ee..4bab5e5cf 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -95,6 +95,8 @@ struct gdb_connection { char *thread_list; /* flag to mask the output from gdb_log_callback() */ enum gdb_output_flag output_flag; + /* Unique index for this GDB connection. */ + unsigned int unique_index; }; #if 0 @@ -392,6 +394,7 @@ static void gdb_log_incoming_packet(struct connection *connection, char *packet) return; struct target *target = get_target_from_connection(connection); + struct gdb_connection *gdb_connection = connection->priv; /* Avoid dumping non-printable characters to the terminal */ const unsigned packet_len = strlen(packet); @@ -406,14 +409,15 @@ static void gdb_log_incoming_packet(struct connection *connection, char *packet) if (packet_prefix_printable) { const unsigned int prefix_len = colon - packet + 1; /* + 1 to include the ':' */ const unsigned int payload_len = packet_len - prefix_len; - LOG_TARGET_DEBUG(target, "received packet: %.*s", prefix_len, - packet, payload_len); + LOG_TARGET_DEBUG(target, "{%d} received packet: %.*s", + gdb_connection->unique_index, prefix_len, packet, payload_len); } else { - LOG_TARGET_DEBUG(target, "received packet: ", packet_len); + LOG_TARGET_DEBUG(target, "{%d} received packet: ", + gdb_connection->unique_index, packet_len); } } else { /* All chars printable, dump the packet as is */ - LOG_TARGET_DEBUG(target, "received packet: %s", packet); + LOG_TARGET_DEBUG(target, "{%d} received packet: %s", gdb_connection->unique_index, packet); } } @@ -424,13 +428,14 @@ static void gdb_log_outgoing_packet(struct connection *connection, char *packet_ return; struct target *target = get_target_from_connection(connection); + struct gdb_connection *gdb_connection = connection->priv; if (find_nonprint_char(packet_buf, packet_len)) - LOG_TARGET_DEBUG(target, "sending packet: $#%2.2x", - packet_len, checksum); + LOG_TARGET_DEBUG(target, "{%d} sending packet: $#%2.2x", + gdb_connection->unique_index, packet_len, checksum); else - LOG_TARGET_DEBUG(target, "sending packet: $%.*s#%2.2x", packet_len, packet_buf, - checksum); + LOG_TARGET_DEBUG(target, "{%d} sending packet: $%.*s#%2.2x", + gdb_connection->unique_index, packet_len, packet_buf, checksum); } static int gdb_put_packet_inner(struct connection *connection, @@ -1017,6 +1022,7 @@ static int gdb_new_connection(struct connection *connection) struct target *target; int retval; int initial_ack; + static unsigned int next_unique_id = 1; target = get_target_from_connection(connection); connection->priv = gdb_connection; @@ -1039,6 +1045,7 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->target_desc.tdesc_length = 0; gdb_connection->thread_list = NULL; gdb_connection->output_flag = GDB_OUTPUT_NO; + gdb_connection->unique_index = next_unique_id++; /* send ACK to GDB for debug request */ gdb_write(connection, "+", 1); @@ -1097,20 +1104,19 @@ static int gdb_new_connection(struct connection *connection) } } - gdb_actual_connections++; log_printf_lf(all_targets->next ? LOG_LVL_INFO : LOG_LVL_DEBUG, __FILE__, __LINE__, __func__, "New GDB Connection: %d, Target %s, state: %s", - gdb_actual_connections, + gdb_connection->unique_index, target_name(target), target_state_name(target)); if (!target_was_examined(target)) { LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!", - target_name(target), gdb_actual_connections); - gdb_actual_connections--; + target_name(target), gdb_connection->unique_index); return ERROR_TARGET_NOT_EXAMINED; } + gdb_actual_connections++; if (target->state != TARGET_HALTED) LOG_WARNING("GDB connection %d on target %s not halted", @@ -1141,7 +1147,8 @@ static int gdb_connection_closed(struct connection *connection) log_remove_callback(gdb_log_callback, connection); gdb_actual_connections--; - LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", + LOG_DEBUG("{%d} GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", + gdb_connection->unique_index, target_name(target), target_state_name(target), gdb_actual_connections); diff --git a/src/target/arc.c b/src/target/arc.c index 2ca6be16d..0f7b11025 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -1265,8 +1265,8 @@ static int arc_resume(struct target *target, int current, target_addr_t address, /* current = 1: continue on current PC, otherwise continue at
*/ if (!current) { target_buffer_set_u32(target, pc->value, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); } @@ -1281,7 +1281,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address, resume_pc, pc->dirty, pc->valid); /* check if GDB tells to set our PC where to continue from */ - if ((pc->valid == 1) && (resume_pc == target_buffer_get_u32(target, pc->value))) { + if (pc->valid && resume_pc == target_buffer_get_u32(target, pc->value)) { value = target_buffer_get_u32(target, pc->value); LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value)); @@ -1573,9 +1573,6 @@ static int arc_set_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return ERROR_OK; } @@ -1658,9 +1655,6 @@ static int arc_unset_breakpoint(struct target *target, return ERROR_FAIL; } - /* core instruction cache is now invalid. */ - CHECK_RETVAL(arc_cache_invalidate(target)); - return retval; } @@ -2013,8 +2007,8 @@ static int arc_step(struct target *target, int current, target_addr_t address, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { buf_set_u32(pc->value, 0, 32, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, diff --git a/src/target/arm.h b/src/target/arm.h index 28e533019..d5053afb8 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -61,6 +61,7 @@ enum arm_arch { /** Known ARM implementor IDs */ enum arm_implementor { ARM_IMPLEMENTOR_ARM = 0x41, + ARM_IMPLEMENTOR_INFINEON = 0x49, ARM_IMPLEMENTOR_REALTEK = 0x72, }; @@ -230,12 +231,22 @@ struct arm { uint32_t crn, uint32_t crm, uint32_t *value); + /** Read coprocessor to two registers. */ + int (*mrrc)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value); + /** Write coprocessor register. */ int (*mcr)(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value); + /** Write coprocessor from two registers. */ + int (*mcrr)(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value); + void *arch_info; /** For targets conforming to ARM Debug Interface v5, diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index ab9b50e23..9f3a444af 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -63,6 +63,29 @@ static int dpm_mrc(struct target *target, int cpnum, return retval; } +static int dpm_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t *value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MRRC p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read coprocessor register into R0, R1; return via DCC */ + retval = dpm->instr_read_data_r0_r1(dpm, + ARMV5_T_MRRC(cpnum, op, 0, 1, crm), + value); + + /* (void) */ dpm->finish(dpm); + return retval; +} + static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, uint32_t value) @@ -88,6 +111,29 @@ static int dpm_mcr(struct target *target, int cpnum, return retval; } +static int dpm_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, uint64_t value) +{ + struct arm *arm = target_to_arm(target); + struct arm_dpm *dpm = arm->dpm; + int retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("MCRR p%d, %d, r0, r1, c%d", cpnum, + (int)op, (int)crm); + + /* read DCC into r0, r1; then write coprocessor register from R0, R1 */ + retval = dpm->instr_write_data_r0_r1(dpm, + ARMV5_T_MCRR(cpnum, op, 0, 1, crm), value); + + /* (void) */ dpm->finish(dpm); + + return retval; +} + /*----------------------------------------------------------------------*/ /* @@ -1070,6 +1116,8 @@ int arm_dpm_setup(struct arm_dpm *dpm) /* coprocessor access setup */ arm->mrc = dpm_mrc; arm->mcr = dpm_mcr; + arm->mrrc = dpm_mrrc; + arm->mcrr = dpm_mcrr; /* breakpoint setup -- optional until it works everywhere */ if (!target->type->add_breakpoint) { diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index d35e9f68d..2da463111 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -72,6 +72,12 @@ struct arm_dpm { int (*instr_write_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t data); + /** + * Runs two instructions, writing data to R0 and R1 before execution. + */ + int (*instr_write_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data); + /** Runs one instruction, writing data to R0 before execution. */ int (*instr_write_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t data); @@ -92,6 +98,13 @@ struct arm_dpm { int (*instr_read_data_r0)(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data); + /** + * Runs two instructions, reading data from r0 and r1 after + * execution. + */ + int (*instr_read_data_r0_r1)(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data); + int (*instr_read_data_r0_64)(struct arm_dpm *dpm, uint32_t opcode, uint64_t *data); diff --git a/src/target/arm_opcodes.h b/src/target/arm_opcodes.h index c182f41c4..c8ce51f29 100644 --- a/src/target/arm_opcodes.h +++ b/src/target/arm_opcodes.h @@ -187,6 +187,17 @@ (0xee100010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to two ARM registers from coprocessor + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MRRC(cp, op, rt, rt2, crm) \ + (0xec500000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Move to coprocessor from ARM register * cp: Coprocessor number * op1: Coprocessor opcode @@ -199,6 +210,17 @@ (0xee000010 | (crm) | ((op2) << 5) | ((cp) << 8) \ | ((rd) << 12) | ((crn) << 16) | ((op1) << 21)) +/* Move to coprocessor from two ARM registers + * cp: Coprocessor number + * op: Coprocessor opcode + * rt: destination register 1 + * rt2: destination register 2 + * crm: coprocessor source register + */ +#define ARMV5_T_MCRR(cp, op, rt, rt2, crm) \ + (0xec400000 | (crm) | ((op) << 4) | ((cp) << 8) \ + | ((rt) << 12) | ((rt2) << 16)) + /* Breakpoint instruction (ARMv5) * im: 16-bit immediate */ diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 8e3f22417..7debb9498 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1093,6 +1093,94 @@ COMMAND_HANDLER(handle_armv4_5_mcrmrc) return ERROR_OK; } +COMMAND_HANDLER(handle_armv4_5_mcrrmrrc) +{ + bool is_mcrr = false; + unsigned int arg_cnt = 3; + + if (!strcmp(CMD_NAME, "mcrr")) { + is_mcrr = true; + arg_cnt = 4; + } + + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "no current target"); + return ERROR_FAIL; + } + if (!target_was_examined(target)) { + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; + } + + struct arm *arm = target_to_arm(target); + if (!is_arm(arm)) { + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; + } + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + int cpnum; + uint32_t op1; + uint32_t crm; + uint64_t value; + + /* NOTE: parameter sequence matches ARM instruction set usage: + * MCRR pNUM, op1, rX1, rX2, CRm ; write CP from rX1 and rX2 + * MREC pNUM, op1, rX1, rX2, CRm ; read CP into rX1 and rX2 + * The "rXn" are necessarily omitted; they use Tcl mechanisms. + */ + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0xf) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + /* + * FIXME change the call syntax here ... simplest to just pass + * the MRC() or MCR() instruction to be executed. That will also + * let us support the "mrrc2" and "mcrr2" opcodes (toggling one bit) + * if that's ever needed. + */ + if (is_mcrr) { + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[3], value); + + /* NOTE: parameters reordered! */ + /* ARMV5_T_MCRR(cpnum, op1, crm) */ + int retval = arm->mcrr(target, cpnum, op1, crm, value); + if (retval != ERROR_OK) + return retval; + } else { + value = 0; + /* NOTE: parameters reordered! */ + /* ARMV5_T_MRRC(cpnum, op1, crm) */ + int retval = arm->mrrc(target, cpnum, op1, crm, &value); + if (retval != ERROR_OK) + return retval; + + command_print(CMD, "0x%" PRIx64, value); + } + + return ERROR_OK; +} + static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", @@ -1115,6 +1203,20 @@ static const struct command_registration arm_exec_command_handlers[] = { .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, + { + .name = "mcrr", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "write coprocessor 64-bit register", + .usage = "cpnum op1 CRm value", + }, + { + .name = "mrrc", + .mode = COMMAND_EXEC, + .handler = handle_armv4_5_mcrrmrrc, + .help = "read coprocessor 64-bit register", + .usage = "cpnum op1 CRm", + }, { .chain = arm_all_profiles_command_handlers, }, @@ -1669,6 +1771,14 @@ static int arm_default_mrc(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mrrc(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t *value) +{ + LOG_ERROR("%s doesn't implement MRRC", target_type_name(target)); + return ERROR_FAIL; +} + static int arm_default_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t crn, uint32_t crm, @@ -1678,6 +1788,14 @@ static int arm_default_mcr(struct target *target, int cpnum, return ERROR_FAIL; } +static int arm_default_mcrr(struct target *target, int cpnum, + uint32_t op, uint32_t crm, + uint64_t value) +{ + LOG_ERROR("%s doesn't implement MCRR", target_type_name(target)); + return ERROR_FAIL; +} + int arm_init_arch_info(struct target *target, struct arm *arm) { target->arch_info = arm; @@ -1697,8 +1815,12 @@ int arm_init_arch_info(struct target *target, struct arm *arm) if (!arm->mrc) arm->mrc = arm_default_mrc; + if (!arm->mrrc) + arm->mrrc = arm_default_mrrc; if (!arm->mcr) arm->mcr = arm_default_mcr; + if (!arm->mcrr) + arm->mcrr = arm_default_mcrr; return ERROR_OK; } diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 9ba6b5453..552bcfa02 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -725,7 +725,8 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) } /** - * Read basic registers of the current context: R0 to R15, and CPSR; + * Read basic registers of the current context: R0 to R15, and CPSR in AArch32 + * state or R0 to R31, PC and CPSR in AArch64 state; * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb). * In normal operation this is called on entry to halting debug state, * possibly after some other operations supporting restore of debug state @@ -772,9 +773,15 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm) /* update core mode and state */ armv8_set_cpsr(arm, cpsr); - for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) { + /* read the remaining registers that would be required by GDB 'g' packet */ + for (unsigned int i = ARMV8_R2; i <= ARMV8_PC ; i++) { struct arm_reg *arm_reg; + /* in AArch32 skip AArch64 registers */ + /* TODO: this should be detected below through arm_reg->mode */ + if (arm->core_state != ARM_STATE_AARCH64 && i > ARMV8_R14 && i < ARMV8_PC) + continue; + r = armv8_reg_current(arm, i); if (!r->exist || r->valid) continue; diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 7d2a9da05..d069c6b0f 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -18,6 +18,11 @@ #include "rtos/rtos.h" #include "smp.h" +enum breakpoint_watchpoint { + BREAKPOINT, + WATCHPOINT, +}; + static const char * const breakpoint_type_strings[] = { "hardware", "software" @@ -418,26 +423,90 @@ int breakpoint_remove(struct target *target, target_addr_t address) return retval; } -int breakpoint_remove_all(struct target *target) +static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) { + struct watchpoint *watchpoint = target->watchpoints; + struct watchpoint **watchpoint_p = &target->watchpoints; + int retval; + + while (watchpoint) { + if (watchpoint == watchpoint_to_remove) + break; + watchpoint_p = &watchpoint->next; + watchpoint = watchpoint->next; + } + + if (!watchpoint) + return ERROR_WATCHPOINT_NOT_FOUND; + retval = target_remove_watchpoint(target, watchpoint); + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target", + watchpoint->number); + return retval; + } + + LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); + (*watchpoint_p) = watchpoint->next; + free(watchpoint); + + return ERROR_OK; +} + +static int watchpoint_remove_all_internal(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + int retval = ERROR_OK; + + while (watchpoint) { + struct watchpoint *tmp = watchpoint; + watchpoint = watchpoint->next; + int status = watchpoint_free(target, tmp); + if (status != ERROR_OK) + retval = status; + } + + return retval; +} + +static int breakpoint_watchpoint_remove_all(struct target *target, enum breakpoint_watchpoint bp_wp) +{ + assert(bp_wp == BREAKPOINT || bp_wp == WATCHPOINT); int retval = ERROR_OK; if (target->smp) { struct target_list *head; foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; - int status = breakpoint_remove_all_internal(curr); + + int status = ERROR_OK; + if (bp_wp == BREAKPOINT) + status = breakpoint_remove_all_internal(curr); + else + status = watchpoint_remove_all_internal(curr); if (status != ERROR_OK) retval = status; } } else { - retval = breakpoint_remove_all_internal(target); + if (bp_wp == BREAKPOINT) + retval = breakpoint_remove_all_internal(target); + else + retval = watchpoint_remove_all_internal(target); } return retval; } +int breakpoint_remove_all(struct target *target) +{ + return breakpoint_watchpoint_remove_all(target, BREAKPOINT); +} + +int watchpoint_remove_all(struct target *target) +{ + return breakpoint_watchpoint_remove_all(target, WATCHPOINT); +} + int breakpoint_clear_target(struct target *target) { int retval = ERROR_OK; @@ -562,35 +631,6 @@ int watchpoint_add(struct target *target, target_addr_t address, } } -static int watchpoint_free(struct target *target, struct watchpoint *watchpoint_to_remove) -{ - struct watchpoint *watchpoint = target->watchpoints; - struct watchpoint **watchpoint_p = &target->watchpoints; - int retval; - - while (watchpoint) { - if (watchpoint == watchpoint_to_remove) - break; - watchpoint_p = &watchpoint->next; - watchpoint = watchpoint->next; - } - - if (!watchpoint) - return ERROR_WATCHPOINT_NOT_FOUND; - retval = target_remove_watchpoint(target, watchpoint); - if (retval != ERROR_OK) { - LOG_TARGET_ERROR(target, "could not remove watchpoint #%d on this target", - watchpoint->number); - return retval; - } - - LOG_DEBUG("free WPID: %d --> %d", watchpoint->unique_id, retval); - (*watchpoint_p) = watchpoint->next; - free(watchpoint); - - return ERROR_OK; -} - static int watchpoint_remove_internal(struct target *target, target_addr_t address) { struct watchpoint *watchpoint = target->watchpoints; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 950283e35..0ec65de71 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -73,6 +73,7 @@ int watchpoint_add(struct target *target, target_addr_t address, uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask); int watchpoint_remove(struct target *target, target_addr_t address); +int watchpoint_remove_all(struct target *target); /* report type and address of just hit watchpoint */ int watchpoint_hit(struct target *target, enum watchpoint_rw *rw, diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index abfd6ac5f..ba3349d09 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -471,6 +471,28 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, return retval; } +static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data & 0xffffffffULL); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 1, data >> 32); + if (retval != ERROR_OK) + return retval; + + /* then the opcode, taking data from R0, R1 */ + retval = cortex_a_exec_opcode(a->armv7a_common.arm.target, + opcode, + &dscr); + return retval; +} + static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; @@ -539,6 +561,29 @@ static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); } +static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + uint32_t lo, hi; + int retval; + + /* the opcode, writing data to RO, R1 */ + retval = cortex_a_instr_read_data_r0(dpm, opcode, &lo); + if (retval != ERROR_OK) + return retval; + + *data = lo; + + /* write R1 to DCC */ + retval = cortex_a_instr_read_data_rt_dcc(dpm, 1, &hi); + if (retval != ERROR_OK) + return retval; + + *data |= (uint64_t)hi << 32; + + return retval; +} + static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, uint32_t addr, uint32_t control) { @@ -612,10 +657,12 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0; + dpm->instr_write_data_r0_r1 = cortex_a_instr_write_data_r0_r1; dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0; + dpm->instr_read_data_r0_r1 = cortex_a_instr_read_data_r0_r1; dpm->bpwp_enable = cortex_a_bpwp_enable; dpm->bpwp_disable = cortex_a_bpwp_disable; diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 854e8eb58..3eafee0a1 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -111,6 +111,11 @@ static const struct cortex_m_part_info cortex_m_parts[] = { .arch = ARM_ARCH_V8M, .flags = CORTEX_M_F_HAS_FPV5, }, + { + .impl_part = INFINEON_SLX2_PARTNO, + .name = "Infineon-SLx2", + .arch = ARM_ARCH_V8M, + }, { .impl_part = REALTEK_M200_PARTNO, .name = "Real-M200 (KM0)", diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index 065e4d47b..0bc139911 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -45,19 +45,20 @@ */ enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ - CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), - CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), - CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), - CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), - CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), - CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), - CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), - CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), - CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), - CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), - REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), - REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), + INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_INFINEON, 0xDB0), + REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), + REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ diff --git a/src/target/etm.c b/src/target/etm.c index 6718875ee..d083017f7 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -552,8 +552,8 @@ static int etm_set_reg(struct reg *reg, uint32_t value) } buf_set_u32(reg->value, 0, reg->size, value); - reg->valid = 1; - reg->dirty = 0; + reg->valid = true; + reg->dirty = false; return ERROR_OK; } diff --git a/src/target/image.c b/src/target/image.c index ad2d856b5..9175c200a 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -96,20 +96,22 @@ static int autodetect_image_type(struct image *image, const char *url) static int identify_image_type(struct image *image, const char *type_string, const char *url) { if (type_string) { - if (!strcmp(type_string, "bin")) + if (!strcmp(type_string, "bin")) { image->type = IMAGE_BINARY; - else if (!strcmp(type_string, "ihex")) + } else if (!strcmp(type_string, "ihex")) { image->type = IMAGE_IHEX; - else if (!strcmp(type_string, "elf")) + } else if (!strcmp(type_string, "elf")) { image->type = IMAGE_ELF; - else if (!strcmp(type_string, "mem")) + } else if (!strcmp(type_string, "mem")) { image->type = IMAGE_MEMORY; - else if (!strcmp(type_string, "s19")) + } else if (!strcmp(type_string, "s19")) { image->type = IMAGE_SRECORD; - else if (!strcmp(type_string, "build")) + } else if (!strcmp(type_string, "build")) { image->type = IMAGE_BUILDER; - else + } else { + LOG_ERROR("Unknown image type: %s, use one of: bin, ihex, elf, mem, s19, build", type_string); return ERROR_IMAGE_TYPE_UNKNOWN; + } } else return autodetect_image_type(image, url); @@ -966,12 +968,13 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_binary->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; + size_t filesize; retval = fileio_size(image_binary->fileio, &filesize); if (retval != ERROR_OK) { fileio_close(image_binary->fileio); - return retval; + goto free_mem_on_error; } image->num_sections = 1; @@ -986,14 +989,14 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_ihex->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_ihex_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering IHEX image, check server output for additional information"); fileio_close(image_ihex->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_ELF) { struct image_elf *image_elf; @@ -1002,12 +1005,12 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_elf->fileio, url, FILEIO_READ, FILEIO_BINARY); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_elf_read_headers(image); if (retval != ERROR_OK) { fileio_close(image_elf->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_MEMORY) { struct target *target = get_target(url); @@ -1037,14 +1040,14 @@ int image_open(struct image *image, const char *url, const char *type_string) retval = fileio_open(&image_mot->fileio, url, FILEIO_READ, FILEIO_TEXT); if (retval != ERROR_OK) - return retval; + goto free_mem_on_error; retval = image_mot_buffer_complete(image); if (retval != ERROR_OK) { LOG_ERROR( "failed buffering S19 image, check server output for additional information"); fileio_close(image_mot->fileio); - return retval; + goto free_mem_on_error; } } else if (image->type == IMAGE_BUILDER) { image->num_sections = 0; @@ -1065,6 +1068,11 @@ int image_open(struct image *image, const char *url, const char *type_string) } return retval; + +free_mem_on_error: + free(image->type_private); + image->type_private = NULL; + return retval; }; int image_read_section(struct image *image, diff --git a/src/target/mips32.c b/src/target/mips32.c index 4e6d25118..5c346c42d 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -27,7 +27,7 @@ static const char *mips_isa_strings[] = { "MIPS32", "MIPS16", "", "MICRO MIPS32", }; -#define MIPS32_GDB_DUMMY_FP_REG 1 +#define MIPS32_GDB_FP_REG 1 /* * GDB registers @@ -39,7 +39,7 @@ static const struct { enum reg_type type; const char *group; const char *feature; - int flag; + int size; } mips32_regs[] = { { 0, "r0", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 1, "r1", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, @@ -73,88 +73,93 @@ static const struct { { 29, "r29", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 30, "r30", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, { 31, "r31", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 32, "status", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 33, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 34, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 35, "badvaddr", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 36, "cause", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, - { 37, "pc", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 32, "lo", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, + { 33, "hi", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cpu", 0 }, - { 38, "f0", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 39, "f1", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 40, "f2", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 41, "f3", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 42, "f4", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 43, "f5", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 44, "f6", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 45, "f7", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 46, "f8", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 47, "f9", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 48, "f10", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 49, "f11", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 50, "f12", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 51, "f13", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 52, "f14", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 53, "f15", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 54, "f16", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 55, "f17", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 56, "f18", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 57, "f19", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 58, "f20", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 59, "f21", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 60, "f22", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 61, "f23", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 62, "f24", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 63, "f25", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 64, "f26", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 65, "f27", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 66, "f28", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 67, "f29", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 68, "f30", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 69, "f31", REG_TYPE_IEEE_SINGLE, NULL, - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 70, "fcsr", REG_TYPE_INT, "float", - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, - { 71, "fir", REG_TYPE_INT, "float", - "org.gnu.gdb.mips.fpu", MIPS32_GDB_DUMMY_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 0, "f0", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 1, "f1", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 2, "f2", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 3, "f3", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 4, "f4", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 5, "f5", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 6, "f6", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 7, "f7", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 8, "f8", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 9, "f9", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 10, "f10", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 11, "f11", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 12, "f12", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 13, "f13", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 14, "f14", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 15, "f15", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 16, "f16", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 17, "f17", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 18, "f18", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 19, "f19", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 20, "f20", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 21, "f21", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 22, "f22", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 23, "f23", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 24, "f24", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 25, "f25", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 26, "f26", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 27, "f27", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 28, "f28", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 29, "f29", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 30, "f30", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + { MIPS32_REGLIST_FP_INDEX + 31, "f31", REG_TYPE_IEEE_DOUBLE, NULL, + "org.gnu.gdb.mips.fpu", MIPS32_GDB_FP_REG }, + + { MIPS32_REGLIST_FPC_INDEX + 0, "fcsr", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + { MIPS32_REGLIST_FPC_INDEX + 1, "fir", REG_TYPE_INT, "float", + "org.gnu.gdb.mips.fpu", 0 }, + + { MIPS32_REGLIST_C0_STATUS_INDEX, "status", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_BADVADDR_INDEX, "badvaddr", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_CAUSE_INDEX, "cause", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, + { MIPS32_REGLIST_C0_PC_INDEX, "pc", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cpu", 0 }, + { MIPS32_REGLIST_C0_GUESTCTL1_INDEX, "guestCtl1", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.cp0", 0 }, }; - #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs) -static uint8_t mips32_gdb_dummy_fp_value[] = {0, 0, 0, 0}; - static int mips32_get_core_reg(struct reg *reg) { int retval; @@ -174,12 +179,21 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) { struct mips32_core_reg *mips32_reg = reg->arch_info; struct target *target = mips32_reg->target; - uint32_t value = buf_get_u32(buf, 0, 32); + uint64_t value; + + if (reg->size == 64) + value = buf_get_u64(buf, 0, 64); + else + value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - buf_set_u32(reg->value, 0, 32, value); + if (reg->size == 64) + buf_set_u64(reg->value, 0, 64, value); + else + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = true; reg->valid = true; @@ -188,7 +202,8 @@ static int mips32_set_core_reg(struct reg *reg, uint8_t *buf) static int mips32_read_core_reg(struct target *target, unsigned int num) { - uint32_t reg_value; + unsigned int cnum; + uint64_t reg_value = 0; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -196,17 +211,40 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; - reg_value = mips32->core_regs[num]; - buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + if (num >= MIPS32_REGLIST_C0_INDEX) { + /* CP0 */ + cnum = num - MIPS32_REGLIST_C0_INDEX; + reg_value = mips32->core_regs.cp0[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_FPC_INDEX) { + /* FPCR */ + cnum = num - MIPS32_REGLIST_FPC_INDEX; + reg_value = mips32->core_regs.fpcr[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_FP_INDEX) { + /* FPR */ + cnum = num - MIPS32_REGLIST_FP_INDEX; + reg_value = mips32->core_regs.fpr[cnum]; + buf_set_u64(mips32->core_cache->reg_list[num].value, 0, 64, reg_value); + } else { + /* GPR */ + cnum = num - MIPS32_REGLIST_GP_INDEX; + reg_value = mips32->core_regs.gpr[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } + mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; + LOG_DEBUG("read core reg %i value 0x%" PRIx64 "", num, reg_value); + return ERROR_OK; } static int mips32_write_core_reg(struct target *target, unsigned int num) { - uint32_t reg_value; + unsigned int cnum; + uint64_t reg_value; /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -214,9 +252,29 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; - reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); - mips32->core_regs[num] = reg_value; - LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num, reg_value); + if (num >= MIPS32_REGLIST_C0_INDEX) { + /* CP0 */ + cnum = num - MIPS32_REGLIST_C0_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.cp0[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_FPC_INDEX) { + /* FPCR */ + cnum = num - MIPS32_REGLIST_FPC_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.fpcr[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_FP_INDEX) { + /* FPR */ + cnum = num - MIPS32_REGLIST_FP_INDEX; + reg_value = buf_get_u64(mips32->core_cache->reg_list[num].value, 0, 64); + mips32->core_regs.fpr[cnum] = reg_value; + } else { + /* GPR */ + cnum = num - MIPS32_REGLIST_GP_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.gpr[cnum] = (uint32_t)reg_value; + } + + LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); mips32->core_cache->reg_list[num].valid = true; mips32->core_cache->reg_list[num].dirty = false; @@ -246,10 +304,13 @@ int mips32_save_context(struct target *target) /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); - struct mips_ejtag *ejtag_info = &mips32->ejtag_info; /* read core registers */ - mips32_pracc_read_regs(ejtag_info, mips32->core_regs); + int retval = mips32_pracc_read_regs(mips32); + if (retval != ERROR_OK) { + LOG_ERROR("Could not read core registers from target"); + return retval; + } for (i = 0; i < MIPS32_NUM_REGS; i++) { if (!mips32->core_cache->reg_list[i].valid) @@ -265,7 +326,6 @@ int mips32_restore_context(struct target *target) /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); - struct mips_ejtag *ejtag_info = &mips32->ejtag_info; for (i = 0; i < MIPS32_NUM_REGS; i++) { if (mips32->core_cache->reg_list[i].dirty) @@ -273,7 +333,7 @@ int mips32_restore_context(struct target *target) } /* write core regs */ - mips32_pracc_write_regs(ejtag_info, mips32->core_regs); + mips32_pracc_write_regs(mips32); return ERROR_OK; } @@ -285,7 +345,7 @@ int mips32_arch_state(struct target *target) LOG_USER("target halted in %s mode due to %s, pc: 0x%8.8" PRIx32 "", mips_isa_strings[mips32->isa_mode], debug_reason_name(target), - buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32)); return ERROR_OK; } @@ -322,25 +382,19 @@ struct reg_cache *mips32_build_reg_cache(struct target *target) arch_info[i].mips32_common = mips32; reg_list[i].name = mips32_regs[i].name; - reg_list[i].size = 32; + reg_list[i].size = mips32_regs[i].size ? 64 : 32; - if (mips32_regs[i].flag == MIPS32_GDB_DUMMY_FP_REG) { - reg_list[i].value = mips32_gdb_dummy_fp_value; - reg_list[i].valid = true; - reg_list[i].arch_info = NULL; - register_init_dummy(®_list[i]); - } else { - reg_list[i].value = calloc(1, 4); - reg_list[i].valid = false; - reg_list[i].type = &mips32_reg_type; - reg_list[i].arch_info = &arch_info[i]; + reg_list[i].value = mips32_regs[i].size ? calloc(1, 8) : calloc(1, 4); + reg_list[i].valid = false; + reg_list[i].type = &mips32_reg_type; + reg_list[i].arch_info = &arch_info[i]; + + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type->type = mips32_regs[i].type; + else + LOG_ERROR("unable to allocate reg type list"); - reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); - if (reg_list[i].reg_data_type) - reg_list[i].reg_data_type->type = mips32_regs[i].type; - else - LOG_ERROR("unable to allocate reg type list"); - } reg_list[i].dirty = false; @@ -407,7 +461,7 @@ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, return ERROR_TARGET_TIMEOUT; } - pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); + pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); return ERROR_TARGET_TIMEOUT; @@ -751,15 +805,82 @@ int mips32_cpu_probe(struct target *target) return ERROR_OK; } +/* reads dsp implementation info from CP0 Config3 register {DSPP, DSPREV}*/ +void mips32_read_config_dsp(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + uint32_t dsp_present = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPP_MASK) >> MIPS32_CONFIG3_DSPP_SHIFT); + if (dsp_present) { + mips32->dsp_imp = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPREV_MASK) >> MIPS32_CONFIG3_DSPREV_SHIFT) + 1; + LOG_USER("DSP implemented: %s, rev %d", "yes", mips32->dsp_imp); + } else { + LOG_USER("DSP implemented: %s", "no"); + } +} + +/* read fpu implementation info from CP0 Config1 register {CU1, FP}*/ +int mips32_read_config_fpu(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) +{ + int retval; + uint32_t fp_imp = (ejtag_info->config[1] & MIPS32_CONFIG1_FP_MASK) >> MIPS32_CONFIG1_FP_SHIFT; + char buf[60] = {0}; + if (!fp_imp) { + LOG_USER("FPU implemented: %s", "no"); + mips32->fp_imp = MIPS32_FP_IMP_NONE; + return ERROR_OK; + } + uint32_t status_value; + bool status_fr, status_cu1; + + retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp0 status register"); + return retval; + } + + status_fr = (status_value >> MIPS32_CP0_STATUS_FR_SHIFT) & 0x1; + status_cu1 = (status_value >> MIPS32_CP0_STATUS_CU1_SHIFT) & 0x1; + if (status_cu1) { + /* TODO: read fpu(cp1) config register for current operating mode. + * Now its set to 32 bits by default. */ + snprintf(buf, sizeof(buf), "yes"); + fp_imp = MIPS32_FP_IMP_32; + } else { + snprintf(buf, sizeof(buf), "yes, disabled"); + fp_imp = MIPS32_FP_IMP_UNKNOWN; + } + + mips32->fpu_in_64bit = status_fr; + mips32->fpu_enabled = status_cu1; + + LOG_USER("FPU implemented: %s", buf); + mips32->fp_imp = fp_imp; + + return ERROR_OK; +} + +/* Checks if current target implements Common Device Memory Map and therefore Fast Debug Channel (MD00090) */ +void mips32_read_config_fdc(struct mips32_common *mips32, struct mips_ejtag *ejtag_info, uint32_t dcr) +{ + if (((ejtag_info->config[3] & MIPS32_CONFIG3_CDMM_MASK) != 0) && ((dcr & EJTAG_DCR_FDC) != 0)) { + mips32->fdc = 1; + mips32->semihosting = 1; + } else { + mips32->fdc = 0; + mips32->semihosting = 0; + } +} + /* read config to config3 cp0 registers and log isa implementation */ int mips32_read_config_regs(struct target *target) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + char buf[60] = {0}; + int retval; if (ejtag_info->config_regs == 0) for (int i = 0; i != 4; i++) { - int retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); + retval = mips32_cp0_read(ejtag_info, &ejtag_info->config[i], 16, i); if (retval != ERROR_OK) { LOG_ERROR("isa info not available, failed to read cp0 config register: %" PRId32, i); ejtag_info->config_regs = 0; @@ -774,27 +895,56 @@ int mips32_read_config_regs(struct target *target) LOG_DEBUG("read %"PRIu32" config registers", ejtag_info->config_regs); + mips32->isa_rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; + snprintf(buf, sizeof(buf), ", release %s(AR=%d)", + mips32->isa_rel == MIPS32_RELEASE_1 ? "1" + : mips32->isa_rel == MIPS32_RELEASE_2 ? "2" + : mips32->isa_rel == MIPS32_RELEASE_6 ? "6" + : "unknown", mips32->isa_rel); + if (ejtag_info->impcode & EJTAG_IMP_MIPS16) { mips32->isa_imp = MIPS32_MIPS16; - LOG_USER("MIPS32 with MIPS16 support implemented"); - + LOG_USER("ISA implemented: %s%s", "MIPS32, MIPS16", buf); } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */ unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; if (isa_imp == 1) { mips32->isa_imp = MMIPS32_ONLY; - LOG_USER("MICRO MIPS32 only implemented"); + LOG_USER("ISA implemented: %s%s", "microMIPS32", buf); } else if (isa_imp != 0) { mips32->isa_imp = MIPS32_MMIPS32; - LOG_USER("MIPS32 and MICRO MIPS32 implemented"); + LOG_USER("ISA implemented: %s%s", "MIPS32, microMIPS32", buf); } + } else if (mips32->isa_imp == MIPS32_ONLY) { + /* initial default value */ + LOG_USER("ISA implemented: %s%s", "MIPS32", buf); } - if (mips32->isa_imp == MIPS32_ONLY) /* initial default value */ - LOG_USER("MIPS32 only implemented"); + /* Retrieve DSP info */ + mips32_read_config_dsp(mips32, ejtag_info); + + /* Retrieve if Float Point CoProcessor Implemented */ + retval = mips32_read_config_fpu(mips32, ejtag_info); + if (retval != ERROR_OK) { + LOG_ERROR("fpu info is not available, error while reading cp0 status"); + mips32->fp_imp = MIPS32_FP_IMP_NONE; + return retval; + } + + uint32_t dcr; + + retval = target_read_u32(target, EJTAG_DCR, &dcr); + if (retval != ERROR_OK) { + LOG_ERROR("failed to read EJTAG_DCR register"); + return retval; + } + + /* Determine if FDC and CDMM are implemented for this core */ + mips32_read_config_fdc(mips32, ejtag_info, dcr); return ERROR_OK; } + int mips32_checksum_memory(struct target *target, target_addr_t address, uint32_t count, uint32_t *checksum) { diff --git a/src/target/mips32.h b/src/target/mips32.h index 3d03e98c5..d072eb99a 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -46,9 +46,21 @@ #define MIPS32_CONFIG0_AR_SHIFT 10 #define MIPS32_CONFIG0_AR_MASK (0x7 << MIPS32_CONFIG0_AR_SHIFT) +#define MIPS32_CONFIG1_FP_SHIFT 0 +#define MIPS32_CONFIG1_FP_MASK BIT(MIPS32_CONFIG1_FP_SHIFT) + #define MIPS32_CONFIG1_DL_SHIFT 10 #define MIPS32_CONFIG1_DL_MASK (0x7 << MIPS32_CONFIG1_DL_SHIFT) +#define MIPS32_CONFIG3_CDMM_SHIFT 3 +#define MIPS32_CONFIG3_CDMM_MASK BIT(MIPS32_CONFIG3_CDMM_SHIFT) + +#define MIPS32_CONFIG3_DSPP_SHIFT 10 +#define MIPS32_CONFIG3_DSPP_MASK BIT(MIPS32_CONFIG3_DSPP_SHIFT) + +#define MIPS32_CONFIG3_DSPREV_SHIFT 11 +#define MIPS32_CONFIG3_DSPREV_MASK BIT(MIPS32_CONFIG3_DSPREV_SHIFT) + #define MIPS32_CONFIG3_ISA_SHIFT 14 #define MIPS32_CONFIG3_ISA_MASK (3 << MIPS32_CONFIG3_ISA_SHIFT) @@ -57,6 +69,141 @@ #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 +#define MIPS32_NUM_DSPREGS 9 + +/* Bit Mask indicating CP0 register supported by this core */ +#define MIPS_CP0_MK4 0x0001 +#define MIPS_CP0_MAPTIV_UC 0x0002 +#define MIPS_CP0_MAPTIV_UP 0x0004 +#define MIPS_CP0_IAPTIV 0x0008 + +/* CP0 Status register fields */ +#define MIPS32_CP0_STATUS_FR_SHIFT 26 +#define MIPS32_CP0_STATUS_CU1_SHIFT 29 + +/* CP1 FIR register fields */ +#define MIPS32_CP1_FIR_F64_SHIFT 22 + +static const struct { + unsigned int reg; + unsigned int sel; + const char *name; + const unsigned int core; +} mips32_cp0_regs[] = { + {0, 0, "index", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {0, 1, "mvpcontrol", MIPS_CP0_IAPTIV}, + {0, 2, "mvpconf0", MIPS_CP0_IAPTIV}, + {0, 3, "mvpconf1", MIPS_CP0_IAPTIV}, + {1, 0, "random", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {1, 1, "vpecontrol", MIPS_CP0_IAPTIV}, + {1, 2, "vpeconf0", MIPS_CP0_IAPTIV}, + {1, 3, "vpeconf1", MIPS_CP0_IAPTIV}, + {1, 4, "yqmask", MIPS_CP0_IAPTIV}, + {1, 5, "vpeschedule", MIPS_CP0_IAPTIV}, + {1, 6, "vpeschefback", MIPS_CP0_IAPTIV}, + {1, 7, "vpeopt", MIPS_CP0_IAPTIV}, + {2, 0, "entrylo0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {2, 1, "tcstatus", MIPS_CP0_IAPTIV}, + {2, 2, "tcbind", MIPS_CP0_IAPTIV}, + {2, 3, "tcrestart", MIPS_CP0_IAPTIV}, + {2, 4, "tchalt", MIPS_CP0_IAPTIV}, + {2, 5, "tccontext", MIPS_CP0_IAPTIV}, + {2, 6, "tcschedule", MIPS_CP0_IAPTIV}, + {2, 7, "tcschefback", MIPS_CP0_IAPTIV}, + {3, 0, "entrylo1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {3, 7, "tcopt", MIPS_CP0_IAPTIV}, + {4, 0, "context", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {4, 2, "userlocal", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {5, 0, "pagemask", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {5, 1, "pagegrain", MIPS_CP0_MAPTIV_UP}, + {5, 2, "segctl0", MIPS_CP0_IAPTIV}, + {5, 3, "segctl1", MIPS_CP0_IAPTIV}, + {5, 4, "segctl2", MIPS_CP0_IAPTIV}, + {6, 0, "wired", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {6, 1, "srsconf0", MIPS_CP0_IAPTIV}, + {6, 2, "srsconf1", MIPS_CP0_IAPTIV}, + {6, 3, "srsconf2", MIPS_CP0_IAPTIV}, + {6, 4, "srsconf3", MIPS_CP0_IAPTIV}, + {6, 5, "srsconf4", MIPS_CP0_IAPTIV}, + {7, 0, "hwrena", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {8, 0, "badvaddr", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {8, 1, "badinstr", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {8, 2, "badinstrp", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {9, 0, "count", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {10, 0, "entryhi", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP}, + {10, 4, "guestctl1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {10, 5, "guestctl2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {10, 6, "guestctl3", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {11, 0, "compare", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {11, 4, "guestctl0ext", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {12, 0, "status", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 1, "intctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 2, "srsctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 3, "srsmap", MIPS_CP0_IAPTIV}, + {12, 3, "srsmap1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {12, 4, "view_ipl", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {12, 5, "srsmap2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {12, 6, "guestctl0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {12, 7, "gtoffset", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MK4}, + {13, 0, "cause", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {13, 5, "nestedexc", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {14, 0, "epc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {14, 2, "nestedepc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 0, "prid", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 1, "ebase", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 2, "cdmmbase", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {15, 3, "cmgcrbase", MIPS_CP0_IAPTIV}, + {16, 0, "config", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 1, "config1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 2, "config2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 3, "config3", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 4, "config4", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 5, "config5", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {16, 7, "config7", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {17, 0, "lladdr", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {18, 0, "watchlo0", MIPS_CP0_IAPTIV}, + {18, 1, "watchlo1", MIPS_CP0_IAPTIV}, + {18, 2, "watchlo2", MIPS_CP0_IAPTIV}, + {18, 3, "watchlo3", MIPS_CP0_IAPTIV}, + {19, 0, "watchhi0", MIPS_CP0_IAPTIV}, + {19, 1, "watchhi1", MIPS_CP0_IAPTIV}, + {19, 2, "watchhi2", MIPS_CP0_IAPTIV}, + {19, 3, "watchhi3", MIPS_CP0_IAPTIV}, + {23, 0, "debug", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 1, "tracecontrol", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 2, "tracecontrol2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 3, "usertracedata1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 4, "tracebpc", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {23, 4, "traceibpc", MIPS_CP0_IAPTIV}, + {23, 5, "tracedbpc", MIPS_CP0_IAPTIV}, + {24, 0, "depc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {24, 2, "tracecontrol3", MIPS_CP0_IAPTIV}, + {24, 3, "usertracedata2", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 0, "perfctl0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 1, "perfcnt0", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 2, "perfctl1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {25, 3, "perfcnt1", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {26, 0, "errctl", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {27, 0, "cacheerr", MIPS_CP0_IAPTIV}, + {28, 0, "itaglo", MIPS_CP0_IAPTIV}, + {28, 0, "taglo", MIPS_CP0_IAPTIV}, + {28, 1, "idatalo", MIPS_CP0_IAPTIV}, + {28, 1, "datalo", MIPS_CP0_IAPTIV}, + {28, 2, "dtaglo", MIPS_CP0_IAPTIV}, + {28, 3, "ddatalo", MIPS_CP0_IAPTIV}, + {28, 4, "l23taglo", MIPS_CP0_IAPTIV}, + {28, 5, "l23datalo", MIPS_CP0_IAPTIV}, + {29, 1, "idatahi", MIPS_CP0_IAPTIV}, + {29, 2, "dtaghi", MIPS_CP0_IAPTIV}, + {29, 5, "l23datahi", MIPS_CP0_IAPTIV}, + {30, 0, "errorepc", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {31, 0, "desave", MIPS_CP0_IAPTIV | MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP | MIPS_CP0_MK4}, + {31, 2, "kscratch1", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, + {31, 3, "kscratch2", MIPS_CP0_MAPTIV_UC | MIPS_CP0_MAPTIV_UP}, +}; + +#define MIPS32NUMCP0REGS ((int)ARRAY_SIZE(mips32_cp0_regs)) + /* Insert extra NOPs after the DRET instruction on exit from debug. */ #define EJTAG_QUIRK_PAD_DRET BIT(0) @@ -67,6 +214,30 @@ enum { MIPS32NUMCOREREGS }; +/* offsets into mips32 core register cache */ + +#define MIPS32_REG_GP_COUNT 34 +#define MIPS32_REG_FP_COUNT 32 +#define MIPS32_REG_FPC_COUNT 2 +#define MIPS32_REG_C0_COUNT 5 + +#define MIPS32_REGLIST_GP_INDEX 0 +#define MIPS32_REGLIST_FP_INDEX (MIPS32_REGLIST_GP_INDEX + MIPS32_REG_GP_COUNT) +#define MIPS32_REGLIST_FPC_INDEX (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT) +#define MIPS32_REGLIST_C0_INDEX (MIPS32_REGLIST_FPC_INDEX + MIPS32_REG_FPC_COUNT) + +#define MIPS32_REGLIST_C0_STATUS_INDEX (MIPS32_REGLIST_C0_INDEX + 0) +#define MIPS32_REGLIST_C0_BADVADDR_INDEX (MIPS32_REGLIST_C0_INDEX + 1) +#define MIPS32_REGLIST_C0_CAUSE_INDEX (MIPS32_REGLIST_C0_INDEX + 2) +#define MIPS32_REGLIST_C0_PC_INDEX (MIPS32_REGLIST_C0_INDEX + 3) +#define MIPS32_REGLIST_C0_GUESTCTL1_INDEX (MIPS32_REGLIST_C0_INDEX + 4) + +#define MIPS32_REG_C0_STATUS_INDEX 0 +#define MIPS32_REG_C0_BADVADDR_INDEX 1 +#define MIPS32_REG_C0_CAUSE_INDEX 2 +#define MIPS32_REG_C0_PC_INDEX 3 +#define MIPS32_REG_C0_GUESTCTL1_INDEX 4 + enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, @@ -80,21 +251,67 @@ enum mips32_isa_imp { MIPS32_MMIPS32 = 3, }; +/* Release 2~5 does not have much change regarding to the ISA under User mode, +* therefore no new Architecture Revision(AR) level is assigned to them. +* Release 6 changed some instruction's encoding/mnemonic, removed instructions that +* has lost its purposes/none are using, and added some new instructions as well. +*/ +enum mips32_isa_rel { + MIPS32_RELEASE_1 = 0, + MIPS32_RELEASE_2 = 1, + MIPS32_RELEASE_6 = 2, + MIPS32_RELEASE_UNKNOWN, +}; + +enum mips32_fp_imp { + MIPS32_FP_IMP_NONE = 0, + MIPS32_FP_IMP_32 = 1, + MIPS32_FP_IMP_64 = 2, + MIPS32_FP_IMP_UNKNOWN = 3, +}; + +enum mips32_dsp_imp { + MIPS32_DSP_IMP_NONE = 0, + MIPS32_DSP_IMP_REV1 = 1, + MIPS32_DSP_IMP_REV2 = 2, +}; + struct mips32_comparator { int used; uint32_t bp_value; uint32_t reg_address; }; +struct mips32_core_regs { + uint32_t gpr[MIPS32_REG_GP_COUNT]; + uint64_t fpr[MIPS32_REG_FP_COUNT]; + uint32_t fpcr[MIPS32_REG_FPC_COUNT]; + uint32_t cp0[MIPS32_REG_C0_COUNT]; +}; + struct mips32_common { unsigned int common_magic; void *arch_info; struct reg_cache *core_cache; struct mips_ejtag ejtag_info; - uint32_t core_regs[MIPS32NUMCOREREGS]; + + struct mips32_core_regs core_regs; + enum mips32_isa_mode isa_mode; enum mips32_isa_imp isa_imp; + enum mips32_isa_rel isa_rel; + enum mips32_fp_imp fp_imp; + enum mips32_dsp_imp dsp_imp; + + int fdc; + int semihosting; + uint32_t cp0_mask; + + /* FPU enabled (cp0.status.cu1) */ + bool fpu_enabled; + /* FPU mode (cp0.status.fr) */ + bool fpu_in_64bit; /* processor identification register */ uint32_t prid; @@ -394,6 +611,173 @@ struct mips32_algorithm { #define MIPS16_SDBBP(isa) (isa ? MMIPS16_SDBBP : MIPS16_ISA_SDBBP) +/* + * MIPS32 Config1 Register (CP0 Register 16, Select 1) + */ +#define MIPS32_CFG1_M 0x80000000 /* Config2 implemented */ +#define MIPS32_CFG1_MMUSMASK 0x7e000000 /* mmu size - 1 */ +#define MIPS32_CFG1_MMUSSHIFT 25 +#define MIPS32_CFG1_ISMASK 0x01c00000 /* icache lines 64<ejtag_info; struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + uint32_t *gprs = mips32->core_regs.gpr; + uint32_t *c0rs = mips32->core_regs.cp0; + pracc_queue_init(&ctx); uint32_t cp0_write_code[] = { @@ -837,66 +841,178 @@ int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) MIPS32_MTC0(ctx.isa, 1, 24, 0), /* move $1 to depc (pc) */ }; + uint32_t cp0_write_data[] = { + /* lo */ + gprs[32], + /* hi */ + gprs[33], + /* status */ + c0rs[0], + /* badvaddr */ + c0rs[1], + /* cause */ + c0rs[2], + /* depc (pc) */ + c0rs[3], + }; + + for (size_t i = 0; i < ARRAY_SIZE(cp0_write_code); i++) { + /* load CP0 value in $1 */ + pracc_add_li32(&ctx, 1, cp0_write_data[i], 0); + /* write value from $1 to CP0 register */ + pracc_add(&ctx, 0, cp0_write_code[i]); + } + /* load registers 2 to 31 with li32, optimize */ for (int i = 2; i < 32; i++) - pracc_add_li32(&ctx, i, regs[i], 1); + pracc_add_li32(&ctx, i, gprs[i], 1); - for (int i = 0; i != 6; i++) { - pracc_add_li32(&ctx, 1, regs[i + 32], 0); /* load CPO value in $1 */ - pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */ - } - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((regs[1])))); /* load upper half word in $1 */ - pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */ + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + /* load upper half word in $1 */ + pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, UPPER16((gprs[1])))); + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load lower half word in $1 */ + pracc_add(&ctx, 0, MIPS32_ORI(ctx.isa, 1, 1, LOWER16((gprs[1])))); ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); - ejtag_info->reg8 = regs[8]; - ejtag_info->reg9 = regs[9]; + ejtag_info->reg8 = gprs[8]; + ejtag_info->reg9 = gprs[9]; pracc_queue_free(&ctx); return ctx.retval; } -int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs) +/* Saves content in `$1` to `DeSave(cp0.31.0)` and loads `MIPS32_PRACC_BASE_ADDR` into `$1` */ +static void mips32_pracc_store_regs_set_base_addr(struct pracc_queue_info *ctx) { - struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; - pracc_queue_init(&ctx); + /* move $1 to COP0 DeSave */ + pracc_add(ctx, 0, MIPS32_MTC0(ctx->isa, 1, 31, 0)); + /* $1 = MIP32_PRACC_BASE_ADDR */ + pracc_add(ctx, 0, MIPS32_LUI(ctx->isa, 1, PRACC_UPPER_BASE_ADDR)); +} - uint32_t cp0_read_code[] = { - MIPS32_MFC0(ctx.isa, 8, 12, 0), /* move status to $8 */ - MIPS32_MFLO(ctx.isa, 8), /* move lo to $8 */ - MIPS32_MFHI(ctx.isa, 8), /* move hi to $8 */ - MIPS32_MFC0(ctx.isa, 8, 8, 0), /* move badvaddr to $8 */ - MIPS32_MFC0(ctx.isa, 8, 13, 0), /* move cause to $8 */ - MIPS32_MFC0(ctx.isa, 8, 24, 0), /* move depc (pc) to $8 */ +/* This function assumes the address for saving is stored in `$1`. + * And that action is performed in `mips32_pracc_set_save_base_addr`. + */ +static void mips32_pracc_store_regs_gpr(struct pracc_queue_info *ctx, unsigned int offset_gpr) +{ + for (int i = 2; i != 32; i++) + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + offset_gpr + (i * 4), + MIPS32_SW(ctx->isa, i, PRACC_OUT_OFFSET + offset_gpr + (i * 4), 1)); +} + +static void mips32_pracc_store_regs_lohi(struct pracc_queue_info *ctx) +{ + uint32_t lohi_read_code[] = { + MIPS32_MFLO(ctx->isa, 8), /* move lo to $8 */ + MIPS32_MFHI(ctx->isa, 8), /* move hi to $8 */ }; - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 1, 31, 0)); /* move $1 to COP0 DeSave */ - pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */ - - for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), - MIPS32_SW(ctx.isa, i, PRACC_OUT_OFFSET + (i * 4), 1)); - - for (int i = 0; i != 6; i++) { - pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */ - MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); + /* store lo & hi */ + for (int i = 0; i < 2; i++) { + /* load COP0 needed registers to $8 */ + pracc_add(ctx, 0, lohi_read_code[i]); + /* store $8 at PARAM OUT */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + (i + 32) * 4, 1)); } - pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 8, 31, 0)); /* move DeSave to $8, reg1 value */ - pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */ - MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + 4, 1)); +} - pracc_add(&ctx, 0, MIPS32_MFC0(ctx.isa, 1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */ - pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); /* jump to start */ - pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); /* load $15 in DeSave */ +/* Saves CP0 registers [status, badvaddr, cause, depc] */ +static void mips32_pracc_store_regs_cp0_context(struct pracc_queue_info *ctx, unsigned int offset_cp0) +{ + uint32_t cp0_read_code[] = { + MIPS32_MFC0(ctx->isa, 8, 12, 0), /* move status to $8 */ + MIPS32_MFC0(ctx->isa, 8, 8, 0), /* move badvaddr to $8 */ + MIPS32_MFC0(ctx->isa, 8, 13, 0), /* move cause to $8 */ + MIPS32_MFC0(ctx->isa, 8, 24, 0), /* move depc (pc) to $8 */ + }; - ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1); + /* store cp0 */ + for (size_t i = 0; i < ARRAY_SIZE(cp0_read_code); i++) { + size_t offset = offset_cp0 + (i * 4); + + /* load COP0 needed registers to $8 */ + pracc_add(ctx, 0, cp0_read_code[i]); + /* store $8 at PARAM OUT */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + offset, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + offset, 1)); + } +} + +/* Loads original content of $1 into $8, + * then store it to the batch data access address. + * Finally it restores $1 from DeSave. + */ +static void mips32_pracc_store_regs_restore(struct pracc_queue_info *ctx) +{ + /* move DeSave to $8, reg1 value */ + pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 8, 31, 0)); + /* store reg1 value from $8 to param out */ + pracc_add(ctx, MIPS32_PRACC_PARAM_OUT + 4, + MIPS32_SW(ctx->isa, 8, PRACC_OUT_OFFSET + 4, 1)); + + /* move COP0 DeSave to $1, restore reg1 */ + pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 1, 31, 0)); +} + +/* This function performs following actions: + * Saves `$1` to `DeSave`, + * then load `PRACC_UPPER_BASE_ADDR` for saving the register data structure into `$1`, + * Saves `$2` ~ `$31` to `PRACC_UPPER_BASE_ADDR + offset_gpr` + * Saves HI and LO, + * Saves necessary cp0 registers. +*/ +static void mips32_pracc_store_regs(struct pracc_queue_info *ctx, + unsigned int offset_gpr, unsigned int offset_cp0) +{ + mips32_pracc_store_regs_set_base_addr(ctx); + mips32_pracc_store_regs_gpr(ctx, offset_gpr); + mips32_pracc_store_regs_lohi(ctx); + mips32_pracc_store_regs_cp0_context(ctx, offset_cp0); + mips32_pracc_store_regs_restore(ctx); +} + +int mips32_pracc_read_regs(struct mips32_common *mips32) +{ + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + struct pracc_queue_info ctx = {.ejtag_info = ejtag_info}; + struct mips32_core_regs *core_regs = &mips32->core_regs; + unsigned int offset_gpr = ((uint8_t *)&core_regs->gpr[0]) - (uint8_t *)core_regs; + unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs; + + /* + * This procedure has to be in 2 distinctive steps, because we can + * only know whether FP is enabled after reading CP0. + * + * Step 1: Read everything except CP1 stuff + * Step 2: Read CP1 stuff if FP is implemented + */ + + pracc_queue_init(&ctx); + + mips32_pracc_store_regs(&ctx, offset_gpr, offset_cp0); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1); - ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */ - ejtag_info->reg9 = regs[9]; pracc_queue_free(&ctx); + + /* reg8 is saved but not restored, next called function should restore it */ + ejtag_info->reg8 = mips32->core_regs.gpr[8]; + ejtag_info->reg9 = mips32->core_regs.gpr[9]; + + /* we only care if FP is actually impl'd and if cp1 is enabled */ + /* since we already read cp0 in the prev step */ + /* now we know what's in cp0.status */ + /* TODO: Read FPRs */ + return ctx.retval; } diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index 1b0076867..587a44691 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -36,6 +36,8 @@ #define PRACC_BLOCK 128 /* 1 Kbyte */ +struct mips32_common; + struct pa_list { uint32_t instr; uint32_t addr; @@ -64,8 +66,8 @@ int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, int write_t, uint32_t addr, int count, uint32_t *buf); -int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); -int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs); +int mips32_pracc_read_regs(struct mips32_common *mips32); +int mips32_pracc_write_regs(struct mips32_common *mips32); /** * \b mips32_cp0_read diff --git a/src/target/mips64.c b/src/target/mips64.c index 37f36855c..48f4563dc 100644 --- a/src/target/mips64.c +++ b/src/target/mips64.c @@ -247,8 +247,8 @@ static int mips64_set_core_reg(struct reg *reg, uint8_t *buf) return ERROR_TARGET_NOT_HALTED; buf_set_u64(reg->value, 0, 64, value); - reg->dirty = 1; - reg->valid = 1; + reg->dirty = true; + reg->valid = true; return ERROR_OK; } @@ -265,8 +265,8 @@ static int mips64_read_core_reg(struct target *target, int num) reg_value = mips64->core_regs[num]; buf_set_u64(mips64->core_cache->reg_list[num].value, 0, 64, reg_value); - mips64->core_cache->reg_list[num].valid = 1; - mips64->core_cache->reg_list[num].dirty = 0; + mips64->core_cache->reg_list[num].valid = true; + mips64->core_cache->reg_list[num].dirty = false; return ERROR_OK; } @@ -284,8 +284,8 @@ static int mips64_write_core_reg(struct target *target, int num) reg_value = buf_get_u64(mips64->core_cache->reg_list[num].value, 0, 64); mips64->core_regs[num] = reg_value; LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, reg_value); - mips64->core_cache->reg_list[num].valid = 1; - mips64->core_cache->reg_list[num].dirty = 0; + mips64->core_cache->reg_list[num].valid = true; + mips64->core_cache->reg_list[num].dirty = false; return ERROR_OK; } @@ -297,8 +297,8 @@ int mips64_invalidate_core_regs(struct target *target) unsigned int i; for (i = 0; i < mips64->core_cache->num_regs; i++) { - mips64->core_cache->reg_list[i].valid = 0; - mips64->core_cache->reg_list[i].dirty = 0; + mips64->core_cache->reg_list[i].valid = false; + mips64->core_cache->reg_list[i].dirty = false; } return ERROR_OK; diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index eb80742d6..852444a51 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -123,11 +123,12 @@ /* Debug Control Register DCR */ #define EJTAG_DCR 0xFF300000 -#define EJTAG_DCR_ENM (1 << 29) -#define EJTAG_DCR_DB (1 << 17) -#define EJTAG_DCR_IB (1 << 16) -#define EJTAG_DCR_INTE (1 << 4) -#define EJTAG_DCR_MP (1 << 2) +#define EJTAG_DCR_ENM BIT(29) +#define EJTAG_DCR_FDC BIT(18) +#define EJTAG_DCR_DB BIT(17) +#define EJTAG_DCR_IB BIT(16) +#define EJTAG_DCR_INTE BIT(4) +#define EJTAG_DCR_MP BIT(2) /* breakpoint support */ /* EJTAG_V20_* was tested on Broadcom BCM7401 diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index 46d241cb3..0a06bb160 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -108,11 +108,11 @@ static int mips_m4k_debug_entry(struct target *target) mips32->isa_mode = MIPS32_ISA_MIPS32; /* other than mips32 only and isa bit set ? */ - if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1)) + if (mips32->isa_imp && buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1)) mips32->isa_mode = mips32->isa_imp == 2 ? MIPS32_ISA_MIPS16E : MIPS32_ISA_MMIPS32; LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", - buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32), + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32), target_state_name(target)); return ERROR_OK; @@ -443,18 +443,18 @@ static int mips_m4k_internal_restore(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); - buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); - mips32->core_cache->reg_list[MIPS32_PC].dirty = true; - mips32->core_cache->reg_list[MIPS32_PC].valid = true; + buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address); + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = true; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true; } if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */ - buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 1, mips32->isa_mode); + buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1, mips32->isa_mode); if (!current) resume_pc = address; else - resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32); + resume_pc = buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32); mips32_restore_context(target); @@ -537,15 +537,15 @@ static int mips_m4k_step(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); - buf_set_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32, address); - mips32->core_cache->reg_list[MIPS32_PC].dirty = true; - mips32->core_cache->reg_list[MIPS32_PC].valid = true; + buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address); + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].dirty = true; + mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true; } /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) { breakpoint = breakpoint_find(target, - buf_get_u32(mips32->core_cache->reg_list[MIPS32_PC].value, 0, 32)); + buf_get_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32)); if (breakpoint) mips_m4k_unset_breakpoint(target, breakpoint); } diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index bf6095358..9921e9380 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -625,8 +625,8 @@ static int mips_mips64_resume(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ if (!current) { buf_set_u64(pc->value, 0, 64, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } resume_pc = buf_get_u64(pc->value, 0, 64); @@ -717,8 +717,8 @@ static int mips_mips64_step(struct target *target, int current, *
*/ if (!current) { buf_set_u64(pc->value, 0, 64, address); - pc->dirty = 1; - pc->valid = 1; + pc->dirty = true; + pc->valid = true; } /* the front-end may request us not to handle breakpoints */ diff --git a/src/target/target.c b/src/target/target.c index 167b1ea5d..cfd06411a 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3053,6 +3053,10 @@ COMMAND_HANDLER(handle_reg_command) LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_TARGET_NOT_EXAMINED; + } struct reg *reg = NULL; /* list all available registers for the current target */ @@ -3117,7 +3121,7 @@ COMMAND_HANDLER(handle_reg_command) if (!reg) { command_print(CMD, "%i is out of bounds, the current target " "has only %i registers (0 - %i)", num, count, count - 1); - return ERROR_OK; + return ERROR_FAIL; } } else { /* access a single register by its name */ @@ -3136,9 +3140,9 @@ COMMAND_HANDLER(handle_reg_command) if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { if ((CMD_ARGC == 2) && (strcmp(CMD_ARGV[1], "force") == 0)) - reg->valid = 0; + reg->valid = false; - if (reg->valid == 0) { + if (!reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { LOG_ERROR("Could not read register '%s'", reg->name); @@ -3176,7 +3180,7 @@ COMMAND_HANDLER(handle_reg_command) not_found: command_print(CMD, "register %s not found in current target", CMD_ARGV[0]); - return ERROR_OK; + return ERROR_FAIL; } COMMAND_HANDLER(handle_poll_command) @@ -4071,13 +4075,14 @@ COMMAND_HANDLER(handle_wp_command) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { + char wp_type = (watchpoint->rw == WPT_READ ? 'r' : (watchpoint->rw == WPT_WRITE ? 'w' : 'a')); command_print(CMD, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 - ", r/w/a: %i, value: 0x%8.8" PRIx64 + ", r/w/a: %c, value: 0x%8.8" PRIx64 ", mask: 0x%8.8" PRIx64, watchpoint->address, watchpoint->length, - (int)watchpoint->rw, + wp_type, watchpoint->value, watchpoint->mask); watchpoint = watchpoint->next; @@ -4138,17 +4143,28 @@ COMMAND_HANDLER(handle_wp_command) COMMAND_HANDLER(handle_rwp_command) { + int retval; + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - target_addr_t addr; - COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - struct target *target = get_current_target(CMD_CTX); - int retval = watchpoint_remove(target, addr); + if (!strcmp(CMD_ARGV[0], "all")) { + retval = watchpoint_remove_all(target); - if (retval != ERROR_OK) - command_print(CMD, "Error during removal of watchpoint at address " TARGET_ADDR_FMT, addr); + if (retval != ERROR_OK) { + command_print(CMD, "Error encountered during removal of all watchpoints."); + command_print(CMD, "Some watchpoints may have remained set."); + } + } else { + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); + + retval = watchpoint_remove(target, addr); + + if (retval != ERROR_OK) + command_print(CMD, "Error during removal of watchpoint at address " TARGET_ADDR_FMT, addr); + } return retval; } @@ -5135,7 +5151,7 @@ static int target_jim_get_reg(Jim_Interp *interp, int argc, return JIM_ERR; } - if (force) { + if (force || !reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { @@ -5860,6 +5876,18 @@ COMMAND_HANDLER(handle_target_current_state) return ERROR_OK; } +COMMAND_HANDLER(handle_target_debug_reason) +{ + if (CMD_ARGC != 0) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct target *target = get_current_target(CMD_CTX); + + command_print(CMD, "%s", debug_reason_name(target)); + + return ERROR_OK; +} + static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct jim_getopt_info goi; @@ -6011,6 +6039,13 @@ static const struct command_registration target_instance_command_handlers[] = { .help = "displays the current state of this target", .usage = "", }, + { + .name = "debug_reason", + .mode = COMMAND_EXEC, + .handler = handle_target_debug_reason, + .help = "displays the debug reason of this target", + .usage = "", + }, { .name = "arp_examine", .mode = COMMAND_EXEC, @@ -6110,7 +6145,7 @@ static int target_create(struct jim_getopt_info *goi) if (e != JIM_OK) return e; struct transport *tr = get_current_transport(); - if (tr->override_target) { + if (tr && tr->override_target) { e = tr->override_target(&cp); if (e != ERROR_OK) { LOG_ERROR("The selected transport doesn't support this target"); @@ -7067,7 +7102,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_rwp_command, .mode = COMMAND_EXEC, .help = "remove watchpoint", - .usage = "address", + .usage = "'all' | address", }, { .name = "load_image", diff --git a/tcl/board/advantech_imx8qm_dmsse20.cfg b/tcl/board/advantech_imx8qm_dmsse20.cfg new file mode 100644 index 000000000..a867b2de0 --- /dev/null +++ b/tcl/board/advantech_imx8qm_dmsse20.cfg @@ -0,0 +1,23 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# configuration file for Advantech IMX8QM DMSSE20 +# + +# only JTAG supported +transport select jtag + +# set a safe JTAG clock speed, can be overridden +adapter speed 1000 + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 70 + +# board has an i.MX8QM with 4 Cortex-A53 cores and 2 Cortex-A72 +set CHIPNAME imx8qm +set CHIPCORES 6 + +# source SoC configuration +source [find tcl/target/imx8qm.cfg] diff --git a/tcl/board/ti_am243_launchpad.cfg b/tcl/board/ti_am243_launchpad.cfg new file mode 100644 index 000000000..aa75dda88 --- /dev/null +++ b/tcl/board/ti_am243_launchpad.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM243 Launchpad +# https://www.ti.com/tool/LP-AM243 +# + +# AM243 Launchpad has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am243 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am263_launchpad.cfg b/tcl/board/ti_am263_launchpad.cfg new file mode 100644 index 000000000..a07a21b3d --- /dev/null +++ b/tcl/board/ti_am263_launchpad.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM263 Launchpad +# https://www.ti.com/tool/LP-AM263 +# + +# AM263 Launchpad has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am263 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/board/ti_am273_launchpad.cfg b/tcl/board/ti_am273_launchpad.cfg new file mode 100644 index 000000000..c17170bf1 --- /dev/null +++ b/tcl/board/ti_am273_launchpad.cfg @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/ +# +# Texas Instruments AM273 Launchpad +# https://www.ti.com/tool/LP-AM273 +# + +# AM273 Launchpad has an xds110 onboard. +source [find interface/xds110.cfg] + +transport select jtag + +# default JTAG configuration has only SRST and no TRST +reset_config srst_only srst_push_pull + +# delay after SRST goes inactive +adapter srst delay 20 + +if { ![info exists SOC] } { + set SOC am273 +} + +source [find target/ti_k3.cfg] + +adapter speed 250 diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index 2539be049..0c82c5758 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -5,6 +5,7 @@ # source [find target/swj-dp.tcl] +source [find mem_helper.tcl] if { [info exists CHIPNAME] } { set _CHIPNAME $CHIPNAME @@ -116,3 +117,51 @@ proc nrf52_recover {} { } add_help_text nrf52_recover "Mass erase and unlock nRF52 device" + +tpiu create $_CHIPNAME.tpiu -dap $_CHIPNAME.dap -ap-num 0 -baseaddr 0xE0040000 + +lappend _telnet_autocomplete_skip _proc_pre_enable_$_CHIPNAME.tpiu +proc _proc_pre_enable_$_CHIPNAME.tpiu {_targetname _chipname} { + targets $_targetname + + # Read FICR.INFO.PART + set PART [mrw 0x10000100] + + switch $PART { + 0x52840 - + 0x52833 - + 0x52832 { + if { [$_chipname.tpiu cget -protocol] eq "sync" } { + if { [$_chipname.tpiu cget -port-width] != 4 } { + echo "Error. Device only supports 4-bit sync traces." + return + } + + # Set TRACECONFIG.TRACEMUX to enable synchronous trace + mmw 0x4000055C 0x00020000 0x00010000 + $_targetname configure -event reset-end { + mmw 0x4000055C 0x00020000 0x00010000 + } + } else { + # Set TRACECONFIG.TRACEMUX to enable SWO + mmw 0x4000055C 0x00010000 0x00020000 + $_targetname configure -event reset-end { + mmw 0x4000055C 0x00010000 0x00020000 + } + } + } + 0x52820 - + 0x52811 - + 0x52810 - + 0x52805 { + echo "Error: Device does not support TPIU" + return + } + default { + echo "Error: Unknown device" + return + } + } +} + +$_CHIPNAME.tpiu configure -event pre-enable "_proc_pre_enable_$_CHIPNAME.tpiu $_TARGETNAME $_CHIPNAME" diff --git a/tcl/target/ti_k3.cfg b/tcl/target/ti_k3.cfg index 01e11c69f..23825b86b 100644 --- a/tcl/target/ti_k3.cfg +++ b/tcl/target/ti_k3.cfg @@ -2,24 +2,30 @@ # Copyright (C) 2019-2021 Texas Instruments Incorporated - http://www.ti.com/ # # Texas Instruments K3 devices: +# * AM243: https://www.ti.com/lit/pdf/spruim2 +# Has 4 R5 Cores, M4F and an M3 +# * AM263: https://www.ti.com/lit/pdf/spruj17 +# Has 4 R5 Cores and an M3 +# * AM273: https://www.ti.com/lit/pdf/spruiu0 +# Has 2 R5 Cores and an M3 +# * AM625: https://www.ti.com/lit/pdf/spruiv7a +# Has 4 ARMV8 Cores and 1 R5 Core and an M4F +# * AM62A7: https://www.ti.com/lit/pdf/spruj16a +# Has 4 ARMV8 Cores and 2 R5 Cores +# * AM62P: https://www.ti.com/lit/pdf/spruj83 +# Has 4 ARMV8 Cores and 2 R5 Cores +# * AM642: https://www.ti.com/lit/pdf/spruim2 +# Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 # * AM654x: https://www.ti.com/lit/pdf/spruid7 # Has 4 ARMV8 Cores and 2 R5 Cores and an M3 -# * J721E: https://www.ti.com/lit/pdf/spruil1 -# Has 2 ARMV8 Cores and 6 R5 Cores and an M3 # * J7200: https://www.ti.com/lit/pdf/spruiu1 # Has 2 ARMV8 Cores and 4 R5 Cores and an M3 +# * J721E: https://www.ti.com/lit/pdf/spruil1 +# Has 2 ARMV8 Cores and 6 R5 Cores and an M3 # * J721S2: https://www.ti.com/lit/pdf/spruj28 # Has 2 ARMV8 Cores and 6 R5 Cores and an M4F # * J784S4/AM69: http://www.ti.com/lit/zip/spruj52 # Has 8 ARMV8 Cores and 8 R5 Cores -# * AM642: https://www.ti.com/lit/pdf/spruim2 -# Has 2 ARMV8 Cores and 4 R5 Cores, M4F and an M3 -# * AM625: https://www.ti.com/lit/pdf/spruiv7a -# Has 4 ARMV8 Cores and 1 R5 Core and an M4F -# * AM62a7: https://www.ti.com/lit/pdf/spruj16a -# Has 4 ARMV8 Cores and 2 R5 Cores -# * AM62P: https://www.ti.com/lit/pdf/spruj83 -# Has 4 ARMV8 Cores and 2 R5 Cores # source [find target/swj-dp.tcl] @@ -44,6 +50,7 @@ set CM3_CTIBASE {0x3C016000} # sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x44} +set _sysctrl_ap_num 7 # All the ARMV8s are the next processors. # CL0,CORE0 CL0,CORE1 CL1,CORE0 CL1,CORE1 @@ -55,6 +62,7 @@ set ARMV8_CTIBASE {0x90420000 0x90520000 0x90820000 0x90920000} set R5_DBGBASE {0x9d010000 0x9d012000 0x9d410000 0x9d412000 0x9d510000 0x9d512000} set R5_CTIBASE {0x9d018000 0x9d019000 0x9d418000 0x9d419000 0x9d518000 0x9d519000} set R5_NAMES {mcu_r5.0 mcu_r5.1 main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} +set _r5_ap_num 1 # Finally an General Purpose(GP) MCU set CM4_CTIBASE {0x20001000} @@ -64,8 +72,46 @@ set _gp_mcu_cores 0 # General Purpose MCU power-ap unlock offsets set _gp_mcu_ap_unlock_offsets {0xf0 0x60} +# Generic mem-ap port number +set _mem_ap_num 2 + # Set configuration overrides for each SOC switch $_soc { + am263 { + set _K3_DAP_TAPID 0x2bb7d02f + + # Mem-ap port + set _mem_ap_num 6 + + # AM263 has 0 ARMV8 CPUs + set _armv8_cores 0 + + # AM263 has 2 cluster of 2 R5s cores. + set _r5_cores 4 + set R5_NAMES {main0_r5.0 main0_r5.1 main1_r5.0 main1_r5.1} + set R5_DBGBASE {0x90030000 0x90032000 0x90050000 0x90052000} + set R5_CTIBASE {0x90038000 0x90039000 0x90058000 0x90059000} + set _r5_ap_num 5 + } + am273 { + set _K3_DAP_TAPID 0x1bb6a02f + + # Mem-ap port + set _mem_ap_num 6 + + # system controller is on AP0 + set _sysctrl_ap_num 0 + + # AM273 has 0 ARMV8 CPUs + set _armv8_cores 0 + + # AM273 has 1 cluster of 2 R5s cores. + set _r5_cores 2 + set R5_NAMES {main0_r5.0 main0_r5.1} + set R5_DBGBASE {0x90030000 0x90032000} + set R5_CTIBASE {0x90038000 0x90039000} + set _r5_ap_num 5 + } am654 { set _K3_DAP_TAPID 0x0bb5a02f @@ -80,6 +126,7 @@ switch $_soc { # Sysctrl power-ap unlock offsets set _sysctrl_ap_unlock_offsets {0xf0 0x50} } + am243 - am642 { set _K3_DAP_TAPID 0x0bb3802f @@ -97,6 +144,12 @@ switch $_soc { # M4 processor set _gp_mcu_cores 1 + + # Overrides for am243 + if { "$_soc" == "am243" } { + # Uses the same JTAG ID + set _armv8_cores 0 + } } am625 { set _K3_DAP_TAPID 0x0bb7e02f @@ -248,6 +301,13 @@ switch $_soc { } } +proc _get_rtos_type_for_cpu { target_name } { + if { [info exists ::RTOS($target_name)] } { + return $::RTOS($target_name) + } + return none +} + set _CHIPNAME $_soc swj_newdap $_CHIPNAME cpu -irlen 4 -expected-id $_K3_DAP_TAPID -ignore-version @@ -259,8 +319,13 @@ set _TARGETNAME $_CHIPNAME.cpu set _CTINAME $_CHIPNAME.cti # sysctrl is always present -cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap -ap-num 7 -baseaddr [lindex $CM3_CTIBASE 0] -target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap -ap-num 7 -defer-examine +cti create $_CTINAME.sysctrl -dap $_CHIPNAME.dap \ + -ap-num $_sysctrl_ap_num -baseaddr [lindex $CM3_CTIBASE 0] + +target create $_TARGETNAME.sysctrl cortex_m -dap $_CHIPNAME.dap \ + -ap-num $_sysctrl_ap_num -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.sysctrl] + $_TARGETNAME.sysctrl configure -event reset-assert { } proc sysctrl_up {} { @@ -303,8 +368,9 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { cti create $_CTINAME.$_armv8_cpu_name.$_core -dap $_CHIPNAME.dap -ap-num 1 \ -baseaddr [lindex $ARMV8_CTIBASE $_core] - target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine + target create $_TARGETNAME.$_armv8_cpu_name.$_core aarch64 -dap $_CHIPNAME.dap -coreid $_core \ + -dbgbase [lindex $ARMV8_DBGBASE $_core] -cti $_CTINAME.$_armv8_cpu_name.$_core -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.$_armv8_cpu_name.$_core] set _v8_smp_targets "$_v8_smp_targets $_TARGETNAME.$_armv8_cpu_name.$_core" @@ -323,34 +389,37 @@ for { set _core 0 } { $_core < $_armv8_cores } { incr _core } { } } -# Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs -set _armv8_up_cmd "$_armv8_cpu_name"_up -# Available if V8_SMP_DEBUG is set to non-zero value -set _armv8_smp_cmd "$_armv8_cpu_name"_smp +if { $_armv8_cores > 0 } { + # Setup ARMV8 proc commands based on CPU to prevent people confusing SoCs + set _armv8_up_cmd "$_armv8_cpu_name"_up + # Available if V8_SMP_DEBUG is set to non-zero value + set _armv8_smp_cmd "$_armv8_cpu_name"_smp -if { $_v8_smp_debug == 0 } { - proc $_armv8_up_cmd { args } { - foreach _core $args { - targets $_core - _cpu_no_smp_up + if { $_v8_smp_debug == 0 } { + proc $_armv8_up_cmd { args } { + foreach _core $args { + targets $_core + _cpu_no_smp_up + } } + } else { + proc $_armv8_smp_cmd { args } { + _armv8_smp_up + } + # Declare SMP + target smp {*}$_v8_smp_targets } -} else { - proc $_armv8_smp_cmd { args } { - _armv8_smp_up - } - # Declare SMP - target smp $:::_v8_smp_targets } for { set _core 0 } { $_core < $_r5_cores } { incr _core } { set _r5_name [lindex $R5_NAMES $_core] - cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num 1 \ + cti create $_CTINAME.$_r5_name -dap $_CHIPNAME.dap -ap-num $_r5_ap_num \ -baseaddr [lindex $R5_CTIBASE $_core] # inactive core examination will fail - wait till startup of additional core target create $_TARGETNAME.$_r5_name cortex_r4 -dap $_CHIPNAME.dap \ - -dbgbase [lindex $R5_DBGBASE $_core] -ap-num 1 -defer-examine + -dbgbase [lindex $R5_DBGBASE $_core] -ap-num $_r5_ap_num -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.$_r5_name] $_TARGETNAME.$_r5_name configure -event gdb-attach { _cpu_no_smp_up @@ -368,7 +437,8 @@ proc r5_up { args } { if { $_gp_mcu_cores != 0 } { cti create $_CTINAME.gp_mcu -dap $_CHIPNAME.dap -ap-num 8 -baseaddr [lindex $CM4_CTIBASE 0] - target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine + target create $_TARGETNAME.gp_mcu cortex_m -dap $_CHIPNAME.dap -ap-num 8 -defer-examine \ + -rtos [_get_rtos_type_for_cpu $_TARGETNAME.gp_mcu] $_TARGETNAME.gp_mcu configure -event reset-assert { } proc gp_mcu_up {} { @@ -404,4 +474,7 @@ if { 0 == [string compare [adapter name] dmem ] } { } else { puts "ERROR: ${SOC} data is missing to support dmem access!" } +} else { + # AXI AP access port for SoC address map + target create $_CHIPNAME.axi_ap mem_ap -dap $_CHIPNAME.dap -ap-num $_mem_ap_num } diff --git a/tools/scripts/camelcase.txt b/tools/scripts/camelcase.txt index 2caa81caa..b78790200 100644 --- a/tools/scripts/camelcase.txt +++ b/tools/scripts/camelcase.txt @@ -77,6 +77,7 @@ bNumInterfaces idProduct idVendor iInterface +iManufacturer iProduct iSerialNumber wMaxPacketSize