this routine hooks interrupt 8h, which can't be pre-empted by any other interrupts. it is the highest priority level interrupt. read that as: DO NOT TRY TO USE INT 1Ch instead!

Code: Select all
;this is the heart of the RetrOS task/context switching. this routine hooks interrupt 8h
;and when it's done, performs a far jmp to the old handler.
jmp entry
curproc dw 0
maxproc dw 100
hookbusy db 0
count dw 0
entry:
; the FIRST thing we do is make sure no other interrupts are already active that we've pre-empted.
; if there are, and we try to swap registers around in the middle of them your system is going to
; crash and burn hard. this involves reading the in-service register on the i8259 chip.
pushf
push ax
mov al, 0bh ;talk to the 8259 on port 20h
out 20h, al ;ask it what interrupts are in service
in al, 20h ;get our answer
test al, 11111110b ; check to make sure that interrupts 1-7 aren't active
pop ax
jnz reallyfinishedandpopf ; are they? if so, just jump to the end and then we'll far jmp to the old 8h handler
popf
cmp cs:hookbusy, 1 ;has the kernel set the busy flag? for some reason it doesnt want us to taskswitch now?
jz reallyfinished ;then let's bail out because that would be bad
mov cs:hookbusy, 1 ;no, so lets set the busy flag. probably dont need to do this since we can't be re-entrant
inc cs:count ; if we're on int 8h, but meh..
push bp
push di
push si
push ds
push es
push dx
push cx
push bx
push ax
mov ax, 0100h ;set ES to RAM area for the process array
mov es, ax
mov ax, cs:curproc
mov bl, 8
mul bl
mov si, ax
add si, 2 ;we need to save the task's SS:SP
mov es:[si], sp
add si, 2
mov es:[si], ss
findnext:
mov ax, cs:curproc
cmp ax, cs:maxproc
jz resetloop
inc ax
jmp continue
resetloop:
mov ax, 0
continue:
mov cs:curproc, ax
mov bl, 8
mul bl
mov si, ax
mov ax, es:[si]
cmp ax, 1 ;is the process curproc points to runnable?
jnz findnext ;if not, check go back and increment curproc
add si, 2 ;we need to retrieve the task's SS:SP
mov ax, es:[si]
mov sp, ax
add si, 2
mov ax, es:[si]
mov ss, ax
finished:
pop ax ;load registers back from the process' stack
pop bx
pop cx
pop dx
pop es
pop ds
pop si
pop di
pop bp
push ax ;next few lines clear our busy flag
mov al, 0
mov cs:hookbusy, al
pop ax
jmp reallyfinished ;skipping the popf
reallyfinishedandpopf:
popf
reallyfinished:
push ax
push bx
push es
mov ax, 0D00h ;the next few lines dump the old CS and IP of int 8h where they need to go from our vector array.
mov es, ax ;the D00h is where the C kernel keeps an array of vectors. 8h is stored before it hooks this new routine.
mov ax, es:32 ;8 * 4 = 32
mov bx, es:34 ;8 * 4 + 2 = 34
mov cs:jmpip, ax
mov cs:jmpcs, bx
pop es
pop bx
pop ax
db 0EAh ;going to far jump to the original 8h handler
jmpip dw 0
jmpcs dw 0
and this is the array structure my C kernel sets up at segment 100h:
Code: Select all
struct structpid {
unsigned isvalid; //so the task-switcher ISR knows if it should switch into a process, this will be 1 if okay.
unsigned sp;
unsigned ss;
unsigned proctty; //which vtty does this PID use for stdin/stdout?
} far *proc = (void far *)MK_FP(0x100, 0x0);
unsigned far *curproc = (void far *)MK_FP(0xE00, 0x2); //my int 8h routine is at E00:0h, and we will keep track of it's curproc so the kernel can always know what the current running PID is when a system call is made.