├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── README.md ├── cmake ├── avatarstub_ST3320413AS_0x7000 │ └── CMakeLists.txt ├── avatarstub_qemu_versatilepb │ └── CMakeLists.txt ├── gdbstub_ST3320413AS_0x3FC000 │ └── CMakeLists.txt ├── gdbstub_ST3320413AS_0x7000 │ └── CMakeLists.txt ├── gdbstub_inforad_k0_0x0 │ └── CMakeLists.txt ├── gdbstub_plc_bootloader_0x16000 │ └── CMakeLists.txt ├── gdbstub_qemu_versatilepb │ └── CMakeLists.txt └── platform_arm.cmake ├── include ├── ArmGdbHelpers.h ├── ArmRegisterMap.h ├── Assert.h ├── AvatarHostInterface.h ├── DefaultDefines.h ├── GdbHostInterface.h ├── HostInterface.h ├── Memory.h ├── RegisterMap.h ├── ST3320413AS_avatar_config.h ├── ST3320413AS_gdb_config.h ├── Serial.h ├── SerialIO.h ├── StubState.h ├── armv7_cortex_r4.h ├── crc.h ├── gdb_utils.h ├── inforad_k0_gdb_config.h ├── plc_bootloader_gdb_config.h ├── qemu_versatilepb_gdb_config.h └── stdlib │ └── string.h ├── link ├── arm_ST3320413AS_0x3FC000.ld ├── arm_ST3320413AS_0x7000.ld ├── arm_beagleboard.ld ├── arm_inforad_k0_0x0.ld ├── arm_plc_bootloader_0x16000.ld └── arm_qemu_versatilepb.ld ├── scripts ├── Inforad_K0_flasher.py └── Seagate_ST3320413AS_flasher.py ├── src ├── ArmGdbHelpers.c ├── ArmRegisterMap.c ├── AvatarHostInterface.c ├── GdbHostInterface.c ├── Memory.c ├── SerialIO.c ├── Serial_pl011.c ├── Serial_sirf.c ├── Serial_uart16550.c ├── armv7_cortex_r4.c ├── crc.c ├── lowlevel_ST3320413AS.S ├── lowlevel_arm.S ├── lowlevel_inforad_k0.S ├── lowlevel_plc.S ├── lowlevel_qemu_versatilepb.S ├── stdlib │ └── memset.c ├── stub.c ├── utils.c └── utils_arm.S ├── test_programs ├── Makefile ├── coprocessor.h ├── cpuid.c ├── debug.c ├── hello_world.c ├── hwdebug.h ├── link.ld ├── startup_inforad_k0.h ├── swbreakpoint.c ├── uart_common.h └── uart_sirf.h └── xml └── arm-gdbstub.xml /.gitignore: -------------------------------------------------------------------------------- 1 | cscope.* 2 | *.swp 3 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | PROJECT(stub C ASM) 7 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) 8 | 9 | FUNCTION(ADDPREFIX list_name prefix) 10 | # create empty list - necessary? 11 | SET(${list_name}_TMP) 12 | 13 | # prefix and suffix elements 14 | foreach(l ${${list_name}}) 15 | list(APPEND ${list_name}_TMP ${prefix}${l} ) 16 | endforeach() 17 | 18 | # replace list by tmp list 19 | SET(${list_name} ${${list_name}_TMP} PARENT_SCOPE) 20 | UNSET(${list_name}_TMP) 21 | ENDFUNCTION(ADDPREFIX) 22 | 23 | INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/include 24 | ${PROJECT_BINARY_DIR}) 25 | 26 | INCLUDE(cmake/platform_arm.cmake) 27 | 28 | SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") #Suppress -rdynamic in linker flags 29 | 30 | SET (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -mno-thumb-interwork -fPIC") 31 | SET(CMAKE_ASM_FLAGS "-fPIC -Wall" ) 32 | 33 | #ADD_SUBDIRECTORY (cmake/avatarstub_qemu_versatilepb) 34 | #ADD_SUBDIRECTORY (cmake/avatarstub_ST3320413AS_0x7000) 35 | ADD_SUBDIRECTORY (cmake/gdbstub_ST3320413AS_0x7000) 36 | ADD_SUBDIRECTORY (cmake/gdbstub_ST3320413AS_0x3FC000) 37 | ADD_SUBDIRECTORY (cmake/gdbstub_qemu_versatilepb) 38 | ADD_SUBDIRECTORY (cmake/gdbstub_plc_bootloader_0x16000) 39 | ADD_SUBDIRECTORY (cmake/gdbstub_inforad_k0_0x0) 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | avatar-gdbstub 2 | ============== 3 | 4 | GDB stub that allows debugging of embedded devices 5 | 6 | 7 | This is the source code for a very small GDB stub implementation. 8 | The stub is supposed to communicate with the host GDB over the 9 | GDB serial protocol or a custom protocol (Avatar). 10 | 11 | Depending on how the serial line is used, you need a Multiplexer 12 | to set up the environment for you and send any stuff that is needed 13 | until the GDB stub is running. 14 | 15 | Adapting the GDB stub for your platform is easy: Copy one of the 16 | existing gdbstub_*.cmake files in the cmake/ directory and adapt 17 | it to your platform. You might need to develop additional serial 18 | drivers and platform initialization files. 19 | 20 | 21 | *test_programs* contains simple programs that test one functionality 22 | of an embedded system - e.g., serial output, CPU features, debug 23 | features. 24 | Those programs are meant to discover an embedded system before the 25 | GDB stub is ported. 26 | -------------------------------------------------------------------------------- /cmake/avatarstub_ST3320413AS_0x7000/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # Build file for the Seagate ST3320413AS hard drive. 7 | 8 | SET (STUB_ASSEMBLER_FILES 9 | src/lowlevel_arm.S 10 | src/lowlevel_ST3320413AS.S 11 | src/utils_arm.S 12 | ) 13 | 14 | SET (STUB_ARM_FILES 15 | ) 16 | 17 | SET (STUB_THUMB_FILES 18 | src/AvatarHostInterface.c 19 | # src/gdbstub_arm.c 20 | # src/utils.c 21 | src/Serial_uart16550.c 22 | src/ArmRegisterMap.c 23 | src/ArmGdbHelpers.c 24 | src/Memory.c 25 | src/stub.c 26 | src/crc.c 27 | ) 28 | 29 | SET (STUB_NAME avatarstub_ST3320413AS_0x7000) 30 | SET (STUB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_ST3320413AS_0x7000.ld) 31 | SET (STUB_CONFIGURATION_HEADER ${PROJECT_SOURCE_DIR}/include/ST3320413AS_avatar_config.h) 32 | SET (TARGET_ARCH armv5t) 33 | 34 | BUILD_DEBUG_STUB() -------------------------------------------------------------------------------- /cmake/avatarstub_qemu_versatilepb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | 7 | SET (LIBSYSTEM_COMMON_ARM_FILES 8 | libsystem/src/arm/exception_handler_fiq.c 9 | libsystem/src/arm/exception_handler_und.c 10 | libsystem/src/arm/exception_handler_pab.c 11 | libsystem/src/arm/exception_handler_dab.c 12 | libsystem/src/arm/exception_handler_irq.c 13 | libsystem/src/arm/ArmCpu.c 14 | libsystem/src/arm/exception_handler_svc.c 15 | libsystem/src/arm/exception_handler_dab.c) 16 | 17 | SET (AVATARSTUB_QEMU_VERSATILEPB_ARM_FILES 18 | src/arm/start.c 19 | ${LIBSYSTEM_COMMON_ARM_FILES} 20 | ) 21 | 22 | SET (AVATARSTUB_COMMON_THUMB_FILES 23 | src/avatar_protocol.c 24 | src/avatar_vm.c 25 | src/avatar_exceptions.c 26 | src/avatar_memory.c 27 | src/minivm.c 28 | src/crc.c 29 | src/avatar_codelet_api.c 30 | src/utils.c 31 | # src/gdb_protocol.c 32 | ) 33 | 34 | SET (AVATARSTUB_QEMU_VERSATILEPB_THUMB_FILES 35 | libsystem/src/hw/serial/Serial_pl011.c 36 | src/platform_qemu_versatilepb.c) 37 | 38 | 39 | 40 | SET (QEMU_VERSATILEPB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_qemu_versatilepb.ld) 41 | 42 | SET_SOURCE_FILES_PROPERTIES(${AVATARSTUB_QEMU_VERSATILEPB_ARM_FILES} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -marm") 43 | SET_SOURCE_FILES_PROPERTIES(${AVATARSTUB_COMMON_THUMB_FILES} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -mthumb") 44 | SET_SOURCE_FILES_PROPERTIES(${AVATARSTUB_QEMU_VERSATILEPB_THUMB_FILES} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -mthumb") 45 | 46 | ADD_EXECUTABLE(avatarstub_qemu_versatilepb ${AVATARSTUB_QEMU_VERSATILEPB_ARM_FILES} ${AVATARSTUB_COMMON_THUMB_FILES} ${AVATARSTUB_QEMU_VERSATILEPB_THUMB_FILES}) 47 | SET_TARGET_PROPERTIES(avatarstub_qemu_versatilepb PROPERTIES LINK_FLAGS "-T ${QEMU_VERSATILEPB_LINKER_FILE} -nostdlib -nodefaultlibs") 48 | TARGET_LINK_LIBRARIES(avatarstub_qemu_versatilepb stdlib) 49 | -------------------------------------------------------------------------------- /cmake/gdbstub_ST3320413AS_0x3FC000/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # Build file for the Seagate ST3320413AS hard drive. 7 | 8 | 9 | SET (STUB_ASSEMBLER_FILES 10 | src/lowlevel_arm.S 11 | src/lowlevel_ST3320413AS.S 12 | src/utils_arm.S 13 | ) 14 | 15 | SET (STUB_ARM_FILES 16 | ) 17 | 18 | SET (STUB_THUMB_FILES 19 | src/GdbHostInterface.c 20 | src/utils.c 21 | src/Serial_uart16550.c 22 | src/ArmRegisterMap.c 23 | src/ArmGdbHelpers.c 24 | src/Memory.c 25 | src/stub.c 26 | src/crc.c 27 | ) 28 | 29 | SET (STUB_NAME gdbstub_ST3320413AS_0x3FC000) 30 | SET (STUB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_ST3320413AS_0x3FC000.ld) 31 | SET (STUB_CONFIGURATION_HEADER ${PROJECT_SOURCE_DIR}/include/ST3320413AS_gdb_config.h) 32 | SET (TARGET_ARCH armv5t) 33 | 34 | BUILD_DEBUG_STUB() 35 | -------------------------------------------------------------------------------- /cmake/gdbstub_ST3320413AS_0x7000/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # Build file for the Seagate ST3320413AS hard drive. 7 | 8 | 9 | SET (STUB_ASSEMBLER_FILES 10 | src/lowlevel_arm.S 11 | src/lowlevel_ST3320413AS.S 12 | src/utils_arm.S 13 | ) 14 | 15 | SET (STUB_ARM_FILES 16 | ) 17 | 18 | SET (STUB_THUMB_FILES 19 | src/GdbHostInterface.c 20 | src/utils.c 21 | src/Serial_uart16550.c 22 | src/ArmRegisterMap.c 23 | src/ArmGdbHelpers.c 24 | src/Memory.c 25 | src/stub.c 26 | src/crc.c 27 | ) 28 | 29 | SET (STUB_NAME gdbstub_ST3320413AS_0x7000) 30 | SET (STUB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_ST3320413AS_0x7000.ld) 31 | SET (STUB_CONFIGURATION_HEADER ${PROJECT_SOURCE_DIR}/include/ST3320413AS_gdb_config.h) 32 | SET (TARGET_ARCH armv5t) 33 | 34 | BUILD_DEBUG_STUB() 35 | -------------------------------------------------------------------------------- /cmake/gdbstub_inforad_k0_0x0/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # Build file for the Inforad K0 SIR III GPS stick 7 | 8 | 9 | SET (STUB_ASSEMBLER_FILES 10 | src/lowlevel_arm.S 11 | src/lowlevel_inforad_k0.S 12 | src/utils_arm.S 13 | ) 14 | 15 | SET (STUB_THUMB_FILES 16 | ) 17 | 18 | SET (STUB_ARM_FILES 19 | src/GdbHostInterface.c 20 | # src/gdbstub_arm.c 21 | src/utils.c 22 | src/Serial_sirf.c 23 | src/ArmRegisterMap.c 24 | src/ArmGdbHelpers.c 25 | src/Memory.c 26 | src/stub.c 27 | src/crc.c 28 | ) 29 | 30 | SET (STUB_NAME gdbstub_inforad_k0_0x0) 31 | SET (STUB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_inforad_k0_0x0.ld) 32 | SET (STUB_CONFIGURATION_HEADER ${PROJECT_SOURCE_DIR}/include/inforad_k0_gdb_config.h) 33 | SET (TARGET_CPU arm7tdmi) 34 | SET (TARGET_ENDIAN little-endian) 35 | 36 | BUILD_DEBUG_STUB() 37 | -------------------------------------------------------------------------------- /cmake/gdbstub_plc_bootloader_0x16000/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Lucian Cojocar , VU 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # Build file for the Siemens S7-1200 PLC (6E7S212-1BE31-0XB0) 7 | 8 | SET (STUB_ASSEMBLER_FILES 9 | src/lowlevel_arm.S 10 | src/lowlevel_plc.S 11 | ) 12 | 13 | SET (STUB_ARM_FILES 14 | src/GdbHostInterface.c 15 | # src/gdbstub_arm.c 16 | src/crc.c 17 | src/utils.c 18 | src/Serial_pl011.c 19 | src/ArmRegisterMap.c 20 | src/ArmGdbHelpers.c 21 | src/Memory.c 22 | src/stub.c 23 | src/SerialIO.c 24 | src/armv7_cortex_r4.c 25 | ) 26 | 27 | SET (STUB_NAME gdbstub_plc_bootloader_0x16000) 28 | SET (STUB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_plc_bootloader_0x16000.ld) 29 | SET (STUB_CONFIGURATION_HEADER ${PROJECT_SOURCE_DIR}/include/plc_bootloader_gdb_config.h) 30 | SET (TARGET_ARCH armv7-r) 31 | SET (TARGET_ENDIAN big-endian) 32 | 33 | BUILD_DEBUG_STUB() -------------------------------------------------------------------------------- /cmake/gdbstub_qemu_versatilepb/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # Build file for the Qemu VersatilePB platform. 7 | 8 | SET (STUB_ASSEMBLER_FILES 9 | src/lowlevel_arm.S 10 | src/lowlevel_qemu_versatilepb.S 11 | src/utils_arm.S) 12 | 13 | SET (STUB_ARM_FILES 14 | src/utils.c 15 | src/GdbHostInterface.c 16 | src/utils.c 17 | src/Serial_pl011.c 18 | src/ArmRegisterMap.c 19 | src/ArmGdbHelpers.c 20 | src/Memory.c 21 | src/stub.c 22 | src/crc.c 23 | ) 24 | 25 | SET (STUB_THUMB_FILES 26 | ) 27 | 28 | SET (STUB_NAME gdbstub_qemu_versatilepb) 29 | SET (STUB_LINKER_FILE ${PROJECT_SOURCE_DIR}/link/arm_qemu_versatilepb.ld) 30 | SET (STUB_CONFIGURATION_HEADER ${PROJECT_SOURCE_DIR}/include/qemu_versatilepb_gdb_config.h) 31 | SET (TARGET_ARCH armv5t) 32 | 33 | BUILD_DEBUG_STUB() -------------------------------------------------------------------------------- /cmake/platform_arm.cmake: -------------------------------------------------------------------------------- 1 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 2 | # 3 | # You can redistribute and/or modify this program under the terms of the 4 | # GNU General Public License version 2 or later. 5 | 6 | # the name of the target operating system 7 | SET(CMAKE_SYSTEM_NAME Generic) 8 | SET(CMAKE_SYSTEM_PROCESSOR arm) 9 | 10 | # which compilers to use for C and C++ 11 | SET(CMAKE_C_COMPILER arm-none-eabi-gcc) 12 | SET(CMAKE_CXX_COMPILER arm-none-eabi-g++) 13 | SET(CMAKE_ASM_COMPILER arm-none-eabi-gcc) 14 | SET(CMAKE_SIZE arm-none-eabi-size) 15 | SET(CMAKE_OBJCOPY arm-none-eabi-objcopy) 16 | SET(CMAKE_AR arm-none-eabi-ar) 17 | SET(CMAKE_RANLIB arm-none-eabi-ranlib) 18 | 19 | # adjust the default behaviour of the FIND_XXX() commands: 20 | # search headers and libraries in the target environment, search 21 | # programs in the host environment 22 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 23 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 24 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 25 | 26 | #Remove switches that prevent inclusion of symbol table in binary 27 | SET (CMAKE_C_LINK_FLAGS "") 28 | 29 | MACRO(BUILD_DEBUG_STUB) 30 | ADDPREFIX(STUB_ASSEMBLER_FILES ../../) 31 | ADDPREFIX(STUB_ARM_FILES ../../) 32 | ADDPREFIX(STUB_THUMB_FILES ../../) 33 | 34 | SET (CUSTOM_FLAGS) 35 | IF (DEFINED TARGET_ARCH) 36 | SET(CUSTOM_FLAGS "${CUSTOM_FLAGS} -march=${TARGET_ARCH}") 37 | ENDIF (DEFINED TARGET_ARCH) 38 | IF (DEFINED TARGET_CPU) 39 | SET(CUSTOM_FLAGS "${CUSTOM_FLAGS} -mcpu=${TARGET_CPU}") 40 | ENDIF (DEFINED TARGET_CPU) 41 | IF (DEFINED TARGET_ENDIAN) 42 | SET(CUSTOM_FLAGS "${CUSTOM_FLAGS} -m${TARGET_ENDIAN}") 43 | ENDIF (DEFINED TARGET_ENDIAN) 44 | 45 | 46 | 47 | SET_SOURCE_FILES_PROPERTIES(${STUB_ARM_FILES} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -include ${STUB_CONFIGURATION_HEADER} -marm ${CUSTOM_FLAGS}") 48 | SET_SOURCE_FILES_PROPERTIES(${STUB_THUMB_FILES} PROPERTIES COMPILE_FLAGS "${CMAKE_C_FLAGS} -include ${STUB_CONFIGURATION_HEADER} -mthumb ${CUSTOM_FLAGS}") 49 | SET_SOURCE_FILES_PROPERTIES(${STUB_ASSEMBLER_FILES} PROPERTIES COMPILE_FLAGS "${CMAKE_ASM_FLAGS} ${CUSTOM_FLAGS}") 50 | 51 | 52 | ADD_EXECUTABLE(${STUB_NAME} ${STUB_ARM_FILES} ${STUB_THUMB_FILES} ${STUB_ASSEMBLER_FILES}) 53 | SET_TARGET_PROPERTIES(${STUB_NAME} PROPERTIES LINK_FLAGS "-T ${STUB_LINKER_FILE} -nostdlib -nodefaultlibs ${CUSTOM_FLAGS}") 54 | 55 | ADD_CUSTOM_COMMAND(OUTPUT ${STUB_NAME}.bin.tmp 56 | COMMAND arm-none-eabi-objcopy --output-format=binary ${STUB_NAME} ${STUB_NAME}.bin.tmp 57 | COMMAND ${CMAKE_COMMAND} -E copy ${STUB_NAME}.bin.tmp ${STUB_NAME}.bin 58 | DEPENDS ${STUB_NAME} 59 | COMMENT "objcopy elf to bin") 60 | ADD_CUSTOM_TARGET(${STUB_NAME}.bin ALL DEPENDS ${STUB_NAME}.bin.tmp) 61 | SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES ${STUB_NAME}.bin) 62 | ENDMACRO(BUILD_DEBUG_STUB) 63 | -------------------------------------------------------------------------------- /include/ArmGdbHelpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _ARM_GDB_HELPERS_H 9 | #define _ARM_GDB_HELPERS_H 10 | 11 | #include "StubState.h" 12 | 13 | unsigned Gdb_map_gdb_register_number_to_stub(StubState *state, unsigned reg); 14 | void Gdb_continue_execution(StubState *state); 15 | 16 | #endif /* _ARM_GDB_HELPERS_H */ 17 | -------------------------------------------------------------------------------- /include/ArmRegisterMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _ARM_REGISTER_MAP_H 9 | #define _ARM_REGISTER_MAP_H 10 | 11 | #include 12 | 13 | #define REG_SPSR_ABT 0 14 | #define REG_SP_ABT 1 15 | 16 | #define REG_SPSR_FIQ 2 17 | #define REG_R8_FIQ 3 18 | #define REG_R9_FIQ 4 19 | #define REG_R10_FIQ 5 20 | #define REG_R11_FIQ 6 21 | #define REG_R12_FIQ 7 22 | #define REG_SP_FIQ 8 23 | #define REG_LR_FIQ 9 24 | 25 | #define REG_SPSR_IRQ 10 26 | #define REG_SP_IRQ 11 27 | #define REG_LR_IRQ 12 28 | 29 | #define REG_SPSR_SVC 13 30 | #define REG_SP_SVC 14 31 | #define REG_LR_SVC 15 32 | 33 | #define REG_SPSR_UND 16 34 | #define REG_SP_UND 17 35 | #define REG_LR_UND 18 36 | 37 | #define REG_SPSR_SYS 19 38 | #define REG_SP_SYS 20 39 | #define REG_LR_SYS 21 40 | 41 | #define REG_SP_USR 22 42 | #define REG_LR_USR 23 43 | 44 | 45 | #define REG_R0 24 46 | #define REG_R1 25 47 | #define REG_R2 26 48 | #define REG_R3 27 49 | #define REG_R4 28 50 | #define REG_R5 29 51 | #define REG_R6 30 52 | #define REG_R7 31 53 | #define REG_R8 32 54 | #define REG_R9 33 55 | #define REG_R10 34 56 | #define REG_R11 35 57 | #define REG_R12 36 58 | 59 | #define REG_PC 37 60 | #define REG_CPSR 0 61 | 62 | 63 | typedef struct 64 | { 65 | uint32_t spsr_abt; //= CPSR 66 | uint32_t sp_abt; 67 | 68 | uint32_t spsr_fiq; 69 | uint32_t high_registers[5]; //r8_fiq - r12_fiq 70 | uint32_t lr_fiq; 71 | 72 | uint32_t spsr_irq; 73 | uint32_t sp_irq; 74 | uint32_t lr_irq; 75 | 76 | uint32_t spsr_svc; 77 | uint32_t sp_svc; 78 | uint32_t lr_svc; 79 | 80 | uint32_t spsr_und; 81 | uint32_t sp_und; 82 | uint32_t lr_und; 83 | 84 | uint32_t spsr_sys; 85 | uint32_t sp_sys; 86 | uint32_t lr_sys; 87 | 88 | uint32_t sp_usr; 89 | uint32_t lr_usr; 90 | 91 | uint32_t registers[13]; //r0 - r12 92 | uint32_t pc; 93 | } __attribute__((__packed__)) RegisterMap; 94 | 95 | #endif /* _ARM_REGISTER_MAP_H */ 96 | -------------------------------------------------------------------------------- /include/Assert.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _ASSERT_H 9 | #define _ASSERT_H 10 | 11 | #define assert(x) do {} while(0) 12 | 13 | #endif /* _ASSERT_H */ 14 | -------------------------------------------------------------------------------- /include/AvatarHostInterface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Created on: Apr 20, 2013 3 | * 4 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 5 | * 6 | * You can redistribute and/or modify this program under the terms of the 7 | * GNU General Public License version 2 or later. 8 | */ 9 | 10 | #ifndef _AVATAR_HOST_INTERFACE_H 11 | #define _AVATAR_HOST_INTERFACE_H 12 | 13 | #include 14 | 15 | /** 16 | * This structure encapsulates data for the GDB serial protocol host interface. 17 | */ 18 | //TODO: This is GDB specific, move it 19 | typedef struct 20 | { 21 | uint8_t recv_checksum; 22 | uint8_t recv_error; 23 | uint8_t send_checksum; 24 | uint8_t send_error; 25 | } HostInterfaceState; 26 | 27 | typedef enum 28 | { 29 | AVATAR_RPC_HTD_READ_MEMORY = 0x01, 30 | AVATAR_RPC_HTD_WRITE_MEMORY = 0x02, 31 | AVATAR_RPC_HTD_GET_REGISTER = 0x03, 32 | AVATAR_RPC_HTD_SET_REGISTER = 0x04, 33 | AVATAR_RPC_HTD_READ_UNTYPED_MEMORY = 0x05, 34 | AVATAR_RPC_HTD_WRITE_UNTYPED_MEMORY = 0x06, 35 | AVATAR_RPC_HTD_CODELET_EXECUTE = 0x07, 36 | 37 | AVATAR_RPC_HTD_INSERT_PAGE = 0x10, 38 | AVATAR_RPC_HTD_EXTRACT_PAGE = 0x11, 39 | AVATAR_RPC_HTD_UNMAP_PAGE = 0x12, 40 | AVATAR_RPC_HTD_SET_MEMORY_MAP = 0x13, 41 | AVATAR_RPC_HTD_GET_DIRTY_PAGES = 0x14, 42 | 43 | AVATAR_RPC_HTD_SET_EXCEPTION_CONFIG = 0x20, 44 | AVATAR_RPC_HTD_CLEAR_EXCEPTION = 0x21, 45 | 46 | AVATAR_RPC_HTD_ADD_EMULATED_INSTRUCTION = 0x30, 47 | AVATAR_RPC_HTD_CLEAR_EMULATED_INSTRUCTIONS = 0x31, 48 | 49 | AVATAR_RPC_HTD_RESUME_VM = 0x40, 50 | AVATAR_RPC_HTD_QUERY_STATE = 0x41, 51 | 52 | 53 | 54 | 55 | 56 | 57 | AVATAR_RPC_DTH_INFO_EXCEPTION = 0x80 + 0x20, 58 | AVATAR_RPC_DTH_STATE = 0x80 + 1, 59 | AVATAR_RPC_DTH_REPLY_STATE = 0x80 + 2, 60 | AVATAR_RPC_DTH_REPLY_OK = 0x80 + 0x31, 61 | AVATAR_RPC_DTH_REPLY_ERROR = 0x80 + 0x32, 62 | AVATAR_RPC_DTH_REPLY_READ_MEMORY = 0x80 + 0x10, 63 | AVATAR_RPC_DTH_REPLY_GET_REGISTER = 0x80 + 0x11, 64 | AVATAR_RPC_DTH_REPLY_EXTRACT_PAGE = 0x80 + 0x12, 65 | AVATAR_RPC_DTH_REPLY_READ_UNTYPED_MEMORY = 0x94, 66 | AVATAR_RPC_DTH_REPLY_CODELET_EXECUTION_FINISHED = 0x95, 67 | 68 | AVATAR_RPC_DTH_PAGEFAULT = 0xA4, 69 | AVATAR_RPC_HTD_CONTINUE_FROM_PAGEFAULT = 0x42, 70 | AVATAR_RPC_DTH_REPLY_GET_DIRTY_PAGES = 0x93 71 | 72 | 73 | } AvatarRpcCommand; 74 | 75 | typedef enum 76 | { 77 | AVATAR_EXCEPTION_IRQ_FORWARD = 1, 78 | AVATAR_EXCEPTION_FIQ_FORWARD = 2, 79 | AVATAR_EXCEPTION_SVC_FORWARD = 4, 80 | AVATAR_EXCEPTION_UND_FORWARD = 8, 81 | AVATAR_EXCEPTION_DAB_FORWARD = 0x10, 82 | AVATAR_EXCEPTION_PAB_FORWARD = 0x20, /* TODO: How to do this? */ 83 | AVATAR_EXCEPTION_IRQ_PRINT = 0x100, 84 | AVATAR_EXCEPTION_FIQ_PRINT = 0x200, 85 | AVATAR_EXCEPTION_SVC_PRINT = 0x400, 86 | AVATAR_EXCEPTION_UND_PRINT = 0x800, 87 | AVATAR_EXCEPTION_DAB_PRINT = 0x1000, 88 | AVATAR_EXCEPTION_PAB_PRINT = 0x2000, /* TODO: How to do this? */ 89 | /* Disable IRQs and FIQs while in supervisor */ 90 | AVATAR_EXCEPTION_INTERRUPTS_DISABLE = 0x10000, 91 | } AvatarExceptionConfiguration; 92 | 93 | typedef enum 94 | { 95 | AVATAR_ERROR_NONE = 0, 96 | AVATAR_ERROR_CHECKSUM = 1, 97 | AVATAR_ERROR_OUT_OF_BOUNDS = 2, 98 | AVATAR_ERROR_NOT_FOUND = 3, 99 | AVATAR_ERROR_OUT_OF_MEMORY = 4 100 | } AvatarError; 101 | 102 | typedef enum 103 | { 104 | AVATAR_VMSTATE_RUNNING = 0x01, 105 | AVATAR_VMSTATE_PAGE_MISS = 0x02, 106 | AVATAR_VMSTATE_BREAKPOINT = 0x04, 107 | AVATAR_VMSTATE_EMULATE_INSTRUCTION = 0x08, 108 | AVATAR_VMSTATE_EXCEPTION = 0x10 109 | } AvatarVmState; 110 | 111 | //TODO: ARM specific 112 | typedef enum 113 | { 114 | CPU_EXCEPTION_RST = 0, 115 | CPU_EXCEPTION_UND = 1, 116 | CPU_EXCEPTION_SVC = 2, 117 | CPU_EXCEPTION_PAB = 3, 118 | CPU_EXCEPTION_DAB = 4, 119 | CPU_EXCEPTION_IRQ = 6, 120 | CPU_EXCEPTION_FIQ = 7 121 | } AvatarProcessorException; 122 | 123 | // void Avatar_report_state(AvatarVmState state); 124 | // void Avatar_report_exception(AvatarProcessorException exc); 125 | // void Avatar_handle_incoming_command(); 126 | 127 | #endif /* _AVATAR_HOST_INTERFACE_H */ 128 | -------------------------------------------------------------------------------- /include/DefaultDefines.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * Copyright 2013-2014 Lucian Cojocar , VU Amsterdam 4 | * 5 | * You can redistribute and/or modify this program under the terms of the 6 | * GNU General Public License version 2 or later. 7 | */ 8 | 9 | #ifndef _DEFAULT_DEFINES_H 10 | #define _DEFAULT_DEFINES_H 11 | 12 | #ifndef WATCHDOG_EXCITE 13 | #define WATCHDOG_EXCITE do {} while(0) 14 | #endif /* WATCHDOG_EXCITE */ 15 | 16 | #ifndef SIGNAL_DEBUG_ENTER 17 | #define SIGNAL_DEBUG_ENTER do {} while(0) 18 | #endif /* SIGNAL_DEBUG_ENTER */ 19 | 20 | #ifndef SIGNAL_DEBUG_EXIT 21 | #define SIGNAL_DEBUG_EXIT do {} while(0) 22 | #endif /* SIGNAL_DEBUG_EXIT */ 23 | 24 | #endif /* _DEFAULT_DEFINES_H */ -------------------------------------------------------------------------------- /include/GdbHostInterface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _GDB_HOST_INTERFACE_H 9 | #define _GDB_HOST_INTERFACE_H 10 | 11 | #include 12 | 13 | /** 14 | * This structure encapsulates data for the GDB serial protocol host interface. 15 | */ 16 | //TODO: This is GDB specific, move it 17 | typedef struct 18 | { 19 | uint8_t input_checksum; 20 | uint8_t input_packet_finished; 21 | uint8_t output_checksum; 22 | } HostInterfaceState; 23 | 24 | #endif /* _GDB_HOST_INTERFACE_H */ 25 | -------------------------------------------------------------------------------- /include/HostInterface.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | /** 9 | * This file specifies the prototype of the interface that the 10 | * stub uses to communicate with the host. 11 | * Most is implementation-specific. 12 | */ 13 | 14 | #ifndef _HOST_INTERFACE_H 15 | #define _HOST_INTERFACE_H 16 | 17 | #include "StubState.h" 18 | 19 | /** 20 | * Called one time during stub initialization. 21 | */ 22 | void HostInterface_init(StubState *state); 23 | 24 | /** 25 | * Called by the stub when an event occured that 26 | * calls for communication with the host, e.g. a breakpoint has been hit. 27 | */ 28 | void HostInterface_communicate(StubState *state); 29 | 30 | 31 | 32 | #endif /* _HOST_INTERFACE_H */ 33 | -------------------------------------------------------------------------------- /include/Memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _MEMORY_H 9 | #define _MEMORY_H 10 | 11 | #include 12 | 13 | #include "StubState.h" 14 | 15 | typedef uint32_t value_t; //This should be the type of the biggest value that can be read 16 | typedef uint32_t address_t;//This type should be able to hold a memory address 17 | 18 | #define SIZE_CHAR 1 19 | #define SIZE_SHORT 2 20 | #define SIZE_LONG 4 21 | 22 | /** 23 | * Read a typed (byte, short, long) value from memory. 24 | */ 25 | value_t Memory_read_typed(StubState *state, address_t address, unsigned size); 26 | 27 | /** 28 | * Write a typed (byte, short, long) value to memory. 29 | */ 30 | void Memory_write_typed(StubState *state, address_t address, unsigned size, value_t value); 31 | 32 | /** 33 | * Read untyped (byte array) data from memory. 34 | */ 35 | void Memory_read_untyped(StubState *state, address_t address, uint8_t *buffer, unsigned length); 36 | 37 | 38 | /** 39 | * Write untyped (byte array) data to memory. 40 | */ 41 | void Memory_write_untyped(StubState *state, address_t address, const uint8_t *buffer, unsigned length); 42 | 43 | /** 44 | * Test or check in memory map if this is a valid address. 45 | */ 46 | int Memory_is_valid_address(StubState *state, address_t address); 47 | 48 | 49 | 50 | 51 | 52 | 53 | #endif /* _MEMORY_H */ 54 | -------------------------------------------------------------------------------- /include/RegisterMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _REGISTER_MAP_H 9 | #define _REGISTER_MAP_H 10 | 11 | #include "StubState.h" 12 | 13 | //Register number that is used to denote an invalid register 14 | #define INVALID_REGISTER 0xffff 15 | 16 | typedef uint32_t register_t; //For now this declaration is good enough 17 | 18 | /** 19 | * Get a value from the register map. 20 | */ 21 | register_t RegisterMap_get_register(StubState *state, unsigned reg); 22 | 23 | /** 24 | * Set a value in the register map. 25 | */ 26 | void RegisterMap_set_register(StubState *state, unsigned reg, register_t val); 27 | 28 | 29 | #endif /* _REGISTER_MAP_H */ 30 | -------------------------------------------------------------------------------- /include/ST3320413AS_avatar_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _ST3320413AS_AVATAR_CONFIG_H 9 | #define _ST3320413AS_AVATAR_CONFIG_H 10 | 11 | #define UART_16550_BASE ((volatile uint32_t *) 0x400D3000) 12 | 13 | #include "AvatarHostInterface.h" 14 | #include "ArmRegisterMap.h" 15 | 16 | #endif /* _ST3320413AS_AVATAR_CONFIG_H */ 17 | -------------------------------------------------------------------------------- /include/ST3320413AS_gdb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _ST3320413AS_GDB_CONFIG_H 9 | #define _ST3320413AS_GDB_CONFIG_H 10 | 11 | #define UART_16550_BASE ((volatile uint32_t *) 0x400D3000) 12 | 13 | #define CONFIG_MEMORY_ERROR 14 | 15 | #include "GdbHostInterface.h" 16 | #include "ArmRegisterMap.h" 17 | 18 | #endif /* _ST3320413AS_GDB_CONFIG_H */ 19 | -------------------------------------------------------------------------------- /include/Serial.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _SERIAL_H 9 | #define _SERIAL_H 10 | 11 | #include 12 | 13 | /** 14 | * Initialize the hardware to sane defaults. 15 | * (E.g. the baudrate and configuration expected by the communication partner) 16 | */ 17 | void Serial_init(); 18 | 19 | /** 20 | * Read one byte from the serial port. 21 | * If the read buffer is currently empty, wait until 22 | * data is available. 23 | * @return character (0 <= char < 256) or negative error code. 24 | */ 25 | int Serial_read_byte_blocking(); 26 | 27 | /** 28 | * Check if the next read will not block. 29 | * @return 0 if the next read will block, 1 otherwise. 30 | */ 31 | int Serial_is_next_read_blocking(); 32 | 33 | /** 34 | * Write one byte to the serial port. 35 | * This function is supposed to block if the write buffer is full, 36 | * and to return as soon as the byte has been successfully written 37 | * to the buffer. 38 | * @return 0 on success or negative error code. 39 | */ 40 | int Serial_write_byte(uint8_t data); 41 | 42 | /** 43 | * Block until all data has been definitely sent. 44 | */ 45 | void Serial_flush_write(); 46 | 47 | #endif /* _SERIAL_H */ 48 | -------------------------------------------------------------------------------- /include/SerialIO.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | /* This header is used mostly for debugging to access the IO functions 8 | * of the serial port 9 | */ 10 | #ifndef _SERIALIO_H 11 | #define _SERIALIO_H 1 12 | 13 | void print_uint8(uint8_t val); 14 | void print_uint32(uint32_t val); 15 | void print_char(char c); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/StubState.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | /** 9 | * This file contains the general state structure of the stub. 10 | */ 11 | #ifndef _STUB_STATE_H 12 | #define _STUB_STATE_H 13 | 14 | /** 15 | * This structure encapsulates all data touched by the stub. 16 | */ 17 | typedef struct 18 | { 19 | RegisterMap *register_map; 20 | HostInterfaceState host_interface; 21 | unsigned signal; 22 | } StubState; 23 | 24 | #endif /* _STUB_STATE_H */ 25 | -------------------------------------------------------------------------------- /include/armv7_cortex_r4.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | #ifndef _ARMV7_CORTEX_R4_H 8 | #define _ARMV7_CORTEX_R4_H 1 9 | 10 | #include 11 | 12 | #include "StubState.h" 13 | 14 | uint32_t armv7_cortex_r4_read_debug_register(StubState *state, uint32_t reg_num); 15 | uint32_t armv7_cortex_r4_read_Debug_ROM_Address_Register(StubState *state); 16 | uint32_t armv7_cortex_r4_read_Debug_Self_Address_Offset_Register(StubState *state); 17 | uint32_t armv7_cortex_r4_read_debug_register(StubState *state, uint32_t reg_num); 18 | void armv7_cortex_r4_write_debug_register(StubState *state, uint32_t reg_num, uint32_t value); 19 | volatile void * armv7_cortex_r4_get_debug_registers_base(StubState *state); 20 | void armv7_cortex_r4_unlock_debug_registers(StubState *state); 21 | void armv7_cortex_r4_lock_debug_registers(StubState *state); 22 | int armv7_cortex_r4_are_debug_register_enabled(StubState *state); 23 | void armv7_cortex_r4_set_hw_watchpoint(StubState *state, uint32_t addr, uint32_t watch_num, uint32_t size); 24 | void armv7_cortex_r4_enable_monitor_mode(StubState *state); 25 | void armv7_cortex_r4_set_hw_breakpoint(StubState *state, uint32_t addr, uint32_t break_num); 26 | 27 | void armv7_cortex_r4_invalidate_instruction_cache(void); 28 | void armv7_cortex_r4_flush_data_cache(void); 29 | void armv7_cortex_r4_invalidate_data_cache(void); 30 | void armv7_cortex_r4_flush_data_cache_by_mva(uint32_t address); 31 | 32 | #define flush_data_cache armv7_cortex_r4_flush_data_cache 33 | #define invalidate_instruction_cache armv7_cortex_r4_invalidate_instruction_cache 34 | #define invalidate_data_cache armv7_cortex_r4_invalidate_data_cache 35 | #define flush_data_cache_by_mva armv7_cortex_r4_flush_data_cache_by_mva 36 | 37 | #define write_debug_register(r, v) armv7_cortex_r4_write_debug_register(state, (r), (v)) 38 | #define read_debug_register(r) armv7_cortex_r4_read_debug_register(state, (r)) 39 | #define set_hw_breakpoint(state, addr, no) do {\ 40 | armv7_cortex_r4_enable_monitor_mode(state);\ 41 | armv7_cortex_r4_set_hw_breakpoint(state, addr, no);\ 42 | } while (0) 43 | #define set_hw_watchpoint(state, addr, no) do {\ 44 | armv7_cortex_r4_enable_monitor_mode(state);\ 45 | armv7_cortex_r4_set_hw_watchpoint(state, addr, no, 4);\ 46 | } while (0) 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/crc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef CRC_H_ 9 | #define CRC_H_ 10 | 11 | #include 12 | 13 | unsigned char crc_calc(uint8_t * crc, uint8_t data); 14 | 15 | #endif /* CRC_H_ */ 16 | -------------------------------------------------------------------------------- /include/gdb_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _GDB_UTILS_H 9 | #define _GDB_UTILS_H 10 | 11 | #include 12 | typedef unsigned size_t; 13 | 14 | /* Defined in utils.c */ 15 | char nibble_to_hex_char(uint8_t nibble); 16 | size_t strlen(const char * str); 17 | int hex_char_to_nibble(char c); 18 | int is_name_character(char c); 19 | 20 | #endif /* _GDB_UTILS_H */ 21 | -------------------------------------------------------------------------------- /include/inforad_k0_gdb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _INFORAD_K0_GDB_CONFIG_H 9 | #define _INFORAD_K0_GDB_CONFIG_H 10 | 11 | #define UART_SIRF_BASE ((volatile uint16_t *) 0x80030000) 12 | 13 | #include "GdbHostInterface.h" 14 | #include "ArmRegisterMap.h" 15 | /* This include has to be last, to not trespass on definitions that should be made in other files */ 16 | #include "DefaultDefines.h" 17 | 18 | #endif /* _INFORAD_K0_GDB_CONFIG_H */ 19 | -------------------------------------------------------------------------------- /include/plc_bootloader_gdb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | #ifndef _PLC_BOOTLOADER_GDB_CONFIG_H 8 | #define _PLC_BOOTLOADER_GDB_CONFIG_H 9 | 10 | #define UART_PL011_BASE ((volatile uint32_t *) 0xfffb8000) 11 | 12 | #include 13 | 14 | static inline void led_set(uint32_t val) 15 | { 16 | *(volatile uint32_t *)(0xfffbb154) = val; 17 | } 18 | 19 | static inline uint32_t led_get(void) 20 | { 21 | return *(volatile uint32_t *)(0xfffbb154); 22 | } 23 | 24 | static inline void led_toggle(uint32_t led_id) 25 | { 26 | uint32_t v = led_get(); 27 | v ^= 1 << (led_id<<4); 28 | led_set(v); 29 | } 30 | 31 | static inline void led_on(uint32_t led_id) 32 | { 33 | led_set(led_get() | (1 << (led_id<<4))); 34 | } 35 | 36 | static inline void led_off(uint32_t led_id) 37 | { 38 | led_set(led_get() & (~(1 << (led_id<<4)))); 39 | } 40 | 41 | static inline void led_blink(uint32_t led_id) 42 | { 43 | led_set(0x1f320000 | ((led_get() | (1 << (led_id<<4))) & 0x0000ffff)); 44 | } 45 | 46 | #define LED_RED 0 47 | #define LED_GREEN 1 48 | #define LED_ORANGE0 2 49 | #define LED_ORANGE1 3 50 | 51 | #define signal_debug_enter() do {led_blink(LED_RED); } while (0) 52 | #define signal_debug_exit() do {led_off(LED_RED); } while (0) 53 | 54 | #define WATCHDOG_EXCITE do {*((volatile uint32_t *)0xFFFBB120) = 0x967EA5C3;} while (0) 55 | 56 | #define HAS_LOW_LEVEL_HELPERS 1 57 | 58 | #define CONFIG_CHECKSUM 1 59 | 60 | #include "GdbHostInterface.h" 61 | #include "ArmRegisterMap.h" 62 | #include "Serial.h" 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /include/qemu_versatilepb_gdb_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #ifndef _QEMU_VERSATILEPB_GDB_CONFIG_H 9 | #define _QEMU_VERSATILEPB_GDB_CONFIG_H 10 | 11 | #define UART_PL011_BASE ((volatile uint32_t *) 0x101F1000) 12 | 13 | #include "GdbHostInterface.h" 14 | #include "ArmRegisterMap.h" 15 | 16 | #endif /* _QEMU_VERSATILEPB_GDB_CONFIG_H */ 17 | -------------------------------------------------------------------------------- /include/stdlib/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _STDLIB_STRING_H 2 | #define _STDLIB_STRING_H 3 | 4 | #include "stdlib/stdlib.h" 5 | 6 | void * memcpy(void *dst, const void *src, size_t len); 7 | void * memset(void *buf, int c, size_t len); 8 | size_t strlen(const char * str); 9 | int strcmp(const char * str1, const char * str2); 10 | 11 | #endif /* _STDLIB_STRING_H */ 12 | -------------------------------------------------------------------------------- /link/arm_ST3320413AS_0x3FC000.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_start) 11 | SECTIONS 12 | { 13 | . = 0x3FC000 ; 14 | _gdb_stub_start = .; 15 | .text : { *(.header) *(.start) *(.text) } 16 | .data : { *(.data) } 17 | .bss : { *(.bss) } 18 | _gdb_stub_end = .; 19 | } 20 | -------------------------------------------------------------------------------- /link/arm_ST3320413AS_0x7000.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_start) 11 | SECTIONS 12 | { 13 | . = 0x7000 ; 14 | _gdb_stub_start = .; 15 | .text : { *(.header) *(.start) *(.text) } 16 | .data : { *(.data) } 17 | .bss : { *(.bss) } 18 | _gdb_stub_end = .; 19 | } 20 | -------------------------------------------------------------------------------- /link/arm_beagleboard.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_start) 11 | SECTIONS 12 | { 13 | . = 0x80000000 ; 14 | _gdb_stub_start = .; 15 | /* . = 0x359E00 ; */ 16 | .text : { *(.vect) *(.text) } 17 | .data : { *(.data) } 18 | .bss : { *(.bss) } 19 | _gdb_stub_end = .; 20 | } 21 | -------------------------------------------------------------------------------- /link/arm_inforad_k0_0x0.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_start) 11 | SECTIONS 12 | { 13 | . = 0x0 ; 14 | _gdb_stub_start = .; 15 | .text : { *(.exception_table) *(.init) *(.text) } 16 | .data : { *(.data) } 17 | .bss : { *(.bss) } 18 | _gdb_stub_end = .; 19 | } 20 | -------------------------------------------------------------------------------- /link/arm_plc_bootloader_0x16000.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-bigarm", "elf32-bigarm", "elf32-bigarm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_start) 11 | SECTIONS 12 | { 13 | . = 0x16000 ; 14 | _gdb_stub_start = .; 15 | .text : { *(.header) *(.start) *(.text) } 16 | .data : { *(.data) } 17 | .bss : { *(.bss) } 18 | _gdb_stub_end = .; 19 | } 20 | -------------------------------------------------------------------------------- /link/arm_qemu_versatilepb.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_start) 11 | SECTIONS 12 | { 13 | _gdb_stub_start = .; 14 | .text : { *(.exception_table) *(.init) *(.text) } 15 | .data : { *(.data) } 16 | .bss : { *(.bss) } 17 | 18 | /* 19 | .debug_info : { *(.debug_info) } 20 | .rel.debug_info : { *(.rel.debug_info) } 21 | .debug_abbrev : { *(.debug_abbrev) } 22 | .debug_loc : { *(.debug_loc) } 23 | .debug_aranges : { *(.debug_aranges) } 24 | .rel.debug_arange : { *(.rel.debug_arange) } 25 | .debug_line : { *(.debug_line) } 26 | .rel.debug_line : { *(.rel.debug_line) } 27 | .debug_str : { *(.debug_str) } 28 | .comment : { *(.comment) } 29 | .ARM.attributes : { *(.ARM.attributes) } 30 | .debug_frame : { *(.debug_frame) } 31 | .rel.debug_frame : { *(.rel.debug_frame) } 32 | .shstrtab : { *(.shstrtab) } 33 | .symtab : { *(.symtab) } */ 34 | _gdb_stub_end = .; 35 | } 36 | -------------------------------------------------------------------------------- /scripts/Inforad_K0_flasher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import argparse 4 | import sys 5 | import serial 6 | import platform 7 | import os 8 | import subprocess 9 | import select 10 | import socket 11 | import time 12 | from functools import reduce 13 | import logging 14 | 15 | 16 | #How many times we retry an operation before giving up 17 | MAX_ERROR_COUNT = 5 18 | 19 | log = logging.getLogger("Inforad_K0_flasher") 20 | 21 | class FlasherError(RuntimeError): 22 | def __init__(self, message): 23 | super(FlasherError, self).__init__(message) 24 | 25 | def encode_nmea_message(cmd): 26 | checksum = reduce(lambda r, x: r ^ x, cmd.encode(encoding = "ascii")) 27 | return ("$%s*%02X\r\n" % (cmd, checksum)).encode(encoding = "ascii") 28 | 29 | class SirfGPS(): 30 | def __init__(self, port): 31 | self._portname = port 32 | self._port = serial.Serial(port, 4800, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE) 33 | 34 | def switch_to_binary_sirf(self): 35 | nmea_cmd = "PSRF100,0,38400,8,1,0" 36 | raw_cmd = encode_nmea_message(nmea_cmd) 37 | 38 | nonascii_found = False 39 | error_count = 0 40 | while not nonascii_found and error_count < MAX_ERROR_COUNT: 41 | self._port.write("\r\n".encode(encoding = "ascii")) 42 | self._port.flush() 43 | self._port.write(raw_cmd) 44 | self._port.flush() 45 | time.sleep(0.5) 46 | self._port.timeout = 0.1 47 | 48 | try: 49 | for count in range(0, 10000): 50 | data = self._port.read(1) 51 | if not data: 52 | break 53 | if data[0] >= 128: 54 | nonascii_found = True 55 | break 56 | 57 | except serial.SerialTimeoutException: 58 | pass 59 | 60 | error_count += 1 61 | 62 | if error_count >= MAX_ERROR_COUNT: 63 | log.error("Too many errors while trying to switch to binary SIRF mode, aborting") 64 | raise FlasherError("Error switching to binary SIRF mode") 65 | 66 | self._port.baudrate = 38400 67 | 68 | def switch_to_bootloader_mode(self): 69 | error_count = 0 70 | while error_count < MAX_ERROR_COUNT: 71 | self._port.write(bytes([0xa0, 0xa2, 0x00, 0x01, 0x94, 0x00, 0x94, 0xb0, 0xb3])) 72 | self._port.flush() 73 | 74 | time.sleep(0.1) 75 | #drain input buffer 76 | self._port.timeout = 0.1 77 | try: 78 | while self._port.read(1): 79 | pass 80 | except serial.SerialTimeoutException: 81 | pass 82 | 83 | time.sleep(0.5) 84 | self._port.timeout = 0.5 85 | try: 86 | data = self._port.read(1) 87 | if data: 88 | error_count += 1 89 | continue 90 | else: 91 | break 92 | except serial.SerialTimeoutException: 93 | break 94 | 95 | if error_count >= MAX_ERROR_COUNT: 96 | log.error("Too many errors while trying to switch to bootloader mode, aborting") 97 | raise FlasherError("Error switching to bootloader mode") 98 | self._port.timeout = None 99 | 100 | def upload_bootloader(self, bootloader): 101 | msg = bytes([0x53, 0x00, 0x00, 0x00, (len(bootloader) >> 8) & 0xff, len(bootloader) & 0xff]) 102 | self._port.write(msg) 103 | 104 | for i in range(0, len(bootloader), 512): 105 | self._port.write(bootloader[i: min(len(bootloader), i + 512)]) 106 | 107 | self._port.timeout = None 108 | 109 | #Probably the start address 110 | self._port.write(bytes([0x00, 0x00, 0x00, 0x00])) 111 | self._port.flush() 112 | 113 | def serve_serial_port(self, port): 114 | server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 115 | server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 116 | server_socket.bind(("localhost", port)) 117 | server_socket.listen(1) 118 | self._port.timeout = 0 119 | (client_socket, sockaddr) = server_socket.accept() 120 | log.info("Client connected from %s:%d" % (sockaddr[0], sockaddr[1])) 121 | try: 122 | while True: 123 | (rd, wr, err) = select.select([client_socket, self._port, server_socket], [], [], 1) 124 | if err: 125 | break 126 | if server_socket in rd: 127 | client_socket.close() 128 | (client_socket, sockaddr) = server_socket.accept() 129 | log.info("Changing to new client from %s:%d", sockaddr[0], sockaddr[1]) 130 | else: 131 | if client_socket in rd: 132 | self._port.write(client_socket.recv(4096)) 133 | if self._port in rd: 134 | client_socket.send(self._port.read(4096)) 135 | except socket.error: 136 | log.error("ERROR: Socket disconnected") 137 | 138 | 139 | #Do not know if this acknowledgement is already from our bootloader or the ROM loader 140 | # data = self._port.read(1) 141 | # if len(data) == 1 and data[0] == 0x06: 142 | 143 | def main(): 144 | parser = argparse.ArgumentParser(description = "Run a debugging stub on the Inforad K0 GPS stick.") 145 | parser.add_argument("-s", "--serial", metavar = "FILE", dest = "serial", default = "/dev/ttyUSB0", help = "Serial port where the GPS is connected") 146 | parser.add_argument("loader_file", metavar = "FILE", help = "Bootloader file") 147 | parser.add_argument("-p", "--port", type = int, dest = "port", default = 2000, help = "TCP port serving the serial connection") 148 | parser.add_argument("-v", "--verbose", action = "store_true", default = False, help = "More verbose output") 149 | 150 | args = parser.parse_args() 151 | 152 | if args.verbose: 153 | logging.basicConfig(level = logging.INFO) 154 | else: 155 | logging.basicConfig(level = logging.WARN) 156 | 157 | gps = SirfGPS(args.serial) 158 | with open(args.loader_file, 'rb') as file: 159 | bootloader = file.read() 160 | 161 | gps.switch_to_binary_sirf() 162 | print("Switched to binary SIRF mode") 163 | gps.switch_to_bootloader_mode() 164 | print("Switched to bootloader mode") 165 | # while True: 166 | # data = gps._port.read(1) 167 | # if data: 168 | # sys.stdout.write(data.decode(encoding = "iso-8859-1")) 169 | gps.upload_bootloader(bootloader) 170 | print("Uploaded bootloader, serving TCP port") 171 | gps.serve_serial_port(args.port) 172 | 173 | if __name__ == "__main__": 174 | main() 175 | 176 | -------------------------------------------------------------------------------- /scripts/Seagate_ST3320413AS_flasher.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2013-2014 Jonas Zaddach , EURECOM 4 | # 5 | # You can redistribute and/or modify this program under the terms of the 6 | # GNU General Public License version 2 or later. 7 | 8 | 9 | import serial 10 | import logging 11 | import time 12 | import re 13 | import select 14 | import socket 15 | import argparse 16 | import subprocess 17 | 18 | SLEEP_TIME_BETWEEN_OFF_ON = 3 19 | MAX_ENTER_BOOT_MENU_TIME = 3 20 | 21 | log = logging.getLogger(__name__) 22 | 23 | class GdbFilter(): 24 | def __init__(self): 25 | self._state = 0 26 | def add_character(self, c): 27 | if self._state == 0 and c in [ord('+'), ord('-')]: 28 | return bytes([c]) 29 | elif c == ord('$'): 30 | self._state = 1 31 | self._buffer = [c] 32 | elif self._state == 1: 33 | self._buffer.append(c) 34 | if c == ord('#'): 35 | self._state = 2 36 | elif self._state == 2: 37 | self._buffer.append(c) 38 | self._state = 3 39 | elif self._state == 3: 40 | self._buffer.append(c) 41 | self._state = 0 42 | return bytes(self._buffer) 43 | return None 44 | 45 | 46 | 47 | class ResetController(): 48 | def __init__(self, controller_script): 49 | self._controller_script = controller_script 50 | 51 | def set_on(self): 52 | subprocess.check_call([self._controller_script, "on"]) 53 | 54 | def set_off(self): 55 | subprocess.check_call([self._controller_script, "off"]) 56 | 57 | def reset(self): 58 | self.set_off() 59 | time.sleep(SLEEP_TIME_BETWEEN_OFF_ON) 60 | self.set_on() 61 | 62 | class UnexpectedReplyException(Exception): 63 | def __init__(self, reply): 64 | self._reply = reply 65 | 66 | def __str__(self): 67 | return "Unexpected reply: '%s'" % self._reply 68 | 69 | class StubDownloader(): 70 | def __init__(self, reset_controller, serial_port_name = "/dev/ttyUSB0"): 71 | if reset_controller is None: 72 | self._emulated_target = True 73 | else: 74 | self.reset_controller = reset_controller 75 | self._emulated_target = False 76 | 77 | self._serial_port = serial.Serial(port = serial_port_name, 78 | baudrate = 38400, 79 | bytesize = serial.EIGHTBITS, 80 | parity = serial.PARITY_NONE, 81 | stopbits = serial.STOPBITS_ONE, 82 | xonxoff = False, 83 | rtscts = False) 84 | self._serial_port_name = serial_port_name 85 | 86 | def _reset_hdd(self): 87 | self.reset_controller.reset() 88 | 89 | def _enter_bootloader(self): 90 | REX_BOOT_MENU_PROMPT = re.compile("Boot Cmds:") 91 | EXPRESSION_BOOT_CMDS = bytes("Boot Cmds:", encoding = 'ascii') 92 | EXPRESSION_RET = bytes("RET\r\n> ", encoding = 'ascii') 93 | EXPRESSION_ECHO_OFF = bytes("Echo off\r\n> ", encoding = 'ascii') 94 | buffer = bytes() 95 | old_timeout = self._serial_port.getTimeout() 96 | self._serial_port.setTimeout(0.01) 97 | start_enter_bootmenu_time = 0 98 | 99 | 100 | while not EXPRESSION_BOOT_CMDS in buffer: 101 | if time.time() - start_enter_bootmenu_time > MAX_ENTER_BOOT_MENU_TIME: 102 | self._reset_hdd() 103 | start_enter_bootmenu_time = time.time() 104 | buffer = bytes() 105 | 106 | self._serial_port.write(bytes('UUUUUUUUUUUUUUUUUU', encoding = 'ascii')) 107 | try: 108 | buffer += self._serial_port.read(1) 109 | except serial.serialutil.SerialException as ex: 110 | if not str(ex).startswith("device reports readiness to read"): 111 | raise ex 112 | 113 | #Flush input stream 114 | try: 115 | while select.select([self._serial_port], [], [], 0.01)[0]: 116 | self._serial_port.read(1) 117 | except serial.serialutil.SerialException as ex: 118 | if not str(ex).startswith("device reports readiness to read"): 119 | raise ex 120 | 121 | 122 | #Check that prompt is ready for commands (not trailing U in output) 123 | self._resynchronize_interface() 124 | 125 | log.info("Entered boot menu") 126 | self._serial_port.setTimeout(old_timeout) 127 | 128 | def _soft_enter_bootloader(self): 129 | old_timeout = self._serial_port.getTimeout() 130 | self._serial_port.setTimeout(0.01) 131 | 132 | self._reset_hdd() 133 | time.sleep(20) 134 | 135 | self._serial_port.write(bytes([0x1a])) 136 | self._serial_port.flush() 137 | time.sleep(0.1) 138 | self._serial_port.write(bytes([0x03])) 139 | 140 | 141 | EXPRESSION_BOOT_CMDS = bytes("Boot Cmds:", encoding = 'ascii') 142 | EXPRESSION_RET = bytes("RET\r\n> ", encoding = 'ascii') 143 | EXPRESSION_ECHO_OFF = bytes("Echo off\r\n> ", encoding = 'ascii') 144 | 145 | buffer = bytes() 146 | while not EXPRESSION_BOOT_CMDS in buffer: 147 | self._serial_port.write(bytes('UUUUUUUUUUUUUUUUUU', encoding = 'ascii')) 148 | try: 149 | buffer += self._serial_port.read(1) 150 | except serial.serialutil.SerialException as ex: 151 | if not str(ex).startswith("device reports readiness to read"): 152 | raise ex 153 | 154 | #Flush input stream 155 | try: 156 | while select.select([self._serial_port], [], [], 0.01)[0]: 157 | self._serial_port.read(1) 158 | except serial.serialutil.SerialException as ex: 159 | if not str(ex).startswith("device reports readiness to read"): 160 | raise ex 161 | 162 | 163 | #Check that prompt is ready for commands (not trailing U in output) 164 | self._resynchronize_interface() 165 | 166 | log.info("Entered boot menu") 167 | self._serial_port.setTimeout(old_timeout) 168 | 169 | def _resynchronize_interface(self): 170 | EXPRESSION_RET = bytes("RET\r\n> ", encoding = 'ascii') 171 | EXPRESSION_ECHO_OFF = bytes("Echo off\r\n> ", encoding = 'ascii') 172 | buffer = bytes() 173 | while not EXPRESSION_RET in buffer: 174 | self._serial_port.write(bytes("?", encoding = "ascii")) 175 | #Read all characters that are still in the input stream 176 | try: 177 | while select.select([self._serial_port], [], [], 0.01)[0]: 178 | buffer += self._serial_port.read(1) 179 | except serial.serialutil.SerialException as ex: 180 | if not str(ex).startswith("device reports readiness to read"): 181 | raise ex 182 | 183 | 184 | buffer = bytes() 185 | while not EXPRESSION_ECHO_OFF in buffer: 186 | self._serial_port.write(bytes("TE\r", encoding = 'ascii')) 187 | time.sleep(0.1) #sleep needed for emulated target 188 | while select.select([self._serial_port], [], [], 0.01)[0]: 189 | try: 190 | buffer += self._serial_port.read(1) 191 | except serial.serialutil.SerialException as ex: 192 | if not str(ex).startswith("device reports readiness to read"): 193 | raise ex 194 | 195 | #Flush input stream 196 | try: 197 | while select.select([self._serial_port], [], [], 0.01)[0]: 198 | self._serial_port.read(1) 199 | except serial.serialutil.SerialException as ex: 200 | if not str(ex).startswith("device reports readiness to read"): 201 | raise ex 202 | 203 | def _set_baudrate(self, baudrate): 204 | DIVISOR_TABLE = {9600 : 0x28b, 205 | 19200 : 0x146, 206 | 38400 : 0xa3, 207 | 57600 : 0x6d, 208 | 115200 : 0x36, 209 | 230400 : 0x1b, 210 | 460800 : 0xe, 211 | 625000 : 0xa, 212 | 921000 : 7, 213 | 921600 : 7, 214 | 1228000: 5, 215 | 1250000: 5} 216 | 217 | self._serial_port.write(bytes("BR %x\r" % DIVISOR_TABLE[baudrate], encoding = 'ascii')) 218 | 219 | while select.select([self._serial_port], [], [], 0.01)[0]: 220 | self._serial_port.read(1) 221 | 222 | self._serial_port.close() 223 | 224 | self._serial_port = serial.Serial(port = self._serial_port_name, 225 | baudrate = baudrate, 226 | bytesize = serial.EIGHTBITS, 227 | parity = serial.PARITY_NONE, 228 | stopbits = serial.STOPBITS_ONE, 229 | xonxoff = False, 230 | rtscts = False) 231 | 232 | 233 | self._serial_port.write(bytes("?", encoding = "ascii")) 234 | #Read all characters that are still in the input stream 235 | while select.select([self._serial_port], [], [], 0.01)[0]: 236 | self._serial_port.read(1) 237 | 238 | log.info("Set baudrate finished") 239 | 240 | def _set_address_pointer(self, address): 241 | 242 | data = bytes("AP %X\r" % address, encoding = "ascii") 243 | self._serial_port.write(data) 244 | 245 | expected_reply = bytes("\r\nAddr Ptr = 0x%08X\r\n> " % address, encoding = 'ascii') 246 | to_read_bytes = len(data) + len(expected_reply) 247 | reply = bytes() 248 | try: 249 | reply = self._serial_port.read(to_read_bytes) 250 | except serial.serialutil.SerialException as ex: 251 | if not str(ex).startswith("device reports readiness to read"): 252 | raise ex 253 | 254 | if reply != data + expected_reply: 255 | raise UnexpectedReplyException(reply) 256 | 257 | def _write_byte(self, val): 258 | EXPECTED_REPLY = bytes("\r\n> ", encoding = 'ascii') 259 | data = bytes("WT %X\r" % val, encoding = 'ascii') 260 | self._serial_port.write(data) 261 | 262 | reply = self._serial_port.read(len(data) + len(EXPECTED_REPLY)) 263 | if reply != data + EXPECTED_REPLY: 264 | raise UnexpectedReplyException(reply) 265 | 266 | def write_data(self, data, address): 267 | self._set_address_pointer(address) 268 | for byte in data: 269 | self._write_byte(byte) 270 | 271 | def _go(self): 272 | data = bytes("GO\r", encoding = 'ascii') 273 | self._serial_port.write(data) 274 | 275 | reply = self._serial_port.read(len(data) + len("\r\nRun: 0x001004E9\r\n")) 276 | if not re.match("GO\r\r\nRun: 0x[0-9A-F]{8}\r\n", reply.decode('ascii')): 277 | raise UnexpectedReplyException(reply) 278 | 279 | 280 | def run_address(self, address): 281 | self._set_address_pointer(address) 282 | self._go() 283 | 284 | 285 | def load_stub(self, stub_file, address, entry_point, baudrate = 115200, soft_reboot = False): 286 | if not self._emulated_target: 287 | self._enter_bootloader() 288 | # self._soft_enter_bootloader() 289 | self._set_baudrate(baudrate) 290 | else: 291 | self._resynchronize_interface() 292 | file = open(stub_file, 'rb') 293 | self.write_data(file.read(), address) 294 | self.run_address(entry_point) 295 | 296 | def serve_serial_port(self, port): 297 | LOCAL_LISTEN_ADDRESS = ("127.0.0.1", port) 298 | gdb_filter = GdbFilter() 299 | server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 300 | server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 301 | server_socket.bind(LOCAL_LISTEN_ADDRESS) 302 | server_socket.listen(1) 303 | log.info("Waiting for client connection on %s:%d", LOCAL_LISTEN_ADDRESS[0], LOCAL_LISTEN_ADDRESS[1]) 304 | (client_socket, sockaddr) = server_socket.accept() 305 | log.info("Client connected from %s:%d", sockaddr[0], sockaddr[1]) 306 | try: 307 | while True: 308 | (rd, wr, err) = select.select([client_socket, self._serial_port, server_socket], [], [], 1) 309 | if err: 310 | break 311 | if server_socket in rd: 312 | client_socket.close() 313 | (client_socket, sockaddr) = server_socket.accept() 314 | log.info("Changing to new client from %s:%d", sockaddr[0], sockaddr[1]) 315 | else: 316 | if client_socket in rd: 317 | self._serial_port.write(client_socket.recv(4096)) 318 | if self._serial_port in rd: 319 | msg = gdb_filter.add_character(self._serial_port.read(1)[0]) 320 | if not msg is None: 321 | # log.debug("Sending message: %s", " ".join(["%02x" % x for x in msg])) 322 | client_socket.send(msg) 323 | except socket.error: 324 | log.exception("Socket disconnected") 325 | 326 | def parse_arguments(): 327 | parser = argparse.ArgumentParser() 328 | parser.add_argument("-v", "--verbose", action = "count", default = 0, dest = "verbosity", 329 | help = "Increase verbosity (Can be specified several times to increase more)") 330 | parser.add_argument("--power-control", type = str, metavar = "FILE", dest = "power_control", 331 | help = "Executable that can switch the HDD on and off (\"on\" or \"off\" is passed as first argument)") 332 | parser.add_argument("--serial", type = str, metavar = "FILE", dest = "serial", 333 | help = "Serial port to which the HDD is connected") 334 | parser.add_argument("--gdbstub", type = str, metavar = "FILE", dest = "gdbstub", 335 | help = "GDB stub that is injected in the HDD") 336 | parser.add_argument("--gdbstub-loadaddress", type = int, dest = "gdbstub_loadaddress", 337 | help = "Load address of GDB stub") 338 | parser.add_argument("--port", type = int, default = 2000, dest = "port", 339 | help = "Port where HDD flasher is listening for serial connections after GDB stub has been flashed") 340 | return parser.parse_args() 341 | 342 | def set_verbosity(verbosity): 343 | if verbosity >= 3: 344 | logging.basicConfig(level = logging.DEBUG) 345 | elif verbosity >= 2: 346 | logging.basicConfig(level = logging.INFO) 347 | elif verbosity >= 1: 348 | logging.basicConfig(level = logging.WARN) 349 | else: 350 | logging.basicConfig(level = logging.ERROR) 351 | 352 | def main(): 353 | args = parse_arguments() 354 | set_verbosity(args.verbosity) 355 | 356 | stub_downloader = StubDownloader(ResetController(args.power_control), args.serial) 357 | log.info("Serial ports opened") 358 | stub_downloader.load_stub(args.gdbstub, args.gdbstub_loadaddress, args.gdbstub_loadaddress) 359 | log.info("Stub download finished") 360 | while True: 361 | stub_downloader.serve_serial_port(args.port) 362 | log.warn("Serial port stream client disconnected") 363 | log.info("exiting") 364 | 365 | if __name__ == "__main__": 366 | main() 367 | -------------------------------------------------------------------------------- /src/ArmGdbHelpers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "ArmGdbHelpers.h" 9 | #include "RegisterMap.h" 10 | #include "ArmRegisterMap.h" 11 | #include "Assert.h" 12 | 13 | unsigned Gdb_map_gdb_register_number_to_stub(StubState *state, unsigned reg) 14 | { 15 | if (reg >= 0 && reg <= 12) //R0 -R12 16 | return REG_R0 + reg; 17 | else if (reg >= 13 && reg <= 14) 18 | { 19 | uint32_t spsr = RegisterMap_get_register(state, REG_SPSR_ABT); 20 | switch (spsr & 0x1F) 21 | { 22 | case 0x10: //USR 23 | if (reg == 13) 24 | return REG_SP_USR; 25 | else 26 | return REG_LR_USR; 27 | case 0x11: //FIQ 28 | if (reg == 13) 29 | return REG_SP_FIQ; 30 | else 31 | return REG_LR_FIQ; 32 | case 0x12: //IRQ 33 | if (reg == 13) 34 | return REG_SP_IRQ; 35 | else 36 | return REG_LR_IRQ; 37 | case 0x13: //SVC 38 | if (reg == 13) 39 | return REG_SP_SVC; 40 | else 41 | return REG_LR_SVC; 42 | case 0x17: //ABRT 43 | if (reg == 13) 44 | return REG_SP_ABT; 45 | else 46 | return REG_PC; 47 | case 0x1b: //UND 48 | if (reg == 13) 49 | return REG_SP_UND; 50 | else 51 | return REG_LR_UND; 52 | case 0x1f: //SYS 53 | if (reg == 13) 54 | return REG_SP_SYS; 55 | else 56 | return REG_LR_SYS; 57 | default: //Unkown mode 58 | return 0; 59 | } 60 | } 61 | else 62 | { 63 | switch (reg) 64 | { 65 | case 15: //PC or LR_abrt 66 | case 51: 67 | return REG_PC; 68 | case 25: //SPSR_abrt == CPSR of previous mode 69 | case 49: 70 | return REG_SPSR_ABT; 71 | case 27: 72 | return REG_SP_USR; 73 | case 28: 74 | return REG_LR_USR; 75 | case 29: 76 | return REG_SPSR_FIQ; 77 | case 30: 78 | case 31: 79 | case 32: 80 | case 33: 81 | case 34: 82 | return REG_R8_FIQ + reg - 30; 83 | case 35: 84 | return REG_SP_FIQ; 85 | case 36: 86 | return REG_LR_FIQ; 87 | case 37: 88 | return REG_SPSR_IRQ; 89 | case 38: 90 | return REG_SP_IRQ; 91 | case 39: 92 | return REG_LR_IRQ; 93 | case 40: 94 | return REG_SPSR_SVC; 95 | case 41: 96 | return REG_SP_SVC; 97 | case 42: 98 | return REG_LR_SVC; 99 | case 43: 100 | return REG_SPSR_UND; 101 | case 44: 102 | return REG_SP_UND; 103 | case 45: 104 | return REG_LR_UND; 105 | case 46: 106 | return REG_SPSR_SYS; 107 | case 47: 108 | return REG_SP_SYS; 109 | case 48: 110 | return REG_LR_SYS; 111 | case 50: 112 | return REG_SP_ABT; 113 | } 114 | } 115 | 116 | assert(0 && "Unknown GDB register number"); 117 | return INVALID_REGISTER; 118 | } 119 | 120 | void Gdb_continue_execution(StubState *state) 121 | { 122 | register_t pc = RegisterMap_get_register(state, REG_PC); 123 | register_t cpsr = RegisterMap_get_register(state, REG_SPSR_ABT); 124 | 125 | if (cpsr & 0x20) //Thumb 126 | { 127 | if ((*((uint16_t *) pc) & 0xFF00) == 0xBE00) //Thumb bkpt instruction 128 | { 129 | RegisterMap_set_register(state, REG_PC, pc + 2); 130 | } 131 | } 132 | else 133 | { 134 | if ((*((uint32_t *) pc) & 0xFFF000F0) == 0xE1200070) //ARM bkpt instruction 135 | { 136 | RegisterMap_set_register(state, REG_PC, pc + 4); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/ArmRegisterMap.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include 9 | 10 | #include "RegisterMap.h" 11 | #include "ArmRegisterMap.h" 12 | #include "Assert.h" 13 | 14 | register_t RegisterMap_get_register(StubState *state, unsigned reg) 15 | { 16 | assert(reg <= REG_PC); 17 | 18 | return ((uint32_t *) state->register_map)[reg]; 19 | } 20 | 21 | /** 22 | * Set a value in the register map. 23 | */ 24 | void RegisterMap_set_register(StubState *state, unsigned reg, register_t val) 25 | { 26 | assert(reg <= REG_PC); 27 | 28 | ((uint32_t *) state->register_map)[reg] = val; 29 | } 30 | -------------------------------------------------------------------------------- /src/AvatarHostInterface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Created on: Apr 19, 2013 3 | * 4 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 5 | * 6 | * You can redistribute and/or modify this program under the terms of the 7 | * GNU General Public License version 2 or later. 8 | */ 9 | 10 | #include "AvatarHostInterface.h" 11 | #include "Serial.h" 12 | #include "StubState.h" 13 | #include "crc.h" 14 | #include "Memory.h" 15 | #include "RegisterMap.h" 16 | 17 | #define SERIAL_BREAK 0x100 18 | 19 | 20 | static int recv_byte_unescape() 21 | { 22 | int val; 23 | 24 | val = Serial_read_byte_blocking(); 25 | 26 | if (val == 0x55) 27 | return SERIAL_BREAK; 28 | else if (val == 0xAA) 29 | { 30 | int second_char = Serial_read_byte_blocking(); 31 | 32 | if (second_char == -1) 33 | return -1; 34 | else if (second_char == 0x01) 35 | return 0x55; 36 | else if (second_char == 0x02) 37 | return 0xAA; 38 | else 39 | /* Error: Unknown escape code */ 40 | return -1; 41 | } 42 | else 43 | return val; 44 | } 45 | 46 | static int send_byte_escape(int val) 47 | { 48 | if (val == SERIAL_BREAK) 49 | return Serial_write_byte(0x55); 50 | else 51 | { 52 | if (val == 0x55) 53 | { 54 | if (Serial_write_byte(0xAA)) 55 | return -1; 56 | return Serial_write_byte(0x01); 57 | } 58 | else if (val == 0xAA) 59 | { 60 | if (Serial_write_byte(0xAA)) 61 | return -1; 62 | return Serial_write_byte(0x02); 63 | } 64 | else 65 | { 66 | return Serial_write_byte(val); 67 | } 68 | } 69 | 70 | } 71 | 72 | 73 | static uint8_t recv_pull_uint8(StubState *state) 74 | { 75 | int val = -1; 76 | 77 | if (!state->host_interface.recv_error) 78 | val = recv_byte_unescape(); 79 | 80 | if (val == -1) 81 | state->host_interface.recv_error = 1; 82 | 83 | crc_calc(&state->host_interface.recv_checksum, val); 84 | 85 | return (uint8_t) val; 86 | } 87 | 88 | static int recv_start(StubState *state) 89 | { 90 | state->host_interface.recv_checksum = 0; 91 | state->host_interface.recv_error = 0; 92 | 93 | return recv_pull_uint8(state); 94 | } 95 | 96 | static uint16_t recv_pull_uint16(StubState *state) 97 | { 98 | uint16_t lower = recv_pull_uint8(state); 99 | uint16_t higher = recv_pull_uint8(state); 100 | 101 | return ((higher << 8) | lower); 102 | } 103 | 104 | static uint32_t recv_pull_uint32(StubState *state) 105 | { 106 | uint32_t lower = recv_pull_uint16(state); 107 | uint32_t higher = recv_pull_uint16(state); 108 | 109 | return (higher << 16) | lower; 110 | } 111 | 112 | static int recv_verify_checksum(StubState *state) 113 | { 114 | if (state->host_interface.recv_error) 115 | return 0; 116 | 117 | recv_pull_uint8(state); 118 | return state->host_interface.recv_checksum == 0; 119 | } 120 | 121 | 122 | static void send_push_uint8(StubState *state, uint8_t val) 123 | { 124 | if (send_byte_escape(val)) 125 | state->host_interface.send_error = 1; 126 | 127 | crc_calc(&state->host_interface.send_checksum, val); 128 | } 129 | 130 | static void send_start_message(StubState *state, int msg) 131 | { 132 | state->host_interface.send_checksum = 0; 133 | state->host_interface.send_error = 0; 134 | 135 | send_push_uint8(state, (uint8_t) msg); 136 | } 137 | 138 | static void send_push_uint16(StubState *state, uint16_t val) 139 | { 140 | send_push_uint8(state, val & 0xff); 141 | send_push_uint8(state, val >> 8); 142 | } 143 | 144 | static void send_push_uint32(StubState *state, uint32_t val) 145 | { 146 | send_push_uint16(state, val & 0xffff); 147 | send_push_uint16(state, val >> 16); 148 | } 149 | 150 | static void send_end_message(StubState *state) 151 | { 152 | send_byte_escape(state->host_interface.send_checksum); 153 | send_byte_escape(SERIAL_BREAK); 154 | } 155 | 156 | static void send_error_message(StubState *state, AvatarError err) 157 | { 158 | send_start_message(state, AVATAR_RPC_DTH_REPLY_ERROR); 159 | send_push_uint8(state, err); 160 | send_end_message(state); 161 | } 162 | 163 | // static void send_ok_message(StubState *state) 164 | // { 165 | // send_start_message(state, AVATAR_RPC_DTH_REPLY_OK); 166 | // send_end_message(state); 167 | // } 168 | 169 | void Avatar_report_state(StubState *state, AvatarVmState vm_state) 170 | { 171 | send_start_message(state, AVATAR_RPC_DTH_STATE); 172 | send_push_uint8(state, vm_state); 173 | send_end_message(state); 174 | } 175 | 176 | void Avatar_report_exception(StubState *state, AvatarProcessorException exc) 177 | { 178 | send_start_message(state, AVATAR_RPC_DTH_INFO_EXCEPTION); 179 | send_push_uint8(state, exc); 180 | send_end_message(state); 181 | } 182 | 183 | // void Avatar_handle_pagefault(uint32_t address, uint32_t size) 184 | // { 185 | // int exit_loop = 0; 186 | // 187 | // send_start_message(AVATAR_RPC_DTH_PAGEFAULT); 188 | // //TODO: Page bits hardcoded (6) 189 | // send_push_uint32(address & (0xFFFFFFFF << 6)); 190 | // send_end_message(); 191 | // 192 | // while (!exit_loop) 193 | // { 194 | // int cmd = recv_start(); 195 | // /* TODO: Error handling, check cmd != -1 */ 196 | // switch (cmd) 197 | // { 198 | // case AVATAR_RPC_HTD_INSERT_PAGE: 199 | // { 200 | // uint32_t page_address = recv_pull_uint32(); 201 | // int i; 202 | // uint8_t page[AVATAR_PAGE_SIZE]; 203 | // 204 | // for (i = 0; i < AVATAR_PAGE_SIZE; i++) 205 | // { 206 | // page[i] = recv_pull_uint8(); 207 | // } 208 | // 209 | // if (recv_verify_checksum()) 210 | // { 211 | // send_ok_message(); 212 | // Avatar_memory_insert_page(page_address, page); 213 | // } 214 | // else 215 | // { 216 | // send_error_message(AVATAR_ERROR_CHECKSUM); 217 | // } 218 | // break; 219 | // } 220 | // case AVATAR_RPC_HTD_CONTINUE_FROM_PAGEFAULT: 221 | // { 222 | // if (recv_verify_checksum()) 223 | // { 224 | // exit_loop = 1; 225 | // } 226 | // else 227 | // { 228 | // send_error_message(AVATAR_ERROR_CHECKSUM); 229 | // } 230 | // break; 231 | // } 232 | // case AVATAR_RPC_HTD_QUERY_STATE: 233 | // { 234 | // if (recv_verify_checksum()) 235 | // { 236 | // Avatar_report_state(Avatar_vm_get_state()); 237 | // } 238 | // else 239 | // { 240 | // send_error_message(AVATAR_ERROR_CHECKSUM); 241 | // } 242 | // break; 243 | // } 244 | // default: 245 | // { 246 | // if (recv_verify_checksum()) 247 | // { 248 | // send_start_message(AVATAR_RPC_DTH_PAGEFAULT); 249 | // send_push_uint32(address & (0xFFFFFFFF << 6)); 250 | // send_end_message(); 251 | // } 252 | // else 253 | // { 254 | // send_error_message(AVATAR_ERROR_CHECKSUM); 255 | // } 256 | // break; 257 | // } 258 | // } 259 | // 260 | // 261 | // while (recv_byte_unescape() != SERIAL_BREAK); 262 | // } 263 | // } 264 | 265 | void HostInterface_init(StubState *state) 266 | { 267 | //Nothing to do 268 | } 269 | 270 | void HostInterface_communicate(StubState *state) 271 | { 272 | while (1) 273 | { 274 | int cmd = recv_start(state); 275 | /* TODO: Error handling, check cmd != -1 */ 276 | switch (cmd) 277 | { 278 | case AVATAR_RPC_HTD_READ_MEMORY: 279 | { 280 | uint32_t address = recv_pull_uint32(state); 281 | uint8_t size = recv_pull_uint8(state); 282 | if (recv_verify_checksum(state)) 283 | { 284 | value_t val = Memory_read_typed(state, address, size); 285 | send_start_message(state, AVATAR_RPC_DTH_REPLY_READ_MEMORY); 286 | send_push_uint8(state, size); 287 | switch (size) 288 | { 289 | case 1: 290 | send_push_uint8(state, val); 291 | break; 292 | case 2: 293 | send_push_uint16(state, val); 294 | break; 295 | default: 296 | send_push_uint32(state, val); 297 | break; 298 | } 299 | send_end_message(state); 300 | } 301 | else 302 | { 303 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 304 | } 305 | break; 306 | } 307 | case AVATAR_RPC_HTD_WRITE_MEMORY: 308 | { 309 | uint32_t address = recv_pull_uint32(state); 310 | uint8_t size = recv_pull_uint8(state); 311 | uint32_t val; 312 | 313 | switch (size) 314 | { 315 | case 1: 316 | val = recv_pull_uint8(state); 317 | break; 318 | case 2: 319 | val = recv_pull_uint16(state); 320 | break; 321 | default: 322 | val = recv_pull_uint32(state); 323 | break; 324 | } 325 | 326 | if (recv_verify_checksum(state)) 327 | { 328 | send_start_message(state, AVATAR_RPC_DTH_REPLY_OK); 329 | Memory_write_typed(state, address, size, val); 330 | send_end_message(state); 331 | } 332 | else 333 | { 334 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 335 | } 336 | break; 337 | } 338 | case AVATAR_RPC_HTD_READ_UNTYPED_MEMORY: 339 | { 340 | uint32_t address = recv_pull_uint32(state); 341 | uint8_t size = recv_pull_uint8(state); 342 | uint8_t i; 343 | 344 | if (recv_verify_checksum(state)) 345 | { 346 | send_start_message(state, AVATAR_RPC_DTH_REPLY_READ_UNTYPED_MEMORY); 347 | for (i = 0; i < size; i++) 348 | { 349 | send_push_uint8(state, Memory_read_typed(state, address, SIZE_CHAR)); 350 | } 351 | send_end_message(state); 352 | } 353 | else 354 | { 355 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 356 | } 357 | break; 358 | } 359 | case AVATAR_RPC_HTD_WRITE_UNTYPED_MEMORY: 360 | { 361 | uint32_t address = recv_pull_uint32(state); 362 | uint8_t size = recv_pull_uint8(state); 363 | uint8_t i; 364 | 365 | for (i = 0; i < size; i++) 366 | { 367 | Memory_write_typed(state, address + i, SIZE_CHAR, recv_pull_uint8(state)); 368 | } 369 | 370 | if (recv_verify_checksum(state)) 371 | { 372 | send_start_message(state, AVATAR_RPC_DTH_REPLY_OK); 373 | send_end_message(state); 374 | } 375 | else 376 | { 377 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 378 | } 379 | break; 380 | } 381 | case AVATAR_RPC_HTD_GET_REGISTER: 382 | { 383 | uint8_t regnum = recv_pull_uint8(state); 384 | 385 | if (recv_verify_checksum(state)) 386 | { 387 | send_start_message(state, AVATAR_RPC_DTH_REPLY_GET_REGISTER); 388 | send_push_uint32(state, RegisterMap_get_register(state, regnum)); 389 | send_end_message(state); 390 | } 391 | else 392 | { 393 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 394 | } 395 | break; 396 | } 397 | case AVATAR_RPC_HTD_SET_REGISTER: 398 | { 399 | uint8_t regnum = recv_pull_uint8(state); 400 | uint32_t val = recv_pull_uint32(state); 401 | 402 | if (recv_verify_checksum(state)) 403 | { 404 | send_start_message(state, AVATAR_RPC_DTH_REPLY_OK); 405 | RegisterMap_set_register(state, regnum, val); 406 | send_end_message(state); 407 | } 408 | else 409 | { 410 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 411 | } 412 | 413 | break; 414 | } 415 | // case AVATAR_RPC_HTD_INSERT_PAGE: 416 | // { 417 | // uint32_t page_address = recv_pull_uint32(state); 418 | // int i; 419 | // uint8_t page[AVATAR_PAGE_SIZE]; 420 | // 421 | // for (i = 0; i < AVATAR_PAGE_SIZE; i++) 422 | // { 423 | // page[i] = recv_pull_uint8(state); 424 | // } 425 | // 426 | // if (recv_verify_checksum(state)) 427 | // { 428 | // send_ok_message(state); 429 | // Avatar_memory_insert_page(page_address, page); 430 | // } 431 | // else 432 | // { 433 | // send_error_message(state, AVATAR_ERROR_CHECKSUM); 434 | // } 435 | // break; 436 | // } 437 | // case AVATAR_RPC_HTD_EXTRACT_PAGE: 438 | // { 439 | // uint32_t page_address = recv_pull_uint32(); 440 | // int i; 441 | // int err; 442 | // uint8_t page[AVATAR_PAGE_SIZE]; 443 | // 444 | // if (recv_verify_checksum()) 445 | // { 446 | // err = Avatar_memory_extract_page(page_address, page); 447 | // if (err) 448 | // { 449 | // send_error_message(err); 450 | // } 451 | // else 452 | // { 453 | // send_start_message(AVATAR_RPC_DTH_REPLY_EXTRACT_PAGE); 454 | // for (i = 0; i < AVATAR_PAGE_SIZE; i++) 455 | // { 456 | // send_push_uint8(page[i]); 457 | // } 458 | // send_end_message(); 459 | // } 460 | // } 461 | // else 462 | // { 463 | // send_error_message(AVATAR_ERROR_CHECKSUM); 464 | // } 465 | // break; 466 | // } 467 | // case AVATAR_RPC_HTD_UNMAP_PAGE: 468 | // { 469 | // uint32_t page_address = recv_pull_uint32(); 470 | // int err; 471 | // 472 | // if (recv_verify_checksum()) 473 | // { 474 | // err = Avatar_memory_unmap_page(page_address); 475 | // if (err) 476 | // { 477 | // send_error_message(err); 478 | // } 479 | // else 480 | // { 481 | // send_ok_message(); 482 | // } 483 | // } 484 | // else 485 | // { 486 | // send_error_message(AVATAR_ERROR_CHECKSUM); 487 | // } 488 | // break; 489 | // } 490 | // case AVATAR_RPC_HTD_SET_EXCEPTION_CONFIG: 491 | // { 492 | // uint32_t config = recv_pull_uint32(); 493 | // uint16_t squelch_irq_limit = recv_pull_uint16(); 494 | // uint16_t squelch_fiq_limit = recv_pull_uint16(); 495 | // uint32_t exception_vectors[8]; 496 | // int i; 497 | // int err; 498 | // 499 | // for (i = 0; i < 8; i++) 500 | // { 501 | // exception_vectors[i] = recv_pull_uint32(); 502 | // } 503 | // 504 | // if (recv_verify_checksum()) 505 | // { 506 | // err = Avatar_exception_set_configuration(config, squelch_irq_limit, squelch_fiq_limit, exception_vectors); 507 | // if (err) 508 | // send_error_message(err); 509 | // else 510 | // send_ok_message(); 511 | // } 512 | // else 513 | // send_error_message(AVATAR_ERROR_CHECKSUM); 514 | // break; 515 | // } 516 | // case AVATAR_RPC_HTD_CLEAR_EXCEPTION: 517 | // { 518 | // uint8_t exception_num = recv_pull_uint8(); 519 | // 520 | // if (recv_verify_checksum()) 521 | // { 522 | // Avatar_exception_clear(exception_num); 523 | // send_ok_message(); 524 | // } 525 | // else 526 | // send_error_message(AVATAR_ERROR_CHECKSUM); 527 | // break; 528 | // } 529 | // case AVATAR_RPC_HTD_ADD_EMULATED_INSTRUCTION: 530 | // { 531 | // uint32_t instr_address = recv_pull_uint32(); 532 | // uint8_t code_size = recv_pull_uint8(); 533 | // int err; 534 | // int i; 535 | // uint8_t code[AVATAR_MAX_MINIVM_CODE_SIZE]; 536 | // 537 | // if (code_size > AVATAR_MAX_MINIVM_CODE_SIZE) 538 | // { 539 | // for (i = 0; i < code_size; i++) 540 | // { 541 | // recv_pull_uint8(); 542 | // } 543 | // 544 | // recv_verify_checksum(); 545 | // send_error_message(AVATAR_ERROR_OUT_OF_BOUNDS); 546 | // } 547 | // else 548 | // { 549 | // for (i = 0; i < code_size; i++) 550 | // { 551 | // code[i] = recv_pull_uint8(); 552 | // } 553 | // if (recv_verify_checksum()) 554 | // { 555 | // err = Avatar_minivm_add_emulated_instruction(instr_address, code, code_size); 556 | // if (err) 557 | // { 558 | // send_error_message(AVATAR_RPC_DTH_REPLY_ERROR); 559 | // } 560 | // else 561 | // { 562 | // send_ok_message(); 563 | // } 564 | // } 565 | // else 566 | // { 567 | // send_error_message(AVATAR_ERROR_CHECKSUM); 568 | // } 569 | // 570 | // } 571 | // break; 572 | // } 573 | // case AVATAR_RPC_HTD_CLEAR_EMULATED_INSTRUCTIONS: 574 | // { 575 | // if (recv_verify_checksum()) 576 | // { 577 | // Avatar_minivm_clear_instructions(); 578 | // send_ok_message(); 579 | // } 580 | // else 581 | // { 582 | // send_error_message(AVATAR_ERROR_CHECKSUM); 583 | // } 584 | // break; 585 | // } 586 | // case AVATAR_RPC_HTD_SET_MEMORY_MAP: 587 | // { 588 | // uint8_t num_entries = recv_pull_uint8(); 589 | // int i; 590 | // int err; 591 | // AvatarMemoryMapEntry memory_map[AVATAR_MAX_MEMORY_MAP_ENTRIES]; 592 | // 593 | // if (num_entries > AVATAR_MAX_MEMORY_MAP_ENTRIES) 594 | // { 595 | // for(i = 0; i < num_entries * 3; i++) 596 | // { 597 | // recv_pull_uint32(); 598 | // } 599 | // recv_verify_checksum(); 600 | // send_error_message(AVATAR_ERROR_OUT_OF_BOUNDS); 601 | // } 602 | // else 603 | // { 604 | // for (i = 0; i < num_entries; i++) 605 | // { 606 | // memory_map[i].start = recv_pull_uint32(); 607 | // memory_map[i].end = recv_pull_uint32(); 608 | // memory_map[i].flags = recv_pull_uint32(); 609 | // } 610 | // 611 | // if (recv_verify_checksum()) 612 | // { 613 | // err = Avatar_memory_set_memory_map(memory_map, num_entries); 614 | // if (err) 615 | // send_error_message(err); 616 | // else 617 | // send_ok_message(); 618 | // } 619 | // else 620 | // send_error_message(AVATAR_ERROR_CHECKSUM); 621 | // } 622 | // break; 623 | // } 624 | case AVATAR_RPC_HTD_RESUME_VM: 625 | { 626 | if (recv_verify_checksum(state)) 627 | { 628 | while (recv_byte_unescape() != SERIAL_BREAK); 629 | /* No ok here, response is state message that is sent when VM stops */ 630 | return; 631 | // Avatar_vm_resume(); /* Does not return */ 632 | } 633 | else 634 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 635 | break; 636 | } 637 | case AVATAR_RPC_HTD_QUERY_STATE: 638 | { 639 | if (recv_verify_checksum(state)) 640 | { 641 | send_start_message(state, AVATAR_RPC_DTH_REPLY_STATE); 642 | send_push_uint8(state, state->signal); 643 | send_end_message(state); 644 | } 645 | else 646 | { 647 | send_error_message(state, AVATAR_ERROR_CHECKSUM); 648 | } 649 | break; 650 | } 651 | // case AVATAR_RPC_HTD_GET_DIRTY_PAGES: 652 | // { 653 | // uint32_t page_addresses[10]; 654 | // uint8_t num = 10; 655 | // uint8_t i; 656 | // 657 | // if (recv_verify_checksum()) 658 | // { 659 | // Avatar_memory_get_dirty_pages(page_addresses, &num); 660 | // send_start_message(AVATAR_RPC_DTH_REPLY_GET_DIRTY_PAGES); 661 | // send_push_uint8(num); 662 | // for(i = 0; i < num; i++) 663 | // { 664 | // send_push_uint32(page_addresses[i]); 665 | // } 666 | // send_end_message(); 667 | // } 668 | // else 669 | // { 670 | // send_error_message(AVATAR_ERROR_CHECKSUM); 671 | // } 672 | // break; 673 | // } 674 | // case AVATAR_RPC_HTD_CODELET_EXECUTE: 675 | // { 676 | // uint32_t codelet_address = recv_pull_uint32(); 677 | // 678 | // if (recv_verify_checksum()) 679 | // { 680 | // codelet_execute((void *) codelet_address); 681 | // send_start_message(AVATAR_RPC_DTH_REPLY_CODELET_EXECUTION_FINISHED); 682 | // send_end_message(); 683 | // } 684 | // else 685 | // { 686 | // send_error_message(AVATAR_ERROR_CHECKSUM); 687 | // } 688 | // break; 689 | // } 690 | } 691 | 692 | while (recv_byte_unescape() != SERIAL_BREAK); 693 | } 694 | } 695 | -------------------------------------------------------------------------------- /src/GdbHostInterface.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "Serial.h" 9 | #include "StubState.h" 10 | #include "Memory.h" 11 | #include "RegisterMap.h" 12 | #include "ArmGdbHelpers.h" 13 | #include "Assert.h" 14 | #include "gdb_utils.h" 15 | #include "SerialIO.h" 16 | #include "crc.h" 17 | 18 | static void target_enter_monitor(StubState *state) 19 | { 20 | } 21 | #ifdef HAS_LOW_LEVEL_HELPERS 22 | /* XXX: Hack */ 23 | #include "armv7_cortex_r4.h" 24 | #endif 25 | 26 | static void target_exit_monitor(StubState *state) 27 | { 28 | } 29 | #ifndef signal_debug_enter 30 | #define signal_debug_enter(...) do {} while (0) 31 | #endif 32 | #ifndef signal_debug_exit 33 | #define signal_debug_exit(...) do {} while (0) 34 | #endif 35 | #ifndef set_hw_breakpoint 36 | #define set_hw_breakpoint(...) do {} while (0) 37 | #endif 38 | #ifndef set_hw_watchpoint 39 | #define set_hw_watchpoint(...) do {} while (0) 40 | #endif 41 | 42 | #ifndef flush_data_cache 43 | #define flush_data_cache(...) do {} while (0) 44 | #endif 45 | 46 | #ifndef invalidate_instruction_cache 47 | #define invalidate_instruction_cache(...) do {} while (0) 48 | #endif 49 | 50 | #ifndef invalidate_data_cache 51 | #define invalidate_data_cache(...) do {} while (0) 52 | #endif 53 | 54 | #ifndef flush_data_cache_by_mva 55 | #define flush_data_cache_by_mva(...) do {} while (0) 56 | #endif 57 | 58 | static void start_packet(StubState *state); 59 | static void put_string(StubState *state, const char * str); 60 | static void end_packet(StubState *state); 61 | static uint32_t get_hex_number(StubState* state, unsigned digits); 62 | static int get_packet_byte(StubState* state); 63 | 64 | #ifdef CONFIG_MEMORY_ERROR 65 | static int in_memory_access = 0; 66 | #endif /* CONFIG_MEMORY_ERROR */ 67 | 68 | static void put_hex_uint8(StubState *state, uint8_t val) 69 | { 70 | char c = nibble_to_hex_char(val >> 4); 71 | state->host_interface.output_checksum += c; 72 | Serial_write_byte(c); 73 | c = nibble_to_hex_char(val); 74 | state->host_interface.output_checksum += c; 75 | Serial_write_byte(c); 76 | } 77 | 78 | 79 | void put_hex_buffer(StubState *state, const uint8_t * buffer, int len) 80 | { 81 | int i; 82 | 83 | for (i = 0; i < len; i++) 84 | { 85 | put_hex_uint8(state, buffer[i]); 86 | } 87 | } 88 | 89 | static void put_buffer(StubState *state, const uint8_t * buffer, int len) 90 | { 91 | int i; 92 | 93 | for (i = 0; i < len; i++) 94 | { 95 | state->host_interface.output_checksum += buffer[i]; 96 | Serial_write_byte(buffer[i]); 97 | } 98 | } 99 | 100 | static void put_ok_packet(StubState *state) 101 | { 102 | start_packet(state); 103 | put_string(state, "OK"); 104 | end_packet(state); 105 | } 106 | 107 | static void put_error_packet(StubState *state, int error) 108 | { 109 | start_packet(state); 110 | put_string(state, "E"); 111 | put_hex_uint8(state, error & 0xff); 112 | end_packet(state); 113 | } 114 | 115 | static void put_dummy_bytes(StubState *state, int count) 116 | { 117 | int i; 118 | 119 | for (i = 0; i < count; i++) 120 | put_hex_uint8(state, 0xFE); 121 | } 122 | 123 | void put_string(StubState *state, const char * str) 124 | { 125 | put_buffer(state, (const uint8_t *) str, strlen(str)); 126 | } 127 | 128 | 129 | void start_packet(StubState *state) 130 | { 131 | state->host_interface.output_checksum = 0; 132 | Serial_write_byte('$'); 133 | } 134 | 135 | void end_packet(StubState *state) 136 | { 137 | Serial_write_byte('#'); 138 | put_hex_uint8(state, state->host_interface.output_checksum); 139 | } 140 | 141 | static void put_signal_packet(StubState *state) 142 | { 143 | start_packet(state); 144 | put_string(state, "S"); 145 | put_hex_uint8(state, state->signal); 146 | end_packet(state); 147 | } 148 | 149 | static void put_empty_packet(StubState *state) 150 | { 151 | start_packet(state); 152 | end_packet(state); 153 | } 154 | 155 | void put_hex_uint32(StubState *state, uint32_t val) 156 | { 157 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 158 | /* put_hex_uint8(state, val >> 24); 159 | put_hex_uint8(state, val >> 16); 160 | put_hex_uint8(state, val >> 8); 161 | put_hex_uint8(state, val); */ 162 | } 163 | 164 | void put_hex_uint16(StubState *state, uint16_t val) 165 | { 166 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 167 | /* put_hex_uint8(state, val >> 8); 168 | put_hex_uint8(state, val); */ 169 | } 170 | 171 | /** 172 | * Read one byte encoded as two hex characters from the serial port. 173 | * @returns -1 if the end of command character '#' is detected, 174 | * -2 if a character cannot be converted to a hex nibble, 175 | * and the byte's value otherwise. 176 | */ 177 | static int get_hex_uint8(StubState* state) 178 | { 179 | uint8_t val = 0; 180 | uint8_t nibble; 181 | 182 | nibble = hex_char_to_nibble(get_packet_byte(state)); 183 | if (nibble == -1) 184 | { 185 | return -1; 186 | } 187 | val = nibble << 4; 188 | 189 | nibble = hex_char_to_nibble(get_packet_byte(state)); 190 | if (nibble == -1) 191 | { 192 | return -1; 193 | } 194 | 195 | return val | nibble; 196 | } 197 | 198 | static uint8_t get_checksum(StubState* state) 199 | { 200 | int low_nibble; 201 | int high_nibble; 202 | 203 | high_nibble = hex_char_to_nibble(Serial_read_byte_blocking()); 204 | if (high_nibble < 0) { 205 | //TODO: Error 206 | } 207 | low_nibble = hex_char_to_nibble(Serial_read_byte_blocking()); 208 | if (low_nibble < 0) { 209 | //TODO: Error 210 | } 211 | 212 | return (high_nibble << 4) | low_nibble; 213 | } 214 | 215 | static void get_hex_buffer(StubState *state, uint8_t *buffer, int len) 216 | { 217 | /* XXX: calling this function and the casting the result (buffer) to 218 | * uint32_t is forbidden, because this code should run on big and 219 | * little endian machines 220 | */ 221 | int i = 0; 222 | int byte; 223 | 224 | for (i = 0; i < len; i++) 225 | { 226 | byte = get_hex_uint8(state); 227 | if (byte == -1) { 228 | return; 229 | } 230 | buffer[i] = (uint8_t) byte; 231 | } 232 | } 233 | 234 | static int received_packet_verify(StubState *state) 235 | { 236 | uint8_t calculated_checksum = state->host_interface.input_checksum; 237 | uint8_t received_checksum = get_checksum(state); 238 | 239 | if (state->host_interface.input_packet_finished && (calculated_checksum == received_checksum)) 240 | { 241 | Serial_write_byte('+'); 242 | Serial_flush_write(); 243 | return 1; 244 | } 245 | else { 246 | Serial_write_byte('-'); 247 | Serial_flush_write(); 248 | return 0; 249 | } 250 | } 251 | 252 | static int receive_packet_end(StubState *state) 253 | { 254 | if (Serial_read_byte_blocking() == '#') 255 | { 256 | state->host_interface.input_packet_finished = 1; 257 | return received_packet_verify(state); 258 | } 259 | else 260 | { 261 | return 0; 262 | } 263 | } 264 | 265 | static int get_packet_byte(StubState *state) 266 | { 267 | char c; 268 | 269 | if (state->host_interface.input_packet_finished) 270 | return -1; 271 | 272 | c = Serial_read_byte_blocking(); 273 | 274 | if (c == '#') 275 | { 276 | state->host_interface.input_packet_finished = 1; 277 | return -1; 278 | } 279 | else 280 | { 281 | state->host_interface.input_checksum += c; 282 | return c; 283 | } 284 | } 285 | 286 | /** 287 | * Reads a hex encoded number from the serial port. 288 | * The number should have at most len digits. 289 | * The number is encoded as read, that is big endian. 290 | * The number is terminated by a non-hex character. 291 | */ 292 | static uint32_t get_hex_number(StubState* state, unsigned len) 293 | { 294 | unsigned i; 295 | uint32_t val = 0; 296 | int nibble; 297 | 298 | for (i = 0; i < len; i++) 299 | { 300 | nibble = hex_char_to_nibble(get_packet_byte(state)); 301 | if (nibble == -1) 302 | { 303 | return val; 304 | } 305 | 306 | val = (val << 4) | nibble; 307 | } 308 | 309 | return val; 310 | } 311 | 312 | // static void get_ignore_bytes(StubState *state, int count) 313 | // { 314 | // int i; 315 | // 316 | // for (i = 0; i < count; i++) 317 | // get_hex_uint32(state, 1); 318 | // } 319 | 320 | static int ignore_rest_of_packet(StubState *state) 321 | { 322 | while (get_packet_byte(state) != -1); 323 | 324 | state->host_interface.input_packet_finished = 1; 325 | return received_packet_verify(state); 326 | } 327 | 328 | void HostInterface_init(StubState *state) 329 | { 330 | } 331 | 332 | 333 | void HostInterface_communicate(StubState *state) 334 | //void gdb_monitor(int signal, uint32_t * register_file) 335 | { 336 | // struct GDB gdb = {.signal = signal, .register_file = register_file}; 337 | 338 | // gdb_init(&state->host_interface); 339 | 340 | target_enter_monitor(state); 341 | 342 | #ifdef CONFIG_MEMORY_ERROR 343 | if (in_memory_access && state->signal == 6) 344 | { 345 | put_error_packet(state, 1); 346 | } 347 | else 348 | { 349 | put_signal_packet(state); 350 | } 351 | #else 352 | put_signal_packet(state); 353 | signal_debug_enter(); 354 | #endif 355 | 356 | while (1) 357 | { 358 | //wait for packet header 359 | while (Serial_read_byte_blocking() != '$'); 360 | state->host_interface.input_checksum = 0; 361 | state->host_interface.input_packet_finished = 0; 362 | 363 | switch(get_packet_byte(state)) 364 | { 365 | case 'm': 366 | { 367 | uint32_t address = get_hex_number(state, 9); 368 | uint32_t len = get_hex_number(state, 9); 369 | 370 | if (received_packet_verify(state)) 371 | { 372 | do 373 | { 374 | 375 | if (!Memory_is_valid_address(state, address) || !Memory_is_valid_address(state, address + len - 1)) 376 | { 377 | start_packet(state); 378 | put_dummy_bytes(state, len); 379 | } 380 | else 381 | { 382 | #ifdef CONFIG_MEMORY_ERROR 383 | in_memory_access = 1; 384 | #endif /* CONFIG_MEMORY_ERROR */ 385 | //If memory is a long or short int and aligned 386 | if ((len == 4 && ((address & 3) == 0)) || (len == 2 && ((address & 1) == 0))) 387 | { 388 | invalidate_data_cache(); 389 | value_t buf = Memory_read_typed(state, address, len); 390 | start_packet(state); 391 | switch (len) { 392 | case 4: { 393 | uint32_t val = buf; 394 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 395 | break; 396 | } 397 | case 2: { 398 | uint16_t val = buf; 399 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 400 | break; 401 | } 402 | } 403 | } 404 | //Unaligned access 405 | else 406 | { 407 | uint32_t i; 408 | uint8_t buf; 409 | 410 | //Do one memory access that would fail if address cannot be read 411 | Memory_read_typed(state, address, SIZE_CHAR); 412 | start_packet(state); 413 | 414 | for (i = 0; i < len; i++) 415 | { 416 | invalidate_data_cache(); 417 | buf = Memory_read_typed(state, address + i, SIZE_CHAR); 418 | put_hex_buffer(state, (const uint8_t *) &buf, 1); 419 | } 420 | } 421 | #ifdef CONFIG_MEMORY_ERROR 422 | in_memory_access = 0; 423 | #endif /* CONFIG_MEMORY_ERROR */ 424 | } 425 | 426 | end_packet(state); 427 | } while (Serial_read_byte_blocking() != '+'); 428 | } 429 | break; 430 | } 431 | case 'M': 432 | { 433 | uint32_t address = get_hex_number(state, 9); 434 | uint32_t len = get_hex_number(state, 9); 435 | 436 | if (!Memory_is_valid_address(state, address) || !Memory_is_valid_address(state, address + len - 1)) 437 | { 438 | ignore_rest_of_packet(state); 439 | put_error_packet(state, 1); 440 | } 441 | else 442 | { 443 | #ifdef CONFIG_MEMORY_ERROR 444 | in_memory_access = 1; 445 | #endif /* CONFIG_MEMORY_ERROR */ 446 | if ((len == 4 && ((address & 0x3) == 0)) || (len == 2 && ((address & 1) == 0))) 447 | { 448 | switch (len) { 449 | case 4: { 450 | uint32_t val; 451 | get_hex_buffer(state, (uint8_t *) &val, sizeof(val)); 452 | Memory_write_typed(state, address, sizeof(val), val); 453 | break; 454 | } 455 | case 2: { 456 | uint16_t val; 457 | get_hex_buffer(state, (uint8_t *) &val, sizeof(val)); 458 | Memory_write_typed(state, address, sizeof(val), val); 459 | break; 460 | } 461 | } 462 | } 463 | else 464 | { 465 | uint32_t i; 466 | uint8_t buf; 467 | 468 | for (i = 0; i < len; i++) 469 | { 470 | get_hex_buffer(state, &buf, 1); 471 | Memory_write_typed(state, address + i, SIZE_CHAR, buf); 472 | flush_data_cache_by_mva(address+i); 473 | } 474 | } 475 | 476 | #ifdef CONFIG_MEMORY_ERROR 477 | in_memory_access = 0; 478 | #endif /* CONFIG_MEMORY_ERROR */ 479 | 480 | receive_packet_end(state); 481 | put_ok_packet(state); 482 | } 483 | break; 484 | } 485 | case 'g': 486 | { 487 | if (receive_packet_end(state)) 488 | { 489 | int i; 490 | register_t val; 491 | 492 | do 493 | { 494 | start_packet(state); 495 | //TODO: ARM specific 496 | for (i = 0; i < 16; i++) 497 | { 498 | val = RegisterMap_get_register(state, Gdb_map_gdb_register_number_to_stub(state, i)); 499 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 500 | } 501 | 502 | val = RegisterMap_get_register(state, Gdb_map_gdb_register_number_to_stub(state, 25)); 503 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 504 | 505 | end_packet(state); 506 | } while (Serial_read_byte_blocking() != '+'); 507 | } 508 | break; 509 | } 510 | case 'G': 511 | { 512 | int i; 513 | register_t val; 514 | /* GDB should have requested a register packet ('g') at this point to know how many registers we expect */ 515 | //TODO: ARM specific 516 | for (i = 0; i < 16; i++) 517 | { 518 | get_hex_buffer(state, (uint8_t *) &val, sizeof(val)); 519 | RegisterMap_set_register(state, Gdb_map_gdb_register_number_to_stub(state, i), val); 520 | } 521 | 522 | get_hex_buffer(state, (uint8_t *) &val, sizeof(val)); 523 | RegisterMap_set_register(state, Gdb_map_gdb_register_number_to_stub(state, 25), val); 524 | 525 | ignore_rest_of_packet(state); 526 | break; 527 | } 528 | case 'c': 529 | { 530 | if (receive_packet_end(state)) 531 | { 532 | /* we should do this because we're accessing the *PC */ 533 | invalidate_data_cache(); 534 | Gdb_continue_execution(state); 535 | target_exit_monitor(state); 536 | signal_debug_exit(); 537 | invalidate_instruction_cache(); 538 | return; 539 | } 540 | else { 541 | //We do not support 'continue at address' 542 | assert(0 && "Continue at address not supported"); 543 | ignore_rest_of_packet(state); 544 | put_signal_packet(state); 545 | } 546 | break; 547 | } 548 | case '?': 549 | { 550 | if (receive_packet_end(state)) 551 | put_signal_packet(state); 552 | break; 553 | } 554 | case 'p': 555 | { 556 | uint32_t reg_id = get_hex_number(state, 9); 557 | register_t val; 558 | 559 | if (received_packet_verify(state)) 560 | { 561 | val = RegisterMap_get_register(state, Gdb_map_gdb_register_number_to_stub(state, reg_id)); 562 | start_packet(state); 563 | //TODO: Register size is ARM specific 564 | put_hex_buffer(state, (const uint8_t *) &val, sizeof(val)); 565 | end_packet(state); 566 | } else { 567 | put_error_packet(state, 1); 568 | } 569 | break; 570 | } 571 | case 'P': 572 | { 573 | uint32_t reg_id = get_hex_number(state, 9); 574 | register_t val; 575 | get_hex_buffer(state, (uint8_t *) &val, sizeof(val)); 576 | RegisterMap_set_register(state, Gdb_map_gdb_register_number_to_stub(state, reg_id), val); 577 | receive_packet_end(state); 578 | put_ok_packet(state); 579 | break; 580 | } 581 | #if defined(CONFIG_HW_BREAKPOINT) || defined(CONFIG_SW_BREAKPOINT) 582 | case 'z': 583 | { 584 | uint32_t type = get_packet_byte(state); 585 | switch (type) { 586 | case '1': 587 | { 588 | /* hw breakpoint */ 589 | 590 | /* skip , */ 591 | get_packet_byte(state); 592 | /* addr */ 593 | uint32_t addr = get_hex_number(state, 8); 594 | /* skip , */ 595 | get_packet_byte(state); 596 | /* kind */ 597 | uint32_t kind = get_hex_number(state, 8); 598 | receive_packet_end(state); 599 | set_hw_breakpoint(state, addr, 0); 600 | put_ok_packet(state); 601 | break; 602 | } 603 | default: 604 | ignore_rest_of_packet(state); 605 | put_empty_packet(state); 606 | break; 607 | } 608 | break; 609 | } 610 | #endif /* defined(CONFIG_HW_BREAKPOINT) || defined(CONFIG_SW_BREAKPOINT) */ 611 | #if defined(CONFIG_CHECKSUM) 612 | case 'u': 613 | { 614 | /* compute the crc of a buffer: 615 | * the format is simillar with the 'm' message: 616 | * $m148ac,4#2e 617 | * the reply is the checksum (one byte) 618 | */ 619 | uint32_t address = get_hex_number(state, 9); 620 | uint32_t len = get_hex_number(state, 9); 621 | 622 | if (received_packet_verify(state)) { 623 | uint8_t crc, buf; 624 | uint32_t i; 625 | invalidate_data_cache(); 626 | crc = 0; 627 | for (i = 0; i < len; ++i) { 628 | buf = Memory_read_typed(state, address + i, SIZE_CHAR); 629 | crc_calc(&crc, buf); 630 | } 631 | start_packet(state); 632 | put_hex_uint8(state, crc); 633 | end_packet(state); 634 | } else { 635 | put_error_packet(state, 1); 636 | } 637 | break; 638 | } 639 | #endif /* defined(CONFIG_CHECKSUM) */ 640 | default: 641 | { 642 | if (ignore_rest_of_packet(state)) 643 | put_empty_packet(state); 644 | break; 645 | } 646 | 647 | } 648 | } 649 | } 650 | 651 | 652 | 653 | 654 | 655 | 656 | -------------------------------------------------------------------------------- /src/Memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "Memory.h" 9 | #include "Assert.h" 10 | 11 | int Memory_is_valid_address(StubState* state, address_t address) 12 | { 13 | return 1; 14 | } 15 | 16 | 17 | value_t Memory_read_typed(StubState *state, address_t address, unsigned size) 18 | { 19 | if (Memory_is_valid_address(state, address)) 20 | { 21 | switch (size) 22 | { 23 | case SIZE_CHAR: 24 | return *((uint8_t *) address); 25 | case SIZE_SHORT: 26 | return *((uint16_t *) address); 27 | case SIZE_LONG: 28 | return *((uint32_t *) address); 29 | default: 30 | assert(0 && "Unknown memory type size"); 31 | break; 32 | } 33 | } 34 | 35 | //Error case 36 | return 0xfefefefe; 37 | } 38 | 39 | /** 40 | * Write a typed (byte, short, long) value to memory. 41 | */ 42 | void Memory_write_typed(StubState *state, address_t address, unsigned size, value_t value) 43 | { 44 | if (Memory_is_valid_address(state, address)) 45 | { 46 | switch (size) 47 | { 48 | case SIZE_CHAR: 49 | *((uint8_t *) address) = value; 50 | break; 51 | case SIZE_SHORT: 52 | *((uint16_t *) address) = value; 53 | break; 54 | case SIZE_LONG: 55 | *((uint32_t *) address) = value; 56 | break; 57 | default: 58 | assert(0 && "Unknown memory type size"); 59 | break; 60 | } 61 | } 62 | } 63 | 64 | 65 | /** 66 | * Read untyped (byte array) data from memory. 67 | */ 68 | void Memory_read_untyped(StubState *state, address_t address, uint8_t *buffer, unsigned length) 69 | { 70 | if (Memory_is_valid_address(state, address)) 71 | { 72 | unsigned i; 73 | for (i = 0; i < length; i++) 74 | buffer[i] = ((uint8_t *) address)[i]; 75 | } 76 | } 77 | 78 | 79 | /** 80 | * Write untyped (byte array) data to memory. 81 | */ 82 | void Memory_write_untyped(StubState *state, address_t address, const uint8_t *buffer, unsigned length) 83 | { 84 | if (Memory_is_valid_address(state, address)) 85 | { 86 | unsigned i; 87 | for (i = 0; i < length; i++) 88 | ((uint8_t *) address)[i] = buffer[i]; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/SerialIO.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | #include 8 | 9 | #include "Serial.h" 10 | #include "SerialIO.h" 11 | #include "gdb_utils.h" 12 | 13 | void 14 | print_uint8(uint8_t val) 15 | { 16 | char c = nibble_to_hex_char(val >> 4); 17 | Serial_write_byte(c); 18 | c = nibble_to_hex_char(val); 19 | Serial_write_byte(c); 20 | } 21 | 22 | void 23 | print_uint32(uint32_t val) 24 | { 25 | print_uint8(val >> 24); 26 | print_uint8(val >> 16); 27 | print_uint8(val >> 8); 28 | print_uint8(val); 29 | } 30 | 31 | void 32 | print_char(char c) 33 | { 34 | Serial_write_byte(c); 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/Serial_pl011.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "Serial.h" 9 | 10 | 11 | #ifndef UART_PL011_BASE 12 | #error Configuration value UART_PL011_BASE must be set, e.g. to ((volatile uint32_t *) 0x400D3000) 13 | #endif 14 | 15 | #define UART_BASE (UART_PL011_BASE) 16 | 17 | 18 | #define UART_REG_DATA 0 19 | #define UART_REG_STATUS 1 20 | #define UART_REG_FLAG 6 21 | #define UART_REG_CONTROL 12 22 | 23 | #define UART_STATUS_OVERRUN_ERR (1 << 3) 24 | #define UART_STATUS_BREAK_ERR (1 << 2) 25 | #define UART_STATUS_PARITY_ERR (1 << 1) 26 | #define UART_STATUS_FRAMING_ERR (1 << 0) 27 | 28 | #define UART_FLAG_TXFE (1 << 7) 29 | #define UART_FLAG_RXFF (1 << 6) 30 | #define UART_FLAG_TXFF (1 << 5) 31 | #define UART_FLAG_RXFE (1 << 4) 32 | #define UART_FLAG_BUSY (1 << 3) 33 | 34 | #ifndef WATCHDOG_EXCITE 35 | #define WATCHDOG_EXCITE do {} while (0) 36 | #endif 37 | 38 | void Serial_init(void) 39 | { 40 | } 41 | 42 | int Serial_write_byte(uint8_t data) 43 | { 44 | 45 | while (UART_BASE[UART_REG_FLAG] & UART_FLAG_TXFF) 46 | WATCHDOG_EXCITE; 47 | 48 | UART_BASE[UART_REG_DATA] = (uint32_t) data; 49 | 50 | return 0; 51 | } 52 | 53 | int Serial_is_data_available(void) 54 | { 55 | return (UART_BASE[UART_REG_FLAG] & UART_FLAG_RXFE) == 0; 56 | } 57 | 58 | int Serial_read_byte_blocking(void) 59 | { 60 | int ret; 61 | while (!Serial_is_data_available()) 62 | WATCHDOG_EXCITE; 63 | 64 | ret = UART_BASE[UART_REG_DATA]; 65 | /* XXX: we want to make sure that we are reading the data before 66 | * reading the error. We need a data barrier here. 67 | */ 68 | if (UART_BASE[UART_REG_STATUS] & 0xF) 69 | { 70 | /* reset the error */ 71 | UART_BASE[UART_REG_STATUS] = 0; 72 | //TODO: some error 73 | } 74 | else 75 | { 76 | return ret; 77 | } 78 | 79 | return -1; 80 | } 81 | 82 | void Serial_flush_write() 83 | { 84 | while (!(UART_BASE[UART_REG_FLAG] & UART_FLAG_TXFE)) 85 | WATCHDOG_EXCITE; 86 | } 87 | -------------------------------------------------------------------------------- /src/Serial_sirf.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | /** 9 | * A driver for the uart found in the Inforad K0 SIRF chip. 10 | */ 11 | 12 | #include "Serial.h" 13 | 14 | 15 | #ifndef UART_SIRF_BASE 16 | #error Configuration value UART_SIRF_BASE must be set, e.g. to ((volatile uint16_t *) 0x80030000) 17 | #endif 18 | 19 | #define UART_BASE (UART_SIRF_BASE) 20 | 21 | 22 | #define UART_REG_RXDATA 3 23 | #define UART_REG_TXDATA 2 24 | #define UART_REG_FLAG 1 25 | 26 | #define UART_FLAG_TXFF (1 << 6) 27 | #define UART_FLAG_RXFF (1 << 4) 28 | 29 | void Serial_init(void) 30 | { 31 | /* Initialization is done by the inforad k0 bootloader */ 32 | } 33 | 34 | int Serial_write_byte(uint8_t data) 35 | { 36 | 37 | while (UART_BASE[UART_REG_FLAG] & UART_FLAG_TXFF) 38 | WATCHDOG_EXCITE; 39 | 40 | UART_BASE[UART_REG_TXDATA] = data; 41 | 42 | return 0; 43 | } 44 | 45 | int Serial_is_data_available(void) 46 | { 47 | return (UART_BASE[UART_REG_FLAG] & UART_FLAG_RXFF) != 0; 48 | } 49 | 50 | int Serial_read_byte_blocking(void) 51 | { 52 | int ret; 53 | while (!Serial_is_data_available()) 54 | WATCHDOG_EXCITE; 55 | 56 | ret = UART_BASE[UART_REG_RXDATA]; 57 | 58 | return ret; 59 | } 60 | 61 | void Serial_flush_write() 62 | { 63 | while (UART_BASE[UART_REG_FLAG] & UART_FLAG_TXFF) 64 | WATCHDOG_EXCITE; 65 | } 66 | -------------------------------------------------------------------------------- /src/Serial_uart16550.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "Serial.h" 9 | 10 | #ifndef UART_16550_BASE 11 | #error Configuration value UART_16550_BASE must be set, e.g. to ((volatile uint32_t *) 0x400D3000) 12 | #endif 13 | 14 | #define UART_BASE UART_16550_BASE 15 | 16 | #define UART_REG_DATA 0 17 | #define UART_REG_LINE_STATUS 5 18 | 19 | #define UART_LINE_FLAG_DATA_READY (1 << 0) 20 | #define UART_LINE_FLAG_PARITY_ERROR (1 << 2) 21 | #define UART_LINE_FLAG_OVERRUN_ERROR (1 << 1) 22 | #define UART_LINE_FLAG_FRAMING_ERROR (1 << 3) 23 | #define UART_LINE_FLAG_TRANSMITTER_HOLDING_REGISTER_EMPTY (1 << 5) 24 | #define UART_LINE_FLAG_TRANSMITTER_EMPTY (1 << 5) 25 | 26 | void Serial_init(void) 27 | { 28 | } 29 | 30 | int Serial_write_byte(uint8_t data) 31 | { 32 | while (!(UART_BASE[UART_REG_LINE_STATUS] & UART_LINE_FLAG_TRANSMITTER_HOLDING_REGISTER_EMPTY)); 33 | 34 | UART_BASE[UART_REG_DATA] = (uint32_t) data; 35 | 36 | return 0; 37 | } 38 | 39 | int Serial_is_data_available(void) 40 | { 41 | return (UART_BASE[UART_REG_LINE_STATUS] & UART_LINE_FLAG_DATA_READY) != 0; 42 | } 43 | 44 | int Serial_read_byte_blocking(void) 45 | { 46 | while (!Serial_is_data_available()); 47 | 48 | if (UART_BASE[UART_REG_LINE_STATUS] & UART_LINE_FLAG_PARITY_ERROR) 49 | { 50 | //TODO: some error 51 | return -1; 52 | } 53 | else if (UART_BASE[UART_REG_LINE_STATUS] & UART_LINE_FLAG_OVERRUN_ERROR) 54 | { 55 | //TODO: some error 56 | return -1; 57 | } 58 | else if (UART_BASE[UART_REG_LINE_STATUS] & UART_LINE_FLAG_FRAMING_ERROR) 59 | { 60 | //TODO: some error 61 | return -1; 62 | } 63 | else 64 | { 65 | return UART_BASE[UART_REG_DATA]; 66 | } 67 | 68 | return -1; 69 | } 70 | 71 | void Serial_flush_write() 72 | { 73 | while ((UART_BASE[UART_REG_LINE_STATUS] & UART_LINE_FLAG_TRANSMITTER_EMPTY) == 0); 74 | } 75 | -------------------------------------------------------------------------------- /src/armv7_cortex_r4.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | #include 8 | 9 | #include "ArmGdbHelpers.h" 10 | #include "RegisterMap.h" 11 | #include "ArmRegisterMap.h" 12 | #include "Assert.h" 13 | #include "armv7_cortex_r4.h" 14 | 15 | uint32_t armv7_cortex_r4_read_debug_register(StubState *state, uint32_t reg_num); 16 | uint32_t armv7_cortex_r4_read_Debug_ROM_Address_Register(StubState *state); 17 | uint32_t armv7_cortex_r4_read_Debug_Self_Address_Offset_Register(StubState *state); 18 | uint32_t armv7_cortex_r4_read_debug_register(StubState *state, uint32_t reg_num); 19 | void armv7_cortex_r4_write_debug_register(StubState *state, uint32_t reg_num, uint32_t value); 20 | volatile void * armv7_cortex_r4_get_debug_registers_base(StubState *state); 21 | void armv7_cortex_r4_unlock_debug_registers(StubState *state); 22 | void armv7_cortex_r4_lock_debug_registers(StubState *state); 23 | int armv7_cortex_r4_are_debug_register_enabled(StubState *state); 24 | 25 | void armv7_cortex_r4_enable_monitor_mode(StubState *state) 26 | { 27 | /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0363e/Cegfhaac.html */ 28 | uint32_t tmp; 29 | asm volatile ("mrc p14, 0, %[r], c0, c1, 0\n" : [r] "=r" (tmp)); 30 | tmp |= (0x1 << 15); 31 | asm volatile ("mcr p14, 0, %[r], c0, c1, 0\n" : /* no output */ : [r] "r" (tmp)); 32 | } 33 | 34 | void 35 | armv7_cortex_r4_set_hw_breakpoint(StubState *state, uint32_t addr, uint32_t break_num) 36 | { 37 | /* 11.11.2. Programming breakpoints and watchpoints of the TRM */ 38 | /* http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0363e/Ceggchda.html 39 | * */ 40 | /* TODO move break_num in StubState */ 41 | 42 | /* Example 11.7. Setting a simple breakpoint */ 43 | /* break_num from 0 to 7 */ 44 | 45 | armv7_cortex_r4_unlock_debug_registers(state); 46 | break_num &= 0x7; 47 | write_debug_register(80 + break_num, 0x0); 48 | write_debug_register(64 + break_num, addr & 0xFFFFFFC); 49 | write_debug_register(80 + break_num, 7 | (15 << 5)); 50 | } 51 | 52 | uint32_t 53 | armv7_cortex_r4_get_Authentication_Status_Register(StubState *state) 54 | { 55 | return read_debug_register(0xFB8 >> 2); 56 | } 57 | 58 | void 59 | armv7_cortex_r4_set_hw_watchpoint(StubState *state, uint32_t addr, uint32_t watch_num, uint32_t size) 60 | { 61 | /* 62 | * Example 11.8. Setting a simple aligned watchpoint 63 | */ 64 | 65 | /* watchpiont from 0 to 7 */ 66 | /* assumptions: addr is aligned */ 67 | uint32_t byte_address_select; 68 | 69 | armv7_cortex_r4_unlock_debug_registers(state); 70 | watch_num &= 0x7; 71 | write_debug_register(112 + watch_num, 0); 72 | write_debug_register(96 + watch_num, addr & 0xFFFFFF8); 73 | 74 | switch (size) { 75 | case 1: 76 | byte_address_select = (1 << (addr & 7)); 77 | break; 78 | case 2: 79 | byte_address_select = (3 << (addr & 6)); 80 | break; 81 | case 4: 82 | byte_address_select = (15 << (addr & 4)); 83 | break; 84 | case 8: 85 | byte_address_select = 255; 86 | default: 87 | byte_address_select = (15 << (addr & 4)); 88 | return; 89 | } 90 | 91 | write_debug_register(112 + watch_num, 23 | (byte_address_select << 5)); 92 | } 93 | 94 | void 95 | armv7_cortex_r4_unlock_debug_registers(StubState *state) 96 | { 97 | /* 98 | * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0363e/Babfcfig.html 99 | */ 100 | /* XXX: this might block */ 101 | while (!armv7_cortex_r4_are_debug_register_enabled(state)) 102 | write_debug_register((0xFB0 >> 2), 0xC5ACCE55); 103 | } 104 | 105 | void 106 | armv7_cortex_r4_lock_debug_registers(StubState *state) 107 | { 108 | /* 109 | * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0363e/Babfcfig.html 110 | */ 111 | write_debug_register((0xFB0 >> 2), 0xABCD1234); 112 | } 113 | 114 | int 115 | armv7_cortex_r4_are_debug_register_enabled(StubState *state) 116 | { 117 | /* Lock Status Register */ 118 | return !(read_debug_register(0xFB4 >> 2) & 0x2); 119 | } 120 | 121 | 122 | uint32_t 123 | armv7_cortex_r4_read_Debug_ROM_Address_Register(StubState *state) 124 | { 125 | uint32_t ret; 126 | asm volatile ("mrc p14, 0, %[r], c1, c0, 0\n" : [r] "=r" (ret)); 127 | return ret; 128 | } 129 | 130 | uint32_t 131 | armv7_cortex_r4_read_Debug_Self_Address_Offset_Register(StubState *state) 132 | { 133 | uint32_t ret; 134 | asm volatile ("mrc p14, 0, %[r], c2, c0, 0\n" : [r] "=r" (ret)); 135 | return ret; 136 | } 137 | 138 | uint32_t 139 | armv7_cortex_r4_read_debug_register(StubState *state, uint32_t reg_num) 140 | { 141 | volatile uint32_t *debug_base = armv7_cortex_r4_get_debug_registers_base(state); 142 | return debug_base[reg_num]; 143 | } 144 | 145 | void 146 | armv7_cortex_r4_write_debug_register(StubState *state, uint32_t reg_num, uint32_t value) 147 | { 148 | volatile uint32_t *debug_base = armv7_cortex_r4_get_debug_registers_base(state); 149 | debug_base[reg_num] = value; 150 | } 151 | 152 | volatile void * 153 | armv7_cortex_r4_get_debug_registers_base(StubState *state) 154 | { 155 | uint32_t rom = armv7_cortex_r4_read_Debug_ROM_Address_Register(state); 156 | uint32_t off = armv7_cortex_r4_read_Debug_Self_Address_Offset_Register(state); 157 | return (volatile void *)((rom&0xfffff000) + (off&0xfffff000)); 158 | } 159 | 160 | void 161 | armv7_cortex_r4_flush_data_cache_by_mva(uint32_t address) 162 | { 163 | /* this function takes a MVA parameter */ 164 | asm("dsb \n" 165 | "mcr p15, 0, %[addr], c7, c14, 1 \n" 166 | "dsb\n" :: [addr] "r" (address & 0xFFFFFFF0)); 167 | } 168 | 169 | void 170 | armv7_cortex_r4_flush_data_cache() 171 | { 172 | int i, j; 173 | 174 | #define no_sets 8/* we don't know for sure, we should check the documentation */ 175 | for (i = 0; i < (1<, EURECOM 5 | * 6 | * You can redistribute and/or modify this program under the terms of the 7 | * GNU General Public License version 2 or later. 8 | */ 9 | 10 | #include "crc.h" 11 | 12 | #ifdef CONFIG_CHECKSUM 13 | static unsigned char r1[16] = { 14 | 0x00, 0x5e, 0xbc, 0xe2, 0x61, 0x3f, 0xdd, 0x83, 15 | 0xc2, 0x9c, 0x7e, 0x20, 0xa3, 0xfd, 0x1f, 0x41, 16 | }; 17 | 18 | static unsigned char r2[16] = { 19 | 0x00, 0x9d, 0x23, 0xbe, 0x46, 0xdb, 0x65, 0xf8, 20 | 0x8c, 0x11, 0xaf, 0x32, 0xca, 0x57, 0xe9, 0x74 21 | }; 22 | 23 | /** 24 | * Calculate CRC8 of the data. 25 | * The polynom used is the same as for Dallas iButton products. 26 | */ 27 | unsigned char crc_calc(uint8_t * crc, uint8_t data) 28 | { 29 | int i = (data ^ *crc) & 0xff; 30 | 31 | *crc = r1[i&0xf] ^ r2[i>>4]; 32 | return *crc; 33 | } 34 | 35 | #endif /* CONFIG_CHECKSUM */ 36 | -------------------------------------------------------------------------------- /src/lowlevel_ST3320413AS.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | .global _start 9 | .global ST3320413AS_flush_write_buffer 10 | .type ST3320413AS_flush_write_buffer STT_FUNC 11 | 12 | .global ST3320413AS_disable_instruction_prefetch 13 | .type ST3320413AS_disable_instruction_prefetch STT_FUNC 14 | 15 | .global ST3320413AS_get_instruction_prefetch 16 | .type ST3320413AS_get_instruction_prefetch STT_FUNC 17 | 18 | .extern _arm_PAB_handler 19 | .extern _arm_DAB_handler 20 | 21 | .arm 22 | .section .start 23 | _start: 24 | mov r3, lr 25 | /* Install PAB and DAB handler */ 26 | /* First write the target adresses */ 27 | bl get_code_offset 28 | ldr r2, =_arm_PAB_handler 29 | add r2, r2, r0 30 | ldr r1, =_arm_DAB_handler 31 | add r1, r1, r0 32 | 33 | mov r0, #0xC 34 | str r2, [r0, #0x20] 35 | str r1, [r0, #0x24] 36 | 37 | /* And then the LDR instruction */ 38 | ldr r1, =(0xe59ff000 | 0x18) 39 | str r1, [r0] 40 | str r1, [r0, #0x04] 41 | 42 | /* Hit breakpoint to allow GDB initialization */ 43 | bkpt #0x42 44 | bx r3 45 | 46 | .text 47 | .arm 48 | 49 | 50 | /* I doubt we would need something like that one day ... 51 | maybe timings ? 52 | ST3320413AS_enable_instruction_prefetch: 53 | mrc p15, 1, r1, c15, c1, 0 54 | bic r1, #0x10000 55 | mcr p15, 1, r1, c15, c1, 0 56 | */ 57 | 58 | -------------------------------------------------------------------------------- /src/lowlevel_arm.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | /* Signal numbers taken from: http://opensource.apple.com/source/cxxfilt/cxxfilt-9/cxxfilt/include/gdb/signals.h */ 9 | 10 | #define MODE_USR 0x10 11 | #define MODE_FIQ 0x11 12 | #define MODE_IRQ 0x12 13 | #define MODE_SVC 0x13 14 | #define MODE_ABRT 0x17 15 | #define MODE_UND 0x1b 16 | #define MODE_SYS 0x1f 17 | #define FIQ_DISABLED 0x40 18 | #define IRQ_DISABLED 0x80 19 | 20 | .global _arm_PAB_handler 21 | .global _arm_DAB_handler 22 | .global _arm_UND_handler 23 | .global get_code_offset 24 | /* .global _arm_RST_handler 25 | .global _arm_UND_handler 26 | .global _arm_SWI_handler 27 | .global _arm_IRQ_handler 28 | .global _arm_FIQ_handler */ 29 | 30 | .extern gdb_monitor 31 | 32 | 33 | .section .header 34 | .arm 35 | b _start 36 | b _arm_PAB_handler 37 | b _arm_DAB_handler 38 | b _arm_UND_handler 39 | 40 | 41 | .section .text 42 | .arm 43 | 44 | _arm_UND_handler: 45 | push {r0} 46 | mrs r0, SPSR 47 | tst r0, #0x20 48 | subeq lr, lr, #4 49 | subne lr, lr, #2 50 | pop {r0} 51 | push {lr} 52 | mov lr, #5 /* SIG_TRAP */ 53 | 54 | b _abort_handlers 55 | 56 | _arm_PAB_handler: 57 | /* 58 | * Our register file on the stack has the following layout: 59 | * - 0: CPSR = SPSR_abrt, SP_abrt 60 | * - 2: SPSR_fiq, R8_fiq - R12_fiq, SP_fiq, LR_fiq 61 | * - 10: SPSR_irq, SP_irq, LR_irq 62 | * - 13: SPSR_svc, SP_svc, LR_svc 63 | * - 16: SPSR_und, SP_und, LR_und 64 | * - 19: SPSR_sys, SP_sys, LR_sys 65 | * - 22: SP_usr, LR_usr 66 | * - 24: R0 - R12 in order 67 | * - 37: PC = LR_abrt 68 | * 69 | * GDB expects the following layout for the register file on the stack: 70 | * - R0 - R12 in order 71 | * - SP 72 | * - LR 73 | * - PC 74 | * - FP0 - FP7 ; each floating point register is 12 bytes 75 | * - CPSR 76 | * A mapper function handles the conversion from our layout to the GDB layout. 77 | */ 78 | /* TODO: Disable interrupts */ 79 | 80 | 81 | 82 | /* Save general purpose registers to register file (R0 - R12) */ 83 | sub lr, lr, #4 84 | push {lr} 85 | mov lr, #5 /* SIG_TRAP */ 86 | 87 | b _abort_handlers 88 | 89 | _arm_DAB_handler: 90 | sub lr, lr, #8 91 | push {lr} 92 | mov lr, #6 /* SIG_ABRT */ 93 | 94 | b _abort_handlers 95 | 96 | _abort_handlers: 97 | /* Save general purpose registers */ 98 | push {r0-r12} 99 | 100 | /* Save banked registers */ 101 | /* First user mode registers */ 102 | sub r2, sp, #(2 * 4) 103 | stm r2, {sp, lr}^ 104 | /* No read access to registers unique to this mode for two cycles after access to banked registers */ 105 | nop 106 | nop 107 | /* Now registers for all other modes. Abort is last mode and is kept. */ 108 | mov r0, #0 109 | /* Use r2 instead of sp for stack because sp is unavailable after we switch modes */ 110 | mrs r4, CPSR 111 | Leach_mode: 112 | adr r1, Lcpu_modes 113 | ldr r1, [r1, r0, LSL #2] 114 | /* Switch mode */ 115 | msr CPSR_c, r1 116 | /* Get SPSR */ 117 | mrs r3, SPSR 118 | cmp r1, #(MODE_FIQ | IRQ_DISABLED | FIQ_DISABLED) 119 | /* For every mode except FIQ, store SPSR, SP, LR */ 120 | stmnedb r2!, {r3, sp, lr} 121 | /* For FIQ store SPSR, R9-R12, SP, LR */ 122 | stmeqdb r2!, {r3, r8-r12, sp, lr} 123 | add r0, r0, #1 124 | cmp r0, #5 125 | blo Leach_mode 126 | 127 | /* Save ABRT registers */ 128 | msr CPSR, r4 129 | 130 | mrs r3, SPSR 131 | stmdb r2!, {r3, sp} 132 | 133 | /* update stack pointer */ 134 | mov sp, r2 135 | 136 | mov r0, lr 137 | mov r1, sp 138 | 139 | /* gdb_monitor(address_t pc, void * register_file) */ 140 | bl stub_handle_exception 141 | 142 | /* Restore banked registers */ 143 | /* First ABRT mode SPSR */ 144 | pop {r1, r2} 145 | msr SPSR, r1 146 | 147 | /* Now the other modes */ 148 | mov r0, #4 149 | mov r2, sp 150 | mrs r4, CPSR 151 | Leach_mode2: 152 | adr r1, Lcpu_modes 153 | ldr r1, [r1, r0, LSL #2] 154 | msr CPSR_c, r1 155 | cmp r1, #(MODE_FIQ | IRQ_DISABLED | FIQ_DISABLED) 156 | /* For every mode except FIQ and ABRT, restore SPSR, SP, LR */ 157 | ldmneia r2!, {r3, sp, lr} 158 | /* For FIQ restore SPSR, R9-R12, SP, LR */ 159 | ldmeqia r2!, {r3, r8-r12, sp, lr} 160 | msr SPSR, r3 161 | subs r0, r0, #1 162 | bpl Leach_mode2 163 | 164 | msr CPSR_c, r4 165 | 166 | 167 | /* Now restore user mode registers */ 168 | ldm r2, {sp, lr}^ 169 | nop 170 | nop 171 | add sp, r2, #(2 * 4) 172 | 173 | ldmia sp!, {r0 - r12, pc}^ 174 | 175 | .align 4 176 | Lcpu_modes: 177 | .long (MODE_SYS | IRQ_DISABLED | FIQ_DISABLED) 178 | .long (MODE_UND | IRQ_DISABLED | FIQ_DISABLED) 179 | .long (MODE_SVC | IRQ_DISABLED | FIQ_DISABLED) 180 | .long (MODE_IRQ | IRQ_DISABLED | FIQ_DISABLED) 181 | .long (MODE_FIQ | IRQ_DISABLED | FIQ_DISABLED) 182 | 183 | /* Uses only register r0 */ 184 | get_code_offset: 185 | ldr r0, =get_code_offset+12 186 | sub r0, r0, pc 187 | bx lr 188 | /* uint32_t get_banked_register(int mode_num, int register) */ 189 | get_banked_register: 190 | cmp r0, #0x10 191 | bne Lnot_user_mode 192 | sub sp, sp, #4 193 | cmp r1, #0 194 | stmeq sp, {sp}^ 195 | stmne sp, {lr}^ 196 | pop {r0} 197 | bx lr 198 | Lnot_user_mode: 199 | mrs r2, CPSR 200 | orr r0, #0xC0 201 | msr CPSR_c, r0 202 | cmp r1, #0 203 | moveq r0, sp 204 | cmp r1, #1 205 | moveq r0, lr 206 | mrsne r0, SPSR 207 | msr CPSR, r2 208 | bx lr 209 | 210 | 211 | 212 | 213 | 214 | -------------------------------------------------------------------------------- /src/lowlevel_inforad_k0.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | .global _start 9 | 10 | .extern _arm_PAB_handler 11 | .extern _arm_DAB_handler 12 | .extern _arm_UND_handler 13 | 14 | .arm 15 | .section .exception_table 16 | _start: 17 | /* The exception vector table */ 18 | b _reset /* RST */ 19 | ldr pc, =_arm_UND_handler /* UND */ 20 | b . /* SVC */ 21 | ldr pc, =_arm_PAB_handler /* PAB */ 22 | ldr pc, =_arm_DAB_handler /* DAB */ 23 | nop /* Reserved */ 24 | b . /* IRQ */ 25 | b . /* FIQ */ 26 | 27 | .arm 28 | .section .init 29 | 30 | _reset: 31 | /* Set up stack for SVC mode */ 32 | ldr sp, =0x60017ffc 33 | 34 | /* Set up stack for UND mode */ 35 | mrs r0, CPSR 36 | mov r1, #0x1f 37 | mvn r2, r1 38 | and r3, r0, r2 39 | orr r3, r3, #0x1b 40 | msr CPSR, r3 41 | ldr sp, =0x60016ffc 42 | msr CPSR, r0 43 | 44 | bl Serial_write_byte 45 | 46 | /* Hit breakpoint to allow GDB initialization */ 47 | .long 0xe7f001f0 48 | 49 | b . 50 | -------------------------------------------------------------------------------- /src/lowlevel_plc.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Lucian Cojocar , VU 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | .global _start 9 | 10 | .extern _arm_PAB_handler 11 | .extern _arm_DAB_handler 12 | .extern _gdb_stub_start 13 | 14 | .arm 15 | .section .start 16 | 17 | /* start is at 0x16000 */ 18 | /* jmp to our stub is at 0xe0000 */ 19 | /* we should return at 0xe0000+16 */ 20 | #define JMP_ADDR 0xE000 21 | #define RET_ADDR 0xE010 22 | 23 | _start: 24 | /* assume that we have a valid stack */ 25 | push {r0, r1, r2, r3, r4, r5, r6, r7, lr} 26 | 27 | /* Install PAB and DAB handler */ 28 | 29 | /* load pointers to handlers */ 30 | ldr r2, =_arm_PAB_handler 31 | ldr r1, =_arm_DAB_handler 32 | 33 | /* at 0xbc we have the Exception vector pointers */ 34 | /* we can override these values to execute our handlers */ 35 | mov r0, $0xbc 36 | str r2, [r0, $0x0c] /* abort prefetch (PAB) */ 37 | #str r1, [r0, $0x10] /* abort data (DAB) */ 38 | 39 | 40 | /* Hit breakpoint to allow GDB initialization */ 41 | bkpt #0x42 42 | 43 | pop {r0, r1, r2, r3, r4, r5, r6, r7, lr} 44 | 45 | /* continue the boot process */ 46 | b RET_ADDR 47 | -------------------------------------------------------------------------------- /src/lowlevel_qemu_versatilepb.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | .global _start 9 | .global ST3320413AS_flush_write_buffer 10 | .type ST3320413AS_flush_write_buffer STT_FUNC 11 | 12 | .global ST3320413AS_disable_instruction_prefetch 13 | .type ST3320413AS_disable_instruction_prefetch STT_FUNC 14 | 15 | .global ST3320413AS_get_instruction_prefetch 16 | .type ST3320413AS_get_instruction_prefetch STT_FUNC 17 | 18 | .extern _arm_PAB_handler 19 | .extern _arm_DAB_handler 20 | .extern _arm_UND_handler 21 | 22 | .arm 23 | .section .init 24 | _start: 25 | /* The exception vector table */ 26 | b _reset /* RST */ 27 | ldr pc, =_arm_UND_handler /* UND */ 28 | b . /* SVC */ 29 | ldr pc, =_arm_PAB_handler /* PAB */ 30 | ldr pc, =_arm_DAB_handler /* DAB */ 31 | nop /* Reserved */ 32 | b . /* IRQ */ 33 | b . /* FIQ */ 34 | 35 | _reset: 36 | mrs r0, CPSR 37 | mov r1, #0x1f 38 | mvn r1, r1 39 | and r2, r0, r1 40 | orr r2, r2, #0x1b 41 | msr CPSR, r2 42 | ldr sp, =0x10000 43 | msr CPSR, r0 44 | ldr sp, =0x20000 45 | 46 | b _arm_UND_handler 47 | /* Hit breakpoint to allow GDB initialization */ 48 | .long 0xe7f001f0 49 | /* bkpt #0x42 */ 50 | b _reset 51 | 52 | 53 | /* I doubt we would need something like that one day ... 54 | maybe timings ? 55 | ST3320413AS_enable_instruction_prefetch: 56 | mrc p15, 1, r1, c15, c1, 0 57 | bic r1, #0x10000 58 | mcr p15, 1, r1, c15, c1, 0 59 | */ 60 | 61 | -------------------------------------------------------------------------------- /src/stdlib/memset.c: -------------------------------------------------------------------------------- 1 | #include "stdlib/string.h" 2 | 3 | void * memset(void *buf, int c, size_t len) 4 | { 5 | size_t i; 6 | 7 | for (i = 0; i < len; i++) 8 | { 9 | ((unsigned char *) buf)[i] = (unsigned char) c; 10 | } 11 | 12 | return buf; 13 | } 14 | -------------------------------------------------------------------------------- /src/stub.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "StubState.h" 9 | #include "HostInterface.h" 10 | 11 | 12 | void stub_handle_exception(unsigned signal, void * register_map) 13 | { 14 | StubState state; 15 | state.signal = signal; 16 | state.register_map = register_map; 17 | 18 | HostInterface_communicate(&state); 19 | } 20 | -------------------------------------------------------------------------------- /src/utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | #include "gdb_utils.h" 9 | 10 | char nibble_to_hex_char(uint8_t nibble) 11 | { 12 | nibble &= 0xf; 13 | if (nibble < 10) 14 | return '0' + nibble; 15 | else 16 | return 'a' + nibble - 10; 17 | } 18 | 19 | /** 20 | * Get the length of an 8-bit string. 21 | */ 22 | size_t strlen(const char * str) 23 | { 24 | size_t i; 25 | 26 | for (i = 0; str[i]; i++); 27 | return i; 28 | } 29 | 30 | int hex_char_to_nibble(char c) 31 | { 32 | if (c >= '0' && c <= '9') 33 | return c - '0'; 34 | else if (c >= 'A' && c <= 'F') 35 | return c - 'A' + 10; 36 | else if (c >= 'a' && c <= 'f') 37 | return c - 'a' + 10; 38 | else return -1; 39 | } 40 | 41 | int is_name_character(char c) 42 | { 43 | if (c >= 'a' && c <= 'z') 44 | return 1; 45 | else if (c >= 'A' && c <= 'Z') 46 | return 1; 47 | else 48 | return 0; 49 | } 50 | 51 | /** 52 | * Set a memory range to a value. 53 | * Only the lowest byte of 'c' is taken into account, the value is set byte-wise. 54 | */ 55 | void * memset(void * mem, int c, size_t len) 56 | { 57 | size_t i = 0; 58 | 59 | for (i = 0; i < len; i++) 60 | ((uint8_t *) mem)[i] = (uint8_t) c; 61 | 62 | return mem; 63 | } 64 | 65 | /** 66 | * Compare to 8-bit strings, return 0 if they are equal, 1 otherwise. 67 | */ 68 | int strcmp(const char * str1, const char * str2) 69 | { 70 | int i; 71 | 72 | for (i = 0; str1[i] && str1[i] == str2[i]; i++); 73 | 74 | return !(str1[i] == str2[i]); 75 | } 76 | -------------------------------------------------------------------------------- /src/utils_arm.S: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | .global __gnu_thumb1_case_si 9 | .global __gnu_thumb1_case_uqi 10 | 11 | .thumb 12 | .align 2 13 | 14 | .thumb_func 15 | __gnu_thumb1_case_si: 16 | push {r0, r1} 17 | mov r1, lr 18 | add r1, r1, #2 /* Align to word. */ 19 | lsr r1, r1, #2 20 | lsl r0, r0, #2 21 | lsl r1, r1, #2 22 | ldr r0, [r1, r0] 23 | add r0, r0, r1 24 | mov lr, r0 25 | pop {r0, r1} 26 | mov pc, lr 27 | 28 | .thumb_func 29 | __gnu_thumb1_case_uqi: 30 | push {r1} 31 | mov r1, lr 32 | lsr r1, r1, #1 33 | lsl r1, r1, #1 34 | ldrb r1, [r1, r0] 35 | lsl r1, r1, #1 36 | add lr, lr, r1 37 | pop {r1} 38 | bx lr 39 | -------------------------------------------------------------------------------- /test_programs/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = arm-none-eabi-gcc 3 | LD = arm-none-eabi-gcc 4 | CFLAGS = -Wall -O0 -Wno-unused-function 5 | LDFLAGS = -nostdlib -nostdinc -nostartfiles -T link.ld 6 | OBJCOPY = arm-none-eabi-objcopy 7 | 8 | 9 | inforad_k0_%.o: CFLAGS += -mcpu=arm7tdmi -include startup_inforad_k0.h -include uart_sirf.h 10 | inforad_k0_%.elf: LDFLAGS += -mcpu=arm7tdmi -Ttext=0x0 11 | 12 | all: inforad_k0_hello_world.bin inforad_k0_debug.bin inforad_k0_cpuid.bin inforad_k0_swbreakpoint.bin 13 | 14 | %.bin: %.elf 15 | $(OBJCOPY) -Obinary $< $@ 16 | 17 | %.elf: %.o 18 | $(LD) $(LDFLAGS) -o $@ $^ 19 | 20 | %_hello_world.o: hello_world.c 21 | $(CC) $(CFLAGS) -c -o $@ $^ 22 | 23 | %_cpuid.o: cpuid.c 24 | $(CC) $(CFLAGS) -c -o $@ $^ 25 | 26 | %_debug.o: debug.c 27 | $(CC) $(CFLAGS) -c -o $@ $^ 28 | 29 | %_swbreakpoint.o: swbreakpoint.c 30 | $(CC) $(CFLAGS) -c -o $@ $^ 31 | 32 | .PHONY: clean 33 | clean: 34 | @rm -f *.bin *.elf *.o 35 | 36 | -------------------------------------------------------------------------------- /test_programs/coprocessor.h: -------------------------------------------------------------------------------- 1 | #ifndef _COPROCESSOR_REGISTER_H 2 | #define _COPROCESSOR_REGISTER_H 3 | 4 | typedef uint32_t (*mrc_func_t)(void); 5 | typedef void (*mcr_func_t)(uint32_t); 6 | 7 | static uint32_t get_coprocessor_register(unsigned cp_num, unsigned opcode_1, unsigned cr_n, unsigned cr_m, unsigned opcode_2) 8 | { 9 | volatile uint32_t buf[2]; 10 | mrc_func_t mrc_func = (mrc_func_t) &buf[0]; 11 | 12 | buf[0] = (0xe << 28) //Condition 13 | | (0xe << 24) //Fixed part 14 | | ((opcode_1 & 0x7) << 21) 15 | | (1 << 20) //Fixed part 16 | | ((cr_n & 0xf) << 16) 17 | | (0 << 12) //R0 18 | | ((cp_num & 0xf) << 8) 19 | | ((opcode_2 & 0x7) << 5) 20 | | (1 << 4) //Fixed part 21 | | (cr_m & 0xf); 22 | buf[1] = 0xe12fff1e; //bx lr 23 | 24 | return mrc_func(); 25 | } 26 | 27 | static void set_coprocessor_register(unsigned cp_num, unsigned opcode_1, unsigned cr_n, unsigned cr_m, unsigned opcode_2, uint32_t val) 28 | { 29 | volatile uint32_t buf[2]; 30 | mcr_func_t mcr_func = (mcr_func_t) &buf[0]; 31 | 32 | buf[0] = (0xe << 28) //Condition 33 | | (0xe << 24) //Fixed part 34 | | ((opcode_1 & 0x7) << 21) 35 | | (0 << 20) //Fixed part 36 | | ((cr_n & 0xf) << 16) 37 | | (0 << 12) //R0 38 | | ((cp_num & 0xf) << 8) 39 | | ((opcode_2 & 0x7) << 5) 40 | | (1 << 4) //Fixed part 41 | | (cr_m & 0xf); 42 | buf[1] = 0xe12fff1e; //bx lr 43 | 44 | mcr_func(val); 45 | } 46 | 47 | #define cp15_get_midr() get_coprocessor_register(15, 0, 0, 0, 0) //Main Identification register, CPUID 48 | 49 | #define cp14_get_didr() get_coprocessor_register(14, 0, 0, 0b0000, 0b000) 50 | #define cp14_get_dscr() get_coprocessor_register(14, 0, 0, 0b0001, 0b000) 51 | #define cp14_get_dtr() get_coprocessor_register(14, 0, 0, 0b0101, 0b000) 52 | #define cp14_get_wfar() get_coprocessor_register(14, 0, 0, 0b0110, 0b000) 53 | #define cp14_get_vcr() get_coprocessor_register(14, 0, 0, 0b0111, 0b000) 54 | #define cp14_get_bvr(n) get_coprocessor_register(14, 0, 0, (n & 0xf), 0b100) 55 | #define cp14_get_bcr(n) get_coprocessor_register(14, 0, 0, (n & 0xf), 0b101) 56 | #define cp14_get_wvr(n) get_coprocessor_register(14, 0, 0, (n & 0xf), 0b110) 57 | #define cp14_get_wcr(n) get_coprocessor_register(14, 0, 0, (n & 0xf), 0b111) 58 | 59 | #define cp14_set_dscr(v) set_coprocessor_register(14, 0, 0, 0b0001, 0b000, v) 60 | #define cp14_set_dtr(v) set_coprocessor_register(14, 0, 0, 0b0101, 0b000, v) 61 | #define cp14_set_vcr(v) set_coprocessor_register(14, 0, 0, 0b0111, 0b000, v) 62 | #define cp14_set_bvr(n, v) set_coprocessor_register(14, 0, 0, (n & 0xf), 0b100, v) 63 | #define cp14_set_bcr(n, v) set_coprocessor_register(14, 0, 0, (n & 0xf), 0b101, v) 64 | #define cp14_set_wvr(n, v) set_coprocessor_register(14, 0, 0, (n & 0xf), 0b110, v) 65 | #define cp14_set_wcr(n, v) set_coprocessor_register(14, 0, 0, (n & 0xf), 0b111, v) 66 | 67 | #endif /* _COPROCESSOR_REGISTER_H */ -------------------------------------------------------------------------------- /test_programs/cpuid.c: -------------------------------------------------------------------------------- 1 | #include "uart_common.h" 2 | 3 | uint32_t get_cpuid_reg() 4 | { 5 | uint32_t cpuid_reg; 6 | 7 | asm("mrc p15, 0, %[cpuid_reg], c0, c0, 0" : [cpuid_reg] "=r" (cpuid_reg)); 8 | return cpuid_reg; 9 | } 10 | 11 | const char * get_implementor(unsigned vendor_id) { 12 | switch(vendor_id) { 13 | case 0x41: return "ARM Ltd"; 14 | case 0x44: return "DEC"; 15 | case 0x4d: return "Motorola - Freescale"; 16 | case 0x56: return "Marvell Semiconductor"; 17 | case 0x69: return "Intel"; 18 | default: return "Unknown vendor"; 19 | } 20 | } 21 | 22 | void identify_post_arm7_processor(uint32_t cpuid) 23 | { 24 | uart_puts("Post-ARMv6 processor\n"); 25 | } 26 | 27 | void identify_pre_armv4_processor(uint32_t cpuid) 28 | { 29 | uart_puts( "Pre-ARMv4 processor\n"); 30 | } 31 | 32 | void identify_arm7_processor(uint32_t cpuid) 33 | { 34 | unsigned implementor_id = (cpuid >> 24) & 0xff; 35 | const char * implementor = get_implementor(implementor_id); 36 | unsigned architecture_id = (cpuid >> 23) & 0x1; 37 | const char * architecture = architecture_id ? "v4T" : "v3"; 38 | unsigned variant_id = (cpuid >> 16) & 0x7f; 39 | unsigned ppn = (cpuid >> 4) & 0xfff; 40 | unsigned revision = cpuid & 0xf; 41 | 42 | uart_puts("CPUID register value: "); uart_puthexn(cpuid, 8); uart_puts("\n"); 43 | uart_puts("Implementor: "); uart_puts(implementor); uart_puts(" ("); uart_puthexn(implementor_id, 2); uart_puts(")\n"); 44 | uart_puts("Archictecture: "); uart_puts(architecture); uart_puts("\n"); 45 | uart_puts("Variant: "); uart_puthexn(variant_id, 2); uart_puts("\n"); 46 | uart_puts("Primary part nr: "); uart_puthexn(ppn, 3); uart_puts("\n"); 47 | uart_puts("Revision: "); uart_puthexn(revision, 1); uart_puts("\n"); 48 | } 49 | 50 | int main() 51 | { 52 | uint32_t cpuid; 53 | 54 | uart_puts("Welcome to the CPUID program\n"); 55 | 56 | cpuid = get_cpuid_reg(); 57 | 58 | uart_puts("CPUID register has been fetched\n"); 59 | 60 | if (cpuid & (1 << 19)) { 61 | identify_post_arm7_processor(cpuid); 62 | } 63 | else if (((cpuid >> 12) & 0xf) == 0) { 64 | identify_pre_armv4_processor(cpuid); 65 | } 66 | else if (((cpuid >> 12) & 0xf) == 7) { 67 | identify_arm7_processor(cpuid); 68 | } 69 | else { 70 | uart_puts("Unknown ARM processor\n"); 71 | } 72 | 73 | uart_puts("CPU identification finished\n"); 74 | while (1); 75 | } 76 | 77 | 78 | -------------------------------------------------------------------------------- /test_programs/debug.c: -------------------------------------------------------------------------------- 1 | #include "uart_common.h" 2 | #include "coprocessor.h" 3 | 4 | void break_in_this_function() 5 | { 6 | uart_puts("Breakpoint not hit\n"); 7 | } 8 | 9 | void test_hw_breakpoint() 10 | { 11 | unsigned i; 12 | 13 | cp14_set_dscr(0); 14 | cp14_set_vcr(0); 15 | for (i = 0; i < 16; i++) { 16 | cp14_set_bcr(i, 0); 17 | cp14_set_wcr(i, 0); 18 | } 19 | 20 | cp14_set_bvr(0, (uint32_t) break_in_this_function); 21 | cp14_set_bcr(0, 22 | (1 << 0) /* Breakpoint enable */ 23 | | (0b11 << 1) /* Supervisor and user mode */ 24 | | (0b1111 << 5) /* Trigger BP if any of the four instruction bytes is read */ 25 | | (0 << 20) /* Breakpoint linking disabled */ 26 | | (0b00 << 21) /* Instruction virtual address match */); 27 | cp14_set_dscr(1 << 15); 28 | 29 | break_in_this_function(); 30 | 31 | uart_puthex(cp14_get_bvr(0)); 32 | } 33 | 34 | static uint32_t get_didr() 35 | { 36 | uint32_t didr; 37 | 38 | asm("mrc 14, 0, %[didr], c0, c0, 0" : [didr] "=r" (didr)); 39 | return didr; 40 | } 41 | 42 | __attribute__((__naked__)) uint32_t get_didr2() 43 | { 44 | asm("mrc 14, 0, r0, c0, c0, 0 \n" 45 | "bx lr"); 46 | return 0; 47 | } 48 | 49 | int main() { 50 | uint32_t didr = cp14_get_didr(); 51 | uint32_t didr2 = get_didr(); 52 | uint32_t didr3 = get_didr2(); 53 | 54 | unsigned debug_ver = (didr >> 16) & 0xf; 55 | unsigned num_brp_context = ((didr >> 20) & 0xf) + 1; 56 | unsigned num_brp = (didr >> 24) & 0xf; 57 | unsigned num_wrp = ((didr >> 28) & 0xf) + 1; 58 | unsigned rev = didr & 0xf; 59 | unsigned var = (didr >> 4) & 0xf; 60 | 61 | if (num_brp > 0) { 62 | num_brp += 1; 63 | } 64 | 65 | uart_puts("DIDR1 register value: "); uart_puthex(didr); uart_puts("\n"); 66 | uart_puts("DIDR2 register value: "); uart_puthex(didr2); uart_puts("\n"); 67 | uart_puts("DIDR3 register value: "); uart_puthex(didr3); uart_puts("\n"); 68 | uart_puts("Debug version: "); uart_puthexn(debug_ver, 1); uart_puts("\n"); 69 | uart_puts("#BRPs with context ID: "); uart_puthexn(num_brp_context, 2); uart_puts("\n"); 70 | uart_puts("#BRPs: "); uart_puthexn(num_brp, 2); uart_puts("\n"); 71 | uart_puts("#WRPs: "); uart_puthexn(num_wrp, 2); uart_puts("\n"); 72 | uart_puts("Variant number: "); uart_puthexn(var, 1); uart_puts("\n"); 73 | uart_puts("Revision number: "); uart_puthexn(rev, 1); uart_puts("\n"); 74 | uart_puts("Finished debug register identification, now testing hardware breakpoint\n"); 75 | 76 | test_hw_breakpoint(); 77 | 78 | uart_puts("Still alive\n"); 79 | 80 | 81 | while (1); 82 | } 83 | 84 | 85 | -------------------------------------------------------------------------------- /test_programs/hello_world.c: -------------------------------------------------------------------------------- 1 | #include "uart_common.h" 2 | 3 | int main() { 4 | uart_puts("Hello world!\n"); 5 | while (1); 6 | } 7 | 8 | 9 | -------------------------------------------------------------------------------- /test_programs/hwdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef _HWDEBUG_H 2 | #define _HWDEBUG_H 3 | 4 | static unsigned max_context_id_breakpoints; 5 | static unsigned max_breakpoints; 6 | static unsigned max_watchpoints; 7 | static unsigned debug_version; 8 | 9 | #define hwdebug_enable() cp14_set_dscr(1 << 15) 10 | #define hwdebug_disable() cp14_set_dscr(0) 11 | 12 | static int hwdebug_init(void) 13 | { 14 | unsigned i; 15 | uint32_t didr = cp14_get_didr(); 16 | 17 | debug_version = (didr >> 16) & 0xf; 18 | max_context_id_breakpoints = ((didr >> 20) & 0xf) + 1; 19 | max_breakpoints = ((didr >> 24) & 0xf) + 1; 20 | max_watchpoints = ((didr >> 28) & 0xf) + 1; 21 | 22 | if (max_breakpoints != 0) { 23 | max_breakpoints += 1; 24 | } 25 | 26 | cp14_set_vcr(0); //Do not catch any exception vectord 27 | for (i = 0; i < max_breakpoints; i++) { 28 | cp14_set_bcr(0); 29 | } 30 | for (i = 0; i < max_watchpoints; i++) { 31 | cp14_set_wcr(0); 32 | } 33 | } 34 | 35 | static int hwdebug_set_breakpoint(uint32_t address, ) 36 | 37 | #endif /* _HWDEBUG_H */ -------------------------------------------------------------------------------- /test_programs/link.ld: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2013-2014 Jonas Zaddach , EURECOM 3 | * 4 | * You can redistribute and/or modify this program under the terms of the 5 | * GNU General Public License version 2 or later. 6 | */ 7 | 8 | OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 9 | OUTPUT_ARCH(arm) 10 | ENTRY(_entry) 11 | SECTIONS 12 | { 13 | _entry = .; 14 | .text : { *(.init) *(.text) } 15 | .data : { *(.data) } 16 | .bss : { *(.bss) } 17 | } 18 | -------------------------------------------------------------------------------- /test_programs/startup_inforad_k0.h: -------------------------------------------------------------------------------- 1 | #ifndef _STARTUP_INFORAD_K0_H 2 | #define _STARTUP_INFORAD_K0_H 3 | 4 | #include 5 | 6 | static int uart_puts(const char * str); 7 | static void uart_puthexn(uint32_t val, unsigned digits); 8 | //static void uart_puthexn(uint32_t num, unsigned x); 9 | 10 | __attribute__((__naked__)) void _start() { 11 | /* TODO: Put startup code here, e.g., stack initialization, 12 | and then call main. */ 13 | __asm__( 14 | ".section .init \n" 15 | "b _reset \n" 16 | "b _und_exception \n" 17 | "b _svc_exception \n" 18 | "b _pab_exception \n" 19 | "b _dab_exception \n" 20 | "nop \n" 21 | "b _irq_exception \n" 22 | "b _fiq_exception \n" 23 | ".section .text \n" 24 | "_und_exception: \n" 25 | "mov r0, #1 \n" 26 | "b _exception \n" 27 | "_svc_exception: \n" 28 | "mov r0, #2 \n" 29 | "b _exception \n" 30 | "_pab_exception: \n" 31 | "mov r0, #1 \n" 32 | "b _exception \n" 33 | "_dab_exception: \n" 34 | "mov r0, #1 \n" 35 | "b _exception \n" 36 | "_irq_exception: \n" 37 | "mov r0, #1 \n" 38 | "b _exception \n" 39 | "_fiq_exception: \n" 40 | "mov r0, #1 \n" 41 | "b _exception \n" 42 | "_exception: \n" 43 | "mov r1, lr \n" 44 | "ldr sp, =0x60017ffc \n" 45 | "bl exception_handler \n" 46 | "b . \n" 47 | "_reset: \n" 48 | "ldr sp, =0x60017ffc \n" 49 | "bl main \n" 50 | "b . \n"); 51 | } 52 | 53 | void exception_handler(unsigned exception_index, uint32_t lr) 54 | { 55 | uart_puts("Exception "); 56 | uart_puthexn(exception_index, 1); 57 | uart_puts(" at "); 58 | uart_puthexn(lr, 8); 59 | uart_puts(" occured.\n"); 60 | 61 | while (1); 62 | } 63 | 64 | #endif /* _STARTUP_INFORAD_K0_H */ 65 | 66 | 67 | -------------------------------------------------------------------------------- /test_programs/swbreakpoint.c: -------------------------------------------------------------------------------- 1 | #include "uart_common.h" 2 | 3 | 4 | int main() 5 | { 6 | uart_puts("Program started\n"); 7 | asm(".long 0xe12fff7f"); 8 | // asm(".long 0xe7f001f0"); 9 | 10 | uart_puts("Xrogram finished\n"); 11 | // asm(".long 0xe7f001f0"); 12 | //For thumb use 0xde01 13 | 14 | while (1); 15 | } 16 | 17 | 18 | -------------------------------------------------------------------------------- /test_programs/uart_common.h: -------------------------------------------------------------------------------- 1 | #ifndef _UART_COMMON_H 2 | #define _UART_COMMON_H 3 | 4 | #include 5 | 6 | static int uart_getc(); 7 | static int uart_putc(int c); 8 | static void uart_puthexn(uint32_t val, unsigned digits); 9 | 10 | int uart_puts(const char * str) { 11 | while (*str) { 12 | uart_putc(*str); 13 | str += 1; 14 | } 15 | 16 | return 0; 17 | } 18 | 19 | void uart_puthexn(uint32_t val, unsigned digits) { 20 | int i; 21 | uint32_t digit; 22 | 23 | uart_puts("0x"); 24 | 25 | for (i = digits - 1; i >= 0; i--) { 26 | digit = (val >> (4 * i)) & 0xf; 27 | if (digit >= 0 && digit <= 9) { 28 | uart_putc(digit + '0'); 29 | } 30 | else { 31 | uart_putc(digit + 'A' - 10); 32 | } 33 | } 34 | } 35 | 36 | #define uart_puthex(val) uart_puthexn(val, 8) 37 | 38 | #endif /* _UART_COMMON_H */ 39 | -------------------------------------------------------------------------------- /test_programs/uart_sirf.h: -------------------------------------------------------------------------------- 1 | #ifndef _UART_SIRF_H 2 | #define _UART_SIRF_H 3 | 4 | #include 5 | 6 | #define UART_BASE ((volatile uint16_t *) 0x80030000) 7 | 8 | static int uart_getc() { 9 | while (!(UART_BASE[1] & (1 << 0x04))); 10 | return UART_BASE[3]; 11 | } 12 | 13 | //static __attribute__((__naked__)) 14 | 15 | static int uart_putc(int c) { 16 | while (UART_BASE[1] & (1 << 0x6)); 17 | UART_BASE[2] = c; 18 | 19 | return 0; 20 | } 21 | #endif /* _UART_SIRF_H */ 22 | -------------------------------------------------------------------------------- /xml/arm-gdbstub.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | arm 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | --------------------------------------------------------------------------------