About your esp, iret does not change it. It's up to your OS to update the esp on a context switch. Don't forget the TSS too.
It's your OS so do whatever makes sense (but be warned, bad design decisions come back to haunt you).
In my IRQ handler, I had in order:
Code:
irq_return:
pop gs
pop fs
pop es
pop ds
popa
add esp, 8 ; Error code and other shenanigans
iret
And so I set up the stack like:
Code:
uint32_t *stack = (uint32_t *)malloc(4096);
stack = (uint32_t *)((int)stack + 4096);
stack -= 16; // Padding
*--stack = 0x10; // ss
*--stack = 0x00; // esp
*--stack = 0x202; // eflags
*--stack = 0x08; // cs
*--stack = entry_point; // eip
*--stack = 0x00; // err_code
*--stack = 0x00; // int_no
/* pushad */
*--stack = 0xCAFEBABE; // eax
*--stack = 0x00; // ecx
*--stack = 0x00; // edx
*--stack = 0x00; // ebx
*--stack = 0x00; // esp_dummy
*--stack = 0x00; // ebp
*--stack = 0x00; // esi
*--stack = 0x00; // edi
/* Push segment registers */
*--stack = 0x10; // ds
*--stack = 0x10; // es
*--stack = 0x10; // fs
*--stack = 0x10; // gs
proc->thread.regs.registers = (void *)stack; // Top of stack
Then to switch tasks, I switch the ESP/page directories and jump to "irq_return" and let the cpu handle the rest. And so to run the task, I set up the task's stack and queue it, where the scheduler then changes the stack and the cpu pops the return address and runs the code. Not sure if it's THE way, but it works and so far nothing bad has happened.
Looking at your code, you do almost the same thing, except that your "switchTasks" works differently. It can't be that bad.