main: Add U-Boot bootlader backend support

This patch adds support to generate files that
can be used by Universal Bootloader (U-Boot).

U-Boot allows to modify boards default boot commands by
reading and executing a bootscript file or importing a
plain text file that contains environment variables that
could parameterize the boot command or a bootscript.

OSTree generates a uEnv.txt file that contains booting
information that is taken from Boot Loader Specification
snippets files as defined in the new OSTree deployment model:

https://wiki.gnome.org/OSTree/DeploymentModel2

On deploy or upgrade an uEnv.txt env var file is created
in the path /boot/loader.${bootversion}/uEnv.txt. Also, a
/boot/uEnv.txt symbolic link to loader/uEnv.txt is created
so U-Boot can always import the file from a fixed path.

Since U-Boot does not support a menu to list a set of
Operative Systems, the most recent bootloader configuration
from the list is used.

To boot an OSTree using the generated uEnv.txt file, a
board has to parameterize its default boot command using the
following variables defined by OSTree:

${kernel_image}:  path to the Linux kernel image
${ramdisk_image}: path to the initial ramdisk image
${bootargs}:      parameters passed to the kernel command line

Alternatively, for boards that don't support this scheme,
a bootscript that overrides the default boot command can be used.

An example of such a bootscript could be:

setenv scriptaddr 40008000
setenv kernel_addr 0x40007000
setenv ramdisk_addr 0x42000000
ext2load mmc 0:1 ${scriptaddr} uEnv.txt
env import -t ${scriptaddr} ${filesize}
ext2load mmc 0:1 ${kernel_addr} ${kernel_image}
ext2load mmc 0:1 ${ramdisk_addr} ${ramdisk_image}
bootm ${kernel_addr} ${ramdisk_addr}

Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>

https://bugzilla.gnome.org/show_bug.cgi?id=706370
This commit is contained in:
Javier Martinez Canillas 2013-08-15 12:33:25 +02:00 committed by Colin Walters
parent cf14b398da
commit 750a60d3aa
4 changed files with 223 additions and 0 deletions

View File

@ -67,6 +67,8 @@ ostree_SOURCES += \
src/ostree/ot-bootloader.c \
src/ostree/ot-bootloader-syslinux.h \
src/ostree/ot-bootloader-syslinux.c \
src/ostree/ot-bootloader-uboot.h \
src/ostree/ot-bootloader-uboot.c \
src/ostree/ot-config-parser.h \
src/ostree/ot-config-parser.c \
src/ostree/ot-deployment.h \

View File

@ -26,6 +26,7 @@
#include "ot-deployment.h"
#include "ot-config-parser.h"
#include "ot-bootloader-syslinux.h"
#include "ot-bootloader-uboot.h"
#include "otutil.h"
#include "ostree.h"
#include "libgsystem.h"
@ -794,11 +795,16 @@ OtBootloader *
ot_admin_query_bootloader (GFile *sysroot)
{
OtBootloaderSyslinux *syslinux;
OtBootloaderUboot *uboot;
syslinux = ot_bootloader_syslinux_new (sysroot);
if (ot_bootloader_query ((OtBootloader*)syslinux))
return (OtBootloader*) (syslinux);
uboot = ot_bootloader_uboot_new (sysroot);
if (ot_bootloader_query ((OtBootloader*)uboot))
return (OtBootloader*) (uboot);
return NULL;
}

View File

@ -0,0 +1,174 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2013 Collabora Ltd
*
* Based on ot-bootloader-syslinux.c by Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
*/
#include "config.h"
#include "ot-bootloader-uboot.h"
#include "otutil.h"
#include "ot-admin-functions.h"
#include "libgsystem.h"
#include <string.h>
struct _OtBootloaderUboot
{
GObject parent_instance;
GFile *sysroot;
GFile *config_path;
};
typedef GObjectClass OtBootloaderUbootClass;
static void ot_bootloader_uboot_bootloader_iface_init (OtBootloaderInterface *iface);
G_DEFINE_TYPE_WITH_CODE (OtBootloaderUboot, ot_bootloader_uboot, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (OT_TYPE_BOOTLOADER, ot_bootloader_uboot_bootloader_iface_init));
static gboolean
ot_bootloader_uboot_query (OtBootloader *bootloader)
{
OtBootloaderUboot *self = OT_BOOTLOADER_UBOOT (bootloader);
return g_file_query_file_type (self->config_path, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL) == G_FILE_TYPE_SYMBOLIC_LINK;
}
static gboolean
create_config_from_boot_loader_entries (OtBootloaderUboot *self,
int bootversion,
GPtrArray *new_lines,
GCancellable *cancellable,
GError **error)
{
gs_unref_ptrarray GPtrArray *boot_loader_configs = NULL;
OtConfigParser *config;
const char *val;
if (!ot_admin_read_boot_loader_configs (self->sysroot, bootversion, &boot_loader_configs,
cancellable, error))
return FALSE;
/* U-Boot doesn't support a menu so just pick the first one since the list is ordered */
config = boot_loader_configs->pdata[0];
val = ot_config_parser_get (config, "linux");
if (!val)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"No \"linux\" key in bootloader config");
return FALSE;
}
g_ptr_array_add (new_lines, g_strdup_printf ("kernel_image=%s", val));
val = ot_config_parser_get (config, "initrd");
if (val)
g_ptr_array_add (new_lines, g_strdup_printf ("ramdisk_image=%s", val));
val = ot_config_parser_get (config, "options");
if (val)
g_ptr_array_add (new_lines, g_strdup_printf ("bootargs=%s", val));
return TRUE;
}
static gboolean
ot_bootloader_uboot_write_config (OtBootloader *bootloader,
int bootversion,
GCancellable *cancellable,
GError **error)
{
OtBootloaderUboot *self = OT_BOOTLOADER_UBOOT (bootloader);
gs_unref_object GFile *new_config_path = NULL;
gs_free char *config_contents = NULL;
gs_free char *new_config_contents = NULL;
gs_unref_ptrarray GPtrArray *new_lines = NULL;
gs_unref_ptrarray GPtrArray *tmp_args = NULL;
/* This should follow the symbolic link to the current bootversion. */
config_contents = gs_file_load_contents_utf8 (self->config_path, cancellable, error);
if (!config_contents)
return FALSE;
new_config_path = ot_gfile_resolve_path_printf (self->sysroot, "boot/loader.%d/uEnv.txt",
bootversion);
new_lines = g_ptr_array_new_with_free_func (g_free);
if (!create_config_from_boot_loader_entries (self, bootversion, new_lines,
cancellable, error))
return FALSE;
new_config_contents = ot_admin_join_lines (new_lines);
if (strcmp (new_config_contents, config_contents) != 0)
{
if (!g_file_replace_contents (new_config_path, new_config_contents,
strlen (new_config_contents),
NULL, FALSE, G_FILE_CREATE_NONE,
NULL, cancellable, error))
return FALSE;
g_print ("Saved new version of %s\n", gs_file_get_path_cached (self->config_path));
}
return TRUE;
}
static void
ot_bootloader_uboot_finalize (GObject *object)
{
OtBootloaderUboot *self = OT_BOOTLOADER_UBOOT (object);
g_clear_object (&self->sysroot);
g_clear_object (&self->config_path);
G_OBJECT_CLASS (ot_bootloader_uboot_parent_class)->finalize (object);
}
void
ot_bootloader_uboot_init (OtBootloaderUboot *self)
{
}
static void
ot_bootloader_uboot_bootloader_iface_init (OtBootloaderInterface *iface)
{
iface->query = ot_bootloader_uboot_query;
iface->write_config = ot_bootloader_uboot_write_config;
}
void
ot_bootloader_uboot_class_init (OtBootloaderUbootClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = ot_bootloader_uboot_finalize;
}
OtBootloaderUboot *
ot_bootloader_uboot_new (GFile *sysroot)
{
OtBootloaderUboot *self = g_object_new (OT_TYPE_BOOTLOADER_UBOOT, NULL);
self->sysroot = g_object_ref (sysroot);
self->config_path = g_file_resolve_relative_path (self->sysroot, "boot/uEnv.txt");
return self;
}

View File

@ -0,0 +1,41 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2013 Collabora Ltd
*
* Based on ot-bootloader-syslinux.h by Colin Walters <walters@verbum.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the licence or (at
* your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* Author: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
*/
#pragma once
#include "ot-bootloader.h"
G_BEGIN_DECLS
#define OT_TYPE_BOOTLOADER_UBOOT (ot_bootloader_uboot_get_type ())
#define OT_BOOTLOADER_UBOOT(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), OT_TYPE_BOOTLOADER_UBOOT, OtBootloaderUboot))
#define OT_IS_BOOTLOADER_UBOOT(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), OT_TYPE_BOOTLOADER_UBOOT))
typedef struct _OtBootloaderUboot OtBootloaderUboot;
GType ot_bootloader_uboot_get_type (void) G_GNUC_CONST;
OtBootloaderUboot * ot_bootloader_uboot_new (GFile *sysroot);
G_END_DECLS