summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/arch/x86/include/bits/bigint.h
blob: d3449af5a96ed33764e47cb8cc2bfbd04448b8a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#ifndef _BITS_BIGINT_H
#define _BITS_BIGINT_H

/** @file
 *
 * Big integer support
 */

FILE_LICENCE ( GPL2_OR_LATER );

#include <stdint.h>
#include <string.h>

/** Element of a big integer */
typedef uint32_t bigint_element_t;

/**
 * Initialise big integer
 *
 * @v value0		Element 0 of big integer to initialise
 * @v size		Number of elements
 * @v data		Raw data
 * @v len		Length of raw data
 */
static inline __attribute__ (( always_inline )) void
bigint_init_raw ( uint32_t *value0, unsigned int size,
		  const void *data, size_t len ) {
	long pad_len = ( sizeof ( bigint_t ( size ) ) - len );
	void *discard_D;
	long discard_c;

	/* Copy raw data in reverse order, padding with zeros */
	__asm__ __volatile__ ( "\n1:\n\t"
			       "movb -1(%2,%1), %%al\n\t"
			       "stosb\n\t"
			       "loop 1b\n\t"
			       "xorl %%eax, %%eax\n\t"
			       "mov %3, %1\n\t"
			       "rep stosb\n\t"
			       : "=&D" ( discard_D ), "=&c" ( discard_c )
			       : "r" ( data ), "g" ( pad_len ), "0" ( value0 ),
				 "1" ( len )
			       : "eax" );
}

/**
 * Add big integers
 *
 * @v addend0		Element 0 of big integer to add
 * @v value0		Element 0 of big integer to be added to
 * @v size		Number of elements
 */
static inline __attribute__ (( always_inline )) void
bigint_add_raw ( const uint32_t *addend0, uint32_t *value0,
		 unsigned int size ) {
	long index;
	void *discard_S;
	long discard_c;

	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
			       "\n1:\n\t"
			       "lodsl\n\t"
			       "adcl %%eax, (%3,%0,4)\n\t"
			       "inc %0\n\t" /* Does not affect CF */
			       "loop 1b\n\t"
			       : "=&r" ( index ), "=&S" ( discard_S ),
				 "=&c" ( discard_c )
			       : "r" ( value0 ), "1" ( addend0 ), "2" ( size )
			       : "eax" );
}

/**
 * Subtract big integers
 *
 * @v subtrahend0	Element 0 of big integer to subtract
 * @v value0		Element 0 of big integer to be subtracted from
 * @v size		Number of elements
 */
static inline __attribute__ (( always_inline )) void
bigint_subtract_raw ( const uint32_t *subtrahend0, uint32_t *value0,
		      unsigned int size ) {
	long index;
	void *discard_S;
	long discard_c;

	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
			       "\n1:\n\t"
			       "lodsl\n\t"
			       "sbbl %%eax, (%3,%0,4)\n\t"
			       "inc %0\n\t" /* Does not affect CF */
			       "loop 1b\n\t"
			       : "=&r" ( index ), "=&S" ( discard_S ),
				 "=&c" ( discard_c )
			       : "r" ( value0 ), "1" ( subtrahend0 ),
				 "2" ( size )
			       : "eax" );
}

/**
 * Rotate big integer left
 *
 * @v value0		Element 0 of big integer
 * @v size		Number of elements
 */
static inline __attribute__ (( always_inline )) void
bigint_rol_raw ( uint32_t *value0, unsigned int size ) {
	long index;
	long discard_c;

	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Zero %0 and clear CF */
			       "\n1:\n\t"
			       "rcll $1, (%2,%0,4)\n\t"
			       "inc %0\n\t" /* Does not affect CF */
			       "loop 1b\n\t"
			       : "=&r" ( index ), "=&c" ( discard_c )
			       : "r" ( value0 ), "1" ( size ) );
}

/**
 * Rotate big integer right
 *
 * @v value0		Element 0 of big integer
 * @v size		Number of elements
 */
static inline __attribute__ (( always_inline )) void
bigint_ror_raw ( uint32_t *value0, unsigned int size ) {
	long discard_c;

	__asm__ __volatile__ ( "clc\n\t"
			       "\n1:\n\t"
			       "rcrl $1, -4(%1,%0,4)\n\t"
			       "loop 1b\n\t"
			       : "=&c" ( discard_c )
			       : "r" ( value0 ), "0" ( size ) );
}

/**
 * Test if big integer is equal to zero
 *
 * @v value0		Element 0 of big integer
 * @v size		Number of elements
 * @ret is_zero		Big integer is equal to zero
 */
static inline __attribute__ (( always_inline, pure )) int
bigint_is_zero_raw ( const uint32_t *value0, unsigned int size ) {
	void *discard_D;
	long discard_c;
	int result;

	__asm__ __volatile__ ( "xor %0, %0\n\t" /* Set ZF */
			       "repe scasl\n\t"
			       "sete %b0\n\t"
			       : "=&a" ( result ), "=&D" ( discard_D ),
				 "=&c" ( discard_c )
			       : "1" ( value0 ), "2" ( size ) );
	return result;
}

/**
 * Compare big integers
 *
 * @v value0		Element 0 of big integer
 * @v reference0	Element 0 of reference big integer
 * @v size		Number of elements
 * @ret geq		Big integer is greater than or equal to the reference
 */
static inline __attribute__ (( always_inline, pure )) int
bigint_is_geq_raw ( const uint32_t *value0, const uint32_t *reference0,
		    unsigned int size ) {
	const bigint_t ( size ) __attribute__ (( may_alias )) *value =
		( ( const void * ) value0 );
	const bigint_t ( size ) __attribute__ (( may_alias )) *reference =
		( ( const void * ) reference0 );
	void *discard_S;
	void *discard_D;
	long discard_c;
	int result;

	__asm__ __volatile__ ( "std\n\t"
			       "\n1:\n\t"
			       "lodsl\n\t"
			       "scasl\n\t"
			       "loope 1b\n\t"
			       "setae %b0\n\t"
			       "cld\n\t"
			       : "=q" ( result ), "=&S" ( discard_S ),
				 "=&D" ( discard_D ), "=&c" ( discard_c )
			       : "0" ( 0 ), "1" ( &value->element[ size - 1 ] ),
				 "2" ( &reference->element[ size - 1 ] ),
				 "3" ( size )
			       : "eax" );
	return result;
}

/**
 * Test if bit is set in big integer
 *
 * @v value0		Element 0 of big integer
 * @v size		Number of elements
 * @v bit		Bit to test
 * @ret is_set		Bit is set
 */
static inline __attribute__ (( always_inline )) int
bigint_bit_is_set_raw ( const uint32_t *value0, unsigned int size,
			unsigned int bit ) {
	const bigint_t ( size ) __attribute__ (( may_alias )) *value =
		( ( const void * ) value0 );
	unsigned int index = ( bit / ( 8 * sizeof ( value->element[0] ) ) );
	unsigned int subindex = ( bit % ( 8 * sizeof ( value->element[0] ) ) );

	return ( value->element[index] & ( 1 << subindex ) );
}

/**
 * Find highest bit set in big integer
 *
 * @v value0		Element 0 of big integer
 * @v size		Number of elements
 * @ret max_bit		Highest bit set + 1 (or 0 if no bits set)
 */
static inline __attribute__ (( always_inline )) int
bigint_max_set_bit_raw ( const uint32_t *value0, unsigned int size ) {
	long discard_c;
	int result;

	__asm__ __volatile__ ( "\n1:\n\t"
			       "bsrl -4(%2,%1,4), %0\n\t"
			       "loopz 1b\n\t"
			       "rol %1\n\t" /* Does not affect ZF */
			       "rol %1\n\t"
			       "leal 1(%k0,%k1,8), %k0\n\t"
			       "jnz 2f\n\t"
			       "xor %0, %0\n\t"
			       "\n2:\n\t"
			       : "=&r" ( result ), "=&c" ( discard_c )
			       : "r" ( value0 ), "1" ( size ) );
	return result;
}

/**
 * Grow big integer
 *
 * @v source0		Element 0 of source big integer
 * @v source_size	Number of elements in source big integer
 * @v dest0		Element 0 of destination big integer
 * @v dest_size		Number of elements in destination big integer
 */
static inline __attribute__ (( always_inline )) void
bigint_grow_raw ( const uint32_t *source0, unsigned int source_size,
		  uint32_t *dest0, unsigned int dest_size ) {
	long pad_size = ( dest_size - source_size );
	void *discard_D;
	void *discard_S;
	long discard_c;

	__asm__ __volatile__ ( "rep movsl\n\t"
			       "xorl %%eax, %%eax\n\t"
			       "mov %3, %2\n\t"
			       "rep stosl\n\t"
			       : "=&D" ( discard_D ), "=&S" ( discard_S ),
				 "=&c" ( discard_c )
			       : "g" ( pad_size ), "0" ( dest0 ),
				 "1" ( source0 ), "2" ( source_size )
			       : "eax" );
}

/**
 * Shrink big integer
 *
 * @v source0		Element 0 of source big integer
 * @v source_size	Number of elements in source big integer
 * @v dest0		Element 0 of destination big integer
 * @v dest_size		Number of elements in destination big integer
 */
static inline __attribute__ (( always_inline )) void
bigint_shrink_raw ( const uint32_t *source0, unsigned int source_size __unused,
		    uint32_t *dest0, unsigned int dest_size ) {
	void *discard_D;
	void *discard_S;
	long discard_c;

	__asm__ __volatile__ ( "rep movsl\n\t"
			       : "=&D" ( discard_D ), "=&S" ( discard_S ),
				 "=&c" ( discard_c )
			       : "0" ( dest0 ), "1" ( source0 ),
				 "2" ( dest_size )
			       : "eax" );
}

/**
 * Finalise big integer
 *
 * @v value0		Element 0 of big integer to finalise
 * @v size		Number of elements
 * @v out		Output buffer
 * @v len		Length of output buffer
 */
static inline __attribute__ (( always_inline )) void
bigint_done_raw ( const uint32_t *value0, unsigned int size __unused,
		  void *out, size_t len ) {
	void *discard_D;
	long discard_c;

	/* Copy raw data in reverse order */
	__asm__ __volatile__ ( "\n1:\n\t"
			       "movb -1(%2,%1), %%al\n\t"
			       "stosb\n\t"
			       "loop 1b\n\t"
			       : "=&D" ( discard_D ), "=&c" ( discard_c )
			       : "r" ( value0 ), "0" ( out ), "1" ( len )
			       : "eax" );
}

extern void bigint_multiply_raw ( const uint32_t *multiplicand0,
				  const uint32_t *multiplier0,
				  uint32_t *value0, unsigned int size );

#endif /* _BITS_BIGINT_H */