Thread management optee-kernel 、Linux kernel 欣赏

好,看我解决这个大bug! 


 91 # Number of threads
 92 CFG_NUM_THREADS ?= 2

这次要放大招了 !

bug实在是影响情绪,TMD!

/*
    Thread的状态切换(Free->Active). 

    从threads[CFG_NUM_THREADS] 数组中获取一个thread,
    更改该Thread 的状态,设定入口函数,
    然后调用 thread_resume() ,该Thread 就跑起来了

    它的领导梯队
    LOCAL_FUNC vector_std_smc_entry
        bl     thread_handle_std_smc    std smc的处理者

    thread_handle_std_smc(...)
    {
        ...
        else
            thread_alloc_and_run(args);
    }

    一个很重要的概念是  一个核上同时只会有一个Thread在运行
    且该Thread独占该CPU核,除非该Thread 自己主动挂起、intr从normal world 过来
*/
static void thread_alloc_and_run(struct thread_smc_args *args)
{

     /* 
        threads[]的下标 
     */    
     size_t n;

     /*
        获取CPU核的信息, 这这个函数引起的的信息量好大! 
        好,扒开看看
     */
     struct thread_core_local *l = thread_get_core_local();
     {
        uint32_t cpu_id = get_core_pos(); // cpu编号
        /* 
           你必须关闭外部中断,这里用到的是 must be .
            
           如果中断环境被enable了, 这里assert 就会明显的提示你, 
           那么 什么操作会导致 该intr被enable了呢 ?
           thread suspend 、resume ? Rpc ?
           知否? 知否 ? Bug 依旧!  
        */
        assert(thread_get_exceptions() & THREAD_EXCP_FOREIGN_INTR);
        
        /*
            不能大于cpu核心数.
        */
	    assert(cpu_id < CFG_TEE_CORE_NB_CORE);
        /*
            返回该cpu核的信息吧.
        */
	    return &thread_core_local[cpu_id];
     }
     /* Threads[] 数组中有没有Free的Thread */
     bool found_thread = false;
    
     /*
		当前cpu核上运行的线程ID 设置为 -1 
		表示当前cpu核上没有线程在运行

        这个curr_thread 以后会变不断的++ -- =-1之间变换
        其实质就是Thread在 Free Active resume suspend之间的切换
	 */
	 assert(l->curr_thread == -1);

     /*
        spinlock.
      */
     lock_global();

    /*
        找吧,不用担心??比例失调而找不到. 嘿嘿?
    */
    for (n = 0; n < CFG_NUM_THREADS; n++) {
		if (threads[n].state == THREAD_STATE_FREE) {
			threads[n].state = THREAD_STATE_ACTIVE;
			found_thread = true;
			break;
		}
	}

    /*
        unspinlock.
    */
    unlock_global();

    /*
        防止找不到. 找不到,你就return走人吧.
    */
    if (!found_thread) {
		args->a0 = OPTEE_SMC_RETURN_ETHREAD_LIMIT;
		return;
	}

    /*
        找到了那个Thread, 赋值给Thread ID
    */
    l->curr_thread = n;

    /*
        清空flags
        这个flags 在thread_resume_rpc()中 会有分支处理,
        这里是初始状态.
    */
    threads[n].flags = 0;
    /*
        该函数中有下面一条语句, 设置入口地址
        在下面thread_resume() 该Thread run起来之后,就会从这个函数开始执行

        该函数正是来处理std smc的,看清,不是fast smc,fast smc有在系统启动阶段被调用
        thread->regs.pc = (uint32_t)thread_std_smc_entry;

        当然了,该函数还有寄存器的赋值,在这里不一一列举,与本bug无关.
     */
	init_regs(threads + n, args);

    /*
        最近在研究中....
    */
    threads[n].hyp_clnt_id = args->a7;

    /*
        runing 吧,像鸟儿一样的自由
    */
    thread_resume(&threads[n].regs);
}
void tee_ta_put_session(struct tee_ta_session *s)
{
    /*
        它是一把锁,是吧,Linux中的锁实质是系统调用,好我们看看
        他们之间有什么区别
    */
    mutex_lock(&tee_ta_mutex);
    {
        /*
            忽略 %rsi %rdi, 关注%rdi.
        */
        __mutex_lock(m, fname, lineno);
        {
            assert_have_no_spinlock();
            {
                assert(!have_spinlock());
                {
                    bool have_spinlock(void)
                    {
                        /*
                            表示cpu core 的信息
                        */
	                    struct thread_core_local *l;

                        /*
                            判断外部中断是否被屏蔽
                            foreign intr 必须disabled, 否则会切换到另外一个cpu core上
                        */
	                    if (!thread_foreign_intr_disabled()) {
		
		                    return false;
	                    }
                        /*
                            返回thread_core_local[]中的元素
                            该数组是cpu core 共享的,
                        */
	                    l = thread_get_core_local();
                        {
                            // 获取 cpu id
                            uint32_t cpu_id = get_core_pos();
                            // foreign intr 是否disableld
                            assert(thread_get_exceptions() & THREAD_EXCP_FOREIGN_INTR);
                            // cpu core的数量
                            assert(cpu_id < CFG_TEE_CORE_NB_CORE)
                            // 返回其中的一个 cpu croe
                            return &thread_core_local[cpu_id];
                        }
                        /*
                            返回持有的自旋锁的数量
                            看互斥锁实现的第一步就是检查cpu core持有的 spinlock的数量
                            一山不容二虎,想使用mutex 必须放弃spinlock.
                        */
                        return !!l->locked_count;
                    }

                }
            }
        }
        assert(thread_get_id_may_fail() != -1);
        {
            /*
                 register  rflags  屏蔽intr
                 为什么要屏蔽intr,你看下面一句是谁来了 ?
            */
            uint32_t exceptions = thread_mask_exceptions(THREAD_EXCP_FOREIGN_INTR);
            // 获取cpu core
            struct thread_core_local *l = thread_get_core_local();
            /* 
                cpu core上运行的Thread ID
                不说了,被这个Thread Id 坑惨了 , 捂脸大哭 ??
            */
            int ct = l->curr_thread;
            // enable intr
            thread_unmask_exceptions(exceptions);
            /*
                 返回吧. 
                 那么这个函数的意思就直白的写在纸上了,
                 cpu core上不能没有Thread 先运行 .

                 所以: 到了这里 
                    1 : 不允许你持有spinlock
                    2 :不允许所有的Thread suspend 或 Free.    
                 好吧 你要什么 我满足你. 看下面的log A-1
            */
            return ct;
        }
        /*
              这里涉及到了线程的模式了,好,下面详细说
        */
        assert(thread_is_in_normal_mode());
        {
            /*
                cpsr & (000011111) arm的模式位 != 10011
                判断cpu 是否是处于 SVC模式 .
                Linux Kernel 中发生中断的时候,ARM首先切换到的是SVC模式然后瞬间
                过渡到 IRQ模式,
                这里来判断ARM是否处于SVC模式,难道用内嵌汇编不好吗?! 不能省几行
                指令吗?! 省去几行指令不就是加快了速度了吗?!
            */
            return (read_cpsr() & ARM32_CPSR_MODE_MASK) == ARM32_CPSR_MODE_SVC;
        }

        mutex_lock_check(m);
        {
            // 获取CPU id.
            int thread = thread_get_id();
            uint32_t exceptions = 0;
            /*
                1 : 屏蔽外部中断
                2 : 将cpu core维护的spinlock 数量增加1
                3 : spinlock的数量必须是非0, 否则 panic()
            */
            exceptions = cpu_spin_lock_xsave(&graph_lock);
            /*
                 在研究. 与本Bug 无关,暂先略去.
            */
	        lockdep_lock_acquire(&graph, &owned[thread], (uintptr_t)m);
            /*
                !同理
            */
	        cpu_spin_unlock_xrestore(&graph_lock, exceptions);
        }

        /*
            deadloop 来也!
        */
        while (true) {
            /*
                该cpu core上维护的spinlock的数量.
            */
            uint32_t old_itr_status;
            /*
                传入的参数.
                -1: write, 0: unlocked, > 0: readers 
            */
            bool can_lock;
            /*
                等待队列项.
            */
            struct wait_queue_elem wqe;
        }
    }
}
这是在 mutex_lock()前加上了 cpu_spin_lock_xsave()函数.

D/TC:? 0 tee_ta_init_session_with_context:483 Re-open TA d96a5b40-c3e5-21e3-8794-1002a5d5c61b
*D/TC:? 1 create_ta:364 create entry point for pseudo TA "invoke_tests.pta"
D/TC:? 0 open_session:377 open entry point for pseudo ta "invoke_tests.pta"
*D/TC:? 1 open_session:377 open entry point for pseudo ta "invoke_tests.pta"
E/TC:1 0 assertion '!have_spinlock()' failed at core/arch/arm/include/kernel/spinlock.h:25 <assert_have_no_spinlock>
E/TC:1 0 Panic at core/kernel/assert.c:28 <_assert_break>

D/TC:? 1 tee_ta_init_pseudo_ta_session:280 Lookup pseudo TA d96a5b40-c3e5-21e3-8794-1002a5d5c61b
D/TC:? 1 tee_ta_init_pseudo_ta_session:293 Open invoke_tests.pta
D/TC:? 1 tee_ta_init_pseudo_ta_session:307 invoke_tests.pta : d96a5b40-c3e5-21e3-8794-1002a5d5c61b
D/TC:? 1 create_ta:364 create entry point for pseudo TA "invoke_tests.pta"
D/TC:? 1 open_session:377 open entry point for pseudo ta "invoke_tests.pta"
E/TC:1 1 assertion 'threads[ct].state == THREAD_STATE_ACTIVE' failed at core/arch/arm/kernel/thread.c:777 <thread_state_suspend>
E/TC:1 1 Panic at core/kernel/assert.c:28 <_assert_break>
E/TC:1 1 Call stack:
E/TC:1 1  0x0e119041

好,现在来看2个thread 在一个 cpu core上是怎么执行的,会发生什么错误, 该如何解决

猜你喜欢

转载自blog.csdn.net/leesagacious/article/details/88357630