• <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>
            隨筆 - 60, 文章 - 0, 評論 - 197, 引用 - 0
            數據加載中……

            學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理

            一、背景
               FS2410 開發板上的 ARM 核心為 ARM920T, ARM920T 代表著什么呢? 其實
            ARM920T = ARM9 core + MMU + Cache,也就是說 ARM920T 為實現虛擬內存管理提供了硬件
            條件,這個硬件條件就是 MMU -- 內存管理單元。前面的實驗我們程序里的地址都是直接對應物理地
            址,也就是說虛擬地址等同于物理地址,而今借助 MMU 我們可以實現虛擬內存管理,程序里面的地址
            不再被直接送到地址總線,而是先通過 MMU,由 MMU 來實現虛地址到物理地址的映射。這有什么意義
            呢?想象有這么兩個程序,它們有相同的虛擬地址,但由于運行時其虛地址分別被映射到不同的物理地址
            ,所以它們各行其道、和平共處,而不會產生沖突...有了 MMU 的支持我們可以設計出高級的作業系統。


            二、目的
               如何啟用 MMU, 并實現虛擬地址到物理地址映射正是這次實驗的目的。呵呵,你也許已經迫不及待...
            那現在我們就去探個究竟!


            三、代碼分析
               程序的整個執行流程都體現在 start.S 文件里(以前不是 head.s文件嗎? 呵呵,我把以前的代碼進
            行了重構,現在代碼看上去更清析--好的架構是很重要的,更便于以后的擴充),start.S里調用的函數有的
            是在 .c 文件實現的,必要時我會做相應解釋。

            1  .text
            2  .global _start
            3  _start:
            4   b reset
            5   NOP
            6   NOP
            7   NOP
            8   NOP
            9   NOP
            10  ldr pc, handle_irq_addr
            11  NOP
            12  handle_irq_addr: 
            13  .long handle_irq
            14 reset:
            15  ldr r0, =0x53000000  @ Close Watch-dog Timer
            16  mov r1, #0x0
            17  str r1, [r0]
            18
            19 @ init stack
            20 ldr sp,=4096
            21 
            22 @ disable all interrupts
            23 mov r1, #0x4A000000
            24 mov r2, #0xffffffff
            25 str r2, [r1, #0x08]
            26 ldr r2, =0x7ff
            27 str r2, [r1, #0x1c]
            28
            29 bl  memory_setup  @ Initialize memory setting
            30 bl  flash_to_sdram  @ Copy code to sdram
            31
            32 ldr pc, =run_on_sdram
            33 run_on_sdram:
            34 ldr sp, =0x33000000
            35  bl init_mmu_tlb   @ setup page table
            36  bl init_mmu         @ MMU enabled
            37
            38 msr cpsr_c, #0xd2  @ set the irq mode stack
            39 ldr sp, =0x31000000
            40 msr cpsr_c, #0xdf  @ set the system mode stack
            41 ldr sp, =0x32000000
            42 bl  init_irq           
            43 msr cpsr_c, #0x5f  @ set the system mode open the irq
            44 
            45 ldr sp, =0x33000000  @ Set stack pointer
            46 bl  main
            47 loop:
            48 b loop


            (1) 設置中斷跳轉指令
                可以看到程序 4~13 行用來設置中斷跳轉指令,目前我們只實現了響應 IRQ 中斷的代
                碼,所以在第 10 行處放了一條 ldr 加載指令,它的意思是當發生 IRQ 中斷時,把
                用于響應 IRQ 中斷的函數 handle_irq 的地址加載進 pc 寄存器讓程序跳轉那里進
                行相應處理
            (2) 關閉看門狗,程序第 15~17 行
            (3) 初始化堆棧寄存器體現在第 20 行,之所這么做因為下面會調用一些 C 函數,而 C函
                數里的變量當然要保存在堆棧里了
            (4) 暫時不響應所有中斷: 22~27 行
            (5) 第 29 行,初始化內存(內存在這里就是 SDRAM) 慢著...程序不是已經運行在內存里
                了嗎? 非也,準確點說是運行在 SRAM 里。ARM 啟動時會將 Nand Flash(相當于硬
                盤)里前 4K 代碼加載進 SRAM 里并運行之。那程序大于 4K 怎么辦? 呵呵,這正是
                下一點要說明的
            (6) 第 30 行,程序自身到內存的般移。我們的程序大于 4K, 只靠 SRAM 的那可憐的 4K
                是運行不開的
            (7) 第 32~33 行,跳轉到 SDRAM 里執行。我們的代碼已經搬到內存了,64M 的空間夠用
                 的了
            (8) 第 34~36 行,設置頁表,啟用 MMU。這是今天的主角。函數
                   init_mmu_tlb
                   init_mmu
                定義在 mmu.c 文件里,我們去看看這個文件里有些什么?

                 1  /* init MMU page table*/
                 2  void init_mmu_tlb() {
                 3    unsigned long vm_addr, idx;
                 4    unsigned long *tb_base = (unsigned long *)MMU_TBL_BASE;
                 5 
                 6    for (vm_addr = MEM_START; vm_addr < MEM_END; vm_addr += PAGE_SIZE) {
                 7      idx = vm_addr >> 20;
                 8      /* entry: section base, AP=0b11, domain=0b00,cached,write-through*/
                 9      *(tb_base + idx) = vm_addr|(0x3<<10)|(0<<5)|(1<<4)|(1<<3)|0x02;
                 10    }
                 11 
                 12    /* set IO mapped-memory addr for function register*/
                 13    for (vm_addr = MEM_IO_MAPPED_START; vm_addr < MEM_IO_MAPPED_END; vm_addr += PAGE_SIZE) {
                 14      idx = vm_addr >> 20;
                 15      /* entry: section base, AP=0b11, domain=0b00, NCNB*/
                 16      *(tb_base + idx) = vm_addr|(0x03<<10)|(0<<5)|(1<<4)|0x02;
                 17    }
                 18 
                 19    /*
                 20     * exception vectors
                 21     * entry: AP=0b11, domain=0b00, cached, write-through
                 22     */
                 23    *(tb_base + 0x00000000) = (0x00000000)|(0x03<<10)|(0<<5)|(1<<4)|(1<<3)|0x02;
                 24    *(tb_base + (0xffff0000>>20)) = VECTORS_PHY_BASE|(0x03<<10)|(0<<5)|(1<<4)|(0<<3)|0x02;
                 25  }
                 26
                 27 void init_mmu() {
                 28   unsigned long ttb = (unsigned long)MMU_TBL_BASE;
                 29   __asm__(
                 30    "mov r0, #0\n"
                 31
                 32    /* disable ICache, DCache*/
                 33    "mcr p15, 0, r0, c7, c7, 0\n"
                 34
                 35    /* clear wirte buffer*/
                 36    "mcr p15, 0, r0, c7, c10, 4\n"
                 37
                 38    /* disable ICache, Dcache, TLBs*/
                 39    "mcr p15, 0, r0, c8, c7, 0\n"
                 40
                 41    /* load page table pointer*/
                 42    "mov r4, %0\n"
                 43    "mcr p15, 0, r4, c2, c0, 0\n"
                 44
                 45    /*
                 46     * write domain id (cp15_r13)
                 47     * domain=0b11, manager mode, no check for permission
                 48     */
                 49    "mvn r0, #0\n"
                 50    "mcr p15, 0, r0, c3, c0, 0\n"
                 51
                 52    /* set control register*/
                 53    "mrc p15, 0, r0, c1, c0, 0\n"
                 54
                 55    /* clear out 'unwanted' bits*/
                 56    "ldr r1, =0x1384\n"
                 57    "bic r0, r0, r1\n"
                 58
                 59    /*
                 60     * turn on what we want
                 61     * base location of exception = 0xffff0000
                 62     */
                 63    "orr r0, r0, #0x2000\n"
                 64    /* fault checking enabled*/
                 65    "orr r0, r0, #0x0002\n"
                 66 #ifdef CONFIG_CPU_DCACHE_ON
                 67    "orr r0, r0, #0x0004\n"
                 68 #endif
                 69 #ifndef CONFIG_CPU_ICACHE_ON
                 70    "orr r0, r0, #0x1000\n"
                 71 #endif
                 72    /* MMU enabled*/
                 73    "orr r0, r0, #0x0001\n"
                 74
                 75    /* write control register*/
                 76    "mcr p15, 0, r0, c1, c0, 0\n"
                 77    : /* no output*/
                 78    : "r"(ttb));
                 79 }
                 
                程序第 1~25 行是函數 init_mmu_tlb 的實現。其實就是建立一級頁表。s3c2410 有四
                種內存映射模式: Fault、Coarse Page、Section、Fine Page. 為了簡單起見我們用
                Section 模式。ARM920T 是 32 位的 CPU,其虛擬地址空間為 2^32 即 4G。 我們用
                Section 模式來劃分這 4G 址址空間,每一個 Section 大小為 1M,這樣就可得到 4K
                個 Section。怎樣管理這些 Section 呢?通過一張表來記錄它們,而這張表被稱做頁表。
                在頁表里,用 4 個字節來記錄一個 Section 的信息。總共有 4K 個 Section,這樣就
                要花費 4x4K = 16K 的內存。這用來描述 Section 的 4 個字節也有個形象的名字,叫
                作描述符。描述符的結構又是什么樣的呢。來看一下:

               

                Section base address: 段基地址
                AP: Access Permission 訪問控制位
                Domain: 訪問控制器的索引
                C: 被置位時為 write-through (WT)模式
                B: 被置位時為 write-back (WB)模式

                s3c2410 的 SDRAM 為 64M,其物理地址范圍是 0x30000000~0x33ffffff,可劃分成
                64 個 Section。我們要實現虛址到物理地址的映射,虛地址是如何被轉換的呢?其實 MMU
                將虛地址分成兩部分: 索引(index) 和 偏移(offset)。index 就是虛地址的高 12 位,
                偏移就是虛地址的低 20 位, MMU 通過 index 在頁表里取到相應描述符,從描述符里取
                到對應 Section 的基地址,再由這個基地址加上偏移 offset 來找出真正的物理地址。

                明白了地址映射的基本原理,我們來分析上面的代碼:
                第 6~13 行令 SDRAM 的虛地址和物理地址相等,從 0x30000000 至 0x33ffffff
                第 12~17 行設置特殊功能寄存器的虛地址,也讓它們的虛地址與物理地址相等
                第 23~24 行設置中斷向量的虛地址,其中高端中斷向量地址 0xffff0000 對應到物理
                地址0x33f00000

                代碼中有幾個常數,定義如下:
                  #define MEM_START 0x30000000UL
                  #define MEM_END   0x34000000UL
                  #define PAGE_SIZE 0x00100000UL /* page size: 1M*/

                  #define MEM_IO_MAPPED_START 0x48000000UL
                  #define MEM_IO_MAPPED_END   0x60000000UL
                  #define MMU_TBL_BASE        0x30000000UL
                  #define VECTORS_PHY_BASE    0x33f00000UL


                為了理解第 27~79 行的內聯匯編到底做了些什么,我們先來了解一下協處理器:
                在基于 ARM 的嵌入式應用系統中,存儲系統通過是通過系統控制協處理器 CP15 來完
                成的。如何設置/讀取協處理器的寄存器呢?借助 MCR/MRC 指令。例如:

                    MCR P15, 0, R4, C1, C0, 0

                將寄存器 R4 中的數據傳送到協處理器 CP15 的寄存器 C1 中,其中 R4 為 ARM 寄存
                器,存放源操作數; C1,C0 為協處理器寄存器,為目的寄存器; 操作碼1為0,操作碼2為0
                相應的, MRC 指令將協處理器的寄存器中的數值傳送到 ARM 處理器的寄存器中。

                好了,我們來分析上面的內聯匯編代碼:
                第 32~33 行使數據Cache 和 指令Cache 無效。呵呵, 你沒明白過來? 其中原由如下:

                  CP15 中的寄存器 C7 用于控制 cache 和寫緩沖區。它是一個只寫的寄存器,使用 MCR 指令
                  來寫該寄存器,具體格式如下:

                      MCR P15, 0, <Rd>, <c7>, <CRm>, <opcode_2>

                  其中, <Rd> 中為將寫入 C7 中的數據; <CRm>, <opcode_2> 的不同組合決定執行不同的操作:

                  ----------------------------------------------------------------------------------
                  <CRm>        <opcode_2>        含義                                   數據
                  ----------------------------------------------------------------------------------
                  C0           4                 等待中斷激活                              0
                  C5           0                 使用無效整個Cache                     0
                  C5           1                 使無效指令Cache 中的某塊           虛地址
                  C5           2                 使無效指令Cache 中的某塊           組號/組內序號
                  C5           4                 清空預取緩沖區                          0
                  C5           6                 清空整個跳轉目標Cache                0
                  C5           7                 清空跳轉目標Cache中的某塊        生產商定義
                  C6           0                 使無效整個數據Cache                    0
                  C6           1                 使無效數據Cache 中的某塊           虛地址
                  C6           2                 使無效數據Cache 中的某塊           組號/組內序號
                  C7           0                 使數據Cache 和指令Cache 無效    0
                  C7           1                 使無效整個Cache 中的某塊           虛地址
                  C7           2                 使無效整個Cache 中的某塊           組號/組內序號
                  C8           2                 等待中斷激活                                  0
                  C10          1                 清空數據Cache 中某塊                  虛地址
                  C10          2                 清空數據Cache 中某塊                  組號/組內序號
                  C10          4                 清空寫緩沖區                                 0
                  C11          1                 清空整個Caceh 中某塊                  虛地址
                  C11          2                 清空整個Caceh 中某塊                  組號/組內序號
                  C13          1                 預取指令Cache 中某塊                  虛地址
                  C14          1                 清空并使無效數據Cache中某塊   虛地址
                  C14          2                 清空并使無效數據Cache中某塊   組號/組內序號
                  C15          1                 清空并使無效整個Cache中某塊   虛地址
                  C15          2                 清空并使無效整個Cache中某塊   組號/組內序號
                  ----------------------------------------------------------------------------------

                第 35~36 行: 清空寫緩沖區
                第 38~39 行,使DCache, ICache 及頁表的內容無效。系統控制協處理器 CP15 的寄存器 C8就
                是用來控制清除 TLB內容相關操作的。指令格式如下:
                 
                  MCR P15, 0, <Rd>, <C8>, <CRm>, <opcode_2>

                其中 <Rd> 中為將寫入 C8中的數據; <CRm>, <opcode_2> 的不同組合決定指令執行不同的操作
               
                  ----------------------------------------------------------------------------------
                  指令                           <opcode_2>   <CRm>   <Rd>    含義
                  ----------------------------------------------------------------------------------
                  MCR P15,0,Rd,C8,C7,0  0b0000     0b0111   0            DCache,ICache 無效  
                  MCR P15,0,Rd,C8,C7,1  0b0000     0b0111   虛地址  整個Cache 中單個地址變換條目無效
                  MCR P15,0,Rd,C8,C5,0  0b0000     0b0101   0            整個Cache無效
                  MCR P15,0,Rd,C8,C5,1  0b0000     0b0101   虛地址  指令Cache 中單個地址變換條目無效
                  MCR P15,0,Rd,C8,C6,0  0b0000     0b0110   0            整個數據Cache無效
                  MCR P15,0,Rd,C8,C6,1  0b0000     0b0110   虛地址  數據Cache 中單個地址變換條目無效
                  ----------------------------------------------------------------------------------

                第 41~43 行:加載頁表的首地址到 CP15 協處理器的寄存器 C2
                第 45~53 行:設置訪問控制權限。協處理器 CP15 中 C3 為 DOMAIN ACCESS CONTROL REGISTER,
                該寄存器有效位為32,被分成16個區域,每個區域由兩個位組成,含義如下:

                  00:當前級別下,該內存區域不允許被訪問,任何的訪問都會引起一個 domain fault
                  01:當前級別下,該內存區域的訪問必須配合該內存區域的段描述符中AP位進行權檢查
                  10:保留狀態
                  11:當前級別下,對該內存區域的訪問都不進行權限檢查

                注意第 49 行我們用的是 "mvn r0, #0" 而非 "mov r0, #0"

                第 59~76 行, 設置并啟用 MMU。這幾行代碼主要是設置了 CP15 的寄存器 C1。C1 是一個控制寄
                存器它包括以下功能:
                 
                  禁止/使能 MMU 以及其它的與存儲系統相關的功能
                  配置存儲系統以及 ARM 處理器中的相關部分的工作方式

                來看一下 C1 寄存器具體是什么樣子:
                  
                 

                  各控制位含義如下表:

                  ----------------------------------------------------------------------------------
                    C1中的控制位  含義
                  ----------------------------------------------------------------------------------
                    M             禁止/使能 MMU
                    A             禁止/使能地址對齊檢查功能
                    C             禁止/使能整個 Cache
                    W             禁止/使能寫緩沖
                    P             32/26地址模式
                    D             禁止/使能26地址異常檢查
                    L             早期/后期中止模型
                    B             little-endian/big-endian
                    S             在 MMU 啟用時用作系統保護
                    R             在 MMU 啟用時用作系統保護
                    F             由生產商定義
                    Z             禁止/使能跳轉預測指令
                    I             禁止/使能 Cache
                    V             低端/高端異常中斷向量表
                    RR            對系統中的 Cache 選擇淘汰算法
                    L4            提供對以前的 ARM 的版本兼容
                    bits[31:16]   保留
                  ----------------------------------------------------------------------------------


                第 77~79 行: 這是使用嵌入匯編的方式,第 78 行的 "r"(ttb) 表示變量 ttb 的值賦給一個寄
                存器作為輸入參數,這個寄存器由編譯器自動分配。我們看到第 42 行的 "%0" 被用來表示這個
                寄存器。

                ......呵呵,總算講完 MMU 這一塊了,程序不多,可引出的內容不少!


            (9) 第 38~48 行設置 irq 模式和 system 模式下的堆棧寄存器,然后程序運行在 system 模式下,
                調用 main 函數后返回, 循環并等待中斷發生......

            這就是 start.S 程序的整個流程,關鍵是 MMU 如何設置和啟用。其它代碼都有詳細的注釋。我在下
            面提供了所有代碼,有興趣的同道自己下載看吧。快過年了,預祝大家新年愉快!

             

                代碼下載


             

            posted on 2008-02-01 15:26 Normandy 閱讀(5620) 評論(14)  編輯 收藏 引用 所屬分類: Embeded Area

            評論

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            niu
            2008-02-14 16:32 | niube' son

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            代碼下載后運行不了!!
            2008-02-14 16:34 | niube' son

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            @niube' son

            代碼在我的板子上是沒有問題的, 不知樓上的兄弟是否成功編譯代碼?
            另外有幾點說明:
            (1) 代碼是直接運行在裸板上的, 而非運行在 arm-linux 上
            (2) 我是借助 FS2410 自帶的sjf2410.exe 燒寫到 Nand Flash 的, 很可能樓上的兄弟沒有燒寫成功

            如果能提供更詳細的信息就好了, 這樣就可以看看到底是哪個環節出錯了!



            2008-02-14 20:58 | Normandy

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理[未登錄]  回復  更多評論   

            樓主的代碼太偉大了。
            2008-02-19 18:26 | jjyy

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            分析的非常那個 好
            2008-02-26 02:20 | longin

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            太強了!佩服!
            2008-04-01 10:12 | liubaosen

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            Normandy你好,我將Makefile中的LIBS改為(因為我的arm-linux-gcc版本與你的例子不同):
            LIBS=-lgcc -L/usr/local/arm/3.3.2/lib/gcc-lib/arm-linux/3.3.2
            之后Make出現下列錯誤:
            arm-linux-ld -Ttext 0x30004000 -o main_tmp.o start.o interrupt.o main.o printf.o serl.o mmu.o -lgcc -L/usr/local/arm/3.4.1/lib/gcc/arm-linux/3.4.1
            /usr/local/arm/3.4.1/lib/gcc/arm-linux/3.4.1/libgcc.a(_udivsi3.oS)(.text+0xec):/work/crosstool-0.27/build/arm-linux/gcc-3.4.1-glibc-2.3.2/gcc-3.4.1/gcc/config/arm/lib1funcs.asm:615: relocation truncated to fit: R_ARM_PLT32 __div0
            /usr/local/arm/3.4.1/lib/gcc/arm-linux/3.4.1/libgcc.a(_umodsi3.oS)(.text+0xc0):/work/crosstool-0.27/build/arm-linux/gcc-3.4.1-glibc-2.3.2/gcc-3.4.1/gcc/config/arm/lib1funcs.asm:656: relocation truncated to fit: R_ARM_PLT32 __div0
            make: *** [main] Error 1
            能幫我分析下是什么錯誤嗎?謝謝。
            2008-04-01 14:45 | FAN

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            剛剛弄錯了,是將你的LIBS中的3.3.2改為了3.4.1。然后出現了上述錯誤。
            2008-04-01 15:00 | FAN

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            @FAN
            從錯誤信息上也看不出什么問題, 我猜測可能是如下兩個原因:
            (1) 你的 arm-linux-gcc 3.4.1 有問題
            或者
            (2) 編譯時你用的 arm-linux-gcc 是 3.3.2, 但鏈接時用的卻是 arm-linux-gcc 3.4.1 的庫(libgcc.a)
            2008-04-01 18:35 | Normandy

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            @Normandy
            我編譯時用的是3.4.1的,鏈接時也是用的3.4.1,可能是這個3.4.1有問題吧,一會換個3.3.2試試。謝謝了。
            2008-04-02 10:08 | FAN

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            受用非常,謝謝
            2008-04-06 14:48 | kerwintian

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            好啊,,,,非常之好。。謝謝
            2008-10-28 20:49 | Saiu

            # re: 學習 ARM 系列 -- FS2410 開發板上啟用 MMU 實現虛擬內存管理  回復  更多評論   

            你是醉生夢死(273279787)吧?
            因在群里推薦了
            李敖:中日關系 不舒服卻不得不服
            http://www.ckxxw.com/html/c9/2009-06/3606.htm
            的文章被你踢了,是不應該在技術論壇談論其它,不過你也過了點吧?
            順便說聲:如果一個好的技術人員不懂國情、不關心國家、不憂天下,即時你有一流的技術又有何用?建議有空看看李敖這篇讓中國人警醒的文章,建議了解些政治,國家興旺、天下治亂,匹夫有責!
            2009-06-28 21:30 | hele

            # QQ群名字大全  回復  更多評論   

            QQ群名字大全
            2011-05-24 06:03 | QQ群名字大全
            嫩草影院久久国产精品| 2019久久久高清456| 久久天天躁狠狠躁夜夜躁2014| 精品一区二区久久| 国产精品久久久久影院色| 久久天天躁狠狠躁夜夜躁2O2O | 伊人久久精品无码av一区| 久久久久这里只有精品| 久久人人爽人人澡人人高潮AV| 国产综合精品久久亚洲| 久久无码一区二区三区少妇 | 国产A级毛片久久久精品毛片| 国产亚洲精品美女久久久| 国产高潮国产高潮久久久| AV无码久久久久不卡蜜桃 | 久久久精品视频免费观看| 久久婷婷五月综合色99啪ak| 亚洲а∨天堂久久精品| 久久精品一区二区三区AV| 无码国产69精品久久久久网站| 久久久一本精品99久久精品88| 久久精品中文字幕久久| 综合久久一区二区三区 | 久久人人爽人人爽人人片av高请| 久久婷婷五月综合97色| 91久久精品电影| 漂亮人妻被中出中文字幕久久 | 99国产精品久久| 精品久久久久久久久久久久久久久 | 国产精品亚洲综合专区片高清久久久 | 国内精品久久久久久久亚洲| 亚洲人成无码网站久久99热国产| 日韩精品久久无码人妻中文字幕| 人人狠狠综合久久亚洲婷婷| 99久久做夜夜爱天天做精品| 97久久超碰国产精品旧版| 色婷婷综合久久久久中文字幕 | 久久精品国产精品国产精品污| 伊人色综合久久天天人守人婷| 99久久免费国产特黄| 国产精品久久婷婷六月丁香|