Sync to trunk head (r40091)
[reactos.git] / reactos / ntoskrnl / ke / i386 / ctxswitch.S
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/i386/ctxswitch.S
5 * PURPOSE: Thread Context Switching
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * Gregor Anich (FPU Code)
9 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ndk/asm.h>
14 .intel_syntax noprefix
15
16 #define Ready 1
17 #define Running 2
18 #define WrDispatchInt 0x1F
19
20 Dividend: .float 4195835.0
21 Divisor: .float 3145727.0
22 Result1: .float 0
23 Result2: .float 0
24
25 /* FUNCTIONS ****************************************************************/
26
27 .globl _KiIsNpxErrataPresent@0
28 .func KiIsNpxErrataPresent@0
29 _KiIsNpxErrataPresent@0:
30
31 /* Disable interrupts */
32 cli
33
34 /* Get CR0 and mask out FPU flags */
35 mov eax, cr0
36 mov ecx, eax
37 and eax, ~(CR0_MP + CR0_TS + CR0_EM)
38 mov cr0, eax
39
40 /* Initialize the FPU */
41 fninit
42
43 /* Do the divison and inverse multiplication */
44 fld qword ptr Dividend
45 fstp qword ptr Result1
46 fld qword ptr Divisor
47 fstp qword ptr Result2
48 fld qword ptr Result1
49 fdiv qword ptr Result2
50 fmul qword ptr Result2
51
52 /* Do the compare and check flags */
53 fcomp qword ptr Result1
54 fstsw ax
55 sahf
56
57 /* Restore CR0 and interrupts */
58 mov cr0, ecx
59 sti
60
61 /* Return errata status */
62 xor eax, eax
63 jz NoErrata
64 inc eax
65
66 NoErrata:
67 ret
68 .endfunc
69
70 .globl _KiIsNpxPresent@0
71 .func KiIsNpxPresent@0
72 _KiIsNpxPresent@0:
73
74 /* Save stack */
75 push ebp
76
77 /* Get CR0 and mask out FPU flags */
78 mov eax, cr0
79 and eax, ~(CR0_MP + CR0_TS + CR0_EM + CR0_ET)
80
81 /* Initialize the FPU and assume FALSE for return */
82 xor edx, edx
83 fninit
84
85 /* Save magic value on stack */
86 mov ecx, 0x42424242
87 push ecx
88
89 /* Setup stack for FPU store */
90 mov ebp ,esp
91 fnstsw [ebp]
92
93 /* Now check if our magic got cleared */
94 cmp byte ptr [ebp], 0
95 jnz NoFpu
96
97 /* Enable FPU, set return to TRUE */
98 or eax, CR0_ET
99 mov edx, 1
100
101 /* If this is a 486 or higher, enable INT 16 as well */
102 cmp dword ptr fs:KPCR_PRCB_CPU_TYPE, 3
103 jbe NoFpu
104 or eax, CR0_NE
105
106 NoFpu:
107 /* Set emulation enabled during the first boot phase and set the CR0 */
108 or eax, (CR0_EM + CR0_TS)
109 mov cr0, eax
110
111 /* Restore stack */
112 pop eax
113 pop ebp
114
115 /* Return true or false */
116 mov eax, edx
117 ret
118 .endfunc
119
120 .globl _KiFlushNPXState@4
121 .func KiFlushNPXState@4
122 _KiFlushNPXState@4:
123
124 /* Save volatiles and disable interrupts */
125 push esi
126 push edi
127 push ebx
128 pushfd
129 cli
130
131 /* Save the PCR and get the current thread */
132 mov edi, fs:[KPCR_SELF]
133 mov esi, [edi+KPCR_CURRENT_THREAD]
134
135 /* Check if we're already loaded */
136 cmp byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
137 je IsValid
138
139 /* Check if we're supposed to get it */
140 cmp dword ptr [esp+20], 0
141 je Return
142
143 #ifdef DBG
144 /* Assert Fxsr support */
145 test byte ptr _KeI386FxsrPresent, 1
146 jnz AssertOk
147 int 3
148 AssertOk:
149 #endif
150
151 /* Get CR0 and test if it's valid */
152 mov ebx, cr0
153 test bl, CR0_MP + CR0_TS + CR0_EM
154 jz Cr0OK
155
156 /* Enable fnsave to work */
157 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
158 mov cr0, ebx
159
160 Cr0OK:
161 /* Check if we are the NPX Thread */
162 mov eax, [edi+KPCR_NPX_THREAD]
163 or eax, eax
164 jz DontSave
165
166 /* Check if it's not loaded */
167 cmp byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
168 jnz DontSave
169
170 #ifdef DBG
171 /* We are the NPX Thread with an unloaded NPX State... this isn't normal! */
172 int 3
173 #endif
174
175 /* Save the NPX State */
176 mov ecx, [eax+KTHREAD_INITIAL_STACK]
177 sub ecx, NPX_FRAME_LENGTH
178 fxsave [ecx]
179 mov byte ptr [eax+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
180
181 DontSave:
182 /* Load the NPX State */
183 mov ecx, [esi+KTHREAD_INITIAL_STACK]
184 sub ecx, NPX_FRAME_LENGTH
185 fxrstor [ecx]
186
187 /* Get the CR0 state and destination */
188 mov edx, [ecx+FN_CR0_NPX_STATE]
189 mov ecx, [esp+20]
190 jmp DoneLoad
191
192 IsValid:
193 /* We already have a valid state, flush it */
194 mov ebx, cr0
195 test bl, CR0_MP + CR0_TS + CR0_EM
196 jz Cr0OK2
197
198 /* Enable fnsave to work */
199 and ebx, ~(CR0_MP + CR0_TS + CR0_EM)
200 mov cr0, ebx
201
202 Cr0OK2:
203 /* Get the kernel stack */
204 mov ecx, [esi+KTHREAD_INITIAL_STACK]
205 test byte ptr _KeI386FxsrPresent, 1
206 lea ecx, [ecx-NPX_FRAME_LENGTH]
207
208 /* Set the NPX State */
209 mov byte ptr [esi+KTHREAD_NPX_STATE], NPX_STATE_NOT_LOADED
210
211 /* Get Cr0 */
212 mov edx, [ecx+FN_CR0_NPX_STATE]
213 jz DoneLoad
214
215 /* Save the FX State */
216 fxsave [ecx]
217
218 /* Check if we also have to save it in the parameter */
219 mov ecx, [esp+20]
220 jecxz NoSave
221
222 DoneLoad:
223 /* Save the Fn state in the parameter we got */
224 fnsave [ecx]
225 fwait
226
227 NoSave:
228 /* Clear eax */
229 xor eax, eax
230
231 /* Add NPX State */
232 or ebx, NPX_STATE_NOT_LOADED
233
234 /* Clear the NPX thread */
235 mov [edi+KPCR_NPX_THREAD], eax
236
237 /* Add saved CR0 into NPX State, and set it */
238 or ebx, edx
239 mov cr0, ebx
240
241 /* Re-enable interrupts and return */
242 Return:
243 popf
244 pop ebx
245 pop edi
246 pop esi
247 ret 4
248
249 .endfunc
250
251 /*++
252 * KiThreadStartup
253 *
254 * The KiThreadStartup routine is the beginning of any thread.
255 *
256 * Params:
257 * SystemRoutine - Pointer to the System Startup Routine. Either
258 * PspUserThreadStartup or PspSystemThreadStartup
259 *
260 * StartRoutine - For Kernel Threads only, specifies the starting execution
261 * point of the new thread.
262 *
263 * StartContext - For Kernel Threads only, specifies a pointer to variable
264 * context data to be sent to the StartRoutine above.
265 *
266 * UserThread - Indicates whether or not this is a user thread. This tells
267 * us if the thread has a context or not.
268 *
269 * TrapFrame - Pointer to the KTHREAD to which the caller wishes to
270 * switch from.
271 *
272 * Returns:
273 * Should never return for a system thread. Returns through the System Call
274 * Exit Dispatcher for a user thread.
275 *
276 * Remarks:
277 * If a return from a system thread is detected, a bug check will occur.
278 *
279 *--*/
280 .func KiThreadStartup@156
281 .globl _KiThreadStartup@156
282 _KiThreadStartup@156:
283
284 /*
285 * Clear all the non-volatile registers, so the thread won't be tempted to
286 * expect any static data (like some badly coded usermode/win9x apps do)
287 */
288 xor ebx, ebx
289 xor esi, esi
290 xor edi, edi
291 xor ebp, ebp
292
293 /* It's now safe to go to APC */
294 mov ecx, APC_LEVEL
295 call @KfLowerIrql@4
296
297 /*
298 * Call the System Routine which is right on our stack now.
299 * After we pop the pointer, the Start Routine/Context will be on the
300 * stack, as parameters to the System Routine
301 */
302 pop eax
303 call eax
304
305 /* The thread returned... was it a user-thread? */
306 pop ecx
307 or ecx, ecx
308 jz BadThread
309
310 /* Yes it was, set our trapframe for the System Call Exit Dispatcher */
311 mov ebp, esp
312
313 /* Exit back to user-mode */
314 jmp _KiServiceExit2
315
316 BadThread:
317
318 /* A system thread returned...this is very bad! */
319 int 3
320 .endfunc
321
322 /*++
323 * KiSwapContextInternal
324 *
325 * \brief
326 * The KiSwapContextInternal routine switches context to another thread.
327 *
328 * BOOLEAN USERCALL KiSwapContextInternal();
329 *
330 * Params:
331 * ESI - Pointer to the KTHREAD to which the caller wishes to
332 * switch to.
333 * EDI - Pointer to the KTHREAD to which the caller wishes to
334 * switch from.
335 *
336 * \returns
337 * APC state.
338 *
339 * \remarks
340 * Absolutely all registers except ESP can be trampled here for maximum code flexibility.
341 *
342 *--*/
343 .globl @KiSwapContextInternal@0
344 .func @KiSwapContextInternal@0, @KiSwapContextInternal@0
345 @KiSwapContextInternal@0:
346
347 /* Save the IRQL */
348 push ecx
349
350 #ifdef CONFIG_SMP
351 GetSwapLock:
352 /* Acquire the swap lock */
353 cmp byte ptr [esi+KTHREAD_SWAP_BUSY], 0
354 jz NotBusy
355 pause
356 jmp GetSwapLock
357 #endif
358 NotBusy:
359 /* Increase context switches (use ES for lazy load) */
360 inc dword ptr es:[ebx+KPCR_CONTEXT_SWITCHES]
361
362 /* Save the Exception list */
363 push [ebx+KPCR_EXCEPTION_LIST]
364
365 /* Check for WMI */
366 cmp dword ptr [ebx+KPCR_PERF_GLOBAL_GROUP_MASK], 0
367 jnz WmiTrace
368
369 AfterTrace:
370 #ifdef CONFIG_SMP
371 #ifdef DBG
372 /* Assert that we're on the right CPU */
373 mov cl, [esi+KTHREAD_NEXT_PROCESSOR]
374 cmp cl, [ebx+KPCR_PROCESSOR_NUMBER]
375 jnz WrongCpu
376 #endif
377 #endif
378
379 /* Get CR0 and save it */
380 mov ebp, cr0
381 mov edx, ebp
382
383 #ifdef CONFIG_SMP
384 /* Check NPX State */
385 cmp byte ptr [edi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
386 jz NpxLoaded
387 #endif
388
389 SetStack:
390 /* Set new stack */
391 mov [edi+KTHREAD_KERNEL_STACK], esp
392
393 /* Checking NPX, disable interrupts now */
394 mov eax, [esi+KTHREAD_INITIAL_STACK]
395
396 /* HACK */
397 mov ecx, [eax - 4]
398 cli
399
400 /* Get the NPX State */
401 movzx ecx, byte ptr [esi+KTHREAD_NPX_STATE]
402
403 /* Clear the other bits, merge in CR0, merge in FPU CR0 bits and compare */
404 and edx, ~(CR0_MP + CR0_EM + CR0_TS)
405 or ecx, edx
406 or ecx, [eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)]
407 cmp ebp, ecx
408 jnz NewCr0
409
410 StackOk:
411 /* Enable interrupts and set the current stack */
412 sti
413 mov esp, [esi+KTHREAD_KERNEL_STACK]
414
415 /* Check if address space switch is needed */
416 mov ebp, [esi+KTHREAD_APCSTATE_PROCESS]
417 mov eax, [edi+KTHREAD_APCSTATE_PROCESS]
418 cmp ebp, eax
419 jz SameProcess
420
421 #ifdef CONFIG_SMP
422 /* Get the active processors and XOR with the process' */
423 mov ecx, [ebx+KPCR_SET_MEMBER_COPY]
424 lock xor [ebp+KPROCESS_ACTIVE_PROCESSORS], ecx
425 lock xor [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
426
427 /* Assert change went ok */
428 #ifdef DBG
429 test [ebp+KPROCESS_ACTIVE_PROCESSORS], ecx
430 jz WrongActiveCpu
431 test [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
432 jz WrongActiveCpu
433 #endif
434 #endif
435
436 /* Check if we need an LDT */
437 mov ecx, [ebp+KPROCESS_LDT_DESCRIPTOR0]
438 or ecx, [eax+KPROCESS_LDT_DESCRIPTOR0]
439 jnz LdtReload
440
441 UpdateCr3:
442 /* Switch address space */
443 mov eax, [ebp+KPROCESS_DIRECTORY_TABLE_BASE]
444 mov cr3, eax
445
446 SameProcess:
447
448 #ifdef CONFIG_SMP
449 /* Release swap lock */
450 and byte ptr [edi+KTHREAD_SWAP_BUSY], 0
451 #endif
452
453 /* Clear gs */
454 xor eax, eax
455 mov gs, ax
456
457 /* Set the TEB */
458 mov eax, [esi+KTHREAD_TEB]
459 mov [ebx+KPCR_TEB], eax
460 mov ecx, [ebx+KPCR_GDT]
461 mov [ecx+0x3A], ax
462 shr eax, 16
463 mov [ecx+0x3C], al
464 mov [ecx+0x3F], ah
465
466 /* Get stack pointer */
467 mov eax, [esi+KTHREAD_INITIAL_STACK]
468
469 /* Make space for the NPX Frame */
470 sub eax, NPX_FRAME_LENGTH
471
472 /* Check if this isn't V86 Mode, so we can bias the Esp0 */
473 test dword ptr [eax - KTRAP_FRAME_SIZE + KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
474 jnz NoAdjust
475
476 /* Bias esp */
477 sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
478
479 NoAdjust:
480
481 /* Set new ESP0 */
482 mov ecx, [ebx+KPCR_TSS]
483 mov [ecx+KTSS_ESP0], eax
484
485 /* Set current IOPM offset in the TSS */
486 mov ax, [ebp+KPROCESS_IOPM_OFFSET]
487 mov [ecx+KTSS_IOMAPBASE], ax
488
489 /* Increase context switches */
490 inc dword ptr [esi+KTHREAD_CONTEXT_SWITCHES]
491
492 /* Restore exception list */
493 pop [ebx+KPCR_EXCEPTION_LIST]
494
495 /* Restore IRQL */
496 pop ecx
497
498 /* DPC shouldn't be active */
499 cmp byte ptr [ebx+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
500 jnz BugCheckDpc
501
502 /* Check if kernel APCs are pending */
503 cmp byte ptr [esi+KTHREAD_PENDING_KERNEL_APC], 0
504 jnz CheckApc
505
506 /* No APCs, return */
507 xor eax, eax
508 ret
509
510 CheckApc:
511
512 /* Check if they're disabled */
513 cmp word ptr [esi+KTHREAD_SPECIAL_APC_DISABLE], 0
514 jnz ApcReturn
515 test cl, cl
516 jz ApcReturn
517
518 /* Request APC Delivery */
519 mov cl, APC_LEVEL
520 call @HalRequestSoftwareInterrupt@4
521 or eax, esp
522
523 ApcReturn:
524
525 /* Return with APC pending */
526 setz al
527 ret
528
529 LdtReload:
530 /* Check if it's empty */
531 mov eax, [ebp+KPROCESS_LDT_DESCRIPTOR0]
532 test eax, eax
533 jz LoadLdt
534
535 /* Write the LDT Selector */
536 mov ecx, [ebx+KPCR_GDT]
537 mov [ecx+KGDT_LDT], eax
538 mov eax, [ebp+KPROCESS_LDT_DESCRIPTOR1]
539 mov [ecx+KGDT_LDT+4], eax
540
541 /* Write the INT21 handler */
542 mov ecx, [ebx+KPCR_IDT]
543 mov eax, [ebp+KPROCESS_INT21_DESCRIPTOR0]
544 mov [ecx+0x108], eax
545 mov eax, [ebp+KPROCESS_INT21_DESCRIPTOR1]
546 mov [ecx+0x10C], eax
547
548 /* Save LDT Selector */
549 mov eax, KGDT_LDT
550
551 LoadLdt:
552 lldt ax
553 jmp UpdateCr3
554
555 NewCr0:
556
557 #ifdef DBG
558 /* Assert NPX State */
559 test byte ptr [esi+KTHREAD_NPX_STATE], ~(NPX_STATE_NOT_LOADED)
560 jnz InvalidNpx
561 test dword ptr [eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)], ~(CR0_PE + CR0_MP + CR0_EM + CR0_TS)
562 jnz InvalidNpx
563 #endif
564
565 /* Update CR0 */
566 mov cr0, ecx
567 jmp StackOk
568
569 #ifdef CONFIG_SMP
570 NpxLoaded:
571
572 /* FIXME: TODO */
573 int 3
574
575 /* Jump back */
576 jmp SetStack
577 #endif
578
579 WmiTrace:
580
581 /* No WMI support yet */
582 int 3
583
584 /* Jump back */
585 jmp AfterTrace
586
587 BugCheckDpc:
588
589 /* Bugcheck the machine, printing out the threads being switched */
590 mov eax, [edi+KTHREAD_INITIAL_STACK]
591 push 0
592 push eax
593 push esi
594 push edi
595 push ATTEMPTED_SWITCH_FROM_DPC
596 call _KeBugCheckEx@20
597
598 #ifdef DBG
599 InvalidNpx:
600 int 3
601 WrongActiveCpu:
602 int 3
603 WrongCpu:
604 int 3
605 #endif
606 .endfunc
607
608 /**
609 * KiSwapContext
610 *
611 * \brief
612 * The KiSwapContext routine switches context to another thread.
613 *
614 * BOOLEAN FASTCALL
615 * KiSwapContext(PKTHREAD CurrentThread, PKTHREAD TargetThread);
616 *
617 * \param CurrentThread
618 * Pointer to the KTHREAD of the current thread.
619 *
620 * \param TargetThread
621 * Pointer to the KTHREAD to which the caller wishes to switch to.
622 *
623 * \returns
624 * The WaitStatus of the Target Thread.
625 *
626 * \remarks
627 * This is a wrapper around KiSwapContextInternal which will save all the
628 * non-volatile registers so that the Internal function can use all of
629 * them. It will also save the old current thread and set the new one.
630 *
631 * The calling thread does not return after KiSwapContextInternal until
632 * another thread switches to IT.
633 *
634 *--*/
635 .globl @KiSwapContext@8
636 .func @KiSwapContext@8, @KiSwapContext@8
637 @KiSwapContext@8:
638
639 /* Save 4 registers */
640 sub esp, 4 * 4
641
642 /* Save all the non-volatile ones */
643 mov [esp+12], ebx
644 mov [esp+8], esi
645 mov [esp+4], edi
646 mov [esp+0], ebp
647
648 /* Get the current KPCR */
649 mov ebx, fs:[KPCR_SELF]
650
651 /* Get the Current Thread */
652 mov edi, ecx
653
654 /* Get the New Thread */
655 mov esi, edx
656
657 /* Get the wait IRQL */
658 movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL]
659
660 /* Do the swap with the registers correctly setup */
661 call @KiSwapContextInternal@0
662
663 /* Return the registers */
664 mov ebp, [esp+0]
665 mov edi, [esp+4]
666 mov esi, [esp+8]
667 mov ebx, [esp+12]
668
669 /* Clean stack */
670 add esp, 4 * 4
671 ret
672 .endfunc
673
674 .globl @KiIdleLoop@0
675 .func @KiIdleLoop@0, @KiIdleLoop@0
676 @KiIdleLoop@0:
677
678 /* Set EBX */
679 mov ebx, fs:[KPCR_SELF]
680
681 /* Jump into mainline code */
682 jmp MainLoop
683
684 CpuIdle:
685 /* Call the CPU's idle function */
686 lea ecx, [ebx+KPCR_PRCB_POWER_STATE_IDLE_FUNCTION]
687 call [ecx]
688
689 MainLoop:
690 /* Cycle interrupts for 1 cycle */
691 sti
692 nop
693 nop
694 cli
695
696 /* Check if we have to deliver DPCs, timers, or deferred threads */
697 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
698 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
699 #ifdef CONFIG_SMP
700 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
701 #endif
702 jz CheckSchedule
703
704 mov cl, DISPATCH_LEVEL
705 call @HalClearSoftwareInterrupt@4
706
707 /* Handle the above */
708 lea ecx, [ebx+KPCR_PRCB_DATA]
709 call @KiRetireDpcList@4
710
711 CheckSchedule:
712 /* Check if a next thread is queued */
713 cmp dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
714 #ifdef CONFIG_SMP
715 jz NoNextThread
716 #else
717 jz CpuIdle
718 #endif
719
720 #ifdef CONFIG_SMP
721 /* There is, raise IRQL to synch level */
722 call _KeRaiseIrqlToSynchLevel@0
723 #endif
724 sti
725
726 /* Set the current thread to ready */
727 mov edi, [ebx+KPCR_CURRENT_THREAD]
728 #ifdef CONFIG_SMP
729 mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
730
731 /* Acquire the PRCB Lock */
732 lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
733 jnb CheckNext
734 lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
735 call @KefAcquireSpinLockAtDpcLevel@4
736 #endif
737
738 CheckNext:
739 /* Check if the next thread is the current */
740 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
741 #ifdef CONFIG_SMP
742 cmp esi, edi
743 jz SameThread
744 #endif
745
746 /* Clear the next thread and set this one instead */
747 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
748 mov [ebx+KPCR_CURRENT_THREAD], esi
749
750 /* Set the thread as running */
751 mov byte ptr [esi+KTHREAD_STATE_], Running
752
753 #ifdef CONFIG_SMP
754 /* Disable the idle scheduler and release the PRCB lock */
755 and byte ptr [ebx+KPCR_PRCB_IDLE_SCHEDULE], 0
756 and dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
757 #endif
758
759 SwapContext:
760 /* ReactOS Mm Hack */
761 mov ecx, esi
762 call @MiSyncForContextSwitch@4
763
764 /* Swap context at APC_LEVEL */
765 mov ecx, APC_LEVEL
766 call @KiSwapContextInternal@0
767
768 #ifdef CONFIG_SMP
769 /* Lower to DPC level */
770 mov ecx, DISPATCH_LEVEL
771 call @KfLowerIrql@4
772 #endif
773 jmp MainLoop
774
775 #ifdef CONFIG_SMP
776 SameThread:
777 /* Clear the next thread, and put the thready as ready after lock release */
778 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
779 and dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
780 and byte ptr [edi+KTHREAD_STATE_], Ready
781 jmp MainLoop
782
783 NoNextThread:
784 /* Check if the idle scheduler is enabled */
785 cmp byte ptr [ebx+KPCR_PRCB_IDLE_SCHEDULE], 0
786 jz CpuIdle
787
788 /* It is, so call the scheduler */
789 lea ecx, [ebx+KPCR_PRCB_DATA]
790 call @KiIdleSchedule@4
791 test eax, eax
792
793 /* Get new thread pointers and either swap or idle loop again */
794 mov esi, eax
795 mov edi, [ebx+KPCR_PRCB_IDLE_THREAD]
796 jnz SwapContext
797 jmp MainLoop
798 #endif
799 .endfunc
800
801 .globl _Ki386AdjustEsp0@4
802 .func Ki386AdjustEsp0@4
803 _Ki386AdjustEsp0@4:
804
805 /* Get the current thread */
806 mov eax, [fs:KPCR_CURRENT_THREAD]
807
808 /* Get trap frame and stack */
809 mov edx, [esp+4]
810 mov eax, [eax+KTHREAD_INITIAL_STACK]
811
812 /* Check if V86 */
813 test dword ptr [edx+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
814 jnz 1f
815
816 /* Bias the stack */
817 sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
818
819 1:
820 /* Skip FX Save Area */
821 sub eax, SIZEOF_FX_SAVE_AREA
822
823 /* Disable interrupts */
824 pushf
825 cli
826
827 /* Adjust ESP0 */
828 mov edx, [fs:KPCR_TSS]
829 mov ss:[edx+KTSS_ESP0], eax
830
831 /* Enable interrupts and return */
832 popf
833 ret 4
834 .endfunc
835
836 .globl _KiSwapProcess@8
837 .func KiSwapProcess@8
838 _KiSwapProcess@8:
839
840 /* Get process pointers */
841 mov edx, [esp+4]
842 mov eax, [esp+8]
843
844 #ifdef CONFIG_SMP
845 /* Update active processors */
846 mov ecx, fs:[KPCR_SET_MEMBER]
847 lock xor [edx+KPROCESS_ACTIVE_PROCESSORS], ecx
848 lock xor [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
849
850 /* Sanity check */
851 #ifdef DBG
852 test dword ptr [edx+KPROCESS_ACTIVE_PROCESSORS], 0
853 jz WrongCpu1
854 test dword ptr [eax+KPROCESS_ACTIVE_PROCESSORS], 0
855 jnz WrongCpu2
856 #endif
857 #endif
858
859 /* Check if their LDTs changed */
860 mov ecx, [edx+KPROCESS_LDT_DESCRIPTOR0]
861 or ecx, [eax+KPROCESS_LDT_DESCRIPTOR0]
862 jnz NewLdt
863
864 /* Update CR3 */
865 mov eax, [edx+KPROCESS_DIRECTORY_TABLE_BASE]
866 mov cr3, eax
867
868 /* Get the KTSS */
869 mov ecx, fs:[KPCR_TSS]
870
871 /* Clear GS on process swap */
872 xor eax, eax
873 mov gs, ax
874
875 /* Update IOPM offset */
876 mov ax, [edx+KPROCESS_IOPM_OFFSET]
877 mov [ecx+KTSS_IOMAPBASE], ax
878
879 /* Return */
880 ret 8
881
882 NewLdt:
883 /* FIXME: TODO */
884 int 3
885
886 #ifdef DBG
887 WrongCpu1:
888 int 3
889 WrongCpu2:
890 int 3
891 #endif
892 .endfunc