From 97f30af3b3b4bbfe51efa1f8bb0cd344280a028e Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sun, 28 Apr 2013 15:31:33 +0200 Subject: [PATCH 380/471] New command `nativedisk'. --- ChangeLog | 4 + docs/grub.texi | 8 ++ grub-core/Makefile.core.def | 5 + grub-core/commands/nativedisk.c | 250 ++++++++++++++++++++++++++++++++++++++++ grub-core/kern/dl.c | 46 +++----- grub-core/normal/main.c | 3 +- include/grub/dl.h | 29 ++++- 7 files changed, 316 insertions(+), 29 deletions(-) create mode 100644 grub-core/commands/nativedisk.c diff --git a/ChangeLog b/ChangeLog index 835895b..69c7839 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ 2013-04-28 Vladimir Serbinenko + New command `nativedisk'. + +2013-04-28 Vladimir Serbinenko + * grub-core/io/lzopio.c: Use GRUB_PROPERLY_ALIGNED_ARRAY. * grub-core/loader/i386/bsd.c: Likewise. diff --git a/docs/grub.texi b/docs/grub.texi index 754e191..587c64e 100644 --- a/docs/grub.texi +++ b/docs/grub.texi @@ -3411,6 +3411,7 @@ you forget a command, you can run the command @command{help} * lsfonts:: List loaded fonts * lsmod:: Show loaded modules * md5sum:: Compute or check MD5 hash +* nativedisk:: Switch to native disk drivers * normal:: Enter normal mode * normal_exit:: Exit from normal mode * parttool:: Modify partition table entries @@ -4035,6 +4036,13 @@ Alias for @code{hashsum --hash md5 arg @dots{}}. See command @command{hashsum} @end deffn +@node nativedisk +@subsection nativedisk + +@deffn Command nativedisk +Switch from firmware disk drivers to native ones. +@end deffn + @node normal @subsection normal diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 7f93723..2e73d89 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -508,6 +508,11 @@ module = { }; module = { + name = nativedisk; + common = commands/nativedisk.c; +}; + +module = { name = emupci; common = bus/emu/pci.c; common = commands/lspci.c; diff --git a/grub-core/commands/nativedisk.c b/grub-core/commands/nativedisk.c new file mode 100644 index 0000000..adb4043 --- /dev/null +++ b/grub-core/commands/nativedisk.c @@ -0,0 +1,250 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2013 Free Software Foundation, Inc. + * + * 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 +#include +#include +#include +#include + +GRUB_MOD_LICENSE ("GPLv3+"); + +static const char *modnames_def[] = { "pata", "ahci", "usbms", "ohci", "uhci", "ehci" }; + +static grub_err_t +get_uuid (const char *name, char **uuid) +{ + grub_device_t dev; + grub_fs_t fs = 0; + + dev = grub_device_open (name); + if (!dev) + return grub_errno; + if (dev) + fs = grub_fs_probe (dev); + if (!fs) + { + grub_device_close (dev); + return grub_errno; + } + if (!fs->uuid || fs->uuid (dev, uuid)) + { + grub_device_close (dev); + + if (!grub_errno) + grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("%s does not support UUIDs"), fs->name); + + return grub_errno; + } + grub_device_close (dev); + return GRUB_ERR_NONE; +} + +struct search_ctx +{ + char *root_uuid; + char *prefix_uuid; + const char *prefix_path; + int prefix_found, root_found; +}; + +static int +iterate_device (const char *name, void *data) +{ + struct search_ctx *ctx = data; + char *cur_uuid; + + if (get_uuid (name, &cur_uuid)) + { + grub_print_error (); + return 0; + } + if (grub_strcasecmp (cur_uuid, ctx->prefix_uuid) == 0) + { + char *prefix; + prefix = grub_xasprintf ("(%s)/%s", name, ctx->prefix_path); + grub_env_set ("prefix", prefix); + grub_free (prefix); + ctx->prefix_found = 1; + } + if (grub_strcasecmp (cur_uuid, ctx->root_uuid) == 0) + { + grub_env_set ("root", name); + ctx->root_found = 1; + } + return ctx->prefix_found && ctx->root_found; +} + +static grub_err_t +grub_cmd_nativedisk (grub_command_t cmd __attribute__ ((unused)), + int argc, char **args_in) +{ + char *uuid_root = 0, *uuid_prefix, *prefdev = 0; + const char *prefix = 0; + const char *path_prefix = 0; + int mods_loaded = 0; + grub_dl_t *mods; + struct search_ctx ctx; + const char **args; + grub_fs_autoload_hook_t saved_autoload; + int i; + + if (argc == 0) + { + argc = ARRAY_SIZE (modnames_def); + args = modnames_def; + } + else + args = (const char **) args_in; + + prefix = grub_env_get ("prefix"); + + if (! prefix) + return grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix"); + + if (prefix) + path_prefix = (prefix[0] == '(') ? grub_strchr (prefix, ')') : NULL; + if (path_prefix) + path_prefix++; + else + path_prefix = prefix; + + mods = grub_malloc (argc * sizeof (mods[0])); + if (!mods) + return grub_errno; + + if (get_uuid (NULL, &uuid_root)) + return grub_errno; + + prefdev = grub_file_get_device_name (prefix); + if (grub_errno) + { + grub_print_error (); + prefdev = 0; + } + + if (get_uuid (prefdev, &uuid_prefix)) + { + grub_free (uuid_root); + return grub_errno; + } + + for (mods_loaded = 0; mods_loaded < argc; mods_loaded++) + { + char *filename; + grub_dl_t mod; + grub_file_t file = NULL; + grub_ssize_t size; + void *core = 0; + + mod = grub_dl_get (args[mods_loaded]); + if (mod) + { + mods[mods_loaded] = 0; + continue; + } + + filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM "/%s.mod", + prefix, args[mods_loaded]); + if (! filename) + goto fail; + + file = grub_file_open (filename); + grub_free (filename); + if (! file) + goto fail; + + size = grub_file_size (file); + core = grub_malloc (size); + if (! core) + { + grub_file_close (file); + goto fail; + } + + if (grub_file_read (file, core, size) != (grub_ssize_t) size) + { + grub_file_close (file); + grub_free (core); + goto fail; + } + + grub_file_close (file); + + mods[mods_loaded] = grub_dl_load_core_noinit (core, size); + if (! mods[mods_loaded]) + goto fail; + } + + for (i = 0; i < argc; i++) + if (mods[i]) + grub_dl_init (mods[i]); + + /* No need to autoload FS since obviously we already have the necessary fs modules. */ + saved_autoload = grub_fs_autoload_hook; + grub_fs_autoload_hook = 0; + + ctx.root_uuid = uuid_root; + ctx.prefix_uuid = uuid_prefix; + ctx.prefix_path = path_prefix; + ctx.prefix_found = 0; + ctx.root_found = 0; + + /* FIXME: try to guess the correct values. */ + grub_device_iterate (iterate_device, &ctx); + + grub_fs_autoload_hook = saved_autoload; + + grub_free (uuid_root); + grub_free (uuid_prefix); + + return GRUB_ERR_NONE; + + fail: + grub_free (uuid_root); + grub_free (uuid_prefix); + + for (i = 0; i < mods_loaded; i++) + if (mods[i]) + { + mods[i]->fini = 0; + grub_dl_unload (mods[i]); + } + return grub_errno; +} + +static grub_command_t cmd; + +GRUB_MOD_INIT(nativedisk) +{ + cmd = grub_register_command ("nativedisk", grub_cmd_nativedisk, "[MODULE1 MODULE2 ...]", + N_("Switch to native disk drivers. If no modules are specified default set (pata,ahci,usbms,ohci,uhci,ehci) is used")); +} + +GRUB_MOD_FINI(nativedisk) +{ + grub_unregister_command (cmd); +} diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c index 641146d..6c086ad 100644 --- a/grub-core/kern/dl.c +++ b/grub-core/kern/dl.c @@ -51,6 +51,7 @@ grub_dl_t grub_dl_head = 0; grub_err_t grub_dl_add (grub_dl_t mod); +/* Keep global so that GDB scripts work. */ grub_err_t grub_dl_add (grub_dl_t mod) { @@ -58,9 +59,6 @@ grub_dl_add (grub_dl_t mod) return grub_error (GRUB_ERR_BAD_MODULE, "`%s' is already loaded", mod->name); - mod->next = grub_dl_head; - grub_dl_head = mod; - return GRUB_ERR_NONE; } @@ -77,18 +75,6 @@ grub_dl_remove (grub_dl_t mod) } } -grub_dl_t -grub_dl_get (const char *name) -{ - grub_dl_t l; - - for (l = grub_dl_head; l; l = l->next) - if (grub_strcmp (name, l->name) == 0) - return l; - - return 0; -} - struct grub_symbol @@ -447,13 +433,6 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) return GRUB_ERR_NONE; } -static void -grub_dl_call_init (grub_dl_t mod) -{ - if (mod->init) - (mod->init) (mod); -} - /* Me, Vladimir Serbinenko, hereby I add this module check as per new GNU module policy. Note that this license check is informative only. Modules have to be licensed under GPLv3 or GPLv3+ (optionally @@ -595,7 +574,7 @@ grub_dl_flush_cache (grub_dl_t mod) /* Load a module from core memory. */ grub_dl_t -grub_dl_load_core (void *addr, grub_size_t size) +grub_dl_load_core_noinit (void *addr, grub_size_t size) { Elf_Ehdr *e; grub_dl_t mod; @@ -651,10 +630,6 @@ grub_dl_load_core (void *addr, grub_size_t size) grub_dprintf ("modules", "module name: %s\n", mod->name); grub_dprintf ("modules", "init function: %p\n", mod->init); - grub_boot_time ("Initing module %s", mod->name); - grub_dl_call_init (mod); - grub_boot_time ("Module %s inited", mod->name); - if (grub_dl_add (mod)) { grub_dl_unload (mod); @@ -664,6 +639,23 @@ grub_dl_load_core (void *addr, grub_size_t size) return mod; } +grub_dl_t +grub_dl_load_core (void *addr, grub_size_t size) +{ + grub_dl_t mod; + + mod = grub_dl_load_core_noinit (addr, size); + + if (!mod) + return NULL; + + grub_boot_time ("Initing module %s", mod->name); + grub_dl_init (mod); + grub_boot_time ("Module %s inited", mod->name); + + return mod; +} + /* Load a module from the file FILENAME. */ grub_dl_t grub_dl_load_file (const char *filename) diff --git a/grub-core/normal/main.c b/grub-core/normal/main.c index 2f203dd..759e0a4 100644 --- a/grub-core/normal/main.c +++ b/grub-core/normal/main.c @@ -506,7 +506,8 @@ static void (*grub_xputs_saved) (const char *str); static const char *features[] = { "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint", "feature_default_font_path", "feature_all_video_module", - "feature_menuentry_id", "feature_menuentry_options", "feature_200_final" + "feature_menuentry_id", "feature_menuentry_options", "feature_200_final", + "feature_nativedisk_cmd" }; GRUB_MOD_INIT(normal) diff --git a/include/grub/dl.h b/include/grub/dl.h index 3119978..f34b5a1 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -25,6 +25,7 @@ #include #include #include +#include #endif /* @@ -181,15 +182,41 @@ typedef struct grub_dl *grub_dl_t; grub_dl_t grub_dl_load_file (const char *filename); grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); +grub_dl_t EXPORT_FUNC(grub_dl_load_core_noinit) (void *addr, grub_size_t size); int EXPORT_FUNC(grub_dl_unload) (grub_dl_t mod); void grub_dl_unload_unneeded (void); int EXPORT_FUNC(grub_dl_ref) (grub_dl_t mod); int EXPORT_FUNC(grub_dl_unref) (grub_dl_t mod); extern grub_dl_t EXPORT_VAR(grub_dl_head); +#ifndef GRUB_UTIL + #define FOR_DL_MODULES(var) FOR_LIST_ELEMENTS ((var), (grub_dl_head)) -grub_dl_t EXPORT_FUNC(grub_dl_get) (const char *name); +static inline void +grub_dl_init (grub_dl_t mod) +{ + if (mod->init) + (mod->init) (mod); + + mod->next = grub_dl_head; + grub_dl_head = mod; +} + +static inline grub_dl_t +grub_dl_get (const char *name) +{ + grub_dl_t l; + + FOR_DL_MODULES(l) + if (grub_strcmp (name, l->name) == 0) + return l; + + return 0; +} + +#endif + grub_err_t grub_dl_register_symbol (const char *name, void *addr, int isfunc, grub_dl_t mod); -- 1.8.2.1