summaryrefslogtreecommitdiffstats
path: root/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm
diff options
context:
space:
mode:
Diffstat (limited to 'CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm')
-rw-r--r--CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm157
1 files changed, 157 insertions, 0 deletions
diff --git a/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm b/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm
new file mode 100644
index 0000000000..c9f07e3666
--- /dev/null
+++ b/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm
@@ -0,0 +1,157 @@
+;***
+;ulldiv.asm - unsigned long divide routine
+;
+; Copyright (c) Microsoft Corporation. All rights reserved.
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+;Purpose:
+; defines the unsigned long divide routine
+; __aulldiv
+;
+;Original Implemenation: MSVC 14.29.30133
+;
+;*******************************************************************************
+ .686
+ .model flat,C
+ .code
+
+;***
+;ulldiv - unsigned long divide
+;
+;Purpose:
+; Does a unsigned long divide of the arguments. Arguments are
+; not changed.
+;
+;Entry:
+; Arguments are passed on the stack:
+; 1st pushed: divisor (QWORD)
+; 2nd pushed: dividend (QWORD)
+;
+;Exit:
+; EDX:EAX contains the quotient (dividend/divisor)
+; NOTE: this routine removes the parameters from the stack.
+;
+;Uses:
+; ECX
+;
+;Exceptions:
+;
+;*******************************************************************************
+_aulldiv PROC NEAR
+
+HIWORD EQU [4] ;
+LOWORD EQU [0]
+
+ push ebx
+ push esi
+
+; Set up the local stack and save the index registers. When this is done
+; the stack frame will look as follows (assuming that the expression a/b will
+; generate a call to uldiv(a, b)):
+;
+; -----------------
+; | |
+; |---------------|
+; | |
+; |--divisor (b)--|
+; | |
+; |---------------|
+; | |
+; |--dividend (a)-|
+; | |
+; |---------------|
+; | return addr** |
+; |---------------|
+; | EBX |
+; |---------------|
+; ESP---->| ESI |
+; -----------------
+;
+
+DVND equ [esp + 12] ; stack address of dividend (a)
+DVSR equ [esp + 20] ; stack address of divisor (b)
+
+;
+; Now do the divide. First look to see if the divisor is less than 4194304K.
+; If so, then we can use a simple algorithm with word divides, otherwise
+; things get a little more complex.
+;
+
+ mov eax,HIWORD(DVSR) ; check to see if divisor < 4194304K
+ or eax,eax
+ jnz short L1 ; nope, gotta do this the hard way
+ mov ecx,LOWORD(DVSR) ; load divisor
+ mov eax,HIWORD(DVND) ; load high word of dividend
+ xor edx,edx
+ div ecx ; get high order bits of quotient
+ mov ebx,eax ; save high bits of quotient
+ mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend
+ div ecx ; get low order bits of quotient
+ mov edx,ebx ; edx:eax <- quotient hi:quotient lo
+ jmp short L2 ; restore stack and return
+
+;
+; Here we do it the hard way. Remember, eax contains DVSRHI
+;
+
+L1:
+ mov ecx,eax ; ecx:ebx <- divisor
+ mov ebx,LOWORD(DVSR)
+ mov edx,HIWORD(DVND) ; edx:eax <- dividend
+ mov eax,LOWORD(DVND)
+L3:
+ shr ecx,1 ; shift divisor right one bit; hi bit <- 0
+ rcr ebx,1
+ shr edx,1 ; shift dividend right one bit; hi bit <- 0
+ rcr eax,1
+ or ecx,ecx
+ jnz short L3 ; loop until divisor < 4194304K
+ div ebx ; now divide, ignore remainder
+ mov esi,eax ; save quotient
+
+;
+; We may be off by one, so to check, we will multiply the quotient
+; by the divisor and check the result against the original dividend
+; Note that we must also check for overflow, which can occur if the
+; dividend is close to 2**64 and the quotient is off by 1.
+;
+
+ mul dword ptr HIWORD(DVSR) ; QUOT * HIWORD(DVSR)
+ mov ecx,eax
+ mov eax,LOWORD(DVSR)
+ mul esi ; QUOT * LOWORD(DVSR)
+ add edx,ecx ; EDX:EAX = QUOT * DVSR
+ jc short L4 ; carry means Quotient is off by 1
+
+;
+; do long compare here between original dividend and the result of the
+; multiply in edx:eax. If original is larger or equal, we are ok, otherwise
+; subtract one (1) from the quotient.
+;
+
+ cmp edx,HIWORD(DVND) ; compare hi words of result and original
+ ja short L4 ; if result > original, do subtract
+ jb short L5 ; if result < original, we are ok
+ cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words
+ jbe short L5 ; if less or equal we are ok, else subtract
+L4:
+ dec esi ; subtract 1 from quotient
+L5:
+ xor edx,edx ; edx:eax <- quotient
+ mov eax,esi
+
+;
+; Just the cleanup left to do. edx:eax contains the quotient.
+; Restore the saved registers and return.
+;
+
+L2:
+
+ pop esi
+ pop ebx
+
+ ret 16
+
+_aulldiv ENDP
+
+ end