深入浅出LDD-9-内存与IO1-内存的储存地址

/***************************************************************************************************
*文件功能:验证内存分配的地方
*编译环境:SUSELinux
*编译结果:成功
*实验结果:与理论不相符,可能因为是虚拟机的原因。
*实 验 者:张永辉 2012年9月13日

理论:
    linux提供了MMU(存储管理器,辅助操作系统进行内存管理,提供虚实地址转换等硬件支持)的处理器而言,
    Linux 提供了复杂的存储管理系统,使得进程所能访问的内存达到4GB。

    LINUX进程的 4GB 内存空间被人为的分为两个部分
        4G =    0X00000000-0X3FFFFFFF
                0X40000000-0X7FFFFFFF
                0X80000000-0XBFFFFFFF
                0XC0000000-0XFFFFFFFF

        用户空间
            0--3GB是用户空间 即0x00000000---0xBFFFFFFF(PAGE_OFFSET,在 0x86 中它等于 0xC0000000)
        内核空间
            1G是内核空间按   即0XC0000000---0XFFFFFFFF
                3G---vmalloc_start              这段地址是物理内存映射区域(该区域中包含了内核镜像、物理页框表 mem_map 等等),
                    比如我们使用的 VMware 虚拟系统内存是 160M,那么 3G~3G+160M 这片内存就应该映射物理内存。
                    对于160M的系统而言,vmalloc_start 位置应在 3G+160M 附近(在物理内存映射区与vmalloc_start 期间还存在一个 8M 的 gap 来防止跃界),

                vmalloc_start---0XFFFFFFFF      是 vmalloc 区域
                    vmalloc_end 位置接近 4G(最后位置系统会保留一片 128k 大小的区域用于专用页面映射)


    内存的操作:

        kmalloc 和 get_free_page     //include\asm-i386\io.h
            他们申请的内存位于3G---vmalloc_start,物理上是连续的,与真实的物理地址只有一个固定的偏移.

            转换关系如下:
                #define __pa(x)    ((unsigned long)(x)-PAGE_OFFSET)
                extern inline unsigned long virt_to_phys(volatile void * address)   //虚拟地址减去3G(PAGE_OFFSET=0XC000000)得到 物理地址
                {   return __pa(address);   }

                #define __va(x)    ((void *)((unsigned long)(x)+PAGE_OFFSET))
                extern inline void * phys_to_virt(unsigned long address)
                {
                    return __va(address);                                           //内核物理地址转化为虚拟地址
                }
        vmalloc
            申请的内存则位于 vmalloc_start~vmalloc_end 之间,与物理地址没有简单的转换关系,在逻辑上也是连续的,但在物理不要求连续。

实验结果:
    连续进行三次 insmod rmmod 操作,三个函数申请得到的内存地址如下
    __get_free_page() [addr应该 = 0xc0000000--0xc0000000+16M]
        pagemem    addr=0X496e5000
        pagemem    addr=0Xcd7a1000
        pagemem    addr=0X9e005000

    kmalloc()         [addr应该 = 0xc0000000--0xc0000000+16M]
        kmallocmem addr=0X26530ac0
        kmallocmem addr=0Xbe7e61c0
        kmallocmem addr=0X4775a640

    vmalloc()         [addr应该 = 0xc0000000+16M--0XFFFFFFFF-128K]
        vmallocmem addr=0X222c000
        vmallocmem addr=0X2246000
        vmallocmem addr=0X2260000
事实上不是这样的,求解为什么?
***************************************************************************************************/
/***************************************************************************************************
* mem.c :查看内存分配地址
编译环境:SUSELinux
编译结果:成功,见注释
实 验 者:张永辉  2012年9月13日
***************************************************************************************************/

#include <linux/module.h>                   /* Needed by all modules */
#include <linux/kernel.h>                   /* Needed for printk:KERN_ALERT */
#include <linux/init.h>

//#include <linux/slab.h>
#include <linux/vmalloc.h>                  //kmalloc()  vmalloc() 's headfile

MODULE_LICENSE("Dual BSD/GPL");

unsigned char *pagemem;
unsigned char *kmallocmem;
unsigned char *vmallocmem;

static int mem_init(void)
{
    pagemem    = (unsigned char*)__get_free_page(0);
    kmallocmem = (unsigned char*)kmalloc(100, 0);
    vmallocmem = (unsigned char*)vmalloc(100000);

    printk(KERN_EMERG  "pagemem    addr=0X%x \n" , pagemem);
    printk(KERN_EMERG  "kmallocmem addr=0X%x \n" , kmallocmem);
    printk(KERN_EMERG  "vmallocmem addr=0X%x \n" , vmallocmem);

    printk(KERN_EMERG "Hello world\n");
    return 0;
}

static void mem_exit(void)
{
    printk(KERN_EMERG "Goodbye world\n");
}

module_init(mem_init);
module_exit(mem_exit);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值