/* 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 . */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2003,2007 Free Software Foundation, Inc. * Copyright (C) 2003 NIIBE Yutaka * * 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 . */ #include #include #include #include #include #include #include #include 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); }