NDIS与WinSock关系之自我扫盲

       起来真是雷人,最近几天纠结与一个最基本的概念,就是NDIS与WinSock关系,想来想去都没有想明白,真实汗Ing,赶紧找了篇精美的文章来扫盲一下。

原文如下:

      文章转自http://www.cnblogs.com/sankye/articles/1651280.html

 

1.WinCE的网络通信架构

WinCE的网络通信架构如图1所示,WinCE的网络通信架构中一个重要的角色是网络结构规范(NetworkDriver Interface Specification,NDIS),它支持多种网络媒体,以及提供包括TCP/IP等多种网络协议。

 

 

 

1 WINCE通信网络的层

其中最上层的Wins0ck是提供给应用层的接口,一般开发网络应用都会用Winsock接口来开发。NDIS位于协议驱动层下面,而位于硬件驱动Miniport Driver之上。协议驱动层通过调用NDIS封装层的接口函数,实现与底层硬件驱动的交互。对于协议层来说,NDIS相当于一个Miniport Driver,而对于底层的硬件驱动来说,NDIS相当于上层的协议层,所以NDIS起到承上启下的作用,也起到对底层硬件接口的规范作用

 

 

2.WinCE网络驱动架构和实现原理

在WinCE中,网卡驱动的实现原理如图2所示,在上层的协议驱动层看来,它调用NDIS接口函数访问网络设备,其具体实现过程(如图2虚线框),是通过调用底层的Miniport Driver接口函数来实现。在WinCE系统中NDIS接口函数库是Microsoft开发好的,所以开发winCE下的网卡驱动就是编写一个Miniport Driver,它向上导出接口函数与NDIS接口实现对接,向下直接管理网卡硬件。

 

 

2 WINCE网络驱动原理

 

 

3.网络驱动的编程与实现

3.1网络驱动接口的实现流程

在WinCE中,应用层通过调用NDIS接口(图3实线框)实现与底层硬件的交互,而NDIS接口是微软已经开发好的,被定义成一个数据结构体的形式。开发网卡驱动就是写一个Miniport Driver,导出相应的Miniport接口函数(图3的虚线框),这些接口函数会在系统注册一个Miniport Driver的时候与NDIS封装层的接口函数对接,这样内核协议层通过调用NDIS的接口就可以访问底层硬件。

3 网络驱动接口实现流程

微软定义的与Miniport Driver相关的NDIS标准接口总共有18个,针对不同的网络设备其接口的实现也不尽相同,本流程图中罗列出的是CS89OO网卡驱动所实现的接口函数,具体的接口实现可参照Platform Builder的帮助文档。

3.2网络驱动接口的具体实现

实际网络驱动的编写,就是理解wincE下网络驱动程序的构架,然后针对实际的硬件编写代码,实现相应的中间层Miniport Driver接口函数。下面结合利用WinCE5.0内核在脉冲发生器嵌入式主板上移植编写嵌入式CS8900网卡驱动程序的实例,介绍网卡驱动程序Miniport Driver接口的具体实现(由于本驱动的硬件设备是CS8900,所以在函数接口的取名上一律用CS8900代替Miniport Driver)。

3.2.1网络驱动程序的入口函数

DriverEntry,该函数中首先调用NdisMinitializeWrapper函数来通知NDIS Library要注册一个Miniport。然后初始化MINIPORT结构体,所有的Miniport的相关接口函数都会赋到 MINIPORT 结构中, 最后调用NdisMRegisterMiniport来注册Miniport。通过此函数,实现了Miniport Driver接口与NDIS接口的对接。

3.2.2网络设备的初始化接口

Miniportlnitialize, 该函数为调用函数CS8900RegisterAdapter来完成网络设备的初始化,而CS8900RegisterAdapter 又会调用CS8900Initialize,CS8900Initialize函数会相继调用:findCS,查找网络设备;resetCS,重启网络控制器,并设置工作模式为16bit的I/0模式;InitIrq,开启网络控制器的中断;initCS,设置临时的物理地址,为网络控制器设置与嵌入式芯片之间中断的硬件连接,以及总线读写的时序。

3.2.3网络数据包的发送

WinCE网络数据发送的流程:当上层协议驱动要发数据时,调用NdisSend请求NDIS发送数据包,NDIS将会调用紧接其下的中间层驱动的CS8900Send,该函数首先调用NdisQueryPacket,得到需要发送包的数据信息,并拷贝到一个缓冲区暂存,这样做的目的是保证包数据不被丢失。然后调用CS8900RequestTransmit,向网络控制器发送传送数据的请求,最后调用函数CS8900CopyTxFrame完成数据包的发生。

3.2.4网络数据的接收和中断

网络设备的接收数据包时通过中断实现,当网络接口接收到新数据包时,发送完成或者报错误信息及连接状态都会出发中断,通常中断处理程序通过检测硬件状态寄存器判断是哪种情况。

当网络设备有数据到来的时候,将触发中断,相应的中断处理程序接管中断后,将调用Miniport Driver所注册的中断处理例程CS8900Isr,通过读取CS8900的中断寄存器判断是否是接收到数据中断,如果是就调用数据接收函数CS8900ReceiveEvent。Miniport Driver通常在这里把网卡上的数据拷贝到Miniport Driver缓冲区队列中去,出于效率的考虑,Miniport Driver这时可能不会立即通知上层处理新的数据,因为很可能,马上还有随后的新的数据到来,当接收到的包的数量达到一定程度的时候,驱动程序的接收线程会调用函数NdisMIndicateReceivePacket指示新的NDIS新数据的到来。

3.2.5Miniport Driver其他接口

    CS8900Reset,复位硬件网卡;

CS8900Querylnformation,网卡信息查询函数;

CS8900Setlnformation,设置网卡信息函数。

3.2.6 驱动下实现的CS8900A的几个函数

1.读写ReadPacketPage和WritePacketPage。这两个函数通常并不被EthDbg驱动程序的使用者直接调用。而是这个两个函数向其他EthDbg驱动程序接口函数提供了最基本的读写CS8900A的PacketPage内部的控制与状态寄存器和收发缓冲区的功能。

在源文件%_WINCEROOT%/PLATFORM/COMMON/SRC/COMMON/ETHDRV/CS8900A/cs8900a.c中定义了一个静态全局指针变量g_pCS8900:

STATIC CS8900A_REGS *g_pCS8900;

其类型CS8900A_ERGSS是在同一源文件中定义的结构体:

Typedef struct{

Unsigned _int16 DATA0;

Unsigned _int16 DATA1;

Unsigned _int16 TXCMD;

Unsigned _int16 TXLENGTH;

Unsigned _int16 ISQ;

Unsigned _int16 PAGEIX;

Unsigned _int16 PAGE0;

Unsigned _int16 PAGE1;

}CS8900A_REGS;

显然,静态全局指针变量g_Pcs8900所指向的CS8900A_REGSS结构体数据专门用于映射CS8900A的8个I/O端口,g_Pcs8900指针的实际取值就应该是这8个I/O端口的基地址。ReadPacketPage和WritePacketPage两个函数的实现对CS8900A的PacketPage读写就是通过这个g_Pcs8900指针进行的。

2.硬件初始化函数CS8900AInit。CS8900AInit函数的功能是执行对CS8900A以太网控制器芯片的硬件初始化,并且设置其工作模式至一个确定的状态。CS8900AInit函数在%_WINCEROOT%/PLATFORM/DEVICEEMULATOR/SRC/DRIVERS/ETHERNET/cs8900a.c源文件中实现,其函数定义:

BOOL CS8900AInit(UINT *pAddress, UINT32 offset, UNIT16 MAC[3]);

*pAddress指针参数记录以太网控制器的I/O端口基地址。Offset成员则是偏移地址,在当前的CS8900AInit函数中它没有被使用。Mac数组记录以太网端口的48位MAC地址。

如果把对全局变量g_pCS8900赋值看作是CS8900AInit函数执行的第一步,则它的第二个执行步骤就是检测CS8900A以太网控制器芯片是否在目标硬件平台上真实存在:

If (ReadPacketPage(EISA_NUMBER)!=CS8900A_EISA_NUMBER)

{

OALMSGS(OAL_ERROR,(LERROR:CS8900AInit:Failed detect chip/r/n));

Goto Exit;

}

检测CS8900A芯片是否存在的依据是读取PacketPage中便宜地址为0的产品ID寄存器,这是个只读的寄存器。如果读取EISA_NUMBER寄存器返回的16为数值是0X630E,则CS8900A芯片存在,否则不存在,CS8900AInit函数中止执行,并且向它的调用者返回FALSE表示执行失败。

CS8900AInit函数执行的第三个步骤就是通过软件操作出发CS8900A芯片复位:

WritePacketPage(SELT_CTL,SELF_CTL_RESET);

接下来,CS8900AInt函数接下来执行两个步骤:

1)等待CS8900A芯片软件复位后完成芯片初始化;

2)等待CS8900A芯片外置的用于存放芯片初始化配置信息的EEPROM存储器可被访问;

接下来CS8900AInit函数要为受CS8900A芯片控制的以太网端口设置MAC地址,方法是写INDIVIDUAL_ADDRESS寄存器:

WritePacketPage(INDIVIDUAL_ADDRESS + 0,mac[0]);

WritePacketPage(INDIVIDUAL_ADDRESS + 0,mac[1]);

WritePacketPage(INDIVIDUAL_ADDRESS + 0,mac[2]);

CS8900AInit剩下的代码就是配置CS8900A以太网控制器的收发数据帧的模式,分为以下四个步骤:

1)配置允许CS8900A以太网控制器芯片接收的以太网数据帧类型:

WritePacketPage(RX_CTL,RX_CTL_RX_OK|RX_CTL_INDIVIDUAL|RX_CTL_BRODCAST);

2)配置CS8900A以太网控制器芯片以中断方式接收数据帧:

WritePacketPage(RX_CFG,RX_CFG_RX_OK_IE);

3)配置CS8900A以太网控制器芯片选择使用第0号中断引脚;

WritePacketPage(INTERRUPT_NUMBER,0);

4)配置CS8900A以太网控制器芯片使之允许接收发送数据帧:

WritePacketPage(LINE_CTL,LINE_CTL_RX_OK|LINE_CTL_TX_ON);

3.发送以太网数据帧。CS8900ASendFrame函数的功能是向以太网发出一个数据帧。其函数原型:

UINT16 CS8900ASendFrame(UINT8 *pData, UINT32 length);

pData参数是指向待发送数据在主机中存放位置的地址指针,length参数记录是以字节为单位的待发送数据的长度。尽管函数的返回值类型定义为UINT16,但是它实际返回的是知识函数执行是否成功的BOOL值。

CS8900ASendFrame函数按照以下步骤完成数据的发送任务:

1)写发送命令和数据长度:

OUTPORT16(&g_pCS8900->TXCMD,TX_CMD_START_ALL);

OUTPORT16(&g_pCS8900->TXLENGTH,length);

这里的宏定义TX_CMD_START_ALL的实际数值(3<<6),它把发送命令端口TxCMD的第6位和第7位(TTxStart)置1,其作用是限定只有当整个数据帧都被写入CS8900A时才开始向外部网络发送数据。

2)检测CS8900A芯片已准备好接收来自主机的待发送数据:

Count = RETRY_COUNT;

While(count-->0){

If((ReadPacketPage(BUS_ST) & BUS_ST_TX_RDY)!=0) break;

}

If (count ==0) goto cleanup;

总线状态寄存器BusST(PacketPage内偏移地址为0138H)的第8位(Rdy4TxNOW)用于CS8900A芯片向主机通知已准备好接收数据,该位置1表示CS8900A已准备好接收来自主机的待发送数据。以上代码采用的是轮询而非中断的方式查询CS8900A芯片是否准备就绪,另一个更好的办法是,将缓冲配置寄存器BufCFG的第8位(Rdy4TxiE)置1,当CS8900A芯片准备好接收待发送数据时将向主机发出中断信号。

3)将待发送的数据依次写入CS8900A的数据端口:

Length = (length + 1)>>1;

While (length-- >0) {

OUTPORT16(&G_Pcs8900->DATA0, *(UINT16*)pData);

pData += sizeof(UINT16);

}

4.接收以太网数据帧CS8900AGetFrame函数。数据帧接收必定要涉及中断,还很有可能要使用DMA操作将接收到的数据从CS8900A芯片搬移到主机中。网络数据如果通过了CS8900A芯片的地址过滤器的筛选(单播地址或广播地址的数据帧),则CS8900A开始接收数据。如果一个数据帧被CS8900A全部接收完毕,具有有效的以太网数据帧长度并且CRC校验无错误,则CS8900A向主机触发RxOK中断,则主机通过CS8900A的数据端口将数据帧读出。

CS8900AGetFrame函数的原型定义如下:

UINT16 CS8900AGetFrame(UINT8 *pData, UINT16 *pLength);

pData参数是主机用来存放接收到的数据帧的内缓冲区起始地址,pLength参数所指向的内存单元记录接收缓冲区的以字节为单位的长度。CS8900AGetFrame函数的返回值是以字节为单位的实际接收到的数据的长度。

CS8900AGetFrame函数首先读CS8900A的ISQ端口,并且判断是否有RxOK中断存在:

Isq = INPORT16(&g_Pcs8900->ISQ);

If ((isq & ISQ_ID_MASK) == RX_EVENT_ID && (isq & RX_EVENT_RX_OK)!=0{

……

}

按照CS8900A的中断机制运行原理,当有中断事件发生时,除反映在事件寄存器的对应位外,还要把该事件寄存器关联到ISQ端口,然后触发中断引脚。此时,ISQ端口的最低6位记录所关联的寄存器的内部偏移地址,其余为是关联寄存器的数据内容。CS8900A芯片共有5个寄存器可以关联到它的ISQ端口,除3个时间寄存器(接收事件寄存器RxEvent、发送事件寄存器TxEvent和缓冲区事件寄存器BufEvent)外,另外两个是接收帧丢失计数器RxMISS和发送冲突计数器TxCOL。所以CS8900AGetFrame函数检测到RxOK中断必须满足两个条件:接收事件寄存器RxEvent(PacketPage内偏移地址为0124H)被关联到ISQ端口,并且其中的RxOK位(第8位)被置1.

如果这两个条件均满足,则主机可以从CS8900A的数据端口读取数据了。读取数据的操作可以按以下的顺序进行:首先是本次数据接收的状态和以字节为单位的数据总长度:

//Get RxStatus and length

Status = INPORT16(&G_Pcs8900->DATA0);

length = INPORT16(&G_Pcs8900->DATA0);

然后是由length指定字节数总长度的帧数据。

如果主机所提供的接收数据缓冲区不够用,则终止数据接收操作并且指令CS8900A丢弃接收到的数据:将接收配置寄存器RxCFG的第6位(Skip_1)置位。这会将当前存在于CS8900A芯片的接收数据缓冲区内的数据帧全部丢弃:

If (length> *pLength) {

// if packet doesnt fit in buffer, skip it

Data = ReadPacketPage(RX_CFG);

WritePacketPage(RX_CFG, data |RX_CFG_SKIP_1);

Length = 0;

} else{

}

5.启用与禁用CS8900A的中断功能的函数CS8900AEnableInts和CS8900ADisableInts。在CS8900A中,总线控制器BusCTL(PacketPage内偏移地址为0116H)的第15位(EnableIRQ)是否被置位即表示CS8900A是否会根据相应的事件产生中断。

6.CS8900A的配置地址过滤机制的函数。CS8900ACurrentPacketFilter和CS8900AMulticastList。

4 网络驱动的编译与加载

在WinCE下,所有的驱动程序都以用户态的DLL文件形式存在。当编写完驱动的模块化接口之后,我们就要将这个模块编译成*.DLL的动态库,然后在编译系统的时候将该DLL动态库加载到系统内核里去,这样操作系统就可以在运行时动态的加载需要的应用程序。

下面以移植CS89O0网卡驱动为实例,介绍如何将网络设备驱动模块加载到WinCE 的内核,编译器为Platform-Builder5.O(简称PB5.O)。其编译、加载过程主要分为六步:

(1)在硬件平台BSP的DRIVERS目录下创建新目录CS89OO。

(2)修改DRIVERS下的DIRS文件,DIR下定义了编译器需要编译的内容,所以需要在DIRS文件中将CS8900目录添加上。

(3)将编写好网络驱动源程序代码拷贝到CS89OO目录下。

(4)编写网络设备驱动的sources文件,告诉编译器和连接器如何编译及连接本驱动程序。这样的sources文件在每个WinCE的驱动下面都有一个,是为了给PB编译驱动的时候提供编译“向导”的。其关键内容为:TARGETTYPE定义编译该驱动成为哪种形式,有DLL和Lib两种形式;TARGETLIBS定义编译该程序的时候需要连接的其他库;SOURCES确定需要编译的文件。本驱动被编译成的形式为DLL,链接了ndis,ntcompat,coredll,ceddk 4个静态库。

(5)编写CS8900的注册表文件,可参考WinCE自带的驱动源码ne2000网卡驱动的注册表文件编写CS8900的注册表文件。注册表定义了网卡的基本参数信息提供给操作系统,其中:Parms项提供网卡驱动在系统中的逻辑中断号,读写基地址,总线类型;TcpIp项提供了网卡IP

地址信息等,如果要修改IP地址就在本注册表项中修改。特别注意网卡的中断的设置,在WinCE中,与外设对应的中断在0AL层被定义,所以这里的中断号必须与0AL层设置的一致,否则网络驱动将无法工作。

(6)将驱动编译进系统内核,修改系统平台初始化文件platform.bib。

经过上述步骤之后,重新编译内核,将内核下载到嵌入式主板上,就可以看到类似Windows操作系统的网络连接一样标志,说明网卡驱动已经被加载到内核。

 

 

    本文在介绍嵌入式WinCE网络驱动架构的基础上,参照WinCE提供的网络驱动模型,详细介绍了嵌入式WinCE以太网驱动程序的设计原理,并已经成功的移植了驱动程序,在嵌入式WinCE下稳定运行。本网络接口已经用于脉冲发生器的远程控制,运行稳定。

{完}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/243134.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

根据状态转移表实现时序电路

根据状态转移表实现时序电路 某同步时序电路转换表如下&#xff0c;请使用D触发器和必要的逻辑门实现此同步时序电路 电路的接口如下图所示 A表示输入&#xff0c;Y 表示输出 理解状态转移表&#xff0c;画成状态转移图 timescale 1ns/1nsmodule seq_circuit(input …

Devoxx 2017美国大会首日重要演讲一览

Devoxx美国大会今天开幕。\u0026#xD;\n\u0026#xD;\nDevoxx是北美版的欧洲软件大会&#xff08;European Software Conference&#xff09;。广受追捧的欧洲软件大会由Stephan Janssen在2001年创立&#xff0c;组织方是比利时Java用户组&#xff08;BeJUG&#xff0c;Belgian Ja…

Linux-Android启动之Machine-Init函数

Linux/Android启动之Machine-Init函数 前言&#xff1a; 前面写过两篇Linux/Android的启动过程分析&#xff0c;这篇接着前两篇的知识点进行分析。 Linux/Android的启动过程包括了很多内容&#xff0c;其中有些需要了解&#xff0c;有些则需要在系统移植的时候进行修改。本篇文…

边沿检测—以脉冲形式给出信号

边沿检测—以脉冲形式给出信号 题目描述&#xff1a; 有一个缓慢变化的1bit信号a&#xff0c;编写一个程序检测a信号的上升沿给出指示信号rise&#xff0c;当a信号出现下降沿时给出指示信号down。 注&#xff1a;rise,down应为单脉冲信号&#xff0c;在相应边沿出现时的下一个…

贷款秒拒?你可能进了“灰名单”!

灰名单/GRAY LIST今天有客户向我反映&#xff0c;他的征信良好没有半点问题&#xff0c;只有一张信用卡备用&#xff0c;没有一次逾期&#xff0c;但是最近想申请贷款都是被秒拒。他觉得很郁闷&#xff0c;是不是办了假的贷款&#xff1f;他完全不知道被拒的理由&#xff0c;只…

Linux--根文件系统的挂载过程分析

前言&#xff1a; 本篇文章以S3C6410公版的Linux BSP和U-Boot来进行分析&#xff0c;文中所有提及的名词和数据都是以该环境为例&#xff0c;所有的代码流程也是以该环境为例来进行分析。哈哈。如果有不正确或者不完善的地方&#xff0c;欢迎前来拍砖留言或者发邮件到guopeixi…

Troubleshooting OpenStack Bug- 每天5分钟玩转 OpenStack(162)

这是 OpenStack 实施经验分享系列的第 12 篇。 问题描述 客户报告了一个问题&#xff1a;对 instance 执行 migrate 操作&#xff0c;几个小时了一直无法完成&#xff0c;不太正常。 问题分析 遇到这种情况&#xff0c;第一个要检查的就是 instance 所在计算节点的 nova-comput…

ROM简单实现

ROM简单实现 题目描述 实现一个深度为8&#xff0c;位宽为4bit的ROM&#xff0c;数据初始化为0&#xff0c;2&#xff0c;4&#xff0c;6&#xff0c;8&#xff0c;10&#xff0c;12&#xff0c;14。可以通过输入地址addr&#xff0c;输出相应的数据data 接口信号图如下&…

Linux--Sys_Read系统调用过程分析

注&#xff1a; 本片文章以Read函数的调用为例来讲述一下系统对块驱动层的一些处理, 哈哈。如果有不正确或者不完善的地方&#xff0c;欢迎前来拍砖留言或者发邮件到guopeixin126.com进行讨论&#xff0c;先行谢过。 一&#xff0e;Read函数经由的层次模型 首先来了解一下Re…

负债的阶梯,你在第几层?

现在的年轻人成为了消费市场上的中流砥柱&#xff0c;他们为我国的GDP贡献了70%的数据。如今年轻人更愿意刷信用卡、网贷平台借钱消费。尽管在外打拼不容易&#xff0c;但是工作稳定&#xff0c;收入稳定&#xff0c;为了犒劳自己及时享乐&#xff0c;他们选择了背负一点债务。…

Android应用程序开发环境的建立

注&#xff1a; 本片文章简单的描述一下Android应用程序开发环境的建立。如果有不正确或者不完善的地方&#xff0c;欢迎前来拍砖留言或者发邮件到guopeixin126.com进行讨论&#xff0c;先行谢过。 一&#xff0e;准备工作... 2 二&#xff0e;安装步骤... 2 1. 安装JDK5.0.…

你真的会 snapshot 吗? - 每天5分钟玩转 OpenStack(163)

​这是 OpenStack 实施经验分享系列的第 13 篇。 instance snapshot 操作可用于备份或者将 instance 保存为新的 image。如果在生产系统中执行 snapshot 操作&#xff0c;必须确保此操作快速且安全。这里有两个关键点&#xff1a; 快速。 为保证数据的一致性&#xff0c;snaps…

输入序列连续的序列检测

输入序列连续的序列检测 题目描述 请编写一个序列检测模块&#xff0c;检测输入信号a是否满足01110001序列&#xff0c;当信号满足该序列&#xff0c;给出指示信号match。 模块的接口信号图如下&#xff1a; 模块的时序图如下&#xff1a; timescale 1ns/1ns module seque…

哪些信用卡取现0手续费?

经常使用信用卡的朋友都知道&#xff0c;信用卡取现一般是要手续费的&#xff0c;而且取现之后不能享受免息期&#xff0c;这点让人很不爽。有时候我们经常会急用钱&#xff0c;这时候用信用卡取现确实很方便&#xff0c;可以解决燃眉之急&#xff0c;能帮上不少忙&#xff0c;…

如何申请到利息低的贷款?

经常有朋友问我&#xff0c;如何才能申请到利息低的贷款&#xff1f;针对这个问题&#xff0c;很多时候我不能给予一个明确的回答。很多朋友之前可能都没有接触过贷款&#xff0c;所以对贷款本身并不是很了解&#xff0c;更有的朋友以为贷款利息可以像商品一样讨价还价&#xf…

含有无关项的序列检测

含有无关项的序列检测 题目描述 请编写一个序列检测模块&#xff0c;检测输入信号a是否满足011XXX110序列&#xff08;长度为9位数据&#xff0c;前三位是011&#xff0c;后三位是110&#xff0c;中间三位不做要求&#xff09;&#xff0c;当信号满足该序列&#xff0c;给出指…

Metadata Service 最高频的应用 - 每天5分钟玩转 OpenStack(164)

实现 instance 定制化&#xff0c;cloud-init&#xff08;或 cloudbase-init&#xff09;只是故事的一半&#xff0c;metadata service 则是故事的的另一半。两者的分工是&#xff1a;metadata service 为 cloud-init 提供自定义配置数据&#xff0c;cloud-init 完成配置工作。…

如何获取并分析Bluetooth HCI层Command Packet和Event Packet包

首先&#xff0c;如何来确定什么样的包为Command/Event Packet呢&#xff1f; 我们知道&#xff0c;通过HCI Packet包括四种&#xff0c;即Command&#xff0c;Event&#xff0c;ACL和SCO/eSCO&#xff0c;对应到MS-Stack中的定义&#xff0c;即为COMMAND_PACKET &#xff0c;E…

Metadata Service 架构详解 - 每天5分钟玩转 OpenStack(165)

下面是 Metadata Service 的架构图&#xff0c;本节我们详细讨论各个组件以及它们之间的关系。 nova-api-metadata nova-api-metadata 是 nova-api 的一个子服务&#xff0c;它是 metadata 的提供者&#xff0c;instance 可以通过 nova-api-metadata 的 REST API 来获取 metada…

hi3531交叉编译环境arm-hisiv100nptl-linux搭建过程

安装SDK 1、Hi3531 SDK包位置 在"Hi3531_V100R001***/01.software/board"目录下&#xff0c;您可以看到一个 Hi3531_SDK_Vx.x.x.x.tgz 的文件&#xff0c; 该文件就是Hi3531的软件开发包。 2、解压缩SDK包 在linux服务器上&#xff08;或者一台装有linux的PC上&…