xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/sim-memopt.c (revision 0d3e0572e40d81edb4fdbff937458d47b685c34c)
14e98e3e1Schristos /* Simulator memory option handling.
2*0d3e0572Schristos    Copyright (C) 1996-2024 Free Software Foundation, Inc.
34e98e3e1Schristos    Contributed by Cygnus Support.
44e98e3e1Schristos 
54e98e3e1Schristos This file is part of GDB, the GNU debugger.
64e98e3e1Schristos 
74e98e3e1Schristos This program is free software; you can redistribute it and/or modify
84e98e3e1Schristos it under the terms of the GNU General Public License as published by
94e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or
104e98e3e1Schristos (at your option) any later version.
114e98e3e1Schristos 
124e98e3e1Schristos This program is distributed in the hope that it will be useful,
134e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
144e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
154e98e3e1Schristos GNU General Public License for more details.
164e98e3e1Schristos 
174e98e3e1Schristos You should have received a copy of the GNU General Public License
184e98e3e1Schristos along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
194e98e3e1Schristos 
204b169a6bSchristos /* This must come before any other includes.  */
214b169a6bSchristos #include "defs.h"
224e98e3e1Schristos 
234e98e3e1Schristos #include <errno.h>
244e98e3e1Schristos #ifdef HAVE_FCNTL_H
254e98e3e1Schristos #include <fcntl.h>
264e98e3e1Schristos #endif
274b169a6bSchristos #include <stdlib.h>
284b169a6bSchristos #include <string.h>
294b169a6bSchristos #include <unistd.h>
304e98e3e1Schristos #ifdef HAVE_SYS_MMAN_H
314e98e3e1Schristos #include <sys/mman.h>
324e98e3e1Schristos #endif
334e98e3e1Schristos #include <sys/stat.h>
344b169a6bSchristos 
354b169a6bSchristos #include "sim-main.h"
364b169a6bSchristos #include "sim-assert.h"
374b169a6bSchristos #include "sim-options.h"
384e98e3e1Schristos 
394e98e3e1Schristos /* Memory fill byte. */
404b169a6bSchristos static uint8_t fill_byte_value;
414e98e3e1Schristos static int fill_byte_flag = 0;
424e98e3e1Schristos 
434e98e3e1Schristos /* Memory mapping; see OPTION_MEMORY_MAPFILE. */
444e98e3e1Schristos static int mmap_next_fd = -1;
454e98e3e1Schristos 
464e98e3e1Schristos /* Memory command line options. */
474e98e3e1Schristos 
484e98e3e1Schristos enum {
494e98e3e1Schristos   OPTION_MEMORY_DELETE = OPTION_START,
504e98e3e1Schristos   OPTION_MEMORY_REGION,
514e98e3e1Schristos   OPTION_MEMORY_SIZE,
524e98e3e1Schristos   OPTION_MEMORY_INFO,
534e98e3e1Schristos   OPTION_MEMORY_ALIAS,
544e98e3e1Schristos   OPTION_MEMORY_CLEAR,
554e98e3e1Schristos   OPTION_MEMORY_FILL,
564e98e3e1Schristos   OPTION_MEMORY_MAPFILE,
574e98e3e1Schristos   OPTION_MAP_INFO
584e98e3e1Schristos };
594e98e3e1Schristos 
604e98e3e1Schristos static DECLARE_OPTION_HANDLER (memory_option_handler);
614e98e3e1Schristos 
624e98e3e1Schristos static const OPTION memory_options[] =
634e98e3e1Schristos {
644e98e3e1Schristos   { {"memory-delete", required_argument, NULL, OPTION_MEMORY_DELETE },
654e98e3e1Schristos       '\0', "ADDRESS|all", "Delete memory at ADDRESS (all addresses)",
664e98e3e1Schristos       memory_option_handler },
674e98e3e1Schristos   { {"delete-memory", required_argument, NULL, OPTION_MEMORY_DELETE },
684e98e3e1Schristos       '\0', "ADDRESS", NULL,
694e98e3e1Schristos       memory_option_handler },
704e98e3e1Schristos 
714e98e3e1Schristos   { {"memory-region", required_argument, NULL, OPTION_MEMORY_REGION },
724e98e3e1Schristos       '\0', "ADDRESS,SIZE[,MODULO]", "Add a memory region",
734e98e3e1Schristos       memory_option_handler },
744e98e3e1Schristos 
754e98e3e1Schristos   { {"memory-alias", required_argument, NULL, OPTION_MEMORY_ALIAS },
764e98e3e1Schristos       '\0', "ADDRESS,SIZE{,ADDRESS}", "Add memory shadow",
774e98e3e1Schristos       memory_option_handler },
784e98e3e1Schristos 
794e98e3e1Schristos   { {"memory-size", required_argument, NULL, OPTION_MEMORY_SIZE },
804e98e3e1Schristos       '\0', "<size>[in bytes, Kb (k suffix), Mb (m suffix) or Gb (g suffix)]",
814e98e3e1Schristos      "Add memory at address zero", memory_option_handler },
824e98e3e1Schristos 
834e98e3e1Schristos   { {"memory-fill", required_argument, NULL, OPTION_MEMORY_FILL },
844e98e3e1Schristos       '\0', "VALUE", "Fill subsequently added memory regions",
854e98e3e1Schristos       memory_option_handler },
864e98e3e1Schristos 
874e98e3e1Schristos   { {"memory-clear", no_argument, NULL, OPTION_MEMORY_CLEAR },
884e98e3e1Schristos       '\0', NULL, "Clear subsequently added memory regions",
894e98e3e1Schristos       memory_option_handler },
904e98e3e1Schristos 
914e98e3e1Schristos #if defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
924e98e3e1Schristos   { {"memory-mapfile", required_argument, NULL, OPTION_MEMORY_MAPFILE },
934e98e3e1Schristos       '\0', "FILE", "Memory-map next memory region from file",
944e98e3e1Schristos       memory_option_handler },
954e98e3e1Schristos #endif
964e98e3e1Schristos 
974e98e3e1Schristos   { {"memory-info", no_argument, NULL, OPTION_MEMORY_INFO },
984e98e3e1Schristos       '\0', NULL, "List configurable memory regions",
994e98e3e1Schristos       memory_option_handler },
1004e98e3e1Schristos   { {"info-memory", no_argument, NULL, OPTION_MEMORY_INFO },
1014e98e3e1Schristos       '\0', NULL, NULL,
1024e98e3e1Schristos       memory_option_handler },
1034e98e3e1Schristos   { {"map-info", no_argument, NULL, OPTION_MAP_INFO },
1044e98e3e1Schristos       '\0', NULL, "List mapped regions",
1054e98e3e1Schristos       memory_option_handler },
1064e98e3e1Schristos 
1074e98e3e1Schristos   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
1084e98e3e1Schristos };
1094e98e3e1Schristos 
1104e98e3e1Schristos 
1114e98e3e1Schristos static sim_memopt *
1124e98e3e1Schristos do_memopt_add (SIM_DESC sd,
1134e98e3e1Schristos 	       int level,
1144e98e3e1Schristos 	       int space,
1154e98e3e1Schristos 	       address_word addr,
1164e98e3e1Schristos 	       address_word nr_bytes,
1174e98e3e1Schristos 	       unsigned modulo,
1184e98e3e1Schristos 	       sim_memopt **entry,
1194e98e3e1Schristos 	       void *buffer)
1204e98e3e1Schristos {
1214e98e3e1Schristos   void *fill_buffer;
1224e98e3e1Schristos   unsigned fill_length;
1234e98e3e1Schristos   void *free_buffer;
1244e98e3e1Schristos   unsigned long free_length;
1254e98e3e1Schristos 
1264e98e3e1Schristos   if (buffer != NULL)
1274e98e3e1Schristos     {
1284e98e3e1Schristos       /* Buffer already given.  sim_memory_uninstall will free it. */
1294e98e3e1Schristos       sim_core_attach (sd, NULL,
1304e98e3e1Schristos 		       level, access_read_write_exec, space,
1314e98e3e1Schristos 		       addr, nr_bytes, modulo, NULL, buffer);
1324e98e3e1Schristos 
1334e98e3e1Schristos       free_buffer = buffer;
1344e98e3e1Schristos       free_length = 0;
1354e98e3e1Schristos       fill_buffer = buffer;
1364e98e3e1Schristos       fill_length = (modulo == 0) ? nr_bytes : modulo;
1374e98e3e1Schristos     }
1384e98e3e1Schristos   else
1394e98e3e1Schristos     {
1404e98e3e1Schristos       /* Allocate new well-aligned buffer, just as sim_core_attach(). */
1414e98e3e1Schristos       void *aligned_buffer;
1424b169a6bSchristos       int padding = (addr % sizeof (uint64_t));
1434e98e3e1Schristos       unsigned long bytes;
1444e98e3e1Schristos 
1454e98e3e1Schristos #ifdef HAVE_MMAP
1464e98e3e1Schristos       struct stat s;
1474e98e3e1Schristos 
1484e98e3e1Schristos       if (mmap_next_fd >= 0)
1494e98e3e1Schristos 	{
1504e98e3e1Schristos 	  /* Check that given file is big enough. */
1514e98e3e1Schristos 	  int rc = fstat (mmap_next_fd, &s);
1524e98e3e1Schristos 
1534e98e3e1Schristos 	  if (rc < 0)
1544e98e3e1Schristos 	    sim_io_error (sd, "Error, unable to stat file: %s\n",
1554e98e3e1Schristos 			  strerror (errno));
1564e98e3e1Schristos 
1574e98e3e1Schristos 	  /* Autosize the mapping to the file length.  */
1584e98e3e1Schristos 	  if (nr_bytes == 0)
1594e98e3e1Schristos 	    nr_bytes = s.st_size;
1604e98e3e1Schristos 	}
1614e98e3e1Schristos #endif
1624e98e3e1Schristos 
1634e98e3e1Schristos       bytes = (modulo == 0 ? nr_bytes : modulo) + padding;
1644e98e3e1Schristos 
1654e98e3e1Schristos       free_buffer = NULL;
1664e98e3e1Schristos       free_length = bytes;
1674e98e3e1Schristos 
1684e98e3e1Schristos #ifdef HAVE_MMAP
1694e98e3e1Schristos       /* Memory map or malloc(). */
1704e98e3e1Schristos       if (mmap_next_fd >= 0)
1714e98e3e1Schristos 	{
1724e98e3e1Schristos 	  /* Some kernels will SIGBUS the application if mmap'd file
1734e98e3e1Schristos 	     is not large enough.  */
1744e98e3e1Schristos 	  if (s.st_size < bytes)
1754e98e3e1Schristos 	    {
1764e98e3e1Schristos 	      sim_io_error (sd,
1774e98e3e1Schristos 			    "Error, cannot confirm that mmap file is large enough "
1784e98e3e1Schristos 			    "(>= %ld bytes)\n", bytes);
1794e98e3e1Schristos 	    }
1804e98e3e1Schristos 
1814e98e3e1Schristos 	  free_buffer = mmap (0, bytes, PROT_READ|PROT_WRITE, MAP_SHARED, mmap_next_fd, 0);
1824e98e3e1Schristos 	  if (free_buffer == 0 || free_buffer == (char*)-1) /* MAP_FAILED */
1834e98e3e1Schristos 	    {
1844e98e3e1Schristos 	      sim_io_error (sd, "Error, cannot mmap file (%s).\n",
1854e98e3e1Schristos 			    strerror (errno));
1864e98e3e1Schristos 	    }
1874e98e3e1Schristos 	}
1884e98e3e1Schristos #endif
1894e98e3e1Schristos 
1904e98e3e1Schristos       /* Need heap allocation? */
1914e98e3e1Schristos       if (free_buffer == NULL)
1924e98e3e1Schristos 	{
1934e98e3e1Schristos 	  /* If filling with non-zero value, do not use clearing allocator. */
1944e98e3e1Schristos 	  if (fill_byte_flag && fill_byte_value != 0)
1954e98e3e1Schristos 	    free_buffer = xmalloc (bytes); /* don't clear */
1964e98e3e1Schristos 	  else
1974e98e3e1Schristos 	    free_buffer = zalloc (bytes); /* clear */
1984e98e3e1Schristos 	}
1994e98e3e1Schristos 
2004e98e3e1Schristos       aligned_buffer = (char*) free_buffer + padding;
2014e98e3e1Schristos 
2024e98e3e1Schristos       sim_core_attach (sd, NULL,
2034e98e3e1Schristos 		       level, access_read_write_exec, space,
2044e98e3e1Schristos 		       addr, nr_bytes, modulo, NULL, aligned_buffer);
2054e98e3e1Schristos 
2064e98e3e1Schristos       fill_buffer = aligned_buffer;
2074e98e3e1Schristos       fill_length = (modulo == 0) ? nr_bytes : modulo;
2084e98e3e1Schristos 
2094e98e3e1Schristos       /* If we just used a clearing allocator, and are about to fill with
2104e98e3e1Schristos          zero, truncate the redundant fill operation. */
2114e98e3e1Schristos 
2124e98e3e1Schristos       if (fill_byte_flag && fill_byte_value == 0)
2134e98e3e1Schristos          fill_length = 1; /* avoid boundary length=0 case */
2144e98e3e1Schristos     }
2154e98e3e1Schristos 
2164e98e3e1Schristos   if (fill_byte_flag)
2174e98e3e1Schristos     {
2184e98e3e1Schristos       ASSERT (fill_buffer != 0);
2194e98e3e1Schristos       memset ((char*) fill_buffer, fill_byte_value, fill_length);
2204e98e3e1Schristos     }
2214e98e3e1Schristos 
2224e98e3e1Schristos   while ((*entry) != NULL)
2234e98e3e1Schristos     entry = &(*entry)->next;
2244e98e3e1Schristos   (*entry) = ZALLOC (sim_memopt);
2254e98e3e1Schristos   (*entry)->level = level;
2264e98e3e1Schristos   (*entry)->space = space;
2274e98e3e1Schristos   (*entry)->addr = addr;
2284e98e3e1Schristos   (*entry)->nr_bytes = nr_bytes;
2294e98e3e1Schristos   (*entry)->modulo = modulo;
2304e98e3e1Schristos   (*entry)->buffer = free_buffer;
2314e98e3e1Schristos 
2324e98e3e1Schristos   /* Record memory unmapping info.  */
2334e98e3e1Schristos   if (mmap_next_fd >= 0)
2344e98e3e1Schristos     {
2354e98e3e1Schristos       (*entry)->munmap_length = free_length;
2364e98e3e1Schristos       close (mmap_next_fd);
2374e98e3e1Schristos       mmap_next_fd = -1;
2384e98e3e1Schristos     }
2394e98e3e1Schristos   else
2404e98e3e1Schristos     (*entry)->munmap_length = 0;
2414e98e3e1Schristos 
2424e98e3e1Schristos   return (*entry);
2434e98e3e1Schristos }
2444e98e3e1Schristos 
2454e98e3e1Schristos static SIM_RC
2464e98e3e1Schristos do_memopt_delete (SIM_DESC sd,
2474e98e3e1Schristos 		  int level,
2484e98e3e1Schristos 		  int space,
2494e98e3e1Schristos 		  address_word addr)
2504e98e3e1Schristos {
2514e98e3e1Schristos   sim_memopt **entry = &STATE_MEMOPT (sd);
2524e98e3e1Schristos   sim_memopt *alias;
2534e98e3e1Schristos   while ((*entry) != NULL
2544e98e3e1Schristos 	 && ((*entry)->level != level
2554e98e3e1Schristos 	      || (*entry)->space != space
2564e98e3e1Schristos 	      || (*entry)->addr != addr))
2574e98e3e1Schristos     entry = &(*entry)->next;
2584e98e3e1Schristos   if ((*entry) == NULL)
2594e98e3e1Schristos     {
2604e98e3e1Schristos       sim_io_eprintf (sd, "Memory at 0x%lx not found, not deleted\n",
2614e98e3e1Schristos 		      (long) addr);
2624e98e3e1Schristos       return SIM_RC_FAIL;
2634e98e3e1Schristos     }
2644e98e3e1Schristos   /* delete any buffer */
2654e98e3e1Schristos   if ((*entry)->buffer != NULL)
2664e98e3e1Schristos     {
2674e98e3e1Schristos #ifdef HAVE_MUNMAP
2684e98e3e1Schristos       if ((*entry)->munmap_length > 0)
2694e98e3e1Schristos 	munmap ((*entry)->buffer, (*entry)->munmap_length);
2704e98e3e1Schristos       else
2714e98e3e1Schristos #endif
2724e98e3e1Schristos 	free ((*entry)->buffer);
2734e98e3e1Schristos     }
2744e98e3e1Schristos 
2754e98e3e1Schristos   /* delete it and its aliases */
2764e98e3e1Schristos   alias = *entry;
2774e98e3e1Schristos   *entry = (*entry)->next;
2784e98e3e1Schristos   while (alias != NULL)
2794e98e3e1Schristos     {
2804e98e3e1Schristos       sim_memopt *dead = alias;
2814e98e3e1Schristos       alias = alias->alias;
2824e98e3e1Schristos       sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
2834e98e3e1Schristos       free (dead);
2844e98e3e1Schristos     }
2854e98e3e1Schristos   return SIM_RC_OK;
2864e98e3e1Schristos }
2874e98e3e1Schristos 
2884e98e3e1Schristos 
2894e98e3e1Schristos static char *
2904e98e3e1Schristos parse_size (char *chp,
2914e98e3e1Schristos 	    address_word *nr_bytes,
2924e98e3e1Schristos 	    unsigned *modulo)
2934e98e3e1Schristos {
2944e98e3e1Schristos   /* <nr_bytes>[K|M|G] [ "%" <modulo> ] */
2954e98e3e1Schristos   *nr_bytes = strtoul (chp, &chp, 0);
2964e98e3e1Schristos   switch (*chp)
2974e98e3e1Schristos     {
2984e98e3e1Schristos     case '%':
2994e98e3e1Schristos       *modulo = strtoul (chp + 1, &chp, 0);
3004e98e3e1Schristos       break;
3014e98e3e1Schristos     case 'g': case 'G': /* Gigabyte suffix.  */
3024e98e3e1Schristos       *nr_bytes <<= 10;
303*0d3e0572Schristos       ATTRIBUTE_FALLTHROUGH;
3044e98e3e1Schristos     case 'm': case 'M': /* Megabyte suffix.  */
3054e98e3e1Schristos       *nr_bytes <<= 10;
306*0d3e0572Schristos       ATTRIBUTE_FALLTHROUGH;
3074e98e3e1Schristos     case 'k': case 'K': /* Kilobyte suffix.  */
3084e98e3e1Schristos       *nr_bytes <<= 10;
3094e98e3e1Schristos       /* Check for a modulo specifier after the suffix.  */
3104e98e3e1Schristos       ++ chp;
3114e98e3e1Schristos       if (* chp == 'b' || * chp == 'B')
3124e98e3e1Schristos 	++ chp;
3134e98e3e1Schristos       if (* chp == '%')
3144e98e3e1Schristos 	*modulo = strtoul (chp + 1, &chp, 0);
3154e98e3e1Schristos       break;
3164e98e3e1Schristos     }
3174e98e3e1Schristos   return chp;
3184e98e3e1Schristos }
3194e98e3e1Schristos 
3204e98e3e1Schristos static char *
3214e98e3e1Schristos parse_ulong_value (char *chp,
3224e98e3e1Schristos 		     unsigned long *value)
3234e98e3e1Schristos {
3244e98e3e1Schristos   *value = strtoul (chp, &chp, 0);
3254e98e3e1Schristos   return chp;
3264e98e3e1Schristos }
3274e98e3e1Schristos 
3284e98e3e1Schristos static char *
3294e98e3e1Schristos parse_addr (char *chp,
3304e98e3e1Schristos 	    int *level,
3314e98e3e1Schristos 	    int *space,
3324e98e3e1Schristos 	    address_word *addr)
3334e98e3e1Schristos {
3344e98e3e1Schristos   /* [ <space> ": " ] <addr> [ "@" <level> ] */
3354e98e3e1Schristos   *addr = (unsigned long) strtoul (chp, &chp, 0);
3364e98e3e1Schristos   if (*chp == ':')
3374e98e3e1Schristos     {
3384e98e3e1Schristos       *space = *addr;
3394e98e3e1Schristos       *addr = (unsigned long) strtoul (chp + 1, &chp, 0);
3404e98e3e1Schristos     }
3414e98e3e1Schristos   if (*chp == '@')
3424e98e3e1Schristos     {
3434e98e3e1Schristos       *level = strtoul (chp + 1, &chp, 0);
3444e98e3e1Schristos     }
3454e98e3e1Schristos   return chp;
3464e98e3e1Schristos }
3474e98e3e1Schristos 
3484e98e3e1Schristos 
3494e98e3e1Schristos static SIM_RC
3504e98e3e1Schristos memory_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
3514e98e3e1Schristos 		       char *arg, int is_command)
3524e98e3e1Schristos {
3534e98e3e1Schristos   switch (opt)
3544e98e3e1Schristos     {
3554e98e3e1Schristos 
3564e98e3e1Schristos     case OPTION_MEMORY_DELETE:
3574e98e3e1Schristos       if (strcasecmp (arg, "all") == 0)
3584e98e3e1Schristos 	{
3594e98e3e1Schristos 	  while (STATE_MEMOPT (sd) != NULL)
3604e98e3e1Schristos 	    do_memopt_delete (sd,
3614e98e3e1Schristos 			      STATE_MEMOPT (sd)->level,
3624e98e3e1Schristos 			      STATE_MEMOPT (sd)->space,
3634e98e3e1Schristos 			      STATE_MEMOPT (sd)->addr);
3644e98e3e1Schristos 	  return SIM_RC_OK;
3654e98e3e1Schristos 	}
3664e98e3e1Schristos       else
3674e98e3e1Schristos 	{
3684e98e3e1Schristos 	  int level = 0;
3694e98e3e1Schristos 	  int space = 0;
3704e98e3e1Schristos 	  address_word addr = 0;
3714e98e3e1Schristos 	  parse_addr (arg, &level, &space, &addr);
3724e98e3e1Schristos 	  return do_memopt_delete (sd, level, space, addr);
3734e98e3e1Schristos 	}
3744e98e3e1Schristos 
3754e98e3e1Schristos     case OPTION_MEMORY_REGION:
3764e98e3e1Schristos       {
3774e98e3e1Schristos 	char *chp = arg;
3784e98e3e1Schristos 	int level = 0;
3794e98e3e1Schristos 	int space = 0;
3804e98e3e1Schristos 	address_word addr = 0;
3814e98e3e1Schristos 	address_word nr_bytes = 0;
3824e98e3e1Schristos 	unsigned modulo = 0;
3834e98e3e1Schristos 	/* parse the arguments */
3844e98e3e1Schristos 	chp = parse_addr (chp, &level, &space, &addr);
3854e98e3e1Schristos 	if (*chp != ',')
3864e98e3e1Schristos 	  {
3874e98e3e1Schristos 	    /* let the file autosize */
3884e98e3e1Schristos 	    if (mmap_next_fd == -1)
3894e98e3e1Schristos 	      {
3904e98e3e1Schristos 		sim_io_eprintf (sd, "Missing size for memory-region\n");
3914e98e3e1Schristos 		return SIM_RC_FAIL;
3924e98e3e1Schristos 	      }
3934e98e3e1Schristos 	  }
3944e98e3e1Schristos 	else
3954e98e3e1Schristos 	  chp = parse_size (chp + 1, &nr_bytes, &modulo);
3964e98e3e1Schristos 	/* old style */
3974e98e3e1Schristos 	if (*chp == ',')
3984e98e3e1Schristos 	  modulo = strtoul (chp + 1, &chp, 0);
3994e98e3e1Schristos 	/* try to attach/insert it */
4004e98e3e1Schristos 	do_memopt_add (sd, level, space, addr, nr_bytes, modulo,
4014e98e3e1Schristos 		       &STATE_MEMOPT (sd), NULL);
4024e98e3e1Schristos 	return SIM_RC_OK;
4034e98e3e1Schristos       }
4044e98e3e1Schristos 
4054e98e3e1Schristos     case OPTION_MEMORY_ALIAS:
4064e98e3e1Schristos       {
4074e98e3e1Schristos 	char *chp = arg;
4084e98e3e1Schristos 	int level = 0;
4094e98e3e1Schristos 	int space = 0;
4104e98e3e1Schristos 	address_word addr = 0;
4114e98e3e1Schristos 	address_word nr_bytes = 0;
4124e98e3e1Schristos 	unsigned modulo = 0;
4134e98e3e1Schristos 	sim_memopt *entry;
4144e98e3e1Schristos 	/* parse the arguments */
4154e98e3e1Schristos 	chp = parse_addr (chp, &level, &space, &addr);
4164e98e3e1Schristos 	if (*chp != ',')
4174e98e3e1Schristos 	  {
4184e98e3e1Schristos 	    sim_io_eprintf (sd, "Missing size for memory-region\n");
4194e98e3e1Schristos 	    return SIM_RC_FAIL;
4204e98e3e1Schristos 	  }
4214e98e3e1Schristos 	chp = parse_size (chp + 1, &nr_bytes, &modulo);
4224e98e3e1Schristos 	/* try to attach/insert the main record */
4234e98e3e1Schristos 	entry = do_memopt_add (sd, level, space, addr, nr_bytes, modulo,
4244e98e3e1Schristos 			       &STATE_MEMOPT (sd),
4254e98e3e1Schristos 			       NULL);
4264e98e3e1Schristos 	/* now attach all the aliases */
4274e98e3e1Schristos 	while (*chp == ',')
4284e98e3e1Schristos 	  {
4294e98e3e1Schristos 	    int a_level = level;
4304e98e3e1Schristos 	    int a_space = space;
4314e98e3e1Schristos 	    address_word a_addr = addr;
4324e98e3e1Schristos 	    chp = parse_addr (chp + 1, &a_level, &a_space, &a_addr);
4334e98e3e1Schristos 	    do_memopt_add (sd, a_level, a_space, a_addr, nr_bytes, modulo,
4344e98e3e1Schristos 			   &entry->alias, entry->buffer);
4354e98e3e1Schristos 	  }
4364e98e3e1Schristos 	return SIM_RC_OK;
4374e98e3e1Schristos       }
4384e98e3e1Schristos 
4394e98e3e1Schristos     case OPTION_MEMORY_SIZE:
4404e98e3e1Schristos       {
4414e98e3e1Schristos 	int level = 0;
4424e98e3e1Schristos 	int space = 0;
4434e98e3e1Schristos 	address_word addr = 0;
4444e98e3e1Schristos 	address_word nr_bytes = 0;
4454e98e3e1Schristos 	unsigned modulo = 0;
4464e98e3e1Schristos 	/* parse the arguments */
4474e98e3e1Schristos 	parse_size (arg, &nr_bytes, &modulo);
4484e98e3e1Schristos 	/* try to attach/insert it */
4494e98e3e1Schristos 	do_memopt_add (sd, level, space, addr, nr_bytes, modulo,
4504e98e3e1Schristos 		       &STATE_MEMOPT (sd), NULL);
4514e98e3e1Schristos 	return SIM_RC_OK;
4524e98e3e1Schristos       }
4534e98e3e1Schristos 
4544e98e3e1Schristos     case OPTION_MEMORY_CLEAR:
4554e98e3e1Schristos       {
4564b169a6bSchristos 	fill_byte_value = (uint8_t) 0;
4574e98e3e1Schristos 	fill_byte_flag = 1;
4584e98e3e1Schristos 	return SIM_RC_OK;
4594e98e3e1Schristos 	break;
4604e98e3e1Schristos       }
4614e98e3e1Schristos 
4624e98e3e1Schristos     case OPTION_MEMORY_FILL:
4634e98e3e1Schristos       {
4644e98e3e1Schristos 	unsigned long fill_value;
4654e98e3e1Schristos 	parse_ulong_value (arg, &fill_value);
4664e98e3e1Schristos 	if (fill_value > 255)
4674e98e3e1Schristos 	  {
4684e98e3e1Schristos 	    sim_io_eprintf (sd, "Missing fill value between 0 and 255\n");
4694e98e3e1Schristos 	    return SIM_RC_FAIL;
4704e98e3e1Schristos 	  }
4714b169a6bSchristos 	fill_byte_value = (uint8_t) fill_value;
4724e98e3e1Schristos 	fill_byte_flag = 1;
4734e98e3e1Schristos 	return SIM_RC_OK;
4744e98e3e1Schristos 	break;
4754e98e3e1Schristos       }
4764e98e3e1Schristos 
4774e98e3e1Schristos     case OPTION_MEMORY_MAPFILE:
4784e98e3e1Schristos       {
4794e98e3e1Schristos 	if (mmap_next_fd >= 0)
4804e98e3e1Schristos 	  {
4814e98e3e1Schristos 	    sim_io_eprintf (sd, "Duplicate memory-mapfile option\n");
4824e98e3e1Schristos 	    return SIM_RC_FAIL;
4834e98e3e1Schristos 	  }
4844e98e3e1Schristos 
4854e98e3e1Schristos 	mmap_next_fd = open (arg, O_RDWR);
4864e98e3e1Schristos 	if (mmap_next_fd < 0)
4874e98e3e1Schristos 	  {
4884e98e3e1Schristos 	    sim_io_eprintf (sd, "Cannot open file `%s': %s\n",
4894e98e3e1Schristos 			    arg, strerror (errno));
4904e98e3e1Schristos 	    return SIM_RC_FAIL;
4914e98e3e1Schristos 	  }
4924e98e3e1Schristos 
4934e98e3e1Schristos 	return SIM_RC_OK;
4944e98e3e1Schristos       }
4954e98e3e1Schristos 
4964e98e3e1Schristos     case OPTION_MEMORY_INFO:
4974e98e3e1Schristos       {
4984e98e3e1Schristos 	sim_memopt *entry;
4994e98e3e1Schristos 	sim_io_printf (sd, "Memory maps:\n");
5004e98e3e1Schristos 	for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next)
5014e98e3e1Schristos 	  {
5024e98e3e1Schristos 	    sim_memopt *alias;
5034e98e3e1Schristos 	    sim_io_printf (sd, " memory");
5044e98e3e1Schristos 	    if (entry->alias == NULL)
5054e98e3e1Schristos 	      sim_io_printf (sd, " region ");
5064e98e3e1Schristos 	    else
5074e98e3e1Schristos 	      sim_io_printf (sd, " alias ");
5084e98e3e1Schristos 	    if (entry->space != 0)
5094e98e3e1Schristos 	      sim_io_printf (sd, "0x%lx:", (long) entry->space);
5104e98e3e1Schristos 	    sim_io_printf (sd, "0x%08lx", (long) entry->addr);
5114e98e3e1Schristos 	    if (entry->level != 0)
5124e98e3e1Schristos 	      sim_io_printf (sd, "@0x%lx", (long) entry->level);
5134e98e3e1Schristos 	    sim_io_printf (sd, ",0x%lx",
5144e98e3e1Schristos 			   (long) entry->nr_bytes);
5154e98e3e1Schristos 	    if (entry->modulo != 0)
5164e98e3e1Schristos 	      sim_io_printf (sd, "%%0x%lx", (long) entry->modulo);
5174e98e3e1Schristos 	    for (alias = entry->alias;
5184e98e3e1Schristos 		 alias != NULL;
5194e98e3e1Schristos 		 alias = alias->next)
5204e98e3e1Schristos 	      {
5214e98e3e1Schristos 		if (alias->space != 0)
5224e98e3e1Schristos 		  sim_io_printf (sd, "0x%lx:", (long) alias->space);
5234e98e3e1Schristos 		sim_io_printf (sd, ",0x%08lx", (long) alias->addr);
5244e98e3e1Schristos 		if (alias->level != 0)
5254e98e3e1Schristos 		  sim_io_printf (sd, "@0x%lx", (long) alias->level);
5264e98e3e1Schristos 	      }
5274e98e3e1Schristos 	    sim_io_printf (sd, "\n");
5284e98e3e1Schristos 	  }
5294e98e3e1Schristos 	return SIM_RC_OK;
5304e98e3e1Schristos 	break;
5314e98e3e1Schristos       }
5324e98e3e1Schristos 
5334e98e3e1Schristos     case OPTION_MAP_INFO:
5344e98e3e1Schristos       {
5354e98e3e1Schristos 	sim_core *memory = STATE_CORE (sd);
5364e98e3e1Schristos 	unsigned nr_map;
5374e98e3e1Schristos 
5384e98e3e1Schristos 	for (nr_map = 0; nr_map < nr_maps; ++nr_map)
5394e98e3e1Schristos 	  {
5404e98e3e1Schristos 	    sim_core_map *map = &memory->common.map[nr_map];
5414e98e3e1Schristos 	    sim_core_mapping *mapping = map->first;
5424e98e3e1Schristos 
5434e98e3e1Schristos 	    if (!mapping)
5444e98e3e1Schristos 	      continue;
5454e98e3e1Schristos 
5464e98e3e1Schristos 	    sim_io_printf (sd, "%s maps:\n", map_to_str (nr_map));
5474e98e3e1Schristos 	    do
5484e98e3e1Schristos 	      {
5494e98e3e1Schristos 		unsigned modulo;
5504e98e3e1Schristos 
5514e98e3e1Schristos 		sim_io_printf (sd, " map ");
5524e98e3e1Schristos 		if (mapping->space != 0)
5534e98e3e1Schristos 		  sim_io_printf (sd, "0x%x:", mapping->space);
5544e98e3e1Schristos 		sim_io_printf (sd, "0x%08lx", (long) mapping->base);
5554e98e3e1Schristos 		if (mapping->level != 0)
5564e98e3e1Schristos 		  sim_io_printf (sd, "@0x%x", mapping->level);
5574e98e3e1Schristos 		sim_io_printf (sd, ",0x%lx", (long) mapping->nr_bytes);
5584e98e3e1Schristos 		modulo = mapping->mask + 1;
5594e98e3e1Schristos 		if (modulo != 0)
5604e98e3e1Schristos 		  sim_io_printf (sd, "%%0x%x", modulo);
5614e98e3e1Schristos 		sim_io_printf (sd, "\n");
5624e98e3e1Schristos 
5634e98e3e1Schristos 		mapping = mapping->next;
5644e98e3e1Schristos 	      }
5654e98e3e1Schristos 	    while (mapping);
5664e98e3e1Schristos 	  }
5674e98e3e1Schristos 
5684e98e3e1Schristos 	return SIM_RC_OK;
5694e98e3e1Schristos 	break;
5704e98e3e1Schristos       }
5714e98e3e1Schristos 
5724e98e3e1Schristos     default:
5734e98e3e1Schristos       sim_io_eprintf (sd, "Unknown memory option %d\n", opt);
5744e98e3e1Schristos       return SIM_RC_FAIL;
5754e98e3e1Schristos 
5764e98e3e1Schristos     }
5774e98e3e1Schristos 
5784e98e3e1Schristos   return SIM_RC_FAIL;
5794e98e3e1Schristos }
5804e98e3e1Schristos 
5814e98e3e1Schristos 
5824e98e3e1Schristos /* "memory" module install handler.
5834e98e3e1Schristos 
5844e98e3e1Schristos    This is called via sim_module_install to install the "memory" subsystem
5854e98e3e1Schristos    into the simulator.  */
5864e98e3e1Schristos 
5874e98e3e1Schristos static MODULE_INIT_FN sim_memory_init;
5884e98e3e1Schristos static MODULE_UNINSTALL_FN sim_memory_uninstall;
5894e98e3e1Schristos 
5904e98e3e1Schristos SIM_RC
5914e98e3e1Schristos sim_memopt_install (SIM_DESC sd)
5924e98e3e1Schristos {
5934e98e3e1Schristos   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
5944e98e3e1Schristos   sim_add_option_table (sd, NULL, memory_options);
5954e98e3e1Schristos   sim_module_add_uninstall_fn (sd, sim_memory_uninstall);
5964e98e3e1Schristos   sim_module_add_init_fn (sd, sim_memory_init);
5974e98e3e1Schristos   return SIM_RC_OK;
5984e98e3e1Schristos }
5994e98e3e1Schristos 
6004e98e3e1Schristos 
6014e98e3e1Schristos /* Uninstall the "memory" subsystem from the simulator.  */
6024e98e3e1Schristos 
6034e98e3e1Schristos static void
6044e98e3e1Schristos sim_memory_uninstall (SIM_DESC sd)
6054e98e3e1Schristos {
6064e98e3e1Schristos   sim_memopt **entry = &STATE_MEMOPT (sd);
6074e98e3e1Schristos   sim_memopt *alias;
6084e98e3e1Schristos 
6094e98e3e1Schristos   while ((*entry) != NULL)
6104e98e3e1Schristos     {
6114e98e3e1Schristos       /* delete any buffer */
6124e98e3e1Schristos       if ((*entry)->buffer != NULL)
6134e98e3e1Schristos 	{
6144e98e3e1Schristos #ifdef HAVE_MUNMAP
6154e98e3e1Schristos 	  if ((*entry)->munmap_length > 0)
6164e98e3e1Schristos 	    munmap ((*entry)->buffer, (*entry)->munmap_length);
6174e98e3e1Schristos 	  else
6184e98e3e1Schristos #endif
6194e98e3e1Schristos 	    free ((*entry)->buffer);
6204e98e3e1Schristos 	}
6214e98e3e1Schristos 
6224e98e3e1Schristos       /* delete it and its aliases */
6234e98e3e1Schristos       alias = *entry;
6244e98e3e1Schristos 
6254e98e3e1Schristos       /* next victim */
6264e98e3e1Schristos       *entry = (*entry)->next;
6274e98e3e1Schristos 
6284e98e3e1Schristos       while (alias != NULL)
6294e98e3e1Schristos 	{
6304e98e3e1Schristos 	  sim_memopt *dead = alias;
6314e98e3e1Schristos 	  alias = alias->alias;
6324e98e3e1Schristos 	  sim_core_detach (sd, NULL, dead->level, dead->space, dead->addr);
6334e98e3e1Schristos 	  free (dead);
6344e98e3e1Schristos 	}
6354e98e3e1Schristos     }
6364e98e3e1Schristos }
6374e98e3e1Schristos 
6384b169a6bSchristos void sim_dump_memory (SIM_DESC sd);
6394b169a6bSchristos 
6404b169a6bSchristos /* Convenience function for use when debugging the simulator, to be
6414b169a6bSchristos    called from within e.g. gdb.  */
6424b169a6bSchristos 
6434b169a6bSchristos void
6444b169a6bSchristos sim_dump_memory (SIM_DESC sd)
6454b169a6bSchristos {
6464b169a6bSchristos   memory_option_handler (sd, NULL, OPTION_MEMORY_INFO, NULL, 0);
6474b169a6bSchristos   memory_option_handler (sd, NULL, OPTION_MAP_INFO, NULL, 0);
6484b169a6bSchristos }
6494e98e3e1Schristos 
6504e98e3e1Schristos static SIM_RC
6514e98e3e1Schristos sim_memory_init (SIM_DESC sd)
6524e98e3e1Schristos {
6534e98e3e1Schristos   /* Reinitialize option modifier flags, in case they were left
6544e98e3e1Schristos      over from a previous sim startup event.  */
6554e98e3e1Schristos   fill_byte_flag = 0;
6564e98e3e1Schristos   mmap_next_fd = -1;
6574e98e3e1Schristos 
6584e98e3e1Schristos   return SIM_RC_OK;
6594e98e3e1Schristos }
660