Android PMem 介绍

原文:http://www.ophonesdn.com/forum/thread-6260-8-1.html


pmemashmem都通过mmap实现共享,区别是Pmem的共享区域是一段连续的物理内存,而Ashmem的共享区域在虚拟空间是连续的,物理内存却不一定连续

APMEM的实现

Pmem的源代码在drivers/misc/pmem.c中,Pmem驱动依赖于linuxmisc deviceplatform driver框架,一个系统可以有多个Pmem,默认的是最多10个。Pmem暴露4组操作,分别是platform driverproberemove操作; misc devicefops接口和vm_ops操作。模块初始化时会注册一个platform driver,在之后probe时,创建misc设备文件,分配内存,完成初始化工作。

Pmem通过pmem_infopmem_datapmem_region三个结构体维护分配的共享内存,其中pmem_info代表一个Pmem设备分配的内存块,pmem_data代表该内存块的一个子块,pmem_region则把每个子块分成多个区域。 pmem_data是分配的基本单位,即每次应用层要分配一块Pmem内存,就会有一个pmem_data来表示这个被分配的内存块,实际上在open的时候,并不是open一个pmem_info表示的整个Pmem内存块,而是创建一个pmem_data以备使用。一个应用可以通过ioctl来分配pmem_data中的一个区域,并可以把它map到进程空间;并不一定每次都要分配和map整个pmem_data内存块

B、用户接口

一个进程首先打开Pmem设备,通过ioctl(PMEM_ALLOCATE)分配内存,它mmap这段内存到自己的进程空间后,该进程成为master进程。其他进程可以重新打开这个pmem 
备,通过调用ioctl(PMEM_CONNECT)将自己的pmem_datamaster进程的pmem_data建立连接关系,这个进程就成为client进程。Client进程可以通过mmapmaster Pmem中的一段或全部重新映射到自己的进程空间,这样就实现了共享Pmem内存。如果是GPUDSP则可以通过ioctl(PMEM_GET_PHYS)获取物理地址进行操作。


3. 在应用程序中的使用: 

1) 
Pmem 例子:


sp<MemoryHeapBase> master_workspace = new 
MemoryHeapBase(pmem_adsp, Coda_WorkSpace_Size); 
//new 
一个 base 
memeoryHeapBase 
,构造函数中做了 2 件事情 一个是 open “/dev/pmem_adsp”  设备,   第二是调用 mapfd  (内部即 mmap )来得到共享内存区域  

if (master_workspace->heapID() < 0) {
 

LOGD("Error creating workspace heap");
 

Status = UNKNOWN_ERROR;
 

}
 

master_workspace->setDevice(pmem); // 
如果 pmem_adsp device 出错,   就是用 pmem device  

mHeapPmem_workspace = new MemoryHeapPmem(master_workspace, 0); 

// new  一个 Pmem , MemoryHeapPmem ,  (构造函数中调用 init  ,设定了 Base,device ,size  等)  

mHeapPmem_workspace->slap();
 

master_workspace.clear();
 


if (ioctl(mHeapPmem_workspace->heapID(), PMEM_GET_PHYS, &region) >= 0)//
得到物理地址  

{
 


pys_address = (unsigned int)region.offset;
 


WORK_SPACE_PMEM_PHY_ADDRESS = pys_address;
 


WORK_SPACE_PMEM_VIR_ADDRESS = mHeapPmem_workspace->base(); //
得到虚拟地址  

}
 

else
 

{
 


pys_address = 0xFFFFFFFF;
 


LOGE("Error: WORKSPACE PMEM_GET_PHYS FAILED");
 


return UNKNOWN_ERROR; 


}
 

2) 
Ashmem  例子:  

sp<MemoryHeapBase> heap = new MemoryHeapBase(frameSize * kBufferCount);
 

if (heap->heapID() < 0) {
 

LOGE("Error creating frame buffer heap");
 

return false;
 
}  
// 没有指定 device    就是用的 ashmem .  构造函数中做了 2 件事情 一个是 ashmem_create_region   第二是调用 mapfd  (内部即 mmap )来得到共享内存区域  

第一步通过调用 ashmem_create_region 函数,这个函数完成这几件事:  

1
fd = open("/dev/ashmem", O_RDWR); 
2
ioctl(fd, ASHMEM_SET_NAME, region_name); //  这一步可选  
3
ioctl(fd, ASHMEM_SET_SIZE, region_size); 

第二步,应用程序一般会调用 mmap 来把 ashmem 分配的空间映射到进程空间:  

mapAddr = mmap(NULL, pHdr->mapLength, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);


4. 如何将PMEM编入内核 

Android PMEM驱动研究(1——如何将PMEM编入内核

PMEM并不像Ashmembinder那样,选中就可以被Android系统使用,他是一个platform设备,需要注册才可以使用。

下面以S3C6410为例,描述使用流程:

1)选中内核选项 
Device Drivers ---> 

  • Misc devices ---> 
  •    Android pmem allocator

    2)修改你的dev.c注册文件,添加如下内容:

    #ifdef CONFIG_ANDROID_PMEM 
    static struct android_pmem_platform_data android_pmem_pdata = { 
           .name = "pmem", 
           .start = PMEM_BASE, 
           .size = PMEM_BASE_SIZE, 
           .no_allocator = 1, 
           .cached = 1, 
    };

    static struct android_pmem_platform_data android_pmem_adsp_pdata = { 
           .name = "pmem_adsp", 
           .start = PMEM_ADSP_BASE, 
           .size = PMEM_ADSP_BASE_SIZE, 
           .no_allocator = 0, 
           .cached = 0, 
    };

    struct platform_device android_pmem_device = { 
           .name = "android_pmem", 
           .id = 0, 
           .dev = { .platform_data = &android_pmem_pdata }, 
    };

    struct platform_device android_pmem_adsp_device = { 
           .name = "android_pmem", 
           .id = 1, 
           .dev = { .platform_data = &android_pmem_adsp_pdata }, 
    }; 
    #endif

    3)在驱动注册列表中添加如下内容
    static struct platform_device *smdk6410_devices[] __initdata = { 
    #ifdef CONFIG_ANDROID_PMEM 
           &android_pmem_device, 
           &android_pmem_adsp_device, 
    #endif 
    };

    4)分配物理地址我用了128MB的最后8MB 
    #define PMEM_BASE 0x57900000 
    #define PMEM_BASE_SIZE SZ_1M*4 
    #define PMEM_ADSP_BASE 0x57c00000 
    #define PMEM_ADSP_BASE_SIZE SZ_1M*4

    5)重新编译内核

    6)修改bootargs 减少Linux可管理的MEM 
    MEM=120MB

    7)重新启动系统 
    启动信息: 
    pmem: 1 init 
    pmem_adsp: 0 init

    8)查看dev目录,多了pmempmem_adsp


  • 你可能感兴趣的:(linux,框架,android,struct,buffer,化工)