Subversion Repositories Kolibri OS

Rev

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