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;
pulSrc = &_sidata;
for(pulDest = &_sdata; pulDest < &_edata; )
{
*pulDest++ = *pulSrc++;
}
__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");
entry();
}
首先将 _sdata 到 _edata 中的内容都拷贝到了 _sidata 开始的内存中
然后执行了一段汇编
ldr R0, =_sbss
ldr R1, =_ebss
mov R2, #0
.thumb_func
zero_loop:
cmp r0, r1
itlt
strlt r2, [r0], #4
blt zero_loop
将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()
int entry(void)
{
DISABLE_INTERRUPT();
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;
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);
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);
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;
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);
#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()
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);
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)
{
KServiceKTaskRecycle();
KSerciveKTaskIdle();
}
可以看到这个启动了两个服务进程,一个是杀僵尸进程的程序,一个是空闲程序
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
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;
}
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;
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
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
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
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);
}
#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
存疑
- 一些代码的拼写错误是否是有意为之
- Seperate Compile 的对立面是什么,有什么差别
- g_service_table 是什么
- 在 InitUserSpace 的时候,为什么要再一次清空.bss,为什么第二次放进的时候没有 ifdef TASK_ISOLATION
- 汇编中的一些变量值是什么
|