mirror of
https://github.com/reactos/reactos.git
synced 2024-07-10 14:45:06 +00:00
[NTOSKRNL]
- Convert KiCallUserMode from asm to C (with a small asm wrapper) - Convert KiGetUserModeStackAddress into a C inline function svn path=/trunk/; revision=52855
This commit is contained in:
parent
425c57b083
commit
ee1da65d47
|
@ -846,4 +846,11 @@ Ki386PerfEnd(VOID)
|
||||||
KeGetContextSwitches(KeGetCurrentPrcb()));
|
KeGetContextSwitches(KeGetCurrentPrcb()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FORCEINLINE
|
||||||
|
PULONG
|
||||||
|
KiGetUserModeStackAddress(void)
|
||||||
|
{
|
||||||
|
return &(KeGetCurrentThread()->TrapFrame->HardwareEsp);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -164,7 +164,7 @@ extern VOID __cdecl KiInterruptTemplate(VOID);
|
||||||
#define TIMER_WAIT_BLOCK 0x3L
|
#define TIMER_WAIT_BLOCK 0x3L
|
||||||
|
|
||||||
#ifdef _M_ARM // FIXME: remove this once our headers are cleaned up
|
#ifdef _M_ARM // FIXME: remove this once our headers are cleaned up
|
||||||
//
|
//
|
||||||
// A system call ID is formatted as such:
|
// A system call ID is formatted as such:
|
||||||
// .________________________________________________________________.
|
// .________________________________________________________________.
|
||||||
// | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
// | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
|
||||||
|
@ -187,7 +187,7 @@ extern VOID __cdecl KiInterruptTemplate(VOID);
|
||||||
//
|
//
|
||||||
// NB. From assembly code, the table number must be computed as an offset into
|
// NB. From assembly code, the table number must be computed as an offset into
|
||||||
// the service descriptor table.
|
// the service descriptor table.
|
||||||
//
|
//
|
||||||
// Each entry into the table is 16 bytes long on 32-bit architectures, and
|
// Each entry into the table is 16 bytes long on 32-bit architectures, and
|
||||||
// 32 bytes long on 64-bit architectures.
|
// 32 bytes long on 64-bit architectures.
|
||||||
//
|
//
|
||||||
|
@ -864,7 +864,7 @@ KeBugCheckWithTf(
|
||||||
ULONG_PTR BugCheckParameter4,
|
ULONG_PTR BugCheckParameter4,
|
||||||
PKTRAP_FRAME Tf
|
PKTRAP_FRAME Tf
|
||||||
);
|
);
|
||||||
|
|
||||||
BOOLEAN
|
BOOLEAN
|
||||||
NTAPI
|
NTAPI
|
||||||
KiHandleNmi(VOID);
|
KiHandleNmi(VOID);
|
||||||
|
@ -1020,12 +1020,6 @@ KiCallUserMode(
|
||||||
IN PULONG OutputLength
|
IN PULONG OutputLength
|
||||||
);
|
);
|
||||||
|
|
||||||
PULONG
|
|
||||||
NTAPI
|
|
||||||
KiGetUserModeStackAddress(
|
|
||||||
VOID
|
|
||||||
);
|
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
KiInitMachineDependent(VOID);
|
KiInitMachineDependent(VOID);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
struct _EPROCESS;
|
struct _EPROCESS;
|
||||||
|
|
||||||
|
extern PMMSUPPORT MmKernelAddressSpace;
|
||||||
extern PFN_NUMBER MiFreeSwapPages;
|
extern PFN_NUMBER MiFreeSwapPages;
|
||||||
extern PFN_NUMBER MiUsedSwapPages;
|
extern PFN_NUMBER MiUsedSwapPages;
|
||||||
extern SIZE_T MmTotalPagedPoolQuota;
|
extern SIZE_T MmTotalPagedPoolQuota;
|
||||||
|
@ -1134,7 +1135,7 @@ MiGetPfnEntry(IN PFN_NUMBER Pfn)
|
||||||
|
|
||||||
/* Make sure the PFN number is valid */
|
/* Make sure the PFN number is valid */
|
||||||
if (Pfn > MmHighestPhysicalPage) return NULL;
|
if (Pfn > MmHighestPhysicalPage) return NULL;
|
||||||
|
|
||||||
/* Make sure this page actually has a PFN entry */
|
/* Make sure this page actually has a PFN entry */
|
||||||
if ((MiPfnBitMap.Buffer) && !(RtlTestBit(&MiPfnBitMap, (ULONG)Pfn))) return NULL;
|
if ((MiPfnBitMap.Buffer) && !(RtlTestBit(&MiPfnBitMap, (ULONG)Pfn))) return NULL;
|
||||||
|
|
||||||
|
@ -1338,7 +1339,7 @@ MmRawDeleteVirtualMapping(PVOID Address);
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
MmGetPageFileMapping(
|
MmGetPageFileMapping(
|
||||||
struct _EPROCESS *Process,
|
struct _EPROCESS *Process,
|
||||||
PVOID Address,
|
PVOID Address,
|
||||||
SWAPENTRY* SwapEntry);
|
SWAPENTRY* SwapEntry);
|
||||||
|
|
||||||
|
@ -1735,7 +1736,15 @@ MmCallDllInitialize(
|
||||||
IN PLIST_ENTRY ListHead
|
IN PLIST_ENTRY ListHead
|
||||||
);
|
);
|
||||||
|
|
||||||
extern PMMSUPPORT MmKernelAddressSpace;
|
|
||||||
|
/* procsup.c *****************************************************************/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
MmGrowKernelStack(
|
||||||
|
IN PVOID StackPointer
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
FORCEINLINE
|
FORCEINLINE
|
||||||
VOID
|
VOID
|
||||||
|
|
|
@ -208,4 +208,146 @@ KeUserModeCallback(IN ULONG RoutineIndex,
|
||||||
return CallbackStatus;
|
return CallbackStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Stack layout:
|
||||||
|
*
|
||||||
|
* ----------------------------------
|
||||||
|
* KCALLOUT_FRAME.ResultLength <= 2nd Parameter to KiCallUserMode
|
||||||
|
* KCALLOUT_FRAME.Result <= 1st Parameter to KiCallUserMode
|
||||||
|
* KCALLOUT_FRAME.ReturnAddress <= Return address of KiCallUserMode
|
||||||
|
* KCALLOUT_FRAME.Ebp \
|
||||||
|
* KCALLOUT_FRAME.Ebx | = volatile registers, pushed
|
||||||
|
* KCALLOUT_FRAME.Esi | by KiCallUserMode
|
||||||
|
* KCALLOUT_FRAME.Edi /
|
||||||
|
* KCALLOUT_FRAME.CallbackStack
|
||||||
|
* KCALLOUT_FRAME.TrapFrame
|
||||||
|
* KCALLOUT_FRAME.InitialStack <= CalloutFrame points here
|
||||||
|
* ----------------------------------
|
||||||
|
* ~~ optional alignment ~~
|
||||||
|
* ----------------------------------
|
||||||
|
* FX_SAVE_AREA
|
||||||
|
* ----------------------------------
|
||||||
|
* KTRAP_FRAME
|
||||||
|
* ----------------------------------
|
||||||
|
* ~~ begin of stack frame for KiUserModeCallout ~~
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
NTSTATUS
|
||||||
|
FASTCALL
|
||||||
|
KiUserModeCallout(PKCALLOUT_FRAME CalloutFrame)
|
||||||
|
{
|
||||||
|
PKTHREAD CurrentThread;
|
||||||
|
PKTRAP_FRAME TrapFrame, CallbackTrapFrame;
|
||||||
|
PFX_SAVE_AREA FxSaveArea, OldFxSaveArea;
|
||||||
|
PKPCR Pcr;
|
||||||
|
PKTSS Tss;
|
||||||
|
ULONG_PTR InitialStack;
|
||||||
|
NTSTATUS Status;
|
||||||
|
|
||||||
|
/* Get the current thread */
|
||||||
|
CurrentThread = KeGetCurrentThread();
|
||||||
|
|
||||||
|
#if DBG
|
||||||
|
/* Check if we are at pasive level */
|
||||||
|
if (KeGetCurrentIrql() != PASSIVE_LEVEL)
|
||||||
|
{
|
||||||
|
/* We're not, bugcheck */
|
||||||
|
KeBugCheckEx(IRQL_GT_ZERO_AT_SYSTEM_SERVICE,
|
||||||
|
0,
|
||||||
|
KeGetCurrentIrql(),
|
||||||
|
0,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if we are attached or APCs are disabled */
|
||||||
|
if ((CurrentThread->ApcStateIndex != OriginalApcEnvironment) ||
|
||||||
|
(CurrentThread->CombinedApcDisable > 0))
|
||||||
|
{
|
||||||
|
KeBugCheckEx(APC_INDEX_MISMATCH,
|
||||||
|
0,
|
||||||
|
CurrentThread->ApcStateIndex,
|
||||||
|
CurrentThread->CombinedApcDisable,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Align stack on 16-byte boundary */
|
||||||
|
InitialStack = (ULONG_PTR)CalloutFrame & ~15;
|
||||||
|
|
||||||
|
/* Check if we have enough space on the stack */
|
||||||
|
if ((InitialStack - KERNEL_STACK_SIZE) < CurrentThread->StackLimit)
|
||||||
|
{
|
||||||
|
/* We don't, we'll have to grow our stack */
|
||||||
|
Status = MmGrowKernelStack((PVOID)InitialStack);
|
||||||
|
|
||||||
|
/* Quit if we failed */
|
||||||
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the current callback stack and initial stack */
|
||||||
|
CalloutFrame->CallbackStack = (ULONG_PTR)CurrentThread->CallbackStack;
|
||||||
|
CalloutFrame->InitialStack = (ULONG_PTR)CurrentThread->InitialStack;
|
||||||
|
|
||||||
|
/* Get and save the trap frame */
|
||||||
|
TrapFrame = CurrentThread->TrapFrame;
|
||||||
|
CalloutFrame->TrapFrame = (ULONG_PTR)TrapFrame;
|
||||||
|
|
||||||
|
/* Set the new callback stack */
|
||||||
|
CurrentThread->CallbackStack = CalloutFrame;
|
||||||
|
|
||||||
|
/* Set destination and origin NPX Areas */
|
||||||
|
OldFxSaveArea = (PVOID)(CalloutFrame->InitialStack - sizeof(FX_SAVE_AREA));
|
||||||
|
FxSaveArea = (PVOID)(InitialStack - sizeof(FX_SAVE_AREA));
|
||||||
|
|
||||||
|
/* Disable interrupts so we can fill the NPX State */
|
||||||
|
_disable();
|
||||||
|
|
||||||
|
/* Now copy the NPX State */
|
||||||
|
FxSaveArea->U.FnArea.ControlWord = OldFxSaveArea->U.FnArea.ControlWord;
|
||||||
|
FxSaveArea->U.FnArea.StatusWord = OldFxSaveArea->U.FnArea.StatusWord;
|
||||||
|
FxSaveArea->U.FnArea.TagWord = OldFxSaveArea->U.FnArea.TagWord;
|
||||||
|
FxSaveArea->U.FnArea.DataSelector = OldFxSaveArea->U.FnArea.DataSelector;
|
||||||
|
FxSaveArea->Cr0NpxState = OldFxSaveArea->Cr0NpxState;
|
||||||
|
|
||||||
|
/* Set the stack address */
|
||||||
|
CurrentThread->InitialStack = (PVOID)InitialStack;
|
||||||
|
|
||||||
|
/* Locate the trap frame on the callback stack */
|
||||||
|
CallbackTrapFrame = (PVOID)((ULONG_PTR)FxSaveArea - sizeof(KTRAP_FRAME));
|
||||||
|
|
||||||
|
/* Copy the trap frame to the new location */
|
||||||
|
*CallbackTrapFrame = *TrapFrame;
|
||||||
|
|
||||||
|
/* Get PCR */
|
||||||
|
Pcr = KeGetPcr();
|
||||||
|
|
||||||
|
/* Update the exception list */
|
||||||
|
CallbackTrapFrame->ExceptionList = Pcr->Used_ExceptionList;
|
||||||
|
|
||||||
|
/* Get TSS */
|
||||||
|
Tss = Pcr->TSS;
|
||||||
|
|
||||||
|
/* Bias the stack for V86 mode */
|
||||||
|
if (CallbackTrapFrame->EFlags & EFLAGS_V86_MASK)
|
||||||
|
{
|
||||||
|
/* Set new stack address in TSS */
|
||||||
|
Tss->Esp0 = (ULONG_PTR)(CallbackTrapFrame + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Set new stack address in TSS */
|
||||||
|
Tss->Esp0 = (ULONG_PTR)&CallbackTrapFrame->V86Es;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set user-mode dispatcher address as EIP */
|
||||||
|
CallbackTrapFrame->Eip = (ULONG_PTR)KeUserCallbackDispatcher;
|
||||||
|
|
||||||
|
/* Bring interrupts back */
|
||||||
|
_enable();
|
||||||
|
|
||||||
|
/* Exit to user-mode */
|
||||||
|
KiServiceExit(CallbackTrapFrame, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* EOF */
|
/* EOF */
|
||||||
|
|
|
@ -17,20 +17,11 @@ EXTERN _KeUserCallbackDispatcher:DWORD
|
||||||
EXTERN @KiServiceExit@8:PROC
|
EXTERN @KiServiceExit@8:PROC
|
||||||
EXTERN _KeGetCurrentIrql@0:PROC
|
EXTERN _KeGetCurrentIrql@0:PROC
|
||||||
EXTERN _KeBugCheckEx@20:PROC
|
EXTERN _KeBugCheckEx@20:PROC
|
||||||
|
EXTERN @KiUserModeCallout@4:PROC
|
||||||
|
|
||||||
/* FUNCTIONS ****************************************************************/
|
/* FUNCTIONS ****************************************************************/
|
||||||
.code
|
.code
|
||||||
|
|
||||||
PUBLIC _KiGetUserModeStackAddress@0
|
|
||||||
_KiGetUserModeStackAddress@0:
|
|
||||||
|
|
||||||
/* Get the current thread's trapframe and return the esp */
|
|
||||||
mov eax, fs:[KPCR_CURRENT_THREAD]
|
|
||||||
mov eax, [eax+KTHREAD_TRAP_FRAME]
|
|
||||||
lea eax, [eax+KTRAP_FRAME_ESP]
|
|
||||||
ret
|
|
||||||
|
|
||||||
|
|
||||||
/*++
|
/*++
|
||||||
* @name KiCallUserMode
|
* @name KiCallUserMode
|
||||||
*
|
*
|
||||||
|
@ -58,166 +49,23 @@ _KiGetUserModeStackAddress@0:
|
||||||
PUBLIC _KiCallUserMode@8
|
PUBLIC _KiCallUserMode@8
|
||||||
_KiCallUserMode@8:
|
_KiCallUserMode@8:
|
||||||
|
|
||||||
/* Save volatile registers */
|
/* Push volatile registers on the stack.
|
||||||
|
This is part of the KCALLOUT_FRAME */
|
||||||
push ebp
|
push ebp
|
||||||
push ebx
|
push ebx
|
||||||
push esi
|
push esi
|
||||||
push edi
|
push edi
|
||||||
|
|
||||||
/* Get the current thread */
|
/* load the address of the callout frame into ecx */
|
||||||
mov ebx, fs:[KPCR_CURRENT_THREAD]
|
lea ecx, [esp - 12]
|
||||||
|
|
||||||
/* Make sure we're at passive */
|
/* Allocate space for the inital stack */
|
||||||
#if DBG
|
sub esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16
|
||||||
call _KeGetCurrentIrql@0
|
|
||||||
or al, al
|
|
||||||
jz AtPassive
|
|
||||||
|
|
||||||
/* We're not, bugcheck! */
|
call @KiUserModeCallout@4
|
||||||
push 0
|
|
||||||
push 0
|
|
||||||
push eax
|
|
||||||
push 0
|
|
||||||
push IRQL_GT_ZERO_AT_SYSTEM_SERVICE
|
|
||||||
call _KeBugCheckEx@20
|
|
||||||
|
|
||||||
AtPassive:
|
add esp, 12 + NPX_FRAME_LENGTH + KTRAP_FRAME_LENGTH + 16
|
||||||
|
|
||||||
/* Make sure that we are not attached and that APCs are not disabled */
|
|
||||||
movzx eax, byte ptr [ebx+KTHREAD_APC_STATE_INDEX]
|
|
||||||
mov edx, [ebx+KTHREAD_COMBINED_APC_DISABLE]
|
|
||||||
or eax, eax
|
|
||||||
jnz InvalidIndex
|
|
||||||
or edx, edx
|
|
||||||
jz ApcsEnabled
|
|
||||||
|
|
||||||
InvalidIndex:
|
|
||||||
|
|
||||||
push 0
|
|
||||||
push edx
|
|
||||||
push eax
|
|
||||||
push 0
|
|
||||||
push APC_INDEX_MISMATCH
|
|
||||||
call _KeBugCheckEx@20
|
|
||||||
ApcsEnabled:
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Get the lowest stack limit and check if we can handle it */
|
|
||||||
lea eax, [esp-HEX(3000)]
|
|
||||||
cmp eax, [ebx+KTHREAD_STACK_LIMIT]
|
|
||||||
jnb StackOk
|
|
||||||
|
|
||||||
/* We can't, we'll have to grow our stack */
|
|
||||||
push esp
|
|
||||||
call _MmGrowKernelStack@4
|
|
||||||
|
|
||||||
/* Quit if we failed */
|
|
||||||
or eax, eax
|
|
||||||
jnz GrowFailed
|
|
||||||
|
|
||||||
/* Save the current callback stack */
|
|
||||||
StackOk:
|
|
||||||
push [ebx+KTHREAD_CALLBACK_STACK]
|
|
||||||
|
|
||||||
/* Get and save the trap frame */
|
|
||||||
mov edx, [ebx+KTHREAD_TRAP_FRAME]
|
|
||||||
push edx
|
|
||||||
|
|
||||||
/* Get and save the initial stack */
|
|
||||||
mov esi, [ebx+KTHREAD_INITIAL_STACK]
|
|
||||||
push esi
|
|
||||||
|
|
||||||
/* Set the new callback stack */
|
|
||||||
mov [ebx+KTHREAD_CALLBACK_STACK], esp
|
|
||||||
|
|
||||||
/* Align stack on 16-byte boundary */
|
|
||||||
and esp, NOT 15
|
|
||||||
mov edi, esp
|
|
||||||
|
|
||||||
/* Set destination and origin NPX Areas */
|
|
||||||
sub esp, NPX_FRAME_LENGTH
|
|
||||||
sub esi, NPX_FRAME_LENGTH
|
|
||||||
|
|
||||||
/* Disable interrupts so we can fill the NPX State */
|
|
||||||
cli
|
|
||||||
|
|
||||||
/* Now copy the NPX State */
|
|
||||||
mov ecx, [esi+FP_CONTROL_WORD]
|
|
||||||
mov [esp+FP_CONTROL_WORD], ecx
|
|
||||||
mov ecx, [esi+FP_STATUS_WORD]
|
|
||||||
mov [esp+FP_STATUS_WORD], ecx
|
|
||||||
mov ecx, [esi+FP_TAG_WORD]
|
|
||||||
mov [esp+FP_TAG_WORD], ecx
|
|
||||||
mov ecx, [esi+FP_DATA_SELECTOR]
|
|
||||||
mov [esp+FP_DATA_SELECTOR], ecx
|
|
||||||
mov ecx, [esi+FN_CR0_NPX_STATE]
|
|
||||||
mov [esp+FN_CR0_NPX_STATE], ecx
|
|
||||||
|
|
||||||
/* Get TSS */
|
|
||||||
mov esi, fs:[KPCR_TSS]
|
|
||||||
|
|
||||||
/* Set the stack address */
|
|
||||||
mov [ebx+KTHREAD_INITIAL_STACK], edi
|
|
||||||
|
|
||||||
/* Bias the stack for V86 mode */
|
|
||||||
mov ecx, esp
|
|
||||||
sub esp, 16
|
|
||||||
test dword ptr [edx+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
|
|
||||||
jnz DontBias
|
|
||||||
mov ecx, esp
|
|
||||||
|
|
||||||
DontBias:
|
|
||||||
/* Set new stack address in TSS */
|
|
||||||
mov [esi+KTSS_ESP0], ecx
|
|
||||||
|
|
||||||
/* Allocate the trap frame and set it */
|
|
||||||
sub esp, KTRAP_FRAME_V86_ES
|
|
||||||
mov ebp, esp
|
|
||||||
|
|
||||||
/* Set copy iterator and dest/origin parameters and do the copy */
|
|
||||||
mov ecx, (KTRAP_FRAME_V86_ES - KTRAP_FRAME_FS) / 4
|
|
||||||
lea edi, [esp+KTRAP_FRAME_FS]
|
|
||||||
lea esi, [edx+KTRAP_FRAME_FS]
|
|
||||||
rep movsd
|
|
||||||
|
|
||||||
/* Copy DR7 */
|
|
||||||
mov edi, [edx+KTRAP_FRAME_DR7]
|
|
||||||
test edi, NOT DR7_RESERVED_MASK
|
|
||||||
mov [esp+KTRAP_FRAME_DR7], edi
|
|
||||||
|
|
||||||
/* Check if we need to save debug registers */
|
|
||||||
jnz SaveDebug
|
|
||||||
|
|
||||||
/* Get user-mode dispatcher address and set it as EIP */
|
|
||||||
SetEip:
|
|
||||||
mov eax, dword ptr [_KeUserCallbackDispatcher]
|
|
||||||
mov [esp+KTRAP_FRAME_EIP], eax
|
|
||||||
|
|
||||||
/* Set the exception list */
|
|
||||||
mov eax, fs:[KPCR_EXCEPTION_LIST]
|
|
||||||
mov [esp+KTRAP_FRAME_EXCEPTION_LIST], eax
|
|
||||||
|
|
||||||
/* Set the previous mode */
|
|
||||||
mov eax, [edx+KTRAP_FRAME_PREVIOUS_MODE]
|
|
||||||
mov [esp+KTRAP_FRAME_PREVIOUS_MODE], eax
|
|
||||||
|
|
||||||
/* Bring interrupts back */
|
|
||||||
sti
|
|
||||||
|
|
||||||
/* Exit to user-mode */
|
|
||||||
mov ecx, esp
|
|
||||||
jmp @KiServiceExit@8
|
|
||||||
|
|
||||||
SaveDebug:
|
|
||||||
|
|
||||||
/* Copy all 5 DRs */
|
|
||||||
mov ecx, 5
|
|
||||||
lea edi, [esp+KTRAP_FRAME_DR0]
|
|
||||||
lea esi, [edx+KTRAP_FRAME_DR0]
|
|
||||||
rep movsd
|
|
||||||
jmp SetEip
|
|
||||||
|
|
||||||
GrowFailed:
|
|
||||||
/* Restore registers */
|
/* Restore registers */
|
||||||
pop edi
|
pop edi
|
||||||
pop esi
|
pop esi
|
||||||
|
|
Loading…
Reference in a new issue