Writing GRUB Modules

From OSDev Wiki
Jump to navigation Jump to search
Difficulty level
Difficulty 3.png
Advanced

The whole architecture of GRUB changed as of version 2. The big new feature is modules. This lead to the elimination of Stage 1.5. It also means it is easier for you to put lot of cool functionality into your bootloader. You can now add support for new executable formats, filesystems, video drivers, kernel boot protocols, and so on.

Modules

GRUB modules are relocatable ELF32 binaries. They have the extension .mod.

Header files

All the standard GRUB header files from the source distribution can be included. If you are building out-of-tree and have not configured the source for your system, then these can still be used with a few modifications:

  • define GRUB_MACHINE_PCBIOS to be 1
  • define GRUB_UTIL
  • define GRUB_FILE to be something appriopriate
  • provide include/grub/cpu/memory.h to typedef grub_phys_addr_t to something appropriate (e.g. intptr_t)

Special Sections

Each module is required to contain three special pieces of information: the module name, the dependencies of the module (i.e. which other modules need to be loaded prior to this one) and the licence of the module. For GRUB 2, the licence is required to be GPL otherwise it will not be loaded. These need to be placed in special sections within the module. The following piece of code (GCC specific) at module scope will achieve the required functionality:

char modname[] __attribute__((section(".modname"))) = "mymodule";

/* Example dependencies */
char moddeps[] __attribute__((section(".moddeps"))) = "relocator\0video\0vbe\0multiboot\0gfxterm";

GRUB_MOD_LICENSE("GPLv3+");

Initialization

You need to provide initialization and finalization functions for your module. These are called when the module is loaded/unloaded, and should register the commands that the module provides along with any other resources it requires. A short example is:

static grub_extcmd_t cmd;

GRUB_MOD_INIT(mymodule)
{
    cmd = grub_register_extcmd("mycommand" /* name of the command */,
            grub_cmd_mycommand /* function to call when the command is run */,
            0 /* flags */,
            0 /* summary */,
            N_("In-depth description of this command") /* description */,
            0 /* argument parser */);
}

GRUB_MOD_FINI(mymodule)
{
    grub_unregister_extcmd(cmd);
}

See the GRUB source/example modules for more information about the other options here.

Functions

Some useful functions exposed by grub are given below. Note that there are implementations of typical libc/POSIX functions often prefixed by grub_ in the grub include directory. Some may require additional modules to be loaded first - GRUB will highlight this when you try and insmod a module that contains functionality that is not currently loaded.

int EXPORT_FUNC() grub_printf(const char* func, ...);  //Very similar to standard printf()
void *grub_malloc(grub_size_t size);         // grub's malloc function - memory allocated by this will
                                             //  not necessarily be accessible to your kernel.  See the
                                             //  relocator module if this is the functionality you need.
grub_extcmd_t grub_register_extcmd (const char * name, grub_extcmd_func_t func, 
    grub_command_flags_t flags, const char * summary, const char * description, 
    const struct grub_arg_option * parser);  //Registers a command on the GRUB command line
grub_fs_register (struct grub_fs* fs);       //Registers a filesystem with GRUB (grub_fs is a set of function pointers)
grub_err_t grub_video_set_mode(const char *modestring, unsigned modemask, unsigned modevalue);
                                             // Attempt to set a video mode.
                                             //  e.g. grub_video_set_mode("1024x768x32,auto", 0, 0);

Building

Modules are object files. You therefore need to use GCC (i686-elf recommended) to build your C files, then use ld's -r option to combine your object files (if necessary). the final output needs to be named .mod.

A particular register calling convention is used by GRUB, such that the first three parameters are passed in eax, edx and ecx then on the stack, and the callee cleans the stack. If you use C and the GRUB build system to handle building your module then this is handled for you. If you build 'out-of-tree' without first configuring GRUB to build for your system, however, then the following GCC flags will be required for compilation (includes the #defines listed above):

GRUBCFLAGS = -Os -DGRUB_MACHINE_PCBIOS=1 -falign-jumps=1 -falign-loops=1 -falign-functions=1 \ 
    -mno-mmx -mno-sse -mno-sse2 -mno-3dnow -m32 -fno-stack-protector -mno-stack-arg-probe \
    -mrtd -mregparm=3 -DGRUB_UTIL -ffreestanding -DGRUB_FILE=__FILE__

Loading

Modules can be loaded with the insmod command, from the GRUB configuration file. For filesystem modules, this allows your OS to be booted from your FS, but requires a recognized format for your module. To solve this, you will need to add your module to core.img using grub-mkimage, which can be installed using grub-setup, or possibly grub-install (which is a shell script wrapper to mkimage and setup).

External Links