Linux如何防止内存冲突? 电子说
在聊这个话题之前,我们先回忆一下单片机系统中是如何分配内存的?如果没有bootloader,那硬件环境起来之后就直接进入主程序运行,如果有引导程序bootloader,那就需要设置好跳转地址,否则设置不对,系统就无法启动了。
那么对于linux系统来说,何尝不是这样呢?因为linux系统包含的文件比较多,启动也分几个阶段,每个阶段也都是通过跳转执行的。如何管理好内存是系统稳定运行的前提。
原生的uboot只能管理自己所在的内存块,无法管理整块空间。于是rk引入了bidram和sysmem,用于管理uboot之外的地址空间,RK平台就把系统所有内存通过sysmem + bidram + malloc管理起来了,防止出现内存冲突等问题。
bidram:管理u-boot、kernel阶段不可用、需要剔除的内存块,例如:ATF、OP-TEE 占用的空间;sysmem:管理kernel 可见、可用的内存块。例如:fdt、ramdisk、kernel、fastboot 占用的空间。
相关代码:
./lib/sysmem.c./lib/bidram.c./include/memblk.h./arch/arm/mach-rockchip/memblk.c
先来大概预览一下源文件吧:
int sysmem_init(void){struct sysmem *sysmem = &plat_sysmem;phys_addr_t mem_start;phys_size_t mem_size;int ret;lmb_init(&sysmem->lmb);INIT_LIST_HEAD(&sysmem->allocated_head);INIT_LIST_HEAD(&sysmem->kmem_resv_head);sysmem->allocated_cnt = 0;sysmem->kmem_resv_cnt = 0;if (gd->flags & GD_FLG_RELOC) {sysmem->has_initr = true;} else {SYSMEM_I("initn");sysmem->has_initf = true;}/* Add all available system memory */#ifdef CONFIG_NR_DRAM_BANKSint i;for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {if (!gd->bd->bi_dram[i].size)continue;ret = sysmem_add(gd->bd->bi_dram[i].start,gd->bd->bi_dram[i].size);if (ret) {SYSMEM_E("Failed to add sysmem from bi_dram[%d]n", i);goto fail;}}#elsemem_start = env_get_bootm_low();mem_size = env_get_bootm_size();ret = sysmem_add(mem_start, mem_size);if (ret) {SYSMEM_E("Failed to add sysmem from bootm_low/sizen");goto fail;}#endif/* Reserved for board */ret = board_sysmem_reserve(sysmem);if (ret) {SYSMEM_E("Failed to reserve sysmem for boardn");goto fail;}/* Reserved for U-boot framework: 'reserve_xxx()' */mem_start = gd->start_addr_sp;mem_size = gd->ram_top - mem_start;if (!sysmem_alloc_base(MEM_UBOOT, mem_start, mem_size)) {SYSMEM_E("Failed to reserve sysmem for U-Boot frameworkn");ret = -ENOMEM;goto fail;}/* Reserved for U-Boot stack */mem_start = gd->start_addr_sp - CONFIG_SYS_STACK_SIZE;mem_size = CONFIG_SYS_STACK_SIZE;if (!sysmem_alloc_base(MEM_STACK, mem_start, mem_size)) {SYSMEM_E("Failed to reserve sysmem for stackn");ret = -ENOMEM;goto fail;}return 0;fail:if (ret && !(gd->flags & GD_FLG_RELOC)) {sysmem_dump();SYSMEM_W("Maybe malloc size %d MiB is too large?nn",SIZE_MB(CONFIG_SYS_MALLOC_LEN));}return ret;}

sysmem 内存信息表:
sysmem_dump_all:--------------------------------------------------------------------// <1> 这里是sysmem可管理的总内存容量,即bidram<3>之外的可用ddr容量,对kernel可见。memory.rgn[0].addr = 0x00200000 - 0x08400000 (size: 0x08200000)memory.rgn[1].addr = 0x0a200000 - 0x80000000 (size: 0x75e00000)memory.total = 0x7e000000 (2016 MiB. 0 KiB)--------------------------------------------------------------------// <2> 这里显示了各个固件alloc走的内存块信息allocated.rgn[0].name = "U-Boot".addr = 0x71dd6140 - 0x80000000 (size: 0x0e229ec0)allocated.rgn[1].name = "STACK"// 表明栈溢出 .addr = 0x71bd6140 - 0x71dd6140 (size: 0x00200000)allocated.rgn[2].name = "FDT".addr = 0x08300000 - 0x08316204 (size: 0x00016204)allocated.rgn[3].name = "KERNEL"// 表明内存块溢出 .addr = 0x00280000 - 0x014ce204 (size: 0x0124e204)allocated.rgn[4].name = "RAMDISK".addr = 0x0a200000 - 0x0a3e6804 (size: 0x001e6804)// <3> malloc_r/f的大小malloc_r: 192 MiB, malloc_f: 16 KiBallocated.total = 0x0f874acc (248 MiB. 466 KiB)--------------------------------------------------------------------// <4> 这里是核心算法对上述<2>进行的信息整理,显示被占用走的内存块信息LMB.reserved[0].addr = 0x00280000 - 0x014ce204 (size: 0x0124e204)LMB.reserved[1].addr = 0x08300000 - 0x08316204 (size: 0x00016204)LMB.reserved[2].addr = 0x0a200000 - 0x0a3e6804 (size: 0x001e6804)LMB.reserved[3].addr = 0x71bd6140 - 0x80000000 (size: 0x0e429ec0)reserved.core.total = 0x0f874acc (248 MiB. 466 KiB)--------------------------------------------------------------------

bidram 内存信息表:
通过上述内存管理,调试中在出现问题时,可以结合分析表去分析问题,如:bidram_dump_all:--------------------------------------------------------------------// <1> 这里显示了U-Boot从前级loader获取的ddr的总容量信息,一共有2GBmemory.rgn[0].addr = 0x00000000 - 0x80000000 (size: 0x80000000)memory.total = 0x80000000 (2048 MiB. 0 KiB)--------------------------------------------------------------------// <2> 这里显示了被预留起来的各固件内存信息,这些空间对kernel不可见reserved.rgn[0].name = "ATF".addr = 0x00000000 - 0x00100000 (size: 0x00100000)reserved.rgn[1].name = "SHM".addr = 0x00100000 - 0x00200000 (size: 0x00100000)reserved.rgn[2].name = "OP-TEE".addr = 0x08400000 - 0x0a200000 (size: 0x01e00000)reserved.total = 0x02000000 (32 MiB. 0 KiB)--------------------------------------------------------------------// <3> 这里是核心算法对上述<2>进行的预留信息整理,例如:会对相邻块进行合并LMB.reserved[0].addr = 0x00000000 - 0x00200000 (size: 0x00200000)LMB.reserved[1].addr = 0x08400000 - 0x0a200000 (size: 0x01e00000)reserved.core.total = 0x02000000 (32 MiB. 0 KiB)--------------------------------------------------------------------

原文标题:Linux如何防止内存冲突?
文章出处:【微信公众号:Linux1024】欢迎添加关注!文章转载请注明出处。
全部0条评论
快来发表一下你的评论吧 !