More AArch64 simulator improvements.
[binutils-gdb.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 "libbfd.h"
30 #include "libiberty.h"
31 #include "elf/internal.h"
32 #include "elf/common.h"
33
34 #include "memory.h"
35 #include "simulator.h"
36
37 #include "sim-core.h"
38
39 static inline void
40 mem_error (sim_cpu *cpu, const char *message, uint64_t addr)
41 {
42 TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr);
43 }
44
45 /* FIXME: Aarch64 requires aligned memory access if SCTRLR_ELx.A is set,
46 but we are not implementing that here. */
47 #define FETCH_FUNC(RETURN_TYPE, ACCESS_TYPE, NAME, N) \
48 RETURN_TYPE \
49 aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \
50 { \
51 RETURN_TYPE val = (RETURN_TYPE) sim_core_read_unaligned_##N (cpu, 0, read_map, address); \
52 TRACE_MEMORY (cpu, \
53 "read of %" PRIx64 " (%d bytes) from %" PRIx64, \
54 (uint64_t) val, N, address); \
55 \
56 return val; \
57 }
58
59 FETCH_FUNC (uint64_t, uint64_t, u64, 8)
60 FETCH_FUNC (int64_t, int64_t, s64, 8)
61 FETCH_FUNC (uint32_t, uint32_t, u32, 4)
62 FETCH_FUNC (int32_t, int32_t, s32, 4)
63 FETCH_FUNC (uint32_t, uint16_t, u16, 2)
64 FETCH_FUNC (int32_t, int16_t, s16, 2)
65 FETCH_FUNC (uint32_t, uint8_t, u8, 1)
66 FETCH_FUNC (int32_t, int8_t, s8, 1)
67
68 void
69 aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a)
70 {
71 a->v[0] = sim_core_read_unaligned_8 (cpu, 0, read_map, address);
72 a->v[1] = sim_core_read_unaligned_8 (cpu, 0, read_map, address + 8);
73 }
74
75 /* FIXME: Aarch64 requires aligned memory access if SCTRLR_ELx.A is set,
76 but we are not implementing that here. */
77 #define STORE_FUNC(TYPE, NAME, N) \
78 void \
79 aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value) \
80 { \
81 TRACE_MEMORY (cpu, \
82 "write of %" PRIx64 " (%d bytes) to %" PRIx64, \
83 (uint64_t) value, N, address); \
84 \
85 sim_core_write_unaligned_##N (cpu, 0, write_map, address, value); \
86 }
87
88 STORE_FUNC (uint64_t, u64, 8)
89 STORE_FUNC (int64_t, s64, 8)
90 STORE_FUNC (uint32_t, u32, 4)
91 STORE_FUNC (int32_t, s32, 4)
92 STORE_FUNC (uint16_t, u16, 2)
93 STORE_FUNC (int16_t, s16, 2)
94 STORE_FUNC (uint8_t, u8, 1)
95 STORE_FUNC (int8_t, s8, 1)
96
97 void
98 aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a)
99 {
100 TRACE_MEMORY (cpu,
101 "write of long double %" PRIx64 " %" PRIx64 " to %" PRIx64,
102 a.v[0], a.v[1], address);
103
104 sim_core_write_unaligned_8 (cpu, 0, write_map, address, a.v[0]);
105 sim_core_write_unaligned_8 (cpu, 0, write_map, address + 8, a.v[1]);
106 }
107
108 void
109 aarch64_get_mem_blk (sim_cpu * cpu,
110 uint64_t address,
111 char * buffer,
112 unsigned length)
113 {
114 unsigned len;
115
116 len = sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map,
117 buffer, address, length);
118 if (len == length)
119 return;
120
121 memset (buffer, 0, length);
122 if (cpu)
123 mem_error (cpu, "read of non-existant mem block at", address);
124
125 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
126 sim_stopped, SIM_SIGBUS);
127 }
128
129 const char *
130 aarch64_get_mem_ptr (sim_cpu *cpu, uint64_t address)
131 {
132 char *addr = sim_core_trans_addr (CPU_STATE (cpu), cpu, read_map, address);
133
134 if (addr == NULL)
135 {
136 mem_error (cpu, "request for non-existant mem addr of", address);
137 sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu),
138 sim_stopped, SIM_SIGBUS);
139 }
140
141 return addr;
142 }
143
144 /* We implement a combined stack and heap. That way the sbrk()
145 function in libgloss/aarch64/syscalls.c has a chance to detect
146 an out-of-memory condition by noticing a stack/heap collision.
147
148 The heap starts at the end of loaded memory and carries on up
149 to an arbitary 2Gb limit. */
150
151 uint64_t
152 aarch64_get_heap_start (sim_cpu *cpu)
153 {
154 uint64_t heap = aarch64_get_sym_value ("end");
155
156 if (heap == 0)
157 heap = aarch64_get_sym_value ("_end");
158 if (heap == 0)
159 {
160 heap = STACK_TOP - 0x100000;
161 sim_io_eprintf (CPU_STATE (cpu),
162 "Unable to find 'end' symbol - using addr based "
163 "upon stack instead %" PRIx64 "\n",
164 heap);
165 }
166 return heap;
167 }
168
169 uint64_t
170 aarch64_get_stack_start (sim_cpu *cpu)
171 {
172 if (aarch64_get_heap_start (cpu) >= STACK_TOP)
173 mem_error (cpu, "executable is too big", aarch64_get_heap_start (cpu));
174 return STACK_TOP;
175 }