在driver/tee/optee/core.c中的optee_probe函数中会调用optee_config_shm_memremap 来配置secure world 和 normal world之间的共享内存
static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
{
union {
struct arm_smccc_res smccc;
struct optee_smc_get_shm_config_result result;
} res;
struct tee_shm_pool *pool;
unsigned long vaddr;
phys_addr_t paddr;
size_t size;
phys_addr_t begin;
phys_addr_t end;
void *va;
struct tee_shm_pool_mem_info priv_info;
struct tee_shm_pool_mem_info dmabuf_info;
invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
if (res.result.status != OPTEE_SMC_RETURN_OK) {
pr_info("shm service not available\n");
return ERR_PTR(-ENOENT);
}
if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
pr_err("only normal cached shared memory supported\n");
return ERR_PTR(-EINVAL);
}
begin = roundup(res.result.start, PAGE_SIZE);
end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
paddr = begin;
size = end - begin;
if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) {
pr_err("too small shared memory area\n");
return ERR_PTR(-EINVAL);
}
//得到共享内存的虚拟地址
va = memremap(paddr, size, MEMREMAP_WB);
if (!va) {
pr_err("shared memory ioremap failed\n");
return ERR_PTR(-EINVAL);
}
vaddr = (unsigned long)va;
//这里的共享内存分为两种,一种是priv_info,一个是dmabuf_info,分别给这两组共享内存赋值后,调用tee_shm_pool_alloc_res_mem
priv_info.vaddr = vaddr;
priv_info.paddr = paddr;
priv_info.size = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
dmabuf_info.vaddr = vaddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
dmabuf_info.paddr = paddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
pool = tee_shm_pool_alloc_res_mem(&priv_info, &dmabuf_info);
if (IS_ERR(pool)) {
memunmap(va);
goto out;
}
*memremaped_shm = va;
out:
return pool;
}
在tee_shm_pool_alloc_res_mem 中分别对priv_info和dmabuf_info 调用pool_res_mem_mgr_init
/*
* Create the pool for driver private shared memory
*/
ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info,
3 /* 8 byte aligned */);
if (ret)
goto err;
这里以对priv_info为例
static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr,
struct tee_shm_pool_mem_info *info,
int min_alloc_order)
{
size_t page_mask = PAGE_SIZE - 1;
struct gen_pool *genpool = NULL;
int rc;
/*
* Start and end must be page aligned
*/
//检查是否page size对其。可见share memory 是要按page size对齐的
if ((info->vaddr & page_mask) || (info->paddr & page_mask) ||
(info->size & page_mask))
return -EINVAL;
//通过gen_pool_create 申请一个struct gen_pool *genpool = NULL;其中gen_pool_create是kernel 提供的公共函数,其和tee 无关
genpool = gen_pool_create(min_alloc_order, -1);
if (!genpool)
return -ENOMEM;
//设置这个pool的algo函数,以后tee driver会从这个pool管理的memory中申请内存,这个algo就用于寻找空闲内存的算法,这里也可以知道gen pool是通过chunk 管理memory的,独立与伙伴系统和slab系统.
gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
//pool 只是管理chunk的,要调用gen_pool_add_virt 来将前面一定映射好的虚拟内存加到pool中
rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size,
-1);
if (rc) {
gen_pool_destroy(genpool);
return rc;
}
mgr->private_data = genpool;
mgr->ops = &pool_ops_generic;
return 0;
}
后面就会通过pool_ops_generic的alloc函数申请内存,通过pool_ops_generic的free函数申请内存。
static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm,
struct tee_shm *shm, size_t size)
{
unsigned long va;
这个private_date就是genpool结构,是在pool_res_mem_mgr_init 中赋值的mgr->private_data = genpool;
struct gen_pool *genpool = poolm->private_data;
size_t s = roundup(size, 1 << genpool->min_alloc_order);
//申请内存,返回的虚拟地址,因为我加到genpool的时候已经是虚拟地址了
va = gen_pool_alloc(genpool, s);
if (!va)
return -ENOMEM;
memset((void *)va, 0, s);
shm->kaddr = (void *)va;
//将虚拟地址转成物理地址
shm->paddr = gen_pool_virt_to_phys(genpool, va);
shm->size = s;
return 0;
}
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;
int order = pool->min_alloc_order;
int nbits, start_bit, end_bit, remain;
#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
BUG_ON(in_nmi());
#endif
if (size == 0)
return 0;
//将要申请的size 转成order来申请
nbits = (size + (1UL << order) - 1) >> order;
rcu_read_lock();
//遍历pool->chunks,
list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
if (size > atomic_read(&chunk->avail))
continue;
start_bit = 0;
end_bit = chunk_size(chunk) >> order;
retry:
//调用algo函数来寻找size 符合nbits的chunk,这里的algo函数为gen_pool_best_fit
start_bit = algo(chunk->bits, end_bit, start_bit,
nbits, data, pool);
if (start_bit >= end_bit)
continue;
remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
if (remain) {
remain = bitmap_clear_ll(chunk->bits, start_bit,
nbits - remain);
BUG_ON(remain);
goto retry;
}
//得到申请的地址
addr = chunk->start_addr + ((unsigned long)start_bit << order);
size = nbits << order;
atomic_sub(size, &chunk->avail);
break;
}
rcu_read_unlock();
return addr;
}
static struct tee_shm_pool *
optee_config_shm_memremap(optee_invoke_fn *invoke_fn, void **memremaped_shm)
{
union {
struct arm_smccc_res smccc;
struct optee_smc_get_shm_config_result result;
} res;
struct tee_shm_pool *pool;
unsigned long vaddr;
phys_addr_t paddr;
size_t size;
phys_addr_t begin;
phys_addr_t end;
void *va;
struct tee_shm_pool_mem_info priv_info;
struct tee_shm_pool_mem_info dmabuf_info;
invoke_fn(OPTEE_SMC_GET_SHM_CONFIG, 0, 0, 0, 0, 0, 0, 0, &res.smccc);
if (res.result.status != OPTEE_SMC_RETURN_OK) {
pr_info("shm service not available\n");
return ERR_PTR(-ENOENT);
}
if (res.result.settings != OPTEE_SMC_SHM_CACHED) {
pr_err("only normal cached shared memory supported\n");
return ERR_PTR(-EINVAL);
}
begin = roundup(res.result.start, PAGE_SIZE);
end = rounddown(res.result.start + res.result.size, PAGE_SIZE);
paddr = begin;
size = end - begin;
if (size < 2 * OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE) {
pr_err("too small shared memory area\n");
return ERR_PTR(-EINVAL);
}
//得到共享内存的虚拟地址
va = memremap(paddr, size, MEMREMAP_WB);
if (!va) {
pr_err("shared memory ioremap failed\n");
return ERR_PTR(-EINVAL);
}
vaddr = (unsigned long)va;
//这里的共享内存分为两种,一种是priv_info,一个是dmabuf_info,分别给这两组共享内存赋值后,调用tee_shm_pool_alloc_res_mem
priv_info.vaddr = vaddr;
priv_info.paddr = paddr;
priv_info.size = OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
dmabuf_info.vaddr = vaddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
dmabuf_info.paddr = paddr + OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
dmabuf_info.size = size - OPTEE_SHM_NUM_PRIV_PAGES * PAGE_SIZE;
pool = tee_shm_pool_alloc_res_mem(&priv_info, &dmabuf_info);
if (IS_ERR(pool)) {
memunmap(va);
goto out;
}
*memremaped_shm = va;
out:
return pool;
}
在tee_shm_pool_alloc_res_mem 中分别对priv_info和dmabuf_info 调用pool_res_mem_mgr_init
/*
* Create the pool for driver private shared memory
*/
ret = pool_res_mem_mgr_init(&pool->private_mgr, priv_info,
3 /* 8 byte aligned */);
if (ret)
goto err;
这里以对priv_info为例
static int pool_res_mem_mgr_init(struct tee_shm_pool_mgr *mgr,
struct tee_shm_pool_mem_info *info,
int min_alloc_order)
{
size_t page_mask = PAGE_SIZE - 1;
struct gen_pool *genpool = NULL;
int rc;
/*
* Start and end must be page aligned
*/
//检查是否page size对其。可见share memory 是要按page size对齐的
if ((info->vaddr & page_mask) || (info->paddr & page_mask) ||
(info->size & page_mask))
return -EINVAL;
//通过gen_pool_create 申请一个struct gen_pool *genpool = NULL;其中gen_pool_create是kernel 提供的公共函数,其和tee 无关
genpool = gen_pool_create(min_alloc_order, -1);
if (!genpool)
return -ENOMEM;
//设置这个pool的algo函数,以后tee driver会从这个pool管理的memory中申请内存,这个algo就用于寻找空闲内存的算法,这里也可以知道gen pool是通过chunk 管理memory的,独立与伙伴系统和slab系统.
gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
//pool 只是管理chunk的,要调用gen_pool_add_virt 来将前面一定映射好的虚拟内存加到pool中
rc = gen_pool_add_virt(genpool, info->vaddr, info->paddr, info->size,
-1);
if (rc) {
gen_pool_destroy(genpool);
return rc;
}
mgr->private_data = genpool;
mgr->ops = &pool_ops_generic;
return 0;
}
后面就会通过pool_ops_generic的alloc函数申请内存,通过pool_ops_generic的free函数申请内存。
static int pool_op_gen_alloc(struct tee_shm_pool_mgr *poolm,
struct tee_shm *shm, size_t size)
{
unsigned long va;
这个private_date就是genpool结构,是在pool_res_mem_mgr_init 中赋值的mgr->private_data = genpool;
struct gen_pool *genpool = poolm->private_data;
size_t s = roundup(size, 1 << genpool->min_alloc_order);
//申请内存,返回的虚拟地址,因为我加到genpool的时候已经是虚拟地址了
va = gen_pool_alloc(genpool, s);
if (!va)
return -ENOMEM;
memset((void *)va, 0, s);
shm->kaddr = (void *)va;
//将虚拟地址转成物理地址
shm->paddr = gen_pool_virt_to_phys(genpool, va);
shm->size = s;
return 0;
}
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;
int order = pool->min_alloc_order;
int nbits, start_bit, end_bit, remain;
#ifndef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
BUG_ON(in_nmi());
#endif
if (size == 0)
return 0;
//将要申请的size 转成order来申请
nbits = (size + (1UL << order) - 1) >> order;
rcu_read_lock();
//遍历pool->chunks,
list_for_each_entry_rcu(chunk, &pool->chunks, next_chunk) {
if (size > atomic_read(&chunk->avail))
continue;
start_bit = 0;
end_bit = chunk_size(chunk) >> order;
retry:
//调用algo函数来寻找size 符合nbits的chunk,这里的algo函数为gen_pool_best_fit
start_bit = algo(chunk->bits, end_bit, start_bit,
nbits, data, pool);
if (start_bit >= end_bit)
continue;
remain = bitmap_set_ll(chunk->bits, start_bit, nbits);
if (remain) {
remain = bitmap_clear_ll(chunk->bits, start_bit,
nbits - remain);
BUG_ON(remain);
goto retry;
}
//得到申请的地址
addr = chunk->start_addr + ((unsigned long)start_bit << order);
size = nbits << order;
atomic_sub(size, &chunk->avail);
break;
}
rcu_read_unlock();
return addr;
}