博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
設置Linux保留物理內存並使用 (1)
阅读量:5973 次
发布时间:2019-06-19

本文共 11443 字,大约阅读时间需要 38 分钟。

在Linux系統中可以通過memblock來設置系統保留物理內存,防止這些內存被內存管理系統分配出去。

 

作者: 彭東林

郵箱: pengdonglin137@163.com

 

平臺

硬件平臺: TQ2440

Linux版本:Linux 3.14.45

 

說明

1. 在tq2440上,物理內存的起始地址是0x30000000,一共有64MB的內存,所以物理內存地址範圍是: 0x30000000 -> 0x33ffffff

2. 可以在uboot傳給kernel的參數bootargs中添加一個"memblock=debug",這樣在Linux啓動的時候,會將設置memblock的信息打印出來

 

參考博文

 

代碼調用

在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 memory\n");27 + return;28 + }29 +30 + printk("reserve : reserve %dM mem\n", 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  = 0x110 [    0.000000]  memory[0x0]    [0x00000030000000-0x00000033ffffff], 0x4000000 bytes flags: 0x011 [    0.000000]  reserved.cnt  = 0x312 [    0.000000]  reserved[0x0]    [0x00000030004000-0x00000030007fff], 0x4000 bytes flags: 0x013 [    0.000000]  reserved[0x1]    [0x00000030008200-0x0000003057fc03], 0x577a04 bytes flags: 0x014 [    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.com\n"; 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: %p\n", __func__, phys_to_virt(RESERVE_PHY));13 14 return 0;15 }16 17 static __exit void reserve_demo_exit(void)18 {19 printk("%s: %s\n", __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: c20000003 [root@TQ2440 /]# 4 [root@TQ2440 /]# rmmod demo5 [ 1420.986938] reserve_demo_exit: pengdonglin137@163.com6 [ 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 memory\n");27 + return;28 + }29 +30 + memblock_free(paddr, size);31 + memblock_remove(paddr, size);32 +33 + printk("reserve : reserve %dM mem\n", 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 = 0x57ba0410 [    0.000000]  memory.cnt  = 0x211 [    0.000000]  memory[0x0]    [0x00000030000000-0x00000031ffffff], 0x2000000 bytes flags: 0x012 [    0.000000]  memory[0x1]    [0x00000032200000-0x00000033ffffff], 0x1e00000 bytes flags: 0x013 [    0.000000]  reserved.cnt  = 0x214 [    0.000000]  reserved[0x0]    [0x00000030004000-0x00000030007fff], 0x4000 bytes flags: 0x015 [    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  11: 0x33ffcb20..0x33ffcb72  12: 0x33ffcb80..0x33ffcb9b  13: 0x33ffcba0..0x33ffcbbb  14: 0x33ffcbc0..0x33ffcdc7  15: 0x33ffcdd0..0x33ffffff

此時在使用這部分保留內存時就不能直接使用了,需要申請,然後映射後才能使用,如下:

1 #include 
2 #include
3 #include
4 5 #define RESERVE_PHY 0x32000000 6 #define RESERVE_SIZE 0x200000 7 8 static char str[] = "pengdonglin137@163.com\n"; 9 static void __iomem *addr;10 11 static __init int reserve_demo_init(void)12 {13 14 if (!request_mem_region(RESERVE_PHY, RESERVE_SIZE, "my reserve"))15 return -EBUSY;16 17 addr = ioremap_nocache(RESERVE_PHY, RESERVE_SIZE);18 memcpy(addr, str, sizeof(str));19 20 printk("%s: virt: %p\n", __func__, addr);21 22 return 0;23 }24 25 static __exit void reserve_demo_exit(void)26 {27 printk("%s: %s\n", __func__, (char *)addr);28 29 iounmap(addr);30 release_mem_region(RESERVE_PHY, RESERVE_SIZE);31 }32 33 module_init(reserve_demo_init);34 module_exit(reserve_demo_exit);35 MODULE_LICENSE("GPL");

 然後加載這個模塊,此時會向addr中寫入字符串,在卸載時再打印出來。log如下:

1 [root@TQ2440 /]# insmod nfs/demo.ko 2 [   43.853848] reserve_demo_init: virt: c50000003 [root@TQ2440 /]# 4 [root@TQ2440 /]# rmmod demo5 [   49.247204] reserve_demo_exit: pengdonglin137@163.com6 [   49.247204] 7 [root@TQ2440 /]#

 

方法三

在uboot可以通過在bootargs中設置mem參數,告訴kernel可用的物理內存。

修改uboot傳給kernel的bootargs,如下:

setenv bootargs "memblock=debug noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0,115200n8 mem=32M"

 此時啓動Linux,啓動信息中可以看到:

[    0.000000] memblock_reserve: [0x00000030008200-0x00000030589c83] flags 0x0 arm_memblock_init+0x5c/0x1d8[    0.000000] memblock_reserve: [0x00000030004000-0x00000030007fff] flags 0x0 arm_memblock_init+0x8c/0x1d8[    0.000000] MEMBLOCK configuration:[    0.000000]  memory size = 0x2000000 reserved size = 0x585a84[    0.000000]  memory.cnt  = 0x1[    0.000000]  memory[0x0]    [0x00000030000000-0x00000031ffffff], 0x2000000 bytes flags: 0x0[    0.000000]  reserved.cnt  = 0x2[    0.000000]  reserved[0x0]    [0x00000030004000-0x00000030007fff], 0x4000 bytes flags: 0x0[    0.000000]  reserved[0x1]    [0x00000030008200-0x00000030589c83], 0x581a84 bytes flags: 0x0... ...[    0.000000] Memory: 26752K/32768K available (3912K kernel code, 214K rwdata, 1176K rodata, 155K init, 176K bss, 6016K reserved)

 可以看到,此時Linux只知道有32MB的物理內存,而實際上板子上有64MB的物理內存。

可以看到memory和reserved節點的內容如下:

1 [root@TQ2440 /]# cat /d/memblock/memory  2    0: 0x30000000..0x31ffffff 3 [root@TQ2440 /]#  4 [root@TQ2440 /]# cat /d/memblock/reserved  5    0: 0x30004000..0x30007fff 6    1: 0x30008200..0x30589c83 7    2: 0x31fa6000..0x31ffbfff 8    3: 0x31ffc840..0x31ffca6b 9    4: 0x31ffca80..0x31ffcaf710    5: 0x31ffcb00..0x31ffcb0311    6: 0x31ffcb20..0x31ffcb2312    7: 0x31ffcb40..0x31ffcb4313    8: 0x31ffcb60..0x31ffcb6314    9: 0x31ffcb80..0x31ffcbda15   10: 0x31ffcbe0..0x31ffcc3a16   11: 0x31ffcc40..0x31ffcc9a17   12: 0x31ffcca0..0x31ffccbb18   13: 0x31ffccc0..0x31ffcdc319   14: 0x31ffcdd0..0x31ffffff

 使用剩餘的物理內存,同樣需要先申請,再映射,然後再使用:

1 #include 
2 #include
3 #include
4 5 #define RESERVE_PHY 0x32000000 6 #define RESERVE_SIZE 0x200000 7 8 static char str[] = "pengdonglin137@163.com\n"; 9 static void __iomem *addr;10 11 static __init int reserve_demo_init(void)12 {13 14 if (!request_mem_region(RESERVE_PHY, RESERVE_SIZE, "my reserve"))15 return -EBUSY;16 17 addr = ioremap_nocache(RESERVE_PHY, RESERVE_SIZE);18 memcpy(addr, str, sizeof(str));19 20 printk("%s: virt: %p\n", __func__, addr);21 22 return 0;23 }24 25 static __exit void reserve_demo_exit(void)26 {27 printk("%s: %s\n", __func__, (char *)addr);28 29 iounmap(addr);30 release_mem_region(RESERVE_PHY, RESERVE_SIZE);31 }32 33 module_init(reserve_demo_init);34 module_exit(reserve_demo_exit);35 MODULE_LICENSE("GPL");

 加載模塊,然後卸載,可以看到log:

1 root@TQ2440 /]# insmod /nfs/demo.ko 2 [  266.998897] reserve_demo_init: virt: c30000003 [root@TQ2440 /]# 4 [root@TQ2440 /]# rmmod demo5 [  271.735731] reserve_demo_exit: pengdonglin137@163.com6 [  271.735731]

 

转载地址:http://zqbox.baihongyu.com/

你可能感兴趣的文章
手动配置 ESXi 主机挂载 NFS 的最大值
查看>>
数据结构与算法
查看>>
1.2封装数组之添加元素
查看>>
使用react的一点提醒17/10/26
查看>>
一步一步学习SignalR进行实时通信_7_非代理
查看>>
UDP可靠传输那些事(转)
查看>>
在CenOS7.5里安装Redis
查看>>
ionic+angularJS+cordova(FileTransfer)上传图片
查看>>
SNS的盈利模式分析
查看>>
矩阵快速幂模板
查看>>
第六章 :进程
查看>>
ios兼容 iphoneX ios10 ios11
查看>>
Oracle中改变表的Owner和tablespace
查看>>
实验三——for 语句及分支结构else-if
查看>>
Ionic background地址写法问题
查看>>
文件操作
查看>>
[WPF]解决模板中ContextMenu绑定CommandParameter的问题
查看>>
[转载]meclipse中project facet问题
查看>>
【51NOD-0】1006 最长公共子序列Lcs
查看>>
profiler内存优化:警惕回调函数
查看>>