• <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>

            天衣有縫

            冠蓋滿京華,斯人獨憔悴~
            posts - 35, comments - 115, trackbacks - 0, articles - 0
               :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

            2課:保護(hù)模式


            聲明:轉(zhuǎn)載請保留:

            譯者http://www.shnenglu.com/jinglexy

            原作者:xiaoming.mo at skelix dot org

            MSN & Email: jinglexy at yahoo dot com dot cn

            目標(biāo)        下載源程序

             

            如前文所述,系統(tǒng)上電時處理器處于實模式。事實上,它還有另外一種工作模式:保護(hù)模式。skelix從磁盤啟動后即進(jìn)入該模式。在本課中我們進(jìn)入保護(hù)模式并打印"Hello World!"



            保護(hù)模式的優(yōu)點

            在實模式下,處理器不能簡單尋址1MB以外的物理地址(實際上用某些方法是可以的),這等內(nèi)存實在是太少了。所以i386系列處理器提供了保護(hù)模式:基于特權(quán)級的保護(hù)和訪問更大的內(nèi)存地址范圍。我們在這里講的是32位保護(hù)模式,16位保護(hù)模式不在討論之列。

            保護(hù)模式最大的好處就是可以直接范圍最大4GB的地址空間,但是經(jīng)過多年的更新?lián)Q代,我們的機(jī)器還沒有達(dá)到4GB內(nèi)存,于是引入了虛擬內(nèi)存的概念,它可以使用硬盤存儲空間作為內(nèi)存使用。保護(hù)模式下對內(nèi)存訪問進(jìn)行保護(hù),它阻止用戶程序?qū)?nèi)核代碼或數(shù)據(jù)的訪問,應(yīng)用程序的crash也不會影響到整個系統(tǒng)。單個進(jìn)程可以訪問自己獨有的4GB虛擬地址空間,而不是混亂在整個內(nèi)存里面使用,它是通過地址映射來實現(xiàn)的,即邏輯地址轉(zhuǎn)換成虛擬地址的過程。更詳細(xì)的內(nèi)容可以參考Intel的文檔。


            概述運(yùn)行原理

            好了,讓我們結(jié)束無聊的理論知識吧,本課的目的是使我們的程序進(jìn)入到保護(hù)模式。在保護(hù)模式中,我們?nèi)匀皇褂枚危ㄊ聦嵣希覀儫o法在處理器上禁用段特性),每個段可以訪問單獨的4GB地址空間。段轉(zhuǎn)載在寄存器中,它表示一個描述符選擇子,和實模式一樣使用csds16位寄存器。這樣說吧:一個內(nèi)存段描述符寄存器 CS = 0x8,我們可以直接訪問04G-1地址空間,注意我說的是可以,因為可以根據(jù)需要設(shè)置這個段有多大,而不是象實模式那樣限制在64KB

             

            我上面提到段是用選擇子來表示的,這個說法可能不是很準(zhǔn)確,實際上選擇子是段描述符表的索引。這個描述符表是系統(tǒng)所有可以使用的段的地址和范圍表的入口,一個描述符包括段起始地址,長度,類型(數(shù)據(jù)/代碼/門),特權(quán)級等。為了范圍到特定的內(nèi)存地址,段選擇子和偏移地址表示為如下形式:selector:offset,和實模式一樣。例如,我們讓 0x08選擇子指向B8000(視頻內(nèi)存區(qū)域) 開始的內(nèi)存范圍,這樣我們可以使用8:00000000來范圍視頻內(nèi)存區(qū)域的第一個字節(jié)。在系統(tǒng)中存在以下幾種描述符表:GDT(全局描述符表),LDT(局部描述符表),IDT(中斷描述符表)。當(dāng)進(jìn)入到保護(hù)模式后,所有的內(nèi)存范圍都通過GDTLDT

            在本課中我們使用GDT,正如它的名字全局GDT可以被所有任務(wù)共享。現(xiàn)在我們來使用一個代碼段和一個數(shù)據(jù)段。

            下面是代碼段/數(shù)據(jù)段描述符的格式,一個描述符是8字節(jié)長(64位):

             

             63_______________56__55__54__53__52__51_____________48_

            基地址(3124位) | G |D/B| X | U | 長度(1916位) |

            |_______________________________________________________|

             

             _47__46__45__44____41______40____39_________________32_

            | P |  DPL |     類型    |  A   |  基地址(2316位)   |

            |_______________________________________________________|

             

             31____________________________________________________16

            |                    基地址(150位)                  |

            |_______________________________________________________|

             

             16_____________________________________________________

            |                    長度(150位)                    |

            |_______________________________________________________|

             

            解釋一下:為什么長度只有20位呢,這是因為粒度一般設(shè)置位4K,所以可以表示04GB大小的長度范圍。

             

             

                                               -域說明

             

            長度( 15-0)

            長度的低16

            基地址( 15-0)

            基地址的低16

            基地址( 23-16)

            基地址的中16

            A

            是否已訪問

            類型

            41

            對于數(shù)據(jù)/堆棧段,為1表示可寫,為0表示只讀

            對于代碼段,為1表示可讀可執(zhí)行,為0表示不可讀可執(zhí)行

            42

            對于代碼段,為0是一般段,為1是一致性代碼段。對于數(shù)據(jù)段,為0表示數(shù)據(jù)段,為1表示堆棧段。

            43

            1表示代碼段,0表示數(shù)據(jù)或堆棧段

            44

            1表示代碼或數(shù)據(jù)段,0表示系統(tǒng)段(中斷門,調(diào)用門,陷阱門)

            DPL

            特權(quán)級:我們只使用兩個,內(nèi)核0級和用戶3

            P

            存在位,為1表示在內(nèi)存中。一般在虛擬內(nèi)存管理中會使用到這個位。

            長度( 19-16)

            長度的低8

            U

            用戶定義位

            X

            恒為0

            D

            32位代碼段還是16位代碼段

            G

            段長度的粒度:4k大小或1字節(jié)

            基地址( 31-24)

            基地址的高16

             

            我們從上面看到,一個描述符保護(hù)32位基地址和20位段長界限等屬性。32位基地址表示32位物理地址,是一個段的開始地址,20位長度界限表示這個段的長度。讀者可能注意到2^20只能表示1M大小范圍。為了訪問4GB地址范圍,描述符中使用了G位來表示粒度。當(dāng)G位為1時,粒度為4K,這是可以訪問的范圍是1M * 4K,即4GB大小;如果G為為0,粒度為1字節(jié),可以訪問的范圍是1M字節(jié)大小。

             

            特權(quán)級保護(hù)是保護(hù)模式的重要概念,為了解釋這個,我們來看一下描述符選擇子。上面已經(jīng)提到了,選擇子是描述符表的一個索引:

             

             15______________________________3___2____1___0__

            |              Index              | TI |   RPL  |

            |_______________________________________________|

             

            RPL

            請求特權(quán)級:requester privilege level

            TI

            使用 GDT(=0) 或者 LDT(=1)

            Index

            描述符表索引值

             

            應(yīng)用程序特權(quán)級(PL)和 cs寄存器中的PL(即RPL)是類似的。程序在低的特權(quán)級(即PL值更高)不能訪問高特權(quán)級的數(shù)據(jù)段或執(zhí)行高特權(quán)級的代碼段。當(dāng)選擇子載入到寄存器中時,處理器會檢查CPLRPL,根據(jù)這兩個PL得到一個EPL(恕我直言,作者增加了一個新的概念并不明智),然后比較EPL和描述符中的DPL。當(dāng)EPL的特權(quán)級更高時,才能正確訪問目標(biāo)段。注意,這里只是大致遵循該法則,處理器還要檢測讀寫屬性,存在位等。正如上面圖所描述,選擇子Index13位的,所以最多可以索引2^13個描述符,即8096個。這只是在GDT中最多索引的描述符個數(shù),另外每個進(jìn)程都可以有自己的LDT。處理器會保留第一個GDT中的描述符,它應(yīng)當(dāng)被清0,不應(yīng)當(dāng)用作訪問內(nèi)存使用。


            進(jìn)入保護(hù)模式

            在上一課中,我們從軟盤啟動skelix。現(xiàn)在我們可以執(zhí)行到實模式代碼,并進(jìn)入保護(hù)模式了,一些模式切換的代碼必不可少,并且不準(zhǔn)備讓skelix在返回到那黑暗時代-實模式了。在進(jìn)入保護(hù)模式之前,需要做一些準(zhǔn)備工作,我們先創(chuàng)建GDT

            02/bootsect.s

             

            gdt:
                    .quad    0x0000000000000000 # 
            空描述符
                    .quad    0x00cf9a000000ffff # cs
                    .quad    0x00cf92000000ffff # ds
                    .quad    0x0000000000000000 #
            用作將來的段描述符
                    .quad    0x0000000000000000 #
            用作將來的段描述符

            可以看到,我們在上面定義了5GDT描述符,但暫時只用到了第2個和第3個。第一個dummy描述符是Intel規(guī)定的,第2個是cs段(代碼段)描述符,下面我們仔細(xì)分析一下這個8字節(jié)值:(紅色表示cs描述符的值域)

             

            Bits 15-0

            FFFFh

            長度界限低16

            Bits 39-16

            000000h

            段基地址低24

            Bit  40

            0b

            訪問位:設(shè)置為0

            Bit  41

            1b

            /寫,或讀/執(zhí)行(值表示可讀可執(zhí)行代碼

            Bit  42

            0b

            棧還是數(shù)據(jù)段,普通代碼段還是一致代碼段

            Bit  43

            1b

            代碼段還是數(shù)據(jù)段

            Bit  44

            1b

            代碼數(shù)據(jù)段,還是門描述符

            Bits 45,46

            00b

            內(nèi)核特權(quán)級

            Bit  47

            1b

            存在位

            Bits 48-51

            Fh

            長度界限高4

            Bits 52

            0b

            軟件可用位,設(shè)置為0

            Bits 53

            0b

            設(shè)置為恒0

            Bits 54

            1b

            32位段還是16位段

            Bits 55

            1b

            粒度為4k還是1字節(jié)

            Bits 63-56

            00h

            段基地址高8

            根據(jù)上面的解釋,這個段描述符描述的段從00000000地址開始,界限是FFFFF*4K,即4G32位代碼段。第3個描述符用于數(shù)據(jù)段或堆棧段,區(qū)別在于第43位,設(shè)置為0表示數(shù)據(jù)段。


            好了,還是讓程序的使用來說明一切吧。處理器有幾個專門的寄存器用于保護(hù)模式,GDTR寄存器使用LGDT來加載,GDTR48位寄存器,低16位表示GDT的長度,高32位表示GDT的基地址。

             

            02/bootsect.s

            gdt_48:
                    .word  .-gdt-1        
            當(dāng)前地址減gdt地址減1得到GDT的長度
                    .long  GDT_ADDR       
            這里使用了一些常量,如GDT_ADDR,定義在一個頭文件中

            02/include/kernel.inc

            .set CODE_SEL, 0x08        # 內(nèi)核代碼段選擇子,二進(jìn)制值是00001000,表示GDT的第2項(索引值為1
            .set DATA_SEL, 0x10        #
            內(nèi)核代碼段選擇子
            .set IDT_ADDR, 0x80000     # IDT
            起始地址

            我們將所有數(shù)據(jù)設(shè)置為固定地址,IDT表(后面課程會介紹到)是所有數(shù)據(jù)的起始部分。

            .set IDT_SIZE, (256*8)     # IDT 大小
            .set GDT_ADDR, (IDT_ADDR+IDT_SIZE)        # GDT
            IDT的后面

            我們用GDT_ADDR,而不是用bootsector.s文件中的gdt符合,是因為在進(jìn)入保護(hù)模式后7c00地址將被覆蓋,于是我們把系統(tǒng)中用到的一些表搬移到固定地址。


            .set GDT_ENTRIES, 5        # GDT 
            5個描述符
                                       # 
            空描述符
                                       # 
            內(nèi)核代碼段描述符
                                       #
            內(nèi)核數(shù)據(jù)段描述符
                                       #
            當(dāng)前進(jìn)程tss
                                       #
            當(dāng)前進(jìn)程ldt

            skelix我們使用了5GDT描述符,這里我們先介紹前3個,最后兩個將會在后面的課程中介紹。
            .set GDT_SIZE, (8*GDT_ENTRIES)
                                       # GDT
            大小,每個描述符是8個字節(jié)大小,所以GDT大小是該值,但是我們用的并不是它
            .set KERNEL_SECT, 72       #
            內(nèi)核大小,單位是,36k對于現(xiàn)在來說已經(jīng)足夠了
            .set STACK_BOT, 0xa0000    #
            堆棧從640K 內(nèi)存處開始向下增長,應(yīng)該是STACK_TOP才對?

             

            下載我們來看一下引導(dǎo)程序
            02/bootsect.s

                    .text
                    .globl    start
                    .include "kernel.inc"
            include the above file
                    .code16
            start:
                    jmp        code
            gdt:  
                    .quad    0x0000000000000000 # null descriptor
                    .quad    0x00cf9a000000ffff # cs
                    .quad    0x00cf92000000ffff # ds
                    .quad    0x0000000000000000 # reserved for further use
                    .quad    0x0000000000000000 # reserved for further use
            gdt_48:
                    .word    .-gdt-1
                    .long    GDT_ADDR
            code:
                    xorw    %ax,    %ax
                    movw    %ax,    %ds    # 
            數(shù)據(jù)段 = 0x0000
                    movw    %ax,    %ss    # 
            堆棧段 = 0x0000
                    movw    $0x1000,%sp    #
            保護(hù)模式前用的堆棧,不要讓他覆蓋到7c00處的引導(dǎo)程序即可

                    # 我們將加載內(nèi)核到地址 0x10000
                    movw    $0x1000,%ax
                    movw    %ax,    %es
                    xorw    %bx,    %bx    # es:bx 
            加載內(nèi)核的目標(biāo)地址
                    movw    $KERNEL_SECT,%cx
                    movw    $1,     %si    # 0
            ,跳過去,所以是1
            rd_kern:
                    call    read_sect      #
            入口參數(shù):si是起始扇區(qū)數(shù),es:bx是指定內(nèi)存地址
                    addw    $512,    %bx
                    incw    %si
                    loop    rd_kern

            我們先把內(nèi)核讀到0x10000這個臨時地址,然后再把它搬移到0x0(進(jìn)入保護(hù)模式后搬移)。這個函數(shù)講起來有些煩,讀者可以自己分析:)


                    cli                    #
            就要進(jìn)入保護(hù)模式了,所以關(guān)掉實模式下的中斷

                    cld                    # 將內(nèi)核的前512字節(jié)移到0x0
                    movw    $0x1000,%ax
                    movw    %ax,    %ds
                    movw    $0x0000,%ax
                    movw    %ax,    %es
                    xorw    %si,    %si
                    xorw    %di,    %di
                    movw    $512>>2,%cx
                    rep
                    movsl

            為什么要這樣做?因為內(nèi)核的這個部分是load.s這個文件編譯出來的(本課后面會介紹到),load.s會讀取真正的內(nèi)核0x200處,但是在這一課,我們只準(zhǔn)備打印"Hello World!",除此之外什么都不做。

                    xorw    %ax,    %ax
                    movw    %ax,    %ds    #
            復(fù)位 ds  0x0000


                    movw    $GDT_ADDR>>4,%ax       # (0x80000 + 256 * 8) >> 2
                    movw    %ax,    %es            # gdt
            所在的數(shù)據(jù)段
                    movw    $gdt,   %si
                    xorw    %di,    %di            # 
            ds:si 拷貝到 es:di
                    movw    $GDT_SIZE>>2,%cx       #
            拷貝數(shù)據(jù)段中的gdt到指定地址
                    rep
                    movsl

            enable_a20:        
                    inb    $0x64,   %al   
                    testb  $0x2,    %al
                    jnz    enable_a20

                    movb   $0xbf,   %al
                    outb   %al,     $0x64

            這種開啟a20地址線的方法來自一本書:"The Undocumented PC",中文紙版是《PC技術(shù)內(nèi)幕》,可惜已絕版。a20地址線通過鍵盤控制器一個端口使能(ibm早期這樣設(shè)計),當(dāng)系統(tǒng)啟動時,該地址線是關(guān)閉的,使能它之后才能訪問1MB以外的地址空間。

                    lgdt    gdt_48                 # 加載gdt地址到寄存器中
                    #
            進(jìn)入保護(hù)模式
                    movl   %cr0,    %eax
                    orl    $0x1,    %eax
                    movl   %eax,    %cr0           #
            使能CR0 控制寄存器中的PE位(即第0位)

            現(xiàn)在我們已經(jīng)進(jìn)入到保護(hù)模式了,是不是簡單的另你不敢相信?呵呵


                    ljmp   $CODE_SEL, $0x0

            我們還需要進(jìn)行一個絕對地址跳轉(zhuǎn),因為解碼管線中預(yù)取了16位指令,需要刷新成后面的32位指令。關(guān)于ia32的指令預(yù)取和解碼管線,網(wǎng)絡(luò)上有很多相關(guān)的文章,建議讀者閱讀一下相關(guān)文章。這個指令跳轉(zhuǎn)到0x08描述符選擇子指向的偏移0x的指令處,并開始執(zhí)行,這個描述符即GDT中的第2項:內(nèi)核代碼段描述符。代碼就是load.s的開始處,一會我們開始分析load.s這個程序。

             

             

            bootsector.s中的函數(shù):

                    # 輸入:    si:    LBA 地址,從0開始
                    # 
            輸出     es:bx  讀取扇區(qū)到這個內(nèi)存地址
            read_sect:
                    pushw   %ax
                    pushw   %cx
                    pushw   %dx
                    pushw   %bx

                    movw    %si,    %ax       
                    xorw    %dx,    %dx
                    movw    $18,    %bx    #
            對于1.44M軟盤:每磁道18扇區(qū)


                    divw    %bx
                    incw    %dx
                    movb    %dl,    %cl    # cl =
            扇區(qū)號
                    xorw    %dx,    %dx
                    movw    $2,     %bx    #
            每磁道2磁頭
                    divw    %bx

                    movb    %dl,    %dh    # 
            磁頭
                    xorb    %dl,    %dl    # 
            軟驅(qū)號
                    movb    %al,    %ch    #
            柱面

                    popw    %bx            # 讀取到:es:bx
            rp_read:
                    movb    $0x1,   %al    #
            1個扇區(qū)
                    movb    $0x2,   %ah
                    int     $0x13
                    jc      rp_read
                    popw    %dx
                    popw    %cx
                    popw    %ax
                    ret

             

            .org    0x1fe,  0x90              # 填充nop指令,機(jī)器碼是0x90
            .word   0xaa55

            當(dāng)我們進(jìn)入到保護(hù)模式后,所有的通用寄存器和段寄存器保持原來實模式的值,代碼段從特權(quán)級0開始執(zhí)行。load.s文件將從地址0處開始執(zhí)行。
            02/load.s

                    .text
                    .globl    pm_mode
                    .include "kernel.inc"
                    .org 0                    #
            告訴加載器,該代碼將從邏輯地址0開始執(zhí)行。它也是物理地址0

            pm_mode:
                    movl    $DATA_SEL,%eax
                    movw    %ax,    %ds
                    movw    %ax,    %es
                    movw    %ax,    %fs
                    movw    %ax,    %gs
                    movw    %ax,    %ss
                    movl    $STACK_BOT,%esp   #
            所有數(shù)據(jù)段選擇子設(shè)置為0x10,即GDT的第3項,特權(quán)級為0。這個步驟非常重要!

                    cld
                    movl    $0x10200,%esi     #
            bootsector程序中,我們將內(nèi)核加載到了0x10200這個地址
                    movl    $0x200, %edi      #
            現(xiàn)在把內(nèi)核搬移到0x200
                    movl    $KERNEL_SECT<<7,%ecx        #
            拷貝2^7次方個,注意下面是movsl,每次4個字節(jié)
                    rep
                    movsl


                    movb    $0x07, %al                  #
            顏色
                    movl    $msg,  %esi
                    movl    $0xb8000,%edi
            1:
                    cmp     $0,    (%esi)               #
            打印"Hello World!"字符串
                    je      1f
                    movsb
                    stosb
                    jmp     1b
            1:      jmp     1b
            msg:
                            .string "Hello World!\x0"

            現(xiàn)在我們用圖來清晰的描述它,引導(dǎo)程序被加載在00007c00,它設(shè)置棧頂在00001000,然后讀取內(nèi)核到00001000,然后把內(nèi)核映象的前一個sector(即load.s)程序讀到地址0。在load.s程序中移到內(nèi)核到地址0

             

                    1                                        2

            |                   |                    |___________________|a0000

            |                   |                    |       內(nèi)核棧      |

            |       GDT         |                    |                   |

            |       IDT         |                    |       GDT/IDT     |

            |___________________| 8000:系統(tǒng)數(shù)據(jù)     |___________________|80000

            |                   |                    |                   |

            |                   |                    |                   |

            |                   |                    |                   |

            |       內(nèi)核        |                    |                   |

            |                   |                    |                   |

            |___________________|10000               |                   |

            |                   |                    |                   |

            |                   |                    |                   |

            |___________________|7e00                |                   |

            |     bootsector.s  |                    |                   |

            |___________________|7c00                |                   |

            |                   |                    |                   |

            |                   |                    |___________________|

            |                   |                    |                   |

            |                   |                    |                   |

            |___________________|1000                |       內(nèi)核        |

            |      stack        |                    |                   |

            |___________________|200                 |___________________|200

            |      load.s       |                    |                   |

            |___________________|0                   |___________________|0


            當(dāng)進(jìn)入到保護(hù)模式后,load.s移到內(nèi)核到它后面,設(shè)置內(nèi)核棧,如圖2

            最后,我們翻開Makefile看看:
            02/Makefile

             

            AS=as -Iinclude            -I選項告訴匯編工具查找頭文件的路徑
            LD=ld

            KERNEL_OBJS= load.o        
            到現(xiàn)在為止,內(nèi)核只保護(hù)load.s匯編文件
            .s.o:
                ${AS} -a $< -o $*.o >$*.map

            all: final.img

            final.img: bootsect kernel
                cat bootsect kernel > final.img
                @wc -c final.img

            bootsect: bootsect.o
                ${LD} --oformat binary -N -e start -Ttext 0x7c00 -o bootsect $<

            kernel: ${KERNEL_OBJS}
                ${LD} --oformat binary -N -e pm_mode -Ttext 0x0000 -o $@ ${KERNEL_OBJS}
                @wc -c kernel

            內(nèi)核代碼段鏈接在0x0000
            clean:
                rm -f *.img kernel bootsect *.o

            執(zhí)行make,用vmware運(yùn)行一下剛才的image看看,是不是hello world呢。

             

            Feedback

            # re: 自己動手寫內(nèi)核(第2課:保護(hù)模式)(原創(chuàng))  回復(fù)  更多評論   

            2007-07-13 10:09 by way
            set CODE_SEL, 0x08 # 內(nèi)核代碼段選擇子
            .set DATA_SEL, 0x10 # 內(nèi)核數(shù)據(jù)段選擇子
            kernel.inc中有點小問題
            請問這里為何知道選擇子分別是0x08及0x10
            謝謝回答

            # re: 自己動手寫內(nèi)核(第2課:保護(hù)模式)(原創(chuàng))[未登錄]  回復(fù)  更多評論   

            2007-07-13 12:12 by 天衣有縫
            0x08的二進(jìn)制值是1000,0x10的二進(jìn)制值是10000
            第三位是屬性(一位表示gdt或者ldt,兩位表示特權(quán)級)
            高13為是在gdt或ldt中的偏移,所以CODE_SEL和DATA_SEL分別表示偏移1項和偏移兩項。
            可以在intel網(wǎng)站上找到ia32/64的三卷手冊下載,里面有詳細(xì)的描述。

            # re: 自己動手寫內(nèi)核(第2課:保護(hù)模式)(原創(chuàng))  回復(fù)  更多評論   

            2007-09-30 15:32 by way
            請問以你的設(shè)計來講code,data段都是0~4G的尋址
            然后你并沒有用data段,這兩個段完全重迭又沒有paging
            所以進(jìn)入保護(hù)模式這里將“l(fā)jmp $CODE_SEL, $0x0”
            改為“l(fā)jmp $DATA_SEL, $0x0”是不是效果完全一樣呢?
            這樣還會正常運(yùn)作嗎?我看很多資料都沒提到為何要重迭
            這問題也困擾我很久了
            謝謝解答
            久久er国产精品免费观看8| 99久久无色码中文字幕人妻| 久久亚洲精品人成综合网| 亚洲狠狠婷婷综合久久蜜芽 | 精品久久久久久亚洲精品| 久久中文娱乐网| 国产精品成人久久久| av国内精品久久久久影院| 国产精品无码久久综合网| 久久久国产亚洲精品| 久久国产精品99精品国产987| 久久综合精品国产一区二区三区| 色婷婷综合久久久中文字幕 | 中文无码久久精品| 青青青国产成人久久111网站| 婷婷久久综合九色综合绿巨人| 久久久久久亚洲精品成人| 久久se这里只有精品| 国内精品九九久久久精品| 久久婷婷色综合一区二区| 国内精品伊人久久久久| 狠狠色狠狠色综合久久| 亚洲国产成人久久精品影视| 色综合久久久久综合体桃花网| 久久精品国产亚洲AV不卡| 精品国产一区二区三区久久久狼| 午夜精品久久久内射近拍高清| 国产 亚洲 欧美 另类 久久| 久久国产高潮流白浆免费观看| 国内精品人妻无码久久久影院导航| 久久免费美女视频| 国产精品禁18久久久夂久 | 人妻无码中文久久久久专区| 合区精品久久久中文字幕一区 | 久久久久亚洲精品日久生情 | 91精品国产91久久久久久蜜臀| 精品久久久久久无码中文字幕一区| 亚洲AV无码久久精品色欲| 国产精品久久婷婷六月丁香| 久久无码人妻精品一区二区三区| 久久精品国产亚洲沈樵|