Message ID | 20190905132919.8765-4-grimm@linux.ibm.com |
---|---|
State | Superseded |
Headers | show |
Series | PEF support in Skiboot | expand |
Context | Check | Description |
---|---|---|
snowpatch_ozlabs/apply_patch | warning | Failed to apply on branch master (7b12d5489fcfd73ef7ec0cb27eff7f8a5f13b238) |
snowpatch_ozlabs/apply_patch | fail | Failed to apply to any branch |
On Thu, Sep 5, 2019, at 6:29 AM, Ryan Grimm wrote: > From: Santosh Sivaraj <santosh@fossix.org> > > Ultravisor firmware is present as a lid file or as 'UVISOR' partition. > Use flash resource load helper to load ultravisor firmware into secure > memory area pointed by the hdata. > > Signed-off-by: Santosh Sivaraj <santosh@fossix.org> > [ grimm: Define load identifiers for ultra.lid.xz ] > [ grimm: Improve error logging ] > Signed-off-by: Ryan Grimm <grimm@linux.vnet.ibm.com> > --- > core/flash.c | 1 + > core/init.c | 14 +++++ > hw/fsp/fsp.c | 2 + > hw/ultravisor.c | 129 +++++++++++++++++++++++++++++++++++++++++++ > include/platform.h | 1 + > include/ultravisor.h | 4 ++ > 6 files changed, 151 insertions(+) > > diff --git a/core/flash.c b/core/flash.c > index 203b695d..a9c25486 100644 > --- a/core/flash.c > +++ b/core/flash.c > @@ -42,6 +42,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 25d827f2..08989b2d 100644 > --- a/core/init.c > +++ b/core/init.c > @@ -44,6 +44,7 @@ > #include <sbe-p9.h> > #include <debug_descriptor.h> > #include <occ.h> > +#include <ultravisor.h> > > enum proc_gen proc_gen; > unsigned int pcie_max_link_speed; > @@ -1203,6 +1204,11 @@ void __noreturn __nomcount main_cpu_entry(const > void *fdt) > pci_nvram_init(); > > preload_capp_ucode(); > + > + /* preload and decompress ultravisor image */ > + uv_preload_image(); > + uv_decompress_image(); > + > start_preload_kernel(); > > /* Catalog decompression routine */ > @@ -1258,6 +1264,14 @@ void __noreturn __nomcount main_cpu_entry(const > void *fdt) > /* Add the list of interrupts going to OPAL */ > add_opal_interrupts(); > > + /* Init uiltravisor software */ > + fdt = create_dtb(dt_root, false); > + if (!fdt) { > + op_display(OP_FATAL, OP_MOD_INIT, 2); > + abort(); > + } > + init_uv(fdt); > + > /* Now release parts of memory nodes we haven't used ourselves... */ > mem_region_release_unused(); > > diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c > index 6fa6534f..829e56f4 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 > @@ -2375,6 +2376,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 f79699ef..4f049254 100644 > --- a/hw/ultravisor.c > +++ b/hw/ultravisor.c > @@ -24,6 +24,10 @@ > #include <inttypes.h> > #include <ultravisor.h> > > +static char *uv_image = NULL; > +static size_t uv_image_size; > +struct xz_decompress *uv_xz = NULL; > + > static struct dt_node *add_uv_dt_node(void) > { > struct dt_node *dev, *uv; > @@ -59,6 +63,37 @@ static struct dt_node *find_uv_node(void) > return uv_node; > } > > +void init_uv(const void *fdt) > +{ > + struct dt_node *node; > + const struct dt_property *base; > + > + assert(fdt); > + > + if (!is_msr_bit_set(MSR_S)) > + return; > + > + if (!uv_xz) > + return; > + > + wait_xz_decompress(uv_xz); > + if (uv_xz->status) > + goto load_error; > + > + /* the uncompressed location will be the base address of ultravisor */ > + node = find_uv_node(); > + base = dt_find_property(node, "uv-base-address"); > + if (base) > + dt_del_property(node, (struct dt_property *)base); > + > + dt_add_property_u64(node, "uv-base-address", (uint64_t)uv_xz->dst); > + > + /* TODO start ultravisor */ > +load_error: > + free(uv_image); > + free(uv_xz); > +} > + > static bool dt_append_memory_range(struct dt_node *node, __be64 start, > __be64 len) > { > @@ -131,3 +166,97 @@ bool uv_add_mem_range(__be64 start, __be64 end) > > return ret; > } > + > +static bool uv_on_hw(void) > +{ > + return (is_msr_bit_set(MSR_S) && > + !(proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) && > + (proc_gen >= proc_gen_p9)); > +} > + > +/* > + * Preload the uv image from SMF pnor partition > + */ SMF isn't a term that's used elsewhere > +void uv_preload_image(void) > +{ > + int ret; > + > + > + if (uv_on_hw() == false) > + return; > + > + prlog(PR_DEBUG, "UV preload starting\n"); > + > + uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE; > + uv_image = malloc(MAX_COMPRESSED_UV_IMAGE_SIZE); > + if (!uv_image) { > + prerror("Memory allocation for ultravisor failed\n"); > + return; > + } Should this be on the heap or should we allocate it off a main memory region somewhere (and subsequently free it)? What if the UV grows? > + > + ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE, > + uv_image, &uv_image_size); > + > + if (ret != OPAL_SUCCESS) { > + prerror("UV: Failed to preload Ultravisor image: %d\n", ret); > + free(uv_image); > + uv_image = NULL; > + } All of this code looks familiar to other resources, there should probably be just some common code o do this. > +} > + > +/* > + * Decompress the UV image > + * > + * This function modifies the uv_image variable to point to the decompressed > + * image location. > + */ > +void uv_decompress_image(void) > +{ > + const struct dt_property *ranges; > + struct dt_node *uv_node; > + uint64_t *range; > + > + if (uv_on_hw() == false) > + return; why can't we run in sim? What prevents us from loading and running it with mambo? > + > + if (uv_image == NULL) { > + prerror("UV: Preload hasn't started yet! Aborting.\n"); or did it error out? > + return; > + } > + > + if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE, > + RESOURCE_SUBID_NONE) != OPAL_SUCCESS) { > + prerror("UV: Ultravisor image load failed\n"); > + return; > + } > + > + uv_node = dt_find_by_name(dt_root, "ibm,uv-firmware"); > + if (!uv_node) { > + prerror("UV: Cannot find ibm,uv-firmware node\n"); > + return; > + } > + > + ranges = dt_find_property(uv_node, "secure-memory-ranges"); > + if (!ranges) { > + prerror("UV: Cannot find secure-memory-ranges"); > + return; > + } > + > + uv_xz = malloc(sizeof(struct xz_decompress)); > + if (!uv_xz) { > + prerror("UV: Cannot allocate memory for decompression of UV\n"); > + return; > + } in all of these cases, memory allocated for the UV image isn't freed. > + /* the load area is the first secure memory range */ > + range = (void *)ranges->prop; > + uv_xz->dst = (void *)dt_get_number(range, 2); > + uv_xz->dst_size = dt_get_number(range + 1, 2); > + uv_xz->src = uv_image; > + uv_xz->src_size = uv_image_size; > + > + /* TODO security and integrity checks? */ I think it should certainly verify and measure loading the UV before any UV patch is merged. > + 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); > +} > diff --git a/include/platform.h b/include/platform.h > index 0b043856..259550d4 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 d038d42b..08f10da4 100644 > --- a/include/ultravisor.h > +++ b/include/ultravisor.h > @@ -20,8 +20,12 @@ > /* Bit 15 of an address should be set for it to be used as a secure memory area > * for the secure virtual machines */ > #define UV_SECURE_MEM_BIT (PPC_BIT(15)) > +#define MAX_COMPRESSED_UV_IMAGE_SIZE 0x40000 /* 256 Kilobytes */ How big is the partition size currently?
Thanks for reviewing! I was subscribed to the skiboot list in digest mode so I'm fixing up replies by hand for this thread, apologies if it looks weird. >> + * Preload the uv image from SMF pnor partition >> + */ >SMF isn't a term that's used elsewhere Oops, we don't want to use that term, I thought I grep'd for them, will remove/fix. >> + uv_image = malloc(MAX_COMPRESSED_UV_IMAGE_SIZE); >> + if (!uv_image) { >> + prerror("Memory allocation for ultravisor failed\n"); >> + return; >> + } >Should this be on the heap or should we allocate it off a main memory >region somewhere (and subsequently free it)? >What if the UV grows? Good point. You asked below but to answer here the UV partition is 1MB. So, we can use local_alloc, but I'm struggling a little bit to figure out how to free it. I looked at examples of local_alloc, but it doesn't seem any of the code in occ, phb4, or xive free their allocations. Is it up to the caller to deal with mem_regions and call mem_free with the mem_region? >> + >> + ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE, >> + uv_image, &uv_image_size); >> + >> + if (ret != OPAL_SUCCESS) { >> + prerror("UV: Failed to preload Ultravisor image: %d\n", ret); >> + free(uv_image); >> + uv_image = NULL; >> + } >All of this code looks familiar to other resources, there should > >probably be just some common code o do this. K, it is similar to loading KERNEL and INITRAMFS, but, I thought we were doing it right. I'll look again. >> + if (uv_on_hw() == false) >> + return; >why can't we run in sim? What prevents us from loading and running it >with mambo? Good point, we don't need that. I removed uv_on_hw and calls to it and things are OK. >> + >> + if (uv_image == NULL) { >> + prerror("UV: Preload hasn't started yet! Aborting.\n"); >or did it error out? K, will check what is done with kernel and try to be consistent. >> + return; >> + } >> + >> + if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE, >> + RESOURCE_SUBID_NONE) != OPAL_SUCCESS) { >> + prerror("UV: Ultravisor image load failed\n"); >> + return; >> + } >> + >> + uv_node = dt_find_by_name(dt_root, "ibm,uv-firmware"); >> + if (!uv_node) { >> + prerror("UV: Cannot find ibm,uv-firmware node\n"); >> + return; >> + } >> + >> + ranges = dt_find_property(uv_node, "secure-memory-ranges"); >> + if (!ranges) { >> + prerror("UV: Cannot find secure-memory-ranges"); >> + return; >> + } >> + >> + uv_xz = malloc(sizeof(struct xz_decompress)); >> + if (!uv_xz) { >> + prerror("UV: Cannot allocate memory for decompression of UV\n"); >> + return; >> + } >in all of these cases, memory allocated for the UV image isn't freed. K, right, will fix it up. >> + /* the load area is the first secure memory range */ >> + range = (void *)ranges->prop; >> + uv_xz->dst = (void *)dt_get_number(range, 2); >> + uv_xz->dst_size = dt_get_number(range + 1, 2); >> + uv_xz->src = uv_image; >> + uv_xz->src_size = uv_image_size; >> + >> + /* TODO security and integrity checks? */ >I think it should certainly verify and measure loading the UV before >any UV patch is merged. K, will do. Thanks, Ryan
diff --git a/core/flash.c b/core/flash.c index 203b695d..a9c25486 100644 --- a/core/flash.c +++ b/core/flash.c @@ -42,6 +42,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 25d827f2..08989b2d 100644 --- a/core/init.c +++ b/core/init.c @@ -44,6 +44,7 @@ #include <sbe-p9.h> #include <debug_descriptor.h> #include <occ.h> +#include <ultravisor.h> enum proc_gen proc_gen; unsigned int pcie_max_link_speed; @@ -1203,6 +1204,11 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) pci_nvram_init(); preload_capp_ucode(); + + /* preload and decompress ultravisor image */ + uv_preload_image(); + uv_decompress_image(); + start_preload_kernel(); /* Catalog decompression routine */ @@ -1258,6 +1264,14 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* Add the list of interrupts going to OPAL */ add_opal_interrupts(); + /* Init uiltravisor software */ + fdt = create_dtb(dt_root, false); + if (!fdt) { + op_display(OP_FATAL, OP_MOD_INIT, 2); + abort(); + } + init_uv(fdt); + /* Now release parts of memory nodes we haven't used ourselves... */ mem_region_release_unused(); diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c index 6fa6534f..829e56f4 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 @@ -2375,6 +2376,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 f79699ef..4f049254 100644 --- a/hw/ultravisor.c +++ b/hw/ultravisor.c @@ -24,6 +24,10 @@ #include <inttypes.h> #include <ultravisor.h> +static char *uv_image = NULL; +static size_t uv_image_size; +struct xz_decompress *uv_xz = NULL; + static struct dt_node *add_uv_dt_node(void) { struct dt_node *dev, *uv; @@ -59,6 +63,37 @@ static struct dt_node *find_uv_node(void) return uv_node; } +void init_uv(const void *fdt) +{ + struct dt_node *node; + const struct dt_property *base; + + assert(fdt); + + if (!is_msr_bit_set(MSR_S)) + return; + + if (!uv_xz) + return; + + wait_xz_decompress(uv_xz); + if (uv_xz->status) + goto load_error; + + /* the uncompressed location will be the base address of ultravisor */ + node = find_uv_node(); + base = dt_find_property(node, "uv-base-address"); + if (base) + dt_del_property(node, (struct dt_property *)base); + + dt_add_property_u64(node, "uv-base-address", (uint64_t)uv_xz->dst); + + /* TODO start ultravisor */ +load_error: + free(uv_image); + free(uv_xz); +} + static bool dt_append_memory_range(struct dt_node *node, __be64 start, __be64 len) { @@ -131,3 +166,97 @@ bool uv_add_mem_range(__be64 start, __be64 end) return ret; } + +static bool uv_on_hw(void) +{ + return (is_msr_bit_set(MSR_S) && + !(proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) && + (proc_gen >= proc_gen_p9)); +} + +/* + * Preload the uv image from SMF pnor partition + */ +void uv_preload_image(void) +{ + int ret; + + + if (uv_on_hw() == false) + return; + + prlog(PR_DEBUG, "UV preload starting\n"); + + uv_image_size = MAX_COMPRESSED_UV_IMAGE_SIZE; + uv_image = malloc(MAX_COMPRESSED_UV_IMAGE_SIZE); + if (!uv_image) { + prerror("Memory allocation for ultravisor failed\n"); + return; + } + + ret = start_preload_resource(RESOURCE_ID_UV_IMAGE, RESOURCE_SUBID_NONE, + uv_image, &uv_image_size); + + if (ret != OPAL_SUCCESS) { + prerror("UV: Failed to preload Ultravisor image: %d\n", ret); + free(uv_image); + uv_image = NULL; + } +} + +/* + * Decompress the UV image + * + * This function modifies the uv_image variable to point to the decompressed + * image location. + */ +void uv_decompress_image(void) +{ + const struct dt_property *ranges; + struct dt_node *uv_node; + uint64_t *range; + + if (uv_on_hw() == false) + return; + + if (uv_image == NULL) { + prerror("UV: Preload hasn't started yet! Aborting.\n"); + return; + } + + if (wait_for_resource_loaded(RESOURCE_ID_UV_IMAGE, + RESOURCE_SUBID_NONE) != OPAL_SUCCESS) { + prerror("UV: Ultravisor image load failed\n"); + return; + } + + uv_node = dt_find_by_name(dt_root, "ibm,uv-firmware"); + if (!uv_node) { + prerror("UV: Cannot find ibm,uv-firmware node\n"); + return; + } + + ranges = dt_find_property(uv_node, "secure-memory-ranges"); + if (!ranges) { + prerror("UV: Cannot find secure-memory-ranges"); + return; + } + + uv_xz = malloc(sizeof(struct xz_decompress)); + if (!uv_xz) { + prerror("UV: Cannot allocate memory for decompression of UV\n"); + return; + } + + /* the load area is the first secure memory range */ + range = (void *)ranges->prop; + uv_xz->dst = (void *)dt_get_number(range, 2); + uv_xz->dst_size = dt_get_number(range + 1, 2); + uv_xz->src = uv_image; + uv_xz->src_size = uv_image_size; + + /* TODO security and integrity checks? */ + 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); +} diff --git a/include/platform.h b/include/platform.h index 0b043856..259550d4 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 d038d42b..08f10da4 100644 --- a/include/ultravisor.h +++ b/include/ultravisor.h @@ -20,8 +20,12 @@ /* Bit 15 of an address should be set for it to be used as a secure memory area * for the secure virtual machines */ #define UV_SECURE_MEM_BIT (PPC_BIT(15)) +#define MAX_COMPRESSED_UV_IMAGE_SIZE 0x40000 /* 256 Kilobytes */ extern int start_uv(uint64_t entry, void *ptr); extern bool uv_add_mem_range(__be64 start, __be64 end); +extern void uv_preload_image(void); +extern void uv_decompress_image(void); +extern void init_uv(const void *fdt); #endif /* __ULTRAVISOR_H */