Wean gdb and sim off private libbfd.h header
[external/binutils.git] / sim / aarch64 / memory.c
1 /* memory.c -- Memory accessor functions for the AArch64 simulator
2
3    Copyright (C) 2015-2016 Free Software Foundation, Inc.
4
5    Contributed by Red Hat.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "config.h"
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "bfd.h"
29 #include "libiberty.h"
30 #include "elf/internal.h"
31 #include "elf/common.h"
32
33 #include "memory.h"
34 #include "simulator.h"
35
36 #include "sim-core.h"
37
38 static inline void
39 mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
40 {
41   TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr);
42 }
43
44 /* FIXME: AArch64 requires aligned memory access if SCTRLR_ELx.A is set,
45    but we are not implementing that here.  */
46 #define FETCH_FUNC64(RETURN_TYPE, ACCESS_TYPE, NAME, N)                 \
47   RETURN_TYPE                                                           \
48   aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address)               \
49   {                                                                     \
50     RETURN_TYPE val = (RETURN_TYPE) (ACCESS_TYPE)                       \
51       sim_core_read_unaligned_##N (cpu, 0, read_map, address);          \
52     TRACE_MEMORY (cpu, "read of %" PRIx64 " (%d bytes) from %" PRIx64,  \
53                   val, N, address);                                     \
54                                                                         \
55     return val;                                                         \
56   }
57
58 FETCH_FUNC64 (uint64_t, uint64_t, u64, 8)
59 FETCH_FUNC64 (int64_t,   int64_t, s64, 8)
60
61 #define FETCH_FUNC32(RETURN_TYPE, ACCESS_TYPE, NAME, N)                 \
62   RETURN_TYPE                                                           \
63   aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address)               \
64   {                                                                     \
65     RETURN_TYPE val = (RETURN_TYPE) (ACCESS_TYPE)                       \
66       sim_core_read_unaligned_##N (cpu, 0, read_map, address);          \
67     TRACE_MEMORY (cpu, "read of %8x (%d bytes) from %" PRIx64,          \
68                   val, N, address);                                     \
69                                                                         \
70     return val;                                                         \
71   }
72
73 FETCH_FUNC32 (uint32_t, uint32_t, u32, 4)
74 FETCH_FUNC32 (int32_t,   int32_t, s32, 4)
75 FETCH_FUNC32 (uint32_t, uint16_t, u16, 2)
76 FETCH_FUNC32 (int32_t,   int16_t, s16, 2)
77 FETCH_FUNC32 (uint32_t,  uint8_t, u8, 1)
78 FETCH_FUNC32 (int32_t,    int8_t, s8, 1)
79
80 void
81 aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a)
82 {
83   a->v[0] = sim_core_read_unaligned_8 (cpu, 0, read_map, address);
84   a->v[1] = sim_core_read_unaligned_8 (cpu, 0, read_map, address + 8);
85 }
86
87 /* FIXME: Aarch64 requires aligned memory access if SCTRLR_ELx.A is set,
88    but we are not implementing that here.  */
89 #define STORE_FUNC(TYPE, NAME, N)                                       \
90   void                                                                  \
91   aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value)   \
92   {                                                                     \
93     TRACE_MEMORY (cpu,                                                  \
94                   "write of %" PRIx64 " (%d bytes) to %" PRIx64,        \
95                   (uint64_t) value, N, address);                        \
96                                                                         \
97     sim_core_write_unaligned_##N (cpu, 0, write_map, address, value);   \
98   }
99
100 STORE_FUNC (uint64_t, u64, 8)
101 STORE_FUNC (int64_t,  s64, 8)
102 STORE_FUNC (uint32_t, u32, 4)
103 STORE_FUNC (int32_t,  s32, 4)
104 STORE_FUNC (uint16_t, u16, 2)
105 STORE_FUNC (int16_t,  s16, 2)
106 STORE_FUNC (uint8_t,  u8, 1)
107 STORE_FUNC (int8_t,   s8, 1)
108
109 void
110 aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a)
111 {
112   TRACE_MEMORY (cpu,
113                 "write of long double %" PRIx64 " %" PRIx64 " to %" PRIx64,
114                 a.v[0], a.v[1], address);
115
116   sim_core_write_unaligned_8 (cpu, 0, write_map, address, a.v[0]);
117   sim_core_write_unaligned_8 (cpu, 0, write_map, address + 8, a.v[1]);
118 }
119
120 void
121 aarch64_get_mem_blk (sim_cpu *  cpu,
122                      uint64_t   address,
123                      char *     buffer,
124                      unsigned   length)
125 {
126   unsigned len;
127
128   len = sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
129                               buffer, address, length);
130   if (len == length)
131     return;
132
133   memset (buffer, 0, length);
134   if (cpu)
135     mem_error (cpu, "read of non-existant mem block at", address);
136
137   sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
138                    sim_stopped, SIM_SIGBUS);
139 }
140
141 const char *
142 aarch64_get_mem_ptr (sim_cpu *cpu, uint64_t address)
143 {
144   char *addr = sim_core_trans_addr (CPU_STATE (cpu), cpu, read_map, address);
145
146   if (addr == NULL)
147     {
148       mem_error (cpu, "request for non-existant mem addr of", address);
149       sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
150                        sim_stopped, SIM_SIGBUS);
151     }
152
153   return addr;
154 }
155
156 /* We implement a combined stack and heap.  That way the sbrk()
157    function in libgloss/aarch64/syscalls.c has a chance to detect
158    an out-of-memory condition by noticing a stack/heap collision.
159
160    The heap starts at the end of loaded memory and carries on up
161    to an arbitary 2Gb limit.  */
162
163 uint64_t
164 aarch64_get_heap_start (sim_cpu *cpu)
165 {
166   uint64_t heap = aarch64_get_sym_value ("end");
167
168   if (heap == 0)
169     heap = aarch64_get_sym_value ("_end");
170   if (heap == 0)
171     {
172       heap = STACK_TOP - 0x100000;
173       sim_io_eprintf (CPU_STATE (cpu),
174                       "Unable to find 'end' symbol - using addr based "
175                       "upon stack instead %" PRIx64 "\n",
176                       heap);
177     }
178   return heap;
179 }
180
181 uint64_t
182 aarch64_get_stack_start (sim_cpu *cpu)
183 {
184   if (aarch64_get_heap_start (cpu) >= STACK_TOP)
185     mem_error (cpu, "executable is too big", aarch64_get_heap_start (cpu));
186   return STACK_TOP;
187 }