Nucleus SE RTOS初始化和启动
Nucleus SE RTOS初始化和启动
Nucleus SE RTOS initialization and start-up
对于任何类型的操作系统,都有某种类型的启动机制。具体的工作方式因系统而异。通常说操作系统会“启动”。这是“bootstrap”的缩写,它描述了CPU如何从一个完全没有内存的内存中获得稳定的程序执行状态。传统上,一小片软件被加载到内存中;它可以简单地保存在ROM中。在过去,它可能是通过电脑前面板上的开关输入的。这个“引导加载器”会读入一个更复杂的引导程序,而这个程序又会加载并启动操作系统。这就是桌面计算机今天开始运行的过程;BIOS中的代码寻找可引导的设备(硬盘驱动器或CD-rom),从中可以加载引导程序,从而加载操作系统。
嵌入式系统的操作系统也可以用这种方式初始化。实际上,源于桌面操作系统的嵌入式操作系统正是这样做的。但对于大多数“经典”rtos,使用的是更简单(因此更快)的过程。
操作系统只是一个软件。如果这个软件已经在内存中了——比如说某种形式的ROM——那就是简单地安排CPU的重置顺序,最终执行操作系统的初始化代码。这就是大多数RTOS的工作方式,Nucleus SE也不例外。
大多数嵌入式软件开发工具包都包含必要的启动代码,以处理CPU重置并到达main()函数的入口点。Nucleus SE发行版代码本身与此过程无关,因为它的目的是尽可能地便于移植。相反,它提供了main()函数,该函数控制CPU并初始化和启动操作系统;稍后将对此进行详细描述。
内存初始化
Nucleus SE代码中所有静态变量的声明都以ROM或RAM作为前缀,以指示它们可能位于哪里。这两个define符号是在nuse_types.h中定义的,应该进行设置以适应正在使用的开发工具包(编译器和链接器)的功能。通常,ROM可以设置为const,RAM留空。
所有的ROM变量都是静态初始化的,这是合乎逻辑的。没有RAM变量是静态初始化的(因为这只适用于某些工具箱,这些工具箱安排从ROM到RAM的自动复制);包含显式初始化代码,本文将详细介绍这些代码。
Nucleus SE不在RAM中保存任何“恒定”的数据,在小型系统中,RAM可能供不应求。不使用复杂的数据结构来描述内核对象,而是使用一系列表(数组),这些表(数组)可以很容易地在ROM或RAM中找到。
main()函数
以下是Nucleus SE main()函数的完整代码
void main(void)
{
NUSE_Init(); /* initialize kernel
data */
/* user initialization
code here */
NUSE_Scheduler(); /* start tasks */
}
操作顺序非常简单:
首先调用NUSE_Init()函数。这将初始化所有Nucleus SE数据结构,并在下面详细介绍。
接下来,用户可以插入任何特定于应用程序的初始化代码,这些代码将在任务调度器启动之前执行。关于这段代码可以实现什么的更多细节可以在本文后面找到。
最后,启动Nucleus SE调度程序(NUSE_scheduler())。本文后面还将更详细地研究这一点。
The NUSE_Init() Function
此函数用于初始化所有Nucleus SE内核变量和数据结构。以下是完整代码:
void NUSE_Init(void)
{
U8 index;
/* global data */
NUSE_Task_Active = 0;
NUSE_Task_State = NUSE_STARTUP_CONTEXT;
#if NUSE_SYSTEM_TIME_SUPPORT
NUSE_Tick_Clock =
0;
#endif
#if NUSE_SCHEDULER_TYPE ==
NUSE_TIME_SLICE_SCHEDULER
NUSE_Time_Slice_Ticks = NUSE_TIME_SLICE_TICKS;
#endif
/* tasks */
#if ((NUSE_SCHEDULER_TYPE !=
NUSE_RUN_TO_COMPLETION_SCHEDULER)
||
NUSE_SIGNAL_SUPPORT || NUSE_TASK_SLEEP
||
NUSE_SUSPEND_ENABLE || NUSE_SCHEDULE_COUNT_SUPPORT)
for (index=0; index
<nuse_task_number; index++)="">
{
NUSE_Init_Task(index);
}
#endif
/* partition pools */
#if NUSE_PARTITION_POOL_NUMBER != 0
for (index=0; index
<nuse_partition_pool_number; index++)="">
{
NUSE_Init_Partition_Pool(index);
}
#endif
/* mailboxes */
#if NUSE_MAILBOX_NUMBER != 0
for (index=0; index
<nuse_mailbox_number; index++)="">
{
NUSE_Init_Mailbox(index);
}
#endif
/* queues */
#if NUSE_QUEUE_NUMBER != 0
for (index=0; index
<nuse_queue_number; index++)="">
{
NUSE_Init_Queue(index);
}
#endif
/* pipes */
#if NUSE_PIPE_NUMBER != 0
for (index=0; index
<nuse_pipe_number; index++)="">
{
NUSE_Init_Pipe(index);
}
#endif
/* semaphores */
#if NUSE_SEMAPHORE_NUMBER != 0
for (index=0; index
<nuse_semaphore_number; index++)="">
{
NUSE_Init_Semaphore(index);
}
#endif
/* event groups */
#if NUSE_EVENT_GROUP_NUMBER != 0
for (index=0; index
<nuse_event_group_number; index++)="">
{
NUSE_Init_Event_Group(index);
}
#endif
/* timers */
#if NUSE_TIMER_NUMBER != 0
for (index=0; index
<nuse_timer_number; index++)="">
{
NUSE_Init_Timer(index);
}
#endif
}
First, some global variables are initialized:
- NUSE_Task_Active – the index of the currently active task – is set to zero;
this may be modified by the scheduler in due course. - NUSE_Task_State is set to NUSE_STARTUP_CONTEXT ,
which indicates the limited API functionality to any following application
initialization code. - If system time support is
enabled, NUSE_Tick_Clock is
set to zero. - If the time slice
scheduler has been enabled, NUSE_Time_Slice_Ticks is
set up to the configured time slice value, NUSE_TIME_SLICE_TICKS .
Then, a series of functions are called to initialize kernel
objects:
- NUSE_Init_Task() is called to initialize data structures for each task.
This call is only omitted if the Run to Completion scheduler is selected and
signals, task suspend, and schedule counting are all not configured (as this
combination would result in there being no RAM data structures appertaining to
tasks and, hence, no initialization to be done). - NUSE_Init_Partition_Pool() is called to initialize each partition pool object. The
calls are omitted if no partition pools have been configured. - NUSE_Init_Mailbox() is called to initialize each mailbox object. The calls are
omitted if no mailboxes have been configured. - NUSE_Init_Queue() is called to initialize each queue object. The calls are
omitted if no queues have been configured. - NUSE_Init_Pipe() is called to initialize each pipe object. The calls are
omitted if no pipes have been configured. - NUSE_Init_Semaphore() is called to initialize each semaphore object. The calls
are omitted if no semaphores have been configured. - NUSE_Init_Event_Group() is called to initialize each event group object. The calls
are omitted if no event groups have been configured. - NUSE_Init_Timer() is called to initialize each timer object. The calls are
omitted if no timers have been configured.
Initializing
Tasks
Here is the complete code for NUSE_Init_Task() :
void NUSE_Init_Task(NUSE_TASK task)
{
#if NUSE_SCHEDULER_TYPE
!= NUSE_RUN_TO_COMPLETION_SCHEDULER
NUSE_Task_Context[task][15]
=
/* SR */
NUSE_STATUS_REGISTER;
NUSE_Task_Context[task][16]
=
/* PC */
NUSE_Task_Start_Address[task];
NUSE_Task_Context[task][17]
=
/* SP */
(U32 *)NUSE_Task_Stack_Base[task] +
NUSE_Task_Stack_Size[task];
#endif
#if NUSE_SIGNAL_SUPPORT
|| NUSE_INCLUDE_EVERYTHING
NUSE_Task_Signal_Flags[task] = 0;
#endif
#if NUSE_TASK_SLEEP ||
NUSE_INCLUDE_EVERYTHING
NUSE_Task_Timeout_Counter[task] = 0;
#endif
#if NUSE_SUSPEND_ENABLE
|| NUSE_INCLUDE_EVERYTHING
#if NUSE_INITIAL_TASK_STATE_SUPPORT ||
NUSE_INCLUDE_EVERYTHING
NUSE_Task_Status[task] =
NUSE_Task_Initial_State[task];
#else
NUSE_Task_Status[task] = NUSE_READY;
#endif
#endif
#if
NUSE_SCHEDULE_COUNT_SUPPORT || NUSE_INCLUDE_EVERYTHING
NUSE_Task_Schedule_Count[task] = 0;
#endif
}
除非已配置“运行到完成”计划程序,否则将初始化任务的上下文块–NUSE_Task_context[Task][]。大多数条目没有设置为值,因为它们表示通用机器寄存器,当任务启动时,这些寄存器被假定具有不确定的值。在Nucleus SE的示例(Freescale ColdFire)实现中(这对于任何处理器都是类似的),最后三个条目是显式设置的:
- ·
NUSE_Task_Context[task][15] holds
the status register (SR ) and is
set to the value in the #define symbol NUSE_STATUS_REGISTER . - · NUSE_Task_Context[task][16] holds
the program counter (PC ) and is
set to the address of the entry point of the task’s code: NUSE_Task_Start_Address[task] . - · NUSE_Task_Context[task][17] holds
the stack pointer (SP), which is initialized to a value computed by adding the
address of the task’s stack base (NUSE_Task_Stack_Base[task] )
to the task’s stack size (NUSE_Task_Stack_Size[task] ).
如果启用信号支持,任务的信号标志(NUSE_task_signal_flags[task])设为零。
如果启用了任务休眠(即API调用NUSE_task_sleep()),则任务的超时计数器(NUSE_task_timeout_counter[task])设置为零。
如果任务状态为“已初始化”,则任务状态为“挂起”。如果启用了任务初始任务状态支持,则此初始值由用户指定(在NUSE_Task_initial_State[Task])。否则,状态设置为NUSE_READY。
如果启用任务计划计数,则任务的计数器(NUSE_task_schedule_Count[task])设置为零。
初始化分区池
以下是NUSE_Init_Partition_Pool()的完整代码:
void NUSE_Init_Partition_Pool(NUSE_PARTITION_POOL
pool)
{
NUSE_Partition_Pool_Partition_Used[pool] = 0;
#if NUSE_BLOCKING_ENABLE
NUSE_Partition_Pool_Blocking_Count[pool] = 0;
#endif
}
分区池的“used”计数器(NUSE_partition_pool_partition_used[pool])设置为零。
如果启用了任务阻塞,则分区池的阻塞任务计数器(NUSE_partition_pool_blocking_Count[pool])设置为零。
初始化邮箱
以下是NUSE_Init_Mailbox()的完整代码:
void NUSE_Init_Mailbox(NUSE_MAILBOX mailbox)
{
NUSE_Mailbox_Data[mailbox] = 0;
NUSE_Mailbox_Status[mailbox] =
0;
#if NUSE_BLOCKING_ENABLE
NUSE_Mailbox_Blocking_Count[mailbox] = 0;
#endif
}
邮箱的数据存储(NUSE_mailbox_data[mailbox])设置为零,其状态(NUSE_mailbox_status[mailbox])设置为“未使用”(即零)。
如果启用任务阻止,则邮箱的阻止任务计数器(NUSE_mailbox_blocking_Count[mailbox])设置为零。
初始化队列
以下是NUSE_Init_Queue()的完整代码:
void NUSE_Init_Queue(NUSE_QUEUE queue)
{
NUSE_Queue_Head[queue] = 0;
NUSE_Queue_Tail[queue] = 0;
NUSE_Queue_Items[queue] = 0;
#if NUSE_BLOCKING_ENABLE
NUSE_Queue_Blocking_Count[queue]
= 0;
#endif
}
队列的head和tail指针(实际上,它们是索引–NUSE_queue_head[queue]和NUSE_queue_tail[queue])被设置为指向队列数据区域的开始(即给定值0)。队列的项目计数器(NUSE_queue_Items[queue])也设置为零。
如果启用任务阻塞,队列的阻塞任务计数器(NUSE_queue_blocking_Count[queue])设置为零。
初始化管道
以下是NUSE_Init_Pipe()的完整代码:
void NUSE_Init_Pipe(NUSE_PIPE pipe)
{
NUSE_Pipe_Head[pipe] = 0;
NUSE_Pipe_Tail[pipe] = 0;
NUSE_Pipe_Items[pipe] = 0;
#if NUSE_BLOCKING_ENABLE
NUSE_Pipe_Blocking_Count[pipe] = 0;
#endif
}
管道的头和尾指针(实际上,它们是索引–NUSE_pipe_head[pipe]和NUSE_pipe_tail[pipe])被设置为指向管道数据区域的开始(即给定值0)。管道的项目计数器(NUSE_pipe_Items[pipe])也设置为零。
如果启用任务阻塞,则管道的阻塞任务计数器(NUSE_pipe_blocking_Count[pipe])设置为零。
初始化信号量
以下是NUSE_Init_Semaphore()的完整代码:
void NUSE_Init_Semaphore(NUSE_SEMAPHORE
semaphore)
{
NUSE_Semaphore_Counter[semaphore] =
NUSE_Semaphore_Initial_Value[semaphore];
#if NUSE_BLOCKING_ENABLE
NUSE_Semaphore_Blocking_Count[semaphore] = 0;
#endif
}
信号量的计数器(NUSE_semaphore_counter[semaphore])初始化为用户指定的值(NUSE_semaphore_Initial_value[semaphore])。
如果启用任务阻塞,则信号量的阻塞任务计数器(NUSE_semaphore_blocking_Count[信号量])设置为零。
初始化事件组
以下是NUSE_Init_Event_Group()的完整代码:
void NUSE_Init_Event_Group(NUSE_EVENT_GROUP
group)
{
NUSE_Event_Group_Data[group] =
0;
#if NUSE_BLOCKING_ENABLE
NUSE_Event_Group_Blocking_Count[group] = 0;
#endif
}
事件组的标志被清除;即NUSE_event_group_Data[group]设置为零。
如果启用任务阻止,则事件组的阻止任务计数器(NUSE_event_group_blocking_Count[group])设置为零。
初始化计时器
以下是NUSE_Init_Timer()的完整代码:
void NUSE_Init_Timer(NUSE_TIMER timer)
{
NUSE_Timer_Status[timer] =
FALSE;
NUSE_Timer_Value[timer] =
NUSE_Timer_Initial_Time[timer];
NUSE_Timer_Expirations_Counter[timer] = 0;
}
计时器的状态(NUSE_timer_status[timer])设置为“未使用”;即FALSE。
其倒计时值(NUSE_Timer_value[Timer])初始化为用户指定的值(NUSE_Timer_Initial_Time[Timer])。
其过期计数器(NUSE_Timer_Expirations_counter[Timer])设置为零。
应用程序代码初始化
一旦Nucleus SE数据结构被初始化,就有机会在执行任务之前执行应用程序初始化的代码。此功能有许多可能的用途:
初始化应用程序数据结构。显式赋值比允许静态变量的自动初始化更容易理解和调试。
内核对象分配。假设所有内核对象都是在构建时静态创建的,并由索引值标识,那么分配“所有权”或定义这些对象的用法可能很有用。这可以使用#define符号来完成,但是,如果存在多个任务实例,则最好通过全局数组(按任务的ID编制索引)来分配对象索引。
设备初始化。这可能是安装任何外围设备的好机会。
显然,在执行Nucleus SE初始化之前,很多事情都可以实现,但是在这里定位应用程序初始化代码的好处是现在可以使用内核服务(API调用)。例如,队列或邮箱可能预加载了任务启动时要处理的数据。
允许API调用有一个限制:不能采取通常会导致调用调度程序的操作,例如任务挂起/阻塞。全局变量NUSE_Task_State已设置为NUSE_STARTUP_CONTEXT以反映此限制。
启动计划程序
初始化完成后,只剩下启动调度程序来开始执行应用程序代码-任务。在前面的一篇文章中详细介绍了调度程序的选项和各种类型的调度程序的操作,因此这里只需要简要总结一下。
顺序中的关键点是:
将全局变量NUSE_Task_State设置为NUSE_Task_CONTEXT。
选择要运行的第一个任务的索引。如果启用了对初始任务状态的支持,将对第一个就绪任务执行搜索;否则将使用值0。
调用调度程序–NUSE_scheduler()。
在最后一步中到底发生了什么取决于选择了哪种调度程序类型。对于Run-to-Completion,进入调度循环并按顺序调用任务。对于其他调度程序类型,将加载第一个任务的上下文并将控制权传递给该任务。
Nucleus SE RTOS初始化和启动的更多相关文章
- 使用Nucleus SE实时操作系统
使用Nucleus SE实时操作系统 Using the Nucleus SE real-time operating system 到目前为止,在本系列文章中,我们详细介绍了Nucleus SE提供 ...
- Solr初始化源码分析-Solr初始化与启动
用solr做项目已经有一年有余,但都是使用层面,只是利用solr现有机制,修改参数,然后监控调优,从没有对solr进行源码级别的研究.但是,最近手头的一个项目,让我感觉必须把solrn内部原理和扩展机 ...
- Hadoop源码学习笔记之NameNode启动场景流程四:rpc server初始化及启动
老规矩,还是分三步走,分别为源码调用分析.伪代码核心梳理.调用关系图解. 一.源码调用分析 根据上篇的梳理,直接从initialize()方法着手.源码如下,部分代码的功能以及说明,已经在注释阐述了. ...
- k8s replicaset controller分析(1)-初始化与启动分析
replicaset controller分析 replicaset controller简介 replicaset controller是kube-controller-manager组件中众多控制 ...
- kube-scheduler源码分析(1)-初始化与启动分析
kube-scheduler源码分析(1)-初始化与启动分析 kube-scheduler简介 kube-scheduler组件是kubernetes中的核心组件之一,主要负责pod资源对象的调度工作 ...
- k8s client-go源码分析 informer源码分析(2)-初始化与启动分析
k8s client-go源码分析 informer源码分析(2)-初始化与启动分析 前面一篇文章对k8s informer做了概要分析,本篇文章将对informer的初始化与启动进行分析. info ...
- 第1章 ZigBee协议栈初始化网络启动流程
作者:宋老师,华清远见嵌入式学院讲师. ZigBee的基本流程:由协调器的组网(创建PAN ID),终端设备和路由设备发现网络以及加入网络. 基本流程:main()->osal_init_sys ...
- TaskTracker任务初始化及启动task源码级分析
在监听器初始化Job.JobTracker相应TaskTracker心跳.调度器分配task源码级分析中我们分析的Tasktracker发送心跳的机制,这一节我们分析TaskTracker接受JobT ...
- ucos系统初始化及启动过程
之前在ucos多任务切换中漏掉了一个变量, OSCtxSwCtr标识系统任务切换次数 主要应该还是用在调试功能中 Ucos系统初始化函数为OSInit(),主要完成以下功能 全局变量初始化 就绪任务表 ...
随机推荐
- hdu1466 递推
题意: 给你n条直线,不会存在三线共点,输出所有的可能交点数.. 思路: 这个是个地推的题目,假设当前的线段i,他里面有r条是随意的,有(i - r)条是平行的,那么当前的交点 ...
- Weblogic SSRF漏洞(CVE-2014-4210)
Weblogic中存在一个SSRF漏洞,利用该漏洞可以发送任意HTTP请求,进而攻击内网中redis.fastcgi等脆弱组件. 关于SSRF漏洞我们就不讲了,传送门--> SSRF(服务端请求 ...
- 绕过CDN查找网站真实ip
在渗透测试过程中,经常会碰到网站有CDN的情况.CDN即内容分发网络,主要解决因传输距离和不同运营商节点造成的网络速度性能低下的问题.说的简单点,就是一组在不同运营商之间的对接点上的高速缓存服务器,把 ...
- Windows PE导出表编程4(重构导出表实现私有函数导出)
本次是尝试调用DLL里面的私有函数. 一: 之前先探索一下,首先可以考虑用偏移量来调用,就是如果知道了某个私有函数和某个导出的公共函数的相对便宜的话,直接加载dll获取公共函数地址,然后自己手动去偏移 ...
- Python 爬虫 BeautifulSoup4 库的使用
BeautifulSoup4库 和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据.lxml 只会局部遍历,而Be ...
- CTF密码学常见加解密总结
CTF密码学常见加解密总结 2018年03月10日 19:35:06 adversity` 本文链接:https://blog.csdn.net/qq_40836553/article/details ...
- 【js】Leetcode每日一题-完成所有工作的最短时间
[js]Leetcode每日一题-完成所有工作的最短时间 [题目描述] 给你一个整数数组 jobs ,其中 jobs[i] 是完成第 i 项工作要花费的时间. 请你将这些工作分配给 k 位工人.所有工 ...
- 【python】Leetcode每日一题-存在重复元素3
[python]Leetcode每日一题-存在重复元素3 [题目描述] 给你一个整数数组 nums 和两个整数 k 和 t .请你判断是否存在 两个不同下标 i 和 j,使得 abs(nums[i] ...
- 【近取 Key】Alpha - v1.0 测试报告
Bug 前端 主页.登录.注册.导航 bug说明 修复方法 修复结果 导航栏有时不显示用户姓名 修改用户信息的获取逻辑与存储方式 成功 展示词图界面导航栏居右失败 在组件中增加自适应相关设置 成功 用 ...
- Shell 脚本重启项目
每次发打包好项目后都需要手动重启项目,写个Shell脚本一键重启项目 Shell 脚本 #!/bin/bash while getopts "n:p:" arg do case $ ...