1160416Smarcel/*
2160416Smarcel * Copyright (c) 2006 Marcel Moolenaar
3160416Smarcel * All rights reserved.
4160416Smarcel *
5160416Smarcel * Redistribution and use in source and binary forms, with or without
6160416Smarcel * modification, are permitted provided that the following conditions
7160416Smarcel * are met:
8160416Smarcel *
9160416Smarcel * 1. Redistributions of source code must retain the above copyright
10160416Smarcel *    notice, this list of conditions and the following disclaimer.
11160416Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12160416Smarcel *    notice, this list of conditions and the following disclaimer in the
13160416Smarcel *    documentation and/or other materials provided with the distribution.
14160416Smarcel *
15160416Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16160416Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17160416Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18160416Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19160416Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20160416Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21160416Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22160416Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23160416Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24160416Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25160416Smarcel *
26160416Smarcel * $FreeBSD$
27160416Smarcel */
28160416Smarcel
29160416Smarcel#include <sys/mman.h>
30160416Smarcel#include <stdio.h>
31160416Smarcel#include <string.h>
32160416Smarcel
33160416Smarcel/* Supported long branch types */
34160416Smarcel#define	Call		1
35160416Smarcel#define	Cond		2
36160416Smarcel
37160416Smarcel/* Supported predicates */
38160416Smarcel#define	False		1
39160416Smarcel#define	True		2
40160416Smarcel
41160416Smarcel/* Supported variations */
42160416Smarcel#define	Backward	1
43160416Smarcel#define	Forward		2
44160416Smarcel
45160416Smarcel#if TYPE == 0 || PRED == 0 || VAR == 0
46160416Smarcel#error Define TYPE, PRED and/or VAR
47160416Smarcel#endif
48160416Smarcel
49160416Smarcelunion bundle {
50160416Smarcel	unsigned char bytes[16];
51160416Smarcel	long double _align;
52160416Smarcel};
53160416Smarcel
54160416Smarcel/*
55160416Smarcel * Machine code of a bundle containing a long branch. The predicate of the
56160416Smarcel * long branch is the result of the compare in the first slot.
57160416Smarcel * The assembly of the bundle is:
58160416Smarcel *	{	.mlx
59160416Smarcel *		cmp.eq		p0,p15= <PREDICATE>,r0
60160416Smarcel *	  (p15)	brl.few		<TARGET> ;;
61160416Smarcel *	}
62160416Smarcel * the predicate is written to bit 18:1
63160416Smarcel * The branch target is written to bits 100:20, 48:39 and 123:1
64160416Smarcel */
65160416Smarcelunsigned char mc_brl_cond[16] = {
66160416Smarcel	0x05, 0x00, 0x00, 0x00, 0x0f, 0x39,
67160416Smarcel	0x00, 0x00, 0x00, 0x00, 0x80, 0x07,
68160416Smarcel	0x00, 0x00, 0x00, 0xc0
69160416Smarcel};
70160416Smarcel
71160416Smarcel/*
72160416Smarcel * Machine code of the epilogue of a typical function returning an integer.
73160416Smarcel * The assembly of the epilogue is:
74160416Smarcel *	{	.mib
75160416Smarcel *		nop.m		0
76160416Smarcel *		addl		r8 = <RETVAL>, r0
77160416Smarcel *		br.ret.sptk.few b0 ;;
78160416Smarcel *	}
79160416Smarcel * The return value is written to bits 59:7, 73:9, 68:5, and 82:1.
80160416Smarcel */
81160416Smarcelunsigned char mc_epilogue[16] = {
82160416Smarcel	0x11, 0x00, 0x00, 0x00, 0x01, 0x00,
83160416Smarcel	0x80, 0x00, 0x00, 0x00, 0x48, 0x80,
84160416Smarcel	0x00, 0x00, 0x84, 0x00
85160416Smarcel};
86160416Smarcel
87160416Smarcelvoid
88160416Smarcelmc_patch(union bundle *b, unsigned long val, int start, int len)
89160416Smarcel{
90160416Smarcel	unsigned long mask;
91160416Smarcel	int bit, byte, run;
92160416Smarcel
93160416Smarcel	byte = start >> 3;
94160416Smarcel	bit = start & 7;
95160416Smarcel	while (len) {
96160416Smarcel		run = ((len > (8 - bit)) ? (8 - bit) : len);
97160416Smarcel		mask = (1UL << run) - 1UL;
98160416Smarcel		b->bytes[byte] |= (val & mask) << bit;
99160416Smarcel		val >>= run;
100160416Smarcel		len -= run;
101160416Smarcel		byte++;
102160416Smarcel		bit = 0;
103160416Smarcel	}
104160416Smarcel}
105160416Smarcel
106160416Smarcelvoid
107160416Smarcelassemble_brl_cond(union bundle *b, int pred, unsigned long tgt)
108160416Smarcel{
109160416Smarcel	unsigned long iprel;
110160416Smarcel
111160416Smarcel	iprel = tgt - (unsigned long)b;
112160416Smarcel	memcpy(b->bytes, mc_brl_cond, sizeof(mc_brl_cond));
113160416Smarcel	mc_patch(b, pred ? 1 : 0, 18, 1);
114160416Smarcel	mc_patch(b, iprel >> 4, 100, 20);
115160416Smarcel	mc_patch(b, iprel >> 24, 48, 39);
116160416Smarcel	mc_patch(b, iprel >> 63, 123, 1);
117160416Smarcel}
118160416Smarcel
119160416Smarcelvoid
120160416Smarcelassemble_epilogue(union bundle *b, int retval)
121160416Smarcel{
122160416Smarcel	memcpy(b->bytes, mc_epilogue, sizeof(mc_epilogue));
123160416Smarcel	mc_patch(b, retval, 59, 7);
124160416Smarcel	mc_patch(b, retval >> 7, 73, 9);
125160416Smarcel	mc_patch(b, retval >> 16, 68, 5);
126160416Smarcel	mc_patch(b, retval >> 21, 82, 1);
127160416Smarcel}
128160416Smarcel
129160416Smarcelint
130160416Smarceldoit(void *addr)
131160416Smarcel{
132160416Smarcel	asm("mov b6 = %0; br.sptk b6;;" :: "r"(addr));
133160416Smarcel	return 1;
134160416Smarcel}
135160416Smarcel
136160416Smarcelint
137160416Smarceltest_cond(int pred, union bundle *src, union bundle *dst)
138160416Smarcel{
139160416Smarcel	assemble_epilogue(dst, pred ? 0 : 2);
140160416Smarcel	assemble_brl_cond(src, pred ? 1 : 0, (unsigned long)dst);
141160416Smarcel	assemble_epilogue(src + 1, !pred ? 0 : 2);
142160416Smarcel	return doit(src);
143160416Smarcel}
144160416Smarcel
145160416Smarcelint
146160416Smarcelmain()
147160416Smarcel{
148160416Smarcel	static union bundle blob_low[2];
149160416Smarcel	union bundle *blob_high;
150160416Smarcel	void *addr;
151160416Smarcel
152160416Smarcel	addr = (void *)0x7FFFFFFF00000000L;
153160416Smarcel	blob_high = mmap(addr, 32, PROT_EXEC | PROT_READ | PROT_WRITE,
154160416Smarcel	    MAP_ANON, -1, 0L);
155160416Smarcel	if (blob_high != addr)
156160416Smarcel		printf("NOTICE: blob_high is at %p, not at %p\n", blob_high,
157160416Smarcel		    addr);
158160416Smarcel
159160416Smarcel#if TYPE == Call
160160416Smarcel	return (test_call(blob_high, blob_low));
161160416Smarcel#elif TYPE == Cond
162160416Smarcel  #if VAR == Forward
163160416Smarcel	return (test_cond(PRED - 1, blob_low, blob_high));
164160416Smarcel  #elif VAR == Backward
165160416Smarcel	return (test_cond(PRED - 1, blob_high, blob_low));
166160416Smarcel  #else
167160416Smarcel	return (1);
168160416Smarcel  #endif
169160416Smarcel#else
170160416Smarcel	return (1);
171160416Smarcel#endif
172160416Smarcel}
173