1 /* memory.c -- Memory accessor functions for the AArch64 simulator 2 3 Copyright (C) 2015-2024 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 /* This must come before any other includes. */ 23 #include "defs.h" 24 25 #include <sys/types.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "libiberty.h" 31 32 #include "memory.h" 33 #include "simulator.h" 34 35 #include "sim-core.h" 36 #include "sim-signal.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 = trace_sym_value (CPU_STATE (cpu), "end"); 167 168 if (heap == 0) 169 heap = trace_sym_value (CPU_STATE (cpu), "_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 } 188