提取标志的位操作为24位整数

时间:2013-12-31 17:54:08

标签: c linux-kernel

我在xen的内核代码(文件:xen / include / asm-x86 / x86_64 / page.h)中看到一行,但无法理解为什么他们这样做:

/* Extract flags into 24-bit integer, or turn 24-bit flags into a pte mask. */                                                                      
#define get_pte_flags(x) (((int)((x) >> 40) & ~0xFFF) | ((int)(x) & 0xFFF))                                                                         
#define put_pte_flags(x) (((intpte_t)((x) & ~0xFFF) << 40) | ((x) & 0xFFF))     

至于

#define get_pte_flags(x) (((int)((x) >> 40) & ~0xFFF) | ((int)(x) & 0xFFF)) 

我理解((int)(x) & 0xFFF)会提取x的最后24位,但为什么需要第一部分((int)((x) >> 40) & ~0xFFF)

至于

  #define put_pte_flags(x) (((intpte_t)((x) & ~0xFFF) << 40) | ((x) & 0xFFF))  

我迷失在((intpte_t)((x) & ~0xFFF) << 40)的目的。在我看来它应该是0。那我们为什么需要呢?

谢谢,

3 个答案:

答案 0 :(得分:3)

我不得不两次看他们的代码。因为我花了一分钟才意识到0xFFF不是24位,所以它只有12位。因此,请举例64位输入:0xAABBCCDDEEFF1122。将它向右移动40,你得到0x0000000000AABBCC。在这种情况下,~0xFFF0xFFFFFFFFFFFFF000的简写。 And他们在一起,你得到0x0000000000AAB000。所以基本上,他们抓住前12位并将它们向下移动。然后他们or底部12位。所以他们最终得到了0x0000000000AAB122

另一半则相反,在底部取24位,将它们切成两半,顶部为12,底部为12。

答案 1 :(得分:1)

0xFFF不是24位,只有12位。

知道了这一点,你会发现get_pte_flags的目的是将前12位移到12-24位,如下所示:

xxxxxxxx xxxx0000 00000000 00000000 00000000 00000000 0000yyyy yyyyyyyy

变为

00000000 00000000 00000000 00000000 00000000 xxxxxxxx xxxxyyyy yyyyyyyy

当然,put_pte_flags执行相反的操作,将位移回最重要的位置。

答案 2 :(得分:0)

64位思考。

在32位系统上,结果当然是0。 但是,当你向左移24位40位时,你有

xxxxxxxx yyyyyyyy zzzzzzzz 00000000 00000000 00000000 00000000 00000000

这是一个有效的64位值。