GRUB2 Modules « Musings

GRUB2 has a modular structure with help for loading and unloading code modules as wanted. Modules are much like Linux kernel modules in some respects however in different methods they’re like plugins for Mozilla Firefox or the Eclipse IDE. On this put up I present an summary of what a GRUB2 module is and present you the way to modify an present module so as to add new performance. I additionally reveal the way to develop, combine and check your personal customized module utilizing the GRUB2 grub-emu userspace emulator.
The present model of GRUB2 (v1.98) has 159 modules:
acpi.mod date.mod gcry_sha1.mod loopback.mod pbkdf2.mod terminfo.mod affs.mod datetime.mod gcry_sha256.mod lsmmap.mod pci.mod check.mod afs_be.mod dm_nv.mod gcry_sha512.mod ls.mod play.mod tga.mod afs.mod drivemap.mod gcry_tiger.mod lspci.mod png.mod trig.mod aout.mod echo.mod gcry_twofish.mod lvm.mod probe.mod true.mod ata.mod efiemu.mod gcry_whirlpool.mod mdraid.mod pxecmd.mod udf.mod ata_pthru.mod elf.mod gettext.mod memdisk.mod pxe.mod ufs1.mod at_keyboard.mod example_functional_test.mod gfxmenu.mod memrw.mod raid5rec.mod ufs2.mod befs_be.mod ext2.mod gfxterm.mod minicmd.mod raid6rec.mod uhci.mod befs.mod extcmd.mod gptsync.mod minix.mod raid.mod usb_keyboard.mod biosdisk.mod fats.mod gzio.mod mmap.mod learn.mod usb.mod bitmap.mod font.mod halt.mod msdospart.mod reboot.mod usbms.mod bitmap_scale.mod fshelp.mod handler.mod multiboot2.mod reiserfs.mod usbtest.mod blocklist.mod functional_test.mod hashsum.mod multiboot.mod relocator.mod vbeinfo.mod boot.mod gcry_arcfour.mod hdparm.mod regular.mod scsi.mod vbe.mod bsd.mod gcry_blowfish.mod howdy.mod ntfscomp.mod search_fs_file.mod vbetest.mod bufio.mod gcry_camellia.mod assist.mod ntfs.mod search_fs_uuid.mod vga.mod cat.mod gcry_cast5.mod hexdump.mod ohci.mod search_label.mod vga_text.mod chain.mod gcry_crc.mod hfs.mod part_acorn.mod search.mod video_fb.mod charset.mod gcry_des.mod hfsplus.mod part_amiga.mod serial.mod video.mod cmp.mod gcry_md4.mod iso9660.mod part_apple.mod setjmp.mod videotest.mod configfile.mod gcry_md5.mod jfs.mod part_gpt.mod setpci.mod xfs.mod cpio.mod gcry_rfc2268.mod jpeg.mod part_msdos.mod sfs.mod xnu.mod cpuid.mod gcry_rijndael.mod keystatus.mod part_sun.mod sh.mod xnu_uuid.mod crc.mod gcry_rmd160.mod linux16.mod parttool.mod sleep.mod crypto.mod gcry_seed.mod linux.mod password.mod tar.mod datehook.mod gcry_serpent.mod loadenv.mod password_pbkdf2.mod terminal.mod
A few of the extra noteworthy modules are:
- ls, cat, echo, cmp: Present related performance to their Unix command couterparts.
- ext2, iso9660, reiserfs, xfs: Present help for filesystems of the identical title.
- part_sun, part_gpt, part_msdos: Present help for varied partition schemes.
- linux: Loader for Linux photographs
- vga, tga, vbe, png,jpeg: Present help for graphics and background photographs.
The instructions to load (insmod) or unload (rmmod) a module into GRUB2 have the identical names as in GNU/Linux.
When a module is loaded, or a linked-in module is initialized, the module registers a number of instructions, and can even register variables, parsers, and drivers. A GRUB2 command similar to hexdump requires a mapping from a reputation to a particular module operate The file /boot/grub/command.lst comprises the mappings from the command title to the module that comprises the operate (and code to implement that command). Right here is a part of the command.lst file:
cat: minicmd chainloader: chain clear: minicmd cmp: cmp .: configfile configfile: configfile *cpuid: cpuid crc: crc date: date *drivemap: drivemap dump: minicmd *echo: echo hexdump: hexdump
In lots of instances the command title is identical title because the module title, e.g. hexdump and hexdump.mod. In different instances a loaded module might register a number of instructions, e.g. loadenv.mod registers the load_env and save_env. If a command is entered (both instantly or by way of a script) the suitable module(s) is loaded if the command is just not already registered. A variable is a mapping from a reputation to a variable outlined within the module. Scripts can entry the variable as $title. Module variable eventing is supported; a module can get a callback when a worth is assigned to a variable.
Modules are literally ELF format information. The principle GRUB2 file core.img comprises the mandatory code to parse the ELF headers, load the module and do dynamic-linking (i.e., resolve calls to capabilities and variables exported by the core.img to be used by modules). A module is usually a built-in, i.e. a part of core.img or dynamically loaded utilizing insmod, or it may be loaded robotically when one other module is loaded by way of insmod as a result of the module being loaded has a dependency on it.
Dependency mappings are listed within the file moddep.lst. Right here is a part of this file:
video: font: bufio video hfsplus: fshelp gettext: regular gzio extcmd: regular: crypto boot terminal charset hashsum: extcmd regular crypto search: extcmd search_label search_fs_uuid search_fs_file xnu_uuid: gcry_md5 drivemap: extcmd boot mmap password: crypto regular learn:
From the above you may see that the password module has dependencies on the crypto and regular modules. Observe that the regular module is robotically loaded by core.img at startup and thus the modules crypto, boot, terminal and charset are additionally loaded at the moment as a result of regular has dependencies on these modules.
The supply code for GRUB2 is pretty properly structured and is usually ANSI C code. Naturally there’s a certain quantity of assembler code (that’s the nature of the beast) however the quantity is small and it is best to by no means have any want to change and even have a look at such code. It runs in 32-bit actual mode and is single-threaded. Usually there are not any synchronization points or races circumstances to contemplate.
Turning now to the query of the way to create and construct a GRUB2 module. The compulsory Hey World module (./howdy/howdy.mod) is included with the GRUB2 supply code tarball. Right here is the supply code for this module:
/* howdy.c - check module for dynamic loading */ /* * GRUB -- GRand Unified Bootloader * Copyright (C) 2003,2007 Free Software program Basis, Inc. * Copyright (C) 2003 NIIBE Yutaka <gniibe@m17n.org> * * GRUB is free software program: you may redistribute it and/or modify * it underneath the phrases of the GNU Normal Public License as printed by * the Free Software program Basis, both model 3 of the License, or * (at your choice) any later model. * * GRUB is distributed within the hope that it is going to be helpful, * however WITHOUT ANY WARRANTY; with out even the implied guarantee of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Normal Public License for extra particulars. * * You need to have acquired a replica of the GNU Normal Public License * together with GRUB. If not, see <http://www.gnu.org/licenses/>. */ #embrace <grub/sorts.h> #embrace <grub/misc.h> #embrace <grub/mm.h> #embrace <grub/err.h> #embrace <grub/dl.h> #embrace <grub/extcmd.h> #embrace <grub/i18n.h> static grub_err_t grub_cmd_hello (struct grub_extcmd *cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { grub_printf ("Hey Worldn"); return 0; } static grub_extcmd_t cmd; GRUB_MOD_INIT(howdy) { cmd = grub_register_extcmd ("howdy", grub_cmd_hello, GRUB_COMMAND_FLAG_BOTH, 0, N_("Say "Hey World"."), 0); } GRUB_MOD_FINI(howdy) { grub_unregister_extcmd (cmd); }
The above C language code shouldn’t be obscure. The definitions for GRUB_MOD_INIT and GRUB_MOD_FINI are within the header dl.h. These capabilities are principally used to register and unregister a command, on this case howdy. While you enter the command howdy the operate grub_cmd_hello within the dynamically loaded module howdy.mod is invoked. By no means attempt to use libc library capabilities in a module. All of the capabilities it is best to want can be found within the supply tarball and have the identical title because the equal libc operate besides that they’re prefixed by grub_, e.g. grub_printf() and printf(), grub_strcpy() and strcpy. As well as don’t embrace common headers similar to stdio.h.
If you’re not going to cross any arguments right into a command, you will need to particularly declare this reality within the operate declaration as follows:
function_name (struct grub_extcmd *cmd __attribute__ ((unused)), int argc __attribute__ ((unused)), char **args __attribute__ ((unused)))
The mandatory construct directives are already current for the howdy module. After compiling and putting in GRUB2, it is best to discover that the howdy module was put in in /boot/grub. On the GRUB2 command immediate, you may load and execute the howdy command as follows:
grub> insmod howdy.mod grub> howdy Hey World grub>
Turning now to to the hexdump command. The supply code for this command is within the ../instructions subdirectory. At the moment there isn’t a choice to dump your complete contents of a file on this command so I’ve determined so as to add this performance. I see from the next code snippet that presently hexdump can take two elective arguments:
static const struct grub_arg_option choices[] = { {"skip", 's', 0, N_("Skip offset bytes from the start of file."), 0, ARG_TYPE_INT}, {"size", 'n', 0, N_("Learn solely LENGTH bytes."), 0, ARG_TYPE_INT}, {0, 0, 0, 0, 0, 0} }; static grub_err_t grub_cmd_hexdump (grub_extcmd_t cmd, int argc, char **args) { struct grub_arg_list *state = cmd->state; grub_ssize_t dimension, size; grub_disk_addr_t skip; .... skip = (state[0].set) ? grub_strtoull (state[0].arg, 0, 0) : 0; size = (state[1].set) ? grub_strtoul (state[1].arg, 0, 0) : 256;
Observe that state[0] refers back to the first choice argument outlined in choices array, i.e. skip, and state[1] refers back to the second choice argument, i.e. size. Thus if one thing like -s 200 is handed as a command line argument to the hexdump command, state[0] is about to a non-zero worth. I exploit this reality to resolve when to hexdump the whole file. This I do if each state[0] and state[1} are set to 0.
Here is the source code for the new functionality:
..... if (!grub_strcmp (args[0], "(mem)")) hexdump (skip, (char *) (grub_addr_t) skip, size); /* new performance */ else if (state[0].set == 0 && state[1].set == 0) { file = grub_gzfile_open (args[0], 1); if (! file) return grub_errno; skip = 0; whereas ((dimension = grub_file_read (file, buf, 256)) > 0 && key != GRUB_TERM_ESC) { hexdump (skip, buf, dimension); skip += dimension; whereas (grub_checkkey () >= 0 && (key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != GRUB_TERM_ESC) ; } grub_putchar ('n'); grub_refresh (); grub_file_close (file); } /* finish new performance */ else if ((args[0][0] == '(') && (args[0][namelen - 1] == ')')) .....
The code needs to be just about self explanatory. Observe that hexdump is a separate library operate which codecs and shows all or a part of no matter is the buf buffer (is determined by the numeric values in skip and dimension). Additionally, the inside whereas loop is activated if the pagerenvironmental variable is about. On this case, hexdump shows a —MORE— immediate and solely shows the following display screen of knowledge when a key’s pressed. No modifications to the construct system are required; you may simply rebuild GRUB2, copy hexdump.mod to /boot/grub, reboot your system and check hexdump from the GRUB2 command immediate.
Subsequent we develop a model new module known as colortest from scratch. This module will show all the colour mixtures supported by GRUB2 (it the identical set as for GRUB Legacy) to be able to test that they’re appropriately displayed by GRUB2.
Right here is the supply code for the module. Observe for the sake of brevity I’ve not noted many of the potential shade mixtures as these would solely add a number of hundred extra strains of repetitive code to the itemizing. The supply code is commented the place I believe an evidence is warranted.
#embrace <grub/env.h> #embrace <grub/sorts.h> #embrace <grub/dl.h> #embrace <grub/misc.h> #embrace <grub/mm.h> #embrace <grub/font.h> #embrace <grub/time period.h> #embrace <grub/command.h> #embrace <grub/extcmd.h> #embrace <grub/i18n.h> /* takes one elective argument -c */ static const struct grub_arg_option choices[] = { {"clear", 'c', 0, N_("Clear the display screen first."), 0, 0}, {0, 0, 0, 0, 0, 0} }; /* since argc and argv aren't used throughout the operate they */ /* have to be declared unused - in any other case the construct fails */ static grub_err_t grub_cmd_colortest (grub_extcmd_t cmd, int argc __attribute__ ((unused)), char **args __attribute__ ((unused))) { struct grub_arg_list *state = cmd->state; grub_err_t err = GRUB_ERR_NONE; char color_normal[50]; const char *tmp; /* save the present shade string for color_normal. It's within the atmosphere */ /* set default if none within the atmosphere in any other case error messages in grub-emu */. tmp = grub_env_get("color_normal"); if (*tmp) grub_strcpy(color_normal, tmp); else grub_strcpy(color_normal, "light-gray/black"); /* clear the display screen if -c handed on command line */ if (state[0].set) grub_cls(); /* set the present shade state to regular jsut in case it it presently spotlight */ grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); /* black */ /* change the color_normal setting within the atmosphere */ grub_env_set ("color_normal", "dark-gray/black"); /* print this string in dark-gray on black. Black as background is clear */ grub_printf (" dark-gray/black "); grub_env_set ("color_normal", "light-blue/black"); grub_printf (" light-blue/black "); grub_env_set ("color_normal", "light-green/black"); grub_printf (" light-green/black "); grub_env_set ("color_normal", "light-cyan/black"); grub_printf (" light-cyan/black n"); grub_env_set ("color_normal", "light-red/black"); grub_printf (" light-red/black "); grub_env_set ("color_normal", "light-magenta/black"); grub_printf (" light-magenta/black "); grub_env_set ("color_normal", "yellow/black"); grub_printf (" yellow/black "); grub_env_set ("color_normal", "white/black"); grub_printf (" white/black n"); /* blue */ grub_env_set ("color_normal", "dark-gray/blue"); grub_printf (" dark-gray/blue "); grub_env_set ("color_normal", "light-blue/blue"); grub_printf (" light-blue/blue "); grub_env_set ("color_normal", "light-green/blue"); grub_printf (" light-green/blue "); grub_env_set ("color_normal", "light-cyan/blue"); grub_printf (" light-cyan/blue n"); grub_env_set ("color_normal", "light-red/blue"); grub_printf (" light-red/blue "); grub_env_set ("color_normal", "light-magenta/blue"); grub_printf (" light-magenta/blue "); grub_env_set ("color_normal", "yellow/blue"); grub_printf (" yellow/blue "); grub_env_set ("color_normal", "white/blue"); grub_printf (" white/blue n"); /* revert to the unique color_normal */ grub_env_set ("color_normal", color_normal); grub_printf ("nn"); /* black spotlight */ /* change the color_highlight setting within the atmosphere */ grub_env_set ("color_highlight", "black/blue"); /* allow color_highlight and print a string */ grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/blue "); grub_env_set ("color_highlight", "black/inexperienced"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/inexperienced "); grub_env_set ("color_highlight", "black/cyan"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/cyan "); grub_env_set ("color_highlight", "black/purple"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/purple n"); grub_env_set ("color_highlight", "black/magenta"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/magenta "); grub_env_set ("color_highlight", "black/brown"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/brown "); grub_env_set ("color_highlight", "black/light-gray"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" black/light-gray n"); /* blue spotlight */ grub_env_set ("color_highlight", "blue/inexperienced"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" blue/inexperienced "); grub_env_set ("color_highlight", "blue/cyan"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" blue/cyan "); grub_env_set ("color_highlight", "blue/purple"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" blue/purple n"); grub_env_set ("color_highlight", "blue/magenta"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" blue/magenta "); grub_env_set ("color_highlight", "blue/brown"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" blue/brown "); grub_env_set ("color_highlight", "blue/light-gray"); grub_setcolorstate (GRUB_TERM_COLOR_HIGHLIGHT); grub_printf (" blue/light-gray n"); /* revert to authentic color_normal */ grub_env_set ("color_normal", color_normal); grub_setcolorstate (GRUB_TERM_COLOR_NORMAL); grub_printf ("n"); /* and exit */ return err; } static grub_extcmd_t cmd; GRUB_MOD_INIT(colortest) { cmd = grub_register_extcmd ("colortest", grub_cmd_colortest, GRUB_COMMAND_FLAG_BOTH, "[-c]", /* the _N assemble is for message localization */ N_("Check supported shade mixtures."), choices); } GRUB_MOD_FINI(colortest) { grub_unregister_extcmd (cmd); }
Now that the C code is written, how can we combine colortest into the present GRUB2 construct system in order that colortest.mod is robotically constructed once we enter make. on the GRUB2 construct prime stage listing? It seems to be long-winded however straightforward. Simply add the next strains to ../conf/widespread.mk:
# For colortest.mod. pkglib_MODULES += colortest.mod colortest_mod_SOURCES = instructions/colortest.c clean-module-colortest.mod.1: rm -f colortest.mod mod-colortest.o mod-colortest.c pre-colortest.o colortest_mod-commands_colortest.o und-colortest.lst CLEAN_MODULE_TARGETS += clean-module-colortest.mod.1 clean-module-colortest.mod-symbol.1: rm -f def-colortest.lst CLEAN_MODULE_TARGETS += clean-module-colortest.mod-symbol.1 DEFSYMFILES += def-colortest.lst mostlyclean-module-colortest.mod.1: rm -f colortest_mod-commands_colortest.d MOSTLYCLEAN_MODULE_TARGETS += mostlyclean-module-colortest.mod.1 UNDSYMFILES += und-colortest.lst ifneq ($(TARGET_APPLE_CC),1) colortest.mod: pre-colortest.o mod-colortest.o $(TARGET_OBJ2ELF) -rm -f $@ $(TARGET_CC) $(colortest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ pre-colortest.o mod-colortest.o if check ! -z "$(TARGET_OBJ2ELF)"; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi $(STRIP) --strip-unneeded -Okay grub_mod_init -Okay grub_mod_fini -Okay _grub_mod_init -Okay _grub_mod_fini -R .be aware -R .remark $@ else colortest.mod: pre-colortest.o mod-colortest.o $(TARGET_OBJ2ELF) -rm -f $@ -rm -f $@.bin $(TARGET_CC) $(colortest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@.bin pre-colortest.o mod-colortest.o $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@ -rm -f $@.bin endif pre-colortest.o: $(colortest_mod_DEPENDENCIES) colortest_mod-commands_colortest.o -rm -f $@ $(TARGET_CC) $(colortest_mod_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ colortest_mod-commands_colortest.o mod-colortest.o: mod-colortest.c $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -c -o $@ $< mod-colortest.c: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh sh $(srcdir)/genmodsrc.sh 'colortest' $< > $@ || (rm -f $@; exit 1) ifneq ($(TARGET_APPLE_CC),1) def-colortest.lst: pre-colortest.o $(NM) -g --defined-only -P -p $< | sed 's/^([^ ]*).*/1 colortest/' > $@ else def-colortest.lst: pre-colortest.o $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]' | sed 's/^([^ ]*).*/1 colortest/' > $@ endif und-colortest.lst: pre-colortest.o echo 'colortest' > $@ $(NM) -u -P -p $< | lower -f1 -d' ' >> $@ colortest_mod-commands_colortest.o: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -MD -c -o $@ $< -include colortest_mod-commands_colortest.d clean-module-colortest_mod-commands_colortest-extra.1: rm -f cmd-colortest_mod-commands_colortest.lst fs-colortest_mod-commands_colortest.lst partmap-colortest_mod-commands_colortest.lst handler-colortest_mod-commands_colortest.lst parttool-colortest_mod-commands_colortest.lst video-colortest_mod-commands_colortest.lst terminal-colortest_mod-commands_colortest.lst CLEAN_MODULE_TARGETS += clean-module-colortest_mod-commands_colortest-extra.1 COMMANDFILES += cmd-colortest_mod-commands_colortest.lst FSFILES += fs-colortest_mod-commands_colortest.lst PARTTOOLFILES += parttool-colortest_mod-commands_colortest.lst PARTMAPFILES += partmap-colortest_mod-commands_colortest.lst HANDLERFILES += handler-colortest_mod-commands_colortest.lst TERMINALFILES += terminal-colortest_mod-commands_colortest.lst VIDEOFILES += video-colortest_mod-commands_colortest.lst cmd-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) gencmdlist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/gencmdlist.sh colortest > $@ || (rm -f $@; exit 1) fs-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) genfslist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/genfslist.sh colortest > $@ || (rm -f $@; exit 1) parttool-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) genparttoollist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/genparttoollist.sh colortest > $@ || (rm -f $@; exit 1) partmap-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) genpartmaplist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/genpartmaplist.sh colortest > $@ || (rm -f $@; exit 1) handler-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) genhandlerlist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/genhandlerlist.sh colortest > $@ || (rm -f $@; exit 1) terminal-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) genterminallist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/genterminallist.sh colortest > $@ || (rm -f $@; exit 1) video-colortest_mod-commands_colortest.lst: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) genvideolist.sh set -e; $(TARGET_CC) -Icommands -I$(srcdir)/instructions $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(colortest_mod_CFLAGS) -E $< | sh $(srcdir)/genvideolist.sh colortest > $@ || (rm -f $@; exit 1) colortest_mod_CFLAGS = $(COMMON_CFLAGS) colortest_mod_LDFLAGS = $(COMMON_LDFLAGS)
A lot of the above is boilerplate. I merely copied it from an present goal similar to tga in widespread.mk and altered the goal title to colortest. If you happen to now execute make from the GRUB2 construct toplevel listing, it ought to comprise the module colortest.mod after the construct completes if the construct was profitable.
Here’s a detailed itemizing of the instructions used to construct colortest.mod:
gcc -Icommands -I./instructions -nostdinc -isystem /usr/lib/gcc/x86_64-redhat-linux/4.4.4/embrace -I./embrace -I. -I./embrace -Wall -W -Os -DGRUB_MACHINE_PCBIOS=1 -Wall -W -Wshadow -Wpointer-arith -Wmissing-prototypes -Wundef -Wstrict-prototypes -g -falign-jumps=1 -falign-loops=1 -falign-functions=1 -mno-mmx -mno-sse -mno-sse2 -mno-3dnow -fno-dwarf2-cfi-asm -m32 -fno-stack-protector -mno-stack-arg-probe -Werror -fno-builtin -mrtd -mregparm=3 -m32 -MD -c -o colortest_mod-commands_colortest.o instructions/colortest.c rm -f pre-colortest.o gcc -m32 -nostdlib -m32 -Wl,--build-id=none -Wl,-r,-d -o pre-colortest.o colortest_mod-commands_colortest.o nm -g --defined-only -P -p pre-colortest.o | sed 's/^([^ ]*).*/1 colortest/' > def-colortest.lst echo 'colortest' > und-colortest.lst nm -u -P -p pre-colortest.o | lower -f1 -d' ' >> und-colortest.lst
As you may see beneath, a 32-bit ELF relocatable binary is produced.
file colortest.mod colortest.mod: ELF 32-bit LSB relocatable, Intel 80386, model 1 (SYSV), not stripped #
There are a selection of how to check and confirm the brand new colortest module. You possibly can copy colortest.mod into /boot/grub, modify /boot/grub/command.lst so as to add the next entry:
and reboot your system to the GRUB2 command immediate. From there you may load the colortest module utilizing insmod and invoke the grub_colortest operate by coming into the command colortest or colortest -c on the grub> immediate. A downside to this technique is that it requires you to reboot your system each time you make a change to the colortest supply code or construct atmosphere.
If you wish to keep away from having to repeatedly reboot your system you may check the performance of colortest utilizing the GRUB2 userspace emulator grub-emu. Observe that grub-emu is just not used for system booting; it’s a standalone utility which you’ll run from the command line after you boot your system into GNU/Linux. It emulates, as greatest it could actually however with some limitations, the conduct of the GRUB2 command line.
To construct grub-emu you must have each the ncurses-libs and ncurses-devel packages put in. I didn’t discover a lot documentation on the way to construct grub-emu however found how to take action principally by trial and error. In the long run it turned out to be fairly easy.
./make clear ./configure --platform=emu ./make ./grub-emu
This could get you to the grub-emu immediate after a number of warning messages are displayed. These warning messages are regular. Here’s what grub-emu outputs when it’s invoked with the -h choice:
# ./grub-emu -h Utilization: ./grub-emu [OPTION]... GRUB emulator. -r, --root-device=DEV use DEV as the foundation system [default=guessed] -m, --device-map=FILE use FILE because the system map [default=/boot/grub/device.map] -d, --directory=DIR use GRUB information within the listing DIR [default=/boot/grub] -v, --verbose print verbose messages -H, --hold[=SECONDS] wait till a debugger will connect -h, --help show this message and exit -V, --version print model data and exit Report bugs to. #
By the way in which, enter exit or reboot to exit grub-emu. Discover that no modules similar to regular.mod or colortest.mod are constructed when constructing the GRUB2 emulator. That’s as a result of insmod doesn’t work in grub-emu and subsequently constructing the modules is pointless. The insmod command is there but it surely can’t do something. If you happen to attempt to use insmod to load a module from /boot/grub, it should reply with an invalid arch impartial ELF magic error message. Modules are both built-in in the course of the construct course of or aren’t out there. At the moment, in case you attempt to execute colortest from inside grub-emu you’ll get a error: unknown command ‘colortest’ error message.
To get grub-emu to acknowledge the colortest command a variety of information should be modified and grub-emu rebuilt. First, add the next two strains to grub-emu-init.c:
grub_colortest_init (); grub_colortest_fini ();
The primary line needs to be added to the grub_init_all process and the second line to the grub_fini_all process. Two appropriate operate prototypes, modeled on the opposite present operate prototypes, needs to be added to grub-emu-init.h additionally. The aim of grub_init_all and grub_fini_all (see …/util/grub-emu.c) is to load the desired modules at grub-emu startup and unload them when grub-emu is terminating.
Subsequent you must modify ../conf/any-emu.mk so as to add help for linking colortest into grub-emu when constructing grun-emu. At a minimal add instructions/colortest.c to the grub_emu_SOURCES record. Whereas not completely required, I’d add grub_emu-commands_colortest.o and grub_emu-commands_colortest.d to the record of information to be eliminated by the cleanup directives, e.g. clean-utility-grub-emu.1:, and many others. Lastly, we have to inform any-emu.mk the way to compile colortest.o for inclusion in grub-emu by including the next directives to the file:
grub_emu-commands_colortest.o: instructions/colortest.c $(instructions/colortest.c_DEPENDENCIES) $(CC) -Icommands -I$(srcdir)/instructions $(CPPFLAGS) $(CFLAGS) -DGRUB_UTIL=1 $(grub_emu_CFLAGS) -MD -c -o $@ $< -include grub_emu-commands_colortest.d
After rebuilding grub-emu, the colortest command needs to be listed once you enter the assist command.
Here’s a screenshot of grub-emu displaying the outcomes of the colortest command.
One other technique to safely check a brand new module is to host GRUB2 on an IA32 processor emulator similar to Qemu or Bochs. Nevertheless, I’m not going to cowl these strategies on this put up. If I discover the time I’ll cowl them in a separate put up within the close to future.
I’m going to cease writing now. Hopefully, after studying this put up, you might have a greater understanding of the way to write, combine and check a GRUB2 module. Please let me know if there’s different pertinent data I ought to add to this put up which might help readers in understanding the related points.
P.S. I constructed and examined the examples included on this put up on X64 platform working Fedora 13.