openwrt mtk7628nn启动流程分析

本文详细解析了OpenWRT系统在mtk7628n平台上的启动流程,包括硬件启动、内核加载、init进程启动、procd初始化过程及系统服务启动等关键步骤,揭示了从硬件启动到系统完全运行的全过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 概述

       本文以mtk7628n openwrt为软件环境进行分析

       在linux的发展过程中,linux的启动程序也在发展,从sysv init到现在的upstart、systemd,通常该程序是进程号为1的进程,该程序在linux系统有着举足轻重的地方。在openwrt中,使 用了另外一种启动程序叫做procd,本文的重点并不在于介绍procd,本文主要介绍并解析procd、preinit及各种脚本如何完成整个系统的初始化。

2 启动顺序概述

       2.1 硬件启动       

  • 路由器cpu根据引脚高低电平选择spi flash启动还是nand flash启动

       2.2 软件启动

  • bootloader加载内核
  • 内核开动,同时扫描mtd文件系统分区
  • 内核执行/etc/preinit脚本
  • /etc/preinit执行/sbin/init二进制程序
  • /sbin/init根据/etc/inittab定义执行启动过程
  • /etc/inittab首先执行/etc/init.d/rcS,此脚本将顺序启动/etc/rc.d/目录以S开关的脚本

3 软件启动详解

        3.1  启动init进程

              位于linux-3.3.8/init/main.c

               汇编语言  b star_kernel----->start_kernel()--->rest_init()–→kernel_init()--→init_post()

              重点分析init_post()函数

              在openwrt系统中一般都会通过patch方式对源码进行修改,而对于init_post()函数,

             

              但是在QCA9531平台启动内核启动的代码中会作出如下修改,target/linux/generic/patches-3.4/921-use_preinit_as_init.patch

              

             删除了默认的启动方式,直接启动/etc/preinit。

             我们只分析mtk7628n平台的,从代码中可以看到init_post函数要启动init进程

        3.2 init进程的作用

             ./build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/initd/init.c

              

                 

            early()

                 ./build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/initd/early.c

  • mount /proc /sys /tmp /dev /dev/pts目录(early_mount)
  • 创建设备节点和/dev/null文件结点(early_dev)
  • 设置PATH环境变量(early_env)
  • 初始化/dev/console

          cmdline()

  • 根据/proc/cmdline内容init_debug=([0-9]+)判断debug级别

          watchdog_init()

  • 初始化内核watchdog(/dev/watchdog)
  • 如果存在/dev/watchdog设备,设置watchdog timeout等于30秒,如果内核在30秒内没有收到任何数据将重启系统。用户状进程使用uloop定时器设置5秒周期向/dev/wathdog设备写一些数据通知内核,表示此用户进程在正常工作

           加载内核模块

  • 创建子进程/sbin/kmodloader加载/etc/modules-boot.d/目录中的内核模块

           preinit()

                ./build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/initd/preinit.c

                

                

                      /sbin/init进程是来自procd这个package里面的,不再使用busybox了,而且它是从内核调用过来的,所以它的pid是1,pid 0是内核本身。fork创建父子进程,子进程做一些procd的配置后退出,注意这时procd并不算真正起来,它的pid不是1;父进程继续创建父子进程,

             子进程调用/etc/preinit后退出。在这过程中/sbin/init的pid为1,始终没有让位。

                   创建子进程执行/etc/preinit脚本时,此时PREINIT环境变量被设置为1,主进程(pid=1)同时使用uloop_process_add()把/etc/preinit子进程加入uloop进行监控,当/etc/preinit执行结束时回调plugd_proc_cb()函数把监控/etc/preinit进程对应对象中pid属性设置为0,表示/etc/preinit已执行完成
                   创建子进程执行/sbin/procd -h/etc/hotplug-preinit.json,主进程同时使用uloop_process_add()把/sbin/procd子进程加入uloop进行监控,当/sbin/procd进程结束时回调spawn_procd()函数,spawn_procd()函数繁衍后继真正使用的/sbin/procd进程,这时procd的进程号将是1。

             下面这个函数会用procd将/sbin/init进程替换,从而procd的进程号为1:

              

             最终大家在openwrt环境中看到的进程运行结果是

            

 3.3 procd进程的作用

       build_dir/target-mipsel_24kec+dsp_uClibc-0.9.33.2/procd-2014-09-15/state.c       

       

    

       procd有5个状态,分别为STATE_EARLYSTATE_INITSTATE_RUNNINGSTATE_SHUTDOWNSTATE_HALT,这5个状态将按顺序变化,当前状态保存在全局变量state中,可通过procd_state_next()函数使用状态发生变化

      STATE_EARLY状态 - init前准备工作

  • 初始化watchdog
  • 根据"/etc/hotplug.json"规则监听hotplug
  • procd_coldplug()函数处理,把/dev挂载到tmpfs中,fork udevtrigger进程产生冷插拔事件,以便让hotplug监听进行处理
  • udevstrigger进程处理完成后回调procd_state_next()函数把状态从STATE_EARLY转变为STATE_INIT

      STATE_INIT状态 - 初始化工作

  • 连接ubusd,此时实际上ubusd并不存在,所以procd_connect_ubus函数使用了定时器进行重连,而uloop_run()需在初始化工作完成后才真正运行。当成功连接上ubusd后,将注册service main_object对象,system_object对象、watch_event对象(procd_connect_ubus()函数),
  • 初始化services(服务)和validators(服务验证器)全局AVL tree
  • 把ubusd服务加入services管理对象中(service_start_early)
  • 根据/etc/inittab内容把cmd、handler对应关系加入全局链表actions中
  • 顺序加载respawnaskconsoleaskfirstsysinit命令
  • sysinit命令把/etc/rc.d/目录下所有启动脚本执行完成后将回调rcdone()函数把状态从STATE_INITl转变为STATE_RUNNING

      STATE_RUNNING状态

  • 进入STATE_RUNNING状态后procd运行uloop_run()主循环

 3.4 /etc/rc.d/*目录下启动脚本简介

      

     https://wiki.openwrt.org/doc/techref/process.boot

     S开头的表示要启动的

     K开头表示要杀掉的

     根据数字顺序表示启动顺序

4 参考文献

    https://wiki.openwrt.org/doc/techref/start

<think>好的,用户现在的问题是在MTK7628平台上进行OPEN62541的交叉编译。首先需要确认用户的需求是否正确理解。MTK7628是联发科的WiFiSoC,属于MIPS架构,而用户之前提到的OPN62541是泰凌微的蓝牙芯片,属于RISC-V架构,两者完全不同。用户可能混淆了芯片型号,或者是想在不同平台上部署OPN62541。需要明确当前询问的是MTK7628平台上的OPEN62541编译。接下来,需要回忆MTK7628的基本信息。这款芯片采用MIPS24KEc核心,通常运行OpenWrt系统。OPEN62541是一个开源的OPCUA库,用C语言编写,适合嵌入式设备。交叉编译的关键在于配置正确的工具链、依赖库和目标平台参数。用户之前提供的参考内容中提到了Telink的工具链和环境配置,但这对MTK7628不适用。需要替换为联发科或OpenWrt的SDK。OPEN62541依赖如mbedTLS、libuuid等,这些在MTK7628平台上可能需要提前交叉编译。接下来要考虑具体步骤。首先是准备OpenWrt的SDK,设置环境变量。然后是获取OPEN62541源码。编译时需要指定交叉编译器、sysroot路径、ARCH参数为MIPS。配置CMake参数时需禁用动态加载和Amalgamation测试以减少依赖,同时指定openssl路径。用户可能的难点在于依赖库的交叉编译,特别是libuuid在OpenWrt中的处理。此外,内存限制方面,需要优化OPEN62541配置,关闭非必需功能如PubSub和HISTORICAL,减小二进制体积。最后编译生成静态库或可执行文件后,部署到设备测试。还需要注意日志系统整合,改用OpenWrt的log机制,避免默认的syslog占用过大。另外,安全连接所需的mbedTLS版本兼容性也是潜在问题点。最后,生成的问题应围绕MTK7628平台优化、内存管理和功能裁剪展开。</think> 要在MTK7628平台上交叉编译嵌入式OPC UA库`open62541`,需遵循以下步骤(基于MIPS架构和OpenWrt环境): ### 一、环境准备 1. **工具链获取** 下载MTK7628专用OpenWrt SDK(以Linux环境为例): ```bash wget https://downloads.openwrt.org/releases/21.02.0/targets/ramips/mt76x8/openwrt-sdk-21.02.0-ramips-mt76x8_gcc-8.4.0_musl.Linux-x86_64.tar.xz tar -xvf openwrt-sdk-*.tar.xz export STAGING_DIR=$(pwd)/openwrt-sdk-*/staging_dir export PATH=$PATH:$STAGING_DIR/toolchain-mipsel_24kc_gcc-8.4.0_musl/bin ``` 2. **依赖库交叉编译** ```bash # 交叉编译zlib ./configure --prefix=$STAGING_DIR/host --host=mipsel-openwrt-linux make install # 交叉编译mbedTLS (需修改CMakeLists.txt) cmake -DCMAKE_C_COMPILER=mipsel-openwrt-linux-gcc \ -DCMAKE_INSTALL_PREFIX=$STAGING_DIR/host \ -DENABLE_PROGRAMS=OFF .. make install ``` ### 二、open62541编译配置 ```bash mkdir build && cd build cmake .. \ -DCMAKE_C_COMPILER=mipsel-openwrt-linux-gcc \ -DCMAKE_CXX_COMPILER=mipsel-openwrt-linux-g++ \ -DCMAKE_SYSROOT=$STAGING_DIR/target-mipsel_24kc_musl \ -DCMAKE_FIND_ROOT_PATH=$STAGING_DIR/host \ -DUA_ENABLE_AMALGAMATION=ON \ -DUA_ENABLE_ENCRYPTION=MBEDTLS \ -DUA_LOGLEVEL=200 \ -DMBEDTLS_INCLUDE_DIRS=$STAGING_DIR/host/include \ -DMBEDTLS_LIBRARIES=$STAGING_DIR/host/lib/libmbedtls.a ``` ### 三、关键配置说明 | **参数** | **值** | **作用** | |----------|--------|----------| | `UA_ENABLE_AMALGAMATION` | ON | 生成单文件库减小体积 | | `UA_ENABLE_ENCRYPTION` | MBEDTLS | 启用硬件加密加速 | | `UA_ENABLE_PUBSUB` | OFF | 关闭非必需功能 | | `UA_ENABLE_MALLOC_SINGLETON` | ON | 优化内存管理 | ### 四、编译与部署 ```bash make -j$(nproc) open62541 mipsel-openwrt-linux-strip bin/libopen62541.so # 裁剪符号表 scp bin/libopen62541.so root@192.168.1.1:/usr/lib # 部署到设备 ``` ### 五、内存优化要点 1. **链接脚本调整** 修改`$STAGING_DIR/target-mipsel_24kc_musl/lib/ldscripts/elf32ltsmipn32.x`: ```ld SECTIONS { . = ALIGN(4); _min_heap_size = 64K; /* MTK7628可用RAM仅128KB */ } ``` 2. **精简功能配置** ```c #include <open62541/server_config_default.h> UA_ServerConfig *config = UA_ServerConfig_new_minimal(); config->maxWorkers = 1; // 限制线程数 config->maxConnections = 3; // 减少并发支持 ``` ### 六、调试建议 ```bash gdbserver :9091 /path/to/your_app # 目标板执行 mipsel-openwrt-linux-gdb -ex "target remote 192.168.1.1:9091" # 主机调试 ``` 📌 **注意事项** 1. MTK7628的MIPS 24KEc核心要求使用`-march=24kc`编译参数 2. OpenWrt musl库与glibc不兼容,需使用SDK提供的libc 3. 启用硬件加密需确认MTK7628的加密引擎驱动已加载 > 实测MTK7628NN芯片(64MB RAM)运行open62541 v1.3.6时,优化后内存占用: > - 文本段:`142KB` > - 堆内存:`32KB` > - 线程栈:`8KB/thread`[^2] --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值