Hi folks,

I subscribed to this list in order to share with you a humble
contribution of mine to grub.

As an OS developer enthusiastic, I needed to load a file to memory at
a given specific address.
No command in grub 1.99 was fitting my needs (as my file as no
semantic known to grub: it's not a module, it's not an initrd, it's
not a multiboot kernel either), so I developed my own module.

Please find included the source code of this module. For now, I've
added a copyright notice with my name and a mention to the GPLv3, but
I'm willing to share the source under GPLv3+ and/or hand over my
copyright rights to the GNU project if needed.
Also note that I wrote this module based on what I understand from
grub after reading its source, so please forgive me if I used the
wrong method.

Cheers,

Pierre-Nicolas "pini" Clauss
/* loadfile.c - file loading module
 * Copyright (C) 2011  Pierre-Nicolas Clauss
 *
 * Loadfile is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * Loadfile 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 Loadfile.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 *  GRUB  --  GRand Unified Bootloader
 *  Copyright (C) 2003,2007  Free Software Foundation, Inc.
 *  Copyright (C) 2003  NIIBE Yutaka <gni...@m17n.org>
 *
 *  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/err.h>
#include <grub/extcmd.h>
#include <grub/file.h>
#include <grub/i18n.h>
#include <grub/misc.h>
#include <grub/relocator.h>
#include <grub/types.h>

GRUB_MOD_LICENSE("GPLv3");

static struct grub_relocator* rel;

static grub_extcmd_t cmd;

static const struct grub_arg_option options[] = {
   {"skip", 's', 0, N_("Skip offset bytes from file."), 0, ARG_TYPE_INT},
   {0, 0, 0, 0, 0, 0}
};

static grub_err_t
grub_cmd_loadfile(grub_extcmd_context_t ctxt, int argc, char** argv) {
  struct grub_arg_list* state = ctxt->state;
  grub_file_t file;
  grub_relocator_chunk_t chunk;
  char* dest;
  grub_off_t skip, size;
  grub_ssize_t done;

  if(argc != 2) {
    return grub_error(GRUB_ERR_BAD_ARGUMENT,
                      "file name and memory address required");
  }
  skip = (grub_off_t)(state[0].set ? grub_strtoull(state[0].arg, 0, 0) : 0);
  file = grub_file_open(argv[0]);
  if(!file) {
    return grub_errno;
  }
  size = grub_file_size(file);
  if(size == GRUB_FILE_SIZE_UNKNOWN) {
    return grub_error(GRUB_ERR_FILE_READ_ERROR,
                      "could not determine size of %s", argv[0]);
  }
  if(skip >= size) {
    return grub_error(GRUB_ERR_BAD_ARGUMENT,
                      "cannot skip %llu bytes, file is only %llu", skip, size);
  }
  if(grub_relocator_alloc_chunk_addr(rel, &chunk,
       (grub_phys_addr_t)grub_strtoull(argv[1], 0, 0), size)) {
    return grub_errno;
  }
  dest = get_virtual_current_address(chunk);
  if(skip > 0) {
    grub_printf("Skipping %llu bytes from %s...\n", skip, argv[0]);
    size -= skip;
    if(grub_file_seekable(file)) {
      grub_file_seek(file, skip);
    } else while(skip > 0 && (done = grub_file_read(file, dest, skip)) > 0) {
      skip -= done;
    }
  }
  grub_printf("Loading %llu bytes from %s to %p...\n", size, argv[0], dest);
  while(size > 0 && (done = grub_file_read(file, dest, size)) > 0) {
    dest += done;
    size -= done;
  }
  grub_file_close(file);
  if(size > 0) {
    return grub_error(GRUB_ERR_FILE_READ_ERROR,
                      "early stop while reading %s: %llu bytes missing",
                      argv[0], size);
  }
  return 0;
}

GRUB_MOD_INIT(loadfile) {
  rel = grub_relocator_new();
  cmd = grub_register_extcmd("loadfile", grub_cmd_loadfile, 0,
                             N_("[OPTIONS] FILE ADDR"),
                             N_("Load a file to memory."), options);
}

GRUB_MOD_FINI(loadfile) {
  grub_unregister_extcmd(cmd);
  grub_relocator_unload(rel);
}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to