diff mbox series

[v8,07/11] Load the ultravisor from flash and decompress

Message ID 20200826183749.143980-8-grimm@linux.ibm.com
State Changes Requested
Headers show
Series Ultravisor support in skiboot | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch master (abe4c4799ffee4be12674ad59fc0bc521b0724f3)
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot success Test snowpatch/job/snowpatch-skiboot on branch master
snowpatch_ozlabs/snowpatch_job_snowpatch-skiboot-dco success Signed-off-by present

Commit Message

Ryan Grimm Aug. 26, 2020, 6:37 p.m. UTC
The ultravisor, labeled UVISOR is preloaded from the PNOR in
main_cpu_entry after the kernel is preloaded.  This also works on
FSP-based systems with an ultra.lid on the FSP.

Skiboot decompresses it later in init_uv.

Signed-off-by: Santosh Sivaraj <santosh@linux.ibm.com>
Signed-off-by: Ryan Grimm <grimm@linux.ibm.com>
---
 core/flash.c         |  1 +
 core/init.c          |  1 +
 hw/fsp/fsp.c         |  2 +
 hw/ultravisor.c      | 95 +++++++++++++++++++++++++++++++++++++++-----
 include/platform.h   |  1 +
 include/ultravisor.h |  3 ++
 6 files changed, 93 insertions(+), 10 deletions(-)

Comments

Oliver O'Halloran Aug. 28, 2020, 4:54 a.m. UTC | #1
On Thu, Aug 27, 2020 at 4:41 AM Ryan Grimm <grimm@linux.ibm.com> wrote:
>
> The ultravisor, labeled UVISOR is preloaded from the PNOR in
> main_cpu_entry after the kernel is preloaded.  This also works on
> FSP-based systems with an ultra.lid on the FSP.
>
> Skiboot decompresses it later in init_uv.
>
> Signed-off-by: Santosh Sivaraj <santosh@linux.ibm.com>
> Signed-off-by: Ryan Grimm <grimm@linux.ibm.com>
> ---
>  core/flash.c         |  1 +
>  core/init.c          |  1 +
>  hw/fsp/fsp.c         |  2 +
>  hw/ultravisor.c      | 95 +++++++++++++++++++++++++++++++++++++++-----
>  include/platform.h   |  1 +
>  include/ultravisor.h |  3 ++
>  6 files changed, 93 insertions(+), 10 deletions(-)
>
> diff --git a/core/flash.c b/core/flash.c
> index de748641..bc44a4e5 100644
> --- a/core/flash.c
> +++ b/core/flash.c
> @@ -45,6 +45,7 @@ static struct {
>         { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE,            "ROOTFS" },
>         { RESOURCE_ID_CAPP,     RESOURCE_SUBID_SUPPORTED,       "CAPP" },
>         { RESOURCE_ID_IMA_CATALOG,  RESOURCE_SUBID_SUPPORTED,   "IMA_CATALOG" },
> +       { RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,            "UVISOR" },
>         { RESOURCE_ID_VERSION,  RESOURCE_SUBID_NONE,            "VERSION" },
>         { RESOURCE_ID_KERNEL_FW,        RESOURCE_SUBID_NONE,            "BOOTKERNFW" },
>  };
> diff --git a/core/init.c b/core/init.c
> index 91754962..77dfb36f 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -1319,6 +1319,7 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt)
>
>         preload_capp_ucode();
>         start_preload_kernel();
> +       uv_preload_image();
>
>         /* Catalog decompression routine */
>         imc_decompress_catalog();
> diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
> index 70452cf9..7b564f93 100644
> --- a/hw/fsp/fsp.c
> +++ b/hw/fsp/fsp.c
> @@ -114,6 +114,7 @@ static u64 fsp_hir_timeout;
>  #define KERNEL_LID_PHYP                        0x80a00701
>  #define KERNEL_LID_OPAL                        0x80f00101
>  #define INITRAMFS_LID_OPAL             0x80f00102
> +#define ULTRA_LID_OPAL                 0x80f00105
>
>  /*
>   * We keep track on last logged values for some things to print only on
> @@ -2381,6 +2382,7 @@ static struct {
>  } fsp_lid_map[] = {
>         { RESOURCE_ID_KERNEL,   RESOURCE_SUBID_NONE,    KERNEL_LID_OPAL },
>         { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE,    INITRAMFS_LID_OPAL },
> +       { RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,    ULTRA_LID_OPAL },
>         { RESOURCE_ID_IMA_CATALOG,IMA_CATALOG_NIMBUS,   0x80f00103 },
>         { RESOURCE_ID_CAPP,     CAPP_IDX_MURANO_DD20,   0x80a02002 },
>         { RESOURCE_ID_CAPP,     CAPP_IDX_MURANO_DD21,   0x80a02001 },
> diff --git a/hw/ultravisor.c b/hw/ultravisor.c
> index 467f0ca6..34c16404 100644
> --- a/hw/ultravisor.c
> +++ b/hw/ultravisor.c
> @@ -10,11 +10,16 @@
>  #include <cpu.h>
>  #include <debug_descriptor.h>
>  #include <console.h>
> +#include <chip.h>
> +#include <libstb/container.h>
>
>  static struct dt_node *uv_fw_node;
>  static uint64_t uv_base_addr;
>  bool uv_present;
>
> +static char *uv_image = NULL;
> +static size_t uv_image_size;
> +
>  struct memcons uv_memcons __section(".data.memcons") = {
>         .magic          = MEMCONS_MAGIC,
>         .obuf_phys      = INMEM_UV_CON_START,
> @@ -70,10 +75,44 @@ int start_ultravisor(void *fdt)
>         return OPAL_SUCCESS;
>  }
>
> +static int uv_decompress_image(void)
> +{
> +       struct xz_decompress uv_xz;
> +       uint64_t uv_fw_size;
> +
> +       if (!uv_image) {
> +               prerror("UV: Preload hasn't started yet! Aborting.\n");
> +               return OPAL_INTERNAL_ERROR;
> +       }
> +
> +       if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
> +                                    RESOURCE_SUBID_NONE) != OPAL_SUCCESS) {
> +               prerror("UV: Ultravisor image load failed\n");
> +               return OPAL_INTERNAL_ERROR;
> +       }
> +
> +       uv_xz.dst = (void *)dt_get_address(uv_fw_node, 0, &uv_fw_size);
> +       uv_xz.dst_size = uv_fw_size;
> +       uv_xz.src_size = uv_image_size;
> +       uv_xz.src = uv_image;
> +
> +       if (stb_is_container((void*)uv_xz.src, uv_xz.src_size))
> +               uv_xz.src = uv_xz.src + SECURE_BOOT_HEADERS_SIZE;
> +
> +       xz_start_decompress(&uv_xz);
> +               if ((uv_xz.status != OPAL_PARTIAL) && (uv_xz.status != OPAL_SUCCESS)) {

Weird indentation and why would we get OPAL_PARTIAL here?

> +                       prerror("UV: XZ decompression failed status 0x%x\n", uv_xz.status);
> +               return OPAL_INTERNAL_ERROR;
> +       }
> +
> +       return OPAL_SUCCESS;
> +}
> +
>  void init_uv()
>  {
>         uint64_t uv_dt_src, uv_fw_sz;
>         struct dt_node *reserved_mem;
> +       int ret;
>
>         if (!is_msr_bit_set(MSR_S)) {
>                 prlog(PR_DEBUG, "UV: S bit not set\n");
> @@ -84,23 +123,59 @@ void init_uv()
>         if (!uv_fw_node) {
>                 prlog(PR_DEBUG, "UV: No ibm,uv-firmware node found, disabling pef\n");
>                 cpu_disable_pef();
> -               return;
> +               goto err;
>         }
>
> -       reserved_mem = dt_find_by_path(dt_root, "/reserved-memory/ibm,uv-firmware");
> -       if (!reserved_mem) {
> -               prerror("UV: No reserved memory for ibm,uv-firmware found\n");
> -               return;
> -       }
> +       /* If decompress fails, look for reserved memory by Mambo tcl or cronus BML */
> +       ret = uv_decompress_image();
> +       if (ret) {
> +               reserved_mem = dt_find_by_path(dt_root, "/reserved-memory/ibm,uv-firmware");
> +               if (!reserved_mem) {
> +                       prerror("UV: No reserved memory for ibm,uv-firmware found\n");
> +                       return;
> +               }
>
> -       uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
> -       uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
> +               uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
> +               uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
>
> -       prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory 0x%llx from 0x%llx\n",
> +               prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory 0x%llx from 0x%llx\n",
>                                         uv_fw_sz, uv_base_addr, uv_dt_src);
>
> -       memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
> +               memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
> +       }
>
>         dt_add_property_u64(uv_fw_node, "memcons", (u64)&uv_memcons);
>         debug_descriptor.uv_memcons_phys = (u64)&uv_memcons;
> +err:
> +       local_free(uv_image);
> +}
> +
> +/*
> + * Preload the UV image from PNOR partition
> + *
> + * uv_image is allocated locally to the chip and freed here if preload fails
> + * or free in init_uv
> + */
> +void uv_preload_image(void)
> +{
> +       struct proc_chip *chip = next_chip(NULL);
> +       int ret;
> +
> +       prlog(PR_DEBUG, "UV: Preload starting\n");
> +
> +       uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE;
> +       uv_image = local_alloc(chip->id, uv_image_size, uv_image_size);
> +       if (!uv_image) {
> +               prerror("UV: Memory allocation failed\n");
> +               return;
> +       }
> +       memset(uv_image, 0, uv_image_size);
> +
> +       ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,
> +                                    uv_image, &uv_image_size);
> +
> +       if (ret != OPAL_SUCCESS) {
> +               local_free(uv_image);
> +               prerror("UV: platform load failed: %d\n", ret);
> +       }
>  }
> diff --git a/include/platform.h b/include/platform.h
> index ef93278b..57b2eeef 100644
> --- a/include/platform.h
> +++ b/include/platform.h
> @@ -17,6 +17,7 @@ enum resource_id {
>         RESOURCE_ID_INITRAMFS,
>         RESOURCE_ID_CAPP,
>         RESOURCE_ID_IMA_CATALOG,
> +       RESOURCE_ID_UV_IMAGE,
>         RESOURCE_ID_VERSION,
>         RESOURCE_ID_KERNEL_FW,
>  };
> diff --git a/include/ultravisor.h b/include/ultravisor.h
> index 84217d66..8048cb76 100644
> --- a/include/ultravisor.h
> +++ b/include/ultravisor.h
> @@ -64,4 +64,7 @@ static inline int uv_xscom_write(u64 partid, u64 pcb_addr, u64 val)
>         return ucall(UV_WRITE_SCOM, retbuf, partid, pcb_addr, val);
>  }
>
> +#define MAX_COMPRESSED_UV_IMAGE_SIZE   0x40000 /* 256 Kilobytes */
> +void uv_preload_image(void);
> +
>  #endif /* __ULTRAVISOR_H */
> --
> 2.18.4
>
> _______________________________________________
> Skiboot mailing list
> Skiboot@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
Santosh Sivaraj Aug. 28, 2020, 3:28 p.m. UTC | #2
On Friday, 28 August, 2020 10:24:50 AM IST Oliver O'Halloran wrote:
> On Thu, Aug 27, 2020 at 4:41 AM Ryan Grimm <grimm@linux.ibm.com> wrote:
> > The ultravisor, labeled UVISOR is preloaded from the PNOR in
> > main_cpu_entry after the kernel is preloaded.  This also works on
> > FSP-based systems with an ultra.lid on the FSP.
> > 
> > Skiboot decompresses it later in init_uv.
> > 
> > Signed-off-by: Santosh Sivaraj <santosh@linux.ibm.com>
> > Signed-off-by: Ryan Grimm <grimm@linux.ibm.com>
> > ---
> > 
> >  core/flash.c         |  1 +
> >  core/init.c          |  1 +
> >  hw/fsp/fsp.c         |  2 +
> >  hw/ultravisor.c      | 95 +++++++++++++++++++++++++++++++++++++++-----
> >  include/platform.h   |  1 +
> >  include/ultravisor.h |  3 ++
> >  6 files changed, 93 insertions(+), 10 deletions(-)
> > 
> > diff --git a/core/flash.c b/core/flash.c
> > index de748641..bc44a4e5 100644
> > --- a/core/flash.c
> > +++ b/core/flash.c
> > @@ -45,6 +45,7 @@ static struct {
> > 
> >         { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE,            "ROOTFS"
> >         },
> >         { RESOURCE_ID_CAPP,     RESOURCE_SUBID_SUPPORTED,       "CAPP" },
> >         { RESOURCE_ID_IMA_CATALOG,  RESOURCE_SUBID_SUPPORTED,  
> >         "IMA_CATALOG" },
> > 
> > +       { RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,            "UVISOR"
> > },
> > 
> >         { RESOURCE_ID_VERSION,  RESOURCE_SUBID_NONE,            "VERSION"
> >         },
> >         { RESOURCE_ID_KERNEL_FW,        RESOURCE_SUBID_NONE,           
> >         "BOOTKERNFW" },>  
> >  };
> > 
> > diff --git a/core/init.c b/core/init.c
> > index 91754962..77dfb36f 100644
> > --- a/core/init.c
> > +++ b/core/init.c
> > @@ -1319,6 +1319,7 @@ void __noreturn __nomcount main_cpu_entry(const 
void
> > *fdt)> 
> >         preload_capp_ucode();
> >         start_preload_kernel();
> > 
> > +       uv_preload_image();
> > 
> >         /* Catalog decompression routine */
> >         imc_decompress_catalog();
> > 
> > diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
> > index 70452cf9..7b564f93 100644
> > --- a/hw/fsp/fsp.c
> > +++ b/hw/fsp/fsp.c
> > @@ -114,6 +114,7 @@ static u64 fsp_hir_timeout;
> > 
> >  #define KERNEL_LID_PHYP                        0x80a00701
> >  #define KERNEL_LID_OPAL                        0x80f00101
> >  #define INITRAMFS_LID_OPAL             0x80f00102
> > 
> > +#define ULTRA_LID_OPAL                 0x80f00105
> > 
> >  /*
> >  
> >   * We keep track on last logged values for some things to print only on
> > 
> > @@ -2381,6 +2382,7 @@ static struct {
> > 
> >  } fsp_lid_map[] = {
> >  
> >         { RESOURCE_ID_KERNEL,   RESOURCE_SUBID_NONE,    KERNEL_LID_OPAL 
},
> >         { RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE,    
INITRAMFS_LID_OPAL
> >         },
> > 
> > +       { RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,    ULTRA_LID_OPAL },
> > 
> >         { RESOURCE_ID_IMA_CATALOG,IMA_CATALOG_NIMBUS,   0x80f00103 },
> >         { RESOURCE_ID_CAPP,     CAPP_IDX_MURANO_DD20,   0x80a02002 },
> >         { RESOURCE_ID_CAPP,     CAPP_IDX_MURANO_DD21,   0x80a02001 },
> > 
> > diff --git a/hw/ultravisor.c b/hw/ultravisor.c
> > index 467f0ca6..34c16404 100644
> > --- a/hw/ultravisor.c
> > +++ b/hw/ultravisor.c
> > @@ -10,11 +10,16 @@
> > 
> >  #include <cpu.h>
> >  #include <debug_descriptor.h>
> >  #include <console.h>
> > 
> > +#include <chip.h>
> > +#include <libstb/container.h>
> > 
> >  static struct dt_node *uv_fw_node;
> >  static uint64_t uv_base_addr;
> >  bool uv_present;
> > 
> > +static char *uv_image = NULL;
> > +static size_t uv_image_size;
> > +
> > 
> >  struct memcons uv_memcons __section(".data.memcons") = {
> >  
> >         .magic          = MEMCONS_MAGIC,
> >         .obuf_phys      = INMEM_UV_CON_START,
> > 
> > @@ -70,10 +75,44 @@ int start_ultravisor(void *fdt)
> > 
> >         return OPAL_SUCCESS;
> >  
> >  }
> > 
> > +static int uv_decompress_image(void)
> > +{
> > +       struct xz_decompress uv_xz;
> > +       uint64_t uv_fw_size;
> > +
> > +       if (!uv_image) {
> > +               prerror("UV: Preload hasn't started yet! Aborting.\n");
> > +               return OPAL_INTERNAL_ERROR;
> > +       }
> > +
> > +       if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
> > +                                    RESOURCE_SUBID_NONE) != 
OPAL_SUCCESS)
> > { +               prerror("UV: Ultravisor image load failed\n");
> > +               return OPAL_INTERNAL_ERROR;
> > +       }
> > +
> > +       uv_xz.dst = (void *)dt_get_address(uv_fw_node, 0, &uv_fw_size);
> > +       uv_xz.dst_size = uv_fw_size;
> > +       uv_xz.src_size = uv_image_size;
> > +       uv_xz.src = uv_image;
> > +
> > +       if (stb_is_container((void*)uv_xz.src, uv_xz.src_size))
> > +               uv_xz.src = uv_xz.src + SECURE_BOOT_HEADERS_SIZE;
> > +
> > +       xz_start_decompress(&uv_xz);
> > +               if ((uv_xz.status != OPAL_PARTIAL) && (uv_xz.status !=
> > OPAL_SUCCESS)) {
> Weird indentation and why would we get OPAL_PARTIAL here?

xz_decompress sets the status partial as the default error, but that itself 
is not needed. status is updated in the same thread anyway. But in this case, 
probably what I meant was OPAL_PARAMETER.

Thanks,
Santosh

> 
> > +                       prerror("UV: XZ decompression failed status
> > 0x%x\n", uv_xz.status); +               return OPAL_INTERNAL_ERROR;
> > +       }
> > +
> > +       return OPAL_SUCCESS;
> > +}
> > +
> > 
> >  void init_uv()
> >  {
> >  
> >         uint64_t uv_dt_src, uv_fw_sz;
> >         struct dt_node *reserved_mem;
> > 
> > +       int ret;
> > 
> >         if (!is_msr_bit_set(MSR_S)) {
> >         
> >                 prlog(PR_DEBUG, "UV: S bit not set\n");
> > 
> > @@ -84,23 +123,59 @@ void init_uv()
> > 
> >         if (!uv_fw_node) {
> >         
> >                 prlog(PR_DEBUG, "UV: No ibm,uv-firmware node found,
> >                 disabling pef\n");
> >                 cpu_disable_pef();
> > 
> > -               return;
> > +               goto err;
> > 
> >         }
> > 
> > -       reserved_mem = dt_find_by_path(dt_root,
> > "/reserved-memory/ibm,uv-firmware"); -       if (!reserved_mem) {
> > -               prerror("UV: No reserved memory for ibm,uv-firmware
> > found\n"); -               return;
> > -       }
> > +       /* If decompress fails, look for reserved memory by Mambo tcl or
> > cronus BML */ +       ret = uv_decompress_image();
> > +       if (ret) {
> > +               reserved_mem = dt_find_by_path(dt_root,
> > "/reserved-memory/ibm,uv-firmware"); +               if (!reserved_mem) {
> > +                       prerror("UV: No reserved memory for
> > ibm,uv-firmware found\n"); +                       return;
> > +               }
> > 
> > -       uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
> > -       uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
> > +               uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
> > +               uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
> > 
> > -       prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory
> > 0x%llx from 0x%llx\n", +               prlog(PR_INFO, "UV: Copying 0x%llx
> > bytes to protected memory 0x%llx from 0x%llx\n",> 
> >                                         uv_fw_sz, uv_base_addr,
> >                                         uv_dt_src);
> > 
> > -       memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
> > +               memcpy((void *)uv_base_addr, (void *)uv_dt_src, 
uv_fw_sz);
> > +       }
> > 
> >         dt_add_property_u64(uv_fw_node, "memcons", (u64)&uv_memcons);
> >         debug_descriptor.uv_memcons_phys = (u64)&uv_memcons;
> > 
> > +err:
> > +       local_free(uv_image);
> > +}
> > +
> > +/*
> > + * Preload the UV image from PNOR partition
> > + *
> > + * uv_image is allocated locally to the chip and freed here if preload
> > fails + * or free in init_uv
> > + */
> > +void uv_preload_image(void)
> > +{
> > +       struct proc_chip *chip = next_chip(NULL);
> > +       int ret;
> > +
> > +       prlog(PR_DEBUG, "UV: Preload starting\n");
> > +
> > +       uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE;
> > +       uv_image = local_alloc(chip->id, uv_image_size, uv_image_size);
> > +       if (!uv_image) {
> > +               prerror("UV: Memory allocation failed\n");
> > +               return;
> > +       }
> > +       memset(uv_image, 0, uv_image_size);
> > +
> > +       ret = start_preload_resource(RESOURCE_ID_UV_IMAGE,
> > RESOURCE_SUBID_NONE, +                                    uv_image,
> > &uv_image_size);
> > +
> > +       if (ret != OPAL_SUCCESS) {
> > +               local_free(uv_image);
> > +               prerror("UV: platform load failed: %d\n", ret);
> > +       }
> > 
> >  }
> > 
> > diff --git a/include/platform.h b/include/platform.h
> > index ef93278b..57b2eeef 100644
> > --- a/include/platform.h
> > +++ b/include/platform.h
> > @@ -17,6 +17,7 @@ enum resource_id {
> > 
> >         RESOURCE_ID_INITRAMFS,
> >         RESOURCE_ID_CAPP,
> >         RESOURCE_ID_IMA_CATALOG,
> > 
> > +       RESOURCE_ID_UV_IMAGE,
> > 
> >         RESOURCE_ID_VERSION,
> >         RESOURCE_ID_KERNEL_FW,
> >  
> >  };
> > 
> > diff --git a/include/ultravisor.h b/include/ultravisor.h
> > index 84217d66..8048cb76 100644
> > --- a/include/ultravisor.h
> > +++ b/include/ultravisor.h
> > @@ -64,4 +64,7 @@ static inline int uv_xscom_write(u64 partid, u64
> > pcb_addr, u64 val)> 
> >         return ucall(UV_WRITE_SCOM, retbuf, partid, pcb_addr, val);
> >  
> >  }
> > 
> > +#define MAX_COMPRESSED_UV_IMAGE_SIZE   0x40000 /* 256 Kilobytes */
> > +void uv_preload_image(void);
> > +
> > 
> >  #endif /* __ULTRAVISOR_H */
> > 
> > --
> > 2.18.4
> > 
> > _______________________________________________
> > Skiboot mailing list
> > Skiboot@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/skiboot
> 
> _______________________________________________
> Skiboot mailing list
> Skiboot@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/skiboot
Ryan Grimm Sept. 8, 2020, 8:19 p.m. UTC | #3
On Fri, 2020-08-28 at 14:54 +1000, Oliver O'Halloran wrote:
> 
> > +static int uv_decompress_image(void)
> > +{
> > +       struct xz_decompress uv_xz;
> > +       uint64_t uv_fw_size;
> > +
> > +       if (!uv_image) {
> > +               prerror("UV: Preload hasn't started yet!
> > Aborting.\n");
> > +               return OPAL_INTERNAL_ERROR;
> > +       }
> > +
> > +       if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
> > +                                    RESOURCE_SUBID_NONE) !=
> > OPAL_SUCCESS) {
> > +               prerror("UV: Ultravisor image load failed\n");
> > +               return OPAL_INTERNAL_ERROR;
> > +       }
> > +
> > +       uv_xz.dst = (void *)dt_get_address(uv_fw_node, 0,
> > &uv_fw_size);
> > +       uv_xz.dst_size = uv_fw_size;
> > +       uv_xz.src_size = uv_image_size;
> > +       uv_xz.src = uv_image;
> > +
> > +       if (stb_is_container((void*)uv_xz.src, uv_xz.src_size))
> > +               uv_xz.src = uv_xz.src + SECURE_BOOT_HEADERS_SIZE;
> > +
> > +       xz_start_decompress(&uv_xz);
> > +               if ((uv_xz.status != OPAL_PARTIAL) && (uv_xz.status
> > != OPAL_SUCCESS)) {
> 
> Weird indentation and why would we get OPAL_PARTIAL here?
> 

Oh, oops, indents fixed. 

Well, the comment in xz_start_decompress show this:

 * The `status` value will be OPAL_PARTIAL till the job completes
(successfully
 * or not)

The code seems to work that way and it's a job queue so we need to
check for both since it might not complete right?

-Ryan


> > +                       prerror("UV: XZ decompression failed status
> > 0x%x\n", uv_xz.status);
> > +               return OPAL_INTERNAL_ERROR;
> > +       }
> > +
> > +       return OPAL_SUCCESS;
> > +}
> > +
> >  void init_uv()
> >  {
> >         uint64_t uv_dt_src, uv_fw_sz;
> >         struct dt_node *reserved_mem;
> > +       int ret;
> > 
> >         if (!is_msr_bit_set(MSR_S)) {
> >                 prlog(PR_DEBUG, "UV: S bit not set\n");
> > @@ -84,23 +123,59 @@ void init_uv()
> >         if (!uv_fw_node) {
> >                 prlog(PR_DEBUG, "UV: No ibm,uv-firmware node found,
> > disabling pef\n");
> >                 cpu_disable_pef();
> > -               return;
> > +               goto err;
> >         }
> > 
> > -       reserved_mem = dt_find_by_path(dt_root, "/reserved-
> > memory/ibm,uv-firmware");
> > -       if (!reserved_mem) {
> > -               prerror("UV: No reserved memory for ibm,uv-firmware 
> > found\n");
> > -               return;
> > -       }
> > +       /* If decompress fails, look for reserved memory by Mambo
> > tcl or cronus BML */
> > +       ret = uv_decompress_image();
> > +       if (ret) {
> > +               reserved_mem = dt_find_by_path(dt_root, "/reserved-
> > memory/ibm,uv-firmware");
> > +               if (!reserved_mem) {
> > +                       prerror("UV: No reserved memory for ibm,uv-
> > firmware found\n");
> > +                       return;
> > +               }
> > 
> > -       uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
> > -       uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
> > +               uv_dt_src = dt_get_address(reserved_mem, 0,
> > &uv_fw_sz);
> > +               uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
> > 
> > -       prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected
> > memory 0x%llx from 0x%llx\n",
> > +               prlog(PR_INFO, "UV: Copying 0x%llx bytes to
> > protected memory 0x%llx from 0x%llx\n",
> >                                         uv_fw_sz, uv_base_addr,
> > uv_dt_src);
> > 
> > -       memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
> > +               memcpy((void *)uv_base_addr, (void *)uv_dt_src,
> > uv_fw_sz);
> > +       }
> > 
> >         dt_add_property_u64(uv_fw_node, "memcons",
> > (u64)&uv_memcons);
> >         debug_descriptor.uv_memcons_phys = (u64)&uv_memcons;
> > +err:
> > +       local_free(uv_image);
> > +}
> > +
> > +/*
> > + * Preload the UV image from PNOR partition
> > + *
> > + * uv_image is allocated locally to the chip and freed here if
> > preload fails
> > + * or free in init_uv
> > + */
> > +void uv_preload_image(void)
> > +{
> > +       struct proc_chip *chip = next_chip(NULL);
> > +       int ret;
> > +
> > +       prlog(PR_DEBUG, "UV: Preload starting\n");
> > +
> > +       uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE;
> > +       uv_image = local_alloc(chip->id, uv_image_size,
> > uv_image_size);
> > +       if (!uv_image) {
> > +               prerror("UV: Memory allocation failed\n");
> > +               return;
> > +       }
> > +       memset(uv_image, 0, uv_image_size);
> > +
> > +       ret = start_preload_resource(RESOURCE_ID_UV_IMAGE,
> > RESOURCE_SUBID_NONE,
> > +                                    uv_image, &uv_image_size);
> > +
> > +       if (ret != OPAL_SUCCESS) {
> > +               local_free(uv_image);
> > +               prerror("UV: platform load failed: %d\n", ret);
> > +       }
> >  }
> > diff --git a/include/platform.h b/include/platform.h
> > index ef93278b..57b2eeef 100644
> > --- a/include/platform.h
> > +++ b/include/platform.h
> > @@ -17,6 +17,7 @@ enum resource_id {
> >         RESOURCE_ID_INITRAMFS,
> >         RESOURCE_ID_CAPP,
> >         RESOURCE_ID_IMA_CATALOG,
> > +       RESOURCE_ID_UV_IMAGE,
> >         RESOURCE_ID_VERSION,
> >         RESOURCE_ID_KERNEL_FW,
> >  };
> > diff --git a/include/ultravisor.h b/include/ultravisor.h
> > index 84217d66..8048cb76 100644
> > --- a/include/ultravisor.h
> > +++ b/include/ultravisor.h
> > @@ -64,4 +64,7 @@ static inline int uv_xscom_write(u64 partid, u64
> > pcb_addr, u64 val)
> >         return ucall(UV_WRITE_SCOM, retbuf, partid, pcb_addr, val);
> >  }
> > 
> > +#define MAX_COMPRESSED_UV_IMAGE_SIZE   0x40000 /* 256 Kilobytes */
> > +void uv_preload_image(void);
> > +
> >  #endif /* __ULTRAVISOR_H */
> > --
> > 2.18.4
> > 
> > _______________________________________________
> > Skiboot mailing list
> > Skiboot@lists.ozlabs.org
> > https://lists.ozlabs.org/listinfo/skiboot
Oliver O'Halloran Sept. 9, 2020, 2:51 a.m. UTC | #4
On Wed, Sep 9, 2020 at 6:19 AM Ryan Grimm <grimm@linux.vnet.ibm.com> wrote:
>
> On Fri, 2020-08-28 at 14:54 +1000, Oliver O'Halloran wrote:
> >
> > > +static int uv_decompress_image(void)
> > > +{
> > > +       struct xz_decompress uv_xz;
> > > +       uint64_t uv_fw_size;
> > > +
> > > +       if (!uv_image) {
> > > +               prerror("UV: Preload hasn't started yet!
> > > Aborting.\n");
> > > +               return OPAL_INTERNAL_ERROR;
> > > +       }
> > > +
> > > +       if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
> > > +                                    RESOURCE_SUBID_NONE) !=
> > > OPAL_SUCCESS) {
> > > +               prerror("UV: Ultravisor image load failed\n");
> > > +               return OPAL_INTERNAL_ERROR;
> > > +       }
> > > +
> > > +       uv_xz.dst = (void *)dt_get_address(uv_fw_node, 0,
> > > &uv_fw_size);
> > > +       uv_xz.dst_size = uv_fw_size;
> > > +       uv_xz.src_size = uv_image_size;
> > > +       uv_xz.src = uv_image;
> > > +
> > > +       if (stb_is_container((void*)uv_xz.src, uv_xz.src_size))
> > > +               uv_xz.src = uv_xz.src + SECURE_BOOT_HEADERS_SIZE;
> > > +
> > > +       xz_start_decompress(&uv_xz);
> > > +               if ((uv_xz.status != OPAL_PARTIAL) && (uv_xz.status
> > > != OPAL_SUCCESS)) {
> >
> > Weird indentation and why would we get OPAL_PARTIAL here?
> >
>
> Oh, oops, indents fixed.
>
> Well, the comment in xz_start_decompress show this:
>
>  * The `status` value will be OPAL_PARTIAL till the job completes
> (successfully
>  * or not)
>
> The code seems to work that way and it's a job queue so we need to
> check for both since it might not complete right?

On closer inspection this whole thing is totally broken. uv_xz is
allocated on the stack then passed to a worker via cpu_queue_job().
Immediately afterwards we return from the function so uv_xz goes out
of scope and the worker is looking at stack garbage. On top of that
uv_image is freed soon afterwards once we've returned to  init_uv().
There's also the problem of the job API not actually guaranteeing that
any part of the worker has executed, so even if we ignore the above
checking uv_xz.status at this point is going to be broken since the
worker may not have written anything to it yet.

At a guess there's supposed to be a call to wait_xz_decompressed()
before checking the result in uv_xz. That would probably fix all those
problems.

Oliver
diff mbox series

Patch

diff --git a/core/flash.c b/core/flash.c
index de748641..bc44a4e5 100644
--- a/core/flash.c
+++ b/core/flash.c
@@ -45,6 +45,7 @@  static struct {
 	{ RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE,		"ROOTFS" },
 	{ RESOURCE_ID_CAPP,	RESOURCE_SUBID_SUPPORTED,	"CAPP" },
 	{ RESOURCE_ID_IMA_CATALOG,  RESOURCE_SUBID_SUPPORTED,	"IMA_CATALOG" },
+	{ RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,            "UVISOR" },
 	{ RESOURCE_ID_VERSION,	RESOURCE_SUBID_NONE,		"VERSION" },
 	{ RESOURCE_ID_KERNEL_FW,	RESOURCE_SUBID_NONE,		"BOOTKERNFW" },
 };
diff --git a/core/init.c b/core/init.c
index 91754962..77dfb36f 100644
--- a/core/init.c
+++ b/core/init.c
@@ -1319,6 +1319,7 @@  void __noreturn __nomcount main_cpu_entry(const void *fdt)
 
 	preload_capp_ucode();
 	start_preload_kernel();
+	uv_preload_image();
 
 	/* Catalog decompression routine */
 	imc_decompress_catalog();
diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c
index 70452cf9..7b564f93 100644
--- a/hw/fsp/fsp.c
+++ b/hw/fsp/fsp.c
@@ -114,6 +114,7 @@  static u64 fsp_hir_timeout;
 #define KERNEL_LID_PHYP			0x80a00701
 #define KERNEL_LID_OPAL			0x80f00101
 #define INITRAMFS_LID_OPAL		0x80f00102
+#define ULTRA_LID_OPAL			0x80f00105
 
 /*
  * We keep track on last logged values for some things to print only on
@@ -2381,6 +2382,7 @@  static struct {
 } fsp_lid_map[] = {
 	{ RESOURCE_ID_KERNEL,	RESOURCE_SUBID_NONE,	KERNEL_LID_OPAL },
 	{ RESOURCE_ID_INITRAMFS,RESOURCE_SUBID_NONE,	INITRAMFS_LID_OPAL },
+	{ RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,	ULTRA_LID_OPAL },
 	{ RESOURCE_ID_IMA_CATALOG,IMA_CATALOG_NIMBUS,	0x80f00103 },
 	{ RESOURCE_ID_CAPP,	CAPP_IDX_MURANO_DD20,	0x80a02002 },
 	{ RESOURCE_ID_CAPP,	CAPP_IDX_MURANO_DD21,	0x80a02001 },
diff --git a/hw/ultravisor.c b/hw/ultravisor.c
index 467f0ca6..34c16404 100644
--- a/hw/ultravisor.c
+++ b/hw/ultravisor.c
@@ -10,11 +10,16 @@ 
 #include <cpu.h>
 #include <debug_descriptor.h>
 #include <console.h>
+#include <chip.h>
+#include <libstb/container.h>
 
 static struct dt_node *uv_fw_node;
 static uint64_t uv_base_addr;
 bool uv_present;
 
+static char *uv_image = NULL;
+static size_t uv_image_size;
+
 struct memcons uv_memcons __section(".data.memcons") = {
 	.magic		= MEMCONS_MAGIC,
 	.obuf_phys	= INMEM_UV_CON_START,
@@ -70,10 +75,44 @@  int start_ultravisor(void *fdt)
 	return OPAL_SUCCESS;
 }
 
+static int uv_decompress_image(void)
+{
+	struct xz_decompress uv_xz;
+	uint64_t uv_fw_size;
+
+	if (!uv_image) {
+		prerror("UV: Preload hasn't started yet! Aborting.\n");
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE,
+				     RESOURCE_SUBID_NONE) != OPAL_SUCCESS) {
+		prerror("UV: Ultravisor image load failed\n");
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	uv_xz.dst = (void *)dt_get_address(uv_fw_node, 0, &uv_fw_size);
+	uv_xz.dst_size = uv_fw_size;
+	uv_xz.src_size = uv_image_size;
+	uv_xz.src = uv_image;
+
+	if (stb_is_container((void*)uv_xz.src, uv_xz.src_size))
+		uv_xz.src = uv_xz.src + SECURE_BOOT_HEADERS_SIZE;
+
+	xz_start_decompress(&uv_xz);
+		if ((uv_xz.status != OPAL_PARTIAL) && (uv_xz.status != OPAL_SUCCESS)) {
+			prerror("UV: XZ decompression failed status 0x%x\n", uv_xz.status);
+		return OPAL_INTERNAL_ERROR;
+	}
+
+	return OPAL_SUCCESS;
+}
+
 void init_uv()
 {
 	uint64_t uv_dt_src, uv_fw_sz;
 	struct dt_node *reserved_mem;
+	int ret;
 
 	if (!is_msr_bit_set(MSR_S)) {
 		prlog(PR_DEBUG, "UV: S bit not set\n");
@@ -84,23 +123,59 @@  void init_uv()
 	if (!uv_fw_node) {
 		prlog(PR_DEBUG, "UV: No ibm,uv-firmware node found, disabling pef\n");
 		cpu_disable_pef();
-		return;
+		goto err;
 	}
 
-	reserved_mem = dt_find_by_path(dt_root, "/reserved-memory/ibm,uv-firmware");
-	if (!reserved_mem) {
-		prerror("UV: No reserved memory for ibm,uv-firmware found\n");
-		return;
-	}
+	/* If decompress fails, look for reserved memory by Mambo tcl or cronus BML */
+	ret = uv_decompress_image();
+	if (ret) {
+		reserved_mem = dt_find_by_path(dt_root, "/reserved-memory/ibm,uv-firmware");
+		if (!reserved_mem) {
+			prerror("UV: No reserved memory for ibm,uv-firmware found\n");
+			return;
+		}
 
-	uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
-	uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
+		uv_dt_src = dt_get_address(reserved_mem, 0, &uv_fw_sz);
+		uv_base_addr = dt_get_address(uv_fw_node, 0, NULL);
 
-	prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory 0x%llx from 0x%llx\n",
+		prlog(PR_INFO, "UV: Copying 0x%llx bytes to protected memory 0x%llx from 0x%llx\n",
 					uv_fw_sz, uv_base_addr, uv_dt_src);
 
-	memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
+		memcpy((void *)uv_base_addr, (void *)uv_dt_src, uv_fw_sz);
+	}
 
 	dt_add_property_u64(uv_fw_node, "memcons", (u64)&uv_memcons);
 	debug_descriptor.uv_memcons_phys = (u64)&uv_memcons;
+err:
+	local_free(uv_image);
+}
+
+/*
+ * Preload the UV image from PNOR partition
+ *
+ * uv_image is allocated locally to the chip and freed here if preload fails
+ * or free in init_uv
+ */
+void uv_preload_image(void)
+{
+	struct proc_chip *chip = next_chip(NULL);
+	int ret;
+
+	prlog(PR_DEBUG, "UV: Preload starting\n");
+
+	uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE;
+	uv_image = local_alloc(chip->id, uv_image_size, uv_image_size);
+	if (!uv_image) {
+		prerror("UV: Memory allocation failed\n");
+		return;
+	}
+	memset(uv_image, 0, uv_image_size);
+
+	ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE,
+				     uv_image, &uv_image_size);
+
+	if (ret != OPAL_SUCCESS) {
+		local_free(uv_image);
+		prerror("UV: platform load failed: %d\n", ret);
+	}
 }
diff --git a/include/platform.h b/include/platform.h
index ef93278b..57b2eeef 100644
--- a/include/platform.h
+++ b/include/platform.h
@@ -17,6 +17,7 @@  enum resource_id {
 	RESOURCE_ID_INITRAMFS,
 	RESOURCE_ID_CAPP,
 	RESOURCE_ID_IMA_CATALOG,
+	RESOURCE_ID_UV_IMAGE,
 	RESOURCE_ID_VERSION,
 	RESOURCE_ID_KERNEL_FW,
 };
diff --git a/include/ultravisor.h b/include/ultravisor.h
index 84217d66..8048cb76 100644
--- a/include/ultravisor.h
+++ b/include/ultravisor.h
@@ -64,4 +64,7 @@  static inline int uv_xscom_write(u64 partid, u64 pcb_addr, u64 val)
 	return ucall(UV_WRITE_SCOM, retbuf, partid, pcb_addr, val);
 }
 
+#define MAX_COMPRESSED_UV_IMAGE_SIZE	0x40000 /* 256 Kilobytes */
+void uv_preload_image(void);
+
 #endif /* __ULTRAVISOR_H */