From bf1ff73c8cde965bfa0fa871ec65cd31a6b9bbd1 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Thu, 3 Aug 2023 12:37:35 +0800 Subject: CryptoPkg: Add instrinsics to support building openssl3 on IA32 windows This dependency is needed to build openssl lib with openssl3 under IA32 Windows, so added implementation for _alldiv, _aulldiv, _aullrem and _alldvrm instrinsics. Signed-off-by: Yi Li Cc: Jiewen Yao Cc: Xiaoyu Lu Cc: Guomin Jiang Reviewed-by: Jiewen Yao Acked-by: Ard Biesheuvel Tested-by: Ard Biesheuvel Tested-by: Brian J. Johnson Tested-by: Kenneth Lautner --- CryptoPkg/Library/IntrinsicLib/Ia32/MathLldiv.asm | 203 +++++++++++++++++++++ CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm | 157 ++++++++++++++++ .../Library/IntrinsicLib/Ia32/MathUlldvrm.asm | 184 +++++++++++++++++++ CryptoPkg/Library/IntrinsicLib/Ia32/MathUllrem.asm | 163 +++++++++++++++++ CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf | 4 + 5 files changed, 711 insertions(+) create mode 100644 CryptoPkg/Library/IntrinsicLib/Ia32/MathLldiv.asm create mode 100644 CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldiv.asm create mode 100644 CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldvrm.asm create mode 100644 CryptoPkg/Library/IntrinsicLib/Ia32/MathUllrem.asm (limited to 'CryptoPkg/Library') diff --git a/CryptoPkg/Library/IntrinsicLib/Ia32/MathLldiv.asm b/CryptoPkg/Library/IntrinsicLib/Ia32/MathLldiv.asm new file mode 100644 index 0000000000..2fccfd6dc0 --- /dev/null +++ b/CryptoPkg/Library/IntrinsicLib/Ia32/MathLldiv.asm @@ -0,0 +1,203 @@ +;*** +;lldiv.asm - signed long divide routine +; +; Copyright (c) Microsoft Corporation. All rights reserved. +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;Purpose: +; defines the signed long divide routine +; __alldiv +; +;Original Implemenation: MSVC 14.29.30133 +; +;******************************************************************************* + .686 + .model flat,C + .code + + + +;*** +;lldiv - signed long divide +; +;Purpose: +; Does a signed 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: +; +;******************************************************************************* +_alldiv PROC NEAR + +HIWORD EQU [4] ; +LOWORD EQU [0] + + push edi + push esi + push ebx + +; 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 lldiv(a, b)): +; +; ----------------- +; | | +; |---------------| +; | | +; |--divisor (b)--| +; | | +; |---------------| +; | | +; |--dividend (a)-| +; | | +; |---------------| +; | return addr** | +; |---------------| +; | EDI | +; |---------------| +; | ESI | +; |---------------| +; ESP---->| EBX | +; ----------------- +; + +DVND equ [esp + 16] ; stack address of dividend (a) +DVSR equ [esp + 24] ; stack address of divisor (b) + + +; Determine sign of the result (edi = 0 if result is positive, non-zero +; otherwise) and make operands positive. + + xor edi,edi ; result sign assumed positive + + mov eax,HIWORD(DVND) ; hi word of a + or eax,eax ; test to see if signed + jge short L1 ; skip rest if a is already positive + inc edi ; complement result sign flag + mov edx,LOWORD(DVND) ; lo word of a + neg eax ; make a positive + neg edx + sbb eax,0 + mov HIWORD(DVND),eax ; save positive value + mov LOWORD(DVND),edx +L1: + mov eax,HIWORD(DVSR) ; hi word of b + or eax,eax ; test to see if signed + jge short L2 ; skip rest if b is already positive + inc edi ; complement the result sign flag + mov edx,LOWORD(DVSR) ; lo word of a + neg eax ; make b positive + neg edx + sbb eax,0 + mov HIWORD(DVSR),eax ; save positive value + mov LOWORD(DVSR),edx +L2: + +; +; 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. +; +; NOTE - eax currently contains the high order word of DVSR +; + + or eax,eax ; check to see if divisor < 4194304K + jnz short L3 ; 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 ; eax <- 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 ; eax <- low order bits of quotient + mov edx,ebx ; edx:eax <- quotient + jmp short L4 ; set sign, restore stack and return + +; +; Here we do it the hard way. Remember, eax contains the high word of DVSR +; + +L3: + mov ebx,eax ; ebx:ecx <- divisor + mov ecx,LOWORD(DVSR) + mov edx,HIWORD(DVND) ; edx:eax <- dividend + mov eax,LOWORD(DVND) +L5: + shr ebx,1 ; shift divisor right one bit + rcr ecx,1 + shr edx,1 ; shift dividend right one bit + rcr eax,1 + or ebx,ebx + jnz short L5 ; loop until divisor < 4194304K + div ecx ; 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 orignal 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 L6 ; 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 L6 ; if result > original, do subtract + jb short L7 ; if result < original, we are ok + cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words + jbe short L7 ; if less or equal we are ok, else subtract +L6: + dec esi ; subtract 1 from quotient +L7: + xor edx,edx ; edx:eax <- quotient + mov eax,esi + +; +; Just the cleanup left to do. edx:eax contains the quotient. Set the sign +; according to the save value, cleanup the stack, and return. +; + +L4: + dec edi ; check to see if result is negative + jnz short L8 ; if EDI == 0, result should be negative + neg edx ; otherwise, negate the result + neg eax + sbb edx,0 + +; +; Restore the saved registers and return. +; + +L8: + pop ebx + pop esi + pop edi + + ret 16 + +_alldiv ENDP + +end 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 diff --git a/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldvrm.asm b/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldvrm.asm new file mode 100644 index 0000000000..fc3a479e8a --- /dev/null +++ b/CryptoPkg/Library/IntrinsicLib/Ia32/MathUlldvrm.asm @@ -0,0 +1,184 @@ +;*** +;ulldvrm.asm - unsigned long divide and remainder routine +; +; Copyright (c) Microsoft Corporation. All rights reserved. +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;Purpose: +; defines the unsigned long divide and remainder routine +; __aulldvrm +; +;Original Implemenation: MSVC 14.29.30133 +; +;******************************************************************************* + .686 + .model flat,C + .code + + +;*** +;ulldvrm - unsigned long divide and remainder +; +;Purpose: +; Does a unsigned long divide and remainder 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) +; EBX:ECX contains the remainder (divided % divisor) +; NOTE: this routine removes the parameters from the stack. +; +;Uses: +; ECX +; +;Exceptions: +; +;******************************************************************************* +_aulldvrm PROC NEAR + +HIWORD EQU [4] ; +LOWORD EQU [0] + 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 aulldvrm(a, b)): +; +; ----------------- +; | | +; |---------------| +; | | +; |--divisor (b)--| +; | | +; |---------------| +; | | +; |--dividend (a)-| +; | | +; |---------------| +; | return addr** | +; |---------------| +; ESP---->| ESI | +; ----------------- +; + +DVND equ [esp + 8] ; stack address of dividend (a) +DVSR equ [esp + 16] ; 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 esi,eax ; ebx:esi <- quotient + +; +; Now we need to do a multiply so that we can compute the remainder. +; + mov eax,ebx ; set up high word of quotient + mul dword ptr LOWORD(DVSR) ; HIWORD(QUOT) * DVSR + mov ecx,eax ; save the result in ecx + mov eax,esi ; set up low word of quotient + mul dword ptr LOWORD(DVSR) ; LOWORD(QUOT) * DVSR + add edx,ecx ; EDX:EAX = QUOT * DVSR + jmp short L2 ; complete remainder calculation + +; +; 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 + sub eax,LOWORD(DVSR) ; subtract divisor from result + sbb edx,HIWORD(DVSR) +L5: + xor ebx,ebx ; ebx:esi <- quotient + +L2: +; +; Calculate remainder by subtracting the result from the original dividend. +; Since the result is already in a register, we will do the subtract in the +; opposite direction and negate the result. +; + + sub eax,LOWORD(DVND) ; subtract dividend from result + sbb edx,HIWORD(DVND) + neg edx ; otherwise, negate the result + neg eax + sbb edx,0 + +; +; Now we need to get the quotient into edx:eax and the remainder into ebx:ecx. +; + mov ecx,edx + mov edx,ebx + mov ebx,ecx + mov ecx,eax + mov eax,esi +; +; Just the cleanup left to do. edx:eax contains the quotient. +; Restore the saved registers and return. +; + + pop esi + + ret 16 + +_aulldvrm ENDP + + end diff --git a/CryptoPkg/Library/IntrinsicLib/Ia32/MathUllrem.asm b/CryptoPkg/Library/IntrinsicLib/Ia32/MathUllrem.asm new file mode 100644 index 0000000000..755fef24d0 --- /dev/null +++ b/CryptoPkg/Library/IntrinsicLib/Ia32/MathUllrem.asm @@ -0,0 +1,163 @@ +;*** +;ullrem.asm - unsigned long remainder routine +; +; Copyright (c) Microsoft Corporation. All rights reserved. +; SPDX-License-Identifier: BSD-2-Clause-Patent +; +;Purpose: +; defines the unsigned long remainder routine +; __aullrem +; +;Original Implemenation: MSVC 14.29.30133 +; +;******************************************************************************* + .686 + .model flat,C + .code + + +;*** +;ullrem - unsigned long remainder +; +;Purpose: +; Does a unsigned long remainder 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 remainder (dividend%divisor) +; NOTE: this routine removes the parameters from the stack. +; +;Uses: +; ECX +; +;Exceptions: +; +;******************************************************************************* +_aullrem PROC NEAR + +HIWORD EQU [4] ; +LOWORD EQU [0] + + push ebx + +; 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 ullrem(a, b)): +; +; ----------------- +; | | +; |---------------| +; | | +; |--divisor (b)--| +; | | +; |---------------| +; | | +; |--dividend (a)-| +; | | +; |---------------| +; | return addr** | +; |---------------| +; ESP---->| EBX | +; ----------------- +; + +DVND equ [esp + 8] ; stack address of dividend (a) +DVSR equ [esp + 16] ; 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 ; edx <- remainder, eax <- quotient + mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend + div ecx ; edx <- final remainder + mov eax,edx ; edx:eax <- remainder + xor edx,edx + 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 + +; +; We may be off by one, so to check, we will multiply the quotient +; by the divisor and check the result against the orignal 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. +; + + mov ecx,eax ; save a copy of quotient in ECX + mul dword ptr HIWORD(DVSR) + xchg ecx,eax ; put partial product in ECX, get quotient in EAX + mul dword ptr 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're ok, otherwise +; subtract the original divisor from the result. +; + + 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're ok + cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words + jbe short L5 ; if less or equal we're ok, else subtract +L4: + sub eax,LOWORD(DVSR) ; subtract divisor from result + sbb edx,HIWORD(DVSR) +L5: + +; +; Calculate remainder by subtracting the result from the original dividend. +; Since the result is already in a register, we will perform the subtract in +; the opposite direction and negate the result to make it positive. +; + + sub eax,LOWORD(DVND) ; subtract original dividend from result + sbb edx,HIWORD(DVND) + neg edx ; and negate it + neg eax + sbb edx,0 + +; +; Just the cleanup left to do. dx:ax contains the remainder. +; Restore the saved registers and return. +; + +L2: + + pop ebx + + ret 16 + +_aullrem ENDP + + end diff --git a/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf b/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf index 86e74b57b1..2ec987b260 100644 --- a/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf +++ b/CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf @@ -32,6 +32,10 @@ Ia32/MathFtol.c | MSFT Ia32/MathLlmul.asm | MSFT Ia32/MathLlshr.asm | MSFT + Ia32/MathUlldiv.asm | MSFT + Ia32/MathUlldvrm.asm | MSFT + Ia32/MathLldiv.asm | MSFT + Ia32/MathUllrem.asm | MSFT Ia32/MathLShiftS64.c | INTEL Ia32/MathRShiftU64.c | INTEL -- cgit v1.2.3