]>
Commit | Line | Data |
---|---|---|
2e8cf49e NC |
1 | /* memory.c -- Memory accessor functions for the AArch64 simulator |
2 | ||
1d506c26 | 3 | Copyright (C) 2015-2024 Free Software Foundation, Inc. |
2e8cf49e NC |
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 | ||
6df01ab8 MF |
22 | /* This must come before any other includes. */ |
23 | #include "defs.h" | |
24 | ||
2e8cf49e NC |
25 | #include <sys/types.h> |
26 | #include <stdio.h> | |
27 | #include <stdlib.h> | |
28 | #include <string.h> | |
29 | ||
2e8cf49e | 30 | #include "libiberty.h" |
2e8cf49e NC |
31 | |
32 | #include "memory.h" | |
33 | #include "simulator.h" | |
34 | ||
35 | #include "sim-core.h" | |
1fef66b0 | 36 | #include "sim-signal.h" |
2e8cf49e NC |
37 | |
38 | static inline void | |
39 | mem_error (sim_cpu *cpu, const char *message, uint64_t addr) | |
40 | { | |
2e8cf49e NC |
41 | TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr); |
42 | } | |
43 | ||
7517e550 | 44 | /* FIXME: AArch64 requires aligned memory access if SCTRLR_ELx.A is set, |
5ab6d79e | 45 | but we are not implementing that here. */ |
7517e550 | 46 | #define FETCH_FUNC64(RETURN_TYPE, ACCESS_TYPE, NAME, N) \ |
2e8cf49e NC |
47 | RETURN_TYPE \ |
48 | aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address) \ | |
49 | { \ | |
7517e550 NC |
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); \ | |
e101a78b NC |
69 | \ |
70 | return val; \ | |
2e8cf49e NC |
71 | } |
72 | ||
7517e550 NC |
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) | |
2e8cf49e NC |
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 | ||
5ab6d79e NC |
87 | /* FIXME: Aarch64 requires aligned memory access if SCTRLR_ELx.A is set, |
88 | but we are not implementing that here. */ | |
2e8cf49e NC |
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 | ||
5ab6d79e NC |
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) | |
2e8cf49e NC |
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 | { | |
5357150c | 166 | uint64_t heap = trace_sym_value (CPU_STATE (cpu), "end"); |
2e8cf49e NC |
167 | |
168 | if (heap == 0) | |
5357150c | 169 | heap = trace_sym_value (CPU_STATE (cpu), "_end"); |
2e8cf49e NC |
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 | } |