# XiUOS 启动流程

XiUOS 启动

因为要编写一个启动的方法,所以需要熟知XiUOS从最开始到运行起来的所有流程

Linux 启动

先复习一下最经典的非实时系统的启动方式

https://www.runoob.com/linux/linux-system-boot.html

XiUOS 启动

XiUOS的boot在arch目录下,以cortex-m3-emulator为例

arch/arm/cortex-m3/

从Makefile可以看到,如果是定义的 BOARD_CORTEX_M3_EVB

那么就会启动 boot.c interrupt_vector_evb.S

否则就是启动 boot.S intterupt_vector_nano.S

boot.c

arch/arm/cortex-m3/boot.c

extern unsigned long _sidata;
extern unsigned long _sdata;
extern unsigned long _edata;
extern unsigned long _sbss;
extern unsigned long _ebss;
extern int entry(void);

void
Reset_Handler(void)
{
    unsigned long *pulSrc, *pulDest;

    //
    // Copy the data segment initializers from flash to SRAM.
    //
    pulSrc = &_sidata;
    for(pulDest = &_sdata; pulDest < &_edata; )
    {
        *pulDest++ = *pulSrc++;
    }

    //
    // Zero fill the bss segment.
    //
    __asm("    ldr     r0, =_sbss\n"
          "    ldr     r1, =_ebss\n"
          "    mov     r2, #0\n"
          "    .thumb_func\n"
          "zero_loop:\n"
          "        cmp     r0, r1\n"
          "        it      lt\n"
          "        strlt   r2, [r0], #4\n"
          "        blt     zero_loop");

    //
    // Call the application's entry point.
    //
    entry();
}

首先将 _sdata 到 _edata 中的内容都拷贝到了 _sidata 开始的内存中

然后执行了一段汇编

ldr R0, =_sbss	// [R0] = _sbss
ldr R1, =_ebss	// [R1] = _ebss
mov R2, #0		// [R2]	= 0
.thumb_func
zero_loop:
	cmp	r0, r1
    itlt		// if [R0] < [R1]
    strlt r2, [r0], #4	// *[R0] = r2, [R0] = [R0] + 4
    blt zero_loop	// while([R0] < [R1])

将sbss到ebss中的部分清零

最后执行entry()函数

init.c

kernel/thread/init.c

其include列表

#include <xiuos.h>
#include <xs_assign.h>
#include <xs_init.h>
#include <xs_spinlock.h>
#include <xs_workqueue.h>
#include <stdlib.h>
#include <board.h>

entry()

/* system entry */
int entry(void)
{
	DISABLE_INTERRUPT();

	/* system irq table must be inited before initialization of Hardware irq  */
	SysInitIsrManager();

    InitBoardHardware();
    XiUOSStartup();
    return 0;
}

DISABLE_INTERRUPT 在 xs_isr.h 定义成了 DisableLocalInterrupt,也给出了函数的声明,但是没有定义,DisableLocalInterrupt() 来自 /arch/arm/cortex-m3/interrupt.c 中

SysInitIsrManager() 定义在 thread/isr.c 中

InitBoardHardware() 定义在 board 目录下的 board.c

XiUOSStartup() 定义在 kernel/thread/init.c 中

DISABLE_INTERRUPT()

这个与处理器架构有关,放在了arch目录下,在cortex-m3中,对应的代码如下:

x_base __attribute__((naked)) DisableLocalInterrupt()
{
    asm volatile ("MRS     r0, PRIMASK");
    asm volatile ("CPSID   I");
    asm volatile ("BX      LR ");
}

其中 asm volatile 的 asm 表示内嵌汇编,volatile表示不进行编译优化

所以这里的arm汇编写的代码的意义就是

将 PRIMASK 的值存入 R0 中

然后 给 PRIMASK 赋值0,这样就达成了屏蔽中断的目的,然后跳转到调用前的代码位置。

同样的可以看到 EnableLocalInterrupt()中的代码

void __attribute__((naked)) EnableLocalInterrupt(x_base level)
{
    asm volatile ("MSR     PRIMASK, r0");
    asm volatile ("BX      LR");
}

就是将刚刚保存在 R0 中 的 PRIMASK 放回,然后函数返回

isr.c

SysInitIsrManager()

void SysInitIsrManager()
{
    extern int __isrtbl_idx_start;
    extern int __isrtbl_start;
    extern int __isrtbl_end;
    memset(&isrManager,0,sizeof(struct InterruptServiceRoutines));
    isrManager.done = &isrDone;

    uint32 *index = (uint32 *)&__isrtbl_idx_start;
    struct IrqDesc *desc = (struct IrqDesc *)&__isrtbl_start;

    while (desc != (struct IrqDesc *)&__isrtbl_end)
        isrManager.irq_table[*index++] = *desc++;
}

将 isrManager 清空之后,根据记录的 __isrtbl_start 和 __isrtbl_idx_start 将start开始的irq表格放入isrManager.irq_table 的对应下标中,同时这个 start 和 idx_start 也跟着增加到末尾

board.c

board/cortex-m3-emulator/board.c

InitBoardHardware()

void InitBoardHardware()
{
	extern int InitHwUart(void);
	InitHwUart();
	InstallConsole(SERIAL_BUS_NAME_1, SERIAL_DRV_NAME_1, SERIAL_DEVICE_NAME_1);
	InitBoardMemory((void*)LM3S_SRAM_START, (void*)LM3S_SRAM_END);

}

InitHwUart() 定义在 board/cortex-m3-emulator/connect_uart.c 中,初始化了UART

InstallConsole() 定义在 thread/console.c 中 这里的console应该不是控制台的意思,更像一个接口

InitBoardMemory() 定义在 memory/byte_manage.c 中

输入的两个参数来自board.h

#define MEM_OFFSET  0x20002000 
#define LM3S_SRAM_START         ( ( ((unsigned long)(&__bss_end)) > MEM_OFFSET)? (unsigned long)(&__bss_end):(MEM_OFFSET)  )
#define LM3S_SRAM_END          ( &_heap_end )

byte_manage.c

InitBoardMemory()

void InitBoardMemory(void *start_phy_address, void *end_phy_address)
{
	register x_size_t offset = 0;

	NULL_PARAM_CHECK(start_phy_address);
	NULL_PARAM_CHECK(end_phy_address);

	KDEBUG_NOT_IN_INTERRUPT;
	struct DynamicBuddyMemory *mheap = &ByteManager.dynamic_buddy_manager;

	/* align begin and end addr to page */
	ByteManager.dynamic_buddy_manager.dynamic_buddy_start = ALIGN_MEN_UP((x_ubase)start_phy_address, MM_PAGE_SIZE);
	ByteManager.dynamic_buddy_manager.dynamic_buddy_end   = ALIGN_MEN_DOWN((x_ubase)end_phy_address, MM_PAGE_SIZE);
    KPrintf("%s: 0x%x-0x%x \n",__func__,ByteManager.dynamic_buddy_manager.dynamic_buddy_start,ByteManager.dynamic_buddy_manager.dynamic_buddy_end);

    /* parameter detection */
	if (ByteManager.dynamic_buddy_manager.dynamic_buddy_start >= ByteManager.dynamic_buddy_manager.dynamic_buddy_end) {
		KPrintf("InitBoardMemory, wrong address[0x%x - 0x%x]\n",
				(x_ubase)start_phy_address, (x_ubase)end_phy_address);
		return;
	}

    mheap->mm_total_size = 0;
	memset(mheap->mm_freenode_list, 0, SIZEOF_XSFREENODE_MEM * MEM_LINKNRS);

	/* initialize the freeNodeList */
	for (offset = 1; offset < MEM_LINKNRS; offset++) {
		mheap->mm_freenode_list[offset - 1].next = &mheap->mm_freenode_list[offset];
		mheap->mm_freenode_list[offset].prev	 = &mheap->mm_freenode_list[offset - 1];
	}

	ByteManager.dynamic_buddy_manager.done = &DynamicDone;
	ByteManager.static_manager[MM_SEGMENT_32B].done = &StaticDone;
	ByteManager.static_manager[MM_SEGMENT_64B].done = &StaticDone;
	ByteManager.done = &NodeDone;


    /* dynamic buddy memory initialization */
	ByteManager.dynamic_buddy_manager.done->init(&ByteManager.dynamic_buddy_manager, ByteManager.dynamic_buddy_manager.dynamic_buddy_start, ByteManager.dynamic_buddy_manager.dynamic_buddy_end - ByteManager.dynamic_buddy_manager.dynamic_buddy_start);

    /* dynamic static segments initialization */
#ifdef KERNEL_SMALL_MEM_ALLOC
	ByteManager.static_manager->done->init(&ByteManager);
#endif
}

把输入的参数的值赋值给 dynamic_buddy_manager 的 start 和 end , 初始化了 freenode 的列表

init.c

XiUOSStartup()

int XiUOSStartup(void)
{
	DISABLE_INTERRUPT();

#ifdef KERNEL_QUEUEMANAGE
	QueuemanagerDoneRegister();
#endif

#ifdef KERNEL_BANNER
    ShowBanner();
#endif

    SysInitOsAssign();

    CreateKServiceKTask();

#ifdef KERNEL_COMPONENTS_INIT
	CreateEnvInitTask();
#else
 
#ifdef TOOL_SHELL
    extern int userShellInit(void);
	userShellInit();
#endif

#ifdef USER_APPLICATION
extern void CreateMainTask(void);
#ifdef SEPARATE_COMPILE
extern int InitUserspace(void);

	if(InitUserspace() == EOK) {
		CreateMainTask();
	}	
#else
	CreateMainTask();
#endif
#endif

#endif

#ifdef ARCH_SMP
	HwLockSpinlock(&AssignSpinLock);
#endif

    StartupOsAssign();
	
    return 0;
}

先暂时不看ifdef中相关的函数,我们可以得到下面的函数为运行流程

SysInitOsAssign() 定义在 kernel/thread/assign.c 中

CreateKServiceKTask() 定义在 kernel/thread/kservicetask.c 中

InitUserspace() 定义在 kernel/thread/appstart.c 中

CreateMainTask() 定义在 kernel/thread/appstart.c 中

StartupOsAssign() 定义在 kernel/thread/assign.c 中

assign.c

SysInitOsAssign()

/**
 *
 * system OsAssign init function
 */
void SysInitOsAssign(void)
{
    SYS_KDEBUG_LOG(KDBG_SCHED, ("start Os Assign: max priority 0x%02x\n",
                                      KTASK_PRIORITY_MAX));

    Assign.ready_vector_done = &SingleReadyVectorDone;
    Assign.ready_vector_done->init(&Assign.os_assign_read_vector); //[这里Ready写成了Read]

    ResetCriticalAreaLock();
}

先注册了Assign.ready_vector_done 的回调函数为 SingleReadyVectorDone

执行了Assign.ready_vector_done 的回调函数

其中这个回调函数也定义在 assign.c 中

SingleReadyVectorDone
static struct PriorityReadyVectorDone SingleReadyVectorDone =
{
    OsAssignReadyVectorInit,
    KTaskInsertToReadyVector,
    KTaskOsAssignRemoveKTask,
};

其中我们调用的Init函数来自 kernel/thread/assignstat.c

OsAssignReadyVectorInit
void OsAssignReadyVectorInit(struct OsAssignReadyVector *ready_vector)
{
    register x_base prio = 0;
    NULL_PARAM_CHECK(ready_vector);

    while(prio < KTASK_PRIORITY_MAX)
    {
        InitDoubleLinkList(&ready_vector->priority_ready_vector[prio]);
        prio++;
    }
    ready_vector->highest_prio = 0;
    ready_vector->priority_ready_group = 0;
#if KTASK_PRIORITY_MAX > 32
        memset(ready_vector->ready_vector, 0, sizeof(ready_vector->ready_vector));
#endif
}

在这里可以看到对 ready_vector 的 priority_ready_vector 进行了遍历和初始化的操作。

其中ready_vector表示现在准备就绪的所有任务。这里ready_vector的ready_vector是一个位图,表示优先级大于32的任务是否存在。

kservicetask.c

kernel/thread/kservicetask.c

CreateKServiceKTask()

void CreateKServiceKTask(void)
{
    /* create zombie recycle task */
    KServiceKTaskRecycle();

    /* create idle task */
    KSerciveKTaskIdle();	// [Service 写成了 Sercive]

}

可以看到这个启动了两个服务进程,一个是杀僵尸进程的程序,一个是空闲程序

KserviceKTaskIdle

void KSerciveKTaskIdle(void)
{
    InitIdleKTask();
}

void KServiceKTaskRecycle()
{
    ZombieTaskRecycleInit();
}

其中 ZombieTaskRecycleInit 定义在 kernel/thread/zombierecycle.c 中

其中 InitIdleKTask() 定义在 kernel/thread/idle.c 中

zombierecycle.c

kernel/thread/zombierecycle.c

ZombieTaskRecycleInit

void ZombieTaskRecycleInit(void)
{
    InitDoubleLinkList(&KTaskZombie);
    
    zombie_recycle = KTaskCreate("ZombieRecycleKTask",
                         ZombieKTaskEntry,
                         NONE,
                         ZOMBIE_KTASK_STACKSIZE,
                         KTASK_LOWEST_PRIORITY + 1);

    StartupKTask(zombie_recycle);
}

可以看到这里注册了一个 ZombieRecycleTask 的任务,其函数体为ZombieTaskEntry,优先级为最低优先级 + 1

ZombieTaskEntry

static void ZombieKTaskEntry(void *parameter)
{
    x_base lock = 0;
    KTaskDescriptorType task = NONE;

    while(RET_TRUE)
    {
        KDEBUG_NOT_IN_INTERRUPT;
        lock = CriticalAreaLock();
        if (JudgeZombieKTaskIsNotEmpty()) {
            task = SYS_DOUBLE_LINKLIST_ENTRY(KTaskZombie.node_next, struct TaskDescriptor, task_dync_sched_member.sched_link);
            DoubleLinkListRmNode(&(task->task_dync_sched_member.sched_link));
            CriticalAreaUnLock(lock);
#ifdef SEPARATE_COMPILE
            if(1 == task->task_dync_sched_member.isolation_flag ){
#ifdef MOMERY_PROTECT_ENABLE
               if(mem_access.Free)
                 mem_access.Free(task->task_dync_sched_member.isolation);
#endif
                x_ufree(task->task_base_info.stack_start);
            } else
#endif
            {
                KERNEL_FREE(task->task_base_info.stack_start);
            }

            DoubleLinkListRmNode(&(task->link));

            KTaskIdDelete(task->id.id);

            if(task->task_dync_sched_member.delay != NONE){
                KERNEL_FREE(task->task_dync_sched_member.delay);
            }
            KERNEL_FREE(task);
        } else {
            SuspendKTask(zombie_recycle);
            CriticalAreaUnLock(lock);
            DO_KTASK_ASSIGN;
        }  
    }
}

这里可以看到,这个函数是一个清理僵尸进程的函数,它会去检查 KTaskZombie 这样一个由 TaskDescriptor.sched_link 构成的双向链表,如果不为空,则会对其资源进行释放。如果为空则会阻塞掉这个清理僵尸进程的进程。

SYS_DOUBLE_LINKLIST_ENTRY(item, type, member)

SYS_DOUBLE_LINKLIST_ENTRY(item, type, member) 定义在 xs_klist.h 中,实际是 CONTAINER_OF(item, type, member) 的别名,其定义如下

#define  CONTAINER_OF(item, type, member) \
    ((type *)((char *)(item) - (unsigned long)(&((type *)0)->member)))

输入的三个值分别表示: item 是 某个type类的实例 的名为member的成员变量,然后这个函数的目的是 输入item, type, member 就可以返回这个成员变量所在的 type类 的实例的指针

其中 (type *)0 会得到它虚构的一个在地址0的type类的实例,而 &((type *)->member) 就是这个虚构的实例的member的地址,因为实例起始地址为0,所以这个地址其实也就是member成员变量的偏移,然后用item的地址减去偏移就是这个实例的起始地址。

idle.c

kernel/thread/idle.c

InitIdleTask

/**
 *
 * init system idle task,then startup the idle task
 *
 */
void InitIdleKTask(void)
{
    uint8 coreid = 0;
    char ktaskidle[NAME_NUM_MAX] = {0};

    for (coreid = 0; coreid < CORE_NUM; coreid++) {
        sprintf(ktaskidle, "ktaskidle%d", coreid);

        idle[coreid] = KTaskCreate(ktaskidle,IdleKTaskEntry,NONE,IDLE_KTASK_STACKSIZE,KTASK_LOWEST_PRIORITY);

#ifdef ARCH_SMP
        KTaskCoreCombine(idle[coreid], coreid);
#endif
        StartupKTask(idle[coreid]);
    
}

给每一个核上启动一个 idle 的线程

IdleKTaskEntry

static void IdleKTaskEntry(void *arg)
{
    while (1) {
#ifdef KERNEL_IDLE_HOOK
        HOOK(hook.idle.hook_Idle,());
#endif
        RunningIntoLowPowerMode();
    }
}

这里可以看到 Idle 调用了RunningIntoLowPowerMode() 而这个函数内部是一段汇编代码,执行的是 wfi 即 Wait For Interrupt, 通过硬件来进入 Idle 状态,等待中断的到来。

appstartup.c

InitUserSpace

#ifdef SEPARATE_COMPILE
int InitUserspace(void)
{
#ifdef APP_STARTUP_FROM_FLASH
    uint8_t *src = NONE;
    uint8_t *dest = NONE;
    uint8_t *end = NONE;
    
    dest = (uint8_t *)USERSPACE->us_bssstart;
    end  = (uint8_t *)USERSPACE->us_bssend;
    while (dest != end) {
        *dest++ = 0;
    }

    /* Initialize all of user-space .data */

    src  = (uint8_t *)USERSPACE->us_datasource;
    dest = (uint8_t *)USERSPACE->us_datastart;
    end  = (uint8_t *)USERSPACE->us_dataend;
    while (dest != end) {
        *dest++ = *src++;
    }
#ifndef  TASK_ISOLATION
    src  = (uint8_t *)&g_service_table_start;
    dest = (uint8_t *)SERVICE_TABLE_ADDRESS;
    end  = (uint8_t *)&g_service_table_end;
    while (src != end) {
        *dest++ = *src++;
    }
#endif 

    UserInitBoardMemory((void*)USER_MEMORY_START_ADDRESS, (void*)USER_MEMORY_END_ADDRESS);

#ifdef  MOMERY_PROTECT_ENABLE
         if ( mem_access.Init != NONE){
             if(mem_access.Init( (void **)(&isolation)) == EOK)
                 mem_access.Load(isolation);
         }
#endif
    return EOK;
#endif

#ifdef APP_STARTUP_FROM_SDCARD
    int fd = 0;
	char buf[1024] = {0};
	int len = 0;
    int len_check = 0;
    uint8_t *src = NONE;
    uint8_t *dest = NONE;
    uint8_t *end = NONE;
#ifndef FS_VFS
    KPrintf("fs not enable!%s %d\n",__func__,__LINE__);
    CHECK(0);
#endif
    
	fd = open(BOARD_APP_NAME,O_RDONLY );
	if(fd > 0) {
        KPrintf("open app bin %s success.\n",BOARD_APP_NAME);

        dest = (uint8_t *)USERSPACE;
        /* copy app to USERSPACE */
        while(RET_TRUE) {
            memset(buf, 0 , 1024); 
            len = read(fd, buf, 1024);
            KPrintf("read app bin len %d\n",len);
            if(len > 0) {
                 memcpy(dest, buf, len);
                 dest = dest + len;
                 len_check = len_check + len;
            } else {
                break;
            }
        }

        if(len_check <= 0){
            return -ERROR;
        }

        dest = (uint8_t *)USERSPACE->us_bssstart;
        end  = (uint8_t *)USERSPACE->us_bssend;
        while (dest != end) {
            *dest++ = 0;
        }

		src  = (uint8_t *)&g_service_table_start;
        dest = (uint8_t *)SERVICE_TABLE_ADDRESS;
        end  = (uint8_t *)&g_service_table_end;

        while (src != end) {
            *dest++ = *src++;
        }

		close(fd);

        UserInitBoardMemory((void*)USER_MEMORY_START_ADDRESS, (void*)USER_MEMORY_END_ADDRESS);

        return EOK;

	} else {
		KPrintf("open app bin %s failed.\n",BOARD_APP_NAME);
        return -EEMPTY;
	}
#endif
}
#endif
#endif

初始化了用户空间的 .bss .data 将 g_service_table 放到 SERVICE_TABLE_ADDRESS , 把内存的 access 初始化为当前的隔离

根据 BOARD_APP_NAME 打开文件把读到的内容放进 USERSPACE 中, 再一次将 .bss 清空, 将 g_service_table_start 放进 SERVICE_TABLE_ADDRESS

BOARD_APP_NAME 在 board/Kconfig 中输入配置,默认是 /XiUOS_cortex-m3-emulator_app.bin

CreateMainTask

/**
 * This function will create main application then startup it
 * 
 * 
 */
void CreateMainTask(void)
{
    int32 main = 0;

#ifdef SEPARATE_COMPILE
	KPrintf("Tip!!! Kernel is separated with application. main entry : 0x%08x \n",USERSPACE->us_entrypoint);

	main = UTaskCreate("main", (void*)USERSPACE->us_entrypoint, NONE,
                           MAIN_KTASK_STACK_SIZE, MAIN_KTASK_PRIORITY);

#else
    main = KTaskCreate("main", MainKTaskFunction, NONE,
                           MAIN_KTASK_STACK_SIZE, MAIN_KTASK_PRIORITY);

#endif

    if(main < 0) {		
		KPrintf("main create failed ...%s %d.\n",__FUNCTION__,__LINE__);
		return;
	}

    StartupKTask(main);
}

十分容易理解就是创建了MainTask然后启动,然后这个函数也很简单:

void MainKTaskFunction(void *parameter)
{  
#if defined(__ICCARM__) || defined(__GNUC__)
    main();
#endif
}
#endif

main 函数定义在 application 的 main.c 中

int main(void)
{
	UserPrintf("Hello, world!\n");
	FrameworkInit();
    return 0;
}

assign.c

/**
 * 
 * OsAssign startup function
 * .
 */
void StartupOsAssign(void)
{
    struct TaskDescriptor *FirstRunningTask = NONE;

    FirstRunningTask = ChooseTaskWithHighestPrio(&Assign.os_assign_read_vector);

    SetSystemRunningTask(FirstRunningTask);

    SwitchToFirstRunningTask(FirstRunningTask);
}

这里的函数名字都比较好理解

其中 ChooseTaskWithHighestPrio 定义在 thread/assignstat.c 中

在ready_vector[]中其实已经定义了 highest_prio ,所以只需要返回在已经准备好的Task中下标为 highest_prio 的任务就可以了

struct TaskDescriptor * ChooseTaskWithHighestPrio(struct OsAssignReadyVector *ready_vector)
{
    struct TaskDescriptor *target_task = NONE;

    NULL_PARAM_CHECK(ready_vector);

    target_task = SYS_DOUBLE_LINKLIST_ENTRY(ready_vector->priority_ready_vector[ready_vector->highest_prio].node_next,
                                  struct TaskDescriptor,
                                  task_dync_sched_member.sched_link);

    return target_task;
}

SetSystemRunningTask 定义在 assign.c 中,只是一个赋值的操作

static inline void SetSystemRunningTask(struct TaskDescriptor* task)
{
    NULL_PARAM_CHECK(task);

    Assign.os_running_task = task;
}

SwitchToFistRunningTask 定义在 assign.c 中

static inline void SwitchToFirstRunningTask(struct TaskDescriptor* task)
{
    NULL_PARAM_CHECK(task);

    Assign.ready_vector_done->remove(task);
    KTaskStatSetAsRunning(task);
    SwitchKtaskContextTo((x_ubase)&task->stack_point, task);
}

Assign.ready_vector_done 之前已经遇到过一次,这里调用了它的 remove 函数

也就是 KTaskOsAssignRemoveKTask

/*
 * a task will be removed from ready table.
 *
 * @param task  task descriptor
 *
 */
void KTaskOsAssignRemoveKTask(struct TaskDescriptor *task)
{
    x_base lock = 0;
    x_ubase number = 0;
    x_ubase highest_priority = 0;

	NULL_PARAM_CHECK(task);

    lock = DISABLE_INTERRUPT();

    SYS_KDEBUG_LOG(KDBG_SCHED, ("remove task[%.*s], the priority: %d\n",
                                      NAME_NUM_MAX, task->task_base_info.name,
                                      task->task_dync_sched_member.cur_prio));

    DoubleLinkListRmNode(&(task->task_dync_sched_member.sched_link));
    
    if (IsDoubleLinkListEmpty(&(Assign.os_assign_read_vector.priority_ready_vector[task->task_dync_sched_member.cur_prio]))) {
#if KTASK_PRIORITY_MAX > 32
        CLEAR_FLAG(&Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset], task->task_dync_sched_member.bitmap_row);
        if (Assign.os_assign_read_vector.ready_vector[task->task_dync_sched_member.bitmap_offset] == 0) {
            CLEAR_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
        }
        number = PrioCaculate(Assign.os_assign_read_vector.priority_ready_group);
        highest_priority = (number * 8) + PrioCaculate(Assign.os_assign_read_vector.ready_vector[number]);
#else
        CLEAR_FLAG(&Assign.os_assign_read_vector.priority_ready_group, task->task_dync_sched_member.bitmap_column);
        highest_priority = PrioCaculate(Assign.os_assign_read_vector.priority_ready_group);
#endif
        Assign.os_assign_read_vector.highest_prio = highest_priority;
    }

    ENABLE_INTERRUPT(lock);
}

可以看到代码也是十分明确的,就是 关中断,然后调用双向链表的删除元素,然后检查当前优先级删除之后,对应的链表中还有没有元素,然后更新位图。同时更新当前的最大优先级,最后打开中断。

KTaskStatSetAsRunning 定义在 ktask_stat.c 中

void KTaskStatSetAsRunning(KTaskDescriptorType task)
{
    NULL_PARAM_CHECK(task);
	KTaskStateSet(task, KTASK_RUNNING);
}

void KTaskStateSet(KTaskDescriptorType task, uint8 stat)
{
    NULL_PARAM_CHECK(task);
	task->task_dync_sched_member.stat = stat | (task->task_dync_sched_member.stat & ~KTASK_STAT_MASK);
}

// xs_ktask.h
#define KTASK_STAT_MASK             0x07
#define KTASK_INIT                  0x00                
#define KTASK_READY                 0x01               
#define KTASK_SUSPEND               0x02                
#define KTASK_RUNNING               0x03                 
#define KTASK_CLOSE                 0x04 

从上面可以看到我们在 & ~KTASK_STAT_MASK 之后就会清空原来的状态的后3位,然后再或上更改的状态,从而达到只更改后三位的目的

SwitchKtaskContextTo 定义在arch/arm/shared/arm32_switch.c 中

其对应的ARM汇编语言为:

LDR r2, =InterruptToKtask
STR r0, [r2]
LDR	r2, =InterruptToKtaskDescriptor
STR r1, [r2]

LDR r1, =InterruptFromKtask
MOV r0, #0x0
STR r0, [r1]
LDR r1, =KtaskSwithInterruptFlag
MOV r0, #1
STR R0, [r1]
LDR R0, = NVIC_SYSPRI2
LDR R1, = NVIC_PENDSV_PRI
LDR.W R2, [R0, #0x00]
ORR R1, R1, R2
STR R1, [R0]
LDR R0, = NVIC_INT_CTRL
LDR R1, = NVIC_PENDSVSET
STR R1, [R0]
LDR R0, = SCB_VTOR
LDR R0, [R0]
LDR R0. [R0]
NOP
MSR MSP, R0
CPSIE F
CPSIE I
BX lr

存疑

  1. 一些代码的拼写错误是否是有意为之
  2. Seperate Compile 的对立面是什么,有什么差别
  3. g_service_table 是什么
  4. 在 InitUserSpace 的时候,为什么要再一次清空.bss,为什么第二次放进的时候没有 ifdef TASK_ISOLATION
  5. 汇编中的一些变量值是什么
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值