Subversion Repositories Kolibri OS

Rev

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

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