I'm writing task switching, which must occur on timer interrupt. But some of threads are in ring 0, others - in ring 3.
So, when task switchs from ring0 to ring3: stack don't switch when entering handler, but on exit, CPU extract 2 extra words from stack and ruins it.
TSS is configured: bochs write the following info:
tr:s=0x2b, base=0x00000000ffffd000, valid=1
ss:esp(0): 0x0010:0x00800ff0
ss:esp(1): 0x0000:0x00000000
ss:esp(2): 0x0000:0x00000000
cr3: 0x00000000
eip: 0x00000000
eflags: 0x00000000
cs: 0x0000 ds: 0x0000 ss: 0x0000
es: 0x0000 fs: 0x0000 gs: 0x0000
eax: 0x00000000 ebx: 0x00000000 ecx: 0x00000000 edx: 0x00000000
esi: 0x00000000 edi: 0x00000000 ebp: 0x00000000 esp: 0x00000000
ldt: 0x0000
i/o map: 0x0000
There is written, that when TSS is configured, stack switchs in any case, not only when ring3-code interrupted. But I can't get such behaviour of CPU.
How to force stack switch even if privilege level don't change?
How to force stack switch in interrupt call
-
- Posts: 1
- Joined: Wed Jul 12, 2017 2:31 am
Re: How to force stack switch in interrupt call
Well, it seems that you're in x86 mode.
If my memory is correct, TSSes in long mode(x64) contain a Interrupt Stack Table and IntGates(x64) contain a index which points to the table. The IST don't rely on which ring to switch and when interrupts happen, if an index in a IntGate(x64) points to an item in the IST, stack switch will always cause.
But in protected mode, you seems to do it manually .
If my memory is correct, TSSes in long mode(x64) contain a Interrupt Stack Table and IntGates(x64) contain a index which points to the table. The IST don't rely on which ring to switch and when interrupts happen, if an index in a IntGate(x64) points to an item in the IST, stack switch will always cause.
But in protected mode, you seems to do it manually .
Doing steadfastly, or doing nil.
Re: How to force stack switch in interrupt call
Hi,
Task switches occur when:
For ring 3 tasks; something causes the CPU to switch to ring 0 (a kernel API call, an exception, an IRQ), then while you're running in ring 0 anyway the kernel decides it should do a task switch for one of the reasons listed above.
Essentially, switching rings (and TSS, etc) has nothing to do with task switching at all.
After the task switch happened, the task might or might not switch back to ring 3; but that still has nothing to do with task switching at all.
For a simple example, imagine that:
Cheers,
Brendan
No.osdevuser1923 wrote:I'm writing task switching, which must occur on timer interrupt.
Task switches occur when:
- The scheduler has to find something else for CPU to do, because:
- The currently running task blocks for any reason (e.g. has to wait for disk IO or network or IPC or ....)
- The currently running task terminates itself (e.g. calls "exit()")
- The currently running task crashes
- The scheduler decides that higher priority task should preempt the currently running (lower priority) task immediately, because:
- The higher priority task was unblocked (whatever it was waiting for happened)
- A new high priority task is being spawned/created
- There are 2 or more tasks running (for the CPU), and the currently running task used all of the time slice it was given, and scheduler wants to give other task/s some CPU time
No; all tasks are running in ring 0 when you find out that a task switch needs to happen.osdevuser1923 wrote:But some of threads are in ring 0, others - in ring 3.
For ring 3 tasks; something causes the CPU to switch to ring 0 (a kernel API call, an exception, an IRQ), then while you're running in ring 0 anyway the kernel decides it should do a task switch for one of the reasons listed above.
Essentially, switching rings (and TSS, etc) has nothing to do with task switching at all.
Because all task switches happen when CPU is running in ring 0; you only ever have to worry about switching from a task that is running at ring 0 to another task that was running at ring 0. The low level task switch code can push a few registers onto the old task's kernel stack, save "kernel stack top" (RSP register) somewhere, load a new "kernel stack top" (RSP register) from somewhere, switch to the new task's virtual address space if necessary, then pop a few registers from the new task's kernel stack.osdevuser1923 wrote:How to force stack switch even if privilege level don't change?
After the task switch happened, the task might or might not switch back to ring 3; but that still has nothing to do with task switching at all.
For a simple example, imagine that:
- A task calls the kernel API's "read()" function (causing switch from ring 3 to ring 0)
- The kernel's "read()" function checks if the data is cached or not, finds out the data isn't cached, and asks the file system code to fetch the data; and the task is blocked (causing a task switch) because it has to wait while the data is read from a hard disk
- Later on the data arrives from disk/file system/whatever; and the task is unblocked
- Sooner or later (possibly immediately) the scheduler does a task switch back to the (now unblocked) task
- Then the kernel figures out how much data was read (or if there was an error, etc) and returns this information from the kernel API's "read()" function (causing a switch from ring 3 back to ring 0).
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.