一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Device Tree(二):基本概念

 風(fēng)之library 2014-07-15

作者:linuxer 發(fā)布于:2014-5-30 16:47

一、前言

一些背景知識(例如:為何要引入Device Tree,這個機制是用來解決什么問題的)請參考引入Device Tree的原因,本文主要是介紹Device Tree的基礎(chǔ)概念。

簡單的說,如果要使用Device Tree,首先用戶要了解自己的硬件配置和系統(tǒng)運行參數(shù),并把這些信息組織成Device Tree source file。通過DTC(Device Tree Compiler),可以將這些適合人類閱讀的Device Tree source file變成適合機器處理的Device Tree binary file(有一個更好聽的名字,DTB,device tree blob)。在系統(tǒng)啟動的時候,boot program(例如:firmware、bootloader)可以將保存在flash中的DTB copy到內(nèi)存(當(dāng)然也可以通過其他方式,例如可以通過bootloader的交互式命令加載DTB,或者firmware可以探測到device的信息,組織成DTB保存在內(nèi)存中),并把DTB的起始地址傳遞給client program(例如OS kernel,bootloader或者其他特殊功能的程序)。對于計算機系統(tǒng)(computer system),一般是firmware->bootloader->OS,對于嵌入式系統(tǒng),一般是bootloader->OS。

本文主要描述下面兩個主題:

1、Device Tree source file語法介紹

2、Device Tree binaryfile格式介紹

 

二、Device Tree的結(jié)構(gòu)

在描述Device Tree的結(jié)構(gòu)之前,我們先問一個基礎(chǔ)問題:是否Device Tree要描述系統(tǒng)中的所有硬件信息?答案是否定的?;旧?,那些可以動態(tài)探測到的設(shè)備是不需要描述的,例如USB device。不過對于SOC上的usb host controller,它是無法動態(tài)識別的,需要在device tree中描述。同樣的道理,在computer system中,PCI device可以被動態(tài)探測到,不需要在device tree中描述,但是PCI bridge如果不能被探測,那么就需要描述之。

為了了解Device Tree的結(jié)構(gòu),我們首先給出一個Device Tree的示例:

/ o device-tree
      |- name = "device-tree"
      |- model = "MyBoardName"
      |- compatible = "MyBoardFamilyName"
      |- #address-cells = <2>
      |- #size-cells = <2>
      |- linux,phandle = <0>
      |
      o cpus
      | | - name = "cpus"
      | | - linux,phandle = <1>
      | | - #address-cells = <1>
      | | - #size-cells = <0>
      | |
      | o PowerPC,970@0
      |   |- name = "PowerPC,970"
      |   |- device_type = "cpu"
      |   |- reg = <0>
      |   |- clock-frequency = <0x5f5e1000>
      |   |- 64-bit
      |   |- linux,phandle = <2>
      |
      o memory@0
      | |- name = "memory"
      | |- device_type = "memory"
      | |- reg = <0x00000000 0x00000000 0x00000000 0x20000000>
      | |- linux,phandle = <3>
      |
      o chosen
        |- name = "chosen"
        |- bootargs = "root=/dev/sda2"
        |- linux,phandle = <4>

從上圖中可以看出,device tree的基本單元是node。這些node被組織成樹狀結(jié)構(gòu),除了root node,每個node都只有一個parent。一個device tree文件中只能有一個root node。每個node中包含了若干的property/value來描述該node的一些特性。每個node用節(jié)點名字(node name)標識,節(jié)點名字的格式是node-name@unit-address。如果該node沒有reg屬性(后面會描述這個property),那么該節(jié)點名字中必須不能包括@和unit-address。unit-address的具體格式是和設(shè)備掛在那個bus上相關(guān)。例如對于cpu,其unit-address就是從0開始編址,以此加一。而具體的設(shè)備,例如以太網(wǎng)控制器,其unit-address就是寄存器地址。root node的node name是確定的,必須是“/”。

在一個樹狀結(jié)構(gòu)的device tree中,如何引用一個node呢?要想唯一指定一個node必須使用full path,例如/node-name-1/node-name-2/node-name-N。在上面的例子中,cpu node我們可以通過/cpus/PowerPC,970@0訪問。

屬性(property)值標識了設(shè)備的特性,它的值(value)是多種多樣的:

1、可能是空,也就是沒有值的定義。例如上圖中的64-bit ,這個屬性沒有賦值。

2、可能是一個u32、u64的數(shù)值(值得一提的是cell這個術(shù)語,在Device Tree表示32bit的信息單位)。例如#address-cells = <1> 。當(dāng)然,可能是一個數(shù)組。例如<0x00000000 0x00000000 0x00000000 0x20000000>

4、可能是一個字符串。例如device_type = "memory" ,當(dāng)然也可能是一個string list。例如"PowerPC,970"

 

三、Device Tree source file語法介紹

了解了基本的device tree的結(jié)構(gòu)后,我們總要把這些結(jié)構(gòu)體現(xiàn)在device tree source code上來。在linux kernel中,擴展名是dts的文件就是描述硬件信息的device tree source file,在dts文件中,一個node被定義成:

[label:] node-name[@unit-address] {
   [properties definitions]
   [child nodes]
}

“[]”表示option,因此可以定義一個只有node name的空節(jié)點。label方便在dts文件中引用,具體后面會描述。child node的格式和node是完全一樣的,因此,一個dts文件中就是若干嵌套組成的node,property以及child note、child note property描述。

考慮到空泛的談比較枯燥,我們用實例來講解Device Tree Source file 的數(shù)據(jù)格式。假設(shè)蝸窩科技制作了一個S3C2416的開發(fā)板,我們把該development board命名為snail,那么需要撰寫一個s3c2416-snail.dts的文件。如果把所有的開發(fā)板的硬件信息(SOC以及外設(shè))都描述在一個文件中是不合理的,因此有可能其他公司也使用S3C2416搭建自己的開發(fā)板并命令pig、cow什么的,如果大家都用自己的dts文件描述硬件,那么其中大部分是重復(fù)的,因此我們把和S3C2416相關(guān)的硬件描述保存成一個單獨的dts文件可以供使用S3C2416的target board來引用并將文件的擴展名變成dtsi(i表示include)。同理,三星公司的S3C24xx系列是一個SOC family,這些SOCs(2410、2416、2450等)也有相同的內(nèi)容,因此同樣的道理,我們可以將公共部分抽取出來,變成s3c24xx.dtsi,方便大家include。同樣的道理,各家ARM vendor也會共用一些硬件定義信息,這個文件就是skeleton.dtsi。我們自下而上(類似C++中的從基類到頂層的派生類)逐個進行分析。

1、skeleton.dtsi。位于linux-3.14\arch\arm\boot\dts目錄下,具體該文件的內(nèi)容如下:

/ {
    #address-cells = <1>;
    #size-cells = <1>;
    chosen { };
    aliases { };
    memory { device_type = "memory"; reg = <0 0>; };
};

device tree顧名思義是一個樹狀的結(jié)構(gòu),既然是樹,必然有根?!?”是根節(jié)點的node name?!皗”和“}”之間的內(nèi)容是該節(jié)點的具體的定義,其內(nèi)容包括各種屬性的定義以及child node的定義。chosen、aliases和memory都是sub node,sub node的結(jié)構(gòu)和root node是完全一樣的,因此,sub node也有自己的屬性和它自己的sub node,最終形成了一個樹狀的device tree。屬性的定義采用property = value的形式。例如#address-cells和#size-cells就是property,而<1>就是value。value有三種情況:

1)屬性值是text string或者string list,用雙引號表示。例如device_type = "memory"

2)屬性值是32bit unsigned integers,用尖括號表示。例如#size-cells = <1>

3)屬性值是binary data,用方括號表示。例如binary-property = [0x01 0x23 0x45 0x67]

如果一個device node中包含了有尋址需求(要定義reg property)的sub node(后文也許會用child node,和sub node是一樣的意思),那么就必須要定義這兩個屬性?!?”是number的意思,#address-cells這個屬性是用來描述sub node中的reg屬性的地址域特性的,也就是說需要用多少個u32的cell來描述該地址域。同理可以推斷#size-cells的含義,下面對reg的描述中會給出更詳細的信息。

chosen node主要用來描述由系統(tǒng)firmware指定的runtime parameter。如果存在chosen這個node,其parent node必須是名字是“/”的根節(jié)點。原來通過tag list傳遞的一些linux kernel的運行時參數(shù)可以通過Device Tree傳遞。例如command line可以通過bootargs這個property這個屬性傳遞;initrd的開始地址也可以通過linux,initrd-start這個property這個屬性傳遞。在本例中,chosen節(jié)點是空的,在實際中,建議增加一個bootargs的屬性,例如:

"root=/dev/nfs nfsroot=1.1.1.1:/nfsboot ip=1.1.1.2:1.1.1.1:1.1.1.1:255.255.255.0::usbd0:off console=ttyS0,115200 mem=64M@0x30000000"

通過該command line可以控制內(nèi)核從usbnet啟動,當(dāng)然,具體項目要相應(yīng)修改command line以便適應(yīng)不同的需求。我們知道,device tree用于HW platform識別,runtime parameter傳遞以及硬件設(shè)備描述。chosen節(jié)點并沒有描述任何硬件設(shè)備節(jié)點的信息,它只是傳遞了runtime parameter。

aliases 節(jié)點定義了一些別名。為何要定義這個node呢?因為Device tree是樹狀結(jié)構(gòu),當(dāng)要引用一個node的時候要指明相對于root node的full path,例如/node-name-1/node-name-2/node-name-N。如果多次引用,每次都要寫這么復(fù)雜的字符串多少是有些麻煩,因此可以在aliases 節(jié)點定義一些設(shè)備節(jié)點full path的縮寫。skeleton.dtsi中沒有定義aliases,下面的section中會進一步用具體的例子描述之。

memory device node是所有設(shè)備樹文件的必備節(jié)點,它定義了系統(tǒng)物理內(nèi)存的layout。device_type屬性定義了該node的設(shè)備類型,例如cpu、serial等。對于memory node,其device_type必須等于memory。reg屬性定義了訪問該device node的地址信息,該屬性的值被解析成任意長度的(address,size)數(shù)組,具體用多長的數(shù)據(jù)來表示address和size是在其parent node中定義(#address-cells和#size-cells)。對于device node,reg描述了memory-mapped IO register的offset和length。對于memory node,定義了該memory的起始地址和長度。

本例中的物理內(nèi)存的布局并沒有通過memory node傳遞,其實我們可以使用command line傳遞,我們command line中的參數(shù)“mem=64M@0x30000000”已經(jīng)給出了具體的信息。我們用另外一個例子來加深對本節(jié)描述的各個屬性以及memory node的理解。假設(shè)我們的系統(tǒng)是64bit的,physical memory分成兩段,定義如下:

RAM: starting address 0x0, length 0x80000000 (2GB)
RAM: starting address 0x100000000, length 0x100000000 (4GB)

對于這樣的系統(tǒng),我們可以將root node中的#address-cells和#size-cells這兩個屬性值設(shè)定為2,可以用下面兩種方法來描述物理內(nèi)存:

方法1:

memory@0 {
    device_type = "memory";
    reg = <0x000000000 0x00000000 0x00000000 0x80000000
              0x000000001 0x00000000 0x00000001 0x00000000>;
};

方法2:

memory@0 {
    device_type = "memory";
    reg = <0x000000000 0x00000000 0x00000000 0x80000000>;
};

memory@100000000 {
    device_type = "memory";
    reg = <0x000000001 0x00000000 0x00000001 0x00000000>;
};

2、s3c24xx.dtsi。位于linux-3.14\arch\arm\boot\dts目錄下,具體該文件的內(nèi)容如下(有些內(nèi)容省略了,領(lǐng)會精神即可,不需要描述每一個硬件定義的細節(jié)):

#include "skeleton.dtsi"

/ {
    compatible = "samsung,s3c24xx"; -------------------(A)
    interrupt-parent = <&intc>; ----------------------(B)

    aliases {
        pinctrl0 = &pinctrl_0; ------------------------(C)
    };

    intc:interrupt-controller@4a000000 { ------------------(D)
        compatible = "samsung,s3c2410-irq";
        reg = <0x4a000000 0x100>;
        interrupt-controller;
        #interrupt-cells = <4>;
    };

    serial@50000000 { ----------------------(E) 
        compatible = "samsung,s3c2410-uart";
        reg = <0x50000000 0x4000>;
        interrupts = <1 0 4 28>, <1 1 4 28>;
        status = "disabled";
    };

    pinctrl_0: pinctrl@56000000 {------------------(F)
        reg = <0x56000000 0x1000>;

        wakeup-interrupt-controller {
            compatible = "samsung,s3c2410-wakeup-eint";
            interrupts = <0 0 0 3>,
                     <0 0 1 3>,
                     <0 0 2 3>,
                     <0 0 3 3>,
                     <0 0 4 4>,
                     <0 0 5 4>;
        };
    };

……
};

這個文件描述了三星公司的S3C24xx系列SOC family共同的硬件block信息。首先提出的問題就是:為何定義了兩個根節(jié)點?按理說Device Tree只能有一個根節(jié)點,所有其他的節(jié)點都是派生于根節(jié)點的。我的猜測是這樣的:Device Tree Compiler會對DTS的node進行合并,最終生成的DTB只有一個root node。OK,我們下面開始逐一分析:

(A)在描述compatible屬性之前要先描述model屬性。model屬性指明了該設(shè)備屬于哪個設(shè)備生產(chǎn)商的哪一個model。一般而言,我們會給model賦值“manufacturer,model”。例如model = "samsung,s3c24xx"。samsung是生產(chǎn)商,s3c24xx是model類型,指明了具體的是哪一個系列的SOC。OK,現(xiàn)在我們回到compatible屬性,該屬性的值是string list,定義了一系列的modle(每個string是一個model)。這些字符串列表被操作系統(tǒng)用來選擇用哪一個driver來驅(qū)動該設(shè)備。假設(shè)定義該屬性:compatible = “aaaaaa”, “bbbbb"。那么操作操作系統(tǒng)可能首先使用aaaaaa來匹配適合的driver,如果沒有匹配到,那么使用字符串bbbbb來繼續(xù)尋找適合的driver,對于本例,compatible = "samsung,s3c24xx",這里只定義了一個modle而不是一個list。對于root node,compatible屬性是用來匹配machine type的(在device tree代碼分析文章中會給出更細致的描述)。對于普通的HW block的節(jié)點,例如interrupt-controller,compatible屬性是用來匹配適合的driver的。

(B)具體各個HW block的interrupt source是如何物理的連接到interruptcontroller的呢?在dts文件中是用interrupt-parent這個屬性來標識的。且慢,這里定義interrupt-parent屬性的是root node,難道root node會產(chǎn)生中斷到interrupt controller嗎?當(dāng)然不會,只不過如果一個能夠產(chǎn)生中斷的device node沒有定義interrupt-parent的話,其interrupt-parent屬性就是跟隨parent node。因此,與其在所有的下游設(shè)備中定義interrupt-parent,不如統(tǒng)一在root node中定義了。

intc是一個lable,標識了一個device node(在本例中是標識了interrupt-controller@4a000000 這個device node)。實際上,interrupt-parent屬性值應(yīng)該是是一個u32的整數(shù)值(這個整數(shù)值在Device Tree的范圍內(nèi)唯一識別了一個device node,也就是phandle),不過,在dts文件中中,可以使用類似c語言的Labels and References機制。定義一個lable,唯一標識一個node或者property,后續(xù)可以使用&來引用這個lable。DTC會將lable轉(zhuǎn)換成u32的整數(shù)值放入到DTB中,用戶層面就不再關(guān)心具體轉(zhuǎn)換的整數(shù)值了。

關(guān)于interrupt,我們值得進一步描述。在Device Tree中,有一個概念叫做interrupt tree,也就是說interrupt也是一個樹狀結(jié)構(gòu)。我們以下圖為例(該圖來自Power_ePAPR_APPROVED_v1.1):

it

系統(tǒng)中有一個interrrupt tree的根節(jié)點,device1、device2以及PCI host bridge的interrupt line都是連接到root interrupt controller的。PCI host bridge設(shè)備中有一些下游的設(shè)備,也會產(chǎn)生中斷,但是他們的中斷都是連接到PCI host bridge上的interrupt controller(術(shù)語叫做interrupt nexus),然后報告到root interrupt controller的。每個能產(chǎn)生中斷的設(shè)備都可以產(chǎn)生一個或者多個interrupt,每個interrupt source(另外一個術(shù)語叫做interrupt specifier,描述了interrupt source的信息)都是限定在其所屬的interrupt domain中。

在了解了上述的概念后,我們可以回頭再看看interrupt-parent這個屬性。其實這個屬性是建立interrupt tree的關(guān)鍵屬性。它指明了設(shè)備樹中的各個device node如何路由interrupt event。另外,需要提醒的是interrupt controller也是可以級聯(lián)的,上圖中沒有表示出來。那么在這種情況下如何定義interrupt tree的root呢?那個沒有定義interrupt-parent的interrupt controller就是root。

(C)pinctrl0是一個縮寫,他是/pinctrl@56000000的別名。這里同樣也是使用了Labels and References機制。

(D)intc(node name是interrupt-controller@4a000000 ,我這里直接使用lable)是描述interrupt controller的device node。根據(jù)S3C24xx的datasheet,我們知道interrupt controller的寄存器地址從0x4a000000開始,長度為0x100(實際2451的interrupt的寄存器地址空間沒有那么長,0x4a000074是最后一個寄存器),也就是reg屬性定義的內(nèi)容。interrupt-controller屬性為空,只是用來標識該node是一個interrupt controller而不是interrupt nexus(interrupt nexus需要在不同的interrupt domains之間進行翻譯,需要定義interrupt-map的屬性,本文不涉及這部分的內(nèi)容)。#interrupt-cells 和#address-cells概念是類似的,也就是說,用多少個u32來標識一個interrupt source。我們可以看到,在具體HW block的interrupt定義中都是用了4個u32來表示,例如串口的中斷是這樣定義的:

interrupts = <1 0 4 28>, <1 1 4 28>;

(E) 從reg屬性可以serial controller寄存器地址從0x50000000 開始,長度為0x4000。對于一個能產(chǎn)生中斷的設(shè)備,必須定義interrupts這個屬性。也可以定義interrupt-parent這個屬性,如果不定義,則繼承其parent node的interrupt-parent屬性。 對于interrupt屬性值,各個interrupt controller定義是不一樣的,有的用3個u32表示,有的用4個。具體上面的各個數(shù)字的解釋權(quán)歸相關(guān)的interrupt controller所有。對于中斷屬性的具體值的描述我們會在device tree的第三份文檔-代碼分析中描述。

(F)這個node是描述GPIO控制的。這個節(jié)點定義了一個wakeup-interrupt-controller 的子節(jié)點,用來描述有喚醒功能的中斷源。

3、s3c2416.dtsi。位于linux-3.14\arch\arm\boot\dts目錄下,具體該文件的內(nèi)容如下(有些內(nèi)容省略了,領(lǐng)會精神即可,不需要描述每一個硬件定義的細節(jié)):

#include "s3c24xx.dtsi"
#include "s3c2416-pinctrl.dtsi"

/ {
    model = "Samsung S3C2416 SoC"; 
    compatible = "samsung,s3c2416"; ---------------A

    cpus { ----------------------------B
        #address-cells = <1>;
        #size-cells = <0>;

        cpu {
            compatible = "arm,arm926ejs";
        };
    };

    interrupt-controller@4a000000 { -----------------C
        compatible = "samsung,s3c2416-irq";
    };

……

};

(A)在s3c24xx.dtsi文件中已經(jīng)定義了compatible這個屬性,在s3c2416.dtsi中重復(fù)定義了這個屬性,一個node不可能有相同名字的屬性,具體如何處理就交給DTC了。經(jīng)過反編譯,可以看出,DTC是丟棄掉了前一個定義。因此,到目前為止,compatible = samsung,s3c2416。在s3c24xx.dtsi文件中定義了compatible的屬性值被覆蓋了。

(B)對于根節(jié)點,必須有一個cpus的child node來描述系統(tǒng)中的CPU信息。對于CPU的編址我們用一個u32整數(shù)就可以描述了,因此,對于cpus node,#address-cells 是1,而#size-cells是0。其實CPU的node可以定義很多屬性,例如TLB,cache、頻率信息什么的,不過對于ARM,這里只是定義了compatible屬性就OK了,arm926ejs包括了所有的processor相關(guān)的信息。

(C)s3c24xx.dtsi文件和s3c2416.dtsi中都有interrupt-controller@4a000000這個node,DTC會對這兩個node進行合并,最終編譯的結(jié)果如下:

interrupt-controller@4a000000 {
        compatible = "samsung,s3c2416-irq";
        reg = <0x4a000000 0x100>;
        interrupt-controller;
        #interrupt-cells = <0x4>;
        linux,phandle = <0x1>;
        phandle = <0x1>;
    };

4、s3c2416-pinctrl.dtsi

  這個文件定義了pinctrl@56000000 這個節(jié)點的若干child node,主要用來描述GPIO的bank信息。

5、s3c2416-snail.dts

  這個文件應(yīng)該定義一些SOC之外的peripherals的定義。

四、Device Tree binary格式

1、DTB整體結(jié)構(gòu)

經(jīng)過Device Tree Compiler編譯,Device Tree source file變成了Device Tree Blob(又稱作flattened device tree)的格式。Device Tree Blob的數(shù)據(jù)組織如下圖所示:

dt

2、DTB header。

對于DTB header,其各個成員解釋如下:

header field name description
magic 用來識別DTB的。通過這個magic,kernel可以確定bootloader傳遞的參數(shù)block是一個DTB還是tag list。
totalsize DTB的total size
off_dt_struct device tree structure block的offset
off_dt_strings device tree strings block的offset
off_mem_rsvmap offset to memory reserve map。有些系統(tǒng),我們也許會保留一些memory有特殊用途(例如DTB或者initrd image),或者在有些DSP+ARM的SOC platform上,有寫memory被保留用于ARM和DSP進行信息交互。這些保留內(nèi)存不會進入內(nèi)存管理系統(tǒng)。
version 該DTB的版本。
last_comp_version 兼容版本信息
boot_cpuid_phys 我們在哪一個CPU(用ID標識)上booting
dt_strings_size device tree strings block的size。和off_dt_strings一起確定了strings block在內(nèi)存中的位置
dt_struct_size device tree structure block的size。和和off_dt_struct一起確定了device tree structure block在內(nèi)存中的位置

3、 memory reserve map的格式描述

這個區(qū)域包括了若干的reserve memory描述符。每個reserve memory描述符是由address和size組成。其中address和size都是用U64來描述。


4、device tree structure block的格式描述

device tree structure block區(qū)域是由若干的分片組成,每個分片開始位置都是保存了token,以此來描述該分片的屬性和內(nèi)容。共計有5種token:

(1)FDT_BEGIN_NODE (0x00000001)。該token描述了一個node的開始位置,緊挨著該token的就是node name(包括unit address)

(2)FDT_END_NODE (0x00000002)。該token描述了一個node的結(jié)束位置。

(3)FDT_PROP (0x00000003)。該token描述了一個property的開始位置,該token之后是兩個u32的數(shù)據(jù),分別是length和name offset。length表示該property value data的size。name offset表示該屬性字符串在device tree strings block的偏移值。length和name offset之后就是長度為length具體的屬性值數(shù)據(jù)。

(4)FDT_NOP (0x00000004)。

(5)FDT_END (0x00000009)。該token標識了一個DTB的結(jié)束位置。

一個可能的DTB的結(jié)構(gòu)如下:

(1)若干個FDT_NOP(可選)

(2)FDT_BEGIN_NODE

              node name

              paddings

(3)若干屬性定義。

(4)若干子節(jié)點定義。

(5)若干個FDT_NOP(可選)

(6)FDT_END


5、device tree strings bloc的格式描述

device tree strings bloc定義了各個node中使用的屬性的字符串表。由于很多屬性會出現(xiàn)在多個node中,因此,所有的屬性字符串組成了一個string block。這樣可以壓縮DTB的size。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    国产一区二区三区香蕉av| 中日韩免费一区二区三区| 成人精品网一区二区三区| 亚洲av专区在线观看| 激情图日韩精品中文字幕| 91精品视频全国免费| 操白丝女孩在线观看免费高清| 国产成人精品在线一区二区三区| 精品欧美日韩一二三区 | 亚洲国产香蕉视频在线观看| 国内九一激情白浆发布| 色播五月激情五月婷婷| 日本黄色录像韩国黄色录像| 亚洲综合精品天堂夜夜| 精品久久综合日本欧美| 久久偷拍视频免费观看| 亚洲中文字幕视频一区二区| 国产日本欧美特黄在线观看| 国产白丝粉嫩av在线免费观看| 精品女同一区二区三区| 九九热在线视频观看最新| 欧美日韩亚洲精品内裤| 加勒比日本欧美在线观看| 久久大香蕉精品在线观看| 亚洲熟妇熟女久久精品| 日本高清视频在线播放| 日韩精品人妻少妇一区二区| 99在线视频精品免费播放| 国产欧美性成人精品午夜| 激情五月激情婷婷丁香| 一区二区三区亚洲国产| 日韩三级黄色大片免费观看| 日本深夜福利视频在线| 国内欲色一区二区三区| 国产亚洲二区精品美女久久| 久久亚洲精品中文字幕| 国产欧美一区二区另类精品| 国产精品久久香蕉国产线| 亚洲精品国产美女久久久99| 国产色第一区不卡高清| 久久偷拍视频免费观看|