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