tee driver 对共享内存的管理

在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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值