reactos操作系统实现(29)
内存大小好像永远追不上人们的需求,以前以为512K就很大了,到现在内存已经是4G,8G内存了,但还是不能满足人们的需求。因为目前的系统都是多进程运行,每个进程都需要占用4G的内存,那么10个进程,就占用相当可观的内存了。这时就需要把进程不经常使用的内存数据切换到硬盘里,需要时再换回来。如果一个进程的内存已经换到硬盘上,而这个进程又想访问那些在硬盘的内存数据时,就会产生一个缺页中断。这个中断是CPU产生的,并且进入操作系统的中断门处理函数里,那么ReactOS是怎么样处理的呢?其实它是调用下面的函数来处理这个中断的,如下:
#001 .func KiTrap14
#002 TRAP_FIXUPS kite_a, kite_t, DoFixupV86, DoNotFixupAbios
#003 _KiTrap14:
#004
中断入口寄存器保存。
#005 /* Enter trap */
#006 TRAP_PROLOG kite_a, kite_t
#007
检查是否有VDM标志。
#008 /* Check if we have a VDM alert */
#009 cmp dword ptr PCR[KPCR_VDM_ALERT], 0
#010 jnz VdmAlertGpf
#011
获取当前线程。
#012 /* Get the current thread */
#013 mov edi, PCR[KPCR_CURRENT_THREAD]
#014
获取当前帧指针。
#015 /* Get the stack address of the frame */
#016 lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
#017 sub eax, [edi+KTHREAD_INITIAL_STACK]
#018 jz NoFixUp
#019
#020 /* This isn't the base frame, check if it's the second */
#021 cmp eax, -KTRAP_FRAME_EFLAGS
#022 jb NoFixUp
#023
#024 /* Check if we have a TEB */
#025 mov eax, PCR[KPCR_TEB]
#026 or eax, eax
#027 jle NoFixUp
#028
#029 /* Fixup the frame */
#030 call _KiFixupFrame
#031
#032 /* Save CR2 */
#033 NoFixUp:
#034 mov edi, cr2
#035
#036 /* ROS HACK: Sometimes we get called with INTS DISABLED! WTF? */
#037 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
#038 je HandlePf
#039
#040 /* Enable interrupts and check if we got here with interrupts disabled */
#041 sti
#042 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
#043 jz IllegalState
#044
#045 HandlePf:
#046 /* Send trap frame and check if this is kernel-mode or usermode */
#047 push ebp
#048 mov eax, [ebp+KTRAP_FRAME_CS]
#049 and eax, MODE_MASK
#050 push eax
#051
设置好参数,准备调用函数MmAccessFault来处理缺页错误。
#052 /* Send faulting address and check if this is read or write */
#053 push edi
#054 mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
#055 and eax, 1
#056 push eax
#057
#058 /* Call the access fault handler */
#059 call _MmAccessFault@16
#060 test eax, eax
#061 jl AccessFail
#062
已经成功处理了缺页中断,返回调用中断处理。
#063 /* Access fault handled, return to caller */
#064 jmp _Kei386EoiHelper@0
#065
#066 AccessFail:
#067 /* First check if this is a fault in the S-LIST functions */
#068 mov ecx, offset _ExpInterlockedPopEntrySListFault@0
#069 cmp [ebp+KTRAP_FRAME_EIP], ecx
#070 jz SlistFault
#071
#072 /* Check if this is a fault in the syscall handler */
#073 mov ecx, offset CopyParams
#074 cmp [ebp+KTRAP_FRAME_EIP], ecx
#075 jz SysCallCopyFault
#076 mov ecx, offset ReadBatch
#077 cmp [ebp+KTRAP_FRAME_EIP], ecx
#078 jnz CheckVdmPf
#079
#080 /* FIXME: TODO */
#081 UNHANDLED_PATH
#082 jmp _Kei386EoiHelper@0
#083
#084 SysCallCopyFault:
#085 /* FIXME: TODO */
#086 UNHANDLED_PATH
#087 jmp _Kei386EoiHelper@0
#088
#089 /* Check if the fault occured in a V86 mode */
#090 CheckVdmPf:
#091 mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
#092 shr ecx, 1
#093 and ecx, 1
#094 test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
#095 jnz VdmPF
#096
#097 /* Check if the fault occured in a VDM */
#098 mov esi, PCR[KPCR_CURRENT_THREAD]
#099 mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
#100 cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
#101 jz CheckStatus
#102
#103 /* Check if we this was in kernel-mode */
#104 test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
#105 jz CheckStatus
#106 cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
#107 jz CheckStatus
#108
#109 VdmPF:
#110 /* FIXME: TODO */
#111 UNHANDLED_PATH
#112
#113 /* Save EIP and check what kind of status failure we got */
#114 CheckStatus:
#115 mov esi, [ebp+KTRAP_FRAME_EIP]
#116 cmp eax, STATUS_ACCESS_VIOLATION
#117 je AccessViol
#118 cmp eax, STATUS_GUARD_PAGE_VIOLATION
#119 je SpecialCode
#120 cmp eax, STATUS_STACK_OVERFLOW
#121 je SpecialCode
#122
#123 /* Setup an in-page exception to dispatch */
#124 mov edx, ecx
#125 mov ebx, esi
#126 mov esi, edi
#127 mov ecx, 3
#128 mov edi, eax
#129 mov eax, STATUS_IN_PAGE_ERROR
#130 call _CommonDispatchException
#131
#132 AccessViol:
#133 /* Use more proper status code */
#134 mov eax, KI_EXCEPTION_ACCESS_VIOLATION
#135
#136 SpecialCode:
#137 /* Setup a normal page fault exception */
#138 mov ebx, esi
#139 mov edx, ecx
#140 mov esi, edi
#141 jmp _DispatchTwoParam
#142
#143 SlistFault:
#144 /* FIXME: TODO */
#145 UNHANDLED_PATH
#146
#147 IllegalState:
#148
#149 /* This is completely illegal, bugcheck the system */
#150 push ebp
#151 push esi
#152 push ecx
#153 push eax
#154 push edi
#155 push IRQL_NOT_LESS_OR_EQUAL
#156 call _KeBugCheckWithTf@24
#157
#158 VdmAlertGpf:
#159
#160 /* FIXME: NOT SUPPORTED */
#161 UNHANDLED_PATH
#162 .endfunc
通过上面函数的分析,可以看到主要调用函数MmAccessFault来处理缺页中断,这个函数在ntoskrnl/mm/mm.c文件里定义的。