|  | /* memory.c -- Memory accessor functions for the AArch64 simulator | 
|  |  | 
|  | Copyright (C) 2015-2021 Free Software Foundation, Inc. | 
|  |  | 
|  | Contributed by Red Hat. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | This program is free software; you can redistribute it and/or modify | 
|  | it under the terms of the GNU General Public License as published by | 
|  | the Free Software Foundation; either version 3 of the License, or | 
|  | (at your option) any later version. | 
|  |  | 
|  | This program is distributed in the hope that it will be useful, | 
|  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | GNU General Public License for more details. | 
|  |  | 
|  | You should have received a copy of the GNU General Public License | 
|  | along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include <sys/types.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  |  | 
|  | #include "libiberty.h" | 
|  |  | 
|  | #include "memory.h" | 
|  | #include "simulator.h" | 
|  |  | 
|  | #include "sim-core.h" | 
|  |  | 
|  | static inline void | 
|  | mem_error (sim_cpu *cpu, const char *message, uint64_t addr) | 
|  | { | 
|  | TRACE_MEMORY (cpu, "ERROR: %s: %" PRIx64, message, addr); | 
|  | } | 
|  |  | 
|  | /* FIXME: AArch64 requires aligned memory access if SCTRLR_ELx.A is set, | 
|  | but we are not implementing that here.  */ | 
|  | #define FETCH_FUNC64(RETURN_TYPE, ACCESS_TYPE, NAME, N)			\ | 
|  | RETURN_TYPE								\ | 
|  | aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address)		\ | 
|  | {									\ | 
|  | RETURN_TYPE val = (RETURN_TYPE) (ACCESS_TYPE)			\ | 
|  | sim_core_read_unaligned_##N (cpu, 0, read_map, address);		\ | 
|  | TRACE_MEMORY (cpu, "read of %" PRIx64 " (%d bytes) from %" PRIx64,	\ | 
|  | val, N, address);					\ | 
|  | \ | 
|  | return val;								\ | 
|  | } | 
|  |  | 
|  | FETCH_FUNC64 (uint64_t, uint64_t, u64, 8) | 
|  | FETCH_FUNC64 (int64_t,   int64_t, s64, 8) | 
|  |  | 
|  | #define FETCH_FUNC32(RETURN_TYPE, ACCESS_TYPE, NAME, N)			\ | 
|  | RETURN_TYPE								\ | 
|  | aarch64_get_mem_##NAME (sim_cpu *cpu, uint64_t address)		\ | 
|  | {									\ | 
|  | RETURN_TYPE val = (RETURN_TYPE) (ACCESS_TYPE)			\ | 
|  | sim_core_read_unaligned_##N (cpu, 0, read_map, address);		\ | 
|  | TRACE_MEMORY (cpu, "read of %8x (%d bytes) from %" PRIx64,		\ | 
|  | val, N, address);					\ | 
|  | \ | 
|  | return val;								\ | 
|  | } | 
|  |  | 
|  | FETCH_FUNC32 (uint32_t, uint32_t, u32, 4) | 
|  | FETCH_FUNC32 (int32_t,   int32_t, s32, 4) | 
|  | FETCH_FUNC32 (uint32_t, uint16_t, u16, 2) | 
|  | FETCH_FUNC32 (int32_t,   int16_t, s16, 2) | 
|  | FETCH_FUNC32 (uint32_t,  uint8_t, u8, 1) | 
|  | FETCH_FUNC32 (int32_t,    int8_t, s8, 1) | 
|  |  | 
|  | void | 
|  | aarch64_get_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister *a) | 
|  | { | 
|  | a->v[0] = sim_core_read_unaligned_8 (cpu, 0, read_map, address); | 
|  | a->v[1] = sim_core_read_unaligned_8 (cpu, 0, read_map, address + 8); | 
|  | } | 
|  |  | 
|  | /* FIXME: Aarch64 requires aligned memory access if SCTRLR_ELx.A is set, | 
|  | but we are not implementing that here.  */ | 
|  | #define STORE_FUNC(TYPE, NAME, N)					\ | 
|  | void									\ | 
|  | aarch64_set_mem_##NAME (sim_cpu *cpu, uint64_t address, TYPE value)	\ | 
|  | {									\ | 
|  | TRACE_MEMORY (cpu,							\ | 
|  | "write of %" PRIx64 " (%d bytes) to %" PRIx64,	\ | 
|  | (uint64_t) value, N, address);			\ | 
|  | \ | 
|  | sim_core_write_unaligned_##N (cpu, 0, write_map, address, value);	\ | 
|  | } | 
|  |  | 
|  | STORE_FUNC (uint64_t, u64, 8) | 
|  | STORE_FUNC (int64_t,  s64, 8) | 
|  | STORE_FUNC (uint32_t, u32, 4) | 
|  | STORE_FUNC (int32_t,  s32, 4) | 
|  | STORE_FUNC (uint16_t, u16, 2) | 
|  | STORE_FUNC (int16_t,  s16, 2) | 
|  | STORE_FUNC (uint8_t,  u8, 1) | 
|  | STORE_FUNC (int8_t,   s8, 1) | 
|  |  | 
|  | void | 
|  | aarch64_set_mem_long_double (sim_cpu *cpu, uint64_t address, FRegister a) | 
|  | { | 
|  | TRACE_MEMORY (cpu, | 
|  | "write of long double %" PRIx64 " %" PRIx64 " to %" PRIx64, | 
|  | a.v[0], a.v[1], address); | 
|  |  | 
|  | sim_core_write_unaligned_8 (cpu, 0, write_map, address, a.v[0]); | 
|  | sim_core_write_unaligned_8 (cpu, 0, write_map, address + 8, a.v[1]); | 
|  | } | 
|  |  | 
|  | void | 
|  | aarch64_get_mem_blk (sim_cpu *  cpu, | 
|  | uint64_t   address, | 
|  | char *     buffer, | 
|  | unsigned   length) | 
|  | { | 
|  | unsigned len; | 
|  |  | 
|  | len = sim_core_read_buffer (CPU_STATE (cpu), cpu, read_map, | 
|  | buffer, address, length); | 
|  | if (len == length) | 
|  | return; | 
|  |  | 
|  | memset (buffer, 0, length); | 
|  | if (cpu) | 
|  | mem_error (cpu, "read of non-existant mem block at", address); | 
|  |  | 
|  | sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu), | 
|  | sim_stopped, SIM_SIGBUS); | 
|  | } | 
|  |  | 
|  | const char * | 
|  | aarch64_get_mem_ptr (sim_cpu *cpu, uint64_t address) | 
|  | { | 
|  | char *addr = sim_core_trans_addr (CPU_STATE (cpu), cpu, read_map, address); | 
|  |  | 
|  | if (addr == NULL) | 
|  | { | 
|  | mem_error (cpu, "request for non-existant mem addr of", address); | 
|  | sim_engine_halt (CPU_STATE (cpu), cpu, NULL, aarch64_get_PC (cpu), | 
|  | sim_stopped, SIM_SIGBUS); | 
|  | } | 
|  |  | 
|  | return addr; | 
|  | } | 
|  |  | 
|  | /* We implement a combined stack and heap.  That way the sbrk() | 
|  | function in libgloss/aarch64/syscalls.c has a chance to detect | 
|  | an out-of-memory condition by noticing a stack/heap collision. | 
|  |  | 
|  | The heap starts at the end of loaded memory and carries on up | 
|  | to an arbitary 2Gb limit.  */ | 
|  |  | 
|  | uint64_t | 
|  | aarch64_get_heap_start (sim_cpu *cpu) | 
|  | { | 
|  | uint64_t heap = trace_sym_value (CPU_STATE (cpu), "end"); | 
|  |  | 
|  | if (heap == 0) | 
|  | heap = trace_sym_value (CPU_STATE (cpu), "_end"); | 
|  | if (heap == 0) | 
|  | { | 
|  | heap = STACK_TOP - 0x100000; | 
|  | sim_io_eprintf (CPU_STATE (cpu), | 
|  | "Unable to find 'end' symbol - using addr based " | 
|  | "upon stack instead %" PRIx64 "\n", | 
|  | heap); | 
|  | } | 
|  | return heap; | 
|  | } | 
|  |  | 
|  | uint64_t | 
|  | aarch64_get_stack_start (sim_cpu *cpu) | 
|  | { | 
|  | if (aarch64_get_heap_start (cpu) >= STACK_TOP) | 
|  | mem_error (cpu, "executable is too big", aarch64_get_heap_start (cpu)); | 
|  | return STACK_TOP; | 
|  | } |