dts中memreserve和reserved-memory的區別
Devicetree 提供了兩種方式預留記憶體: reserved-memory和memreserve
memreserve示例
/memreserve/ 0x40000000 0x01000000
reserved-memory示例
reserved-memory { #address-cells = <1>; #size-cells = <1>; ranges; [email protected] { compatible = "shared-dma-pool"; reg = <0x90000000 0x4000000>; reusable; status = "okay"; };
區別1:
二者在dtc編譯時中處理的方法不同, reserved-memory做為device tree node解析到device-tree structure中; memreserve最終會加到dtb檔案的memory reserve map,
見下圖
區別2
二者在核心中的處理方式不同
1 memreserve處理流程
start_kernel - init/main.c
->setup_arch - arch/arm/kernel/setup.c
->arm_memblock_init - arch/arm/kernel/setup.c
->arm_dt_memblock_reserve - arch/arm/kernel/devtree.c
arm_dt_memblock_reserve實現如下
/* Reserve the dtb region */ memblock_reserve(virt_to_phys(initial_boot_params), be32_to_cpu(initial_boot_params->totalsize)); /* * Process the reserve map. This will probably overlap the initrd * and dtb locations which are already reserved, but overlaping * doesn't hurt anything */ reserve_map = ((void*)initial_boot_params) + be32_to_cpu(initial_boot_params->off_mem_rsvmap); while (1) { base = be64_to_cpup(reserve_map++); size = be64_to_cpup(reserve_map++); if (!size) break; memblock_reserve(base, size); }
initial_boot_params實際指向dtb檔案在記憶體中的位置, 該地址還可以指向其他型別的啟動引數
initial_boot_params頭中的off_mem_rsvmap指向一系列的reserve memory(地址, 尺寸)空間, 對於dtb來說, 就是memory reserve map.
2 reserved-memory處理流程
start_kernel - init/main.c
->setup_arch - arch/arm/kernel/setup.c
->arm_memblock_init - arch/arm/kernel/setup.c
->early_init_fdt_scan_reserved_mem - arch/arm/mm/init.c->__fdt_scan_reserved_mem, - drivers/of/fdt.c
->__reserved_mem_reserve_reg - drivers/of/fdt.c
->early_init_dt_reserve_memory_arch - drivers/of/fdt.c
->memblock_remove - mm/memblock.c
->memblock_reserve - mm/memblock.c
->fdt_init_reserved_mem
reserved-memory有一些可選引數, 比如no-map, 如果使用了no-map, 那麼這段區域執行memblock_remove, 反之執行memblock_reserve.
在呼叫完memblock_reserve後,還會執行fdt_init_reserved_mem
void __init fdt_init_reserved_mem(void)
{
...
if (rmem->size == 0)
err = __reserved_mem_alloc_size(node, rmem->name,
&rmem->base, &rmem->size);
if (err == 0)
__reserved_mem_init_node(rmem);
...
}
/**
* res_mem_init_node() - call region specific reserved memory init code
*/
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
...
for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
reservedmem_of_init_fn initfn = i->data;
const char *compat = i->compatible;
if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
continue;
if (initfn(rmem) == 0) {
pr_info("Reserved memory: initialized node %s, compatible id %s\n",
rmem->name, compat);
return 0;
}
}
return -ENOENT;
}
如果reserved-memory下節點的compatible=<shared-dma-pool>, 則這塊記憶體會被用來進行Contiguous Memory Allocator for dma
initfn對應drivers/base/dma-contiguous.c下的rmem_cma_setup以及drivers/base/dma-coherent.c中的rmem_dma_setup, 由於二者的compatible相同,所以前者優先.
rmem_cma_setup會對這塊記憶體做初始化, 把這塊區域加到cma_areas[cma_area_count]中
cma_areas儲存著所有的CMA區域, 稍後core_init_reserved_areas會對這個陣列進行處理
static int __init cma_init_reserved_areas(void)
{
int i;
for (i = 0; i < cma_area_count; i++) {
int ret = cma_activate_area(&cma_areas[i]);
if (ret)
return ret;
}
return 0;
}
core_initcall(cma_init_reserved_areas);
cma_activate_area把該cma area中的所有pages都改為MIGRATE_CMA, 並加到MIGRATE_CMA的free_list上.
區別3
由於二者的處理流程不同, 導致memreserve分配的記憶體, 無法再被作業系統使用; 而reserved-memory記憶體有可能進入系統CMA, 是否做為CMA, 依賴以下幾個條件:
1. compatible 必須為shared-dma-pool
2. 沒有定義no-map屬性
3. 定義了resuable屬性