0,0 → 1,286 |
label next_usage_update dword at 0xB008 |
label timer_ticks dword at 0xFDF0 |
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
;; IRQ0 HANDLER (TIMER INTERRUPT) ;; |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; |
|
align 32 |
irq0: |
|
cmp [error_interrupt],-1 |
je no_error_in_previous_process |
|
mov edi,[error_interrupt] |
shl edi, 3 |
mov [edi+tss0i_l +5], word 01010000b *256 +11101001b |
|
mov edi,[error_interrupt] |
shl edi,7 |
add edi,0x290000 |
mov esi,[error_interrupt_entry] |
mov [edi+l.eip-tss_sceleton],esi |
mov [edi+l.eflags-tss_sceleton],dword 0x11002 |
|
mov [0xffff],byte 0 |
|
mov [error_interrupt],-1 |
|
no_error_in_previous_process: |
|
mov edi,[0x3000] |
shl edi, 3 |
; fields of TSS descriptor: |
mov [edi+gdts+ tss0 +5], word 01010000b *256 +11101001b |
|
inc dword [timer_ticks] |
|
mov eax, [timer_ticks] |
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
call playNote ; <<<--- INSERT THIS LINE !!!!!!!!!! |
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
|
cmp eax,[next_usage_update] |
jb .nocounter |
add eax,100 |
mov [next_usage_update],eax |
call updatecputimes |
.nocounter: |
|
mov edi, [0x3010] |
|
mov ebx, [edi+0x18] ; time stamp counter add |
call _rdtsc |
sub eax, ebx |
add eax, [edi+0x14] ; counter sum |
mov [edi+0x14], eax |
|
mov ebx,[0x3000] |
|
cmp [0xffff], byte 1 ;1 |
je do_not_change_task ;je |
|
.waiting_for_termination: |
.waiting_for_reuse: |
.waiting_on_queue: |
add edi,0x20 |
inc ebx |
|
mov al, byte [edi+0xA] |
cmp al, 3 |
je .waiting_for_termination |
cmp al, 4 |
je .waiting_for_termination |
cmp al, 9 |
je .waiting_for_reuse |
cmp al, 16 |
je .waiting_on_queue |
cmp al, 17 |
je .waiting_on_queue |
|
cmp ebx,[0x3004] |
jbe nsched0 |
mov ebx,1 |
mov edi,0x3020 |
|
nsched0: |
|
mov [0x3000],ebx |
mov [0x3010],edi |
|
do_not_change_task: |
|
mov edx,[0x3000] |
lea edx,[tss0sys+8*edx] |
;mov [8*0x40+idts+8+0], word 0 |
mov [8*0x40+idts+8+2],dx |
;mov [8*0x40+idts+8+4],word 11100101b*256 |
;mov [8*0x40+idts+8+6], word 0 |
|
call _rdtsc |
mov [edi+0x18],eax |
|
cmp [0xffff],byte 0 |
je nodecffff |
dec byte [0xffff] |
nodecffff: |
|
|
shl ebx, 3 |
xor eax, eax |
add ebx, tss0 |
mov word [0xB004], bx ; selector ;mov [tss_s],bx |
mov dword [0xB000], eax ; offset |
|
mov al,0x20 ; send End Of Interrupt signal |
mov dx,0x20 |
out dx,al |
.switch: |
jmp pword [0xB000] |
inc [context_counter] ;noname & halyavin |
jmp irq0 |
|
iglobal |
context_counter dd 0 ;noname & halyavin |
endg |
|
|
align 4 |
change_task: |
|
mov [0xffff],byte 2 |
|
dec dword [timer_ticks] ; because irq0 will increase it |
|
int 0x20 ; irq0 handler |
|
ret |
|
|
|
align 4 |
updatecputimes: |
|
mov eax,[idleuse] |
mov [idleusesec],eax |
mov [idleuse],dword 0 |
mov ecx, [0x3004] |
mov edi, 0x3020 |
.newupdate: |
mov ebx,[edi+0x14] |
mov [edi+0x1c],ebx |
mov [edi+0x14],dword 0 |
add edi,0x20 |
dec ecx |
jnz .newupdate |
|
ret |
|
|
|
; |
; Wait queue is 16 bytes |
; dd return code +12 |
; dd pointer to process +8 |
; dd prev +4 |
; dd next +0 |
; |
; eax - pointer to pointer to the wait queue |
; return: |
; ecx - return code |
sleep_on_queue: |
sub esp,16 ; reserve space for wait node |
mov ecx,esp ; ecx=this_node, [eax]=queue |
|
pusha |
|
mov ebx,[0x3010] ; get pointer to the current process |
mov [ecx+8],ebx |
|
pushf |
cli ; adding element to the wait queue must be atomic |
|
mov edi,[eax] ; edi=queue |
and edi,edi ; check if queue is empty |
jz .is_empty |
|
; add element at the end of wait queue |
|
mov edx,[edi+4] ; get pointer to prev edx=queue->prev |
mov [ecx+4],edx ; this_node->prev=queue->prev |
mov [ecx+0],edi ; this_node->next=queue |
mov [edx+0],ecx ; this_node->prev->next=this_node |
mov [edi+4],ecx ; queue->prev=this_node |
jmp .added_ok |
.is_empty: |
; set this element as first in the queue |
mov [ecx+0],ecx ; this_node->next=this_node |
mov [ecx+4],ecx ; this_node->prev=this_node |
mov [eax],ecx ; [queue]=this_node |
.added_ok: |
|
popf ; we can safely restore interrupts |
|
mov [ebx+0xa],byte 17 ; set current task state as sleeping |
call change_task ; schedule new thread |
|
; someone has called wake_up_queue |
|
pushf ; disable interrupts |
cli |
|
mov edx,[ecx+0] ; edx=this_node->next |
mov esi,[ecx+4] ; esi=this_node->prev |
|
; check if we need to remove this node from head |
cmp [eax],ecx |
jne .no_head |
|
cmp [ecx+0],ecx ; check if queue is empty |
jne .not_empty |
|
mov [eax],dword 0 |
jmp .no_head |
|
.not_empty: |
mov [eax],edx |
|
; remove our node from the queue (this must be atomic) |
.no_head: |
mov [edx+4],esi ; this_node->next->prev=this_node->prev |
mov [esi+0],edx ; this_node->prev->next=this_node->next |
|
popf |
popa |
add esp,12 |
pop ecx |
ret |
|
; eax - pointer to the wait queue |
; ebx - wake up all (1=yes, 0=no) |
; ecx - return code |
; return: |
; ebx - number of processes woken |
wake_up_queue: |
and eax,eax |
jnz .nz |
ret |
.nz: |
push eax |
push ebx |
push ecx |
push edx |
push esi |
|
pushf |
cli |
|
xor ebx,ebx |
mov edx,eax |
.wake_loop: |
|
mov [edx+12],ecx |
mov esi,[edx+8] |
mov byte [esi+0xa],0 |
inc ebx |
|
mov edx,[edx+0] |
cmp edx,eax |
jne .wake_loop |
|
and ebx,ebx |
jz .wake_up_1 |
|
.return_it: |
popf |
pop esi |
pop edx |
pop ecx |
add esp,4 |
pop eax |
ret |
.wake_up_1: |
mov [eax+12],ecx |
mov ecx,[eax+8] |
mov byte [ecx+0xa],0 |
jmp .return_it |