From: Alexander Shiyan <eagle.alexander923@gmail.com>
To: barebox@lists.infradead.org
Cc: Alexander Shiyan <eagle.alexander923@gmail.com>
Subject: [PATCH v2 1/2] Add support for extlinux.conf
Date: Tue, 28 Apr 2026 16:28:10 +0300 [thread overview]
Message-ID: <20260428132811.3691086-1-eagle.alexander923@gmail.com> (raw)
This adds support for the extlinux.conf configuration format, commonly
used by Syslinux and many Linux distributions. The configuration file
is typically located at /boot/extlinux/extlinux.conf or
/extlinux/extlinux.conf and defines boot entries with kernel, initrd,
device tree, and command line options.
The implementation integrates with the existing boot entry framework:
- The extlinux scanner discovers entries on mounted filesystems.
- The default LABEL is turned into a boot entry.
- The "root=" parameter is stripped from the APPEND line only when
global.bootm.appendroot is set. This allows barebox to inject the
correct root device based on the actual boot device (e.g., when the
same rootfs image is used across different storage media).
- Bootm is used to load and start the kernel.
---
barebox@Diasom DS-RK3568-SOM-EVB:/ global.bootm.appendroot=true
barebox@Diasom DS-RK3568-SOM-EVB:/ global.boot.default=mmc1.2
barebox@Diasom DS-RK3568-SOM-EVB:/ boot
ext4 ext40: EXT2 rev 1, inode_size 256, descriptor size 64
Booting entry 'extlinux: linux'
extlinux: Booting extlinux label 'linux'
Adding "root=/dev/mmcblk1p3" to Kernel commandline
Loading ARM aarch64 Linux/EFI image '/mnt/mmc1.2/boot/extlinux/../vmlinuz'
commandline: root=/dev/mmcblk1p3 console=ttyS2,1500000n8 ro systemd.unit=setup.target quiet splash systemd.machine_id=181af2816b4c6b0aef77068e0ccc69ad
Loaded kernel to 0x0a400000, devicetree at 0x000000000fb49000
Signed-off-by: Alexander Shiyan <eagle.alexander923@gmail.com>
---
common/Kconfig | 19 +++
common/Makefile | 1 +
common/extlinux.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 306 insertions(+)
create mode 100644 common/extlinux.c
diff --git a/common/Kconfig b/common/Kconfig
index fd422714d5..0e93686e4f 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -734,6 +734,25 @@ config BLSPEC
on a device and it allows the Operating System to install / update
kernels.
+config EXTLINUX
+ bool
+ prompt "Support extlinux.conf"
+ depends on FLEXIBLE_BOOTARGS
+ depends on !SHELL_NONE
+ select BOOT
+ select BOOTM
+ select MMCBLKDEV_ROOTARG if MCI
+ help
+ Enable this to let barebox parse extlinux.conf configuration files,
+ commonly used by the Syslinux bootloader and many Linux distributions
+ (e.g., on SD cards or USB drives).
+ extlinux.conf is typically located at /boot/extlinux/extlinux.conf or
+ /extlinux/extlinux.conf. It defines boot entries with kernel, initrd,
+ device tree, and command line options.
+ This option allows barebox to discover and boot operating systems
+ that follow the extlinux configuration format, providing a simple
+ and portable way to manage multiple boot options.
+
config FLEXIBLE_BOOTARGS
bool
prompt "flexible Linux bootargs generation"
diff --git a/common/Makefile b/common/Makefile
index 27c5dea168..cd929b2194 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -9,6 +9,7 @@ obj-y += clock.o
pbl-$(CONFIG_PBL_CLOCKSOURCE) += clock.o
obj-y += console_common.o
obj-$(CONFIG_OFDEVICE) += deep-probe.o
+obj-$(CONFIG_EXTLINUX) += extlinux.o
obj-y += startup.o
obj-y += misc.o
obj-pbl-y += memsize.o
diff --git a/common/extlinux.c b/common/extlinux.c
new file mode 100644
index 0000000000..0e838e9889
--- /dev/null
+++ b/common/extlinux.c
@@ -0,0 +1,286 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* SPDX-FileCopyrightText: Alexander Shiyan <shc_work@mail.ru> */
+
+#define pr_fmt(fmt) "extlinux: " fmt
+
+#include <boot.h>
+#include <bootm.h>
+#include <bootscan.h>
+#include <common.h>
+#include <environment.h>
+#include <fs.h>
+#include <globalvar.h>
+#include <libfile.h>
+#include <libgen.h>
+#include <malloc.h>
+#include <string.h>
+
+struct extlinux_entry {
+ struct bootentry entry;
+ char *rootpath;
+ char *label;
+ char *kernel;
+ char *initrd;
+ char *fdtdir;
+ char *fdt;
+ char *append;
+};
+
+static char *remove_param(const char *params, const char *param)
+{
+ char *result, *dst;
+ const char *src;
+
+ result = xmalloc(strlen(params) + 1);
+
+ src = params;
+ dst = result;
+
+ while (*src) {
+ if (!strncasecmp(src, param, strlen(param))) {
+ while (*src && *src != ' ')
+ src++;
+
+ src = skip_spaces(src);
+
+ continue;
+ }
+
+ *dst++ = *src++;
+ }
+
+ *dst = '\0';
+
+ return result;
+}
+
+static int extlinux_boot(struct bootentry *be, int verbose, int dryrun)
+{
+ struct extlinux_entry *e =
+ container_of(be, struct extlinux_entry, entry);
+ char *kernel_abs, *initrd_abs = NULL, *fdt_abs = NULL;
+ struct bootm_data data = {};
+ int ret;
+
+ bootm_data_init_defaults(&data);
+
+ data.dryrun = max_t(int, dryrun, data.dryrun);
+ data.verbose = max(verbose, data.verbose);
+
+ kernel_abs = basprintf("%s/%s", e->rootpath, e->kernel);
+ data.os_file = kernel_abs;
+
+ if (e->initrd) {
+ initrd_abs = basprintf("%s/%s", e->rootpath, e->initrd);
+ data.initrd_file = initrd_abs;
+ }
+
+ if (e->fdt) {
+ char *fdtdir = e->fdtdir ? : e->rootpath;
+
+ fdt_abs = basprintf("%s/%s", fdtdir, e->fdt);
+ data.oftree_file = fdt_abs;
+ }
+
+ if (e->append) {
+ char *append;
+
+ /*
+ * The same rootfs image may be launched from eMMC or SD card.
+ * Remove any hardcoded root= parameter from "append" to avoid
+ * conflicts, then let barebox automatically add the correct
+ * root= (via global.bootm.appendroot) based on the boot device.
+ */
+ if (data.appendroot)
+ append = remove_param(e->append, "ROOT=");
+ else
+ append = xstrdup(e->append);
+
+ globalvar_add_simple("linux.bootargs.dyn.extlinux", append);
+
+ free(append);
+ }
+
+ pr_info("Booting extlinux label '%s'\n", e->label);
+
+ ret = bootm_boot(&data);
+ if (ret)
+ pr_err("bootm failed: %s\n", strerror(-ret));
+
+ free(kernel_abs);
+ free(initrd_abs);
+ free(fdt_abs);
+
+ return ret;
+}
+
+static void extlinux_entry_free(struct bootentry *be)
+{
+ struct extlinux_entry *e =
+ container_of(be, struct extlinux_entry, entry);
+
+ free(e->rootpath);
+ free(e->label);
+ free(e->kernel);
+ free(e->initrd);
+ free(e->fdtdir);
+ free(e->fdt);
+ free(e->append);
+ free(e);
+}
+
+static struct extlinux_entry *parse_extlinux_conf(const char *abspath,
+ const char *rootpath)
+{
+ char *buf, *bufptr, *line, *default_label = NULL;
+ struct extlinux_entry *entry = NULL;
+
+ bufptr = read_file(abspath, NULL);
+ if (!bufptr)
+ return ERR_PTR(-errno);
+
+ buf = bufptr;
+ while ((line = strsep(&buf, "\n\r")) != NULL) {
+ char *key, *val;
+
+ line = skip_spaces(line);
+
+ if (*line == '#' || *line == '\0')
+ continue;
+
+ key = strsep(&line, " \t");
+ val = isempty(line) ? NULL : skip_spaces(line);
+ if (!key || !val)
+ continue;
+
+ if (!default_label) {
+ if (!strcasecmp(key, "DEFAULT"))
+ default_label = xstrdup(val);
+
+ continue;
+ }
+
+ if (!strcasecmp(key, "LABEL")) {
+ if (!strcmp(val, default_label)) {
+ entry = xzalloc(sizeof(*entry));
+ entry->label = xstrdup(val);
+ entry->rootpath = dirname(xstrdup(abspath));
+ } else if (entry) {
+ break;
+ }
+ continue;
+ }
+
+ if (entry) {
+ if (!strcasecmp(key, "KERNEL"))
+ entry->kernel = xstrdup(val);
+ else if (!strcasecmp(key, "INITRD"))
+ entry->initrd = xstrdup(val);
+ else if (!strcasecmp(key, "FDTDIR"))
+ entry->fdtdir = xstrdup(val);
+ else if (!strcasecmp(key, "FDT"))
+ entry->fdt = xstrdup(val);
+ else if (!strcasecmp(key, "APPEND"))
+ entry->append = xstrdup(val);
+ else
+ pr_warn("Unhandled key: %s\n", key);
+ }
+ }
+
+ free(default_label);
+ free(bufptr);
+
+ if (!entry || !entry->kernel) {
+ if (entry)
+ extlinux_entry_free(&entry->entry);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return entry;
+}
+
+static int _extlinux_scan_file(struct bootscanner *scanner,
+ struct bootentries *bootentries,
+ const char *configname,
+ const char *rootpath)
+{
+ struct extlinux_entry *e;
+
+ if (!strends(configname, "extlinux.conf"))
+ return 0;
+
+ e = parse_extlinux_conf(configname, rootpath);
+ if (IS_ERR(e))
+ return PTR_ERR(e);
+
+ e->entry.boot = extlinux_boot;
+ e->entry.release = extlinux_entry_free;
+ e->entry.path = xstrdup_const(configname);
+ e->entry.title = basprintf("extlinux: %s", e->label);
+ e->entry.description = basprintf("extlinux entry \'%s\" on %s",
+ e->label, rootpath);
+ e->entry.me.type = MENU_ENTRY_NORMAL;
+
+ bootentries_add_entry(bootentries, &e->entry);
+
+ return 1;
+}
+
+static int extlinux_scan_file(struct bootscanner *scanner,
+ struct bootentries *bootentries,
+ const char *configname)
+{
+ const char *rootpath = get_mounted_path(configname);
+ if (IS_ERR(rootpath))
+ return PTR_ERR(rootpath);
+
+ return _extlinux_scan_file(scanner, bootentries, configname, rootpath);
+}
+
+static int extlinux_scan_directory(struct bootscanner *scanner,
+ struct bootentries *bootentries,
+ const char *rootpath)
+{
+ char *path;
+ struct stat s;
+ int ret;
+
+ path = basprintf("%s/boot/extlinux/extlinux.conf", rootpath);
+ ret = stat(path, &s);
+ if (!ret && S_ISREG(s.st_mode))
+ ret = _extlinux_scan_file(scanner, bootentries, path, rootpath);
+ free(path);
+ if (ret > 0)
+ return ret;
+
+ path = basprintf("%s/extlinux/extlinux.conf", rootpath);
+ ret = stat(path, &s);
+ if (!ret && S_ISREG(s.st_mode))
+ ret = _extlinux_scan_file(scanner, bootentries, path, rootpath);
+ free(path);
+
+ return ret;
+}
+
+static struct bootscanner extlinux_scanner = {
+ .name = "extlinux",
+ .scan_file = extlinux_scan_file,
+ .scan_directory = extlinux_scan_directory,
+};
+
+static int extlinux_generate(struct bootentries *bootentries, const char *name)
+{
+ return bootentry_scan_generate(&extlinux_scanner, bootentries, name);
+}
+
+static struct bootentry_provider extlinux_provider = {
+ .name = "extlinux",
+ .generate = extlinux_generate,
+ .priority = -25,
+};
+
+static int extlinux_init(void)
+{
+ return bootentry_register_provider(&extlinux_provider);
+}
+device_initcall(extlinux_init);
--
2.52.0
next reply other threads:[~2026-04-28 13:28 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 13:28 Alexander Shiyan [this message]
2026-04-28 13:28 ` [PATCH v2 2/2] Documentation: add extlinux.conf support description Alexander Shiyan
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260428132811.3691086-1-eagle.alexander923@gmail.com \
--to=eagle.alexander923@gmail.com \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox