Subversion Repositories Kolibri OS

Rev

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

  1. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  2. ;;                                                              ;;
  3. ;; Copyright (C) KolibriOS team 2004-2015. 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: 5788 $
  9.  
  10.  
  11. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  12. ;; IRQ0 HANDLER (TIMER INTERRUPT) ;;
  13. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  14.  
  15.  
  16. align 32
  17. irq0:
  18.         pushad
  19.         mov     ax, app_data
  20.         mov     ds, ax
  21.         mov     es, ax
  22.         inc     [timer_ticks]
  23.         mov     eax, [timer_ticks]
  24.         call    playNote       ; <<<--- Speaker driver
  25.         sub     eax, [next_usage_update]
  26.         cmp     eax, 100
  27.         jb      .nocounter
  28.         add     [next_usage_update], 100
  29.         call    updatecputimes
  30.   .nocounter:
  31.         xor     ecx, ecx        ; send End Of Interrupt signal
  32.         call    irq_eoi
  33.  
  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.         mov     bl, SCHEDULE_ANY_PRIORITY
  48.         call    find_next_task
  49.         jz      .return  ; the same task -> skip switch
  50.  
  51.         call    do_change_task
  52.   .return:
  53.         popad
  54.         popfd
  55.         ret
  56.  
  57. uglobal
  58. align 4
  59. ;  far_jump:
  60. ;   .offs dd ?
  61. ;   .sel  dw ?
  62.    context_counter     dd 0 ;noname & halyavin
  63.    next_usage_update   dd 0
  64.    timer_ticks         dd 0
  65. ;  prev_slot           dd ?
  66. ;  event_sched         dd ?
  67. endg
  68.  
  69. align 4
  70. update_counters:
  71.         mov     edi, [TASK_BASE]
  72.         rdtsc
  73.         sub     eax, [edi+TASKDATA.counter_add] ; time stamp counter add
  74.         add     [edi+TASKDATA.counter_sum], eax ; counter sum
  75.         ret
  76. align 4
  77. updatecputimes:
  78.         mov     ecx, [TASK_COUNT]
  79.         mov     edi, TASK_DATA
  80.   .newupdate:
  81.         xor     eax, eax
  82.         xchg    eax, [edi+TASKDATA.counter_sum]
  83.         mov     [edi+TASKDATA.cpu_usage], eax
  84.         add     edi, 0x20
  85.         loop    .newupdate
  86.         ret
  87.  
  88. ;TODO: Надо бы убрать использование do_change_task из V86...
  89. ; и после этого перенести обработку TASKDATA.counter_add/sum в do_change_task
  90.  
  91. align 4
  92. do_change_task:
  93. ;param:
  94. ;   ebx = address of the APPDATA for incoming task (new)
  95. ;warning:
  96. ;   [CURRENT_TASK] and [TASK_BASE] must be changed before (e.g. in find_next_task)
  97. ;   [current_slot] is the outcoming (old), and set here to a new value (ebx)
  98. ;scratched: eax,ecx,esi
  99.         mov     esi, ebx
  100.         xchg    esi, [current_slot]
  101. ; set new stack after saving old
  102.         mov     [esi+APPDATA.saved_esp], esp
  103.         mov     esp, [ebx+APPDATA.saved_esp]
  104. ; set new thread io-map
  105.         mov     eax, [ebx+APPDATA.io_map]
  106.         mov     dword [page_tabs+((tss._io_map_0 and -4096) shr 10)], eax
  107.         mov     eax, [ebx+APPDATA.io_map+4]
  108.         mov     dword [page_tabs+((tss._io_map_1 and -4096) shr 10)], eax
  109. ; set new thread memory-map
  110.         mov     eax, [ebx+APPDATA.process]
  111.         cmp     eax, [current_process]
  112.         je      @f
  113.         mov     [current_process], eax
  114.         mov     eax, [eax+PROC.pdt_0_phys]
  115.         mov     cr3, eax
  116. @@:
  117. ; set tss.esp0
  118.  
  119.         mov     eax, [ebx+APPDATA.saved_esp0]
  120.         mov     [tss._esp0], eax
  121.  
  122.         mov     edx, [ebx+APPDATA.tls_base]
  123.  
  124.         mov     [tls_data_l+2], dx
  125.         shr     edx, 16
  126.         mov     [tls_data_l+4], dl
  127.         mov     [tls_data_l+7], dh
  128.  
  129.         mov     dx, app_tls
  130.         mov     fs, dx
  131.  
  132. ; set gs selector unconditionally
  133.         Mov     ax, graph_data
  134.         Mov     gs, ax
  135.       ; set CR0.TS
  136.         cmp     bh, byte[fpu_owner] ;bh == incoming task (new)
  137.         clts                        ;clear a task switch flag
  138.         je      @f
  139.         mov     eax, cr0            ;and set it again if the owner
  140.         or      eax, CR0_TS         ;of a fpu has changed
  141.         mov     cr0, eax
  142.   @@: ; set context_counter (only for user pleasure ???)
  143.         inc     [context_counter]   ;noname & halyavin
  144.       ; set debug-registers, if it's necessary
  145.         test    byte[ebx+APPDATA.dbg_state], 1
  146.         jz      @f
  147.         xor     eax, eax
  148.         mov     dr6, eax
  149.         lea     esi, [ebx+APPDATA.dbg_regs]
  150.         cld
  151.   macro lodsReg [reg] {
  152.         lodsd
  153.         mov     reg, eax
  154.   }     lodsReg dr0, dr1, dr2, dr3, dr7
  155.   purge lodsReg
  156.   @@:
  157.         ret
  158. ;end.
  159.  
  160.  
  161. struct  MUTEX_WAITER
  162.         list    LHEAD
  163.         task    dd ?
  164.         type    dd ?
  165. ends
  166.  
  167. RWSEM_WAITING_FOR_WRITE equ 0
  168. RWSEM_WAITING_FOR_READ  equ 1
  169.  
  170. ;void  __fastcall mutex_init(struct mutex *lock)
  171.  
  172. align 4
  173. mutex_init:
  174.         mov     [ecx+MUTEX.wait_list.next], ecx
  175.         mov     [ecx+MUTEX.wait_list.prev], ecx
  176.         mov     [ecx+MUTEX.count], 1
  177.         ret
  178.  
  179. ;void  __fastcall mutex_lock(struct mutex *lock)
  180.  
  181. align 4
  182. mutex_lock:
  183.  
  184.         dec     [ecx+MUTEX.count]
  185.         jns     .done
  186.  
  187.         pushfd
  188.         cli
  189.  
  190.         sub     esp, sizeof.MUTEX_WAITER
  191.  
  192.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  193.  
  194.         mov     edx, [TASK_BASE]
  195.         mov     [esp+MUTEX_WAITER.task], edx
  196.  
  197. .forever:
  198.  
  199.         mov     eax, -1
  200.         xchg    eax, [ecx+MUTEX.count]
  201.         dec     eax
  202.         jz      @F
  203.  
  204.         mov     [edx+TASKDATA.state], 1
  205.         call    change_task
  206.         jmp     .forever
  207. @@:
  208.         mov     eax, ecx
  209.         list_del esp
  210.  
  211.         cmp     [eax+MUTEX.wait_list.next], eax
  212.         jne     @F
  213.  
  214.         mov     [eax+MUTEX.count], 0
  215. @@:
  216.         add     esp, sizeof.MUTEX_WAITER
  217.  
  218.         popfd
  219. .done:
  220.         ret
  221.  
  222. ;void  __fastcall mutex_unlock(struct mutex *lock)
  223.  
  224. align 4
  225. mutex_unlock:
  226.  
  227.         pushfd
  228.         cli
  229.  
  230.         mov     eax, [ecx+MUTEX.wait_list.next]
  231.         cmp     eax, ecx
  232.         mov     [ecx+MUTEX.count], 1
  233.         je      @F
  234.  
  235.         mov     eax, [eax+MUTEX_WAITER.task]
  236.         mov     [eax+TASKDATA.state], 0
  237. @@:
  238.         popfd
  239.         ret
  240.  
  241.  
  242. ;void __fastcall init_rwsem(struct rw_semaphore *sem)
  243.  
  244. align 4
  245. init_rwsem:
  246.         mov     [ecx+RWSEM.wait_list.next], ecx
  247.         mov     [ecx+RWSEM.wait_list.prev], ecx
  248.         mov     [ecx+RWSEM.count], 0
  249.         ret
  250.  
  251. ;void __fastcall down_read(struct rw_semaphore *sem)
  252.  
  253. align 4
  254. down_read:
  255.         pushfd
  256.         cli
  257.  
  258.         mov     eax, [ecx+RWSEM.count]
  259.         test    eax, eax
  260.         js      @F
  261.  
  262.         cmp     ecx, [ecx+RWSEM.wait_list.next]
  263.         je      .ok
  264. @@:
  265.         sub     esp, sizeof.MUTEX_WAITER
  266.  
  267.         mov     eax, [TASK_BASE]
  268.         mov     [esp+MUTEX_WAITER.task], eax
  269.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_READ
  270.         mov     [eax+TASKDATA.state], 1
  271.  
  272.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  273.  
  274.         call    change_task
  275.  
  276.         add     esp, sizeof.MUTEX_WAITER
  277.         popfd
  278.         ret
  279. .ok:
  280.         inc     eax
  281.         mov     [ecx+RWSEM.count], eax
  282.  
  283.         popfd
  284.         ret
  285.  
  286. ;void __fastcall down_write(struct rw_semaphore *sem)
  287.  
  288. align 4
  289. down_write:
  290.         pushfd
  291.         cli
  292.         sub     esp, sizeof.MUTEX_WAITER
  293.  
  294.         mov     edx, [TASK_BASE]
  295.         mov     [esp+MUTEX_WAITER.task], edx
  296.         mov     [esp+MUTEX_WAITER.type], RWSEM_WAITING_FOR_WRITE
  297.         mov     [edx+TASKDATA.state], 1
  298.  
  299.         list_add_tail esp, ecx      ;esp= new waiter, ecx= list head
  300.  
  301.         xor     eax, eax
  302.         not     eax
  303.  
  304. .forever:
  305.         test    eax, [ecx+RWSEM.count]
  306.         jz      @F
  307.  
  308.         mov     [edx+TASKDATA.state], 1
  309.         call    change_task
  310.         jmp     .forever
  311. @@:
  312.         mov     [ecx+RWSEM.count], eax
  313.         list_del esp
  314.  
  315.         add     esp, sizeof.MUTEX_WAITER
  316.         popfd
  317.         ret
  318.  
  319. ;void __fastcall up_read(struct rw_semaphore *sem)
  320.  
  321. align 4
  322. up_read:
  323.         pushfd
  324.         cli
  325.  
  326.         dec     [ecx+RWSEM.count]
  327.         jnz     @F
  328.  
  329.         mov     eax, [ecx+RWSEM.wait_list.next]
  330.         cmp     eax, ecx
  331.         je      @F
  332.  
  333.         mov     eax, [eax+MUTEX_WAITER.task]
  334.         mov     [eax+TASKDATA.state], 0
  335. @@:
  336.         popfd
  337.         ret
  338.  
  339. ;void __fastcall up_write(struct rw_semaphore *sem)
  340.  
  341. align 4
  342. up_write:
  343.  
  344.         pushfd
  345.         cli
  346.  
  347.         mov     eax, [ecx+RWSEM.wait_list.next]
  348.         mov     [ecx+RWSEM.count], 0
  349.  
  350.         cmp     ecx, eax
  351.         je      .done
  352.  
  353.         mov     edx, [eax+MUTEX_WAITER.type]
  354.         test    edx, edx
  355.         jnz     .wake
  356.  
  357.         mov     eax, [eax+MUTEX_WAITER.task]
  358.         mov     [eax+TASKDATA.state], 0
  359. .done:
  360.         popfd
  361.         ret
  362.  
  363. .wake:
  364.         push    ebx
  365.         push    esi
  366.         push    edi
  367.  
  368.         xor     esi, esi
  369.         mov     edi, ecx
  370.  
  371. .wake_list:
  372.  
  373.         mov     ebx, [eax+MUTEX_WAITER.list.next]
  374.         list_del eax
  375.         mov     edx, [eax+MUTEX_WAITER.task]
  376.         mov     [edx+TASKDATA.state], 0
  377.         inc     esi
  378.         cmp     edi, ebx
  379.         je      .wake_done
  380.  
  381.         mov     ecx, [ebx+MUTEX_WAITER.type]
  382.         test    ecx, ecx
  383.         jz      .wake_done
  384.  
  385.         mov     eax, ebx
  386.         jmp     .wake_list
  387.  
  388. .wake_done:
  389.         add     [edi+RWSEM.count], esi
  390.  
  391.         pop     edi
  392.         pop     esi
  393.         pop     ebx
  394.         popfd
  395.         ret
  396.  
  397.  
  398. purge MUTEX_WAITER
  399. purge RWSEM_WAITING_FOR_WRITE
  400. purge RWSEM_WAITING_FOR_READ
  401.  
  402.  
  403. MAX_PRIORITY      = 0   ; highest, used for kernel tasks
  404. USER_PRIORITY     = 1   ; default
  405. IDLE_PRIORITY     = 2   ; lowest, only IDLE thread goes here
  406. NR_SCHED_QUEUES   = 3   ; MUST equal IDLE_PRIORYTY + 1
  407.  
  408. uglobal
  409. ; [scheduler_current + i*4] = zero if there are no threads with priority i,
  410. ;  pointer to APPDATA of the current thread with priority i otherwise.
  411. align 4
  412. scheduler_current       rd      NR_SCHED_QUEUES
  413. endg
  414.  
  415. ; Add the given thread to the given priority list for the scheduler.
  416. ; in: edx -> APPDATA, ecx = priority
  417. proc scheduler_add_thread
  418. ; 1. Acquire the lock.
  419.         spin_lock_irqsave SchedulerLock
  420. ; 2. Store the priority in APPDATA structure.
  421.         mov     [edx+APPDATA.priority], ecx
  422. ; 3. There are two different cases: the given list is empty or not empty.
  423. ; In first case, go to 6. Otherwise, advance to 4.
  424.         mov     eax, [scheduler_current+ecx*4]
  425.         test    eax, eax
  426.         jz      .new_list
  427. ; 4. Insert the new item immediately before the current item.
  428.         mov     ecx, [eax+APPDATA.in_schedule.prev]
  429.         mov     [edx+APPDATA.in_schedule.next], eax
  430.         mov     [edx+APPDATA.in_schedule.prev], ecx
  431.         mov     [eax+APPDATA.in_schedule.prev], edx
  432.         mov     [ecx+APPDATA.in_schedule.next], edx
  433. ; 5. Release the lock and return.
  434.         spin_unlock_irqrestore SchedulerLock
  435.         ret
  436. .new_list:
  437. ; 6. Initialize the list with one item and make it the current item.
  438.         mov     [edx+APPDATA.in_schedule.next], edx
  439.         mov     [edx+APPDATA.in_schedule.prev], edx
  440.         mov     [scheduler_current+ecx*4], edx
  441. ; 7. Release the lock and return.
  442.         spin_unlock_irqrestore SchedulerLock
  443.         ret
  444. endp
  445.  
  446. ; Remove the given thread from the corresponding priority list for the scheduler.
  447. ; in: edx -> APPDATA
  448. proc scheduler_remove_thread
  449. ; 1. Acquire the lock.
  450.         spin_lock_irqsave SchedulerLock
  451. ; 2. Remove the item from the corresponding list.
  452.         mov     eax, [edx+APPDATA.in_schedule.next]
  453.         mov     ecx, [edx+APPDATA.in_schedule.prev]
  454.         mov     [eax+APPDATA.in_schedule.prev], ecx
  455.         mov     [ecx+APPDATA.in_schedule.next], eax
  456. ; 3. If the given thread is the current item in the list,
  457. ; advance the current item.
  458. ; 3a. Check whether the given thread is the current item;
  459. ; if no, skip the rest of this step.
  460.         mov     ecx, [edx+APPDATA.priority]
  461.         cmp     [scheduler_current+ecx*4], edx
  462.         jnz     .return
  463. ; 3b. Set the current item to eax; step 2 has set eax = next item.
  464.         mov     [scheduler_current+ecx*4], eax
  465. ; 3c. If there were only one item in the list, zero the current item.
  466.         cmp     eax, edx
  467.         jnz     .return
  468.         mov     [scheduler_current+ecx*4], 0
  469. .return:
  470. ; 4. Release the lock and return.
  471.         spin_unlock_irqrestore SchedulerLock
  472.         ret
  473. endp
  474.  
  475. SCHEDULE_ANY_PRIORITY = 0
  476. SCHEDULE_HIGHER_PRIORITY = 1
  477. ;info:
  478. ;   Find next task to execute
  479. ;in:
  480. ;   bl = SCHEDULE_ANY_PRIORITY:
  481. ;        consider threads with any priority
  482. ;   bl = SCHEDULE_HIGHER_PRIORITY:
  483. ;        consider only threads with strictly higher priority than the current one,
  484. ;        keep running the current thread if other ready threads have the same or lower priority
  485. ;retval:
  486. ;   ebx = address of the APPDATA for the selected task (slot-base)
  487. ;   edi = address of the TASKDATA for the selected task
  488. ;   ZF  = 1  if the task is the same
  489. ;warning:
  490. ;   [CURRENT_TASK] = bh , [TASK_BASE] = edi -- as result
  491. ;   [current_slot] is not set to new value (ebx)!!!
  492. ;scratched: eax,ecx
  493. proc find_next_task
  494.         call    update_counters
  495.         spin_lock_irqsave SchedulerLock
  496.         push    NR_SCHED_QUEUES
  497. ; If bl == SCHEDULE_ANY_PRIORITY = 0, loop over all NR_SCHED lists.
  498. ; Otherwise, loop over first [APPDATA.priority] lists.
  499.         test    bl, bl
  500.         jz      .start
  501.         mov     ebx, [current_slot]
  502.         mov     edi, [TASK_BASE]
  503.         mov     eax, [ebx+APPDATA.priority]
  504.         test    eax, eax
  505.         jz      .unlock_found
  506.         mov     [esp], eax
  507. .start:
  508.         xor     ecx, ecx
  509. .priority_loop:
  510.         mov     ebx, [scheduler_current+ecx*4]
  511.         test    ebx, ebx
  512.         jz      .priority_next
  513. .task_loop:
  514.         mov     ebx, [ebx+APPDATA.in_schedule.next]
  515.         mov     edi, ebx
  516.         shr     edi, 3
  517.         add     edi, CURRENT_TASK - (SLOT_BASE shr 3)
  518.         mov     al, [edi+TASKDATA.state]
  519.         test    al, al
  520.         jz      .task_found     ; state == 0
  521.         cmp     al, 5
  522.         jne     .task_next      ; state == 1,2,3,4,9
  523.       ; state == 5
  524.         pushad  ; more freedom for [APPDATA.wait_test]
  525.         call    [ebx+APPDATA.wait_test]
  526.         mov     [esp+28], eax
  527.         popad
  528.         or      eax, eax
  529.         jnz     @f
  530.       ; testing for timeout
  531.         mov     eax, [timer_ticks]
  532.         sub     eax, [ebx+APPDATA.wait_begin]
  533.         cmp     eax, [ebx+APPDATA.wait_timeout]
  534.         jb      .task_next
  535.         xor     eax, eax
  536. @@:
  537.         mov     [ebx+APPDATA.wait_param], eax  ; retval for wait
  538.         mov     [edi+TASKDATA.state], 0
  539. .task_found:
  540.         mov     [scheduler_current+ecx*4], ebx
  541. ; If we have selected a thread with higher priority
  542. ; AND rescheduling is due to IRQ,
  543. ; turn the current scheduler list one entry back,
  544. ; so the current thread will be next after high-priority thread is done.
  545.         mov     ecx, [esp]
  546.         cmp     ecx, NR_SCHED_QUEUES
  547.         jz      .unlock_found
  548.         mov     eax, [current_slot]
  549.         mov     eax, [eax+APPDATA.in_schedule.prev]
  550.         mov     [scheduler_current+ecx*4], eax
  551. .unlock_found:
  552.         pop     ecx
  553.         spin_unlock_irqrestore SchedulerLock
  554. .found:
  555.         mov     [CURRENT_TASK], bh
  556.         mov     [TASK_BASE], edi
  557.         rdtsc   ;call  _rdtsc
  558.         mov     [edi+TASKDATA.counter_add], eax; for next using update_counters
  559.         cmp     ebx, [current_slot]
  560.         ret
  561. .task_next:
  562.         cmp     ebx, [scheduler_current+ecx*4]
  563.         jnz     .task_loop
  564. .priority_next:
  565.         inc     ecx
  566.         cmp     ecx, [esp]
  567.         jb      .priority_loop
  568.         mov     ebx, [current_slot]
  569.         mov     edi, [TASK_BASE]
  570.         jmp     .unlock_found
  571. endp
  572.  
  573. if 0
  574.  
  575. struc TIMER
  576. {
  577.   .next      dd ?
  578.   .exp_time  dd ?
  579.   .func      dd ?
  580.   .arg       dd ?
  581. }
  582.  
  583.  
  584. uglobal
  585. rdy_head   rd 16
  586. endg
  587.  
  588. align 4
  589. pick_task:
  590.  
  591.         xor     eax, eax
  592.   .pick:
  593.         mov     ebx, [rdy_head+eax*4]
  594.         test    ebx, ebx
  595.         jz      .next
  596.  
  597.         mov     [next_task], ebx
  598.         test    [ebx+flags.billable]
  599.         jz      @F
  600.         mov     [bill_task], ebx
  601.   @@:
  602.         ret
  603.   .next:
  604.         inc     eax
  605.         jmp     .pick
  606.  
  607. ; param
  608. ;  eax= task
  609. ;
  610. ; retval
  611. ;  eax= task
  612. ;  ebx= queue
  613. ;  ecx= front if 1 or back if 0
  614. align 4
  615. shed:
  616.         cmp     [eax+.tics_left], 0;signed compare
  617.         mov     ebx, [eax+.priority]
  618.         setg    ecx
  619.         jg      @F
  620.  
  621.         mov     edx, [eax+.tics_quantum]
  622.         mov     [eax+.ticks_left], edx
  623.         cmp     ebx, (IDLE_PRIORITY-1)
  624.         je      @F
  625.         inc     ebx
  626.   @@:
  627.         ret
  628.  
  629. ; param
  630. ;  eax= task
  631. align 4
  632. enqueue:
  633.         call    shed;eax
  634.         cmp     [rdy_head+ebx*4], 0
  635.         jnz     @F
  636.  
  637.         mov     [rdy_head+ebx*4], eax
  638.         mov     [rdy_tail+ebx*4], eax
  639.         mov     [eax+.next_ready], 0
  640.         jmp     .pick
  641.   @@:
  642.         test    ecx, ecx
  643.         jz      .back
  644.  
  645.         mov     ecx, [rdy_head+ebx*4]
  646.         mov     [eax+.next_ready], ecx
  647.         mov     [rdy_head+ebx*4], eax
  648.         jmp     .pick
  649.   .back:
  650.         mov     ecx, [rdy_tail+ebx*4]
  651.         mov     [ecx+.next_ready], eax
  652.         mov     [rdy_tail+ebx*4], eax
  653.         mov     [eax+.next_ready], 0
  654.   .pick:
  655.         call    pick_proc;select next task
  656.         ret
  657.  
  658. end if
  659.