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