summaryrefslogtreecommitdiff
path: root/include/asm-v850/flat.h
blob: 17f0ea566611bfffe443462903333b7e49c49901 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * include/asm-v850/flat.h -- uClinux flat-format executables
 *
 *  Copyright (C) 2002,03  NEC Electronics Corporation
 *  Copyright (C) 2002,03  Miles Bader <miles@gnu.org>
 *
 * This file is subject to the terms and conditions of the GNU General
 * Public License.  See the file COPYING in the main directory of this
 * archive for more details.
 *
 * Written by Miles Bader <miles@gnu.org>
 */

#ifndef __V850_FLAT_H__
#define __V850_FLAT_H__

/* The amount by which a relocation can exceed the program image limits
   without being regarded as an error.  On the v850, the relocations of
   some base-pointers can be offset by 0x8000 (to allow better usage of the
   space offered by 16-bit signed offsets -- in most cases the offsets used
   with such a base-pointer will be negative).  */

#define	flat_reloc_valid(reloc, size)	((reloc) <= (size + 0x8000))

#define	flat_stack_align(sp)		/* nothing needed */
#define	flat_argvp_envp_on_stack()	0
#define	flat_old_ram_flag(flags)	(flags)
#define	flat_set_persistent(relval, p)	0

/* We store the type of relocation in the top 4 bits of the `relval.' */

/* Convert a relocation entry into an address.  */
static inline unsigned long
flat_get_relocate_addr (unsigned long relval)
{
	return relval & 0x0fffffff; /* Mask out top 4-bits */
}

#define flat_v850_get_reloc_type(relval) ((relval) >> 28)

#define FLAT_V850_R_32		0 /* Normal 32-bit reloc */
#define FLAT_V850_R_HI16S_LO15	1 /* High 16-bits + signed 15-bit low field */
#define FLAT_V850_R_HI16S_LO16	2 /* High 16-bits + signed 16-bit low field */

/* Extract the address to be relocated from the symbol reference at RP;
   RELVAL is the raw relocation-table entry from which RP is derived.
   For the v850, RP should always be half-word aligned.  */
static inline unsigned long flat_get_addr_from_rp (unsigned long *rp,
						   unsigned long relval,
						   unsigned long flags,
						   unsigned long *persistent)
{
	short *srp = (short *)rp;

	switch (flat_v850_get_reloc_type (relval))
	{
	case FLAT_V850_R_32:
		/* Simple 32-bit address.  */
		return srp[0] | (srp[1] << 16);

	case FLAT_V850_R_HI16S_LO16:
		/* The high and low halves of the address are in the 16
		   bits at RP, and the 2nd word of the 32-bit instruction
		   following that, respectively.  The low half is _signed_
		   so we have to sign-extend it and add it to the upper
		   half instead of simply or-ing them together.

		   Unlike most relocated address, this one is stored in
		   native (little-endian) byte-order to avoid problems with
		   trashing the low-order bit, so we have to convert to
		   network-byte-order before returning, as that's what the
		   caller expects.  */
		return htonl ((srp[0] << 16) + srp[2]);

	case FLAT_V850_R_HI16S_LO15:
		/* The high and low halves of the address are in the 16
		   bits at RP, and the upper 15 bits of the 2nd word of the
		   32-bit instruction following that, respectively.  The
		   low half is _signed_ so we have to sign-extend it and
		   add it to the upper half instead of simply or-ing them
		   together.  The lowest bit is always zero.

		   Unlike most relocated address, this one is stored in
		   native (little-endian) byte-order to avoid problems with
		   trashing the low-order bit, so we have to convert to
		   network-byte-order before returning, as that's what the
		   caller expects.  */
		return htonl ((srp[0] << 16) + (srp[2] & ~0x1));

	default:
		return ~0;	/* bogus value */
	}
}

/* Insert the address ADDR into the symbol reference at RP;
   RELVAL is the raw relocation-table entry from which RP is derived.
   For the v850, RP should always be half-word aligned.  */
static inline void flat_put_addr_at_rp (unsigned long *rp, unsigned long addr,
					unsigned long relval)
{
	short *srp = (short *)rp;

	switch (flat_v850_get_reloc_type (relval)) {
	case FLAT_V850_R_32:
		/* Simple 32-bit address.  */
		srp[0] = addr & 0xFFFF;
		srp[1] = (addr >> 16);
		break;

	case FLAT_V850_R_HI16S_LO16:
		/* The high and low halves of the address are in the 16
		   bits at RP, and the 2nd word of the 32-bit instruction
		   following that, respectively.  The low half is _signed_
		   so we must carry its sign bit to the upper half before
		   writing the upper half.  */
		srp[0] = (addr >> 16) + ((addr >> 15) & 0x1);
		srp[2] = addr & 0xFFFF;
		break;

	case FLAT_V850_R_HI16S_LO15:
		/* The high and low halves of the address are in the 16
		   bits at RP, and the upper 15 bits of the 2nd word of the
		   32-bit instruction following that, respectively.  The
		   low half is _signed_ so we must carry its sign bit to
		   the upper half before writing the upper half.  The
		   lowest bit we preserve from the existing instruction.  */
		srp[0] = (addr >> 16) + ((addr >> 15) & 0x1);
		srp[2] = (addr & 0xFFFE) | (srp[2] & 0x1);
		break;
	}
}

#endif /* __V850_FLAT_H__ */