|  | /* Copyright (C) 1992-2021 Free Software Foundation, Inc. | 
|  |  | 
|  | 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 "defs.h" | 
|  | #include "target-dcache.h" | 
|  | #include "gdbcmd.h" | 
|  | #include "progspace.h" | 
|  | #include "cli/cli-cmds.h" | 
|  |  | 
|  | /* The target dcache is kept per-address-space.  This key lets us | 
|  | associate the cache with the address space.  */ | 
|  |  | 
|  | static const struct address_space_key<DCACHE, dcache_deleter> | 
|  | target_dcache_aspace_key; | 
|  |  | 
|  | /* Target dcache is initialized or not.  */ | 
|  |  | 
|  | int | 
|  | target_dcache_init_p (void) | 
|  | { | 
|  | DCACHE *dcache | 
|  | = target_dcache_aspace_key.get (current_program_space->aspace); | 
|  |  | 
|  | return (dcache != NULL); | 
|  | } | 
|  |  | 
|  | /* Invalidate the target dcache.  */ | 
|  |  | 
|  | void | 
|  | target_dcache_invalidate (void) | 
|  | { | 
|  | DCACHE *dcache | 
|  | = target_dcache_aspace_key.get (current_program_space->aspace); | 
|  |  | 
|  | if (dcache != NULL) | 
|  | dcache_invalidate (dcache); | 
|  | } | 
|  |  | 
|  | /* Return the target dcache.  Return NULL if target dcache is not | 
|  | initialized yet.  */ | 
|  |  | 
|  | DCACHE * | 
|  | target_dcache_get (void) | 
|  | { | 
|  | return target_dcache_aspace_key.get (current_program_space->aspace); | 
|  | } | 
|  |  | 
|  | /* Return the target dcache.  If it is not initialized yet, initialize | 
|  | it.  */ | 
|  |  | 
|  | DCACHE * | 
|  | target_dcache_get_or_init (void) | 
|  | { | 
|  | DCACHE *dcache | 
|  | = target_dcache_aspace_key.get (current_program_space->aspace); | 
|  |  | 
|  | if (dcache == NULL) | 
|  | { | 
|  | dcache = dcache_init (); | 
|  | target_dcache_aspace_key.set (current_program_space->aspace, dcache); | 
|  | } | 
|  |  | 
|  | return dcache; | 
|  | } | 
|  |  | 
|  | /* The option sets this.  */ | 
|  | static bool stack_cache_enabled_1 = true; | 
|  | /* And set_stack_cache updates this. | 
|  | The reason for the separation is so that we don't flush the cache for | 
|  | on->on transitions.  */ | 
|  | static int stack_cache_enabled = 1; | 
|  |  | 
|  | /* This is called *after* the stack-cache has been set. | 
|  | Flush the cache for off->on and on->off transitions. | 
|  | There's no real need to flush the cache for on->off transitions, | 
|  | except cleanliness.  */ | 
|  |  | 
|  | static void | 
|  | set_stack_cache (const char *args, int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | if (stack_cache_enabled != stack_cache_enabled_1) | 
|  | target_dcache_invalidate (); | 
|  |  | 
|  | stack_cache_enabled = stack_cache_enabled_1; | 
|  | } | 
|  |  | 
|  | static void | 
|  | show_stack_cache (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | fprintf_filtered (file, _("Cache use for stack accesses is %s.\n"), value); | 
|  | } | 
|  |  | 
|  | /* Return true if "stack cache" is enabled, otherwise, return false.  */ | 
|  |  | 
|  | int | 
|  | stack_cache_enabled_p (void) | 
|  | { | 
|  | return stack_cache_enabled; | 
|  | } | 
|  |  | 
|  | /* The option sets this.  */ | 
|  |  | 
|  | static bool code_cache_enabled_1 = true; | 
|  |  | 
|  | /* And set_code_cache updates this. | 
|  | The reason for the separation is so that we don't flush the cache for | 
|  | on->on transitions.  */ | 
|  | static int code_cache_enabled = 1; | 
|  |  | 
|  | /* This is called *after* the code-cache has been set. | 
|  | Flush the cache for off->on and on->off transitions. | 
|  | There's no real need to flush the cache for on->off transitions, | 
|  | except cleanliness.  */ | 
|  |  | 
|  | static void | 
|  | set_code_cache (const char *args, int from_tty, struct cmd_list_element *c) | 
|  | { | 
|  | if (code_cache_enabled != code_cache_enabled_1) | 
|  | target_dcache_invalidate (); | 
|  |  | 
|  | code_cache_enabled = code_cache_enabled_1; | 
|  | } | 
|  |  | 
|  | /* Show option "code-cache".  */ | 
|  |  | 
|  | static void | 
|  | show_code_cache (struct ui_file *file, int from_tty, | 
|  | struct cmd_list_element *c, const char *value) | 
|  | { | 
|  | fprintf_filtered (file, _("Cache use for code accesses is %s.\n"), value); | 
|  | } | 
|  |  | 
|  | /* Return true if "code cache" is enabled, otherwise, return false.  */ | 
|  |  | 
|  | int | 
|  | code_cache_enabled_p (void) | 
|  | { | 
|  | return code_cache_enabled; | 
|  | } | 
|  |  | 
|  | /* Implement the 'maint flush dcache' command.  */ | 
|  |  | 
|  | static void | 
|  | maint_flush_dcache_command (const char *command, int from_tty) | 
|  | { | 
|  | target_dcache_invalidate (); | 
|  | if (from_tty) | 
|  | printf_filtered (_("The dcache was flushed.\n")); | 
|  | } | 
|  |  | 
|  | void _initialize_target_dcache (); | 
|  | void | 
|  | _initialize_target_dcache () | 
|  | { | 
|  | add_setshow_boolean_cmd ("stack-cache", class_support, | 
|  | &stack_cache_enabled_1, _("\ | 
|  | Set cache use for stack access."), _("\ | 
|  | Show cache use for stack access."), _("\ | 
|  | When on, use the target memory cache for all stack access, regardless of any\n\ | 
|  | configured memory regions.  This improves remote performance significantly.\n\ | 
|  | By default, caching for stack access is on."), | 
|  | set_stack_cache, | 
|  | show_stack_cache, | 
|  | &setlist, &showlist); | 
|  |  | 
|  | add_setshow_boolean_cmd ("code-cache", class_support, | 
|  | &code_cache_enabled_1, _("\ | 
|  | Set cache use for code segment access."), _("\ | 
|  | Show cache use for code segment access."), _("\ | 
|  | When on, use the target memory cache for all code segment accesses,\n\ | 
|  | regardless of any configured memory regions.  This improves remote\n\ | 
|  | performance significantly.  By default, caching for code segment\n\ | 
|  | access is on."), | 
|  | set_code_cache, | 
|  | show_code_cache, | 
|  | &setlist, &showlist); | 
|  |  | 
|  | add_cmd ("dcache", class_maintenance, maint_flush_dcache_command, | 
|  | _("\ | 
|  | Force gdb to flush its target memory data cache.\n\ | 
|  | \n\ | 
|  | The dcache caches all target memory accesses where possible, this\n\ | 
|  | includes the stack-cache and the code-cache."), | 
|  | &maintenanceflushlist); | 
|  | } |