- In Win32 DBG is defined to 0 for a non-debug build and to 1 for a debug build....
[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 #if 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 #if 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 * The KiSwapContextInternal routine switches context to another thread.
326 *
327 * Params:
328 * ESI - Pointer to the KTHREAD to which the caller wishes to
329 * switch to.
330 * EDI - Pointer to the KTHREAD to which the caller wishes to
331 * switch from.
332 *
333 * Returns:
334 * None.
335 *
336 * Remarks:
337 * Absolutely all registers except ESP can be trampled here for maximum code flexibility.
338 *
339 *--*/
340 .globl @KiSwapContextInternal@0
341 .func @KiSwapContextInternal@0, @KiSwapContextInternal@0
342 @KiSwapContextInternal@0:
343
344 /* Save the IRQL */
345 push ecx
346
347 #ifdef CONFIG_SMP
348 GetSwapLock:
349 /* Acquire the swap lock */
350 cmp byte ptr [esi+KTHREAD_SWAP_BUSY], 0
351 jz NotBusy
352 pause
353 jmp GetSwapLock
354 #endif
355 NotBusy:
356 /* Increase context switches (use ES for lazy load) */
357 inc dword ptr es:[ebx+KPCR_CONTEXT_SWITCHES]
358
359 /* Save the Exception list */
360 push [ebx+KPCR_EXCEPTION_LIST]
361
362 /* Check for WMI */
363 cmp dword ptr [ebx+KPCR_PERF_GLOBAL_GROUP_MASK], 0
364 jnz WmiTrace
365
366 AfterTrace:
367 #ifdef CONFIG_SMP
368 #if DBG
369 /* Assert that we're on the right CPU */
370 mov cl, [esi+KTHREAD_NEXT_PROCESSOR]
371 cmp cl, [ebx+KPCR_PROCESSOR_NUMBER]
372 jnz WrongCpu
373 #endif
374 #endif
375
376 /* Get CR0 and save it */
377 mov ebp, cr0
378 mov edx, ebp
379
380 #ifdef CONFIG_SMP
381 /* Check NPX State */
382 cmp byte ptr [edi+KTHREAD_NPX_STATE], NPX_STATE_LOADED
383 jz NpxLoaded
384 #endif
385
386 SetStack:
387 /* Set new stack */
388 mov [edi+KTHREAD_KERNEL_STACK], esp
389
390 /* Checking NPX, disable interrupts now */
391 mov eax, [esi+KTHREAD_INITIAL_STACK]
392 cli
393
394 /* Get the NPX State */
395 movzx ecx, byte ptr [esi+KTHREAD_NPX_STATE]
396
397 /* Clear the other bits, merge in CR0, merge in FPU CR0 bits and compare */
398 and edx, ~(CR0_MP + CR0_EM + CR0_TS)
399 or ecx, edx
400 or ecx, [eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)]
401 cmp ebp, ecx
402 jnz NewCr0
403
404 StackOk:
405 /* Enable interrupts and set the current stack */
406 sti
407 mov esp, [esi+KTHREAD_KERNEL_STACK]
408
409 /* Check if address space switch is needed */
410 mov ebp, [esi+KTHREAD_APCSTATE_PROCESS]
411 mov eax, [edi+KTHREAD_APCSTATE_PROCESS]
412 cmp ebp, eax
413 jz SameProcess
414
415 #ifdef CONFIG_SMP
416 /* Get the active processors and XOR with the process' */
417 mov ecx, [ebx+KPCR_SET_MEMBER_COPY]
418 lock xor [ebp+KPROCESS_ACTIVE_PROCESSORS], ecx
419 lock xor [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
420
421 /* Assert change went ok */
422 #if DBG
423 test [ebp+KPROCESS_ACTIVE_PROCESSORS], ecx
424 jz WrongActiveCpu
425 test [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
426 jz WrongActiveCpu
427 #endif
428 #endif
429
430 /* Check if we need an LDT */
431 mov ecx, [ebp+KPROCESS_LDT_DESCRIPTOR0]
432 or ecx, [eax+KPROCESS_LDT_DESCRIPTOR0]
433 jnz LdtReload
434
435 UpdateCr3:
436 /* Switch address space */
437 mov eax, [ebp+KPROCESS_DIRECTORY_TABLE_BASE]
438 mov cr3, eax
439
440 SameProcess:
441
442 #ifdef CONFIG_SMP
443 /* Release swap lock */
444 and byte ptr [edi+KTHREAD_SWAP_BUSY], 0
445 #endif
446
447 /* Clear gs */
448 xor eax, eax
449 mov gs, ax
450
451 /* Set the TEB */
452 mov eax, [esi+KTHREAD_TEB]
453 mov [ebx+KPCR_TEB], eax
454 mov ecx, [ebx+KPCR_GDT]
455 mov [ecx+0x3A], ax
456 shr eax, 16
457 mov [ecx+0x3C], al
458 mov [ecx+0x3F], ah
459
460 /* Get stack pointer */
461 mov eax, [esi+KTHREAD_INITIAL_STACK]
462
463 /* Make space for the NPX Frame */
464 sub eax, NPX_FRAME_LENGTH
465
466 /* Check if this isn't V86 Mode, so we can bias the Esp0 */
467 test dword ptr [eax - KTRAP_FRAME_SIZE + KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
468 jnz NoAdjust
469
470 /* Bias esp */
471 sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
472
473 NoAdjust:
474
475 /* Set new ESP0 */
476 mov ecx, [ebx+KPCR_TSS]
477 mov [ecx+KTSS_ESP0], eax
478
479 /* Set current IOPM offset in the TSS */
480 mov ax, [ebp+KPROCESS_IOPM_OFFSET]
481 mov [ecx+KTSS_IOMAPBASE], ax
482
483 /* Increase context switches */
484 inc dword ptr [esi+KTHREAD_CONTEXT_SWITCHES]
485
486 /* Restore exception list */
487 pop [ebx+KPCR_EXCEPTION_LIST]
488
489 /* Restore IRQL */
490 pop ecx
491
492 /* DPC shouldn't be active */
493 cmp byte ptr [ebx+KPCR_PRCB_DPC_ROUTINE_ACTIVE], 0
494 jnz BugCheckDpc
495
496 /* Check if kernel APCs are pending */
497 cmp byte ptr [esi+KTHREAD_PENDING_KERNEL_APC], 0
498 jnz CheckApc
499
500 /* No APCs, return */
501 xor eax, eax
502 ret
503
504 CheckApc:
505
506 /* Check if they're disabled */
507 cmp word ptr [esi+KTHREAD_SPECIAL_APC_DISABLE], 0
508 jnz ApcReturn
509 test cl, cl
510 jz ApcReturn
511
512 /* Request APC Delivery */
513 mov cl, APC_LEVEL
514 call @HalRequestSoftwareInterrupt@4
515 or eax, esp
516
517 ApcReturn:
518
519 /* Return with APC pending */
520 setz al
521 ret
522
523 LdtReload:
524 /* Check if it's empty */
525 mov eax, [ebp+KPROCESS_LDT_DESCRIPTOR0]
526 test eax, eax
527 jz LoadLdt
528
529 /* Write the LDT Selector */
530 mov ecx, [ebx+KPCR_GDT]
531 mov [ecx+KGDT_LDT], eax
532 mov eax, [ebp+KPROCESS_LDT_DESCRIPTOR1]
533 mov [ecx+KGDT_LDT+4], eax
534
535 /* Write the INT21 handler */
536 mov ecx, [ebx+KPCR_IDT]
537 mov eax, [ebp+KPROCESS_INT21_DESCRIPTOR0]
538 mov [ecx+0x108], eax
539 mov eax, [ebp+KPROCESS_INT21_DESCRIPTOR1]
540 mov [ecx+0x10C], eax
541
542 /* Save LDT Selector */
543 mov eax, KGDT_LDT
544
545 LoadLdt:
546 lldt ax
547 jmp UpdateCr3
548
549 NewCr0:
550
551 #if DBG
552 /* Assert NPX State */
553 test byte ptr [esi+KTHREAD_NPX_STATE], ~(NPX_STATE_NOT_LOADED)
554 jnz InvalidNpx
555 test dword ptr [eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)], ~(CR0_PE + CR0_MP + CR0_EM + CR0_TS)
556 jnz InvalidNpx
557 #endif
558
559 /* Update CR0 */
560 mov cr0, ecx
561 jmp StackOk
562
563 #ifdef CONFIG_SMP
564 NpxLoaded:
565
566 /* FIXME: TODO */
567 int 3
568
569 /* Jump back */
570 jmp SetStack
571 #endif
572
573 WmiTrace:
574
575 /* No WMI support yet */
576 int 3
577
578 /* Jump back */
579 jmp AfterTrace
580
581 BugCheckDpc:
582
583 /* Bugcheck the machine, printing out the threads being switched */
584 mov eax, [edi+KTHREAD_INITIAL_STACK]
585 push 0
586 push eax
587 push esi
588 push edi
589 push ATTEMPTED_SWITCH_FROM_DPC
590 call _KeBugCheckEx@20
591
592 #if DBG
593 InvalidNpx:
594 int 3
595 WrongActiveCpu:
596 int 3
597 WrongCpu:
598 int 3
599 #endif
600 .endfunc
601
602 /*++
603 * KiSwapContext
604 *
605 * The KiSwapContext routine switches context to another thread.
606 *
607 * Params:
608 * TargetThread - Pointer to the KTHREAD to which the caller wishes to
609 * switch to.
610 *
611 * Returns:
612 * The WaitStatus of the Target Thread.
613 *
614 * Remarks:
615 * This is a wrapper around KiSwapContextInternal which will save all the
616 * non-volatile registers so that the Internal function can use all of
617 * them. It will also save the old current thread and set the new one.
618 *
619 * The calling thread does not return after KiSwapContextInternal until
620 * another thread switches to IT.
621 *
622 *--*/
623 .globl @KiSwapContext@8
624 .func @KiSwapContext@8, @KiSwapContext@8
625 @KiSwapContext@8:
626
627 /* Save 4 registers */
628 sub esp, 4 * 4
629
630 /* Save all the non-volatile ones */
631 mov [esp+12], ebx
632 mov [esp+8], esi
633 mov [esp+4], edi
634 mov [esp+0], ebp
635
636 /* Get the current KPCR */
637 mov ebx, fs:[KPCR_SELF]
638
639 /* Get the Current Thread */
640 mov edi, ecx
641
642 /* Get the New Thread */
643 mov esi, edx
644
645 /* Get the wait IRQL */
646 movzx ecx, byte ptr [edi+KTHREAD_WAIT_IRQL]
647
648 /* Do the swap with the registers correctly setup */
649 call @KiSwapContextInternal@0
650
651 /* Return the registers */
652 mov ebp, [esp+0]
653 mov edi, [esp+4]
654 mov esi, [esp+8]
655 mov ebx, [esp+12]
656
657 /* Clean stack */
658 add esp, 4 * 4
659 ret
660 .endfunc
661
662 .globl @KiIdleLoop@0
663 .func @KiIdleLoop@0, @KiIdleLoop@0
664 @KiIdleLoop@0:
665
666 /* Set EBX */
667 mov ebx, fs:[KPCR_SELF]
668
669 /* Jump into mainline code */
670 jmp MainLoop
671
672 CpuIdle:
673 /* Call the CPU's idle function */
674 lea ecx, [ebx+KPCR_PRCB_POWER_STATE_IDLE_FUNCTION]
675 call [ecx]
676
677 MainLoop:
678 /* Cycle interrupts for 1 cycle */
679 sti
680 nop
681 nop
682 cli
683
684 /* Check if we have to deliver DPCs, timers, or deferred threads */
685 mov eax, [ebx+KPCR_PRCB_DPC_QUEUE_DEPTH]
686 or eax, [ebx+KPCR_PRCB_TIMER_REQUEST]
687 #ifdef CONFIG_SMP
688 or eax, [ebx+KPCR_PRCB_DEFERRED_READY_LIST_HEAD]
689 #endif
690 jz CheckSchedule
691
692 mov cl, DISPATCH_LEVEL
693 call @HalClearSoftwareInterrupt@4
694
695 /* Handle the above */
696 lea ecx, [ebx+KPCR_PRCB_DATA]
697 call @KiRetireDpcList@4
698
699 CheckSchedule:
700 /* Check if a next thread is queued */
701 cmp dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
702 #ifdef CONFIG_SMP
703 jz NoNextThread
704 #else
705 jz CpuIdle
706 #endif
707
708 #ifdef CONFIG_SMP
709 /* There is, raise IRQL to synch level */
710 call _KeRaiseIrqlToSynchLevel@0
711 #endif
712 sti
713
714 /* Set the current thread to ready */
715 mov edi, [ebx+KPCR_CURRENT_THREAD]
716 #ifdef CONFIG_SMP
717 mov byte ptr [edi+KTHREAD_SWAP_BUSY], 1
718
719 /* Acquire the PRCB Lock */
720 lock bts dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
721 jnb CheckNext
722 lea ecx, [ebx+KPCR_PRCB_PRCB_LOCK]
723 call @KefAcquireSpinLockAtDpcLevel@4
724 #endif
725
726 CheckNext:
727 /* Check if the next thread is the current */
728 mov esi, [ebx+KPCR_PRCB_NEXT_THREAD]
729 #ifdef CONFIG_SMP
730 cmp esi, edi
731 jz SameThread
732 #endif
733
734 /* Clear the next thread and set this one instead */
735 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
736 mov [ebx+KPCR_CURRENT_THREAD], esi
737
738 /* Set the thread as running */
739 mov byte ptr [esi+KTHREAD_STATE_], Running
740
741 #ifdef CONFIG_SMP
742 /* Disable the idle scheduler and release the PRCB lock */
743 and byte ptr [ebx+KPCR_PRCB_IDLE_SCHEDULE], 0
744 and dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
745 #endif
746
747 SwapContext:
748 /* ReactOS Mm Hack */
749 mov ecx, esi
750 call @MiSyncForContextSwitch@4
751
752 /* Swap context at APC_LEVEL */
753 mov ecx, APC_LEVEL
754 call @KiSwapContextInternal@0
755
756 #ifdef CONFIG_SMP
757 /* Lower to DPC level */
758 mov ecx, DISPATCH_LEVEL
759 call @KfLowerIrql@4
760 #endif
761 jmp MainLoop
762
763 #ifdef CONFIG_SMP
764 SameThread:
765 /* Clear the next thread, and put the thready as ready after lock release */
766 and dword ptr [ebx+KPCR_PRCB_NEXT_THREAD], 0
767 and dword ptr [ebx+KPCR_PRCB_PRCB_LOCK], 0
768 and byte ptr [edi+KTHREAD_STATE_], Ready
769 jmp MainLoop
770
771 NoNextThread:
772 /* Check if the idle scheduler is enabled */
773 cmp byte ptr [ebx+KPCR_PRCB_IDLE_SCHEDULE], 0
774 jz CpuIdle
775
776 /* It is, so call the scheduler */
777 lea ecx, [ebx+KPCR_PRCB_DATA]
778 call @KiIdleSchedule@4
779 test eax, eax
780
781 /* Get new thread pointers and either swap or idle loop again */
782 mov esi, eax
783 mov edi, [ebx+KPCR_PRCB_IDLE_THREAD]
784 jnz SwapContext
785 jmp MainLoop
786 #endif
787 .endfunc
788
789 .globl _Ki386AdjustEsp0@4
790 .func Ki386AdjustEsp0@4
791 _Ki386AdjustEsp0@4:
792
793 /* Get the current thread */
794 mov eax, [fs:KPCR_CURRENT_THREAD]
795
796 /* Get trap frame and stack */
797 mov edx, [esp+4]
798 mov eax, [eax+KTHREAD_INITIAL_STACK]
799
800 /* Check if V86 */
801 test dword ptr [edx+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
802 jnz 1f
803
804 /* Bias the stack */
805 sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
806
807 1:
808 /* Skip FX Save Area */
809 sub eax, SIZEOF_FX_SAVE_AREA
810
811 /* Disable interrupts */
812 pushf
813 cli
814
815 /* Adjust ESP0 */
816 mov edx, [fs:KPCR_TSS]
817 mov ss:[edx+KTSS_ESP0], eax
818
819 /* Enable interrupts and return */
820 popf
821 ret 4
822 .endfunc
823
824 .globl _KiSwapProcess@8
825 .func KiSwapProcess@8
826 _KiSwapProcess@8:
827
828 /* Get process pointers */
829 mov edx, [esp+4]
830 mov eax, [esp+8]
831
832 #ifdef CONFIG_SMP
833 /* Update active processors */
834 mov ecx, fs:[KPCR_SET_MEMBER]
835 lock xor [edx+KPROCESS_ACTIVE_PROCESSORS], ecx
836 lock xor [eax+KPROCESS_ACTIVE_PROCESSORS], ecx
837
838 /* Sanity check */
839 #if DBG
840 test dword ptr [edx+KPROCESS_ACTIVE_PROCESSORS], 0
841 jz WrongCpu1
842 test dword ptr [eax+KPROCESS_ACTIVE_PROCESSORS], 0
843 jnz WrongCpu2
844 #endif
845 #endif
846
847 /* Check if their LDTs changed */
848 mov ecx, [edx+KPROCESS_LDT_DESCRIPTOR0]
849 or ecx, [eax+KPROCESS_LDT_DESCRIPTOR0]
850 jnz NewLdt
851
852 /* Update CR3 */
853 mov eax, [edx+KPROCESS_DIRECTORY_TABLE_BASE]
854 mov cr3, eax
855
856 /* Get the KTSS */
857 mov ecx, fs:[KPCR_TSS]
858
859 /* Clear GS on process swap */
860 xor eax, eax
861 mov gs, ax
862
863 /* Update IOPM offset */
864 mov ax, [edx+KPROCESS_IOPM_OFFSET]
865 mov [ecx+KTSS_IOMAPBASE], ax
866
867 /* Return */
868 ret 8
869
870 NewLdt:
871 /* FIXME: TODO */
872 int 3
873
874 #if DBG
875 WrongCpu1:
876 int 3
877 WrongCpu2:
878 int 3
879 #endif
880 .endfunc