Subversion Repositories Kolibri OS

Rev

Rev 5984 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
431 serge 1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2
;;                                                              ;;
5565 serge 3
;; Copyright (C) KolibriOS team 2004-2015. All rights reserved. ;;
431 serge 4
;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
5
;; Distributed under terms of the GNU General Public License    ;;
6
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
7
 
593 mikedld 8
$Revision: 6339 $
9
 
10
 
1 ha 11
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12
;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
13
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
14
 
465 serge 15
 
1 ha 16
align 32
17
irq0:
1055 Galkov 18
        pushad
5599 serge 19
        mov     ax, app_data
20
        mov     ds, ax
1055 Galkov 21
        mov     es, ax
22
        inc     [timer_ticks]
23
        mov     eax, [timer_ticks]
24
        call    playNote       ; <<<--- Speaker driver
2434 Serge 25
        sub     eax, [next_usage_update]
26
        cmp     eax, 100
1055 Galkov 27
        jb      .nocounter
2434 Serge 28
        add     [next_usage_update], 100
1055 Galkov 29
        call    updatecputimes
30
  .nocounter:
2434 Serge 31
        xor     ecx, ecx        ; send End Of Interrupt signal
2166 serge 32
        call    irq_eoi
5201 serge 33
 
3626 Serge 34
        mov     bl, SCHEDULE_ANY_PRIORITY
1055 Galkov 35
        call    find_next_task
36
        jz      .return  ; if there is only one running process
37
        call    do_change_task
38
  .return:
39
        popad
40
        iretd
1 ha 41
 
101 poddubny 42
align 4
43
change_task:
1055 Galkov 44
        pushfd
45
        cli
46
        pushad
3626 Serge 47
        mov     bl, SCHEDULE_ANY_PRIORITY
1055 Galkov 48
        call    find_next_task
49
        jz      .return  ; the same task -> skip switch
5201 serge 50
 
1055 Galkov 51
        call    do_change_task
52
  .return:
53
        popad
54
        popfd
55
        ret
465 serge 56
 
101 poddubny 57
uglobal
1055 Galkov 58
align 4
59
   context_counter     dd 0 ;noname & halyavin
60
   next_usage_update   dd 0
61
   timer_ticks         dd 0
62
;  prev_slot           dd ?
63
;  event_sched         dd ?
101 poddubny 64
endg
65
 
1055 Galkov 66
align 4
101 poddubny 67
update_counters:
1055 Galkov 68
        mov     edi, [TASK_BASE]
69
        rdtsc
70
        sub     eax, [edi+TASKDATA.counter_add] ; time stamp counter add
71
        add     [edi+TASKDATA.counter_sum], eax ; counter sum
72
        ret
73
align 4
74
updatecputimes:
75
        mov     ecx, [TASK_COUNT]
76
        mov     edi, TASK_DATA
77
  .newupdate:
2434 Serge 78
        xor     eax, eax
79
        xchg    eax, [edi+TASKDATA.counter_sum]
80
        mov     [edi+TASKDATA.cpu_usage], eax
81
        add     edi, 0x20
1055 Galkov 82
        loop    .newupdate
83
        ret
1 ha 84
 
3555 Serge 85
;TODO: Надо бы убрать использование do_change_task из V86...
86
; и после этого перенести обработку TASKDATA.counter_add/sum в do_change_task
1 ha 87
 
1055 Galkov 88
align 4
101 poddubny 89
do_change_task:
1055 Galkov 90
;param:
91
;   ebx = address of the APPDATA for incoming task (new)
92
;warning:
93
;   [CURRENT_TASK] and [TASK_BASE] must be changed before (e.g. in find_next_task)
94
;   [current_slot] is the outcoming (old), and set here to a new value (ebx)
95
;scratched: eax,ecx,esi
2434 Serge 96
        mov     esi, ebx
97
        xchg    esi, [current_slot]
1220 serge 98
; set new stack after saving old
1055 Galkov 99
        mov     [esi+APPDATA.saved_esp], esp
100
        mov     esp, [ebx+APPDATA.saved_esp]
1220 serge 101
; set new thread io-map
5599 serge 102
        mov     eax, [ebx+APPDATA.io_map]
6339 serge 103
;        mov     dword [page_tabs+((tss._io_map_0 and -4096) shr 9)], eax
5599 serge 104
        mov     eax, [ebx+APPDATA.io_map+4]
6339 serge 105
;        mov     dword [page_tabs+((tss._io_map_1 and -4096) shr 9)], eax
1220 serge 106
; set new thread memory-map
5201 serge 107
        mov     eax, [ebx+APPDATA.process]
108
        cmp     eax, [current_process]
1055 Galkov 109
        je      @f
5201 serge 110
        mov     [current_process], eax
6339 serge 111
 
112
        mov     ecx, [eax+PROC.pdt_0_phys]
113
        mov     eax, [eax+PROC.pdt_1_phys]
114
        or      ecx, PG_READ
115
        or      eax, PG_READ
116
        mov     [sys_pml3],   ecx
117
        mov     [sys_pml3+8], eax
118
 
119
        or      ecx, PG_SWR
120
        or      eax, PG_SWR
121
 
122
        mov     [sys_pml2+OS_BASE+8192-20*8], ecx
123
        mov     [sys_pml2+OS_BASE+8192-19*8], eax
124
 
125
        mov     eax, sys_pml3-OS_BASE
1055 Galkov 126
        mov     cr3, eax
1220 serge 127
@@:
128
; set tss.esp0
129
 
5599 serge 130
        mov     eax, [ebx+APPDATA.saved_esp0]
131
        mov     [tss._esp0], eax
1220 serge 132
 
2434 Serge 133
        mov     edx, [ebx+APPDATA.tls_base]
1220 serge 134
 
2434 Serge 135
        mov     [tls_data_l+2], dx
136
        shr     edx, 16
137
        mov     [tls_data_l+4], dl
138
        mov     [tls_data_l+7], dh
1220 serge 139
 
2434 Serge 140
        mov     dx, app_tls
141
        mov     fs, dx
5565 serge 142
 
1220 serge 143
; set gs selector unconditionally
5599 serge 144
        Mov     ax, graph_data
145
        Mov     gs, ax
1055 Galkov 146
      ; set CR0.TS
147
        cmp     bh, byte[fpu_owner] ;bh == incoming task (new)
148
        clts                        ;clear a task switch flag
149
        je      @f
150
        mov     eax, cr0            ;and set it again if the owner
151
        or      eax, CR0_TS         ;of a fpu has changed
152
        mov     cr0, eax
153
  @@: ; set context_counter (only for user pleasure ???)
154
        inc     [context_counter]   ;noname & halyavin
155
      ; set debug-registers, if it's necessary
156
        test    byte[ebx+APPDATA.dbg_state], 1
157
        jz      @f
158
        xor     eax, eax
159
        mov     dr6, eax
5201 serge 160
        lea     esi, [ebx+APPDATA.dbg_regs]
1055 Galkov 161
        cld
162
  macro lodsReg [reg] {
163
        lodsd
2434 Serge 164
        mov     reg, eax
1055 Galkov 165
  }     lodsReg dr0, dr1, dr2, dr3, dr7
166
  purge lodsReg
2434 Serge 167
  @@:
168
        ret
1055 Galkov 169
;end.
465 serge 170
 
1434 serge 171
 
172
 
5565 serge 173
 
3555 Serge 174
MAX_PRIORITY      = 0   ; highest, used for kernel tasks
175
USER_PRIORITY     = 1   ; default
176
IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
177
NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
178
 
179
uglobal
180
; [scheduler_current + i*4] = zero if there are no threads with priority i,
181
;  pointer to APPDATA of the current thread with priority i otherwise.
182
align 4
183
scheduler_current       rd      NR_SCHED_QUEUES
184
endg
185
 
186
; Add the given thread to the given priority list for the scheduler.
187
; in: edx -> APPDATA, ecx = priority
188
proc scheduler_add_thread
189
; 1. Acquire the lock.
190
        spin_lock_irqsave SchedulerLock
191
; 2. Store the priority in APPDATA structure.
192
        mov     [edx+APPDATA.priority], ecx
193
; 3. There are two different cases: the given list is empty or not empty.
194
; In first case, go to 6. Otherwise, advance to 4.
195
        mov     eax, [scheduler_current+ecx*4]
196
        test    eax, eax
197
        jz      .new_list
198
; 4. Insert the new item immediately before the current item.
199
        mov     ecx, [eax+APPDATA.in_schedule.prev]
200
        mov     [edx+APPDATA.in_schedule.next], eax
201
        mov     [edx+APPDATA.in_schedule.prev], ecx
202
        mov     [eax+APPDATA.in_schedule.prev], edx
203
        mov     [ecx+APPDATA.in_schedule.next], edx
204
; 5. Release the lock and return.
205
        spin_unlock_irqrestore SchedulerLock
206
        ret
207
.new_list:
208
; 6. Initialize the list with one item and make it the current item.
209
        mov     [edx+APPDATA.in_schedule.next], edx
210
        mov     [edx+APPDATA.in_schedule.prev], edx
211
        mov     [scheduler_current+ecx*4], edx
212
; 7. Release the lock and return.
213
        spin_unlock_irqrestore SchedulerLock
214
        ret
215
endp
216
 
217
; Remove the given thread from the corresponding priority list for the scheduler.
218
; in: edx -> APPDATA
219
proc scheduler_remove_thread
220
; 1. Acquire the lock.
221
        spin_lock_irqsave SchedulerLock
222
; 2. Remove the item from the corresponding list.
223
        mov     eax, [edx+APPDATA.in_schedule.next]
224
        mov     ecx, [edx+APPDATA.in_schedule.prev]
225
        mov     [eax+APPDATA.in_schedule.prev], ecx
226
        mov     [ecx+APPDATA.in_schedule.next], eax
227
; 3. If the given thread is the current item in the list,
228
; advance the current item.
229
; 3a. Check whether the given thread is the current item;
230
; if no, skip the rest of this step.
231
        mov     ecx, [edx+APPDATA.priority]
232
        cmp     [scheduler_current+ecx*4], edx
233
        jnz     .return
234
; 3b. Set the current item to eax; step 2 has set eax = next item.
235
        mov     [scheduler_current+ecx*4], eax
236
; 3c. If there were only one item in the list, zero the current item.
237
        cmp     eax, edx
238
        jnz     .return
239
        mov     [scheduler_current+ecx*4], 0
240
.return:
241
; 4. Release the lock and return.
242
        spin_unlock_irqrestore SchedulerLock
243
        ret
244
endp
245
 
3626 Serge 246
SCHEDULE_ANY_PRIORITY = 0
247
SCHEDULE_HIGHER_PRIORITY = 1
3555 Serge 248
;info:
249
;   Find next task to execute
3626 Serge 250
;in:
251
;   bl = SCHEDULE_ANY_PRIORITY:
252
;        consider threads with any priority
253
;   bl = SCHEDULE_HIGHER_PRIORITY:
254
;        consider only threads with strictly higher priority than the current one,
255
;        keep running the current thread if other ready threads have the same or lower priority
3555 Serge 256
;retval:
257
;   ebx = address of the APPDATA for the selected task (slot-base)
258
;   edi = address of the TASKDATA for the selected task
259
;   ZF  = 1  if the task is the same
260
;warning:
261
;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
262
;   [current_slot] is not set to new value (ebx)!!!
263
;scratched: eax,ecx
264
proc find_next_task
265
        call    update_counters
266
        spin_lock_irqsave SchedulerLock
3626 Serge 267
        push    NR_SCHED_QUEUES
268
; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
269
; Otherwise, loop over first [APPDATA.priority] lists.
270
        test    bl, bl
271
        jz      .start
272
        mov     ebx, [current_slot]
273
        mov     edi, [TASK_BASE]
274
        mov     eax, [ebx+APPDATA.priority]
275
        test    eax, eax
276
        jz      .unlock_found
277
        mov     [esp], eax
278
.start:
3555 Serge 279
        xor     ecx, ecx
280
.priority_loop:
281
        mov     ebx, [scheduler_current+ecx*4]
282
        test    ebx, ebx
283
        jz      .priority_next
284
.task_loop:
285
        mov     ebx, [ebx+APPDATA.in_schedule.next]
286
        mov     edi, ebx
287
        shr     edi, 3
288
        add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
289
        mov     al, [edi+TASKDATA.state]
290
        test    al, al
291
        jz      .task_found     ; state == 0
292
        cmp     al, 5
293
        jne     .task_next      ; state == 1,2,3,4,9
294
      ; state == 5
295
        pushad  ; more freedom for [APPDATA.wait_test]
296
        call    [ebx+APPDATA.wait_test]
297
        mov     [esp+28], eax
298
        popad
5984 serge 299
        or      eax, eax
3555 Serge 300
        jnz     @f
301
      ; testing for timeout
302
        mov     eax, [timer_ticks]
303
        sub     eax, [ebx+APPDATA.wait_begin]
304
        cmp     eax, [ebx+APPDATA.wait_timeout]
305
        jb      .task_next
306
        xor     eax, eax
307
@@:
308
        mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
309
        mov     [edi+TASKDATA.state], 0
310
.task_found:
311
        mov     [scheduler_current+ecx*4], ebx
3626 Serge 312
; If we have selected a thread with higher priority
313
; AND rescheduling is due to IRQ,
314
; turn the current scheduler list one entry back,
315
; so the current thread will be next after high-priority thread is done.
316
        mov     ecx, [esp]
317
        cmp     ecx, NR_SCHED_QUEUES
318
        jz      .unlock_found
319
        mov     eax, [current_slot]
320
        mov     eax, [eax+APPDATA.in_schedule.prev]
321
        mov     [scheduler_current+ecx*4], eax
322
.unlock_found:
323
        pop     ecx
3555 Serge 324
        spin_unlock_irqrestore SchedulerLock
325
.found:
326
        mov     [CURRENT_TASK], bh
327
        mov     [TASK_BASE], edi
328
        rdtsc   ;call  _rdtsc
329
        mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
330
        cmp     ebx, [current_slot]
331
        ret
332
.task_next:
333
        cmp     ebx, [scheduler_current+ecx*4]
334
        jnz     .task_loop
335
.priority_next:
336
        inc     ecx
3626 Serge 337
        cmp     ecx, [esp]
3555 Serge 338
        jb      .priority_loop
3626 Serge 339
        mov     ebx, [current_slot]
340
        mov     edi, [TASK_BASE]
341
        jmp     .unlock_found
3555 Serge 342
endp
343
 
465 serge 344
if 0
1434 serge 345
 
465 serge 346
struc TIMER
347
{
348
  .next      dd ?
349
  .exp_time  dd ?
350
  .func      dd ?
1055 Galkov 351
  .arg       dd ?
465 serge 352
}
353
 
1276 Lrz 354
 
355
uglobal
465 serge 356
rdy_head   rd 16
1276 Lrz 357
endg
465 serge 358
 
359
align 4
360
pick_task:
361
 
2434 Serge 362
        xor     eax, eax
1055 Galkov 363
  .pick:
2434 Serge 364
        mov     ebx, [rdy_head+eax*4]
365
        test    ebx, ebx
366
        jz      .next
465 serge 367
 
2434 Serge 368
        mov     [next_task], ebx
369
        test    [ebx+flags.billable]
370
        jz      @F
371
        mov     [bill_task], ebx
1055 Galkov 372
  @@:
2434 Serge 373
        ret
1055 Galkov 374
  .next:
2434 Serge 375
        inc     eax
376
        jmp     .pick
465 serge 377
 
378
; param
379
;  eax= task
380
;
381
; retval
382
;  eax= task
383
;  ebx= queue
384
;  ecx= front if 1 or back if 0
385
align 4
386
shed:
2434 Serge 387
        cmp     [eax+.tics_left], 0;signed compare
388
        mov     ebx, [eax+.priority]
389
        setg    ecx
390
        jg      @F
465 serge 391
 
2434 Serge 392
        mov     edx, [eax+.tics_quantum]
393
        mov     [eax+.ticks_left], edx
394
        cmp     ebx, (IDLE_PRIORITY-1)
395
        je      @F
396
        inc     ebx
1055 Galkov 397
  @@:
2434 Serge 398
        ret
465 serge 399
 
400
; param
401
;  eax= task
402
align 4
403
enqueue:
2434 Serge 404
        call    shed;eax
405
        cmp     [rdy_head+ebx*4], 0
406
        jnz     @F
465 serge 407
 
2434 Serge 408
        mov     [rdy_head+ebx*4], eax
409
        mov     [rdy_tail+ebx*4], eax
410
        mov     [eax+.next_ready], 0
411
        jmp     .pick
1055 Galkov 412
  @@:
2434 Serge 413
        test    ecx, ecx
414
        jz      .back
465 serge 415
 
2434 Serge 416
        mov     ecx, [rdy_head+ebx*4]
417
        mov     [eax+.next_ready], ecx
418
        mov     [rdy_head+ebx*4], eax
419
        jmp     .pick
1055 Galkov 420
  .back:
2434 Serge 421
        mov     ecx, [rdy_tail+ebx*4]
422
        mov     [ecx+.next_ready], eax
423
        mov     [rdy_tail+ebx*4], eax
424
        mov     [eax+.next_ready], 0
1055 Galkov 425
  .pick:
2434 Serge 426
        call    pick_proc;select next task
427
        ret
465 serge 428
 
429
end if