From patchwork Tue Nov 21 23:13:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Malat X-Patchwork-Id: 168032 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:2b07:b0:403:3b70:6f57 with SMTP id io7csp973055vqb; Tue, 21 Nov 2023 15:14:23 -0800 (PST) X-Google-Smtp-Source: AGHT+IFqsK+1TE8myhhzwUp3ZDGx2/d3zoP4WzisdQ9ozktVS4xx0K0W2/IyR47FvabNbO/57aHm X-Received: by 2002:a17:90b:1bcf:b0:27d:2108:af18 with SMTP id oa15-20020a17090b1bcf00b0027d2108af18mr853785pjb.25.1700608463023; Tue, 21 Nov 2023 15:14:23 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1700608463; cv=none; d=google.com; s=arc-20160816; b=cngCL4vQJCC+6hrNWhx4YxO+IwwwDPI7uKf6YreVazz0RzXw+1r8qnnxRfKrx1vRXD iIA4Qoi2AFW8HQsb0kWW2z3Tkkd2Xymu6imcDFjoyckjKHopA10mUoHzPjSZUnaPQA3D AhxRO2oGT9ac0tpSsx4/6Dh4ghhUk5MpOmbSUPG1MlBrvHGMHGGECJDPx7OCJQAzPtA7 b/w9+xXPOWqIZ+vbVUO6rAgDpzc64lcqaYYjudeDbokS4b1fB1PqLVn3d/1kQceJKtXa E7TUFIEbO7UYhTxG5DD6/5lfNgnB2ibE3KAKSALLLBg3nk36uNgZU7gErAhwA2faKma6 i+FA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=GZ+OWvH5/CFA7FeA4X2r+g0PzIL9HC5yDJCChVi7III=; fh=7b2BgFWeMSfoyniPx828ASBftS1Bm6+CDBwFVQh34Rw=; b=DUU8UlDM4UjjxjfOeU28kZaHCCIEBfVEtguKA2RfhiVRt30nY5sbnRuUwGpeVoVDdE RNAGuOMzEKl04SQwFtzoRqvDN4ckVA/W9xIwP+e9rMd8FIs0D4GLqub64UBEy2jFrsMz VQEo954yllVF5cwilHn4a8ZltK+G3sJSMaEGyVe226bBmhgROSKb5ImYzfvoFPiiNUGY /Q2euXEeRibo1xpjU2PAn/rBWBK72HLXQevjnSgd8q987vIxS/PEDB3oWdJ+wC10Q3B/ YS4Wp+EfnvXLp8tJ9bnk+kjwJiz/Qq/f6d+5Zdhij6u+IbIHcVGZnpHnkoDsBZVIkh+t nHqQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@malat-biz.20230601.gappssmtp.com header.s=20230601 header.b=ihahlgjy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from lipwig.vger.email (lipwig.vger.email. [23.128.96.33]) by mx.google.com with ESMTPS id go20-20020a17090b03d400b002801ac582d0si126415pjb.185.2023.11.21.15.14.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Nov 2023 15:14:23 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) client-ip=23.128.96.33; Authentication-Results: mx.google.com; dkim=pass header.i=@malat-biz.20230601.gappssmtp.com header.s=20230601 header.b=ihahlgjy; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.33 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by lipwig.vger.email (Postfix) with ESMTP id B4BFB817C1EA; Tue, 21 Nov 2023 15:14:13 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at lipwig.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234879AbjKUXOO (ORCPT + 99 others); Tue, 21 Nov 2023 18:14:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53960 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229527AbjKUXON (ORCPT ); Tue, 21 Nov 2023 18:14:13 -0500 Received: from mail-ed1-x52b.google.com (mail-ed1-x52b.google.com [IPv6:2a00:1450:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id AE314191 for ; Tue, 21 Nov 2023 15:14:08 -0800 (PST) Received: by mail-ed1-x52b.google.com with SMTP id 4fb4d7f45d1cf-548d4fc9579so536645a12.1 for ; Tue, 21 Nov 2023 15:14:08 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=malat-biz.20230601.gappssmtp.com; s=20230601; t=1700608447; x=1701213247; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GZ+OWvH5/CFA7FeA4X2r+g0PzIL9HC5yDJCChVi7III=; b=ihahlgjyWsx5JIWJR50Hhgkxqqe2Axrd7647apWGiaZ5HpIUik+MIRTkZclULBmpqX OigZ5KMYoMPo9Ld0l+mg7nr9zhYWmJLxU7Oj0ThysFGx8dH0/OHpux9z6j88z38Ab77j 2Fh+LwKTvpqBbIIrYVRqVMkV8h+peqKVqxgrVtQObqwCoCNMuoiSfxO5hMysSt5msrH6 sLReWj+/WRo/dVIRe0sG8ttkl2WuwzwsAV54Nsty/vOKWkg66eysdzcDamVxDbzvSNwH DLHnjvv9+55OJJnWq0Sk87lA1I8lC1GLZ59oGZ+wTufJzqp8FIiOjQEOu+CK5rmTK1DG WRMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700608447; x=1701213247; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GZ+OWvH5/CFA7FeA4X2r+g0PzIL9HC5yDJCChVi7III=; b=kKCqM6AHlt9WT6B4GhbYau+Dr5XTaxYG0M+XVaLzMOlgjf0PiNBkqS4fJod2WJVZ33 1r7D6iDM93O8VlLKpYgVznSxPxjnB2OL3eX6cfZFZqoSTIRW/EH+IYpu8+4xYjqW5cqx vuLmoaP2AVPWYbU473zrezSK/odstkwL9woE3HSUwxmrrfXHReilPIXzZ6rkTPSkwKa9 XRjETrIDYMjYnncXuTdqfktvXBJpEXxHFMZ4fEJsTOXIFD+473pDHcpyRlaiA4cM/X0q qxHxUkbbQ2Sics7cutgbsAIyql49gcps5NMlcj8DVH8yY2b4l73yqy7mfmX1CbkMfKOT tS6g== X-Gm-Message-State: AOJu0YwbwxTAAPnck6sAKj9CtVxh4BDPLvfjhiwatFYJePcY09Asdf1B cUpZUvB3wRF/sTugl9gCkrYX/+qKhm1JMwfQA9DaXQ== X-Received: by 2002:a05:6402:5022:b0:546:d6e1:fbf3 with SMTP id p34-20020a056402502200b00546d6e1fbf3mr4565575eda.1.1700608447246; Tue, 21 Nov 2023 15:14:07 -0800 (PST) Received: from ntb.lan ([193.86.118.65]) by smtp.googlemail.com with ESMTPSA id f7-20020a056402160700b00548b6175881sm2964840edv.77.2023.11.21.15.14.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Nov 2023 15:14:06 -0800 (PST) From: Petr Malat To: linux-kernel@vger.kernel.org Cc: mhiramat@kernel.org, paulmck@kernel.org, rostedt@goodmis.org, oss@malat.biz Subject: [PATCH 1/2] bootconfig: Support appending initrd config to embedded one Date: Wed, 22 Nov 2023 00:13:41 +0100 Message-Id: <20231121231342.193646-2-oss@malat.biz> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231121231342.193646-1-oss@malat.biz> References: <20231121231342.193646-1-oss@malat.biz> MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lipwig.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (lipwig.vger.email [0.0.0.0]); Tue, 21 Nov 2023 15:14:13 -0800 (PST) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1783217219828410508 X-GMAIL-MSGID: 1783217219828410508 When both embedded and initrd boot configs are present, initrd config is preferred. Introduce CONFIG_BOOT_CONFIG_EMBED_APPEND_INITRD option, which allows appending the initrd config to the embedded one. We handle embedded boot config in-place to avoid allocations, which will be handy for early parameters support. Signed-off-by: Petr Malat --- include/linux/bootconfig.h | 10 ++- init/Kconfig | 9 +++ init/main.c | 62 ++++++++++-------- lib/bootconfig-data.S | 3 +- lib/bootconfig.c | 129 +++++++++++++++++++++++++++---------- 5 files changed, 146 insertions(+), 67 deletions(-) diff --git a/include/linux/bootconfig.h b/include/linux/bootconfig.h index ca73940e26df..88bbcffa82d5 100644 --- a/include/linux/bootconfig.h +++ b/include/linux/bootconfig.h @@ -281,7 +281,10 @@ static inline int __init xbc_node_compose_key(struct xbc_node *node, } /* XBC node initializer */ -int __init xbc_init(const char *buf, size_t size, const char **emsg, int *epos); +int __init xbc_init(char *buf, size_t size, const char **emsg, int *epos); + +/* Append XBC data */ +int __init xbc_append(const char *data, size_t size, const char **emsg, int *epos); /* XBC node and size information */ int __init xbc_get_info(int *node_size, size_t *data_size); @@ -291,10 +294,11 @@ void __init xbc_exit(void); /* XBC embedded bootconfig data in kernel */ #ifdef CONFIG_BOOT_CONFIG_EMBED -const char * __init xbc_get_embedded_bootconfig(size_t *size); +char * __init xbc_get_embedded_bootconfig(size_t *size); #else -static inline const char *xbc_get_embedded_bootconfig(size_t *size) +static inline char *xbc_get_embedded_bootconfig(size_t *size) { + *size = 0; return NULL; } #endif diff --git a/init/Kconfig b/init/Kconfig index 6d35728b94b2..9161d2dbad0c 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1339,6 +1339,15 @@ config BOOT_CONFIG_EMBED If unsure, say N. +config BOOT_CONFIG_EMBED_APPEND_INITRD + bool "Append initrd bootconfig to the embedded one" + depends on BOOT_CONFIG_EMBED && BLK_DEV_INITRD + default n + help + By default if both embedded bootconfig and initrd bootconfig are + found, initrd bootconfig is preferred. If this option is set, initrd + bootconfig gets appended to the embedded one. + config BOOT_CONFIG_EMBED_FILE string "Embedded bootconfig file path" depends on BOOT_CONFIG_EMBED diff --git a/init/main.c b/init/main.c index 436d73261810..0cd738f7f0cf 100644 --- a/init/main.c +++ b/init/main.c @@ -267,6 +267,9 @@ static void * __init get_boot_config_from_initrd(size_t *_size) u32 *hdr; int i; + if (_size) + *_size = 0; + if (!initrd_end) return NULL; @@ -309,6 +312,8 @@ static void * __init get_boot_config_from_initrd(size_t *_size) #else static void * __init get_boot_config_from_initrd(size_t *_size) { + if (_size) + *_size = 0; return NULL; } #endif @@ -404,16 +409,16 @@ static int __init warn_bootconfig(char *str) static void __init setup_boot_config(void) { static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; - const char *msg, *data; + const char *msg, *initrd_data; int pos, ret; - size_t size; - char *err; + size_t initrd_size, embeded_size = 0; + char *err, *embeded_data = NULL; /* Cut out the bootconfig data even if we have no bootconfig option */ - data = get_boot_config_from_initrd(&size); + initrd_data = get_boot_config_from_initrd(&initrd_size); /* If there is no bootconfig in initrd, try embedded one. */ - if (!data) - data = xbc_get_embedded_bootconfig(&size); + if (!initrd_data || IS_ENABLED(CONFIG_BOOT_CONFIG_EMBED_APPEND_INITRD)) + embeded_data = xbc_get_embedded_bootconfig(&embeded_size); strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL, @@ -426,7 +431,7 @@ static void __init setup_boot_config(void) if (err) initargs_offs = err - tmp_cmdline; - if (!data) { + if (!initrd_data && !embeded_data) { /* If user intended to use bootconfig, show an error level message */ if (bootconfig_found) pr_err("'bootconfig' found on command line, but no bootconfig found\n"); @@ -435,28 +440,29 @@ static void __init setup_boot_config(void) return; } - if (size >= XBC_DATA_MAX) { - pr_err("bootconfig size %ld greater than max size %d\n", - (long)size, XBC_DATA_MAX); - return; - } - - ret = xbc_init(data, size, &msg, &pos); - if (ret < 0) { - if (pos < 0) - pr_err("Failed to init bootconfig: %s.\n", msg); - else - pr_err("Failed to parse bootconfig: %s at %d.\n", - msg, pos); - } else { - xbc_get_info(&ret, NULL); - pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)size, ret); - /* keys starting with "kernel." are passed via cmdline */ - extra_command_line = xbc_make_cmdline("kernel"); - /* Also, "init." keys are init arguments */ - extra_init_args = xbc_make_cmdline("init"); - } + ret = xbc_init(embeded_data, embeded_size, &msg, &pos); + if (ret < 0) + goto err0; + + /* Call append even if no data are there as embedded bootconfig is in .init */ + ret = xbc_append(initrd_data, initrd_size, &msg, &pos); + if (ret < 0) + goto err0; + + xbc_get_info(&ret, NULL); + pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)(embeded_size + initrd_size), ret); + /* keys starting with "kernel." are passed via cmdline */ + extra_command_line = xbc_make_cmdline("kernel"); + /* Also, "init." keys are init arguments */ + extra_init_args = xbc_make_cmdline("init"); return; + +err0: if (pos < 0) + pr_err("Failed to init bootconfig: %s.\n", msg); + else + pr_err("Failed to parse %s bootconfig: %s at %zu.\n", + pos < embeded_size ? "embedded" : "initrd", + msg, pos < embeded_size ? pos : pos - embeded_size); } static void __init exit_boot_config(void) diff --git a/lib/bootconfig-data.S b/lib/bootconfig-data.S index ef85ba1a82f4..f447e24eb8fa 100644 --- a/lib/bootconfig-data.S +++ b/lib/bootconfig-data.S @@ -2,9 +2,10 @@ /* * Embed default bootconfig in the kernel. */ - .section .init.rodata, "aw" + .section .init.data, "aw" .global embedded_bootconfig_data embedded_bootconfig_data: .incbin "lib/default.bconf" + .byte 0 .global embedded_bootconfig_data_end embedded_bootconfig_data_end: diff --git a/lib/bootconfig.c b/lib/bootconfig.c index c59d26068a64..841163ce5313 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -15,13 +15,13 @@ #ifdef CONFIG_BOOT_CONFIG_EMBED /* embedded_bootconfig_data is defined in bootconfig-data.S */ -extern __visible const char embedded_bootconfig_data[]; -extern __visible const char embedded_bootconfig_data_end[]; +extern __visible char embedded_bootconfig_data[]; +extern __visible char embedded_bootconfig_data_end[]; -const char * __init xbc_get_embedded_bootconfig(size_t *size) +char * __init xbc_get_embedded_bootconfig(size_t *size) { *size = embedded_bootconfig_data_end - embedded_bootconfig_data; - return (*size) ? embedded_bootconfig_data : NULL; + return *size ? embedded_bootconfig_data : NULL; } #endif @@ -48,6 +48,7 @@ const char * __init xbc_get_embedded_bootconfig(size_t *size) static struct xbc_node *xbc_nodes __initdata; static int xbc_node_num __initdata; static char *xbc_data __initdata; +static bool xbc_data_allocated __initdata; static size_t xbc_data_size __initdata; static struct xbc_node *last_parent __initdata; static const char *xbc_err_msg __initdata; @@ -846,13 +847,14 @@ static int __init xbc_verify_tree(void) } /* Need to setup xbc_data and xbc_nodes before call this. */ -static int __init xbc_parse_tree(void) +static int __init xbc_parse_tree(int offset) { char *p, *q; int ret = 0, c; - last_parent = NULL; - p = xbc_data; + if (!offset) + last_parent = NULL; + p = xbc_data + offset; do { q = strpbrk(p, "{}=+;:\n#"); if (!q) { @@ -906,18 +908,42 @@ static int __init xbc_parse_tree(void) */ void __init xbc_exit(void) { - xbc_free_mem(xbc_data, xbc_data_size); + if (xbc_data_allocated) + xbc_free_mem(xbc_data, xbc_data_size); xbc_data = NULL; xbc_data_size = 0; + xbc_data_allocated = 0; xbc_node_num = 0; xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX); xbc_nodes = NULL; brace_index = 0; } +static int xbc_parse_and_verify_tree(int offset, int *epos, const char **emsg) +{ + int ret; + + ret = xbc_parse_tree(offset); + if (!ret) { + ret = xbc_verify_tree(); + if (!ret) + return xbc_node_num; + } + + if (epos) + *epos = xbc_err_pos; + if (emsg) + *emsg = xbc_err_msg; + + xbc_exit(); + return ret; +} + /** * xbc_init() - Parse given XBC file and build XBC internal tree - * @data: The boot config text original data + * @data: Null terminated boot config data, that can be directly + * modified by the parser and will exist till xbc_exit() + * or xbc_append() is called. * @size: The size of @data * @emsg: A pointer of const char * to store the error message * @epos: A pointer of int to store the error position @@ -930,10 +956,8 @@ void __init xbc_exit(void) * @epos will be updated with the error position which is the byte offset * of @buf. If the error is not a parser error, @epos will be -1. */ -int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos) +int __init xbc_init(char *data, size_t size, const char **emsg, int *epos) { - int ret; - if (epos) *epos = -1; @@ -942,44 +966,79 @@ int __init xbc_init(const char *data, size_t size, const char **emsg, int *epos) *emsg = "Bootconfig is already initialized"; return -EBUSY; } - if (size > XBC_DATA_MAX || size == 0) { + if (size > XBC_DATA_MAX || (size == 0 && data != NULL)) { if (emsg) *emsg = size ? "Config data is too big" : "Config data is empty"; return -ERANGE; } - xbc_data = xbc_alloc_mem(size + 1); - if (!xbc_data) { - if (emsg) - *emsg = "Failed to allocate bootconfig data"; - return -ENOMEM; - } - memcpy(xbc_data, data, size); - xbc_data[size] = '\0'; - xbc_data_size = size + 1; - xbc_nodes = xbc_alloc_mem(sizeof(struct xbc_node) * XBC_NODE_MAX); if (!xbc_nodes) { if (emsg) *emsg = "Failed to allocate bootconfig nodes"; - xbc_exit(); return -ENOMEM; } memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX); - ret = xbc_parse_tree(); - if (!ret) - ret = xbc_verify_tree(); + if (!data) + return 0; + xbc_data = data; + xbc_data_size = size; + return xbc_parse_and_verify_tree(0, epos, emsg); +} - if (ret < 0) { - if (epos) - *epos = xbc_err_pos; +/** + * xbc_append() - Append data to already existing XBC tree + * @data: Boot config data, which are copied by the function. + * @size: The size of @data + * @emsg: A pointer of const char * to store the error message + * @epos: A pointer of int to store the error position + */ +int __init xbc_append(const char *data, size_t size, const char **emsg, int *epos) +{ + size_t new_size, parse_start; + char *new_data; + + new_size = xbc_data_size + size; + if (new_size > XBC_DATA_MAX) { if (emsg) - *emsg = xbc_err_msg; - xbc_exit(); - } else - ret = xbc_node_num; + *emsg = "Merged config data is too big"; + return -ERANGE; + } + if (new_size == 0) { + if (data) { + if (emsg) + *emsg = "Appended data is empty"; + return -ERANGE; + } + return 0; + } - return ret; + new_data = xbc_alloc_mem(new_size); + if (!new_data) { + if (emsg) + *emsg = "Failed to allocate bootconfig data"; + return -ENOMEM; + } + + if (xbc_data_size) { + memcpy(new_data, xbc_data, xbc_data_size - 1); + new_data[xbc_data_size - 1] = '\n'; + parse_start = xbc_data_size - 1; + } else { + parse_start = 0; + } + memcpy(new_data + xbc_data_size, data, size); + new_data[new_size - 1] = 0; + if (xbc_data_allocated) + xbc_free_mem(xbc_data, xbc_data_size); + xbc_data_allocated = 1; + xbc_data = new_data; + xbc_data_size = new_size; + + if (!data) + return 0; + + return xbc_parse_and_verify_tree(parse_start, epos, emsg); } From patchwork Tue Nov 21 23:13:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Petr Malat X-Patchwork-Id: 168033 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a05:612c:2b07:b0:403:3b70:6f57 with SMTP id io7csp973205vqb; Tue, 21 Nov 2023 15:14:47 -0800 (PST) X-Google-Smtp-Source: AGHT+IFHBFJVRWKW/hgOQ795D+dPeEFi+AORN8g+waNJR14MQWuWEZlQa129aAZQpEKXsrB8NvM2 X-Received: by 2002:a17:902:eb8d:b0:1cc:49e7:ee1b with SMTP id q13-20020a170902eb8d00b001cc49e7ee1bmr734897plg.58.1700608487452; Tue, 21 Nov 2023 15:14:47 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1700608487; cv=none; d=google.com; s=arc-20160816; b=pBU2BJ4mFQ1rswfM7oUQjPAfNpC6bX2L4mwFTho1fZ62f57gfzdTN5bJHLUHEWWII3 NWBSWY32cEH2wxLLknX4FLNeanxcSAz0sLQwC3RXNp9Cv0yaDj/4LFXisiAIYylQGfyY sSnB+Uv4FmgNgMD9xDH40tE+8B9Fbx4zYVIKrFa1KklM055gzWObP2+e8hprWIBxN+Ot Vqh1osW1gwjrTHGkVd4uLj6LkaUEVGfmaPaeNgBmjt7/SOS4X+dZiBFg6MoAf5lN1BTd hbg0ZvW1pV8fQDk1WOsmDWn/9b97qM0sND9eBaRFIeHYbaOkw5Qd14HNPvQ1rGy2bKKP g3Vg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=D5G4Wz4OBw0AmK7UNuw/1S873XlbXYn1AKtv0k3We8A=; fh=7b2BgFWeMSfoyniPx828ASBftS1Bm6+CDBwFVQh34Rw=; b=AHJnnpstr/iF5l4CQjYcEgLNHvno90sLxmVPacq/8/FPXjQBMbxmFYkBAyfRhWMzr+ tFItuvBJ1puhIqeh23t0lgqX+94t6kDSmTyIEB7t4MCCd0J7KtJAx/dAhnGbo6LZt6m9 USG1rDO5vgITAgXGnNcYUR4a3nRnqTbx38vgX6OC+ftp7TL/8ycy61lY4CZnDaACQ7qV /twzc2U9Dn3MTPKzL4AXrHYmwwqgyPqlPpv4sJdytgMg+omWZ0bwkDX/hJjn8DAKGufz wdHkceXGB5vfxivjHRnSspkkPq3/Fqj4Aw0xs4VHhpH8CFrLl8oGYgqLeqkHyDLuRPK/ HXDQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@malat-biz.20230601.gappssmtp.com header.s=20230601 header.b=nIZF8YKP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.38 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from fry.vger.email (fry.vger.email. [23.128.96.38]) by mx.google.com with ESMTPS id l18-20020a170902eb1200b001bf1d1d99b0si10849150plb.568.2023.11.21.15.14.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Nov 2023 15:14:47 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.38 as permitted sender) client-ip=23.128.96.38; Authentication-Results: mx.google.com; dkim=pass header.i=@malat-biz.20230601.gappssmtp.com header.s=20230601 header.b=nIZF8YKP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.38 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by fry.vger.email (Postfix) with ESMTP id 06A0380764AB; Tue, 21 Nov 2023 15:14:44 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at fry.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234919AbjKUXOU (ORCPT + 99 others); Tue, 21 Nov 2023 18:14:20 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54070 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234892AbjKUXOQ (ORCPT ); Tue, 21 Nov 2023 18:14:16 -0500 Received: from mail-ed1-x52b.google.com (mail-ed1-x52b.google.com [IPv6:2a00:1450:4864:20::52b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 10A1797 for ; Tue, 21 Nov 2023 15:14:12 -0800 (PST) Received: by mail-ed1-x52b.google.com with SMTP id 4fb4d7f45d1cf-548f0b7ab11so2469001a12.1 for ; Tue, 21 Nov 2023 15:14:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=malat-biz.20230601.gappssmtp.com; s=20230601; t=1700608450; x=1701213250; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=D5G4Wz4OBw0AmK7UNuw/1S873XlbXYn1AKtv0k3We8A=; b=nIZF8YKPnyIysTz1y/ITBp5YZROL6AzVEq+zRJRyJgKu/p2PUG3KFBnWw3v+U2M51X AXT9dAnpMBvqimu8vvRhIPfUsxe8SG3DidDI8H4nUMRBWhLs1U6jj9OC7b6suneZhmSC ZzypXKqf0+JQr869pqINuFz175ywM3yInFABdAWWVdCz309U1Zg9ChMWGdBXPuJUMytx 9eD+ju8/X+TY8bG/OiLXS7zd837c2djumvDij9ibCIcNYZNVLEvapxU/SE6olYIfljY2 YIfrgHjxKgqE53nlIyJC305iK5DVgmvIrX2dD5HuV5mMllkGmxkfKJUGzStiM/DHZp8G fqmw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1700608450; x=1701213250; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=D5G4Wz4OBw0AmK7UNuw/1S873XlbXYn1AKtv0k3We8A=; b=vOie3MoLfTSdyGCQr3Og1qu5mfybNf71HVTiNVi2W50DU7c6rMK8awhKqhadjNiv/y qOwnfL5KWX2OtN+Zo/q/I7IFWaUQDwyRIEU/NEATqnz7QKaZQYvO+bKwtBshR07Wq/1i avzUSxT3b9aTSgs4tlKXmN7LZWcVn3Mq1J8Fo9d7SHweuDonBQy0tAu/P9PkZpV9Xq7V k3sEvRbhoYmaWVILv6DGIM7K42aByalHeX4x+21O2el58kUYKNqYXsqz+noOSSWiXM6K dGIWYnd56ew4NIExBSgIVgBMUfvNm8SnfFyOVuCKRK0cJYGSJ3M4o2DmbxVNslmiz5Ho RjOw== X-Gm-Message-State: AOJu0YyWzyBq1pv+0dkqsVlqxU+3SZeKNXS1lWfFY0coqUaBARXntjZD i3INGWYbYA/x5oiVgG/lMWq645tW9fc+qE8AVlA3WQ== X-Received: by 2002:a05:6402:1a2e:b0:53f:9ced:e5b4 with SMTP id be14-20020a0564021a2e00b0053f9cede5b4mr572213edb.13.1700608450571; Tue, 21 Nov 2023 15:14:10 -0800 (PST) Received: from ntb.lan ([193.86.118.65]) by smtp.googlemail.com with ESMTPSA id f7-20020a056402160700b00548b6175881sm2964840edv.77.2023.11.21.15.14.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 21 Nov 2023 15:14:10 -0800 (PST) From: Petr Malat To: linux-kernel@vger.kernel.org Cc: mhiramat@kernel.org, paulmck@kernel.org, rostedt@goodmis.org, oss@malat.biz Subject: [PATCH 2/2] bootconfig: Apply early options from embedded config Date: Wed, 22 Nov 2023 00:13:42 +0100 Message-Id: <20231121231342.193646-3-oss@malat.biz> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20231121231342.193646-1-oss@malat.biz> References: <20231121231342.193646-1-oss@malat.biz> MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS,MAILING_LIST_MULTI,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on fry.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (fry.vger.email [0.0.0.0]); Tue, 21 Nov 2023 15:14:44 -0800 (PST) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1783217245827695952 X-GMAIL-MSGID: 1783217245827695952 Eliminate all allocations in embedded config handling to allow calling it from arch_setup and applying early options. Config stored in initrd can't be used for early options, because initrd is set up after early options are processed. Add this information to the documentation and also to the option description. Signed-off-by: Petr Malat --- Documentation/admin-guide/bootconfig.rst | 3 + init/Kconfig | 4 +- init/main.c | 141 ++++++++++++++++++----- lib/bootconfig.c | 20 +++- 4 files changed, 132 insertions(+), 36 deletions(-) diff --git a/Documentation/admin-guide/bootconfig.rst b/Documentation/admin-guide/bootconfig.rst index 91339efdcb54..fb085f696f9b 100644 --- a/Documentation/admin-guide/bootconfig.rst +++ b/Documentation/admin-guide/bootconfig.rst @@ -161,6 +161,9 @@ Boot Kernel With a Boot Config There are two options to boot the kernel with bootconfig: attaching the bootconfig to the initrd image or embedding it in the kernel itself. +Early options may be specified only in the embedded bootconfig, because +they are processed before the initrd. + Attaching a Boot Config to Initrd --------------------------------- diff --git a/init/Kconfig b/init/Kconfig index 9161d2dbad0c..04de756c935e 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1310,7 +1310,9 @@ config BOOT_CONFIG Extra boot config allows system admin to pass a config file as complemental extension of kernel cmdline when booting. The boot config file must be attached at the end of initramfs - with checksum, size and magic word. + with checksum, size and magic word. Note that early options may + be specified in the embedded bootconfig only. Early options + specified in initrd bootconfig will not be applied. See for details. If unsure, say Y. diff --git a/init/main.c b/init/main.c index 0cd738f7f0cf..9aac59673a3a 100644 --- a/init/main.c +++ b/init/main.c @@ -158,6 +158,9 @@ static size_t initargs_offs; static char *execute_command; static char *ramdisk_execute_command = "/init"; +static int __init do_early_param(char *param, char *val, + const char *unused, void *arg); + /* * Used to generate warnings if static_key manipulation functions are used * before jump_label_init is called. @@ -406,63 +409,134 @@ static int __init warn_bootconfig(char *str) return 0; } -static void __init setup_boot_config(void) +static void __init boot_config_pr_err(const char *msg, int pos, const char *src) +{ + if (pos < 0) + pr_err("Failed to init bootconfig: %s.\n", msg); + else + pr_err("Failed to parse %s bootconfig: %s at %d.\n", + src, msg, pos); +} + +static int __init setup_boot_config_early(void) { static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; - const char *msg, *initrd_data; - int pos, ret; - size_t initrd_size, embeded_size = 0; - char *err, *embeded_data = NULL; + static int prev_rtn __initdata; + struct xbc_node *root, *knode, *vnode; + char *embeded_data, *err; + const char *val, *msg; + size_t embeded_size; + int ret, pos; - /* Cut out the bootconfig data even if we have no bootconfig option */ - initrd_data = get_boot_config_from_initrd(&initrd_size); - /* If there is no bootconfig in initrd, try embedded one. */ - if (!initrd_data || IS_ENABLED(CONFIG_BOOT_CONFIG_EMBED_APPEND_INITRD)) - embeded_data = xbc_get_embedded_bootconfig(&embeded_size); + if (prev_rtn) + return prev_rtn; + embeded_data = xbc_get_embedded_bootconfig(&embeded_size); strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); err = parse_args("bootconfig", tmp_cmdline, NULL, 0, 0, 0, NULL, bootconfig_params); - - if (IS_ERR(err) || !(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE))) - return; - + if (IS_ERR(err) || !(bootconfig_found || IS_ENABLED(CONFIG_BOOT_CONFIG_FORCE))) { + prev_rtn = embeded_data ? -ENOMSG : -ENODATA; + return prev_rtn; + } /* parse_args() stops at the next param of '--' and returns an address */ if (err) initargs_offs = err - tmp_cmdline; - if (!initrd_data && !embeded_data) { - /* If user intended to use bootconfig, show an error level message */ - if (bootconfig_found) - pr_err("'bootconfig' found on command line, but no bootconfig found\n"); - else - pr_info("No bootconfig data provided, so skipping bootconfig"); - return; + if (!embeded_data) { + prev_rtn = -ENOPROTOOPT; + return prev_rtn; } ret = xbc_init(embeded_data, embeded_size, &msg, &pos); - if (ret < 0) - goto err0; + if (ret < 0) { + boot_config_pr_err(msg, pos, "embedded"); + prev_rtn = ret; + return prev_rtn; + } + prev_rtn = 1; + + /* Process early options */ + root = xbc_find_node("kernel"); + if (!root) + goto out; + + xbc_node_for_each_key_value(root, knode, val) { + ret = xbc_node_compose_key_after(root, knode, + xbc_namebuf, XBC_KEYLEN_MAX); + if (ret < 0) + continue; + + vnode = xbc_node_get_child(knode); + if (!vnode) { + do_early_param(xbc_namebuf, NULL, NULL, NULL); + continue; + } + + xbc_array_for_each_value(vnode, val) { + if (strscpy(tmp_cmdline, val, sizeof(tmp_cmdline)) < 1) { + pr_err("Value for '%s' too long\n", xbc_namebuf); + break; + } + do_early_param(xbc_namebuf, tmp_cmdline, NULL, NULL); + } + } + +out: return embeded_data ? 1 : 0; +} + +static void __init setup_boot_config(void) +{ + const char *msg, *initrd_data; + int pos, ret; + size_t initrd_size, s; + + /* Cut out the bootconfig data even if we have no bootconfig option */ + initrd_data = get_boot_config_from_initrd(&initrd_size); + + ret = setup_boot_config_early(); + if (ret == -ENOMSG || (ret == -ENODATA && initrd_data)) { + pr_info("Bootconfig data present, but handling is disabled\n"); + return; + } else if (ret == -ENODATA) { + /* Bootconfig disabled and bootconfig data are not present */ + return; + } else if (ret == -ENOPROTOOPT) { + /* Embedded bootconfig not found */ + if (!initrd_data) { + pr_err("'bootconfig' found on command line, but no bootconfig data found\n"); + return; + } + ret = xbc_init(NULL, 0, &msg, &pos); + if (ret) + goto err0; + } else if (ret < 0) { + /* Other error, should be logged already */ + return; + } else if (initrd_data && !IS_ENABLED(CONFIG_BOOT_CONFIG_EMBED_APPEND_INITRD)) { + /* Embedded bootconfig handled, but we should not append to it */ + xbc_get_info(&ret, &s); + pr_info("Replacing embedded bootconfig of %d nodes and %zu bytes.\n", ret, s); + xbc_exit(); + ret = xbc_init(NULL, 0, &msg, &pos); + if (ret) + goto err0; + } /* Call append even if no data are there as embedded bootconfig is in .init */ ret = xbc_append(initrd_data, initrd_size, &msg, &pos); if (ret < 0) goto err0; - xbc_get_info(&ret, NULL); - pr_info("Load bootconfig: %ld bytes %d nodes\n", (long)(embeded_size + initrd_size), ret); + xbc_get_info(&ret, &s); + pr_info("Load bootconfig: %d nodes %zu bytes.\n", ret, s); /* keys starting with "kernel." are passed via cmdline */ extra_command_line = xbc_make_cmdline("kernel"); /* Also, "init." keys are init arguments */ extra_init_args = xbc_make_cmdline("init"); return; -err0: if (pos < 0) - pr_err("Failed to init bootconfig: %s.\n", msg); - else - pr_err("Failed to parse %s bootconfig: %s at %zu.\n", - pos < embeded_size ? "embedded" : "initrd", - msg, pos < embeded_size ? pos : pos - embeded_size); +err0: boot_config_pr_err(msg, pos, "initrd"); } static void __init exit_boot_config(void) @@ -766,6 +840,11 @@ void __init parse_early_param(void) if (done) return; +#ifdef CONFIG_BOOT_CONFIG_EMBED + /* Process early options from boot config */ + setup_boot_config_early(); +#endif + /* All fall through to do_early_param. */ strscpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); parse_early_options(tmp_cmdline); diff --git a/lib/bootconfig.c b/lib/bootconfig.c index 841163ce5313..4048057e3e23 100644 --- a/lib/bootconfig.c +++ b/lib/bootconfig.c @@ -45,7 +45,11 @@ char * __init xbc_get_embedded_bootconfig(size_t *size) * node (for array). */ +#ifdef CONFIG_BOOT_CONFIG_EMBED +static struct xbc_node xbc_nodes[XBC_NODE_MAX]; +#else static struct xbc_node *xbc_nodes __initdata; +#endif static int xbc_node_num __initdata; static char *xbc_data __initdata; static bool xbc_data_allocated __initdata; @@ -914,8 +918,12 @@ void __init xbc_exit(void) xbc_data_size = 0; xbc_data_allocated = 0; xbc_node_num = 0; +#ifdef CONFIG_BOOT_CONFIG_EMBED + memset(xbc_nodes, 0, sizeof(xbc_nodes)); +#else xbc_free_mem(xbc_nodes, sizeof(struct xbc_node) * XBC_NODE_MAX); xbc_nodes = NULL; +#endif brace_index = 0; } @@ -973,6 +981,7 @@ int __init xbc_init(char *data, size_t size, const char **emsg, int *epos) return -ERANGE; } +#ifndef CONFIG_BOOT_CONFIG_EMBED xbc_nodes = xbc_alloc_mem(sizeof(struct xbc_node) * XBC_NODE_MAX); if (!xbc_nodes) { if (emsg) @@ -980,7 +989,7 @@ int __init xbc_init(char *data, size_t size, const char **emsg, int *epos) return -ENOMEM; } memset(xbc_nodes, 0, sizeof(struct xbc_node) * XBC_NODE_MAX); - +#endif if (!data) return 0; xbc_data = data; @@ -999,6 +1008,7 @@ int __init xbc_append(const char *data, size_t size, const char **emsg, int *epo { size_t new_size, parse_start; char *new_data; + int ret; new_size = xbc_data_size + size; if (new_size > XBC_DATA_MAX) { @@ -1024,8 +1034,8 @@ int __init xbc_append(const char *data, size_t size, const char **emsg, int *epo if (xbc_data_size) { memcpy(new_data, xbc_data, xbc_data_size - 1); - new_data[xbc_data_size - 1] = '\n'; parse_start = xbc_data_size - 1; + new_data[parse_start] = '\n'; } else { parse_start = 0; } @@ -1039,6 +1049,8 @@ int __init xbc_append(const char *data, size_t size, const char **emsg, int *epo if (!data) return 0; - - return xbc_parse_and_verify_tree(parse_start, epos, emsg); + ret = xbc_parse_and_verify_tree(parse_start, epos, emsg); + if (ret && epos) + *epos -= parse_start; + return ret; }