Initrd support
This commit is contained in:
parent
368a0c61fd
commit
96c210daa3
1 changed files with 70 additions and 18 deletions
|
@ -34,13 +34,14 @@ static grub_dl_t my_mod;
|
|||
|
||||
static int loaded;
|
||||
|
||||
static grub_size_t initrd_size;
|
||||
static grub_size_t linux_size;
|
||||
|
||||
static grub_uint8_t *playground;
|
||||
static grub_addr_t target_addr, entry_addr, initrd_addr;
|
||||
static grub_addr_t target_addr, entry_addr;
|
||||
static int linux_argc;
|
||||
static grub_addr_t argv_addr, envp_addr;
|
||||
static grub_off_t argv_off, envp_off;
|
||||
static grub_off_t rd_addr_arg_off, rd_size_arg_off;
|
||||
static int initrd_loaded = 0;
|
||||
|
||||
static grub_err_t
|
||||
grub_linux_boot (void)
|
||||
|
@ -50,8 +51,8 @@ grub_linux_boot (void)
|
|||
/* Boot the kernel. */
|
||||
state.gpr[1] = entry_addr;
|
||||
state.gpr[4] = linux_argc;
|
||||
state.gpr[5] = argv_addr;
|
||||
state.gpr[6] = envp_addr;
|
||||
state.gpr[5] = target_addr + argv_off;
|
||||
state.gpr[6] = target_addr + envp_off;
|
||||
state.jumpreg = 1;
|
||||
grub_relocator32_boot (playground, target_addr, state);
|
||||
|
||||
|
@ -198,11 +199,24 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
|
||||
/* For arguments. */
|
||||
linux_argc = argc;
|
||||
/* Main arguments. */
|
||||
size = (linux_argc + 1) * sizeof (grub_uint32_t);
|
||||
size += ALIGN_UP (sizeof ("g"), 4);
|
||||
/* Initrd address and size. */
|
||||
size += 2 * sizeof (grub_uint32_t);
|
||||
/* NULL terminator. */
|
||||
size += sizeof (grub_uint32_t);
|
||||
|
||||
/* First arguments are always "a0" and "a1". */
|
||||
size += ALIGN_UP (sizeof ("a0"), 4);
|
||||
size += ALIGN_UP (sizeof ("a1"), 4);
|
||||
/* Normal arguments. */
|
||||
for (i = 1; i < argc; i++)
|
||||
size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
|
||||
|
||||
/* rd arguments. */
|
||||
size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
|
||||
size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
|
||||
|
||||
/* For the environment. */
|
||||
size += sizeof (grub_uint32_t);
|
||||
|
||||
|
@ -220,15 +234,21 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
return err;
|
||||
|
||||
linux_argv = extra;
|
||||
argv_addr = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground
|
||||
+ target_addr;
|
||||
extra = linux_argv + (linux_argc + 1);
|
||||
argv_off = (grub_uint8_t *) linux_argv - (grub_uint8_t *) playground;
|
||||
extra = linux_argv + (linux_argc + 1 + 1 + 2);
|
||||
linux_args = extra;
|
||||
grub_memcpy (linux_args, "g", sizeof ("g"));
|
||||
|
||||
grub_memcpy (linux_args, "a0", sizeof ("a0"));
|
||||
*linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground
|
||||
+ target_addr;
|
||||
linux_argv++;
|
||||
linux_args += ALIGN_UP (sizeof ("g"), 4);
|
||||
linux_args += ALIGN_UP (sizeof ("a0"), 4);
|
||||
|
||||
grub_memcpy (linux_args, "a1", sizeof ("a1"));
|
||||
*linux_argv = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground
|
||||
+ target_addr;
|
||||
linux_argv++;
|
||||
linux_args += ALIGN_UP (sizeof ("a1"), 4);
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
|
@ -238,16 +258,28 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
|
|||
linux_argv++;
|
||||
linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4);
|
||||
}
|
||||
|
||||
/* Reserve space for rd arguments. */
|
||||
rd_addr_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground;
|
||||
linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4);
|
||||
*linux_argv = 0;
|
||||
linux_argv++;
|
||||
|
||||
rd_size_arg_off = (grub_uint8_t *) linux_args - (grub_uint8_t *) playground;
|
||||
linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4);
|
||||
*linux_argv = 0;
|
||||
linux_argv++;
|
||||
|
||||
*linux_argv = 0;
|
||||
|
||||
extra = linux_args;
|
||||
|
||||
linux_envp = extra;
|
||||
envp_addr = (grub_uint8_t *) linux_envp - (grub_uint8_t *) playground
|
||||
+ target_addr;
|
||||
envp_off = (grub_uint8_t *) linux_envp - (grub_uint8_t *) playground;
|
||||
linux_envp[0] = 0;
|
||||
|
||||
grub_loader_set (grub_linux_boot, grub_linux_unload, 1);
|
||||
initrd_addr = 0;
|
||||
initrd_loaded = 0;
|
||||
loaded = 1;
|
||||
grub_dl_ref (my_mod);
|
||||
|
||||
|
@ -260,6 +292,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
{
|
||||
grub_file_t file = 0;
|
||||
grub_ssize_t size;
|
||||
grub_size_t overhead;
|
||||
|
||||
if (argc == 0)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "no initrd specified");
|
||||
|
@ -267,20 +300,28 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
if (!loaded)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "You need to load the kernel first.");
|
||||
|
||||
if (initrd_loaded)
|
||||
return grub_error (GRUB_ERR_BAD_ARGUMENT, "Only one initrd can be loaded.");
|
||||
|
||||
file = grub_file_open (argv[0]);
|
||||
if (! file)
|
||||
return grub_errno;
|
||||
|
||||
size = grub_file_size (file);
|
||||
|
||||
playground = grub_relocator32_realloc (playground, linux_size + size);
|
||||
overhead = ALIGN_UP (target_addr + linux_size + 0x10000, 0x10000)
|
||||
- (target_addr + linux_size);
|
||||
|
||||
playground = grub_relocator32_realloc (playground,
|
||||
linux_size + overhead + size);
|
||||
|
||||
if (!playground)
|
||||
{
|
||||
grub_file_close (file);
|
||||
return grub_errno;
|
||||
}
|
||||
|
||||
if (grub_file_read (file, playground + linux_size, size) != size)
|
||||
if (grub_file_read (file, playground + linux_size + overhead, size) != size)
|
||||
{
|
||||
grub_error (GRUB_ERR_FILE_READ_ERROR, "Couldn't read file");
|
||||
grub_file_close (file);
|
||||
|
@ -288,8 +329,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
|
|||
return grub_errno;
|
||||
}
|
||||
|
||||
initrd_addr = target_addr + linux_size;
|
||||
initrd_size = size;
|
||||
grub_sprintf ((char *) playground + rd_addr_arg_off, "rd_start=0x%llx",
|
||||
(unsigned long long) target_addr + linux_size + overhead);
|
||||
((grub_uint32_t *) (playground + argv_off))[linux_argc]
|
||||
= target_addr + rd_addr_arg_off;
|
||||
linux_argc++;
|
||||
|
||||
grub_sprintf ((char *) playground + rd_size_arg_off, "rd_size=0x%llx",
|
||||
(unsigned long long) size);
|
||||
((grub_uint32_t *) (playground + argv_off))[linux_argc]
|
||||
= target_addr + rd_size_arg_off;
|
||||
linux_argc++;
|
||||
|
||||
initrd_loaded = 1;
|
||||
|
||||
grub_file_close (file);
|
||||
|
||||
|
|
Loading…
Reference in a new issue