天天看點

QEMU分頁機制分析1 qemu頁面層次劃分2 頁的查找與配置設定

1 qemu頁面層次劃分

qemu通過定義一些宏靈活地進行分頁,首先由宏TARGET_PAGE_BITS(12)确定頁的大小,然後根據目标機的實體位址空間和主控端的字長确定P_L1_BITS和V_L1_BITS,進而使得剩餘部分可以被L2_BITS均分。那麼如何确定P_L1_BITS和V_L1_BITS的值呢?先看下面兩個宏定義:

#define P_L1_BITS_REM \

((TARGET_PHYS_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS)

#define V_L1_BITS_REM \

((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS)

這兩個宏确定了按照L2_BITS大小均分後剩餘的bit數。

再看P_L1_BITS的定義,它取決于P_L1_BITS_REM的大小,這麼做得目的就是既能保證除去L1層之後,剩餘長度的頁面可以按照L2_BITS大小均分,也避免了L1頁面尺寸太小,降低了通路效率。

#if P_L1_BITS_REM < 4

#define P_L1_BITS (P_L1_BITS_REM + L2_BITS)

#else

#define P_L1_BITS P_L1_BITS_REM

#endif

V_L1_BITS定義的思想與P_L1_BITS完全一緻,如下:

#if V_L1_BITS_REM < 4

#define V_L1_BITS (V_L1_BITS_REM + L2_BITS)

#else

#define V_L1_BITS V_L1_BITS_REM

#endif

P_L1_SHIFT和V_L1_SHIFT分别表示除去L1層與頁寬後剩餘的實體空間與虛拟位址寬度。從P_L1_BITS與V_L1_BITS定義不難看出這兩個宏模L2_BITS的值恰好為0。

#define P_L1_SHIFT (TARGET_PHYS_ADDR_SPACE_BITS - TARGET_PAGE_BITS - P_L1_BITS)

#define V_L1_SHIFT (L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)

2 頁的查找與配置設定

這裡以虛拟頁的查找與配置設定為例進行說明,L1層采用靜态配置設定,最底層是指向PageDesc的指針。

static void *l1_map[V_L1_SIZE];

static PageDesc *page_find_alloc(tb_page_addr_t index, int alloc)

{//假如頁位址為addr,參數index為addr >> TARGET_PAGE_BITS

//參數alloc非零時表示待查找的頁不存在時動态進行配置設定,否則傳回NULL

PageDesc *pd;

void **lp;

int i;

...

//找出indexL1層對應的位置

lp = l1_map + ((index >> V_L1_SHIFT) & (V_L1_SIZE - 1));

//最底層頁面配置設定的是PageDesc元素,是以需單獨處理

for (i = V_L1_SHIFT / L2_BITS - 1; i > 0; i--) {

void **p = *lp;

if (p == NULL) {

if (!alloc) {

return NULL;

}

ALLOC(p, sizeof(void *) * L2_SIZE);

*lp = p;

}

lp = p + ((index >> (i * L2_BITS)) & (L2_SIZE - 1));

}

pd = *lp;

if (pd == NULL) {

if (!alloc) {

return NULL;

}

ALLOC(pd, sizeof(PageDesc) * L2_SIZE);//動态配置設定最底層頁面

*lp = pd;

}

#undef ALLOC

//傳回最底層頁面相應位置的PageDesc指針

return pd + (index & (L2_SIZE - 1));

}

下面舉例說明一下,假設L1_MAP_ADDR_SPACE_BITS為32,那麼

V_L1_BITS_REM=((L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS) % L2_BITS)=0.

V_L1_BITS=L2_BITS

V_L1_SHIFT=(L1_MAP_ADDR_SPACE_BITS - TARGET_PAGE_BITS - V_L1_BITS)=10

調用page_find_alloc函數時,如果參數alloc非零,其中的for循環不會執行,因為

i = V_L1_SHIFT / L2_BITS - 1=0,不滿足i>0的條件。

這時我們可以看到32位虛位址空間的頁共配置設定了兩層,第一層大小為2^10,其内容是指向下一層的指針;第二層大小也為2^10,其内容是PageDesc;

qemu的這種實作方法可以相容各種長度的宿主與目标機長度,程式代碼不用做任何修改。

繼續閱讀