arm_coreboot: Support loading linux images.
This commit is contained in:
parent
3edabad8fe
commit
656c3b0d7f
2 changed files with 83 additions and 65 deletions
|
@ -31,8 +31,6 @@
|
||||||
|
|
||||||
GRUB_MOD_LICENSE ("GPLv3+");
|
GRUB_MOD_LICENSE ("GPLv3+");
|
||||||
|
|
||||||
#ifndef GRUB_MACHINE_COREBOOT
|
|
||||||
|
|
||||||
static grub_dl_t my_mod;
|
static grub_dl_t my_mod;
|
||||||
|
|
||||||
static grub_addr_t initrd_start;
|
static grub_addr_t initrd_start;
|
||||||
|
@ -44,7 +42,7 @@ static grub_size_t linux_size;
|
||||||
static char *linux_args;
|
static char *linux_args;
|
||||||
|
|
||||||
static grub_uint32_t machine_type;
|
static grub_uint32_t machine_type;
|
||||||
static void *fdt_addr;
|
static const void *current_fdt;
|
||||||
|
|
||||||
typedef void (*kernel_entry_t) (int, unsigned long, void *);
|
typedef void (*kernel_entry_t) (int, unsigned long, void *);
|
||||||
|
|
||||||
|
@ -56,9 +54,9 @@ typedef void (*kernel_entry_t) (int, unsigned long, void *);
|
||||||
#define LINUX_FDT_PHYS_OFFSET (LINUX_INITRD_PHYS_OFFSET - 0x10000)
|
#define LINUX_FDT_PHYS_OFFSET (LINUX_INITRD_PHYS_OFFSET - 0x10000)
|
||||||
|
|
||||||
static grub_size_t
|
static grub_size_t
|
||||||
get_atag_size (grub_uint32_t *atag)
|
get_atag_size (const grub_uint32_t *atag)
|
||||||
{
|
{
|
||||||
grub_uint32_t *atag0 = atag;
|
const grub_uint32_t *atag0 = atag;
|
||||||
while (atag[0] && atag[1])
|
while (atag[0] && atag[1])
|
||||||
atag += atag[0];
|
atag += atag[0];
|
||||||
return atag - atag0;
|
return atag - atag0;
|
||||||
|
@ -70,10 +68,11 @@ get_atag_size (grub_uint32_t *atag)
|
||||||
* Merges in command line parameters and sets up initrd addresses.
|
* Merges in command line parameters and sets up initrd addresses.
|
||||||
*/
|
*/
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
linux_prepare_atag (void)
|
linux_prepare_atag (void *target_atag)
|
||||||
{
|
{
|
||||||
grub_uint32_t *atag_orig = (grub_uint32_t *) fdt_addr;
|
const grub_uint32_t *atag_orig = (const grub_uint32_t *) current_fdt;
|
||||||
grub_uint32_t *tmp_atag, *from, *to;
|
grub_uint32_t *tmp_atag, *to;
|
||||||
|
const grub_uint32_t *from;
|
||||||
grub_size_t tmp_size;
|
grub_size_t tmp_size;
|
||||||
grub_size_t arg_size = grub_strlen (linux_args);
|
grub_size_t arg_size = grub_strlen (linux_args);
|
||||||
char *cmdline_orig = NULL;
|
char *cmdline_orig = NULL;
|
||||||
|
@ -144,7 +143,7 @@ linux_prepare_atag (void)
|
||||||
to += 2;
|
to += 2;
|
||||||
|
|
||||||
/* Copy updated FDT to its launch location */
|
/* Copy updated FDT to its launch location */
|
||||||
grub_memcpy (atag_orig, tmp_atag, sizeof (grub_uint32_t) * (to - tmp_atag));
|
grub_memcpy (target_atag, tmp_atag, sizeof (grub_uint32_t) * (to - tmp_atag));
|
||||||
grub_free (tmp_atag);
|
grub_free (tmp_atag);
|
||||||
|
|
||||||
grub_dprintf ("loader", "ATAG updated for Linux boot\n");
|
grub_dprintf ("loader", "ATAG updated for Linux boot\n");
|
||||||
|
@ -158,19 +157,19 @@ linux_prepare_atag (void)
|
||||||
* Merges in command line parameters and sets up initrd addresses.
|
* Merges in command line parameters and sets up initrd addresses.
|
||||||
*/
|
*/
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
linux_prepare_fdt (void)
|
linux_prepare_fdt (void *target_fdt)
|
||||||
{
|
{
|
||||||
int node;
|
int node;
|
||||||
int retval;
|
int retval;
|
||||||
int tmp_size;
|
int tmp_size;
|
||||||
void *tmp_fdt;
|
void *tmp_fdt;
|
||||||
|
|
||||||
tmp_size = grub_fdt_get_totalsize (fdt_addr) + 0x100 + grub_strlen (linux_args);
|
tmp_size = grub_fdt_get_totalsize (current_fdt) + 0x100 + grub_strlen (linux_args);
|
||||||
tmp_fdt = grub_malloc (tmp_size);
|
tmp_fdt = grub_malloc (tmp_size);
|
||||||
if (!tmp_fdt)
|
if (!tmp_fdt)
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
|
||||||
grub_memcpy (tmp_fdt, fdt_addr, grub_fdt_get_totalsize (fdt_addr));
|
grub_memcpy (tmp_fdt, current_fdt, grub_fdt_get_totalsize (current_fdt));
|
||||||
grub_fdt_set_totalsize (tmp_fdt, tmp_size);
|
grub_fdt_set_totalsize (tmp_fdt, tmp_size);
|
||||||
|
|
||||||
/* Find or create '/chosen' node */
|
/* Find or create '/chosen' node */
|
||||||
|
@ -211,7 +210,7 @@ linux_prepare_fdt (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Copy updated FDT to its launch location */
|
/* Copy updated FDT to its launch location */
|
||||||
grub_memcpy (fdt_addr, tmp_fdt, tmp_size);
|
grub_memcpy (target_fdt, tmp_fdt, tmp_size);
|
||||||
grub_free (tmp_fdt);
|
grub_free (tmp_fdt);
|
||||||
|
|
||||||
grub_dprintf ("loader", "FDT updated for Linux boot\n");
|
grub_dprintf ("loader", "FDT updated for Linux boot\n");
|
||||||
|
@ -228,16 +227,17 @@ linux_boot (void)
|
||||||
{
|
{
|
||||||
kernel_entry_t linuxmain;
|
kernel_entry_t linuxmain;
|
||||||
int fdt_valid, atag_valid;
|
int fdt_valid, atag_valid;
|
||||||
|
void *target_fdt = 0;
|
||||||
|
|
||||||
fdt_valid = (fdt_addr && grub_fdt_check_header_nosize (fdt_addr) == 0);
|
fdt_valid = (current_fdt && grub_fdt_check_header_nosize (current_fdt) == 0);
|
||||||
atag_valid = ((((grub_uint16_t *) fdt_addr)[3] & ~3) == 0x5440
|
atag_valid = ((((const grub_uint16_t *) current_fdt)[3] & ~3) == 0x5440
|
||||||
&& *((grub_uint32_t *) fdt_addr));
|
&& *((const grub_uint32_t *) current_fdt));
|
||||||
grub_dprintf ("loader", "atag: %p, %x, %x, %s, %s\n",
|
grub_dprintf ("loader", "atag: %p, %x, %x, %s, %s\n",
|
||||||
fdt_addr,
|
current_fdt,
|
||||||
((grub_uint16_t *) fdt_addr)[3],
|
((const grub_uint16_t *) current_fdt)[3],
|
||||||
*((grub_uint32_t *) fdt_addr),
|
*((const grub_uint32_t *) current_fdt),
|
||||||
(char *) fdt_addr,
|
(const char *) current_fdt,
|
||||||
(char *) fdt_addr + 1);
|
(const char *) current_fdt + 1);
|
||||||
|
|
||||||
if (!fdt_valid && machine_type == GRUB_ARM_MACHINE_TYPE_FDT)
|
if (!fdt_valid && machine_type == GRUB_ARM_MACHINE_TYPE_FDT)
|
||||||
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
return grub_error (GRUB_ERR_FILE_NOT_FOUND,
|
||||||
|
@ -247,23 +247,40 @@ linux_boot (void)
|
||||||
|
|
||||||
grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
|
grub_dprintf ("loader", "Kernel at: 0x%x\n", linux_addr);
|
||||||
|
|
||||||
|
if (fdt_valid || atag_valid)
|
||||||
|
{
|
||||||
|
#ifdef GRUB_MACHINE_EFI
|
||||||
|
grub_size_t size;
|
||||||
|
if (fdt_valid)
|
||||||
|
size = grub_fdt_get_totalsize (fdt_addr);
|
||||||
|
else
|
||||||
|
size = 4 * get_atag_size (atag_orig);
|
||||||
|
size += grub_strlen (linux_args) + 256;
|
||||||
|
target_fdt = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
|
||||||
|
if (!fdt_addr)
|
||||||
|
return grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
||||||
|
#else
|
||||||
|
target_fdt = (void *) LINUX_FDT_ADDRESS;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (fdt_valid)
|
if (fdt_valid)
|
||||||
{
|
{
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
|
|
||||||
err = linux_prepare_fdt ();
|
err = linux_prepare_fdt (target_fdt);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
grub_dprintf ("loader", "FDT @ 0x%p\n", fdt_addr);
|
grub_dprintf ("loader", "FDT @ %p\n", target_fdt);
|
||||||
}
|
}
|
||||||
else if (atag_valid)
|
else if (atag_valid)
|
||||||
{
|
{
|
||||||
grub_err_t err;
|
grub_err_t err;
|
||||||
|
|
||||||
err = linux_prepare_atag ();
|
err = linux_prepare_atag (target_fdt);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
grub_dprintf ("loader", "ATAG @ 0x%p\n", fdt_addr);
|
grub_dprintf ("loader", "ATAG @ %p\n", target_fdt);
|
||||||
}
|
}
|
||||||
|
|
||||||
grub_dprintf ("loader", "Jumping to Linux...\n");
|
grub_dprintf ("loader", "Jumping to Linux...\n");
|
||||||
|
@ -287,7 +304,7 @@ linux_boot (void)
|
||||||
|
|
||||||
grub_arm_disable_caches_mmu ();
|
grub_arm_disable_caches_mmu ();
|
||||||
|
|
||||||
linuxmain (0, machine_type, fdt_addr);
|
linuxmain (0, machine_type, target_fdt);
|
||||||
|
|
||||||
return grub_error (GRUB_ERR_BAD_OS, "Linux call returned");
|
return grub_error (GRUB_ERR_BAD_OS, "Linux call returned");
|
||||||
}
|
}
|
||||||
|
@ -446,11 +463,26 @@ fail:
|
||||||
static grub_err_t
|
static grub_err_t
|
||||||
load_dtb (grub_file_t dtb, int size)
|
load_dtb (grub_file_t dtb, int size)
|
||||||
{
|
{
|
||||||
if ((grub_file_read (dtb, fdt_addr, size) != size)
|
void *new_fdt = grub_zalloc (size);
|
||||||
|| (grub_fdt_check_header (fdt_addr, size) != 0))
|
if (!new_fdt)
|
||||||
return grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
|
return grub_errno;
|
||||||
|
grub_dprintf ("loader", "Loading device tree to %p\n",
|
||||||
|
new_fdt);
|
||||||
|
if ((grub_file_read (dtb, new_fdt, size) != size)
|
||||||
|
|| (grub_fdt_check_header (new_fdt, size) != 0))
|
||||||
|
{
|
||||||
|
grub_free (new_fdt);
|
||||||
|
return grub_error (GRUB_ERR_BAD_OS, N_("invalid device tree"));
|
||||||
|
}
|
||||||
|
|
||||||
|
grub_fdt_set_totalsize (new_fdt, size);
|
||||||
|
current_fdt = new_fdt;
|
||||||
|
/*
|
||||||
|
* We've successfully loaded an FDT, so any machine type passed
|
||||||
|
* from firmware is now obsolete.
|
||||||
|
*/
|
||||||
|
machine_type = GRUB_ARM_MACHINE_TYPE_FDT;
|
||||||
|
|
||||||
grub_fdt_set_totalsize (fdt_addr, size);
|
|
||||||
return GRUB_ERR_NONE;
|
return GRUB_ERR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -466,42 +498,13 @@ grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)),
|
||||||
|
|
||||||
dtb = grub_file_open (argv[0]);
|
dtb = grub_file_open (argv[0]);
|
||||||
if (!dtb)
|
if (!dtb)
|
||||||
goto out;
|
return grub_errno;
|
||||||
|
|
||||||
size = grub_file_size (dtb);
|
size = grub_file_size (dtb);
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
{
|
grub_error (GRUB_ERR_BAD_OS, "empty file");
|
||||||
grub_error (GRUB_ERR_BAD_OS, "empty file");
|
else
|
||||||
goto out;
|
load_dtb (dtb, size);
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef GRUB_MACHINE_EFI
|
|
||||||
fdt_addr = grub_efi_allocate_loader_memory (LINUX_FDT_PHYS_OFFSET, size);
|
|
||||||
if (!fdt_addr)
|
|
||||||
{
|
|
||||||
grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
fdt_addr = (void *) LINUX_FDT_ADDRESS;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
grub_dprintf ("loader", "Loading device tree to 0x%08x\n",
|
|
||||||
(grub_addr_t) fdt_addr);
|
|
||||||
load_dtb (dtb, size);
|
|
||||||
if (grub_errno != GRUB_ERR_NONE)
|
|
||||||
{
|
|
||||||
fdt_addr = NULL;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We've successfully loaded an FDT, so any machine type passed
|
|
||||||
* from firmware is now obsolete.
|
|
||||||
*/
|
|
||||||
machine_type = GRUB_ARM_MACHINE_TYPE_FDT;
|
|
||||||
|
|
||||||
out:
|
|
||||||
grub_file_close (dtb);
|
grub_file_close (dtb);
|
||||||
|
|
||||||
return grub_errno;
|
return grub_errno;
|
||||||
|
@ -519,7 +522,7 @@ GRUB_MOD_INIT (linux)
|
||||||
/* TRANSLATORS: DTB stands for device tree blob. */
|
/* TRANSLATORS: DTB stands for device tree blob. */
|
||||||
0, N_("Load DTB file."));
|
0, N_("Load DTB file."));
|
||||||
my_mod = mod;
|
my_mod = mod;
|
||||||
fdt_addr = (void *) grub_arm_firmware_get_boot_data ();
|
current_fdt = grub_arm_firmware_get_boot_data ();
|
||||||
machine_type = grub_arm_firmware_get_machine_type ();
|
machine_type = grub_arm_firmware_get_machine_type ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -529,4 +532,3 @@ GRUB_MOD_FINI (linux)
|
||||||
grub_unregister_command (cmd_initrd);
|
grub_unregister_command (cmd_initrd);
|
||||||
grub_unregister_command (cmd_devicetree);
|
grub_unregister_command (cmd_devicetree);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -46,6 +46,22 @@ grub_arm_firmware_get_machine_type (void)
|
||||||
{
|
{
|
||||||
return GRUB_ARM_MACHINE_TYPE_FDT;
|
return GRUB_ARM_MACHINE_TYPE_FDT;
|
||||||
}
|
}
|
||||||
|
#elif defined (GRUB_MACHINE_COREBOOT)
|
||||||
|
#include <grub/fdtbus.h>
|
||||||
|
#include <grub/machine/kernel.h>
|
||||||
|
# define LINUX_ADDRESS (start_of_ram + 0x8000)
|
||||||
|
# define LINUX_INITRD_ADDRESS (start_of_ram + 0x02000000)
|
||||||
|
# define LINUX_FDT_ADDRESS (LINUX_INITRD_ADDRESS - 0x10000)
|
||||||
|
static inline const void *
|
||||||
|
grub_arm_firmware_get_boot_data (void)
|
||||||
|
{
|
||||||
|
return grub_fdtbus_get_fdt ();
|
||||||
|
}
|
||||||
|
static inline grub_uint32_t
|
||||||
|
grub_arm_firmware_get_machine_type (void)
|
||||||
|
{
|
||||||
|
return GRUB_ARM_MACHINE_TYPE_FDT;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define FDT_ADDITIONAL_ENTRIES_SIZE 0x300
|
#define FDT_ADDITIONAL_ENTRIES_SIZE 0x300
|
||||||
|
|
Loading…
Reference in a new issue