精华内容
下载资源
问答
  • 2017-07-28 23:49:26

    浅谈以太网帧格式                                      

    一、Ethernet帧格式的发展

    1980 DEC,Intel,Xerox制订了Ethernet I的标准
    1982 DEC,Intel,Xerox又制订了Ehternet II的标准
    1982 IEEE开始研究Ethernet的国际标准802.3
    1983 迫不及待的Novell基于IEEE的802.3的原始版开发了专用的Ethernet帧格式
    1985 IEEE推出IEEE 802.3规范,后来为解决EthernetII与802.3帧格式的兼容问题,
    推出折衷的Ethernet SNAP格式

    (其中早期的Ethernet I已经完全被其他帧格式取代了 ,所以现在Ethernet只能见到后面几种Ethernet的帧格式,
    现在大部分的网络设备都支持这几种Ethernet的帧格式,
    如:cisco的路由器再设定Ethernet接口时可以指定不同的以太网的帧格式:arpa,sap,snap,novell-ether)

    二.各种不同的帧格式
    下面介绍一下各个帧格式 
    1.Ethernet II
    就是DIX以太网联盟推出的。。。。 它由6个字节的目的MAC地址,6个字节的源MAC地址,
    2个字节的类型域(用于标示封装在这个Frame、里面 数据的类型)以上为Frame Header,
    接下来是46--1500字节的数据,和4字节的帧校验
    2.Novell Ethernet
    它的帧头与Ethernet有所不同其中EthernetII帧头中的类型域变成了长度域,
    后面接着的两个字节为0xFFFF,用于标示这个帧是Novell Ether类型的Frame,
    由于前面的0xFFFF站掉了两个字节所以数据域缩小为44-1498个字节,帧校验不变。
    3.IEEE 802.3/802.2
    802.3的Frame Header和Ethernet II的帧头有所不同,EthernetII类型域变成了长度域。
    其中又引入802.2协议(LLC)在802.3帧头后面添加了一个LLC首部,
    由DSAP(Destination Service Access Point)1 byte,SSAP(Source SAP),一个控制域--1 byte! SAP用于标示帧的上层协议。

    4.Ethernet SNAP
    SNAP Frame与802.3/802.2 Frame的最大区别是增加了一个5 Bytes的SNAP ID
    其中前面3个byte通常与源mac地址 的前三个bytes相同为厂商代码!
    有时也可设为0,后2 bytes与Ethernet II的类型域相同。。。


    三.如何区分不同的帧格式
      
    Ethernet中存在这四种Frame那些网络设备又是如何识别的呢? 如何区分EthernetII与其他三种格式的Frame
    如果帧头跟随source mac地址的2 bytes的值大于1500,则此Frame为EthernetII格式的
       
    接着比较紧接着的两bytes如果为0xFFFF则为Novell Ether类型的Frame,
    如果为0xAAAA则为Ethernet SNAP格式的Frame ,如果都不是则为Ethernet 802.3/802.2格式的帧

    几种以太网帧格式
     
     
    相当长的一段时间里我都没搞明白一个很基础的问题---以太网的封装格式;最近查了查相关文档,总结如下;
     
    首先说明一下,Ethernet和802.3并不是一回事,虽然我们经常混用这两个术语;
     
    历史上以太网帧格式有五种:
     
    1.Ethernet V1:这是最原始的一种格式,是由Xerox PARC提出的3Mbps CSMA/CD以太网标准的封装格式,
    后来在1980年由DEC,Intel和Xerox标准化形成Ethernet V1标准;
     
    2.Ethernet V2(ARPA):这是最常见的一种以太网帧格式,也是今天以太网的事实标准,
    由DEC,Intel和Xerox在1982年公布其标准,主要更改了Ethernet V1的电气特性和物理接口,
    在帧格式上并无变化;Ethernet V2出现后迅速取代Ethernet V1成为以太网事实标准;
    Ethernet V2帧头结构为6bytes的源地址+6bytes的目标地址+2Bytes的协议类型字段+数据。
    常见协议类型如下:
    0800       IP
    0806       ARP
    8137       Novell IPX
    809b       Apple Talk
    如果协议类型字段取值为0000-05dc(十进制的0-1500),则该帧就不是Ethernet V2(ARPA)类型了,而是下面讲到的三种802.3帧类型之一;
    Ethernet可以支持TCP/IP,Novell IPX/SPX,Apple Talk Phase I等协议;RFC 894定义了IP报文在Ethernet V2上的封装格式;
     
    3.RAW 802.3:这是1983年Novell发布其划时代的Netware/86网络套件时采用的私有以太网帧格式,
    该格式以当时尚未正式发布的802.3标准为基础;
    但是当两年以后IEEE正式发布802.3标准时情况发生了变化—IEEE在802.3帧头中又加入了802.2 LLC(Logical Link Control)头,
    这使得Novell的RAW 802.3格式跟正式的IEEE 802.3标准互不兼容;可以看到在Novell的RAW 802.3帧结构中并没有标志协议类型的字段,
    而只有Length字段(2bytes,取值为0000-05dc,即十进制的0-1500),因为RAW 802.3帧只支持IPX/SPX一种协议;
     
    4.802.3/802.2 LLC:这是IEEE 正式的802.3标准,它由Ethernet V2发展而来。
    它将Ethernet V2帧头的协议类型字段替换为帧长度字段(取值为0000-05dc;十进制的1500);
    并加入802.2 LLC头用以标志上层协议,LLC头中包含DSAP,SSAP以及Crontrol字段;
    常见SAP值:
    0         Null LSAP        [IEEE]
    4        SNA Path Control         [IEEE]
    6        DOD IP        [79,JBP]
    AA         SNAP        [IEEE]
    FE        Global DSAP        [IEEE]
    SAP值用以标志上层应用,但是每个SAP字段只有8bits长,
    而且其中仅保留了6比特用于标识上层协议,因此所能标识的协议数有限(不超过32种);
    并且IEEE拒绝为某些重要的协议比如ARP协议定义SAP值(奇怪的是同时他们却定义了IP的SAP值);
    因此802.3/802.2 LLC的使用有很大局限性;
     
    5.802.3/802.2 SNAP:这是IEEE为保证在802.2 LLC上支持更多的上层协议同时更好的支持IP协议而发布的标准,
    与802.3/802.2 LLC一样802.3/802.2 SNAP也带有LLC头,但是扩展了LLC属性,
    新添加了一个2Bytes的协议类型域(同时将SAP的值置为AA),
    从而使其可以标识更多的上层协议类型;
    另外添加了一个3Bytes的OUI字段用于代表不同的组织,RFC 1042定义了IP报文在802.2网络中的封装方法和ARP协议在802.2 SANP中的实现;
     
    今天的实际环境中大多数TCP/IP设备都使用Ethernet V2格式的帧。
    这是因为第一种大规模使用的TCP/IP系统(4.2/3 BSD UNIX)的出现时间介于RFC 894和RFC 1042之间,
    它为了避免不能和别的主机互操作的风险而采用了RFC 894的实现;
    也由于大家都抱着这种想法,所以802.3标准并没有如预期那样得到普及;
     
    CISCO设备的Ethernet Interface默认封装格式是ARPA(Ethernet V2)

    不同厂商对这几种帧格式通常有不同的叫法,比如:
    Frame Type         Novel        Cisco
    Ethernet Version 2        Ethernet_II        arpa
    802.3 Raw        Ethernet_802.3        novell_ether
    IEEE 802.3/802.2        Ethernet_802.2        sap
    IEEE 802.3/802.2 SNAP        ETHERNET_SNAP        snap

    **************************************************************************************************************************************
    
    
    
    

    一、 以太网数据帧的格式分析

    大家都知道我们目前的局域网大多数是以太网,但以太网有多种标准,其数据帧有多种格式,恐怕有许多人不是太清楚,本文的目的就是通过帧格式和Sniffer捕捉的数据包解码来区别它们。

    以太网这个术语一般是指数字设备公司(DigitalEquipment)、英特尔公司(Intel)和施乐公司(Xerox)在1982年联合公布的一个标准(实际上它是第二版本,第一版本早在1972年就在施乐公司帕洛阿尔托研究中心PARC里产生了)。它是目前TCP/IP网络采用的主要的局域网技术。它采用一种称作CSMA/CD的媒体接入方法,其意思是带冲突检测的载波侦听多路接入(Carrier Sense, Multiple Access with CollisionDetection)。它的速率为10 Mb/s,地址为48 bit。

    1985年,IEEE(电子电气工程师协会)802委员会公布了一个稍有不同的标准集,其中802.3针对整个CSMA/CD网络,802.4针对令牌总线网络,802.5针对令牌环网络。这三者的共同特性由802.2标准来定义,那就是802网络共有的逻辑链路控制(LLC)。不幸的是,802.2和802.3定义了一个与以太网不同的帧格式,加上1983年Novell为其Netware开发的私有帧,这些给以太网造成了一定的混乱,也给我们学习以太网带来了一定的影响。

    1、通用基础

    数据链路层头(Header)是数据链路层的控制信息的长度不是固定的,根据以太网数据帧的格式的不同而不同,那么判断IEEE802.3、IEEE802.3 SNAP、Ethernet Version2、Netware 802.3“Raw”这些数据帧的最主要依据也源于Header的变化。

    从Sniffer捕捉数据包中也可以看出,Sniffer捕捉数据包的时候是掐头去尾的,不要前面的前导码,也丢弃后面的CRC校验(注意它只是不在Decode里显示该区域,但并不代表它不去做数据包CRC校验),这就是很多人困惑为什么Sniffer捕捉到的数据包长度跟实际长度不相符的原因。那么,Sniffer是如何来判断这些不同类型的以太网格式呢?

    Sniffer可以判断出不同的以太网格式,这里需要注意的是,Sniffer在数据包解码时有自己的格式,所以有Offset之说,offset ØE是指在SnifferHex解码窗口中从左向右第15位的数值。大家如果有点发懵的话,没有关系,看完后面的格式分析后再来分析前面提到的,相信一定能够明白?

    下面我们通过一些具体的数据包来说明各种以太网格式的具体区别。

    2、Ethernet Version2

    以太网版本2是先于IEEE标准的以太网版本。

    从数据包中可以看出,EthernetV2通过在DLC头中2个字节的类型(Type)字段来辨别接收处理。类型字段是用来指定上层协议的(如0800指示IP、0806指示ARP等),它的值一定是大于05FF的,它提供无连接服务的,本身不控制数据(DATA)的长度,它要求网络层来确保数据字段的最小包长度(46字节)。

    Sniffer捕获的Ethernet V2帧的解码,可以看到在DLC层,源DLC地址后紧跟着就是以太网类型(Etehertype)值0800,代表上层封装的是IP报文,0800大于05FF,因而我们可以断定它是Ethernet V2的帧。

     

    3、IEEE802.3

    IEEE802.3把DLC层分隔成明显的两个子层:MAC层和LLC层,其中MAC层主要是指示硬件目的地址和源地址。LLC层用来提供一些服务:

    – 通过SAP地址来辨别接收和发送方法

    – 兼容无连接和面向连接服务

    – 提供子网访问协议(Sub-network Access Protocol,SNAP),类型字段即由它的首部给出。

    MAC层要保证最小帧长度不小于64字节,如果数据不满足64字节长度就必须进行填充。

    是Sniffer捕获的IEEE802.3帧的解码,可以看到在DLC层源地址后紧跟着就是802.3的长度(Length)字段0026,它小于05FF,可以肯定它不是Ethernet V2的帧,而接下来的Offset0E处的值“4242”(代表DSAP和SSAP),既不是Novell 802.3 “Raw”的特征值“FFFF”,也不是IEEE 802.3SNAP的特征值“AAAA”,因此它肯定是一个IEEE802.3的帧。

     

    4、IEEE802.3 SNAP

    SNAP (Sub-Network AccessProtocol)子网访问协议,是逻辑链路控制(Logical LinkControl)的一个子集,它允许协议不用通过服务访问点(SAP)即可实现IEEE兼容的MAC层功能,因此它在DSAP和SSAP域里的值是固定的(AAAA)。也正源于此,它需要额外提供5个字节的头来指定接收方法,3个字节标识厂商代码,2个字节标识上层协议。

    其MAC层保证数据帧长度不小于64字节,不足的话需要进行数据填充。

    是Sniffer捕获的IEEE802.3SNAP帧的解码,可以看到在DLC层源地址后紧跟着就是802.3的长度(Length)字段0175,它小于05FF,可以肯定它不是Ethernet V2的帧,而接下来的Offset 0E处的值“AAAA”(代表DSAP和SSAP),这是IEEE 802.3SNAP的特征值“AAAA”,因此可以断定它是一个IEEE802.3 SNAP的帧。

     

    5、Novell Netware 802.3 “Raw”

    虽然它的产生先于IEEE802.3规范,但已成为IEEE802.3规范的一部分。它仅使用DLC层的下半部,而不使用LLC。

    802.3 “Raw”帧通过在DLC头中2个字节的长度(Length)字段来标记数据帧长度,而在长度字段后紧跟着就是两个字节的十六进制值FFFF,它是用来标识IPX协议头的开始。为了确保最小数据帧长度为64字节,MAC层会进行填充数据区域来确保最小长度。

    在所有工作站都使用同一种数据帧类型情况下不会有什么问题,但如果是在混合以太网帧类型环境中,Novell的这种以太网帧会造成负面影响:当Novell发出广播帧时,其FF字段正好是IEEE802.3帧中的服务访问点(SAP)域,它的“FF”值代表着广播SAP,因此所有的工作站(不管是不是Netware工作站)都会拷贝,这会造成不必要的广播影响。

    Sniffer捕获的Netware 802.3“RAW”帧的解码,可以看到在DLC层源地址后紧跟着就是802.3的长度(Length)字段0120,它小于05FF,可以肯定它不是Ethernet V2的帧,而接下来的Offset 0E处的值“FFFF”(代表IPX协议的开始),这是Netware 802.3“Raw”的特征值“FFFF”,因此可以断定它是一个Novell 802.3 “Raw”的帧。

     

    二、 Ethernet V2帧与IEEE 802.3帧的比较

    因为这两种帧是我们在现在的局域网里最常见的两种帧,因此,我们对它们进行一些比较。

    Ethernet V2可以装载的最大数据长度是1500字节,而IEEE802.3可以装载的最大数据是1492字节(SNAP)或是1497字节; Ethernet V2不提供MAC层的数据填充功能,而IEEE802.3不仅提供该功能,还具备服务访问点(SAP)和SNAP层,能够提供更有效的数据链路层控制和更好的传输保证。那么我们可以得出这样的结论:Ethernet V2比IEEE802.3更适合于传输大量的数据,但EthernetV2缺乏数据链路层的控制,不利于传输需要严格传输控制的数据,这也正是IEEE802.3的优势所在,越需要严格传输控制的应用,越需要用IEEE802.3或SNAP来封装,但IEEE802.3也不可避免的带来数据装载量的损失,因此该格式的封装往往用在较少数据量承载但又需要严格控制传输的应用中。

    在实际应用中,我们会发现,大多数应用的以太网数据包是EthernetV2的帧(如HTTP、FTP、SMTP、POP3等应用),而交换机之间的BPDU(桥协议数据单元)数据包则是IEEE802.3的帧,VLANTrunk协议如802.1Q和Cisco的CDP(思科发现协议)等则是采用IEEE802.3SNAP的帧。大家有兴趣的话,可以利用Sniffer等协议分析工具去捕捉数据包,然后解码查看是不是这样的。

    更多相关内容
  • pci 学习笔记

    千次阅读 2015-01-15 17:08:39
    PCI是Peripheral Component Interconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,其位宽为32位或64位,工作频率为33MHz,最大数据传输率为133MB/sec(32位)和266MB/sec(64位)。可插接显卡、...
    

    摘自:http://blog.chinaunix.net/uid-618506-id-204331.html

    PCI是Peripheral Component Interconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,其位宽为32位或64位,工作频率为33MHz,最大数据传输率为133MB/sec(32位)和266MB/sec(64位)。可插接显卡、声卡、网卡、内置Modem、内置ADSL Modem、USB2.0卡、IEEE1394卡、IDE接口卡、RAID卡、电视卡、视频采集卡以及其它种类繁多的扩展卡.

      目前PCI-E是PCI最新的发展方向,串行,点对点传输,每个传输通道独享带宽;支持双向传输模式和数据分通道传输模式;在PCI-E 3.0规范中,X32端口的双向速率高达320Gbps,可以满足新一代的I/O接口,比如:千兆(GE)、万兆(10GE)的以太网技术、4G/8G的FC技术
    一. PCI 引脚


    1. 接口控制管脚 (出问题时常测这些管脚)

    FRAME#:帧周期信号。Master驱动,表示一次访问的开始和持续时间。 FRAME#无效时,是传输的最后一个数据周期。

    IRDY#:Master准备好信号。
    TRDY#:Slave准备好信号。

    当这两者同时有效时,才能进行完整的数据传输,否则即为等待周期。

    在写周期,IRDY#信号有效时,表示有效的数据信号已在AD0~AD31中建立;
    在读周期,IRDY#信号有效时,表示Master已做好接收数据的准备。

    在写周期,TRDY#信号有效,表示Slave已做好了接收数据的准备。
    在读周期,TRDY#信号有效,表示有效数据已被送入AD0~AD31中,


    STOP#:停止数据传送信号,由Slave发出。当它有效时,表示Slave请求Master终止当前的数据传送。

    IDSEL:初始化设备选择信号。在读写配置空间时,用作Slave的片选信号(Slave通常把IDSEL连到AD[31:0]上的一根,PFA中的device id就是这么确定的)

    DEVSEL#:设备选择信号,由Slave驱动,该信号有效时,当前Slave设备已被选中
     
    二.时序
    读时序


    写时序:


     
     
     
    三.PCI配置空间

    256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。

     

    配置空间的头标区又分为两部分:前16个字节的定义在各种类型的PCI设备中都是一样的;剩余的字节随设备类型不同而有所不同。位于偏移地址0EH处的头标类型字段规定了头标区的布局结构。目前,规范定义了三种头标类型。

     

    头标类型

    设备

    2

    PCI-CardBus

    1

    PCI-PCI

    0

    除上述桥外的所有设备

     

    因为PCI网卡的头标类型是0,所以下面我们就来详细说说其布局结构,至于其他类型的头标请读者自行阅读。图3就是头标类型0的头标区的布局。头标区中的寄存器根据功能可分成下面几组:

     

    1. 设备的识别

    1       供应商代码:该寄存器用于识别PCI设备的制造商,具体代码由PCI SIGhttp://www.pcisig.com)分配。0FFFFH是无效的供应商代码。

    2       设备代码。该寄存器用来标识某供应商生产的具体设备,代码由各供应商定义。供应商代码和设备代码,读者可以到网站http://www.pcidatabase.com/查阅。

     

    3 头标类型0的头标区的布局

     

    3       版本号。该寄存器用来定义指定设备的版本信息。

    4       头标类型。该字段的第7位为“1”标识该设备是多功能设备,为“0”标识为单功能设备;该字段的06位就是上文表中所述的头标类型。

    5       设备分类代码。用来标识设备的总体功能和特定的寄存器级编程接口。

    上面5个字段均为只读类型,所有的PCI设备都必须实现其功能。

     

    2. 设备控制和设备状态

    1       命令寄存器为一个设备发出和响应PCI总线命令提供粗略的控制。图4就是命令寄存器格式。

    4 命令寄存器格式

     

    我们比较感兴趣的位有:

    a.0I/O空间控制):控制对I/O空间访问的响应。该位为0时,禁止设备响应对I/O空间的访问;该位为1时,允许设备响应I/O空间的访问。缺省设置为0

    b.1(存储器空间控制):控制一个设备对存储器空间访问的响应。该位为0时,禁止响应;该位为1时,允许设备响应对存储器空间的访问。缺省设置为0

     

    至于其他位的功能,读者若有兴趣可以自行查阅。

     

    2       状态寄存器用来记录PCI总线有关的状态信息。

     

    3. 基址寄存器

    PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。关于基址寄存器,我们下一章重点讲述。

     

    4. 其他寄存器

    其他寄存器包括一些本文不涉及到的寄存器,如中断引脚、中断线等等。有兴趣的读者可以自行阅读。

     

    四.PCI配置空间的访问

    上面说过,PCI规范使用从0CF8H~0CFFH 8I/O地址来访问所有设备的PCI配置空间。这8个字节实际上构成了两个32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置数据寄存器”。当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了J

     

    我们说过,PCI配置空间对应于一个PCI逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:PCI总线号、PCI设备号、PCI设备功能号和寄存器号。配置地址寄存器的格式如下:

     

    31

    30   24

    23     16

    15     11

    10    8

    7       2

    1

    0

    使能位

    保留

    总线号

    设备号

    功能号

    寄存器号

    0

    0

     

    01位上的“0”是用来要求你只能按双字(4字节)来读写配置空间寄存器。第31位“使能位”用来决定是否允许访问配置空间:为“1”时表示可以访问;为“0”时表示不可以访问。

     

    例如,为了读总线号0、设备号17H、功能号030H寄存器,你可以使用下面的代码:

     

    MOV  EAX, 8000B830H

    MOV  DX, 0CF8H

    OUT   DX, EAX

     

    MOV DX, 0CFCH

    IN  EAX, DA

     

    五.PCI配置空间的遍历

    从上面的配置地址寄存器的格式我们可以看出:总线号从0255、设备号从031、功能号从07。根据配置空间的第0个寄存器是否返回0FFFFH值来判断是否存在该PCI设备。下面是PCI配置空间遍历的流程图:

    5遍历PCI配置空间流程图

    六.基址寄存器

    PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。

     

    PCI设备可以在地址空间中浮动是PCI局部总线中最重要的功能之一。它能够简化设备的配置过程。在系统上电时,与设备无关的系统软件必须确定有哪些设备存在,同时建立一个统一的地址映射关系,并确定一个设备是否有扩展ROM

     

    1.   地址映射

    加电软件在引导操作系统之前必须建立一个统一的地址映射。也就是说,必须确定在系统中有多少存储器以及系统中的I/O控制器要求多少地址空间。当这些信息确定之后,加电软件便可以把I/O控制器映射到合理的地址空间并引导系统。为了使这种映射能够做到与响应的设备无关,从而在配置空间的头标区中安排了一个供映射时使用的基址寄存器。

     

    在所有的基址寄存器中,位0均为只读位并且用来决定能够是存储器空间还是I/O空间。如果该位为0,则表示映射到存储器空间;若为1则表示映射到I/O地址空间。

     

    2.   存储器基地址寄存器

    映射到存储器空间的基址寄存器可以是32位宽度,也可以是64位宽度(支持映射到一个64位地址空间时)(如图6)。

    6  32/64存储器基地址寄存器格式

     

    其中位0要用硬件方法使其恒为0。而位2和位1两位用来表示映射类型,具体如下:

     

    2和位1

    映射类型

    00

    基地址寄存器为32位宽,可以在32位表示的存储器地址范围的任何地方进行映射

    01

    保留

    10

    基地址寄存器为64位宽,可以映射到以64位表示的存储器空间的任何地方

    11

    保留

     

    至于位3,若数据是可预取的,就应将它置为1,否则清0。该寄存器的区域各位用来将一设备映射到存储器空间。

     

    基地址寄存器中用于32位存储器译码器的位【31::4】和用于64位存储器译码器的位【63::4】称为基地址单元。它的作用是:确定与译码器相关的存储器的大小;给译码器分配地址。如果存储器设备需要小于4K的存储空间,规范建议存储器范围强行设为4KB

     

    3.   I/O基地址寄存器

    映射到I/O空间的基址寄存器宽度总是32位(如图7):

     

    7  I/O基地址寄存器格式

     

    其中位0值为1(用硬件实现的),位1为保留位并且其读出值必须为0,其余各位用来把设备映射到I/O空间。

     

    当基地址寄存器位0的返回值为1时,表示这是一个I/O译码器,而不是存储器译码器,位1保留并总是返回0,【31::2】是基地址单元,并用于确定需要的I/O块容量,设置它的起始地址。

     

    规范要求映射它的控制寄存器组到I/O空间的 设备不必请求每个I/O基地址寄存器超过256个单元。

     

    4.   确定块容量和分配地址范围

    要确定存储器的容量或I/O空间大小可以通过简单地向基地址寄存器写入全“1”并回读来确定。若返回一个是0值,则表示未实现基地址寄存器;如果读回地值为非0,则编程人员通过从基地址单元的最低有效位向上扫描返回值以找到第一个被成功置“1”的位来确定所需存储器的容量或I/0空间的大小。假设寄存器的位0是一个加权二进制1,那么位1的值就是2,位2的值就是4,依此类推。这样,在基地址单元中第一个发现的1所对应的加权二进制值便是所需的空间数。这也是寄存器的第一个可读/可写位,在它之上的所有位钧定义为可读/可写位。这个信息发现后,程序将32/64位存储器起始地址或32I/O地址写入基地址寄存器中。

     

    5.   扩展ROM基地址寄存器

    有些PCI设备,尤其是那些准备用于PC结构扩展板上的设备,需要EPROM作为扩展ROM。为此,在配置空间偏移地址30H处开始定义了四个字节的寄存器,用来处理这个扩展ROM的基地址和大小。(如图8)

     

    8 扩展ROM基地址寄存器格式

     

    该寄存器和32位基地址寄存器相比,除了位的编码和用途不同之外,其它功能完全相似。它的高21位对应于扩展ROM基地址的高21位。一个设备实际实现的位数取决于该设备要求多大的地址空间。例如,一个设备要求它的扩展ROM映射到一64KB存储区域时,它就应该实现此寄存器的高16位,其它5位用硬件方法使它们恒为0。凡是支持扩展ROM的设备必须实现这个寄存器。

    与设备无关的配置软件通过对扩展ROM基址寄存器的地址位上写入全“1”,然后再读回以确定设备要求多大的地址范围。所有的无关位上都返回0,从而有效地指出了地址边界,也就知道了设备要求的这一块地址空间的大小。一个设备要求的地址空间范围不能超过16MB

     

    这个寄存器的位0用来控制相应的设备是否能够接受对其扩展ROM的访问。当该位为0时,禁止访问设备的扩展ROM地址空间;当该位为1时,允许将本寄存器的其它位作为参数进行地址译码。命令寄存器中的存储器空间位优先于扩展ROM的使能位,但是,如果存储器空间位和扩展ROM的的使能位同时为1时,设备就必须响应对其扩展ROM的访问。扩展ROM的使能位在复位后应该为0

     

    七.PCI拓扑结构
    PCI拓扑结构,有如下例子



        在上图的总线结构中,ethernet设备和pci-pci bridge的资源空间必须要是pci bus0的一个子集
        同理,SCSI和VIDEO同类型资源必须要是pci_bus1的子集。
        CPU访问PCI的过程是这样的(只有一个根总线和pci-pci bridge过滤窗口功能打开的情况):
        1.cpu向pci发出一个I/O请求。
        首先经过根总线.它会判断是否在它的资源范围内.如果在它的范围,它就会丢向总线所在的每一个设备.包括pci bridge. 如果没有在根总线的资源范围,则不会处理这个请求.
        2.如果pci设备判断该地址属于它的资源范围,则处理后发出应答
        3.pci bridge接收到这个请求,它会判断I/O地址是否在它的资源范围内.如果在它的范围,它会把它丢到它的下层子线.
        4.下层总线经过经过相同的处理后,就会找到这个PCI设备了
        一个PCI设备访问其它PCI设备或者其它外设的过程:
        1.首先这个PCI发出一个请求,这个请求会在总线上广播
        2.如果要请求的设备是在同级总线,就会产生应答
        3.请求的设备不是在同层总线,就会进行pci bridge.pci桥判断该请求不在它的范围内(目的地不是它下层的设备),就会将它丢向上层.
        4.这样辗转之后,就能找到对应的设备了


    八.PCI枚举过程
    通过PCI枚举,CPU知道当前系统上有多少PCI设备,多少根PCI总线,PCI配置空间初始化。
        PCI 总线扫描的原理是从总线 0 扫描到总线 255,对于每条总线,系统都会扫描所有(总线号,设备号,功能号),读出每个设备配置空间的Device ID和Vendor ID寄存器,如果这两个寄存器的值是个无效值(0xFFFF),则说明当前位置上没有设备,接着扫描下一个位置。
        如果是有效值(非0xFFFF),当前位置是个有效的 PCI 设备/桥。进而再读取该设备的 Header Type 寄存器,如果该寄存器为 1,则表示当前设备是 PCI 桥,否则是 PCI 设备。
    Register Number:配置空间寄存器偏移量
    Function Number:多功能设备有多个功能号
    Device Number:设备编号
    Bus Number:总线编号

    对所有 PCI 总线进行编号
        PCI 桥如何知道它所连接的 PCI 总线情况呢?这就需要对 PCI 桥进行总线编号。前面介绍过 PCI 桥提供了 Primary Bus Number、Secondary Bus Number 和 Subordinate Bus Number 三个寄存器用于标志该桥所连接的 PCI 总线,下面通过一个示例来说明内核对于 PCI 总线是如何进行编号的。

    1.系统运行初始,Bus A 为 0,通过上面的 PCI 总线扫描得到连接在 Bus A 上的 PCI 桥(即图中Bridge 1)
    2.下面开始设置 Bridge 1 的 Bus 寄存器。将 Primary Bus Number 寄存器设置成 Bus A 的编号,即 0。将 Secondary Bus Number 寄存器设置成 Bus B 的编号,它的值等于(Bus A + 1),也就是 1。由于暂时无法知道该桥所能访问的所有下行总线数目,Subordinate Bus Number 寄存器暂时设置成 0xFF。
    3.当扫描完所有 Bus A 上所有(设备号,功能号)后,开始扫描 Bus B,Bus B 的编号在扫描完 Bus A 后已经得到,为 1。Bus B 的扫描方法同步骤(1),先扫描出 Bus B 上的 PCI 桥(即图中的 Bridge 2),然后配置 Primary Bus Number 寄存器为 1,Secondary Bus Number 寄存器为 2,而 Subordinate Bus Number 寄存器依然为 0xFF。
    4.Bus B 扫描完后得到 Bus C 的编号,为2。下面开始扫描 Bus C,因为 Bus C 上没有 PCI 桥,于是在扫描完其它(设备号,功能号)后,Bus C 的扫描结束。
    5.由于 Bridge 2 所能访问到的最大 Bus 编号是 2,因此重新设置 Bridge 2 的 Subordinate Bus Number 寄存器为 2。
    6.由于 Bridge 1 所能访问到的最大 Bus 编号也是 2,因此重新设置 Bridge 1 的 Subordinate Bus Number 寄存器为 2。
    7.总线编号结束。


    九.Linux内核PCI数据结构
    内核(linux-2.6.24) 提供了三类数据结构用以描述 PCI 控制器、PCI 设备以及 PCI 总线。
    数据结构关系如下所示

    PCI 控制器 用 pci_controller 结构来描述,它有以下几个主要的属性:
    index:该属性标志 PCI 控制器的编号。
    next:该属性指向下一个 PCI 控制器,通过 next 属性,PCI 控制器可以形成一个单向链表。
    first_busno:该属性标志了连接在该控制器上第一条总线的编号。
    last_busno:该属性标志了连接在该控制器上最后一条总线的编号。
    ops:该属性标志了当前 PCI 控制器所对应的 PCI 配制空间读写操作函数。
    io_space:该属性标志了当前 PCI 控制器所支持的 IO 地址空间。
    mem_space:该属性标志了当前 PCI 控制器所支持的 Memory 地址区间。
    cfg_addr:该属性标志了当前 PCI 控制器发起 Configuration 访问方式时所需要写入的地址空间。
    cfg_data:该属性标志了当前 PCI 控制器发起 Configuration 访问方式时所需要读写的数据空间。
    bus:该属性标志了当前 PCI 控制器所连接的 PCI 总线,它对应的数据结构是 pci_bus。
    PCI 总线 用 pci_bus 结构来描述,它有以下几个主要的属性:
    parent:可通过该属性索引到上层 PCI 总线。
    self:该属性标志了连接的上行 PCI 桥(对应的数据结构是 pci_dev)。
    children:该属性标志了总线连接的所有 PCI 子总线链表。
    devices:该属性标志了总线连接的所有 PCI 设备链表。
    ops:该属性标志了总线上所有 PCI 设备的配制空间读写操作函数。
    number:该属性标志了当前 PCI 总线的编号。
    primary:该属性标志了 PCI 上行总线编号。
    secondary:该属性标志了 PCI 下行总线编号。
    subordinate:该属性标志了能够访问到的最大总线编号。
    resource:该属性标志了 Memory/IO 地址空间。
    PCI 设备 用 pci_dev 结构来描述,它有以下几个主要的属性:
    global_list:Linux 定义了一个全局列表来索引所有PCI 设备,该属性标志了这个全局列表的首指针。
    bus:该属性标志了当前设备所在的 PCI 总线(对应的数据结构是 pci_bus)。
    devfn:该属性标志了设备编号和功能编号。
    vendor:该属性标志了供应商编号。
    device:该属性标志了设备编号。
    driver:该属性标志了设备对应的驱动代码(对应的数据结构是 pci_driver)。
    irq:该属性标志了中断号。
    resource:该属性标志了 Memory/IO 地址区间。
    当 Linux 内核在做 PCI 初始化工作时,它会根据建立一个由 pci_controller、pci_bus 和 pci_dev 三者组成的一个组织结构图。根据这个结构,软件开发者可以很方便的通过 PCI 控制器索引到每个 PCI 设备或者 PCI 总线。


     

      十.linux的PCI子系统初始化流程
    第一步:Linux分配数据结构pci_contoller,并初始化,包括PCI的mem/io空间范围和访问PCI配置空间所需的handler。
    第二步:PCI设备的枚举:扫描系统上所有PCI设备,初始化它们的配置空间。(硬件上的初始化)
    第三步:用数据结构将PCI设备信息联系起来,构建PCI树。(软件上的初始化)
    第四步:加载PCI设备驱动。
    1 初始化PCI控制器
    pci_controller结构是内核描述PCI子系统信息的数据结构,里面定义了可供PCI设备使用的mem资源和io资源的范围,访问pci设备配置空间的handler等等。
    函数调用关系:

     

    1. start_kernel --> mpc8560ads_setup_arch --> mpc85xx_setup_hose()
    2. 此函数分配并初始化了pci_controller
    3. mpc85xx_setup_hose()
    4.     -->pcibios_alloc_controller() //分配数据结构pci_controller

    5.     ppc_md.pci_map_irq = mpc85xx_map_irq; //用来获得pci设备irq号的handler

    6.     -->setup_indirect_pci() //设置pci_controller里访问PCI配置空间的钩子函数

    7.                             //使用ioremap后的CFG_ADDR和CFG_DATA的虚拟地址

    8.     -->mpc85xx_setup_pci1() //设置PCI inbound和outbound窗口寄存器。

    9. PCI子系统的mem和io地址空间范围也在函数mpc85xx_setup_hose()中定义:
    10.     pci_controller *hose_a;
    11.     hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM;
    12.     hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM;
    13.     hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO;
    14.     hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;


    2 PCI枚举过程
    目前为止,内核只知道PCI子系统总的mem资源和io资源地址范围。
    接下来,内核需要扫描所有PCI设备,把这些资源分配给PCI设备,具体方法参考前面讲的PCI枚举过程。
    内核分配mem资源时是从高地址开始分配的。

     

    1. mpc85xx_setup_hose()
    2.     -->pciauto_bus_scan()
    3.     for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { //遍历0号总线上所有PCI设备

    4.         if (读当前设备配置空间PCI_HEADER_TYPE失败)
    5.             continue; //当前设备不存在,扫描下一个

    6.         读当前设备配置空间PCI_CLASS_REVISION
    7.         If(当前设备是PCI桥){
    8.             pciauto_setup_bars() //分配pci_controller的资源的子集

    9.             pciauto_prescan_setup_bridge() //写PCI桥配置空间 PCI_PRIMARY_BUS

    10.                                                 //PCI_SECONDARY_BUS

    11.                                                 //PCI_SUBORDINATE_BUS

    12.             pciauto_bus_scan() //递归扫描下一条pci bus

    13.             pciauto_postscan_setup_bridge() //写PCI桥配置空间PCI_SUBORDINATE_BUS

    14.         }
    15.         。。。。。略去
    16.         else {
    17.             //当前设备是PCI设备

    18.             pciauto_setup_bars()
    19.         }
    20.     }


     

        注意:执行完 pciauto_bus_scan后,所有pci设备(包括桥)的配置空间都已经傻瓜式的简单初始化
          但这些桥和设备还没有通过数据结构组织起来,这些工作要在第四步 pcibios_init里来完成
    3 创建PCI树
    上面说了,PCI设备配置空间都初始化差不多了,但是PCI设备还没有通过数据结构组织起来。   

     

    1. do_initcalls()
    2.   -->pcibios_init() //所在文件 arch/ppc/kernel/pci.c

    3. pcibios_init()
    4.     (1):为PCI设备构造数据结构,组织成PCI树

    5. ->pci_scan_bus(hose->first_busno,hose->ops,hose)//hose就是上面的pci_controller结构


    6.  -->pci_scan_bus_parented

    7.    -->pci_create_bus // 建立 PCI bus 0 对应的数据结构,这个bus的资源尚未初始化

    8.  -->pci_scan_child_bus // 从PCI bus 0 开始扫描生成PCI树,使用了递归


    9.      -->pci_scan_slot

    10.       -->pci_scan_single_dev
    11.     -->pci_scan_device() //创建 pci_dev结构

    12.      -->pci_setup_device() //区分桥与设备,分别进行初始化

    13.       -->pci_read_bases();


     

    pci_dev->resouce[]中保存的才是cpu internal address(EA),可以对这些地址进行用ioremap,在驱动程序对bar所指位置读写的时候一定要用这       
        (2)给PCI设备分配IRQ号

     

    1. -->pci_fixup_irqs()
    2.         //遍历所有pci设备,调用pdev_fixup_irq()

    3.    -->pdev_fixup_irq
    4.        -->ppc_md.pci_swizzle() //实际调用common_swizzle(),获得pci所在slot编号

    5. 读PCI设备配置空间PCI_INTERRUPT_PIN,获得中断pin编号[1到4]

    6.     之所以是1到4,因为PCI规范里设备最多4个管脚(除第一个外,其他3个仅用于多功能设备)
    7.        -->ppc_md.pci_map_irq() //实际调用mpc85xx_map_irq()

    8.                                     //根据slot,pin 和 pci_irq_table[][4]

    9.                                     //来计算出irq号

    10.        -->pcibios_update_irq(pci_dev,irq)
    11.         //将irq号写入pci设备的配置空间PCI_INTERRUPT_LINE

    12.         //注意,这里寄存器只是用来保存结果,例如把其值8改为9,并不能改变中断号

    13.     (3)PCI结构树有了,现在构建PCI的资源树,有冲突就修改
    14.     -->pcibios_allocate_bus_resource()
    15.         //只考虑pci_bus,形成bus级资源树(并同时check,资源冲突了就修改)

    16.     -->pcibios_allocate_resources()
    17.         


     

    4 加载PCI设备驱动
    以e1000 PCI 网卡 82546GB为例,讲解一个PCI驱动的加载过程
    驱动里有如下代码:

     

    1. static struct pci_driver e1000_driver = {
    2.     .name = e1000_driver_name,
    3.     .id_table = e1000_pci_tbl,
    4.     .probe = e1000_probe,
    5.     .remove = __devexit_p(e1000_remove),
    6. #ifdef CONFIG_PM
    7.     /* Power Managment Hooks */
    8.     .suspend = e1000_suspend,
    9.     .resume = e1000_resume,
    10. #endif
    11.     .shutdown = e1000_shutdown,
    12.     .err_handler = &e1000_err_handler
    13. };
    14. module_init(e1000_init_module);
    15. do_initcalls()
    16.     -->e1000_init_module
    17.         pci_register_driver(&e1000_driver)
    18.         // e1000_driver.driver.bus = &pci_bus_type;

    19.     -->driver_register(e1000_driver.driver);
    20.     //pci_bus_type.probe() 非空,即调用pci_device_probe()

    21. pci_device_probe(*device)
    22.     -->__pci_device_probe(*pci_driver,*pci_dev)
    23.         -->pci_match_device(*pci_driver,*pci_dev)
    24.         -->pci_call_probe(*pci_driver,*pci_dev,pci_device_id)
    25.             -->drv->probe(*pci_device,*pci_device_id)
    26.             即执行 e1000_probe(*pci_device,*pci_device_id)PCI是Peripheral Component Interconnect(外设部件互连标准)的缩写,它是目前个人电脑中使用最为广泛的接口,其位宽为32位或64位,工作频率为33MHz,最大数据传输率为133MB/sec(32位)和266MB/sec(64位)。可插接显卡、声卡、网卡、内置Modem、内置ADSL Modem、USB2.0卡、IEEE1394卡、IDE接口卡、RAID卡、电视卡、视频采集卡以及其它种类繁多的扩展卡.

      目前PCI-E是PCI最新的发展方向,串行,点对点传输,每个传输通道独享带宽;支持双向传输模式和数据分通道传输模式;在PCI-E 3.0规范中,X32端口的双向速率高达320Gbps,可以满足新一代的I/O接口,比如:千兆(GE)、万兆(10GE)的以太网技术、4G/8G的FC技术

      一. PCI 引脚



      1. 接口控制管脚 (出问题时常测这些管脚)

      FRAME#:帧周期信号。Master驱动,表示一次访问的开始和持续时间。 FRAME#无效时,是传输的最后一个数据周期。

      IRDY#:Master准备好信号。
      TRDY#:Slave准备好信号。

      当这两者同时有效时,才能进行完整的数据传输,否则即为等待周期。

      在写周期,IRDY#信号有效时,表示有效的数据信号已在AD0~AD31中建立;
      在读周期,IRDY#信号有效时,表示Master已做好接收数据的准备。

      在写周期,TRDY#信号有效,表示Slave已做好了接收数据的准备。
      在读周期,TRDY#信号有效,表示有效数据已被送入AD0~AD31中,


      STOP#:停止数据传送信号,由Slave发出。当它有效时,表示Slave请求Master终止当前的数据传送。

      IDSEL:初始化设备选择信号。在读写配置空间时,用作Slave的片选信号(Slave通常把IDSEL连到AD[31:0]上的一根,PFA中的device id就是这么确定的)

      DEVSEL#:设备选择信号,由Slave驱动,该信号有效时,当前Slave设备已被选中



      二.时序
      读时序


      写时序:










      三.PCI配置空间


      256字节的PCI配置空间分为64字节的头标区和192字节的设备相关区两部分。头标区的各个寄存器用来唯一地识别设备;设备相关区则保存一些与设备相关的数据。



      配置空间的头标区又分为两部分:前16个字节的定义在各种类型的PCI设备中都是一样的;剩余的字节随设备类型不同而有所不同。位于偏移地址0EH处的头标类型字段规定了头标区的布局结构。目前,规范定义了三种头标类型。





      头标类型

      设备


      2

      PCI-CardBus桥


      1

      PCI-PCI桥


      0

      除上述桥外的所有设备




      因为PCI网卡的头标类型是0,所以下面我们就来详细说说其布局结构,至于其他类型的头标请读者自行阅读。图3就是头标类型0的头标区的布局。头标区中的寄存器根据功能可分成下面几组:



      1. 设备的识别

      (1) 供应商代码:该寄存器用于识别PCI设备的制造商,具体代码由PCI SIG(http://www.pcisig.com)分配。0FFFFH是无效的供应商代码。

      (2) 设备代码。该寄存器用来标识某供应商生产的具体设备,代码由各供应商定义。供应商代码和设备代码,读者可以到网站http://www.pcidatabase.com/查阅。







      图3 头标类型0的头标区的布局



      (3) 版本号。该寄存器用来定义指定设备的版本信息。

      (4) 头标类型。该字段的第7位为“1”标识该设备是多功能设备,为“0”标识为单功能设备;该字段的0~6位就是上文表中所述的头标类型。

      (5) 设备分类代码。用来标识设备的总体功能和特定的寄存器级编程接口。

      上面5个字段均为只读类型,所有的PCI设备都必须实现其功能。



      2. 设备控制和设备状态

      (1) 命令寄存器为一个设备发出和响应PCI总线命令提供粗略的控制。图4就是命令寄存器格式。







      图4 命令寄存器格式



      我们比较感兴趣的位有:

      a.位0(I/O空间控制):控制对I/O空间访问的响应。该位为0时,禁止设备响应对I/O空间的访问;该位为1时,允许设备响应I/O空间的访问。缺省设置为0。

      b.位1(存储器空间控制):控制一个设备对存储器空间访问的响应。该位为0时,禁止响应;该位为1时,允许设备响应对存储器空间的访问。缺省设置为0。



      至于其他位的功能,读者若有兴趣可以自行查阅。



      (2) 状态寄存器用来记录PCI总线有关的状态信息。



      3. 基址寄存器

      PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。关于基址寄存器,我们下一章重点讲述。



      4. 其他寄存器

      其他寄存器包括一些本文不涉及到的寄存器,如中断引脚、中断线等等。有兴趣的读者可以自行阅读。



      四.PCI配置空间的访问

      上面说过,PCI规范使用从0CF8H~0CFFH 这8个I/O地址来访问所有设备的PCI配置空间。这8个字节实际上构成了两个32位寄存器:0CF8H寄存器叫做“配置地址寄存器”;0CFCH叫做“配置数据寄存器”。当要访问配置空间的寄存器时,先向地址寄存器写上目标地址,然后就可以从数据寄存器中读写数据了J。



      我们说过,PCI配置空间对应于一个PCI逻辑设备,所以要访问一个配置空间的某个寄存器,必须要指定:PCI总线号、PCI设备号、PCI设备功能号和寄存器号。配置地址寄存器的格式如下:





      31

      30 24

      23 16

      15 11

      10 8

      7 2

      1

      0


      使能位

      保留

      总线号

      设备号

      功能号

      寄存器号

      0

      0




      第0、1位上的“0”是用来要求你只能按双字(4字节)来读写配置空间寄存器。第31位“使能位”用来决定是否允许访问配置空间:为“1”时表示可以访问;为“0”时表示不可以访问。



      例如,为了读总线号0、设备号17H、功能号0的30H寄存器,你可以使用下面的代码:







      MOV EAX, 8000B830H

      MOV DX, 0CF8H

      OUT DX, EAX



      MOV DX, 0CFCH

      IN EAX, DA






      五.PCI配置空间的遍历

      从上面的配置地址寄存器的格式我们可以看出:总线号从0~255、设备号从0~31、功能号从0~7。根据配置空间的第0个寄存器是否返回0FFFFH值来判断是否存在该PCI设备。下面是PCI配置空间遍历的流程图:





      图5遍历PCI配置空间流程图

      六.基址寄存器

      PCI设备中,除了配置空间外,还有两个物理空间:内存空间和I/O空间。为了访问这两个地址空间,就必须使用基址寄存器。头标类型0中涉及3种基址寄存器:内存空间基址寄存器、I/O空间基址寄存器和扩展ROM基址寄存器。



      PCI设备可以在地址空间中浮动是PCI局部总线中最重要的功能之一。它能够简化设备的配置过程。在系统上电时,与设备无关的系统软件必须确定有哪些设备存在,同时建立一个统一的地址映射关系,并确定一个设备是否有扩展ROM。



      1. 地址映射

      加电软件在引导操作系统之前必须建立一个统一的地址映射。也就是说,必须确定在系统中有多少存储器以及系统中的I/O控制器要求多少地址空间。当这些信息确定之后,加电软件便可以把I/O控制器映射到合理的地址空间并引导系统。为了使这种映射能够做到与响应的设备无关,从而在配置空间的头标区中安排了一个供映射时使用的基址寄存器。



      在所有的基址寄存器中,位0均为只读位并且用来决定能够是存储器空间还是I/O空间。如果该位为0,则表示映射到存储器空间;若为1则表示映射到I/O地址空间。



      2. 存储器基地址寄存器

      映射到存储器空间的基址寄存器可以是32位宽度,也可以是64位宽度(支持映射到一个64位地址空间时)(如图6)。







      图6 32/64存储器基地址寄存器格式



      其中位0要用硬件方法使其恒为0。而位2和位1两位用来表示映射类型,具体如下:





      位2和位1

      映射类型


      00

      基地址寄存器为32位宽,可以在32位表示的存储器地址范围的任何地方进行映射


      01

      保留


      10

      基地址寄存器为64位宽,可以映射到以64位表示的存储器空间的任何地方


      11

      保留




      至于位3,若数据是可预取的,就应将它置为1,否则清0。该寄存器的区域各位用来将一设备映射到存储器空间。



      基地址寄存器中用于32位存储器译码器的位【31::4】和用于64位存储器译码器的位【63::4】称为基地址单元。它的作用是:确定与译码器相关的存储器的大小;给译码器分配地址。如果存储器设备需要小于4K的存储空间,规范建议存储器范围强行设为4KB。



      3. I/O基地址寄存器

      映射到I/O空间的基址寄存器宽度总是32位(如图7):





      图7 I/O基地址寄存器格式



      其中位0值为1(用硬件实现的),位1为保留位并且其读出值必须为0,其余各位用来把设备映射到I/O空间。



      当基地址寄存器位0的返回值为1时,表示这是一个I/O译码器,而不是存储器译码器,位1保留并总是返回0,【31::2】是基地址单元,并用于确定需要的I/O块容量,设置它的起始地址。



      规范要求映射它的控制寄存器组到I/O空间的 设备不必请求每个I/O基地址寄存器超过256个单元。



      4. 确定块容量和分配地址范围

      要确定存储器的容量或I/O空间大小可以通过简单地向基地址寄存器写入全“1”并回读来确定。若返回一个是0值,则表示未实现基地址寄存器;如果读回地值为非0,则编程人员通过从基地址单元的最低有效位向上扫描返回值以找到第一个被成功置“1”的位来确定所需存储器的容量或I/0空间的大小。假设寄存器的位0是一个加权二进制1,那么位1的值就是2,位2的值就是4,依此类推。这样,在基地址单元中第一个发现的1所对应的加权二进制值便是所需的空间数。这也是寄存器的第一个可读/可写位,在它之上的所有位钧定义为可读/可写位。这个信息发现后,程序将32/64位存储器起始地址或32位I/O地址写入基地址寄存器中。



      5. 扩展ROM基地址寄存器

      有些PCI设备,尤其是那些准备用于PC结构扩展板上的设备,需要EPROM作为扩展ROM。为此,在配置空间偏移地址30H处开始定义了四个字节的寄存器,用来处理这个扩展ROM的基地址和大小。(如图8)



      图8 扩展ROM基地址寄存器格式



      该寄存器和32位基地址寄存器相比,除了位的编码和用途不同之外,其它功能完全相似。它的高21位对应于扩展ROM基地址的高21位。一个设备实际实现的位数取决于该设备要求多大的地址空间。例如,一个设备要求它的扩展ROM映射到一64KB存储区域时,它就应该实现此寄存器的高16位,其它5位用硬件方法使它们恒为0。凡是支持扩展ROM的设备必须实现这个寄存器。

      与设备无关的配置软件通过对扩展ROM基址寄存器的地址位上写入全“1”,然后再读回以确定设备要求多大的地址范围。所有的无关位上都返回0,从而有效地指出了地址边界,也就知道了设备要求的这一块地址空间的大小。一个设备要求的地址空间范围不能超过16MB。



      这个寄存器的位0用来控制相应的设备是否能够接受对其扩展ROM的访问。当该位为0时,禁止访问设备的扩展ROM地址空间;当该位为1时,允许将本寄存器的其它位作为参数进行地址译码。命令寄存器中的存储器空间位优先于扩展ROM的使能位,但是,如果存储器空间位和扩展ROM的的使能位同时为1时,设备就必须响应对其扩展ROM的访问。扩展ROM的使能位在复位后应该为0。



      七.PCI拓扑结构
      PCI拓扑结构,有如下例子



      在上图的总线结构中,ethernet设备和pci-pci bridge的资源空间必须要是pci bus0的一个子集
      同理,SCSI和VIDEO同类型资源必须要是pci_bus1的子集。
      CPU访问PCI的过程是这样的(只有一个根总线和pci-pci bridge过滤窗口功能打开的情况):
      1.cpu向pci发出一个I/O请求。
      首先经过根总线.它会判断是否在它的资源范围内.如果在它的范围,它就会丢向总线所在的每一个设备.包括pci bridge. 如果没有在根总线的资源范围,则不会处理这个请求.
      2.如果pci设备判断该地址属于它的资源范围,则处理后发出应答
      3.pci bridge接收到这个请求,它会判断I/O地址是否在它的资源范围内.如果在它的范围,它会把它丢到它的下层子线.
      4.下层总线经过经过相同的处理后,就会找到这个PCI设备了
      一个PCI设备访问其它PCI设备或者其它外设的过程:
      1.首先这个PCI发出一个请求,这个请求会在总线上广播
      2.如果要请求的设备是在同级总线,就会产生应答
      3.请求的设备不是在同层总线,就会进行pci bridge.pci桥判断该请求不在它的范围内(目的地不是它下层的设备),就会将它丢向上层.
      4.这样辗转之后,就能找到对应的设备了


      八.PCI枚举过程
      通过PCI枚举,CPU知道当前系统上有多少PCI设备,多少根PCI总线,PCI配置空间初始化。
      PCI 总线扫描的原理是从总线 0 扫描到总线 255,对于每条总线,系统都会扫描所有(总线号,设备号,功能号),读出每个设备配置空间的Device ID和Vendor ID寄存器,如果这两个寄存器的值是个无效值(0xFFFF),则说明当前位置上没有设备,接着扫描下一个位置。
      如果是有效值(非0xFFFF),当前位置是个有效的 PCI 设备/桥。进而再读取该设备的 Header Type 寄存器,如果该寄存器为 1,则表示当前设备是 PCI 桥,否则是 PCI 设备。
      Register Number:配置空间寄存器偏移量
      Function Number:多功能设备有多个功能号
      Device Number:设备编号
      Bus Number:总线编号

      对所有 PCI 总线进行编号
      PCI 桥如何知道它所连接的 PCI 总线情况呢?这就需要对 PCI 桥进行总线编号。前面介绍过 PCI 桥提供了 Primary Bus Number、Secondary Bus Number 和 Subordinate Bus Number 三个寄存器用于标志该桥所连接的 PCI 总线,下面通过一个示例来说明内核对于 PCI 总线是如何进行编号的。

      1.系统运行初始,Bus A 为 0,通过上面的 PCI 总线扫描得到连接在 Bus A 上的 PCI 桥(即图中Bridge 1)
      2.下面开始设置 Bridge 1 的 Bus 寄存器。将 Primary Bus Number 寄存器设置成 Bus A 的编号,即 0。将 Secondary Bus Number 寄存器设置成 Bus B 的编号,它的值等于(Bus A + 1),也就是 1。由于暂时无法知道该桥所能访问的所有下行总线数目,Subordinate Bus Number 寄存器暂时设置成 0xFF。
      3.当扫描完所有 Bus A 上所有(设备号,功能号)后,开始扫描 Bus B,Bus B 的编号在扫描完 Bus A 后已经得到,为 1。Bus B 的扫描方法同步骤(1),先扫描出 Bus B 上的 PCI 桥(即图中的 Bridge 2),然后配置 Primary Bus Number 寄存器为 1,Secondary Bus Number 寄存器为 2,而 Subordinate Bus Number 寄存器依然为 0xFF。
      4.Bus B 扫描完后得到 Bus C 的编号,为2。下面开始扫描 Bus C,因为 Bus C 上没有 PCI 桥,于是在扫描完其它(设备号,功能号)后,Bus C 的扫描结束。
      5.由于 Bridge 2 所能访问到的最大 Bus 编号是 2,因此重新设置 Bridge 2 的 Subordinate Bus Number 寄存器为 2。
      6.由于 Bridge 1 所能访问到的最大 Bus 编号也是 2,因此重新设置 Bridge 1 的 Subordinate Bus Number 寄存器为 2。
      7.总线编号结束。

      九.Linux内核PCI数据结构
      内核(linux-2.6.24) 提供了三类数据结构用以描述 PCI 控制器、PCI 设备以及 PCI 总线。
      数据结构关系如下所示

      PCI 控制器 用 pci_controller 结构来描述,它有以下几个主要的属性:
      index:该属性标志 PCI 控制器的编号。
      next:该属性指向下一个 PCI 控制器,通过 next 属性,PCI 控制器可以形成一个单向链表。
      first_busno:该属性标志了连接在该控制器上第一条总线的编号。
      last_busno:该属性标志了连接在该控制器上最后一条总线的编号。
      ops:该属性标志了当前 PCI 控制器所对应的 PCI 配制空间读写操作函数。
      io_space:该属性标志了当前 PCI 控制器所支持的 IO 地址空间。
      mem_space:该属性标志了当前 PCI 控制器所支持的 Memory 地址区间。
      cfg_addr:该属性标志了当前 PCI 控制器发起 Configuration 访问方式时所需要写入的地址空间。
      cfg_data:该属性标志了当前 PCI 控制器发起 Configuration 访问方式时所需要读写的数据空间。
      bus:该属性标志了当前 PCI 控制器所连接的 PCI 总线,它对应的数据结构是 pci_bus。
      PCI 总线 用 pci_bus 结构来描述,它有以下几个主要的属性:
      parent:可通过该属性索引到上层 PCI 总线。
      self:该属性标志了连接的上行 PCI 桥(对应的数据结构是 pci_dev)。
      children:该属性标志了总线连接的所有 PCI 子总线链表。
      devices:该属性标志了总线连接的所有 PCI 设备链表。
      ops:该属性标志了总线上所有 PCI 设备的配制空间读写操作函数。
      number:该属性标志了当前 PCI 总线的编号。
      primary:该属性标志了 PCI 上行总线编号。
      secondary:该属性标志了 PCI 下行总线编号。
      subordinate:该属性标志了能够访问到的最大总线编号。
      resource:该属性标志了 Memory/IO 地址空间。
      PCI 设备 用 pci_dev 结构来描述,它有以下几个主要的属性:
      global_list:Linux 定义了一个全局列表来索引所有PCI 设备,该属性标志了这个全局列表的首指针。
      bus:该属性标志了当前设备所在的 PCI 总线(对应的数据结构是 pci_bus)。
      devfn:该属性标志了设备编号和功能编号。
      vendor:该属性标志了供应商编号。
      device:该属性标志了设备编号。
      driver:该属性标志了设备对应的驱动代码(对应的数据结构是 pci_driver)。
      irq:该属性标志了中断号。
      resource:该属性标志了 Memory/IO 地址区间。
      当 Linux 内核在做 PCI 初始化工作时,它会根据建立一个由 pci_controller、pci_bus 和 pci_dev 三者组成的一个组织结构图。根据这个结构,软件开发者可以很方便的通过 PCI 控制器索引到每个 PCI 设备或者 PCI 总线。




      十.linux的PCI子系统初始化流程
      第一步:Linux分配数据结构pci_contoller,并初始化,包括PCI的mem/io空间范围和访问PCI配置空间所需的handler。
      第二步:PCI设备的枚举:扫描系统上所有PCI设备,初始化它们的配置空间。(硬件上的初始化)
      第三步:用数据结构将PCI设备信息联系起来,构建PCI树。(软件上的初始化)
      第四步:加载PCI设备驱动。
      1 初始化PCI控制器
      pci_controller结构是内核描述PCI子系统信息的数据结构,里面定义了可供PCI设备使用的mem资源和io资源的范围,访问pci设备配置空间的handler等等。
      函数调用关系:



      1.start_kernel --> mpc8560ads_setup_arch --> mpc85xx_setup_hose()

      2.此函数分配并初始化了pci_controller

      3.mpc85xx_setup_hose()

      4. -->pcibios_alloc_controller() //分配数据结构pci_controller

      5.

      6. ppc_md.pci_map_irq = mpc85xx_map_irq; //用来获得pci设备irq号的handler

      7.

      8. -->setup_indirect_pci() //设置pci_controller里访问PCI配置空间的钩子函数

      9.

      10. //使用ioremap后的CFG_ADDR和CFG_DATA的虚拟地址

      11.

      12. -->mpc85xx_setup_pci1() //设置PCI inbound和outbound窗口寄存器。

      13.

      14.PCI子系统的mem和io地址空间范围也在函数mpc85xx_setup_hose()中定义:

      15. pci_controller *hose_a;

      16. hose_a->mem_space.start = MPC85XX_PCI1_LOWER_MEM;

      17. hose_a->mem_space.end = MPC85XX_PCI1_UPPER_MEM;

      18. hose_a->io_space.start = MPC85XX_PCI1_LOWER_IO;

      19. hose_a->io_space.end = MPC85XX_PCI1_UPPER_IO;


      2 PCI枚举过程
      目前为止,内核只知道PCI子系统总的mem资源和io资源地址范围。
      接下来,内核需要扫描所有PCI设备,把这些资源分配给PCI设备,具体方法参考前面讲的PCI枚举过程。
      内核分配mem资源时是从高地址开始分配的。



      1.mpc85xx_setup_hose()

      2. -->pciauto_bus_scan()

      3. for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) { //遍历0号总线上所有PCI设备

      4.

      5. if (读当前设备配置空间PCI_HEADER_TYPE失败)

      6. continue; //当前设备不存在,扫描下一个

      7.

      8. 读当前设备配置空间PCI_CLASS_REVISION

      9. If(当前设备是PCI桥){

      10. pciauto_setup_bars() //分配pci_controller的资源的子集

      11.

      12. pciauto_prescan_setup_bridge() //写PCI桥配置空间 PCI_PRIMARY_BUS

      13.

      14. //PCI_SECONDARY_BUS

      15.

      16. //PCI_SUBORDINATE_BUS

      17.

      18. pciauto_bus_scan() //递归扫描下一条pci bus

      19.

      20. pciauto_postscan_setup_bridge() //写PCI桥配置空间PCI_SUBORDINATE_BUS

      21.

      22. }

      23. 。。。。。略去

      24. else {

      25. //当前设备是PCI设备

      26.

      27. pciauto_setup_bars()

      28. }

      29. }




      注意:执行完 pciauto_bus_scan后,所有pci设备(包括桥)的配置空间都已经傻瓜式的简单初始化
      但这些桥和设备还没有通过数据结构组织起来,这些工作要在第四步 pcibios_init里来完成
      3 创建PCI树
      上面说了,PCI设备配置空间都初始化差不多了,但是PCI设备还没有通过数据结构组织起来。



      1.do_initcalls()

      2. -->pcibios_init() //所在文件 arch/ppc/kernel/pci.c

      3.

      4.pcibios_init()

      5. (1):为PCI设备构造数据结构,组织成PCI树

      6.

      7.->pci_scan_bus(hose->first_busno,hose->ops,hose)//hose就是上面的pci_controller结构

      8.

      9.

      10. -->pci_scan_bus_parented

      11.

      12. -->pci_create_bus // 建立 PCI bus 0 对应的数据结构,这个bus的资源尚未初始化

      13.

      14. -->pci_scan_child_bus // 从PCI bus 0 开始扫描生成PCI树,使用了递归

      15.

      16.

      17. -->pci_scan_slot

      18.

      19. -->pci_scan_single_dev

      20. -->pci_scan_device() //创建 pci_dev结构

      21.

      22. -->pci_setup_device() //区分桥与设备,分别进行初始化

      23.

      24. -->pci_read_bases();




      pci_dev->resouce[]中保存的才是cpu internal address(EA),可以对这些地址进行用ioremap,在驱动程序对bar所指位置读写的时候一定要用这
      (2)给PCI设备分配IRQ号



      1.-->pci_fixup_irqs()

      2. //遍历所有pci设备,调用pdev_fixup_irq()

      3.

      4. -->pdev_fixup_irq

      5. -->ppc_md.pci_swizzle() //实际调用common_swizzle(),获得pci所在slot编号

      6.

      7.读PCI设备配置空间PCI_INTERRUPT_PIN,获得中断pin编号[1到4]

      8.

      9. 之所以是1到4,因为PCI规范里设备最多4个管脚(除第一个外,其他3个仅用于多功能设备)

      10. -->ppc_md.pci_map_irq() //实际调用mpc85xx_map_irq()

      11.

      12. //根据slot,pin 和 pci_irq_table[][4]

      13.

      14. //来计算出irq号

      15.

      16. -->pcibios_update_irq(pci_dev,irq)

      17. //将irq号写入pci设备的配置空间PCI_INTERRUPT_LINE

      18.

      19. //注意,这里寄存器只是用来保存结果,例如把其值8改为9,并不能改变中断号

      20.

      21. (3)PCI结构树有了,现在构建PCI的资源树,有冲突就修改

      22. -->pcibios_allocate_bus_resource()

      23. //只考虑pci_bus,形成bus级资源树(并同时check,资源冲突了就修改)

      24.

      25. -->pcibios_allocate_resources()

      26.




      4 加载PCI设备驱动
      以e1000 PCI 网卡 82546GB为例,讲解一个PCI驱动的加载过程
      驱动里有如下代码:



      1.static struct pci_driver e1000_driver = {

      2. .name = e1000_driver_name,

      3. .id_table = e1000_pci_tbl,

      4. .probe = e1000_probe,

      5. .remove = __devexit_p(e1000_remove),

      6.#ifdef CONFIG_PM

      7. /* Power Managment Hooks */

      8. .suspend = e1000_suspend,

      9. .resume = e1000_resume,

      10.#endif

      11. .shutdown = e1000_shutdown,

      12. .err_handler = &e1000_err_handler

      13.};

      14.module_init(e1000_init_module);

      15.do_initcalls()

      16. -->e1000_init_module

      17. pci_register_driver(&e1000_driver)

      18. // e1000_driver.driver.bus = &pci_bus_type;

      19.

      20. -->driver_register(e1000_driver.driver);

      21. //pci_bus_type.probe() 非空,即调用pci_device_probe()

      22.

      23.pci_device_probe(*device)

      24. -->__pci_device_probe(*pci_driver,*pci_dev)

      25. -->pci_match_device(*pci_driver,*pci_dev)

      26. -->pci_call_probe(*pci_driver,*pci_dev,pci_device_id)

      27. -->drv->probe(*pci_device,*pci_device_id)

      28. 即执行 e1000_probe(*pci_device,*pci_device_id)
    展开全文
  • 以太网帧格式

    2012-06-12 16:40:16
     为了标识以太网上的每台主机,需要给每台主机上的网络适配器(网络接口卡)分配一个唯一的通信地址,即Ethernet地址或称为网卡的物理地址、MAC地址。  IEEE负责为网络适配器制造厂商分配Ethernet地址块,各厂商

    转自:http://hi.baidu.com/dark_hc/blog/item/e584c68b67fc48d8fc1f1009.html

    一、Ethernet地址
      为了标识以太网上的每台主机,需要给每台主机上的网络适配器(网络接口卡)分配一个唯一的通信地址,即Ethernet地址或称为网卡的物理地址、MAC地址。
      IEEE负责为网络适配器制造厂商分配Ethernet地址块,各厂商为自己生产的每块网络适配器分配一个唯一的Ethernet地址。因为在每块网络适配器出厂时,其Ethernet地址就已被烧录到网络适配器中。所以,有时我们也将此地址称为烧录地址(Burned-In-Address,BIA)。
      Ethernet地址长度为48比特,共6个字节,如图1所示。其中,前3字节为IEEE分配给厂商的厂商代码,后3字节为网络适配器编号。

                              

                                 图1  Ethernet地址

     

    二、CSMA/CD
    在ISO的OSI参考模型中,数据链路层的功能相对简单。它只负责将数据从一个节点可靠地传输到相邻节点。但在局域网中,多个节点共享传输介质,必须有某种机制来决定下一个时刻,哪个设备占用传输介质传送数据。因此,局域网的数据链路层要有介质访问控制的功能。为此,一般将数据链路层又划分成两个子层:

    ●逻辑链路控制LLC(Logic Line Control)子层
    ●介质访问控制MAC(Media Access Control)子层

                       

                    图2  LLC和MAC子层

        如图2所示。其中,LLC子层负责向其上层提供服务;MAC子层的主要功能包括数据帧的封装/卸装,帧的寻址和识别,帧的接收与发送,链路的管理,帧的差错控制等。MAC子层的存在屏蔽了不同物理链路种类的差异性。
    在MAC子层的诸多功能中,非常重要的一项功能是仲裁介质的使用权,即规定站点何时可以使用通信介质。
      实际上,局域网技术中是采用具有冲突检测的载波侦听多路访问(Carrier Sense Multiple Access / Collision Detection,CSMA/CD)这种介质访问方法的。
      在这种介质访问方法中规定:在发送数据之前,一个节点必须首先侦听网线上的载波,如果在9.6微秒的时间之内没有检测到载波(说明通信介质空闲),节点才可以发送一帧数据。
      如果两个节点同时检测到介质空闲并同时发送出一帧数据,则会导致数据帧的冲突,双方的数据帧均被破坏。一方面,检测到冲突的节点会发送"冲突增强"信号(32比特的"1")通知介质上的每个节点发生了冲突。另一方面,发生冲突的节点在再次发送自己的数据帧之前会各自等待一段随机的时间。
    随着以太网上节点数量的增加,冲突的数量也随之增加,而整个网段的有效带宽将随之减少。

    三、以太网帧格式
    目前,有四种不同格式的以太网帧在使用,它们分别是:
    ●Ethernet II即DIX 2.0:Xerox与DEC、Intel在1982年制定的以太网标准帧格式。Cisco名称为:ARPA。
    ●Ethernet 802.3 raw:Novell在1983年公布的专用以太网标准帧格式。Cisco名称为:Novell-Ether。
    ●Ethernet 802.3 SAP:IEEE在1985年公布的Ethernet 802.3的SAP版本以太网帧格式。Cisco名称为:SAP。
    ●Ethernet 802.3 SNAP:IEEE在1985年公布的Ethernet 802.3的SNAP版本以太网帧格式。Cisco名称为:SNAP。
    在每种格式的以太网帧的开始处都有64比特(8字节)的前导字符,如图3所示。其中,前7个字节称为前同步码(Preamble),LSB在前,内容是16进制数0x55,最后1字节为帧起始标志符0xD5,它标识着以太网帧的开始。前导字符的作用是使接收节点进行同步并做好接收数据帧的准备。

                                               

                                                                         图3  以太网帧前导字符

                除此之外,不同格式的以太网帧的各字段定义都不相同,彼此也不嫒荨?/font>

    四、Ethernet II帧格式
                如图4所示,是Ethernet II类型以太网帧格式。

                 

                   图4  Ethernet II帧格式

      Ethernet II类型以太网帧的最小长度为64字节(6+6+2+46+4),最大长度为1518字节(6+6+2+1500+4)。其中前12字节分别标识出发送数据帧的源节点MAC地址和接收数据帧的目标节点MAC地址。(注:ISL封装后可达1548字节,802.1Q封装后可达1522字节)
      接下来的2个字节标识出以太网帧所携带的上层数据类型,如16进制数0x0800代表IP协议数据,16进制数0x809B代表AppleTalk协议数据,16进制数0x8138代表Novell类型协议数据等。
      在不定长的数据字段后是4个字节的帧校验序列(Frame. Check Sequence,FCS),采用32位CRC循环冗余校验对从"目标MAC地址"字段到"数据"字段的数据进行校验。

    五、Ethernet 802.3 raw帧格式
      如图5所示,是Ethernet 802.3 raw类型以太网帧格式。

                

                   图5  Ethernet 802.3 raw帧格式

      在Ethernet 802.3 raw类型以太网帧中,原来Ethernet II类型以太网帧中的类型字段被"总长度"字段所取代,它指明其后数据域的长度,其取值范围为:46-1500。
      接下来的2个字节是固定不变的16进制数0xFFFF,它标识此帧为Novell以太类型数据帧。

    六、Ethernet 802.3 SAP帧格式
      如图6所示,是Ethernet 802. 3 SAP类型以太网帧格式。

              

                 图6  Ethernet 802. 3 SAP帧格式

      从图中可以看出,在Ethernet 802.3 SAP帧中,将原Ethernet 802.3 raw帧中2个字节的0xFFFF变为各1个字节的DSAP和SSAP,同时增加了1个字节的"控制"字段,构成了802.2逻辑链路控制(LLC)的首部。LLC提供了无连接(LLC类型1)和面向连接(LLC类型2)的网络服务。LLC1是应用于以太网中,而LLC2应用在IBM SNA网络环境中。
      新增的802.2 LLC首部包括两个服务访问点:源服务访问点(SSAP)和目标服务访问点(DSAP)。它们用于标识以太网帧所携带的上层数据类型,如16进制数0x06代表IP协议数据,16进制数0xE0代表Novell类型协议数据,16进制数0xF0代表IBM NetBIOS类型协议数据等。
      至于1个字节的"控制"字段,则基本不使用(一般被设为0x03,指明采用无连接服务的802.2无编号数据格式)。

    七、Ethernet 802.3 SNAP帧格式
      如图7所示,是Ethernet 802. 3 SNAP类型以太网帧格式。

           

                 图7  Ethernet 802. 3 SNAP帧格式

        Ethernet 802. 3 SNAP类型以太网帧格式和Ethernet 802. 3 SAP类型以太网帧格式的主要区别在于:
           ●2个字节的DSAP和SSAP字段内容被固定下来,其值为16进制数0xAA。
           ●1个字节的"控制"字段内容被固定下来,其值为16进制数0x03。
           ●增加了SNAP字段,由下面两项组成:


        ◆新增了3个字节的组织唯一标识符(Organizationally Unique Identifier,OUI ID)字段,其值通常等于MAC地址的前3字节,
    即网络适配器厂商代码。

        ◆2个字节的"类型"字段用来标识以太网帧所携带的上层数据类型。

     

    物理层是依靠特殊的线路编码来指示帧结束的。
    10M
    以太网的曼彻斯特编码中是用没有中间跳变得码字表示帧结束。
    100M
    以太网是靠4B/5B编码中的特殊码字表示的。

    千兆以太网是用8B/10B编码来实现的
    /SPD/
    /EPD/ 来界定一个Frame

     

    展开全文
  • PCI详解

    2022-04-24 15:21:11
    PCI PCI(外围部件互连)是由 Intel 于 1991 年推出的一种局部总线,作为一种通用的总线接口标准,它在目前的计算机系统中得到了非常广泛应用。PCI 总线具有如下特点。 ● 数据总线为 32 位,可扩充到 64 位。 ● 可...

    PCI

    PCI(外围部件互连)是由 Intel 于 1991 年推出的一种局部总线,作为一种通用的总线接口标准,它在目前的计算机系统中得到了非常广泛应用。PCI 总线具有如下特点。
    ● 数据总线为 32 位,可扩充到 64 位。

    ● 可进行突发(Burst)模式传输。突发方式传输是指取得总线控制权后连续进行多个数据的传输。突发传输时,只需要给出目的地的首地址,访问第 1 个数据后,第 2 ~ n个数据会在首地址的基础上按一定规则自动寻址和传输。与突发方式对应的是单周期方式,它在 1 个总线周期只传送 1 个数据。

    ● 总线操作与处理器—存储器子系统操作并行。

    ● 采用中央集中式总线仲裁

    ● 支持全自动配置资源分配,PCI 卡内有设备信息寄存器组为系统提供卡的信息,可实现即插即用

    ● PCI 总线规范独立于微处理器,通用性好。

    ● PCI 设备可以完全作为主控设备控制总线

    下图 给出了一个典型的基于 PCI 总线的计算机系统逻辑示意图,系统的各个部分通过PCI 总线和 PCI-PCI 桥连接在一起。CPU 和 RAM 通过 PCI 桥连接到 PCI 总线 0(即主 PCI总线),而具有 PCI 接口的显卡则可以直接连接到主 PCI 总线上。PCI-PCI 桥是一个特殊的PCI 设备,它负责将 PCI 总线 0 和 PCI 总线 1(即从 PCI 主线)连接在一起,通常 PCI 总线 1称为 PCI-PCI 桥的下游Downstream),而 PCI 总线 0 则称为 PCI-PCI 桥的上游(Upstream)。为了兼容旧的 ISA 总线标准,PCI 总线还可以通过 PCI-ISA 桥来连接 ISA 总线,从而支持以前的 ISA 设备。
    在这里插入图片描述
    当 PCI 卡刚加电时,卡上配置空间即可以被访问。PCI 配置空间保存着该卡工作时所需
    所有信息,如厂家、卡功能、资源要求、处理能力、功能模块数量、主控卡能力等。通过
    对这个空间信息的读取与编程,可完成对 PCI 卡的配置。如图 2.17 所示,PCI 配置空间共为
    256 字节,主要包括如下信息。
    制造商标识(Vendor ID):由 PCI 组织分配给厂家。

    设备标识(Device ID):按产品分类给本卡的编号。

    分类码(Class Code):本卡功能的分类码,如图卡、显示卡、解压卡等。

    申请存储器空间:PCI 卡内有存储器或以存储器编址的寄存器和 I/O 空间,为使驱动程序和应用程序能访问它们,需申请 CPU 的一段存储区域以进行定位。配置空间的基地址寄存器用于此目的。

    申请 I/O 空间:配置空间中的基地址寄存器用来进行系统 I/O 空间的申请。

    中断资源申请:配置空间中的中断引脚和中断线用来向系统申请中断资源。偏移

    3Dh 处为中断引脚寄存器,其值表明 PCI 设备使用了哪一个中断引脚,对应关系为
    1—INTA#、2—INTB#、3—INTC#、4—INTD#。
    在这里插入图片描述
    PCI-E(PCI Express)是 Intel 公司提出的新一代的总线接口,PCI Express 采用了目前业内流行的点对点串行连接,比起 PCI 以及更早的计算机总线的共享并行架构,每个设备都有自己的专用连接,采用串行方式传输数据,不需要向整个总线请求带宽,并可以把数据传输率提高到一个很高的频率,达到 PCI 所不能提供的高带宽。
    PCI Express 在软件层面上兼容目前的 PCI 技术和设备,支持 PCI 设备和内存模组的初始化,也就是说无须推倒目前的驱动程序、操作系统,就可以支持 PCI Express 设备。

    上文摘抄自《Linux设备驱动开发详解:基于最新的Linux 4.0内核》

    展开全文
  • 2.2、以太网数据 OSI数据链路层作为七层模型的第2层负责把上面传的数据封装经物理层传出去,也就是在整个数据进行打包的最后一道工序,好比打包完成准备装车发送一样。数据是什么结构?有什么功能? EthernetⅡ...
  • 以太网MAC是什么?

    万次阅读 2015-09-12 21:43:16
     以太网数据链路层其实包含MAC(介质访问控制)子层和LLC(逻辑链路控制)子层.一块以太网卡MAC芯片的作用不但要实现MAC子层和LLC子层的功能,还要提供符合规范的PCI界面以实现和主机的数据交换.  MAC从PCI总线收到...
  • PCI是一个总线标准,PCI总线上的设备就是PCI设备,这些设备有很多类型,当然也包括网卡设备,每一个PCI设备在内核中抽象为一个数据结构pci_dev,它描述了一个PCI设备的所有的特性,具体请查询相关文档,本文限于篇幅...
  • 下表中,第一行(即分组头部的前4Byte)包含内容该分组的最基本信息 第二行内容有三个字段,体现网络层的分组和该分组可能在数据链路层被分片有关 更细的划分 用户数据的多次封装:(4次头部封装) 应用程序添加的...
  • 以太网PHY寄存器分析

    千次阅读 2020-07-17 10:04:39
    以太网PHY寄存器分析    11、以太网PHY标准寄存器分析    21.1 Control Register    21.2 Status register    51.3 PHY ...
  • Xilinx-AX7103-学习笔记(25):基于UDP的以太网通信 实验将实现AX7103开发板和PC之间进行以太网数据通信, 通信协议采用Ethernet UDP通信协议。开发板上FPGA通过以太网PHY芯片KSZ9031RNX和网口连接, 通过RGMII接口跟...
  • 以太网详解一

    千次阅读 2020-09-15 17:04:56
    网络设备中肯定离开不MAC和PHY,本篇文章将详细介绍下以太网中一些常见术语与接口。 MAC和PHY结构 从硬件角度来看以太网是由CPU,MAC,PHY三部分组成的,如下图示意: 上图中DMA集成在CPU,CPU,MAC,PHY并不是...
  • 计算机网络笔记三 以太网

    千次阅读 2019-10-04 16:40:03
    第3章 以太网 "以太网"这个名字起源于一个科学假说:19世纪科学家们普遍认为光是通过一种叫以太的物质传播的。时至今日,以太的存在早就被爱因斯坦狭义相对论否定了,而以太网却成了主流的计算机网络,依旧为人类...
  • USB,蓝牙,以太网,还是WIFI?

    千次阅读 2014-04-12 09:07:04
    声明在本文中,我没有严格按照IEEE 802来描述,比如我将以太网IEEE 802.3和IEEE 802.11混合在一起,并将后者看成前者的扩展(也有人说802.11是802.3的杀手...),事实上我这么理解是有道理的,因为毕竟是802.3独领风骚...
  • 车载以太网基础知识介绍(MAC/PHY/MII解释对比)

    万次阅读 多人点赞 2020-05-04 10:58:21
    车载以太网用于连接汽车内不同电气设备的一种网络,从而满足车载环境中一些特殊需求,它与传统以太网不尽相同,车载以太网主要由MAC(介质访问控制)、PHY(物理接口收发器)组成,与传统以太网不同,车载以太网固定...
  • 网络设备中肯定离开不MAC和PHY,本篇文章将详细介绍下以太网中一些常见术语与接口。 MAC和PHY结构 从硬件角度来看以太网是由CPU,MAC,PHY三部分组成的,如下图示意: 上图中DMA集成在CPU,CPU,MAC,PHY并不是...
  • XILINX SGMII千兆以太网 (1)

    千次阅读 多人点赞 2019-08-30 17:29:45
    这篇文章将对以太网的学习过程进行简单记录和总结。 因为工程进度的原因,先采用xilinx自带的IP的形式进行开发,参考PG047。 The LogiCORE™ IP 1G/2.5G Ethernet PCS/PMA or Serial Gigabit Media ...
  • 以太网详解二

    千次阅读 2020-09-15 17:06:44
      从硬件的角度看,以太网接口电路主要由MAC(Media Access Control)控制器和物理层接口PHY(Physical Layer,PHY)两大部分构成。如下图所示   但是,在实际的设计中,以上三部分并不一定独立分开的。 由于,...
  • 问:如何实现单片以太网微控制器? 答:诀窍是将微控制器、以太网媒体接入控制器(MAC)和物理接口收发器(PHY)整合进同一芯片,这样能去掉许多外接元器件.这种方案可使MAC和PHY实现很好的匹配,同时还可减小引脚数、缩小...
  • 本文主要介绍以太网的MAC(Media Access Control,即媒体访问控制子层协议)和PHY(物理层)之间的MII(Media Independent Interface ,媒体独立接口),以及MII的各种衍生版本——GMII、SGMII、RMII、RGMII等。...
  • Network 之二 Ethernet(以太网)中的 MAC、MII、PHY 详解

    万次阅读 多人点赞 2018-04-26 14:06:47
      从硬件的角度看,以太网接口电路主要由MAC(Media Access Control)控制器和物理层接口PHY(Physical Layer,PHY)两大部分构成。如下图所示   但是,在实际的设计中,以上三部分并不一定独立分开的。 由于...
  • 4 以太网设备

    千次阅读 2016-12-01 15:52:01
    4 以太网设备EtherCAT协议基于以太网标准,因此主站依靠标准以太网硬件与总线通信。术语设备用作以太网网络接口硬件的同义词。本地以太网设备驱动程序 处理以太网硬件的本机设备驱动程序模块(见第4.2节),主机可以...
  • 1 --> 以太网 PHY 层简介

    千次阅读 2021-01-22 15:45:16
    一、网卡的主要特点 ...我们可以把看做是一种数据包,在数据包中不仅包含有数据信息,而且还包含有数据的发送地、接收地信息和数据的校验信息。 一块网卡包括OSI模型的两个层——物理层和数据链
  • 以太网介绍及硬件设计

    千次阅读 多人点赞 2020-04-15 21:54:44
    以太网MAC和PHY MAC MAC(Media Access Control) 即媒体访问控制层协议。MAC由硬件控制器及MAC通信协议构成。该协议位于OSI七层协议中数据链路层的下半部分,主要负责控制与连接物理层的物理介质。MAC硬件框图如下图...
  • 产品概述 以太网故障注入器是一种基于PXIE总线的以太网故障注入仪器,该仪器采用串 接在以太网线路中的连接方式实现故障注入功能。进行故障注入时,不需要对连接到以太网上的原有设备进行任何改变...接口支持 cPCIe/PCI
  • 以太网进化历程半景-从10Mbps到1Tbps

    万次阅读 2017-04-15 19:10:44
    继Netfilter conntrack,Linux Bridge之后又是一个半景,依然如故,我不会在文中罗列技术规范和细节,仅仅是希望本文可以帮助人们理解以太网到底是什么,为什么如此成功。0.动机,愿景以及声明前端时间帮朋友解决一...
  • 以太网网卡的结构和工作原理

    千次阅读 2017-05-06 16:00:06
    以太网网卡的结构和工作原理,按照老师的要求写的一个小论文。
  • 以太网帧的格式为:前导符+开始位+目的mac地址+源mac地址+类型/长度+数据+padding(optional)+32bitCRC。如果有vlan,则要在类型/长度后面加上2个字节的vlan tag,其中12bit来表示vlan id,另外4bit表示数据的优先级! ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,414
精华内容 965
关键字:

以太网帧格的pci包含哪些内容?