From patchwork Fri Jun 9 06:55:41 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Brown X-Patchwork-Id: 773687 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wkY4x135hz9s8F for ; Fri, 9 Jun 2017 16:57:21 +1000 (AEST) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="tPU0HrTt"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3wkY4x049yzDqNp for ; Fri, 9 Jun 2017 16:57:21 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="tPU0HrTt"; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from mail-pf0-x241.google.com (mail-pf0-x241.google.com [IPv6:2607:f8b0:400e:c00::241]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3wkY481KkszDqLk for ; Fri, 9 Jun 2017 16:56:40 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="tPU0HrTt"; dkim-atps=neutral Received: by mail-pf0-x241.google.com with SMTP id u26so7673631pfd.2 for ; Thu, 08 Jun 2017 23:56:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id:in-reply-to:references; bh=m9aWRo6XEFIBCNvC4xutgB2t83XLi/JQUH5kW69WgGQ=; b=tPU0HrTt+TikxRUnUpLyE6oBjfQl/yvZLvvXSnMj7JePxKOjDSkCqVGtbetZzYf1iB HdqU39r2w0wHWdZJd+rOkE18HpQgQKA2i/9vhHwu+zFPbFuiUcwVRQSHpPqa04mmdPQM Z92DVzu2G0oRzDBjIbjAUjowQVoP2ix7J/nxAnE9tR+KpDH0FauP1y69Muws5dqQWia5 cin4E+Pb+ZDeJnq+0qQqDgXzuYukdDF7xM5fpXrLUiNlnMonFmnYA+3erSTu1261dXGV Cu1jrMH2bLiUJxUc7g+kv/vxJmUlue1Il9thKxr1nLkIGDhdOYyxTgiARgckIg/H2V7X wG5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:subject:date:message-id:in-reply-to :references; bh=m9aWRo6XEFIBCNvC4xutgB2t83XLi/JQUH5kW69WgGQ=; b=Mc0itHQGibaaLOxRXe2NyJj7XVtdGqXX4p2y9qeMAiMBLyYy0oGPi4uL1LRl5ReJx3 E+QkLqxFGzIHXAStF9DlmNAiHRL8CflV3JFOT7iiiKfTUDiZWPa47LxJjt57qRR1sGMJ jXKEGnA6+hdyCWegKVvKP614LxJMg0VIaXHZ6US9q65xdcxhVTTKooFEnPK3GhMjVlIc H0L4b6e5YzcEBSTgAPCSNkrjZM8XD30K0GLkzq2BqsvzdhTm/WE/kdYbAHhMsRtyUIkT 1GgxCvLr65p920S0743xj04YB36uHqCR/VACZeR/wBb1IhY4LnPDD+ZYlqgMK06dfCyI yM4Q== X-Gm-Message-State: AODbwcARmxeYTSkyfkRRy9vTgPqfM8TO44LQdFjhzw/d5Q7DjegdNG21 E2u9Fx5X0nfO2wh4 X-Received: by 10.84.133.65 with SMTP id 59mr39814553plf.230.1496991398228; Thu, 08 Jun 2017 23:56:38 -0700 (PDT) Received: from matt.ozlabs.ibm.com ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id 81sm653535pge.46.2017.06.08.23.56.36 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 08 Jun 2017 23:56:37 -0700 (PDT) From: Matt Brown To: skiboot@lists.ozlabs.org Date: Fri, 9 Jun 2017 16:55:41 +1000 Message-Id: <20170609065546.28963-5-matthew.brown.dev@gmail.com> X-Mailer: git-send-email 2.9.3 In-Reply-To: <20170609065546.28963-1-matthew.brown.dev@gmail.com> References: <20170609065546.28963-1-matthew.brown.dev@gmail.com> Subject: [Skiboot] [PATCH 05/10] core: Decode payload initrd on openpower X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" This patch adds the ability for openpower machines to decode the payloads initramfs before the kernel requires it. Allowing petitboot to boot faster. Openpower machines use zImage files for the payload. This contains the kernel, with the initramfs baked into the file. There is not way to determine the location of the initramfs this way. In order to do the asyncronous decoding on openpower, the payload must be packaged as a Flattened Image Tree (FIT). This is similar to a standard DT, but contains the kernel and initramfs images. This allows us to locate the initramfs and decode it before the kernel requires it. This gives similar performance benefits to the FSP case, saving around 2.7 seconds during the boot process. To create the FIT file we use the `mkimage` tool. You can find documentation on FIT files and how to create them on from the u-boot repository. (Under /doc/uImage.FIT/) Signed-off-by: Matt Brown --- core/flash.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++- include/skiboot.h | 3 ++ 2 files changed, 159 insertions(+), 1 deletion(-) diff --git a/core/flash.c b/core/flash.c index 793401c..5d37ac9 100644 --- a/core/flash.c +++ b/core/flash.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,9 @@ #include #include #include +#include +#include +#include struct flash { struct list_node list; @@ -612,7 +616,11 @@ static int flash_load_resource(enum resource_id id, uint32_t subid, if (!content_size) { prerror("FLASH: Invalid ELF header part %s\n", name); - goto out_free_ffs; + /* Check for DT header */ + if (!fdt_check_header(buf)) + content_size = fdt_totalsize(buf); + else + goto out_free_ffs; } prlog(PR_DEBUG, "FLASH: computed %s size %u\n", name, content_size); @@ -790,3 +798,150 @@ int flash_start_preload_resource(enum resource_id id, uint32_t subid, return OPAL_SUCCESS; } + +struct boot_resources *boot_res; +static struct dt_node *uImg_root; +static size_t initramfs_uncomp_size = 0; +static struct cpu_job *flash_load_res_job = NULL; + +/* + * setup_boot_resource_dt parses the device-tree and configures the locations + * of the boot resources. + * The default configuration will be used. If there is no default property, + * we take the first configuration. + */ +static void setup_boot_resource_dt(void) +{ + const struct dt_property *def_conf, *kname, *rname, *kdata, *rdata, *usize; + char *kernel_name, *ramdisk_name, *end; + struct dt_node *node; + + /* Find configuration node*/ + node = dt_find_by_name(uImg_root, "configurations"); + + if (!node) { + prlog(PR_PRINTF, "FLASH: FDT configurations node not found\n"); + return; + } + + /* Find default config property */ + def_conf = dt_find_property(node, "default"); + + if (!def_conf) { + /* If no default node, take first config child node as default */ + node = dt_first(node); + if (!node) { + prlog(PR_PRINTF, "FLASH: FDT has empty configuration list\n"); + return; + } + } + else { + /* Get node for config based on default value */ + node = dt_find_by_name(node, def_conf->prop); + } + + + /* Find corresponding kernel and ramdisk names for the config */ + kname = dt_find_property(node, "kernel"); + kernel_name = (char *)kname->prop; + + rname = dt_find_property(node, "ramdisk"); + ramdisk_name = (char *)rname->prop; + + /* Setup kernel location */ + node = dt_find_by_name(uImg_root, kernel_name); + kdata = dt_find_property(node, "data"); + if (kdata) { + boot_res->kernel_size = kdata->len; + boot_res->kernel_base = (void *)&kdata->prop; + } + + + /* Setup initramfs location */ + node = dt_find_by_name(uImg_root, ramdisk_name); + rdata = dt_find_property(node, "data"); + if (rdata) { + boot_res->initramfs_size = rdata->len; + boot_res->initramfs_base = (void *)&rdata->prop; + boot_res->initramfs_loaded = true; + } + + /* Setup uncompressed size of the initramfs (optional property) */ + usize = dt_find_property(node, "uncompressed_size"); + if (usize) + initramfs_uncomp_size = strtol(usize->prop, &end, 10); +} + +/* + * flash_setup_boot_resources is used to setup the location of the boot + * resources and decode the initramfs. + * The information is passed through a FDT in the BOOTKERNEL partition. + * This method is only used on BMC machines. + */ +static void flash_setup_boot_resource(void *data __unused) +{ + int loaded, waited, r; + void *buf; + size_t len; + char *strt; + + waited = 0; + + /* Wait for the kernel to be loaded */ + do { + opal_run_pollers(); + r = flash_resource_loaded(RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE); + time_wait_ms_nopoll(5); + if (r != OPAL_BUSY) + break; + time_wait_ms_nopoll(5); + waited += 10; + + } + while (r == OPAL_BUSY); + + boot_res->kernel_loaded = true; + + strt = (char *)boot_res->kernel_base; + + prlog(PR_PRINTF, "FLASH: waited %u ms for kernel\n", waited); + + /* Setup kernel and initramfs FDT */ + uImg_root = dt_new_root("uImage"); + loaded = dt_expand_node(uImg_root, boot_res->kernel_base, 0); + + if (loaded < 0) + return; + + setup_boot_resource_dt(); + + /* Now the resources have been setup, try and decode the initramfs */ + buf = boot_res->initramfs_base; + len = boot_res->initramfs_size; + + r = decode_resource_xz(&buf, &len, &initramfs_uncomp_size); + + if (r == XZ_STREAM_END) { + /* Set new initramfs location */ + boot_res->initramfs_base = buf; + boot_res->initramfs_size = len; + } + + boot_res->success = true; + + return; +} + +struct cpu_job* flash_load_boot_resource(struct boot_resources *r) +{ + boot_res = r; + if (flash_load_res_job) + cpu_wait_job(flash_load_res_job, true); + + flash_load_res_job = cpu_queue_job(NULL, "flash_setup_boot_resource", + flash_setup_boot_resource, NULL); + + cpu_process_local_jobs(); + + return flash_load_res_job; +} diff --git a/include/skiboot.h b/include/skiboot.h index 8bc767a..6543cfa 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -236,6 +236,9 @@ extern int flash_start_preload_resource(enum resource_id id, uint32_t subid, extern int flash_resource_loaded(enum resource_id id, uint32_t idx); extern bool flash_reserve(void); extern void flash_release(void); + +extern struct cpu_job* flash_load_boot_resource(struct boot_resources *r); + #define FLASH_SUBPART_ALIGNMENT 0x1000 #define FLASH_SUBPART_HEADER_SIZE FLASH_SUBPART_ALIGNMENT extern int flash_subpart_info(void *part_header, uint32_t header_len,