xref: /titanic_52/usr/src/uts/intel/io/acpica/utilities/utmath.c (revision 385cc6b4ad1792caef3f84eb61eed3f27085801f)
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