Message board for the users of flat assembler.
> OS Construction > Stack Switching.
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.
|25 Dec 2008, 00:08||
Try asking on alt.os.development (usenet/nntp)
|25 Dec 2008, 21:02||
< Last Thread | Next Thread >
Copyright © 1999-2020, Tomasz Grysztar. Also on GitHub, YouTube, Twitter.
Website powered by rwasa.