Message ID | 20200826183749.143980-8-grimm@linux.ibm.com |
---|---|
State | Changes Requested |
Headers | show |
Series | Ultravisor support in skiboot | expand |
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 |
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
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
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
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 --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 */