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