diff mbox series

physmem: allow debug writes to MMIO regions

Message ID 20240513233305.2975295-1-perry@mosi.io
State New
Headers show
Series physmem: allow debug writes to MMIO regions | expand

Commit Message

Perry Hung May 13, 2024, 11:33 p.m. UTC
Writes from GDB to memory-mapped IO regions are currently silently
dropped. cpu_memory_rw_debug() calls address_space_write_rom(), which
calls address_space_write_rom_internal(), which ignores all non-ram/rom
regions.

Add a check for MMIO regions and direct those to address_space_rw()
instead.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/213
Signed-off-by: Perry Hung <perry@mosi.io>
---
 system/physmem.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

Comments

Philippe Mathieu-Daudé May 15, 2024, 12:49 p.m. UTC | #1
Hi Perry,

On 14/5/24 01:33, Perry Hung wrote:
> Writes from GDB to memory-mapped IO regions are currently silently
> dropped. cpu_memory_rw_debug() calls address_space_write_rom(), which
> calls address_space_write_rom_internal(), which ignores all non-ram/rom
> regions.
> 
> Add a check for MMIO regions and direct those to address_space_rw()
> instead.
> 

Reported-by: Andreas Rasmusson <andreas.rasmusson@gmail.com>
BugLink: https://bugs.launchpad.net/qemu/+bug/1625216

> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/213
> Signed-off-by: Perry Hung <perry@mosi.io>
> ---
>   system/physmem.c | 5 ++++-
>   1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/system/physmem.c b/system/physmem.c
> index 342b7a8fd4..013cdd2ab1 100644
> --- a/system/physmem.c
> +++ b/system/physmem.c
> @@ -3508,7 +3508,10 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
>           if (l > len)
>               l = len;
>           phys_addr += (addr & ~TARGET_PAGE_MASK);
> -        if (is_write) {
> +        if (cpu_physical_memory_is_io(phys_addr)) {
> +            res = address_space_rw(cpu->cpu_ases[asidx].as, phys_addr, attrs,
> +                                   buf, l, is_write);
> +        } else if (is_write) {
>               res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr,
>                                             attrs, buf, l);
>           } else {

I wonder if we shouldn't be safer with a preliminary patch
adding a 'can_do_io' boolean argument to cpu_memory_rw_debug()
(updating the call sites), then this patch would become:

     if (can_do_io && cpu_physical_memory_is_io(phys_addr)) {

One of my worries for example is if someone accidently insert
a breakpoint at a I/O address, the device might change its
state and return MEMTX_OK which is confusing.

Regards,

Phil.
Peter Maydell May 20, 2024, 5:22 p.m. UTC | #2
On Wed, 15 May 2024 at 13:49, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>
> Hi Perry,
>
> On 14/5/24 01:33, Perry Hung wrote:
> > Writes from GDB to memory-mapped IO regions are currently silently
> > dropped. cpu_memory_rw_debug() calls address_space_write_rom(), which
> > calls address_space_write_rom_internal(), which ignores all non-ram/rom
> > regions.
> >
> > Add a check for MMIO regions and direct those to address_space_rw()
> > instead.
> >
>
> Reported-by: Andreas Rasmusson <andreas.rasmusson@gmail.com>
> BugLink: https://bugs.launchpad.net/qemu/+bug/1625216
>
> > Resolves: https://gitlab.com/qemu-project/qemu/-/issues/213
> > Signed-off-by: Perry Hung <perry@mosi.io>
> > ---
> >   system/physmem.c | 5 ++++-
> >   1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/system/physmem.c b/system/physmem.c
> > index 342b7a8fd4..013cdd2ab1 100644
> > --- a/system/physmem.c
> > +++ b/system/physmem.c
> > @@ -3508,7 +3508,10 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
> >           if (l > len)
> >               l = len;
> >           phys_addr += (addr & ~TARGET_PAGE_MASK);
> > -        if (is_write) {
> > +        if (cpu_physical_memory_is_io(phys_addr)) {
> > +            res = address_space_rw(cpu->cpu_ases[asidx].as, phys_addr, attrs,
> > +                                   buf, l, is_write);
> > +        } else if (is_write) {
> >               res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr,
> >                                             attrs, buf, l);
> >           } else {

The other option is to make address_space_write_rom_internal()
also write to devices...

> I wonder if we shouldn't be safer with a preliminary patch
> adding a 'can_do_io' boolean argument to cpu_memory_rw_debug()
> (updating the call sites), then this patch would become:
>
>      if (can_do_io && cpu_physical_memory_is_io(phys_addr)) {
>
> One of my worries for example is if someone accidently insert
> a breakpoint at a I/O address, the device might change its
> state and return MEMTX_OK which is confusing.

You can definitely do some silly things if we remove this
restriction.

On the other hand if you're using gdb as a debugger on real
(bare metal) hardware does anything stop you doing that?

-- PMM
Perry Hung May 20, 2024, 6:48 p.m. UTC | #3
Philippe, Peter,

Thank you for the comments. I am not even sure what the semantics of 
putting a breakpoint or watchpoint
on device regions are supposed to be. I would imagine it is 
architecture-specific as to whether this is even allowed.

It appears for example, that armv8-a allows watchpoints to be set on any 
type of memory. armv7-a prohibits
watchpoints on Device or Strongly-ordered memory that might be accessed 
by instructions multiple times
(e.g LDM and LDC instructions).

What is the current behavior for QEMU and what should 
breakpoints/watchpoints do when placed on IO memory?

-perry

On 5/20/24 10:22 AM, Peter Maydell wrote:
> On Wed, 15 May 2024 at 13:49, Philippe Mathieu-Daudé <philmd@linaro.org> wrote:
>> Hi Perry,
>>
>> On 14/5/24 01:33, Perry Hung wrote:
>>> Writes from GDB to memory-mapped IO regions are currently silently
>>> dropped. cpu_memory_rw_debug() calls address_space_write_rom(), which
>>> calls address_space_write_rom_internal(), which ignores all non-ram/rom
>>> regions.
>>>
>>> Add a check for MMIO regions and direct those to address_space_rw()
>>> instead.
>>>
>> Reported-by: Andreas Rasmusson <andreas.rasmusson@gmail.com>
>> BugLink: https://bugs.launchpad.net/qemu/+bug/1625216
>>
>>> Resolves: https://gitlab.com/qemu-project/qemu/-/issues/213
>>> Signed-off-by: Perry Hung <perry@mosi.io>
>>> ---
>>>    system/physmem.c | 5 ++++-
>>>    1 file changed, 4 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/system/physmem.c b/system/physmem.c
>>> index 342b7a8fd4..013cdd2ab1 100644
>>> --- a/system/physmem.c
>>> +++ b/system/physmem.c
>>> @@ -3508,7 +3508,10 @@ int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
>>>            if (l > len)
>>>                l = len;
>>>            phys_addr += (addr & ~TARGET_PAGE_MASK);
>>> -        if (is_write) {
>>> +        if (cpu_physical_memory_is_io(phys_addr)) {
>>> +            res = address_space_rw(cpu->cpu_ases[asidx].as, phys_addr, attrs,
>>> +                                   buf, l, is_write);
>>> +        } else if (is_write) {
>>>                res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr,
>>>                                              attrs, buf, l);
>>>            } else {
> The other option is to make address_space_write_rom_internal()
> also write to devices...
>
>> I wonder if we shouldn't be safer with a preliminary patch
>> adding a 'can_do_io' boolean argument to cpu_memory_rw_debug()
>> (updating the call sites), then this patch would become:
>>
>>       if (can_do_io && cpu_physical_memory_is_io(phys_addr)) {
>>
>> One of my worries for example is if someone accidently insert
>> a breakpoint at a I/O address, the device might change its
>> state and return MEMTX_OK which is confusing.
> You can definitely do some silly things if we remove this
> restriction.
>
> On the other hand if you're using gdb as a debugger on real
> (bare metal) hardware does anything stop you doing that?
>
> -- PMM
diff mbox series

Patch

diff --git a/system/physmem.c b/system/physmem.c
index 342b7a8fd4..013cdd2ab1 100644
--- a/system/physmem.c
+++ b/system/physmem.c
@@ -3508,7 +3508,10 @@  int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
         if (l > len)
             l = len;
         phys_addr += (addr & ~TARGET_PAGE_MASK);
-        if (is_write) {
+        if (cpu_physical_memory_is_io(phys_addr)) {
+            res = address_space_rw(cpu->cpu_ases[asidx].as, phys_addr, attrs,
+                                   buf, l, is_write);
+        } else if (is_write) {
             res = address_space_write_rom(cpu->cpu_ases[asidx].as, phys_addr,
                                           attrs, buf, l);
         } else {