Thumb 的 LPC4088 校验和值?
LPC4088 checksum value for Thumb?
在 LPC4088 user manual(第 876 页)中我们可以看到 LPC4088 微控制器有一个非常特别的启动程序:
这看起来完全是胡说八道,我需要有人帮我解决问题...在 ARM 的世界里,我听过无数次将矢量 table 看起来像这样:
reset: b _start
undefined: b undefined
software_interrupt: b software_interrupt
prefetch_abort: b prefetch_abort
data_abort: b data_abort
nop
interrupt_request: b interrupt_request
fast_interrupt_request: b fast_interrupt_request
正好在我的二进制文件中的 0x00000000
位置,但是如果这个位置在启动时被引导 ROM 向量 table 遮蔽了,我们为什么要这样做,因为它甚至无法更改是只读的?!那么我们可以把自己的向量table放在哪里呢?我想把它放在 0x1FFF0000
上,这样它会在重置时转移到位置 0x00000000
但不能这样做,因为只读区域...
现在进入第二部分。 ARM 希望在 0x00000000
处准确找到 8 向量,并且在重置引导 ROM 时检查 8 向量的总和是否为零,并且仅当此是真正的用户代码执行。要通过此检查,我们需要首先对 7 个向量求和,并将其与最后一个向量的 2 补码保存在一起,最后一个向量是用于驻留在 0x0000001C
处的快速中断请求的向量。好吧,这仅在您的代码是 4 字节对齐(ARM 编码)时才是正确的,但如果您的代码是 2 字节对齐(Thumb 编码),它仍然是正确的,所有 Cortex-M4 内核都是这种情况,只能执行 Thumb 编码操作码...那么为什么他们明确提到总和的 2 的补码必须在 0x0000001C
,而这永远不会与 Cortex-M4 一起玩。 0x0000000E
是保存 2 的补码的正确地址吗?
还有第三部分。为什么引导 ROM 甚至会检查第一个 8 向量的总和是否为零,因为它们已经在引导 ROM 中了?!并且是只读的!
你能看出这里有什么奇怪的地方吗?上面三段的不明之处需要有人给我解释一下...
你需要阅读 arm 文档以及 nxp 文档。非 cortex-m 内核的启动方式与您一直卡在那里的 cortex-m 内核不同。
cortex m在armv7m ARM ARM(架构参考手册)中有记载。它基于 VECTORS 而不是 Instructions。处理程序的地址而不是全尺寸 arm 内核中的指令。异常 7 被记录为保留(对于来自他们的基于 ARM7TDMI 的 mcus,它也是他们用于此校验和的保留向量)。根据您使用的 arm 内核,他们期望多达 144 或 272 个(异常加上最多 128 或 256 个中断,具体取决于内核支持的内容)。
(注意 aarch64 处理器,64 位模式下的 armv8 也不同于传统的全尺寸 32 位 arm 处理器,甚至更大 table)。
这个校验和是经典的 NXP 并且很有意义,没有理由启动一个已擦除或未正确准备的闪存和砖块或挂起。
.cpu cortex-m0
.thumb
.thumb_func
.globl _start
_start:
.word 0x20001000 @ 0 SP load
.word reset @ 1 Reset
.word hang @ 2 NMI
.word hang @ 3 HardFault
.word hang @ 4 MemManage
.word hang @ 5 BusFault
.word hang @ 6 UsageFault
.word 0x00000000 @ 7 Reserved
.thumb_func
hang: b hang
.thumb_func
reset:
b hang
给出:
Disassembly of section .text:
00000000 <_start>:
0: 20001000 andcs r1, r0, r0
4: 00000023 andeq r0, r0, r3, lsr #32
8: 00000021 andeq r0, r0, r1, lsr #32
c: 00000021 andeq r0, r0, r1, lsr #32
10: 00000021 andeq r0, r0, r1, lsr #32
14: 00000021 andeq r0, r0, r1, lsr #32
18: 00000021 andeq r0, r0, r1, lsr #32
1c: 00000000 andeq r0, r0, r0
00000020 <hang>:
20: e7fe b.n 20 <hang>
00000022 <reset>:
22: e7fd b.n 20 <hang>
现在制作一个执行校验和并将其添加到二进制文件的临时工具
看上面的程序是这样的程序:
0x20001000
0x00000023
0x00000021
0x00000021
0x00000021
0x00000021
0x00000021
0xDFFFEF38
0xE7FDE7FE
如果你刷它,引导加载程序应该会满意它并让它 运行。
现在假设校验和是基于字的,如果它是基于字节的,那么您需要一个不同的数字。
99% 的裸机编程都是阅读和研究。如果您已经构建了他们的二进制文件或使用了支持此处理器或系列的沙箱,您可以检查构建的二进制文件并查看所有这些是如何工作的。或者查看某人 github 示例或博客以了解其工作原理。他们确实记录了这一点,在成为 NXP 之前,他们已经使用这种方案很多年了,所以没有什么新鲜事……现在它是基于字还是基于字节的校验和,文档暗示基于字,这更有意义。但是一个简单的实验 and/or 查看沙箱生成的二进制文件就可以解决这个问题。
这个答案我是怎么做到的。
#include <stdio.h>
unsigned int data[8]=
{
0x20001000,
0x00000023,
0x00000021,
0x00000021,
0x00000021,
0x00000021,
0x00000021,
0x00000000,
};
int main ( void )
{
unsigned int ra;
unsigned int rb;
rb=0;
for(ra=0;ra<7;ra++)
{
rb+=data[ra];
}
data[7]=(-rb);
rb=0;
for(ra=0;ra<8;ra++)
{
rb+=data[ra];
printf("0x%08X 0x%08X\n",data[ra],rb);
}
return(0);
}
输出:
0x20001000 0x20001000
0x00000023 0x20001023
0x00000021 0x20001044
0x00000021 0x20001065
0x00000021 0x20001086
0x00000021 0x200010A7
0x00000021 0x200010C8
0xDFFFEF38 0x00000000
然后将内容剪切并粘贴到答案中。
我过去的做法是制作一个临时实用程序,我从我的 makefile 调用它,该实用程序对 objcopied .bin 文件进行操作,然后修改该文件或创建一个应用了校验和的新 .bin 文件。你应该可以用 20-50 行代码写出那个,选择你喜欢的语言。
另一个评论问题:
.cpu cortex-m0
.thumb
.word one
.word two
.word three
.thumb_func
one:
nop
two:
.thumb_func
three:
nop
Disassembly of section .text:
00000000 <one-0xc>:
0: 0000000d andeq r0, r0, sp
4: 0000000e andeq r0, r0, lr
8: 0000000f andeq r0, r0, pc
0000000c <one>:
c: 46c0 nop ; (mov r8, r8)
0000000e <three>:
e: 46c0 nop ; (mov r8, r8)
.thumb_func 影响标签 AFTER...
在 LPC4088 user manual(第 876 页)中我们可以看到 LPC4088 微控制器有一个非常特别的启动程序:
这看起来完全是胡说八道,我需要有人帮我解决问题...在 ARM 的世界里,我听过无数次将矢量 table 看起来像这样:
reset: b _start
undefined: b undefined
software_interrupt: b software_interrupt
prefetch_abort: b prefetch_abort
data_abort: b data_abort
nop
interrupt_request: b interrupt_request
fast_interrupt_request: b fast_interrupt_request
正好在我的二进制文件中的 0x00000000
位置,但是如果这个位置在启动时被引导 ROM 向量 table 遮蔽了,我们为什么要这样做,因为它甚至无法更改是只读的?!那么我们可以把自己的向量table放在哪里呢?我想把它放在 0x1FFF0000
上,这样它会在重置时转移到位置 0x00000000
但不能这样做,因为只读区域...
现在进入第二部分。 ARM 希望在 0x00000000
处准确找到 8 向量,并且在重置引导 ROM 时检查 8 向量的总和是否为零,并且仅当此是真正的用户代码执行。要通过此检查,我们需要首先对 7 个向量求和,并将其与最后一个向量的 2 补码保存在一起,最后一个向量是用于驻留在 0x0000001C
处的快速中断请求的向量。好吧,这仅在您的代码是 4 字节对齐(ARM 编码)时才是正确的,但如果您的代码是 2 字节对齐(Thumb 编码),它仍然是正确的,所有 Cortex-M4 内核都是这种情况,只能执行 Thumb 编码操作码...那么为什么他们明确提到总和的 2 的补码必须在 0x0000001C
,而这永远不会与 Cortex-M4 一起玩。 0x0000000E
是保存 2 的补码的正确地址吗?
还有第三部分。为什么引导 ROM 甚至会检查第一个 8 向量的总和是否为零,因为它们已经在引导 ROM 中了?!并且是只读的!
你能看出这里有什么奇怪的地方吗?上面三段的不明之处需要有人给我解释一下...
你需要阅读 arm 文档以及 nxp 文档。非 cortex-m 内核的启动方式与您一直卡在那里的 cortex-m 内核不同。
cortex m在armv7m ARM ARM(架构参考手册)中有记载。它基于 VECTORS 而不是 Instructions。处理程序的地址而不是全尺寸 arm 内核中的指令。异常 7 被记录为保留(对于来自他们的基于 ARM7TDMI 的 mcus,它也是他们用于此校验和的保留向量)。根据您使用的 arm 内核,他们期望多达 144 或 272 个(异常加上最多 128 或 256 个中断,具体取决于内核支持的内容)。
(注意 aarch64 处理器,64 位模式下的 armv8 也不同于传统的全尺寸 32 位 arm 处理器,甚至更大 table)。
这个校验和是经典的 NXP 并且很有意义,没有理由启动一个已擦除或未正确准备的闪存和砖块或挂起。
.cpu cortex-m0
.thumb
.thumb_func
.globl _start
_start:
.word 0x20001000 @ 0 SP load
.word reset @ 1 Reset
.word hang @ 2 NMI
.word hang @ 3 HardFault
.word hang @ 4 MemManage
.word hang @ 5 BusFault
.word hang @ 6 UsageFault
.word 0x00000000 @ 7 Reserved
.thumb_func
hang: b hang
.thumb_func
reset:
b hang
给出:
Disassembly of section .text:
00000000 <_start>:
0: 20001000 andcs r1, r0, r0
4: 00000023 andeq r0, r0, r3, lsr #32
8: 00000021 andeq r0, r0, r1, lsr #32
c: 00000021 andeq r0, r0, r1, lsr #32
10: 00000021 andeq r0, r0, r1, lsr #32
14: 00000021 andeq r0, r0, r1, lsr #32
18: 00000021 andeq r0, r0, r1, lsr #32
1c: 00000000 andeq r0, r0, r0
00000020 <hang>:
20: e7fe b.n 20 <hang>
00000022 <reset>:
22: e7fd b.n 20 <hang>
现在制作一个执行校验和并将其添加到二进制文件的临时工具
看上面的程序是这样的程序:
0x20001000
0x00000023
0x00000021
0x00000021
0x00000021
0x00000021
0x00000021
0xDFFFEF38
0xE7FDE7FE
如果你刷它,引导加载程序应该会满意它并让它 运行。
现在假设校验和是基于字的,如果它是基于字节的,那么您需要一个不同的数字。
99% 的裸机编程都是阅读和研究。如果您已经构建了他们的二进制文件或使用了支持此处理器或系列的沙箱,您可以检查构建的二进制文件并查看所有这些是如何工作的。或者查看某人 github 示例或博客以了解其工作原理。他们确实记录了这一点,在成为 NXP 之前,他们已经使用这种方案很多年了,所以没有什么新鲜事……现在它是基于字还是基于字节的校验和,文档暗示基于字,这更有意义。但是一个简单的实验 and/or 查看沙箱生成的二进制文件就可以解决这个问题。
这个答案我是怎么做到的。
#include <stdio.h>
unsigned int data[8]=
{
0x20001000,
0x00000023,
0x00000021,
0x00000021,
0x00000021,
0x00000021,
0x00000021,
0x00000000,
};
int main ( void )
{
unsigned int ra;
unsigned int rb;
rb=0;
for(ra=0;ra<7;ra++)
{
rb+=data[ra];
}
data[7]=(-rb);
rb=0;
for(ra=0;ra<8;ra++)
{
rb+=data[ra];
printf("0x%08X 0x%08X\n",data[ra],rb);
}
return(0);
}
输出:
0x20001000 0x20001000
0x00000023 0x20001023
0x00000021 0x20001044
0x00000021 0x20001065
0x00000021 0x20001086
0x00000021 0x200010A7
0x00000021 0x200010C8
0xDFFFEF38 0x00000000
然后将内容剪切并粘贴到答案中。
我过去的做法是制作一个临时实用程序,我从我的 makefile 调用它,该实用程序对 objcopied .bin 文件进行操作,然后修改该文件或创建一个应用了校验和的新 .bin 文件。你应该可以用 20-50 行代码写出那个,选择你喜欢的语言。
另一个评论问题:
.cpu cortex-m0
.thumb
.word one
.word two
.word three
.thumb_func
one:
nop
two:
.thumb_func
three:
nop
Disassembly of section .text:
00000000 <one-0xc>:
0: 0000000d andeq r0, r0, sp
4: 0000000e andeq r0, r0, lr
8: 0000000f andeq r0, r0, pc
0000000c <one>:
c: 46c0 nop ; (mov r8, r8)
0000000e <three>:
e: 46c0 nop ; (mov r8, r8)
.thumb_func 影响标签 AFTER...