一、初始化共享内存
/*
*计算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节点区域和数据区域,通过管理相关的位图来管理相关的数据,达到共享内存有序管理的目的。