Subversion Repositories Kolibri OS

Rev

Rev 3615 | Rev 5130 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2012. All rights reserved. ;;
  4. ;; Copyright (C) MenuetOS 2000-2004 Ville Mikael Turjanmaa      ;;
  5. ;; Distributed under terms of the GNU General Public License    ;;
  6. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  7.  
  8. $Revision: 3617 $
  9.  
  10.  
  11. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  12. ;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14.  
  15.  
  16. align 32
  17. irq0:
  18.         pushad
  19.         Mov     ds, ax, app_data
  20.         mov     es, ax
  21.         inc     [timer_ticks]
  22.         mov     eax, [timer_ticks]
  23.         call    playNote       ; <<<--- Speaker driver
  24.         sub     eax, [next_usage_update]
  25.         cmp     eax, 100
  26.         jb      .nocounter
  27.         add     [next_usage_update], 100
  28.         call    updatecputimes
  29.   .nocounter:
  30.         xor     ecx, ecx        ; send End Of Interrupt signal
  31.         call    irq_eoi
  32. ;        btr     dword[DONT_SWITCH], 0
  33. ;        jc      .return
  34.         mov     bl, SCHEDULE_ANY_PRIORITY
  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
  41.  
  42. align 4
  43. change_task:
  44.         pushfd
  45.         cli
  46.         pushad
  47. if 0
  48. ; \begin{Mario79} ; <- must be refractoried, if used...
  49.         cmp     [dma_task_switched], 1
  50.         jne     .find_next_task
  51.         mov     [dma_task_switched], 0
  52.         mov     ebx, [dma_process]
  53.         cmp     [CURRENT_TASK], ebx
  54.         je      .return
  55.         mov     edi, [dma_slot_ptr]
  56.         mov     [CURRENT_TASK], ebx
  57.         mov     [TASK_BASE], edi
  58.         jmp     @f
  59. .find_next_task:
  60. ; \end{Mario79}
  61. end if
  62.         mov     bl, SCHEDULE_ANY_PRIORITY
  63.         call    find_next_task
  64.         jz      .return  ; the same task -> skip switch
  65.   @@:
  66. ;        mov     byte[DONT_SWITCH], 1
  67.         call    do_change_task
  68.   .return:
  69.         popad
  70.         popfd
  71.         ret
  72.  
  73. uglobal
  74. align 4
  75. ;  far_jump:
  76. ;   .offs dd ?
  77. ;   .sel  dw ?
  78.    context_counter     dd 0 ;noname & halyavin
  79.    next_usage_update   dd 0
  80.    timer_ticks         dd 0
  81. ;  prev_slot           dd ?
  82. ;  event_sched         dd ?
  83. endg
  84.  
  85. align 4
  86. update_counters:
  87.         mov     edi, [TASK_BASE]
  88.         rdtsc
  89.         sub     eax, [edi+TASKDATA.counter_add] ; time stamp counter add
  90.         add     [edi+TASKDATA.counter_sum], eax ; counter sum
  91.         ret
  92. align 4
  93. updatecputimes:
  94.         mov     ecx, [TASK_COUNT]
  95.         mov     edi, TASK_DATA
  96.   .newupdate:
  97.         xor     eax, eax
  98.         xchg    eax, [edi+TASKDATA.counter_sum]
  99.         mov     [edi+TASKDATA.cpu_usage], eax
  100.         add     edi, 0x20
  101.         loop    .newupdate
  102.         ret
  103.  
  104. ;TODO: Надо бы убрать использование do_change_task из V86...
  105. ; и после этого перенести обработку TASKDATA.counter_add/sum в do_change_task
  106.  
  107. align 4
  108. do_change_task:
  109. ;param:
  110. ;   ebx = address of the APPDATA for incoming task (new)
  111. ;warning:
  112. ;   [CURRENT_TASK] and [TASK_BASE] must be changed before (e.g. in find_next_task)
  113. ;   [current_slot] is the outcoming (old), and set here to a new value (ebx)
  114. ;scratched: eax,ecx,esi
  115.         mov     esi, ebx
  116.         xchg    esi, [current_slot]
  117. ; set new stack after saving old
  118.         mov     [esi+APPDATA.saved_esp], esp
  119.         mov     esp, [ebx+APPDATA.saved_esp]
  120. ; set new thread io-map
  121.         Mov     dword [page_tabs+((tss._io_map_0 and -4096) shr 10)],eax,[ebx+APPDATA.io_map]
  122.         Mov     dword [page_tabs+((tss._io_map_1 and -4096) shr 10)],eax,[ebx+APPDATA.io_map+4]
  123. ; set new thread memory-map
  124.         mov     ecx, APPDATA.dir_table
  125.         mov     eax, [ebx+ecx]      ;offset>0x7F
  126.         cmp     eax, [esi+ecx]      ;offset>0x7F
  127.         je      @f
  128.         mov     cr3, eax
  129. @@:
  130. ; set tss.esp0
  131.  
  132.         Mov     [tss._esp0],eax,[ebx+APPDATA.saved_esp0]
  133.  
  134.         mov     edx, [ebx+APPDATA.tls_base]
  135.         cmp     edx, [esi+APPDATA.tls_base]
  136.         je      @f
  137.  
  138.         mov     [tls_data_l+2], dx
  139.         shr     edx, 16
  140.         mov     [tls_data_l+4], dl
  141.         mov     [tls_data_l+7], dh
  142.  
  143.         mov     dx, app_tls
  144.         mov     fs, dx
  145. @@:
  146. ; set gs selector unconditionally
  147.         Mov     gs,ax,graph_data
  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
  158.         test    byte[ebx+APPDATA.dbg_state], 1
  159.         jz      @f
  160.         xor     eax, eax
  161.         mov     dr6, eax
  162.         lea     esi, [ebx+ecx+APPDATA.dbg_regs-APPDATA.dir_table];offset>0x7F
  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.  
  175. struct  MUTEX_WAITER
  176.         list    LHEAD
  177.         task    dd ?
  178. ends
  179.  
  180. ;void  __fastcall mutex_init(struct mutex *lock)
  181.  
  182. align 4
  183. mutex_init:
  184.         mov     [ecx+MUTEX.lhead.next], ecx
  185.         mov     [ecx+MUTEX.lhead.prev], ecx
  186.         mov     [ecx+MUTEX.count], 1
  187.         ret
  188.  
  189.  
  190. ;void  __fastcall mutex_lock(struct mutex *lock)
  191.  
  192. align 4
  193. mutex_lock:
  194.  
  195.         dec     [ecx+MUTEX.count]
  196.         jns     .done
  197.  
  198.         pushfd
  199.         cli
  200.  
  201.         sub     esp, sizeof.MUTEX_WAITER
  202.  
  203.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  204.  
  205.         mov     edx, [TASK_BASE]
  206.         mov     [esp+MUTEX_WAITER.task], edx
  207.  
  208. .forever:
  209.  
  210.         mov     eax, -1
  211.         xchg    eax, [ecx+MUTEX.count]
  212.         dec     eax
  213.         jz      @F
  214.  
  215.         mov     [edx+TASKDATA.state], 1
  216.         call    change_task
  217.         jmp     .forever
  218. @@:
  219.         mov     edx, [esp+MUTEX_WAITER.list.next]
  220.         mov     eax, [esp+MUTEX_WAITER.list.prev]
  221.  
  222.         mov     [eax+MUTEX_WAITER.list.next], edx
  223.         mov     [edx+MUTEX_WAITER.list.prev], eax
  224.         cmp     [ecx+MUTEX.lhead.next], ecx
  225.         jne     @F
  226.  
  227.         mov     [ecx+MUTEX.count], 0
  228. @@:
  229.         add     esp, sizeof.MUTEX_WAITER
  230.  
  231.         popfd
  232. .done:
  233.         ret
  234.  
  235. ;void  __fastcall mutex_unlock(struct mutex *lock)
  236.  
  237. align 4
  238. mutex_unlock:
  239.  
  240.         pushfd
  241.         cli
  242.  
  243.         mov     eax, [ecx+MUTEX.lhead.next]
  244.         cmp     eax, ecx
  245.         mov     [ecx+MUTEX.count], 1
  246.         je      @F
  247.  
  248.         mov     eax, [eax+MUTEX_WAITER.task]
  249.         mov     [eax+TASKDATA.state], 0
  250. @@:
  251.         popfd
  252.         ret
  253.  
  254.  
  255. purge MUTEX_WAITER
  256.  
  257. MAX_PRIORITY      = 0   ; highest, used for kernel tasks
  258. USER_PRIORITY     = 1   ; default
  259. IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
  260. NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
  261.  
  262. uglobal
  263. ; [scheduler_current + i*4] = zero if there are no threads with priority i,
  264. ;  pointer to APPDATA of the current thread with priority i otherwise.
  265. align 4
  266. scheduler_current       rd      NR_SCHED_QUEUES
  267. endg
  268.  
  269. ; Add the given thread to the given priority list for the scheduler.
  270. ; in: edx -> APPDATA, ecx = priority
  271. proc scheduler_add_thread
  272. ; 1. Acquire the lock.
  273.         spin_lock_irqsave SchedulerLock
  274. ; 2. Store the priority in APPDATA structure.
  275.         mov     [edx+APPDATA.priority], ecx
  276. ; 3. There are two different cases: the given list is empty or not empty.
  277. ; In first case, go to 6. Otherwise, advance to 4.
  278.         mov     eax, [scheduler_current+ecx*4]
  279.         test    eax, eax
  280.         jz      .new_list
  281. ; 4. Insert the new item immediately before the current item.
  282.         mov     ecx, [eax+APPDATA.in_schedule.prev]
  283.         mov     [edx+APPDATA.in_schedule.next], eax
  284.         mov     [edx+APPDATA.in_schedule.prev], ecx
  285.         mov     [eax+APPDATA.in_schedule.prev], edx
  286.         mov     [ecx+APPDATA.in_schedule.next], edx
  287. ; 5. Release the lock and return.
  288.         spin_unlock_irqrestore SchedulerLock
  289.         ret
  290. .new_list:
  291. ; 6. Initialize the list with one item and make it the current item.
  292.         mov     [edx+APPDATA.in_schedule.next], edx
  293.         mov     [edx+APPDATA.in_schedule.prev], edx
  294.         mov     [scheduler_current+ecx*4], edx
  295. ; 7. Release the lock and return.
  296.         spin_unlock_irqrestore SchedulerLock
  297.         ret
  298. endp
  299.  
  300. ; Remove the given thread from the corresponding priority list for the scheduler.
  301. ; in: edx -> APPDATA
  302. proc scheduler_remove_thread
  303. ; 1. Acquire the lock.
  304.         spin_lock_irqsave SchedulerLock
  305. ; 2. Remove the item from the corresponding list.
  306.         mov     eax, [edx+APPDATA.in_schedule.next]
  307.         mov     ecx, [edx+APPDATA.in_schedule.prev]
  308.         mov     [eax+APPDATA.in_schedule.prev], ecx
  309.         mov     [ecx+APPDATA.in_schedule.next], eax
  310. ; 3. If the given thread is the current item in the list,
  311. ; advance the current item.
  312. ; 3a. Check whether the given thread is the current item;
  313. ; if no, skip the rest of this step.
  314.         mov     ecx, [edx+APPDATA.priority]
  315.         cmp     [scheduler_current+ecx*4], edx
  316.         jnz     .return
  317. ; 3b. Set the current item to eax; step 2 has set eax = next item.
  318.         mov     [scheduler_current+ecx*4], eax
  319. ; 3c. If there were only one item in the list, zero the current item.
  320.         cmp     eax, edx
  321.         jnz     .return
  322.         mov     [scheduler_current+ecx*4], 0
  323. .return:
  324. ; 4. Release the lock and return.
  325.         spin_unlock_irqrestore SchedulerLock
  326.         ret
  327. endp
  328.  
  329. SCHEDULE_ANY_PRIORITY = 0
  330. SCHEDULE_HIGHER_PRIORITY = 1
  331. ;info:
  332. ;   Find next task to execute
  333. ;in:
  334. ;   bl = SCHEDULE_ANY_PRIORITY:
  335. ;        consider threads with any priority
  336. ;   bl = SCHEDULE_HIGHER_PRIORITY:
  337. ;        consider only threads with strictly higher priority than the current one,
  338. ;        keep running the current thread if other ready threads have the same or lower priority
  339. ;retval:
  340. ;   ebx = address of the APPDATA for the selected task (slot-base)
  341. ;   edi = address of the TASKDATA for the selected task
  342. ;   ZF  = 1  if the task is the same
  343. ;warning:
  344. ;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
  345. ;   [current_slot] is not set to new value (ebx)!!!
  346. ;scratched: eax,ecx
  347. proc find_next_task
  348.         call    update_counters
  349.         spin_lock_irqsave SchedulerLock
  350.         push    NR_SCHED_QUEUES
  351. ; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
  352. ; Otherwise, loop over first [APPDATA.priority] lists.
  353.         test    bl, bl
  354.         jz      .start
  355.         mov     ebx, [current_slot]
  356.         mov     edi, [TASK_BASE]
  357.         mov     eax, [ebx+APPDATA.priority]
  358.         test    eax, eax
  359.         jz      .unlock_found
  360.         mov     [esp], eax
  361. .start:
  362.         xor     ecx, ecx
  363. .priority_loop:
  364.         mov     ebx, [scheduler_current+ecx*4]
  365.         test    ebx, ebx
  366.         jz      .priority_next
  367. .task_loop:
  368.         mov     ebx, [ebx+APPDATA.in_schedule.next]
  369.         mov     edi, ebx
  370.         shr     edi, 3
  371.         add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
  372.         mov     al, [edi+TASKDATA.state]
  373.         test    al, al
  374.         jz      .task_found     ; state == 0
  375.         cmp     al, 5
  376.         jne     .task_next      ; state == 1,2,3,4,9
  377.       ; state == 5
  378.         pushad  ; more freedom for [APPDATA.wait_test]
  379.         call    [ebx+APPDATA.wait_test]
  380.         mov     [esp+28], eax
  381.         popad
  382.         or      eax, eax
  383.         jnz     @f
  384.       ; testing for timeout
  385.         mov     eax, [timer_ticks]
  386.         sub     eax, [ebx+APPDATA.wait_begin]
  387.         cmp     eax, [ebx+APPDATA.wait_timeout]
  388.         jb      .task_next
  389.         xor     eax, eax
  390. @@:
  391.         mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
  392.         mov     [edi+TASKDATA.state], 0
  393. .task_found:
  394.         mov     [scheduler_current+ecx*4], ebx
  395. ; If we have selected a thread with higher priority
  396. ; AND rescheduling is due to IRQ,
  397. ; turn the current scheduler list one entry back,
  398. ; so the current thread will be next after high-priority thread is done.
  399.         mov     ecx, [esp]
  400.         cmp     ecx, NR_SCHED_QUEUES
  401.         jz      .unlock_found
  402.         mov     eax, [current_slot]
  403.         mov     eax, [eax+APPDATA.in_schedule.prev]
  404.         mov     [scheduler_current+ecx*4], eax
  405. .unlock_found:
  406.         pop     ecx
  407.         spin_unlock_irqrestore SchedulerLock
  408. .found:
  409.         mov     [CURRENT_TASK], bh
  410.         mov     [TASK_BASE], edi
  411.         rdtsc   ;call  _rdtsc
  412.         mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
  413.         cmp     ebx, [current_slot]
  414.         ret
  415. .task_next:
  416.         cmp     ebx, [scheduler_current+ecx*4]
  417.         jnz     .task_loop
  418. .priority_next:
  419.         inc     ecx
  420.         cmp     ecx, [esp]
  421.         jb      .priority_loop
  422.         mov     ebx, [current_slot]
  423.         mov     edi, [TASK_BASE]
  424.         jmp     .unlock_found
  425. endp
  426.  
  427. if 0
  428.  
  429. struc TIMER
  430. {
  431.   .next      dd ?
  432.   .exp_time  dd ?
  433.   .func      dd ?
  434.   .arg       dd ?
  435. }
  436.  
  437.  
  438. uglobal
  439. rdy_head   rd 16
  440. endg
  441.  
  442. align 4
  443. pick_task:
  444.  
  445.         xor     eax, eax
  446.   .pick:
  447.         mov     ebx, [rdy_head+eax*4]
  448.         test    ebx, ebx
  449.         jz      .next
  450.  
  451.         mov     [next_task], ebx
  452.         test    [ebx+flags.billable]
  453.         jz      @F
  454.         mov     [bill_task], ebx
  455.   @@:
  456.         ret
  457.   .next:
  458.         inc     eax
  459.         jmp     .pick
  460.  
  461. ; param
  462. ;  eax= task
  463. ;
  464. ; retval
  465. ;  eax= task
  466. ;  ebx= queue
  467. ;  ecx= front if 1 or back if 0
  468. align 4
  469. shed:
  470.         cmp     [eax+.tics_left], 0;signed compare
  471.         mov     ebx, [eax+.priority]
  472.         setg    ecx
  473.         jg      @F
  474.  
  475.         mov     edx, [eax+.tics_quantum]
  476.         mov     [eax+.ticks_left], edx
  477.         cmp     ebx, (IDLE_PRIORITY-1)
  478.         je      @F
  479.         inc     ebx
  480.   @@:
  481.         ret
  482.  
  483. ; param
  484. ;  eax= task
  485. align 4
  486. enqueue:
  487.         call    shed;eax
  488.         cmp     [rdy_head+ebx*4], 0
  489.         jnz     @F
  490.  
  491.         mov     [rdy_head+ebx*4], eax
  492.         mov     [rdy_tail+ebx*4], eax
  493.         mov     [eax+.next_ready], 0
  494.         jmp     .pick
  495.   @@:
  496.         test    ecx, ecx
  497.         jz      .back
  498.  
  499.         mov     ecx, [rdy_head+ebx*4]
  500.         mov     [eax+.next_ready], ecx
  501.         mov     [rdy_head+ebx*4], eax
  502.         jmp     .pick
  503.   .back:
  504.         mov     ecx, [rdy_tail+ebx*4]
  505.         mov     [ecx+.next_ready], eax
  506.         mov     [rdy_tail+ebx*4], eax
  507.         mov     [eax+.next_ready], 0
  508.   .pick:
  509.         call    pick_proc;select next task
  510.         ret
  511.  
  512. end if
  513.