diff --git a/MdePkg/Include/Library/BaseOverflowLib.h b/MdePkg/Include/Library/BaseOverflowLib.h new file mode 100644 index 0000000000..749b64d5b5 --- /dev/null +++ b/MdePkg/Include/Library/BaseOverflowLib.h @@ -0,0 +1,445 @@ +/** @file + +BaseOverflowLib + +Copyright (c) 2018, vit9696 + +All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __BASE_OVERFLOW_LIB__ +#define __BASE_OVERFLOW_LIB__ + +// +// The macros below provide pointer alignment checking interfaces. +// TypedPtr - pointer of a dedicated type, which alignment is to be checked. +// Align - valid alignment for the target platform (power of two so far). +// Type - valid complete typename. +// Ptr - raw pointer value, must fit into UINTN, meant to be uintptr_t equivalent. +// + +#define BASE_ALIGNOF(Type) (_Alignof (Type)) +#define BASE_POT_ALIGNED(Align, Ptr) (0ULL == (((UINTN) (Ptr)) & (Align-1U))) +#define BASE_TYPE_ALIGNED(Type, Ptr) (BASE_POT_ALIGNED (BASE_ALIGNOF (Type), Ptr)) + +// +// Force member alignment for the structure. +// +#if (defined (__STDC__) && __STDC_VERSION__ >= 201112L) || defined (__GNUC__) || defined (__clang__) +#define BASE_ALIGNAS(Alignment) _Alignas(Alignment) +#else +#define BASE_ALIGNAS(Alignment) +#endif + +/** + Return the result of (Multiplicand * Multiplier / Divisor). + + @param Multiplicand A 64-bit unsigned value. + @param Multiplier A 64-bit unsigned value. + @param Divisor A 32-bit unsigned value. + @param Remainder A pointer to a 32-bit unsigned value. This parameter is + optional and may be NULL. + + @return Multiplicand * Multiplier / Divisor. + **/ +UINT64 +BaseMultThenDivU64x64x32 ( + IN UINT64 Multiplicand, + IN UINT64 Multiplier, + IN UINT32 Divisor, + OUT UINT32 *Remainder OPTIONAL + ); + +// +// The interfaces below provide base safe arithmetics, reporting +// signed integer overflow and unsigned integer wraparound similarly to +// os/overflow.h in macOS SDK. +// +// Each interface may be implemented not only as an actual function, but +// a macro as well. Macro implementations are allowed to evaluate the +// expressions no more than once, and are supposed to provide faster +// compiler builtins if available. +// +// Each interface returns FALSE when the the stored result is equal to +// the infinite precision result, otherwise TRUE. The operands should +// be read left to right with the last argument representing a non-NULL +// pointer to the resulting value of the same type. +// +// More information could be found in Clang Extensions documentation: +// http://releases.llvm.org/7.0.0/tools/clang/docs/LanguageExtensions.html#checked-arithmetic-builtins +// + +// +// 32-bit integer addition, subtraction, multiplication, triple addition (A+B+C), +// triple multiplication (A*B*C), addition with multiplication ((A+B)*C), +// and multiplication with addition (A*B+C) support. +// + +BOOLEAN +BaseOverflowAddU16 ( + UINT16 A, + UINT16 B, + UINT16 *Result + ); + +BOOLEAN +BaseOverflowSubU16 ( + UINT16 A, + UINT16 B, + UINT16 *Result + ); + +BOOLEAN +BaseOverflowMulU16 ( + UINT16 A, + UINT16 B, + UINT16 *Result + ); + +BOOLEAN +BaseOverflowAddU32 ( + UINT32 A, + UINT32 B, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowSubU32 ( + UINT32 A, + UINT32 B, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowMulU32 ( + UINT32 A, + UINT32 B, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowTriAddU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowTriMulU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowAddMulU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowMulAddU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowAlignUpU32 ( + UINT32 Value, + UINT32 Alignment, + UINT32 *Result + ); + +BOOLEAN +BaseOverflowAddS32 ( + INT32 A, + INT32 B, + INT32 *Result + ); + +BOOLEAN +BaseOverflowSubS32 ( + INT32 A, + INT32 B, + INT32 *Result + ); + +BOOLEAN +BaseOverflowMulS32 ( + INT32 A, + INT32 B, + INT32 *Result + ); + +BOOLEAN +BaseOverflowTriAddS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ); + +BOOLEAN +BaseOverflowTriMulS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ); + +BOOLEAN +BaseOverflowAddMulS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ); + +BOOLEAN +BaseOverflowMulAddS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ); + +// +// 64-bit integer addition, subtraction, multiplication, triple addition (A+B+C), +// triple multiplication (A*B*C), addition with multiplication ((A+B)*C), +// and multiplication with addition (A*B+C) support. +// + +BOOLEAN +BaseOverflowAddU64 ( + UINT64 A, + UINT64 B, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowSubU64 ( + UINT64 A, + UINT64 B, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowMulU64 ( + UINT64 A, + UINT64 B, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowTriAddU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowTriMulU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowAddMulU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowMulAddU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ); + +BOOLEAN +BaseOverflowAddS64 ( + INT64 A, + INT64 B, + INT64 *Result + ); + +BOOLEAN +BaseOverflowSubS64 ( + INT64 A, + INT64 B, + INT64 *Result + ); + +BOOLEAN +BaseOverflowMulS64 ( + INT64 A, + INT64 B, + INT64 *Result + ); + +BOOLEAN +BaseOverflowTriAddS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ); + +BOOLEAN +BaseOverflowTriMulS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ); + +BOOLEAN +BaseOverflowAddMulS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ); + +BOOLEAN +BaseOverflowMulAddS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ); + +// +// Native integer addition, subtraction, multiplication, triple addition (A+B+C), +// triple multiplication (A*B*C), addition with multiplication ((A+B)*C), +// and multiplication with addition (A*B+C) support. +// + +BOOLEAN +BaseOverflowAddUN ( + UINTN A, + UINTN B, + UINTN *Result + ); + +BOOLEAN +BaseOverflowSubUN ( + UINTN A, + UINTN B, + UINTN *Result + ); + +BOOLEAN +BaseOverflowMulUN ( + UINTN A, + UINTN B, + UINTN *Result + ); + +BOOLEAN +BaseOverflowTriAddUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ); + +BOOLEAN +BaseOverflowTriMulUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ); + +BOOLEAN +BaseOverflowAddMulUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ); + +BOOLEAN +BaseOverflowMulAddUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ); + +BOOLEAN +BaseOverflowAddSN ( + INTN A, + INTN B, + INTN *Result + ); + +BOOLEAN +BaseOverflowSubSN ( + INTN A, + INTN B, + INTN *Result + ); + +BOOLEAN +BaseOverflowMulSN ( + INTN A, + INTN B, + INTN *Result + ); + +BOOLEAN +BaseOverflowTriAddSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ); + +BOOLEAN +BaseOverflowTriMulSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ); + +BOOLEAN +BaseOverflowAddMulSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ); + +BOOLEAN +BaseOverflowMulAddSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ); + +#endif // __BASE_OVERFLOW_LIB__ diff --git a/MdePkg/Library/BaseOverflowLib/BaseAlignment.c b/MdePkg/Library/BaseOverflowLib/BaseAlignment.c new file mode 100644 index 0000000000..141f124f61 --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseAlignment.c @@ -0,0 +1,36 @@ +/** @file + +BaseOverflowLib + +Copyright (c) 2020, Download-Fritz + +All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ +#include + +#include +#include + +BOOLEAN +BaseOverflowAlignUpU32 ( + UINT32 Value, + UINT32 Alignment, + UINT32 *Result + ) +{ + BOOLEAN Status; + + Status = BaseOverflowAddU32 (Value, Alignment - 1U, Result); + *Result &= ~(Alignment - 1U); + + return Status; +} diff --git a/MdePkg/Library/BaseOverflowLib/BaseBitOverflow.c b/MdePkg/Library/BaseOverflowLib/BaseBitOverflow.c new file mode 100644 index 0000000000..1ea658cd93 --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseBitOverflow.c @@ -0,0 +1,442 @@ +/** @file + +BaseOverflowLib + +Copyright (c) 2018, vit9696 + +All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include + +#include "BaseOverflowInternals.h" + +// +// Software implementations provided try not to be obviously slow, but primarily +// target C99 compliance rather than performance. +// + +BOOLEAN +BaseOverflowAddU16 ( + UINT16 A, + UINT16 B, + UINT16 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #else + UINT32 Temp; + + // + // I believe casting will be faster on X86 at least. + // + Temp = A + B; + *Result = (UINT16)Temp; + if (Temp <= MAX_UINT16) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowSubU16 ( + UINT16 A, + UINT16 B, + UINT16 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #else + *Result = (UINT16)(A - B); + + if (A >= B) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowMulU16 ( + UINT16 A, + UINT16 B, + UINT16 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_mul_overflow (A, B, Result); + #else + UINT32 Temp; + + Temp = (UINT32)A * B; + *Result = (UINT16)Temp; + if (Temp <= MAX_UINT32) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowAddU32 ( + UINT32 A, + UINT32 B, + UINT32 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_uadd_overflow (A, B, Result); + #else + UINT32 Temp; + + // + // I believe casting will be faster on X86 at least. + // + Temp = A + B; + *Result = Temp; + if (Temp >= A) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowSubU32 ( + UINT32 A, + UINT32 B, + UINT32 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_usub_overflow (A, B, Result); + #else + *Result = A - B; + if (B <= A) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowMulU32 ( + UINT32 A, + UINT32 B, + UINT32 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_mul_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_umul_overflow (A, B, Result); + #else + UINT64 Temp; + + Temp = (UINT64)A * B; + *Result = (UINT32)Temp; + if (Temp <= MAX_UINT32) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowAddS32 ( + INT32 A, + INT32 B, + INT32 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_sadd_overflow (A, B, Result); + #else + INT64 Temp; + + Temp = (INT64)A + B; + *Result = (INT32)Temp; + if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowSubS32 ( + INT32 A, + INT32 B, + INT32 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_ssub_overflow (A, B, Result); + #else + INT64 Temp; + + Temp = (INT64)A - B; + *Result = (INT32)Temp; + if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowMulS32 ( + INT32 A, + INT32 B, + INT32 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_mul_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_smul_overflow (A, B, Result); + #else + INT64 Temp; + + Temp = MultS64x64 (A, B); + *Result = (INT32)Temp; + if ((Temp >= MIN_INT32) && (Temp <= MAX_INT32)) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowAddU64 ( + UINT64 A, + UINT64 B, + UINT64 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_uaddll_overflow (A, B, Result); + #else + UINT64 Temp; + + Temp = A + B; + *Result = Temp; + if (Temp >= A) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowSubU64 ( + UINT64 A, + UINT64 B, + UINT64 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_usubll_overflow (A, B, Result); + #else + *Result = A - B; + if (B <= A) { + return FALSE; + } + + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowMulU64 ( + UINT64 A, + UINT64 B, + UINT64 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_mul_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_umulll_overflow (A, B, Result); + #else + UINT64 AHi; + UINT64 ALo; + UINT64 BHi; + UINT64 BLo; + UINT64 LoBits; + UINT64 HiBits1; + UINT64 HiBits2; + BOOLEAN Overflow; + + // + // Based on the 2nd option written by Charphacy, believed to be the fastest portable on x86. + // See: https://stackoverflow.com/a/26320664 + // Implements overflow checking by a series of up to 3 multiplications. + // + + AHi = RShiftU64 (A, 32); + ALo = A & MAX_UINT32; + BHi = RShiftU64 (B, 32); + BLo = B & MAX_UINT32; + + LoBits = MultU64x64 (ALo, BLo); + if ((AHi == 0) && (BHi == 0)) { + *Result = LoBits; + return FALSE; + } + + Overflow = AHi > 0 && BHi > 0; + HiBits1 = MultU64x64 (ALo, BHi); + HiBits2 = MultU64x64 (AHi, BLo); + + *Result = LoBits + LShiftU64 (HiBits1 + HiBits2, 32); + return Overflow || *Result < LoBits || RShiftU64 (HiBits1, 32) != 0 || RShiftU64 (HiBits2, 32) != 0; + #endif +} + +BOOLEAN +BaseOverflowAddS64 ( + INT64 A, + INT64 B, + INT64 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_saddll_overflow (A, B, Result); + #else + if (((B <= 0) || (A <= MAX_INT64 - B)) && ((B >= 0) || (A >= MIN_INT64 - B))) { + *Result = A + B; + return FALSE; + } + + // + // Assign some defined value to *Result. + // + *Result = 0; + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowSubS64 ( + INT64 A, + INT64 B, + INT64 *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) + return __builtin_ssubll_overflow (A, B, Result); + #else + if (((B >= 0) || (A <= MAX_INT64 + B)) && ((B <= 0) || (A >= MIN_INT64 + B))) { + *Result = A - B; + return FALSE; + } + + // + // Assign some defined value to *Result. + // + *Result = 0; + return TRUE; + #endif +} + +BOOLEAN +BaseOverflowMulS64 ( + INT64 A, + INT64 B, + INT64 *Result + ) +{ + // + // Intel 32-bit architectures do not have hardware signed 64-bit + // multiplication with overflow. + // + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) && !defined (MDE_CPU_IA32) + return __builtin_mul_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS) && !defined (MDE_CPU_IA32) + return __builtin_smulll_overflow (A, B, Result); + #else + UINT64 AU; + UINT64 BU; + UINT64 ResultU; + + // + // It hurts to implement it without unsigned multiplication, maybe rewrite it one day. + // The idea taken from BaseSafeIntLib. + // + + #define OC_ABS_64(X) (((X) < 0) ? (((UINT64) (-((X) + 1))) + 1) : (UINT64) (X)) + + AU = OC_ABS_64 (A); + BU = OC_ABS_64 (B); + + if (BaseOverflowMulU64 (AU, BU, &ResultU)) { + *Result = 0; + return TRUE; + } + + // + // Split into positive and negative results and check just one range. + // + if ((A < 0) == (B < 0)) { + if (ResultU <= MAX_INT64) { + *Result = (INT64)ResultU; + return FALSE; + } + } else { + if (ResultU < OC_ABS_64 (MIN_INT64)) { + *Result = -((INT64)ResultU); + return FALSE; + } else if (ResultU == OC_ABS_64 (MIN_INT64)) { + *Result = MIN_INT64; + return FALSE; + } + } + + #undef OC_ABS_64 + + *Result = 0; + return TRUE; + #endif +} diff --git a/MdePkg/Library/BaseOverflowLib/BaseMath.c b/MdePkg/Library/BaseOverflowLib/BaseMath.c new file mode 100644 index 0000000000..9547c08935 --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseMath.c @@ -0,0 +1,64 @@ +/** @file + Copyright (C) 2019, vit9696. All rights reserved. + + All rights reserved. + + This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + **/ + +#include + +#include + +/** + BaseMultThenDivU64x64x32 is from MdeModulePkg's PciRootBridgeIo.c + + Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause-Patent + **/ +UINT64 +BaseMultThenDivU64x64x32 ( + IN UINT64 Multiplicand, + IN UINT64 Multiplier, + IN UINT32 Divisor, + OUT UINT32 *Remainder OPTIONAL + ) +{ + UINT64 Uint64; + UINT32 LocalRemainder; + UINT32 Uint32; + + if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) { + // + // Make sure Multiplicand is the bigger one. + // + if (Multiplicand < Multiplier) { + Uint64 = Multiplicand; + Multiplicand = Multiplier; + Multiplier = Uint64; + } + + // + // Because Multiplicand * Multiplier overflows, + // Multiplicand * Multiplier / Divisor + // = (2 * Multiplicand' + 1) * Multiplier / Divisor + // = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor + // + Uint64 = BaseMultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder); + Uint64 = LShiftU64 (Uint64, 1); + Uint32 = 0; + if ((Multiplicand & 0x1) == 1) { + Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32); + } + + return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder); + } else { + return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder); + } +} diff --git a/MdePkg/Library/BaseOverflowLib/BaseNativeOverflow.c b/MdePkg/Library/BaseOverflowLib/BaseNativeOverflow.c new file mode 100644 index 0000000000..204b552beb --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseNativeOverflow.c @@ -0,0 +1,156 @@ +/** @file + +BaseOverflowLib + +Copyright (c) 2018, vit9696 + +All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include +#include + +#include "BaseOverflowInternals.h" + +BOOLEAN +BaseOverflowAddUN ( + UINTN A, + UINTN B, + UINTN *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_uaddll_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32) + return __builtin_uadd_overflow (A, B, Result); + #else + if (sizeof (UINTN) == sizeof (UINT64)) { + return BaseOverflowAddU64 (A, B, (UINT64 *)Result); + } + + return BaseOverflowAddU32 ((UINT32)A, (UINT32)B, (UINT32 *)Result); + #endif +} + +BOOLEAN +BaseOverflowSubUN ( + UINTN A, + UINTN B, + UINTN *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_usubll_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32) + return __builtin_usub_overflow (A, B, Result); + #else + if (sizeof (UINTN) == sizeof (UINT64)) { + return BaseOverflowSubU64 (A, B, (UINT64 *)Result); + } + + return BaseOverflowSubU32 ((UINT32)A, (UINT32)B, (UINT32 *)Result); + #endif +} + +BOOLEAN +BaseOverflowMulUN ( + UINTN A, + UINTN B, + UINTN *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_mul_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_umulll_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32) + return __builtin_umul_overflow (A, B, Result); + #else + if (sizeof (UINTN) == sizeof (UINT64)) { + return BaseOverflowMulU64 (A, B, (UINT64 *)Result); + } + + return BaseOverflowMulU32 ((UINT32)A, (UINT32)B, (UINT32 *)Result); + #endif +} + +BOOLEAN +BaseOverflowAddSN ( + INTN A, + INTN B, + INTN *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_add_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_saddll_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32) + return __builtin_sadd_overflow (A, B, Result); + #else + if (sizeof (INTN) == sizeof (INT64)) { + return BaseOverflowAddS64 (A, B, (INT64 *)Result); + } + + return BaseOverflowAddS32 ((INT32)A, (INT32)B, (INT32 *)Result); + #endif +} + +BOOLEAN +BaseOverflowSubSN ( + INTN A, + INTN B, + INTN *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_sub_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_ssubll_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32) + return __builtin_ssub_overflow (A, B, Result); + #else + if (sizeof (INTN) == sizeof (INT64)) { + return BaseOverflowSubS64 (A, B, (INT64 *)Result); + } + + return BaseOverflowSubS32 ((INT32)A, (INT32)B, (INT32 *)Result); + #endif +} + +BOOLEAN +BaseOverflowMulSN ( + INTN A, + INTN B, + INTN *Result + ) +{ + #if defined (BASE_HAS_TYPE_GENERIC_BUILTINS) + return __builtin_mul_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_64) + return __builtin_smulll_overflow (A, B, Result); + #elif defined (BASE_HAS_TYPE_SPECIFIC_BUILTINS_32) + return __builtin_smul_overflow (A, B, Result); + #else + if (sizeof (INTN) == sizeof (INT64)) { + return BaseOverflowMulS64 (A, B, (INT64 *)Result); + } + + return BaseOverflowMulS32 ((INT32)A, (INT32)B, (INT32 *)Result); + #endif +} diff --git a/MdePkg/Library/BaseOverflowLib/BaseOverflowInternals.h b/MdePkg/Library/BaseOverflowLib/BaseOverflowInternals.h new file mode 100644 index 0000000000..e4377a6e59 --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseOverflowInternals.h @@ -0,0 +1,50 @@ +/** @file + This header provides internal BaseOverflowLib definitions. + + Copyright (c) 2020, vit9696. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef __OVERFLOW_INTERNALS__ +#define __OVERFLOW_INTERNALS__ + +#if defined (__has_builtin) + #if __has_builtin (__builtin_add_overflow) && __has_builtin (__builtin_sub_overflow) && __has_builtin (__builtin_mul_overflow) +#define BASE_HAS_TYPE_GENERIC_BUILTINS 1 + #endif +#endif + +#if defined (__GNUC__) || defined (__clang__) + #if defined (MDE_CPU_AARCH64) || defined (MDE_CPU_X64) +STATIC_ASSERT (sizeof (INTN) == 8, "INTN is expected to be 8 bytes"); +STATIC_ASSERT (sizeof (UINTN) == 8, "UINTN is expected to be 8 bytes"); +#define BASE_HAS_TYPE_SPECIFIC_BUILTINS_64 1 + #elif defined (MDE_CPU_ARM) || defined (MDE_CPU_IA32) +STATIC_ASSERT (sizeof (INTN) == 4, "INTN is expected to be 4 bytes"); +STATIC_ASSERT (sizeof (UINTN) == 4, "UINTN is expected to be 4 bytes"); +#define BASE_HAS_TYPE_SPECIFIC_BUILTINS_32 1 + #endif + +STATIC_ASSERT (sizeof (int) == 4, "int is expected to be 4 bytes"); +STATIC_ASSERT (sizeof (unsigned) == 4, "unsigned is expected to be 4 bytes"); +STATIC_ASSERT (sizeof (long long) == 8, "long long is expected to be 8 bytes"); +STATIC_ASSERT (sizeof (unsigned long long) == 8, "unsigned long long is expected to be 8 bytes"); +#define BASE_HAS_TYPE_SPECIFIC_BUILTINS 1 +#endif + +// +// Currently no architectures provide UINTN and INTN different from 32-bit or 64-bit +// integers. For this reason they are the only variants supported and are enforced here. +// + +STATIC_ASSERT ( + sizeof (INTN) == sizeof (INT64) || sizeof (INTN) == sizeof (INT32), + "INTN must be 32 or 64 Bits wide." + ); + +STATIC_ASSERT ( + sizeof (UINTN) == sizeof (UINT64) || sizeof (UINTN) == sizeof (UINT32), + "UINTN must be 32 or 64 Bits wide." + ); + +#endif // __OVERFLOW_INTERNALS__ diff --git a/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf b/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf new file mode 100644 index 0000000000..a14bd80e56 --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf @@ -0,0 +1,48 @@ +## @file +# BaseOverflowLib +# +# Copyright (c) 2018, vit9696 +# +# All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = BaseOverflowLib + FILE_GUID = 57D4B14C-CC2C-4779-8A80-0BA5AAC1B8F3 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = BaseOverflowLib + + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources] + BaseAlignment.c + BaseBitOverflow.c + BaseOverflowInternals.h + BaseMath.c + BaseNativeOverflow.c + BaseTripleOverflow.c + +[Packages] + MdePkg/MdePkg.dec + +[LibraryClasses] + BaseLib + +[BuildOptions] + XCODE:DEBUG_*_*_CC_FLAGS = -fno-stack-protector + XCODE:NOOPT_*_*_CC_FLAGS = -fno-stack-protector + XCODE:RELEASE_*_*_CC_FLAGS = -fno-stack-protector diff --git a/MdePkg/Library/BaseOverflowLib/BaseTripleOverflow.c b/MdePkg/Library/BaseOverflowLib/BaseTripleOverflow.c new file mode 100644 index 0000000000..ebcadc9ed4 --- /dev/null +++ b/MdePkg/Library/BaseOverflowLib/BaseTripleOverflow.c @@ -0,0 +1,429 @@ +/** @file + +BaseOverflowLib + +Copyright (c) 2018, vit9696 + +All rights reserved. + +This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include + +#include + +BOOLEAN +BaseOverflowTriAddU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ) +{ + UINT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddU32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddU32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriMulU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ) +{ + UINT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulU32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulU32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowAddMulU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ) +{ + UINT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddU32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulU32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowMulAddU32 ( + UINT32 A, + UINT32 B, + UINT32 C, + UINT32 *Result + ) +{ + UINT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulU32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddU32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriAddS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ) +{ + INT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddS32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddS32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriMulS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ) +{ + INT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulS32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulS32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowAddMulS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ) +{ + INT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddS32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulS32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowMulAddS32 ( + INT32 A, + INT32 B, + INT32 C, + INT32 *Result + ) +{ + INT32 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulS32 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddS32 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriAddU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ) +{ + UINT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddU64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddU64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriMulU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ) +{ + UINT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulU64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulU64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowAddMulU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ) +{ + UINT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddU64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulU64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowMulAddU64 ( + UINT64 A, + UINT64 B, + UINT64 C, + UINT64 *Result + ) +{ + UINT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulU64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddU64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriAddS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ) +{ + INT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddS64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddS64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriMulS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ) +{ + INT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulS64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulS64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowAddMulS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ) +{ + INT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddS64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulS64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowMulAddS64 ( + INT64 A, + INT64 B, + INT64 C, + INT64 *Result + ) +{ + INT64 BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulS64 (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddS64 (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriAddUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ) +{ + UINTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddUN (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddUN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriMulUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ) +{ + UINTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulUN (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulUN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowAddMulUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ) +{ + UINTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddUN (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulUN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowMulAddUN ( + UINTN A, + UINTN B, + UINTN C, + UINTN *Result + ) +{ + UINTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulUN (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddUN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriAddSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ) +{ + INTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddSN (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddSN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowTriMulSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ) +{ + INTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulSN (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulSN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowAddMulSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ) +{ + INTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowAddSN (A, B, &BaseTmp); + BaseSecond = BaseOverflowMulSN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} + +BOOLEAN +BaseOverflowMulAddSN ( + INTN A, + INTN B, + INTN C, + INTN *Result + ) +{ + INTN BaseTmp; + BOOLEAN BaseFirst; + BOOLEAN BaseSecond; + + BaseFirst = BaseOverflowMulSN (A, B, &BaseTmp); + BaseSecond = BaseOverflowAddSN (BaseTmp, C, Result); + return BaseFirst | BaseSecond; +} diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec index 5fc3bbfc70..3a45a7e9d5 100644 --- a/MdePkg/MdePkg.dec +++ b/MdePkg/MdePkg.dec @@ -341,6 +341,11 @@ ## @libraryclass Provides function to support TDX processing. TdxLib|Include/Library/TdxLib.h + ## @libraryclass Provides base safe arithmetics, reporting signed integer overflow + # and unsigned integer wraparound similarly to os/overflow.h in macOS SDK. + ## + BaseOverflowLib|Include/Library/BaseOverflowLib.h + [LibraryClasses.RISCV64] ## @libraryclass Provides function to make ecalls to SBI BaseRiscVSbiLib|Include/Library/BaseRiscVSbiLib.h diff --git a/MdePkg/MdePkg.dsc b/MdePkg/MdePkg.dsc index e97c664ebe..48dc40d4e1 100644 --- a/MdePkg/MdePkg.dsc +++ b/MdePkg/MdePkg.dsc @@ -186,6 +186,7 @@ MdePkg/Library/TdxLib/TdxLib.inf MdePkg/Library/MipiSysTLib/MipiSysTLib.inf MdePkg/Library/TraceHubDebugSysTLibNull/TraceHubDebugSysTLibNull.inf + MdePkg/Library/BaseOverflowLib/BaseOverflowLib.inf [Components.EBC] MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf