前言
- 1)前面几节我们学习了 ① ~ ③ 中的解析命令行参数与解析配置文件,接下来我们来看一下剩余的 ④ ~ ⑥ 部分:server_init() 函数、init 命令和 server_loop() 函数:
1 server_init()
-
1)server_init() 的执行逻辑如下:
-
2)总的来说,添加了两个 service 到 struct service *services; 链表中:
- (1)tcl_service:应该是与 tcl 语法相关的 tcp 连接,暂时未用到
- (2)telnet_service:创建 telnet 相关的 tcp 连接,主要作用是让我们可以通过 telnet 连接到 OpenOCD 服务端,OpenOCD 支持的所有命令均可以在 telnet 连接后执行,也是我编写芯片烧录驱动的主要测试方式。
2 执行 init 命令
- 1)OpenOCD 通过 command_run_line(ctx, “init”) 执行 init 命令的逻辑如下:
这可能就是所谓的冰山一角吧:看着是一条 init 命令,其实内部执行一系列的初始化操作。
2.1 target init
-
1)target init 命令的大概执行逻辑如下:
-
2)init_targets、init_target_events、init_board 三个命令是定义在 src/target/startup.tcl 文件中三个调用过程 proc。可以让用户在初始化过程中的进行功能补充。
-
3)接下来在 target_init() 函数中,主要有以下内容:
-
(1)根据全局变量 struct target *all_targets; 遍历所有 target,并通过 target->type->init_target() 函数指针进行 target_type 的初始化,最后对 target_type 进行其它属性填充。关于 target_type,上一节中创建 target 时,我们提到:
-
(2)通过 target_register_user_commands() 函数注册 target 相关命令,如 target_request debugmsgs,trace history, reg/poll/halt/resume/reset/mdd[w/h/b]/mwd[w/h/b]/verify_image 等等
-
(3)通过将 handle_target() 函数指针注册给 target_timer_callbacks,获得处理 srst 与 power 事件的能力。
-
-
4)关于 target_type->init_target() 的初始化,以 cortexm_target 为例:
-
百度上说,Semihosting 技术是将目标板的输入/输出请求从应用程序代码传递到远程运行调试器的主机的一种机制。
2.2 adapter_init()
-
1)adapter 初始化的逻辑如下(右侧还是以 cmsis-dap 为例):
-
2)首先进行 adapter_driver 的初始化(这里为 cmsis-dap),都是 cmsis-dap 相关的细节,有时间我们再通过 DAPLink 项目深入学习。
-
3)然后是设置 adapter 的速度。这里首先设置速度,然后会再读取 adapter 的实际速度。
2.3 其它命令
剩余的命令就不再一一分析了,这里仅列出命令的执行函数入口以供有兴趣者研究。
command | handler function entry | location | 概要说明 |
---|---|---|---|
transport init | handle_transport_init() | src/transport/transport.c | 对命令 ‘transport select <transport>’ 中的 <transport> 进行初始化,包括 swd、jtag 等 |
dap init | handle_dap_init() | src/target/arm_dap.c | 对 DAP(Debug Access Port)进行初始化。 |
flash init | handle_flash_init_command() | src/flash/nor/tcl.c | 注册了许多 flash 开头的命令,如检测命令 flash probe、擦除扇区命令 flash erase_check 等 |
nand init | handle_nand_init_command() | src/flash/nand/tcl.c | 注册了许多 nand 开头的命令,可能是操作 nand 类存储设备的命令 |
pld init | handle_pld_init_command() | src/pld/pld.c | pld,Programmable Logic Device,不太明白,不敢妄言 |
tpiu init | handle_arm_tpiu_swo_init() | src/target/arm_tpiu_swo.c | 完全不懂 |
以上命令不再作解析,因为有些内容我实在搞不明白,这里仅做逻辑记录,待日后有机会再深入了解。
- 可参考:
-
官网说明:https://openocd.org/doc-release/html/index.html#SEC_Contents
-
《Arm Debug Interface Architecture Specification v5.2》:https://documentation-service.arm.com/static/5f900b1af86e16515cdc0642
-
3 server_loop()
-
1)该函数遍历 service,并以 select 的方式对其内部的 socket 进行轮询。
-
2)从前面几章我们知道,OpenOCD 中一共有以下几种 service:
名称 | 端口 | 简述 |
---|---|---|
gdb service | 3333 | 用于 gdb 调试 |
telnet service | 4444 | 执行擦除、烧录、读取等命令 |
jtag vpi | 5555 | 没用到过,不了解 |
tcl service | 6666 | 猜测是用来执行 tcl 文件中命令的 |
jsp service | 7777 | 没用到过,不了解 |
rtt service | xxxx | Real Time Transfer,类比 SEGGER 的 RTT,通过 rtt start [message] 指定 |
通过 telnet ip:port 连接到 OpenOCD 后,根据连接的端口,由对应的 Service 进行命令处理。我们已经了解通过 4444 端口的烧录等命令处理。
下一次,我们将了解通过 RTT service 来打印 DAPLINK 日志的方式。