青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

string

string
posts - 27, comments - 177, trackbacks - 0, articles - 0
  C++博客 :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

UEFI 實戰(4) protocol

Posted on 2012-03-06 07:30 djx_zh 閱讀(18181) 評論(18)  編輯 收藏 引用
什么是protocol
從字面意思上看,protocol是server和client之間的一種約定,雙方根據這種約定互通信息。這里的server和client是一種廣義的稱呼,提供服務的稱為server,使用服務的稱為client。 TCP是一種protocol, client(應用程序)通過一組函數來壓包和解包,壓包和解包是server提供的服務。COM也是一種protocol,client通過CoCreateInstance(...)和GUID獲得指向COM對象的指針,然后使用該指針獲得COM對象提供的服務, GUID標示了這個COM對象。現在我們對protocol有了概念上的理解,那么具體到UEFI里,protocol是什么樣子呢? 如何標示一個protocol?如何得到protocol對應的對象?...容我慢慢道來.
在講protocol什么樣子之前,還要插幾句C與C++的區別。我們知道UEFI是用C來開發的,C是面向過程的一種語言。而管理和使用UEFI眾多的protocol完全使用面向過程的思想會使程序變得復雜。protocol作為一種對象來設計管理會比較直觀。因而UEFI中的Protocol引入了面向對象的思想,用struct來模擬class, Protocol用struct來實現,用函數指針(Protocol的成員變量)模擬成員函數,此種函數的第一參數必須是指向Protocol的指針,用來模擬this指針。
Protocol的摸樣
以EFI_DISKIO_PROTOCOL 來看看Protocol的樣子。 
MdePkg/Include/Protocol/BlockIo.h
:
220
///
///  This protocol provides control over block devices.
///
struct _EFI_BLOCK_IO_PROTOCOL {
  
///
  
/// The revision to which the block IO interface adheres. All future
  
/// revisions must be backwards compatible. If a future version is not
  
/// back wards compatible, it is not the same GUID.
  
///
  UINT64              Revision;
  
///
  
/// Pointer to the EFI_BLOCK_IO_MEDIA data for this device.
  
///
  EFI_BLOCK_IO_MEDIA  *Media;

  EFI_BLOCK_RESET     Reset;
  EFI_BLOCK_READ      ReadBlocks;
  EFI_BLOCK_WRITE     WriteBlocks;
  EFI_BLOCK_FLUSH     FlushBlocks;

};

extern EFI_GUID gEfiBlockIoProtocolGuid;
MdePkg/Include/Protocol/BlockIo.h
:
220
#define EFI_BLOCK_IO_PROTOCOL_GUID \
  { \
    
0x964e5b210x64590x11d2, {0x8e0x390x00xa00xc90x690x720x3b } \
  }

typedef 
struct _EFI_BLOCK_IO_PROTOCOL  EFI_BLOCK_IO_PROTOCOL;
EFI_BLOCK_IO_PROTOCOL 有兩個成員變量,四個成員函數(當然從C的角度來看,“成員函數”叫法不準確,它實際上也是一個成員變量,只是這個變量是函數指針).  gEfiBlockIoProtocolGuid({0x964e5b210x64590x11d2, {0x8e0x390x00xa00xc90x690x720x3b })標示了EFI_BLOCK_IO_PROTOCOL 。
來看成員函數的聲明

/**
  Read BufferSize bytes from Lba into Buffer.

  @param  This       Indicates a pointer to the calling context.
  @param  MediaId    Id of the media, changes every time the media is replaced.
  @param  Lba        The starting Logical Block Address to read from
  @param  BufferSize Size of Buffer, must be a multiple of device block size.
  @param  Buffer     A pointer to the destination buffer for the data. The caller is
                     responsible for either having implicit or explicit ownership of the buffer.

  @retval EFI_SUCCESS           The data was read correctly from the device.
  @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
  @retval EFI_NO_MEDIA          There is no media in the device.
  @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
  @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
  @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
                                or the buffer is not on proper alignment.

*
*/
typedef
EFI_STATUS
(EFIAPI 
*EFI_BLOCK_READ)(
  IN EFI_BLOCK_IO_PROTOCOL          
*This,
  IN UINT32                         MediaId,
  IN EFI_LBA                        Lba,
  IN UINTN                          BufferSize,
  OUT VOID                          
*Buffer
  );
EFI_BLOCK_READ具體用法我們先不看,我們來看它的第一個參數,指向EFI_BLOCK_IO_PROTOCOL  對象自己的this指針,這是成員函數區別于一般函數的重要特征。

如何使用Protocol       

使用Protocol之前,我們要弄清楚Protocol位于什么地方。首先我們要來認識一下EFI_HANDLE,
///
/// A collection of related interfaces.
///
typedef VOID                      *EFI_HANDLE;
EFI_HANDLE是指向某種對象的指針,UEFI用它來表示某個對象。 UEFI掃描總線后,會為每個設備建立一個Controller對象,用于控制設備,所有該設備的驅動以protocol的形式安裝到這個controller中,這個Controller就是一個EFI_HANDLE對象。 當我們將一個.efi文件加載到內存中,UEFI也會為該文件建立一個Image對象(此Image非圖像的意識), 這個Image對象也是一個EFI_HANDLE對象。 在UEFI內部,EFI_HANDLE被理解為IHANDLE
///
/// IHANDLE - contains a list of protocol handles
///
typedef struct {
  UINTN               Signature;
  
/// All handles list of IHANDLE
  LIST_ENTRY          AllHandles;
  
/// List of PROTOCOL_INTERFACE's for this handle
  LIST_ENTRY          Protocols;
  UINTN               LocateRequest;
  
/// The Handle Database Key value when this handle was last created or modified
  UINT64              Key;
} IHANDLE;
每個IHANDLE中都有一個Protocols鏈表,存放屬于自己的protocol。所有的IHANDLE通過AllHandles鏈接起來。
要使用Protocol,首先要找到protocol對象,可以通過BootServices的OpenProtocol(...), HandleProtocl(...), LocateProtocol(...)獲得。
typedef
/**
  Queries a handle to determine if it supports a specified protocol. If the protocol is supported by the
  handle, it opens the protocol on behalf of the calling agent.
  @param  Handle                The handle for the protocol interface that is being opened.
  @param  Protocol              The published unique identifier of the protocol.
  @param  Interface             Supplies the address where a pointer to the corresponding Protocol
                                        Interface is returned.
  @param  AgentHandle        The handle of the agent that is opening the protocol interface
                                        specified by Protocol and Interface.
  @param  ControllerHandle    If the agent that is opening a protocol is a driver that follows the
                                        UEFI Driver Model, then this parameter is the controller handle
                                        that requires the protocol interface. If the agent does not follow
                                        the UEFI Driver Model, then this parameter is optional and may
                                        be NULL.
  @param  Attributes            The open mode of the protocol interface specified by Handle
                                        and Protocol.
  @retval EFI_SUCCESS         An item was added to the open list for the protocol interface, and the
                                        protocol interface was returned in Interface.
  @retval EFI_UNSUPPORTED       Handle does not support Protocol.
  @retval EFI_INVALID_PARAMETER One or more parameters are invalid.
  @retval EFI_ACCESS_DENIED     Required attributes can't be supported in current environment.
  @retval EFI_ALREADY_STARTED   Item on the open list already has requierd attributes whose agent
                                                handle is the same as AgentHandle.
**/
EFI_STATUS
(EFIAPI *EFI_OPEN_PROTOCOL)(
  IN  EFI_HANDLE                Handle,
  IN  EFI_GUID                   *Protocol,
  OUT VOID                       **Interface, OPTIONAL
  IN  EFI_HANDLE                AgentHandle,
  IN  EFI_HANDLE                ControllerHandle,
  IN  UINT32                      Attributes
  );
Handle是Protocol的提供者,如果Handle的Protocols鏈表中有該Potocol,Protocol對象的指針寫到*Interface,并返回EFI_SUCCESS;否則 返回EFI_UNSUPPORTED
如果在驅動中調用OpenProtocol(), AgentHandle是擁有該EFI_DRIVER_BINDING_PROTOCOL對象的Handle;ControllerHandle是擁有該驅動的Controller。
如果調用OpenProtocol的是應用程序,那么AgentHandle是該應用對應的Handle,也就main函數的第一個參數。 
ControllerHandle此時可以忽略。
Attributes可以取以下5種值。
#define EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL   0x00000001
#define EFI_OPEN_PROTOCOL_GET_PROTOCOL             0x00000002
#define EFI_OPEN_PROTOCOL_TEST_PROTOCOL           0x00000004
#define EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER  0x00000008
#define EFI_OPEN_PROTOCOL_BY_DRIVER                   0x00000010
#define EFI_OPEN_PROTOCOL_EXCLUSIVE                   0x00000020

HandleProtocol是OpenProtocol的簡化版,因為大部分情況下我們都不需要關心AgentHandle,ControllerHandle和Attributes。
EFI_STATUS
EFIAPI
CoreHandleProtocol (
  IN EFI_HANDLE       UserHandle,
  IN EFI_GUID         
*Protocol,
  OUT VOID            
**Interface
  )
{
  
return CoreOpenProtocol (
          UserHandle,
          Protocol,
          Interface,
          gDxeCoreImageHandle,
          NULL,
          EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
          );
}
LocateProtocol(...)是從內核中找出指定Protocol的第一個實例。
typedef
EFI_STATUS
LocateProtocol (
IN EFI_GUID 
*Protocol,
IN VOID       
*Registration OPTIONAL,
OUT VOID     
**Interface
);
UEFI內核中某個Protocol的實例可能不止一個,例如每個硬盤及每個分區都有一個EFI_DISK_IO_PROTOCOL實例。LocateProtocol順序搜索HANDLE鏈表,返回找到的第一個該Protocol的實例。
我們可以用BootServices提供的其它函數處理HANDLE和Protocol。
typedef
EFI_STATUS
LocateHandleBuffer (
IN EFI_LOCATE_SEARCH_TYPE SearchType,
IN EFI_GUID                         
*Protocol OPTIONAL,
IN VOID
                              
 
*SearchKey OPTIONAL,
IN OUT UINTN                       
*NoHandles,
OUT EFI_HANDLE                  
**Buffer
);
可以獲得所有支持指定Protocol的HANDLE,SearchType 有三種:AllHandles(查找所有HANDLE), ByRegisterNotify, ByProtocol(查找支持指定Protocol的HANDLE)。NoHandles是找到的HANDLE的數量, Buffer數組由UEFI復雜分配,由用戶負責釋放。
typedef
EFI_STATUS
LocateHandle (
IN EFI_LOCATE_SEARCH_TYPE SearchType,
IN EFI_GUID                        
*Protocol OPTIONAL,
IN VOID                              
*SearchKey OPTIONAL,
IN OUT UINTN                      
*BufferSize,
OUT EFI_HANDLE                  
*Buffer
);
與LocateHandleBuffer相似,只是用戶負責分配和釋放Buffer數組。
typedef
EFI_STATUS
ProtocolsPerHandle (
IN EFI_HANDLE Handle,
OUT EFI_GUID  
***ProtocolBuffer,
OUT UINTN      
*ProtocolBufferCount
);
獲得指定Handle所支持的所有Protocol, UEFI負責分配內存給ProtocolBuffer,用戶負責釋放該內存。

typedef
EFI_STATUS
(EFIAPI 
*EFI_OPEN_PROTOCOL_INFORMATION) (
IN EFI_HANDLE Handle,
IN EFI_GUID    
*Protocol,
OUT EFI_OPEN_PROTOCOL_INFORMATION_ENTRY 
**EntryBuffer,
OUT UINTN     
*EntryCount
);
typedef struct {
  EFI_HANDLE  AgentHandle;
  EFI_HANDLE  ControllerHandle;
  UINT32        Attributes;
  UINT32        OpenCount;
} EFI_OPEN_PROTOCOL_INFORMATION_ENTRY;
OpenProtocolInformation()獲得指定Handle中指定Protocol的打開信息。
SPEC2.3.1第165頁有很好的例子演示了怎么打開一個Protocol, 
EFI_BOOT_SERVICES *gBS;
EFI_HANDLE ImageHandle;
EFI_DRIVER_BINDING_PROTOCOL 
*This;
IN EFI_HANDLE ControllerHandle,
extern EFI_GUID gEfiXyzIoProtocol;
EFI_XYZ_IO_PROTOCOL 
*XyzIo;
EFI_STATUS Status;

Status 
= gBS->OpenProtocol (
ControllerHandle,
&gEfiXyzIoProtocol,
&XyzIo,
ImageHandle,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
);

Status 
= gBS->OpenProtocol (
ControllerHandle,
&gEfiXyzIoProtocol,
&XyzIo,
This
->DriverBindingHandle,
ControllerHandle,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
打開Protocol之后就可以使用了,最后要通過CloseProtocol關閉打開的Protocol。
typedef
EFI_STATUS
(EFIAPI 
*EFI_CLOSE_PROTOCOL) (
IN EFI_HANDLE Handle,
IN EFI_GUID 
*Protocol,
IN EFI_HANDLE AgentHandle,
IN EFI_HANDLE ControllerHandle
);
通過HandleProtocol和LocateProtocol打開的Protocol因為沒有指定AgentHandle,所以無法關閉。如果一定要去關閉它,要調用OpenProtocolInformation()獲得AgentHandle和ControllerHandle,然后關閉它。
下面看一個完整的例子,用EFI_DISK_IO_PROTOCOL讀取GPT硬盤的分區表
#include <Uefi.h> 
#include <Base.h> 
#include <Library/UefiLib.h>
#include <Library/BaseLib.h>
#include <Library/BaseMemoryLib.h>
#include <Library/UefiBootServicesTableLib.h>
#include <Library/PrintLib.h>
#include <Protocol/DiskIo.h> 
#include <Protocol/BlockIo.h> 
#include <Protocol/DevicePath.h>    
#include <Uefi/UefiGpt.h>
#include <Library/DevicePathLib.h>
EFI_STATUS
EFIAPI
UefiMain(
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
        EFI_STATUS                              Status;
        UINTN                                       HandleIndex, HandleCount;
        EFI_HANDLE                               *DiskControllerHandles = NULL;
        EFI_DISK_IO_PROTOCOL               *DiskIo;

        /*找到所有提供 EFI_DISK_IO_PROTOCOL 的Controller  */
        Status = gBS->LocateHandleBuffer(
                        ByProtocol,
                        &gEfiDiskIoProtocolGuid,
                        NULL,
                        &HandleCount,
                        &DiskControllerHandles);

        if (!EFI_ERROR(Status)) {
                CHAR8 gptHeaderBuf[512];
                EFI_PARTITION_TABLE_HEADER* gptHeader = (EFI_PARTITION_TABLE_HEADER*
)gpHeaderBuf;
                for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
                       /*打開EFI_DISK_IO_PROTOCOL  */ 
                       Status = gBS->HandleProtocol(
                                        DiskControllerHandles[HandleIndex],
                                        &gEfiDiskIoProtocolGuid,
                                        (VOID**)&DiskIo);

                        if (!EFI_ERROR(Status)){
                                {
                                        EFI_DEVICE_PATH_PROTOCOL                 *DiskDevicePath;
                                        EFI_DEVICE_PATH_TO_TEXT_PROTOCOL   *Device2TextProtocol = 0;
                                        CHAR16*                                             TextDevicePath = 0;
                                          /*1. 打開EFI_DEVICE_PATH_PROTOCOL  */  
                                        Status = gBS->OpenProtocol(
                                                        DiskControllerHandles[HandleIndex],
                                                        &gEfiDevicePathProtocolGuid,
                                                        (VOID**)&DiskDevicePath,
                                                        ImageHandle,
                                                        NULL,
                                                        EFI_OPEN_PROTOCOL_GET_PROTOCOL
                                                        );
                                        if(!EFI_ERROR(Status)){
                                                if(Device2TextProtocol == 0)
                                                        Status = gBS->LocateProtocol(
                                                                        &gEfiDevicePathToTextProtocolGuid,
                                                                        NULL,
                                                                        (VOID**)&Device2TextProtocol
                                                                        );
                                                /*2. 使用 EFI_DEVICE_PATH_PROTOCOL  得到文本格式的Device Path  */  
                                                TextDevicePath = Device2TextProtocol->ConvertDevicePathToText(DiskDevicePath, TRUE, TRUE);
                                                Print(L"%s\n", TextDevicePath);
                                                if(TextDevicePath)gBS->FreePool(TextDevicePath);
                                                /*3. 關閉 EFI_DEVICE_PATH_PROTOCO */   
                                                Status = gBS->CloseProtocol(
                                                                DiskControllerHandles[HandleIndex],
                                                                &gEfiDevicePathProtocolGuid,
                                                                ImageHandle,
                                                                );
                                        }
                                }
                                {
                                        EFI_BLOCK_IO_PROTOCOL* BlockIo = *(EFI_BLOCK_IO_PROTOCOL**) (DiskIo + 1);
                                        EFI_BLOCK_IO_MEDIA* Media = BlockIo->Media;
                                        /*讀1號扇區。  */   
                                        Status = DiskIo->ReadDisk(DiskIo, Media->MediaId, 512, 512, gptHeader);
                                        /*檢查GPT標志。  */    
                                        if((!EFI_ERROR(Status)) &&( gptHeader -> Header.Signature == 0x5452415020494645)){
                                                UINT32 CRCsum;
                                                UINT32 GPTHeaderCRCsum =  (gptHeader->Header.CRC32);
                                                gptHeader->Header.CRC32 = 0;
                                                gBS -> CalculateCrc32(gptHeader , (gptHeader->Header.HeaderSize), &CRCsum);
                                                if(GPTHeaderCRCsum == CRCsum){
                                                // Find out a GPT Header
                                                }

                                        }

                                }

                        }

                }
                gBS->FreePool(DiskControllerHandles);
        }
}
 









Feedback

# re: UEFI 實戰(4) protocol   回復  更多評論   

2012-08-13 13:55 by 劉煒
EFI_BLOCK_IO_PROTOCOL* BlockIo = *(EFI_BLOCK_IO_PROTOCOL**) (DiskIo + 1);

這是說明兩個協議的數據結構連續地放在一起嗎?

# re: UEFI 實戰(4) protocol [未登錄]  回復  更多評論   

2012-08-15 22:02 by djx_zh
@劉煒
是的。
MdeModulePkg\Universal\Disk\DiskIoDxe\DiskIo.h:36
typedef struct {
UINTN Signature;
EFI_DISK_IO_PROTOCOL DiskIo;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
} DISK_IO_PRIVATE_DATA

# re: UEFI 實戰(4) protocol   回復  更多評論   

2012-10-04 16:29 by 關于 gptHeader-> Header.Signature
你好 我接觸 UFEI 不長時間
有個問題
CHAR8 gptHeader[512];
gptHeader-> Header.Signature
這樣寫可以嗎?
gptHeader 應該是個 struct吧
還有能否把inf文件也發上來呢 謝謝了

# re: UEFI 實戰(4) protocol   回復  更多評論   

2012-10-04 17:44 by snowman1101
你好
我復制了你的代碼
編譯后提示 未聲明 DevicePathToText 于是我加入了
#include <Protocol/DevicePathToText.h>
修改所有錯誤以后
又說 外部 gEfiDevicePathToTextProtocolGuid
請問怎么解決呢。可以發一下完整代碼嗎
謝謝了

# re: UEFI 實戰(4) protocol   回復  更多評論   

2012-10-05 08:37 by djx_zh
代碼中少了一句
EFI_PARTITION_TABLE_HEADER* gptHeader = (EFI_PARTITION_TABLE_HEADER*
)gpHeaderBuf;

在你.inf文件的[Protocols]下面加上
gEfiDevicePathToTextProtocolGuid

# re: UEFI 實戰(4) protocol [未登錄]  回復  更多評論   

2012-10-06 22:06 by snowman1101
多謝指教,已經可以了


# re: UEFI 實戰(4) protocol [未登錄]  回復  更多評論   

2012-11-15 11:47 by ktfun
親,find out a GPT header 后面的內容呢?

# re: UEFI 實戰(4) protocol   回復  更多評論   

2013-01-07 17:43 by linhao
關于:EFI_BLOCK_IO_PROTOCOL* BlockIo = *(EFI_BLOCK_IO_PROTOCOL**) (DiskIo + 1);
我認為這樣更方便理解:
DISK_IO_PRIVATE_DATA *Private_Data;
Private_Data = DISK_IO_PRIVATE_DATA_FROM_THIS (DiskIo);
BlockIo = Private_Data;

# re: UEFI 實戰(4) protocol   回復  更多評論   

2013-01-07 17:45 by linhao
修改:
BlockIo = Private_Data->BlockIo;

# re: UEFI 實戰(4) protocol   回復  更多評論   

2013-01-07 22:12 by djxzh
@linhao
是的。如果你看DiskIO的源碼會發現EDK2就是這樣做的。

# re: UEFI 實戰(4) protocol   回復  更多評論   

2013-02-28 06:44 by howard
hi, 請問如何選擇特定的device進行讀寫?我想parse EFI_DEVICE_PATH_PROTOCOL 的bus id 部分,然后找到目標進行讀寫,但貌似沒有合適的API可以用

Thanks in advance!

# re: UEFI 實戰(4) protocol   回復  更多評論   

2013-03-06 06:08 by djxzh
@howard

EFI_DEVICE_PATH_PROTOCOL 是一個辦法, 確實沒有順手的API, 你要一個node一個node的分析。

也可以用PciIo讀取PCI設備的配置空間,來判斷設備。

# re: UEFI 實戰(4) protocol   回復  更多評論   

2013-03-08 03:29 by howard
恩,我現在暫時用capacity來找我的device. 不知樓主用過EADK嗎,把C標準庫加到EDKII里。 我試了一下,build出來的efi放在shell那一跑就crash with exception, sample efi也一樣問題。。

# re: UEFI 實戰(4) protocol   回復  更多評論   

2014-12-27 03:54 by asam
【UEFI是用C來開發的,C是面向過程的一種語言。而管理和使用UEFI眾多的protocol完全使用面向過程的思想會使程序變得復雜。protocol作為一種對象來設計管理會比較直觀。因而UEFI中的Protocol引入了面向對象的思想,用struct來模擬class, Protocol用struct來實現,用函數指針(Protocol的成員變量)模擬成員函數,此種函數的第一參數必須是指向Protocol的指針,用來模擬this指針。。。。。。】



怪不得,看了hello world,沒有消息機制。特別是和硬件打交道,對這個uefi表示亞歷山大。

# re: UEFI 實戰(4) protocol   回復  更多評論   

2015-05-29 15:07 by 周彬彬
@djx_zh
這個在EDK2 SPE2.4的MdeModulePkg\Universal\Disk\DiskIoDxe\DiskIo.h
這樣定義的:二者并沒有相鄰
#define DISK_IO_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('d', 's', 'k', 'I')
typedef struct {
UINT32 Signature;

EFI_DISK_IO_PROTOCOL DiskIo;
EFI_DISK_IO2_PROTOCOL DiskIo2;
EFI_BLOCK_IO_PROTOCOL *BlockIo;
EFI_BLOCK_IO2_PROTOCOL *BlockIo2;

UINT8 *SharedWorkingBuffer;

EFI_LOCK TaskQueueLock;
LIST_ENTRY TaskQueue;
} DISK_IO_PRIVATE_DATA;

# re: UEFI 實戰(4) protocol   回復  更多評論   

2015-06-01 04:38 by djx_zh
@周彬彬
對。本文中的方法依賴于 DISK_IO_PRIVATE_DATA的實現,而這個實現沒有一個標準,故不能保證向前兼容。這不是一個安全的方法,只是一個快速的方法。安全的方法還是調用OpenPrototocol或LocateProtocol。

# re: UEFI 實戰(4) protocol   回復  更多評論   

2015-06-02 19:58 by 夏濤
怎么添加關注的啊?

只有注冊用戶登錄后才能發表評論。
網站導航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美丝袜一区二区三区| 亚洲第一精品在线| 伊人久久婷婷| 国产亚洲网站| 好吊妞这里只有精品| 黄色国产精品| 亚洲精品五月天| 一区二区三区精品| 亚洲欧美日韩直播| 久久香蕉国产线看观看av| 免费黄网站欧美| 亚洲人成网站色ww在线| 一区二区欧美日韩| 日韩小视频在线观看专区| 中文av字幕一区| 性欧美xxxx视频在线观看| 久久爱另类一区二区小说| 免费成人高清| 亚洲精品在线二区| 欧美一级播放| 久久亚洲精品一区| 亚洲黄色性网站| 亚洲一区二区免费看| 久久精品二区三区| 欧美视频一二三区| 亚洲成人资源网| 午夜在线a亚洲v天堂网2018| 女生裸体视频一区二区三区| 99视频在线精品国自产拍免费观看| 性做久久久久久免费观看欧美| 欧美 日韩 国产 一区| 国产精品日韩在线观看| 亚洲欧洲一级| 久久一区二区三区四区五区| 亚洲精品欧美专区| 久久在精品线影院精品国产| 国产精品美女久久久久久久| 亚洲欧洲精品一区二区精品久久久| 欧美一区二区黄| 亚洲伦理一区| 欧美福利视频网站| 一区二区三区在线观看国产| 亚洲永久在线| 亚洲精品视频二区| 女生裸体视频一区二区三区| 国产自产高清不卡| 欧美一区二区三区四区高清| 日韩午夜电影在线观看| 欧美国产精品久久| 最新国产成人av网站网址麻豆| 久久久亚洲影院你懂的| 午夜精品久久久| 国产日韩亚洲欧美| 国产精品久久久对白| 亚洲精选在线观看| 亚洲国产日韩欧美在线图片| 久久青草久久| 在线看视频不卡| 免费成人激情视频| 久久婷婷国产综合精品青草| 黄色一区二区在线| 老司机亚洲精品| 久久米奇亚洲| 亚洲国产一区二区三区a毛片| 蜜臀av性久久久久蜜臀aⅴ| 久久大香伊蕉在人线观看热2| 国产欧美日韩亚洲一区二区三区 | 亚洲综合色在线| 国产精品毛片| 亚洲免费精彩视频| 欧美在线一级va免费观看| 亚洲伦伦在线| 欧美午夜精品理论片a级大开眼界| 亚洲视频观看| 亚洲自拍偷拍视频| 国产精品入口尤物| 久久久中精品2020中文| 久久久亚洲午夜电影| 亚洲人成网在线播放| 一区二区三区不卡视频在线观看| 欧美日韩一级片在线观看| 亚洲欧美一区二区三区在线| 欧美影片第一页| 亚洲精品欧美| 亚洲网在线观看| 激情久久综艺| 99亚洲视频| 韩日精品视频一区| 亚洲激情专区| 国产欧美日韩视频一区二区| 欧美成人在线免费观看| 欧美色播在线播放| 久久先锋资源| 国产精品va在线| 欧美大片91| 国产精品日本一区二区| 欧美成人a视频| 国产精品免费视频xxxx| 欧美插天视频在线播放| 国产精品都在这里| 欧美成人精品激情在线观看| 欧美日韩一区二区三区四区五区 | 巨乳诱惑日韩免费av| 欧美激情亚洲| 久久免费的精品国产v∧| 欧美日本国产一区| 久久香蕉国产线看观看av| 欧美性猛片xxxx免费看久爱| 另类图片国产| 国产精品亚洲а∨天堂免在线| 你懂的国产精品| 国产精品一区二区久久精品| 亚洲国产精品久久人人爱蜜臀| 国产欧美日韩一级| 一本色道久久综合| 日韩视频一区二区三区在线播放| 欧美一区二区在线看| 亚洲天堂av综合网| 欧美精品久久久久久久免费观看| 久久精视频免费在线久久完整在线看| 欧美a级片网站| 老巨人导航500精品| 国产日韩亚洲| 午夜视频在线观看一区| 亚洲午夜电影| 欧美日产在线观看| 欧美va亚洲va香蕉在线| 黄色工厂这里只有精品| 欧美一区二区播放| 久久国产精品久久国产精品| 欧美日韩综合在线| 国产九九精品| 国产欧美二区| 亚洲天堂视频在线观看| 亚洲视频网在线直播| 欧美日韩大片一区二区三区| 亚洲激情小视频| 亚洲毛片在线看| 蘑菇福利视频一区播放| 亚洲第一久久影院| 一本色道久久综合亚洲精品婷婷 | 亚洲午夜成aⅴ人片| 亚洲特级毛片| 国产精品久久一级| 亚洲欧美日韩精品在线| 欧美一区二视频在线免费观看| 国产精品女主播在线观看| 亚洲天堂成人在线观看| 欧美日韩国产精品一区| 亚洲人成网站色ww在线| 亚洲精选中文字幕| 欧美三区在线视频| 午夜精品久久久久久99热软件| 久久aⅴ国产紧身牛仔裤| 国产一区999| 蜜桃av一区二区三区| 亚洲经典视频在线观看| 亚洲一区二区在线免费观看| 国产欧美一区二区三区久久| 久久精品九九| 亚洲日本成人在线观看| 午夜精品一区二区三区四区| 国模精品一区二区三区| 欧美成人按摩| 亚洲天堂av在线免费| 久久久欧美一区二区| 亚洲精品国产品国语在线app| 欧美日韩免费观看一区二区三区| 亚洲午夜精品一区二区三区他趣| 久久在精品线影院精品国产| 一本大道久久精品懂色aⅴ| 国产精品久久久久久久久久妞妞| 久久精品国产一区二区三 | 久久久久国产精品厨房| 最近中文字幕日韩精品| 欧美在线欧美在线| 亚洲精品综合精品自拍| 国产日韩欧美一二三区| 欧美国产精品v| 欧美影院精品一区| 亚洲精品一区二区三区蜜桃久| 欧美中文字幕视频| 一本色道久久99精品综合| 国产一区二区中文字幕免费看| 欧美精品福利| 久久嫩草精品久久久精品一| 亚洲一区二区av电影| 欧美成人综合一区| 亚洲国产精品t66y| 欧美一区三区二区在线观看| 欧美激情精品久久久久久免费印度| 久久综合图片| 亚洲精品欧洲精品| 久久综合久久综合这里只有精品| 一本久久a久久免费精品不卡 | 激情综合自拍| 久久综合狠狠| 欧美v日韩v国产v| 欧美中文字幕视频| 亚洲字幕一区二区|