Cortex M7:刚开始就分支

Cortex M7: Branch just after start

我正在使用采用 cortex-M7 处理器的 ATSAMV71Q21B MCU。为了增加冗余,我想有多个引导加载程序并在启动微控制器后立即进入其中一个引导加载程序。最后,ARM 处理器开始在复位向量位置 0x00000000 处执行。我无法选择我想从哪里开始。

我想知道是否可以使用少量指令分支到我的引导加载程序之一。

目前,我尝试生成数百条指令的所有解决方案对我来说太多了。我想我需要手动添加分支指令到向量位置 0x00000000。虽然,我不确定我应该在哪里分支,以及是否可以这样做。

确实,我不确定我是否真正理解了生成的汇编代码的开头。因此,我不确定在哪里分支。

这里是程序开头的例子:

0x00400000  70 0a 40 20 d9 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00  p.@ Ù.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.....
0x00400020  00 00 00 00 00 00 00 00 00 00 00 00 d5 01 40 00 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00  ............Õ.@.Õ.@.....Õ.@.Õ.@.
0x00400040  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400060  d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.....Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400080  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x004000A0  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x004000C0  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x004000E0  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400100  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00 00 00 00 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.........
0x00400120  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400140  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400160  d5 01 40 00 d5 01 40 00 10 b5 05 4c 23 78 33 b9 04 4b 13 b1 04 48 af f3 00 80 01 23 23 70 10 bd  Õ.@.Õ.@..µ.L#x3..K.±.H¯ó.€.##p..
0x00400180  2c 04 40 20 00 00 00 00 28 04 40 00 0c 4b 43 b1 0c 48 0d 49 10 b5 af f3 00 80 0c 48 03 68 23 b9  ,.@ ....(.@..KC±.H.I.µ¯ó.€.H.h#.
0x004001A0  10 bd 0a 48 03 68 33 b9 70 47 09 4b 00 2b f7 d0 bd e8 10 40 18 47 06 4b 00 2b f5 d0 18 47 00 bf  ...H.h3.pG.K.+÷Ð.è.@.G.K.+õÐ.G.¿
0x004001C0  00 00 00 00 28 04 40 00 30 04 40 20 28 04 40 00 00 00 00 00 fe e7 00 bf 16 49 17 4a 91 42 08 b5  ....(.@.0.@ (.@.....þç.¿.I.J‘B.µ

如果我没理解错的话,这是一个向量table,我不应该在这里分支。对吗?

0x00400000  70 0a 40 20 d9 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 00 00 00 00  p.@ Ù.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.....
0x00400020  00 00 00 00 00 00 00 00 00 00 00 00 d5 01 40 00 d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00  ............Õ.@.Õ.@.....Õ.@.Õ.@.
0x00400040  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400060  d5 01 40 00 00 00 00 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.....Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.
0x00400080  d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00 d5 01 40 00  Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.Õ.@.

所以这些看起来不错第一个是堆栈指针加载值

0x20400a70 

可能是一个奇怪的数字,但这部分有 0x80000 字节的 ram,所以它是有效的。所以可能是链接描述文件生成的值(链接描述文件中的堆栈设置,而不是仅从 ram 顶部开始)。

重置向量是

0x004001d9 

哪个格式正确(设置了 lsbit)至于它指向的内容你没有提供。

其他很多都是

0x004001d5

同样正确格式化的可能是一个无限循环,基于它与重置向量的接近程度,但谁知道必须查看代码。开机没关系。

chip/family 文档表明用户闪存位于地址 0x00400000 并且对于这些部分来说相当大,因此此转储左侧的地址和复位向量看起来都很好。

有提示说在0x00800000或者0x08000000这个地址有一个sam-babootloader或者我不记得了,你可以查一下。现在我已经使用了其他 Atmel 部件,这些部件没有从 Atmel 的闪存中烧录引导加载程序,而是源代码到 sam-ba 你可以自己构建和使用(为什么要让你自己的更简单更不笨重),但我有该方法的问题闪存如何锁定或未锁定,解锁和擦除有多容易,那么有什么意义呢?使用社署。文档中的此评论可能表明在这种情况下已被烧毁,那么您需要查看如何选择引导该应用程序而不是用户应用程序,在任何一种情况下,因为它们指示特定地址。如果它是用户可更改的,那么这就是您想要放置引导加载程序的地方,或者如果它是固定的且不可更改的,那么只需将它用作您的引导加载程序。

至于通常你把引导加载程序放在哪里,你可以选择你的设计,你所说的引导加载程序是什么意思,有什么功能等。经常被误用,但这个术语意味着既可以引导部件,也可以有办法以某种方式加载其他应用程序(运行 一个在 ram 中,重新编程 user/boot/application 闪存,等等)。您需要了解的是闪存在该设备上的工作方式,假设您希望能够 re-write 其一部分使用新固件。有时你可以同时执行 out 和 flash 但更有可能这样做他们使用多个闪存组所以你可以 运行 在一个中修改另一个,然后导致他们的引导方案总是这样只在一个上启动,而不能在另一个上启动,所以你要么必须永远保留引导加载程序 as-is,要么有一个方案,还必须有一个方案来选择哪些图像在哪些银行上成为引导加载程序后的默认固件靴子。

这些核心通常可以 运行 在 ram 中编写代码,没有理由不期望这里不存在(这不是核心,重要的是芯片供应商的实现)所以复制和跳转引导加载程序的一部分为了不被 运行 连接到闪存上,您可以对任何闪存进行重新编程,但如果闪存出现故障或断电,部件可能会变砖,这会使您自己处于危险之中。

如果芯片供应商还没有使用工厂引导加载程序完成此操作,并且该工厂加载程序适合现场使用,它可能会使用 I/O 引脚来确定引导哪一个,必须查看文档.如果您选择自己执行此操作,让一个 gpio 引脚选择两个引导路径并不是不明智的,那么您可以有一个非常小的,理想情况下没有错误的十几行汇编读取 gpio 引脚并分支到一个固定点您选择的闪存 例如说 0x00500000 和 0x00600000,具体取决于您认为您的应用程序实际有多大。然后,如果用户希望加载闪存,您可以复制并跳入 ram,然后您可以选择加载一个或另一个。少数几行代码可能是几十行,如果选择的是错误的并且没有完成,则对某种选定的银行和未选择的银行进行校验和。或您提供的第三个引导加载程序,以防两者不校验和。

大量的解决方案,通常如果你没有单独存储的闪存,你需要分支到 ram 并且在如何设计内存方面有更多的自由space(假设闪存可以按页面擦除) .否则,您可能只想使用芯片供应商的银行解决方案。

因此,所有这些都记录在 arm 和 Atmel(微芯片)的文档中,您在开始使用此设备之前应该已经拥有这些文档。在所有这些中,唯一与 arm 相关的是向量 table 的工作方式。其余所有,地址,大小等都是芯片供应商实现的。所以你的大部分阅读都在芯片供应商文档中,在这种情况下,他们有大量数据sheet方法(而不是单独的数据sheet和参考手册方法)。

你需要 re-read 我发现的 sam-ba 如果你想使用它,如果它适合你,闪存实现的性质,它是否在应用程序中可编程,等等。和然后你设计 n不仅是引导加载程序的功能,还有地址 space,无论它是在闪存还是 ram 中执行。

编辑

以防我没看懂问题。

手臂重置向量位于 0x00000004 而不是 0x00000000(对于 cortex-ms),它是处理程序的地址与 1 或。地址 0x00000000 是堆栈指针的初始化值,如果你选择在代码中初始化堆栈指针而不是使用这种机制,你可以在那里放任何你想要的东西。

如果你想更改重置处理程序地址,那么你必须修改 0x00000004,在某些部分你可以在不擦除的情况下更改(通常闪烁要么通过擦除到所有工作然后你可以写零,不能写一个,但可以在每个 byte/word/chunk 的基础上将 1 更改为 0)。因此,要更改此设置,您可能需要将其保存并擦除 block/page,更改您想要的位并写回。例如,您可能能够将它从 0x004001d9 更改为 sah 0x004101d9 或 0x004000d9,但不值得尝试这样做。该值是处理程序的地址与 1 或。

这不是分支,因为此时代码未执行 (normally/assumed) 它是读取该位置并将其用作起点的逻辑,第一次提取不是分支。

正如所指出的,查看矢量 table 在项目中的位置,然后修改它以指向您的备用重置处理程序。可能是这样的代码

.word STACK_END
.word reset_handler
.word 

在这种情况下,一些 fill/dummy 向量用于其余的许多向量。只需用您的处理程序替换 reset_handler 或您找到的任何内容,记住这是一个引导加载程序,如果您打算调用任何 C 函数,则需要 bootstrap C,如果是 C++ 或其他语言则更糟。