Member Avatar for iret
iret

I wanted to get a feel for preemptive multi-tasking. The easiest way I could think of was to write Real Mode boot code.

To compile: nasm bt.asm -o bt.img I ran this by loading bt.img as a floppy image under VirtualBox. Not sure if it'd work with other emulators.

The code below works, but only the main loop runs (the main loop, task1 loop, and task2 loop are all supposed to run). What am I doing wrong?

BITS 16

  ORG 0x7C00

  cli

  ; Save data segment
  mov     [data], ds

  ; Get flags
  pushf
  pop     ax

  mov     bx, sp

  ; Save main loop SS:SP
  mov     [stacks + (0 * 4) + 0], bx
  mov     [stacks + (0 * 4) + 2], ss

  ; Initialize task1 loop SS:SP
  sub     bx, 128
  mov     [stacks + (1 * 4) + 0], bx
  mov     [stacks + (1 * 4) + 2], ss

  ; Initialize task2 loop SS:SP
  sub     bx, 128
  mov     [stacks + (2 * 4) + 0], bx
  mov     [stacks + (2 * 4) + 2], ss

  ; Save old timer handler
  xor     ax, ax
  mov     es, ax
  mov     di, [es:0x08 * 4 + 0]
  mov     ax, [es:0x08 * 4 + 2]
  mov     [old_timer + 0], di
  mov     [old_timer + 2], ax

  ; Set timer handler
  mov     word [es:0x08 * 4 + 0], timer
  mov     [es:0x08 * 4 + 2], cs

  sti

  ; Init common register values
  mov     ax, 0xB800
  mov     es, ax
  mov     di, (80 * 2) * 10

main:
  mov     bx, 20 * 2
  inc     byte [es:di + bx]
  jmp     main

task1:
  mov     bx, 40 * 2
  inc     byte [es:di + bx]
  jmp     task1

task2:
  mov     bx, 60 * 2
  inc     byte [es:di + bx]
  jmp     task2

timer:
  ; Save registers to current stack
  push    ds
  push    es
  pusha

  ; Restore data segment
  mov     ax, [cs:data]
  mov     ds, ax

  ; Initalize current task and next task SS:SP indices
  xor     bx, bx
  xor     si, si

  cmp     word [ntasks], 0
  je      SkipSwitch

  ; If more than 1 task is running, set task indices
  mov     ax, [curtask]
  mov     bx, ax

  inc     ax
  xor     dx, dx

  div     word [ntasks]

  mov     si, ax
  mov     [curtask], ax

  shl     bx, 2 ; current task
  shl     si, 2 ; next task

SkipSwitch:
  ; Save current SS:SP
  mov     [bx + stacks + 0], sp
  mov     [bx + stacks + 2], ss

  ; Restore next SS:SP
  mov     sp, [si + stacks + 0]
  mov     ss, [si + stacks + 2]

  ; Restore registers
  popa
  pop     es
  pop     ds

  ; Chain to old timer handler
  jmp     far [old_timer]

old_timer: dd 0

data:   dw 0
stacks: times 4 dd 0

curtask: dw 0
ntasks:  dw 2

times 512 - ($ - $$) db 0