diff mbox series

[1/2] cpu: Do not reset a vCPU before it is created

Message ID 20200309121103.20234-2-philmd@redhat.com (mailing list archive)
State New, archived
Headers show
Series cpu: Avoid latent bug calling cpu_reset() on uninitialized vCPU | expand

Commit Message

Philippe Mathieu-Daudé March 9, 2020, 12:11 p.m. UTC
cpu_reset() might modify architecture-specific fields allocated
by qemu_init_vcpu(). To avoid bugs similar to the one fixed in
commit 00d0f7cb66 when introducing new architectures, move the
cpu_reset() calls after qemu_init_vcpu().

Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
---
 target/cris/cpu.c    | 2 +-
 target/lm32/cpu.c    | 3 +--
 target/m68k/cpu.c    | 2 +-
 target/mips/cpu.c    | 2 +-
 target/sh4/cpu.c     | 2 +-
 target/tilegx/cpu.c  | 2 +-
 target/tricore/cpu.c | 2 +-
 7 files changed, 7 insertions(+), 8 deletions(-)

Comments

Laurent Vivier March 9, 2020, 1:08 p.m. UTC | #1
Le 09/03/2020 à 13:11, Philippe Mathieu-Daudé a écrit :
> cpu_reset() might modify architecture-specific fields allocated
> by qemu_init_vcpu(). To avoid bugs similar to the one fixed in
> commit 00d0f7cb66 when introducing new architectures, move the
> cpu_reset() calls after qemu_init_vcpu().
> 
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> ---
>  target/cris/cpu.c    | 2 +-
>  target/lm32/cpu.c    | 3 +--
>  target/m68k/cpu.c    | 2 +-
>  target/mips/cpu.c    | 2 +-
>  target/sh4/cpu.c     | 2 +-
>  target/tilegx/cpu.c  | 2 +-
>  target/tricore/cpu.c | 2 +-
>  7 files changed, 7 insertions(+), 8 deletions(-)
> 
> diff --git a/target/cris/cpu.c b/target/cris/cpu.c
> index 17c6712e29..9b8b99840d 100644
> --- a/target/cris/cpu.c
> +++ b/target/cris/cpu.c
> @@ -134,8 +134,8 @@ static void cris_cpu_realizefn(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    cpu_reset(cs);
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      ccc->parent_realize(dev, errp);
>  }
> diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c
> index 687bf35e65..56f7b97c8f 100644
> --- a/target/lm32/cpu.c
> +++ b/target/lm32/cpu.c
> @@ -132,9 +132,8 @@ static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    cpu_reset(cs);
> -
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      lcc->parent_realize(dev, errp);
>  }
> diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
> index f0653cda2f..51ca62694e 100644
> --- a/target/m68k/cpu.c
> +++ b/target/m68k/cpu.c
> @@ -247,8 +247,8 @@ static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)
>  
>      m68k_cpu_init_gdb(cpu);
>  
> -    cpu_reset(cs);
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      mcc->parent_realize(dev, errp);
>  }
> diff --git a/target/mips/cpu.c b/target/mips/cpu.c
> index 6cd6b9650b..553945005f 100644
> --- a/target/mips/cpu.c
> +++ b/target/mips/cpu.c
> @@ -149,8 +149,8 @@ static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
>  
>      cpu_mips_realize_env(&cpu->env);
>  
> -    cpu_reset(cs);
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      mcc->parent_realize(dev, errp);
>  }
> diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
> index 70c8d8170f..2564436719 100644
> --- a/target/sh4/cpu.c
> +++ b/target/sh4/cpu.c
> @@ -184,8 +184,8 @@ static void superh_cpu_realizefn(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    cpu_reset(cs);
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      scc->parent_realize(dev, errp);
>  }
> diff --git a/target/tilegx/cpu.c b/target/tilegx/cpu.c
> index cd422a0467..7e9982197f 100644
> --- a/target/tilegx/cpu.c
> +++ b/target/tilegx/cpu.c
> @@ -91,8 +91,8 @@ static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp)
>          return;
>      }
>  
> -    cpu_reset(cs);
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      tcc->parent_realize(dev, errp);
>  }
> diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
> index 85bc9f03a1..c5a5d54569 100644
> --- a/target/tricore/cpu.c
> +++ b/target/tricore/cpu.c
> @@ -94,8 +94,8 @@ static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)
>      if (tricore_feature(env, TRICORE_FEATURE_131)) {
>          set_feature(env, TRICORE_FEATURE_13);
>      }
> -    cpu_reset(cs);
>      qemu_init_vcpu(cs);
> +    cpu_reset(cs);
>  
>      tcc->parent_realize(dev, errp);
>  }
> 

Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Peter Maydell March 9, 2020, 1:09 p.m. UTC | #2
On Mon, 9 Mar 2020 at 12:11, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>
> cpu_reset() might modify architecture-specific fields allocated
> by qemu_init_vcpu(). To avoid bugs similar to the one fixed in
> commit 00d0f7cb66 when introducing new architectures, move the
> cpu_reset() calls after qemu_init_vcpu().
>
> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>

Why do we need to call cpu_reset() from realize anyway?
Generally for devices this is incorrect as they should be
being reset by some other mechanism.

Obviously actually determining that dropping the cpu_reset()
call is safe would require some tedious auditing.

If we do do a cpu_reset() in realize, should it be after
the call to the parent realize function ?

thanks
-- PMM
Laurent Vivier March 9, 2020, 1:13 p.m. UTC | #3
Le 09/03/2020 à 14:09, Peter Maydell a écrit :
> On Mon, 9 Mar 2020 at 12:11, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>>
>> cpu_reset() might modify architecture-specific fields allocated
>> by qemu_init_vcpu(). To avoid bugs similar to the one fixed in
>> commit 00d0f7cb66 when introducing new architectures, move the
>> cpu_reset() calls after qemu_init_vcpu().
>>
>> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> 
> Why do we need to call cpu_reset() from realize anyway?
> Generally for devices this is incorrect as they should be
> being reset by some other mechanism.

I have this same change in my branch for q800 to set the initial PC and
stack pointer read from memory on cold boot.

Do we have another way to do that?

Thanks,
Laurent
Peter Maydell March 9, 2020, 1:18 p.m. UTC | #4
On Mon, 9 Mar 2020 at 13:13, Laurent Vivier <laurent@vivier.eu> wrote:
>
> Le 09/03/2020 à 14:09, Peter Maydell a écrit :
> > On Mon, 9 Mar 2020 at 12:11, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
> >>
> >> cpu_reset() might modify architecture-specific fields allocated
> >> by qemu_init_vcpu(). To avoid bugs similar to the one fixed in
> >> commit 00d0f7cb66 when introducing new architectures, move the
> >> cpu_reset() calls after qemu_init_vcpu().
> >>
> >> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
> >
> > Why do we need to call cpu_reset() from realize anyway?
> > Generally for devices this is incorrect as they should be
> > being reset by some other mechanism.
>
> I have this same change in my branch for q800 to set the initial PC and
> stack pointer read from memory on cold boot.
>
> Do we have another way to do that?

The expectation at the moment is that the board code should
register a reset function with qemu_register_reset() which
calls cpu_reset(). Relying on doing a reset in realize won't
work for the case where there's a QEMU system reset, because
we don't re-init/realize everything, we just call all the
reset hooks.

If m68k reads pc/sp from memory on reset you'll probably run
into the same reset-ordering vs hw/cpu/loader.c that Arm M-profile
has; we currently work around that in the arm reset function.
I had hoped that 3-phase reset would resolve this reset order
issue, but it has not turned out to be so easy.

thanks
-- PMM
Laurent Vivier March 9, 2020, 1:28 p.m. UTC | #5
Le 09/03/2020 à 14:18, Peter Maydell a écrit :
> On Mon, 9 Mar 2020 at 13:13, Laurent Vivier <laurent@vivier.eu> wrote:
>>
>> Le 09/03/2020 à 14:09, Peter Maydell a écrit :
>>> On Mon, 9 Mar 2020 at 12:11, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>>>>
>>>> cpu_reset() might modify architecture-specific fields allocated
>>>> by qemu_init_vcpu(). To avoid bugs similar to the one fixed in
>>>> commit 00d0f7cb66 when introducing new architectures, move the
>>>> cpu_reset() calls after qemu_init_vcpu().
>>>>
>>>> Signed-off-by: Philippe Mathieu-Daudé <philmd@redhat.com>
>>>
>>> Why do we need to call cpu_reset() from realize anyway?
>>> Generally for devices this is incorrect as they should be
>>> being reset by some other mechanism.
>>
>> I have this same change in my branch for q800 to set the initial PC and
>> stack pointer read from memory on cold boot.
>>
>> Do we have another way to do that?
> 
> The expectation at the moment is that the board code should
> register a reset function with qemu_register_reset() which
> calls cpu_reset(). Relying on doing a reset in realize won't
> work for the case where there's a QEMU system reset, because
> we don't re-init/realize everything, we just call all the
> reset hooks.
> 
> If m68k reads pc/sp from memory on reset you'll probably run
> into the same reset-ordering vs hw/cpu/loader.c that Arm M-profile
> has; we currently work around that in the arm reset function.
> I had hoped that 3-phase reset would resolve this reset order
> issue, but it has not turned out to be so easy.


Thank you for the hint, I'll have a look.

Laurent
diff mbox series

Patch

diff --git a/target/cris/cpu.c b/target/cris/cpu.c
index 17c6712e29..9b8b99840d 100644
--- a/target/cris/cpu.c
+++ b/target/cris/cpu.c
@@ -134,8 +134,8 @@  static void cris_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     ccc->parent_realize(dev, errp);
 }
diff --git a/target/lm32/cpu.c b/target/lm32/cpu.c
index 687bf35e65..56f7b97c8f 100644
--- a/target/lm32/cpu.c
+++ b/target/lm32/cpu.c
@@ -132,9 +132,8 @@  static void lm32_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    cpu_reset(cs);
-
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     lcc->parent_realize(dev, errp);
 }
diff --git a/target/m68k/cpu.c b/target/m68k/cpu.c
index f0653cda2f..51ca62694e 100644
--- a/target/m68k/cpu.c
+++ b/target/m68k/cpu.c
@@ -247,8 +247,8 @@  static void m68k_cpu_realizefn(DeviceState *dev, Error **errp)
 
     m68k_cpu_init_gdb(cpu);
 
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     mcc->parent_realize(dev, errp);
 }
diff --git a/target/mips/cpu.c b/target/mips/cpu.c
index 6cd6b9650b..553945005f 100644
--- a/target/mips/cpu.c
+++ b/target/mips/cpu.c
@@ -149,8 +149,8 @@  static void mips_cpu_realizefn(DeviceState *dev, Error **errp)
 
     cpu_mips_realize_env(&cpu->env);
 
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     mcc->parent_realize(dev, errp);
 }
diff --git a/target/sh4/cpu.c b/target/sh4/cpu.c
index 70c8d8170f..2564436719 100644
--- a/target/sh4/cpu.c
+++ b/target/sh4/cpu.c
@@ -184,8 +184,8 @@  static void superh_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     scc->parent_realize(dev, errp);
 }
diff --git a/target/tilegx/cpu.c b/target/tilegx/cpu.c
index cd422a0467..7e9982197f 100644
--- a/target/tilegx/cpu.c
+++ b/target/tilegx/cpu.c
@@ -91,8 +91,8 @@  static void tilegx_cpu_realizefn(DeviceState *dev, Error **errp)
         return;
     }
 
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     tcc->parent_realize(dev, errp);
 }
diff --git a/target/tricore/cpu.c b/target/tricore/cpu.c
index 85bc9f03a1..c5a5d54569 100644
--- a/target/tricore/cpu.c
+++ b/target/tricore/cpu.c
@@ -94,8 +94,8 @@  static void tricore_cpu_realizefn(DeviceState *dev, Error **errp)
     if (tricore_feature(env, TRICORE_FEATURE_131)) {
         set_feature(env, TRICORE_FEATURE_13);
     }
-    cpu_reset(cs);
     qemu_init_vcpu(cs);
+    cpu_reset(cs);
 
     tcc->parent_realize(dev, errp);
 }