1ae115bc7Smrj /******************************************************************************* 2ae115bc7Smrj * 3ae115bc7Smrj * Module Name: utmath - Integer math support routines 4ae115bc7Smrj * 5ae115bc7Smrj ******************************************************************************/ 6ae115bc7Smrj 726f3cdf0SGordon Ross /* 8*385cc6b4SJerry Jelinek * Copyright (C) 2000 - 2016, Intel Corp. 9ae115bc7Smrj * All rights reserved. 10ae115bc7Smrj * 1126f3cdf0SGordon Ross * Redistribution and use in source and binary forms, with or without 1226f3cdf0SGordon Ross * modification, are permitted provided that the following conditions 1326f3cdf0SGordon Ross * are met: 1426f3cdf0SGordon Ross * 1. Redistributions of source code must retain the above copyright 1526f3cdf0SGordon Ross * notice, this list of conditions, and the following disclaimer, 1626f3cdf0SGordon Ross * without modification. 1726f3cdf0SGordon Ross * 2. Redistributions in binary form must reproduce at minimum a disclaimer 1826f3cdf0SGordon Ross * substantially similar to the "NO WARRANTY" disclaimer below 1926f3cdf0SGordon Ross * ("Disclaimer") and any redistribution must be conditioned upon 2026f3cdf0SGordon Ross * including a substantially similar Disclaimer requirement for further 2126f3cdf0SGordon Ross * binary redistribution. 2226f3cdf0SGordon Ross * 3. Neither the names of the above-listed copyright holders nor the names 2326f3cdf0SGordon Ross * of any contributors may be used to endorse or promote products derived 2426f3cdf0SGordon Ross * from this software without specific prior written permission. 25ae115bc7Smrj * 2626f3cdf0SGordon Ross * Alternatively, this software may be distributed under the terms of the 2726f3cdf0SGordon Ross * GNU General Public License ("GPL") version 2 as published by the Free 2826f3cdf0SGordon Ross * Software Foundation. 29ae115bc7Smrj * 3026f3cdf0SGordon Ross * NO WARRANTY 3126f3cdf0SGordon Ross * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 3226f3cdf0SGordon Ross * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3326f3cdf0SGordon Ross * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 3426f3cdf0SGordon Ross * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3526f3cdf0SGordon Ross * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3626f3cdf0SGordon Ross * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3726f3cdf0SGordon Ross * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3826f3cdf0SGordon Ross * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 3926f3cdf0SGordon Ross * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 4026f3cdf0SGordon Ross * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 4126f3cdf0SGordon Ross * POSSIBILITY OF SUCH DAMAGES. 4226f3cdf0SGordon Ross */ 43ae115bc7Smrj 44ae115bc7Smrj #include "acpi.h" 45aa2aa9a6SDana Myers #include "accommon.h" 46ae115bc7Smrj 47ae115bc7Smrj 48ae115bc7Smrj #define _COMPONENT ACPI_UTILITIES 49ae115bc7Smrj ACPI_MODULE_NAME ("utmath") 50ae115bc7Smrj 51ae115bc7Smrj /* 5226f3cdf0SGordon Ross * Optional support for 64-bit double-precision integer divide. This code 5326f3cdf0SGordon Ross * is configurable and is implemented in order to support 32-bit kernel 5426f3cdf0SGordon Ross * environments where a 64-bit double-precision math library is not available. 5526f3cdf0SGordon Ross * 5626f3cdf0SGordon Ross * Support for a more normal 64-bit divide/modulo (with check for a divide- 5726f3cdf0SGordon Ross * by-zero) appears after this optional section of code. 58ae115bc7Smrj */ 59ae115bc7Smrj #ifndef ACPI_USE_NATIVE_DIVIDE 6026f3cdf0SGordon Ross 6126f3cdf0SGordon Ross /* Structures used only for 64-bit divide */ 6226f3cdf0SGordon Ross 6326f3cdf0SGordon Ross typedef struct uint64_struct 6426f3cdf0SGordon Ross { 6526f3cdf0SGordon Ross UINT32 Lo; 6626f3cdf0SGordon Ross UINT32 Hi; 6726f3cdf0SGordon Ross 6826f3cdf0SGordon Ross } UINT64_STRUCT; 6926f3cdf0SGordon Ross 7026f3cdf0SGordon Ross typedef union uint64_overlay 7126f3cdf0SGordon Ross { 7226f3cdf0SGordon Ross UINT64 Full; 7326f3cdf0SGordon Ross UINT64_STRUCT Part; 7426f3cdf0SGordon Ross 7526f3cdf0SGordon Ross } UINT64_OVERLAY; 7626f3cdf0SGordon Ross 7726f3cdf0SGordon Ross 78ae115bc7Smrj /******************************************************************************* 79ae115bc7Smrj * 80ae115bc7Smrj * FUNCTION: AcpiUtShortDivide 81ae115bc7Smrj * 82ae115bc7Smrj * PARAMETERS: Dividend - 64-bit dividend 83ae115bc7Smrj * Divisor - 32-bit divisor 84ae115bc7Smrj * OutQuotient - Pointer to where the quotient is returned 85ae115bc7Smrj * OutRemainder - Pointer to where the remainder is returned 86ae115bc7Smrj * 87ae115bc7Smrj * RETURN: Status (Checks for divide-by-zero) 88ae115bc7Smrj * 89ae115bc7Smrj * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits) 90ae115bc7Smrj * divide and modulo. The result is a 64-bit quotient and a 91ae115bc7Smrj * 32-bit remainder. 92ae115bc7Smrj * 93ae115bc7Smrj ******************************************************************************/ 94ae115bc7Smrj 95ae115bc7Smrj ACPI_STATUS 96ae115bc7Smrj AcpiUtShortDivide ( 9726f3cdf0SGordon Ross UINT64 Dividend, 98ae115bc7Smrj UINT32 Divisor, 9926f3cdf0SGordon Ross UINT64 *OutQuotient, 100ae115bc7Smrj UINT32 *OutRemainder) 101ae115bc7Smrj { 102ae115bc7Smrj UINT64_OVERLAY DividendOvl; 103ae115bc7Smrj UINT64_OVERLAY Quotient; 104ae115bc7Smrj UINT32 Remainder32; 105ae115bc7Smrj 106ae115bc7Smrj 107ae115bc7Smrj ACPI_FUNCTION_TRACE (UtShortDivide); 108ae115bc7Smrj 109ae115bc7Smrj 110ae115bc7Smrj /* Always check for a zero divisor */ 111ae115bc7Smrj 112ae115bc7Smrj if (Divisor == 0) 113ae115bc7Smrj { 114ae115bc7Smrj ACPI_ERROR ((AE_INFO, "Divide by zero")); 115ae115bc7Smrj return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); 116ae115bc7Smrj } 117ae115bc7Smrj 118ae115bc7Smrj DividendOvl.Full = Dividend; 119ae115bc7Smrj 120ae115bc7Smrj /* 121ae115bc7Smrj * The quotient is 64 bits, the remainder is always 32 bits, 122ae115bc7Smrj * and is generated by the second divide. 123ae115bc7Smrj */ 124ae115bc7Smrj ACPI_DIV_64_BY_32 (0, DividendOvl.Part.Hi, Divisor, 125ae115bc7Smrj Quotient.Part.Hi, Remainder32); 126*385cc6b4SJerry Jelinek 127ae115bc7Smrj ACPI_DIV_64_BY_32 (Remainder32, DividendOvl.Part.Lo, Divisor, 128ae115bc7Smrj Quotient.Part.Lo, Remainder32); 129ae115bc7Smrj 130ae115bc7Smrj /* Return only what was requested */ 131ae115bc7Smrj 132ae115bc7Smrj if (OutQuotient) 133ae115bc7Smrj { 134ae115bc7Smrj *OutQuotient = Quotient.Full; 135ae115bc7Smrj } 136ae115bc7Smrj if (OutRemainder) 137ae115bc7Smrj { 138ae115bc7Smrj *OutRemainder = Remainder32; 139ae115bc7Smrj } 140ae115bc7Smrj 141ae115bc7Smrj return_ACPI_STATUS (AE_OK); 142ae115bc7Smrj } 143ae115bc7Smrj 144ae115bc7Smrj 145ae115bc7Smrj /******************************************************************************* 146ae115bc7Smrj * 147ae115bc7Smrj * FUNCTION: AcpiUtDivide 148ae115bc7Smrj * 149ae115bc7Smrj * PARAMETERS: InDividend - Dividend 150ae115bc7Smrj * InDivisor - Divisor 151ae115bc7Smrj * OutQuotient - Pointer to where the quotient is returned 152ae115bc7Smrj * OutRemainder - Pointer to where the remainder is returned 153ae115bc7Smrj * 154ae115bc7Smrj * RETURN: Status (Checks for divide-by-zero) 155ae115bc7Smrj * 156ae115bc7Smrj * DESCRIPTION: Perform a divide and modulo. 157ae115bc7Smrj * 158ae115bc7Smrj ******************************************************************************/ 159ae115bc7Smrj 160ae115bc7Smrj ACPI_STATUS 161ae115bc7Smrj AcpiUtDivide ( 16226f3cdf0SGordon Ross UINT64 InDividend, 16326f3cdf0SGordon Ross UINT64 InDivisor, 16426f3cdf0SGordon Ross UINT64 *OutQuotient, 16526f3cdf0SGordon Ross UINT64 *OutRemainder) 166ae115bc7Smrj { 167ae115bc7Smrj UINT64_OVERLAY Dividend; 168ae115bc7Smrj UINT64_OVERLAY Divisor; 169ae115bc7Smrj UINT64_OVERLAY Quotient; 170ae115bc7Smrj UINT64_OVERLAY Remainder; 171ae115bc7Smrj UINT64_OVERLAY NormalizedDividend; 172ae115bc7Smrj UINT64_OVERLAY NormalizedDivisor; 173ae115bc7Smrj UINT32 Partial1; 174ae115bc7Smrj UINT64_OVERLAY Partial2; 175ae115bc7Smrj UINT64_OVERLAY Partial3; 176ae115bc7Smrj 177ae115bc7Smrj 178ae115bc7Smrj ACPI_FUNCTION_TRACE (UtDivide); 179ae115bc7Smrj 180ae115bc7Smrj 181ae115bc7Smrj /* Always check for a zero divisor */ 182ae115bc7Smrj 183ae115bc7Smrj if (InDivisor == 0) 184ae115bc7Smrj { 185ae115bc7Smrj ACPI_ERROR ((AE_INFO, "Divide by zero")); 186ae115bc7Smrj return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); 187ae115bc7Smrj } 188ae115bc7Smrj 189ae115bc7Smrj Divisor.Full = InDivisor; 190ae115bc7Smrj Dividend.Full = InDividend; 191ae115bc7Smrj if (Divisor.Part.Hi == 0) 192ae115bc7Smrj { 193ae115bc7Smrj /* 194ae115bc7Smrj * 1) Simplest case is where the divisor is 32 bits, we can 195ae115bc7Smrj * just do two divides 196ae115bc7Smrj */ 197ae115bc7Smrj Remainder.Part.Hi = 0; 198ae115bc7Smrj 199ae115bc7Smrj /* 200ae115bc7Smrj * The quotient is 64 bits, the remainder is always 32 bits, 201ae115bc7Smrj * and is generated by the second divide. 202ae115bc7Smrj */ 203ae115bc7Smrj ACPI_DIV_64_BY_32 (0, Dividend.Part.Hi, Divisor.Part.Lo, 204ae115bc7Smrj Quotient.Part.Hi, Partial1); 205*385cc6b4SJerry Jelinek 206ae115bc7Smrj ACPI_DIV_64_BY_32 (Partial1, Dividend.Part.Lo, Divisor.Part.Lo, 207ae115bc7Smrj Quotient.Part.Lo, Remainder.Part.Lo); 208ae115bc7Smrj } 209ae115bc7Smrj 210ae115bc7Smrj else 211ae115bc7Smrj { 212ae115bc7Smrj /* 213ae115bc7Smrj * 2) The general case where the divisor is a full 64 bits 214ae115bc7Smrj * is more difficult 215ae115bc7Smrj */ 216ae115bc7Smrj Quotient.Part.Hi = 0; 217ae115bc7Smrj NormalizedDividend = Dividend; 218ae115bc7Smrj NormalizedDivisor = Divisor; 219ae115bc7Smrj 220ae115bc7Smrj /* Normalize the operands (shift until the divisor is < 32 bits) */ 221ae115bc7Smrj 222ae115bc7Smrj do 223ae115bc7Smrj { 224*385cc6b4SJerry Jelinek ACPI_SHIFT_RIGHT_64 ( 225*385cc6b4SJerry Jelinek NormalizedDivisor.Part.Hi, NormalizedDivisor.Part.Lo); 226*385cc6b4SJerry Jelinek ACPI_SHIFT_RIGHT_64 ( 227*385cc6b4SJerry Jelinek NormalizedDividend.Part.Hi, NormalizedDividend.Part.Lo); 228ae115bc7Smrj 229ae115bc7Smrj } while (NormalizedDivisor.Part.Hi != 0); 230ae115bc7Smrj 231ae115bc7Smrj /* Partial divide */ 232ae115bc7Smrj 233*385cc6b4SJerry Jelinek ACPI_DIV_64_BY_32 ( 234*385cc6b4SJerry Jelinek NormalizedDividend.Part.Hi, NormalizedDividend.Part.Lo, 235*385cc6b4SJerry Jelinek NormalizedDivisor.Part.Lo, Quotient.Part.Lo, Partial1); 236ae115bc7Smrj 237ae115bc7Smrj /* 238*385cc6b4SJerry Jelinek * The quotient is always 32 bits, and simply requires 239*385cc6b4SJerry Jelinek * adjustment. The 64-bit remainder must be generated. 240ae115bc7Smrj */ 241ae115bc7Smrj Partial1 = Quotient.Part.Lo * Divisor.Part.Hi; 24226f3cdf0SGordon Ross Partial2.Full = (UINT64) Quotient.Part.Lo * Divisor.Part.Lo; 24326f3cdf0SGordon Ross Partial3.Full = (UINT64) Partial2.Part.Hi + Partial1; 244ae115bc7Smrj 245ae115bc7Smrj Remainder.Part.Hi = Partial3.Part.Lo; 246ae115bc7Smrj Remainder.Part.Lo = Partial2.Part.Lo; 247ae115bc7Smrj 248ae115bc7Smrj if (Partial3.Part.Hi == 0) 249ae115bc7Smrj { 250ae115bc7Smrj if (Partial3.Part.Lo >= Dividend.Part.Hi) 251ae115bc7Smrj { 252ae115bc7Smrj if (Partial3.Part.Lo == Dividend.Part.Hi) 253ae115bc7Smrj { 254ae115bc7Smrj if (Partial2.Part.Lo > Dividend.Part.Lo) 255ae115bc7Smrj { 256ae115bc7Smrj Quotient.Part.Lo--; 257ae115bc7Smrj Remainder.Full -= Divisor.Full; 258ae115bc7Smrj } 259ae115bc7Smrj } 260ae115bc7Smrj else 261ae115bc7Smrj { 262ae115bc7Smrj Quotient.Part.Lo--; 263ae115bc7Smrj Remainder.Full -= Divisor.Full; 264ae115bc7Smrj } 265ae115bc7Smrj } 266ae115bc7Smrj 267ae115bc7Smrj Remainder.Full = Remainder.Full - Dividend.Full; 268ae115bc7Smrj Remainder.Part.Hi = (UINT32) -((INT32) Remainder.Part.Hi); 269ae115bc7Smrj Remainder.Part.Lo = (UINT32) -((INT32) Remainder.Part.Lo); 270ae115bc7Smrj 271ae115bc7Smrj if (Remainder.Part.Lo) 272ae115bc7Smrj { 273ae115bc7Smrj Remainder.Part.Hi--; 274ae115bc7Smrj } 275ae115bc7Smrj } 276ae115bc7Smrj } 277ae115bc7Smrj 278ae115bc7Smrj /* Return only what was requested */ 279ae115bc7Smrj 280ae115bc7Smrj if (OutQuotient) 281ae115bc7Smrj { 282ae115bc7Smrj *OutQuotient = Quotient.Full; 283ae115bc7Smrj } 284ae115bc7Smrj if (OutRemainder) 285ae115bc7Smrj { 286ae115bc7Smrj *OutRemainder = Remainder.Full; 287ae115bc7Smrj } 288ae115bc7Smrj 289ae115bc7Smrj return_ACPI_STATUS (AE_OK); 290ae115bc7Smrj } 291ae115bc7Smrj 292ae115bc7Smrj #else 293ae115bc7Smrj 294ae115bc7Smrj /******************************************************************************* 295ae115bc7Smrj * 296ae115bc7Smrj * FUNCTION: AcpiUtShortDivide, AcpiUtDivide 297ae115bc7Smrj * 298ae115bc7Smrj * PARAMETERS: See function headers above 299ae115bc7Smrj * 300ae115bc7Smrj * DESCRIPTION: Native versions of the UtDivide functions. Use these if either 301ae115bc7Smrj * 1) The target is a 64-bit platform and therefore 64-bit 302ae115bc7Smrj * integer math is supported directly by the machine. 303ae115bc7Smrj * 2) The target is a 32-bit or 16-bit platform, and the 304ae115bc7Smrj * double-precision integer math library is available to 305ae115bc7Smrj * perform the divide. 306ae115bc7Smrj * 307ae115bc7Smrj ******************************************************************************/ 308ae115bc7Smrj 309ae115bc7Smrj ACPI_STATUS 310ae115bc7Smrj AcpiUtShortDivide ( 31126f3cdf0SGordon Ross UINT64 InDividend, 312ae115bc7Smrj UINT32 Divisor, 31326f3cdf0SGordon Ross UINT64 *OutQuotient, 314ae115bc7Smrj UINT32 *OutRemainder) 315ae115bc7Smrj { 316ae115bc7Smrj 317ae115bc7Smrj ACPI_FUNCTION_TRACE (UtShortDivide); 318ae115bc7Smrj 319ae115bc7Smrj 320ae115bc7Smrj /* Always check for a zero divisor */ 321ae115bc7Smrj 322ae115bc7Smrj if (Divisor == 0) 323ae115bc7Smrj { 324ae115bc7Smrj ACPI_ERROR ((AE_INFO, "Divide by zero")); 325ae115bc7Smrj return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); 326ae115bc7Smrj } 327ae115bc7Smrj 328ae115bc7Smrj /* Return only what was requested */ 329ae115bc7Smrj 330ae115bc7Smrj if (OutQuotient) 331ae115bc7Smrj { 332ae115bc7Smrj *OutQuotient = InDividend / Divisor; 333ae115bc7Smrj } 334ae115bc7Smrj if (OutRemainder) 335ae115bc7Smrj { 336db2bae30SDana Myers *OutRemainder = (UINT32) (InDividend % Divisor); 337ae115bc7Smrj } 338ae115bc7Smrj 339ae115bc7Smrj return_ACPI_STATUS (AE_OK); 340ae115bc7Smrj } 341ae115bc7Smrj 342ae115bc7Smrj ACPI_STATUS 343ae115bc7Smrj AcpiUtDivide ( 34426f3cdf0SGordon Ross UINT64 InDividend, 34526f3cdf0SGordon Ross UINT64 InDivisor, 34626f3cdf0SGordon Ross UINT64 *OutQuotient, 34726f3cdf0SGordon Ross UINT64 *OutRemainder) 348ae115bc7Smrj { 349ae115bc7Smrj ACPI_FUNCTION_TRACE (UtDivide); 350ae115bc7Smrj 351ae115bc7Smrj 352ae115bc7Smrj /* Always check for a zero divisor */ 353ae115bc7Smrj 354ae115bc7Smrj if (InDivisor == 0) 355ae115bc7Smrj { 356ae115bc7Smrj ACPI_ERROR ((AE_INFO, "Divide by zero")); 357ae115bc7Smrj return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO); 358ae115bc7Smrj } 359ae115bc7Smrj 360ae115bc7Smrj 361ae115bc7Smrj /* Return only what was requested */ 362ae115bc7Smrj 363ae115bc7Smrj if (OutQuotient) 364ae115bc7Smrj { 365ae115bc7Smrj *OutQuotient = InDividend / InDivisor; 366ae115bc7Smrj } 367ae115bc7Smrj if (OutRemainder) 368ae115bc7Smrj { 369ae115bc7Smrj *OutRemainder = InDividend % InDivisor; 370ae115bc7Smrj } 371ae115bc7Smrj 372ae115bc7Smrj return_ACPI_STATUS (AE_OK); 373ae115bc7Smrj } 374ae115bc7Smrj 375ae115bc7Smrj #endif 376