【SemiDrive源码分析】【X9芯片启动流程】15 - freertos_safetyos目录 R5 SafetyOS 之 tcpip_init 代码流程分析
- 1. tcpip_init() 初始化tcpip相关模块,初始化MailBox邮箱,创建tcpip_thread 线程
- 1.1 lwip_init() 初始化回环网卡,随机生成Port口,配置超时时间及处理函数
- 1.2 tcpip_thread() 线程函数
本 SemiDrive源码分析 之 Yocto源码分析 系列文章汇总如下:
- 《【SemiDrive源码分析】【Yocto源码分析】01 - yocto/base目录源码分析(编译环境初始化流程)》
- 《【SemiDrive源码分析】【Yocto源码分析】02 - yocto/meta-openembedded目录源码分析》
- 《【SemiDrive源码分析】【Yocto源码分析】03 - yocto/meta-semidrive目录及Yocto Kernel编译过程分析(上)》
- 《【SemiDrive源码分析】【Yocto源码分析】04 - yocto/meta-semidrive目录及Yocto Kernel编译过程分析(下)》
- 《【SemiDrive源码分析】【Yocto源码分析】05 - 找一找Yocto Kernel编译过程中所有Task的源码在哪定义的呢?》
- 《【SemiDrive源码分析】【Yocto源码分析】06 - Kernel编译生成的Image.bin、Image_nobt.dtb、modules.tgz 这三个文件分别是如何生成的?》
- 《【SemiDrive源码分析】【Yocto源码分析】07 - core-image-base-x9h_ref_serdes.rootfs.ext4 文件系统是如何生成的》
- 《【SemiDrive源码分析】【X9芯片启动流程】08 - X9平台 lk 目录源码分析 之 目录介绍》
- 《【SemiDrive源码分析】【X9芯片启动流程】09 - X9平台系统启动流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】10 - BareMetal_Suite目录R5 DIL.bin 引导程序源代码分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】11 - freertos_safetyos目录Cortex-R5 DIL2.bin 引导程序源代码分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】12 - freertos_safetyos目录Cortex-R5 DIL2.bin 之 sdm_display_init 显示初始化源码分析》
- 《【SemiDrive源码分析】【X9芯片驱动调试】13 - GPIO 配置方法》
- 《【SemiDrive源码分析】【X9芯片启动流程】14 - freertos_safetyos目录Cortex-R5 SafetyOS/RTOS工作流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】15 - freertos_safetyos目录 R5 SafetyOS 之 tcpip_init() 代码流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】16 - freertos_safetyos目录 R5 SafetyOS 之 LK_INIT_LEVEL_PLATFORM 阶段代码流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】17 - freertos_safetyos目录 R5 SafetyOS 之 LK_INIT_LEVEL_TARGET 阶段代码流程分析》
- 《【SemiDrive源码分析】【X9芯片启动流程】18 - freertos_safetyos目录 R5 SafetyOS 之 .apps 应用启动代码流程分析》
前文,我们分析Cortex-R5
SafetyOS
系统的启动流程,分析到执行LK_INIT_LEVEL_THREADING
阶段的任务,
在这个阶段时,主要是执行boot_sec()
、lwip_init_hook()
两个函数,其中:
-
boot_sec()
主要是Safety R5
CPU
触发Secure R5
CPU
重启,加载并运行Ssytem
镜像。 -
lwip_init_hook()
主要是初始化并启动lwip
这个小型开源的TCP/IP
协议栈功能。
lwip
是一个小型开源的TCP/IP
协议栈源码,主要目的是在保持TCP
协议主要功能的基础上减少对RAM
的占用,
有无操作系统的支持都可以运行,它只需十几KB
的RAM
和40K
左右的ROM
就可以运行。
它由宏控SUPPORT_LWIP
来控制是否编译。
在lwip_init_hook()
中主要是对tcpip_init()
函数的封装,如下:
/* run lwip init as soon as threads are running */
void lwip_init_hook(uint level){
tcpip_init(NULL, NULL);
}
LK_INIT_HOOK(lwip, &lwip_init_hook, LK_INIT_LEVEL_THREADING);
那本文来分析下tcpip_init()
这个小型TCP/IP
开源协议栈的初始化过程。
1. tcpip_init() 初始化tcpip相关模块,初始化MailBox邮箱,创建tcpip_thread 线程
主要工作如下:
- 初始化回环网卡,随机生成
Port
口,配置超时时间及处理函数 - 初始化
tcpip mailbox
邮箱 - 创建
tcpip_thread
线程
/* @ingroup lwip_os Initialize this module: initialize all sub modules, start the tcpip_thread */
void tcpip_init(tcpip_init_done_fn initfunc, void *arg)
{
// 1. 初始化回环网卡,随机生成Port口,配置超时时间及处理函数
lwip_init();
tcpip_init_done = initfunc;
tcpip_init_done_arg = arg;
// 2. 初始化 tcpip mailbox 邮箱
if (sys_mbox_new(&tcpip_mbox, TCPIP_MBOX_SIZE) != ERR_OK) { LWIP_ASSERT("failed to create tcpip_thread mbox", 0);}
================>
mbox->sem = CreateSemaphore(0, 0, MAX_QUEUE_ENTRIES, 0);
memset(&mbox->q_mem, 0, sizeof(u32_t)*MAX_QUEUE_ENTRIES);
mbox->head = 0;
mbox->tail = 0;
<================
// 3. 创建 tcpip_thread 线程
sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);
}
1.1 lwip_init() 初始化回环网卡,随机生成Port口,配置超时时间及处理函数
主要工作如下:
- 初始化并启动
127.0.0.1
回环网卡 - 从
49152
到65535
随机生成一个UDP Port口
- 从
49152
到65535
随机生成一个TCP Port口
- 配置各场景超时时间及超时函数
/* Initialize all modules, Use this in NO_SYS mode. Use tcpip_init() otherwise*/
void lwip_init(void){
/* Modules initialization */
stats_init(); // 空函数 lwip_stats.mem.name = "MEM";
sys_init(); // 空函数
lwip_mem_init(); // 空函数
memp_init(); // 定义了MEMP_MEM_MALLOC ,不需要提前申请内存池,这个函数不会跑
pbuf_init(); // 空函数
netif_init(); // 初始化并启动 127.0.0.1 回环网卡
===============>
ip4_addr_t loop_ipaddr, loop_netmask, loop_gw;
IP4_ADDR(&loop_gw, 127, 0, 0, 1);
IP4_ADDR(&loop_ipaddr, 127, 0, 0, 1);
IP4_ADDR(&loop_netmask, 255, 0, 0, 0);
netif_add(&loop_netif, LOOPIF_ADDRINIT NULL, netif_loopif_init, tcpip_input);
netif_set_link_up(&loop_netif);
netif_set_up(&loop_netif);
<===============
ip_init(); // 空函数
etharp_init(); // 空函数
raw_init(); // 空函数
udp_init(); // 从49152 through 65535随机生成一个UDP Port口:udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
tcp_init(); // 从49152 through 65535随机生成一个TCP Port口:tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND());
// 0
dns_init();
/* LWIP_DNS */
// 0
ppp_init();
sys_timeouts_init(); // 配置各场景超时时间及超时函数
==================>
/** Initialize this module */
void sys_timeouts_init(void)
{
size_t i;
/* tcp_tmr() at index 0 is started on demand */
for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
sys_timeout(lwip_cyclic_timers[i].interval_ms, lwip_cyclic_timer, LWIP_CONST_CAST(void *, &lwip_cyclic_timers[i]));
}
}
// 超时时间定义于: buildsystem\rtos\lk_boot\3rd\lwip\src\core\timeouts.c
const struct lwip_cyclic_timer lwip_cyclic_timers[] = {
{TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, // 250ms, 如果超时运行 tcp_tmr() 释放
/* LWIP_TCP */
{IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, // 1s , 如果超时运行 ip_reass_tmr() 释放
{ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, // 1s , 如果超时运行 ip_reass_tmr() 释放
/* LWIP_ARP */
/* LWIP_IPV4 */
// 后面的宏都没定义,我就不写了
};
<==================
}
1.2 tcpip_thread() 线程函数
主要工作如下:
/**
* The main lwIP thread. This thread has exclusive access to lwIP core functions (unless access to them is not locked).
* Other threads communicate with this thread using message boxes.
* It also starts all the timers to make sure they are running in the right thread context.
*/
static void tcpip_thread(void *arg)
{
struct tcpip_msg *msg;
LWIP_UNUSED_ARG(arg);
LWIP_MARK_TCPIP_THREAD();
LOCK_TCPIP_CORE();
if (tcpip_init_done != NULL) {
tcpip_init_done(tcpip_init_done_arg);
}
while (1) { /* MAIN Loop */
LWIP_TCPIP_THREAD_ALIVE();
/* wait for a message, timeouts are processed while waiting */
TCPIP_MBOX_FETCH(&tcpip_mbox, (void **)&msg);
if (msg == NULL) {
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: NULL\n"));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
continue;
}
tcpip_thread_handle_msg(msg);
}
}