在使用的是128M dram的小内存配置,播放视频需要通过ion申请较多的连续物理内存空间,所以需要扩充CMA的大小,否则会导致cma扩充和开机logo消失。
【芯片平台】R311
【软件版本】tina3.5.1
【问题背景】
使用的是128MB的ddr,对于多视频播放和旋转的场景ion的使用非常吃紧,需要想办法扩大cma的大小。
【问题简述】
R311更改cma大小后,出现了不进kernel,开机logo消失等问题。
【问题处理过程】
(1)不进kernel:
更改cma大小为72MB后,系统无法进kernel,撤回修改,查看系统保留内存的分布:
root@TinaLinux:/# cat /sys/kernel/debug/memblock/reserved
0: 0x40004000..0x40007fff, size:16K
1: 0x40020000..0x40020fff, size:4K
2: 0x40100000..0x40b480cb, size:10528K
3: 0x41000000..0x4100000b, size:0K
4: 0x43500000..0x4351617f, size:88K
5: 0x43c00000..0x47bfffff, size:65536K
6: 0x47cc8000..0x47f65fff, size:2680K
7: 0x47f7da00..0x47f961ff, size:98K
8: 0x47f9621c..0x47ffefff, size:419K
9: 0x47fff640..0x47fff67b, size:0K
10: 0x47fff680..0x47fff6bb, size:0K
11: 0x47fff6c0..0x47fff737, size:0K
12: 0x47fff740..0x47fff74f, size:0K
13: 0x47fff780..0x47fff78f, size:0K
14: 0x47fff7c0..0x47fff7c3, size:0K
15: 0x47fff800..0x47fff9ad, size:0K
16: 0x47fff9c0..0x47fffb6d, size:0K
17: 0x47fffb80..0x47fffd2d, size:0K
18: 0x47fffd40..0x47fffd43, size:0K
19: 0x47fffd64..0x47fffd81, size:0K
20: 0x47fffd84..0x47fffdb8, size:0K
21: 0x47fffdbc..0x47fffe1c, size:0K
22: 0x47fffe20..0x47fffe70, size:0K
23: 0x47fffe74..0x47ffff06, size:0K
24: 0x47ffff08..0x47ffff22, size:0K
25: 0x47ffff24..0x47ffff3e, size:0K
26: 0x47ffff40..0x47ffff5f, size:0K
27: 0x47ffff64..0x47ffff7e, size:0K
28: 0x47ffff80..0x47ffff8f, size:0K
29: 0x47ffff94..0x47ffffae, size:0K
30: 0x47ffffb0..0x47ffffff, size:0K
发现dts起始地址为0x43500000,cma的下一个保留区域起始地址为0x47cc8000,留给dts和cma的空间只有0x47cc8000-0x43500000约为71MB,cma大小设置为72MB后,超出了范围,导致不进kernel。怎么解决问题?把dts的起始地址往前挪动一下,cma的空间就可以得到扩充,如下所示,把dts的位置向前挪动0x00500000,cma足够容纳72MB的cma保留区域:
include/configs/sunxi-base.h:
-#define CONFIG_SUNXI_FDT_ADDR SDRAM_OFFSET(0x03500000)
+#define CONFIG_SUNXI_FDT_ADDR SDRAM_OFFSET(0x03000000)
修改后的保留内存的分布如下:
root@TinaLinux:/# cat /sys/kernel/debug/memblock/reserved
0: 0x40004000..0x40007fff, size:16K
1: 0x40020000..0x40020fff, size:4K
2: 0x40100000..0x40b480cb, size:10528K
3: 0x41000000..0x4100000b, size:0K
4: 0x43000000..0x4301617f, size:88K
5: 0x433fffff..0x47bfffff, size:73728K
6: 0x47cc8000..0x47f65fff, size:2680K
7: 0x47f7da00..0x47f961ff, size:98K
8: 0x47f9621c..0x47ffefff, size:419K
9: 0x47fff640..0x47fff67b, size:0K
10: 0x47fff680..0x47fff6bb, size:0K
11: 0x47fff6c0..0x47fff737, size:0K
12: 0x47fff740..0x47fff74f, size:0K
13: 0x47fff780..0x47fff78f, size:0K
14: 0x47fff7c0..0x47fff7c3, size:0K
15: 0x47fff800..0x47fff9ad, size:0K
16: 0x47fff9c0..0x47fffb6d, size:0K
17: 0x47fffb80..0x47fffd2d, size:0K
18: 0x47fffd40..0x47fffd43, size:0K
19: 0x47fffd64..0x47fffd81, size:0K
20: 0x47fffd84..0x47fffdb8, size:0K
21: 0x47fffdbc..0x47fffe1c, size:0K
22: 0x47fffe20..0x47fffe70, size:0K
23: 0x47fffe74..0x47ffff06, size:0K
24: 0x47ffff08..0x47ffff22, size:0K
25: 0x47ffff24..0x47ffff3e, size:0K
26: 0x47ffff40..0x47ffff5f, size:0K
27: 0x47ffff64..0x47ffff7e, size:0K
28: 0x47ffff80..0x47ffff8f, size:0K
29: 0x47ffff94..0x47ffffae, size:0K
30: 0x47ffffb0..0x47ffffff, size:0K
(2)开机logo消失:
开机logo是从uboot解码并显示的,找到logo解码的地方:
compress_buf = get_decode_buffer();
if (compress_buf == NULL) {
printf("bmp compress_buf empty,quit\n");
set_bmp_decode_flag(BMP_DECODE_FAIL);
goto __third_cpu_end;
}
buf = (unsigned char *)(SUNXI_DISPLAY_FRAME_BUFFER_ADDR + SUNXI_DISPLAY_FRAME_BUFFER_SIZE);
ret = sunxi_bmp_decode_from_compress(buf, compress_buf);
发现需要从地址compress_buf把logo的bmp格式数据解压到buf地址,buf地址为SUNXI_DISPLAY_FRAME_BUFFER_ADDR + SUNXI_DISPLAY_FRAME_BUFFER_SIZE,也就是0x47400000。compress_buf的地址如下所示:
if (next_mode == SUNXI_STATE_NORMAL_BOOT) {
set_decode_buffer((unsigned char *)
(SUNXI_LOGO_COMPRESSED_LOGO_BUFF));
} else if (next_mode == SUNXI_STATE_SHUTDOWN_CHARGE) {
从这里的代码片段知道,logo的原始数据放在地址SUNXI_LOGO_COMPRESSED_LOGO_BUFF,也就是0x43000010,而现在dts的区域的保留区域是( 0x43000000..0x4301617f),刚好覆盖到了SUNXI_LOGO_COMPRESSED_LOGO_BUFF。将SUNXI_LOGO_COMPRESSED_LOGO_BUFF改为0x42000000,这样就能使logo数据不落在内存的保留区域内。
然而编译后再验证,发现logo还是没法显示,从目前得到的信息看不到问题点,说明问题的原因还是没有全部被找到,继续跟进解码数据的过程:
int lzmaBuffToBuffDecompress (unsigned char *outStream, SizeT *uncompressedSize,
unsigned char *inStream, SizeT length)
{
.......
/* Read the uncompressed size */
for (i = 0; i < 8; i++) {
unsigned char b = inStream[LZMA_SIZE_OFFSET + i];
if (i < 4) {
outSize += (UInt32)(b) << (i * 8);
} else {
outSizeHigh += (UInt32)(b) << ((i - 4) * 8);
}
}
outSizeFull = (SizeT)outSize;
if (sizeof(SizeT) >= 8) {
/*
* SizeT is a 64 bit uint => We can manage files larger than 4GB!
*
*/
outSizeFull |= (((SizeT)outSizeHigh << 16) << 16);
} else if (outSizeHigh != 0 || (UInt32)(SizeT)outSize != outSize) {
/*
* SizeT is a 32 bit uint => We cannot manage files larger than
* 4GB! Assume however that all 0xf values is "unknown size" and
* not actually a file of 2^64 bits.
*
*/
if (outSizeHigh != (SizeT)-1 || outSize != (SizeT)-1) {
debug ("LZMA: 64bit support not enabled.\n");
return SZ_ERROR_DATA;
}
}
.......
}
如上面代码片段所示,检查*inStream(内存中的bmp数据)前面8位信息的时候,函数报错返回了,这里说明了内存中的bmp数据有问题。bmp数据需要先从flash里面拷贝到内存SUNXI_LOGO_COMPRESSED_LOGO_BUFF中,后面才能从SUNXI_LOGO_COMPRESSED_LOGO_BUFF解码出来 。现数据有异常,需要检查bmp数据从flash拷贝到内存的过程。查找SUNXI_LOGO_COMPRESSED_LOGO_BUFF使用的地方,arch/arm/cpu/armv7/sun8iw15p1/spl/fip_common.c里面有类似从flash拷贝logo数据到内存的代码:
arch/arm/cpu/armv7/sun8iw15p1/spl/fip_common.c:
int load_fip(int *use_monitor)
{
......
} else if (strncmp(toc1_item->name, ITEM_LOGO_NAME, sizeof(ITEM_LOGO_NAME)) == 0) {
*(uint *)(SUNXI_LOGO_COMPRESSED_LOGO_SIZE_ADDR) = toc1_item->data_len;
toc1_flash_read(toc1_item->data_offset/512, (toc1_item->data_len+511)/512, (void *)SUNXI_LOGO_COMPRESSED_LOGO_BUFF);
} else if (strncmp(toc1_item->name, ITEM_SHUTDOWNCHARGE_LOGO_NAME, sizeof(ITEM_SHUTDOWNCHARGE_LOGO_NAME)) == 0) {
......
}
从这段代码中看不出来有问题,再看看发现编译uboot的时候跟本不会编译到这个文件,怎么回事,询问负责uboot模块的同事得知,这里的文件是给boot0用的,logo数据从flash拷贝到内存的动作也是在boot0的时候做的。所以更新了SUNXI_LOGO_COMPRESSED_LOGO_BUFF的地址,还需要同时编译boot0,这样对于logo数据的拷贝和解码来说,SUNXI_LOGO_COMPRESSED_LOGO_BUFF才是相同的地址。
(文 by. shaokang)