1 /*
2  * Copyright (c) 2006 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD: stable/10/tools/regression/ia64/emulated/test.c 160416 2006-07-17 00:27:12Z marcel $
27  */
28 
29 #include <sys/mman.h>
30 #include <stdio.h>
31 #include <string.h>
32 
33 /* Supported long branch types */
34 #define	Call		1
35 #define	Cond		2
36 
37 /* Supported predicates */
38 #define	False		1
39 #define	True		2
40 
41 /* Supported variations */
42 #define	Backward	1
43 #define	Forward		2
44 
45 #if TYPE == 0 || PRED == 0 || VAR == 0
46 #error Define TYPE, PRED and/or VAR
47 #endif
48 
49 union bundle {
50 	unsigned char bytes[16];
51 	long double _align;
52 };
53 
54 /*
55  * Machine code of a bundle containing a long branch. The predicate of the
56  * long branch is the result of the compare in the first slot.
57  * The assembly of the bundle is:
58  *	{	.mlx
59  *		cmp.eq		p0,p15= <PREDICATE>,r0
60  *	  (p15)	brl.few		<TARGET> ;;
61  *	}
62  * the predicate is written to bit 18:1
63  * The branch target is written to bits 100:20, 48:39 and 123:1
64  */
65 unsigned char mc_brl_cond[16] = {
66 	0x05, 0x00, 0x00, 0x00, 0x0f, 0x39,
67 	0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
68 	0x00, 0x00, 0x00, 0xc0
69 };
70 
71 /*
72  * Machine code of the epilogue of a typical function returning an integer.
73  * The assembly of the epilogue is:
74  *	{	.mib
75  *		nop.m		0
76  *		addl		r8 = <RETVAL>, r0
77  *		br.ret.sptk.few b0 ;;
78  *	}
79  * The return value is written to bits 59:7, 73:9, 68:5, and 82:1.
80  */
81 unsigned char mc_epilogue[16] = {
82 	0x11, 0x00, 0x00, 0x00, 0x01, 0x00,
83 	0x80, 0x00, 0x00, 0x00, 0x48, 0x80,
84 	0x00, 0x00, 0x84, 0x00
85 };
86 
87 void
mc_patch(union bundle * b,unsigned long val,int start,int len)88 mc_patch(union bundle *b, unsigned long val, int start, int len)
89 {
90 	unsigned long mask;
91 	int bit, byte, run;
92 
93 	byte = start >> 3;
94 	bit = start & 7;
95 	while (len) {
96 		run = ((len > (8 - bit)) ? (8 - bit) : len);
97 		mask = (1UL << run) - 1UL;
98 		b->bytes[byte] |= (val & mask) << bit;
99 		val >>= run;
100 		len -= run;
101 		byte++;
102 		bit = 0;
103 	}
104 }
105 
106 void
assemble_brl_cond(union bundle * b,int pred,unsigned long tgt)107 assemble_brl_cond(union bundle *b, int pred, unsigned long tgt)
108 {
109 	unsigned long iprel;
110 
111 	iprel = tgt - (unsigned long)b;
112 	memcpy(b->bytes, mc_brl_cond, sizeof(mc_brl_cond));
113 	mc_patch(b, pred ? 1 : 0, 18, 1);
114 	mc_patch(b, iprel >> 4, 100, 20);
115 	mc_patch(b, iprel >> 24, 48, 39);
116 	mc_patch(b, iprel >> 63, 123, 1);
117 }
118 
119 void
assemble_epilogue(union bundle * b,int retval)120 assemble_epilogue(union bundle *b, int retval)
121 {
122 	memcpy(b->bytes, mc_epilogue, sizeof(mc_epilogue));
123 	mc_patch(b, retval, 59, 7);
124 	mc_patch(b, retval >> 7, 73, 9);
125 	mc_patch(b, retval >> 16, 68, 5);
126 	mc_patch(b, retval >> 21, 82, 1);
127 }
128 
129 int
doit(void * addr)130 doit(void *addr)
131 {
132 	asm("mov b6 = %0; br.sptk b6;;" :: "r"(addr));
133 	return 1;
134 }
135 
136 int
test_cond(int pred,union bundle * src,union bundle * dst)137 test_cond(int pred, union bundle *src, union bundle *dst)
138 {
139 	assemble_epilogue(dst, pred ? 0 : 2);
140 	assemble_brl_cond(src, pred ? 1 : 0, (unsigned long)dst);
141 	assemble_epilogue(src + 1, !pred ? 0 : 2);
142 	return doit(src);
143 }
144 
145 int
main()146 main()
147 {
148 	static union bundle blob_low[2];
149 	union bundle *blob_high;
150 	void *addr;
151 
152 	addr = (void *)0x7FFFFFFF00000000L;
153 	blob_high = mmap(addr, 32, PROT_EXEC | PROT_READ | PROT_WRITE,
154 	    MAP_ANON, -1, 0L);
155 	if (blob_high != addr)
156 		printf("NOTICE: blob_high is at %p, not at %p\n", blob_high,
157 		    addr);
158 
159 #if TYPE == Call
160 	return (test_call(blob_high, blob_low));
161 #elif TYPE == Cond
162   #if VAR == Forward
163 	return (test_cond(PRED - 1, blob_low, blob_high));
164   #elif VAR == Backward
165 	return (test_cond(PRED - 1, blob_high, blob_low));
166   #else
167 	return (1);
168   #endif
169 #else
170 	return (1);
171 #endif
172 }
173