最近又要折腾2k1000的设备了,研究了一下gzrom文件组成部分。
pmon的编译可以参考之前的文档,这里我就不详述了
源码:GitHub - zhaozhi0810/pmon-ls2k1000-2022
gzrom-dtb.bin的生成命令在Makefile.inc(zloader.ls2k-hj20004目录)中
截取出来如下:
[ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin && python ../tools/pmonenv.py -f gzrom-dtb.bin -d ${TARGET}.dtb -w al=\(usb0,0\)/boot/vmlinuz al1=\(wd0,0\)/vmlinuz append="'console=ttyS0,115200 noinitrd root=/dev/sda2 rootfstype=ext4 rootwait rw'" FR=1
- [ -f gzrom.bin ] && cp gzrom.bin gzrom-dtb.bin 存在gzrom.bin这个文件,复制这个文件为gzrom-dtb.bin,相当于重命名了。
2. python ../tools/pmonenv.py 用这个脚本来处理。(1.把dtb合并起来,2.加入一些环境变量)
3. gzrom-dtb.bin = gzrom.bin + dtb + env
4. pmonenv.py 注意这个命令之后的几个选项,这里有-f -d -w
5. pmonenv.py 可以看到源码,在tools目录中
一、加入env变量
1.1 从main函数入口。
if __name__ == '__main__':
opt,argv=getopt.getopt(sys.argv[1:],'b:o:s:f:wd:')
opt=dict(opt)
foff = int(opt['-o'],0) if '-o' in opt else 0x000ff000
fsz = int(opt['-s'],0) if '-s' in opt else 500
fname = opt['-f'] if '-f' in opt else 'gzrom.bin'
d=readenv(fname,foff,fsz,argv)
print(d)
if '-w' in opt:
writeenv(fname,foff,fsz,d)
if '-b' in opt: writehexenv(fname, opt['-b'])
if '-d' in opt: writedtb(fname, opt['-d'], foff)
1.1.1 分析一下foff,fsz,fname
实际没有-o 选项,所以foff = 0x000ff000 (十进制1044480)
实际没有-o 选项 ,所以fsz = 500
有-f 选项 fname = gzrom-dtb.bin
可以使用打印语句打印出来看看
1.1.2 gzrom-dtb.bin的文件大小正好等于foff + fsz;
打开gzrom-dtb.bin,果然是这个位置开始放置环境变量
1.2 继续往下,看到writeenv
def writeenv(fname,foff,fsz,d):
# print("\nwriteenv start*******************")
# print("7 d = ",d) # 8
a=b'\x00\x00'
for i in d.keys():
a += i+b'='+d[i]+b'\x00'
# print("8 a = ",a) # 9
a=a.ljust(fsz,b'\x00')
b = struct.pack('!H',(-sum(struct.unpack('!'+str(len(a)//2)+'H',a)))&0xffff)
# print("9 b = ",b) # 10
a=b+a[2:]
# print("10 a = ",a) # 11
f=open(fname,'rb+')
f.seek(foff,0)
f.write(a)
f.close()
1.2.1 可以打开其中的注释,看到一些打印信息
打开 9,10,11 处的打印
('8 a = ', '\x00\x00FR=1\x00')
('8 a = ', '\x00\x00FR=1\x00al=(usb0,0)/boot/vmlinuz\x00')
('8 a = ', "\x00\x00FR=1\x00al=(usb0,0)/boot/vmlinuz\x00append='console=ttyS0,115200 noinitrd root=/dev/sda2 rootfstype=ext4 rootwait rw'\x00")
('8 a = ', "\x00\x00FR=1\x00al=(usb0,0)/boot/vmlinuz\x00append='console=ttyS0,115200 noinitrd root=/dev/sda2 rootfstype=ext4 rootwait rw'\x00al1=(wd0,0)/vmlinuz\x00")
('9 b = ', ')\x0e') # 这个位置应该是0x290e 转为两个字节存放,0x29 正好对应一个右括号
('10 a = ', ")\x0eFR=1\x00al=(usb0,0)/boot/vmlinuz\x00append='console=ttyS0,115200 noinitrd root=/dev/sda2 rootfstype=ext4 rootwait rw'\x00al1=(wd0,0)/vmlinuz\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
1.2.2 简要分析
通过加入打印信息,做出如下解析
1.2.2.1 struct.unpack('!'+str(len(a)//2)+'H',a) //这个!指的是大端模式,H表示unsigned short类型
这里的意思是把两个字节按大端的形式,组合,得到一个250个数的数组,类型为unsigned short
(0, 18002, 15665, 97, 27709, 10357, 29538, 12332, 12329, 12130, 28527, 29743, 30317, 27753, 28277, 31232, 24944, 28773, 28260, 15655, 25455, 28275, 28524, 25917, 29812, 31059, 12332, 12593, 13618, 12336, 8302, 28521, 28265, 29810, 25632, 29295, 28532, 15663, 25701, 30255, 29540, 24882, 8224, 29295, 28532, 26227, 29817, 28773, 15717, 30836, 13344, 29295, 28532, 30561, 26996, 8306, 30503, 97, 27697, 15656, 30564, 12332, 12329, 12150, 28012, 26990, 30074, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
注意18002 十六进制 0x4652 跟上面的截图(0xff002)能对上。其他就不看了
1.2.2.2 Sum 把他们加起来,按照unsigned short的类型,总共250个数 加起来等于1496818
1.2.2.3 - 把得到的校验和取负数, 等于-1496818
1.2.2.4 &0xffff 只取负数的最低16位 等于0x290e
1.2.2.5 struct.pack('!H',…) 再用大端模式,打包unsigned short类型
0x290e,按大端解析为字节,data[0]=0x29,data[1]=0x0e ,这个就是校验和!!!!写在最开始的两个字节,跟上面的截图(0xff000)能对上
1.2.2.6 尾部没有校验和,检验和在最开始的两个字节。校验的方法参考前面的描述
1.2.2.7 a=a.ljust(fsz,b'\x00') 对数据字节数进行补全,不足的位置补0.
二、加入dtb文件
2.1 明白env的加入之后,dtb 就比较简单了,
def writedtb(fname,dtb,foff):
# print("\n writedtb start----------------------")
f=open(dtb,'rb')
a=f.read();
# print("a.len= ",len(a)) # 12
f.close()
a=a.ljust(0x4000-8,'\x00')
# print("a = ",a)
b = struct.pack('I',(-sum(struct.unpack(''+str(len(a)//4)+'I',a)))&0xffffffff)
a=b+a+b
# print("a.len= ",len(a)) # 13
# print("a = ",a)
f=open(fname,'rb+')
f.seek(foff-0x4000,0)
f.write(a)
f.close()
首先dtb能够保存的大小是0x4000-8个字节 (16K-8个字节),字节不足的地方填充0
文件偏移 0x000ff000 - 0x4000 = 0xfb000
前4个字节是校验和
最末尾也是校验和(4个字节)
2.2 校验和的计算
经过上面的折腾,校验和计算比较简单了吧,小端的4个字节(unsigned int类型)组合,加起来,然后取负数,然后取低4个字节,即校验和了。
三、思考
最后,看到bin文件中env 和dtb 都是自己独立检验和,并且没有整体校验!!
3.1 env写的位置是ff000 后面的500字节,这个位置能否改动呢?
3.2 dtb写的位置是fb000 ,大小是0x4000(16k),这个位置能否改动呢?
3.3 能否只修改flash中的某个部分呢?这就提供了可行性。
(回答上面问题,就要看pmon怎么解析这几个部分了,看源码吧)