Jlink OB 自己做

我做的板子,在保证功能完整的情况下,一般都会尽量做小。于是就 2.54mm 排针,或者标准的 JTAG 的体积我都不能忍。。不管什么芯片,我都会上 RT-Thread, RTT 的 finsh 调试非常好用,但是必须要有串口。

所以,大概是在大二做飞控的时候,我定义了一个 8-pin 的 FPC 来做专用的调试,里面包含了 SWD 和 UART。并且 SWD 是带 SWO 的。

这么多年来,我只做了一个调试器,用的 USB HUB 芯片,把 Jlink OB 和 CP2102 整合在一块板子上。

板子错误挺多的,最严重的是 CP2102 芯片整个是用飞线飞过去的。。

就这么不稳定地过了好多年,在知道 STM32F072 的 Jlink OB 同时支持了虚拟 UART 之后,就决定还是要做一个新的。

新旧对比。板子很快就做好了。

有了硬件,开始愁固件了。

这位大神,从JlinkARM.dll 里面硬生生把 STM32F072 的Jlink OB 固件给拔出来了。

牛不牛掰!

可惜他的帖子里面提供的文件,是从5.12版本的 JlinkARM.dll,里面拔出来的,现在最新的到了至少 6.20, 我的 keil 里面是 6.10j,每次链接都会提示固件升级,神烦。

而且在我的板子上,出现了点击取消升级后,板子掉线的情况。

拿 JlinkARM.dll 开刀

于是我打算自己尝试把固件拔出来。方法跟他的一样,从 JlinkARM.dll 下手。

他本人已经在帖子里面回复了最新的 6.10n 这个版本的 JlinkARM.dll 的固件位置

Can't say about 610i but for 610n start from 0x8C8054 and length 0x0B66C

不过我没找到这个版本的 JlinkARM.dll。我打算拿自己 keil 带的 6.10j 的dll来尝试定位 STM32 的固件位置。

开始挖坑

需要的工具是 WinHex

首先我尝试打开从他博客下载的固件,我的设想是,在我的 JlinkARM.dll 里面找看看,有没有一样的至少前面几个字节。比如这几个,0x38 1C 00 20

结果并没有。我又试试找了其他的字段,并没有什么线索。

我反思了一下,既然固件是有可能变化的,那我还是尝试一下在博客主用的 5.12j 的 JlinkARM.dll 里面先定位一下固件。

于是我把 5.12j 下了下来,打开后果然定位到了固件的位置。这个版本的固件,是 38 1C 开头的。

但是要怎么在其他版本的 JlinkARM.dll 里面定位呢?依旧用我手上的 6.10j 版本的 JlinkARM.dll 试一下。我注意到了固件之前,也就是 38 1C 之前的这几个字节。先不管他们有什么意义,先在 6.10j 里面搜搜试试。

哈哈哈,果然给我找到了,难道固件就是后面 4A 25 00 EA 开头的么? 现在还不好确定。先假设这里就是开始位置,那么长度是多少?

于是我又回到 5.12j 里面,参考一下原博,找找是否有长度信息。

原博对 5.12j 版本的描述

  1. Extract binary part from JLinkARM.dll (from JLink_V512)
    For example from offset 7153340 (0x6D26BC) and size 41192 (0x0A0E8).

Use any binary extraction tool as you prefer.

现在有两个思路,

  1. 找到 5.12 里面的 0x0A0E8,看看这个长度信息的位置有什么线索。
  2. 找到固件的结尾,看看是否是一个固定的特殊格式

打住!以上是错误的。上面那个图,仔细看的话,就会发现,右边的描述里面,写着,这个固件是给 SAM7 用的,而不是STM32!!! 而且,博主并不是用 5.12j 的 JlinkARM.dll 开刀的! 偏移地址根本不对。 满满的坑。

填坑

虽然上面找到的代码,并不合适 STM32F072,但是!我找到了线索和规律,

线索就是,直接搜索单片机的型号!
规律就是,不同芯片的固件,是连续放置的!

先看线索,在博主提供的 5.12 版本里面提取的固件中,有这样一个规律。

单片机相关的描述之前,有一些 64个字节的 FF 和 16个字节的 00,这些明显是保留的块,具体用来干嘛的我不懂,我也不想理。然后之前是 12 * 16 个字节的数据,我印象中,这个地方应该是放置了中断跳转的函数指针,具体不确定。

但是,他们的长度是固定的,也就是说,找到单片机的描述,再往前推一定数量的字节,就是固件开始地方!

具体是多少个字节呢,17行 * 16 = 0x1FA 个 (506个)。

好了,那我们就去其他版本的 JlinkARM.dll 里面搜,这里以我手上的 6.10j 版本为例。

很轻松就找到了关于 STM32F072的描述,然后根据 保留的 FF 和 00, 往前推 12 行, 看到一个“60 1D 00 20” 开头的字段。看到的第一眼,我就很肯定这就是固件的开头了!

因为这个跟博主提供的 5.12 版本的固件太像了 “30 1C 00 20”。最后两个字节一模一样。“30” 和 “60” 在二进制上,只移位了1位,然后 1D 就很简单的是 1C+1.

找到开头了,可喜可贺,那么固件的长度是多少呢?找不到固件的长度,裁剪不出来,有个毛用?

然而,我不需要知道固件的长度。因为固件的存放,是连续的,这是我在浏览上下文发现的一个规律。我只需要知道下一个固件什么时候开始,然后大概裁剪一下就好了。原则是只能多裁剪,不能少裁剪。

有人会担心,如果多余的字节被裁剪进去了,会不会影响程序,答案是否定的。为啥自己去考虑考虑。

于是我开始寻找下一个固件开始的位置,怎么找?直接用手翻。也就 40+k 的固件大小,翻几十页就好了。鼠标点几下还是很快的。

嘿嘿,下一个居然是 STM32F103 的 Jlink OB 固件。

到这里其实可以结束了,想省事,直接裁剪到那堆 FFFF 里面随意位置就好,因为显然这个地方已经是另一个固件开始的地方了。符合“只多裁,不少裁”的原则。当然我是按 32bit 对齐裁剪的。新建一个文件,把固件开始位置,到结束位置复制过去,然后保存为 .bin 就可以了。

下载,测试,bingo!固件显示已经是 2017年5月的固件,比我的 jlink 驱动还新。这回不会再提示更新固件了吧

但是如果我想知道固件准确的结束位置,怎么办

再挖一个坑

仔细看了一下 F103 的固件,保留的 FF 区域的大小,跟 F072 固件完全不同,那我就很难确定了。当然,F103 的 Jlink OB 固件满天飞,去网站上下一个,用相同的方法查看 F103 固件的偏移量,就大概能知道是什么地方开始的了。但是,知道开始的位置并没有什么用,虽然 JlinkARM.dll 里面固件看起来是连续存放的,但是固件之间可能会有一些其他的描述符。如果想去除这些,必须找到真正的固件结束位置。

然后我就继续往上翻了。 滚了几个滚轮之后,马上看到了熟悉的 pattern。 一大堆 "0xFE 0xE7"

对比一下 5.12 JlinkARM.dll 提取的固件结尾:

非常相似,所以呢,大概就是这个地方了。

然而并不是这样。。。反正这个地方失败了

保存,测试,失败。

坑不填了

就这么先用着吧。

因为固件不完美,最新的 Jlink OB STM32F072 的 bin 文件 (来自 6.20e) 就不放了,如果有需求清留言。

看完以上,需要的人应该已经能自己定位固件的位置自己提取最新版本的固件了。
ST 的 DFU 软件也是各种各样的坑,祝好。

关于固件自动升级的问题

答案是:不能
以上固件在单片机的 flash 中,是从 0x8004800 开始的,从 0x8000000 开始,是 bootloader。

问题在于,博客里面提供的 bootloader 并不是 jlink 写的 bootloader。博客里面能下载的bootloader,我查看了一下,非常短。我推断它只提供了很简单的跳转到 0x8004800 的功能。

这就导致了 Jlink 的驱动,无法升级固件。没授权下拿到 Jlink 提供的 bootloader 的可能性极小。