OpenHarmony (1)
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任务
调度运行