qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: Igor Mammedov <imammedo@redhat.com>, qemu-devel@nongnu.org
Cc: yingwen.chen@intel.com, devel@edk2.groups.io,
	phillip.goerl@oracle.com, alex.williamson@redhat.com,
	jiewen.yao@intel.com, jun.nakajima@intel.com,
	michael.d.kinney@intel.com, pbonzini@redhat.com,
	boris.ostrovsky@oracle.com, rfc@edk2.groups.io,
	joao.m.martins@oracle.com
Subject: Re: [Qemu-devel] [PATCH] q35: lpc: allow to lock down 128K RAM at default SMBASE address
Date: Mon, 9 Sep 2019 21:15:44 +0200	[thread overview]
Message-ID: <dbe8cc44-ef30-3104-2bd3-6a6fe4438ada@redhat.com> (raw)
In-Reply-To: <20190905154925.30478-1-imammedo@redhat.com>

Hi Igor,

On 09/05/19 17:49, Igor Mammedov wrote:
> lpc already has SMI negotiation feature, extend it by adding
> optin ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT to supported features.
>
> Writing this bit into "etc/smi/requested-features" fw_cfg file,
> tells QEMU to alias 0x30000,128K RAM range into SMRAM address
> space and mask this region from normal RAM address space
> (reads return 0xff and writes are ignored, i.e. guest code
> should be able to deal with not usable 0x30000,128K RAM range
> once ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT is activated).
>
> To make negotiated change effective, guest should read
> "etc/smi/features-ok" fw_cfg file, which activates negotiated
> features and locks down negotiating capabilities until hard reset.
>
> Flow for initializing SMI handler on guest side:
>  1. set SMI handler entry point at default SMBASE location
>  2. check that host supports ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT
>     in "etc/smi/supported-features" and set if supported set
>     it in "etc/smi/requested-features"
>  3. read "etc/smi/features-ok", if returned value is 1
>     negotiated at step 2 features are activated successfully.

Tying the [0x30000+128K) lockdown to the broadcast SMI negotiation is a
simplification for QEMU, but it is a complication for OVMF.

(This QEMU patch ties those things together in effect because
"etc/smi/features-ok" can be selected for lockdown only once.)

In OVMF, at least 6 modules are involved in SMM setup. Here I'm only
going to list some steps for 4 modules (skipping
"OvmfPkg/SmmAccess/SmmAccess2Dxe.inf" and
"UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf").


(1) The "OvmfPkg/SmmControl2Dxe/SmmControl2Dxe.inf" driver is launched,
and it produces the EFI_SMM_CONTROL2_PROTOCOL.

EFI_SMM_CONTROL2_PROTOCOL.Trigger() is the standard / abstract method
for synchronously raising an SMI. The OVMF implementation writes to IO
port 0xB2.

Because OVMF exposes this protocol to the rest of the firmware, it first
negotiates SMI broadcast, if QEMU offers it. The idea is that, without
negotiating SMI broadcast (if it's available), EFI_SMM_CONTROL2_PROTOCOL
is not fully configured, and should not be exposed. (Because, Trigger()
wouldn't work properly). Incomplete / halfway functional protocols are
not to be published.

That is, we have

(1a) negotiate SMI broadcast
(1b) install EFI_SMM_CONTROL2_PROTOCOL.


(2) Dependent on EFI_SMM_CONTROL2_PROTOCOL, the SMM IPL (Initial Program
Load -- "MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf") is launched.

This module
(2a) registers a callback for EFI_SMM_CONFIGURATION_PROTOCOL,
(2b) loads the SMM Core ("MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf")
     into SMRAM and starts it.


(3) The SMM Core launches the SMM processor driver
("UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf").

The SMM processor driver
(3a) performs the initial SMBASE relocation,
(3b) and then installs EFI_SMM_CONFIGURATION_PROTOCOL.

(Side remark: the SMM processor driver does not use IO port 0xB2 (it
does not call Trigger()); it uses LAPIC accesses. This is by design (PI
spec); Trigger() is supposed to be called  after the relocation is done,
and not for starting the relocation.)


(4) The SMM IPL's callback fires. It uses EFI_SMM_CONFIGURATION_PROTOCOL
to connect the platform-independent SMM entry point (= central
high-level SMI handler), which is in the SMM Core, into the low-level
(CPU-specific) SMI handler in the SMM processor driver.

At this point, SMIs are considered fully functional. General drivers
that are split into privileged (SMM) and unprivileged (runtime DXE)
halves, such as the variable service driver, can use
EFI_SMM_COMMUNICATION_PROTOCOL to submit messages to the privileged
(SMM) halves. And that boils down to EFI_SMM_CONTROL2_PROTOCOL.Trigger()
calls, which depends on SMI broadcast.

--*--

The present QEMU patch requires the firmware to (i) negotiate SMI
broadcast and to (ii) lock down [0x30000+128K) at the same time.

If OVMF does both in step (1a) -- i.e. where it currently negotiates the
broadcast --, then step (3a) breaks: because the initial SMBASE
relocation depends on RAM at [0x30000+128K).

In a theoretical ordering perspective, we could perhaps move the logic
from step (1a) between steps (3a) and (3b). There are two problems with
that:

- The platform logic from step (1a) doesn't belong in the SMM processor
driver (even if we managed to hook it in).

- In step (1b), we'd be installing a protocol
(EFI_SMM_CONTROL2_PROTOCOL) that is simply not set up correctly -- it's
incomplete.


Can QEMU offer this new "[0x30000+128K) lockdown" hardware feature in a
separate platform device? (Such as a PCI device with fixed
(QEMU-specified) B/D/F, and config space register(s).)

It would be less difficult to lock such hardware down in isolation: I
wouldn't even attempt to inject that action between steps (3a) and (3b),
but write it as a new, independent End-of-DXE handler, in
"OvmfPkg/SmmAccess/SmmAccess2Dxe.inf". (That driver already offers SMRAM
open/close/lock services.) I would also reserve the memory away at that
time -- I don't expect the firmware to keep anything that low.
(Allocations are generally served top-down.)

--*--

... I've done some testing too. Applying the QEMU patch on top of
89ea03a7dc83, my plan was:

- do not change OVMF, just see if it continues booting with the QEMU
patch

- then negotiate bit#1 too, in step (1a) -- this is when I'd expect (3a)
to break.

Unfortunately, the result is worse than that; even without negotiating
bit#1 (i.e. in the baseline test), the firmware crashes (reboots) in
step (3a). I've checked "info mtree", and all occurences of
"smbase-blackhole" and "smbase-blackhole" are marked [disabled]. I'm not
sure what's wrong with the baseline test (i.e. without negotiating
bit#1). If I drop the patch (build QEMU at 89ea03a7dc83), then things
work fine.

Thank you!
Laszlo

>
> Signed-off-by: Igor Mammedov <imammedo@redhat.com>
> ---
>  include/hw/i386/ich9.h | 11 ++++++--
>  hw/i386/pc.c           |  4 ++-
>  hw/i386/pc_q35.c       |  3 ++-
>  hw/isa/lpc_ich9.c      | 58 +++++++++++++++++++++++++++++++++++++++++-
>  4 files changed, 71 insertions(+), 5 deletions(-)
>
> diff --git a/include/hw/i386/ich9.h b/include/hw/i386/ich9.h
> index 72e803f6e2..c28685b753 100644
> --- a/include/hw/i386/ich9.h
> +++ b/include/hw/i386/ich9.h
> @@ -12,11 +12,14 @@
>  #include "hw/acpi/acpi.h"
>  #include "hw/acpi/ich9.h"
>  #include "hw/pci/pci_bus.h"
> +#include "qemu/units.h"
>
>  void ich9_lpc_set_irq(void *opaque, int irq_num, int level);
>  int ich9_lpc_map_irq(PCIDevice *pci_dev, int intx);
>  PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, int pirq_pin);
> -void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled);
> +void ich9_lpc_pm_init(PCIDevice *pci_lpc, bool smm_enabled,
> +                      MemoryRegion *system_memory, MemoryRegion *ram,
> +                      MemoryRegion *smram);
>  I2CBus *ich9_smb_init(PCIBus *bus, int devfn, uint32_t smb_io_base);
>
>  void ich9_generate_smi(void);
> @@ -71,6 +74,8 @@ typedef struct ICH9LPCState {
>      uint8_t smi_features_ok;          /* guest-visible, read-only; selecting it
>                                         * triggers feature lockdown */
>      uint64_t smi_negotiated_features; /* guest-invisible, host endian */
> +    MemoryRegion smbase_blackhole;
> +    MemoryRegion smbase_window;
>
>      /* isa bus */
>      ISABus *isa_bus;
> @@ -248,5 +253,7 @@ typedef struct ICH9LPCState {
>
>  /* bit positions used in fw_cfg SMI feature negotiation */
>  #define ICH9_LPC_SMI_F_BROADCAST_BIT            0
> -
> +#define ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT        1
> +#define ICH9_LPC_SMBASE_ADDR                    0x30000
> +#define ICH9_LPC_SMBASE_RAM_SIZE                (128 * KiB)
>  #endif /* HW_ICH9_H */
> diff --git a/hw/i386/pc.c b/hw/i386/pc.c
> index c14ed86439..99a98303eb 100644
> --- a/hw/i386/pc.c
> +++ b/hw/i386/pc.c
> @@ -119,7 +119,9 @@ struct hpet_fw_config hpet_cfg = {.count = UINT8_MAX};
>  /* Physical Address of PVH entry point read from kernel ELF NOTE */
>  static size_t pvh_start_addr;
>
> -GlobalProperty pc_compat_4_1[] = {};
> +GlobalProperty pc_compat_4_1[] = {
> +    { "ICH9-LPC", "x-smi-locked-smbase", "off" },
> +};
>  const size_t pc_compat_4_1_len = G_N_ELEMENTS(pc_compat_4_1);
>
>  GlobalProperty pc_compat_4_0[] = {};
> diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
> index d4e8a1cb9f..50462686a0 100644
> --- a/hw/i386/pc_q35.c
> +++ b/hw/i386/pc_q35.c
> @@ -292,7 +292,8 @@ static void pc_q35_init(MachineState *machine)
>                           0xff0104);
>
>      /* connect pm stuff to lpc */
> -    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms));
> +    ich9_lpc_pm_init(lpc, pc_machine_is_smm_enabled(pcms), get_system_memory(),
> +        ram_memory, MEMORY_REGION(object_resolve_path("/machine/smram", NULL)));
>
>      if (pcms->sata_enabled) {
>          /* ahci and SATA device, for q35 1 ahci controller is built-in */
> diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
> index 17c292e306..17a8cd1b51 100644
> --- a/hw/isa/lpc_ich9.c
> +++ b/hw/isa/lpc_ich9.c
> @@ -359,6 +359,38 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
>      }
>  }
>
> +static uint64_t smbase_blackhole_read(void *ptr, hwaddr reg, unsigned size)
> +{
> +    return 0xffffffff;
> +}
> +
> +static void smbase_blackhole_write(void *opaque, hwaddr addr, uint64_t val,
> +                                   unsigned width)
> +{
> +    /* nothing */
> +}
> +
> +static const MemoryRegionOps smbase_blackhole_ops = {
> +    .read = smbase_blackhole_read,
> +    .write = smbase_blackhole_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid.min_access_size = 1,
> +    .valid.max_access_size = 4,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void ich9_lpc_smbase_locked_update(ICH9LPCState *lpc)
> +{
> +    bool en = lpc->smi_negotiated_features & ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT;
> +
> +    memory_region_transaction_begin();
> +    memory_region_set_enabled(&lpc->smbase_blackhole, en);
> +    memory_region_set_enabled(&lpc->smbase_window, en);
> +    memory_region_transaction_commit();
> +}
> +
>  static void smi_features_ok_callback(void *opaque)
>  {
>      ICH9LPCState *lpc = opaque;
> @@ -379,9 +411,13 @@ static void smi_features_ok_callback(void *opaque)
>      /* valid feature subset requested, lock it down, report success */
>      lpc->smi_negotiated_features = guest_features;
>      lpc->smi_features_ok = 1;
> +
> +    ich9_lpc_smbase_locked_update(lpc);
>  }
>
> -void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
> +void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled,
> +                      MemoryRegion *system_memory,  MemoryRegion *ram,
> +                      MemoryRegion *smram)
>  {
>      ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
>      qemu_irq sci_irq;
> @@ -413,6 +449,20 @@ void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
>                                   &lpc->smi_features_ok,
>                                   sizeof lpc->smi_features_ok,
>                                   true);
> +
> +        memory_region_init_io(&lpc->smbase_blackhole, OBJECT(lpc),
> +                              &smbase_blackhole_ops, NULL,
> +                              "smbase-blackhole", ICH9_LPC_SMBASE_RAM_SIZE);
> +        memory_region_set_enabled(&lpc->smbase_blackhole, false);
> +        memory_region_add_subregion_overlap(system_memory, ICH9_LPC_SMBASE_ADDR,
> +                                            &lpc->smbase_blackhole, 1);
> +
> +
> +        memory_region_init_alias(&lpc->smbase_window, OBJECT(lpc),
> +            "smbase-window", ram,
> +             ICH9_LPC_SMBASE_ADDR, ICH9_LPC_SMBASE_RAM_SIZE);
> +        memory_region_set_enabled(&lpc->smbase_window, false);
> +        memory_region_add_subregion(smram, 0x30000, &lpc->smbase_window);
>      }
>
>      ich9_lpc_reset(DEVICE(lpc));
> @@ -508,6 +558,7 @@ static int ich9_lpc_post_load(void *opaque, int version_id)
>      ich9_lpc_pmbase_sci_update(lpc);
>      ich9_lpc_rcba_update(lpc, 0 /* disabled ICH9_LPC_RCBA_EN */);
>      ich9_lpc_pmcon_update(lpc);
> +    ich9_lpc_smbase_locked_update(lpc);
>      return 0;
>  }
>
> @@ -567,6 +618,8 @@ static void ich9_lpc_reset(DeviceState *qdev)
>      memset(lpc->smi_guest_features_le, 0, sizeof lpc->smi_guest_features_le);
>      lpc->smi_features_ok = 0;
>      lpc->smi_negotiated_features = 0;
> +
> +    ich9_lpc_smbase_locked_update(lpc);
>  }
>
>  /* root complex register block is mapped into memory space */
> @@ -697,6 +750,7 @@ static void ich9_lpc_realize(PCIDevice *d, Error **errp)
>      qdev_init_gpio_out_named(dev, lpc->gsi, ICH9_GPIO_GSI, GSI_NUM_PINS);
>
>      isa_bus_irqs(isa_bus, lpc->gsi);
> +
>  }
>
>  static bool ich9_rst_cnt_needed(void *opaque)
> @@ -764,6 +818,8 @@ static Property ich9_lpc_properties[] = {
>      DEFINE_PROP_BOOL("noreboot", ICH9LPCState, pin_strap.spkr_hi, true),
>      DEFINE_PROP_BIT64("x-smi-broadcast", ICH9LPCState, smi_host_features,
>                        ICH9_LPC_SMI_F_BROADCAST_BIT, true),
> +    DEFINE_PROP_BIT64("x-smi-locked-smbase", ICH9LPCState, smi_host_features,
> +                      ICH9_LPC_SMI_F_LOCKED_SMBASE_BIT, true),
>      DEFINE_PROP_END_OF_LIST(),
>  };
>
>



  reply	other threads:[~2019-09-09 19:17 UTC|newest]

Thread overview: 66+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-13 14:16 [Qemu-devel] CPU hotplug using SMM with QEMU+OVMF Laszlo Ersek
2019-08-13 16:09 ` Laszlo Ersek
2019-08-13 16:18   ` Laszlo Ersek
2019-08-14 13:20   ` Yao, Jiewen
2019-08-14 14:04     ` Paolo Bonzini
2019-08-15  9:55       ` Yao, Jiewen
2019-08-15 16:04         ` Paolo Bonzini
2019-08-15 15:00       ` [Qemu-devel] [edk2-devel] " Laszlo Ersek
2019-08-15 16:16         ` Igor Mammedov
2019-08-15 16:21         ` Paolo Bonzini
2019-08-16  2:46           ` Yao, Jiewen
2019-08-16  7:20             ` Paolo Bonzini
2019-08-16  7:49               ` Yao, Jiewen
2019-08-16 20:15                 ` Laszlo Ersek
2019-08-16 22:19                   ` Alex Williamson
2019-08-17  0:20                     ` Yao, Jiewen
2019-08-18 19:50                       ` Paolo Bonzini
2019-08-18 23:00                         ` Yao, Jiewen
2019-08-19 14:10                           ` Paolo Bonzini
2019-08-21 12:07                             ` Laszlo Ersek
     [not found]                           ` <E92EE9817A31E24EB0585FDF735412F5B9D9C671@ORSMSX113.amr.corp.intel.com>
2019-08-21 17:05                             ` [Qemu-devel] [edk2-rfc] " Paolo Bonzini
     [not found]                               ` <E92EE9817A31E24EB0585FDF735412F5B9D9D74A@ORSMSX113.amr.corp.intel.com>
2019-08-21 17:39                                 ` Paolo Bonzini
2019-08-21 20:17                                   ` Kinney, Michael D
2019-08-22  6:18                                     ` Paolo Bonzini
2019-08-22 18:29                                       ` Laszlo Ersek
2019-08-22 18:51                                         ` Paolo Bonzini
2019-08-23 14:53                                           ` Laszlo Ersek
2019-08-22 20:13                                         ` Kinney, Michael D
2019-08-22 17:59                               ` Laszlo Ersek
2019-08-22 18:43                                 ` Paolo Bonzini
2019-08-22 20:06                                   ` Kinney, Michael D
2019-08-22 22:18                                     ` Paolo Bonzini
2019-08-22 22:32                                       ` Kinney, Michael D
2019-08-22 23:11                                         ` Paolo Bonzini
2019-08-23  1:02                                           ` Kinney, Michael D
2019-08-23  5:00                                             ` Yao, Jiewen
2019-08-23 15:25                                               ` Kinney, Michael D
2019-08-24  1:48                                                 ` Yao, Jiewen
2019-08-27 18:31                                                   ` Igor Mammedov
2019-08-29 17:01                                                     ` Laszlo Ersek
2019-08-30 14:48                                                       ` Igor Mammedov
2019-08-30 18:46                                                         ` Laszlo Ersek
2019-09-02  8:45                                                           ` Igor Mammedov
2019-09-02 19:09                                                             ` Laszlo Ersek
2019-09-03 14:53                                                               ` Igor Mammedov
2019-09-03 17:20                                                                 ` Laszlo Ersek
2019-09-04  9:52                                                                   ` Igor Mammedov
2019-09-05 13:08                                                                     ` Laszlo Ersek
2019-09-05 15:45                                                                       ` Igor Mammedov
2019-09-05 15:49                                                                       ` [Qemu-devel] [PATCH] q35: lpc: allow to lock down 128K RAM at default SMBASE address Igor Mammedov
2019-09-09 19:15                                                                         ` Laszlo Ersek [this message]
2019-09-09 19:20                                                                           ` Laszlo Ersek
2019-09-10 15:58                                                                           ` Igor Mammedov
2019-09-11 17:30                                                                             ` Laszlo Ersek
2019-09-17 13:11                                                                               ` [Qemu-devel] [edk2-devel] " Igor Mammedov
2019-08-26 15:30                                                 ` [Qemu-devel] [edk2-rfc] [edk2-devel] CPU hotplug using SMM with QEMU+OVMF Laszlo Ersek
2019-08-27 16:23                                                   ` Igor Mammedov
2019-08-27 20:11                                                     ` Laszlo Ersek
2019-08-28 12:01                                                       ` Igor Mammedov
2019-08-29 16:25                                                         ` Laszlo Ersek
2019-08-30 13:49                                                           ` Igor Mammedov
2019-08-22 17:53                             ` Laszlo Ersek
2019-08-16 20:00           ` [Qemu-devel] " Laszlo Ersek
2019-08-15 16:07       ` [Qemu-devel] " Igor Mammedov
2019-08-15 16:24         ` Paolo Bonzini
2019-08-16  7:42           ` Igor Mammedov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=dbe8cc44-ef30-3104-2bd3-6a6fe4438ada@redhat.com \
    --to=lersek@redhat.com \
    --cc=alex.williamson@redhat.com \
    --cc=boris.ostrovsky@oracle.com \
    --cc=devel@edk2.groups.io \
    --cc=imammedo@redhat.com \
    --cc=jiewen.yao@intel.com \
    --cc=joao.m.martins@oracle.com \
    --cc=jun.nakajima@intel.com \
    --cc=michael.d.kinney@intel.com \
    --cc=pbonzini@redhat.com \
    --cc=phillip.goerl@oracle.com \
    --cc=qemu-devel@nongnu.org \
    --cc=rfc@edk2.groups.io \
    --cc=yingwen.chen@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).