精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

鴻蒙輕內(nèi)核A核源碼分析系列三物理內(nèi)存之一

開發(fā)
從本篇開始,我們分析下鴻蒙輕內(nèi)核A核的內(nèi)存管理部分,包括物理內(nèi)存、虛擬內(nèi)存、虛擬映射等部分。物理內(nèi)存(Physical memory)是指通過物理內(nèi)存條而獲得的內(nèi)存空間,相對(duì)應(yīng)的概念是虛擬內(nèi)存(Virtual memory)。

[[433544]]

想了解更多內(nèi)容,請(qǐng)?jiān)L問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

從本篇開始,我們分析下鴻蒙輕內(nèi)核A核的內(nèi)存管理部分,包括物理內(nèi)存、虛擬內(nèi)存、虛擬映射等部分。物理內(nèi)存(Physical memory)是指通過物理內(nèi)存條而獲得的內(nèi)存空間,相對(duì)應(yīng)的概念是虛擬內(nèi)存(Virtual memory)。虛擬內(nèi)存使得應(yīng)用進(jìn)程認(rèn)為它擁有一個(gè)連續(xù)完整的內(nèi)存地址空間,而通常是通過虛擬內(nèi)存和物理內(nèi)存的映射對(duì)應(yīng)著多個(gè)物理內(nèi)存頁。本文我們先來熟悉下OpenHarmony鴻蒙輕內(nèi)核提供的物理內(nèi)存(Physical memory)管理模塊。

本文中所涉及的源碼,以O(shè)penHarmony LiteOS-A內(nèi)核為例,均可以在開源站點(diǎn)https://gitee.com/openharmony/kernel_liteos_a 獲取。如果涉及開發(fā)板,則默認(rèn)以hispark_taurus為例。

我們首先了解了物理內(nèi)存管理的結(jié)構(gòu)體,接著閱讀了物理內(nèi)存如何初始化,然后分析了物理內(nèi)存的申請(qǐng)、釋放和查詢等操作接口的源代碼。

1、物理內(nèi)存結(jié)構(gòu)體介紹

1.1、物理內(nèi)存頁LosVmPage

鴻蒙輕內(nèi)核A核的物理內(nèi)存采用了段頁式管理,每個(gè)物理內(nèi)存段被分割為物理內(nèi)存頁。在頭文件kernel/base/include/los_vm_page.h中定義了物理內(nèi)存頁結(jié)構(gòu)體,以及內(nèi)存頁數(shù)組g_vmPageArray及數(shù)組大小g_vmPageArraySize。物理內(nèi)存頁結(jié)構(gòu)體LosVmPage可以和物理內(nèi)存頁一一對(duì)應(yīng),也可以對(duì)應(yīng)多個(gè)連續(xù)的內(nèi)存頁,此時(shí)使用nPages指定內(nèi)存頁的數(shù)量。

 

  1. typedef struct VmPage { 
  2.     LOS_DL_LIST         node;        /**< 物理內(nèi)存頁節(jié)點(diǎn),掛在VmFreeList空閑內(nèi)存頁鏈表上 */ 
  3.     PADDR_T             physAddr;    /**< 物理內(nèi)存頁內(nèi)存開始地址*/ 
  4.     Atomic              refCounts;   /**< 物理內(nèi)存頁引用計(jì)數(shù) */ 
  5.     UINT32              flags;       /**< 物理內(nèi)存頁標(biāo)記 */ 
  6.     UINT8               order;       /**< 物理內(nèi)存頁所在的鏈表數(shù)組的索引,總共有9個(gè)鏈表 */ 
  7.     UINT8               segID;       /**< 物理內(nèi)存頁所在的物理內(nèi)存段的編號(hào) */ 
  8.     UINT16              nPages;      /**< 連續(xù)物理內(nèi)存頁的數(shù)量 */ 
  9. } LosVmPage; 
  10.  
  11. extern LosVmPage *g_vmPageArray; 
  12. extern size_t g_vmPageArraySize; 

 

在文件kernel\base\include\los_vm_common.h中定義了內(nèi)存頁的大小、掩碼和邏輯位移值,可以看出每個(gè)內(nèi)存頁的大小為4KiB。

 

  1. #ifndef PAGE_SIZE 
  2. #define PAGE_SIZE                        (0x1000U) 
  3. #endif 
  4. #define PAGE_MASK                        (~(PAGE_SIZE - 1)) 
  5. #define PAGE_SHIFT                       (12) 

 

1.2、物理內(nèi)存段LosVmPhysSeg

在文件kernel/base/include/los_vm_phys.h中定義了物理內(nèi)存段LosVmPhysSeg等幾個(gè)結(jié)構(gòu)體。該文件的部分代碼如下所示。⑴處的宏是物理內(nèi)存伙伴算法中空閑內(nèi)存頁節(jié)點(diǎn)鏈表數(shù)組的大小,VM_PHYS_SEG_MAX表示系統(tǒng)支持的物理內(nèi)存段的數(shù)量。⑵處的結(jié)構(gòu)體用于伙伴算法中空閑內(nèi)存頁節(jié)點(diǎn)鏈表數(shù)組的元素類型,除了記錄雙向鏈表,還維護(hù)鏈表上節(jié)點(diǎn)數(shù)量。⑶就是我們要介紹的物理內(nèi)存段,包含開始地址,大小,內(nèi)存頁基地址,空閑內(nèi)存頁節(jié)點(diǎn)鏈表數(shù)組,LRU鏈表數(shù)組等成員。

 

  1. ⑴  #define VM_LIST_ORDER_MAX    9 
  2.     #define VM_PHYS_SEG_MAX    32 
  3.  
  4. ⑵  struct VmFreeList { 
  5.         LOS_DL_LIST node;   // 空閑物理內(nèi)存頁節(jié)點(diǎn) 
  6.         UINT32 listCnt;     // 空閑物理內(nèi)存頁節(jié)點(diǎn)數(shù)量 
  7.     }; 
  8.  
  9. ⑶  typedef struct VmPhysSeg { 
  10.         PADDR_T start;            /* 物理內(nèi)存段的開始地址 */ 
  11.         size_t size;              /* 物理內(nèi)存段的大小,bytes */ 
  12.         LosVmPage *pageBase;      /* 物理內(nèi)存段第一個(gè)物理內(nèi)存頁結(jié)構(gòu)體地址 */ 
  13.  
  14.         SPIN_LOCK_S freeListLock; /* 伙伴算法雙向鏈表自旋鎖 */ 
  15.         struct VmFreeList freeList[VM_LIST_ORDER_MAX];  /* 空閑物理內(nèi)存頁的伙伴雙向鏈表 */ 
  16.  
  17.         SPIN_LOCK_S lruLock;  /* LRU雙向鏈表自旋鎖 */ 
  18.         size_t lruSize[VM_NR_LRU_LISTS];  /* LRU大小 */ 
  19.         LOS_DL_LIST lruList[VM_NR_LRU_LISTS];/* LRU雙向鏈表 */ 
  20.     } LosVmPhysSeg; 
  21.  
  22.     struct VmPhysArea { 
  23.         PADDR_T start;  // 物理內(nèi)存區(qū)開始地址 
  24.         size_t size;    // 物理內(nèi)存區(qū)大小 
  25.     }; 

在kernel/base/vm/los_vm_phys.c文件中定義了物理內(nèi)存區(qū)數(shù)組g_physArea[],如下代碼所示,其中SYS_MEM_BASE為DDR_MEM_ADDR的宏名稱,DDR_MEM_ADDR和SYS_MEM_SIZE_DEFAULT定義在文件./device/hisilicon/hispark_taurus/sdk_liteos/board/target_config.h中,表示開發(fā)板相關(guān)的物理內(nèi)存地址和大小。

 

  1. STATIC struct VmPhysArea g_physArea[] = { 
  2.     { 
  3.         .start = SYS_MEM_BASE, 
  4.         .size = SYS_MEM_SIZE_DEFAULT, 
  5.     }, 
  6. }; 

 

看下物理內(nèi)存區(qū)VmPhysArea和物理內(nèi)存段的LosVmPhysSeg區(qū)別,前者信息教少,主要記錄開始地址和大小,為一塊物理內(nèi)存的最簡(jiǎn)單描述;后者除了物理內(nèi)存塊開始地址和大小,還維護(hù)物理頁開始地址,空閑物理頁伙伴鏈表,LRU鏈表,相應(yīng)的自旋鎖等信息。

上面提到了伙伴算法,先看下伙伴算法的示意圖,如下。每個(gè)物理內(nèi)存段都分割為一個(gè)一個(gè)的內(nèi)存頁,空閑的內(nèi)存頁掛載在空閑內(nèi)存頁節(jié)點(diǎn)鏈表上。共有9個(gè)空閑內(nèi)存頁節(jié)點(diǎn)鏈表,這些鏈表組成鏈表數(shù)組。第一個(gè)鏈表上的內(nèi)存頁節(jié)點(diǎn)大小為1個(gè)內(nèi)存頁,第二個(gè)鏈表上的內(nèi)存頁節(jié)點(diǎn)大小為2個(gè)內(nèi)存頁,第三個(gè)鏈表上的內(nèi)存頁節(jié)點(diǎn)大小為4個(gè)內(nèi)存頁,依次下去,第9個(gè)鏈表上的內(nèi)存頁節(jié)點(diǎn)大小為2^8個(gè)內(nèi)存頁。申請(qǐng)內(nèi)存、釋放內(nèi)存時(shí)會(huì)操作這些空閑內(nèi)存頁節(jié)點(diǎn)鏈表,后文詳細(xì)分析。

鴻蒙輕內(nèi)核A核源碼分析系列三 物理內(nèi)存(1)-鴻蒙HarmonyOS技術(shù)社區(qū)

1.3、物理內(nèi)存伙伴位圖

上文提到伙伴算法,還需要了解下伙伴位圖。在伙伴算法中,每個(gè)鏈表的索引都對(duì)應(yīng)一個(gè)位圖。 位圖的某位對(duì)應(yīng)于兩個(gè)伙伴塊,為1就表示其中一塊忙,為0表示兩塊都閑或都在使用 。系統(tǒng)每次分配和回收伙伴塊時(shí)都要對(duì)它們的伙伴位 跟1進(jìn)行異或運(yùn)算 。所謂異或是指剛開始時(shí),兩個(gè)伙伴塊都空閑,它們的伙伴位為0,如果其中一塊被使用,異或后得1;如果另一塊也被使用,異或后得0;如果前面一塊回收了異或后得1;如果另一塊也回收了異或后得0。位圖用于在釋放內(nèi)存頁塊時(shí),判斷兩塊內(nèi)存是否屬于地址連續(xù)的伙伴內(nèi)存塊。

在文件kernel/base/include/los_vm_phys.h中定義了2個(gè)比較重要的和伙伴位圖相關(guān)的宏,如下。⑴處的宏VM_ORDER_TO_PHYS(order)表示對(duì)應(yīng)每個(gè)空閑鏈表都有一個(gè)位來標(biāo)記伙伴內(nèi)存塊。⑵處宏VM_PHYS_TO_ORDER(phys)把物理內(nèi)存地址轉(zhuǎn)換為空閑鏈表索引。那么問題是,物理內(nèi)存地址和索引有對(duì)應(yīng)關(guān)系?物理地址已基于內(nèi)存頁大小進(jìn)行對(duì)齊。理論上這個(gè)值可大可小,不明白為什么這么設(shè)計(jì)?TODO。

 

  1. ⑴  #define VM_ORDER_TO_PHYS(order)  (1 << (PAGE_SHIFT + (order))) 
  2. ⑵  #define VM_PHYS_TO_ORDER(phys)   (min(LOS_LowBitGet((phys) >> PAGE_SHIFT), VM_LIST_ORDER_MAX - 1)) 

 

2、物理內(nèi)存管理模塊初始化

本節(jié)主要講解物理內(nèi)存管理模塊是如何初始化的,核心函數(shù)是OsVmPageStartup()。在講解之前,會(huì)先看下物理內(nèi)存初始化過程中的一些內(nèi)部函數(shù)。

2.1 物理內(nèi)存管理初始化內(nèi)部函數(shù)

2.1.1 函數(shù)OsVmPhysSegCreate

函數(shù)OsVmPhysSegCreate用于把指定的一個(gè)物理內(nèi)存區(qū)VmPhysArea轉(zhuǎn)換為物理內(nèi)存段LosVmPhysSeg。傳入的2個(gè)參數(shù)分別為物理內(nèi)存區(qū)的開始內(nèi)存地址和大小。⑴處表示系統(tǒng)支持的物理內(nèi)存段的數(shù)量為32個(gè),超過則轉(zhuǎn)換錯(cuò)誤。⑵處從物理內(nèi)存段全局?jǐn)?shù)組g_vmPhysSeg中獲取一個(gè)可用的物理內(nèi)存段。⑶處如果物理內(nèi)存段seg為數(shù)組g_vmPhysSeg中的第一個(gè)元素,則跳過循環(huán)體直接執(zhí)行⑸設(shè)置物理內(nèi)存段的開始地址和大小。如果不為第一個(gè)元素,并且前一個(gè)物理內(nèi)存段的開始地址在要轉(zhuǎn)換的物理內(nèi)存段的結(jié)束地址之后,則執(zhí)行⑷處代碼覆蓋前一個(gè)物理內(nèi)存段。在配置物理內(nèi)存區(qū)的時(shí)候,需要注意這里的影響。

 

  1. STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size
  2.     struct VmPhysSeg *seg = NULL
  3.  
  4. ⑴  if (g_vmPhysSegNum >= VM_PHYS_SEG_MAX) { 
  5.         return -1; 
  6.     } 
  7.  
  8. ⑵  seg = &g_vmPhysSeg[g_vmPhysSegNum++]; 
  9. ⑶  for (; (seg > g_vmPhysSeg) && ((seg - 1)->start > (start + size)); seg--) { 
  10. ⑷      *seg = *(seg - 1); 
  11.     } 
  12. ⑸  seg->start = start; 
  13.     seg->size = size
  14.  
  15.     return 0; 

函數(shù)OsVmPhysSegAdd調(diào)用上述函數(shù)OsVmPhysSegCreate依次把配置的多個(gè)物理內(nèi)存區(qū)一一進(jìn)行轉(zhuǎn)換,對(duì)于開發(fā)板hispark_taurus只配置了一塊物理內(nèi)存區(qū)域。

 

  1. VOID OsVmPhysSegAdd(VOID) 
  2.     INT32 i, ret; 
  3.  
  4.     LOS_ASSERT(g_vmPhysSegNum < VM_PHYS_SEG_MAX); 
  5.  
  6.     for (i = 0; i < (sizeof(g_physArea) / sizeof(g_physArea[0])); i++) { 
  7.         ret = OsVmPhysSegCreate(g_physArea[i].start, g_physArea[i].size); 
  8.         if (ret != 0) { 
  9.             VM_ERR("create phys seg failed"); 
  10.         } 
  11.     } 

 

2.1.2 函數(shù)OsVmPhysInit

函數(shù)OsVmPhysInit繼續(xù)初始化物理內(nèi)存段信息。⑴處循環(huán)物理內(nèi)存段數(shù)組,這里不是循環(huán)32次,而是多少個(gè)物理段就循環(huán)遍歷多少次。遍歷到每一個(gè)物理內(nèi)存段,然后執(zhí)行⑵設(shè)置當(dāng)前物理內(nèi)存段的第一個(gè)物理頁結(jié)構(gòu)體的地址,每一個(gè)物理內(nèi)存頁都有自己的結(jié)構(gòu)體LosVmPage,這些結(jié)構(gòu)體維護(hù)在通過malloc內(nèi)存堆申請(qǐng)的g_vmPageArray數(shù)組里,后文會(huì)詳細(xì)講述。⑶處seg->size >> PAGE_SHIFT計(jì)算當(dāng)前內(nèi)存段對(duì)于的內(nèi)存頁數(shù)量,然后更新nPages,這是后續(xù)物理內(nèi)存段第一個(gè)內(nèi)存頁對(duì)應(yīng)的的物理內(nèi)存頁結(jié)構(gòu)體在數(shù)組g_vmPageArray中索引。⑷處開始的函數(shù)OsVmPhysFreeListInit和OsVmPhysLruInit初始化伙伴雙向鏈表和LRU雙向鏈表,后續(xù)分析這2個(gè)函數(shù)。

 

  1. VOID OsVmPhysInit(VOID) 
  2.     struct VmPhysSeg *seg = NULL
  3.     UINT32 nPages = 0; 
  4.     int i; 
  5.  
  6.     for (i = 0; i < g_vmPhysSegNum; i++) { 
  7. ⑴      seg = &g_vmPhysSeg[i]; 
  8. ⑵      seg->pageBase = &g_vmPageArray[nPages]; 
  9. ⑶      nPages += seg->size >> PAGE_SHIFT; 
  10. ⑷      OsVmPhysFreeListInit(seg); 
  11.         OsVmPhysLruInit(seg); 
  12.     } 

 

2.1.3 函數(shù)OsVmPhysFreeListInit

每個(gè)物理內(nèi)存段使用9個(gè)空閑物理內(nèi)存頁節(jié)點(diǎn)鏈表來維護(hù)空閑物理內(nèi)存頁。OsVmPhysFreeListInit函數(shù)用于初始化指定物理內(nèi)存段的空閑物理內(nèi)存頁節(jié)點(diǎn)鏈表。操作前后需要開啟、關(guān)閉空閑鏈表自旋鎖。⑴處遍歷空閑物理內(nèi)存頁節(jié)點(diǎn)鏈表數(shù)組,然后執(zhí)行⑵初始化每個(gè)雙向鏈表。⑶處把每個(gè)鏈表中的空閑物理內(nèi)存頁的數(shù)量初始化為0。

 

  1. STATIC INLINE VOID OsVmPhysFreeListInit(struct VmPhysSeg *seg) 
  2.     int i; 
  3.     UINT32 intSave; 
  4.     struct VmFreeList *list = NULL
  5.  
  6.     LOS_SpinInit(&seg->freeListLock); 
  7.  
  8.     LOS_SpinLockSave(&seg->freeListLock, &intSave); 
  9.     for (i = 0; i < VM_LIST_ORDER_MAX; i++) { 
  10. ⑴      list = &seg->freeList[i]; 
  11. ⑵      LOS_ListInit(&list->node); 
  12. ⑶      list->listCnt = 0; 
  13.     } 
  14.     LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 

 

2.1.4 函數(shù)OsVmPhysLruInit

和上個(gè)函數(shù)類似,函數(shù)OsVmPhysLruInit初始化指定物理內(nèi)存段的LRU鏈表數(shù)組中的LRU鏈表。LRU鏈表分五類,由枚舉類型enum OsLruList定義。代碼較簡(jiǎn)單,讀者自行閱讀代碼即可。

 

  1. STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg) 
  2.     INT32 i; 
  3.     UINT32 intSave; 
  4.     LOS_SpinInit(&seg->lruLock); 
  5.  
  6.     LOS_SpinLockSave(&seg->lruLock, &intSave); 
  7.     for (i = 0; i < VM_NR_LRU_LISTS; i++) { 
  8.         seg->lruSize[i] = 0; 
  9.         LOS_ListInit(&seg->lruList[i]); 
  10.     } 
  11.     LOS_SpinUnlockRestore(&seg->lruLock, intSave); 

 

2.1.5 函數(shù)OsVmPageInit

函數(shù)OsVmPageInit用于初始化物理內(nèi)存頁的初始值,該函數(shù)需要3個(gè)參數(shù),分別是物理內(nèi)存頁結(jié)構(gòu)體地址,物理內(nèi)存頁的開始地址,物理內(nèi)存段編號(hào)。⑴處初始化內(nèi)存頁的鏈表節(jié)點(diǎn),這個(gè)鏈表節(jié)點(diǎn)通常會(huì)掛載在伙伴算法的空閑內(nèi)存頁節(jié)點(diǎn)鏈表上。⑵處設(shè)置內(nèi)存頁標(biāo)記為空閑內(nèi)存頁FILE_PAGE_FREE,該值由枚舉類型enum OsPageFlags定義。⑶處設(shè)置內(nèi)存頁的引用計(jì)數(shù)為0。⑷處設(shè)置內(nèi)存頁的開始地址。⑸處設(shè)置內(nèi)存頁所在的物理內(nèi)存段的編號(hào)。⑹處設(shè)置內(nèi)存頁順序order初始值,此時(shí)不屬于任何空閑內(nèi)存頁節(jié)點(diǎn)鏈表。⑺處設(shè)置內(nèi)存頁的nPages數(shù)值為0。⑻處的宏VMPAGEINIT調(diào)用函數(shù)OsVmPageInit并自動(dòng)增加內(nèi)存頁結(jié)構(gòu)體page地址和內(nèi)存頁pa地址。

 

  1. STATIC VOID OsVmPageInit(LosVmPage *page, paddr_t pa, UINT8 segID) 
  2. ⑴  LOS_ListInit(&page->node); 
  3. ⑵  page->flags = FILE_PAGE_FREE; 
  4. ⑶  LOS_AtomicSet(&page->refCounts, 0); 
  5. ⑷  page->physAddr = pa; 
  6. ⑸  page->segID = segID; 
  7. ⑹  page->order = VM_LIST_ORDER_MAX; 
  8. ⑺  page->nPages = 0; 
  9.  
  10. ... 
  11.      
  12. #define VMPAGEINIT(page, pa, segID) do {    \ 
  13. ⑻   OsVmPageInit(page, pa, segID);         \ 
  14.     (page)++;                               \ 
  15.     (pa) += PAGE_SIZE;                      \ 
  16. } while (0) 

 

2.2 物理內(nèi)存頁初始化函數(shù)VOID OsVmPageStartup(VOID)

了解上述幾個(gè)內(nèi)部函數(shù)后,我們正式開始閱讀物理內(nèi)存頁初始化函數(shù)VOID OsVmPageStartup(VOID)。系統(tǒng)在啟動(dòng)時(shí),該函數(shù)用于初始化物理內(nèi)存,把物理內(nèi)存段劃分割為為物理內(nèi)存頁。該函數(shù)被kernel/base/vm/los_vm_boot.c中的UINT32 OsSysMemInit(VOID)調(diào)用,進(jìn)一步被文件platform/los_config.c中的INT32 OsMain(VOID)函數(shù)調(diào)用。下面詳細(xì)分析下函數(shù)的代碼。

⑴處的g_vmBootMemBase初始值為(UINTPTR)&__bss_end,表示系統(tǒng)可用內(nèi)存在bss段之后;ROUNDUP用于內(nèi)存向上對(duì)齊。函數(shù)OsVmPhysAreaSizeAdjust()用于調(diào)整物理區(qū)的開始地址和大小。⑵處的 OsVmPhysPageNumGet()計(jì)算物理內(nèi)存段可以劃分多少物理內(nèi)存頁,此行代碼重新計(jì)算物理內(nèi)存頁數(shù)目,此時(shí)每個(gè)物理頁對(duì)應(yīng)一個(gè)物理頁結(jié)構(gòu)體,相應(yīng)結(jié)構(gòu)體也占用內(nèi)存空間。 ⑶處計(jì)算物理頁結(jié)構(gòu)體數(shù)組的大小,數(shù)組的每個(gè)元素對(duì)應(yīng)每個(gè)物理頁結(jié)構(gòu)體LosVmPage。接下來一行調(diào)用函數(shù)OsVmBootMemAlloc為物理頁結(jié)構(gòu)體數(shù)組g_vmPageArray申請(qǐng)內(nèi)存空間,申請(qǐng)的內(nèi)存空間從地址g_vmBootMemBase截取指定的長(zhǎng)度。⑷處再次調(diào)用函數(shù)OsVmPhysAreaSizeAdjust()用于調(diào)整物理內(nèi)存區(qū)的開始地址和大小,確保基于內(nèi)存頁對(duì)齊。⑸處調(diào)用函數(shù)OsVmPhysSegAdd()轉(zhuǎn)換為物理內(nèi)存段,⑹處調(diào)用OsVmPhysInit函數(shù)初始化物理內(nèi)存段的空閑物理內(nèi)存頁節(jié)點(diǎn)鏈表和LRU鏈表。上文分析過這幾個(gè)內(nèi)部函數(shù)。⑺處遍歷每個(gè)物理內(nèi)存段,獲取遍歷到的物理內(nèi)存段的總頁數(shù)nPage。⑻處為提升初始化物理內(nèi)存頁的性能,把頁數(shù)分為8份,count為每份的內(nèi)存頁的數(shù)目,left為等分為8份后剩余的內(nèi)存頁數(shù)。⑼處循環(huán)初始化物理內(nèi)存頁,⑽處初始化剩余的物理內(nèi)存頁。⑾處的函數(shù)OsVmPageOrderListInit把物理內(nèi)存頁插入到空閑內(nèi)存頁節(jié)點(diǎn)鏈表,該函數(shù)進(jìn)一步調(diào)用OsVmPhysPagesFreeContiguous函數(shù),后續(xù)再分析該函數(shù)。初始化完成后,物理內(nèi)存段上的內(nèi)存頁都掛載到空閑內(nèi)存頁節(jié)點(diǎn)鏈表上了。

 

  1. VOID OsVmPageStartup(VOID) 
  2.     struct VmPhysSeg *seg = NULL
  3.     LosVmPage *page = NULL
  4.     paddr_t pa; 
  5.     UINT32 nPage; 
  6.     INT32 segID; 
  7.  
  8. ⑴  OsVmPhysAreaSizeAdjust(ROUNDUP((g_vmBootMemBase - KERNEL_ASPACE_BASE), PAGE_SIZE)); 
  9.  
  10.     /* 
  11.      * Pages getting from OsVmPhysPageNumGet() interface here contain the memory 
  12.      * struct LosVmPage occupied, which satisfies the equation: 
  13.      * nPage * sizeof(LosVmPage) + nPage * PAGE_SIZE = OsVmPhysPageNumGet() * PAGE_SIZE. 
  14.      */ 
  15. ⑵  nPage = OsVmPhysPageNumGet() * PAGE_SIZE / (sizeof(LosVmPage) + PAGE_SIZE); 
  16. ⑶  g_vmPageArraySize = nPage * sizeof(LosVmPage); 
  17.     g_vmPageArray = (LosVmPage *)OsVmBootMemAlloc(g_vmPageArraySize); 
  18.  
  19. ⑷  OsVmPhysAreaSizeAdjust(ROUNDUP(g_vmPageArraySize, PAGE_SIZE)); 
  20.  
  21. ⑸  OsVmPhysSegAdd(); 
  22. ⑹  OsVmPhysInit(); 
  23.  
  24.     for (segID = 0; segID < g_vmPhysSegNum; segID++) { 
  25. ⑺      seg = &g_vmPhysSeg[segID]; 
  26.         nPage = seg->size >> PAGE_SHIFT; 
  27. ⑻      UINT32 count = nPage >> 3; /* 3: 2 ^ 3, nPage / 8, cycle count */ 
  28.         UINT32 left = nPage & 0x7; /* 0x7: nPage % 8, left page */ 
  29.  
  30. ⑼      for (page = seg->pageBase, pa = seg->start; count > 0; count--) { 
  31.             /* note: process large amount of data, optimize performance */ 
  32.             VMPAGEINIT(page, pa, segID); 
  33.             VMPAGEINIT(page, pa, segID); 
  34.             VMPAGEINIT(page, pa, segID); 
  35.             VMPAGEINIT(page, pa, segID); 
  36.             VMPAGEINIT(page, pa, segID); 
  37.             VMPAGEINIT(page, pa, segID); 
  38.             VMPAGEINIT(page, pa, segID); 
  39.             VMPAGEINIT(page, pa, segID); 
  40.         } 
  41.         for (; left > 0; left--) { 
  42. ⑽          VMPAGEINIT(page, pa, segID); 
  43.         } 
  44. ⑾      OsVmPageOrderListInit(seg->pageBase, nPage); 
  45.     } 

3、物理內(nèi)存管理模塊接口

學(xué)習(xí)過物理內(nèi)存初始化后,接下來我們會(huì)分析物理內(nèi)存管理模塊的接口函數(shù),包含申請(qǐng)、釋放、查詢等功能接口。

3.1 申請(qǐng)物理內(nèi)存頁接口

3.1.1 申請(qǐng)物理內(nèi)存頁接口介紹

申請(qǐng)物理內(nèi)存頁的接口有3個(gè),分別用于滿足不同的申請(qǐng)需求。LOS_PhysPagesAllocContiguous函數(shù)的傳入?yún)?shù)為要申請(qǐng)物理內(nèi)存頁的數(shù)目,返回值為申請(qǐng)到的物理內(nèi)存頁對(duì)應(yīng)的內(nèi)核虛擬地址空間中的虛擬內(nèi)存地址。⑴處調(diào)用函數(shù)OsVmPhysPagesGet申請(qǐng)指定數(shù)目的物理內(nèi)存頁,然后⑵處調(diào)用函數(shù)OsVmPageToVaddr轉(zhuǎn)換為內(nèi)核虛擬內(nèi)存地址。函數(shù)LOS_PhysPageAlloc申請(qǐng)一個(gè)物理內(nèi)存頁,返回值為申請(qǐng)到的物理頁對(duì)應(yīng)的物理頁結(jié)構(gòu)體地址。代碼比較簡(jiǎn)單,見⑶處,調(diào)用函數(shù)OsVmPageToVaddr傳入ONE_PAGE參數(shù)申請(qǐng)1個(gè)物理內(nèi)存頁。函數(shù)LOS_PhysPagesAlloc用于申請(qǐng)nPages個(gè)物理內(nèi)存頁,并掛在雙向鏈表list上,返回值為實(shí)際申請(qǐng)到的物理頁數(shù)目。⑷處循環(huán)調(diào)用函數(shù)OsVmPhysPagesGet()申請(qǐng)一個(gè)物理內(nèi)存頁,如果申請(qǐng)成功不為空,則插入到雙向鏈表,申請(qǐng)成功的物理頁的數(shù)目加1;如果申請(qǐng)失敗則跳出循環(huán)。⑹返回實(shí)際申請(qǐng)到的物理頁的數(shù)目。

 

  1. VOID *LOS_PhysPagesAllocContiguous(size_t nPages) 
  2.     LosVmPage *page = NULL
  3.  
  4.     if (nPages == 0) { 
  5.         return NULL
  6.     } 
  7.  
  8. ⑴  page = OsVmPhysPagesGet(nPages); 
  9.     if (page == NULL) { 
  10.         return NULL
  11.     } 
  12.  
  13. ⑵   return OsVmPageToVaddr(page); 
  14. ...... 
  15.      
  16. LosVmPage *LOS_PhysPageAlloc(VOID) 
  17. ⑶   return OsVmPhysPagesGet(ONE_PAGE); 
  18.  
  19. size_t LOS_PhysPagesAlloc(size_t nPages, LOS_DL_LIST *list) 
  20.     LosVmPage *page = NULL
  21.     size_t count = 0; 
  22.  
  23.     if ((list == NULL) || (nPages == 0)) { 
  24.         return 0; 
  25.     } 
  26.  
  27.     while (nPages--) { 
  28. ⑷      page = OsVmPhysPagesGet(ONE_PAGE); 
  29.         if (page == NULL) { 
  30.             break; 
  31.         } 
  32. ⑸      LOS_ListTailInsert(list, &page->node); 
  33.         count++; 
  34.     } 
  35.  
  36. ⑹   return count

3.1.2 申請(qǐng)物理內(nèi)存頁內(nèi)部接口實(shí)現(xiàn)

3個(gè)內(nèi)存頁申請(qǐng)函數(shù)都調(diào)用了函數(shù)OsVmPhysPagesGet,下文會(huì)詳細(xì)分析申請(qǐng)物理內(nèi)存頁內(nèi)部接口實(shí)現(xiàn)。

3.1.2.1 函數(shù)OsVmPhysPagesGet

函數(shù)OsVmPhysPagesGet用于申請(qǐng)指定數(shù)量的物理內(nèi)存頁,返回值為物理內(nèi)存頁結(jié)構(gòu)體地址。⑴處遍歷物理內(nèi)存段數(shù)組,對(duì)遍歷到的物理內(nèi)存段執(zhí)行⑵處代碼,調(diào)用函數(shù)OsVmPhysPagesAlloc()從指定的內(nèi)存段中申請(qǐng)指定數(shù)目的物理內(nèi)存頁。如果申請(qǐng)成功,則執(zhí)行⑶把內(nèi)存頁的引用計(jì)數(shù)初始化為0,根據(jù)注釋,如果是連續(xù)的內(nèi)存頁,則第一個(gè)內(nèi)存頁持有引用計(jì)數(shù)數(shù)值。接下來以后更新內(nèi)存頁的數(shù)量,并返回申請(qǐng)到的內(nèi)存頁的結(jié)構(gòu)體地址;如果申請(qǐng)失敗則繼續(xù)循環(huán)申請(qǐng)或者返回NULL。

 

  1. STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages) 
  2.     UINT32 intSave; 
  3.     struct VmPhysSeg *seg = NULL
  4.     LosVmPage *page = NULL
  5.     UINT32 segID; 
  6.  
  7.     for (segID = 0; segID < g_vmPhysSegNum; segID++) { 
  8. ⑴      seg = &g_vmPhysSeg[segID]; 
  9.         LOS_SpinLockSave(&seg->freeListLock, &intSave); 
  10. ⑵      page = OsVmPhysPagesAlloc(seg, nPages); 
  11.         if (page != NULL) { 
  12.             /* the first page of continuous physical addresses holds refCounts */ 
  13. ⑶          LOS_AtomicSet(&page->refCounts, 0); 
  14.             page->nPages = nPages; 
  15.             LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  16.             return page; 
  17.         } 
  18.         LOS_SpinUnlockRestore(&seg->freeListLock, intSave); 
  19.     } 
  20.     return NULL

3.1.2.2 函數(shù)OsVmPhysPagesAlloc

從上文的介紹,我們知道物理內(nèi)存段包含一個(gè)空閑內(nèi)存頁節(jié)點(diǎn)鏈表數(shù)組,數(shù)組大小為9。數(shù)組中的每個(gè)鏈表上的內(nèi)存頁節(jié)點(diǎn)的大小等于2的冪次方個(gè)內(nèi)存頁,例如:第0個(gè)鏈表上掛載的空閑內(nèi)存節(jié)點(diǎn)的大小為2的0次方個(gè)內(nèi)存頁,即1個(gè)內(nèi)存頁;第8個(gè)鏈表上掛載的內(nèi)存頁節(jié)點(diǎn)的大小為2的8次方個(gè)內(nèi)存頁,即256個(gè)內(nèi)存頁。相同大小的內(nèi)存塊掛在同一個(gè)鏈表上進(jìn)行管理。

分析函數(shù)OsVmPhysPagesAlloc之前,先看下函數(shù)OsVmPagesToOrder,該函數(shù)根據(jù)指定的物理頁的數(shù)目計(jì)算屬于空閑內(nèi)存頁節(jié)點(diǎn)鏈表數(shù)組中的第幾個(gè)雙向鏈表。當(dāng)nPages為最小1時(shí),order取值為0;當(dāng)為2時(shí),order取值1…等于取底為2的對(duì)數(shù)Log2(nPages)。

 

  1. #define VM_ORDER_TO_PAGES(order) (1 << (order)) 
  2. ...... 
  3. UINT32 OsVmPagesToOrder(size_t nPages) 
  4.     UINT32 order
  5.  
  6.     for (order = 0; VM_ORDER_TO_PAGES(order) < nPages; order++); 
  7.  
  8.     return order

 

繼續(xù)分析下函數(shù)OsVmPhysPagesAlloc(),該函數(shù)基于傳入?yún)?shù)從指定的內(nèi)存段申請(qǐng)指定數(shù)目的內(nèi)存頁。⑴處調(diào)用的函數(shù)上文已經(jīng)講述,根據(jù)內(nèi)存頁數(shù)目計(jì)算出鏈表數(shù)組索引值。如果索引值小于鏈表最大索引值VM_LIST_ORDER_MAX,則執(zhí)行⑵從小內(nèi)存頁節(jié)點(diǎn)向大內(nèi)存頁節(jié)點(diǎn)循環(huán)各個(gè)雙向鏈表。⑶處獲取雙向鏈表,如果空閑鏈表為空則繼續(xù)循環(huán);如果不為空,則執(zhí)行⑷獲取鏈表上的空閑內(nèi)存頁結(jié)構(gòu)體。

如果根據(jù)內(nèi)存頁數(shù)計(jì)算出的數(shù)組索引值大于等于鏈表最大索引值VM_LIST_ORDER_MAX,說明空閑鏈表上并沒有這么大塊的內(nèi)存頁節(jié)點(diǎn),需要從物理內(nèi)存段上申請(qǐng),需要執(zhí)行⑸調(diào)用函數(shù)OsVmPhysLargeAlloc()申請(qǐng)大的內(nèi)存頁。如果申請(qǐng)不到內(nèi)存頁則申請(qǐng)失敗,返回NULL;如果申請(qǐng)到合適的內(nèi)存頁,則繼續(xù)執(zhí)行后續(xù)DONE標(biāo)簽代碼。這些代碼從空閑鏈表中刪除,拆分,多余的空閑內(nèi)存頁插入空閑鏈表等,后文繼續(xù)分析調(diào)用的這些函數(shù)。先看下這些參數(shù)的實(shí)際傳入?yún)?shù),order為要申請(qǐng)的內(nèi)存頁對(duì)應(yīng)的鏈表數(shù)組索引,newOrder為實(shí)際申請(qǐng)的內(nèi)存頁對(duì)應(yīng)的鏈表數(shù)組索引。⑹處的for循環(huán)條件中,&page[nPages]為需要申請(qǐng)的內(nèi)存頁結(jié)構(gòu)體的結(jié)束地址,&tmp[1 << newOrder]表示伙伴算法中空閑內(nèi)存頁節(jié)點(diǎn)鏈表上的內(nèi)存塊的結(jié)束地址。這里為啥使用for循環(huán)呢,上面申請(qǐng)內(nèi)存時(shí),應(yīng)該申請(qǐng)了多個(gè)內(nèi)存節(jié)點(diǎn)拼接起來了。看下⑺處的函數(shù)的傳入?yún)?shù),&page[nPages]為需要申請(qǐng)的內(nèi)存頁結(jié)構(gòu)體的結(jié)束地址,往后的部分被拆分放入空閑鏈表。(1 << min(order, newOrder))表示實(shí)際申請(qǐng)的內(nèi)存頁的數(shù)目。

 

  1. STATIC LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages) 
  2.     struct VmFreeList *list = NULL
  3.     LosVmPage *page = NULL
  4.     LosVmPage *tmp = NULL
  5.     UINT32 order
  6.     UINT32 newOrder; 
  7.  
  8. ⑴  order = OsVmPagesToOrder(nPages); 
  9.     if (order < VM_LIST_ORDER_MAX) { 
  10. ⑵      for (newOrder = order; newOrder < VM_LIST_ORDER_MAX; newOrder++) { 
  11. ⑶          list = &seg->freeList[newOrder]; 
  12.             if (LOS_ListEmpty(&list->node)) { 
  13.                 continue
  14.             } 
  15. ⑷          page = LOS_DL_LIST_ENTRY(LOS_DL_LIST_FIRST(&list->node), LosVmPage, node); 
  16.             goto DONE; 
  17.         } 
  18.     } else { 
  19.         newOrder = VM_LIST_ORDER_MAX - 1; 
  20. ⑸      page = OsVmPhysLargeAlloc(seg, nPages); 
  21.         if (page != NULL) { 
  22.             goto DONE; 
  23.         } 
  24.     } 
  25.     return NULL
  26. DONE: 
  27.  
  28.     for (tmp = page; tmp < &page[nPages]; tmp = &tmp[1 << newOrder]) { 
  29. ⑹       OsVmPhysFreeListDelUnsafe(tmp); 
  30.     } 
  31.     OsVmPhysPagesSpiltUnsafe(page, order, newOrder); 
  32. ⑺  OsVmRecycleExtraPages(&page[nPages], nPages, ROUNDUP(nPages, (1 << min(order, newOrder)))); 
  33.  
  34.     return page; 

想了解更多內(nèi)容,請(qǐng)?jiān)L問:

51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)

https://harmonyos.51cto.com

 

責(zé)任編輯:jianghua 來源: 鴻蒙社區(qū)
相關(guān)推薦

2021-11-08 15:06:15

鴻蒙HarmonyOS應(yīng)用

2021-12-03 16:20:26

鴻蒙HarmonyOS應(yīng)用

2021-05-17 09:28:59

鴻蒙HarmonyOS應(yīng)用

2022-03-11 20:23:14

鴻蒙源碼分析進(jìn)程管理

2022-03-03 18:28:28

Harmony進(jìn)程任務(wù)管理模塊

2022-04-13 11:02:12

鴻蒙事件模塊事件Event

2022-03-31 16:26:49

鴻蒙源碼分析進(jìn)程管理

2021-05-21 09:25:11

鴻蒙HarmonyOS應(yīng)用

2022-01-10 15:31:44

鴻蒙HarmonyOS應(yīng)用

2022-01-12 10:50:23

鴻蒙HarmonyOS應(yīng)用

2021-06-04 09:57:49

鴻蒙HarmonyOS應(yīng)用

2021-06-04 14:15:10

鴻蒙HarmonyOS應(yīng)用

2021-05-08 15:14:50

鴻蒙HarmonyOS應(yīng)用

2022-04-13 11:12:43

鴻蒙輕內(nèi)核信號(hào)量模塊操作系統(tǒng)

2021-10-20 16:08:57

鴻蒙HarmonyOS應(yīng)用

2021-05-25 09:28:34

鴻蒙HarmonyOS應(yīng)用

2021-05-10 15:05:56

鴻蒙HarmonyOS應(yīng)用

2021-12-01 15:59:22

鴻蒙HarmonyOS應(yīng)用

2021-05-31 20:30:55

鴻蒙HarmonyOS應(yīng)用

2021-06-17 09:36:07

鴻蒙HarmonyOS應(yīng)用
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

欧美人与禽zoz0善交| 人妻少妇被粗大爽9797pw| 精品人妻一区二区三区含羞草| 亚洲va在线| 精品国产一区a| av免费在线播放网站| gogo在线高清视频| aaa欧美色吧激情视频| 国产97在线视频| 欧美黄色一级网站| 精品日本12videosex| 日韩三区在线观看| 男人天堂成人在线| 欧美wwww| av女在线播放| 国产一区二区三区四区五区传媒| 欧美三级在线播放| 欧美国产日韩激情| 97在线观看免费观看高清| 国产999精品久久久久久| 国产精品福利在线| 国产精品久久久久久久妇| 国产韩日影视精品| 亚洲人成电影网站| 性农村xxxxx小树林| 日韩黄色碟片| 日本精品一区二区三区四区的功能| 熟妇熟女乱妇乱女网站| 国产在线黄色| 91视视频在线观看入口直接观看www | 国产亚洲一区| 亚洲成人中文字幕| 亚洲免费成人在线视频| 欧美天堂视频| 激情久久av一区av二区av三区| 色吧影院999| 久久久国产精品无码| 国产精品视频一区二区三区| 一本大道久久a久久精品综合| 屁屁影院ccyy国产第一页| 欧美尤物美女在线| 国产精品天干天干在观线| 狼狼综合久久久久综合网| 亚洲av无码国产精品永久一区| 蜜臀久久99精品久久久画质超高清 | 亚洲字幕av一区二区三区四区| 亚洲黄色高清| 欧美国产第二页| 91高清免费看| 婷婷色综合网| 久久精品视频一| 久久视频一区二区三区| 精品视频日韩| 亚洲一品av免费观看| 亚洲天堂网一区二区| 精品视频高潮| 亚洲电影免费观看高清完整版在线观看 | 国产cdts系列另类在线观看| 亚洲国产精品二十页| 色视频一区二区三区| 高清中文字幕一区二区三区| 久久嫩草精品久久久精品一| 美女视频久久| 黄色av网址在线免费观看| 久久久五月婷婷| 欧美精品人人做人人爱视频| 国产在线自天天| 国产欧美日韩麻豆91| 欧美成熟毛茸茸复古| 男人天堂亚洲二区| 国产精品视频在线看| 蜜桃传媒一区二区| 日产精品久久久久久久性色| 久久精品水蜜桃av综合天堂| 日韩av电影免费观看| 91激情在线| 一区二区三区自拍| 国产香蕉精品视频一区二区三区 | 在线视频日韩一区| 久久天堂影院| 在线播放中文一区| 香蕉在线观看视频| 少妇精品导航| 中文字幕视频在线免费欧美日韩综合在线看 | 国产精品不卡av| 99在线热播精品免费99热| 国产精品成人观看视频国产奇米| 真实新婚偷拍xxxxx| 国产一区中文字幕| 久久精品日产第一区二区三区乱码 | 亚洲欧美在线免费观看| 国产不卡在线观看视频| 欧美久久成人| 日本伊人精品一区二区三区介绍| 伊人影院中文字幕| 成人av网站免费观看| 日本高清久久一区二区三区| av在线免费网站| 欧美日韩一二三四五区| 岛国av在线免费| 久久久久高潮毛片免费全部播放| 在线精品高清中文字幕| 青娱乐国产盛宴| 日韩黄色在线观看| 97久久精品午夜一区二区| 神马精品久久| 亚洲蜜臀av乱码久久精品 | 日本片在线看| 欧美性色综合网| 久久久久亚洲av无码专区首jn| 国产欧美日韩精品一区二区免费 | 久久久久人妻一区精品色| 亚洲小说欧美另类婷婷| 国产精品一区二区三区久久| 少妇高潮喷水久久久久久久久久| 青青草视频在线免费观看| 中文字幕一区二区不卡 | 欧美专区一区二区三区| 亚洲在线免费视频| 国产福利在线| 黑人巨大精品欧美一区免费视频| 两性午夜免费视频| 精品久久久久久久| 97在线视频观看| 朝桐光av在线一区二区三区| 亚洲国产成人午夜在线一区| 成熟丰满熟妇高潮xxxxx视频| 精品国产亚洲一区二区三区在线| 一区二区三区视频观看| 五月婷婷色丁香| 成人妖精视频yjsp地址| 在线观看视频黄色| 亚洲a成人v| 色七七影院综合| 欧美性受xxx黑人xyx性爽| 99re66热这里只有精品3直播| 国产a级黄色大片| www久久久| 日韩在线视频二区| 最近中文字幕在线视频| 久久精品一区八戒影视| 国产日产欧美视频| 校花撩起jk露出白色内裤国产精品| 欧美高清视频免费观看| 亚洲AV无码乱码国产精品牛牛 | 精品一区二区成人精品| 日韩在线导航| 国产亚洲一区二区手机在线观看 | 三级网站在线免费观看| аⅴ资源新版在线天堂| 亚洲高清在线| www.久久草| www视频在线看| 555www色欧美视频| 疯狂试爱三2浴室激情视频| 黄色日韩网站视频| 国产又爽又黄ai换脸| 欧美综合影院| 久久亚洲精品成人| av在线资源观看| 亚洲激情图片一区| 免费观看黄网站| 欧美成人app| 亚洲深夜福利视频| 在线观看你懂的网站| 国产精品欧美一级免费| 亚洲第一成肉网| 欧美国产三区| 97国产精品视频人人做人人爱| 性生活黄色大片| 午夜精品一区二区三区免费视频| fc2成人免费视频| 国产视频一区免费看| 品久久久久久久久久96高清| 欧美xnxx| 美女精品久久久| 成人午夜福利视频| 欧美激情一区二区三区全黄 | 福利视频第一页| 国产一区二区精品在线观看| 国产精品无码免费专区午夜| 欧美变态网站| 国产精品久久77777| a级网站在线播放| 国产午夜精品久久久| 中文字字幕在线中文乱码| 亚洲精品视频免费观看| av鲁丝一区鲁丝二区鲁丝三区| 日韩av午夜在线观看| 男女激烈动态图| 日日天天久久| 成人字幕网zmw| 国产乱码午夜在线视频| 在线不卡国产精品| 黄色片一区二区| 欧美在线观看禁18| 国产无码精品一区二区| 欧美国产精品中文字幕| 日韩久久久久久久久久久| 欧美一级网站| 国产精品8888| 欧美色图国产精品| 国产欧美在线| 肥熟一91porny丨九色丨| 欧美xxxxxx| 欧美激情手机在线视频| 超碰免费在线观看| 亚洲黄色www网站| 国产精品视频第一页| 色综合色狠狠天天综合色| 精品国产乱码久久久久久鸭王1| 久久久久国产精品麻豆| 亚洲911精品成人18网站| 奇米色一区二区三区四区| 国产在线播放观看| 亚欧美无遮挡hd高清在线视频| 久久九九视频| 91午夜精品| 久热精品视频在线观看| 水莓100在线视频| 欧美一区二区视频在线观看| 一级久久久久久| 精品久久久久久国产91| 永久看片925tv| 中文字幕乱码久久午夜不卡| 国产在线观看无码免费视频| 国产91精品免费| 五月天六月丁香| 免费成人美女在线观看.| 乱子伦视频在线看| 国产精品嫩草99av在线| 久久久久久久9| 欧美88av| 中文字幕色呦呦| 91精品国产乱码久久久久久| 午夜精品区一区二区三| 久久99高清| 欧美一区二区在线| 欧美热在线视频精品999| 久久精品一区二区三区不卡免费视频 | 五月婷婷伊人网| 亚洲第一黄色网| 97精品在线视频| 午夜成人鲁丝片午夜精品| 精品国产亚洲在线| 亚洲女同志亚洲女同女播放| 日韩欧美国产一区二区三区| 亚洲高清精品视频| 精品国产三级a在线观看| 国产黄色大片网站| 精品久久五月天| 人妻少妇精品无码专区| 亚洲电影中文字幕| 污污视频在线免费看| 日韩成人高清在线| 青青草视频免费在线观看| 亚洲免费av网址| 成人影视在线播放| 精品国偷自产在线| av黄色在线| 久久久人成影片一区二区三区| aa国产成人| 国产成人综合久久| 日韩一区二区三免费高清在线观看| 国产主播精品在线| 日韩三级不卡| 国精产品一区二区| 精品国产不卡| 手机成人av在线| 国产精品久久| 少妇高清精品毛片在线视频| 蜜臀av性久久久久av蜜臀妖精| 中文字幕 欧美日韩| 丁香婷婷综合网| 国产特黄级aaaaa片免| 国产精品久久久久久久蜜臀| 亚洲精品卡一卡二| 亚洲成人av一区| 亚洲中文字幕无码爆乳av| 欧美日韩国产经典色站一区二区三区| 国产情侣在线播放| 精品视频在线播放色网色视频| 成人免费在线视频网| 精品中文字幕视频| 亚洲最大成人| 亚洲自拍偷拍色图| 综合国产视频| 中文字幕乱码一区二区三区| 亚洲福利专区| 97超碰人人爽| 91在线porny国产在线看| 永久免费看片直接| av午夜在线| 国产亚洲欧美日韩一区二区| 欧美精品日韩少妇| 91高清在线免费观看| 久久亚洲人体| 久久精品国产精品国产精品污 | 夜夜嗨av一区二区三区免费区 | 欧美性受xxx| 国产精久久久| 欧美精品久久久| 黄色亚洲精品| 成 人 黄 色 小说网站 s色| 成人国产精品免费观看动漫| 天堂网av2018| 精品成人国产在线观看男人呻吟| 中文字幕日本人妻久久久免费| 欧美大片在线观看| 在线国产91| 欧美专区日韩视频| 综合中文字幕| 黄瓜视频免费观看在线观看www | 97超碰色婷婷| 久久av网站| 午夜精品亚洲一区二区三区嫩草| 在线精品在线| 青娱乐精品在线| 国产精品水嫩水嫩| 毛片在线免费播放| 亚洲精品国产精品国自产在线 | 亚洲视频在线观看三级| 加勒比在线一区| 亚洲精品一区二区三区影院| 麻豆视频免费在线播放| 99国产精品久久久久久久成人热| 性生活免费在线观看| 91一区二区在线| 久久精品视频9| 日韩一级黄色片| 久久日韩视频| 成人妇女免费播放久久久| sdde在线播放一区二区| 久久久久免费精品| 久久久五月婷婷| 国产做受高潮漫动| 亚洲国产三级网| 国内激情视频在线观看| 国产精品裸体一区二区三区| 欧美阿v一级看视频| 色偷偷中文字幕| 亚洲人被黑人高潮完整版| 91精品国产乱码久久| 色综合亚洲精品激情狠狠| 国产精品美女午夜爽爽| 亚洲欧美久久234| 日本女优在线视频一区二区| 国产熟女一区二区| 欧美三级日韩三级国产三级| 岛国大片在线观看| 国产精品露脸av在线| 色88久久久久高潮综合影院| 超碰在线播放91| 亚洲欧美在线aaa| 精品人妻无码一区二区| 国语自产在线不卡| 欧美a一欧美| 91视频免费版污| 国产精品成人午夜| 国产sm主人调教女m视频| 欧美疯狂xxxx大交乱88av| 国产伦精品一区二区三区在线播放| 国产aaa免费视频| 91在线国产福利| 色老头一区二区| 北条麻妃久久精品| 日本成人精品| 欧美性久久久久| 欧美国产精品久久| a视频免费在线观看| 久久久亚洲影院你懂的| 希岛爱理av免费一区二区| 欧美精品性生活| 亚洲免费电影在线| 天天操天天干天天插| 国产成人精品综合久久久| 天天射综合网视频| 最新版天堂资源在线| 日本韩国精品一区二区在线观看| 尤物在线视频| 国产伦精品一区二区三区四区视频 | 日韩中文在线不卡| 98视频精品全部国产| 欧美 激情 在线| 亚洲欧美激情插| 天堂成人在线| 成人免费视频网址| 中文在线不卡| 91嫩草丨国产丨精品| 亚洲精品天天看| 日本精品一区二区三区在线观看视频| 男人添女人下面高潮视频| 中文字幕亚洲视频| 午夜福利一区二区三区| 91美女福利视频高清| 免费永久网站黄欧美| 成人观看免费视频| 亚洲网站视频福利| 国产日韩三级| 欧美一级xxxx|