Subversion Repositories Kolibri OS

Rev

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

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