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);