Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 31 additions & 12 deletions lk2nd/boot/boot.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <list.h>
#include <stdlib.h>
#include <target.h>
#include <err.h>

#include <lk2nd/boot.h>
#include <lk2nd/hw/bdev.h>
Expand All @@ -20,7 +21,7 @@
/**
* lk2nd_scan_devices() - Scan filesystems and try to boot
*/
static void lk2nd_scan_devices(void)
int lk2nd_scan_devices(char **root_out, struct label **labels, int *default_label_idx, int* labels_count)
{
struct bdev_struct *bdevs = bio_get_bdevs();
char mountpoint[16];
Expand All @@ -34,7 +35,6 @@ static void lk2nd_scan_devices(void)
/* Skip top level block devices. */
if (!bdev->is_leaf)
continue;

/*
* Skip partitions that are too small to have a boot fs on.
*
Expand All @@ -48,7 +48,7 @@ static void lk2nd_scan_devices(void)

snprintf(mountpoint, sizeof(mountpoint), "/%s", bdev->name);
ret = fs_mount(mountpoint, "ext2", bdev->name);
if (ret < 0)
if (ret < 0 && ret != ERR_ALREADY_MOUNTED)
continue;

if (DEBUGLEVEL >= SPEW) {
Expand All @@ -57,10 +57,36 @@ static void lk2nd_scan_devices(void)
lk2nd_print_file_tree(mountpoint, " ");
}

lk2nd_try_extlinux(mountpoint);
ret = lk2nd_get_extlinux_labels(mountpoint, labels, default_label_idx, labels_count);
if (ret < 0)
continue;
*root_out = strdup(mountpoint);
break;
}
if (*root_out) {
return 0;
}

dprintf(INFO, "boot: Bootable file system not found. Reverting to android boot.\n");
return -1;
}

static void lk2nd_scan_and_boot(void) {
char *root;
struct label *labels;
int default_label_idx;
int labels_count;
int ret;

lk2nd_bdev_init();

ret = lk2nd_scan_devices(&root, &labels, &default_label_idx, &labels_count);
if (ret < 0) {
return;
}
ret = lk2nd_expand_conf_and_boot_label(
&labels[default_label_idx], root
);
}

/**
Expand All @@ -72,12 +98,5 @@ static void lk2nd_scan_devices(void)
*/
void lk2nd_boot(void)
{
static bool init_done = false;

if (!init_done) {
lk2nd_bdev_init();
init_done = true;
}

lk2nd_scan_devices();
lk2nd_scan_and_boot();
}
15 changes: 15 additions & 0 deletions lk2nd/boot/boot.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,25 @@

#include <lk2nd/boot.h>

struct label {
const char *name;
const char *kernel;
const char *initramfs;
const char *dtb;
const char *dtbdir;
const char **dtboverlays;
const char *cmdline;
};

/* util.c */
void lk2nd_print_file_tree(char *root, char *prefix);

/* extlinux.c */
void lk2nd_try_extlinux(const char *mountpoint);
int lk2nd_get_extlinux_labels(const char *root, struct label **labels, int *default_label_idx, int* labels_count);
int lk2nd_expand_conf_and_boot_label(struct label *label, const char *root);

/* boot.c */
int lk2nd_scan_devices(char **root_out, struct label **labels, int *default_label_idx, int* labels_count);

#endif /* LK2ND_BOOT_BOOT_H */
119 changes: 83 additions & 36 deletions lk2nd/boot/extlinux.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,6 @@

#include "boot.h"

struct label {
const char *name;
const char *kernel;
const char *initramfs;
const char *dtb;
const char *dtbdir;
const char **dtboverlays;
const char *cmdline;
};

enum token {
CMD_LABEL,
CMD_DEFAULT,
Expand Down Expand Up @@ -193,6 +183,21 @@ static int count_lines(char *data, size_t size)
return acc;
}

static void copy_label_data(struct label *label) {
if (label->name)
label->name = strdup(label->name);
if (label->kernel)
label->kernel = strdup(label->kernel);
if (label->initramfs)
label->initramfs = strdup(label->initramfs);
if (label->dtb)
label->dtb = strdup(label->dtb);
if (label->dtbdir)
label->dtbdir = strdup(label->dtbdir);
if (label->cmdline)
label->cmdline = strdup(label->cmdline);
}

/**
* parse_conf() - Extract default label from extlinux.conf
* @data: File contents
Expand All @@ -208,7 +213,7 @@ static int count_lines(char *data, size_t size)
*
* Returns: 0 on success or negative error on parse failure.
*/
static int parse_conf(char *data, size_t size, struct label *label)
static int parse_conf(char *data, size_t size, struct label **labels_out, int* default_label_idx, int* labels_count_out)
{
char *command = NULL, *value = NULL;
char *overlay, *saveptr;
Expand All @@ -219,7 +224,6 @@ static int parse_conf(char *data, size_t size, struct label *label)
} *commands;
int commands_count;
struct label *labels;
struct label *default_label = NULL;
const char *default_name = "";
int labels_count = 0;
int label_idx;
Expand Down Expand Up @@ -302,18 +306,22 @@ static int parse_conf(char *data, size_t size, struct label *label)
}
}

default_label = &labels[0];
*default_label_idx = 0;

for(i = 0; i < labels_count; i++) {
copy_label_data(&labels[i]);
}

for (i = 0; i < labels_count; ++i) {
if (!strcmp(default_name, labels[i].name)) {
default_label = &labels[i];
*default_label_idx = i;
break;
}
}

memcpy(label, default_label, sizeof(*label));
*labels_out = labels;
*labels_count_out = labels_count;

free(labels);
free(commands);

return 0;
Expand Down Expand Up @@ -635,17 +643,11 @@ static void lk2nd_boot_label(struct label *label)
0);
}

/**
* lk2nd_try_extlinux() - Try to boot with extlinux
*
* Check if /extlinux/extlinux.conf exists and try to
* boot it if so.
*/
void lk2nd_try_extlinux(const char *root)

int lk2nd_get_extlinux_labels(const char *root, struct label **labels, int *default_label_idx, int* labels_count)
{
struct filehandle *fileh;
struct file_stat stat;
struct label label = {0};
char path[64];
char *data;
int ret;
Expand All @@ -654,35 +656,80 @@ void lk2nd_try_extlinux(const char *root)
ret = fs_open_file(path, &fileh);
if (ret < 0) {
dprintf(SPEW, "No extlinux config in %s: %d\n", root, ret);
return;
return -1;
}

fs_stat_file(fileh, &stat);
data = malloc(stat.size + 1);
fs_read_file(fileh, data, 0, stat.size);
fs_close_file(fileh);

ret = parse_conf(data, stat.size, &label);
ret = parse_conf(data, stat.size, labels, default_label_idx, labels_count);
if (ret < 0)
goto error;

if (!expand_conf(&label, root))
goto error;
dprintf(INFO, "count: %d\n", *labels_count);

free(data);

dprintf(SPEW, "Parsed %s\n", path);
dprintf(SPEW, "kernel = %s\n", label.kernel);
dprintf(SPEW, "dtb = %s\n", label.dtb);
dprintf(SPEW, "dtbdir = %s\n", label.dtbdir);
dprintf(SPEW, "initramfs = %s\n", label.initramfs);
dprintf(SPEW, "cmdline = %s\n", label.cmdline);
return 0;

lk2nd_boot_label(&label);
error:
dprintf(INFO, "Failed to parse %s\n", path);
free(data);
return -1;
}

int lk2nd_expand_conf_and_boot_label(struct label *label, const char *root)
{
if (!expand_conf(label, root))
return -1;
dprintf(INFO, "kernel = %s\n", label->kernel);
dprintf(INFO, "dtb = %s\n", label->dtb);
dprintf(INFO, "dtbdir = %s\n", label->dtbdir);
dprintf(INFO, "initramfs = %s\n", label->initramfs);
dprintf(INFO, "cmdline = %s\n", label->cmdline);
lk2nd_boot_label(label);
return -1;
}

/**
* lk2nd_try_extlinux() - Try to boot with extlinux
*
* Check if /extlinux/extlinux.conf exists and try to
* boot it if so.
*/
void lk2nd_try_extlinux(const char *root)
{
struct label *labels;
struct label *label;
char path[64];
int ret;
int default_label_idx;
int labels_count;

ret = lk2nd_get_extlinux_labels(root, &labels, &default_label_idx, &labels_count);
if (ret < 0) {
return;
}

label = &labels[default_label_idx];

if (!expand_conf(label, root))
goto error;

dprintf(INFO, "Parsed %s\n", path);
dprintf(INFO, "kernel = %s\n", label->kernel);
dprintf(INFO, "dtb = %s\n", label->dtb);
dprintf(INFO, "dtbdir = %s\n", label->dtbdir);
dprintf(INFO, "initramfs = %s\n", label->initramfs);
dprintf(INFO, "cmdline = %s\n", label->cmdline);

lk2nd_boot_label(label);

free(labels);
return;

error:
dprintf(INFO, "Failed to parse extlinux.conf\n");
free(data);
}
Loading