U-boot 脚本错误 Header CRC
U-boot Script Bad Header CRC
我有一个“闪烁”脚本正在通过 sdp 从主机 PC 加载到 iMX6 上的 Uboot 中。该脚本已 运行 到 mkimage
,因此它有一个图像 header。这是 mkimage 命令:
mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "U-Boot script" -d $files_dir$flash_txt $files_dir$flash_scr
我可以用 binwalk
:
解析 header
$ binwalk -B flash.scr
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x315E128A, created: 2021-09-13 14:52:46, image size: 2406 bytes, Data Address: 0x0, Entry Point: 0x0, data CRC: 0x7B909BAE, OS: Linux, CPU: ARM, image type: Script file, compression type: none, image name: "U-Boot script"
执行失败,uboot 显示“Bad Header CRC”。因此,我试图至少强制它在设备上工作,方法是使用 built-in crc32 工具当场更正 CRC。还是不行。
这是我正在尝试的 uboot 命令(在脚本已经在地址 0x10100000
的内存中之后):
# display the script bytes
md 0x10100000
# reset the crc
mw 0x10100004 0x0 1
# verify the change
md 0x10100000
# recalc the crc
crc32 0x10100000 64
# write the crc
#mw 0x10100004 <VALUE> 1
# example:
mw 0x10100004 0x3a833d99 1
# run the script
source 0x10100000
当我这样做时,我仍然遇到可怕的“Bad Header CRC”错误!
我发现有许多来源揭示/指出哪些字节包含“header CRC”。我见过多个消息来源说,在尝试计算校验和之前需要“重置”校验和。这一切看起来都是有效的逻辑。我做错了什么?
更新
正确的uboot输入/结果
木屑的帮助
...
Bad header crc
CTRL+C - Operation aborted.
SDP ended
uboot# md 0x10100000
10100000: 56190527 229a2e76 f4f64161 66090000 '..Vv.."aA.....f
10100010: 00000000 00000000 0533a380 00060205 ..........3.....
10100020: 6f422d55 7320746f 70697263 00000074 U-Boot script...
10100030: 00000000 00000000 00000000 00000000 ................
10100040: 5e090000 00000000 20766e65 61666564 ...^....env defa
10100050: 20746c75 2d20662d 65730a61 766e6574 ult -f -a.setenv
10100060: 7a697320 79625f65 685f6574 725f7865 size_byte_hex_r
10100070: 66746f6f 33352073 35453937 65730a41 ootfs 5379E5A.se
10100080: 766e6574 7a697320 6c625f65 5f6b636f tenv size_block_
10100090: 5f786568 746f6f72 32207366 30444239 hex_rootfs 29BD0
101000a0: 7465730a 20766e65 657a6973 7479625f .setenv size_byt
101000b0: 65685f65 62755f78 20746f6f 30433337 e_hex_uboot 73C0
101000c0: 65730a30 766e6574 7a697320 6c625f65 0.setenv size_bl
101000d0: 5f6b636f 5f786568 6f6f6275 39332074 ock_hex_uboot 39
101000e0: 730a0a45 6e657465 6f722076 7366746f E..setenv rootfs
101000f0: 6c5f615f 6c656261 6f722220 7366746f _a_label "rootfs
uboot# mw 0x10100004 0x0 1
uboot# crc32 0x10100000 0x40 0x10100004
crc32 for 10100000 ... 1010003f ==> 94926f83
uboot# md 0x10100000
10100000: 56190527 836f9294 f4f64161 66090000 '..V..o.aA.....f
10100010: 00000000 00000000 0533a380 00060205 ..........3.....
10100020: 6f422d55 7320746f 70697263 00000074 U-Boot script...
10100030: 00000000 00000000 00000000 00000000 ................
10100040: 5e090000 00000000 20766e65 61666564 ...^....env defa
10100050: 20746c75 2d20662d 65730a61 766e6574 ult -f -a.setenv
10100060: 7a697320 79625f65 685f6574 725f7865 size_byte_hex_r
10100070: 66746f6f 33352073 35453937 65730a41 ootfs 5379E5A.se
10100080: 766e6574 7a697320 6c625f65 5f6b636f tenv size_block_
10100090: 5f786568 746f6f72 32207366 30444239 hex_rootfs 29BD0
101000a0: 7465730a 20766e65 657a6973 7479625f .setenv size_byt
101000b0: 65685f65 62755f78 20746f6f 30433337 e_hex_uboot 73C0
101000c0: 65730a30 766e6574 7a697320 6c625f65 0.setenv size_bl
101000d0: 5f6b636f 5f786568 6f6f6275 39332074 ock_hex_uboot 39
101000e0: 730a0a45 6e657465 6f722076 7366746f E..setenv rootfs
101000f0: 6c5f615f 6c656261 6f722220 7366746f _a_label "rootfs
uboot# source 0x10100000
## Executing script at 10100000
... SUCCESS!!!!!
Pre-upload PC补丁
在运行ning mkimage 之后,我用这种方法修复了CRC。我敢肯定,这可以用更优雅的方式编写 - 但至少证明了它的功能:
# The mkimage "header CRC" is invalid for some reason, so it needs to be corrected!
$files_dir=files/
$flash_scr=flash.scr
$flash_hdr=flash.hdr
chmod 644 $files_dir$flash_scr
# zero the current crc, and copy the 64 byte header to a separate file
printf '\x00\x00\x00\x00' | dd of=$files_dir$flash_scr bs=1 seek=4 count=4 conv=notrunc
head -c 64 $files_dir$flash_scr > $files_dir$flash_hdr
# calculate the correct crc
crc=$(crc32 $files_dir$flash_hdr)
b1=$(echo $crc | cut -c 1,2)
b2=$(echo $crc | cut -c 3,4)
b3=$(echo $crc | cut -c 5,6)
b4=$(echo $crc | cut -c 7,8)
# update the script, with the correct value
printf "\x${b1}\x${b2}\x${b3}\x${b4}" | dd of=$files_dir$flash_scr bs=1 seek=4 count=4 conv=notrunc
# clean up
rm $files_dir$flash_hdr
mkimage 的根本缺陷
理想情况下,mkimage 首先会正确地完成它的工作。为什么它出现故障仍然是个谜...
What am I doing wrong?
U-Boot 几乎总是假定命令参数为十六进制值,因此使用 0x...
前缀实际上是多余的。据我所知,无法输入十进制值。
# recalc the crc
crc32 0x10100000 64
因此,当您在 crc32
命令中将 header 的长度指定为 64
时,您指定了不正确的 (header) 长度 0x64 或 100十进制。
查看 U-Boot 命令响应确认您的错误:
=> crc32 0x10100000 64
CRC32 for 10100000 ... 10100063 ==> 9988c6ca
0x10100000 到 0x10100063 的地址范围是 100 个字节的跨度。
附录(有修订)
安装计算值时,可能会引入字节序(字节顺序)问题。
# write the crc
#mw 0x10100004 <VALUE> 1
计算出的 CRC32 值可能需要在 mw
命令中反向指定 byte-order(假设 i.MX6 为 little-endian 模式)。
例如,mkimage 命令安装一个原始的 header CRC32 值 d8bc0e3a
3a0ebcd8
在第二个单词中(按 little-endian 顺序):
=> md 20000000
20000000: 56190527 3a0ebcd8 a0284161 1f000000 '..V...:aA(.....
20000010: ...
=> imi 20000000
## Checking Image at 20000000 ...
Legacy image found
Image Name: U-Boot script
Image Type: PowerPC Linux Script (uncompressed)
Data Size: ...
将第二个字归零后,CRC32 命令产生(相同)值(如预期)(但作为 4 字节字符串而不是整数):
=> crc32 20000000 40
crc32 for 20000000 ... 2000003f ==> d8bc0e3a
如果使用 mw
命令逐字安装此值,则字节顺序不是 32 位字值所要求的顺序。
=> mw 20000004 d8bc0e3a
=> md 20000000
20000000: 56190527 d8bc0e3a a0284161 1f000000 '..V:...aA(.....
20000010: ...
=> imi 20000000
## Checking Image at 20000000 ...
Legacy image found
Bad Header Checksum
=>
mw
命令将要写入的值视为 a byte string
而不是整数值 整数值,因此 不执行字节重新排序(即使这是 little-endian CPU) 需要对 CRC32 值进行字节重新排序。
附录 2
对上面关于 U-Boot 命令在 little-endian 模式下显示结果的细微修正。
假设存储值处于 little-endian 模式,md
命令正在显示字值。
要查看内存中的真实字节顺序,请使用 md.b
命令。
=> md 20000000 4
20000000: 56190527 3a0ebcd8 a0284161 1f000000 '..V...:aA(.....
=> md.b 20000000 10
20000000: 27 05 19 56 d8 bc 0e 3a 61 41 28 a0 00 00 00 1f '..V...:aA(.....
=>
因此,mkimage 命令会在第二个单词中安装原始 header CRC32 值 3a0ebcd8
(按 little-endian 顺序)。
CRC32 命令生成字节字符串形式的 4 字节值(即已经在 little-endian 顺序中)。
mw
命令知道这是一个 little-endian CPU,并将要写入的值视为整数值。
由于 CRC32 结果是 byte string
(而不是整数值),因此必须使用 mw
命令对这些字节进行重新排序以供输入。
明白了吗?
避免这种端序混乱的一种可能方法是使用 CRC32 命令的自动写入功能。
将 header CRC 的地址附加到您的 crc32
命令,计算出的值将以正确的顺序存储,例如
crc32 0x10100000 0x40 0x10100004
仍然想知道为什么您一开始就没有使用 mkimage 的良好 CRC32,以及为什么您不得不求助于此 hack。
我有一个“闪烁”脚本正在通过 sdp 从主机 PC 加载到 iMX6 上的 Uboot 中。该脚本已 运行 到 mkimage
,因此它有一个图像 header。这是 mkimage 命令:
mkimage -A arm -O linux -T script -C none -a 0 -e 0 -n "U-Boot script" -d $files_dir$flash_txt $files_dir$flash_scr
我可以用 binwalk
:
$ binwalk -B flash.scr
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
0 0x0 uImage header, header size: 64 bytes, header CRC: 0x315E128A, created: 2021-09-13 14:52:46, image size: 2406 bytes, Data Address: 0x0, Entry Point: 0x0, data CRC: 0x7B909BAE, OS: Linux, CPU: ARM, image type: Script file, compression type: none, image name: "U-Boot script"
执行失败,uboot 显示“Bad Header CRC”。因此,我试图至少强制它在设备上工作,方法是使用 built-in crc32 工具当场更正 CRC。还是不行。
这是我正在尝试的 uboot 命令(在脚本已经在地址 0x10100000
的内存中之后):
# display the script bytes
md 0x10100000
# reset the crc
mw 0x10100004 0x0 1
# verify the change
md 0x10100000
# recalc the crc
crc32 0x10100000 64
# write the crc
#mw 0x10100004 <VALUE> 1
# example:
mw 0x10100004 0x3a833d99 1
# run the script
source 0x10100000
当我这样做时,我仍然遇到可怕的“Bad Header CRC”错误!
我发现有许多来源揭示/指出哪些字节包含“header CRC”。我见过多个消息来源说,在尝试计算校验和之前需要“重置”校验和。这一切看起来都是有效的逻辑。我做错了什么?
更新
正确的uboot输入/结果
木屑的帮助
...
Bad header crc
CTRL+C - Operation aborted.
SDP ended
uboot# md 0x10100000
10100000: 56190527 229a2e76 f4f64161 66090000 '..Vv.."aA.....f
10100010: 00000000 00000000 0533a380 00060205 ..........3.....
10100020: 6f422d55 7320746f 70697263 00000074 U-Boot script...
10100030: 00000000 00000000 00000000 00000000 ................
10100040: 5e090000 00000000 20766e65 61666564 ...^....env defa
10100050: 20746c75 2d20662d 65730a61 766e6574 ult -f -a.setenv
10100060: 7a697320 79625f65 685f6574 725f7865 size_byte_hex_r
10100070: 66746f6f 33352073 35453937 65730a41 ootfs 5379E5A.se
10100080: 766e6574 7a697320 6c625f65 5f6b636f tenv size_block_
10100090: 5f786568 746f6f72 32207366 30444239 hex_rootfs 29BD0
101000a0: 7465730a 20766e65 657a6973 7479625f .setenv size_byt
101000b0: 65685f65 62755f78 20746f6f 30433337 e_hex_uboot 73C0
101000c0: 65730a30 766e6574 7a697320 6c625f65 0.setenv size_bl
101000d0: 5f6b636f 5f786568 6f6f6275 39332074 ock_hex_uboot 39
101000e0: 730a0a45 6e657465 6f722076 7366746f E..setenv rootfs
101000f0: 6c5f615f 6c656261 6f722220 7366746f _a_label "rootfs
uboot# mw 0x10100004 0x0 1
uboot# crc32 0x10100000 0x40 0x10100004
crc32 for 10100000 ... 1010003f ==> 94926f83
uboot# md 0x10100000
10100000: 56190527 836f9294 f4f64161 66090000 '..V..o.aA.....f
10100010: 00000000 00000000 0533a380 00060205 ..........3.....
10100020: 6f422d55 7320746f 70697263 00000074 U-Boot script...
10100030: 00000000 00000000 00000000 00000000 ................
10100040: 5e090000 00000000 20766e65 61666564 ...^....env defa
10100050: 20746c75 2d20662d 65730a61 766e6574 ult -f -a.setenv
10100060: 7a697320 79625f65 685f6574 725f7865 size_byte_hex_r
10100070: 66746f6f 33352073 35453937 65730a41 ootfs 5379E5A.se
10100080: 766e6574 7a697320 6c625f65 5f6b636f tenv size_block_
10100090: 5f786568 746f6f72 32207366 30444239 hex_rootfs 29BD0
101000a0: 7465730a 20766e65 657a6973 7479625f .setenv size_byt
101000b0: 65685f65 62755f78 20746f6f 30433337 e_hex_uboot 73C0
101000c0: 65730a30 766e6574 7a697320 6c625f65 0.setenv size_bl
101000d0: 5f6b636f 5f786568 6f6f6275 39332074 ock_hex_uboot 39
101000e0: 730a0a45 6e657465 6f722076 7366746f E..setenv rootfs
101000f0: 6c5f615f 6c656261 6f722220 7366746f _a_label "rootfs
uboot# source 0x10100000
## Executing script at 10100000
... SUCCESS!!!!!
Pre-upload PC补丁
在运行ning mkimage 之后,我用这种方法修复了CRC。我敢肯定,这可以用更优雅的方式编写 - 但至少证明了它的功能:
# The mkimage "header CRC" is invalid for some reason, so it needs to be corrected!
$files_dir=files/
$flash_scr=flash.scr
$flash_hdr=flash.hdr
chmod 644 $files_dir$flash_scr
# zero the current crc, and copy the 64 byte header to a separate file
printf '\x00\x00\x00\x00' | dd of=$files_dir$flash_scr bs=1 seek=4 count=4 conv=notrunc
head -c 64 $files_dir$flash_scr > $files_dir$flash_hdr
# calculate the correct crc
crc=$(crc32 $files_dir$flash_hdr)
b1=$(echo $crc | cut -c 1,2)
b2=$(echo $crc | cut -c 3,4)
b3=$(echo $crc | cut -c 5,6)
b4=$(echo $crc | cut -c 7,8)
# update the script, with the correct value
printf "\x${b1}\x${b2}\x${b3}\x${b4}" | dd of=$files_dir$flash_scr bs=1 seek=4 count=4 conv=notrunc
# clean up
rm $files_dir$flash_hdr
mkimage 的根本缺陷
理想情况下,mkimage 首先会正确地完成它的工作。为什么它出现故障仍然是个谜...
What am I doing wrong?
U-Boot 几乎总是假定命令参数为十六进制值,因此使用 0x...
前缀实际上是多余的。据我所知,无法输入十进制值。
# recalc the crc crc32 0x10100000 64
因此,当您在 crc32
命令中将 header 的长度指定为 64
时,您指定了不正确的 (header) 长度 0x64 或 100十进制。
查看 U-Boot 命令响应确认您的错误:
=> crc32 0x10100000 64
CRC32 for 10100000 ... 10100063 ==> 9988c6ca
0x10100000 到 0x10100063 的地址范围是 100 个字节的跨度。
附录(有修订)
安装计算值时,可能会引入字节序(字节顺序)问题。
# write the crc #mw 0x10100004 <VALUE> 1
计算出的 CRC32 值可能需要在 mw
命令中反向指定 byte-order(假设 i.MX6 为 little-endian 模式)。
例如,mkimage 命令安装一个原始的 header CRC32 值 d8bc0e3a
3a0ebcd8
在第二个单词中(按 little-endian 顺序):
=> md 20000000
20000000: 56190527 3a0ebcd8 a0284161 1f000000 '..V...:aA(.....
20000010: ...
=> imi 20000000
## Checking Image at 20000000 ...
Legacy image found
Image Name: U-Boot script
Image Type: PowerPC Linux Script (uncompressed)
Data Size: ...
将第二个字归零后,CRC32 命令产生(相同)值(如预期)(但作为 4 字节字符串而不是整数):
=> crc32 20000000 40
crc32 for 20000000 ... 2000003f ==> d8bc0e3a
如果使用 mw
命令逐字安装此值,则字节顺序不是 32 位字值所要求的顺序。
=> mw 20000004 d8bc0e3a
=> md 20000000
20000000: 56190527 d8bc0e3a a0284161 1f000000 '..V:...aA(.....
20000010: ...
=> imi 20000000
## Checking Image at 20000000 ...
Legacy image found
Bad Header Checksum
=>
mw
命令将要写入的值视为 a 整数值,因此 byte string
而不是整数值不执行字节重新排序(即使这是 little-endian CPU) 需要对 CRC32 值进行字节重新排序。
附录 2
对上面关于 U-Boot 命令在 little-endian 模式下显示结果的细微修正。
假设存储值处于 little-endian 模式,md
命令正在显示字值。
要查看内存中的真实字节顺序,请使用 md.b
命令。
=> md 20000000 4
20000000: 56190527 3a0ebcd8 a0284161 1f000000 '..V...:aA(.....
=> md.b 20000000 10
20000000: 27 05 19 56 d8 bc 0e 3a 61 41 28 a0 00 00 00 1f '..V...:aA(.....
=>
因此,mkimage 命令会在第二个单词中安装原始 header CRC32 值 3a0ebcd8
(按 little-endian 顺序)。
CRC32 命令生成字节字符串形式的 4 字节值(即已经在 little-endian 顺序中)。
mw
命令知道这是一个 little-endian CPU,并将要写入的值视为整数值。
由于 CRC32 结果是 byte string
(而不是整数值),因此必须使用 mw
命令对这些字节进行重新排序以供输入。
明白了吗?
避免这种端序混乱的一种可能方法是使用 CRC32 命令的自动写入功能。
将 header CRC 的地址附加到您的 crc32
命令,计算出的值将以正确的顺序存储,例如
crc32 0x10100000 0x40 0x10100004
仍然想知道为什么您一开始就没有使用 mkimage 的良好 CRC32,以及为什么您不得不求助于此 hack。