Hi, I've been investigating why some of my code failed on qemu, but succeeded in bochs and on real hardware. In particular, it turns out that qemu would reset the FS/GS_BASE_MSR whenever I did iret from ring 0 to 3.
I traced it down to this bit of code (in target-i386/op_helper.c): static inline void validate_seg(int seg_reg, int cpl) { int dpl; uint32_t e2; /* XXX: on x86_64, we do not want to nullify FS and GS because they may still contain a valid base. I would be interested to know how a real x86_64 CPU behaves */ if ((seg_reg == R_FS || seg_reg == R_GS) && (env->segs[seg_reg].selector & 0xfffc) == 0) return; So the reason why this didn't work in qemu for me was that I was loading the selector as 8 -- which fails the above test and validate_seg() proceeds to clear the segment base value. Changing my own code to only load 0 into %gs from the start fixed the problem for me. However, qemu is clearly doing something differently from the real hardware. I tested both versions (loading 0 or 8 into %gs) on my Intel P4, and GS_BASE_MSR is preserved in both cases. Perhaps the condition on the selector value should be removed? (Or perhaps the calls to validate_seg() for R_FS/R_GS should be removed from helper_ret_protected()?) Just a heads up. Vegard