Ein Problem ist auf jeden Fall, wie du den IRQ-Handler einrichtest. Das passt nicht zu dem Stack.
Der Interrupthandler muss auf IRET enden, nicht RET. Wenn SwitchTask der komplette Interrupthandler ist, dann fehlt das IRET. Wenn hingegen IRQ_install_handler SwitchTask so einträgt, dass er indirekt von einem Interrupthandler aufgerufen wird, dann passt die struct cpu_state nicht dazu. Ich glaube alle Tutorials im Wiki (inkl. unseres
empfohlenen Tutorials) wechseln die Tasks in den Interrupt-Stubs, nicht indirekt über eine zusätzliche Methode. Ein Vorteil davon ist, dass die struct cpu_state dann einfacher ist.
Falls SwitchTask tatsächlich indirekt aufgerufen wird: Du könntest zwar die Idee den Taskwechsel in einer ausgelagerten Methode durchzuführen weiterverfolgen, aber dann musst du mindestens die struct cpu_state anpassen. Unter anderem muss dann CS raus, und du musst EFLAGS in SwitchTask manuell wechseln, ebenso wie die General Purpose Register, die in der C-Konvention als Callee-Save deklariert sind. Die übrigen Register (Caller-Save inkl. Clobber-Register wie EAX) musst du im Interruptstub wechseln. Klingt kompliziert und ist es auch. Ich weiß nicht, ob das wirklich dein Plan ist, weil du nicht den kompletten Interruptcode gezeigt hast, aber wenn ja, dann rate ich davon ab. Ich empfehle, dass du dich an die Tutorials hältst, bis du weißt, was da genau passiert.
Das mit dem Interrupts deaktivieren und wieder aktivieren halte ich auch für problematisch. (Denk mal über den Fall nach, wenn beim CLI die Interrupts bereits aus irgendeinem guten Grund deaktiviert waren. Dann aktiviert STI sie wieder, obwohl das gar nicht so sein soll.) In unseren Tutorials werden die Interrupts übrigens immer so eingerichtet, dass die Interrupts für die dauer der Behandlung deaktiviert sind, und nach Rückkehr wieder aktiviert werden. Das heißt Kernel-Code läuft immer mit deaktiviertem Interrupts und User-Code mit aktiviertem Interrupts. Das vermeidet viele Probleme.