Wow, that's a huge sentence in your first post (I count 9 lines)
Yep, that's correct, except that the CPU won't save most registers for you. If you look at the Intel docs (IIRC under interrupt stack frames) you'll see that, for an interrupt from ring 3 to ring 0, the CPU will save EIP, CS, ESP, SS and EFLAGS, as well as pushing an error code sometimes. You need to save, and restore, everything else, including the general-purpose registers (use PUSHA/POPA), the other segment registers and, optionally, the FPU registers. Note that the CPU doesn't pop the error code on IRET, so you need to do ADD ESP, 4 before you IRET.
The CPU doesn't tell you what interrupt called the code, so you need to write a separate assembly handler stub for each one. Most people automate this in their assembly file using macros, with each one JMP'ing to a common handler, which calls the main interrupt handler. For example, my first 8 interrupt handlers look like this:
Code: Select all
%macro interrupt 1
[global _interrupt_%1]
_interrupt_%1:
push dword 0
push dword 0x%1
jmp _isr_and_switch
align 8
%endmacro
interrupt 0
interrupt 1
interrupt 2
interrupt 3
interrupt 4
interrupt 5
interrupt 6
interrupt 7
_isr_and_switch pushes all the other registers, calls a C handler, switches stacks if necessary, and pops the registers from the new stack (thereby implementing multi-tasking). Note that each interrupt stub pushes the interrupt number onto the stack, as well as a fake error code (exception handlers don't push the error code since the CPU has already pushed it).
Your guess about using the timer interrupt to do multitasking is right. However, in practice you'll only multitask on the timer interrupt if some task is taking too long over some calculations. Most of the time a task will be waiting for user input, so you can switch to some other task when it starts waiting, and switch back when input is available (e.g. when the user presses a key). However, it could happen that all tasks are waiting for input (this will happen most of the time), so you'll need an idle thread to 'suck up' the remaining CPU time. The idle thread's job is to run when no other threads need to.
Usually it's up to the PIT (the 8254 programmable interval timer, not the APIC) to give you an IRQ 0 periodically. The BIOS sets it to run at 18.2Hz, giving you about 50ms between interrupts, but you'll probably want to speed it up a bit. Speed it up too much and you'll find that your scheduler is taking up more CPU time that your threads; slow it down too much and multitasking will be too jerky. 100Hz is a common setting.