reactos操作系统实现(46)

前端之家收集整理的这篇文章主要介绍了reactos操作系统实现(46)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

在线程调度里可以看到,需要调用函数@H_404_5@KiSwapContext来进行运行环境切换,由于每个@H_404_5@cpu都是只能运行一个线程,而多个线程在运行过程中被中断了,那么就需要保存@H_404_5@cpu所有寄存器,以便下一次恢复线程时可以接续运行。现在就来分析这个函数是怎么样实现这些工作的,代码如下:@H_404_5@

@H_404_5@#001 /*++

@H_404_5@#002 * KiSwapContext

@H_404_5@#003 *

@H_404_5@#004 * The KiSwapContext routine switches context to another thread.

@H_404_5@#005 *

@H_404_5@#006 * Params:

@H_404_5@#007 * TargetThread - Pointer to the KTHREAD to which the caller wishes to

@H_404_5@#008 * switch to.

@H_404_5@#009 *

@H_404_5@#010 * Returns:

@H_404_5@#011 * The WaitStatus of the Target Thread.

@H_404_5@#012 *

@H_404_5@#013 * Remarks:

@H_404_5@#014 * This is a wrapper around KiSwapContextInternal which will save all the

@H_404_5@#015 * non-volatile registers so that the Internal function can use all of

@H_404_5@#016 * them. It will also save the old current thread and set the new one.

@H_404_5@#017 *

@H_404_5@#018 * The calling thread does not return after KiSwapContextInternal until

@H_404_5@#019 * another thread switches to IT.

@H_404_5@#020 *

@H_404_5@#021 *--*/

@H_404_5@#022 .globl @KiSwapContext@8

@H_404_5@#023 .func @KiSwapContext@8,@KiSwapContext@8

@H_404_5@#024 @KiSwapContext@8:

@H_404_5@#025

@H_404_5@

保存寄存器的值,以便调用后返回。@H_404_5@

@H_404_5@#026 /* Save 4 registers */

@H_404_5@#027 sub esp,4 * 4

@H_404_5@#028

@H_404_5@#029 /* Save all the non-volatile ones */

@H_404_5@#030 mov [esp+12],ebx

@H_404_5@#031 mov [esp+8],esi

@H_404_5@#032 mov [esp+4],edi

@H_404_5@#033 mov [esp+0],ebp

@H_404_5@#034

@H_404_5@

获取处理器块@H_404_5@KPCR,因为@H_404_5@FS保存了@H_404_5@KPCR的数据结构所在的段。@H_404_5@

@H_404_5@#035 /* Get the current KPCR */

@H_404_5@#036 mov ebx,fs:[KPCR_SELF]

@H_404_5@#037

@H_404_5@

获取当前线程指针。@H_404_5@

@H_404_5@#038 /* Get the Current Thread */

@H_404_5@#039 mov edi,ecx

@H_404_5@#040

@H_404_5@

获取下一个将要运行的线程指针。@H_404_5@

@H_404_5@#041 /* Get the New Thread */

@H_404_5@#042 mov esi,edx

@H_404_5@#043

@H_404_5@

获取当前的@H_404_5@IRQL

@H_404_5@#044 /* Get the wait IRQL */

@H_404_5@#045 movzx ecx,byte ptr [edi+KTHREAD_WAIT_IRQL]

@H_404_5@#046

@H_404_5@

调用函数@H_404_5@KiSwapContextInternal来切换运行环境。@H_404_5@

@H_404_5@#047 /* Do the swap with the registers correctly setup */

@H_404_5@#048 call @KiSwapContextInternal@0

@H_404_5@#049

@H_404_5@

恢复调用前的寄存器值。@H_404_5@

@H_404_5@#050 /* Return the registers */

@H_404_5@#051 mov ebp,[esp+0]

@H_404_5@#052 mov edi,[esp+4]

@H_404_5@#053 mov esi,[esp+8]

@H_404_5@#054 mov ebx,[esp+12]

@H_404_5@#055

@H_404_5@#056 /* Clean stack */

@H_404_5@#057 add esp,4 * 4

@H_404_5@#058 ret

@H_404_5@#059 .endfunc

@H_404_5@

这个函数主要把@H_404_5@C函数调用修改为合适的函数@H_404_5@KiSwapContextInternal调用。因此接着下来分析函数@H_404_5@KiSwapContextInternal代码,如下:@H_404_5@

@H_404_5@#001 /*++

@H_404_5@#002 * KiSwapContextInternal

@H_404_5@#003 *

@H_404_5@#004 * The KiSwapContextInternal routine switches context to another thread.

@H_404_5@#005 *

@H_404_5@#006 * Params:

@H_404_5@

下一个将要运行的线程。@H_404_5@

@H_404_5@#007 * ESI - Pointer to the KTHREAD to which the caller wishes to

@H_404_5@#008 * switch to.

@H_404_5@

当前运行的线程。@H_404_5@

@H_404_5@#009 * EDI - Pointer to the KTHREAD to which the caller wishes to

@H_404_5@#010 * switch from.

@H_404_5@#011 *

@H_404_5@#012 * Returns:

@H_404_5@#013 * None.

@H_404_5@#014 *

@H_404_5@#015 * Remarks:

@H_404_5@#016 * Absolutely all registers except ESP can be trampled here for maximum code flexibility.

@H_404_5@#017 *

@H_404_5@#018 *--*/

@H_404_5@#019 .globl @KiSwapContextInternal@0

@H_404_5@#020 .func @KiSwapContextInternal@0,@KiSwapContextInternal@0

@H_404_5@#021 @KiSwapContextInternal@0:

@H_404_5@#022

@H_404_5@

保存@H_404_5@IRQL@H_404_5@

@H_404_5@#023 /* Save the IRQL */

@H_404_5@#024 push ecx

@H_404_5@#025

@H_404_5@

判断是否支持对称多核处理器。@H_404_5@

@H_404_5@#026 #ifdef CONFIG_SMP

@H_404_5@#027 GetSwapLock:

@H_404_5@#028 /* Acquire the swap lock */

@H_404_5@#029 cmp byte ptr [esi+KTHREAD_SWAP_BUSY],0

@H_404_5@#030 jz NotBusy

@H_404_5@#031 pause

@H_404_5@#032 jmp GetSwapLock

@H_404_5@#033 #endif

@H_404_5@#034 NotBusy:

@H_404_5@#035 /* Increase context switches (use ES for lazy load) */

@H_404_5@#036 inc dword ptr es:[ebx+KPCR_CONTEXT_SWITCHES]

@H_404_5@#037

@H_404_5@

保存当前线程的运行环境到当前线程栈里。@H_404_5@

@H_404_5@#038 /* Save the Exception list */

@H_404_5@#039 push [ebx+KPCR_EXCEPTION_LIST]

@H_404_5@#040

@H_404_5@#041 /* Check for WMI */

@H_404_5@#042 cmp dword ptr [ebx+KPCR_PERF_GLOBAL_GROUP_MASK],0

@H_404_5@#043 jnz WmiTrace

@H_404_5@#044

@H_404_5@#045 AfterTrace:

@H_404_5@#046 #ifdef CONFIG_SMP

@H_404_5@#047 #ifdef DBG

@H_404_5@#048 /* Assert that we're on the right cpu */

@H_404_5@#049 mov cl,[esi+KTHREAD_NEXT_PROCESSOR]

@H_404_5@#050 cmp cl,[ebx+KPCR_PROCESSOR_NUMBER]

@H_404_5@#051 jnz Wrongcpu

@H_404_5@#052 #endif

@H_404_5@#053 #endif

@H_404_5@#054

@H_404_5@#055 /* Get CR0 and save it */

@H_404_5@#056 mov ebp,cr0

@H_404_5@#057 mov edx,ebp

@H_404_5@#058

@H_404_5@#059 #ifdef CONFIG_SMP

@H_404_5@#060 /* Check NPX State */

@H_404_5@#061 cmp byte ptr [edi+KTHREAD_NPX_STATE],NPX_STATE_LOADED

@H_404_5@#062 jz NpxLoaded

@H_404_5@#063 #endif

@H_404_5@#064

@H_404_5@#065 SetStack:

@H_404_5@

保存当前线程的栈。@H_404_5@

@H_404_5@#066 /* Set new stack */

@H_404_5@#067 mov [edi+KTHREAD_KERNEL_STACK],esp

@H_404_5@#068

@H_404_5@#069 /* Checking NPX,disable interrupts now */

@H_404_5@#070 mov eax,[esi+KTHREAD_INITIAL_STACK]

@H_404_5@#071 cli

@H_404_5@#072

@H_404_5@#073 /* Get the NPX State */

@H_404_5@#074 movzx ecx,byte ptr [esi+KTHREAD_NPX_STATE]

@H_404_5@#075

@H_404_5@#076 /* Clear the other bits,merge in CR0,merge in FPU CR0 bits and compare */

@H_404_5@#077 and edx,~(CR0_MP + CR0_EM + CR0_TS)

@H_404_5@#078 or ecx,edx

@H_404_5@#079 or ecx,[eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)]

@H_404_5@#080 cmp ebp,ecx

@H_404_5@#081 jnz NewCr0

@H_404_5@#082

@H_404_5@#083 StackOk:

@H_404_5@

开中断,并切换到新的栈上。@H_404_5@

@H_404_5@#084 /* Enable interrupts and set the current stack */

@H_404_5@#085 sti

@H_404_5@#086 mov esp,[esi+KTHREAD_KERNEL_STACK]

@H_404_5@#087

@H_404_5@

检查当前线程和下一个运行线程是否同一个进程空间。@H_404_5@

@H_404_5@#088 /* Check if address space switch is needed */

@H_404_5@#089 mov ebp,[esi+KTHREAD_APCSTATE_PROCESS]

@H_404_5@#090 mov eax,[edi+KTHREAD_APCSTATE_PROCESS]

@H_404_5@#091 cmp ebp,eax

@H_404_5@

跳到同一个进程处理。@H_404_5@

@H_404_5@#092 jz SameProcess

@H_404_5@#093

@H_404_5@#094 #ifdef CONFIG_SMP

@H_404_5@#095 /* Get the active processors and XOR with the process' */

@H_404_5@#096 mov ecx,[ebx+KPCR_SET_MEMBER_COPY]

@H_404_5@#097 lock xor [ebp+KPROCESS_ACTIVE_PROCESSORS],ecx

@H_404_5@#098 lock xor [eax+KPROCESS_ACTIVE_PROCESSORS],ecx

@H_404_5@#099

@H_404_5@#100 /* Assert change went ok */

@H_404_5@#101 #ifdef DBG

@H_404_5@#102 test [ebp+KPROCESS_ACTIVE_PROCESSORS],ecx

@H_404_5@#103 jz WrongActivecpu

@H_404_5@#104 test [eax+KPROCESS_ACTIVE_PROCESSORS],ecx

@H_404_5@#105 jz WrongActivecpu

@H_404_5@#106 #endif

@H_404_5@#107 #endif

@H_404_5@#108

@H_404_5@

检查是否需要加载@H_404_5@LDT@H_404_5@

@H_404_5@#109 /* Check if we need an LDT */

@H_404_5@#110 mov ecx,[ebp+KPROCESS_LDT_DESCRIPTOR0]

@H_404_5@#111 or ecx,[eax+KPROCESS_LDT_DESCRIPTOR0]

@H_404_5@#112 jnz LdtReload

@H_404_5@#113

@H_404_5@

更新@H_404_5@CR3寄存器,以便更新进程的地址空间。其实就是更新内存的页寄存目录。@H_404_5@

@H_404_5@#114 UpdateCr3:

@H_404_5@#115 /* Switch address space */

@H_404_5@#116 mov eax,[ebp+KPROCESS_DIRECTORY_TABLE_BASE]

@H_404_5@#117 mov cr3,eax

@H_404_5@#118

@H_404_5@

同一个进程地址空间。@H_404_5@

@H_404_5@#119 SameProcess:

@H_404_5@#120

@H_404_5@#121 #ifdef CONFIG_SMP

@H_404_5@#122 /* Release swap lock */

@H_404_5@#123 and byte ptr [edi+KTHREAD_SWAP_BUSY],0

@H_404_5@#124 #endif

@H_404_5@#125

@H_404_5@#126 /* Clear gs */

@H_404_5@#127 xor eax,eax

@H_404_5@#128 mov gs,ax

@H_404_5@#129

@H_404_5@

设置下一个线程运行的@H_404_5@TEB@H_404_5@

@H_404_5@#130 /* Set the TEB */

@H_404_5@#131 mov eax,[esi+KTHREAD_TEB]

@H_404_5@#132 mov [ebx+KPCR_TEB],eax

@H_404_5@#133 mov ecx,[ebx+KPCR_GDT]

@H_404_5@#134 mov [ecx+0x3A],ax

@H_404_5@#135 shr eax,16

@H_404_5@#136 mov [ecx+0x3C],al

@H_404_5@#137 mov [ecx+0x3F],ah

@H_404_5@#138

@H_404_5@

获取下一个线程的栈指针。@H_404_5@

@H_404_5@#139 /* Get stack pointer */

@H_404_5@#140 mov eax,[esi+KTHREAD_INITIAL_STACK]

@H_404_5@#141

@H_404_5@

计算下一个线程运行的栈空间大小。@H_404_5@

@H_404_5@#142 /* Make space for the NPX Frame */

@H_404_5@#143 sub eax,NPX_FRAME_LENGTH

@H_404_5@#144

@H_404_5@

检查是否为虚拟@H_404_5@86的运行模式。@H_404_5@

@H_404_5@#145 /* Check if this isn't V86 Mode,so we can bias the Esp0 */

@H_404_5@#146 test dword ptr [eax - KTRAP_FRAME_SIZE + KTRAP_FRAME_EFLAGS],EFLAGS_V86_MASK

@H_404_5@#147 jnz NoAdjust

@H_404_5@#148

@H_404_5@#149 /* Bias esp */

@H_404_5@#150 sub eax,KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS

@H_404_5@#151

@H_404_5@#152 NoAdjust:

@H_404_5@#153

@H_404_5@

设置下一个运行线程的任务段@H_404_5@TSS@H_404_5@

@H_404_5@#154 /* Set new ESP0 */

@H_404_5@#155 mov ecx,[ebx+KPCR_TSS]

@H_404_5@#156 mov [ecx+KTSS_ESP0],eax

@H_404_5@#157

@H_404_5@#158 /* Set current IOPM offset in the TSS */

@H_404_5@#159 mov ax,[ebp+KPROCESS_IOPM_OFFSET]

@H_404_5@#160 mov [ecx+KTSS_IOMAPBASE],ax

@H_404_5@#161

@H_404_5@#162 /* Increase context switches */

@H_404_5@#163 inc dword ptr [esi+KTHREAD_CONTEXT_SWITCHES]

@H_404_5@#164

@H_404_5@

从下一个线程的栈里获取将要运行的环境。@H_404_5@

@H_404_5@#165 /* Restore exception list */

@H_404_5@#166 pop [ebx+KPCR_EXCEPTION_LIST]

@H_404_5@#167

@H_404_5@#168 /* Restore IRQL */

@H_404_5@#169 pop ecx

@H_404_5@#170

@H_404_5@#171 /* DPC shouldn't be active */

@H_404_5@#172 cmp byte ptr [ebx+KPCR_PRCB_DPC_ROUTINE_ACTIVE],0

@H_404_5@#173 jnz BugCheckDpc

@H_404_5@#174

@H_404_5@#175 /* Check if kernel APCs are pending */

@H_404_5@#176 cmp byte ptr [esi+KTHREAD_PENDING_KERNEL_APC],0

@H_404_5@#177 jnz CheckApc

@H_404_5@#178

@H_404_5@

如果没有异步调用@H_404_5@APC,就直接返回。@H_404_5@

@H_404_5@#179 /* No APCs,return */

@H_404_5@#180 xor eax,eax

@H_404_5@#181 ret

@H_404_5@#182

@H_404_5@

下面检查异步调用@H_404_5@APC@H_404_5@

@H_404_5@#183 CheckApc:

@H_404_5@#184

@H_404_5@#185 /* Check if they're disabled */

@H_404_5@#186 cmp word ptr [esi+KTHREAD_SPECIAL_APC_DISABLE],0

@H_404_5@#187 jnz ApcReturn

@H_404_5@#188 test cl,cl

@H_404_5@#189 jz ApcReturn

@H_404_5@#190

@H_404_5@#191 /* Request APC Delivery */

@H_404_5@#192 mov cl,APC_LEVEL

@H_404_5@#193 call @HalRequestSoftwareInterrupt@4

@H_404_5@#194 or eax,esp

@H_404_5@#195

@H_404_5@#196 ApcReturn:

@H_404_5@#197

@H_404_5@#198 /* Return with APC pending */

@H_404_5@#199 setz al

@H_404_5@#200 ret

@H_404_5@#201

@H_404_5@

需要重新加局部描述符表@H_404_5@LDT@H_404_5@

@H_404_5@#202 LdtReload:

@H_404_5@#203 /* Check if it's empty */

@H_404_5@#204 mov eax,[ebp+KPROCESS_LDT_DESCRIPTOR0]

@H_404_5@#205 test eax,eax

@H_404_5@#206 jz LoadLdt

@H_404_5@#207

@H_404_5@#208 /* Write the LDT Selector */

@H_404_5@#209 mov ecx,[ebx+KPCR_GDT]

@H_404_5@#210 mov [ecx+KGDT_LDT],eax

@H_404_5@#211 mov eax,[ebp+KPROCESS_LDT_DESCRIPTOR1]

@H_404_5@#212 mov [ecx+KGDT_LDT+4],eax

@H_404_5@#213

@H_404_5@#214 /* Write the INT21 handler */

@H_404_5@#215 mov ecx,[ebx+KPCR_IDT]

@H_404_5@#216 mov eax,[ebp+KPROCESS_INT21_DESCRIPTOR0]

@H_404_5@#217 mov [ecx+0x108],eax

@H_404_5@#218 mov eax,[ebp+KPROCESS_INT21_DESCRIPTOR1]

@H_404_5@#219 mov [ecx+0x10C],eax

@H_404_5@#220

@H_404_5@#221 /* Save LDT Selector */

@H_404_5@#222 mov eax,KGDT_LDT

@H_404_5@#223

@H_404_5@#224 LoadLdt:

@H_404_5@#225 lldt ax

@H_404_5@#226 jmp UpdateCr3

@H_404_5@#227

@H_404_5@

需要重新计算@H_404_5@CR0寄存器值。@H_404_5@

@H_404_5@#228 NewCr0:

@H_404_5@#229

@H_404_5@#230 #ifdef DBG

@H_404_5@#231 /* Assert NPX State */

@H_404_5@#232 test byte ptr [esi+KTHREAD_NPX_STATE],~(NPX_STATE_NOT_LOADED)

@H_404_5@#233 jnz InvalidNpx

@H_404_5@#234 test dword ptr [eax - (NPX_FRAME_LENGTH - FN_CR0_NPX_STATE)],~(CR0_PE + CR0_MP + CR0_EM + CR0_TS)

@H_404_5@#235 jnz InvalidNpx

@H_404_5@#236 #endif

@H_404_5@#237

@H_404_5@#238 /* Update CR0 */

@H_404_5@#239 mov cr0,ecx

@H_404_5@#240 jmp StackOk

@H_404_5@#241

@H_404_5@#242 #ifdef CONFIG_SMP

@H_404_5@#243 NpxLoaded:

@H_404_5@#244

@H_404_5@#245 /* FIXME: TODO */

@H_404_5@#246 int 3

@H_404_5@#247

@H_404_5@#248 /* Jump back */

@H_404_5@#249 jmp SetStack

@H_404_5@#250 #endif

@H_404_5@#251

@H_404_5@

下面出错处理。@H_404_5@

@H_404_5@#252 WmiTrace:

@H_404_5@#253

@H_404_5@#254 /* No WMI support yet */

@H_404_5@#255 int 3

@H_404_5@#256

@H_404_5@#257 /* Jump back */

@H_404_5@#258 jmp AfterTrace

@H_404_5@#259

@H_404_5@#260 BugCheckDpc:

@H_404_5@#261

@H_404_5@#262 /* Bugcheck the machine,printing out the threads being switched */

@H_404_5@#263 mov eax,[edi+KTHREAD_INITIAL_STACK]

@H_404_5@#264 push 0

@H_404_5@#265 push eax

@H_404_5@#266 push esi

@H_404_5@#267 push edi

@H_404_5@#268 push ATTEMPTED_SWITCH_FROM_DPC

@H_404_5@#269 call _KeBugCheckEx@20

@H_404_5@#270

@H_404_5@#271 #ifdef DBG

@H_404_5@#272 InvalidNpx:

@H_404_5@#273 int 3

@H_404_5@#274 WrongActivecpu:

@H_404_5@#275 int 3

@H_404_5@#276 Wrongcpu:

@H_404_5@#277 int 3

@H_404_5@#278 #endif

@H_404_5@#279 .endfunc

@H_404_5@

通过上面的函数分析,可以了解到线程的环境切换,主要就是线程的页面切换(@H_404_5@CR3),线程的环境块切换(@H_404_5@TEB),任务段切换@H_404_5@ESP0@H_404_5@TSS)。

猜你在找的React相关文章