Preemptive scheduling on 16-bit real-mode os?
27 Sep 2022I was browsing the MS-DOS source code and I was thinking is it possible to have a preemptive scheduler in a 16-bit OS running purely in real-mode? I think it should be possible.
IBM published the entire source code of BIOS (written for 8086) as a technical reference, and if we look closely there is a particular interrupt that can be of help, INT 08H.
;-- HARDWARE INT 08 H - ( IRQ LEVEL 0 ) --------------------------------------
; THIS ROUTINE HANDLES THE TIMER INTERRUPT FROM CHANNEL 0 OF :
; THE 8254 TIMER. INPUT FREQUENCY IS 1.19314 MHZ AND THE DIVISOR :
; IS 65536, RESULTING IN APPROXIMATELY 18.2 INTERRUPTS EVERY SECOND. :
; :
; THE INTERRUPT HANDLER MAINTAINS A COUNT (40:6C) OF INTERRUPTS SINCE :
; POWER ON TIME, WHICH MAY BE USED TO ESTABLISH TIME OF DAY. :
; THE INTERRUPT HANDLER ALSO DECREMENTS THE MOTOR CONTROL COUNT (40:40) :
; OF THE DISKETTE, AND WHEN IT EXPIRES, WILL TURN OFF THE :
; DISKETTE MOTOR(s), AND RESET THE MOTOR RUNNING FLAGS. :
; THE INTERRUPT HANDLER WILL ALSO INVOKE A USER ROUTINE THROUGH :
; INTERRUPT 1CH AT EVERY TIME TICK. THE USER MUST CODE A :
; ROUTINE AND PLACE THE CORRECT ADDRESS IN THE VECTOR TABLE. :
; -----------------------------------------------------------------------------
TIMER_INT_1 PROC FAR
STI ; INTERRUPTS BACK ON
PUSH DS
PUSH AX
PUSH DX ; SAVE MACHINE STATE
CALL DDS ; ESTABLISH ADDRESSABILITY
INC @TIMER_LOW ; INCREMENT TIME
JNZ T4 ; GO TO TEST DAY
INC @TIMER_HICH ; INCREMENT HIGH WORD OF TIME
T4: ; TEST DAY
CMP @TIMER_HIGH,018H ; TEST FOR COUNT EQUALING 24 HOURS
JNZ T5 ; GO TO DISKETTE_CTL
CMP @TIMER_LOW,0B0H
JNZ T5 ; GO TO DISKETTE_CTL
;----- TIMER HAS GONE 24 HOURS
SUB AX,AX
MOV @TIMER_HIGH,AX
MOV @TIMER_LOW,AX
MOV @TIMER_OFL,1
;----- TEST FOR DISKETTE TIME OUT
T5:
DEC @MOTOR_COUNT ; DECREMENT DISKETTE MOTOR CONTROL
JNZ T6 ; RETURN IF COUNT NOT OUT
AND @MOTOR_STATUS,0F0H ; TURN OFF MOTOR RUNNING BITS
MOV AL,0CH
MOV DX,03F2H ; FDC CTL PORT
OUT DX,AL ; TURN OFF THE MOTOR
T6: ; TIMER TICK INTERRUPT
INT 1CH ; TRANSFER CONTROL TO A USER ROUTINE
POP DX ; RESTORE (DX)
MOV AL,EOI ; GET END OF INTERRUPT MASK
CLI ; DISABLE INTERRUPTS TILL STACK CLEARED
OUT INTA00,AL ; END OF INTERRUPT TO 8259 - 1
POP AX
POP DS ; RESET MACHINE STATE
IRET ; RETURN FROM INTERRUPT
TIMER_INT_1 ENDP
The interrupt has the highest IRQL. Here ISR increases a timer, turns off the floppy disk motor if needed and sends a EOI command. But it also calls a software interrupt INT 1CH to “transfer control to a user routine”. By default INT 1CH is just a dummy routine:
DW OFFSET DUMMY_RETURN ; INT 1CH -- TIMER BREAK ADDRESS
which translates to a simple IRET:
;----- DUMMY INTERRUPT HANDLER
;;- ORG 0FF53H
ORG 01F53H
DUMMY_RETURN EQU $ ; BIOS DUMMY (NULL) INTERRUPT RETURN
IRET
So I think by installing a INT 1CH hook it should be possible to implement a (possibly slow) preemptive scheduler, obviously there is no protection and any process can trash memory or scheduler.