blob: 57da889ef49b1d1870e38e96c1ba54f07be7c36b [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: BSD-3-Clause
Stefan Roesedfafe7a2017-11-29 16:23:31 +01002/*
3 * This file is copied from the coreboot repository as part of
4 * the libpayload project:
5 *
6 * Copyright 2014 Google Inc.
Stefan Roesedfafe7a2017-11-29 16:23:31 +01007 */
8
Tom Rinidec7ea02024-05-20 13:35:03 -06009#include <linux/types.h>
Stefan Roesedfafe7a2017-11-29 16:23:31 +010010
11union overlay64 {
12 u64 longw;
13 struct {
14 u32 lower;
15 u32 higher;
16 } words;
17};
18
19u64 __ashldi3(u64 num, unsigned int shift)
20{
21 union overlay64 output;
22
23 output.longw = num;
24 if (shift >= 32) {
25 output.words.higher = output.words.lower << (shift - 32);
26 output.words.lower = 0;
27 } else {
28 if (!shift)
29 return num;
30 output.words.higher = (output.words.higher << shift) |
31 (output.words.lower >> (32 - shift));
32 output.words.lower = output.words.lower << shift;
33 }
34 return output.longw;
35}
36
37u64 __lshrdi3(u64 num, unsigned int shift)
38{
39 union overlay64 output;
40
41 output.longw = num;
42 if (shift >= 32) {
43 output.words.lower = output.words.higher >> (shift - 32);
44 output.words.higher = 0;
45 } else {
46 if (!shift)
47 return num;
48 output.words.lower = output.words.lower >> shift |
49 (output.words.higher << (32 - shift));
50 output.words.higher = output.words.higher >> shift;
51 }
52 return output.longw;
53}
54
55#define MAX_32BIT_UINT ((((u64)1) << 32) - 1)
56
57static u64 _64bit_divide(u64 dividend, u64 divider, u64 *rem_p)
58{
59 u64 result = 0;
60
61 /*
62 * If divider is zero - let the rest of the system care about the
63 * exception.
64 */
65 if (!divider)
66 return 1 / (u32)divider;
67
68 /* As an optimization, let's not use 64 bit division unless we must. */
69 if (dividend <= MAX_32BIT_UINT) {
70 if (divider > MAX_32BIT_UINT) {
71 result = 0;
72 if (rem_p)
73 *rem_p = divider;
74 } else {
75 result = (u32)dividend / (u32)divider;
76 if (rem_p)
77 *rem_p = (u32)dividend % (u32)divider;
78 }
79 return result;
80 }
81
82 while (divider <= dividend) {
83 u64 locald = divider;
84 u64 limit = __lshrdi3(dividend, 1);
85 int shifts = 0;
86
87 while (locald <= limit) {
88 shifts++;
89 locald = locald + locald;
90 }
91 result |= __ashldi3(1, shifts);
92 dividend -= locald;
93 }
94
95 if (rem_p)
96 *rem_p = dividend;
97
98 return result;
99}
100
101u64 __udivdi3(u64 num, u64 den)
102{
103 return _64bit_divide(num, den, NULL);
104}
105
106u64 __umoddi3(u64 num, u64 den)
107{
108 u64 v = 0;
109
110 _64bit_divide(num, den, &v);
111 return v;
112}