android内存管理之ion
创始人
2024-05-29 11:23:36
0

参考:android内存管理之ion - 知乎

驱动代码分析:

static struct of_device_id tcc_ion_of_match[] = {{ .compatible = "telechips,tcc-ion" },{},
};static struct platform_driver tcc_ion_driver = {.probe = tcc_ion_probe,.driver = {.of_match_table = of_match_ptr(tcc_ion_of_match),},
};
int tcc_ion_probe(struct platform_device *pdev)
{struct ion_platform_data *pdata;int i;if (pdev->dev.of_node) {pdata = tcc_ion_parse_dt(pdev);} num_heaps = pdata->nr;heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL);/* create the heaps as specified in the board file */for (i = 0; i < num_heaps; i++) {struct ion_platform_heap *heap_data = &pdata->heaps[i];heaps[i] = ion_heap_create(heap_data);ion_device_add_heap(heaps[i]);}return 0;
}

结构体定义:

struct ion_platform_data {int nr;struct ion_platform_heap *heaps;
};/*** struct ion_platform_heap - defines a heap in the given platform* @type:	type of the heap from ion_heap_type enum* @id:		unique identifier for heap. * @name:	used for debug purposes* @base:	base address of heap in physical memory if applicable* @size:	size of the heap in bytes if applicable* @priv:	private info passed from the board file** Provided by the board file.*/
struct ion_platform_heap {enum ion_heap_type type;unsigned int id;const char *name;phys_addr_t base;size_t size;phys_addr_t align;void *priv;
};

 设备树节点设置:

        telechips,ion {compatible = "telechips,tcc-ion";ion-heap@2 {reg = <2>;telechips,ion-heap-name = "ion_carveout_heap";};ion-heap@3 {reg = <3>;telechips,ion-heap-name = "ion_carveout_cam_heap";};};pmap_ump_reserved: ump_reserved {compatible = "telechips,pmap";telechips,pmap-name = "ump_reserved";size = ; };

tcc_ion_parse_dt函数,解析设备树: 

static struct ion_platform_data *tcc_ion_parse_dt(struct platform_device *pdev)
{struct device_node *node = pdev->dev.of_node;struct device_node *child;struct ion_platform_data *pdata;int index = 0;u32 val;num_heaps = 0;for_each_child_of_node(node, child)++num_heaps;pdata = devm_kzalloc(&pdev->dev, sizeof(struct ion_platform_data),GFP_KERNEL);pdata->heaps = devm_kzalloc(&pdev->dev,num_heaps * sizeof(struct ion_platform_heap),GFP_KERNEL);for_each_child_of_node(node, child) {struct ion_platform_heap *heap = &pdata->heaps[index];of_property_read_u32(child, "reg", &val);heap->id = index;heap->type = val;of_property_read_string(child,"telechips,ion-heap-name", &heap->name);if(heap->type == ION_HEAP_TYPE_CARVEOUT){if(0 > pmap_get_info("ump_reserved", &pmap_ump_reserved)){return ERR_PTR(-ENOMEM);}heap->base = pmap_ump_reserved.base;heap->size = pmap_ump_reserved.size;}.....	++index;}pdata->nr = num_heaps;return pdata;
}

ion_heap_create函数:

struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{struct ion_heap *heap = NULL;switch (heap_data->type) {
#ifdef CONFIG_ION_CARVEOUT_HEAPcase ION_HEAP_TYPE_CARVEOUT:heap = ion_carveout_heap_create(heap_data);break;
#endif		......default:return ERR_PTR(-EINVAL);}heap->name = heap_data->name;heap->id = heap_data->id;return heap;
}

ion_carveout_heap_create函数:

struct ion_heap *ion_carveout_heap_create(struct ion_platform_heap *heap_data)
{struct ion_carveout_heap *carveout_heap;struct page *page;size_t size;int ret;page = pfn_to_page(PFN_DOWN(heap_data->base));size = heap_data->size;ion_heap_pages_zero(page, size, pgprot_writecombine(PAGE_KERNEL));carveout_heap = kzalloc(sizeof(*carveout_heap), GFP_KERNEL);carveout_heap->pool = gen_pool_create(PAGE_SHIFT, -1);carveout_heap->base = heap_data->base;gen_pool_add(carveout_heap->pool, carveout_heap->base, heap_data->size,-1);carveout_heap->heap.ops = &carveout_heap_ops;carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;......return &carveout_heap->heap;
}

结构体定义:

struct ion_carveout_heap {struct ion_heap heap;struct gen_pool *pool;phys_addr_t base;......
};//函数指针
typedef unsigned long (*genpool_algo_t)(unsigned long *map,unsigned long size,unsigned long start, unsigned int nr,void *data, struct gen_pool *pool);/*General purpose special memory pool descriptor.*/
struct gen_pool {struct list_head chunks;	/* list of chunks in this pool */int min_alloc_order;		/* minimum allocation order */genpool_algo_t algo;		/* allocation function */void *data;const char *name;......
};struct ion_heap {struct plist_node node;struct ion_device *dev;enum ion_heap_type type;struct ion_heap_ops *ops;unsigned long flags;unsigned int id;const char *name;struct shrinker shrinker;struct list_head free_list;size_t free_list_size;wait_queue_head_t waitqueue;struct task_struct *task;int (*debug_show)(struct ion_heap *heap, struct seq_file *, void *);
};/*General purpose special memory pool chunk descriptor.*/
struct gen_pool_chunk {struct list_head next_chunk;	/* next chunk in pool */atomic_long_t avail;phys_addr_t phys_addr;		/* physical starting address of memory chunk */unsigned long start_addr;	/* start address of memory chunk */unsigned long end_addr;		/* end address of memory chunk (inclusive) */unsigned long bits[0];		/* bitmap for allocating memory chunk */
};

gen_pool_create函数:分配一个内存池

struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
{struct gen_pool *pool;pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid);if (pool != NULL) {spin_lock_init(&pool->lock);INIT_LIST_HEAD(&pool->chunks);pool->min_alloc_order = min_alloc_order;pool->algo = gen_pool_first_fit;pool->data = NULL;pool->name = NULL;}return pool;
}

gen_pool_first_fit函数:查找第一块满足要求的可用内存区域。

/** @map: The address to base the search on* @size: The bitmap size in bits* @start: The bitnumber to start searching at* @nr: The number of zeroed bits we're looking for* @data: additional data - unused* @pool: pool to find the fit region memory from*/
unsigned long gen_pool_first_fit(unsigned long *map, unsigned long size,unsigned long start, unsigned int nr, void *data,struct gen_pool *pool)
{return bitmap_find_next_zero_area(map, size, start, nr, 0);
}
static inline unsigned long bitmap_find_next_zero_area(unsigned long *map,unsigned long size,unsigned long start,unsigned int nr,unsigned long align_mask)
{return bitmap_find_next_zero_area_off(map, size, start, nr, align_mask, 0);
}
/*** bitmap_find_next_zero_area_off - find a contiguous aligned zero area* @map: The address to base the search on* @size: The bitmap size in bits* @start: The bitnumber to start searching at* @nr: The number of zeroed bits we're looking for* @align_mask: Alignment mask for zero area* @align_offset: Alignment offset for zero area.*/
unsigned long bitmap_find_next_zero_area_off(unsigned long *map,unsigned long size,unsigned long start,unsigned int nr,unsigned long align_mask,unsigned long align_offset)
{unsigned long index, end, i;again://以位图的map为基地址、start为起点、大小为size,开始查找第一个是0的比特值的索引下标index = find_next_zero_bit(map, size, start);//从该下标开始连续nr个bit都是0end = index + nr;//以位图的map为基地址、index为起点、大小为end,开始查找第一个是1的比特值的索引下标i = find_next_bit(map, end, index);if (i < end) { //如果i小于end,表示以index为起点、大小为nr个bit的范围内有比特值为1的值start = i + 1;goto again;}return index; //表示以index为起点、大小为nr个bit的范围内都是0
}

first fit:

First Fit分配器是最基本的内存分配器,它使用bitmap而不是空闲块列表来表示内存。在bitmap中,如果page对应位为1,则表示此page已经被分配,为0则表示此page没有被分配。为了分配小于一个page的内存块,First Fit分配器记录了最后被分配的PFN (Page Frame Number)和分配的结束地址在页内的偏移量。随后小的内存分配被Merge到一起并存储到同一页中。

First Fit分配器不会造成严重的内存碎片,但其效率较低,由于内存经常通过线性地址进行search,而First Fit中的小块内存经常在物理内存的开始处,为了分配大块内存而不得不扫描前面大量的内存。

参考:安全验证 - 知乎

gen_pool_add函数:

/*** gen_pool_add - add a new chunk of special memory to the pool* @pool: pool to add new memory chunk to* @addr: starting address of memory chunk to add to pool* @size: size in bytes of the memory chunk to add to pool* @nid: node id of the node the chunk structure and bitmap should be*       allocated on, or -1*/
static inline int gen_pool_add(struct gen_pool *pool, unsigned long addr,size_t size, int nid)
{return gen_pool_add_virt(pool, addr, -1, size, nid);
}
/*** gen_pool_add_virt - add a new chunk of special memory to the pool* @pool: pool to add new memory chunk to* @virt: virtual starting address of memory chunk to add to pool* @phys: physical starting address of memory chunk to add to pool* @size: size in bytes of the memory chunk to add to pool* @nid: node id of the node the chunk structure and bitmap should be*       allocated on, or -1*/
int gen_pool_add_virt(struct gen_pool *pool, unsigned long virt, phys_addr_t phys,size_t size, int nid)
{struct gen_pool_chunk *chunk;// pool->min_alloc_order等于PAGE_SHIFT,用位图表示:一个page对应1个bit,//大小为size的内存有多少page,即有多少bit位int nbits = size >> pool->min_alloc_order;//BITS_TO_LONGS(nbits) * sizeof(long)://nbits个bit数转换成long的数量*每个long占的字节数,计算出bitmap占的字节数int nbytes = sizeof(struct gen_pool_chunk) +BITS_TO_LONGS(nbits) * sizeof(long);chunk = kzalloc_node(nbytes, GFP_KERNEL, nid);chunk->phys_addr = phys;chunk->start_addr = virt;chunk->end_addr = virt + size - 1;atomic_long_set(&chunk->avail, size);//将内存块添加到内存池的链表中list_add_rcu(&chunk->next_chunk, &pool->chunks);return 0;
}
struct gen_pool_chunk {struct list_head next_chunk;	/* next chunk in pool */atomic_long_t avail;phys_addr_t phys_addr;		/* physical starting address of memory chunk */unsigned long start_addr;	/* start address of memory chunk */unsigned long end_addr;		/* end address of memory chunk (inclusive) */unsigned long bits[0];		/* bitmap for allocating memory chunk */
};

carveout_heap_ops的实现: 

static struct ion_heap_ops carveout_heap_ops = {.allocate = ion_carveout_heap_allocate,.free = ion_carveout_heap_free,.map_user = ion_heap_map_user,.map_kernel = ion_heap_map_kernel,.unmap_kernel = ion_heap_unmap_kernel,
};

重点关注ion_carveout_heap_allocate函数,该函数的实现在下面会连续起来一起讲。

ion_device_add_heap函数:将堆添加到ion设备的链表上

void ion_device_add_heap(struct ion_heap *heap)
{struct ion_device *dev = internal_dev;heap->dev = dev;heap->id = heap_id++;//将heap添加到ion设备的heaps链表上plist_node_init(&heap->node, -heap->id);plist_add(&heap->node, &dev->heaps);dev->heap_cnt++;......
}

ion的入口驱动:

static int ion_device_create(void)
{struct ion_device *idev;idev = kzalloc(sizeof(*idev), GFP_KERNEL);idev->dev.minor = MISC_DYNAMIC_MINOR;idev->dev.name = "ion";idev->dev.fops = &ion_fops;misc_register(&idev->dev);......
debugfs_done:plist_head_init(&idev->heaps);//internal_dev作为全局变量,在这里初始化,后面将会被到处使用internal_dev = idev;return 0;
}
subsys_initcall(ion_device_create);
static const struct file_operations ion_fops = {.owner          = THIS_MODULE,.unlocked_ioctl = ion_ioctl,
};

ioctl函数:

long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{unsigned int dir;union ion_ioctl_arg data;dir = ion_ioctl_dir(cmd);if (copy_from_user(&data, (void __user *)arg, _IOC_SIZE(cmd)))return -EFAULT;switch (cmd) {case ION_IOC_ALLOC:{int fd;fd = ion_alloc(data.allocation.len,data.allocation.heap_id_mask,data.allocation.flags);data.allocation.fd = fd;break;}}
}

ion_alloc函数:

int ion_alloc(size_t len, unsigned int heap_id_mask, unsigned int flags)
{struct ion_device *dev = internal_dev;struct ion_buffer *buffer = NULL;struct ion_heap *heap;len = PAGE_ALIGN(len);plist_for_each_entry(heap, &dev->heaps, node) {/* if the caller didn't specify this heap id */if (!((1 << heap->id) & heap_id_mask))continue;buffer = ion_buffer_create(heap, dev, len, flags);if (!IS_ERR(buffer))break;}......
}

结构体定义:

struct ion_buffer {union {struct rb_node node;struct list_head list;};struct ion_device *dev;struct ion_heap *heap;unsigned long flags;unsigned long private_flags;size_t size;void *priv_virt;struct mutex lock;int kmap_cnt;void *vaddr;struct sg_table *sg_table;......
};

ion_buffer_create函数:

static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,struct ion_device *dev,unsigned long len,unsigned long flags)
{struct ion_buffer *buffer;struct sg_table *table;buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);buffer->heap = heap;buffer->flags = flags;//对应ion_carveout_heap_allocate函数heap->ops->allocate(heap, buffer, len, flags);table = buffer->sg_table;buffer->dev = dev;buffer->size = len;ion_buffer_add(dev, buffer);return buffer;
}

ion_carveout_heap_allocate函数实现:

static int ion_carveout_heap_allocate(struct ion_heap *heap,struct ion_buffer *buffer,unsigned long size,unsigned long flags)
{struct sg_table *table;unsigned long paddr;table = kmalloc(sizeof(*table), GFP_KERNEL);sg_alloc_table(table, 1, GFP_KERNEL);paddr = ion_carveout_allocate(heap, size);sg_set_page(table->sgl, pfn_to_page(PFN_DOWN(paddr)), size, 0);buffer->sg_table = table;return 0;}

ion_carveout_allocate函数:

static unsigned long ion_carveout_allocate(struct ion_heap *heap,unsigned long size)
{struct ion_carveout_heap *carveout_heap = container_of(heap, struct ion_carveout_heap, heap);unsigned long offset = gen_pool_alloc(carveout_heap->pool, size);return offset;
}

gen_pool_alloc函数:

/*** gen_pool_alloc - allocate special memory from the pool* @pool: pool to allocate from* @size: number of bytes to allocate from the pool*/
unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
{return gen_pool_alloc_algo(pool, size, pool->algo, pool->data);
}
unsigned long gen_pool_alloc_algo(struct gen_pool *pool, size_t size,genpool_algo_t algo, void *data)
{struct gen_pool_chunk *chunk;unsigned long addr = 0;//1 page =4KB,即2^12B,order即是指数12,用log2X即是对数int order = pool->min_alloc_order;int nbits, start_bit, end_bit, remain;//(1UL << order) - 1低12位都是1//只要size低12位不为0,就会向高位进1,即如果size剩余内存有不满1page时当作1pagenbits = (size + (1UL << order) - 1) >> order;//遍历内存池的块链表list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {if (size > atomic_long_read(&chunk->avail))continue;start_bit = 0;end_bit = chunk_size(chunk) >> order;
retry://查找chunk位图中连续nbits都是0的开始下标,algo指向gen_pool_first_fit函数start_bit = algo(chunk->bits, end_bit, start_bit,nbits, data, pool);if (start_bit >= end_bit)continue;//将块中位图以start_bit为开始、大小为nbits的值都设置为1,表示已用过remain = bitmap_set_ll(chunk->bits, start_bit, nbits);//计算开始地址、大小addr = chunk->start_addr + ((unsigned long)start_bit << order);size = nbits << order;atomic_long_sub(size, &chunk->avail);break;}return addr;
}

相关内容

热门资讯

【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AsusVivobook无法开... 首先,我们可以尝试重置BIOS(Basic Input/Output System)来解决这个问题。...
ASM贪吃蛇游戏-解决错误的问... 要解决ASM贪吃蛇游戏中的错误问题,你可以按照以下步骤进行:首先,确定错误的具体表现和问题所在。在贪...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...