From patchwork Fri Jun 9 06:55:37 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matt Brown X-Patchwork-Id: 773678 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3wkY3m5sJZz9s8N for ; Fri, 9 Jun 2017 16:56:20 +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="XiZpsH9S"; 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 3wkY3l6M1ZzDqLp for ; Fri, 9 Jun 2017 16:56:19 +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="XiZpsH9S"; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Received: from mail-pf0-x244.google.com (mail-pf0-x244.google.com [IPv6:2607:f8b0:400e:c00::244]) (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 3wkY3c6x2jzDqLd for ; Fri, 9 Jun 2017 16:56:12 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="XiZpsH9S"; dkim-atps=neutral Received: by mail-pf0-x244.google.com with SMTP id u26so7672563pfd.2 for ; Thu, 08 Jun 2017 23:56:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:subject:date:message-id; bh=LZIhXjDkxoiYSpj3U0uqG0D0nPRJ3mA4a4NaG8CpzUY=; b=XiZpsH9SARUd77b8vFO/7uKeRvIZTzXY9tuJ0cLMrJPQxppkW6TsHNVya7ZBA4zSCZ mcHGkYEmFM6shZjZ64bGZeZJmfZ3KQFeZu98SQRXf5oqZof+fLrlREcWK+KA736ifjjm UcmjznSFiSKi7y4zlHb+8i/hRMDOpcT/NO9efJONeANjAXlTu5YW/9XQZhYeLxWxXO6R AmWRUJpNcq65X2JUjoVcrsc/c63kNSpTk7suL2pXsiX4RYSdF8aork0S5Ngfu++WdwOt etOJMEJnoiP8u9YIwZi04mLBhCX3Nh5+Wxxqds6N9oAUD6LAzi+uok+JODhwtDiAthRf RzpA== 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; bh=LZIhXjDkxoiYSpj3U0uqG0D0nPRJ3mA4a4NaG8CpzUY=; b=ZlVNXFz4nIYW6SHncYwwH9IDVohfAFWY/XJwat8Tv8RnIu8k7LSEkwCCaeTWXzA0be vuwFWXIS0Ql5gxpNYoc9BHxWZIZWzckFXGkHSPUR2FFbYpeCX5Spkq30Suw+TwPHn/Al qdroRcrstrZLJWiZcY9WR6X6HCXGHSW27zszDXTIQHKQJbIyq+76wxAf4rdN6Gzperzt Pif9HokaN3jQGi7A8bTUi1AMoZ+DCilkrGWxYfrClxZYLq22t+keRFiyIQMRlTdwHavu MlvmUml28vKI9lA4kiNoUvcenpB/4fFIe84HwIfW+ztOXmz1KNXUfsSS//wjVAJbpbC9 N5Lg== X-Gm-Message-State: AODbwcB0525fVa8QImlEcefchltReUOl2QU+gHzMw0Gimc0dNATYgFn/ h1q3OALNaokCnN+a X-Received: by 10.98.52.66 with SMTP id b63mr15287393pfa.7.1496991370762; Thu, 08 Jun 2017 23:56:10 -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.08 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 08 Jun 2017 23:56:10 -0700 (PDT) From: Matt Brown To: skiboot@lists.ozlabs.org Date: Fri, 9 Jun 2017 16:55:37 +1000 Message-Id: <20170609065546.28963-1-matthew.brown.dev@gmail.com> X-Mailer: git-send-email 2.9.3 Subject: [Skiboot] [PATCH 01/10] hw/fsp: Decode payload initrd on FSP machines 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" During bootup on FSP systems, the payload kernel and initrd files are loaded seperately. While the initrd has been loaded, it is still in its compressed form. The initrd is generally compressed using xz encoding. As we have plenty of spare resources during the Skiboot initialisation we can preemptively decode the initrd file before the Linux kernel needs it. This saves time during the kernel boot as it doesn't need to wait for the initrd to decompress before continuing. This patch adds the load_done function to platforms, with a FSP specific implementation, which loads and configures the boot resources. This consists of asyncronously loading and then decoding the initramfs. By using the asyncronous load_done function we reduce the boot time by 2.5 seconds. Note: This requires the skiboot libxz patches Signed-off-by: Matt Brown --- The next load of patches adds this asyncronous decoding for both FSP and Openpower systems. The FSP method works with the existing file formats. To use this improvement in openpower we need to package the payload kernel and initramfs as a Flattened Image Tree (FIT). It will still work if you use a zImage but there won't be any significant performance gain. --- core/init.c | 92 +++++++++++++++++++++++++++++++++++++++++++----------- core/platform.c | 11 +++++++ hw/fsp/fsp.c | 59 ++++++++++++++++++++++++++++++++++ include/fsp.h | 3 ++ include/platform.h | 24 ++++++++++++++ 5 files changed, 170 insertions(+), 19 deletions(-) diff --git a/core/init.c b/core/init.c index 6b8137c..bf42f3e 100644 --- a/core/init.c +++ b/core/init.c @@ -47,6 +47,8 @@ #include #include #include +#include +#include "libxz/xz.h" enum proc_gen proc_gen; unsigned int pcie_max_link_speed; @@ -302,34 +304,50 @@ extern char __builtin_kernel_start[]; extern char __builtin_kernel_end[]; extern uint64_t boot_offset; -static size_t initramfs_size; +static struct boot_resources boot_res = { + .kernel_base = KERNEL_LOAD_BASE, + .kernel_size = KERNEL_LOAD_SIZE, + .kernel_loaded = false, + .initramfs_base = INITRAMFS_LOAD_BASE, + .initramfs_size = INITRAMFS_LOAD_SIZE, + .initramfs_loaded = false, + .success = false, +}; +static struct cpu_job *load_boot_resource_job = NULL; bool start_preload_kernel(void) { int loaded; - + /* Try to load an external kernel payload through the platform hooks */ - kernel_size = KERNEL_LOAD_SIZE; loaded = start_preload_resource(RESOURCE_ID_KERNEL, RESOURCE_SUBID_NONE, KERNEL_LOAD_BASE, - &kernel_size); + &boot_res.kernel_size); if (loaded != OPAL_SUCCESS) { printf("INIT: platform start load kernel failed\n"); kernel_size = 0; return false; } - initramfs_size = INITRAMFS_LOAD_SIZE; loaded = start_preload_resource(RESOURCE_ID_INITRAMFS, RESOURCE_SUBID_NONE, - INITRAMFS_LOAD_BASE, &initramfs_size); + INITRAMFS_LOAD_BASE, + &boot_res.initramfs_size); if (loaded != OPAL_SUCCESS) { printf("INIT: platform start load initramfs failed\n"); - initramfs_size = 0; return false; } + + /* + * Async job to load, configure and decode kernel and initramfs + * This is platform specific. FSPs only have to decode the initramfs. + * BMCs have to parse the FIT, configure the resource locations, then + * decode the initramfs. + */ + load_boot_resource_job = start_async_load(&boot_res); + return true; } @@ -342,12 +360,16 @@ static bool load_kernel(void) prlog(PR_NOTICE, "INIT: Waiting for kernel...\n"); - loaded = wait_for_resource_loaded(RESOURCE_ID_KERNEL, - RESOURCE_SUBID_NONE); + /* If on FSP machine, initramfs is decoded but need to load the kernel*/ + if (!boot_res.kernel_loaded) { - if (loaded != OPAL_SUCCESS) { - printf("INIT: platform wait for kernel load failed\n"); - kernel_size = 0; + loaded = wait_for_resource_loaded(RESOURCE_ID_KERNEL, + RESOURCE_SUBID_NONE); + + if (loaded != OPAL_SUCCESS) { + printf("INIT: platform wait for kernel load failed\n"); + kernel_size = 0; + } } /* Try embedded kernel payload */ @@ -395,6 +417,9 @@ static bool load_kernel(void) } } + if (boot_res.success) + kh = (struct elf_hdr *)boot_res.kernel_base; + printf("INIT: Kernel loaded, size: %zu bytes (0 = unknown preload)\n", kernel_size); @@ -433,23 +458,27 @@ static bool load_kernel(void) static void load_initramfs(void) { - int loaded; + int loaded = 0; - loaded = wait_for_resource_loaded(RESOURCE_ID_INITRAMFS, - RESOURCE_SUBID_NONE); + printf("INIT: called load_initramfs\n"); + if (!boot_res.initramfs_loaded) + loaded = wait_for_resource_loaded(RESOURCE_ID_INITRAMFS, + RESOURCE_SUBID_NONE); - if (loaded != OPAL_SUCCESS || !initramfs_size) + if (loaded != OPAL_SUCCESS || !boot_res.initramfs_size) return; dt_check_del_prop(dt_chosen, "linux,initrd-start"); dt_check_del_prop(dt_chosen, "linux,initrd-end"); - printf("INIT: Initramfs loaded, size: %zu bytes\n", initramfs_size); + printf("INIT: Initramfs loaded, base: %p, size: %zu bytes\n", + boot_res.initramfs_base, boot_res.initramfs_size); dt_add_property_u64(dt_chosen, "linux,initrd-start", - (uint64_t)INITRAMFS_LOAD_BASE); + (uint64_t)boot_res.initramfs_base); dt_add_property_u64(dt_chosen, "linux,initrd-end", - (uint64_t)INITRAMFS_LOAD_BASE + initramfs_size); + (uint64_t)boot_res.initramfs_base + + boot_res.initramfs_size); } int64_t mem_dump_free(void); @@ -553,6 +582,23 @@ void __noreturn load_and_boot_kernel(bool is_reboot) start_kernel(kernel_entry, fdt, mem_top); } +static int wait_for_async_load(void) +{ + cpu_wait_job(load_boot_resource_job, true); + prlog(PR_PRINTF, "Completed async job. boot_res.success = %i, \ + kernel_base %p, size %lu \n", + boot_res.success, boot_res.kernel_base, + boot_res.kernel_size); + + /* Set new local values for kernel base and size */ + if (boot_res.kernel_loaded) { + kernel_entry = (uint64_t)boot_res.kernel_base; + kernel_size = boot_res.kernel_size; + } + + return OPAL_SUCCESS; +} + static void dt_fixups(void) { struct dt_node *n; @@ -936,6 +982,10 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) phb3_preload_vpd(); phb3_preload_capp_ucode(); + + /* Initialise crc32 tables before trying to decode */ + xz_crc32_init(); + start_preload_kernel(); /* NX init */ @@ -978,6 +1028,10 @@ void __noreturn __nomcount main_cpu_entry(const void *fdt) /* Add the list of interrupts going to OPAL */ add_opal_interrupts(); + /* Wait for async job to setup images*/ + if (load_boot_resource_job) + wait_for_async_load(); + /* Now release parts of memory nodes we haven't used ourselves... */ mem_region_release_unused(); diff --git a/core/platform.c b/core/platform.c index 2a206c8..63b67c3 100644 --- a/core/platform.c +++ b/core/platform.c @@ -261,3 +261,14 @@ int wait_for_resource_loaded(enum resource_id id, uint32_t idx) id, idx, waited); return r; } + +/* Start async job to load and setup the boot resources */ +struct cpu_job* start_async_load(struct boot_resources *r) +{ + if (!platform.load_done) { + printf("PLATFORM: start_async_load not supported on this arch"); + return NULL; + } + + return platform.load_done(r); +} diff --git a/hw/fsp/fsp.c b/hw/fsp/fsp.c index a0c5a78..c564a3e 100644 --- a/hw/fsp/fsp.c +++ b/hw/fsp/fsp.c @@ -23,6 +23,7 @@ * If we are going to support P8 PSI and FSP2, we probably want * to split the PSI support from the FSP support proper first. */ +#include #include #include #include @@ -38,6 +39,8 @@ #include #include #include +#include +#include DEFINE_LOG_ENTRY(OPAL_RC_FSP_POLL_TIMEOUT, OPAL_PLATFORM_ERR_EVT, OPAL_FSP, OPAL_PLATFORM_FIRMWARE, OPAL_ERROR_PANIC, OPAL_NA); @@ -2635,3 +2638,59 @@ void fsp_used_by_console(void) lock(&fsp_lock); unlock(&fsp_lock); } + +struct boot_resources *boot_res; +static struct cpu_job *fsp_load_res_job = NULL; + +static void fsp_setup_boot_resource(void *data __unused) +{ + int r, waited; + size_t len; + void *buf; + + waited = 0; + /* Wait for initramfs to load */ + do { + opal_run_pollers(); + r = fsp_resource_loaded(RESOURCE_ID_INITRAMFS, + RESOURCE_SUBID_NONE); + if (r != OPAL_BUSY) + break; + time_wait_ms_nopoll(5); + waited += 5; + } + while (r == OPAL_BUSY); + + boot_res->initramfs_loaded = true; + prlog(PR_PRINTF, "FSP: fsp_decode_resource loaded INITRAMFS %u ms\n", + waited); + + /* Decode the initramfs*/ + buf = boot_res->initramfs_base; + len = boot_res->initramfs_size; + + r = decode_resource_xz(&buf, &len, NULL); + printf("FSP: deocde result r=%i\n", r); + + if (r) { + boot_res->initramfs_base = buf; + boot_res->initramfs_size = len; + } + + boot_res->success = true; + return; +} + +struct cpu_job* fsp_load_boot_resource(struct boot_resources *r) +{ + boot_res = r; + if (fsp_load_res_job) + cpu_wait_job(fsp_load_res_job, true); + + fsp_load_res_job = cpu_queue_job(NULL, "fsp_setup_boot_resource", + fsp_setup_boot_resource, NULL); + + cpu_process_local_jobs(); + + return fsp_load_res_job; +} diff --git a/include/fsp.h b/include/fsp.h index f75b6ad..74582e6 100644 --- a/include/fsp.h +++ b/include/fsp.h @@ -756,6 +756,9 @@ extern int fsp_resource_loaded(enum resource_id id, uint32_t idx); extern int fsp_preload_lid(uint32_t lid_no, char *buf, size_t *size); extern int fsp_wait_lid_loaded(uint32_t lid_no); +/* Setup boot resources */ +extern struct cpu_job* fsp_load_boot_resource(struct boot_resources *r); + /* FSP console stuff */ extern void fsp_console_preinit(void); extern void fsp_console_init(void); diff --git a/include/platform.h b/include/platform.h index 9133204..e8848ca 100644 --- a/include/platform.h +++ b/include/platform.h @@ -42,6 +42,18 @@ struct bmc_platform { uint32_t ipmi_oem_pnor_access_status; }; +struct boot_resources { + void *kernel_base; + size_t kernel_size; + bool kernel_loaded; + + void *initramfs_base; + size_t initramfs_size; + bool initramfs_loaded; + /* Success of loading boot resources */ + bool success; +}; + /* * Each platform can provide a set of hooks * that can affect the generic code @@ -168,6 +180,16 @@ struct platform { int (*resource_loaded)(enum resource_id id, uint32_t idx); /* + * Returns a pointer to the cpu_job struct. + * load_done is platform specific. On FSP machines we wait for the + * initramfs to load, then decode it. + * On BMC machines we first have to parse and setup the FIT, then + * decode the initramfs. + * This is done asyncronously. + */ + struct cpu_job* (*load_done)(struct boot_resources *r); + + /* * Executed just prior to handing control over to the payload. */ void (*exit)(void); @@ -210,4 +232,6 @@ extern int wait_for_resource_loaded(enum resource_id id, uint32_t idx); extern void set_bmc_platform(const struct bmc_platform *bmc); +extern struct cpu_job* start_async_load(struct boot_resources *r); + #endif /* __PLATFORM_H */