Subversion Repositories Kolibri OS

Rev

Rev 9932 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

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