On 12.02.2016 20:34, Shea Levy wrote: > OK. Do you have any thoughts on how best to extract the "load the kernel > and set the command line to a specific string" functionality out of the > linux command, then? > At first I wanted to write a short skeleton patch to show what I meant but once skeleton is done, there is little actual code involved. Please try attached patch > On 2016-02-12 14:22, Vladimir 'phcoder' Serbinenko wrote: >> Separate command is better as it keeps interface tidy and unpoluted, >> decreasing maintenance cost. Correct me if I'm wrong but it should be >> clear from context of file is Android image or usual linux one? >> >> Le ven. 12 févr. 2016 20:19, Shea Levy <[email protected]> a écrit : >> >>> On 2016-02-12 12:50, Vladimir 'φ-coder/phcoder' Serbinenko wrote: >>> > On 08.02.2016 21:47, Shea Levy wrote: >>> >> --- >>> >> grub-core/loader/i386/linux.c | 27 +++++++++++++++++++++------ >>> >> 1 file changed, 21 insertions(+), 6 deletions(-) >>> >> >>> >> diff --git a/grub-core/loader/i386/linux.c >>> >> b/grub-core/loader/i386/linux.c >>> >> index fddcc46..6ab8d3c 100644 >>> >> --- a/grub-core/loader/i386/linux.c >>> >> +++ b/grub-core/loader/i386/linux.c >>> >> @@ -35,6 +35,7 @@ >>> >> #include <grub/i18n.h> >>> >> #include <grub/lib/cmdline.h> >>> >> #include <grub/linux.h> >>> >> +#include <grub/android_bootimg.h> >>> >> >>> >> GRUB_MOD_LICENSE ("GPLv3+"); >>> >> >>> >> @@ -695,7 +696,13 @@ grub_cmd_linux (grub_command_t cmd >>> >> __attribute__ ((unused)), >>> >> goto fail; >>> >> } >>> >> >>> >> - file = grub_file_open (argv[0]); >>> >> + char android_cmdline[BOOT_ARGS_SIZE]; >>> >> + android_cmdline[0] = ''; >>> >> + if (grub_memcmp (argv[0], "android_bootimg:", sizeof >>> >> "android_bootimg:" - 1) == 0) >>> >> + grub_android_bootimg_load_kernel (argv[0] + sizeof >>> >> "android_bootimg:" - 1, >>> >> + &file, android_cmdline); >>> >> + else >>> >> + file = grub_file_open (argv[0]); >>> > I hoped more for autodetection. This gets a bit hairy and proper >>> > separation is better. Sorry for confusion. I think it's simpler with >>> > commands like >>> > android_bootimg [--no-cmdline] [--no-initrd] IMAGE [EXTRA_ARGUMENTS] >>> > by default it will load both IMAGE, with cmdline and initrd. With >>> > --no-initrd you can use initrd for custom initrd. >>> >>> Autodetection would be possible actually, I didn't think of that. If >>> grub_file_open fails, we can try grub_android_bootimg_load_kernel on the >>> same file. Would that be preferable or do we still want a separate >>> command? >>> >>> > >>> >> if (! file) >>> >> goto fail; >>> >> >>> >> @@ -1008,12 +1015,20 @@ grub_cmd_linux (grub_command_t cmd >>> >> __attribute__ ((unused)), >>> >> linux_cmdline = grub_zalloc (maximal_cmdline_size + 1); >>> >> if (!linux_cmdline) >>> >> goto fail; >>> >> - grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); >>> >> + grub_size_t cmdline_offset = 0; >>> >> + if (android_cmdline[0]) >>> >> + { >>> >> + cmdline_offset = grub_strlen (android_cmdline) + 1; >>> >> + grub_memcpy (linux_cmdline, android_cmdline, cmdline_offset - >>> >> 1); >>> >> + linux_cmdline[cmdline_offset - 1] = ' '; >>> >> + } >>> >> + grub_memcpy (linux_cmdline + cmdline_offset, LINUX_IMAGE, sizeof >>> >> (LINUX_IMAGE)); >>> >> + cmdline_offset += sizeof LINUX_IMAGE - 1; >>> > LINUX_IMAGE must be at the beginning. don't forget brackets around >>> > sizeof. >>> >> grub_create_loader_cmdline (argc, argv, >>> >> - linux_cmdline >>> >> - + sizeof (LINUX_IMAGE) - 1, >>> >> - maximal_cmdline_size >>> >> - - (sizeof (LINUX_IMAGE) - 1)); >>> >> + linux_cmdline >>> >> + + cmdline_offset, >>> >> + maximal_cmdline_size >>> >> + - cmdline_offset); >>> >> >>> >> len = prot_file_size; >>> >> if (grub_file_read (file, prot_mode_mem, len) != len && >>> >> !grub_errno) >>> >> >>> > >>> > >>> > >>> > _______________________________________________ >>> > Grub-devel mailing list >>> > [email protected] >>> > https://lists.gnu.org/mailman/listinfo/grub-devel [1] >>> >>> _______________________________________________ >>> Grub-devel mailing list >>> [email protected] >>> https://lists.gnu.org/mailman/listinfo/grub-devel [1] >> >> >> Links: >> ------ >> [1] https://lists.gnu.org/mailman/listinfo/grub-devel >> >> _______________________________________________ >> Grub-devel mailing list >> [email protected] >> https://lists.gnu.org/mailman/listinfo/grub-devel > > > _______________________________________________ > Grub-devel mailing list > [email protected] > https://lists.gnu.org/mailman/listinfo/grub-devel
diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c
index fddcc46..d3870ae 100644
--- a/grub-core/loader/i386/linux.c
+++ b/grub-core/loader/i386/linux.c
@@ -35,6 +35,7 @@
#include <grub/i18n.h>
#include <grub/lib/cmdline.h>
#include <grub/linux.h>
+#include <grub/android.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -673,11 +674,11 @@ grub_linux_unload (void)
return GRUB_ERR_NONE;
}
+
static grub_err_t
-grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *argv[])
+linux_load (grub_file_t file, grub_off_t fileoffset, grub_off_t filesize,
+ const char *extra_cmdline, int argc, char *argv[])
{
- grub_file_t file = 0;
struct linux_kernel_header lh;
grub_uint8_t setup_sects;
grub_size_t real_size, prot_size, prot_file_size;
@@ -689,15 +690,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
grub_dl_ref (my_mod);
- if (argc == 0)
- {
- grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- goto fail;
- }
-
- file = grub_file_open (argv[0]);
- if (! file)
- goto fail;
+ grub_file_seek (file, fileoffset);
if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
{
@@ -757,7 +750,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
- prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
+ prot_file_size = filesize - real_size - GRUB_DISK_SECTOR_SIZE;
if (grub_le_to_cpu16 (lh.version) >= 0x205
&& lh.kernel_alignment != 0
@@ -871,7 +864,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
/* The other parameters are filled when booting. */
- grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
+ grub_file_seek (file, fileoffset + real_size + GRUB_DISK_SECTOR_SIZE);
grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
(unsigned) real_size, (unsigned) prot_size);
@@ -1008,12 +1001,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
linux_cmdline = grub_zalloc (maximal_cmdline_size + 1);
if (!linux_cmdline)
goto fail;
- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
- grub_create_loader_cmdline (argc, argv,
- linux_cmdline
- + sizeof (LINUX_IMAGE) - 1,
- maximal_cmdline_size
- - (sizeof (LINUX_IMAGE) - 1));
+ char *cmdline_ptr = linux_cmdline;
+ char *cmdline_ptr_end = linux_cmdline + maximal_cmdline_size;
+ /* Construct BOOT_IMAGE=/boot/... */
+ cmdline_ptr = grub_stpcpy (cmdline_ptr, LINUX_IMAGE);
+ grub_create_loader_cmdline (1, argv, cmdline_ptr,
+ cmdline_ptr_end - cmdline_ptr);
+ cmdline_ptr += grub_strlen (cmdline_ptr);
+ /* Extra */
+ if (cmdline_ptr < cmdline_ptr_end - 1 && *extra_cmdline)
+ {
+ *cmdline_ptr++ = ' ';
+ cmdline_ptr = grub_stpncpy (cmdline_ptr, extra_cmdline,
+ cmdline_ptr_end - cmdline_ptr);
+ }
+
+ /* Rest of command line. */
+ if (cmdline_ptr < cmdline_ptr_end - 1 && argc > 1)
+ {
+ *cmdline_ptr++ = ' ';
+ grub_create_loader_cmdline (argc - 1, argv + 1, cmdline_ptr,
+ cmdline_ptr_end - cmdline_ptr);
+ }
+ else
+ {
+ *cmdline_ptr = '\0';
+ }
len = prot_file_size;
if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
@@ -1029,9 +1042,6 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
fail:
- if (file)
- grub_file_close (file);
-
if (grub_errno != GRUB_ERR_NONE)
{
grub_dl_unref (my_mod);
@@ -1042,31 +1052,32 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
}
static grub_err_t
-grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
- int argc, char *argv[])
+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
{
- grub_size_t size = 0, aligned_size = 0;
- grub_addr_t addr_min, addr_max;
- grub_addr_t addr;
+ grub_file_t file = 0;
grub_err_t err;
- struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
-
if (argc == 0)
- {
- grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- goto fail;
- }
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
- if (! loaded)
- {
- grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
- goto fail;
- }
+ file = grub_file_open (argv[0]);
+ if (! file)
+ return grub_errno;
- if (grub_initrd_init (argc, argv, &initrd_ctx))
- goto fail;
+ err = linux_load (file, 0, grub_file_size (file), "", argc, argv);
+ grub_file_close (file);
+ return err;
+}
+
+static grub_err_t
+load_initrd (struct grub_linux_initrd_context *initrd_ctx, char *filenames[])
+{
+ grub_size_t size = 0, aligned_size = 0;
+ grub_addr_t addr_min, addr_max;
+ grub_addr_t addr;
+ grub_err_t err;
- size = grub_get_initrd_size (&initrd_ctx);
+ size = grub_get_initrd_size (initrd_ctx);
aligned_size = ALIGN_UP (size, 4096);
/* Get the highest address available for the initrd. */
@@ -1098,10 +1109,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
addr = (addr_max - aligned_size) & ~0xFFF;
if (addr < addr_min)
- {
- grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
- goto fail;
- }
+ return grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
{
grub_relocator_chunk_t ch;
@@ -1116,8 +1124,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
initrd_mem_target = get_physical_target_address (ch);
}
- if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
- goto fail;
+ err = grub_initrd_load (initrd_ctx, filenames, initrd_mem);
+ if (err)
+ return err;
grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
(unsigned) addr, (unsigned) size);
@@ -1126,18 +1135,123 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
linux_params.ramdisk_size = size;
linux_params.root_dev = 0x0100; /* XXX */
- fail:
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
+ grub_err_t err;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ if (! loaded)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
+
+ err = grub_initrd_init (argc, argv, &initrd_ctx);
+
+ if (!err)
+ err = load_initrd (&initrd_ctx, argv);
+
grub_initrd_close (&initrd_ctx);
+ return err;
+}
+
+static grub_err_t
+grub_cmd_android_bootimg (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file = 0;
+ grub_err_t err = GRUB_ERR_NONE;
+ int do_load_initrd = 1, do_load_cmdline = 1;
+ struct grub_android_boot_img_hdr boot_img_header;
+ char *cmdline = NULL;
+
+ for (; argc > 0; argc--, argv++)
+ {
+ if (grub_strcmp (argv[0], "--no-cmdline") == 0)
+ {
+ do_load_cmdline = 0;
+ continue;
+ }
+ if (grub_strcmp (argv[0], "--no-initrd") == 0)
+ {
+ do_load_initrd = 0;
+ continue;
+ }
+ break;
+ }
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ file = grub_file_open (argv[0]);
+ if (! file)
+ return grub_errno;
+
+ if (grub_file_read (file, &boot_img_header, sizeof (boot_img_header)) != sizeof (boot_img_header))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ argv[0]);
+ err = grub_errno;
+ goto fail;
+ }
+
+ if (grub_memcmp (boot_img_header.magic, GRUB_ANDROID_BOOT_MAGIC, GRUB_ANDROID_BOOT_MAGIC_SIZE) != 0)
+ {
+ err = grub_error (GRUB_ERR_BAD_OS, "invalid android magic");
+ goto fail;
+ }
+
+ if (do_load_cmdline)
+ {
+ cmdline = grub_malloc (GRUB_ANDROID_BOOT_EXTRA_ARGS_SIZE
+ + GRUB_ANDROID_BOOT_ARGS_SIZE + 1);
+ if (!cmdline)
+ goto fail;
+ grub_memcpy (cmdline, boot_img_header.cmdline, GRUB_ANDROID_BOOT_ARGS_SIZE);
+ grub_memcpy (cmdline + GRUB_ANDROID_BOOT_ARGS_SIZE, boot_img_header.extra_cmdline, GRUB_ANDROID_BOOT_EXTRA_ARGS_SIZE);
+ cmdline[GRUB_ANDROID_BOOT_EXTRA_ARGS_SIZE + GRUB_ANDROID_BOOT_ARGS_SIZE] = '\0';
+ }
+
+ err = linux_load (file, boot_img_header.page_size, boot_img_header.kernel_size, cmdline ? : "", argc, argv);
+ if (err)
+ goto fail;
+
+ if (do_load_initrd && boot_img_header.ramdisk_size)
+ {
+ struct grub_linux_initrd_component component = {
+ .size = boot_img_header.ramdisk_size,
+ .newc_name = 0,
+ .file = file,
+ .fileoffset = ALIGN_UP (boot_img_header.kernel_size, boot_img_header.page_size)
+ };
+ struct grub_linux_initrd_context initrd_ctx = {
+ .nfiles = 1,
+ .size = boot_img_header.ramdisk_size,
+ .components = &component
+ };
+ err = load_initrd (&initrd_ctx, argv);
+ }
+ fail:
+ grub_file_close (file);
return grub_errno;
}
-static grub_command_t cmd_linux, cmd_initrd;
+
+static grub_command_t cmd_linux, cmd_initrd, cmd_android_bootimg;
GRUB_MOD_INIT(linux)
{
cmd_linux = grub_register_command ("linux", grub_cmd_linux,
0, N_("Load Linux."));
+ cmd_android_bootimg = grub_register_command ("android_bootimg", grub_cmd_android_bootimg,
+ "[--no-initrd] [--no-cmdline] IMAGE [OPTIONS]", N_("Load Android bootimg."));
cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd,
0, N_("Load initrd."));
my_mod = mod;
@@ -1147,4 +1261,5 @@ GRUB_MOD_FINI(linux)
{
grub_unregister_command (cmd_linux);
grub_unregister_command (cmd_initrd);
+ grub_unregister_command (cmd_android_bootimg);
}
diff --git a/grub-core/loader/linux.c b/grub-core/loader/linux.c
index be6fa0f..dea0299 100644
--- a/grub-core/loader/linux.c
+++ b/grub-core/loader/linux.c
@@ -23,13 +23,6 @@ struct newc_head
char check[8];
} GRUB_PACKED;
-struct grub_linux_initrd_component
-{
- grub_file_t file;
- char *newc_name;
- grub_off_t size;
-};
-
struct dir
{
char *name;
@@ -208,6 +201,7 @@ grub_initrd_init (int argc, char *argv[],
initrd_ctx->nfiles++;
initrd_ctx->components[i].size
= grub_file_size (initrd_ctx->components[i].file);
+ initrd_ctx->components[i].fileoffset = 0;
initrd_ctx->size += initrd_ctx->components[i].size;
}
@@ -279,6 +273,8 @@ grub_initrd_load (struct grub_linux_initrd_context *initrd_ctx,
}
cursize = initrd_ctx->components[i].size;
+ grub_file_seek (initrd_ctx->components[i].file,
+ initrd_ctx->components[i].fileoffset);
if (grub_file_read (initrd_ctx->components[i].file, ptr, cursize)
!= cursize)
{
diff --git a/include/grub/android.h b/include/grub/android.h
new file mode 100644
index 0000000..7cd25f4
--- /dev/null
+++ b/include/grub/android.h
@@ -0,0 +1,73 @@
+/* tools/mkbootimg/bootimg.h
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+#ifndef _GRUB_ANDROID_BOOT_IMAGE_H_
+#define _GRUB_ANDROID_BOOT_IMAGE_H_
+
+#include <grub/types.h>
+
+#define GRUB_ANDROID_BOOT_MAGIC "ANDROID!"
+#define GRUB_ANDROID_BOOT_MAGIC_SIZE 8
+#define GRUB_ANDROID_BOOT_NAME_SIZE 16
+#define GRUB_ANDROID_BOOT_ARGS_SIZE 512
+#define GRUB_ANDROID_BOOT_EXTRA_ARGS_SIZE 1024
+struct grub_android_boot_img_hdr
+{
+ grub_uint8_t magic[GRUB_ANDROID_BOOT_MAGIC_SIZE];
+ grub_uint32_t kernel_size; /* size in bytes */
+ grub_uint32_t kernel_addr; /* physical load addr */
+ grub_uint32_t ramdisk_size; /* size in bytes */
+ grub_uint32_t ramdisk_addr; /* physical load addr */
+ grub_uint32_t second_size; /* size in bytes */
+ grub_uint32_t second_addr; /* physical load addr */
+ grub_uint32_t tags_addr; /* physical addr for kernel tags */
+ grub_uint32_t page_size; /* flash page size we assume */
+ grub_uint32_t unused[2]; /* future expansion: should be 0 */
+ grub_uint8_t name[GRUB_ANDROID_BOOT_NAME_SIZE]; /* asciiz product name */
+ grub_uint8_t cmdline[GRUB_ANDROID_BOOT_ARGS_SIZE];
+ grub_uint32_t id[8]; /* timestamp / checksum / sha1 / etc */
+ /* Supplemental command line data; kept here to maintain
+ * binary compatibility with older versions of mkbootimg */
+ grub_uint8_t extra_cmdline[GRUB_ANDROID_BOOT_EXTRA_ARGS_SIZE];
+} __attribute__((packed));
+/*
+** +-----------------+
+** | boot header | 1 page
+** +-----------------+
+** | kernel | n pages
+** +-----------------+
+** | ramdisk | m pages
+** +-----------------+
+** | second stage | o pages
+** +-----------------+
+**
+** n = (kernel_size + page_size - 1) / page_size
+** m = (ramdisk_size + page_size - 1) / page_size
+** o = (second_size + page_size - 1) / page_size
+**
+** 0. all entities are page_size aligned in flash
+** 1. kernel and ramdisk are required (size != 0)
+** 2. second is optional (second_size == 0 -> no second)
+** 3. load each element (kernel, ramdisk, second) at
+** the specified physical address (kernel_addr, etc)
+** 4. prepare tags at tag_addr. kernel_args[] is
+** appended to the kernel commandline in the tags.
+** 5. r0 = 0, r1 = MACHINE_TYPE, r2 = tags_addr
+** 6. if second_size != 0: jump to second_addr
+** else: jump to kernel_addr
+*/
+
+#endif
diff --git a/include/grub/linux.h b/include/grub/linux.h
index 594a3f3..4a99d78 100644
--- a/include/grub/linux.h
+++ b/include/grub/linux.h
@@ -9,6 +9,14 @@ struct grub_linux_initrd_context
grub_size_t size;
};
+struct grub_linux_initrd_component
+{
+ grub_file_t file;
+ char *newc_name;
+ grub_off_t fileoffset;
+ grub_off_t size;
+};
+
grub_err_t
grub_initrd_init (int argc, char *argv[],
struct grub_linux_initrd_context *ctx);
diff --git a/include/grub/misc.h b/include/grub/misc.h
index 2a9f87c..ef9c9b6 100644
--- a/include/grub/misc.h
+++ b/include/grub/misc.h
@@ -64,6 +64,17 @@ grub_stpcpy (char *dest, const char *src)
return d - 1;
}
+static inline char *
+grub_stpncpy (char *dest, const char *src, int c)
+{
+ char *p = dest;
+
+ while ((*p++ = *src++) != '\0' && --c)
+ ;
+
+ return p - 1;
+}
+
/* XXX: If grub_memmove is too slow, we must implement grub_memcpy. */
static inline void *
grub_memcpy (void *dest, const void *src, grub_size_t n)
signature.asc
Description: OpenPGP digital signature
_______________________________________________ Grub-devel mailing list [email protected] https://lists.gnu.org/mailman/listinfo/grub-devel
