[Skiboot] [RFC PATCH 4/8] pef: Ultravisor initialisation
Stewart Smith
stewart at flamingspork.com
Fri Sep 6 02:45:13 AEST 2019
On Thu, Sep 5, 2019, at 6:29 AM, Ryan Grimm wrote:
> From: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
>
> The ultravisor image after is start on each CPU after being loaded from
> the flash/fsp. It is copied to secure memory and run.
>
> Signed-off-by: Madhavan Srinivasan <maddy at linux.vnet.ibm.com>
> Signed-off-by: Santosh Sivaraj <santosh at fossix.org>
> [ grimm: Add init_uv comments, logging, and logic cleanups ]
> [ grimm: Increase UV image max size to 2MB ]
> [ grimm: Redfine the OPAL UV shared data structure ]
> [ grimm: Remove Hostboot regions from secure range 0 ]
> Signed-off-by: Ryan Grimm <grimm at linux.ibm.com>
> [ andmike: Split init and start of ultravisor ]
> Signed-off-by: Michael Anderson <andmike at linux.ibm.com>
> ---
> core/init.c | 11 +-
> hw/ultravisor.c | 256 +++++++++++++++++++++++++++++++++++++--
> include/ultravisor-api.h | 31 +++++
> include/ultravisor.h | 13 +-
> 4 files changed, 294 insertions(+), 17 deletions(-)
> create mode 100644 include/ultravisor-api.h
>
> diff --git a/core/init.c b/core/init.c
> index 08989b2d..756ee211 100644
> --- a/core/init.c
> +++ b/core/init.c
> @@ -544,6 +544,10 @@ void __noreturn load_and_boot_kernel(bool is_reboot)
>
> trustedboot_exit_boot_services();
>
> + if (!is_reboot) {
> + start_ultravisor();
> + }
> +
I don't think this should live in a function that is claled load_and_boot_kernel(), have it be a separate step in the main init flow.
It represents a fairly significant step in boot, and completely changes how we have to talk to things.
> ipmi_set_fw_progress_sensor(IPMI_FW_OS_BOOT);
>
>
> @@ -1265,12 +1269,7 @@ void __noreturn __nomcount main_cpu_entry(const
> void *fdt)
> 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);
> + init_uv();
>
> /* Now release parts of memory nodes we haven't used ourselves... */
> mem_region_release_unused();
> diff --git a/hw/ultravisor.c b/hw/ultravisor.c
> index 4f049254..e3d7d42a 100644
> --- a/hw/ultravisor.c
> +++ b/hw/ultravisor.c
> @@ -23,10 +23,14 @@
> #include <string.h>
> #include <inttypes.h>
> #include <ultravisor.h>
> +#include <mem_region.h>
> +#include <ultravisor-api.h>
> +#include <libfdt/libfdt.h>
>
> static char *uv_image = NULL;
> static size_t uv_image_size;
> struct xz_decompress *uv_xz = NULL;
> +static struct uv_opal *uv_opal;
>
> static struct dt_node *add_uv_dt_node(void)
> {
> @@ -63,32 +67,266 @@ static struct dt_node *find_uv_node(void)
> return uv_node;
> }
>
> -void init_uv(const void *fdt)
> +static bool find_secure_mem_to_copy(uint64_t *target, uint64_t *sz)
> +{
> + struct dt_node *uv_node = find_uv_node();
> + const struct dt_property *ranges;
> + uint64_t uv_pef_reg;
> + uint64_t *range, sm_size, img_size = UV_LOAD_MAX_SIZE;
> +
> + /*
> + * "uv-secure-memory" property could have multiple
> + * secure memory blocks. Pick first to load
> + * ultravisor in it.
> + */
> + ranges = dt_find_property(uv_node, "secure-memory-ranges");
> + if (!ranges)
> + return false;
> +
> + range = (void *)ranges->prop;
> + do {
> + uv_pef_reg = dt_get_number(range, 2);
> + if (!uv_pef_reg)
> + return false;
> +
> + sm_size = dt_get_number(range + 1, 2);
> + if (sm_size > img_size)
> + break;
> + range += 2;
> + } while (range);
> +
> + *target = uv_pef_reg;
> + *sz = sm_size;
> + return true;
> +}
> +
> +static uint64_t find_uv_fw_base_addr(struct dt_node *uv_node)
> +{
> + uint64_t base_addr = 0;
> +
> + if (dt_has_node_property(uv_node, "uv-base-address", NULL))
> + base_addr = dt_prop_get_u64(uv_node, "uv-base-address");
> +
> + return base_addr;
> +}
> +
> +static void reserve_secure_memory_region(void)
> +{
> + struct dt_node *uv_node = find_uv_node();
> + const struct dt_property *ranges;
> + uint64_t *range, *rangesp, sm_size, addr;
> + char buf[128];
> + int i=0;
> +
> + ranges = dt_find_property(uv_node, "secure-memory-ranges");
> + if (!ranges)
> + return;
> +
> + for (rangesp = (uint64_t *)(ranges->prop + ranges->len),
> + range = (uint64_t *)ranges->prop;
> + range < rangesp;
> + range += 2) {
> + addr = dt_get_number(range, 2);
> + if (!addr)
> + break;
> +
> + sm_size = dt_get_number(range + 1, 2);
> + if (!sm_size)
> + break;
> +
> + /* Remove Hostboot regions from secure memory 0 so we don't abort
> + * on overlapping regions */
> + if (i == 0) {
> + prlog(PR_INFO, "Secure region 0, removing HB region\n");
> + /* TODO: Check with Hostboot for memory map */
> + sm_size = sm_size - UV_HB_RESERVE_SIZE;
> + }
> +
> + snprintf(buf, 128, "ibm,secure-region-%d",i++);
> + mem_reserve_fw(strdup(buf), addr, sm_size);
> + }
> +
> + return;
> +}
> +
> +static void reserve_uv_memory(struct uv_opal *uv_opal)
> +{
> + if (uv_opal->uv_base_addr == UV_LOAD_BASE) {
> + mem_reserve_fw("ibm,uv-code", UV_LOAD_BASE, UV_LOAD_MAX_SIZE);
> + } else {
> + reserve_secure_memory_region();
> + }
> +}
> +
> +static void cpu_start_ultravisor(void *data)
> +{
> + struct uv_opal *ptr = (struct uv_opal *)data;
> + start_uv(ptr->uv_base_addr, ptr);
> +}
> +
> +int start_ultravisor(void)
> +{
> + struct cpu_thread *cpu;
> + struct cpu_job **jobs;
> + int i=0;
> +
> + prlog(PR_NOTICE, "UV: Starting Ultravisor at 0x%llx sys_fdt 0x%llx
> uv_fdt 0x%0llx\n",
> + uv_opal->uv_base_addr, uv_opal->sys_fdt, uv_opal->uv_fdt);
> +
> + /* Alloc memory for Jobs */
> + jobs = zalloc(sizeof(struct cpu_job*) * cpu_max_pir);
> +
> + for_each_available_cpu(cpu) {
> + if (cpu == this_cpu())
> + continue;
> + jobs[i++] = cpu_queue_job(cpu, "start_ultravisor",
> + cpu_start_ultravisor, (void *)uv_opal);
> + }
> +
> + cpu_start_ultravisor((void *)uv_opal);
> +
> + /* wait for everyone to sync back */
> + while (i > 0) {
> + cpu_wait_job(jobs[--i], true);
> + }
> +
> + /* free used stuff */
> + free(jobs);
> +
> + /* Check everything is fine */
> + if (uv_opal->uv_ret_code) {
> + return OPAL_HARDWARE;
> + }
> +
> + return OPAL_SUCCESS;
> +}
> +
> +static int create_dtb_uv(void *uv_fdt)
> +{
> + if (fdt_create(uv_fdt, UV_FDT_MAX_SIZE)) {
> + prerror("UV: Failed to create uv_fdt\n");
> + return 1;
> + }
> +
> + fdt_finish_reservemap(uv_fdt);
> + fdt_begin_node(uv_fdt, "");
> + fdt_property_string(uv_fdt, "description", "UV dt");
> + fdt_begin_node(uv_fdt, "ibm,uv-firmware");
> + fdt_property_string(uv_fdt, "compatible", "ibm,uv-v1");
> + fdt_end_node(uv_fdt);
> + fdt_end_node(uv_fdt);
> + fdt_finish(uv_fdt);
> +
> + return OPAL_SUCCESS;
> +}
why are you manually manipulating the FDT rather than just using the normal functions and flattening it?
> +/* We could be running on Mambo, Cronus, or Hostboot
> + *
> + * Detect Mambo via chip quirk. Mambo writes the uncompressed UV
> images
> + * directly to secure memory and passes secure memory location via
> device tree.
> + *
> + * Detect Cronus when HB decompress fails. Cronus writes the
> uncompressed UV
> + * image to insecure memory and init_uv will copy from insecure to
> secure.
> + *
> + * Assume HB by waiting for decompress. UV should have been loaded
> from FSP
> + * and decompressed earlier via uv_preload_image and
> uv_decompress_image. The
> + * secure location of the UV provided by those functions in xz struct.
> */
> +void init_uv()
> {
> struct dt_node *node;
> const struct dt_property *base;
> + uint64_t uv_src_addr, uv_pef_reg, uv_pef_size;
> + void *uv_fdt;
>
> - assert(fdt);
> + prlog(PR_NOTICE, "UV: Init starting\n");
>
> - if (!is_msr_bit_set(MSR_S))
> + uv_opal = zalloc(sizeof(struct uv_opal));
> + if (!uv_opal) {
> + prerror("UV: Failed to allocate uv_opal\n");
> return;
> + }
> +
> + if (!is_msr_bit_set(MSR_S)) {
> + prlog(PR_DEBUG, "UV: S bit not set\n");
> + return;
> + }
>
> - if (!uv_xz)
> + node = find_uv_node();
> + if (!node) {
> + prlog(PR_DEBUG, "UV: Device tree node not found\n");
> return;
> + }
> +
> + if (proc_chip_quirks & QUIRK_MAMBO_CALLOUTS) {
> + prlog(PR_INFO, "UV: Mambo simulator detected\n");
> +
> + if (!find_secure_mem_to_copy(&uv_pef_reg, &uv_pef_size)) {
> + prlog(PR_DEBUG, "UV: No secure memory configured, exiting\n");
> + goto load_error;
> + }
> +
> + goto start;
> + }
> +
> + /* This would be null in case we are on Mambo or Cronus */
> + if (!uv_xz) {
> +
> + prlog(PR_INFO, "UV: Platform load failed, detecting UV image via
> device tree\n");
> +
> + if (!find_secure_mem_to_copy(&uv_pef_reg, &uv_pef_size)) {
> + prlog(PR_DEBUG, "UV: No secure memory configured, exiting\n");
> + goto load_error;
> + }
> +
> + uv_src_addr = find_uv_fw_base_addr(node);
> + if (!uv_src_addr) {
> + prlog(PR_DEBUG, "UV: Couldn't find UV base address in device
> tree\n");
> + goto load_error;
> + }
>
> + prlog(PR_INFO, "UV: Copying Ultravisor to protected memory 0x%llx
> from 0x%llx\n", uv_pef_reg, uv_src_addr);
> +
> + memcpy((void *)uv_pef_reg, (void *)uv_src_addr, UV_LOAD_MAX_SIZE);
> +
> + goto start;
> + }
> +
> + /* Hostboot path */
> wait_xz_decompress(uv_xz);
> - if (uv_xz->status)
> + if (uv_xz->status) {
> + prlog(PR_INFO, "UV: Compressed Ultravisor image failed to
> decompress");
> goto load_error;
> + }
IMNSHO in all of these situations the secure and trusted boot dance should be done.
> - /* the uncompressed location will be the base address of ultravisor */
> - node = find_uv_node();
> + /* the uncompressed location will be the base address of ultravisor
> + * so fix up if it's already there */
> 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 */
> + uv_pef_reg = (uint64_t)uv_xz->dst;
> + uv_pef_size = (uint64_t)uv_xz->dst_size;
> +
> +start:
> + uv_opal->uv_base_addr = uv_pef_reg;
> +
> + uv_opal->sys_fdt = (__be64)create_dtb(dt_root, false);
> + if (!uv_opal->sys_fdt) {
> + prerror("UV: Failed to create system fdt\n");
> + goto load_error;
> + }
> +
> + uv_fdt = (void *)(uv_pef_reg + UV_LOAD_MAX_SIZE);
> + if (create_dtb_uv(uv_fdt)) {
> + prerror("UV: Failed to create uv fdt\n");
> + goto load_error;
> + }
> + uv_opal->uv_fdt = (__be64)uv_fdt;
> +
> + reserve_uv_memory(uv_opal);
> +
> load_error:
> free(uv_image);
> free(uv_xz);
> @@ -190,7 +428,7 @@ void uv_preload_image(void)
> 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");
> + prerror("UV: Memory allocation for Ultravisor failed\n");
> return;
> }
>
> diff --git a/include/ultravisor-api.h b/include/ultravisor-api.h
> new file mode 100644
> index 00000000..52d86024
> --- /dev/null
> +++ b/include/ultravisor-api.h
> @@ -0,0 +1,31 @@
> +/* Copyright 2013-2018 IBM Corp.
nothing in 2019?
Also, should be SPDX headers.
> + *
> + * Licensed under the Apache License, Version 2.0 (the "License");
> + * you may not use this file except in compliance with the License.
> + * You may obtain a copy of the License at
> + *
> + * http://www.apache.org/licenses/LICENSE-2.0
> + *
> + * Unless required by applicable law or agreed to in writing, software
> + * distributed under the License is distributed on an "AS IS" BASIS,
> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> + * implied.
> + * See the License for the specific language governing permissions and
> + * limitations under the License.
> + */
> +
> +#ifndef __ULTRAVISOR_API_H
> +#define __ULTRAVISOR_API_H
> +
> +struct uv_opal {
> + __be32 magic; /**< 'OPUV' 0x4F505556 OPUV_MAGIC */
> + __be32 version; /**< uv_opal struct version */
> + __be32 uv_ret_code; /**< 0 - Success, <0> : error. */
> + __be32 uv_api_ver; /**< Current uv api version. */
> + __be64 uv_base_addr; /**< Base address of UV in secure memory. */
> + __be64 sys_fdt; /**< System FDT. */
> + __be64 uv_fdt; /**< UV FDT in secure memory. */
> + __be64 uv_mem; /**< struct memcons */
> +};
> +
> +#endif /* __ULTRAVISOR_API_H */
> diff --git a/include/ultravisor.h b/include/ultravisor.h
> index 08f10da4..976b6323 100644
> --- a/include/ultravisor.h
> +++ b/include/ultravisor.h
> @@ -17,15 +17,24 @@
> #ifndef __ULTRAVISOR_H
> #define __ULTRAVISOR_H
needs spdx header.
More information about the Skiboot
mailing list