diff mbox

[v6,02/23] exec: add ram_debug_ops support

Message ID 20180129174132.108925-3-brijesh.singh@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

Brijesh Singh Jan. 29, 2018, 5:41 p.m. UTC
Currently, the guest memory access for the debug purpose is performed
using the memcpy(). Lets extend the 'struct MemoryRegion' to include
ram_debug_ops callbacks. The ram_debug_ops can be used to override
memcpy() with something else.

The feature can be used by encrypted guest -- which can register
callbacks to override memcpy() with memory encryption/decryption APIs.

a typical usage:

mem_read(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
mem_write(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);

MemoryRegionRAMReadWriteOps ops;
ops.read = mem_read;
ops.write = mem_write;

memory_region_init_ram(mem, NULL, "memory", size, NULL);
memory_region_set_ram_debug_ops(mem, ops);

Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
Cc: Richard Henderson <rth@twiddle.net>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 exec.c                | 66 ++++++++++++++++++++++++++++++++++++++-------------
 include/exec/memory.h | 27 +++++++++++++++++++++
 2 files changed, 77 insertions(+), 16 deletions(-)

Comments

Edgar E. Iglesias Jan. 30, 2018, 9:59 p.m. UTC | #1
On Mon, Jan 29, 2018 at 11:41:11AM -0600, Brijesh Singh wrote:
> Currently, the guest memory access for the debug purpose is performed
> using the memcpy(). Lets extend the 'struct MemoryRegion' to include
> ram_debug_ops callbacks. The ram_debug_ops can be used to override
> memcpy() with something else.
> 
> The feature can be used by encrypted guest -- which can register
> callbacks to override memcpy() with memory encryption/decryption APIs.
> 
> a typical usage:
> 
> mem_read(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
> mem_write(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
> 
> MemoryRegionRAMReadWriteOps ops;
> ops.read = mem_read;
> ops.write = mem_write;


Hi,

Do these really need to be RAM specific (ram_debug_ops -> debug_ops) ?
I was hoping a similar infrastructure could be used for MMIO
debug accesses.

Best regards,
Edgar



> 
> memory_region_init_ram(mem, NULL, "memory", size, NULL);
> memory_region_set_ram_debug_ops(mem, ops);
> 
> Cc: Paolo Bonzini <pbonzini@redhat.com>
> Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
> Cc: Richard Henderson <rth@twiddle.net>
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  exec.c                | 66 ++++++++++++++++++++++++++++++++++++++-------------
>  include/exec/memory.h | 27 +++++++++++++++++++++
>  2 files changed, 77 insertions(+), 16 deletions(-)
> 
> diff --git a/exec.c b/exec.c
> index 629a5083851d..1919052b7385 100644
> --- a/exec.c
> +++ b/exec.c
> @@ -3050,7 +3050,11 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
>          } else {
>              /* RAM case */
>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
> -            memcpy(ptr, buf, l);
> +            if (attrs.debug && mr->ram_debug_ops) {
> +                mr->ram_debug_ops->write(ptr, buf, l, attrs);
> +            } else {
> +                memcpy(ptr, buf, l);
> +            }
>              invalidate_and_set_dirty(mr, addr1, l);
>          }
>  
> @@ -3148,7 +3152,11 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
>          } else {
>              /* RAM case */
>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
> -            memcpy(buf, ptr, l);
> +            if (attrs.debug && mr->ram_debug_ops) {
> +                mr->ram_debug_ops->read(buf, ptr, l, attrs);
> +            } else {
> +                memcpy(buf, ptr, l);
> +            }
>          }
>  
>          if (release_lock) {
> @@ -3218,11 +3226,13 @@ void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
>  
>  enum write_rom_type {
>      WRITE_DATA,
> +    READ_DATA,
>      FLUSH_CACHE,
>  };
>  
> -static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
> -    hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
> +static inline void cpu_physical_memory_rw_internal(AddressSpace *as,
> +    hwaddr addr, uint8_t *buf, int len, MemTxAttrs attrs,
> +    enum write_rom_type type)
>  {
>      hwaddr l;
>      uint8_t *ptr;
> @@ -3237,12 +3247,33 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>          if (!(memory_region_is_ram(mr) ||
>                memory_region_is_romd(mr))) {
>              l = memory_access_size(mr, l, addr1);
> +            /* Pass MMIO down to address address_space_rw */
> +            switch (type) {
> +            case READ_DATA:
> +            case WRITE_DATA:
> +                address_space_rw(as, addr1, attrs, buf, l,
> +                                 type == WRITE_DATA);
> +                break;
> +            case FLUSH_CACHE:
> +                break;
> +            }
>          } else {
>              /* ROM/RAM case */
>              ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
>              switch (type) {
> +            case READ_DATA:
> +                if (mr->ram_debug_ops) {
> +                    mr->ram_debug_ops->read(buf, ptr, l, attrs);
> +                } else {
> +                    memcpy(buf, ptr, l);
> +                }
> +                break;
>              case WRITE_DATA:
> -                memcpy(ptr, buf, l);
> +                if (mr->ram_debug_ops) {
> +                    mr->ram_debug_ops->write(ptr, buf, l, attrs);
> +                } else {
> +                    memcpy(ptr, buf, l);
> +                }
>                  invalidate_and_set_dirty(mr, addr1, l);
>                  break;
>              case FLUSH_CACHE:
> @@ -3261,7 +3292,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>  void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
>                                     const uint8_t *buf, int len)
>  {
> -    cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
> +    cpu_physical_memory_rw_internal(as, addr, (uint8_t *)buf, len,
> +            MEMTXATTRS_UNSPECIFIED, WRITE_DATA);
>  }
>  
>  void cpu_flush_icache_range(hwaddr start, int len)
> @@ -3276,8 +3308,10 @@ void cpu_flush_icache_range(hwaddr start, int len)
>          return;
>      }
>  
> -    cpu_physical_memory_write_rom_internal(&address_space_memory,
> -                                           start, NULL, len, FLUSH_CACHE);
> +    cpu_physical_memory_rw_internal(&address_space_memory,
> +                                    start, NULL, len,
> +                                    MEMTXATTRS_UNSPECIFIED,
> +                                    FLUSH_CACHE);
>  }
>  
>  typedef struct {
> @@ -3583,6 +3617,7 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>      int l;
>      hwaddr phys_addr;
>      target_ulong page;
> +    int type = is_write ? WRITE_DATA : READ_DATA;
>  
>      cpu_synchronize_state(cpu);
>      while (len > 0) {
> @@ -3592,6 +3627,10 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>          page = addr & TARGET_PAGE_MASK;
>          phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
>          asidx = cpu_asidx_from_attrs(cpu, attrs);
> +
> +        /* set debug attrs to indicate memory access is from the debugger */
> +        attrs.debug = 1;
> +
>          /* if no physical page mapped, return an error */
>          if (phys_addr == -1)
>              return -1;
> @@ -3599,14 +3638,9 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>          if (l > len)
>              l = len;
>          phys_addr += (addr & ~TARGET_PAGE_MASK);
> -        if (is_write) {
> -            cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
> -                                          phys_addr, buf, l);
> -        } else {
> -            address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
> -                             MEMTXATTRS_UNSPECIFIED,
> -                             buf, l, 0);
> -        }
> +        cpu_physical_memory_rw_internal(cpu->cpu_ases[asidx].as,
> +                                        phys_addr, buf, l, attrs,
> +                                        type);
>          len -= l;
>          buf += l;
>          addr += l;
> diff --git a/include/exec/memory.h b/include/exec/memory.h
> index 07c5d6d59796..4d027fffeebf 100644
> --- a/include/exec/memory.h
> +++ b/include/exec/memory.h
> @@ -215,6 +215,18 @@ typedef struct IOMMUMemoryRegionClass {
>  typedef struct CoalescedMemoryRange CoalescedMemoryRange;
>  typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
>  
> +/* Memory Region RAM debug callback */
> +typedef struct MemoryRegionRAMReadWriteOps MemoryRegionRAMReadWriteOps;
> +
> +struct MemoryRegionRAMReadWriteOps {
> +    /* Write data into guest memory */
> +    int (*write) (uint8_t *dest, const uint8_t *src,
> +                  uint32_t len, MemTxAttrs attrs);
> +    /* Read data from guest memory */
> +    int (*read) (uint8_t *dest, const uint8_t *src,
> +                 uint32_t len, MemTxAttrs attrs);
> +};
> +
>  struct MemoryRegion {
>      Object parent_obj;
>  
> @@ -254,6 +266,7 @@ struct MemoryRegion {
>      const char *name;
>      unsigned ioeventfd_nb;
>      MemoryRegionIoeventfd *ioeventfds;
> +    const MemoryRegionRAMReadWriteOps *ram_debug_ops;
>  };
>  
>  struct IOMMUMemoryRegion {
> @@ -624,6 +637,20 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
>                                               Error **errp);
>  
>  /**
> + * memory_region_set_ram_debug_ops: Set debug access ops for a given memory region
> + *
> + * @mr: the #MemoryRegion to be initialized
> + * @ops: a function that will be used for when accessing @target region during
> + *       debug
> + */
> +static inline void
> +memory_region_set_ram_debug_ops(MemoryRegion *mr,
> +                                const MemoryRegionRAMReadWriteOps *ops)
> +{
> +    mr->ram_debug_ops = ops;
> +}
> +
> +/**
>   * memory_region_init_reservation: Initialize a memory region that reserves
>   *                                 I/O space.
>   *
> -- 
> 2.9.5
>
Brijesh Singh Jan. 30, 2018, 10:34 p.m. UTC | #2
On 1/30/18 3:59 PM, Edgar E. Iglesias wrote:
> On Mon, Jan 29, 2018 at 11:41:11AM -0600, Brijesh Singh wrote:
>> Currently, the guest memory access for the debug purpose is performed
>> using the memcpy(). Lets extend the 'struct MemoryRegion' to include
>> ram_debug_ops callbacks. The ram_debug_ops can be used to override
>> memcpy() with something else.
>>
>> The feature can be used by encrypted guest -- which can register
>> callbacks to override memcpy() with memory encryption/decryption APIs.
>>
>> a typical usage:
>>
>> mem_read(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
>> mem_write(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
>>
>> MemoryRegionRAMReadWriteOps ops;
>> ops.read = mem_read;
>> ops.write = mem_write;
>
> Hi,
>
> Do these really need to be RAM specific (ram_debug_ops -> debug_ops) ?
> I was hoping a similar infrastructure could be used for MMIO
> debug accesses.

Hi Edgar,

The MMIO regions will contains unencrypted data hence I do not find the
need to add debug hooks for it. A memcpy() to/from MMIO should be fine.
If we see the need for MMIO case then it can extended later.

Brijesh
> Best regards,
> Edgar
>
>
>
>> memory_region_init_ram(mem, NULL, "memory", size, NULL);
>> memory_region_set_ram_debug_ops(mem, ops);
>>
>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>> Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
>> Cc: Richard Henderson <rth@twiddle.net>
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>>  exec.c                | 66 ++++++++++++++++++++++++++++++++++++++-------------
>>  include/exec/memory.h | 27 +++++++++++++++++++++
>>  2 files changed, 77 insertions(+), 16 deletions(-)
>>
>> diff --git a/exec.c b/exec.c
>> index 629a5083851d..1919052b7385 100644
>> --- a/exec.c
>> +++ b/exec.c
>> @@ -3050,7 +3050,11 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
>>          } else {
>>              /* RAM case */
>>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
>> -            memcpy(ptr, buf, l);
>> +            if (attrs.debug && mr->ram_debug_ops) {
>> +                mr->ram_debug_ops->write(ptr, buf, l, attrs);
>> +            } else {
>> +                memcpy(ptr, buf, l);
>> +            }
>>              invalidate_and_set_dirty(mr, addr1, l);
>>          }
>>  
>> @@ -3148,7 +3152,11 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
>>          } else {
>>              /* RAM case */
>>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
>> -            memcpy(buf, ptr, l);
>> +            if (attrs.debug && mr->ram_debug_ops) {
>> +                mr->ram_debug_ops->read(buf, ptr, l, attrs);
>> +            } else {
>> +                memcpy(buf, ptr, l);
>> +            }
>>          }
>>  
>>          if (release_lock) {
>> @@ -3218,11 +3226,13 @@ void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
>>  
>>  enum write_rom_type {
>>      WRITE_DATA,
>> +    READ_DATA,
>>      FLUSH_CACHE,
>>  };
>>  
>> -static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>> -    hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
>> +static inline void cpu_physical_memory_rw_internal(AddressSpace *as,
>> +    hwaddr addr, uint8_t *buf, int len, MemTxAttrs attrs,
>> +    enum write_rom_type type)
>>  {
>>      hwaddr l;
>>      uint8_t *ptr;
>> @@ -3237,12 +3247,33 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>>          if (!(memory_region_is_ram(mr) ||
>>                memory_region_is_romd(mr))) {
>>              l = memory_access_size(mr, l, addr1);
>> +            /* Pass MMIO down to address address_space_rw */
>> +            switch (type) {
>> +            case READ_DATA:
>> +            case WRITE_DATA:
>> +                address_space_rw(as, addr1, attrs, buf, l,
>> +                                 type == WRITE_DATA);
>> +                break;
>> +            case FLUSH_CACHE:
>> +                break;
>> +            }
>>          } else {
>>              /* ROM/RAM case */
>>              ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
>>              switch (type) {
>> +            case READ_DATA:
>> +                if (mr->ram_debug_ops) {
>> +                    mr->ram_debug_ops->read(buf, ptr, l, attrs);
>> +                } else {
>> +                    memcpy(buf, ptr, l);
>> +                }
>> +                break;
>>              case WRITE_DATA:
>> -                memcpy(ptr, buf, l);
>> +                if (mr->ram_debug_ops) {
>> +                    mr->ram_debug_ops->write(ptr, buf, l, attrs);
>> +                } else {
>> +                    memcpy(ptr, buf, l);
>> +                }
>>                  invalidate_and_set_dirty(mr, addr1, l);
>>                  break;
>>              case FLUSH_CACHE:
>> @@ -3261,7 +3292,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>>  void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
>>                                     const uint8_t *buf, int len)
>>  {
>> -    cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
>> +    cpu_physical_memory_rw_internal(as, addr, (uint8_t *)buf, len,
>> +            MEMTXATTRS_UNSPECIFIED, WRITE_DATA);
>>  }
>>  
>>  void cpu_flush_icache_range(hwaddr start, int len)
>> @@ -3276,8 +3308,10 @@ void cpu_flush_icache_range(hwaddr start, int len)
>>          return;
>>      }
>>  
>> -    cpu_physical_memory_write_rom_internal(&address_space_memory,
>> -                                           start, NULL, len, FLUSH_CACHE);
>> +    cpu_physical_memory_rw_internal(&address_space_memory,
>> +                                    start, NULL, len,
>> +                                    MEMTXATTRS_UNSPECIFIED,
>> +                                    FLUSH_CACHE);
>>  }
>>  
>>  typedef struct {
>> @@ -3583,6 +3617,7 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>>      int l;
>>      hwaddr phys_addr;
>>      target_ulong page;
>> +    int type = is_write ? WRITE_DATA : READ_DATA;
>>  
>>      cpu_synchronize_state(cpu);
>>      while (len > 0) {
>> @@ -3592,6 +3627,10 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>>          page = addr & TARGET_PAGE_MASK;
>>          phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
>>          asidx = cpu_asidx_from_attrs(cpu, attrs);
>> +
>> +        /* set debug attrs to indicate memory access is from the debugger */
>> +        attrs.debug = 1;
>> +
>>          /* if no physical page mapped, return an error */
>>          if (phys_addr == -1)
>>              return -1;
>> @@ -3599,14 +3638,9 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>>          if (l > len)
>>              l = len;
>>          phys_addr += (addr & ~TARGET_PAGE_MASK);
>> -        if (is_write) {
>> -            cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
>> -                                          phys_addr, buf, l);
>> -        } else {
>> -            address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
>> -                             MEMTXATTRS_UNSPECIFIED,
>> -                             buf, l, 0);
>> -        }
>> +        cpu_physical_memory_rw_internal(cpu->cpu_ases[asidx].as,
>> +                                        phys_addr, buf, l, attrs,
>> +                                        type);
>>          len -= l;
>>          buf += l;
>>          addr += l;
>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>> index 07c5d6d59796..4d027fffeebf 100644
>> --- a/include/exec/memory.h
>> +++ b/include/exec/memory.h
>> @@ -215,6 +215,18 @@ typedef struct IOMMUMemoryRegionClass {
>>  typedef struct CoalescedMemoryRange CoalescedMemoryRange;
>>  typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
>>  
>> +/* Memory Region RAM debug callback */
>> +typedef struct MemoryRegionRAMReadWriteOps MemoryRegionRAMReadWriteOps;
>> +
>> +struct MemoryRegionRAMReadWriteOps {
>> +    /* Write data into guest memory */
>> +    int (*write) (uint8_t *dest, const uint8_t *src,
>> +                  uint32_t len, MemTxAttrs attrs);
>> +    /* Read data from guest memory */
>> +    int (*read) (uint8_t *dest, const uint8_t *src,
>> +                 uint32_t len, MemTxAttrs attrs);
>> +};
>> +
>>  struct MemoryRegion {
>>      Object parent_obj;
>>  
>> @@ -254,6 +266,7 @@ struct MemoryRegion {
>>      const char *name;
>>      unsigned ioeventfd_nb;
>>      MemoryRegionIoeventfd *ioeventfds;
>> +    const MemoryRegionRAMReadWriteOps *ram_debug_ops;
>>  };
>>  
>>  struct IOMMUMemoryRegion {
>> @@ -624,6 +637,20 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
>>                                               Error **errp);
>>  
>>  /**
>> + * memory_region_set_ram_debug_ops: Set debug access ops for a given memory region
>> + *
>> + * @mr: the #MemoryRegion to be initialized
>> + * @ops: a function that will be used for when accessing @target region during
>> + *       debug
>> + */
>> +static inline void
>> +memory_region_set_ram_debug_ops(MemoryRegion *mr,
>> +                                const MemoryRegionRAMReadWriteOps *ops)
>> +{
>> +    mr->ram_debug_ops = ops;
>> +}
>> +
>> +/**
>>   * memory_region_init_reservation: Initialize a memory region that reserves
>>   *                                 I/O space.
>>   *
>> -- 
>> 2.9.5
>>
Edgar E. Iglesias Jan. 30, 2018, 10:37 p.m. UTC | #3
On Tue, Jan 30, 2018 at 04:34:37PM -0600, Brijesh Singh wrote:
> 
> 
> On 1/30/18 3:59 PM, Edgar E. Iglesias wrote:
> > On Mon, Jan 29, 2018 at 11:41:11AM -0600, Brijesh Singh wrote:
> >> Currently, the guest memory access for the debug purpose is performed
> >> using the memcpy(). Lets extend the 'struct MemoryRegion' to include
> >> ram_debug_ops callbacks. The ram_debug_ops can be used to override
> >> memcpy() with something else.
> >>
> >> The feature can be used by encrypted guest -- which can register
> >> callbacks to override memcpy() with memory encryption/decryption APIs.
> >>
> >> a typical usage:
> >>
> >> mem_read(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
> >> mem_write(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
> >>
> >> MemoryRegionRAMReadWriteOps ops;
> >> ops.read = mem_read;
> >> ops.write = mem_write;
> >
> > Hi,
> >
> > Do these really need to be RAM specific (ram_debug_ops -> debug_ops) ?
> > I was hoping a similar infrastructure could be used for MMIO
> > debug accesses.
> 
> Hi Edgar,
> 
> The MMIO regions will contains unencrypted data hence I do not find the
> need to add debug hooks for it. A memcpy() to/from MMIO should be fine.
> If we see the need for MMIO case then it can extended later.

In this use-case yes, but in a general use-case MMIO regions may also
want to differentiate debug from normal accesses.

I'm not saying you need to implement MMIO examples but do we really
need to have ram_debug_ops and mmio_debug_ops in the future?
Can we get away with one somehow?

Cheers,
Edgar

> 
> Brijesh
> > Best regards,
> > Edgar
> >
> >
> >
> >> memory_region_init_ram(mem, NULL, "memory", size, NULL);
> >> memory_region_set_ram_debug_ops(mem, ops);
> >>
> >> Cc: Paolo Bonzini <pbonzini@redhat.com>
> >> Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
> >> Cc: Richard Henderson <rth@twiddle.net>
> >> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> >> ---
> >>  exec.c                | 66 ++++++++++++++++++++++++++++++++++++++-------------
> >>  include/exec/memory.h | 27 +++++++++++++++++++++
> >>  2 files changed, 77 insertions(+), 16 deletions(-)
> >>
> >> diff --git a/exec.c b/exec.c
> >> index 629a5083851d..1919052b7385 100644
> >> --- a/exec.c
> >> +++ b/exec.c
> >> @@ -3050,7 +3050,11 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
> >>          } else {
> >>              /* RAM case */
> >>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
> >> -            memcpy(ptr, buf, l);
> >> +            if (attrs.debug && mr->ram_debug_ops) {
> >> +                mr->ram_debug_ops->write(ptr, buf, l, attrs);
> >> +            } else {
> >> +                memcpy(ptr, buf, l);
> >> +            }
> >>              invalidate_and_set_dirty(mr, addr1, l);
> >>          }
> >>  
> >> @@ -3148,7 +3152,11 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
> >>          } else {
> >>              /* RAM case */
> >>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
> >> -            memcpy(buf, ptr, l);
> >> +            if (attrs.debug && mr->ram_debug_ops) {
> >> +                mr->ram_debug_ops->read(buf, ptr, l, attrs);
> >> +            } else {
> >> +                memcpy(buf, ptr, l);
> >> +            }
> >>          }
> >>  
> >>          if (release_lock) {
> >> @@ -3218,11 +3226,13 @@ void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
> >>  
> >>  enum write_rom_type {
> >>      WRITE_DATA,
> >> +    READ_DATA,
> >>      FLUSH_CACHE,
> >>  };
> >>  
> >> -static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
> >> -    hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
> >> +static inline void cpu_physical_memory_rw_internal(AddressSpace *as,
> >> +    hwaddr addr, uint8_t *buf, int len, MemTxAttrs attrs,
> >> +    enum write_rom_type type)
> >>  {
> >>      hwaddr l;
> >>      uint8_t *ptr;
> >> @@ -3237,12 +3247,33 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
> >>          if (!(memory_region_is_ram(mr) ||
> >>                memory_region_is_romd(mr))) {
> >>              l = memory_access_size(mr, l, addr1);
> >> +            /* Pass MMIO down to address address_space_rw */
> >> +            switch (type) {
> >> +            case READ_DATA:
> >> +            case WRITE_DATA:
> >> +                address_space_rw(as, addr1, attrs, buf, l,
> >> +                                 type == WRITE_DATA);
> >> +                break;
> >> +            case FLUSH_CACHE:
> >> +                break;
> >> +            }
> >>          } else {
> >>              /* ROM/RAM case */
> >>              ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
> >>              switch (type) {
> >> +            case READ_DATA:
> >> +                if (mr->ram_debug_ops) {
> >> +                    mr->ram_debug_ops->read(buf, ptr, l, attrs);
> >> +                } else {
> >> +                    memcpy(buf, ptr, l);
> >> +                }
> >> +                break;
> >>              case WRITE_DATA:
> >> -                memcpy(ptr, buf, l);
> >> +                if (mr->ram_debug_ops) {
> >> +                    mr->ram_debug_ops->write(ptr, buf, l, attrs);
> >> +                } else {
> >> +                    memcpy(ptr, buf, l);
> >> +                }
> >>                  invalidate_and_set_dirty(mr, addr1, l);
> >>                  break;
> >>              case FLUSH_CACHE:
> >> @@ -3261,7 +3292,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
> >>  void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
> >>                                     const uint8_t *buf, int len)
> >>  {
> >> -    cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
> >> +    cpu_physical_memory_rw_internal(as, addr, (uint8_t *)buf, len,
> >> +            MEMTXATTRS_UNSPECIFIED, WRITE_DATA);
> >>  }
> >>  
> >>  void cpu_flush_icache_range(hwaddr start, int len)
> >> @@ -3276,8 +3308,10 @@ void cpu_flush_icache_range(hwaddr start, int len)
> >>          return;
> >>      }
> >>  
> >> -    cpu_physical_memory_write_rom_internal(&address_space_memory,
> >> -                                           start, NULL, len, FLUSH_CACHE);
> >> +    cpu_physical_memory_rw_internal(&address_space_memory,
> >> +                                    start, NULL, len,
> >> +                                    MEMTXATTRS_UNSPECIFIED,
> >> +                                    FLUSH_CACHE);
> >>  }
> >>  
> >>  typedef struct {
> >> @@ -3583,6 +3617,7 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
> >>      int l;
> >>      hwaddr phys_addr;
> >>      target_ulong page;
> >> +    int type = is_write ? WRITE_DATA : READ_DATA;
> >>  
> >>      cpu_synchronize_state(cpu);
> >>      while (len > 0) {
> >> @@ -3592,6 +3627,10 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
> >>          page = addr & TARGET_PAGE_MASK;
> >>          phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
> >>          asidx = cpu_asidx_from_attrs(cpu, attrs);
> >> +
> >> +        /* set debug attrs to indicate memory access is from the debugger */
> >> +        attrs.debug = 1;
> >> +
> >>          /* if no physical page mapped, return an error */
> >>          if (phys_addr == -1)
> >>              return -1;
> >> @@ -3599,14 +3638,9 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
> >>          if (l > len)
> >>              l = len;
> >>          phys_addr += (addr & ~TARGET_PAGE_MASK);
> >> -        if (is_write) {
> >> -            cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
> >> -                                          phys_addr, buf, l);
> >> -        } else {
> >> -            address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
> >> -                             MEMTXATTRS_UNSPECIFIED,
> >> -                             buf, l, 0);
> >> -        }
> >> +        cpu_physical_memory_rw_internal(cpu->cpu_ases[asidx].as,
> >> +                                        phys_addr, buf, l, attrs,
> >> +                                        type);
> >>          len -= l;
> >>          buf += l;
> >>          addr += l;
> >> diff --git a/include/exec/memory.h b/include/exec/memory.h
> >> index 07c5d6d59796..4d027fffeebf 100644
> >> --- a/include/exec/memory.h
> >> +++ b/include/exec/memory.h
> >> @@ -215,6 +215,18 @@ typedef struct IOMMUMemoryRegionClass {
> >>  typedef struct CoalescedMemoryRange CoalescedMemoryRange;
> >>  typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
> >>  
> >> +/* Memory Region RAM debug callback */
> >> +typedef struct MemoryRegionRAMReadWriteOps MemoryRegionRAMReadWriteOps;
> >> +
> >> +struct MemoryRegionRAMReadWriteOps {
> >> +    /* Write data into guest memory */
> >> +    int (*write) (uint8_t *dest, const uint8_t *src,
> >> +                  uint32_t len, MemTxAttrs attrs);
> >> +    /* Read data from guest memory */
> >> +    int (*read) (uint8_t *dest, const uint8_t *src,
> >> +                 uint32_t len, MemTxAttrs attrs);
> >> +};
> >> +
> >>  struct MemoryRegion {
> >>      Object parent_obj;
> >>  
> >> @@ -254,6 +266,7 @@ struct MemoryRegion {
> >>      const char *name;
> >>      unsigned ioeventfd_nb;
> >>      MemoryRegionIoeventfd *ioeventfds;
> >> +    const MemoryRegionRAMReadWriteOps *ram_debug_ops;
> >>  };
> >>  
> >>  struct IOMMUMemoryRegion {
> >> @@ -624,6 +637,20 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
> >>                                               Error **errp);
> >>  
> >>  /**
> >> + * memory_region_set_ram_debug_ops: Set debug access ops for a given memory region
> >> + *
> >> + * @mr: the #MemoryRegion to be initialized
> >> + * @ops: a function that will be used for when accessing @target region during
> >> + *       debug
> >> + */
> >> +static inline void
> >> +memory_region_set_ram_debug_ops(MemoryRegion *mr,
> >> +                                const MemoryRegionRAMReadWriteOps *ops)
> >> +{
> >> +    mr->ram_debug_ops = ops;
> >> +}
> >> +
> >> +/**
> >>   * memory_region_init_reservation: Initialize a memory region that reserves
> >>   *                                 I/O space.
> >>   *
> >> -- 
> >> 2.9.5
> >>
>
Brijesh Singh Jan. 30, 2018, 11:26 p.m. UTC | #4
On 1/30/18 4:37 PM, Edgar E. Iglesias wrote:
> On Tue, Jan 30, 2018 at 04:34:37PM -0600, Brijesh Singh wrote:
>>
>> On 1/30/18 3:59 PM, Edgar E. Iglesias wrote:
>>> On Mon, Jan 29, 2018 at 11:41:11AM -0600, Brijesh Singh wrote:
>>>> Currently, the guest memory access for the debug purpose is performed
>>>> using the memcpy(). Lets extend the 'struct MemoryRegion' to include
>>>> ram_debug_ops callbacks. The ram_debug_ops can be used to override
>>>> memcpy() with something else.
>>>>
>>>> The feature can be used by encrypted guest -- which can register
>>>> callbacks to override memcpy() with memory encryption/decryption APIs.
>>>>
>>>> a typical usage:
>>>>
>>>> mem_read(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
>>>> mem_write(uint8_t *dst, uint8_t *src, uint32_t len, MemTxAttrs *attrs);
>>>>
>>>> MemoryRegionRAMReadWriteOps ops;
>>>> ops.read = mem_read;
>>>> ops.write = mem_write;
>>> Hi,
>>>
>>> Do these really need to be RAM specific (ram_debug_ops -> debug_ops) ?
>>> I was hoping a similar infrastructure could be used for MMIO
>>> debug accesses.
>> Hi Edgar,
>>
>> The MMIO regions will contains unencrypted data hence I do not find the
>> need to add debug hooks for it. A memcpy() to/from MMIO should be fine.
>> If we see the need for MMIO case then it can extended later.
> In this use-case yes, but in a general use-case MMIO regions may also
> want to differentiate debug from normal accesses.
>
> I'm not saying you need to implement MMIO examples but do we really
> need to have ram_debug_ops and mmio_debug_ops in the future?
> Can we get away with one somehow?

If anyone see this coming in near future then having one debug_ops makes
sense and it should beĀ  doable. If we decide to use debug_ops for MMIO
then I could see us needing to add a new argument to debug_ops callback
to let the client knows whether the access came MMIO vs RAM region
because client may do different things for RAM vs MMIO case (e.g in SEV
RAM is encrypted but MMIO is unencrypted).

> Cheers,
> Edgar
>
>> Brijesh
>>> Best regards,
>>> Edgar
>>>
>>>
>>>
>>>> memory_region_init_ram(mem, NULL, "memory", size, NULL);
>>>> memory_region_set_ram_debug_ops(mem, ops);
>>>>
>>>> Cc: Paolo Bonzini <pbonzini@redhat.com>
>>>> Cc: Peter Crosthwaite <crosthwaite.peter@gmail.com>
>>>> Cc: Richard Henderson <rth@twiddle.net>
>>>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>>>> ---
>>>>  exec.c                | 66 ++++++++++++++++++++++++++++++++++++++-------------
>>>>  include/exec/memory.h | 27 +++++++++++++++++++++
>>>>  2 files changed, 77 insertions(+), 16 deletions(-)
>>>>
>>>> diff --git a/exec.c b/exec.c
>>>> index 629a5083851d..1919052b7385 100644
>>>> --- a/exec.c
>>>> +++ b/exec.c
>>>> @@ -3050,7 +3050,11 @@ static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
>>>>          } else {
>>>>              /* RAM case */
>>>>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
>>>> -            memcpy(ptr, buf, l);
>>>> +            if (attrs.debug && mr->ram_debug_ops) {
>>>> +                mr->ram_debug_ops->write(ptr, buf, l, attrs);
>>>> +            } else {
>>>> +                memcpy(ptr, buf, l);
>>>> +            }
>>>>              invalidate_and_set_dirty(mr, addr1, l);
>>>>          }
>>>>  
>>>> @@ -3148,7 +3152,11 @@ MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
>>>>          } else {
>>>>              /* RAM case */
>>>>              ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
>>>> -            memcpy(buf, ptr, l);
>>>> +            if (attrs.debug && mr->ram_debug_ops) {
>>>> +                mr->ram_debug_ops->read(buf, ptr, l, attrs);
>>>> +            } else {
>>>> +                memcpy(buf, ptr, l);
>>>> +            }
>>>>          }
>>>>  
>>>>          if (release_lock) {
>>>> @@ -3218,11 +3226,13 @@ void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
>>>>  
>>>>  enum write_rom_type {
>>>>      WRITE_DATA,
>>>> +    READ_DATA,
>>>>      FLUSH_CACHE,
>>>>  };
>>>>  
>>>> -static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>>>> -    hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
>>>> +static inline void cpu_physical_memory_rw_internal(AddressSpace *as,
>>>> +    hwaddr addr, uint8_t *buf, int len, MemTxAttrs attrs,
>>>> +    enum write_rom_type type)
>>>>  {
>>>>      hwaddr l;
>>>>      uint8_t *ptr;
>>>> @@ -3237,12 +3247,33 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>>>>          if (!(memory_region_is_ram(mr) ||
>>>>                memory_region_is_romd(mr))) {
>>>>              l = memory_access_size(mr, l, addr1);
>>>> +            /* Pass MMIO down to address address_space_rw */
>>>> +            switch (type) {
>>>> +            case READ_DATA:
>>>> +            case WRITE_DATA:
>>>> +                address_space_rw(as, addr1, attrs, buf, l,
>>>> +                                 type == WRITE_DATA);
>>>> +                break;
>>>> +            case FLUSH_CACHE:
>>>> +                break;
>>>> +            }
>>>>          } else {
>>>>              /* ROM/RAM case */
>>>>              ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
>>>>              switch (type) {
>>>> +            case READ_DATA:
>>>> +                if (mr->ram_debug_ops) {
>>>> +                    mr->ram_debug_ops->read(buf, ptr, l, attrs);
>>>> +                } else {
>>>> +                    memcpy(buf, ptr, l);
>>>> +                }
>>>> +                break;
>>>>              case WRITE_DATA:
>>>> -                memcpy(ptr, buf, l);
>>>> +                if (mr->ram_debug_ops) {
>>>> +                    mr->ram_debug_ops->write(ptr, buf, l, attrs);
>>>> +                } else {
>>>> +                    memcpy(ptr, buf, l);
>>>> +                }
>>>>                  invalidate_and_set_dirty(mr, addr1, l);
>>>>                  break;
>>>>              case FLUSH_CACHE:
>>>> @@ -3261,7 +3292,8 @@ static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
>>>>  void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
>>>>                                     const uint8_t *buf, int len)
>>>>  {
>>>> -    cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
>>>> +    cpu_physical_memory_rw_internal(as, addr, (uint8_t *)buf, len,
>>>> +            MEMTXATTRS_UNSPECIFIED, WRITE_DATA);
>>>>  }
>>>>  
>>>>  void cpu_flush_icache_range(hwaddr start, int len)
>>>> @@ -3276,8 +3308,10 @@ void cpu_flush_icache_range(hwaddr start, int len)
>>>>          return;
>>>>      }
>>>>  
>>>> -    cpu_physical_memory_write_rom_internal(&address_space_memory,
>>>> -                                           start, NULL, len, FLUSH_CACHE);
>>>> +    cpu_physical_memory_rw_internal(&address_space_memory,
>>>> +                                    start, NULL, len,
>>>> +                                    MEMTXATTRS_UNSPECIFIED,
>>>> +                                    FLUSH_CACHE);
>>>>  }
>>>>  
>>>>  typedef struct {
>>>> @@ -3583,6 +3617,7 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>>>>      int l;
>>>>      hwaddr phys_addr;
>>>>      target_ulong page;
>>>> +    int type = is_write ? WRITE_DATA : READ_DATA;
>>>>  
>>>>      cpu_synchronize_state(cpu);
>>>>      while (len > 0) {
>>>> @@ -3592,6 +3627,10 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>>>>          page = addr & TARGET_PAGE_MASK;
>>>>          phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
>>>>          asidx = cpu_asidx_from_attrs(cpu, attrs);
>>>> +
>>>> +        /* set debug attrs to indicate memory access is from the debugger */
>>>> +        attrs.debug = 1;
>>>> +
>>>>          /* if no physical page mapped, return an error */
>>>>          if (phys_addr == -1)
>>>>              return -1;
>>>> @@ -3599,14 +3638,9 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
>>>>          if (l > len)
>>>>              l = len;
>>>>          phys_addr += (addr & ~TARGET_PAGE_MASK);
>>>> -        if (is_write) {
>>>> -            cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
>>>> -                                          phys_addr, buf, l);
>>>> -        } else {
>>>> -            address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
>>>> -                             MEMTXATTRS_UNSPECIFIED,
>>>> -                             buf, l, 0);
>>>> -        }
>>>> +        cpu_physical_memory_rw_internal(cpu->cpu_ases[asidx].as,
>>>> +                                        phys_addr, buf, l, attrs,
>>>> +                                        type);
>>>>          len -= l;
>>>>          buf += l;
>>>>          addr += l;
>>>> diff --git a/include/exec/memory.h b/include/exec/memory.h
>>>> index 07c5d6d59796..4d027fffeebf 100644
>>>> --- a/include/exec/memory.h
>>>> +++ b/include/exec/memory.h
>>>> @@ -215,6 +215,18 @@ typedef struct IOMMUMemoryRegionClass {
>>>>  typedef struct CoalescedMemoryRange CoalescedMemoryRange;
>>>>  typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
>>>>  
>>>> +/* Memory Region RAM debug callback */
>>>> +typedef struct MemoryRegionRAMReadWriteOps MemoryRegionRAMReadWriteOps;
>>>> +
>>>> +struct MemoryRegionRAMReadWriteOps {
>>>> +    /* Write data into guest memory */
>>>> +    int (*write) (uint8_t *dest, const uint8_t *src,
>>>> +                  uint32_t len, MemTxAttrs attrs);
>>>> +    /* Read data from guest memory */
>>>> +    int (*read) (uint8_t *dest, const uint8_t *src,
>>>> +                 uint32_t len, MemTxAttrs attrs);
>>>> +};
>>>> +
>>>>  struct MemoryRegion {
>>>>      Object parent_obj;
>>>>  
>>>> @@ -254,6 +266,7 @@ struct MemoryRegion {
>>>>      const char *name;
>>>>      unsigned ioeventfd_nb;
>>>>      MemoryRegionIoeventfd *ioeventfds;
>>>> +    const MemoryRegionRAMReadWriteOps *ram_debug_ops;
>>>>  };
>>>>  
>>>>  struct IOMMUMemoryRegion {
>>>> @@ -624,6 +637,20 @@ void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
>>>>                                               Error **errp);
>>>>  
>>>>  /**
>>>> + * memory_region_set_ram_debug_ops: Set debug access ops for a given memory region
>>>> + *
>>>> + * @mr: the #MemoryRegion to be initialized
>>>> + * @ops: a function that will be used for when accessing @target region during
>>>> + *       debug
>>>> + */
>>>> +static inline void
>>>> +memory_region_set_ram_debug_ops(MemoryRegion *mr,
>>>> +                                const MemoryRegionRAMReadWriteOps *ops)
>>>> +{
>>>> +    mr->ram_debug_ops = ops;
>>>> +}
>>>> +
>>>> +/**
>>>>   * memory_region_init_reservation: Initialize a memory region that reserves
>>>>   *                                 I/O space.
>>>>   *
>>>> -- 
>>>> 2.9.5
>>>>
diff mbox

Patch

diff --git a/exec.c b/exec.c
index 629a5083851d..1919052b7385 100644
--- a/exec.c
+++ b/exec.c
@@ -3050,7 +3050,11 @@  static MemTxResult flatview_write_continue(FlatView *fv, hwaddr addr,
         } else {
             /* RAM case */
             ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
-            memcpy(ptr, buf, l);
+            if (attrs.debug && mr->ram_debug_ops) {
+                mr->ram_debug_ops->write(ptr, buf, l, attrs);
+            } else {
+                memcpy(ptr, buf, l);
+            }
             invalidate_and_set_dirty(mr, addr1, l);
         }
 
@@ -3148,7 +3152,11 @@  MemTxResult flatview_read_continue(FlatView *fv, hwaddr addr,
         } else {
             /* RAM case */
             ptr = qemu_ram_ptr_length(mr->ram_block, addr1, &l, false);
-            memcpy(buf, ptr, l);
+            if (attrs.debug && mr->ram_debug_ops) {
+                mr->ram_debug_ops->read(buf, ptr, l, attrs);
+            } else {
+                memcpy(buf, ptr, l);
+            }
         }
 
         if (release_lock) {
@@ -3218,11 +3226,13 @@  void cpu_physical_memory_rw(hwaddr addr, uint8_t *buf,
 
 enum write_rom_type {
     WRITE_DATA,
+    READ_DATA,
     FLUSH_CACHE,
 };
 
-static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
-    hwaddr addr, const uint8_t *buf, int len, enum write_rom_type type)
+static inline void cpu_physical_memory_rw_internal(AddressSpace *as,
+    hwaddr addr, uint8_t *buf, int len, MemTxAttrs attrs,
+    enum write_rom_type type)
 {
     hwaddr l;
     uint8_t *ptr;
@@ -3237,12 +3247,33 @@  static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
         if (!(memory_region_is_ram(mr) ||
               memory_region_is_romd(mr))) {
             l = memory_access_size(mr, l, addr1);
+            /* Pass MMIO down to address address_space_rw */
+            switch (type) {
+            case READ_DATA:
+            case WRITE_DATA:
+                address_space_rw(as, addr1, attrs, buf, l,
+                                 type == WRITE_DATA);
+                break;
+            case FLUSH_CACHE:
+                break;
+            }
         } else {
             /* ROM/RAM case */
             ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
             switch (type) {
+            case READ_DATA:
+                if (mr->ram_debug_ops) {
+                    mr->ram_debug_ops->read(buf, ptr, l, attrs);
+                } else {
+                    memcpy(buf, ptr, l);
+                }
+                break;
             case WRITE_DATA:
-                memcpy(ptr, buf, l);
+                if (mr->ram_debug_ops) {
+                    mr->ram_debug_ops->write(ptr, buf, l, attrs);
+                } else {
+                    memcpy(ptr, buf, l);
+                }
                 invalidate_and_set_dirty(mr, addr1, l);
                 break;
             case FLUSH_CACHE:
@@ -3261,7 +3292,8 @@  static inline void cpu_physical_memory_write_rom_internal(AddressSpace *as,
 void cpu_physical_memory_write_rom(AddressSpace *as, hwaddr addr,
                                    const uint8_t *buf, int len)
 {
-    cpu_physical_memory_write_rom_internal(as, addr, buf, len, WRITE_DATA);
+    cpu_physical_memory_rw_internal(as, addr, (uint8_t *)buf, len,
+            MEMTXATTRS_UNSPECIFIED, WRITE_DATA);
 }
 
 void cpu_flush_icache_range(hwaddr start, int len)
@@ -3276,8 +3308,10 @@  void cpu_flush_icache_range(hwaddr start, int len)
         return;
     }
 
-    cpu_physical_memory_write_rom_internal(&address_space_memory,
-                                           start, NULL, len, FLUSH_CACHE);
+    cpu_physical_memory_rw_internal(&address_space_memory,
+                                    start, NULL, len,
+                                    MEMTXATTRS_UNSPECIFIED,
+                                    FLUSH_CACHE);
 }
 
 typedef struct {
@@ -3583,6 +3617,7 @@  int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
     int l;
     hwaddr phys_addr;
     target_ulong page;
+    int type = is_write ? WRITE_DATA : READ_DATA;
 
     cpu_synchronize_state(cpu);
     while (len > 0) {
@@ -3592,6 +3627,10 @@  int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
         page = addr & TARGET_PAGE_MASK;
         phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
         asidx = cpu_asidx_from_attrs(cpu, attrs);
+
+        /* set debug attrs to indicate memory access is from the debugger */
+        attrs.debug = 1;
+
         /* if no physical page mapped, return an error */
         if (phys_addr == -1)
             return -1;
@@ -3599,14 +3638,9 @@  int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
         if (l > len)
             l = len;
         phys_addr += (addr & ~TARGET_PAGE_MASK);
-        if (is_write) {
-            cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
-                                          phys_addr, buf, l);
-        } else {
-            address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
-                             MEMTXATTRS_UNSPECIFIED,
-                             buf, l, 0);
-        }
+        cpu_physical_memory_rw_internal(cpu->cpu_ases[asidx].as,
+                                        phys_addr, buf, l, attrs,
+                                        type);
         len -= l;
         buf += l;
         addr += l;
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 07c5d6d59796..4d027fffeebf 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -215,6 +215,18 @@  typedef struct IOMMUMemoryRegionClass {
 typedef struct CoalescedMemoryRange CoalescedMemoryRange;
 typedef struct MemoryRegionIoeventfd MemoryRegionIoeventfd;
 
+/* Memory Region RAM debug callback */
+typedef struct MemoryRegionRAMReadWriteOps MemoryRegionRAMReadWriteOps;
+
+struct MemoryRegionRAMReadWriteOps {
+    /* Write data into guest memory */
+    int (*write) (uint8_t *dest, const uint8_t *src,
+                  uint32_t len, MemTxAttrs attrs);
+    /* Read data from guest memory */
+    int (*read) (uint8_t *dest, const uint8_t *src,
+                 uint32_t len, MemTxAttrs attrs);
+};
+
 struct MemoryRegion {
     Object parent_obj;
 
@@ -254,6 +266,7 @@  struct MemoryRegion {
     const char *name;
     unsigned ioeventfd_nb;
     MemoryRegionIoeventfd *ioeventfds;
+    const MemoryRegionRAMReadWriteOps *ram_debug_ops;
 };
 
 struct IOMMUMemoryRegion {
@@ -624,6 +637,20 @@  void memory_region_init_rom_device_nomigrate(MemoryRegion *mr,
                                              Error **errp);
 
 /**
+ * memory_region_set_ram_debug_ops: Set debug access ops for a given memory region
+ *
+ * @mr: the #MemoryRegion to be initialized
+ * @ops: a function that will be used for when accessing @target region during
+ *       debug
+ */
+static inline void
+memory_region_set_ram_debug_ops(MemoryRegion *mr,
+                                const MemoryRegionRAMReadWriteOps *ops)
+{
+    mr->ram_debug_ops = ops;
+}
+
+/**
  * memory_region_init_reservation: Initialize a memory region that reserves
  *                                 I/O space.
  *