板级支持包函数组
空闲 HOOK 初始化
系统启动时通过 halIdleInit 函数来初始化目标系统空闲时间作业,代码实现如下:
#include <SylixOS.h>
static VOID halIdleInit (VOID)
{
API_SystemHookAdd(__arm_wfi, LW_OPTION_THREAD_IDLE_HOOK);
}
API_SystemHookAdd 函数将 arm_wfi 函数注册为空闲 HOOK。此 HOOK 在任务上下文中被调用,空闲线程会不间断的调用此 HOOK,此 HOOK 只能在系统进入多任务前被设置。arm_wfi 函数的作用是使 CPU 进入空闲等待中断。
注意:
CPU0 不能使用 WFI 指令。
函数 API_SystemHookAdd 的原型如下:
#include <SylixOS.h>
ULONG API_SystemHookAdd (LW_HOOK_FUNC hookfunc, ULONG ulOpt);
函数 API_KernelFpuPrimaryInit 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 hookfunc 是递的是 HOOK 功能函数。
- 参数 ulOpt 是 HOOK 类型,如下表所示。
HOOK 类型 | 含义 |
---|---|
LW_OPTION_THREAD_CREATE_HOOK | 线程创建 HOOK |
LW_OPTION_THREAD_DELETE_HOOK | 线程删除 HOOK |
LW_OPTION_THREAD_SWAP_HOOK | 线程切换 HOOK |
LW_OPTION_THREAD_TICK_HOOK | 时钟中断 HOOK |
LW_OPTION_THREAD_INIT_HOOK | 线程初始化过程 HOOK |
LW_OPTION_THREAD_IDLE_HOOK | 空闲线程 HOOK |
LW_OPTION_KERNEL_INITBEGIN | 系统初始化 HOOK |
LW_OPTION_KERNEL_INITEND | 系统初始化完成 HOOK |
LW_OPTION_KERNEL_REBOOT | 系统重启(关机)HOOK |
LW_OPTION_WATCHDOG_TIMER | 系统软件看门狗 HOOK |
LW_OPTION_OBJECT_CREATE_HOOK | 内核对象创建 HOOK |
LW_OPTION_OBJECT_DELETE_HOOK | 内核对象删除 HOOK |
LW_OPTION_FD_CREATE_HOOK | 文件描述符创建 HOOK |
LW_OPTION_FD_DELETE_HOOK | 文件描述符删除 HOOK |
LW_OPTION_CPU_IDLE_ENTER | 当前 CPU 准备运行/恢复运行 IDLE 任务 HOOK |
LW_OPTION_CPU_IDLE_EXIT | 当前 CPU IDLE 任务被抢占 HOOK |
LW_OPTION_CPU_INT_ENTER | 当前 CPU 发生中断,在调用中断处理函数前 HOOK |
LW_OPTION_CPU_INT_EXIT | 当前 CPU 发生中断,在调用中断处理函数后 HOOK |
LW_OPTION_STACK_OVERFLOW_HOOK | 线程堆栈溢出 HOOK |
LW_OPTION_FATAL_ERROR_HOOK | 线程出现致命错误(接收到异常信号)HOOK |
LW_OPTION_VPROC_CREATE_HOOK | 进程创建 HOOK |
LW_OPTION_VPROC_DELETE_HOOK | 进程删除 HOOK |
浮点运算器初始化
早期的 ARM 没有协处理器,所有浮点运算是由 CPU 来模拟的,即所需浮点运算均在浮点运算模拟器(float math emulation)上进行,需要的浮点运算,常要耗费数千个循环才能执行完毕,因此特别缓慢。ARM 核浮点运算分为软浮点和硬浮点,软浮点是通过浮点库去实现浮点运算的,效率低。硬浮点是通过浮点运算单元(FPU)来完成的,效率高。
浮点运算器初始化函数是 halFpuInit,该函数的代码实现如下:
#include <SylixOS.h>
static VOID halFpuInit (VOID)
{
API_KernelFpuPrimaryInit(ARM_MACHINE_A7, ARM_FPU_NONE);
}
API_KernelFpuPrimaryInit 函数进行浮点运算器初始化。在该函数中,会调用 archFpuPrimaryInit 函数初始化 FPU 单元,此函数针对不同架构,有不同的实现。主要是针对不同的 FPU,初始化并获取 VFP 控制器操作函数集。
API_KernelFpuPrimaryInit 函数的原型如下:
#include <SylixOS.h>
VOID API_KernelFpuPrimaryInit (CPCHAR pcMachineName, CPCHAR pcFpuName);
函数 API_KernelFpuPrimaryInit 原型分析:
- 参数 pcMachineName 是处理器的名称。可选择的处理器如下表所示。
处理器架构 | 处理器宏 | 处理器名称 |
---|---|---|
ARM | ARM_MACHINE_920 | 920 |
ARM | ARM_MACHINE_926 | 926 |
ARM | ARM_MACHINE_1136 | 1136 |
ARM | ARM_MACHINE_1176 | 1176 |
ARM | ARM_MACHINE_A5 | A5 |
ARM | ARM_MACHINE_A7 | A7 |
ARM | ARM_MACHINE_A8 | A8 |
ARM | ARM_MACHINE_A9 | A9 |
ARM | ARM_MACHINE_A15 | A15 |
ARM | ARM_MACHINE_A17 | A17 |
ARM | ARM_MACHINE_A53 | A53 |
ARM | ARM_MACHINE_A57 | A57 |
ARM | ARM_MACHINE_A72 | A72 |
ARM | ARM_MACHINE_A73 | A73 |
ARM | ARM_MACHINE_R4 | R4 |
ARM | ARM_MACHINE_R5 | R5 |
ARM | ARM_MACHINE_R7 | R7 |
MIPS | MIPS_MACHINE_24KF | 24kf |
MIPS | MIPS_MACHINE_LS1X | loongson1x |
MIPS | MIPS_MACHINE_LS2X | loongson2x |
MIPS | MIPS_MACHINE_LS3X | loongson3x |
MIPS | MIPS_MACHINE_JZ47XX | jz47xx |
PPC | PPC_MACHINE_603 | 603 |
PPC | PPC_MACHINE_EC603 | EC603 |
PPC | PPC_MACHINE_604 | 604 |
PPC | PPC_MACHINE_750 | 750 |
PPC | PPC_MACHINE_MPC83XX | MPC83XX |
PPC | PPC_MACHINE_E200 | E200 |
PPC | PPC_MACHINE_E300 | E300 |
PPC | PPC_MACHINE_E500 | E500 |
PPC | PPC_MACHINE_E500V1 | E500V1 |
PPC | PPC_MACHINE_E500V2 | E500V2 |
PPC | PPC_MACHINE_E500MC | E500MC |
PPC | PPC_MACHINE_E600 | E600 |
x86 | X86_MACHINE_PC | x86 |
- 参数 pcFpuName 是 FPU 的名称,可选择的 FPU 如下表所示。
处理器架构 | FPU 宏或变量 | FPU 名称 |
---|---|---|
ARM | ARM_FPU_NONE | none |
ARM | ARM_FPU_VFP9_D16 | vfp9-d16 |
ARM | ARM_FPU_VFP9_D32 | vfp9-d32 |
ARM | ARM_FPU_VFP11 | vfp11 |
ARM | ARM_FPU_VFPv3 | vfpv3 |
ARM | ARM_FPU_VFPv4 | vfpv4 |
ARM | ARM_FPU_NEONv3 | ARM_FPU_VFPv3 |
ARM | ARM_FPU_NEONv4 | ARM_FPU_VFPv4 |
MIPS | MIPS_FPU_NONE | none |
MIPS | MIPS_FPU_VFP32 | vfp32 |
PPC | PPC_FPU_NONE | none |
PPC | PPC_FPU_VFP | vfp |
PPC | PPC_FPU_SPE | spe |
PPC | PPC_FPU_ALTIVEC | altivec |
x86 | _G_bX86HasX87FPU | x87 FPU |
实时时钟初始化
实时时钟(RTC)的主要功能是在系统掉电的情况下,利用备用电源使时钟继续运行,保证不会丢失时间信息。系统启动时通过 halTimeInit 函数初始化目标电路板时间系统,该函数代码实现如下:
#include <SylixOS.h>
static VOID halTimeInit (VOID)
{
boardTimeInit();
}
在 halTimeInit 函数中,调用 boardTimeInit 函数初始化目标电路板时间系统。用户可以根据需要,实现对应开发板的初始化代码。现以 SylixOS-EVB-i.MX6Q 验证平台为例,该平台 BSP 的 boardTimeInit 函数代码实现如下:
#include <SylixOS.h>
VOID boardTimeInit (VOID)
{
PLW_RTC_FUNCS pRtcFuncs;
pRtcFuncs = rtcGetFuncs();
rtcDrv();
rtcDevCreate(pRtcFuncs);
rtcToSys();
}
在 boardTimeInit 函数中,通过 rtcGetFuncs 函数获取 RTC 驱动硬件函数接口。
rtcDrv 宏定义的是 API_RtcDrvInstall 函数。该函数向内核注册了一组操作接口,包括设备打开、设备关闭、设备 I/O 控制接口,函数原型如下:
#include <SylixOS.h>
INT API_RtcDrvInstall (VOID);
rtcDevCreate 宏定义的是 API_RtcDevCreate 函数。该函数建立一个 RTC 设备,并调用 RTC_pfuncInit 成员函数初始化硬件 RTC,函数原型如下:
#include <SylixOS.h>
INT API_RtcDevCreate (PLW_RTC_FUNCS prtcfuncs);
函数 API_RtcDevCreate 原型分析如下:
- 该函数成功返回 ERROR_NONE 。
- 参数 prtcfuncs 是rtc操作函数集。
rtcToSys 宏定义的是 API_RtcToSys 函数,该函数将RTC设备时间同步到系统时间,函数原型如下:
#include <SylixOS.h>
INT API_RtcToSys (VOID);
MMU 全局内存映射表
内存管理单元(Memory Management Unit)简称 MMU,负责虚拟地址到物理地址的转换,并提供硬件机制的内存访问权限检查。MMU 全局内存映射表的初始化函数是 halVmmInit,该函数的代码实现如下:
#include <SylixOS.h>
static VOID halVmmInit (VOID)
{
API_VmmLibInit(_G_physicalDesc, _G_virtualDesc, ARM_MACHINE_A7);
API_VmmMmuEnable();
}
API_VmmLibInit 宏定义的是 API_VmmLibPrimaryInit 函数,该函数初始化 VMM 系统,函数原型如下所示:
#include <SylixOS.h>
ULONG API_VmmLibPrimaryInit (LW_MMU_PHYSICAL_DESC pphydesc[],
LW_MMU_VIRTUAL_DESC pvirdes[],
CPCHAR pcMachineName);
函数 API_VmmLibPrimaryInit 原型分析:
- 此函数成功返回 ERROR_NONE ;
- 参数 pphydesc 是物理内存区描述表;
- 参数 pvirdes 是虚拟内存区描述表;
- 参数 pcMachineName 是 CPU 型号。
CACHE 初始化
在计算机系统中,CPU 的速度远远高于内存的速度,为了解决内存速度低下的问题,CPU 内部会放置一些 SRAM 用做 Cache(缓存),来提高 CPU 访问程序和数据的速度。Cache 的初始化函数是 halCacheInit,函数代码实现如下:
#include <SylixOS.h>
static VOID halCacheInit (VOID)
{
API_CacheLibInit(CACHE_COPYBACK, CACHE_COPYBACK, ARM_MACHINE_A7);
API_CacheEnable(INSTRUCTION_CACHE);
API_CacheEnable(DATA_CACHE);
}
该函数中,主要调用 API_CacheLibInit 初始化 Cache 系统,以及调用 API_CacheEnable 使能指令和数据 CACHE。
API_CacheLibPrimaryInit 功能是初始化 Cache 功能,CPU 构架相关,函数原型如下:
#include <SylixOS.h>
ULONG API_CacheLibPrimaryInit (CACHE_MODE uiInstruction,
CACHE_MODE uiData,
CPCHAR pcMachineName);
函数 API_CacheLibPrimaryInit 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 uiInstruction 是 Cache 模式,可参见表 CACHE 模式。
- 参数 uiData 是数据 Cache 模式。可选择的模式与指令 Cache 一样。
- 参数 pcMachineName 是CPU类型。支持的处理器可以参见上面表 支持的处理器。
Cache 模式 | 说明 |
---|---|
CACHE_COPYBACK | 回写模式 |
CACHE_WRITETHROUGH | 写通模式 |
CACHE_DISABLED | 旁路模式 |
API_CacheEnable 功能是使能指定类型的 Cache,函数原型如下:
#include <SylixOS.h>
INT API_CacheEnable (LW_CACHE_TYPE cachetype);
函数 API_CacheEnable 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 cachetype 指定Cache类型可参见下表。
Cache 类型 | 说明 |
---|---|
INSTRUCTION_CACHE | 指令 Cache |
DATA_CACHE | 数据 Cache |
内核 shell 系统初始化
内核 shell 系统初始化函数是 halShellInit,函数代码实现如下所示:
#include <SylixOS.h>
static VOID halShellInit (VOID)
{
API_TShellInit();
zlibShellInit();
viShellInit();
gdbInit();
gdbModuleInit();
}
在该函数中主要有以下操作:
API_TShellInit 函数安装 Tshell 程序,函数原型如下:
#include <SylixOS.h>
VOID API_TShellInit (VOID);
zlibShellInit 函数用于初始化 zlib shell 接口,函数原型如下:
#include <SylixOS.h>
VOID zlibShellInit (VOID);
viShellInit 函数用于初始化 vi shell 接口,函数原型如下:
#include <SylixOS.h>
VOID viShellInit (VOID);
gdbInit 宏定义的是 API_GdbInit 函数,该函数的作用是注册 GDBServer 命令,函数原型如下:
#include <SylixOS.h>
VOID API_GdbInit (VOID);
gdbModuleInit 宏定义的是 API_GdbModuleInit 函数。该函数的作用是注册 GDB module 命令,函数原型如下:
#include <SylixOS.h>
VOID API_GdbModuleInit (VOID);
总线系统初始化
总线系统初始化函数是 halBusInit,该函数的代码实现如下所示:
#include <SylixOS.h>
static VOID halBusInit (VOID)
{
boardBusInit();
}
在该函数中,boardBusInit 函数用于初始化目标开发板总线系统。用户可以根据需要,实现对应开发板的初始化程序。现以 SylixOS-EVB-i.MX6Q 验证平台的 BSP 为例,代码实现如下:
#include <SylixOS.h>
VOID boardBusInit (VOID)
{
PLW_I2C_FUNCS pI2cFuncs;
PLW_SPI_FUNCS pSpiFuncs;
API_I2cLibInit();
API_SpiLibInit();
pI2cFuncs = i2cBusFuns(0);
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/0", pI2cFuncs, 10, 1);
}
pI2cFuncs = i2cBusFuns(1);
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/1", pI2cFuncs, 10, 1);
}
pI2cFuncs = i2cBusFuns(2);
if (pI2cFuncs) {
API_I2cAdapterCreate("/bus/i2c/2", pI2cFuncs, 10, 1);
}
}
该函数调用 API_I2cLibInit 和 API_SpiLibInit 函数,初始化 I2C 和 SPI 组件库;调用 i2cBusFuns 函数初始化 I2C 总线并获取驱动程序;最后调用 API_I2cAdapterCreate 函数创建 I2C 适配器。初始化 I2C 总线并获取操作函数集:
#include <SylixOS.h>
PLW_I2C_FUNCS i2cBusFuns (UINT uiChannel);
函数 i2cBusFuns 原型分析:
- 此函数返回总线操作函数集。
- 参数 uiChannel 是通道号。
创建一个 I2C 适配器
#include <SylixOS.h>
INT API_I2cAdapterCreate (CPCHAR pcName,
PLW_I2C_FUNCS pi2cfunc,
ULONG ulTimeout,
INT iRetry);
函数 API_I2cAdapterCreate 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 pcName 是适配器名称。
- 参数 pi2cfunc 是操作函数组,可通过 i2cBusFuns 函数获得。
- 参数 ulTimeout 是操作超时时间(ticks)。
- 参数 iRetry 是重试次数。
驱动程序初始化
系统启动时通过 halDrvInit 函数初始化目标系统静态驱动程序,代码实现如下:
#include <SylixOS.h>
static VOID halDrvInit (VOID)
{
rootFsDrv();
procFsDrv();
shmDrv();
randDrv();
ptyDrv();
ttyDrv();
memDrv();
pipeDrv();
spipeDrv();
fatFsDrv();
tpsFsDrv();
ramFsDrv();
romFsDrv();
nfsDrv();
yaffsDrv();
canDrv();
}
在初始化标准设备驱动之前,需要安装 rootfs 和 procfs。halDrvInit 函数中都是宏操作,该函数内的初始化操作主要是向内核注册了操作接口。用户可以根据需要,在该函数中添加自己的驱动初始化程序,函数说明如下表所示:
宏 | 宏定义的函数 | 说明 |
---|---|---|
rootFsDrv | API_RootFsDrvInstall | 安装 rootfs 文件系统驱动程序 |
procFsDrv | API_ProcFsDrvInstall | 安装 procfs 文件系统驱动程序 |
shmDrv | API_ShmDrvInstall | 安装共享内存驱动程序 |
randDrv | API_RandDrvInstall | 安装随机数发生器设备驱动程序 |
ptyDrv | API_PtyDrvInstall | 安装 PTY 设备驱动程序 |
ttyDrv | API_TtyDrvInstall | 安装 TTY 设备驱动程序 |
memDrv | API_MemDrvInstall | 安装内存设备驱动程序 |
pipeDrv | API_PipeDrvInstall | 安装管道设备驱动程序 |
spipeDrv | API_SpipeDrvInstall | 安装字符流管道设备驱动程序 |
tpsFsDrv | API_TpsFsDrvInstall | 安装 TPS 文件系统驱动程序 |
fatFsDrv | API_FatFsDrvInstall | 安装 FAT 文件系统驱动程序 |
ramFsDrv | API_RamFsDrvInstall | 安装 ramfs 文件系统驱动程序 |
romFsDrv | API_RomFsDrvInstall | 安装 romfs 文件系统驱动程序 |
nfsDrv | API_NfsDrvInstall | 安装 NFS 文件系统驱动程序 |
yaffsDrv | API_YaffsDrvInstall | 安装 yaffs 文件系统驱动程序 |
canDrv | API_CanDrvInstall | 安装 can 驱动程序 |
创建设备
系统启动时通过 halDevInit 函数初始化目标系统静态设备组件,该函数中的代码实现如下:
#include <SylixOS.h>
static VOID halDevInit (VOID)
{
rootFsDevCreate();
procFsDevCreate();
shmDevCreate();
randDevCreate();
SIO_CHAN *psio0 = sioChanCreate(0);
ttyDevCreate("/dev/ttyS0", psio0, 30, 50);
boardDevInit();
yaffsDevCreate("/yaffs2");
}
用户可以根据需要,在该函数中创建设备。该函数中主要做了如下操作:
rootFsDevCreate 宏定义的是 API_RootFsDevCreate 函数,该函数创建根文件系统,函数原型如下:
#include <SylixOS.h>
INT API_RootFsDevCreate (VOID);
procFsDevCreate 宏定义的是 API_ProcFsDevCreate 函数,该函数创建 proc 文件系统,函数原型如下:
#include <SylixOS.h>
INT API_ProcFsDevCreate (VOID);
shmDevCreate 宏定义的是 API_ShmDevCreate 函数,该函数创建共享内存设备,函数原型如下:
#include <SylixOS.h>
INT API_ShmDevCreate (VOID);
randDevCreate 宏定义的是 API_RandDevCreate 函数,该函数创建随机数文件,函数原型如下:
#include <SylixOS.h>
INT API_RandDevCreate (VOID);
sioChanCreate 函数用于创建串口 0 通道,函数原型如下:
#include <SylixOS.h>
SIO_CHAN *sioChanCreate (INT iChannelNum);
函数 sioChanCreate 原型分析:
- 此函数成功返回 SIO 通道。
- 参数 iChannelNum 是硬件通道号。
ttyDevCreate 宏定义的是 API_TtyDevCreate 函数,该函数用于添加 TTY 设备,函数原型如下:
#include <SylixOS.h>
INT API_TtyDevCreate (PCHAR pcName,
SIO_CHAN *psiochan,
size_t stRdBufSize,
size_t stWrtBufSize)
函数 API_TtyDevCreate 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 pcName 是设备名。
- 参数 psiochan 是同步 I/O 函数集。
- 参数 stRdBufSize 是输入缓冲区大小。
- 参数 stWrtBufSize 是输出缓冲区大小。
7.yaffsDevCreate 宏定义的是 API_YaffsDevCreate 函数,该函数创建 YAFFS 设备,函数原型如下:
#include <SylixOS.h>
LW_API INT API_YaffsDevCreate(PCHAR pcName);
函数 API_YaffsDevCreate 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 pcName 是设备名(设备挂接的节点地址)。
创建内核标准文件描述符
系统启动时通过 halStdFileInit 函数初始化目标系统标准文件描述符,函数代码实现如下:
#include <SylixOS.h>
static VOID halStdFileInit (VOID)
{
int iFd = open("/dev/ttyS0", O_RDWR, 0);
if (iFd >= 0) {
ioctl(iFd, FIOBAUDRATE, SIO_BAUD_115200);
ioctl(iFd, FIOSETOPTIONS, (OPT_TERMINAL & (~OPT_7_BIT)));
ioGlobalStdSet(STD_IN, iFd);
ioGlobalStdSet(STD_OUT, iFd);
ioGlobalStdSet(STD_ERR, iFd);
}
}
内核标准文件描述符有三种,具体参见下表。在 halStdFileInit 函数中,将这三个标准文件描述符定向到串口设备/dev/ttyS0。
标准文件描述符 | 说明 |
---|---|
STD_IN | 标准输入 |
STD_OUT | 标准输出 |
STD_ERR | 标准错误 |
日志系统初始化
日志系统将系统运行的每一个状况信息都使用文字记录下来,这些信息有助于观察系统运行过程中正常状态和系统运行错误时快速定位错误位置的途径等。
系统启动时通过 halLogInit 函数初始化目标系统日志系统。代码实现如下所示:
#include <SylixOS.h>
static VOID halLogInit (VOID)
{
fd_set fdLog;
FD_ZERO(&fdLog);
FD_SET(STD_OUT, &fdLog);
API_LogFdSet(STD_OUT + 1, &fdLog);
}
该函数中主要调用 API_LogFdSet 函数初始化日志系统。API_LogFdSet 函数首先设置 LOG 需要关心的文件集,然后启动内核打印线程。函数原型如下所示:
#include <SylixOS.h>
INT API_LogFdSet (INT iWidth, fd_set *pfdsetLog);
函数 API_LogFdSet 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 iWidth 是最大的文件描述符加一,类似 select()第一个参数。
- 参数 pfdsetLog 是新的文件集。
在日志系统中,使用消息队列来传递信息。当内核打印线程从消息队列中读取到数据时,就向文件集中的所有对象输出信息。消息的来源为 API_LogPrintk 函数和 API_logMsg 函数。
挂载磁盘系统
用户可以根据需要,在 halBootThread 函数中挂载对应的磁盘系统。现以 mini2440 的 SylixOS BSP 为例,代码片段如下:
#ifdef __GNUC__
nand_init();
mtdDevCreateEx("/n");
#else
nandDevCreateEx("/n");
#endif
nandInit 函数初始化 NandFlash 驱动,函数原型如下:
#include <SylixOS.h>
VOID nandInit (VOID);
mtdDevCreateEx 函数用来挂载文件系统。该函数中,会首先初始化 boot 分区 YAFFS 设备结构体以及 common 分区 YAFFS 设备结构体,然后调用 yaffs_add_device 函数,将这两个对象添加到 YAFFS 设备表,执行 yaffs_mount 命令进行挂载。函数原型如下:
#include <SylixOS.h>
int mtdDevCreateEx (char *pcDevName);
函数 mtdDevCreateEx 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 pcDevName 是设备名。
创建根文件系统目录
系统启动时通过 halStdDirInit 函数创建根文件系统目录,目录的权限为文件夹默认权限(754)。需要创建的目录如下表所示:
目录 | SD 或 eMMC 符号链接路径 | NAND FLASH 符号链接路径 | 说明 |
---|---|---|---|
/usb | 无 | 无 | 通常用于挂载 USB 设备 |
/boot | /media/sdcard0 | /yaffs2/n0/boot | 引导程序文件,例如:BSP;时常是一个单独的分区 |
/etc | /media/sdcard1/etc | /yaffs2/n0/etc | 系统主要的设定档几乎都放置在这个目录内,例如环境变量配置文件 profile、网络配置文件 ifparam.ini、系统启动脚本 startup.sh |
/ftk | /media/sdcard1/ftk | /yaffs2/n1/ftk | FTK 图形系统 |
/qt | /media/sdcard1/qt | /yaffs2/n1/qt | Qt 图形系统 |
/lib | /media/sdcard1/lib | /yaffs2/n1/lib | /bin/和/sbin/中二进制文件必要的库文件。对于 NAND Flash 还会创建/yaffs2/n1/lib/modules 文件夹 |
/usr | /media/sdcard1/usr | /yaffs2/n1/usr | 默认软件都会存于该目录下。用于存储只读用户数据的第二层次;包含绝大多数的用户工具和应用程序。对于 NAND Flash 还会创建/yaffs2/n1/usr/lib 文件夹 |
/bin | /media/sdcard1/bin | /yaffs2/n1/bin | 需要在单用户模式可用的必要命令(可执行文件);面向所有用户,例如:cat、ls、cp,和/usr/bin 类似 |
/sbin | /media/sdcard1/sbin | /yaffs2/n1/sbin | 必要的系统二进制文件 |
/apps | /media/sdcard1/apps | /yaffs2/n1/apps | 用户应用程序 |
/home | /media/sdcard1/home | /yaffs2/n1/home | 用户的家目录,包含保存的文件、个人设置等 |
/root | /media/sdcard1/root | /yaffs2/n1/root | 超级用户的家目录 |
/var | /media/sdcard1/var | /yaffs2/n1/var | 变量文件,即在正常运行的系统中其内容不断变化的文件,如日志,脱机文件和临时电子邮件文件 |
/tmp | /var/tmp | /yaffs2/n1/tmp | 临时文件,在系统重启时目录中文件不会被保留 |
sdcard0 和 sdcard1 分别为 SD 或 eMMC 的两个分区,其中 sdcard0 通常为 FAT32 文件系统,作为启动分区;sdcard1 通常为 TpsFs 文件系统。n0 和 n1 为 NAND 的两个分区,均为 YAFFS 文件系统。
配置系统环境
系统环境的配置包括环境变量的配置、设置时区和设置 rootfs 时间基准,下面分别介绍。
环境变量的配置
环境变量(environment variables)是指在操作系统中用来指定操作系统运行环境的参数,如:临时文件夹位置和系统文件夹位置等。SylixOS 初始环境变量如下表所示:
数据传输标志 | 含义 |
---|---|
SYSTEM | 系统打印信息 |
VERSION | 版本信息 |
LICENSE | 许可信息 |
TMPDIR | 临时文件夹 |
TZ | 时区 |
KEYBOARD | 键盘 |
MOUSE | 鼠标 |
TSLIB_TSDEVICE | 触摸屏校准关联设备 |
TSLIB_CALIBFILE | 触摸屏校准文件 |
SO_MEM_PAGES | 动态内存虚拟页面数量 |
FIO_FLOAT | fio 浮点支持 |
SYSLOGD_HOST | syslog 服务器地址 |
NFS_CLIENT_AUTH | NFS 默认使用 auth_unix |
NFS_CLIENT_PROTO | NFS 默认使用 udp 协议 |
PATH | PATH 启动时默认路径 |
LD_LIBRARY_PATH | LD_LIBRARY_PATH 默认值 |
LANG | 多国语言与编码 |
LC_ALL | 多国语言与编码 |
PATH_LOCALE | 多国语言与编码 |
DEBUG_CPU | 是否将被调对象锁定到一个 CPU |
LOGINBL_TO | 网络登录黑名单刷新时间 |
LOGINBL_REP | 连续出现几次则加入黑名单 |
LUA_PATH | LUA 环境 |
LUA_CPATH | LUA 环境 |
TERM | 终端 |
TERMCAP | 终端 |
内核 shell 系统初始化时,halShellInit 中的 API_TShellInit 函数会初始化系统环境变量。函数原型如下所示:
#include <SylixOS.h>
VOID API_TShellInit (VOID);
在 halBootThread 函数中会调用 system("varload")指令,从/etc/profile 中读取环境变量。
设置时区
环境变量配置完成后,会调用 lib_tzset 函数,该函数通过环境变量中的 TZ 设置时区。在 lib_tzset 函数中,如果获取 TZ 环境变量失败,则使用默认时区信息,为中国标准时间。该函数原型如下所示:
#include <SylixOS.h>
VOID lib_tzset (VOID);
设置 rootfs 时间基准
rtcToRoot 宏定义的是 API_RtcToRoot 函数,该函数用于设置当前 RTC 时间为根文件系统基准时间。此函数成功返回 ERROR_NONE 。函数原型如下所示:
#include <SylixOS.h>
INT API_RtcToRoot (VOID);
网络系统初始化
系统启动时通过 halNetInit 和 halNetifAttch 函数初始化网络系统。网络初始化一般放在 shell 初始化之后,因为初始化网络组件时,会自动注册 shell 命令。
halNetInit 函数主要是初始化网络组件,函数代码实现如下:
#include <SylixOS.h>
static VOID halNetInit (VOID)
{
API_NetInit();
API_NetSnmpInit();
#if LW_CFG_NET_PING_EN > 0
API_INetPingInit();
API_INetPing6Init();
#endif
#if LW_CFG_NET_NETBIOS_EN > 0
API_INetNetBiosInit();
API_INetNetBiosNameSet("sylixos");
#endif
#if LW_CFG_NET_TFTP_EN > 0
API_INetTftpServerInit("/tmp");
#endif
#if LW_CFG_NET_FTPD_EN > 0
API_INetFtpServerInit("/");
#endif
#if LW_CFG_NET_TELNET_EN > 0
API_INetTelnetInit(LW_NULL);
#endif
#if LW_CFG_NET_NAT_EN > 0
API_INetNatInit();
#endif
#if LW_CFG_NET_NPF_EN > 0
API_INetNpfInit();
#endif
#if LW_CFG_NET_VPN_EN > 0
API_INetVpnInit();
#endif
}
函数中的主要操作如下:
API_NetInit 函数:向操作系统内核注册网络组件,函数原型如下:
#include <SylixOS.h>
VOID API_NetInit (VOID);
API_INetPingInit 函数:初始化 ping 工具,函数原型如下:
#include <SylixOS.h>
VOID API_INetPingInit (VOID);
API_INetPing6Init 函数:初始化 Ipv6 ping 工具,函数原型如下:
#include <SylixOS.h>
VOID API_INetPing6Init (VOID);
API_INetNetBiosInit 和 API_INetNetBiosNameSet 函数:初始化 lwip netbios 简易名字服务器,函数原型如下:
#include <SylixOS.h>
VOID API_INetNetBiosInit (VOID);
ULONG API_INetNetBiosNameSet (CPCHAR pcLocalName);
函数 API_INetNetBiosNameSet 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 pcLocalName 是名称。
API_INetTftpServerInit 函数:初始化 tftp 服务器,函数原型如下:
#include <SylixOS.h>
VOID API_INetTftpServerInit (CPCHAR pcPath);
函数 API_INetTftpServerInit 原型分析:
- 参数 pcPath 是本地目录。
API_INetFtpServerInit 函数:初始化 tftp 服务器根目录,函数原型如下:
#include <SylixOS.h>
VOID API_INetFtpServerInit (CPCHAR pcPath);
函数 API_INetFtpServerInit 原型分析:
- 参数 pcPath 是本地目录。
API_INetTelnetInit 函数:初始化 telnet 工具,函数原型如下:
#include <SylixOS.h>
VOID API_INetTelnetInit (const PCHAR pcPtyStartName);
函数 API_INetFtpServerInit 原型分析:
- 参数 pcPtyStartName 是 pty 起始文件名。
API_INetNatInit 函数:internet NAT 初始化,函数原型如下:
#include <SylixOS.h>
VOID API_INetNatInit (VOID);
API_INetNpfInit 函数:net packet filter 初始化,函数原型如下:
#include <SylixOS.h>
INT API_INetNpfInit (VOID);
函数 API_INetNpfInit 原型分析:
- 此函数成功返回 ERROR_NONE 。
API_INetVpnInit 函数:初始化VPN服务,函数原型如下:
#include <SylixOS.h>
VOID API_INetVpnInit (VOID);
POSIX 兼容系统初始化
POSIX 子系统的初始化函数是 halPosixInit。如果系统支持 proc 文件系统,则必须放在 proc 文件系统安装之后。halPosixInit 函数的代码实现如下:
#include <SylixOS.h>
static VOID halPosixInit (VOID)
{
API_PosixInit();
}
该函数中调用 API_PosixInit 函数初始化 posix 系统,函数原型如下:
#include <SylixOS.h>
VOID API_PosixInit (VOID);
内核符号系统初始化
驱动也是存在于内核空间的,它的每一个函数每一个变量都会有对应的符号,这部分符号也可以称作内核符号,它们不导出就只能为自身所用,导出后就可以成为公用,对于导出的那部分内核符号就是常说的内核符号表。
halSymbolInit 函数初始化目标系统符号表环境,为模块加载提供环境。halSymbolInit 函数代码实现如下:
#include <SylixOS.h>
static VOID halSymbolInit (VOID)
{
#ifdef __GNUC__
void *__aeabi_read_tp();
#endif
API_SymbolInit();
#ifdef __GNUC__
symbolAddAll();
API_SymbolAdd("__aeabi_read_tp", (caddr_t)__aeabi_read_tp,
LW_SYMBOL_FLAG_XEN);
API_SymbolAdd("lcdDevInit", (caddr_t)lcdDevInit, LW_SYMBOL_FLAG_REN);
API_SymbolAdd("boardGpioCheck", (caddr_t)boardGpioCheck,
LW_SYMBOL_FLAG_REN);
API_SymbolAdd("sysClockGet", (caddr_t)sysClockGet, LW_SYMBOL_FLAG_REN);
#endif
}
函数中的主要操作如下:
API_SymbolInit 函数:初始化系统符号表,函数原型如下:
#include <SylixOS.h>
VOID API_SymbolInit (VOID);
symbolAddAll 函数:将系统的所有 API 导入到符号表中,供模块装载器使用,函数原型如下:
#include <SylixOS.h>
static LW_INLINE INT symbolAddAll (VOID);
API_SymbolAdd 函数:向符号表添加一个符号,函数原型如下:
#include <SylixOS.h>
INT API_SymbolAdd (CPCHAR pcName, caddr_t pcAddr, INT iFlag);
函数 API_SymbolAdd 原型分析:
- 此函数成功返回 ERROR_NONE 。
- 参数 pcName 是符号名。
- 参数 pcAddr 是地址。
- 参数 iFlag 参数是符号类型,可参见下表。
符号类型 | 说明 |
---|---|
LW_SYMBOL_FLAG_STATIC | 不能删除的静态符号 |
LW_SYMBOL_FLAG_REN | 可读符号 |
LW_SYMBOL_FLAG_WEN | 可写符号 |
LW_SYMBOL_FLAG_XEN | 可执行符号 |
内核装载器初始化
系统启动时通过 halLoaderInit 函数初始化目标系统程序或模块装载器,函数的代码实现如下:
#include <SylixOS.h>
static VOID halLoaderInit (VOID)
{
API_LoaderInit();
}
该函数调用 API_LoaderInit 函数初始化 loader 组件。主要是安装符号表查询的回调函数、安装 I/O 系统回调组和系统重启回调函数、以及初始化 loader 内部 shell 命令。函数原型如下:
#include <SylixOS.h>
VOID API_LoaderInit (VOID);
内核跟踪器初始化
SylixOS 提供了内核跟踪的功能,通过该功能上层应用程序可以很方面地监视到内核的运行情况(例如:中断信息、信号量信息,文件操作信息等),以下函数为跟踪器创建一个跟踪通道:
static VOID halMonitorInit (VOID)
{
}
注意 :
SylixOS 支持普通文件与网络两种跟踪通道,也可以通过“monitor”命令启动跟踪器,需要注意的是,需要配置 LW_CFG_MONITOR_EN 宏来启用内核跟踪器功能。
执行系统启动脚本
系统启动时通过执行 system("shfile /etc/startup.sh")指令,执行系统启动脚本 startup.sh。该指令必须在 shell 初始化后调用。
用户可以通过该启动脚本,设置开机自启动。编辑“/etc/startup.sh”,把启动程序的 shell 命令输入进去即可,类似于 windows 下的“启动”。
启动系统内核主线程
在 BSP 的初始化工作完成后,会创建并启动 t_main 线程,即系统内核主线程。t_main 的代码实现如下:
#include <SylixOS.h>
int t_main (void)
{
struct utsname name;
uname(&name);
printf("sysname : %s\n", name.sysname);
printf("nodename : %s\n", name.nodename);
printf("release : %s\n", name.release);
printf("version : %s\n", name.version);
printf("machine : %s\n", name.machine);
Lw_TShell_Create(STDOUT_FILENO, LW_OPTION_TSHELL_PROMPT_FULL | LW_OPTION_TSHELL_VT100);
return (0);
}
在该函数中,通过调用 uname 函数,获取当前系统的信息。在输出这些信息后,会调用 Lw_TShell_Create 来创建一个 ttiny shell 系统。Lw_TShell_Create 宏定义的是 API_TShellCreate 函数,函数原型如下:
#include<SylixOS.h>
LW_OBJECT_HANDLE API_TShellCreate (INT iTtyFd, ULONG ulOption)
函数 API_TShellCreate 原型分析:
- 该函数返回 shell 线程的句柄。
- 参数 iTtyFd 是终端设备的文件描述符。在 BSP 中传的参数是 STDOUT_FILENO ,该宏是标准输出描述符。
- 参数 ulOption 是启动参数。具体参见下表。
启动参数 | 说明 |
---|---|
LW_OPTION_TSHELL_VT100 | 使用 VT100 终端控制字符 |
LW_OPTION_TSHELL_AUTHEN | 使用用户认证 |
LW_OPTION_TSHELL_NOLOGO | 是否不显示 logo |
LW_OPTION_TSHELL_NOECHO | 无回显 |
LW_OPTION_TSHELL_PROMPT_FULL | 全部显示命令提示符 |
LW_OPTION_TSHELL_CLOSE_FD | shell 退出时关闭 fd |