精华内容
下载资源
问答
  • Linux系统启动初始化

    2020-09-28 21:03:10
    内核初始化五.系统调用 Linux系统启动初始化的主要流程是: 1.上电BIOS自检 2.启动Boot Loader(GRUB) 3.加载内核 4.启动第一个进程 5.配置环境 一.BIOS 加载启动引导程序 BIOS(英文:Basic Input/Output System...

    Linux系统启动初始化的主要流程是:

    1.上电BIOS自检

    2.启动Boot Loader(GRUB)

    3.加载内核

    4.启动第一个进程

    5.配置环境

    一.BIOS 加载启动引导程序

    BIOS(英文:Basic Input/Output System),即基本输入输出系统,亦称为ROM BIOS、System BIOS、PC BIOS,是在通电引导阶段运行硬件初始化,以及为操作系统提供运行时服务的固件。BIOS最早随着CP/M操作系统的推出在1975年出现。BIOS预安装在个人电脑主板上,是个人电脑启动时加载的第一个软件。

    现在,BIOS的作用是初始化和测试硬件组件,以及从大容量存储设备(如硬盘)加载引导程序,并由引导程序加载操作系统。BIOS还为DOS操作系统提供键盘、显示及其他I/O设备的硬件抽象层

    许多BIOS程序都只能在特定电脑型号或特定主板型号上运行。早年,BIOS存储于ROM芯片上;现在的BIOS多存储于闪存芯片上,这方便了BIOS的更新。

    计算机上电之后,CPU就可以执行程序了,但是此时内存中并没有程序让CPU执行,因为内存是RAM掉电丢失。而且操作系统也没有装上,这个时候就要装系统了。ROM中就固化了一些计算机刚上电要执行的初始化程序,也就是BIOS(Basic Input and Output System,基本输入输出系统) 。简单地理解 BIOS,它就是固化在主板上一个 ROM(只读存储器)芯片上的程序,主要保存计算机的基本输入/输出信息、系统设置信息、开机自检程和系统自启动程序,用来为 计算机提供最底层和最直接的硬件设置与控制。

    BIOS 的初始化主要完成以下 3 项工作:

    1. 第一次检查计算机硬件和外围设备(第二次自检由内核完后,后续会讲),例如 CPU、内存、风扇灯。当 BIOS 一启动,就会做一个自我检测的工作,整个自检过程也被称为 POST(Power On Self Test)自检。
    2. 如果自检没有问题,BIOS 开始对硬件进行初始化,并规定当前可启动设备的先后顺序,选择由那个设备来开机。
    3. 选择好开启设备后,就会从该设备的 MBR(主引导扇区)中读取 Boot Loader(启动引导程序)并执行。启动引导程序用于引导操作系统启动,Linux 系统中默认使用的启动引导程序是 GRUB。

    BIOS从MBR中读取启动引导程序,加载至RAM中,就可以执行启动引导程序了。

    二.MBR 主引导扇区

    MBR是用来存储启动引导程序的!!!

    MBR 也就是主引导扇区 ,位于硬盘的 0 磁道、0 柱面、1 扇区中,主要记录了启动引导程序和磁盘的分区表 ,如图是MBR的结构:
    在这里插入图片描述

    MBR大小是一个扇区512Byte, 其中 446 Byte 安装了启动引导程序,其后 64 Byte 描述分区表,最后的 2 Byte 是结束标记 。

    BIOS从MBR中读取启动引导程序,将启动引导程序加载至RAM中,然后BIOS将控制权交给启动引导程序。

    所以,虽然启动引导程序是在MBR中的,但是实际上是由BIOS从MBR中将启动引导程序加载至RAM中运行的!

    注意:这里的446Byte中存放的只是启动引导程序的一个镜像文件,后面还要通过这个镜像文件来加载出完整的启动引导程序!

    三.GRUB引导内核

    Linux下是通过一个工具Grub2( Grand Unified Bootloader Version 2 ),这个工具就是专门引导系统启动的。

    GNU GRUB(简称“GRUB”)是一个来自GNU项目启动引导程序。GRUB是多启动规范的实现,它允许用户可以在计算机内同时拥有多个操作系统,并在计算机启动时选择希望运行的操作系统。GRUB可用于选择操作系统分区上的不同内核,也可用于向这些内核传递启动参数。

    3.1运行 boot.img

    BootLoader,是启动引导程序,启动引导程序的主要任务就是加载操作系统内核, 每种操作系统的文件格式不同,因此,每种操作系统的启动引导程序也不一样。不同的操作系统只有使用自己的启动引导程序才能加载自己的内核。这里使用GRUB2作为启动引导程序。

    上面说BIOS将启动引导程序加载到RAM中执行,但是实际上启动引导程序的大小比512Byte要大,所以MBR中的只是一个镜像文件:boot.img。我们还得通过MBR中的boot.img找到完整的启动引导程序,从而正式启动内核。

    所以,boot.img的任务并不是启动内核,而是加载其他镜像文件来完成内核的启动,也可以理解为只有446Byte大小的boot.img不足以启动内核,只能召唤出更加强大厉害的其他镜像文件来启动内核。

    3.2加载 core.img

    这个强大的后援就是:core.img, core.img 由 lzma_decompress.img、diskboot.img、kernel.img 和一系列的模块组成,功能比较丰富,能做很多事情。
    在这里插入图片描述

    boot.img 先加载的是 core.img 的第一个扇区。如果从硬盘启动的话,这个扇区里面是 diskboot.img,对应的代码是 diskboot.S。boot.img 将控制权交给 diskboot.img 后,diskboot.img 的任务就是将 core.img 的其他部分加载进来,先是解压缩程序 lzma_decompress.img,再往下是 kernel.img,最后是各个模块 module 对应的映像。这里需要注意,它不是 Linux 的内核,而是 grub 的内核。lzma_decompress.img 对应的代码是 startup_raw.S,本来 kernel.img 是压缩过的,现在执行的时候,需要解压缩。

    在这之前,我们所有遇到过的程序都非常非常小,完全可以在实模式下运行,但是随着我们加载的东西越来越大,实模式这 1M 的地址空间实在放不下了,所以在真正的解压缩之前,lzma_decompress.img 做了一个重要的决定,就是调用 real_to_prot,切换到保护模式,这样就能在更大的寻址空间里面,加载更多的东西。

    3.3切换到保护模式

    切换到保护模式需要做以下几点:

    • 启用分段,在内存中建立段描述符表(和中断向量表差不多),原来的段寄存器指向现在的段描述符
    • 启动分页,现在内存大了,需要分页进行管理
    • 打开Gate A20,使用第21根地址控制线

    3.4kernel.img 引导内核

    这里kernel.img不是Linux的内核,而是GRUB的内核。

    kernel.img 对应的代码是 startup.S 以及一堆 c 文件,在 startup.S 中会调用 grub_main,这是 grub kernel 的主函数,主函数中 grub_load_config() 开始解析,我们上面写的那个 grub.conf 文件里的配置信息。

    当启动了操作系统后,就要开始调用 grub_menu_execute_entry() ,开始解析并执行你选择的那一项。

    例如里面的 linux16 命令,表示装载指定的内核文件,并传递内核启动参数。于是 grub_cmd_linux() 函数会被调用,它会首先读取 Linux 内核镜像头部的一些数据结构,放到内存中的数据结构来,进行检查。如果检查通过,则会读取整个 Linux 内核镜像到内存。

    在这里插入图片描述

    四.内核初始化

    上面已经引导了操作系统,也就是引导了内核,接下来就是内核的初始化了。

    内核启动的入口函数从start_kernel()开始, 在init/main.c 文件中,start_kernel 相当于内核的 main 函数。打开这个函数,你会发现,里面是各种各样初始化函数 XXXX_init .

    内核初始化做了以下这些事:

    • 创建0号进程, 这是唯一一个没有通过 fork 或者 kernel_thread 产生的进程,是进程列表的第一个。
    • 初始化中断, 对应的函数是 trap_init() ,里面设置了很多中断门(Interrupt Gate),用于处理各种中断。其中有一个 set_system_intr_gate(IA32_SYSCALL_VECTOR, entry_INT80_32),这是系统调用的中断门。系统调用也是通过发送中断的方式进行的。
    • 初始化内存管理模块, mm_init()
    • 初始化调度模块, sched_init()
    • 初始化基于内存的文件系统rootfs, vfs_caches_init()
    • 初始化其他, rest_init()
    • 创建用户态第一个进程:1号进程,用 kernel_thread(kernel_init, NULL, CLONE_FS) 创建1号进程
    • 创建内核态第一个进程:2号进程, kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES)

    这样看来,内核初始化靠的是start_kernel()函数,初始化主要做三件事:
    1.创建样板进程(也就是0号进程),以及各个模块的初始化

    2.创建用户态的进程

    3.创建内核态的进程

    用户态访问核心资源时,通过中断来请求,就是系统调用的统一中断,流程如下:
    在这里插入图片描述

    用户态和内核态进程执行的框图如下:
    img

    五.系统调用

    从上面得知,一般程序运行在用户态,如果要想使用核心资源,就要进入内核态,就要通过系统调用。

    此外,linux的一些驱动程序都是写在内核中的,当上层应用想要调用驱动的接口时,也要通过系统调用来实现。

    但是,直接操作系统调用比较繁琐,所以一般使用glibc库对系统调用进行封装。

    64位的系统调用如图所示:
    在这里插入图片描述

    展开全文
  • 上回ICMP的插曲说完了,把一个ICMP socket的创建流程说完了。对于数据结构关系图没有加入什么新元素。执行的流程是从inet_family_ops到inet_create,raw_prot,这样的执行顺序。...其实仔细一看,我们的协议栈的初始化

    上回ICMP的插曲说完了,把一个ICMP socket的创建流程说完了。对于数据结构关系图没有加入什么新元素。执行的流程是从inet_family_ops到inet_create,raw_prot,这样的执行顺序。此时完成的只是ICMP协议的处理socket。继续看源码,icmp_init函数返回后,后面还有内容。当然要有,IP层和设备还没有关联呢。走继续看。
    其实仔细一看,我们的协议栈的初始化也基本上接近尾声了。下面是来到1434行的一个函数调用。一般预编译里的内容,我会选择跳过,但这次要破例下。是的,你总想在自己的人生中坚持自己的原则,但总会有些人会让你破坏自己的原则。没有错,这个函数正是这样的。因为,它太有诱惑力了。关乎IP协议中的多播实现,忍不了了。
    1434 ip_mr_init()
    函数定义在net/ipv4/ipmr.c中。

    1886 void __init ip_mr_init(void)
    1887 {
    1888 mrt_cachep = kmem_cache_create("ip_mrt_cache",
    1889 sizeof(struct mfc_cache),
    1890 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
    1891 NULL);
    1892 init_timer(&ipmr_expire_timer);
    1893 ipmr_expire_timer.function=ipmr_expire_process;
    1894 register_netdevice_notifier(&ip_mr_notifier);
    1895 #ifdef CONFIG_PROC_FS
    1896 proc_net_fops_create(&init_net, "ip_mr_vif", 0, &ipmr_vif_fops);
    1897 proc_net_fops_create(&init_net, "ip_mr_cache", 0, &ipmr_mfc_fops);
    1898 #endif
    1899 }

    1888 申请了一个缓存对象,对象单元是struct mfc_cache。一般协议栈里的缓存都会记录在协议的数据结构里,作为成员存在。这里没有采用这样的方式。暂不明白。
    1892 初始化了一个定时器。同之前说过的路由表一样,多播路由表也有超时的时间。看expire就是超期的意思。看源码的同时还学习了英文,多好。一箭双雕。
    1893 超时定时器的事件处理函数。暂时记下就行,等超时了再去看,它干了什么。
    1894 同路由表一样,多播路由表也要接受特定的消息来自我更新。注册一个通知消息的处理实例吧。同样暂且不表。
    后面两个可以跳过。不能每次都破例。总结来说,这个函数,为多播创建了条件,可以存贮、更新多播路由表。
    回到inet_init。来了一个函数。mibs是什么东西?s是表示复数,mib 什么?这个光猜是猜不出来的。我负责地去源码里找了一圈,没有找到。最后去bing的词典里查了下,是Management Information Base,可以翻译为管理信息库。
    1440 if (init_ipv4_mibs())
    1441 printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");

    然而这个函数我没有打算把源码列出来,分析一下。没有什么新鲜的东西,全是协议栈的数据统计结构实例,形如xxx_statistics的名称。然而,这是一个吉兆,如周易里的“见龙在田,利见大人”一样。这预示着,我们的协议栈初始化基本上完成了,快可以工作了。
    1443 这个我打算跳过。还是去/proc目录下创建一些目录和文件,提供访问协议栈的接口。
    1445 ipfrag_init();
    这个是关于IP分片的初始化。当从上层协议中得到的数据分组,比当前链路层中的MTU还大时,IP就要开始分片了。本以为它会很复杂,进去一看,一堆初始化赋值,外加一个函数调用。函数来自net/ipv4/ip_fragment.c中。

    610 void __init ipfrag_init(void)
    611 {
    612 ip4_frags.ctl = &ip4_frags_ctl;
    613 ip4_frags.hashfn = ip4_hashfn;
    614 ip4_frags.constructor = ip4_frag_init;
    615 ip4_frags.destructor = ip4_frag_free;
    616 ip4_frags.skb_free = NULL;
    617 ip4_frags.qsize = sizeof(struct ipq);
    618 ip4_frags.match = ip4_frag_match;
    619 ip4_frags.frag_expire = ip_expire;
    620 inet_frags_init(&ip4_frags);
    621 }

    至此需要引入一个管理数据结构实例。ip4_frags,类型为struct inet_frags。这个类型的具体成员,暂不去管。先记着,看我们会遇到哪些内容。
    612 初始化了一个控制成员变量。
    613-615 初始化散列函数,初始化函数,释放函数(C++中的析构函数)。
    616 把skb_free给置空。为什么?或许ip4_frags永远都不是真正拥有sk_buff,所以就不可去释放它。
    617 ip4_frags维护了一个队列,这个队列的单元长度被赋心struct ipq的字节长度。一个典型的生产者消费者模式。我理解的这里的队列,既可能是接收的队列,也可能是发送的队列。
    618 一个匹配函数。什么时候会执行呢?暂时我也不知道。
    619 设置一个超时处理函数。函数头部的注释中写着,如果超时了要清空整个队列了。这个会在什么情况下发生呢?IP协议告诉我们,IP分片发生在发送端,也可能是中间的路由器上。但分片重装只会发生在目的主机上。当目的主机上的IP分片接收队列中,有一个分片丢失了,这个时候,由于IP协议本身没有重传机制,只能通过额外的机制,来触发清空整个分片接收队列,来进行重新接收。
    620 针对inet层对ip4_frags进一步的初始化。这个函数只说明下它的功能,不再列源码。初始化ip4_frags的散列表,散列随机数,缓存计数,初始化重建定时器。
    从ipgfrag_init中返回。看到了最后一个函数
    1447 dev_add_pack(&ip_packet_type);
    至此我们的IP层和设备关联起来了,以后网卡接到的IP分组的数据就会发给IP协议了。先看下传入的参数ip_packet_type,定义在af_net.c中。
    1348 static struct packet_type ip_packet_type = {
    1349 .type = __constant_htons(ETH_P_IP),
    1350 .func = ip_rcv,
    1351 .gso_send_check = inet_gso_send_check,
    1352 .gso_segment = inet_gso_segment,
    1353 };

    这里重点关注ip_rcv的成员函数。对,它就是IP分组数据进入IP层的入口函数。其他成员先不看,ip_rcv的光环太耀眼了。而dev_add_pack,之前有遇到过,只是把ip_packet_type挂在了ptype_base的全局列表里。
    至此协议栈的初始化完成了,可以工作了,刚好11篇,真是个好数字。随后的一篇中,我会把整个流程再梳理一下,把关系图完善下。之后,开始协议栈工作之旅了:)

    展开全文
  • systemd 初始化

    2017-11-15 19:20:35
    一,systemd是什么?有什么用? systemd是Linux下的一种...其开发目标是提供更优秀的框架以表示系统服务(英语:Service (systems architecture))间的依赖关系,并以此实现系统初始化时服务的并行启动,同时达到降低S

    一,systemd是什么?有什么用?
    systemd是Linux下的一种init软件,是 Linux 下的一款系统和服务管理器,由Lennart Poettering(英语:Lennart Poettering)带头开发。其开发目标是提供更优秀的框架以表示系统服务(英语:Service (systems architecture))间的依赖关系,并以此实现系统初始化时服务的并行启动,同时达到降低Shell的系统开销(英语:Computational overhead)的效果。
    systemd 兼容 SysV 和 LSB 的启动脚本。

    systemd的特性有:
    支持并行化任务
    同时采用socket式与D-Bus总线式激活服务;
    按需启动守护进程(daemon);
    利用 Linux 的 cgroups 监视进程;
    支持快照和系统恢复;
    维护挂载点和自动挂载点;
    各服务间基于依赖关系进行精密控制。

    systemd基本工具
    检视和控制systemd的主要命令是systemctl。该命令可用于查看系统状态和管理系统及服务.

    systemctl start 单元 #使用单元
    systemctl stop 单元 #停止单元
    systemctl status 单元 #查看单元的状态
    systemctl restart 单元 #重启单元

    什么是单元?
    一个单元配置文件可以描述如下内容 之一 :系统服务(.service)、挂载点(.mount)、sockets(.sockets 、系统设备、交换分区/文件、启动目标(target)、文件系统路径、由 systemd 管理的计时器

    二,系统引导过程概述:

    传统的Linux系统启动过程主要由著名的init进程(也被称为SysV init启动系统)处理,而基于init的启动系统被认为有效率不足的问题,systemd是Linux系统机器的另一种启动方式,宣称弥补了以传统Linux SysV init为基础的系统的缺点。

    传统的 init启动过程

    在我们打开Linux电脑的电源后第一个启动的进程就是init。分配给init进程的PID是1。它是系统其他所有进程的父进程。当一台Linux电脑启动后,处理器会先在系统存储中查找BIOS,之后BIOS会检测系统资源然后找到第一个引导设备,通常为硬盘,然后会查找硬盘的主引导记录(MBR),然后加载到内存中并把控制权交给它,以后的启动过程就由MBR控制。
    
    主引导记录会初始化引导程序(Linux上有两个著名的引导程序,GRUB和LILO,80%的Linux系统在用GRUB引导程序),这个时候GRUB或LILO会加载内核模块。内核会马上查找/sbin下的“init”程序并执行它。从这里开始init成为了Linux系统的父进程。init读取的第一个文件是/etc/inittab,通过它init会确定我们Linux操作系统的运行级别。它会从文件/etc/fstab里查找分区表信息然后做相应的挂载。然后init会启动/etc/init.d里指定的默认启动级别的所有服务/脚本。所有服务在这里通过init一个一个被初始化。在这个过程里,init每次只启动一个服务,所有服务/守护进程都在后台执行并由init来管理。
    
    关机过程差不多是相反的过程,首先init停止所有服务,最后阶段卸载文件系统。
    

    systemd启动过程

        打开电源后电脑所做的第一件事情就是BIOS初始化。BIOS会读取引导设备设定,定位并传递系统控制权给MBR(假设硬盘是第一引导设备)。
        MBR从Grub或LILO引导程序读取相关信息并初始化内核。接下来将由Grub或LILO继续引导系统。如果你在grub配置文件里指定了systemd作为引导管理程序,之后的引导过程将由systemd完成。Systemd使用“target”来处理引导和服务管理过程。这些systemd里的“target”文件被用于分组不同的引导单元以及启动同步进程。
        systemd执行的第一个目标是default.target。但实际上default.target是指向graphical.target的软链接。Linux里的软链接用起来和Windows下的快捷方式一样。文件Graphical.target的实际位置是/usr/lib/systemd/system/graphical.target
    

    以流程来看:
    通电——>进入初始化阶段——>bios 初始化——>grub2 磁盘引导阶段——>grub2 文件引导阶段——> 指定boot所在分区——>启动内核,只读挂在 / 设备启动——>init 程序进入初始化阶段——> 启动 systemd 初始化进程——>读取 /etc/systemd/中的文件——>启动程序——>启动登陆环境
    grub文件引导阶段

    由文件/boot/grub2/grub.cfg控制流程:
    指定/boot分区位置 —–> 加载内核 —–> 启动系统初始化进程 —–> grub2-mkconfig
    内核引导阶段

    检测硬件设备 —–> 设备驱动初始化 —–> 将/只读挂载 —–> 载入初始进程systemd —–> 内核文件丢失请重新安装内核
    systemd初始化

    开启selinux和systemd-tools —–> 加载内核参数 —–> 加载系统时钟,键盘,主机名称 —–> 读写挂载/文件系统 —–> 激活raid, lvm设备 —–> 激活系统配额 —–> 启动multi-user.target.wants中的所有服务脚本 —–> 启用虚拟控台 —–> 启动图形

    三,开机启动级别:
    1,开机启动级别:
    runlever0.target -> poweroff.target //关机’
    runlever1.target -> rescue.target //单用户模式
    runlever2.target -> multi-user.target //多用户模式,不支持NFS
    runlever3.target -> multi-user.target //完整多元化模式
    runlever4.target -> multi-user.target //未定义使用
    runlever5.target -> grapical.target //带有图形界面的多用户使用
    runlever6.target -> reboot.target //重启\
    例如开机自启动就是因为添加了链接到脚本上,开机就会自动运行脚本启动,有无图形也是因为链接到有无图形的脚本上。

    2.设定开机启动级别:
    systemctl set-default 启动级别
    /etc/systemd/system/defaults.target

    四,关于systemd的实验:

    1,主机陷入无尽的重新启动,可是不能真正重启的问题:
    [root@server1 system]# ls -l default.target
    lrwxrwxrwx. 1 root root 40 Jul 10 2014 default.target -> /usr/lib/systemd/system/graphical.target
    可以看见默认目标链接再图形目标上
    [root@server1 system]# systemctl set-default reboot.target #重新设置默认目标
    rm ‘/etc/systemd/system/default.target’
    ln -s ‘/usr/lib/systemd/system/reboot.target’ ‘/etc/systemd/system/default.target’
    可以看见执行设置默认目标的操作时,发生的子操作为先删除原有的链接,再建立要设置的链接。
    [root@server1 system]# vim /etc/sysconfig/selinux #关闭selinux可以使开机初始化速度加快
    执行完以上操作后,主机会陷入无尽的重启状态,
    在下图卡住:
    这里写图片描述
    之后会进入下面的界面:
    这里写图片描述
    按‘e‘进如另一界面,并做如下修改:
    这里写图片描述
    又进入以下界面,做如下修改:
    这里写图片描述
    到此可以完成启动。

    2,忘记主机root的密码问题
    忘记主机密码则无法进入系统,解决如下
    这里写图片描述
    按‘e‘,进入另一界面,并做如下改动:
    这里写图片描述
    再另一界面:
    这里写图片描述
    sh-4.2# touch /.autorelabel #为了selinux生效,不可忘记!!!
    到此可以完成密码的重置。

    展开全文
  • zigbee初始化流程

    千次阅读 2019-05-17 18:53:34
    main函数里主要完成了系统的各种初始化,最后启动系统。 int main( void ) { osal_int_disable( INTS_ALL );// 关闭中断 HAL_BOARD_INIT();// 初始化系统时钟 zmain_vdd_check();// 检查芯片电压 ...

    1.zigbee协议栈构成

    协议栈

    1.1 物理层(PHY)和介质访问控制层(MAC)

           物理层和介质控制层是由IEEE 802.15.4规范定义的,物理层控制天线的收发数据;zigbee无线网络中的网络号,网络发现等概念是介质访问控制层的内容。此外介质访问控制层还提供点对点的通信数据确认(Per-hop Acknowledgments)以及一些用于网络发现和网络形成的命令。

    1.2 网络层(NWK)

           网络层是对网型网络提供支持,如在全网范围内发送广播包,为单播数据包选择路由,确保数据包能够可靠地从一个节点发送到另一节点,此外网络层还具有安全特性,可以自行选择所需的安全策略。

    1.3 应用程序支持子层

           该层主要提供了一些API函数调用,此外,绑定表也是存储在应用程序支持子层。Zigbee设备对象ZDO是运行在端口0的应用程序,主要提供了一些网络管理方面的函数。每个Zigbee设备都与一个特定类别(profile)有关,这些类别定义了设备的应用环境,设备类型以及用于设备间通信的从集。

    1.4 总述

    • 所有端点都使用应用支持子层(APS)提供的服务。APS透过网络层和安全服务提供层与端点相接,并为数据传送、安全和固定服务
    • APS使用网络层(NWK)提供的服务。NWK负责设备到设备的通信,并负责网络中设备的初始化所包含的活动、消息路由和网络发现。应用层可透过Zigbee设备对象(ZDO)对网络层参数进行配置和存取。

    1.5 缩写与全程

    英文缩写全称备注
    APSApplication Support Sub-Layer应用程序支持子层
    SAPService Access Points服务接入点
    APSDE-SAPAps Data Entity-SAP应用程序支持子层
    数据实体服务接入点
    AOSME-SAPAPS Management Entity-SAP应用程序支持子层
    管理实体服务接入点
    NLDE-SAPNetwork Layer Data Entity-SAP网络层数据实体服务接入点
    NLME-SAPNetwork Layer Management Entity-SAP网络层管理实体服务接入点
    MCPS-SAPMAC Common Part Service-SAPMAC层通用服务接入点
    PD-SAPPhysical Layer Data Entity-SAP物理层数据实体服务接入点
    PLME-SAPPhysical Layer Management Entity-SAP物理层管理实体服务接入点

    2.源码分析

    1.1 main.c

    • 首先看zmain.c 中的main函数
      main函数里主要完成了系统的各种初始化,最后启动系统。
    		int main( void )
    		{ 
    		  osal_int_disable( INTS_ALL );// 关闭中断  
    		  HAL_BOARD_INIT();//  初始化系统时钟  
    		  zmain_vdd_check();// 检查芯片电压  
    		  InitBoard( OB_COLD );//初始化I/O  
    		  HalDriverInit();//初始化硬件驱动层 
    		  osal_nv_init( NULL );//初始化Flash存储器  
    		  ZMacInit();// 初始化MAC层  
    		  zmain_ext_addr();//确定64位网络地址
    		  zgInit();
    		#ifndef NONWK
    		  afInit(); //初始化AF层
    		#endif  
    		  osal_init_system(); // 初始化操作系统	  
    		  osal_int_enable( INTS_ALL );//  打开所有中断  
    		  InitBoard( OB_READY );// 初始化按键,显示等
    		  osal_start_system(); // 启动OSAL,运行操作系统
    		  return 0; 
    		} 
    
    • 在main函数的各种初始化函数中,需要我们关注的是下面两个

      osal_init_system(); // 初始化操作系统
      osal_start_system(); // 启动OSAL,运行操作系统

    1.2 osal_init_system() 初始化操作系统

    • osal_init_system() 这个函数的作用是初始化操作系统,在这个函数内初始化了系统的所有任务
      /*OSAL.c中的代码*/
      uint8 osal_init_system( void )
      {
        // Initialize the Memory Allocation System
        osal_mem_init();
      
        // Initialize the message queue
        osal_qHead = NULL;
      
        // Initialize the timers
        osalTimerInit();
      
        // Initialize the Power Management System
        osal_pwrmgr_init();
      
        // Initialize the system tasks.
        osalInitTasks();/****初始化了系统的所有任务******/
      
        // Setup efficient search for the first free block of heap.
        osal_mem_kick();
      
        return ( SUCCESS );
      }
      
    1.2.1追踪osalInitTasks()函数

    这个函数的作用就是要找的初始化所有任务的函数

    • OSAL_IoTApp.c中的代码 (我们书写的应用层代码)
    void osalInitTasks( void )//为各个进程添加任务ID,用作查找任务时用
    {
      uint8 taskID = 0;
    
      tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
      osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));
    
      macTaskInit( taskID++ ); //MAC层的任务ID号
      nwk_init( taskID++ );   //网络ID分配
      Hal_Init( taskID++ );   //硬件ID分配
    #if defined( MT_TASK )
      MT_TaskInit( taskID++ );
    #endif
      APS_Init( taskID++ );
    #if defined ( ZIGBEE_FRAGMENTATION )
      APSF_Init( taskID++ );
    #endif
      ZDApp_Init( taskID++ );
    #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
      ZDNwkMgr_Init( taskID++ );
    #endif
      IoTApp_Init( taskID );//为自己的任务添加ID,自己分配ID
    }
    
    • 不过这里需要注意的是,taskID和对应任务的处理函数的顺序要一致
    const pTaskEventHandlerFn tasksArr[] = {   //数组里存放的都是任务处理函数指针
    	  macEventLoop,   //MAC任务循环
    	  nwk_event_loop, //网络层任务函数
    	  Hal_ProcessEvent,//硬件层函数
    	#if defined( MT_TASK )
    	  MT_ProcessEvent,  //串口支持层定义
    	#endif
    	  APS_event_loop,   //应用支持层任务事件函数
    	#if defined ( ZIGBEE_FRAGMENTATION )
    	  APSF_ProcessEvent,
    	#endif
    	  ZDApp_event_loop,   //设备对象层函数
    	#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
    	  ZDNwkMgr_event_loop,
    	#endif
    	  IoTApp_ProcessEvent //自定义任务处理函数,需要自己添加和任务
    	};
    
    1.2.2 自定义IoTApp_ProcessEvent()函数。

           通过osal_msg_receive()函数取出系统事件消息,系统事件消息又分为多种消息,常用的有:
        AF_INCOMING_MSG_CMD 接收到了无线数据
        KEY_CHANGE 按键触发
        ZDO_STATE_CHANGE 网络状态发生变化

    UINT16 IoTApp_ProcessEvent( byte task_id, UINT16 events )
    {
      afIncomingMSGPacket_t *MSGpkt; //接收消息的结构体指针
    
      if ( events & SYS_EVENT_MSG )
      {
    	/*osal_msg_receive从消息队列中接收消息(接收指向消息结构体的指针)*/
    	MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( IoTApp_TaskID );
    	while ( MSGpkt )
    	{
    	  switch ( MSGpkt->hdr.event ) //对接收消息进行判断
    	  {
    		case AF_INCOMING_MSG_CMD: //接收到了无线数据
    		  IoTApp_MessageMSGCB( MSGpkt );
    		  break;
    		default:
    		  break;
    	  }
    
    	  //释放内存,因为zigbee消息都是存在堆上,需要手动释放
    	  osal_msg_deallocate( (uint8 *)MSGpkt ); 
    
    	  //从消息队列中接收下一条消息
    	  MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( IoTApp_TaskID );
    	}
    
    	// return unprocessed events
    	return (events ^ SYS_EVENT_MSG); //异或
      }
      return 0;
    }
    

    1.3 osal_start_system() 启动OSAL,运行操作系统

            追踪这个代码的实现,是在OSAL.c这个文件中。
            该函数是任务系统的主循环函数。它将查看所有任务事件,并为事件调用相应的任务task_event_processor()函数。
            如果没有事件(对于所有任务),此函数将使处理器进入休眠状态。这个函数不返回。

    void osal_start_system( void )
    {
    #if !defined ( ZBIT ) && !defined ( UBIT )
      for(;;)  // Forever Loop
    #endif
      {
    	uint8 idx = 0;
    
    	osalTimeUpdate();
    	Hal_ProcessPoll();  // This replaces MT_SerialPoll() and osal_check_timer().
    	
    	do {
    	  if (tasksEvents[idx])  // Task is highest priority that is ready.
    	  {
    		break;
    	  }
    	} while (++idx < tasksCnt);
    
    	if (idx < tasksCnt)
    	{
    	  uint16 events;
    	  halIntState_t intState;
    
    	  HAL_ENTER_CRITICAL_SECTION(intState);
    	  events = tasksEvents[idx];
    	  tasksEvents[idx] = 0;  // Clear the Events for this task.
    	  HAL_EXIT_CRITICAL_SECTION(intState);
    
    	  events = (tasksArr[idx])( idx, events );
    
    	  HAL_ENTER_CRITICAL_SECTION(intState);
    	  tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    	  HAL_EXIT_CRITICAL_SECTION(intState);
    	}
    #if defined( POWER_SAVING )
    	else  // Complete pass through all task events with no activity?
    	{
    	  osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
    	}
    #endif
      }
    }
    
    展开全文
  • JAVA 数组的初始化

    千次阅读 2016-06-23 18:10:25
    数组的初始化有如下两种方式:静态初始化: 初始化时由程序员显式指定 每个数组元素的初始值, 由系统决定数组长度. 动态初始化: 初始化时程序员只指定数组长度, 由系统为数组元素分配初始值. 静态初始
  • memset对数组的初始化

    千次阅读 2015-06-14 01:09:22
    花了半个下午,总结了一下memset对int,long long,char型数组的初始化。//0x(零和英文字母x)是十六进制的前缀(十六进制不区分大小写) //memset对字节赋值 #include #include using namespace std; const int maxx...
  • 初始化单链表

    千次阅读 2011-07-06 15:50:44
    #include typedef struct Node ... * 初始化一个拥有n个结点的链表 */ stud *InitList(int n) { //第一个结点(头结点)--->......--->第n个结点--->......--->最后一个结点 stud *head,*pf,*pb;
  • 交换机初始化配置

    千次阅读 2014-10-18 14:20:02
    2012自学CCNP路由与交换之四交换机初始化 2012-02-07 16:16:05 标签:休闲 cisco 职场 h3c ccnp 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律...
  • 初始化mysql数据库脚本1.使用springboot jdbc初始化数据库2.使用原生mybatis执行sql脚本3.改良springboot jdbc初始化数据库参考地址 基于spring2.x 1.初始化mysql数据库脚本 1.使用springboot jdbc初始化数据库 # ...
  • 类变量的初始化时机
  • idea 初始化设置1

    2019-01-28 22:01:20
    idea 初始化设置。 我一直坚信工欲善其事,必先利其器。磨刀不误砍柴功,对开发工具的理解是非常重要的,可以大大提高工作效率。 idea的设置分为两种: 一种叫全局设置:就是设置完成以后,所有的项目都受益。 第二...
  • 先贴上DATASHEET给出的初始化顺序: 1.2.1.3 DDR2 Initialization sequence for DDR2 memory type: 1. To provide stable power for controller and memory device, the controller must assert and hold CKE to...
  • 20-1-tcp连接——初始化序列号(ISN)

    千次阅读 多人点赞 2018-06-02 22:15:14
    1. 为什么要初始化序列号(ISN)   在前面学习tcp连接三次握手的时候,客户端和服务端在建立tcp连接时,双方都会发送SYN报文并初始化序号(ISN)。大家不妨先思考一下:为什么要在建立tcp连接时初始化序列号?...
  • 请教:变量到底是在编译的时候初始化的,还是在运行的时候初始化的? [问题点数:40分,结帖人learnc2015] https://bbs.csdn.net/topics/391832733 收藏帖子 回复 learnc2015 结帖率 62.5% 变量到底是在...
  • 在Struts1整体概览和核心组件一文中,我们提到了Struts1框架的两条主线:初始化主线和请求处理主线,本文将探寻Struts1框架初始化这条主线。本文使用的Struts版本为1.2.8, 不同版本会略有差异,1.3.x系列对请求处理...
  • 初始化和未初始化的局部变量和全局变量在内存中如何分布? 阿基米东 2020-12-31 01:00:22 415 收藏 分类专栏: 嵌入式面试精选 文章标签: C语言 面试题 内存分布 堆栈 版权 玩转STM32MP1 从 STM32MP1 开始玩转 ...
  • 陷阱:全零初始化 使用小随机数初始化 用1 / sqrt(n)标准化方差 稀疏初始化 初始化偏差 批量标准化 正则化 L2正则化 L1正则化 最大范数约束 Dropout 损失函数 分类问题 属性分类 回归 结构化预测 小结 .....
  • springMVC系列源码之初始化过程——10

    千次阅读 2014-02-24 14:58:15
    摘要: 本文以结合源码的方式来说明springMVC启动做了哪些初始化工作, 具体是怎么做的,通过哪些具体的步骤来完成初始化.以图文的形式来尽力说的清楚点,有理解不到位的地方望不吝指正.
  • Linux虚拟机环境初始化设置

    千次阅读 2020-07-25 00:47:19
    以下介绍如何快速初始化Linux虚拟机设置。 版本:CentOS7.5 + 安装过程略,建议选择最小安装。 基础组件安装 修复主机名,笔者这里改成centos-linux hostnamectl set-hostname centos-linux 查看Linux系统...
  • Java实例初始化详解

    千次阅读 2014-06-01 16:41:14
    The body of a class declares members (fields and methods and nested classes and interfaces), instance and static ...类***声明成员(变量,方法,内部类和接口),实例和静态初始化和构造器。 At the beginni
  • Spring IOC容器初始化过程 源码分析

    千次阅读 2018-10-16 18:05:00
    往下继续走,进入到AbstractApplicationContext的refresh()方法,Spring容器的初始化过程就在该方法中完成的。 本文会进入每个方法,看看方法里面的代码,但可能不会很细。 1、接下来,继续Debug,进入第一个...
  • 《Thinking in java》中说,可以用静态方法打印出静态变量证明它们在使用之前完成初始化动作(英文版190/中文版97的练习14)。 个人以为,此方法不可行,因为,访问即触发初始化动作,而用NetBeans调试下即可证明。...
  • 在使用dminit工具或dbca图形化工具初始化达梦...在达梦数据库中,这两个初始化参数在实例创建完成后,不能修改,若发现选错了,只能重新初始化一个新的实例。 字符集比较好理解,就是字符的不同表示方式,具体区别可以
  • Linux系统初始化配置

    2018-11-17 15:30:52
    CentOS - 网络设置 系统的特点,也许是处于安全考虑,在默认情况下,...至此,完成服务器的基本初始化配置。 为了以防万一,我们可以输入service network restart再确认一下,如果弹出如下信息,说明配置成功  
  • 准备工作完成,看代码: ChromeOptions options = new ChromeOptions(); options.addExtensions( new File("C:\\Users\\swang\\AppData\\Local\\Google\\Chrome\\UserData\\Default\\Extensions\\...
  • Java中对象数组初始化和排序

    千次阅读 2017-09-26 21:32:01
    java中对象数组初始化和排序由于今天上机的一道题感觉比较坑,所以总结一下。
  • 但是,2.42寸OLED的滚动显示和0.96寸初始化设置还是有略微的区别的,如果直接复制粘贴,你会发现屏幕只有一小块地方在动。 网上搜了很久,都是0.96寸的介绍应用,无奈之下自己查阅英文文档,最终解决。 希望为要...
  • Linux部署达梦数据库及初始化实例 1、调整sysctl.conf参数 [root@dm-1 ~]# vim /etc/sysctl.conf fs.file-max = 6815744 fs.aio-max-nr = 1048576 kernel.shmall = 2097152 kernel.shmmax = 2147483648 kernel....
  • Centos7系统初始化和Centos7软件的安装

    千次阅读 2020-09-19 10:38:39
    Centos7系统初始化和Centos7软件的安装方法
  • JQuery Datatables初始化 个人比较喜欢JQueryDatatables的Bootstrap4风格,所以文章以Bootstrap4风格为例。 JQueryDatatable的初始化很简单,按照官网的举例说明,只要如下几个JS和CSS文件即可: 1、jquery-3.3.1...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 130,086
精华内容 52,034
关键字:

初始化完成英语