let me start by saying that i'm an assembly newbie,
i was given the task to write an round-robin scheduler for a simple OS running in BOCHS
but when i try to register the interrupt service routine to count the ticks
(interrupt 0x1C vector, address 0x0070)
bochs throws me the following error twice and my OS freezes
"[CPU0 ] LOCK prefix unallowed (op1=0x53, modrm=0x00)"
here is the code for the kernel
only the "_scheduleprogram", "_startRoundRobinScheduler" and everything after "_trapISRA" is written by me
i have no clue what is going wrong, please help
thanks.
P.S. the os runs in 16-bits, very DOS like and uses segmented memory model
Code: Select all
.global _interrupt
.global _loadbuffer
.global _scheduleprogram
.global _run
.global _registerTrapISR
.global _startRoundRobinScheduler
.global _setKernelMode
.global _exitKernelMode
.extern _trapISRC
;.extern _trapClockISRC
KCLOCKTICKS equ 100
_setKernelMode: ; we also need to save the BP and SP of the calling proc and restore the BP and SP of the kernel
pop bx ;load the BX of the calling proc
push ds ;segment of the calling proc
push bx
mov ax,#0x1000
mov ds,ax
ret
;restores the data segment
_exitKernelMode:
pop bx
pop ds
push bx
ret
_interrupt:
push bp
mov bp,sp
mov ax,[bp+4] ;get the interrupt number in AL
push ds ;use self-modifying code to call the right interrupt
mov bx,cs
mov ds,bx
mov si,#intr
mov [si+1],al ;change the 00 below to the contents of AL
pop ds
mov ax,[bp+6] ;get the other parameters AX, BX, CX, and DX
mov bx,[bp+8]
mov cx,[bp+10]
mov dx,[bp+12]
intr: int #0x00 ;call the interrupt (00 will be changed above)
mov ah,#0 ;we only want AL returned
pop bp
ret
;this loads a new program but doesn't start it running
;the scheduler will take care of that
;the program will be located at the beginning of the segment at [sp+2]
;the filebuffer is located in the current segment at [sp+4]
;the number of bytes is located at [sp+6]
_loadbuffer:
;bx=new segment
;cx=length
;si=buffer
;di=new location
push bp
push es
;; xchg bx, bx ;; bochs magic breakpoint, commented out to disable
mov bp, sp
mov es, [bp+6] ;; es = new segment
mov si, [bp+8] ;; si = buffer
mov cx, [bp+10] ;; cx = length
mov di, #0 ;; di = 0 (so you get ES:0000 to start with)
xferloop:
cmp cx, #0
je xferdone
movsb ;; ES:[DI++] = DS:[SI++], to mix C and assembly
dec cx
jmp xferloop
xferdone:
pop es
pop bp
ret
; parameters : the program number (0-7), the program segment address. both are WORD (2 bytes) size
_scheduleprogram:
push bp
push ax
xchg bx, bx ;; bochs magic breakpoint, commented out to disable
mov bp, sp
mov si, [bp+6] ;; si = program number
and si,7 ; (8-1), essentially performs mod 8
shl si,1 ; multiplication by 2
mov di,storedCS
add di,si
mov ax,[bp+8]
mov [di],ax ; segment address
mov di,storedIP
add di,si
mov ax,0
mov [di],ax
mov di,storedSP
add di,si
mov ax,#0xfff0
mov [di],ax
mov di,storedBP
add di,si
mov ax,#0xfff0
mov [di],ax
pop ax
pop bp
ret
;this launches a new program
;the number of bytes is located at [sp+6]
;the filebuffer is located in the current segment at [sp+4]
;the program will be located at the beginning of the segment at [sp+2]
_run:
mov bp,sp
mov bx,[bp+2] ;get the segment into bx
mov ax,cs ;modify the jmp below to jump to our segment. Put the current instruction Code Segment (CS) into AX
mov ds,ax ;this is self-modifying code
mov si,#jump
mov [si+3],bx ;change the first 0000 to the segment
mov ds,bx ;set up the segment registers
mov ss,bx
mov es,bx
mov sp,#0xfff0 ;set up the stack pointer
mov bp,#0xfff0
jump: jmp #0x0000:0x0000 ;and start running (the first 0000 is changed above)
_registerTrapISR:
;get the address of the service routine
mov dx,#_trapISRA
push ds
mov ax, #0 ;interrupts are in lowest memory
mov ds,ax
mov si,#0x84 ;interrupt 0x21 vector (21 * 4 = 84)
mov ax,cs ;have interrupt go to the current segment
mov [si+2],ax
mov [si],dx ;set up our vector
pop ds
ret
_startRoundRobinScheduler:
;xchg bx, bx ;; bochs magic breakpoint, commented out to disable
;get the address of the service routine
mov dx,#_trapClockTickISRA
push ds
mov ax, #0 ;interrupts are in lowest memory
mov ds,ax
mov si,#0x70 ;interrupt 0x1C vector (address 0x0070)
mov ax,cs ;have interrupt go to the current segment
mov [si+2],ax
mov [si],dx ;set up our vector
pop ds
ret
;this is called when interrupt 21 happens
;it will call your function:
;void handleInterrupt21 (int AX, int BX, int CX, int DX)
_trapISRA:
push dx ; save dx, cx, bx, ax into the stack
push cx
push bx
push ax
call _trapISRC ; call the interrupt handler
pop ax ; restore the ax, bx, cx, dx from the stack
pop bx
pop cx
pop dx
iret
;this is called when interrupt 1C happens
;it will call your function:
;void handleInterrupt21 (int AX, int BX, int CX, int DX)
_trapClockTickISRA:
;push cx
inc [clockCounter]
mov si,KCLOCKTICKS
push ax
mov ah,0
mov al,BYTE PTR [clockCounter]
cmp ax,si
pop ax
jge doSwitchTask
iret
doSwitchTask:
push bp
mov bp,sp
push ax
mov al,0
mov BYTE PTR [clockCounter],al
;mov [callerBP],bp
;mov [callerSP],sp
mov ah,0
mov al,BYTE PTR [currentProg]
mov si,ax
shl si,1 ; multiply by 2
mov di,storedFlags
add di,si
mov ax,[bp+10]
mov [di],ax
mov di,storedCS
add di,si
mov ax,[bp+8]
mov [di],ax
mov di,storedIP
add di,si
mov ax,[bp+6]
mov [di],ax
mov di,storedSP
add di,si
mov ax,[bp+4]
mov [di],ax
mov di,storedBP
add di,si
mov ax,[bp+2]
mov [di],ax
mov di,storedAX
add di,si
mov ax,[bp]
mov [di],ax
mov di,storedBX
add di,si
mov [di],bx
mov di,storedCX
add di,si
mov [di],cx ;[sp]
mov di,storedDX
add di,si
mov [di],dx
schedLoop: ; loop until it finds a non-zero [storedCS] entry
add si,2 ; 1*2
and si,14 ; (8-1)*2. essentially performs a mod 8
mov di,storedCS
add di,si
mov ax,0
cmp [di],ax
je schedLoop ; continue loop, if the entry is zero
switchToProgram:
mov ax,si
mov BYTE PTR [currentProg],al
pop ax ; pop AX
pop dx ; pop BP
pop dx ; pop the IP register
pop dx ; pop the CS register
popf ; pop the flags register
mov di,storedCS
add di,si
mov ds,[di] ;set up the segment registers
mov ss,[di]
mov es,[di]
mov di,storedSP
add di,si
mov sp,[di] ;set up the stack pointer
mov di,storedBP
add di,si
mov bp,[di]
mov di,storedAX
add di,si
mov ax,[di] ; restore the general purpose registers
mov di,storedBX
add di,si
mov bx,[di]
mov di,storedCX
add di,si
mov cx,[di]
mov di,storedDX
add di,si
mov dx,[di]
mov di,storedFlags
add di,si
push [di] ; push the correct parameter on stack for 'iret' to work
mov di,storedCS
add di,si
push [di]
mov di,storedIP
add di,si
push [di]
iret
clockCounter: db 0
currentProg: db 0
storedAX: dw 0,0,0,0,0,0,0,0
storedBX: dw 0,0,0,0,0,0,0,0
storedCX: dw 0,0,0,0,0,0,0,0
storedDX: dw 0,0,0,0,0,0,0,0
storedSP: dw 0xfff0,0xfff0,0xfff0,0xfff0,0xfff0,0xfff0,0xfff0,0xfff0
storedBP: dw 0xfff0,0xfff0,0xfff0,0xfff0,0xfff0,0xfff0,0xfff0,0xfff0
storedCS: dw 0,0,0,0,0,0,0,0
storedIP: dw 0,0,0,0,0,0,0,0
storedFlags: dw 0,0,0,0,0,0,0,0
kernelBP: dw 0
kernelSP: dw 0
callerBP: dw 0xfff0
callerSP: dw 0xfff0