/[qemu]/qemu/dyngen.h
ViewVC logotype

Diff of /qemu/dyngen.h

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.7 by bellard, Mon Jan 3 23:40:55 2005 UTC revision 1.8 by bellard, Thu Apr 7 22:20:28 2005 UTC
# Line 43  static inline void flush_icache_range(un Line 43  static inline void flush_icache_range(un
43  #ifdef __ia64__  #ifdef __ia64__
44  static inline void flush_icache_range(unsigned long start, unsigned long stop)  static inline void flush_icache_range(unsigned long start, unsigned long stop)
45  {  {
46        while (start < stop) {
47            asm volatile ("fc %0" :: "r"(start));
48            start += 32;
49        }
50        asm volatile (";;sync.i;;srlz.i;;");
51  }  }
52  #endif  #endif
53    
# Line 204  static uint8_t *arm_flush_ldr(uint8_t *g Line 209  static uint8_t *arm_flush_ldr(uint8_t *g
209  }  }
210    
211  #endif /* __arm__ */  #endif /* __arm__ */
212    
213    #ifdef __ia64
214    
215    
216    /* Patch instruction with "val" where "mask" has 1 bits. */
217    static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
218    {
219        uint64_t m0, m1, v0, v1, b0, b1, *b = (uint64_t *) (insn_addr & -16);
220    #   define insn_mask ((1UL << 41) - 1)
221        unsigned long shift;
222    
223        b0 = b[0]; b1 = b[1];
224        shift = 5 + 41 * (insn_addr % 16); /* 5 template, 3 x 41-bit insns */
225        if (shift >= 64) {
226            m1 = mask << (shift - 64);
227            v1 = val << (shift - 64);
228        } else {
229            m0 = mask << shift; m1 = mask >> (64 - shift);
230            v0 = val  << shift; v1 = val >> (64 - shift);
231            b[0] = (b0 & ~m0) | (v0 & m0);
232        }
233        b[1] = (b1 & ~m1) | (v1 & m1);
234    }
235    
236    static inline void ia64_patch_imm60 (uint64_t insn_addr, uint64_t val)
237    {
238            ia64_patch(insn_addr,
239                       0x011ffffe000UL,
240                       (  ((val & 0x0800000000000000UL) >> 23) /* bit 59 -> 36 */
241                        | ((val & 0x00000000000fffffUL) << 13) /* bit 0 -> 13 */));
242            ia64_patch(insn_addr - 1, 0x1fffffffffcUL, val >> 18);
243    }
244    
245    static inline void ia64_imm64 (void *insn, uint64_t val)
246    {
247        /* Ignore the slot number of the relocation; GCC and Intel
248           toolchains differed for some time on whether IMM64 relocs are
249           against slot 1 (Intel) or slot 2 (GCC).  */
250        uint64_t insn_addr = (uint64_t) insn & ~3UL;
251    
252        ia64_patch(insn_addr + 2,
253                   0x01fffefe000UL,
254                   (  ((val & 0x8000000000000000UL) >> 27) /* bit 63 -> 36 */
255                    | ((val & 0x0000000000200000UL) <<  0) /* bit 21 -> 21 */
256                    | ((val & 0x00000000001f0000UL) <<  6) /* bit 16 -> 22 */
257                    | ((val & 0x000000000000ff80UL) << 20) /* bit  7 -> 27 */
258                    | ((val & 0x000000000000007fUL) << 13) /* bit  0 -> 13 */)
259                );
260        ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22);
261    }
262    
263    static inline void ia64_imm60b (void *insn, uint64_t val)
264    {
265        /* Ignore the slot number of the relocation; GCC and Intel
266           toolchains differed for some time on whether IMM64 relocs are
267           against slot 1 (Intel) or slot 2 (GCC).  */
268        uint64_t insn_addr = (uint64_t) insn & ~3UL;
269    
270        if (val + ((uint64_t) 1 << 59) >= (1UL << 60))
271            fprintf(stderr, "%s: value %ld out of IMM60 range\n",
272                    __FUNCTION__, (int64_t) val);
273        ia64_patch_imm60(insn_addr + 2, val);
274    }
275    
276    static inline void ia64_imm22 (void *insn, uint64_t val)
277    {
278        if (val + (1 << 21) >= (1 << 22))
279            fprintf(stderr, "%s: value %li out of IMM22 range\n",
280                    __FUNCTION__, (int64_t)val);
281        ia64_patch((uint64_t) insn, 0x01fffcfe000UL,
282                   (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
283                    | ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
284                    | ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
285                    | ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
286    }
287    
288    /* Like ia64_imm22(), but also clear bits 20-21.  For addl, this has
289       the effect of turning "addl rX=imm22,rY" into "addl
290       rX=imm22,r0".  */
291    static inline void ia64_imm22_r0 (void *insn, uint64_t val)
292    {
293        if (val + (1 << 21) >= (1 << 22))
294            fprintf(stderr, "%s: value %li out of IMM22 range\n",
295                    __FUNCTION__, (int64_t)val);
296        ia64_patch((uint64_t) insn, 0x01fffcfe000UL | (0x3UL << 20),
297                   (  ((val & 0x200000UL) << 15) /* bit 21 -> 36 */
298                    | ((val & 0x1f0000UL) <<  6) /* bit 16 -> 22 */
299                    | ((val & 0x00ff80UL) << 20) /* bit  7 -> 27 */
300                    | ((val & 0x00007fUL) << 13) /* bit  0 -> 13 */));
301    }
302    
303    static inline void ia64_imm21b (void *insn, uint64_t val)
304    {
305        if (val + (1 << 20) >= (1 << 21))
306            fprintf(stderr, "%s: value %li out of IMM21b range\n",
307                    __FUNCTION__, (int64_t)val);
308        ia64_patch((uint64_t) insn, 0x11ffffe000UL,
309                   (  ((val & 0x100000UL) << 16) /* bit 20 -> 36 */
310                    | ((val & 0x0fffffUL) << 13) /* bit  0 -> 13 */));
311    }
312    
313    static inline void ia64_nop_b (void *insn)
314    {
315        ia64_patch((uint64_t) insn, (1UL << 41) - 1, 2UL << 37);
316    }
317    
318    static inline void ia64_ldxmov(void *insn, uint64_t val)
319    {
320        if (val + (1 << 21) < (1 << 22))
321            ia64_patch((uint64_t) insn, 0x1fff80fe000UL, 8UL << 37);
322    }
323    
324    static inline int ia64_patch_ltoff(void *insn, uint64_t val,
325                                       int relaxable)
326    {
327        if (relaxable && (val + (1 << 21) < (1 << 22))) {
328            ia64_imm22_r0(insn, val);
329            return 0;
330        }
331        return 1;
332    }
333    
334    struct ia64_fixup {
335        struct ia64_fixup *next;
336        void *addr;                 /* address that needs to be patched */
337        long value;
338    };
339    
340    #define IA64_PLT(insn, plt_index)                       \
341    do {                                                    \
342        struct ia64_fixup *fixup = alloca(sizeof(*fixup));  \
343        fixup->next = plt_fixes;                            \
344        plt_fixes = fixup;                                  \
345        fixup->addr = (insn);                               \
346        fixup->value = (plt_index);                         \
347        plt_offset[(plt_index)] = 1;                        \
348    } while (0)
349    
350    #define IA64_LTOFF(insn, val, relaxable)                        \
351    do {                                                            \
352        if (ia64_patch_ltoff(insn, val, relaxable)) {               \
353            struct ia64_fixup *fixup = alloca(sizeof(*fixup));      \
354            fixup->next = ltoff_fixes;                              \
355            ltoff_fixes = fixup;                                    \
356            fixup->addr = (insn);                                   \
357            fixup->value = (val);                                   \
358        }                                                           \
359    } while (0)
360    
361    static inline void ia64_apply_fixes (uint8_t **gen_code_pp,
362                                         struct ia64_fixup *ltoff_fixes,
363                                         uint64_t gp,
364                                         struct ia64_fixup *plt_fixes,
365                                         int num_plts,
366                                         unsigned long *plt_target,
367                                         unsigned int *plt_offset)
368    {
369        static const uint8_t plt_bundle[] = {
370            0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; movl r1=GP */
371            0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x60,
372    
373            0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /* nop 0; brl IP */
374            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0
375        };
376        uint8_t *gen_code_ptr = *gen_code_pp, *plt_start, *got_start, *vp;
377        struct ia64_fixup *fixup;
378        unsigned int offset = 0;
379        struct fdesc {
380            long ip;
381            long gp;
382        } *fdesc;
383        int i;
384    
385        if (plt_fixes) {
386            plt_start = gen_code_ptr;
387    
388            for (i = 0; i < num_plts; ++i) {
389                if (plt_offset[i]) {
390                    plt_offset[i] = offset;
391                    offset += sizeof(plt_bundle);
392    
393                    fdesc = (struct fdesc *) plt_target[i];
394                    memcpy(gen_code_ptr, plt_bundle, sizeof(plt_bundle));
395                    ia64_imm64 (gen_code_ptr + 0x02, fdesc->gp);
396                    ia64_imm60b(gen_code_ptr + 0x12,
397                                (fdesc->ip - (long) (gen_code_ptr + 0x10)) >> 4);
398                    gen_code_ptr += sizeof(plt_bundle);
399                }
400            }
401    
402            for (fixup = plt_fixes; fixup; fixup = fixup->next)
403                ia64_imm21b(fixup->addr,
404                            ((long) plt_start + plt_offset[fixup->value]
405                             - ((long) fixup->addr & ~0xf)) >> 4);
406        }
407    
408        got_start = gen_code_ptr;
409    
410        /* First, create the GOT: */
411        for (fixup = ltoff_fixes; fixup; fixup = fixup->next) {
412            /* first check if we already have this value in the GOT: */
413            for (vp = got_start; vp < gen_code_ptr; ++vp)
414                if (*(uint64_t *) vp == fixup->value)
415                    break;
416            if (vp == gen_code_ptr) {
417                /* Nope, we need to put the value in the GOT: */
418                *(uint64_t *) vp = fixup->value;
419                gen_code_ptr += 8;
420            }
421            ia64_imm22(fixup->addr, (long) vp - gp);
422        }
423        *gen_code_pp = gen_code_ptr;
424    }
425    
426    #endif

Legend:
Removed from v.1.7  
changed lines
  Added in v.1.8

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26