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