Chinaunix

标题: current宏的疑问[己解答] [打印本页]

作者: hellolwq    时间: 2012-07-13 17:30
标题: current宏的疑问[己解答]
本帖最后由 hellolwq 于 2012-07-16 12:57 编辑

x86 64下面,使用内核2.6.30。
current宏用于内核模块获取当前运行的进程结构体,展开为:
  1. movq %%gs:0xb000,%0
复制代码
比如得到地址可能是:ffff88007d0c9870

但是将段寄存器gs打印出来,发现其值为0,
16位段描述符号的TI位如果为0则为GDT,这里GS为全0,只能是GDT里面的第一项,也就是空描述符那项。
手册里面明明写着使用空描述符赋值可以,用来寻址就报错啊。。。


询问同事,提到linux下gs是被弃用的,使用的是MSR_GS_BASE。
发现有俩问题:
1、如果GS被弃用,为什么内核代码使得的是movq %%gs:0xb000,%0
2、将MSR_GS_BASE读出来的值,跟%%gs:0xb000对不上。[后面证实这里能匹配上的。]
3、代码上显示MSR_GS_BASE存储的是 (unsigned long)per_cpu(irq_stack_union.gs_base, cpu)
  1. void load_percpu_segment(int cpu)
  2. {
  3. #ifdef CONFIG_X86_32
  4.         loadsegment(fs, __KERNEL_PERCPU);
  5. #else
  6.         loadsegment(gs, 0);
  7.         wrmsrl(MSR_GS_BASE, (unsigned long)per_cpu(irq_stack_union.gs_base, cpu));
  8. #endif
  9.         load_stack_canary_segment();
  10. }
复制代码
盼高手指条出路,内核似海,回头无岸。


在stackoverflow发的帖子上有个朋友给出了AMD上面的实现说明。
http://stackoverflow.com/questio ... 4/11497742#11497742

我在Intel手册找到类似的描述。
大部分段寄存器在64位下被忽略,fs和gs有点特殊,用来寻址的时候,实际使用的是对应的[fs,gs].base,而这些值是映射到其对应的MSR_[GS|FS]_BASE上的。

3.4.4  Segment Loading Instructions in IA-32e Mode
[...]
When FS and GS segment overrides are used in 64-bit mode, their respective base
addresses are used in the linear address calculation: (FS or GS).base + index +
displacement. FS.base and GS.base are then expanded to the full linear-address size
supported by the implementation. The resu lting effective address calculation can
wrap across positive and negative addresses; the resulting linear address must be
canonical.
In 64-bit mode, memory accesses using FS -segment and GS-segment overrides are
not checked for a runtime limit nor subjected to attribute-checking. Normal segment
loads (MOV to Sreg and POP Sreg) into FS and GS load a standard 32-bit base value
in the hidden portion of the segment descriptor register. The base address bits above
the standard 32 bits are cleared to 0 to  allow consistency for implementations that
use less than 64 bits.
The hidden descriptor register fields for FS.base and GS.base are physically mapped
to MSRs in order to load all address bits supported by a 64-bit implementation. Soft-ware with CPL = 0 (privileged software) can load all supported linear-address bits
into FS.base or GS.base using WRMSR. Addresses written into the 64-bit FS.base and
GS.base registers must be in canonical form. A WRMSR instruction that attempts to
write a non-canonical address to those registers causes a #GP fault.
...

作者: luoyan_xy    时间: 2012-07-13 23:18
  友情帮顶
作者: cdtits    时间: 2012-07-14 00:04
用的是哪个版本?
作者: hellolwq    时间: 2012-07-15 17:42
回复 2# luoyan_xy


   
作者: hellolwq    时间: 2012-07-15 17:42
x86 64 2.6.30。
盼高手赐教!
cdtits 发表于 2012-07-14 00:04
用的是哪个版本?

作者: hellolwq    时间: 2012-07-16 10:02
经高人指点,找到问题的解决办法,但是关于%%gs为0却能继续使用的原因仍然未知,不知道是否为CPU特性?
  1. //内核自带的current宏
  2. println("current:%p",current);

  3. //gs确实保存在MSR_GS_BASE中
  4. gs_base = x86_rdmsr64(MSR_GS_BASE);
  5. println("MSR_GS_BASE:%p",gs_base);
  6. cur_task = (unsigned long*)(gs_base + 0xb000);//0xb000为per_cpu__current_task偏移量
  7. println("cur_task:%p",*cur_task);
复制代码





欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2