平臺
硬件平臺: TQ2440
Linux版本:Linux 3.14.45
說明
1.在tq2440上,物理內存的起始地址是0x30000000,一共有64MB的內存,所以物理內存地址範圍是: 0x30000000 -> 0x33ffffff
2.可以在uboot傳給kernel的參數bootargs中添加一個"memblock=debug",這樣在Linux啓動的時候,會將設置memblock的信息打印出來
參考博文
Linux内核---41.arm 内存初始化
http://bbs.chinaunix.net/thread-4143403-1-1.html
代碼調用
在Linux啓動的時候會調用machine相關的代碼定製部分系統保留內存,函數調用如下:
start_kernel
----> setup_arch
----> arm_memblock_init
----> mdesc->reserve()
所以我們可以修改machine相關的代碼,添加reserve函數的實現。
方法一
修改mach-tq2440.c如下:
1 diff --git a/arch/arm/mach-s3c24xx/mach-tq2440.c b/arch/arm/mach-s3c24xx/mach-tq2440.c
2 index f9679fb..da75db2 100644
3 --- a/arch/arm/mach-s3c24xx/mach-tq2440.c
4 +++ b/arch/arm/mach-s3c24xx/mach-tq2440.c
5 @@ -23,6 +23,7 @@
6 #include 7 #include 8 #include 9 +#include 10 11 #include 12 #include 13 @@ -503,11 +504,28 @@ static void __init tq2440_machine_init(void) 14 s3c_pm_init(); 15 } 16 17 +static void __init tq2440_reserve(void) { 18 + u32 paddr,size; 19 + 20 + printk("%s enter.n", __func__); 21 + 22 + paddr = 0x32000000; 23 + size = 0x200000; 24 + 25 + if (memblock_reserve(paddr, size) < 0) { 26 + pr_err("failed to reserve DRAM - no memoryn"); 27 + return; 28 + } 29 + 30 + printk("reserve : reserve %dM memn", size>>20); 31 +} 32 + 33 MACHINE_START(TQ2440, "TQ2440") 34 /* Maintainer: Ben Dooks 35 .atag_offset = 0x100, 36 37 .init_irq = s3c2440_init_irq, 38 + .reserve = tq2440_reserve, 39 .map_io = tq2440_map_io, 40 .init_machine = tq2440_machine_init, 41 .init_time = samsung_timer_init, 上面我們在0x32000000開始的地方保留了2MB的物理內存,然後調用memblock_reserve告訴系統。這個在系統的啓動信息中可以看到: 1 [ 0.000000] Machine: TQ2440 2 [ 0.000000] memblock_reserve: [0x00000030008200-0x0000003057fc03] flags 0x0 arm_memblock_init+0x4c/0x1bc 3 [ 0.000000] memblock_reserve: [0x00000030004000-0x00000030007fff] flags 0x0 arm_memblock_init+0x158/0x1bc 4 [ 0.000000] tq2440_reserve enter. 5 [ 0.000000] memblock_reserve: [0x00000032000000-0x000000321fffff] flags 0x0 tq2440_reserve+0x1c/0x50 6 [ 0.000000] reserve : reserve 2M mem 7 [ 0.000000] MEMBLOCK configuration: 8 [ 0.000000] memory size = 0x4000000 reserved size = 0x77ba04 9 [ 0.000000] memory.cnt = 0x1 10 [ 0.000000] memory[0x0] [0x00000030000000-0x00000033ffffff], 0x4000000 bytes flags: 0x0 11 [ 0.000000] reserved.cnt = 0x3 12 [ 0.000000] reserved[0x0] [0x00000030004000-0x00000030007fff], 0x4000 bytes flags: 0x0 13 [ 0.000000] reserved[0x1] [0x00000030008200-0x0000003057fc03], 0x577a04 bytes flags: 0x0 14 [ 0.000000] reserved[0x2] [0x00000032000000-0x000000321fffff], 0x200000 bytes flags: 0x0 上面的第5行和第14行就是我們自己設置的保留內存範圍信息。在Linux啓動後,在debugfs中也可以看到memblock的信息: [root@TQ2440 /]# cat /sys/kernel/debug/memblock/memory 0: 0x30000000..0x33ffffff [root@TQ2440 /]# cat /sys/kernel/debug/memblock/reserved 0: 0x30004000..0x30007fff 1: 0x30008200..0x3057fc03 2: 0x32000000..0x321fffff 3: 0x33f60000..0x33ffbfff 4: 0x33ffc540..0x33ffc96b 5: 0x33ffc980..0x33ffc9f7 6: 0x33ffca00..0x33ffca03 7: 0x33ffca20..0x33ffca23 8: 0x33ffca40..0x33ffca43 9: 0x33ffca60..0x33ffca63 10: 0x33ffca80..0x33ffcad2 11: 0x33ffcae0..0x33ffcb32 12: 0x33ffcb40..0x33ffcb92 13: 0x33ffcba0..0x33ffcbbb 14: 0x33ffcbc0..0x33ffcdc7 15: 0x33ffcdd0..0x33ffffff 其中memory節點中存放的是可用的物理內存地址範圍,reserved表示已經分配出去的物理地址,第2行記錄的就是我們設置的。 既然添加了保留物理內存,那麼如何使用呢?下面我寫了一個簡單的內核模塊,使用我們添加的保留物理內存,下面是內核模塊的代碼: 1 #include 2 3 #define RESERVE_PHY 0x32000000 4 #define RESERVE_SIZE 0x200000 5 6 static char str[] = "pengdonglin137@163.comn"; 7 8 static __init int reserve_demo_init(void) 9 { 10 memcpy(phys_to_virt(RESERVE_PHY), str, sizeof(str)); 11 12 printk("%s: virt: %pn", __func__, phys_to_virt(RESERVE_PHY)); 13 14 return 0; 15 } 16 17 static __exit void reserve_demo_exit(void) 18 { 19 printk("%s: %sn", __func__, (char *)phys_to_virt(RESERVE_PHY)); 20 } 21 22 module_init(reserve_demo_init); 23 module_exit(reserve_demo_exit); 24 MODULE_LICENSE("GPL"); 可以看到,我們直接調用函數phys_to_virt將物理地址轉換成虛擬地址,然後直接向這個虛擬地址中寫入數據,在模塊卸載時再將內容打印出出來。 1 [root@TQ2440 /]# insmod nfs/demo.ko 2 [ 1417.153362] reserve_demo_init: virt: c2000000 3 [root@TQ2440 /]# 4 [root@TQ2440 /]# rmmod demo 5 [ 1420.986938] reserve_demo_exit: pengdonglin137@163.com 6 [ 1420.986938] 可以看到,第2行中得到物理地址0x32000000對應的虛擬地址是0xC2000000。在模塊卸載時打印出了我們之前寫入的內容。 這種方法使用與物理內存在Normal區域的情況。 方法二 修改mach-tq2440.c 1 diff --git a/arch/arm/mach-s3c24xx/mach-tq2440.c b/arch/arm/mach-s3c24xx/mach-tq2440.c 2 index f9679fb..345a868 100644 3 --- a/arch/arm/mach-s3c24xx/mach-tq2440.c 4 +++ b/arch/arm/mach-s3c24xx/mach-tq2440.c 5 @@ -23,6 +23,7 @@ 6 #include 7 #include 8 #include 9 +#include 10 11 #include 12 #include 13 @@ -503,11 +504,31 @@ static void __init tq2440_machine_init(void) 14 s3c_pm_init(); 15 } 16 17 +static void __init tq2440_reserve(void) { 18 + u32 paddr,size; 19 + 20 + printk("%s enter.n", __func__); 21 + 22 + paddr = 0x32000000; 23 + size = 0x200000; 24 + 25 + if (memblock_reserve(paddr, size) < 0) { 26 + pr_err("failed to reserve DRAM - no memoryn"); 27 + return; 28 + } 29 + 30 + memblock_free(paddr, size); 31 + memblock_remove(paddr, size); 32 + 33 + printk("reserve : reserve %dM memn", size>>20); 34 +} 35 + 36 MACHINE_START(TQ2440, "TQ2440") 37 /* Maintainer: Ben Dooks 38 .atag_offset = 0x100, 39 40 .init_irq = s3c2440_init_irq, 41 + .reserve = tq2440_reserve, 42 .map_io = tq2440_map_io, 43 .init_machine = tq2440_machine_init, 44 .init_time = samsung_timer_init, 用新kernel啓動,在啓動信息中可以看到: 1 [ 0.000000] Machine: TQ2440 2 [ 0.000000] memblock_reserve: [0x00000030008200-0x0000003057fc03] flags 0x0 arm_memblock_init+0x4c/0x1bc 3 [ 0.000000] memblock_reserve: [0x00000030004000-0x00000030007fff] flags 0x0 arm_memblock_init+0x158/0x1bc 4 [ 0.000000] tq2440_reserve enter. 5 [ 0.000000] memblock_reserve: [0x00000032000000-0x000000321fffff] flags 0x0 tq2440_reserve+0x1c/0x68 6 [ 0.000000] memblock_free: [0x00000032000000-0x000000321fffff] tq2440_reserve+0x3c/0x68 7 [ 0.000000] reserve : reserve 2M mem 8 [ 0.000000] MEMBLOCK configuration: 9 [ 0.000000] memory size = 0x3e00000 reserved size = 0x57ba04 10 [ 0.000000] memory.cnt = 0x2 11 [ 0.000000] memory[0x0] [0x00000030000000-0x00000031ffffff], 0x2000000 bytes flags: 0x0 12 [ 0.000000] memory[0x1] [0x00000032200000-0x00000033ffffff], 0x1e00000 bytes flags: 0x0 13 [ 0.000000] reserved.cnt = 0x2 14 [ 0.000000] reserved[0x0] [0x00000030004000-0x00000030007fff], 0x4000 bytes flags: 0x0 15 [ 0.000000] reserved[0x1] [0x00000030008200-0x0000003057fc03], 0x577a04 bytes flags: 0x0 在kernel啓動後,在memory和reserved節點中: [root@TQ2440 /]# cat /sys/kernel/debug/memblock/memory 0: 0x30000000..0x31ffffff 1: 0x32200000..0x33ffffff 可以看到,此時系統中有兩塊物理內存,但是這兩塊物理內存的地址之間不連續,中間有一個大小爲2MB的“洞”。此時在reserved節點看不到這部分內存。 [root@TQ2440 /]# cat /sys/kernel/debug/memblock/reserved 0: 0x30004000..0x30007fff 1: 0x30008200..0x3057fc03 2: 0x33f60000..0x33ffbfff 3: 0x33ffc520..0x33ffc94b 4: 0x33ffc960..0x33ffc9d7 5: 0x33ffc9e0..0x33ffc9e3 6: 0x33ffca00..0x33ffca03 7: 0x33ffca20..0x33ffca23 8: 0x33ffca40..0x33ffca43 9: 0x33ffca60..0x33ffcab2 10: 0x33ffcac0..0x33ffcb12