VOGONS


First post, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

So I have 1 TSS set up in my global descriptor table so that when user mode is switching to kernel mode via an INT instruction that TSS is used to set up

a) kernel stack (SS0 and ESP0)
b) set all segments to the kernel's code and data descriptors.

Now on the other side of the INT (once I hit kernel mode) I still have access to all the user's registers (EAX, EBX, etc) however the segment registers that the user had are overwritten (as per TSS). How can I get access to the user's segment registers prior to the INT instruction (like I have access to the user's normal registers)?

Clearly the CPU knows them as upon IRET and return to user mode, those are being restored.

It feels like I am missing something very basic....

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 1 of 3, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

It seems upon task switch, one of the action the processor takes is this:

"Saving the state of the current task. The processor finds the base address of the current TSS cached in the task register. It copies the registers into the current TSS (EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, ES, CS, SS, DS, FS, GS, and the flag register). The EIP field of the TSS points to the instruction after the one that caused the task switch."

Now, how do I access this task registers? Because immediately after the step above, the CPU does this step:

"Loading the task register with the selector of the incoming task's TSS descriptor, marking the incoming task's TSS descriptor as busy, and setting the TS (task switched) bit of the MSW. The selector is either the operand of a control transfer instruction or is taken from a task gate."

So the task register (TR) now points to the new TSS. How do I get the old TSS (of the task that was switched out) ? As I need to access its registers?

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/

Reply 2 of 3, by superfury

User metadata
Rank l33t++
Rank
l33t++
vladstamate wrote on 2020-01-27, 20:15:
It seems upon task switch, one of the action the processor takes is this: […]
Show full quote

It seems upon task switch, one of the action the processor takes is this:

"Saving the state of the current task. The processor finds the base address of the current TSS cached in the task register. It copies the registers into the current TSS (EAX, ECX, EDX, EBX, ESP, EBP, ESI, EDI, ES, CS, SS, DS, FS, GS, and the flag register). The EIP field of the TSS points to the instruction after the one that caused the task switch."

Now, how do I access this task registers? Because immediately after the step above, the CPU does this step:

"Loading the task register with the selector of the incoming task's TSS descriptor, marking the incoming task's TSS descriptor as busy, and setting the TS (task switched) bit of the MSW. The selector is either the operand of a control transfer instruction or is taken from a task gate."

So the task register (TR) now points to the new TSS. How do I get the old TSS (of the task that was switched out) ? As I need to access its registers?

It depends. The switched out task is written to memory(at it's TSS location). The old TSS selector is only written to the new TSS that's switched to when nesting(e.g. using CALL or interrupt task switch mechanism). At TSS+0 there's the backlink to that. Other than that, you'll need to read the TSS directly from RAM at the location of the TSS that the backlink(only valid if the FLAGS registers' Nested Task flag is set). If NT isn't set in the flags register, the old task is permanently leaved(usually not the case with CALL/INT) and it's whatever was in the current task's backlink field before the task switch to the current task(e.g. previous link if unlinking/unchaining was done by software). Ofc, switching to tasks which are busy is prohibited normally(except when worked around), so the field should always be valid with NT set in FLAGS.

So, unless strange trickery is used(NT should be set), read the word at [currentTSS+0] for the originating TSS selector, then use the GDT to find it's location by the selector, then read said block for the original task's registers.

Author of the UniPCemu emulator.
UniPCemu Git repository
UniPCemu for Android, Windows, PSP, Vita and Switch on itch.io

Reply 3 of 3, by vladstamate

User metadata
Rank Oldbie
Rank
Oldbie

Thank you superfury.

I figured it out (I think). My problem was that when coming out of VM86 via an exception handler, there was no task switch as such (so no previous task link was updated). However that is not needed as after the exception (say general protection fault) the registers all remain the same, with the exception of segment registers (which is what I noticed). However the old segment registers are simply put on the stack as seen here:

https://css.csail.mit.edu/6.858/2014/readings … i386/s15_03.htm

Specifically part 15.3.2 and figure 15.3

As such I can get the general registers (as they are still the same) and the segment registers (from the stack). This is what I needed really.

YouTube channel: https://www.youtube.com/channel/UC7HbC_nq8t1S9l7qGYL0mTA
Collection: http://www.digiloguemuseum.com/index.html
Emulator: https://sites.google.com/site/capex86/
Raytracer: https://sites.google.com/site/opaqueraytracer/