> 文档中心 > OpenHarmony (1)

OpenHarmony (1)

HarmonyOS框架

  LiteOS,比较熟悉了,出来很久了,真正接触它是在Hi3559v200运动相机上,跑着LiteOS + Linux双系。在学习了解时,希望按照自己的风格来,于是边了解边结构。

  但毕竟没有全开源,所以对于底层的调度等都无法看到代码,只能望着libcortex-a7.a而惆怅。

  处于对系统调度算法及SMP的好奇,搜索到RT-Thread是全开源的,于是下载研究,并在HI3518EV300上边学边写。了解了后,原来是那么简单,有点类似单片机,开个定时器,到时间了就调度。虽说简单,但设计上要考虑的东西还是挺多了,由于时间原因,只学习到优先级调度,同级时间轮转调度,完成了几个测试任务的打印输出。

/*
 * Future Kernel Bootloader
 *
 * Copyright (c) 2020 FineClass
 *
 * LOC: main.c
 * */

#include
#include
#include

#define RTS_MAIN_THREAD_PRIORITY    (RTS_PRIORITY_MAX / 3)

/* the system main thread */
static void main_thread(void *param)
{
#ifdef RTS_USING_SMP
    rt_hw_secondary_cpu_up();
#endif
    while(1) {
        RTS_ThreadId tid = RTS_thread_self_id();
        kprint("MainThread(id: %u) run\n", tid);
        nop_delay(1000);
    }
}

static void test_thread(void *param)
{
    while(1) {
        RTS_ThreadId tid = RTS_thread_self_id();
        kprint("TestThread(id: %u) run\n", tid);
        nop_delay(1000);
    }
}

void boot_main(u32 base)
{    
    u32 ret = 0;
    RTS_ThreadId mainTid = RTS_THREAD_ID_INVAILD;

    RTS_hw_interrupt_disable();

    kprint("Fukeboot v%u.%u.%u (Build %s %s)\n",
            MAJOR, MINOR, PATCH, __DATE__, __TIME__);
    
    RTS_init(base, DDR_BASE + DDR_SIZE - base);

    // create app_thread
    ret = RTS_thread_create(&mainTid, "MainThread", main_thread,
                            NULL, RTS_MAIN_THREAD_PRIORITY);
    if(ret != RTS_RESULT_OK) {
        kprint("create MainThread err(0x%08X)\n", ret);
    } else {
        kprint("create MainThread (id: %u) OK\n", mainTid);
    }

    // create test_thread
    ret = RTS_thread_create(&mainTid, "TestThread", test_thread,
                            NULL, RTS_MAIN_THREAD_PRIORITY);
    if(ret != RTS_RESULT_OK) {
        kprint("create TestThread err(0x%08X)\n", ret);
    } else {
        kprint("create TestThread (id: %u) OK\n", mainTid);
    }

    // then start
    RTS_run();
    
    /* if ok, never reach here */
    kprint(" ERROR RESET the board \n");
    nop_delay(1000);
    board_reset_cpu();
    
    /* never reach here */
    while(1);
}

/*
 * Future Kernel Bootloader
 *
 * Copyright (c) 2020 FineClass
 *
 * LOC: rts/rts_sched.c
 * */

#include "rts_sched.h"

#include

RTS_Thread *gCurrentThread;

static u32 threadTick;

static RTS_List priorityTable[RTS_PRIORITY_MAX];
static u32 readyPriorityGroup;
/* Maximum priority level, 256 */
static u8 readyTable[32];
static RTS_List defunct;

#if 0//def RTS_USING_SMP

RTS_Thread* RTS_thread_self(void)
{
    rt_base_t lock;
    rt_thread_t self;

    lock = rt_hw_local_irq_disable();
    self = rt_cpu_self()->current_thread;
    rt_hw_local_irq_enable(lock);
    return self;
}

#else

static s16 schedLockNest;
static u8 currentPriority;

RTS_Thread* RTS_thread_self(void)
{
    return gCurrentThread;
}

static RTS_Thread* get_highest_priority_thread(u8 *highestPrio)
{
    register RTS_Thread *highestPriorityThread;
    register u8 highestReadyPriority;
    register u8 number;

    number = RTS_ffs(readyPriorityGroup) - 1;
    highestReadyPriority = (number << 3) + RTS_ffs(readyTable[number]) - 1;

    /* get highest ready priority thread */
    highestPriorityThread = RTS_LIST_ENTRY(priorityTable[highestReadyPriority].next,
                                              RTS_Thread, list);

    *highestPrio = highestReadyPriority;

    return highestPriorityThread;
}

void RTS_schedule_insert_thread(RTS_Thread *thread)
{
    register u32 temp;

    if(!thread) {
        return;
    }

    /* disable interrupt */
    temp = RTS_hw_interrupt_disable();

    /* it's current thread, it should be RUNNING thread */
    if(thread == gCurrentThread) {
        thread->stat = RTS_THREAD_RUNNING | (thread->stat & ~RTS_THREAD_STAT_MASK);
    } else {
        /* READY thread, insert to ready queue */
        thread->stat = RTS_THREAD_READY | (thread->stat & ~RTS_THREAD_STAT_MASK);
        /* insert thread to ready list */
        RTS_list_tail_insert(&(priorityTable[thread->curPriority]), &(thread->list));

#if 0
        kprint(RTS_PREFIX"insert thread[%.*s], the priority: %d\n",
                RTS_NAME_MAX, thread->name, thread->curPriority);
#endif
        /* set priority mask */
        readyTable[thread->number] |= thread->highMask;
        readyPriorityGroup |= thread->numberMask;
    }
    
    /* enable interrupt */
    RTS_hw_interrupt_enable(temp);
}

void RTS_schedule_remove_thread(RTS_Thread *thread)
{
    register u32 level;

       if(!thread) {
        return;
    }

    /* disable interrupt */
    level = RTS_hw_interrupt_disable();

#if 0
    kprint(RTS_PREFIX"remove thread[%.*s], the priority: %d\n",
            RTS_NAME_MAX, thread->name, thread->curPriority);
#endif

    /* remove thread from ready list */
    RTS_list_delete(&(thread->list));
    if(RTS_list_empty(&(priorityTable[thread->curPriority]))) {
        readyTable[thread->number] &= ~thread->highMask;
        if(!readyTable[thread->number]) {
            readyPriorityGroup &= ~thread->numberMask;
        }
    }

    /* enable interrupt */
    RTS_hw_interrupt_enable(level);
}

/
 * This function will perform one schedule. It will select one thread
 * with the highest priority level, then switch to it.
 */
void RTS_schedule(void)
{
    u32 level;
    RTS_Thread *toThread;
    RTS_Thread *fromThread;
    u8 highestReadyPriority;
    /* need_insert_from_thread: need to insert from_thread to ready queue */
    int needInsertFromThread = 0;

    /* disable interrupt */
    level = RTS_hw_interrupt_disable();

    /* check the scheduler is enabled or not */
    if(!schedLockNest && readyPriorityGroup) {
        toThread = get_highest_priority_thread(&highestReadyPriority);
        if((gCurrentThread->stat & RTS_THREAD_STAT_MASK) == RTS_THREAD_RUNNING) {
            if(gCurrentThread->curPriority < highestReadyPriority) {
                toThread = gCurrentThread;
            }
            else if(gCurrentThread->curPriority == highestReadyPriority
                    && (gCurrentThread->stat & RTS_THREAD_STAT_YIELD_MASK) == 0) {
                toThread = gCurrentThread;
            }
            else {
                gCurrentThread->stat &= ~RTS_THREAD_STAT_YIELD_MASK;
                needInsertFromThread = 1;
            }
        }

        if(toThread != gCurrentThread) {
            /* if the destination thread is not the same as current thread */
            currentPriority = (u8)highestReadyPriority;
            fromThread = gCurrentThread;
            gCurrentThread = toThread;
            //RT_OBJECT_HOOK_CALL(rt_scheduler_hook, (fromThread, toThread));
            if(needInsertFromThread) {
                RTS_schedule_insert_thread(fromThread);
            }

            RTS_schedule_remove_thread(toThread);
            toThread->stat = RTS_THREAD_RUNNING | (toThread->stat & ~RTS_THREAD_STAT_MASK);

            /* switch to new thread */
#if 0
            kprint(RTS_PREFIX"[%d]switch to priority#%d "
                     "thread:%.*s(sp:0x%08x), from thread:%.*s(sp: 0x%08x)\n",
                     gInterruptNest, highestReadyPriority,
                     RTS_NAME_MAX, toThread->name, toThread->sp,
                     RTS_NAME_MAX, fromThread->name, fromThread->sp);
#endif

#ifdef RT_USING_OVERFLOW_CHECK
            _rt_scheduler_stack_check(to_thread);
#endif

            if(!gInterruptNest) {
                RTS_hw_context_switch((u32)&fromThread->sp, (u32)&toThread->sp);

                /* enable interrupt */
                RTS_hw_interrupt_enable(level);

#ifdef RT_USING_SIGNALS
                /* check stat of thread for signal */
                level = rt_hw_interrupt_disable();
                if(gCurrentThread->stat & RTS_THREAD_STAT_SIGNAL_PENDING) {
                    gCurrentThread->stat &= ~RTS_THREAD_STAT_SIGNAL_PENDING;

                    RTS_hw_interrupt_enable(level);

                    /* check signal status */
                    rt_thread_handle_sig(RT_TRUE);
                }
                else {
                    RTS_hw_interrupt_enable(level);
                }
#endif
                return ;
            }
#if 0
            kprint(RTS_PREFIX"switch in interrupt\n");
#endif
            RTS_hw_context_switch_interrupt((u32)&fromThread->sp, (u32)&toThread->sp);
        }
        else {
            RTS_schedule_remove_thread(gCurrentThread);
            gCurrentThread->stat = RTS_THREAD_RUNNING | (gCurrentThread->stat & ~RTS_THREAD_STAT_MASK);
        }
    }

    /* enable interrupt */
    RTS_hw_interrupt_enable(level);
}

#endif /* RTS_USING_SMP */

void RTS_scheduler_init(void)
{
    u32 i = 0;

    threadTick = 0;
    
    for(i=0; i<RTS_PRIORITY_MAX; i++) {
        RTS_list_init(&priorityTable[i]);
    }

    /* initialize ready priority group */
    readyPriorityGroup = 0;

    /* initialize ready table */
    memset(readyTable, 0, sizeof(readyTable));

    /* initialize thread defunct */
    RTS_list_init(&defunct);
}

void RTS_scheduler_start(void)
{
    register RTS_Thread *toThread;
    u8 highestReadyPriority;

    toThread = get_highest_priority_thread(&highestReadyPriority);

#if 0//def RTS_USING_SMP
    toThread->oncpu = rt_hw_cpu_id();
#else
    gCurrentThread = toThread;
#endif /*RT_USING_SMP*/

    RTS_schedule_remove_thread(toThread);
    toThread->stat = RTS_THREAD_RUNNING;

    board_timer_start();

    /* switch to new thread */
#if 0//def RTS_USING_SMP
    RTS_hw_context_switch_to((u32)&toThread->sp, toThread);
#else
    RTS_hw_context_switch_to((u32)&toThread->sp);
#endif /*RT_USING_SMP*/

    /* never come back */
}

/* -------------------------------------------------------- */
/* time slice schedule */

void RTS_sched_timer_handler(u32 irq, void *param)
{
    /* increase the tick */
    ++threadTick;

    --gCurrentThread->remainingTick;
#if 0
    kprint("[%5u] %s tick %u / %u\n", threadTick,
            gCurrentThread->name,
            gCurrentThread->remainingTick,
            gCurrentThread->initTick);
#endif
    if(0 == gCurrentThread->remainingTick) {
        gCurrentThread->remainingTick = gCurrentThread->initTick;
        gCurrentThread->stat |= RTS_THREAD_STAT_YIELD;
        /* yield */
        RTS_thread_yield();
    }

    /* check soft timer */
    //RTS_timer_check();
}

 

这次开源了OpenHarmonyOS,以LiteOS为基础,看了下,相对来说是全开源了。

在 harmonyos/kernel/liteos_a/arch/arm/arm/src下,可以看到los_exc.c los_dispatch.S los_hw_runstop.S等文件了。

  之前,由于设定好了,就连运行地址都只能设定在libcortex-a7.a的0x80200000上,一修改就无法运行。

这次,可以好好看看这些实现了。

大致回顾下,

vectors 中断向量表

reset

  设置cortex-a资源

  设置CPU资源

  调用osMain

osMain

  初始化系统资源

  准备系统运行环境

  创建IDLE

  创建APP任务

  调度运行