From 90cb0b0ae541303b3efb5ddbdc2ff8adab26cb49 Mon Sep 17 00:00:00 2001 From: Aidan MacDonald Date: Sat, 5 Mar 2022 14:28:57 +0000 Subject: x1000: bootloader: add mainline Linux boot option This adds a *very basic* Linux loader to the Rockbox bootloader, which allows running a mainline Linux kernel using the following file layout on the SD card: - /uImage - /linux_cmdline.txt The command line arguments are listed in linux_cmdline.txt, all lines are concatenated together and whitespace is converted into spaces. Comments aren't supported however. The loader doesn't support the modern devicetree boot protocol, so it can only pass command line arguments. It would be easy to support an appended dtb though. Change-Id: I373f465dbbdafe94738f619748cbb0278fc2c25f --- bootloader/x1000/boot.c | 91 ++++++++++++++++++++++++++++++++++++++ bootloader/x1000/recovery.c | 1 + bootloader/x1000/x1000bootloader.h | 1 + 3 files changed, 93 insertions(+) (limited to 'bootloader') diff --git a/bootloader/x1000/boot.c b/bootloader/x1000/boot.c index ca69e2e057..153c2277aa 100644 --- a/bootloader/x1000/boot.c +++ b/bootloader/x1000/boot.c @@ -24,8 +24,11 @@ #include "system.h" #include "kernel.h" #include "power.h" +#include "file.h" #include "linuxboot.h" #include "boot-x1000.h" +#include +#include void boot_rockbox(void) { @@ -52,6 +55,94 @@ void reboot(void) while(1); } +/* + * boot_linux() is intended for mainline kernels, and as such it + * should not need any major target-specific modifications. + */ + +static int read_linux_args(const char* filename) +{ + if(check_disk(false) != DISK_PRESENT) + return -1; + + int ret; + + size_t max_size; + int handle = core_alloc_maximum("args", &max_size, &buflib_ops_locked); + if(handle <= 0) { + splash(5*HZ, "Out of memory"); + return -2; + } + + int fd = open(filename, O_RDONLY); + if(fd < 0) { + splash2(5*HZ, "Can't open args file", filename); + ret = -3; + goto err_free; + } + + /* this isn't 100% correct but will be good enough */ + off_t fsize = filesize(fd); + if(fsize < 0 || fsize+1 > (off_t)max_size) { + splash(5*HZ, "Arguments too long"); + ret = -4; + goto err_close; + } + + char* buf = core_get_data(handle); + core_shrink(handle, buf, fsize+1); + + ssize_t rdres = read(fd, buf, fsize); + close(fd); + + if(rdres != (ssize_t)fsize) { + splash(5*HZ, "Can't read args file"); + ret = -5; + goto err_free; + } + + /* append a null terminator */ + char* end = buf + fsize; + *end = 0; + + /* change all newlines, etc, to spaces */ + for(; buf != end; ++buf) + if(isspace(*buf)) + *buf = ' '; + + return handle; + + err_close: + close(fd); + err_free: + core_free(handle); + return ret; +} + +/* + * Provisional linux loading function: kernel is at "/uImage", + * contents of "/linux_cmdline.txt" are used as kernel arguments. + */ +void boot_linux(void) +{ + struct uimage_header uh; + size_t img_length; + int handle = load_uimage_file("/uImage", &uh, &img_length); + if(handle < 0) + return; + + int args_handle = read_linux_args("/linux_cmdline.txt"); + if(args_handle < 0) { + core_free(handle); + return; + } + + x1000_boot_linux(core_get_data(handle), img_length, + (void*)uimage_get_load(&uh), + (void*)uimage_get_ep(&uh), + core_get_data(args_handle)); +} + /* * WARNING: Original firmware can be finicky. * Be careful when modifying this code. diff --git a/bootloader/x1000/recovery.c b/bootloader/x1000/recovery.c index ffd6151858..de6b3961cd 100644 --- a/bootloader/x1000/recovery.c +++ b/bootloader/x1000/recovery.c @@ -47,6 +47,7 @@ static const struct menuitem recovery_items[] = { #ifdef OF_RECOVERY_NAME {MENUITEM_ACTION, OF_RECOVERY_NAME, &boot_of_recovery}, #endif + {MENUITEM_ACTION, "Linux", &boot_linux}, {MENUITEM_HEADING, "System", NULL}, {MENUITEM_ACTION, "USB mode", &usb_mode}, {MENUITEM_ACTION, "Shutdown", &shutdown}, diff --git a/bootloader/x1000/x1000bootloader.h b/bootloader/x1000/x1000bootloader.h index 88d4e3585b..587a820eaf 100644 --- a/bootloader/x1000/x1000bootloader.h +++ b/bootloader/x1000/x1000bootloader.h @@ -141,6 +141,7 @@ void bootloader_restore(void); void boot_rockbox(void); void boot_of_player(void); void boot_of_recovery(void); +void boot_linux(void); void shutdown(void); void reboot(void); -- cgit v1.2.3