Subversion Repositories Kolibri OS

Rev

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