Skip to content
  • Peter Maydell's avatar
    3a45f4f5
    target/arm/arm-powerctl: Correctly init CPUs when powered on to lower EL · 3a45f4f5
    Peter Maydell authored
    The code for powering on a CPU in arm-powerctl.c has two separate
    use cases:
     * emulation of a real hardware power controller
     * emulation of firmware interfaces (primarily PSCI) with
       CPU on/off APIs
    
    For the first case, we only need to reset the CPU and set its
    starting PC and X0.  For the second case, because we're emulating the
    firmware we need to ensure that it's in the state that the firmware
    provides.  In particular, when we reset to a lower EL than the
    highest one we are emulating, we need to put the CPU into a state
    that permits correct running at that lower EL.  We already do a
    little of this in arm-powerctl.c (for instance we set SCR_HCE to
    enable the HVC insn) but we don't do enough of it.  This means that
    in the case where we are emulating EL3 but also providing emulated
    PSCI the guest will crash when a secondary core tries to use a
    feature that needs an SCR_EL3 bit to be set, such as MTE or PAuth.
    
    The hw/arm/boot.c code also has to support this "start guest code in
    an EL that's lower than the highest emulated EL" case in order to do
    direct guest kernel booting; it has all the necessary initialization
    code to set the SCR_EL3 bits.  Pull the relevant boot.c code out into
    a separate function so we can share it between there and
    arm-powerctl.c.
    
    This refactoring has a few code changes that look like they
    might be behaviour changes but aren't:
     * if info->secure_boot is false and info->secure_board_setup is
       true, then the old code would start the first CPU in Hyp
       mode but without changing SCR.NS and NSACR.{CP11,CP10}.
       This was wrong behaviour because there's no such thing
       as Secure Hyp mode. The new code will leave the CPU in SVC.
       (There is no board which sets secure_boot to false and
       secure_board_setup to true, so this isn't a behaviour
       change for any of our boards.)
     * we don't explicitly clear SCR.NS when arm-powerctl.c
       does a CPU-on to EL3. This was a no-op because CPU reset
       will reset to NS == 0.
    
    And some real behaviour changes:
     * we no longer set HCR_EL2.RW when booting into EL2: the guest
       can and should do that themselves before dropping into their
       EL1 code. (arm-powerctl and boot did this differently; I
       opted to use the logic from arm-powerctl, which only sets
       HCR_EL2.RW when it's directly starting the guest in EL1,
       because it's more correct, and I don't expect guests to be
       accidentally depending on our having set the RW bit for them.)
     * if we are booting a CPU into AArch32 Secure SVC then we won't
       set SCR.HCE any more. This affects only the vexpress-a15 and
       raspi2b machine types. Guests booting in this case will either:
        - be able to set SCR.HCE themselves as part of moving from
          Secure SVC into NS Hyp mode
        - will move from Secure SVC to NS SVC, and won't care about
          behaviour of the HVC insn
        - will stay in Secure SVC, and won't care about HVC
     * on an arm-powerctl CPU-on we will now set the SCR bits for
       pauth/mte/sve/sme/hcx/fgt features
    
    The first two of these are very minor and I don't expect guest
    code to trip over them, so I didn't judge it worth convoluting
    the code in an attempt to keep exactly the same boot.c behaviour.
    The third change fixes issue 1899.
    
    Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1899
    
    
    Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
    Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
    Message-id: 20230926155619.4028618-1-peter.maydell@linaro.org
    3a45f4f5
    target/arm/arm-powerctl: Correctly init CPUs when powered on to lower EL
    Peter Maydell authored
    The code for powering on a CPU in arm-powerctl.c has two separate
    use cases:
     * emulation of a real hardware power controller
     * emulation of firmware interfaces (primarily PSCI) with
       CPU on/off APIs
    
    For the first case, we only need to reset the CPU and set its
    starting PC and X0.  For the second case, because we're emulating the
    firmware we need to ensure that it's in the state that the firmware
    provides.  In particular, when we reset to a lower EL than the
    highest one we are emulating, we need to put the CPU into a state
    that permits correct running at that lower EL.  We already do a
    little of this in arm-powerctl.c (for instance we set SCR_HCE to
    enable the HVC insn) but we don't do enough of it.  This means that
    in the case where we are emulating EL3 but also providing emulated
    PSCI the guest will crash when a secondary core tries to use a
    feature that needs an SCR_EL3 bit to be set, such as MTE or PAuth.
    
    The hw/arm/boot.c code also has to support this "start guest code in
    an EL that's lower than the highest emulated EL" case in order to do
    direct guest kernel booting; it has all the necessary initialization
    code to set the SCR_EL3 bits.  Pull the relevant boot.c code out into
    a separate function so we can share it between there and
    arm-powerctl.c.
    
    This refactoring has a few code changes that look like they
    might be behaviour changes but aren't:
     * if info->secure_boot is false and info->secure_board_setup is
       true, then the old code would start the first CPU in Hyp
       mode but without changing SCR.NS and NSACR.{CP11,CP10}.
       This was wrong behaviour because there's no such thing
       as Secure Hyp mode. The new code will leave the CPU in SVC.
       (There is no board which sets secure_boot to false and
       secure_board_setup to true, so this isn't a behaviour
       change for any of our boards.)
     * we don't explicitly clear SCR.NS when arm-powerctl.c
       does a CPU-on to EL3. This was a no-op because CPU reset
       will reset to NS == 0.
    
    And some real behaviour changes:
     * we no longer set HCR_EL2.RW when booting into EL2: the guest
       can and should do that themselves before dropping into their
       EL1 code. (arm-powerctl and boot did this differently; I
       opted to use the logic from arm-powerctl, which only sets
       HCR_EL2.RW when it's directly starting the guest in EL1,
       because it's more correct, and I don't expect guests to be
       accidentally depending on our having set the RW bit for them.)
     * if we are booting a CPU into AArch32 Secure SVC then we won't
       set SCR.HCE any more. This affects only the vexpress-a15 and
       raspi2b machine types. Guests booting in this case will either:
        - be able to set SCR.HCE themselves as part of moving from
          Secure SVC into NS Hyp mode
        - will move from Secure SVC to NS SVC, and won't care about
          behaviour of the HVC insn
        - will stay in Secure SVC, and won't care about HVC
     * on an arm-powerctl CPU-on we will now set the SCR bits for
       pauth/mte/sve/sme/hcx/fgt features
    
    The first two of these are very minor and I don't expect guest
    code to trip over them, so I didn't judge it worth convoluting
    the code in an attempt to keep exactly the same boot.c behaviour.
    The third change fixes issue 1899.
    
    Resolves: https://gitlab.com/qemu-project/qemu/-/issues/1899
    
    
    Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
    Reviewed-by: default avatarRichard Henderson <richard.henderson@linaro.org>
    Message-id: 20230926155619.4028618-1-peter.maydell@linaro.org
Loading