Hi,
ManyGifts wrote:Code: Select all
irq0_interrupt_service:
call 0x30:0x0 ; call task1, selector is 0x30
call 0x38:0x0 ; call task2, selector is 0x38
;send eoi signal (end of interrupt)
mov al, 0x20
out 0x20, al
iretd
For hardware task switching, only ever use "call far" when you expect the other task switch tasks back (with "retf"). You need to use "jmp far" because you don't expect the other task to switch back.
You also need to send the EOI *before* you do a task switch, because after the task there's no way to guess what the CPU will be doing.
The IRQ handler needs to choose one task to jump to (you can't just jump to all tasks in the same IRQ).
Finally, if you modify any register in an IRQ handler then you *must* save it and then restore it after. You're using AL but not saving it or restoring it.
For a rough example of all this:
Code: Select all
section .data
currentTSSfarPointer:
dd 0 ;Note: CPU ignores the "offset" part, so there's not much point having it..
currentTSS:
dw 0x38
section .text
;Note: IRQ0 *must* be an "interrupt gate" (and can not be a "trap gate")
irq0_interrupt_service:
push eax
;send eoi signal (end of interrupt)
mov al, 0x20
out 0x20, al
add word [currentTSS],8 ;Get next TSS to switch to
cmp word [currentTSS],0x38 ;Is it too high?
jbe .l1 ; no
mov word [currentTSS],0x30 ; yes, wrap around to first TSS
.l1:
jmp far [currentTSSfarPointer] ;WARNING: Task switch and not a JMP (execution continues after the jump)
pop eax
iretd
Of course thepowersgang is right - this should be broken up into 3 pieces (IRQ0 handler, a "reschedule", and a "goto task"). For example:
Code: Select all
section .data
currentTSSfarPointer:
dd 0 ;Note: CPU ignores the "offset" part, so there's not much point having it..
currentTSS:
dw 0x38
section .text
;Note: IRQ0 *must* be an "interrupt gate" (and can not be a "trap gate")
irq0_interrupt_service:
push eax
;send eoi signal (end of interrupt)
mov al, 0x20
out 0x20, al
call reschedule
pop eax
iretd
;Find task to run and switch to it
reschedule:
push eax
movzx eax,[currentTSS]
add eax,,8 ;eax = next TSS to switch to
cmp eax,0x38 ;Is it too high?
jbe .l1 ; no
mov eax,0x30 ; yes, wrap around to first TSS
call gotoTask
pop eax
ret
;Switch to a specific task
;
;Input
; ax = TSS for task to switch to
gotoTask:
cmp [currentTSS],ax ;Is this task currently running?
je .done ; yes, do *not* attempt to switch (will cause GPF)
mov [currentTSS],ax
jmp far [currentTSSfarPointer] ;WARNING: Task switch and not a JMP (execution continues after the jump)
.done:
ret
Eventually "reschedule" will become something more sane (e.g. maybe using queues or something to choose which task to switch to (instead of doing a "2 hard-coded tasks" thing). Also (later) if a task blocks you can just call "reschedule" without waiting for the timer, and if the currently running task is preempted (e.g. a higher priority task is restarted) you can call "gotoTask" directly to avoid any unnecessary overhead (as you know which task to switch to already in those cases).
Cheers,
Brendan