Code: Select all
;----------------------------
PROC scheduler_add_scheduler, ptr2thread
;----------------------------
BEGIN
cli
; mov ebx,[ptr2thread]
;----------------------------
; wait till thread isn´t running anymore
;align 4
;.loop:
; test dword[ebx+thread_t.flags],THREAD_RUN
; je .go_on
; pause
; jmp .loop
;----------------------------
; get spinlock for the scheduler queues
;align 4
;.go_on:
CALL spinlock_acquire, schdl_flags
;----------------------------
; add thread to ready queue
mov esi,[ptr2thread] ;esi= actThread
mov ebx,1
mov ecx,[esi+thread_t.dyn_prio]
mov edi,ready_queue
shl ebx,cl
or [ready_queue_bitmap],ebx
mov eax,[edi+4*ecx] ;eax= firstThread
xor edx,edx
test eax,eax
jz .first
mov ebx,[eax+thread_t.prev] ;ebx= firstThread.prev= lastThread
mov [esi+thread_t.prev],ebx ;actThread.prev= lastThread
mov [esi+thread_t.next],edx ;actThread.next= NULL
mov [eax+thread_t.prev],esi ;firstThread.prev= actThread
mov [ebx+thread_t.next],esi ;lastThread.next= actThread
jmp .end
;----------------------------
; it is the 1st thread in this priority queue
align 4
.first:
mov [esi+thread_t.prev],esi ;actThread.prev= firstThread.prev= actThread
mov [esi+thread_t.next],eax ;actThread.next= firstThread.next= NULL
mov [edi+4*ecx],esi
;----------------------------
align 4
.end:
and dword[esi+thread_t.flags],not (THREAD_WAIT or THREAD_SLEEP)
or dword[schdl_flags],SCHEDULER_RESCHEDULE
CALL spinlock_release, schdl_flags
sti
RETURN
ENDP
;----------------------------
;----------------------------
PROC scheduler_dequeue_intel_smp, this_cpu
;----------------------------
BEGIN
;----------------------------
; get the thread with the highest priority
mov eax,[ready_queue_bitmap]
mov esi,ready_queue
;----------------------------
; get the highest priority thread
.get_thread:
bsr eax,eax
jz .idle
mov ebx,[esi+4*eax] ;ebx= firstThread
mov edx,[ebx+thread_t.next] ;edx= firstThread.next= secondThread
mov ecx,[ebx+thread_t.prev] ;ecx= firstThread.prev= lastThread
test edx,edx
jz .last
mov [esi+4*eax],edx ;firstThread= secondThread
mov [edx+thread_t.prev],ecx ;secondThread.prev= lastThread
mov eax,ebx
;----------------------------
; move the needed values from the thread struc in the right regs
.init:
CALL spinlock_release, schdl_flags
mov edx,[this_cpu]
cmp eax,[edx+cpu_t.schdl_act_thread]
je .set_time
mov [edx+cpu_t.schdl_act_thread],eax
;----------------------------
; set base addr for fs and gs regs
push eax
CALL gdt_set_base, dword[edx+cpu_t.fs], eax
pop eax
add eax,thread_t.free_start
CALL gdt_set_base, dword[edx+cpu_t.gs], eax
;----------------------------
; write the esp value for the ring0 code into the msr reg
mov eax,[fs:thread_t.esp0]
mov ecx,176h
xor edx,edx
wrmsr
jmp .set_time
;----------------------------
align 4
.idle:
mov edx,[this_cpu]
mov eax,[edx+cpu_t.idle_thread]
jmp .init
;----------------------------
; this is the last thread in the queue, so del the bit in the bitmap
align 4
.last:
xor ecx,ecx
mov edx,1
mov [esi+4*eax],ecx
mov ecx,eax
shl edx,cl
xor [ready_queue_bitmap],edx
mov eax,ebx
jmp .init
;----------------------------
align 4
.set_time:
;----------------------------
; we removed the thread from the queue and we need to give the thread some time 2 run
mov edx,[this_cpu]
xor ebx,ebx
mov eax,[edx+cpu_t.schdl_act_thread]
mov ecx,32
mov [eax+thread_t.prev],ebx
sub ecx,[eax+thread_t.dyn_prio]
mov [eax+thread_t.next],ebx
cmp ecx,32
jne .end
mov ecx,1
;----------------------------
.end:
mov edx,[eax+thread_t.dyn_prio]
mov edi,APIC_BASE_ADDR
mov [eax+thread_t.time2run],ecx
shr edx,1
xor dword[eax+thread_t.flags],THREAD_RUN or THREAD_READY
mov [edi+apic_regs_t.tpr],edx
RETURN
ENDP
;----------------------------
;----------------------------
PROC scheduler_enqueue_smp
;----------------------------
BEGIN
;----------------------------
; save esp
mov ebx,cr0
mov [eax+thread_t.esp3],ecx
;----------------------------
; test if need to save the fpu
test ebx,8
jne .go_on
mov edi,[eax+thread_t.ptr2fpu]
;----------------------------
; save fpu env
.fpu_save:
fxsave [edi]
or ebx,8
mov cr0,ebx
;----------------------------
; look if we just ran the idle thread
align 4
.go_on:
CALL spinlock_acquire, schdl_flags
cmp eax,dword[edx+cpu_t.idle_thread]
je .end
;----------------------------
; get and check the flags of the thread
mov ebx,[eax+thread_t.flags]
test ebx,THREAD_KILL
jne .kill
test ebx,THREAD_WAIT
jne .wait
test ebx,THREAD_SLEEP
jne .sleep
;----------------------------
; calc new priority
cmp dword[eax+thread_t.time2run],0
jne .do_it
mov ebx,[eax+thread_t.dyn_prio]
sub ebx,1
cmp ebx,[eax+thread_t.priority]
jl .do_it
mov [eax+thread_t.dyn_prio],ebx
;----------------------------
; enqueue the thread into the ready queue
.do_it:
mov ecx,[eax+thread_t.dyn_prio]
mov ebx,1
mov esi,ready_queue
shl ebx,cl
or [ready_queue_bitmap],ebx
mov edi,[esi+4*ecx] ;edi= firstThread
xor edx,edx
test edi,edi
jz .first
mov ebx,[edi+thread_t.prev] ;ebx= firstThread.prev= lastThread
mov [eax+thread_t.prev],ebx ;actThread.prev= lastThread
mov [eax+thread_t.next],edx ;actThread.next= NULL
mov [edi+thread_t.prev],eax ;firstThread.prev= actThread
mov [ebx+thread_t.next],eax ;lastThread.next= actThread
or dword[eax+thread_t.flags],THREAD_READY
jmp .end
;----------------------------
; it is the first thread in this priority
align 4
.first:
mov [eax+thread_t.prev],eax ;actThread.prev= firstThread.prev= actThread
mov [eax+thread_t.next],edi ;actThread.next= firstThread.next= NULL
mov [esi+4*ecx],eax
jmp .end
;----------------------------
; the thread waits for something in a wait queue
align 4
.wait:
cmp dword[eax+thread_t.dyn_prio],31
je .end
mov ebx,[eax+thread_t.dyn_prio]
mov edx,[eax+thread_t.priority]
add ebx,1
add edx,5
cmp ebx,edx
jg .end
mov [eax+thread_t.dyn_prio],ebx
jmp .end
;----------------------------
; the owner of the thread is going to be killed
align 4
.kill:
xor ecx,ecx
mov [eax+thread_t.prev],ecx
mov [eax+thread_t.next],ecx
jmp .end
;----------------------------
; the thread wants to sleep
align 4
.sleep:
;to-do
jmp .end
;----------------------------
align 4
.end:
and dword[eax+thread_t.flags],not (THREAD_RESCHEDULE or THREAD_RUN)
and dword[schdl_flags],not SCHEDULER_RESCHEDULE
RETURN
ENDP
;----------------------------
;----------------------------
PROC scheduler_smp
;----------------------------
BEGIN_IRQ
;----------------------------
; get cpu ptr and tss ptr
APIC_GET_ID eax
mov edx,[CPU_PTR+4*eax]
mov ebx,[TSS_PTR+4*eax]
;----------------------------
align 4
.entry:
;----------------------------
; inc the timer
add dword[edx+cpu_t.timer],1
adc dword[edx+cpu_t.timer+4],0
;----------------------------
; move the ptr of the act thrad into eax
mov eax,[edx+cpu_t.schdl_act_thread]
;----------------------------
; check if we need to reschedule
test dword[schdl_flags],SCHEDULER_RESCHEDULE
jne .next_thread
test dword[eax+thread_t.flags],THREAD_RESCHEDULE
jne .next_thread
;----------------------------
; check if the thread has more time 2 run
sub dword[eax+thread_t.time2run],1
jnz .end
;----------------------------
; put thread back on a queue and get a new one
.next_thread:
mov ecx,esp
mov esp,[edx+cpu_t.scheduler_esp]
push ebx edx
CALL scheduler_enqueue_smp
CALL dword[scheduler_dequeue_smp]
;----------------------------
; check if this is a ring0 thread
mov ecx,[eax+thread_t.esp0]
mov edx,cr3
mov ebx,[eax+thread_t.pd]
test ecx,ecx
jz .stack_change
;----------------------------
; check if we need to change cr3
cmp ebx,edx
je .stack_change
mov cr3,ebx
;----------------------------
; set new esp
.stack_change:
pop edx ebx
mov esp,[eax+thread_t.esp3]
mov [ebx+tss_t.esp0],ecx
;----------------------------
; test if we need to send an eoi
btr dword[edx+cpu_t.scheduler_flags],1
jnc .end
RETURN_NOAPIC
;----------------------------
align 4
.end:
RETURN_APIC
ENDP
;----------------------------