binder pro驱动的编码实现:共享内存管理

一、初始化共享内存

/*
 *计算2的阶乘
 */
static uint cacu_two_factorial(uint n) {
	uint i = 0;
	uint result = 1;
	if (n == 0) return 1;
	if (n > 10) return HW_BINDER_ERROR;
	for (;i < n; i++) {
		result *= 2;
	}
	return result;
}
/*
 * 申请一片连续内存,将该内存作为共享内存,并且记录该块内存总体信息
 */
void init_binder_block(struct binder_buffer_info *buffer)
{
	struct page *pages;
	pages = alloc_pages(GFP_KERNEL,TWO_FACTORIAL_NUM);
	buffer->buffer_address = page_address(pages);
	buffer->pfn = page_to_pfn(pages);
	buffer->buffer_size = PAGE_SIZE * cacu_two_factorial();
	buffer->block_num = buffer->buffer_size / BINDER_BLOCK_SIZE;
	memset(buffer->buffer_address,0,buffer->buffer_size);
}

/*
 *计算每个区域的大小并且规划整个共享内存的使用
 */
void init_super_block(struct bind_super *super, struct binder_buffer_info *buffer_info)
{
	uint per_cpu_size_total; //per cpu占用内存的总大小。
	uint per_cpu_size;       //每个per cpu占用的内存大小
	uint rpc_node_size;      //每个rpc业务节点大小
	uint node_num_perblock;  //每个数据块存放业务节点的数量
	uint node_block_num;     //业务节点总数
	uint node_map_size;      //节点映射区域大小
	uint data_map_size;      //数据映射区域大小
	uint node_size;          //业务节点数据大小
	uint block_left;         //剩余没有规划的数据块


	spin_lock_init(&super->lock_node_map);
	spin_lock_init(&super->lock_data_map);
	super->binder_buffer_info = buffer_info;

	/* 计算per cpu区域的信息 */
	block_left = buffer_info->block_num;
	super->cpu_num = num_present_cpus();
	super->per_cpu_start = buffer_info->buffer_address;
	super->per_cpu_id = 0;
	per_cpu_size = sizeof(struct bind_percpu);
	per_cpu_size = ALIGN_PER32(per_cpu_size);
	super->per_cpu_size = per_cpu_size;
	per_cpu_size_total = per_cpu_size * super->cpu_num;
	per_cpu_size_total = ALIGN_BLOCKSIZE(per_cpu_size_total);
	super->per_cpu_size_total = per_cpu_size_total;
	block_left -= (per_cpu_size_total / BINDER_BLOCK_SIZE);

	/* 计算业务节点数据 */
	super->node_map_start = buffer_info->buffer_address + per_cpu_size_total;
	super->node_map_id = super->per_cpu_id + per_cpu_size_total/BINDER_BLOCK_SIZE;
	rpc_node_size = sizeof(struct rpc_node);
	rpc_node_size = ALIGN_PER32(rpc_node_size);
	super->per_node_size = rpc_node_size;
	node_num_perblock = BINDER_BLOCK_SIZE / rpc_node_size;
	/* 每个业务节点需要规划2个数据块,一个输入,一个输出 */
	node_block_num = block_left / (node_num_perblock * 2 + 1);
	node_size = node_block_num * rpc_node_size * node_num_perblock;
	super->node_num_total = node_block_num * node_num_perblock;
	block_left -= node_block_num;
	super->node_size_total =  node_size;
	
	/* 计算节点映射区域和数据映射区域的大小 */
	node_map_size = ALIGN_BLOCKSIZE((super->node_num_total + 7) / 8);
	super->node_map_size = node_map_size;
	super->data_map_id = super->node_map_id + node_map_size/BINDER_BLOCK_SIZE;
	super->data_map_start = buffer_info->buffer_address + super->data_map_id * BINDER_BLOCK_SIZE;
	block_left -= (node_map_size/BINDER_BLOCK_SIZE);
	data_map_size = ALIGN_BLOCKSIZE((block_left + 7) / 8);
	super->data_map_size = data_map_size;
	block_left -= (data_map_size/BINDER_BLOCK_SIZE);
	super->data_num_total =  block_left;

	/* 计算节点区域的起始id号和内核起始地址 */
	super->node_id = super->data_map_id + data_map_size/BINDER_BLOCK_SIZE;
	super->node_start = buffer_info->buffer_address + super->node_id * BINDER_BLOCK_SIZE;

	/* 计算数据区域的信息 */
	super->data_id = super->node_id + node_size / BINDER_BLOCK_SIZE;
	super->data_start =  buffer_info->buffer_address + super->data_id * BINDER_BLOCK_SIZE;
	super->data_size_total = super->data_num_total * BINDER_BLOCK_SIZE;


	super->data_num_left = super->data_num_total;
	super->node_num_left = super->node_num_total;

	return;
}

二、根据data节点和node的节点编号计算偏移和地址

uint node_offset_start(struct bind_super *super) {
    uint offset;
    offset = super->per_cpu_size_total + super->node_map_size + super->data_map_size;
    return offset;
}

uint data_offset_start(struct bind_super *super) {
    uint offset;
    offset = super->per_cpu_size_total + super->node_map_size + super->data_map_size + super->node_size_total;
    return offset;
}

uint caculate_offset_by_node_id(struct bind_super *super, uint idx){
    uint offset;
    offset = node_offset_start(super) + idx * super->per_node_size;
    return offset;
}

uint caculate_offset_by_data_id(struct bind_super *super,uint idx){
    uint offset;
    offset = data_offset_start(super) + idx * BINDER_BLOCK_SIZE;
    return offset;
}

void *caculate_node_address(struct bind_super *super, uint idx) {
    void *address;
    if (idx >= super->node_num_total) return NULL;
    if (idx == BIND_INVLIED_ID) return NULL;
    address = super->binder_buffer_info->buffer_address + caculate_offset_by_node_id(super,idx);
    return address;
}

void *caculate_data_address(struct bind_super *super, uint idx) {
    void *address;
    address = super->binder_buffer_info->buffer_address + caculate_offset_by_data_id(super,idx);
    return address;
}

三、位图操作,方便查找与之映射的节点和数据块

/* 判断bit_idx位是否为1,若为1则返回true,否则返回false */
bool bitmap_scan_test(unsigned char *bitmap, uint bit_size, uint bit_idx) {
    uint byte_idx = bit_idx / 8;    // 向下取整用于索引数组下标
    uint bit_odd  = bit_idx % 8;    // 取余用于索引数组内的位

	if (bit_idx >= bit_size) return false;
    return (bitmap[byte_idx] & (BITMAP_MASK << bit_odd));
}

uint bitmap_scan(unsigned char *bitmap, uint bit_size, uint32_t cnt) {
    uint bit_continue_size;
    uint bit_odd;
    uint start_bit;
	uint bit_idx;
    
    bit_odd = 8;    /* default value is 8, for the last byte set the real bit_odd */
    bit_continue_size = 0;

	for(bit_idx = 0; bit_idx < bit_size; bit_idx++) {
		if ((bitmap[bit_idx / 8] & (BITMAP_MASK << (bit_idx % 8))) == 0) {
			if (bit_continue_size == 0) {
				start_bit = bit_idx;
			}
			bit_continue_size++;
		} else {
			bit_continue_size = 0;
		}

		if (bit_continue_size == cnt) {
			return start_bit;
		}
	}

    return BIND_MAP_ERROR;
}

void bitmap_set_zero(unsigned char *bitmap, uint bit_idx) {
   uint32_t byte_idx = bit_idx / 8;    // 向下取整用于索引数组下标
   uint32_t bit_odd  = bit_idx % 8;    // 取余用于索引数组内的位

    bitmap[byte_idx] &= ~(BITMAP_MASK << bit_odd);
}

void bitmap_set_one(unsigned char *bitmap, uint bit_idx) {
   uint32_t byte_idx = bit_idx / 8;    // 向下取整用于索引数组下标
   uint32_t bit_odd  = bit_idx % 8;    // 取余用于索引数组内的位

   bitmap[byte_idx] |= (BITMAP_MASK << bit_odd);
}

uint bitmap_scan_set(unsigned char *bitmap, uint bit_size, uint32_t cnt, spinlock_t *lock , uint *bit_left) {
	unsigned long flags;
	uint i;
	uint idx;

	spin_lock_irqsave(lock, flags);	/* 上锁 */
	idx = bitmap_scan(bitmap, bit_size, cnt);
	if (idx == BIND_MAP_ERROR) {
		printk("binder map error\n");
		spin_unlock_irqrestore(lock, flags);/* 解锁 */
		return BIND_MAP_ERROR;
	}
	for (i = 0; i < cnt; i++) {
		bitmap_set_one(bitmap, idx + i);
	}
	*bit_left = *bit_left - cnt;
	spin_unlock_irqrestore(lock, flags);/* 解锁 */
	return idx;
}

void bitmap_set_zero_lock(unsigned char *bitmap, uint bit_idx, spinlock_t *lock, uint *bit_left) {
	unsigned long flags;

	spin_lock_irqsave(lock, flags);	/* 上锁 */
	bitmap_set_zero(bitmap, bit_idx);
	(*bit_left)++;
	spin_unlock_irqrestore(lock, flags);/* 解锁 */
}

四、共享内存的分配和释放

uint malloc_data(struct bind_super *super, uint cnt)
{
    uint bit_idx;
    if (cnt == 0) return 0;
	bit_idx = bitmap_scan_set((unsigned char *)super->data_map_start,super->data_num_total,cnt, &super->lock_data_map, &super->data_num_left);
    if (bit_idx == BIND_MAP_ERROR) {
        printk("not enough space \n");
        return BIND_MAP_ERROR;
    }
    return bit_idx;
}

uint malloc_data_bysize(struct bind_super *super, uint size) {
	uint size_align_block;
	uint bit_idx;

	size_align_block = ALIGN_BLOCKSIZE(size);
    if (size_align_block == 0) {
        return 0;
    }

	bit_idx = malloc_data(super, size_align_block / BINDER_BLOCK_SIZE);
    if (bit_idx == BIND_MAP_ERROR) {
        printk("not enough space \n");
        return BIND_MAP_ERROR;
    }
    return bit_idx;
}

struct rpc_node *bind_rpc_source_malloc(struct bind_super *super,struct client_server *client_req) {
	struct rpc_node *node;
	uint offset;
    uint bit_idx;

	bit_idx = bitmap_scan_set((unsigned char *)super->node_map_start,super->node_num_total,1, &super->lock_node_map, &super->node_num_left);
	if (bit_idx == BIND_MAP_ERROR) {
		printk("binder node out of buffer\n");
		return NULL;
	}
	//offset = super->per_cpu_size_total + super->node_map_size + super->data_map_size + bit_idx * super->per_node_size;
    offset = super->node_id * BINDER_BLOCK_SIZE + bit_idx * super->per_node_size;
	node = (struct rpc_node *)(super->binder_buffer_info->buffer_address + offset);
	node->node_id = bit_idx;
    printk("node idx = %d\n",node->node_id);

    bit_idx = malloc_data_bysize(super, client_req->input_size);
    if (bit_idx == BIND_MAP_ERROR) {
        printk("not enough space \n");
        bind_nodemap_free(super, node->node_id);
        return NULL;
    }
    node->input_data = bit_idx;
    node->input_data_size = client_req->input_size;
    printk("input idx = %d, node input idx = %d\n",bit_idx, node->input_data);


    bit_idx = malloc_data_bysize(super, client_req->output_size);
    if (bit_idx == BIND_MAP_ERROR) {
        printk("not enough space \n");
        bind_nodemap_free(super, node->node_id);
        bind_datamap_free_size(super, node->input_data, node->input_data_size);
        return NULL;
    }
    node->output_data = bit_idx;
    printk("output idx = %d, node output idx = %d\n",bit_idx, node->output_data);
    node->output_data_size = client_req->output_size;

	return node;
}


void bind_datamap_free(struct bind_super *super, uint map_idx, uint cnt)
{
    uint i;
    for (i = 0; i < cnt; i++) {
        bitmap_set_zero_lock((unsigned char *)super->data_map_start, map_idx + i, &super->lock_data_map, &super->data_num_left);
    }
}

void bind_datamap_free_size(struct bind_super *super, uint map_idx, uint size)
{
    uint cnt;
    cnt = ALIGN_BLOCKSIZE(size);
    cnt /= BINDER_BLOCK_SIZE;
    bind_datamap_free(super, map_idx, cnt);
}

void bind_nodemap_free(struct bind_super *super, uint map_idx)
{
    bitmap_set_zero_lock((unsigned char *)super->node_map_start, map_idx, &super->lock_node_map, &super->node_num_left);
}

void bind_node_free(struct bind_super *super, struct rpc_node *rpc_node)
{
    uint input_size;
    uint output_size;

    input_size = rpc_node->input_data_size;
    output_size = rpc_node->output_data_size;
    
    if (input_size != 0) {
        bind_datamap_free_size(super, rpc_node->input_data, input_size );
    }

    if (output_size != 0) {
        bind_datamap_free_size(super, rpc_node->output_data, output_size);
    }

    bind_nodemap_free(super, rpc_node->node_id);

}

void bind_node_chain_free(struct bind_super *super, struct rpc_node *rpc_node)
{
    struct rpc_node *node = rpc_node;
    uint next_node_id;
    while (node != NULL) {
        next_node_id = node->next_client_req;
        bind_node_free(super, node);
        node = (struct rpc_node *)caculate_node_address(super, next_node_id);
    }
}

void bind_node_free_id_chain(struct bind_super *super, uint node_id)
{
    struct rpc_node *rpc_node;

    rpc_node = (struct rpc_node *)caculate_node_address(super, node_id);
    bind_node_chain_free(super, rpc_node);
}

void bind_nodes_free(struct bind_super *super, struct rpc_node **rpc_node, uint cnt) {
    uint i;
    for(i = 0; i < cnt; cnt++) {
        bind_node_free(super, rpc_node[i]);
    }
}

总结:位图映射node节点区域和数据区域,通过管理相关的位图来管理相关的数据,达到共享内存有序管理的目的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
binder_open是Binder机制中的一个函数,用于打开Binder驱动并返回一个Binder状态结构体。在该函数中,会调用copy_from_user函数从用户空间获取一个struct binder_write_read结构体,并将其作为参数传递给binder_thread_write和binder_thread_read函数。\[1\] 在Binder机制的Native层实现中,binder_open函数被用于开启Binder,并将自身注册为Binder进程的上下文,然后通过调用binder_loop函数来启动Binder循环。\[2\] 在binder_loop函数中,如果收到了Binder的读写消息信息,会调用binder_parse函数进行处理。binder_parse函数会将读取到的消息进行解析,并调用相应的处理函数进行处理。\[3\] #### 引用[.reference_title] - *1* [05.Binder系统:第6课第2节_Binder系统_驱动情景分析_打印数据交互过](https://blog.csdn.net/weixin_43013761/article/details/88171380)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [【Binder 机制】Native 层 Binder 机制分析 ( binder_loop | svcmgr_handler | binder.c | binder_parse )](https://blog.csdn.net/han1202012/article/details/120345228)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值