[SOLVED] QEMU GPF on 64-bit ring0 IRETQ to ring3

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
darfo
Posts: 1
Joined: Wed Jan 04, 2023 9:29 pm

[SOLVED] QEMU GPF on 64-bit ring0 IRETQ to ring3

Post by darfo »

tl;dr The AMD System Programming manual (Vol 2) can be misleading. DPL=3 code and stack
descriptors must both have bit 12 set (code or data desciptor) and the stack
descriptor must have the writable bit 9 set.

After setting up the TSS with RSP0 and correctly setting the STAR and LSTAR
MSRs sysret to ring 3 and syscall back to ring 0 was working fine. Until
turning on ring 0 timer interrupts.

On interrupt of the ring3 process the timer handler would GPF on the iretq every time.
And the error code had the ring 3 code selector in it.

Stared at that desciptor so long though marriage might be the answer. But,
thanks to the this forum the veracity of the manuals was not 100%. I noticed
that some of the ignored bits (grey) in Figure 4-20 had a 1 in it instead of a
label.

I remembered reading about the LAR instruction so I put it to work. After OS
init I had it display all the segment and TSS desciptors. It didn't like the
DPL=3 descriptors. I added bit 12 to the DPL=3 descriptors. That got the GPF to
stop complaining about the code descriptor. Instead it complained about stack
desciptor. Eureka! Progress! Added bit 9 (writable) to the stack descriptor and
the GPF from iretq stopped. LAR is my new best friend.

It is interesting that calls in ring3 didn't complain about the stack desciptor. But
there is something about using the TSS stack switching from ring-3 to ring-0
interrupt that causes a problem.

Don't know if it is qemu only. I'm not ready/able to test on real hardware yet.

In the manuals defense it does say:
In Figure 4-20, gray shading indicates the code-segment descriptor fields that are ignored in 64-bit
mode when the descriptor is used during a memory reference. However, the fields are loaded whenever
the segment register is loaded in 64-bit mode.
[emphasis mine]

It just doesn't say what the implications of (not) loading those fields means.

Cheers to all osdevers.
MichaelPetch
Member
Member
Posts: 797
Joined: Fri Aug 26, 2016 1:41 pm
Libera.chat IRC: mpetch

Re: [SOLVED] QEMU GPF on 64-bit ring0 IRETQ to ring3

Post by MichaelPetch »

Sysret/Syscall don't load segment registers in the traditional sense, CS and SS Segment registers are not loaded from the GDT/LDT. Their values are fixed and are loaded from the STAR/LSTAR registers. As a result normal checks are not done. Part of the reason Syscall/Sysret are fast is that the SS/CS segment registers aren't reloaded putting the processor through all the typical validation checks.

When it comes to an Interrupt in Ring 3, the IRETQ instruction first reloads the CS register from the GDT/LDT putting it through all the validity checks. Then SS is reloaded when it retrieves (SS:RSP) from the stack. Again validity checks are done here.

The Intel Manual is clearer on the fact that legacy checks are still performed (and why) in 64-bit mode:
3.4.2.1 Segment Registers in 64-Bit Mode
...
Even though segmentation is generally disabled, segment register loads may cause the processor to perform segment access assists. During these activities, enabled processors will still perform most of the legacy checks on loaded values (even if the checks are not applicable in 64-bit mode). Such checks are needed because a segment register loaded in 64-bit mode may be used by an application running in compatibility mode.
...
Post Reply