1 /*
2 	Compatibility <intrin.h> header for GCC -- GCC equivalents of intrinsic
3 	Microsoft Visual C++ functions. Originally developed for the ReactOS
4 	(<https://reactos.org/>) and TinyKrnl (<http://www.tinykrnl.org/>)
5 	projects.
6 
7 	Copyright (c) 2006 KJK::Hyperion <hackbunny@reactos.com>
8 
9 	Permission is hereby granted, free of charge, to any person obtaining a
10 	copy of this software and associated documentation files (the "Software"),
11 	to deal in the Software without restriction, including without limitation
12 	the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 	and/or sell copies of the Software, and to permit persons to whom the
14 	Software is furnished to do so, subject to the following conditions:
15 
16 	The above copyright notice and this permission notice shall be included in
17 	all copies or substantial portions of the Software.
18 
19 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 	DEALINGS IN THE SOFTWARE.
26 */
27 
28 #ifndef KJK_INTRIN_PPC_H_
29 #define KJK_INTRIN_PPC_H_
30 
31 //#define PPC_QUAL static __inline__ __attribute__((always_inline))
32 #define PPC_QUAL extern __inline__
33 
34 #ifndef __GNUC__
35 #error Unsupported compiler
36 #endif
37 
38 /*** Stack frame juggling ***/
39 #define _ReturnAddress() (__builtin_return_address(0))
40 #define _AddressOfReturnAddress() (&(((void **)(__builtin_frame_address(0)))[1]))
41 /* TODO: __getcallerseflags but how??? */
42 
43 
44 /*** Atomic operations ***/
45 /* TODO: _ReadBarrier */
46 /* TODO: _WriteBarrier */
47 
48 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
49 #define _ReadWriteBarrier() __sync_synchronize()
50 #else
51 /* TODO: _ReadWriteBarrier() */
52 #endif
53 
54 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) > 40100
55 
_InterlockedCompareExchange8(volatile char * const Destination,const char Exchange,const char Comperand)56 PPC_QUAL char _InterlockedCompareExchange8(volatile char * const Destination, const char Exchange, const char Comperand)
57 {
58 	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
59 }
60 
_InterlockedCompareExchange16(volatile short * const Destination,const short Exchange,const short Comperand)61 PPC_QUAL short _InterlockedCompareExchange16(volatile short * const Destination, const short Exchange, const short Comperand)
62 {
63 	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
64 }
65 
_InterlockedCompareExchange(volatile long * const Destination,const long Exchange,const long Comperand)66 PPC_QUAL long _InterlockedCompareExchange(volatile long * const Destination, const long Exchange, const long Comperand)
67 {
68 	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
69 }
70 
_InterlockedCompareExchange64(volatile long long * const Destination,const long long Exchange,const long long Comperand)71 PPC_QUAL long long _InterlockedCompareExchange64(volatile long long * const Destination, const long long Exchange, const long long Comperand)
72 {
73 	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
74 }
75 
_InterlockedCompareExchangePointer(void * volatile * const Destination,void * const Exchange,void * const Comperand)76 PPC_QUAL void * _InterlockedCompareExchangePointer(void * volatile * const Destination, void * const Exchange, void * const Comperand)
77 {
78 	return __sync_val_compare_and_swap(Destination, Comperand, Exchange);
79 }
80 
_InterlockedExchange(volatile long * const Target,const long Value)81 PPC_QUAL long _InterlockedExchange(volatile long * const Target, const long Value)
82 {
83 	/* NOTE: __sync_lock_test_and_set would be an acquire barrier, so we force a full barrier */
84 	__sync_synchronize();
85 	return __sync_lock_test_and_set(Target, Value);
86 }
87 
_InterlockedExchangePointer(void * volatile * const Target,void * const Value)88 PPC_QUAL void * _InterlockedExchangePointer(void * volatile * const Target, void * const Value)
89 {
90 	/* NOTE: ditto */
91 	__sync_synchronize();
92 	return __sync_lock_test_and_set(Target, Value);
93 }
94 
_InterlockedExchangeAdd(volatile long * const Addend,const long Value)95 PPC_QUAL long _InterlockedExchangeAdd(volatile long * const Addend, const long Value)
96 {
97 	return __sync_fetch_and_add(Addend, Value);
98 }
99 
_InterlockedAnd8(volatile char * const value,const char mask)100 PPC_QUAL char _InterlockedAnd8(volatile char * const value, const char mask)
101 {
102 	return __sync_fetch_and_and(value, mask);
103 }
104 
_InterlockedAnd16(volatile short * const value,const short mask)105 PPC_QUAL short _InterlockedAnd16(volatile short * const value, const short mask)
106 {
107 	return __sync_fetch_and_and(value, mask);
108 }
109 
_InterlockedAnd(volatile long * const value,const long mask)110 PPC_QUAL long _InterlockedAnd(volatile long * const value, const long mask)
111 {
112 	return __sync_fetch_and_and(value, mask);
113 }
114 
_InterlockedOr8(volatile char * const value,const char mask)115 PPC_QUAL char _InterlockedOr8(volatile char * const value, const char mask)
116 {
117 	return __sync_fetch_and_or(value, mask);
118 }
119 
_InterlockedOr16(volatile short * const value,const short mask)120 PPC_QUAL short _InterlockedOr16(volatile short * const value, const short mask)
121 {
122 	return __sync_fetch_and_or(value, mask);
123 }
124 
_InterlockedOr(volatile long * const value,const long mask)125 PPC_QUAL long _InterlockedOr(volatile long * const value, const long mask)
126 {
127 	return __sync_fetch_and_or(value, mask);
128 }
129 
_InterlockedXor8(volatile char * const value,const char mask)130 PPC_QUAL char _InterlockedXor8(volatile char * const value, const char mask)
131 {
132 	return __sync_fetch_and_xor(value, mask);
133 }
134 
_InterlockedXor16(volatile short * const value,const short mask)135 PPC_QUAL short _InterlockedXor16(volatile short * const value, const short mask)
136 {
137 	return __sync_fetch_and_xor(value, mask);
138 }
139 
_InterlockedXor(volatile long * const value,const long mask)140 PPC_QUAL long _InterlockedXor(volatile long * const value, const long mask)
141 {
142 	return __sync_fetch_and_xor(value, mask);
143 }
144 
145 #else
146 
_InterlockedCompareExchange8(volatile char * const Destination,const char Exchange,const char Comperand)147 PPC_QUAL char _InterlockedCompareExchange8(volatile char * const Destination, const char Exchange, const char Comperand)
148 {
149         volatile long retval __asm__("r8") = 0;
150 	__asm__ __volatile__ (
151 	    "sync\n"
152 	    "1: lbarx   %0,0,%1\n"
153             : "=r" (retval) : "r" (Destination));
154         __asm__ __volatile__ (
155 	    "   cmpw    %3,%1\n"
156 	    "   bne-    2f\n"
157 	    "   stbcx.  %2,0,%0\n"
158 	    "   bne-    1b\n"
159 	    "2: isync"
160 	    :
161 	    : "r" (Destination), "r" (Comperand), "r" (Exchange), "r" (retval));
162 	return retval;
163 }
164 
_InterlockedCompareExchange16(volatile short * const Destination,const short Exchange,const short Comperand)165 PPC_QUAL short _InterlockedCompareExchange16(volatile short * const Destination, const short Exchange, const short Comperand)
166 {
167         volatile long retval __asm__("r8") = 0;
168 	__asm__ __volatile__ (
169 	    "sync\n"
170 	    "1: lharx   %0,0,%1\n"
171             : "=&r" (retval) : "r" (Destination));
172         __asm__ __volatile__ (
173 	    "   cmpw    %3,%1\n"
174 	    "   bne-    2f\n"
175 	    "   sthcx.  %2,0,%0\n"
176 	    "   bne-    1b\n"
177 	    "2: isync"
178 	    :
179 	    : "r" (Destination), "r" (Comperand), "r" (Exchange), "r" (retval));
180 	return retval;
181 }
182 
_InterlockedCompareExchange(volatile long * const Destination,const long Exchange,const long Comperand)183 PPC_QUAL long _InterlockedCompareExchange(volatile long * const Destination, const long Exchange, const long Comperand)
184 {
185         volatile long retval __asm__("r8") = 0;
186 	__asm__ __volatile__ (
187 	    "sync\n"
188 	    "1: lwarx   %0,0,%1\n"
189             : "=&r" (retval) : "r" (Destination));
190         __asm__ __volatile__ (
191 	    "   cmpw    %3,%1\n"
192 	    "   bne-    2f\n"
193 	    "   stwcx.  %2,0,%0\n"
194 	    "   bne-    1b\n"
195 	    "2: isync"
196 	    :
197 	    : "r" (Destination), "r" (Comperand), "r" (Exchange), "r" (retval));
198 	return retval;
199 }
200 
_InterlockedCompareExchange64(volatile long long * const Target,const long long Exchange,const long long Comperand)201 PPC_QUAL long long _InterlockedCompareExchange64(volatile long long * const Target, const long long Exchange, const long long Comperand)
202 {
203     long long capture = *Target;
204     if (*Target == Comperand) *Target = Exchange;
205     return capture;
206 }
207 
_InterlockedCompareExchangePointer(void * volatile * const Destination,void * const Exchange,void * const Comperand)208 PPC_QUAL void * _InterlockedCompareExchangePointer(void * volatile * const Destination, void * const Exchange, void * const Comperand)
209 {
210     return (void *)_InterlockedCompareExchange
211 	((long *)Destination, (long) Exchange, (long) Comperand);
212 }
213 
_InterlockedExchange(volatile long * const Target,const long Value)214 PPC_QUAL long _InterlockedExchange(volatile long * const Target, const long Value)
215 {
216     long retval __asm__("r8");
217     __asm__ __volatile__ (
218         "sync\n"
219         "1: lwarx   8,0,3\n"
220         "   stwcx.  4,0,3\n"
221         "   bne-    1b\n"
222         "   mr      3,8\n"
223         : "=b" (retval)
224         : "b" (Target), "b" (Value)
225         : "cr0", "memory");
226     return retval;
227 }
228 
_InterlockedExchangePointer(void * volatile * const Target,void * const Value)229 PPC_QUAL void * _InterlockedExchangePointer(void * volatile * const Target, void * const Value)
230 {
231     return (void *)_InterlockedExchange((long *)Target, (long)Value);
232 }
233 
234 #define PPC_MakeInterlockedFunction(type,name,op,proto) \
235 PPC_QUAL type name proto \
236 { \
237         long addend, y; \
238         do \
239         { \
240                 addend = *value; \
241                 y = _InterlockedCompareExchange(value, addend op modify, addend); \
242 	} \
243 	while(y != addend); \
244  \
245 	return y; \
246 }
247 
_interlockedbittestandreset(volatile long * const a,const long b)248 PPC_QUAL unsigned char _interlockedbittestandreset(volatile long * const a, const long b)
249 {
250 	long x;
251 	long y;
252 	long mask = ~(1<<b);
253 
254 	do
255 	{
256 		x = *a;
257 		y = _InterlockedCompareExchange(a, x & mask, x);
258 	}
259 	while(y != x);
260 
261 	return (y & ~mask) != 0;
262 }
263 
264 PPC_MakeInterlockedFunction(long,_InterlockedExchangeAdd,+,(volatile long * const value, const long modify))
265 PPC_MakeInterlockedFunction(char,_InterlockedAnd8,&,(volatile char * const value, const char modify))
266 PPC_MakeInterlockedFunction(short,_InterlockedAnd16,&,(volatile short * const value, const short modify))
267 PPC_MakeInterlockedFunction(long,_InterlockedAnd,&,(volatile long * const value, const long modify))
268 PPC_MakeInterlockedFunction(char,_InterlockedOr8,|,(volatile char * const value, const char modify))
269 PPC_MakeInterlockedFunction(short,_InterlockedOr16,|,(volatile short * const value, const short modify))
270 PPC_MakeInterlockedFunction(long,_InterlockedOr,|,(volatile long * const value, const long modify))
271 PPC_MakeInterlockedFunction(char,_InterlockedXor8,^,(volatile char * const value, const char modify))
272 PPC_MakeInterlockedFunction(short,_InterlockedXor16,^,(volatile short * const value, const short modify))
273 PPC_MakeInterlockedFunction(long,_InterlockedXor,^,(volatile long * const value, const long modify))
274 
_interlockedbittestandset(volatile long * const a,const long b)275 PPC_QUAL unsigned char _interlockedbittestandset(volatile long * const a, const long b)
276 {
277 	long x;
278 	long y;
279 	long mask = 1<<b;
280 
281 	do
282 	{
283                 x = *a;
284 		y = _InterlockedCompareExchange(a, x | mask, x);
285 	}
286 	while(y != x);
287 
288 	return (y & ~mask) != 0;
289 }
290 #endif
291 
_InterlockedDecrement(volatile long * const lpAddend)292 PPC_QUAL long _InterlockedDecrement(volatile long * const lpAddend)
293 {
294 	return _InterlockedExchangeAdd(lpAddend, -1) - 1;
295 }
296 
_InterlockedIncrement(volatile long * const lpAddend)297 PPC_QUAL long _InterlockedIncrement(volatile long * const lpAddend)
298 {
299 	return _InterlockedExchangeAdd(lpAddend, 1) + 1;
300 }
301 
302 /*** String operations ***/
303 /* NOTE: we don't set a memory clobber in the __stosX functions because Visual C++ doesn't */
304 /* Note that the PPC store multiple operations may raise an exception in LE
305  * mode */
__stosb(unsigned char * Dest,const unsigned char Data,unsigned long Count)306 PPC_QUAL void __stosb(unsigned char * Dest, const unsigned char Data, unsigned long Count)
307 {
308     memset(Dest, Data, Count);
309 }
310 
__stosw(unsigned short * Dest,const unsigned short Data,unsigned long Count)311 PPC_QUAL void __stosw(unsigned short * Dest, const unsigned short Data, unsigned long Count)
312 {
313     while(Count--)
314 	*Dest++ = Data;
315 }
316 
__stosd(unsigned long * Dest,const unsigned long Data,unsigned long Count)317 PPC_QUAL void __stosd(unsigned long * Dest, const unsigned long Data, unsigned long Count)
318 {
319     while(Count--)
320 	*Dest++ = Data;
321 }
322 
__movsb(unsigned char * Destination,const unsigned char * Source,unsigned long Count)323 PPC_QUAL void __movsb(unsigned char * Destination, const unsigned char * Source, unsigned long Count)
324 {
325     memcpy(Destination, Source, Count);
326 }
327 
__movsw(unsigned short * Destination,const unsigned short * Source,unsigned long Count)328 PPC_QUAL void __movsw(unsigned short * Destination, const unsigned short * Source, unsigned long Count)
329 {
330     memcpy(Destination, Source, Count * sizeof(*Source));
331 }
332 
__movsd(unsigned long * Destination,const unsigned long * Source,unsigned long Count)333 PPC_QUAL void __movsd(unsigned long * Destination, const unsigned long * Source, unsigned long Count)
334 {
335     memcpy(Destination, Source, Count * sizeof(*Source));
336 }
337 
338 
339 /*** FS segment addressing ***/
340 /* On PowerPC, r13 points to TLS data, including the TEB at 0(r13) from what I
341  * can tell */
__writefsbyte(const unsigned long Offset,const unsigned char Data)342 PPC_QUAL void __writefsbyte(const unsigned long Offset, const unsigned char Data)
343 {
344     char *addr;
345     __asm__("\tadd %0,13,%1\n\tstb %2,0(%0)" : "=r" (addr) : "r" (Offset), "r" (Data));
346 }
347 
__writefsword(const unsigned long Offset,const unsigned short Data)348 PPC_QUAL void __writefsword(const unsigned long Offset, const unsigned short Data)
349 {
350     char *addr;
351     __asm__("\tadd %0,13,%1\n\tsth %2,0(%0)" : "=r" (addr) : "r" (Offset), "r" (Data));
352 }
353 
__writefsdword(const unsigned long Offset,const unsigned long Data)354 PPC_QUAL void __writefsdword(const unsigned long Offset, const unsigned long Data)
355 {
356     char *addr;
357     __asm__("\tadd %0,13,%1\n\tstw %2,0(%0)" : "=r" (addr) : "r" (Offset), "r" (Data));
358 }
359 
__readfsbyte(const unsigned long Offset)360 PPC_QUAL unsigned char __readfsbyte(const unsigned long Offset)
361 {
362     unsigned short result;
363     __asm__("\tadd 7,13,%1\n"
364 	    "\tlbz %0,0(7)\n"
365 	    : "=r" (result)
366 	    : "r" (Offset)
367 	    : "r7");
368     return result;
369 }
370 
__readfsword(const unsigned long Offset)371 PPC_QUAL unsigned short __readfsword(const unsigned long Offset)
372 {
373     unsigned short result;
374     __asm__("\tadd 7,13,%1\n"
375 	    "\tlhz %0,0(7)\n"
376 	    : "=r" (result)
377 	    : "r" (Offset)
378 	    : "r7");
379     return result;
380 }
381 
__readfsdword(const unsigned long Offset)382 PPC_QUAL unsigned long __readfsdword(const unsigned long Offset)
383 {
384     unsigned long result;
385     __asm__("\tadd 7,13,%1\n"
386 	    "\tlwz %0,0(7)\n"
387 	    : "=r" (result)
388 	    : "r" (Offset)
389 	    : "r7");
390     return result;
391 }
392 
__incfsbyte(const unsigned long Offset)393 PPC_QUAL void __incfsbyte(const unsigned long Offset)
394 {
395     __writefsbyte(Offset, __readfsbyte(Offset)+1);
396 }
397 
__incfsword(const unsigned long Offset)398 PPC_QUAL void __incfsword(const unsigned long Offset)
399 {
400     __writefsword(Offset, __readfsword(Offset)+1);
401 }
402 
__incfsdword(const unsigned long Offset)403 PPC_QUAL void __incfsdword(const unsigned long Offset)
404 {
405     __writefsdword(Offset, __readfsdword(Offset)+1);
406 }
407 
408 /* NOTE: the bizarre implementation of __addfsxxx mimics the broken Visual C++ behavior */
409 /* PPC Note: Not sure about the bizarre behavior.  We'll try to emulate it later */
__addfsbyte(const unsigned long Offset,const unsigned char Data)410 PPC_QUAL void __addfsbyte(const unsigned long Offset, const unsigned char Data)
411 {
412     __writefsbyte(Offset, __readfsbyte(Offset) + Data);
413 }
414 
__addfsword(const unsigned long Offset,const unsigned short Data)415 PPC_QUAL void __addfsword(const unsigned long Offset, const unsigned short Data)
416 {
417     __writefsword(Offset, __readfsword(Offset) + Data);
418 }
419 
__addfsdword(const unsigned long Offset,const unsigned int Data)420 PPC_QUAL void __addfsdword(const unsigned long Offset, const unsigned int Data)
421 {
422     __writefsdword(Offset, __readfsdword(Offset) + Data);
423 }
424 
425 
426 /*** Bit manipulation ***/
_BitScanForward(unsigned long * const Index,const unsigned long Mask)427 PPC_QUAL unsigned char _BitScanForward(unsigned long * const Index, const unsigned long Mask)
428 {
429     if(Mask == 0) return 0;
430     else {
431 	unsigned long mask = Mask;
432 	mask &= -mask;
433 	*Index =
434 	    ((mask & 0xffff0000) ? 16 : 0) +
435 	    ((mask & 0xff00ff00) ? 8  : 0) +
436 	    ((mask & 0xf0f0f0f0) ? 4  : 0) +
437 	    ((mask & 0xcccccccc) ? 2  : 0) +
438 	    ((mask & 0xaaaaaaaa) ? 1  : 0);
439 	return 1;
440     }
441 }
442 
443 /* Thanks http://www.jjj.de/bitwizardry/files/bithigh.h */
_BitScanReverse(unsigned long * const Index,const unsigned long Mask)444 PPC_QUAL unsigned char _BitScanReverse(unsigned long * const Index, const unsigned long Mask)
445 {
446     unsigned long check = 16, checkmask;
447     if(Mask == 0) return 0;
448     else {
449 	unsigned long mask = Mask;
450 	*Index = 0;
451 	while(check) {
452 	    checkmask = ((1<<check)-1) << check;
453 	    if( mask & checkmask ) {
454 		mask >>= check;
455 		*Index += check;
456 	    }
457 	    check >>= 1;
458 	}
459 	return 1;
460     }
461 }
462 
463 /* NOTE: again, the bizarre implementation follows Visual C++ */
_bittest(const long * const a,const long b)464 PPC_QUAL unsigned char _bittest(const long * const a, const long b)
465 {
466     return ((*a) & (1<<b)) != 0;
467 }
468 
_bittestandcomplement(long * const a,const long b)469 PPC_QUAL unsigned char _bittestandcomplement(long * const a, const long b)
470 {
471     unsigned char ret = ((*a) & (1<<b)) != 0;
472     (*a) ^= (1<<b);
473     return ret;
474 }
475 
_bittestandreset(long * const a,const long b)476 PPC_QUAL unsigned char _bittestandreset(long * const a, const long b)
477 {
478     unsigned char ret = ((*a) & (1<<b)) != 0;
479     (*a) &= ~(1<<b);
480     return ret;
481 }
482 
_bittestandset(long * const a,const long b)483 PPC_QUAL unsigned char _bittestandset(long * const a, const long b)
484 {
485     unsigned char ret = ((*a) & (1<<b)) != 0;
486     (*a) |= (1<<b);
487     return ret;
488 }
489 
_rotl8(const unsigned char value,const unsigned char shift)490 PPC_QUAL unsigned char _rotl8(const unsigned char value, const unsigned char shift)
491 {
492     return (value << shift) | (value >> (8-shift));
493 }
494 
_rotl16(const unsigned short value,const unsigned char shift)495 PPC_QUAL unsigned short _rotl16(const unsigned short value, const unsigned char shift)
496 {
497     return (value << shift) | (value >> (16-shift));
498 }
499 
_rotr8(const unsigned char value,const unsigned char shift)500 PPC_QUAL unsigned char _rotr8(const unsigned char value, const unsigned char shift)
501 {
502     return (value >> shift) | (value << (8-shift));
503 }
504 
_rotr16(const unsigned short value,const unsigned char shift)505 PPC_QUAL unsigned short _rotr16(const unsigned short value, const unsigned char shift)
506 {
507     return (value >> shift) | (value << (16-shift));
508 }
509 
__ll_lshift(const unsigned long long Mask,int Bit)510 PPC_QUAL unsigned long long __ll_lshift(const unsigned long long Mask, int Bit)
511 {
512     return Mask << Bit;
513 }
514 
__ll_rshift(const long long Mask,const int Bit)515 PPC_QUAL long long __ll_rshift(const long long Mask, const int Bit)
516 {
517     return Mask >> Bit;
518 }
519 
__ull_rshift(const unsigned long long Mask,int Bit)520 PPC_QUAL unsigned long long __ull_rshift(const unsigned long long Mask, int Bit)
521 {
522     return Mask >> Bit;
523 }
524 
525 
526 /*** 64-bit math ***/
__emul(const int a,const int b)527 PPC_QUAL long long __emul(const int a, const int b)
528 {
529     return a * b;
530 }
531 
__emulu(const unsigned int a,const unsigned int b)532 PPC_QUAL unsigned long long __emulu(const unsigned int a, const unsigned int b)
533 {
534     return a * b;
535 }
536 
537 
538 /*** Port I/O ***/
__inbyte(const unsigned long Port)539 PPC_QUAL unsigned char __inbyte(const unsigned long Port)
540 {
541     int ret;
542     __asm__(
543 	"mfmsr 5\n\t"
544 	"andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
545 	"mtmsr 6\n\t"
546 	"isync\n\t"
547 	"sync\n\t"
548 	"lbz   %0,0(%1)\n\t"    /* Get actual value at phys addr r3 */
549 	"mtmsr 5\n\t" : "=r" (ret) : "b" (Port)
550     );
551     return ret;
552 }
553 
__inword(const unsigned long Port)554 PPC_QUAL unsigned short __inword(const unsigned long Port)
555 {
556     int ret;
557     __asm__(
558 	"mfmsr 5\n\t"
559 	"andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
560 	"mtmsr 6\n\t"
561 	"isync\n\t"
562 	"sync\n\t"
563 	"lhz   %0,0(%1)\n\t"    /* Get actual value at phys addr r3 */
564 	"mtmsr 5\n\t" : "=r" (ret) : "b" (Port)
565     );
566     return ret;
567 }
568 
__indword(const unsigned long Port)569 PPC_QUAL unsigned long __indword(const unsigned long Port)
570 {
571     int ret;
572     __asm__(
573 	"mfmsr 5\n\t"
574 	"andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
575 	"mtmsr 6\n\t"
576 	"isync\n\t"
577 	"sync\n\t"
578 	"lwz   %0,0(%1)\n\t"    /* Get actual value at phys addr r3 */
579 	"mtmsr 5\n\t" : "=r" (ret) : "b" (Port)
580     );
581     return ret;
582 }
583 
__inbytestring(unsigned long Port,unsigned char * Buffer,unsigned long Count)584 PPC_QUAL void __inbytestring(unsigned long Port, unsigned char * Buffer, unsigned long Count)
585 {
586     while(Count--) {
587 	*Buffer++ = __inbyte(Port);
588     }
589 }
590 
__inwordstring(unsigned long Port,unsigned short * Buffer,unsigned long Count)591 PPC_QUAL void __inwordstring(unsigned long Port, unsigned short * Buffer, unsigned long Count)
592 {
593     while(Count--) {
594 	*Buffer++ = __inword(Port);
595     }
596 }
597 
__indwordstring(unsigned long Port,unsigned long * Buffer,unsigned long Count)598 PPC_QUAL void __indwordstring(unsigned long Port, unsigned long * Buffer, unsigned long Count)
599 {
600     while(Count--) {
601 	*Buffer++ = __indword(Port);
602     }
603 }
604 
__outbyte(unsigned long const Port,const unsigned char Data)605 PPC_QUAL void __outbyte(unsigned long const Port, const unsigned char Data)
606 {
607     __asm__(
608 	"mfmsr 5\n\t"
609 	"andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
610 	"mtmsr 6\n\t"
611 	"sync\n\t"
612 	"eieio\n\t"
613 	"stb   %1,0(%0)\n\t"    /* Set actual value at phys addr r3 */
614 	"dcbst 0,%1\n\t"
615 	"mtmsr 5\n\t"
616 	"sync\n\t"
617 	"eieio\n\t" : : "b" (Port), "r" (Data)
618 	);
619 }
620 
__outword(unsigned long const Port,const unsigned short Data)621 PPC_QUAL void __outword(unsigned long const Port, const unsigned short Data)
622 {
623     __asm__(
624 	"mfmsr 5\n\t"
625 	"andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
626 	"mtmsr 6\n\t"
627 	"sync\n\t"
628 	"eieio\n\t"
629 	"sth   %1,0(%0)\n\t"    /* Set actual value at phys addr r3 */
630 	"dcbst 0,%1\n\t"
631 	"mtmsr 5\n\t"
632 	"sync\n\t"
633 	"eieio\n\t" : : "b" (Port), "b" (Data)
634 	);
635 }
636 
__outdword(unsigned long const Port,const unsigned long Data)637 PPC_QUAL void __outdword(unsigned long const Port, const unsigned long Data)
638 {
639     __asm__(
640 	"mfmsr 5\n\t"
641 	"andi. 6,5,0xffef\n\t"/* turn off MSR[DR] */
642 	"mtmsr 6\n\t"
643 	"sync\n\t"
644 	"eieio\n\t"
645 	"stw   %1,0(%0)\n\t"    /* Set actual value at phys addr r3 */
646 	"dcbst 0,%1\n\t"
647 	"mtmsr 5\n\t"
648 	"sync\n\t"
649 	"eieio\n\t" : : "b" (Port), "b" (Data)
650 	);
651 }
652 
__outbytestring(unsigned long const Port,const unsigned char * const Buffer,const unsigned long Count)653 PPC_QUAL void __outbytestring(unsigned long const Port, const unsigned char * const Buffer, const unsigned long Count)
654 {
655     unsigned long count = Count;
656     const unsigned char *buffer = Buffer;
657     while(count--) {
658 	__outbyte(Port, *buffer++);
659     }
660 }
661 
__outwordstring(unsigned long const Port,const unsigned short * const Buffer,const unsigned long Count)662 PPC_QUAL void __outwordstring(unsigned long const Port, const unsigned short * const Buffer, const unsigned long Count)
663 {
664     unsigned long count = Count;
665     const unsigned short *buffer = Buffer;
666     while(count--) {
667 	__outword(Port, *buffer++);
668     }
669 }
670 
__outdwordstring(unsigned long const Port,const unsigned long * const Buffer,const unsigned long Count)671 PPC_QUAL void __outdwordstring(unsigned long const Port, const unsigned long * const Buffer, const unsigned long Count)
672 {
673     unsigned long count = Count;
674     const unsigned long *buffer = Buffer;
675     while(count--) {
676 	__outdword(Port, *buffer++);
677     }
678 }
679 
680 
681 /*** System information ***/
__cpuid(int CPUInfo[],const int InfoType)682 PPC_QUAL void __cpuid(int CPUInfo[], const int InfoType)
683 {
684     unsigned long lo32;
685     __asm__("mfpvr" : "=b" (lo32));
686 }
687 
__rdtsc(void)688 PPC_QUAL unsigned long long __rdtsc(void)
689 {
690     unsigned long lo32;
691     __asm__("mfdec %0" : "=b" (lo32));
692     return -lo32;
693 }
694 
695 
696 /*** Interrupts ***/
697 /* Finally decided to do this by enabling single step trap */
__debugbreak(void)698 PPC_QUAL void __debugbreak(void)
699 {
700 
701 }
702 
__int2c(void)703 PPC_QUAL void __int2c(void)
704 {
705     /* Not sure yet */
706 }
707 
708 #ifndef _ENABLE_DISABLE_DEFINED
709 #define _ENABLE_DISABLE_DEFINED
_disable(void)710 PPC_QUAL void _disable(void)
711 {
712     __asm__ __volatile__("mfmsr 0\n\t" \
713 			 "li    8,0x7fff\n\t" \
714 			 "and   0,8,0\n\t" \
715 			 "mtmsr 0\n\t");
716 }
717 
_enable(void)718 PPC_QUAL void _enable(void)
719 {
720     __asm__ __volatile__("mfmsr 8\n\t" \
721 			 "ori   8,8,0x8000\n\t" \
722 			 "mtmsr 8\n\t");
723 }
724 
725 /*** Protected memory management ***/
__readsdr1(void)726 PPC_QUAL unsigned long __readsdr1(void)
727 {
728     unsigned long value;
729     __asm__("mfsdr1 %0" : "=b" (value));
730     return value;
731 }
732 
__writesdr1(const unsigned long long Data)733 PPC_QUAL void __writesdr1(const unsigned long long Data)
734 {
735     __asm__("mtsdr1 %0" : : "b" (Data));
736 }
737 
738 /*** System operations ***/
739 /* This likely has a different meaning from the X86 equivalent.  We'll keep
740  * the name cause it fits */
__readmsr()741 PPC_QUAL unsigned long long __readmsr()
742 {
743     unsigned long temp;
744     __asm__("mfmsr %0" : "=b" (temp));
745     return temp;
746 }
747 
__writemsr(const unsigned long Value)748 PPC_QUAL void __writemsr(const unsigned long Value)
749 {
750     __asm__("mtmsr %0" : : "b" (Value));
751 }
752 
753 /* We'll make sure of the following:
754  * IO operations have completed
755  * Write operations through cache have completed
756  * We've reloaded anything in the data or instruction cache that might have
757  * changed in real ram.
758  */
__wbinvd(void)759 PPC_QUAL void __wbinvd(void)
760 {
761     __asm__("eieio\n\t"
762 	    "dcs\n\t"
763 	    "sync\n\t"
764 	    "isync\n\t");
765 }
766 #endif
767 
_InterlockedAddLargeStatistic(volatile long long * const Addend,const long Value)768 PPC_QUAL long _InterlockedAddLargeStatistic(volatile long long * const Addend, const long Value)
769 {
770 #if 0
771 	__asm__
772 	(
773 		"lock; add %[Value], %[Lo32];"
774 		"jae LABEL%=;"
775 		"lock; adc $0, %[Hi32];"
776 		"LABEL%=:;" :
777 		[Lo32] "=m" (*((volatile long *)(Addend) + 0)), [Hi32] "=m" (*((volatile long *)(Addend) + 1)) :
778 		[Value] "ir" (Value)
779 	);
780 #endif
781 	return Value;
782 }
783 
784 /*** Miscellaneous ***/
785 /* BUGBUG: only good for use in macros. Cannot be taken the address of */
786 #define __noop(...) ((void)0)
787 
788 #define __assume(x) if (!(x)) __builtin_unreachable()
789 
790 #endif
791 /* EOF */
792