Home | History | Annotate | Line # | Download | only in aarch64
      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