* [PATCH 6/7] add ARM Linux loader
@ 2013-03-24 17:01 Leif Lindholm
2013-04-01 16:18 ` Francesco Lavra
2013-04-07 21:17 ` Francesco Lavra
0 siblings, 2 replies; 4+ messages in thread
From: Leif Lindholm @ 2013-03-24 17:01 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 1 bytes --]
[-- Attachment #2: 0006-linux-loader.patch --]
[-- Type: application/octet-stream, Size: 12985 bytes --]
=== modified file 'grub-core/Makefile.core.def'
--- grub-core/Makefile.core.def 2013-03-24 13:26:27 +0000
+++ grub-core/Makefile.core.def 2013-03-24 13:49:04 +0000
@@ -1472,9 +1472,12 @@
powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c;
sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c;
ia64_efi = loader/ia64/efi/linux.c;
+ arm = loader/arm/linux.c;
common = loader/linux.c;
common = lib/cmdline.c;
enable = noemu;
+
+ fdt_cppflags = '$(CPPFLAGS_LIBFDT)';
};
module = {
=== added directory 'grub-core/loader/arm'
=== added file 'grub-core/loader/arm/linux.c'
--- grub-core/loader/arm/linux.c 1970-01-01 00:00:00 +0000
+++ grub-core/loader/arm/linux.c 2013-03-24 13:49:04 +0000
@@ -0,0 +1,405 @@
+/* linux.c - boot Linux */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/loader.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/command.h>
+#include <grub/cache.h>
+#include <grub/cpu/linux.h>
+#include <grub/lib/cmdline.h>
+
+#include <libfdt.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static grub_dl_t my_mod;
+
+static grub_addr_t initrd_start;
+static grub_size_t initrd_end;
+
+static grub_addr_t linux_addr;
+static grub_size_t linux_size;
+
+static char *linux_args;
+
+static grub_addr_t firmware_boot_data;
+static grub_addr_t boot_data;
+static grub_uint32_t machine_type;
+
+/*
+ * linux_prepare_fdt():
+ * Prepares a loaded FDT for being passed to Linux.
+ * Merges in command line parameters and sets up initrd addresses.
+ */
+static grub_err_t
+linux_prepare_fdt (void)
+{
+ int node;
+ int retval;
+ int tmp_size;
+ void *tmp_fdt;
+
+ tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE;
+ tmp_fdt = grub_malloc (tmp_size);
+ if (!tmp_fdt)
+ return GRUB_ERR_OUT_OF_MEMORY;
+
+ fdt_open_into ((void *) boot_data, tmp_fdt, tmp_size);
+
+ /* Find or create '/chosen' node */
+ node = fdt_subnode_offset (tmp_fdt, 0, "chosen");
+ if (node < 0)
+ {
+ grub_printf ("No 'chosen' node in FDT - creating.\n");
+ node = fdt_add_subnode (tmp_fdt, 0, "chosen");
+ if (node < 0)
+ goto failure;
+ }
+
+ grub_printf ("linux_args: '%s'\n", linux_args);
+
+ /* Generate and set command line */
+ retval = fdt_setprop (tmp_fdt, node, "bootargs", linux_args,
+ grub_strlen (linux_args) + 1);
+ if (retval)
+ goto failure;
+
+ if (initrd_start && initrd_end)
+ {
+ /*
+ * We're using physical addresses, so even if we have LPAE, we're
+ * restricted to a 32-bit address space.
+ */
+ grub_uint32_t fdt_initrd_start = cpu_to_fdt32 (initrd_start);
+ grub_uint32_t fdt_initrd_end = cpu_to_fdt32 (initrd_end);
+
+ grub_dprintf ("loader", "Initrd @ 0x%08x-0x%08x\n",
+ initrd_start, initrd_end);
+
+ retval = fdt_setprop (tmp_fdt, node, "linux,initrd-start",
+ &fdt_initrd_start, sizeof (fdt_initrd_start));
+ if (retval)
+ goto failure;
+ retval = fdt_setprop (tmp_fdt, node, "linux,initrd-end",
+ &fdt_initrd_end, sizeof (fdt_initrd_end));
+ if (retval)
+ goto failure;
+ }
+
+ /* Copy updated FDT to its launch location */
+ fdt_move (tmp_fdt, (void *) boot_data, fdt_totalsize (tmp_fdt));
+ grub_free (tmp_fdt);
+ fdt_pack ((void *) boot_data);
+
+ grub_dprintf ("loader", "FDT updated for Linux boot\n");
+
+ return GRUB_ERR_NONE;
+
+failure:
+ grub_free (tmp_fdt);
+ return GRUB_ERR_BAD_ARGUMENT;
+}
+
+static grub_err_t
+linux_boot (void)
+{
+ kernel_entry_t linuxmain;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ grub_arch_sync_caches ((void *) linux_addr, linux_size);
+
+ grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
+
+ if (!boot_data)
+ {
+ if (firmware_boot_data)
+ {
+ grub_printf ("Using firmware-supplied boot data @ 0x%08x\n",
+ firmware_boot_data);
+ boot_data = firmware_boot_data;
+ }
+ else
+ {
+ return GRUB_ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ grub_dprintf ("loader", "Boot data at: 0x%x\n", boot_data);
+
+ if (fdt32_to_cpu (*(grub_uint32_t *) (boot_data)) == FDT_MAGIC)
+ {
+ grub_dprintf ("loader", "FDT @ 0x%08x\n", (grub_addr_t) boot_data);
+ if (linux_prepare_fdt () != GRUB_ERR_NONE)
+ {
+ grub_dprintf ("loader", "linux_prepare_fdt() failed\n");
+ return GRUB_ERR_FILE_NOT_FOUND;
+ }
+ }
+
+ grub_dprintf ("loader", "Jumping to Linux...\n");
+
+ /* Boot the kernel.
+ * Arguments to kernel:
+ * r0 - 0
+ * r1 - machine type (possibly passed from firmware)
+ * r2 - address of DTB or ATAG list
+ */
+ linuxmain = (kernel_entry_t) linux_addr;
+
+#ifdef GRUB_MACHINE_EFI
+ err = grub_efi_prepare_platform();
+ if (err != GRUB_ERR_NONE)
+ return err;
+#endif
+
+ linuxmain (0, machine_type, (void *) boot_data);
+
+ return err;
+}
+
+/*
+ * Only support zImage, so no relocations necessary
+ */
+static grub_err_t
+linux_load (const char *filename)
+{
+ grub_file_t file;
+ int size;
+
+ file = grub_file_open (filename);
+ if (!file)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+ size = grub_file_size (file);
+ if (size == 0)
+ return GRUB_ERR_FILE_READ_ERROR;
+
+#ifdef GRUB_MACHINE_EFI
+ linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
+#else
+ linux_addr = LINUX_ADDRESS;
+#endif
+ grub_dprintf ("loader", "Loading Linux to 0x%08x\n",
+ (grub_addr_t) linux_addr);
+
+ if (grub_file_read (file, (void *) linux_addr, size) != size)
+ {
+ grub_printf ("Kernel read failed!\n");
+ return GRUB_ERR_FILE_READ_ERROR;
+ }
+
+ if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
+ != LINUX_ZIMAGE_MAGIC)
+ {
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid zImage"));
+ }
+
+ linux_size = size;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+linux_unload (void)
+{
+ grub_dl_unref (my_mod);
+
+ grub_free (linux_args);
+ linux_args = NULL;
+
+ initrd_start = initrd_end = 0;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int size, retval;
+ grub_file_t file;
+ grub_dl_ref (my_mod);
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (argv[0]);
+ if (!file)
+ goto fail;
+
+ retval = linux_load (argv[0]);
+ grub_file_close (file);
+ if (retval != GRUB_ERR_NONE)
+ goto fail;
+
+ grub_loader_set (linux_boot, linux_unload, 1);
+
+ size = grub_loader_cmdline_size (argc, argv);
+ linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
+ if (!linux_args)
+ goto fail;
+
+ /* Create kernel command line. */
+ grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+ grub_create_loader_cmdline (argc, argv,
+ linux_args + sizeof (LINUX_IMAGE) - 1, size);
+
+ return GRUB_ERR_NONE;
+
+fail:
+ grub_dl_unref (my_mod);
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file;
+ int size;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (argv[0]);
+ if (!file)
+ return grub_errno;
+
+ size = grub_file_size (file);
+ if (size == 0)
+ goto fail;
+
+#ifdef GRUB_MACHINE_EFI
+ initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
+#else
+ initrd_start = LINUX_INITRD_ADDRESS;
+#endif
+ grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
+ (grub_addr_t) initrd_start);
+
+ if (grub_file_read (file, (void *) initrd_start, size) != size)
+ goto fail;
+
+ initrd_end = initrd_start + size;
+
+ return GRUB_ERR_NONE;
+
+fail:
+ grub_file_close (file);
+
+ return grub_errno;
+}
+
+static void *
+load_dtb (grub_file_t dtb, int size)
+{
+ void *fdt;
+
+ fdt = grub_malloc (size);
+ if (!fdt)
+ return NULL;
+
+ if (grub_file_read (dtb, fdt, size) != size)
+ {
+ grub_free (fdt);
+ return NULL;
+ }
+
+ if (fdt_check_header (fdt) != 0)
+ {
+ grub_free (fdt);
+ return NULL;
+ }
+
+ return fdt;
+}
+
+static grub_err_t
+grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t dtb;
+ void *blob;
+ int size;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ dtb = grub_file_open (argv[0]);
+ if (!dtb)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file"));
+
+ size = grub_file_size (dtb);
+ if (size == 0)
+ goto out;
+
+ blob = load_dtb (dtb, size);
+ if (!blob)
+ return GRUB_ERR_FILE_NOT_FOUND;
+
+#ifdef GRUB_MACHINE_EFI
+ boot_data = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
+#else
+ boot_data = LINUX_FDT_ADDRESS;
+#endif
+ grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
+ (grub_addr_t) boot_data);
+ fdt_move (blob, (void *) boot_data, fdt_totalsize (blob));
+ grub_free (blob);
+
+ /*
+ * We've successfully loaded an FDT, so any machine type passed
+ * from firmware is now obsolete.
+ */
+ machine_type = ARM_FDT_MACHINE_TYPE;
+
+ return GRUB_ERR_NONE;
+
+ out:
+ grub_file_close (dtb);
+
+ return grub_errno;
+}
+
+static grub_command_t cmd_linux, cmd_initrd, cmd_devicetree;
+
+GRUB_MOD_INIT (linux)
+{
+ cmd_linux = grub_register_command ("linux", grub_cmd_linux,
+ 0, N_("Load Linux."));
+ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
+ 0, N_("Load initrd."));
+ cmd_devicetree = grub_register_command ("devicetree", grub_cmd_devicetree,
+ 0, N_("Load DTB file."));
+ my_mod = mod;
+ firmware_boot_data = firmware_get_boot_data ();
+
+ boot_data = (grub_addr_t) NULL;
+ machine_type = firmware_get_machine_type ();
+}
+
+GRUB_MOD_FINI (linux)
+{
+ grub_unregister_command (cmd_linux);
+ grub_unregister_command (cmd_initrd);
+ grub_unregister_command (cmd_devicetree);
+}
=== added file 'include/grub/arm/linux.h'
--- include/grub/arm/linux.h 1970-01-01 00:00:00 +0000
+++ include/grub/arm/linux.h 2013-03-24 13:49:04 +0000
@@ -0,0 +1,59 @@
+/* linux.h - ARM linux specific definitions */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GRUB_LINUX_CPU_HEADER
+#define GRUB_LINUX_CPU_HEADER 1
+
+#define LINUX_ZIMAGE_OFFSET 0x24
+#define LINUX_ZIMAGE_MAGIC 0x016f2818
+
+#define ARM_FDT_MACHINE_TYPE 0xFFFFFFFF
+
+#if defined GRUB_MACHINE_UBOOT
+# include <grub/uboot/uboot.h>
+# define LINUX_ADDRESS (start_of_ram + 0x8000)
+# define LINUX_INITRD_ADDRESS (start_of_ram + 0x02000000)
+# define LINUX_FDT_ADDRESS (LINUX_INITRD_ADDRESS - 0x10000)
+# define firmware_get_boot_data uboot_get_boot_data
+# define firmware_get_machine_type uboot_get_machine_type
+#elif defined GRUB_MACHINE_EFI
+# include <grub/efi/efi.h>
+# include <grub/machine/loader.h>
+/* On UEFI platforms - load the images at the lowest available address not
+ less than *_PHYS_OFFSET from the first available memory location. */
+# define LINUX_PHYS_OFFSET (0x00008000)
+# define LINUX_INITRD_PHYS_OFFSET (LINUX_PHYS_OFFSET + 0x02000000)
+# define LINUX_FDT_PHYS_OFFSET (LINUX_INITRD_PHYS_OFFSET - 0x10000)
+static inline grub_addr_t
+firmware_get_boot_data (void)
+{
+ return 0;
+}
+static inline grub_uint32_t
+firmware_get_machine_type (void)
+{
+ return ARM_FDT_MACHINE_TYPE;
+}
+#endif
+
+#define FDT_ADDITIONAL_ENTRIES_SIZE 0x300
+
+typedef void (*kernel_entry_t) (int, unsigned long, void *);
+
+#endif /* ! GRUB_LINUX_CPU_HEADER */
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH 6/7] add ARM Linux loader
2013-03-24 17:01 [PATCH 6/7] add ARM Linux loader Leif Lindholm
@ 2013-04-01 16:18 ` Francesco Lavra
2013-04-03 17:30 ` Leif Lindholm
2013-04-07 21:17 ` Francesco Lavra
1 sibling, 1 reply; 4+ messages in thread
From: Francesco Lavra @ 2013-04-01 16:18 UTC (permalink / raw)
To: grub-devel
On 03/24/2013 06:01 PM, Leif Lindholm wrote:
> === added directory 'grub-core/loader/arm'
> === added file 'grub-core/loader/arm/linux.c'
> --- grub-core/loader/arm/linux.c 1970-01-01 00:00:00 +0000
> +++ grub-core/loader/arm/linux.c 2013-03-24 13:49:04 +0000
> @@ -0,0 +1,405 @@
> +/* linux.c - boot Linux */
> +/*
> + * GRUB -- GRand Unified Bootloader
> + * Copyright (C) 2013 Free Software Foundation, Inc.
> + *
> + * GRUB is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 3 of the License, or
> + * (at your option) any later version.
> + *
> + * GRUB 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 General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <grub/dl.h>
> +#include <grub/file.h>
> +#include <grub/loader.h>
> +#include <grub/mm.h>
> +#include <grub/misc.h>
> +#include <grub/command.h>
> +#include <grub/cache.h>
> +#include <grub/cpu/linux.h>
> +#include <grub/lib/cmdline.h>
> +
> +#include <libfdt.h>
> +
> +GRUB_MOD_LICENSE ("GPLv3+");
> +
> +static grub_dl_t my_mod;
> +
> +static grub_addr_t initrd_start;
> +static grub_size_t initrd_end;
initrd_end should be the same type as initrd_start.
> +
> +static grub_addr_t linux_addr;
> +static grub_size_t linux_size;
> +
> +static char *linux_args;
> +
> +static grub_addr_t firmware_boot_data;
> +static grub_addr_t boot_data;
> +static grub_uint32_t machine_type;
> +
> +/*
> + * linux_prepare_fdt():
> + * Prepares a loaded FDT for being passed to Linux.
> + * Merges in command line parameters and sets up initrd addresses.
> + */
> +static grub_err_t
> +linux_prepare_fdt (void)
> +{
> + int node;
> + int retval;
> + int tmp_size;
> + void *tmp_fdt;
> +
> + tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE;
Having a fixed size limit (FDT_ADDITIONAL_ENTRIES_SIZE) to insert
variable-sized data (such as the linux command line) seems suboptimal,
as this may fail when a very long command line is passed. How about
removing the FDT_ADDITIONAL_ENTRIES_SIZE define from the header file
include/grub/arm/linux.h (after all, this is an implementation detail
and IMHO shouldn't go in a public header file) and defining it in this
function, say:
#define FDT_ADDITIONAL_ENTRIES_SIZE (0x100 + \
grub_strlen (linux_args))
[...]
> +/*
> + * Only support zImage, so no relocations necessary
> + */
> +static grub_err_t
> +linux_load (const char *filename)
> +{
> + grub_file_t file;
> + int size;
> +
> + file = grub_file_open (filename);
> + if (!file)
> + return GRUB_ERR_FILE_NOT_FOUND;
> +
> + size = grub_file_size (file);
> + if (size == 0)
> + return GRUB_ERR_FILE_READ_ERROR;
> +
> +#ifdef GRUB_MACHINE_EFI
> + linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
There should be a check against allocation failure.
> +#else
> + linux_addr = LINUX_ADDRESS;
> +#endif
> + grub_dprintf ("loader", "Loading Linux to 0x%08x\n",
> + (grub_addr_t) linux_addr);
> +
> + if (grub_file_read (file, (void *) linux_addr, size) != size)
> + {
> + grub_printf ("Kernel read failed!\n");
> + return GRUB_ERR_FILE_READ_ERROR;
In the EFI case, the allocated memory should be freed before returning.
> + }
> +
> + if (*(grub_uint32_t *) (linux_addr + LINUX_ZIMAGE_OFFSET)
> + != LINUX_ZIMAGE_MAGIC)
> + {
> + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid zImage"));
As above, in the EFI case the allocated memory should be freed before
returning.
> + }
> +
> + linux_size = size;
> +
> + return GRUB_ERR_NONE;
> +}
> +static grub_err_t
> +linux_unload (void)
> +{
> + grub_dl_unref (my_mod);
> +
> + grub_free (linux_args);
> + linux_args = NULL;
linux_args might already be NULL, if memory allocation for it failed in
grub_cmd_linux().
In the EFI case, the memory allocated for the kernel image should be
freed as well.
> +
> + initrd_start = initrd_end = 0;
Why should the initrd data be discarded here?
> +
> + return GRUB_ERR_NONE;
> +}
> +static grub_err_t
> +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
> + int argc, char *argv[])
> +{
> + int size, retval;
The return type of linux_load() is grub_err_t, so retval should be the
same type.
> + grub_file_t file;
> + grub_dl_ref (my_mod);
> +
> + if (argc == 0)
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
> +
> + file = grub_file_open (argv[0]);
> + if (!file)
> + goto fail;
> +
> + retval = linux_load (argv[0]);
Here the file is already open: why not just pass the file handle to
linux_load()?
> + grub_file_close (file);
> + if (retval != GRUB_ERR_NONE)
> + goto fail;
In order to correctly report all error types, grub_errno should be set
to retval before entering the error path.
> +
> + grub_loader_set (linux_boot, linux_unload, 1);
Since linux_boot() may return control to its caller, the third argument
of grub_loader_set() should be 0, otherwise linux_boot() returning
control to its caller results in a dysfunctional state.
> +
> + size = grub_loader_cmdline_size (argc, argv);
> + linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
> + if (!linux_args)
> + goto fail;
grub_loader_unset() should be called in this error path, otherwise if
one tries to boot in this state, linux_prepare_fdt() will access a NULL
pointer.
> +
> + /* Create kernel command line. */
> + grub_memcpy (linux_args, LINUX_IMAGE, sizeof (LINUX_IMAGE));
> + grub_create_loader_cmdline (argc, argv,
> + linux_args + sizeof (LINUX_IMAGE) - 1, size);
> +
> + return GRUB_ERR_NONE;
> +
> +fail:
> + grub_dl_unref (my_mod);
> + return grub_errno;
> +}
> +
> +static grub_err_t
> +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
> + int argc, char *argv[])
> +{
> + grub_file_t file;
> + int size;
> +
> + if (argc == 0)
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
> +
> + file = grub_file_open (argv[0]);
> + if (!file)
> + return grub_errno;
> +
> + size = grub_file_size (file);
> + if (size == 0)
> + goto fail;
> +
> +#ifdef GRUB_MACHINE_EFI
> + initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
If the initrd memory was already allocated as a result of the initrd
command being already called previously, it should be freed before
re-allocating memory. Also there should be a check against memory
allocation failure.
> +#else
> + initrd_start = LINUX_INITRD_ADDRESS;
> +#endif
> + grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
> + (grub_addr_t) initrd_start);
> +
> + if (grub_file_read (file, (void *) initrd_start, size) != size)
> + goto fail;
In the EFI case, the memory allocated for the initrd should be freed
here. And in both EFI and U-Boot cases, initrd_start should be zeroed.
> +
> + initrd_end = initrd_start + size;
> +
> + return GRUB_ERR_NONE;
> +
> +fail:
> + grub_file_close (file);
> +
> + return grub_errno;
> +}
> +
> +static void *
> +load_dtb (grub_file_t dtb, int size)
> +{
> + void *fdt;
> +
> + fdt = grub_malloc (size);
> + if (!fdt)
> + return NULL;
> +
> + if (grub_file_read (dtb, fdt, size) != size)
> + {
> + grub_free (fdt);
> + return NULL;
> + }
> +
> + if (fdt_check_header (fdt) != 0)
> + {
> + grub_free (fdt);
> + return NULL;
> + }
> +
> + return fdt;
> +}
> +
> +static grub_err_t
> +grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
> + int argc, char *argv[])
> +{
> + grub_file_t dtb;
> + void *blob;
> + int size;
> +
> + if (argc != 1)
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
> +
> + dtb = grub_file_open (argv[0]);
> + if (!dtb)
> + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("failed to open file"));
> +
> + size = grub_file_size (dtb);
> + if (size == 0)
> + goto out;
> +
> + blob = load_dtb (dtb, size);
> + if (!blob)
> + return GRUB_ERR_FILE_NOT_FOUND;
> +
> +#ifdef GRUB_MACHINE_EFI
> + boot_data = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
As above, if the fdt memory was already allocated as a result of the
devicetree command being already called previously, it should be freed
before re-allocating memory. Also there should be a check against memory
allocation failure.
> +#else
> + boot_data = LINUX_FDT_ADDRESS;
> +#endif
> + grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
> + (grub_addr_t) boot_data);
> + fdt_move (blob, (void *) boot_data, fdt_totalsize (blob));
> + grub_free (blob);
I don't get the point of allocating memory for the FDT in load_dtb()
just to move the FDT data to boot_data and then freeing the temporary
memory. Isn't it easier if load_dtb() operates directly on boot_data?
> +
> + /*
> + * We've successfully loaded an FDT, so any machine type passed
> + * from firmware is now obsolete.
> + */
> + machine_type = ARM_FDT_MACHINE_TYPE;
> +
> + return GRUB_ERR_NONE;
The file should be closed before returning.
> +
> + out:
> + grub_file_close (dtb);
> +
> + return grub_errno;
> +}
--
Francesco
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH 6/7] add ARM Linux loader
2013-04-01 16:18 ` Francesco Lavra
@ 2013-04-03 17:30 ` Leif Lindholm
0 siblings, 0 replies; 4+ messages in thread
From: Leif Lindholm @ 2013-04-03 17:30 UTC (permalink / raw)
To: The development of GNU GRUB
On Mon, Apr 01, 2013 at 06:18:17PM +0200, Francesco Lavra wrote:
> On 03/24/2013 06:01 PM, Leif Lindholm wrote:
> > === added directory 'grub-core/loader/arm'
> > === added file 'grub-core/loader/arm/linux.c'
> > --- grub-core/loader/arm/linux.c 1970-01-01 00:00:00 +0000
> > +++ grub-core/loader/arm/linux.c 2013-03-24 13:49:04 +0000
[...]
> > +static grub_addr_t initrd_start;
> > +static grub_size_t initrd_end;
>
> initrd_end should be the same type as initrd_start.
Clearly.
[...]
> > +static grub_err_t
> > +linux_prepare_fdt (void)
> > +{
> > + int node;
> > + int retval;
> > + int tmp_size;
> > + void *tmp_fdt;
> > +
> > + tmp_size = fdt_totalsize ((void *) boot_data) + FDT_ADDITIONAL_ENTRIES_SIZE;
>
> Having a fixed size limit (FDT_ADDITIONAL_ENTRIES_SIZE) to insert
> variable-sized data (such as the linux command line) seems suboptimal,
> as this may fail when a very long command line is passed. How about
> removing the FDT_ADDITIONAL_ENTRIES_SIZE define from the header file
> include/grub/arm/linux.h (after all, this is an implementation detail
> and IMHO shouldn't go in a public header file) and defining it in this
> function, say:
>
> #define FDT_ADDITIONAL_ENTRIES_SIZE (0x100 + \
> grub_strlen (linux_args))
Mmm. It was only used in one location though, so I'll use your suggestion,
but just inline it.
> [...]
> > +#ifdef GRUB_MACHINE_EFI
> > + linux_addr = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_PHYS_OFFSET, size);
>
> There should be a check against allocation failure.
Yes, this is a global issue with this loader under EFI - dealing with memory
allocation/deallocation. Will be resolved in next version.
> > +static grub_err_t
> > +linux_unload (void)
> > +{
> > + grub_dl_unref (my_mod);
> > +
> > + grub_free (linux_args);
> > + linux_args = NULL;
>
> linux_args might already be NULL, if memory allocation for it failed in
> grub_cmd_linux().
Yes, but on the other hand grub_free (like libc free) checks for NULL.
> In the EFI case, the memory allocated for the kernel image should be
> freed as well.
Yes.
> > +
> > + initrd_start = initrd_end = 0;
>
> Why should the initrd data be discarded here?
It probably shouldn't.
> > +
> > + return GRUB_ERR_NONE;
> > +}
> > +static grub_err_t
> > +grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
> > + int argc, char *argv[])
> > +{
> > + int size, retval;
>
> The return type of linux_load() is grub_err_t, so retval should be the
> same type.
>
> > + grub_file_t file;
> > + grub_dl_ref (my_mod);
> > +
> > + if (argc == 0)
> > + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
> > +
> > + file = grub_file_open (argv[0]);
> > + if (!file)
> > + goto fail;
> > +
> > + retval = linux_load (argv[0]);
>
> Here the file is already open: why not just pass the file handle to
> linux_load()?
Unfortunate leftover from earlier version, thanks.
> > + grub_file_close (file);
> > + if (retval != GRUB_ERR_NONE)
> > + goto fail;
>
> In order to correctly report all error types, grub_errno should be set
> to retval before entering the error path.
OK, adding grub_error() to all failure paths in linux_load.
> > +
> > + grub_loader_set (linux_boot, linux_unload, 1);
>
> Since linux_boot() may return control to its caller, the third argument
> of grub_loader_set() should be 0, otherwise linux_boot() returning
> control to its caller results in a dysfunctional state.
OK.
> > +
> > + size = grub_loader_cmdline_size (argc, argv);
> > + linux_args = grub_malloc (size + sizeof (LINUX_IMAGE));
> > + if (!linux_args)
> > + goto fail;
>
> grub_loader_unset() should be called in this error path, otherwise if
> one tries to boot in this state, linux_prepare_fdt() will access a NULL
> pointer.
Yes.
> > + if (grub_file_read (file, (void *) initrd_start, size) != size)
> > + goto fail;
>
> In the EFI case, the memory allocated for the initrd should be freed
> here. And in both EFI and U-Boot cases, initrd_start should be zeroed.
Yes.
> > +#else
> > + boot_data = LINUX_FDT_ADDRESS;
> > +#endif
> > + grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
> > + (grub_addr_t) boot_data);
> > + fdt_move (blob, (void *) boot_data, fdt_totalsize (blob));
> > + grub_free (blob);
>
> I don't get the point of allocating memory for the FDT in load_dtb()
> just to move the FDT data to boot_data and then freeing the temporary
> memory. Isn't it easier if load_dtb() operates directly on boot_data?
Maybe not the sanest of reasons, but the U-Boot port permits passing
through ATAGs if no FDT is available, so I prefer not corrupting
boot_data until a successful load has occurred.
> > +
> > + /*
> > + * We've successfully loaded an FDT, so any machine type passed
> > + * from firmware is now obsolete.
> > + */
> > + machine_type = ARM_FDT_MACHINE_TYPE;
> > +
> > + return GRUB_ERR_NONE;
>
> The file should be closed before returning.
Yes.
/
Leif
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 6/7] add ARM Linux loader
2013-03-24 17:01 [PATCH 6/7] add ARM Linux loader Leif Lindholm
2013-04-01 16:18 ` Francesco Lavra
@ 2013-04-07 21:17 ` Francesco Lavra
1 sibling, 0 replies; 4+ messages in thread
From: Francesco Lavra @ 2013-04-07 21:17 UTC (permalink / raw)
To: The development of GNU GRUB; +Cc: Leif Lindholm
Hi, I noticed another minor issue in this patch.
On 03/24/2013 06:01 PM, Leif Lindholm wrote:
> --- grub-core/loader/arm/linux.c 1970-01-01 00:00:00 +0000
> +++ grub-core/loader/arm/linux.c 2013-03-24 13:49:04 +0000
[...]
> +static grub_err_t
> +grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
> + int argc, char *argv[])
> +{
> + grub_file_t file;
> + int size;
> +
> + if (argc == 0)
> + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
> +
> + file = grub_file_open (argv[0]);
> + if (!file)
> + return grub_errno;
> +
> + size = grub_file_size (file);
> + if (size == 0)
> + goto fail;
> +
> +#ifdef GRUB_MACHINE_EFI
> + initrd_start = (grub_addr_t) grub_efi_allocate_loader_memory (LINUX_INITRD_PHYS_OFFSET, size);
> +#else
> + initrd_start = LINUX_INITRD_ADDRESS;
> +#endif
> + grub_dprintf ("loader", "Loading initrd to 0x%08x\n",
> + (grub_addr_t) initrd_start);
> +
> + if (grub_file_read (file, (void *) initrd_start, size) != size)
> + goto fail;
> +
> + initrd_end = initrd_start + size;
> +
> + return GRUB_ERR_NONE;
The file should be closed also if the initrd is successfully loaded.
> +
> +fail:
> + grub_file_close (file);
> +
> + return grub_errno;
> +}
--
Francesco
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2013-04-07 21:17 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-03-24 17:01 [PATCH 6/7] add ARM Linux loader Leif Lindholm
2013-04-01 16:18 ` Francesco Lavra
2013-04-03 17:30 ` Leif Lindholm
2013-04-07 21:17 ` Francesco Lavra
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.