有关Linux x86 64中MSR_GS_BASE的详细信息

我试图弄清楚Linux内核中MACRO电stream的细节。 当前最后的汇编代码是:

movq %%gs:0xb000,%0 

上面的代码可以工作! 但是当我打印%% gs时,它的值是0,所以%% gs指向GDT NULL的第一项! 怎么运行的?

 mov %%gs, %0 

相反,gs的基础在MSR_GS_BASE中,并且当前可以被replace为:

 /*0xb000 is the offset of per_cpu__current_task*/ cur_task = (unsigned long*)(x86_rdmsr64(MSR_GS_BASE) + 0xb000); println("cur_task:%p",*cur_task); 

我的问题是:

%gs指向GDT NULL的第一项! 从MSR_GS_BASE读取它是如何工作的,它是一个CPUfunction吗?我需要一些关于这个的参考。

从“ AMD体系结构程序员手册”卷2:系统编程 ,第4.5.3节:

FS和GS寄存器在64位模式下。 与CS,DS,ES和SS段不同,FS和GS段覆盖可以在64位模式下使用。 在64位模式下使用FS和GS段覆盖时,其有效地址(EA)计算中将使用其各自的基址。 完整的EA计算变成(FS或GS).base + base +(scale * index)+位移。 FS.base和GS.base值也扩展为完整的64位虚拟地址大小,如图4-5所示。 由此产生的EA计算被允许包裹正面和负面的地址。

[…]

有两种方法来更新FS.base和GS.base隐藏描述符字段的内容。 第一个专门用于特权软件(CPL = 0)。 FS.base和GS.base隐藏描述符寄存器字段被映射到MSR。 特权软件可以使用单个WRMSR指令将规范形式的64位基址加载到FS.base或GS.base中。 FS.base MSR地址是C000_0100h,而GS.base MSR地址是C000_0101h。

更新FS和GS基本字段的第二种方法可用于在任何特权级别运行的软件(当由实现支持并通过设置CR4 [FSGSBASE]启用时)。 WRFSBASE和WRGSBASE指令分别将GPR的内容复制到FS.base和GS.base字段。 当操作数大小为32位时,基址的高位双字清零。 WRFSBASE和WRGSBASE仅在64位模式下受支持。