EDIT: turns out that wouldnt work anyway, if it was a sysenter/exit then it wouldnt put cs on the stack, it would be in a MSR. NEVERMIND.
Okay, im currently working on a task scheduler which works but im just curious about how i should act during system routines.
Take for example Process A and Process B, if you have IF flag set during system routines then you could switch to from A to Process B during a system routine which uses the kernel stack, but process B could call a system routine (TSS would set stack pointer) and process B could overwrite the data on the kernel stack that process A left on there. It took me a while to realise this...way too long :p.
However by setting IF to 0 during system routines (with interrupts you can use an interrupt gate) you fix this problem (not very elegant IMO but im open to suggestions). However, onto my problem with the use of sysenter/exit instructions where you cant automaticall set IF to 0. So what if you get a interrupt just as you jump to the routine BUT before the cli? Youll overrwrite the eip/cs/flags which will stored on the kernel stack on the entry to the routine by process A IF process B also enters a system routine. This can be fixed by ONLY using sysenter/sysexit (they dont leave stuff on the stack) and no interrupts and by doing cli before you use the stack and sti when you done (or cli and sti around stuff that cant be interrupted, e.g. port I/O).
Another solution is maybe in the task scheduler check cs on the stack. 3 and if it was coming from a ring 0 routine id simply just jump back without a switch. Here lies my problem, i can't get it to work i get GPF when i switch back to process A. Take a look at my IRQ 0 handler:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; IRQ 0 - Task Switcher ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IRQ0:
push eax ;temporarily store eax as i use it for ptr to struct and checking if caller is ring 3 or 0
mov eax,[esp+8] ;check if previous process was in ring 0 or ring 3, if ring 0 then dont task switch
or eax,3
jnz SwitchTask
pop eax
jmp DontSwitchTask
SwitchTask:
mov eax,[ActiveProcess]
mov [eax],edi ;save context to current process structure
mov [eax+4],esi
mov [eax+8],ebp
mov [eax+16],ebx
mov [eax+20],edx
mov [eax+24],ecx
popd [eax+28]
popd [eax+32]
popd [eax+36]
popd [eax+40]
popd [eax+44]
popd [eax+48]
mov eax,[eax+52] ;get pointer to next process from link entry in current processes context structure
mov [ActiveProcess],eax ;set it as current process structure
mov esp,eax ;set esp to this structure and pop of values, okay to trash esp as it gets reset on each ring 3 -> 0 switch
popa ;it doesnt actually load the ESP from the struct
DontSwitchTask:
iret
ActiveProcess dd ProcessAContext
My processes are laid out like this. Its a round robin scheduler, each process has a context structure attributed with it, you set the last entry of this structure to a pointer to the next processes context structure (set a to b and b to a so they loop around). Really simple and somewhat elegant way of doing it i think. I plan to have 3 priorities levels and round robin each process in each priority level but its simple for now.
ProcessA: ;main process that initialize jumps to
mov esi,AMsg ;before activating scheduler.
xor eax,eax
int 0x30
jmp ProcessA
AMsg db 'A',0
ProcessAContext:
dd 0 ;edi
dd 0 ;esi
dd 0 ;ebp
dd 0x9FFFF ;esp
dd 0 ;ebx
dd 0 ;edx
dd 0 ;ecx
dd 0 ;eax
dd ProcessA ;eip
dd 0x1B ;cs
dd 0x200 ;eflags
dd 0x80000 ;esp (only used when switching back to ring 3)
dd 0x23 ;ss (only used when switching back to ring 3)
dd ProcessBContext ;link the next process in chain
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; Process B ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ProcessB: ;simple process repeatedly prints "B"
mov esi,BMsg
xor eax,eax
int 0x30
jmp ProcessB
BMsg db 'B',0
ProcessBContext:
dd 0 ;edi
dd 0 ;esi
dd 0 ;ebp
dd 0x9FFFF ;esp
dd 0 ;ebx
dd 0 ;edx
dd 0 ;ecx
dd 0 ;eax
dd ProcessB ;eip
dd 0x1B ;cs
dd 0x200 ;eflags
dd 0x70000 ;esp (only used when switching back to ring 3)
dd 0x23 ;ss (only used when switching back to ring 3)
dd ProcessAContext ;link the next process in chain
I figured this would work, i took into account that eax would reduce esp by 4 and id have to add another 4 to get past EIP yet i still get GPF. If its a ring 0 routine that gets interrupted all that should happen is a push and pop for eax then a iret. why would a push and a pop of eax make any difference? is cs at [esp+8] at that point?
it works if i set the systemcall to be a interrupt gate so its definetly happening because its not switching back if its from ring 0, but not if i set it to be a trap gate. I *SHOULD* have it as a interrupt gate, i know, im just trying to simulate how im going to handle sysenter/exit as you cant automatically set them to clear IF on the entry to the routine.
Any advice appreciated.
Cal.