在聊這個話題之前,我們先回憶一下單片機系統中是如何分配內存的?如果沒有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
先來大概預覽一下源文件吧:
intsysmem_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;}return0;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】歡迎添加關注!文章轉載請注明出處。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
Linux
+關注
關注
88文章
11782瀏覽量
219256 -
內存
+關注
關注
9文章
3218瀏覽量
76417 -
bootloader
+關注
關注
2文章
245瀏覽量
48156
發布評論請先 登錄
相關推薦
熱點推薦
走進Linux內存系統探尋內存管理的機制和奧秘
Linux 內存是后臺開發人員,需要深入了解的計算機資源。合理的使用內存,有助于提升機器的性能和穩定性。本文主要介紹Linux 內存組織結構
關于Linux內存管理的詳細介紹
Linux內存管理是指對系統內存的分配、釋放、映射、管理、交換、壓縮等一系列操作的管理。在Linux中,內存被劃分為多個區域,每個區域有不同
發表于 03-06 09:28
?1455次閱讀
Linux內存相關知識科普
Linux 內存是后臺開發人員,需要深入了解的計算機資源。合理的使用內存,有助于提升機器的性能和穩定性。本文主要介紹**Linu****x 內存組織結構和頁面布局,
發表于 07-25 14:43
?1196次閱讀
Linux中的沖突問題及其應對策略
Linux服務器系統是不存在沖突的,然而些許時候該系統的沖突、停滯問題的確存在。對于應用軟件層面的沖突或者停滯問題,與內核層面有何不同呢?
發表于 05-16 11:41
?1053次閱讀
你知道linux內存管理基礎及方法?
linux的內存管理采取的分頁存取機制,會將內存中不經常使用的數據塊交換到虛擬內存中。linux會不時地進行頁面交換操作,以保持盡可能多的空
發表于 04-28 17:12
?1628次閱讀
深入剖析Linux共享內存原理
在Linux系統中,每個進程都有獨立的虛擬內存空間,也就是說不同的進程訪問同一段虛擬內存地址所得到的數據是不一樣的,這是因為不同進程相同的虛擬內存地址會映射到不同的物理
Linux系統的共享內存的使用
但有時候為了讓不同進程之間進行通信,需要讓不同進程共享相同的物理內存,Linux通過 共享內存 來實現這個功能。下面先來介紹一下Linux系統的共享
Linux如何防止內存沖突?
評論