I'm probably going to have only one TSS entry since I don't think my operating will be supporting multiple processors, and I'm going to implement software multitasking. I've set up the TSS descriptor in my GDT, and now I'm actually defining the TSS entry itself. I've set SS0 to 2, since that's the GDT entry for my kernel data, but I can't work out what to set ESP0 to. I know it's supposed to be the kernel's stack pointer, but that of course will not be a constant value. So, do I have to update this value in the TSS entry whenever I change from kernel mode to userspace mode?
(A related but less important question I have, which I'll probably put as a seperate thread if it doesn't get answered here, is: why do I need a TSS at all if I'm implementing software task switching? I don't see the purpose of it.)
Thanks!
What should I actually set ESP0 to in my TSS entry?
-
- Member
- Posts: 64
- Joined: Fri Jan 26, 2018 11:43 am
Re: What should I actually set ESP0 to in my TSS entry?
I doubt it is. 2 is effectively a NULL selector. See the bit layout in selectors.j4cobgarby wrote:I've set SS0 to 2, since that's the GDT entry for my kernel data
There are two main reasons for having a TSS:j4cobgarby wrote:but I can't work out what to set ESP0 to. I know it's supposed to be the kernel's stack pointer, but that of course will not be a constant value. So, do I have to update this value in the TSS entry whenever I change from kernel mode to userspace mode?
(A related but less important question I have, which I'll probably put as a seperate thread if it doesn't get answered here, is: why do I need a TSS at all if I'm implementing software task switching? I don't see the purpose of it.)
- hardware-assisted task switching
- switching between privilege levels/rings
If you're already in ring 0, there's no any more privileged level (-1?), so, everything keeps using the current SS:ESP (all exception and interrupt handlers).
But if ring 3 code needs to go to ring 0 to handle an exception or hardware interrupt, then SS0:ESP0 is used.
You typically should set SS0:ESP0 to point to the end of the buffer for interrupt/exception handlers to use as their stack.
Read the CPU manual.
-
- Member
- Posts: 64
- Joined: Fri Jan 26, 2018 11:43 am
Re: What should I actually set ESP0 to in my TSS entry?
Okay got it, thanks! I tried reading the manual and got some information from it, but I find it difficult to find exact pieces of information I'm looking for.alexfru wrote:I doubt it is. 2 is effectively a NULL selector. See the bit layout in selectors.j4cobgarby wrote:I've set SS0 to 2, since that's the GDT entry for my kernel data
There are two main reasons for having a TSS:j4cobgarby wrote:but I can't work out what to set ESP0 to. I know it's supposed to be the kernel's stack pointer, but that of course will not be a constant value. So, do I have to update this value in the TSS entry whenever I change from kernel mode to userspace mode?
(A related but less important question I have, which I'll probably put as a seperate thread if it doesn't get answered here, is: why do I need a TSS at all if I'm implementing software task switching? I don't see the purpose of it.)When there's a transition to a higher privilege level/ring (lower CPL), SS:ESP is pulled from the TSS.
- hardware-assisted task switching
- switching between privilege levels/rings
If you're already in ring 0, there's no any more privileged level (-1?), so, everything keeps using the current SS:ESP (all exception and interrupt handlers).
But if ring 3 code needs to go to ring 0 to handle an exception or hardware interrupt, then SS0:ESP0 is used.
You typically should set SS0:ESP0 to point to the end of the buffer for interrupt/exception handlers to use as their stack.
Read the CPU manual.
-
- Member
- Posts: 64
- Joined: Fri Jan 26, 2018 11:43 am
Re: What should I actually set ESP0 to in my TSS entry?
Another quick clarification, when you say I should set SS0:ESP0 to the end of the buffer, by buffer do you mean the kernel's stack memory?alexfru wrote:I doubt it is. 2 is effectively a NULL selector. See the bit layout in selectors.j4cobgarby wrote:I've set SS0 to 2, since that's the GDT entry for my kernel data
There are two main reasons for having a TSS:j4cobgarby wrote:but I can't work out what to set ESP0 to. I know it's supposed to be the kernel's stack pointer, but that of course will not be a constant value. So, do I have to update this value in the TSS entry whenever I change from kernel mode to userspace mode?
(A related but less important question I have, which I'll probably put as a seperate thread if it doesn't get answered here, is: why do I need a TSS at all if I'm implementing software task switching? I don't see the purpose of it.)When there's a transition to a higher privilege level/ring (lower CPL), SS:ESP is pulled from the TSS.
- hardware-assisted task switching
- switching between privilege levels/rings
If you're already in ring 0, there's no any more privileged level (-1?), so, everything keeps using the current SS:ESP (all exception and interrupt handlers).
But if ring 3 code needs to go to ring 0 to handle an exception or hardware interrupt, then SS0:ESP0 is used.
You typically should set SS0:ESP0 to point to the end of the buffer for interrupt/exception handlers to use as their stack.
Read the CPU manual.
Re: What should I actually set ESP0 to in my TSS entry?
you are making it harder than it needs to be:
ESP0 rarely needs to change (and never outside of task switching)
ESP does change as you use the stack... but when in ring3, the kernel stack isn't being used
think about this:
when the ring0 code returns to ring3, where is ESP?
of course it must be in exactly the same place it was when it first started, because that is where the CPU stored the return information!
therefore, ESP0 never changes, because ESP0 is not in use, and thus never changes, while in ring3, and when returning to ring3 it is always in the same place it was when switching from ring3 to ring0
a simple way to think about it:
the stack is for temporary local storage, therefore, when kernel code isn't running, it is always empty
there is only 1 exception to this:
when you switch threads within a single process, most OSes create a kernel stack for each thread, placing all of them at different addresses in the same address space, therefore, if you follow this system you must patch ESP0 when switching threads, otherwise the thread might overwrite the in-use stack from another thread in the same address space
ESP0 rarely needs to change (and never outside of task switching)
ESP does change as you use the stack... but when in ring3, the kernel stack isn't being used
think about this:
when the ring0 code returns to ring3, where is ESP?
of course it must be in exactly the same place it was when it first started, because that is where the CPU stored the return information!
therefore, ESP0 never changes, because ESP0 is not in use, and thus never changes, while in ring3, and when returning to ring3 it is always in the same place it was when switching from ring3 to ring0
a simple way to think about it:
the stack is for temporary local storage, therefore, when kernel code isn't running, it is always empty
there is only 1 exception to this:
when you switch threads within a single process, most OSes create a kernel stack for each thread, placing all of them at different addresses in the same address space, therefore, if you follow this system you must patch ESP0 when switching threads, otherwise the thread might overwrite the in-use stack from another thread in the same address space